release: v1.2.5 - load the CommonJS entry without top-level await - #52
Merged
Merged
Conversation
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.
Contributor
Author
🔒 Dependency Review
|
Contributor
Author
|
| 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.
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
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).
Shared fix-headers config 1.2.4 no longer forces author updates. Restamping the file headers changed no headers (0 files restamped).
Shinrai
approved these changes
Oct 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
@cldmv/uuid v1.2.5 Changelog
Release Date: October 2026
Release Type: Patch
Branch:
release/1.2.5Overview
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-levelawait. This release removes the top-levelawait, sorequire()returns the sameUUIDobject thatimportdoes on any Node.js version with synchronousrequire(esm), and fails with a clear message on versions without it.It also gives TypeScript users real types for the first time:
UUIDused to resolve toany, and it is now fully typed, withBufferreturns in Node projects andUint8Arrayreturns in browser and bundler projects. The repository finally carries the Apache-2.0LICENSEfile thatpackage.jsonhas always declared. The dev toolchain moves to@cldmv/fix-headers2.2.0 and@cldmv/configs1.2.4, and@types/nodeis 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.cjsloadsindex.mjsthrough Node's synchronousrequire(esm). Node rejects any module graph that contains top-levelawaitthere, andindex.mjshad two: one around the optionaldevcheck.mjsimport and one forawait import("@cldmv/uuid/main"). So on Node.js versions withrequire(esm),require("@cldmv/uuid")threwERR_REQUIRE_ASYNC_MODULE, and on older versions it threwERR_REQUIRE_ESM. Either way, no CommonJS consumer could load the package.index.mjsnow imports@cldmv/uuid/mainstatically, and the optional development check runs inside an async function rather than at the top level.devcheck.mjsexists only in a source checkout and has never been published, so its import is still allowed to fail.index.cjscallsrequire("./index.mjs")directly instead of going throughcreateRequire.require(esm)(anything before 20.19.0, or 22.0.0 to 22.11.x),index.cjsnow throws anERR_REQUIRE_ESMerror whose message names the supported versions and points toimport()instead.tests/cjs/entry.test.cjssuite runs under Node's own test runner, since Vitest loads files through its own module runner and can't show how a plainrequire()behaves. It checks thatrequire()returns the same objects asimportand that the error message appears whenrequire(esm)is turned off.npm testandnpm run coverageboth run it through the newtest:cjsscript.Export the default from the named export list (#50)
tscemittedexport default UUID;above the declaration it referred to intypes/index.d.mts, which CodeQL flags asjs/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 importsUUIDandISSUER_CATEGORIESfrom@cldmv/uuid/mainfirst 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.mtsimports from@cldmv/uuid/main, but./mainhad notypescondition, so TypeScript could not find its declarations andUUIDwas typedany.skipLibCheckhid the error../main,./rng,./bytesand./hashnow all havetypesconditions, and the generated declarations were fixed in the source JSDoc so they compile withstrictandskipLibCheck: false:v1,v4,v6,v7andv8is optional and typed (UUID.v4()used to be a compile error once the types resolved). Passingbufreturns that same buffer, typed as whatever you passed in; otherwise the methods return astring.TA/TBtimestamps andentropyarguments are optional, andgetRegistry()'sIssuerRegistrytype resolves.toBuffer()returnsBufferin Node projects (module/moduleResolutionnode16/nodenextwith@types/node) andUint8Arrayin browser and bundler projects, chosen through a private#bytes-typeimport. The package never forces Node's globals into a project: without@types/nodethe type falls back toUint8Array. The two alias declarations behind it live in a newtypings/folder (typings/bytes.d.mtsandtypings/bytes-node.d.mts), which is added to the package'sfilesand selected through a newimportsentry inpackage.json.A new
npm run test:typescheck (run bynpm testandnpm run coverage) packs the package, installs it into a throwaway consumer and compiles it undernodenextandbundlerresolution, including the README's TypeScript example.📄 License
The repository now includes the Apache-2.0
LICENSEfile (#54).package.jsonhas always declared Apache-2.0 and listedLICENSEinfiles, but the file was missing, so GitHub showed no license and the published package shipped without the license text.📚 Documentation
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 asnode_modules. Version 2.2.0 changes@Last modified byonly 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 setsforceAuthorUpdateandforceLastModifiedAuthorUpdateto false (#59).@types/node^26.6.4added (resolved to 26.6.4, with its transitiveundici-types8.9.0). The type-check suite uses it to prove thattoBuffer()returnsBufferin a Node project (#55).package.jsonand the lockfile, and the published package is unaffected.Upgrade notes
UUIDbeinganymay now see real type errors in their own code; those are calls the types previously failed to check.const UUID = require("@cldmv/uuid")(withUUID.UUID,UUID.uuidandUUID.ISSUER_CATEGORIESas properties). This needs Node.js ^20.19.0 or >=22.12.0. On older Node.js versions, load the package withimport().👥 Contributors
Avg: 87.1% ·
2782926· Node lts/*Co-authored-by: Shinrai Shinrai@users.noreply.github.com