Skip to content

release: v1.2.5 - load the CommonJS entry without top-level await - #52

Merged
cldmv-bot[bot] merged 24 commits into
masterfrom
next
Oct 5, 2026
Merged

cldmv-bot[bot] merged 24 commits into
masterfrom
next

Conversation

@cldmv-bot

@cldmv-bot cldmv-bot Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

@cldmv/uuid v1.2.5 Changelog

Release Date: October 2026
Release Type: Patch
Branch: release/1.2.5


Overview

v1.2.5 makes require("@cldmv/uuid") work. The CommonJS entry has failed to load in every release up to and including v1.2.4, because the ESM entry it wraps used top-level await. This release removes the top-level await, so require() returns the same UUID object that import does on any Node.js version with synchronous require(esm), and fails with a clear message on versions without it.

It also gives TypeScript users real types for the first time: UUID used to resolve to any, and it is now fully typed, with Buffer returns in Node projects and Uint8Array returns in browser and bundler projects. The repository finally carries the Apache-2.0 LICENSE file that package.json has always declared. The dev toolchain moves to @cldmv/fix-headers 2.2.0 and @cldmv/configs 1.2.4, and @types/node is added for the new type tests.

ESM consumers see no change in runtime behavior. The exported names (default, UUID, uuid, ISSUER_CATEGORIES) and their values are the same as in v1.2.4.


🐛 Bug Fixes

Load the CommonJS entry without top-level await (#50)

index.cjs loads index.mjs through Node's synchronous require(esm). Node rejects any module graph that contains top-level await there, and index.mjs had two: one around the optional devcheck.mjs import and one for await import("@cldmv/uuid/main"). So on Node.js versions with require(esm), require("@cldmv/uuid") threw ERR_REQUIRE_ASYNC_MODULE, and on older versions it threw ERR_REQUIRE_ESM. Either way, no CommonJS consumer could load the package.

  • index.mjs now imports @cldmv/uuid/main statically, and the optional development check runs inside an async function rather than at the top level. devcheck.mjs exists only in a source checkout and has never been published, so its import is still allowed to fail.
  • index.cjs calls require("./index.mjs") directly instead of going through createRequire.
  • On a Node.js version without require(esm) (anything before 20.19.0, or 22.0.0 to 22.11.x), index.cjs now throws an ERR_REQUIRE_ESM error whose message names the supported versions and points to import() instead.
  • A new tests/cjs/entry.test.cjs suite runs under Node's own test runner, since Vitest loads files through its own module runner and can't show how a plain require() behaves. It checks that require() returns the same objects as import and that the error message appears when require(esm) is turned off. npm test and npm run coverage both run it through the new test:cjs script.

Export the default from the named export list (#50)

tsc emitted export default UUID; above the declaration it referred to in types/index.d.mts, which CodeQL flags as js/use-before-declaration. The entry now exports a single list (export { UUID as default, UUID, UUID as uuid, ISSUER_CATEGORIES }), so the generated declaration file imports UUID and ISSUER_CATEGORIES from @cldmv/uuid/main first and then re-exports them. The exported types are unchanged.

🔷 TypeScript

Accurate type declarations for the package and its subpaths (#55, fixes #51)

types/index.d.mts imports from @cldmv/uuid/main, but ./main had no types condition, so TypeScript could not find its declarations and UUID was typed any. skipLibCheck hid the error. ./main, ./rng, ./bytes and ./hash now all have types conditions, and the generated declarations were fixed in the source JSDoc so they compile with strict and skipLibCheck: false:

  • The options argument of v1, v4, v6, v7 and v8 is optional and typed (UUID.v4() used to be a compile error once the types resolved). Passing buf returns that same buffer, typed as whatever you passed in; otherwise the methods return a string.
  • TA/TB timestamps and entropy arguments are optional, and getRegistry()'s IssuerRegistry type resolves.
  • toBuffer() returns Buffer in Node projects (module/moduleResolution node16/nodenext with @types/node) and Uint8Array in browser and bundler projects, chosen through a private #bytes-type import. The package never forces Node's globals into a project: without @types/node the type falls back to Uint8Array. The two alias declarations behind it live in a new typings/ folder (typings/bytes.d.mts and typings/bytes-node.d.mts), which is added to the package's files and selected through a new imports entry in package.json.

A new npm run test:types check (run by npm test and npm run coverage) packs the package, installs it into a throwaway consumer and compiles it under nodenext and bundler resolution, including the README's TypeScript example.


📄 License

The repository now includes the Apache-2.0 LICENSE file (#54). package.json has always declared Apache-2.0 and listed LICENSE in files, but the file was missing, so GitHub showed no license and the published package shipped without the license text.


📚 Documentation

  • NEW: docs/changelog/v1/v1.2.5.md: this changelog.
  • NEW: backfilled v1.2.4, and corrected the v1.2.3 release month to October 2026.
  • README restructured to the standard CLDMV layout, with a new Requirements section that states the require() Node.js floor.

🔧 Dependencies

All changes are dev-only and none ships in the package. The package still has no runtime dependencies.

  • @cldmv/fix-headers ^2.1.2 → ^2.2.0, resolved to 2.2.0. The range was first raised to ^2.1.4 (#57) and then to ^2.2.0 (#59). Version 2.1.4 no longer writes a JavaScript comment into JSON or Markdown files, processes every repeated --input, and never walks dependency folders such as node_modules. Version 2.2.0 changes @Last modified by only when a file's content was edited, so header-only rewrites keep the recorded editor.
  • @cldmv/configs ^1.2.1 → ^1.2.4, resolved to 1.2.4. The shared fix-headers config now sets forceAuthorUpdate and forceLastModifiedAuthorUpdate to false (#59).
  • @types/node ^26.6.4 added (resolved to 26.6.4, with its transitive undici-types 8.9.0). The type-check suite uses it to prove that toBuffer() returns Buffer in a Node project (#55).
  • No file headers were restamped: the fix-headers and configs bump PRs change only package.json and the lockfile, and the published package is unaffected.

Upgrade notes

  • No breaking changes. ESM imports behave exactly as in v1.2.4.
  • TypeScript projects that relied on UUID being any may now see real type errors in their own code; those are calls the types previously failed to check.
  • CommonJS consumers can now use const UUID = require("@cldmv/uuid") (with UUID.UUID, UUID.uuid and UUID.ISSUER_CATEGORIES as properties). This needs Node.js ^20.19.0 or >=22.12.0. On older Node.js versions, load the package with import().
👥 Contributors

coverage

Metric Coverage
Statements 85.7%
Branches 84.9%
Functions 92.5%
Lines 85.4%

Avg: 87.1% · 2782926 · Node lts/*

Co-authored-by: Shinrai Shinrai@users.noreply.github.com

Shinrai and others added 4 commits October 3, 2026 10:24
index.cjs loads index.mjs through Node's synchronous require(esm), and
index.mjs used top-level await for the devcheck and the library import,
so every require("@cldmv/uuid") failed with ERR_REQUIRE_ASYNC_MODULE.

- index.mjs: devcheck runs inside an async function (it is never
  published, so a failed import is ignored) and the library is a static
  import, so the module graph has no top-level await.
- index.cjs: a plain require of index.mjs. Where Node.js has no
  require(esm) (before 20.19 / 22.12) it throws ERR_REQUIRE_ESM with a
  message pointing to import() instead of a bare loader error.
- tests/cjs: node:test checks run by `npm test` and `npm run coverage`
  after Vitest: require() returns the same objects as import, and the
  version check fires when require(esm) is off.

Fixes #49
tsc emitted `export default UUID;` above `import { UUID }` in
types/index.d.mts, which CodeQL flags as js/use-before-declaration. A
single export list with `UUID as default` generates the import first.
@cldmv-bot cldmv-bot Bot added ! release → master v4 flow: persistent next → master release PR (carries the next feature release) release Marks a pull request as a pending release — merge to publish a new version semver: patch This release contains only backwards-compatible bug fixes type: bug Something is broken or not behaving as expected labels Oct 3, 2026
@cldmv-bot

cldmv-bot Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor Author

🔒 Dependency Review

  • ✅ 0 vulnerable package(s)
  • ✅ 0 package(s) with incompatible licenses
  • ✅ 0 package(s) with invalid SPDX license definitions
  • ✅ 0 package(s) with unknown licenses
  • ✅ 0 denied package(s)
  • ✅ 0 package(s) with OpenSSF Scorecard score < 3

Full job summary

@cldmv-bot cldmv-bot Bot added area: tests Touches test files, fixtures, or test infrastructure type: dependencies Relates to dependency updates, version bumps, or package management labels Oct 3, 2026
@cldmv-bot

cldmv-bot Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor Author

⚠️ Bundle size increased

File Raw Δ Raw Gzipped Δ Gzipped
dist/data/issuers.json 1.3 kB — 538 B —
dist/lib/bit-utils.mjs 7.9 kB — 2.2 kB —
dist/lib/bytes-browser.mjs 2.0 kB — 1.0 kB —
dist/lib/bytes.mjs 1.4 kB — 717 B —
dist/lib/constants.mjs 3.1 kB — 1.1 kB —
dist/lib/entropy-sources.mjs 9.3 kB — 3.2 kB —
dist/lib/hash-browser.mjs 5.9 kB — 2.1 kB —
dist/lib/hash.mjs 1.3 kB — 600 B —
dist/lib/issuer-registry.mjs 10.9 kB — 2.9 kB —
dist/lib/rng-browser.mjs 1007 B — 564 B —
dist/lib/rng.mjs 840 B — 499 B —
dist/lib/validators.mjs 13.6 kB — 3.7 kB —
dist/lib/versions/index.mjs 1.1 kB — 552 B —
dist/lib/versions/issuer/index.mjs 644 B — 412 B —
dist/lib/versions/issuer/v1.mjs 3.8 kB — 1.5 kB —
dist/lib/versions/rfc/index.mjs 1009 B — 539 B —
dist/lib/versions/rfc/utils.mjs 3.1 kB −6 B (-0.2%) ✅ 1.3 kB −1 B
dist/lib/versions/rfc/v1.mjs 2.8 kB +74 B (+2.6%) 1.2 kB +36 B
dist/lib/versions/rfc/v35.mjs 2.8 kB +156 B (+5.7%) ⚠️ 1015 B +32 B
dist/lib/versions/rfc/v4.mjs 1.5 kB +56 B (+3.8%) 772 B +28 B
dist/lib/versions/rfc/v6.mjs 2.8 kB +74 B (+2.7%) 1.2 kB +39 B
dist/lib/versions/rfc/v7.mjs 2.0 kB +56 B (+2.8%) 969 B +28 B
dist/lib/versions/rfc/v8.mjs 2.0 kB +56 B (+2.8%) 1011 B +29 B
dist/lib/versions/timestamp/index.mjs 708 B — 417 B —
dist/lib/versions/timestamp/v1.mjs 5.5 kB — 1.9 kB —
dist/lib/versions/timestamp/v2.mjs 5.5 kB — 1.9 kB —
dist/uuid.mjs 27.9 kB +4.4 kB (+18.7%) ⚠️ 6.6 kB +841 B
index.cjs 1.4 kB +427 B (+44.1%) ⚠️ 784 B +249 B
index.mjs 1.1 kB +347 B (+43.1%) ⚠️ 700 B +202 B
Total 124.2 kB +5.6 kB 41.7 kB +1.4 kB

📊 Generated by bundle-size. Brotli sizes also measured but omitted from the table for brevity.

Shinrai and others added 8 commits October 3, 2026 16:46
package.json declares Apache-2.0 and lists LICENSE in `files`, but the
repository never had the file, so GitHub detected no license and the
published package shipped without the license text.
TypeScript users got `any` for UUID: ./main had no `types` condition, so
types/index.d.mts could not resolve `@cldmv/uuid/main` (TS7016, hidden by
skipLibCheck). ./rng, ./bytes and ./hash had no `types` either.

Wiring the condition exposed declarations that did not compile or described
the API wrongly, so the source JSDoc is corrected:

- v1/v4/v6/v7/v8 options are optional, with typed option objects
  (TimeOptions, V4Options, V7Options, V8Options), and overloads that return
  a Uint8Array when `options.buf` is given.
- TA/TB timestamp and every `entropy` argument are optional;
  createTimestampVariant/timestamp accept null/undefined for the timestamp.
- getRegistry() imports IssuerRegistry instead of naming an undeclared type.
- The UUID class no longer references Node's Buffer, so the main entry
  type-checks without @types/node (the package also runs in browsers).
- _buffer is declared private instead of leaking Uint8Array<ArrayBuffer>.

./rng, ./bytes and ./hash get `types` for the Node variants and nested
`browser` -> `types` for the browser variants.

`npm run test:types` (run by `npm test` and `coverage`) builds, packs the
package, unpacks it into a throwaway consumer and compiles fixtures with
strict, nodenext and no skipLibCheck: the main entry, ./main, the README
TypeScript example, the subpaths (Node and browser conditions), and a
deliberately wrong assignment that must fail. The README example is
corrected to match the real types.

Fixes #51
…y elsewhere

toBuffer() returns a Buffer in Node but was typed Uint8Array everywhere, so
Node consumers could not call Buffer APIs on it without a cast.

A `Bytes` alias now comes from the private `#bytes-type` import, mapped in
package.json `imports` (types only): typings/bytes-node.d.mts (Buffer) under
the `node` condition, which TypeScript applies with node16/nodenext, and
typings/bytes.d.mts (Uint8Array) otherwise (bundler resolution, or the
`browser` condition). toBuffer() returns `Bytes`. The `buf` overloads of
v1/v4/v6/v7/v8 are generic and return the buffer they were given, so a
Buffer stays a Buffer and a plain Uint8Array is not mistyped as one.
typings/ ships in `files`.

The consumer type test checks the main entry under nodenext with
@types/node and under bundler without it, that Buffer methods compile on
the Node flavour, that they fail on the default flavour, and which typings
file each mode resolves.

Refs #51
…@types/node

The Node flavour of #bytes-type used /// <reference types="node" />, so a
nodenext project without @types/node got TS2688 from the package, and any
project that imported it had Node's globals (process, Buffer, ...) forced
in. Bytes is now Buffer when @types/node is loaded and Uint8Array
otherwise. A new consumer test checks that importing the package under
nodenext without @types/node does not make process available.

Refs #51
@cldmv-bot cldmv-bot Bot added area: core Touches core library / runtime source code type: documentation Relates to docs, README updates, guides, or inline code comments labels Oct 4, 2026
Shinrai and others added 8 commits October 3, 2026 18:27
The LICENSE file and the TypeScript declaration fix merged into next ahead
of the v1.2.5 notes but were not described. Add both to the changelog and
the What's New block, and show the GitHub license badge now that the file
exists.
Bumps @cldmv/fix-headers to 2.1.4 (JSON/Markdown/extension-less files never get a JS comment; dependency folders never walked). Ran fix:headers: 0 files restamped.
Restamping the file headers under 2.2.0 changed no headers (0 files restamped).
Shinrai and others added 4 commits October 4, 2026 19:14
Shared fix-headers config 1.2.4 no longer forces author updates. Restamping the file headers changed no headers (0 files restamped).
@cldmv-bot
cldmv-bot Bot merged commit 1542ed6 into master Oct 5, 2026
42 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: core Touches core library / runtime source code area: tests Touches test files, fixtures, or test infrastructure ! release → master v4 flow: persistent next → master release PR (carries the next feature release) release Marks a pull request as a pending release — merge to publish a new version semver: patch This release contains only backwards-compatible bug fixes type: bug Something is broken or not behaving as expected type: dependencies Relates to dependency updates, version bumps, or package management type: documentation Relates to docs, README updates, guides, or inline code comments

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TypeScript users get any for UUID: ./main has no types entry, and the generated declarations are inaccurate

1 participant