diff --git a/README.md b/README.md index 7a0f582..5ad854d 100644 --- a/README.md +++ b/README.md @@ -982,9 +982,9 @@ Full TypeScript definitions included for both custom and RFC UUID APIs: import { UUID } from "@cldmv/uuid"; // Custom UUID specification (RFC-ready) -const ta: string = UUID.TA(); -const tb: string = UUID.TB(); -const ia: string = UUID.IA(404); +const ta: string = UUID.TA().toString(); +const tb: string = UUID.TB().toString(); +const ia: string = UUID.IA(404).toString(); // Instance methods with proper types const uuid = new UUID(ta); @@ -998,7 +998,7 @@ const category: string | null = uuid.getIssuerCategory(); // Standard RFC UUIDs const v4: string = UUID.v4(); const bytes: Uint8Array = UUID.parse(v4); -const rfcVersion: number | null = UUID.version(v4); +const rfcVersion: string | number | null = UUID.version(v4); // 4 here; "TA" / "TB" / "IA" for the custom variants ``` ## Specification Documentation diff --git a/package-lock.json b/package-lock.json index 0544377..598c76b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@cldmv/configs": "^1.2.1", "@cldmv/fix-headers": "^2.1.2", "@cldmv/vitest-runner": "^1.2.0", + "@types/node": "^26.6.4", "@vitest/coverage-v8": "^5.0.0", "typescript": "^5.9.3", "vitest": "^5.0.0" @@ -494,6 +495,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/node": { + "version": "26.6.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.4.tgz", + "integrity": "sha512-ldVPDCzj7fsaGZrLB0NuHuTvJcsNasysBAqMolr/cgxrLd1xbqxIr3XJiPnHHJUCxj5sNF1vnRj9aWnrVh5Jcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~8.9.0" + } + }, "node_modules/@vitest/coverage-v8": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-5.0.2.tgz", @@ -1223,6 +1234,13 @@ "node": ">=14.17" } }, + "node_modules/undici-types": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz", + "integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==", + "dev": true, + "license": "MIT" + }, "node_modules/vite": { "version": "8.3.1", "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.1.tgz", diff --git a/package.json b/package.json index df46453..75b0803 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "require": "./index.cjs" }, "./main": { + "types": "./types/dist/uuid.d.mts", "uuid-dev": { "import": "./src/uuid.mjs" }, @@ -22,7 +23,11 @@ "browser": "./src/lib/rng-browser.mjs", "import": "./src/lib/rng.mjs" }, - "browser": "./dist/lib/rng-browser.mjs", + "browser": { + "types": "./types/dist/lib/rng-browser.d.mts", + "default": "./dist/lib/rng-browser.mjs" + }, + "types": "./types/dist/lib/rng.d.mts", "import": "./dist/lib/rng.mjs" }, "./bytes": { @@ -30,7 +35,11 @@ "browser": "./src/lib/bytes-browser.mjs", "import": "./src/lib/bytes.mjs" }, - "browser": "./dist/lib/bytes-browser.mjs", + "browser": { + "types": "./types/dist/lib/bytes-browser.d.mts", + "default": "./dist/lib/bytes-browser.mjs" + }, + "types": "./types/dist/lib/bytes.d.mts", "import": "./dist/lib/bytes.mjs" }, "./hash": { @@ -38,11 +47,24 @@ "browser": "./src/lib/hash-browser.mjs", "import": "./src/lib/hash.mjs" }, - "browser": "./dist/lib/hash-browser.mjs", + "browser": { + "types": "./types/dist/lib/hash-browser.d.mts", + "default": "./dist/lib/hash-browser.mjs" + }, + "types": "./types/dist/lib/hash.d.mts", "import": "./dist/lib/hash.mjs" }, "./package.json": "./package.json" }, + "imports": { + "#bytes-type": { + "types": { + "browser": "./typings/bytes.d.mts", + "node": "./typings/bytes-node.d.mts", + "default": "./typings/bytes.d.mts" + } + } + }, "type": "module", "engines": { "node": ">=16.12.0" @@ -53,10 +75,11 @@ "build:dist": "node -e \"const fs = require('fs'); const path = require('path'); fs.rmSync('dist', {recursive: true, force: true}); fs.mkdirSync('dist', {recursive: true}); fs.cpSync('src', 'dist', {recursive: true});\"", "build:types": "node -e \"require('fs').rmSync('types', {recursive: true, force: true})\" && tsc --project .configs/tsconfig.dts.jsonc", "demo": "node scripts/demo-custom-uuids.mjs", - "test": "node tests/run-vitest.mjs && npm run test:cjs", + "test": "node tests/run-vitest.mjs && npm run test:cjs && npm run test:types", "test:cjs": "node --conditions=uuid-dev --test tests/cjs/entry.test.cjs", + "test:types": "npm run build && node --test tests/types/consumer.test.mjs", "test:watch": "vitest --config .configs/vitest.config.mjs", - "coverage": "node tests/run-vitest.mjs --coverage-quiet && npm run test:cjs", + "coverage": "node tests/run-vitest.mjs --coverage-quiet && npm run test:cjs && npm run test:types", "ci:coverage": "npm run coverage", "fix:headers": "fix-headers --config .configs/fix-headers.json", "types:build": "tsc -p .configs/tsconfig.dts.jsonc --noCheck", @@ -112,6 +135,7 @@ "types/dist/", "types/index.d.mts", "types/index.d.mts.map", + "typings/", "dist/" ], "sideEffects": false, @@ -119,6 +143,7 @@ "@cldmv/configs": "^1.2.1", "@cldmv/fix-headers": "^2.1.2", "@cldmv/vitest-runner": "^1.2.0", + "@types/node": "^26.6.4", "@vitest/coverage-v8": "^5.0.0", "typescript": "^5.9.3", "vitest": "^5.0.0" diff --git a/src/lib/versions/rfc/utils.mjs b/src/lib/versions/rfc/utils.mjs index 0f90ef3..78abeb0 100644 --- a/src/lib/versions/rfc/utils.mjs +++ b/src/lib/versions/rfc/utils.mjs @@ -55,7 +55,7 @@ export function parse(uuid) { /** * Convert array of bytes to UUID string - * @param {Uint8Array|Buffer|Array} bytes - 16-byte array + * @param {ArrayLike} bytes - 16-byte array * @returns {string} UUID string with dashes * @example * stringify([110, 192, 189, 127, 17, 192, 67, 218, 151, 94, 42, 138, 217, 235, 174, 11]); diff --git a/src/lib/versions/rfc/v1.mjs b/src/lib/versions/rfc/v1.mjs index 8b3abb0..084927d 100644 --- a/src/lib/versions/rfc/v1.mjs +++ b/src/lib/versions/rfc/v1.mjs @@ -24,13 +24,13 @@ import { stringify } from "./utils.mjs"; /** * Create a version 1 (timestamp) UUID - * @param {Object} options - Optional parameters - * @param {Array} options.node - 6-byte node id (MAC address) - * @param {number} options.clockseq - 14-bit clock sequence - * @param {number} options.msecs - Timestamp in milliseconds since unix epoch - * @param {number} options.nsecs - Additional 100-nanosecond intervals - * @param {Uint8Array} options.buf - Buffer to write UUID into - * @param {number} options.offset - Offset in buffer to start writing + * @param {object} [options] - Optional parameters + * @param {ArrayLike} [options.node] - 6-byte node id (MAC address) + * @param {number} [options.clockseq] - 14-bit clock sequence + * @param {number} [options.msecs] - Timestamp in milliseconds since unix epoch + * @param {number} [options.nsecs] - Additional 100-nanosecond intervals + * @param {Uint8Array} [options.buf] - Buffer to write UUID into; when given, it is returned instead of a string + * @param {number} [options.offset] - Offset in buffer to start writing * @returns {string|Uint8Array} UUID string or buffer */ export function v1(options = {}) { diff --git a/src/lib/versions/rfc/v35.mjs b/src/lib/versions/rfc/v35.mjs index 4a7683a..1cb7851 100644 --- a/src/lib/versions/rfc/v35.mjs +++ b/src/lib/versions/rfc/v35.mjs @@ -29,8 +29,8 @@ import { parse, stringify } from "./utils.mjs"; * @param {string|Uint8Array} namespace - Namespace UUID * @param {number} versionByte - Version byte (0x30 for v3, 0x50 for v5) * @param {Function} hashFn - Isomorphic hash function (md5 or sha1), signature (namespaceBytes, name) - * @param {Uint8Array} buf - Optional buffer to write into - * @param {number} offset - Optional offset in buffer + * @param {Uint8Array} [buf] - Optional buffer to write into; when given, it is returned instead of a string + * @param {number} [offset] - Optional offset in buffer * @returns {string|Uint8Array} UUID string or buffer * @private */ @@ -67,8 +67,8 @@ function _v35(name, namespace, versionByte, hashFn, buf, offset) { * Create a version 3 (namespace with MD5) UUID * @param {string} name - Name to hash * @param {string|Uint8Array} namespace - Namespace UUID - * @param {Uint8Array} buf - Optional buffer to write into - * @param {number} offset - Optional offset in buffer + * @param {Uint8Array} [buf] - Optional buffer to write into; when given, it is returned instead of a string + * @param {number} [offset] - Optional offset in buffer * @returns {string|Uint8Array} UUID string or buffer */ export function v3(name, namespace, buf, offset) { @@ -79,8 +79,8 @@ export function v3(name, namespace, buf, offset) { * Create a version 5 (namespace with SHA-1) UUID * @param {string} name - Name to hash * @param {string|Uint8Array} namespace - Namespace UUID - * @param {Uint8Array} buf - Optional buffer to write into - * @param {number} offset - Optional offset in buffer + * @param {Uint8Array} [buf] - Optional buffer to write into; when given, it is returned instead of a string + * @param {number} [offset] - Optional offset in buffer * @returns {string|Uint8Array} UUID string or buffer */ export function v5(name, namespace, buf, offset) { diff --git a/src/lib/versions/rfc/v4.mjs b/src/lib/versions/rfc/v4.mjs index 1091cfa..586de69 100644 --- a/src/lib/versions/rfc/v4.mjs +++ b/src/lib/versions/rfc/v4.mjs @@ -24,10 +24,10 @@ import { stringify } from "./utils.mjs"; /** * Create a version 4 (random) UUID - * @param {Object} options - Optional parameters - * @param {Uint8Array} options.random - 16 random bytes - * @param {Uint8Array} options.buf - Buffer to write UUID into - * @param {number} options.offset - Offset in buffer to start writing + * @param {object} [options] - Optional parameters + * @param {Uint8Array} [options.random] - 16 random bytes + * @param {Uint8Array} [options.buf] - Buffer to write UUID into; when given, it is returned instead of a string + * @param {number} [options.offset] - Offset in buffer to start writing * @returns {string|Uint8Array} UUID string or buffer */ export function v4(options = {}) { diff --git a/src/lib/versions/rfc/v6.mjs b/src/lib/versions/rfc/v6.mjs index 0b807f9..0a958ff 100644 --- a/src/lib/versions/rfc/v6.mjs +++ b/src/lib/versions/rfc/v6.mjs @@ -25,13 +25,13 @@ import { stringify } from "./utils.mjs"; /** * Create a version 6 (timestamp, reordered) UUID - * @param {Object} options - Optional parameters - * @param {Array} options.node - 6-byte node id (MAC address) - * @param {number} options.clockseq - 14-bit clock sequence - * @param {number} options.msecs - Timestamp in milliseconds since unix epoch - * @param {number} options.nsecs - Additional 100-nanosecond intervals - * @param {Uint8Array} options.buf - Buffer to write UUID into - * @param {number} options.offset - Offset in buffer to start writing + * @param {object} [options] - Optional parameters + * @param {ArrayLike} [options.node] - 6-byte node id (MAC address) + * @param {number} [options.clockseq] - 14-bit clock sequence + * @param {number} [options.msecs] - Timestamp in milliseconds since unix epoch + * @param {number} [options.nsecs] - Additional 100-nanosecond intervals + * @param {Uint8Array} [options.buf] - Buffer to write UUID into; when given, it is returned instead of a string + * @param {number} [options.offset] - Offset in buffer to start writing * @returns {string|Uint8Array} UUID string or buffer */ export function v6(options = {}) { diff --git a/src/lib/versions/rfc/v7.mjs b/src/lib/versions/rfc/v7.mjs index ae1276a..89952f6 100644 --- a/src/lib/versions/rfc/v7.mjs +++ b/src/lib/versions/rfc/v7.mjs @@ -25,10 +25,10 @@ import { stringify } from "./utils.mjs"; /** * Create a version 7 (Unix Epoch time-based) UUID - * @param {Object} options - Optional parameters - * @param {number} options.msecs - Timestamp in milliseconds since unix epoch - * @param {Uint8Array} options.buf - Buffer to write UUID into - * @param {number} options.offset - Offset in buffer to start writing + * @param {object} [options] - Optional parameters + * @param {number} [options.msecs] - Timestamp in milliseconds since unix epoch + * @param {Uint8Array} [options.buf] - Buffer to write UUID into; when given, it is returned instead of a string + * @param {number} [options.offset] - Offset in buffer to start writing * @returns {string|Uint8Array} UUID string or buffer */ export function v7(options = {}) { diff --git a/src/lib/versions/rfc/v8.mjs b/src/lib/versions/rfc/v8.mjs index ac648a1..c9c1102 100644 --- a/src/lib/versions/rfc/v8.mjs +++ b/src/lib/versions/rfc/v8.mjs @@ -26,10 +26,10 @@ import { stringify } from "./utils.mjs"; /** * Create a version 8 (custom/experimental) UUID - * @param {Object} options - Optional parameters - * @param {Uint8Array} options.data - Custom data to fill the UUID (16 bytes) - * @param {Uint8Array} options.buf - Buffer to write UUID into - * @param {number} options.offset - Offset in buffer to start writing + * @param {object} [options] - Optional parameters + * @param {Uint8Array} [options.data] - Custom data to fill the UUID (16 bytes) + * @param {Uint8Array} [options.buf] - Buffer to write UUID into; when given, it is returned instead of a string + * @param {number} [options.offset] - Offset in buffer to start writing * @returns {string|Uint8Array} UUID string or buffer * @example * // Generate with random data diff --git a/src/uuid.mjs b/src/uuid.mjs index b3260a3..1723583 100644 --- a/src/uuid.mjs +++ b/src/uuid.mjs @@ -44,6 +44,42 @@ import { } from "./lib/constants.mjs"; import * as rfcUuids from "./lib/versions/rfc/index.mjs"; +/** + * The byte container toBuffer() returns: a Buffer in Node, a plain Uint8Array elsewhere. + * `#bytes-type` (package.json `imports`) resolves to a Buffer alias under the `node` + * condition and to a Uint8Array alias otherwise. + * @typedef {import("#bytes-type").Bytes} Bytes + */ + +/** + * Options shared by the RFC generators that can write into a caller-supplied buffer. + * @typedef {object} RFCBufferOptions + * @property {Uint8Array} [buf] - Buffer to write the UUID into; when given, the generator returns it instead of a string + * @property {number} [offset] - Offset in `buf` to start writing at (default 0) + */ + +/** + * Options for {@link UUID.v1} and {@link UUID.v6}. `node` is the 6-byte node id (MAC address), + * `clockseq` the 14-bit clock sequence, `msecs` the timestamp in milliseconds since the Unix + * epoch, and `nsecs` additional 100-nanosecond intervals. + * @typedef {RFCBufferOptions & { node?: ArrayLike, clockseq?: number, msecs?: number, nsecs?: number }} TimeOptions + */ + +/** + * Options for {@link UUID.v4}. `random` supplies the 16 random bytes instead of generating them. + * @typedef {RFCBufferOptions & { random?: Uint8Array }} V4Options + */ + +/** + * Options for {@link UUID.v7}. `msecs` is the timestamp in milliseconds since the Unix epoch. + * @typedef {RFCBufferOptions & { msecs?: number }} V7Options + */ + +/** + * Options for {@link UUID.v8}. `data` supplies the 16 bytes of custom data instead of random bytes. + * @typedef {RFCBufferOptions & { data?: Uint8Array }} V8Options + */ + /** * UUID class implementing the new specification */ @@ -53,6 +89,11 @@ class UUID { * @param {Uint8Array|string|null} data - Optional UUID data to parse */ constructor(data = null) { + /** + * The 16 UUID bytes. + * @type {Uint8Array} + * @private + */ this._buffer = new Uint8Array(16); if (data !== null && data !== undefined) { @@ -87,7 +128,7 @@ class UUID { * Create a new Issuer Variant UUID * @param {number} issuerID - Issuer ID (0-ISSUER_ID_MASK) * @param {number} version - Version number - * @param {Uint8Array} entropy - Additional entropy data + * @param {Uint8Array|null} [entropy] - Additional entropy data * @returns {UUID} New UUID instance */ static createIssuerVariant(issuerID, version, entropy = null) { @@ -121,9 +162,9 @@ class UUID { /** * Create a new Timestamp Variant UUID - * @param {number|Date} timestamp - Timestamp value (optional, defaults to Date.now()) + * @param {number|Date|null|undefined} timestamp - Timestamp value (null/undefined defaults to the current time) * @param {number} version - Version number - * @param {Uint8Array} entropy - Optional entropy for bits 79-127 + * @param {Uint8Array|null} [entropy] - Optional entropy for bits 79-127 * @returns {UUID} New UUID instance */ static createTimestampVariant(timestamp, version, entropy = null) { @@ -192,7 +233,7 @@ class UUID { * Create an issuer-based UUID (short name alias) * @param {number} issuerID - Issuer ID (0-1023) * @param {number} version - Version number - * @param {Uint8Array} entropy - Additional entropy data + * @param {Uint8Array|null} [entropy] - Additional entropy data * @returns {UUID} New UUID instance */ static issuer(issuerID, version, entropy = null) { @@ -201,9 +242,9 @@ class UUID { /** * Create a timestamp-based UUID (short name alias) - * @param {number|Date} timestamp - Timestamp value (optional, defaults to Date.now()) + * @param {number|Date|null|undefined} timestamp - Timestamp value (null/undefined defaults to the current time) * @param {number} version - Version number - * @param {Uint8Array} entropy - Optional entropy for bits 79-127 + * @param {Uint8Array|null} [entropy] - Optional entropy for bits 79-127 * @returns {UUID} New UUID instance */ static timestamp(timestamp, version, entropy = null) { @@ -213,8 +254,8 @@ class UUID { /** * Create Timestamp Variant v1 UUID (ultra-short alias) * Subvariant 00 - Timestamp-based identification (seconds precision) - * @param {number|Date} timestamp - Timestamp value (optional, defaults to Date.now()) - * @param {Uint8Array} entropy - Optional entropy for bits 79-127 + * @param {number|Date|null} [timestamp] - Timestamp value (optional, defaults to the current time) + * @param {Uint8Array|null} [entropy] - Optional entropy for bits 79-127 * @returns {UUID} New UUID instance */ static TA(timestamp, entropy = null) { @@ -225,7 +266,7 @@ class UUID { * Create Issuer Variant v1 UUID (ultra-short alias) * Subvariant 01 - Issuer-based identification * @param {number} issuerID - Issuer ID (0-1023) - * @param {Uint8Array} entropy - Additional entropy data + * @param {Uint8Array|null} [entropy] - Additional entropy data * @returns {UUID} New UUID instance */ static IA(issuerID, entropy = null) { @@ -235,8 +276,8 @@ class UUID { /** * Create Timestamp Variant v2 UUID (ultra-short alias) * Subvariant 00 - Timestamp-based identification (milliseconds precision) - * @param {number|Date} timestamp - Timestamp value (optional, defaults to Date.now()) - * @param {Uint8Array} entropy - Optional entropy for bits 79-127 + * @param {number|Date|null} [timestamp] - Timestamp value (optional, defaults to the current time) + * @param {Uint8Array|null} [entropy] - Optional entropy for bits 79-127 * @returns {UUID} New UUID instance */ static TB(timestamp, entropy = null) { @@ -286,7 +327,7 @@ class UUID { /** * Fill remaining bits with entropy while preserving immutable fields - * @param {Uint8Array} entropy - Entropy data + * @param {Uint8Array|null} [entropy] - Entropy data * @private */ _fillEntropy(entropy) { @@ -532,7 +573,7 @@ class UUID { /** * Convert UUID to buffer - * @returns {Buffer} UUID as 16-byte buffer (Node); a Uint8Array copy in environments without Buffer + * @returns {Bytes} UUID as a 16-byte copy: a Node Buffer (a Uint8Array subclass) in Node, a plain Uint8Array in environments without Buffer */ toBuffer() { return toBufferLike(this._buffer); @@ -605,7 +646,7 @@ class UUID { /** * Get the shared issuer registry instance - * @returns {Promise} Shared registry instance + * @returns {Promise} Shared registry instance */ static async getRegistry() { if (!UUID._registryInstance) { @@ -674,9 +715,22 @@ class UUID { /** * Generate a version 1 (timestamp) UUID - * @param {Object} options - Optional parameters + * @overload + * @param {TimeOptions & { buf?: undefined }} [options] - Optional parameters * @returns {string} UUID string */ + /** + * Generate a version 1 (timestamp) UUID, written into `options.buf` + * @template {Uint8Array} T + * @overload + * @param {TimeOptions & { buf: T }} options - Options with the buffer to write into + * @returns {T} `options.buf` itself, so its type is kept (a Buffer stays a Buffer) + */ + /** + * Generate a version 1 (timestamp) UUID + * @param {TimeOptions} [options] - Optional parameters + * @returns {string|Uint8Array} UUID string, or `options.buf` when one is given + */ static v1(options) { return rfcUuids.v1(options); } @@ -693,9 +747,22 @@ class UUID { /** * Generate a version 4 (random) UUID - * @param {Object} options - Optional parameters + * @overload + * @param {V4Options & { buf?: undefined }} [options] - Optional parameters * @returns {string} UUID string */ + /** + * Generate a version 4 (random) UUID, written into `options.buf` + * @template {Uint8Array} T + * @overload + * @param {V4Options & { buf: T }} options - Options with the buffer to write into + * @returns {T} `options.buf` itself, so its type is kept (a Buffer stays a Buffer) + */ + /** + * Generate a version 4 (random) UUID + * @param {V4Options} [options] - Optional parameters + * @returns {string|Uint8Array} UUID string, or `options.buf` when one is given + */ static v4(options) { return rfcUuids.v4(options); } @@ -712,27 +779,66 @@ class UUID { /** * Generate a version 6 (timestamp, reordered) UUID - * @param {Object} options - Optional parameters + * @overload + * @param {TimeOptions & { buf?: undefined }} [options] - Optional parameters * @returns {string} UUID string */ + /** + * Generate a version 6 (timestamp, reordered) UUID, written into `options.buf` + * @template {Uint8Array} T + * @overload + * @param {TimeOptions & { buf: T }} options - Options with the buffer to write into + * @returns {T} `options.buf` itself, so its type is kept (a Buffer stays a Buffer) + */ + /** + * Generate a version 6 (timestamp, reordered) UUID + * @param {TimeOptions} [options] - Optional parameters + * @returns {string|Uint8Array} UUID string, or `options.buf` when one is given + */ static v6(options) { return rfcUuids.v6(options); } /** * Generate a version 7 (Unix Epoch) UUID - * @param {Object} options - Optional parameters + * @overload + * @param {V7Options & { buf?: undefined }} [options] - Optional parameters * @returns {string} UUID string */ + /** + * Generate a version 7 (Unix Epoch) UUID, written into `options.buf` + * @template {Uint8Array} T + * @overload + * @param {V7Options & { buf: T }} options - Options with the buffer to write into + * @returns {T} `options.buf` itself, so its type is kept (a Buffer stays a Buffer) + */ + /** + * Generate a version 7 (Unix Epoch) UUID + * @param {V7Options} [options] - Optional parameters + * @returns {string|Uint8Array} UUID string, or `options.buf` when one is given + */ static v7(options) { return rfcUuids.v7(options); } /** * Generate a version 8 (custom/experimental) UUID - * @param {Object} options - Optional parameters + * @overload + * @param {V8Options & { buf?: undefined }} [options] - Optional parameters * @returns {string} UUID string */ + /** + * Generate a version 8 (custom/experimental) UUID, written into `options.buf` + * @template {Uint8Array} T + * @overload + * @param {V8Options & { buf: T }} options - Options with the buffer to write into + * @returns {T} `options.buf` itself, so its type is kept (a Buffer stays a Buffer) + */ + /** + * Generate a version 8 (custom/experimental) UUID + * @param {V8Options} [options] - Optional parameters + * @returns {string|Uint8Array} UUID string, or `options.buf` when one is given + */ static v8(options) { return rfcUuids.v8(options); } @@ -748,7 +854,7 @@ class UUID { /** * Convert byte array to UUID string - * @param {Uint8Array|Buffer|Array} bytes - 16-byte array + * @param {ArrayLike} bytes - 16-byte array (Uint8Array, Buffer or plain array) * @returns {string} UUID string */ static stringify(bytes) { @@ -766,7 +872,7 @@ class UUID { /** * Detect version/variant identifier of UUID (handles both RFC and custom variants) - * @param {string|Buffer|UUID} uuid - UUID string, buffer, or UUID instance + * @param {string|Uint8Array|UUID} uuid - UUID string, buffer, or UUID instance * @returns {string|number|null} Version identifier (e.g., "TA", "TB", "IA" for custom, 1-8 for RFC, or null if invalid) * @example * UUID.version(uuidString); // => "TA" for Timestamp v1 @@ -795,7 +901,7 @@ class UUID { /** * Detect variant identifier (alias for version()) - * @param {string|Buffer|UUID} uuid - UUID string, buffer, or UUID instance + * @param {string|Uint8Array|UUID} uuid - UUID string, buffer, or UUID instance * @returns {string|number|null} Version identifier * @deprecated Use UUID.version() instead */ diff --git a/tests/types/consumer.test.mjs b/tests/types/consumer.test.mjs new file mode 100644 index 0000000..7971680 --- /dev/null +++ b/tests/types/consumer.test.mjs @@ -0,0 +1,336 @@ +/** + * + * @Project: @cldmv/uuid + * @Filename: /tests/types/consumer.test.mjs + * @Date: 2026-10-03T17:37:05-07:00 (1791074225) + * @Author: Nate Corcoran + * @Email: + * ----- + * @Last modified by: Nate Corcoran (Shinrai@users.noreply.github.com) + * @Last modified time: 2026-10-03T17:44:07-07:00 (1791074647) + * ----- + * @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. + * + */ + +/** + * Consumer type-check tests. These run under Node's own test runner (`node --test`), not + * Vitest: they pack the package with `npm pack`, unpack the tarball into a throwaway + * consumer project, and compile TypeScript fixtures that import it by name with + * `moduleResolution: nodenext`, `strict: true` and no `skipLibCheck`. That is what a + * TypeScript user installing the published package sees, so it catches a missing `types` + * condition (the import silently becomes `any`) as well as declarations that do not + * compile or describe the API wrongly. + * + * Needs a build first (`npm run build`): the published declarations live in types/dist/. + * `npm run test:types` builds and then runs this file. + */ +import { test, before, after } from "node:test"; +import assert from "node:assert/strict"; +import { spawnSync } from "node:child_process"; +import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { createRequire } from "node:module"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const require = createRequire(import.meta.url); +const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); +const tscBin = require.resolve("typescript/bin/tsc"); +// Inside the repo's gitignored tmp/ so the consumer can find @types/node in the repo's +// node_modules (TypeScript walks up the tree for type roots), while @cldmv/uuid itself +// resolves to the unpacked tarball in the consumer's own node_modules. +const workDir = path.join(repoRoot, "tmp", `types-consumer-${process.pid}`); +const consumerDir = path.join(workDir, "consumer"); + +/** + * Write a tsconfig for one fixture and compile it. + * @param {string} name - Fixture name, used for the tsconfig file name. + * @param {string[]} files - Fixture files to compile. + * @param {string[]} types - Global type packages to load (`[]` = none, not even @types/node). + * @param {object} [extra] - Additional compiler options. + * @returns {{ status: number|null, output: string }} tsc exit status and combined output. + */ +function compile(name, files, types, extra = {}) { + const tsconfig = path.join(consumerDir, `tsconfig.${name}.json`); + writeFileSync( + tsconfig, + JSON.stringify( + { + compilerOptions: { + strict: true, + module: "nodenext", + moduleResolution: "nodenext", + target: "es2022", + lib: ["es2022"], + types, + noEmit: true, + skipLibCheck: false, + ...extra + }, + files + }, + null, + "\t" + ) + ); + const res = spawnSync(process.execPath, [tscBin, "-p", tsconfig, "--pretty", "false"], { cwd: consumerDir, encoding: "utf8" }); + return { status: res.status, output: `${res.stdout}${res.stderr}` }; +} + +before(() => { + for (const built of ["dist/uuid.mjs", "types/dist/uuid.d.mts"]) { + assert.ok(existsSync(path.join(repoRoot, built)), `${built} is missing; run \`npm run build\` first (or use \`npm run test:types\`)`); + } + + rmSync(workDir, { recursive: true, force: true }); + const pkgDir = path.join(consumerDir, "node_modules", "@cldmv", "uuid"); + mkdirSync(pkgDir, { recursive: true }); + + const pack = spawnSync("npm", ["pack", "--pack-destination", workDir], { + cwd: repoRoot, + encoding: "utf8", + shell: process.platform === "win32" + }); + assert.equal(pack.status, 0, `npm pack failed:\n${pack.stderr}`); + // workDir was emptied above, so the tarball npm just wrote is the only .tgz in it. + const [filename] = readdirSync(workDir).filter((file) => file.endsWith(".tgz")); + assert.ok(filename, `npm pack wrote no tarball:\n${pack.stdout}`); + + const untar = spawnSync("tar", ["-xzf", path.join(workDir, filename), "-C", pkgDir, "--strip-components=1"], { encoding: "utf8" }); + assert.equal(untar.status, 0, `tar failed:\n${untar.stderr}`); + + writeFileSync(path.join(consumerDir, "package.json"), JSON.stringify({ name: "uuid-types-consumer", private: true, type: "module" })); + + writeFileSync( + path.join(consumerDir, "main.mts"), + `import UUIDDefault, { UUID, uuid, ISSUER_CATEGORIES } from "@cldmv/uuid"; +import { UUID as MainUUID, uuid as mainUuid, ISSUER_CATEGORIES as MAIN_CATEGORIES } from "@cldmv/uuid/main"; + +// The default export, the named exports and the ./main subpath are all the same class. +const same: typeof UUID = UUIDDefault; +const sameLower: typeof UUID = uuid; +const sameMain: typeof UUID = MainUUID; +const sameMainLower: typeof UUID = mainUuid; + +// RFC generators: options are optional, and passing a buffer returns the buffer. +const v1: string = UUID.v1(); +const v4: string = UUID.v4(); +const v4Random: string = UUID.v4({ random: new Uint8Array(16) }); +const v4Buf: Uint8Array = UUID.v4({ buf: new Uint8Array(16), offset: 0 }); +const v6: string = UUID.v6({ msecs: Date.now() }); +const v7: string = UUID.v7(); +const v8: string = UUID.v8({ data: new Uint8Array(16) }); +const v1Node: string = UUID.v1({ node: [1, 2, 3, 4, 5, 6], clockseq: 0 }); +const v3: string = UUID.v3("example.com", UUID.DNS); +const v5: string = UUID.v5("https://example.com", UUID.URL); +const nil: string = UUID.NIL; +const parsed: Uint8Array = UUID.parse(v4); +const text: string = UUID.stringify(parsed); +const fromArray: string = UUID.stringify(Array.from(parsed)); +const valid: boolean = UUID.validateRFC(v4); +const rfcVersion: string | number | null = UUID.version(v4); + +// Custom variants: the timestamp argument is optional. +const ta: UUID = UUID.TA(); +const tb: UUID = UUID.TB(new Date()); +const ia: UUID = UUID.IA(ISSUER_CATEGORIES.SPEC_ORIGINATOR); +const viaTimestamp: UUID = UUID.createTimestampVariant(undefined, 2); +const viaIssuer: UUID = UUID.createIssuerVariant(MAIN_CATEGORIES.UNASSIGNED, 1, new Uint8Array(16)); +const instance = new UUID(); +const fromString = new UUID(ta.toString()); +const ts: number | null = tb.getTimestamp(); +const issuerID: number | null = ia.getIssuerID(); +const bytes: Uint8Array = ta.toBuffer(); +const asString: string = \`\${ta}\`; +const json: string = JSON.stringify({ id: ta }); +const category: number = ISSUER_CATEGORIES.UNASSIGNED; + +// Registry and validation helpers. +const registry = await UUID.getRegistry(); +const available: boolean = registry.isAvailable(300); +const info = await UUID.getIssuerInfo(1); +const report = await UUID.validate(ta.toBuffer()); + +export { + same, sameLower, sameMain, sameMainLower, v1, v4, v4Random, v4Buf, v6, v7, v8, v1Node, v3, v5, nil, parsed, + text, fromArray, valid, rfcVersion, ta, tb, ia, viaTimestamp, viaIssuer, instance, fromString, ts, issuerID, + bytes, asString, json, category, available, info, report +}; +` + ); + + writeFileSync( + path.join(consumerDir, "subpaths.mts"), + `import { randomBytes } from "@cldmv/uuid/rng"; +import { fromHex, toHex, toBufferLike } from "@cldmv/uuid/bytes"; +import { md5, sha1 } from "@cldmv/uuid/hash"; + +const random: Uint8Array = randomBytes(16); +const hex: string = toHex(random); +const back: Uint8Array = fromHex(hex); +const copy: Uint8Array = toBufferLike(back); +const md5Digest: Uint8Array = md5(random, "name"); +const sha1Digest: Uint8Array = sha1(random, "name"); + +export { random, hex, back, copy, md5Digest, sha1Digest }; +` + ); + + // The README's TypeScript example, verbatim, so the documented types stay true. + const readme = readFileSync(path.join(repoRoot, "README.md"), "utf8"); + const example = /TypeScript Support\n[\s\S]*?```typescript\n([\s\S]*?)```/.exec(readme); + assert.ok(example, "README.md has no ```typescript block under its TypeScript Support heading"); + writeFileSync(path.join(consumerDir, "readme.mts"), `${example[1]}\nexport {};\n`); + + // Node flavour: under nodenext the "node" condition picks the declarations where the + // runtime byte container is a Buffer, so Buffer-only APIs compile. + writeFileSync( + path.join(consumerDir, "node.mts"), + `import { UUID } from "@cldmv/uuid"; + +const length: number = UUID.v4().length; +const ta = UUID.TA(); +const tb = UUID.TB(new Date()); +const bytes: Buffer = ta.toBuffer(); +const hex: string = tb.toBuffer().toString("hex"); +const v4Hex: string = UUID.v4({ buf: Buffer.alloc(16) }).toString("hex"); +const v7Hex: string = UUID.v7({ buf: Buffer.alloc(32), offset: 16 }).toString("hex"); +// A plain Uint8Array passed as buf comes back as exactly that, not as a Buffer. +const plain: Uint8Array = UUID.v1({ buf: new Uint8Array(16) }); + +export { length, bytes, hex, v4Hex, v7Hex, plain }; +` + ); + + // Default flavour: without the "node" condition (bundler resolution, browsers) the byte + // container is a plain Uint8Array, so Buffer-only APIs must not compile. + writeFileSync( + path.join(consumerDir, "node-no-types.mts"), + `import { UUID } from "@cldmv/uuid"; +const id: string = UUID.v4(); +const bytes: Uint8Array = UUID.TA().toBuffer(); +const env = process.env; +export { id, bytes, env }; +` + ); + + writeFileSync( + path.join(consumerDir, "bundler-bytes.mts"), + `import { UUID } from "@cldmv/uuid"; + +const length: number = UUID.v4().length; +const bytes: Uint8Array = UUID.TA().toBuffer(); +const written: Uint8Array = UUID.v4({ buf: new Uint8Array(16) }); + +export { length, bytes, written }; +` + ); + + writeFileSync( + path.join(consumerDir, "bundler-wrong.mts"), + `import { UUID } from "@cldmv/uuid"; + +const hex: string = UUID.TA().toBuffer().toString("hex"); +const first: number = UUID.TA().toBuffer().readUInt8(0); +const written: string = UUID.v4({ buf: new Uint8Array(16) }).toString("hex"); + +export { hex, first, written }; +` + ); + + writeFileSync( + path.join(consumerDir, "wrong.mts"), + `import { UUID } from "@cldmv/uuid"; + +const n: number = UUID.v4(); + +export { n }; +` + ); +}); + +after(() => { + rmSync(workDir, { recursive: true, force: true }); +}); + +/** Compiler options for a bundler-resolution (browser/bundler) consumer. */ +const bundler = { module: "esnext", moduleResolution: "bundler" }; + +test("the main entry and ./main type-check under nodenext with @types/node", () => { + const { status, output } = compile("main", ["main.mts"], ["node"]); + assert.equal(status, 0, output); +}); + +test("the main entry and ./main type-check under bundler resolution without @types/node", () => { + // types: [] keeps @types/node out, so this also shows the default (non-Node) declarations + // do not depend on Node-only globals such as Buffer (the package also runs in browsers). + const { status, output } = compile("main-bundler", ["main.mts"], [], bundler); + assert.equal(status, 0, output); +}); + +test("under nodenext the byte returns are Buffers", () => { + // The "node" condition serves the Node flavour: toBuffer() returns a Buffer, and a buf + // overload returns the buffer it was given, so Buffer-only APIs compile. + const { status, output } = compile("node", ["node.mts"], ["node"], { explainFiles: true }); + assert.equal(status, 0, output); + assert.match(output, /typings\/bytes-node\.d\.mts\n/, "expected #bytes-type to resolve to the Node flavour"); + assert.doesNotMatch(output, /typings\/bytes\.d\.mts\n/, output); +}); + +test("under nodenext without @types/node the package does not pull in Node globals", () => { + // The Node flavour must read Buffer from the global scope rather than reference + // @types/node: a Node project without @types/node still compiles against the package, + // and importing it does not make Node globals such as \`process\` appear. + const { status, output } = compile("node-no-types", ["node-no-types.mts"], []); + assert.notEqual(status, 0, "expected tsc to reject the Node global"); + assert.match(output, /node-no-types\.mts\(4,\d+\): error TS2(580|591)/, output); + assert.equal(output.trim().split("\n").filter((line) => /error TS\d+/.test(line)).length, 1, output); +}); + +test("under bundler resolution the byte returns are plain Uint8Arrays", () => { + const { status, output } = compile("bundler-bytes", ["bundler-bytes.mts"], [], { ...bundler, explainFiles: true }); + assert.equal(status, 0, output); + assert.match(output, /typings\/bytes\.d\.mts\n/, "expected #bytes-type to resolve to the default flavour"); + assert.doesNotMatch(output, /typings\/bytes-node\.d\.mts\n/, output); +}); + +test("under bundler resolution Buffer-only methods on the byte returns fail to compile", () => { + // If the default flavour leaked Buffer, these would compile. + const { status, output } = compile("bundler-wrong", ["bundler-wrong.mts"], [], bundler); + assert.notEqual(status, 0, "expected tsc to reject Buffer-only methods on a Uint8Array"); + assert.match(output, /bundler-wrong\.mts\(3,51\): error TS2554: Expected 0 arguments, but got 1\./); + assert.match(output, /bundler-wrong\.mts\(4,44\): error TS2339: Property 'readUInt8' does not exist on type 'Bytes'\./); + assert.match(output, /bundler-wrong\.mts\(5,71\): error TS2554: Expected 0 arguments, but got 1\./); + assert.equal(output.trim().split("\n").filter((line) => /error TS\d+/.test(line)).length, 3, output); +}); + +test("the README TypeScript example type-checks", () => { + // noUnusedLocals is off by default, so the example's unused bindings are fine. + const { status, output } = compile("readme", ["readme.mts"], []); + assert.equal(status, 0, output); +}); + +test("the ./rng, ./bytes and ./hash subpaths type-check", () => { + // The Node variants of these modules return Buffers, so they need @types/node like any + // other Node-only declaration. + const { status, output } = compile("subpaths", ["subpaths.mts"], ["node"]); + assert.equal(status, 0, output); +}); + +test("the browser variants of ./rng, ./bytes and ./hash type-check without @types/node", () => { + // With the "browser" condition the browser declarations are picked, which return plain + // Uint8Arrays and must not need Node's globals. + // main.mts is included too: with "browser" the main entry gets the Uint8Array flavour even + // under nodenext, so it compiles without @types/node. + const { status, output } = compile("browser", ["subpaths.mts", "main.mts"], [], { customConditions: ["browser"] }); + assert.equal(status, 0, output); +}); + +test("a wrong assignment from UUID.v4() fails to compile", () => { + // If UUID were `any` (no types condition on ./main), this would compile. + const { status, output } = compile("wrong", ["wrong.mts"], []); + assert.notEqual(status, 0, "expected tsc to reject assigning UUID.v4() to a number"); + assert.match(output, /wrong\.mts\(3,7\): error TS2322: Type 'string' is not assignable to type 'number'\./); + // The only error is the deliberate one, not a problem in the package's own declarations. + assert.equal(output.trim().split("\n").filter((line) => /error TS\d+/.test(line)).length, 1, output); +}); diff --git a/types/src/lib/versions/rfc/utils.d.mts b/types/src/lib/versions/rfc/utils.d.mts index dd44b0d..d746c87 100644 --- a/types/src/lib/versions/rfc/utils.d.mts +++ b/types/src/lib/versions/rfc/utils.d.mts @@ -9,13 +9,13 @@ export function parse(uuid: string): Uint8Array; /** * Convert array of bytes to UUID string - * @param {Uint8Array|Buffer|Array} bytes - 16-byte array + * @param {ArrayLike} bytes - 16-byte array * @returns {string} UUID string with dashes * @example * stringify([110, 192, 189, 127, 17, 192, 67, 218, 151, 94, 42, 138, 217, 235, 174, 11]); * // => '6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b' */ -export function stringify(bytes: Uint8Array | Buffer | any[]): string; +export function stringify(bytes: ArrayLike): string; /** * Test a string to see if it is a valid UUID * @param {string} uuid - UUID string to validate diff --git a/types/src/lib/versions/rfc/utils.d.mts.map b/types/src/lib/versions/rfc/utils.d.mts.map index e879571..1b04db7 100644 --- a/types/src/lib/versions/rfc/utils.d.mts.map +++ b/types/src/lib/versions/rfc/utils.d.mts.map @@ -1 +1 @@ -{"version":3,"file":"utils.d.mts","sourceRoot":"","sources":["../../../../../src/lib/versions/rfc/utils.mjs"],"names":[],"mappings":"AAuBA;;;;;;;GAOG;AACH,4BANW,MAAM,GACJ,UAAU,CA2BtB;AAED;;;;;;;GAOG;AACH,iCANW,UAAU,GAAC,MAAM,QAAM,GACrB,MAAM,CAelB;AAED;;;;;;;GAOG;AACH,+BANW,MAAM,GACJ,OAAO,CAiBnB;AAED;;;;;;GAMG;AACH,8BALW,MAAM,GACJ,MAAM,GAAC,IAAI,CAavB"} \ No newline at end of file +{"version":3,"file":"utils.d.mts","sourceRoot":"","sources":["../../../../../src/lib/versions/rfc/utils.mjs"],"names":[],"mappings":"AAuBA;;;;;;;GAOG;AACH,4BANW,MAAM,GACJ,UAAU,CA2BtB;AAED;;;;;;;GAOG;AACH,iCANW,SAAS,CAAC,MAAM,CAAC,GACf,MAAM,CAelB;AAED;;;;;;;GAOG;AACH,+BANW,MAAM,GACJ,OAAO,CAiBnB;AAED;;;;;;GAMG;AACH,8BALW,MAAM,GACJ,MAAM,GAAC,IAAI,CAavB"} \ No newline at end of file diff --git a/types/src/lib/versions/rfc/v1.d.mts b/types/src/lib/versions/rfc/v1.d.mts index 325d4e5..1495ca4 100644 --- a/types/src/lib/versions/rfc/v1.d.mts +++ b/types/src/lib/versions/rfc/v1.d.mts @@ -1,20 +1,20 @@ /** * Create a version 1 (timestamp) UUID - * @param {Object} options - Optional parameters - * @param {Array} options.node - 6-byte node id (MAC address) - * @param {number} options.clockseq - 14-bit clock sequence - * @param {number} options.msecs - Timestamp in milliseconds since unix epoch - * @param {number} options.nsecs - Additional 100-nanosecond intervals - * @param {Uint8Array} options.buf - Buffer to write UUID into - * @param {number} options.offset - Offset in buffer to start writing + * @param {object} [options] - Optional parameters + * @param {ArrayLike} [options.node] - 6-byte node id (MAC address) + * @param {number} [options.clockseq] - 14-bit clock sequence + * @param {number} [options.msecs] - Timestamp in milliseconds since unix epoch + * @param {number} [options.nsecs] - Additional 100-nanosecond intervals + * @param {Uint8Array} [options.buf] - Buffer to write UUID into; when given, it is returned instead of a string + * @param {number} [options.offset] - Offset in buffer to start writing * @returns {string|Uint8Array} UUID string or buffer */ export function v1(options?: { - node: any[]; - clockseq: number; - msecs: number; - nsecs: number; - buf: Uint8Array; - offset: number; + node?: ArrayLike; + clockseq?: number; + msecs?: number; + nsecs?: number; + buf?: Uint8Array; + offset?: number; }): string | Uint8Array; //# sourceMappingURL=v1.d.mts.map \ No newline at end of file diff --git a/types/src/lib/versions/rfc/v1.d.mts.map b/types/src/lib/versions/rfc/v1.d.mts.map index 1ddc193..e69fd31 100644 --- a/types/src/lib/versions/rfc/v1.d.mts.map +++ b/types/src/lib/versions/rfc/v1.d.mts.map @@ -1 +1 @@ -{"version":3,"file":"v1.d.mts","sourceRoot":"","sources":["../../../../../src/lib/versions/rfc/v1.mjs"],"names":[],"mappings":"AAwBA;;;;;;;;;;GAUG;AACH,6BARG;IAAuB,IAAI;IACH,QAAQ,EAAxB,MAAM;IACU,KAAK,EAArB,MAAM;IACU,KAAK,EAArB,MAAM;IACc,GAAG,EAAvB,UAAU;IACM,MAAM,EAAtB,MAAM;CACd,GAAU,MAAM,GAAC,UAAU,CAoD7B"} \ No newline at end of file +{"version":3,"file":"v1.d.mts","sourceRoot":"","sources":["../../../../../src/lib/versions/rfc/v1.mjs"],"names":[],"mappings":"AAwBA;;;;;;;;;;GAUG;AACH,6BARG;IAAoC,IAAI,GAAhC,SAAS,CAAC,MAAM,CAAC;IACA,QAAQ,GAAzB,MAAM;IACW,KAAK,GAAtB,MAAM;IACW,KAAK,GAAtB,MAAM;IACe,GAAG,GAAxB,UAAU;IACO,MAAM,GAAvB,MAAM;CACd,GAAU,MAAM,GAAC,UAAU,CAoD7B"} \ No newline at end of file diff --git a/types/src/lib/versions/rfc/v35.d.mts b/types/src/lib/versions/rfc/v35.d.mts index 806d635..83c110d 100644 --- a/types/src/lib/versions/rfc/v35.d.mts +++ b/types/src/lib/versions/rfc/v35.d.mts @@ -2,18 +2,18 @@ * Create a version 3 (namespace with MD5) UUID * @param {string} name - Name to hash * @param {string|Uint8Array} namespace - Namespace UUID - * @param {Uint8Array} buf - Optional buffer to write into - * @param {number} offset - Optional offset in buffer + * @param {Uint8Array} [buf] - Optional buffer to write into; when given, it is returned instead of a string + * @param {number} [offset] - Optional offset in buffer * @returns {string|Uint8Array} UUID string or buffer */ -export function v3(name: string, namespace: string | Uint8Array, buf: Uint8Array, offset: number): string | Uint8Array; +export function v3(name: string, namespace: string | Uint8Array, buf?: Uint8Array, offset?: number): string | Uint8Array; /** * Create a version 5 (namespace with SHA-1) UUID * @param {string} name - Name to hash * @param {string|Uint8Array} namespace - Namespace UUID - * @param {Uint8Array} buf - Optional buffer to write into - * @param {number} offset - Optional offset in buffer + * @param {Uint8Array} [buf] - Optional buffer to write into; when given, it is returned instead of a string + * @param {number} [offset] - Optional offset in buffer * @returns {string|Uint8Array} UUID string or buffer */ -export function v5(name: string, namespace: string | Uint8Array, buf: Uint8Array, offset: number): string | Uint8Array; +export function v5(name: string, namespace: string | Uint8Array, buf?: Uint8Array, offset?: number): string | Uint8Array; //# sourceMappingURL=v35.d.mts.map \ No newline at end of file diff --git a/types/src/lib/versions/rfc/v35.d.mts.map b/types/src/lib/versions/rfc/v35.d.mts.map index 828d509..e7264b9 100644 --- a/types/src/lib/versions/rfc/v35.d.mts.map +++ b/types/src/lib/versions/rfc/v35.d.mts.map @@ -1 +1 @@ -{"version":3,"file":"v35.d.mts","sourceRoot":"","sources":["../../../../../src/lib/versions/rfc/v35.mjs"],"names":[],"mappings":"AAiEA;;;;;;;GAOG;AACH,yBANW,MAAM,aACN,MAAM,GAAC,UAAU,OACjB,UAAU,UACV,MAAM,GACJ,MAAM,GAAC,UAAU,CAI7B;AAED;;;;;;;GAOG;AACH,yBANW,MAAM,aACN,MAAM,GAAC,UAAU,OACjB,UAAU,UACV,MAAM,GACJ,MAAM,GAAC,UAAU,CAI7B"} \ No newline at end of file +{"version":3,"file":"v35.d.mts","sourceRoot":"","sources":["../../../../../src/lib/versions/rfc/v35.mjs"],"names":[],"mappings":"AAiEA;;;;;;;GAOG;AACH,yBANW,MAAM,aACN,MAAM,GAAC,UAAU,QACjB,UAAU,WACV,MAAM,GACJ,MAAM,GAAC,UAAU,CAI7B;AAED;;;;;;;GAOG;AACH,yBANW,MAAM,aACN,MAAM,GAAC,UAAU,QACjB,UAAU,WACV,MAAM,GACJ,MAAM,GAAC,UAAU,CAI7B"} \ No newline at end of file diff --git a/types/src/lib/versions/rfc/v4.d.mts b/types/src/lib/versions/rfc/v4.d.mts index 5c9a043..11ce22b 100644 --- a/types/src/lib/versions/rfc/v4.d.mts +++ b/types/src/lib/versions/rfc/v4.d.mts @@ -1,14 +1,14 @@ /** * Create a version 4 (random) UUID - * @param {Object} options - Optional parameters - * @param {Uint8Array} options.random - 16 random bytes - * @param {Uint8Array} options.buf - Buffer to write UUID into - * @param {number} options.offset - Offset in buffer to start writing + * @param {object} [options] - Optional parameters + * @param {Uint8Array} [options.random] - 16 random bytes + * @param {Uint8Array} [options.buf] - Buffer to write UUID into; when given, it is returned instead of a string + * @param {number} [options.offset] - Offset in buffer to start writing * @returns {string|Uint8Array} UUID string or buffer */ export function v4(options?: { - random: Uint8Array; - buf: Uint8Array; - offset: number; + random?: Uint8Array; + buf?: Uint8Array; + offset?: number; }): string | Uint8Array; //# sourceMappingURL=v4.d.mts.map \ No newline at end of file diff --git a/types/src/lib/versions/rfc/v4.d.mts.map b/types/src/lib/versions/rfc/v4.d.mts.map index 2f94be3..73d30ed 100644 --- a/types/src/lib/versions/rfc/v4.d.mts.map +++ b/types/src/lib/versions/rfc/v4.d.mts.map @@ -1 +1 @@ -{"version":3,"file":"v4.d.mts","sourceRoot":"","sources":["../../../../../src/lib/versions/rfc/v4.mjs"],"names":[],"mappings":"AAwBA;;;;;;;GAOG;AACH,6BALG;IAA4B,MAAM,EAA1B,UAAU;IACU,GAAG,EAAvB,UAAU;IACM,MAAM,EAAtB,MAAM;CACd,GAAU,MAAM,GAAC,UAAU,CAkB7B"} \ No newline at end of file +{"version":3,"file":"v4.d.mts","sourceRoot":"","sources":["../../../../../src/lib/versions/rfc/v4.mjs"],"names":[],"mappings":"AAwBA;;;;;;;GAOG;AACH,6BALG;IAA6B,MAAM,GAA3B,UAAU;IACW,GAAG,GAAxB,UAAU;IACO,MAAM,GAAvB,MAAM;CACd,GAAU,MAAM,GAAC,UAAU,CAkB7B"} \ No newline at end of file diff --git a/types/src/lib/versions/rfc/v6.d.mts b/types/src/lib/versions/rfc/v6.d.mts index d3e3024..14ba6de 100644 --- a/types/src/lib/versions/rfc/v6.d.mts +++ b/types/src/lib/versions/rfc/v6.d.mts @@ -1,20 +1,20 @@ /** * Create a version 6 (timestamp, reordered) UUID - * @param {Object} options - Optional parameters - * @param {Array} options.node - 6-byte node id (MAC address) - * @param {number} options.clockseq - 14-bit clock sequence - * @param {number} options.msecs - Timestamp in milliseconds since unix epoch - * @param {number} options.nsecs - Additional 100-nanosecond intervals - * @param {Uint8Array} options.buf - Buffer to write UUID into - * @param {number} options.offset - Offset in buffer to start writing + * @param {object} [options] - Optional parameters + * @param {ArrayLike} [options.node] - 6-byte node id (MAC address) + * @param {number} [options.clockseq] - 14-bit clock sequence + * @param {number} [options.msecs] - Timestamp in milliseconds since unix epoch + * @param {number} [options.nsecs] - Additional 100-nanosecond intervals + * @param {Uint8Array} [options.buf] - Buffer to write UUID into; when given, it is returned instead of a string + * @param {number} [options.offset] - Offset in buffer to start writing * @returns {string|Uint8Array} UUID string or buffer */ export function v6(options?: { - node: any[]; - clockseq: number; - msecs: number; - nsecs: number; - buf: Uint8Array; - offset: number; + node?: ArrayLike; + clockseq?: number; + msecs?: number; + nsecs?: number; + buf?: Uint8Array; + offset?: number; }): string | Uint8Array; //# sourceMappingURL=v6.d.mts.map \ No newline at end of file diff --git a/types/src/lib/versions/rfc/v6.d.mts.map b/types/src/lib/versions/rfc/v6.d.mts.map index 5eabd42..5e5e9a1 100644 --- a/types/src/lib/versions/rfc/v6.d.mts.map +++ b/types/src/lib/versions/rfc/v6.d.mts.map @@ -1 +1 @@ -{"version":3,"file":"v6.d.mts","sourceRoot":"","sources":["../../../../../src/lib/versions/rfc/v6.mjs"],"names":[],"mappings":"AAyBA;;;;;;;;;;GAUG;AACH,6BARG;IAAuB,IAAI;IACH,QAAQ,EAAxB,MAAM;IACU,KAAK,EAArB,MAAM;IACU,KAAK,EAArB,MAAM;IACc,GAAG,EAAvB,UAAU;IACM,MAAM,EAAtB,MAAM;CACd,GAAU,MAAM,GAAC,UAAU,CA+C7B"} \ No newline at end of file +{"version":3,"file":"v6.d.mts","sourceRoot":"","sources":["../../../../../src/lib/versions/rfc/v6.mjs"],"names":[],"mappings":"AAyBA;;;;;;;;;;GAUG;AACH,6BARG;IAAoC,IAAI,GAAhC,SAAS,CAAC,MAAM,CAAC;IACA,QAAQ,GAAzB,MAAM;IACW,KAAK,GAAtB,MAAM;IACW,KAAK,GAAtB,MAAM;IACe,GAAG,GAAxB,UAAU;IACO,MAAM,GAAvB,MAAM;CACd,GAAU,MAAM,GAAC,UAAU,CA+C7B"} \ No newline at end of file diff --git a/types/src/lib/versions/rfc/v7.d.mts b/types/src/lib/versions/rfc/v7.d.mts index 330806f..423c5e7 100644 --- a/types/src/lib/versions/rfc/v7.d.mts +++ b/types/src/lib/versions/rfc/v7.d.mts @@ -1,14 +1,14 @@ /** * Create a version 7 (Unix Epoch time-based) UUID - * @param {Object} options - Optional parameters - * @param {number} options.msecs - Timestamp in milliseconds since unix epoch - * @param {Uint8Array} options.buf - Buffer to write UUID into - * @param {number} options.offset - Offset in buffer to start writing + * @param {object} [options] - Optional parameters + * @param {number} [options.msecs] - Timestamp in milliseconds since unix epoch + * @param {Uint8Array} [options.buf] - Buffer to write UUID into; when given, it is returned instead of a string + * @param {number} [options.offset] - Offset in buffer to start writing * @returns {string|Uint8Array} UUID string or buffer */ export function v7(options?: { - msecs: number; - buf: Uint8Array; - offset: number; + msecs?: number; + buf?: Uint8Array; + offset?: number; }): string | Uint8Array; //# sourceMappingURL=v7.d.mts.map \ No newline at end of file diff --git a/types/src/lib/versions/rfc/v7.d.mts.map b/types/src/lib/versions/rfc/v7.d.mts.map index e14751f..18913a8 100644 --- a/types/src/lib/versions/rfc/v7.d.mts.map +++ b/types/src/lib/versions/rfc/v7.d.mts.map @@ -1 +1 @@ -{"version":3,"file":"v7.d.mts","sourceRoot":"","sources":["../../../../../src/lib/versions/rfc/v7.mjs"],"names":[],"mappings":"AAyBA;;;;;;;GAOG;AACH,6BALG;IAAwB,KAAK,EAArB,MAAM;IACc,GAAG,EAAvB,UAAU;IACM,MAAM,EAAtB,MAAM;CACd,GAAU,MAAM,GAAC,UAAU,CA4B7B"} \ No newline at end of file +{"version":3,"file":"v7.d.mts","sourceRoot":"","sources":["../../../../../src/lib/versions/rfc/v7.mjs"],"names":[],"mappings":"AAyBA;;;;;;;GAOG;AACH,6BALG;IAAyB,KAAK,GAAtB,MAAM;IACe,GAAG,GAAxB,UAAU;IACO,MAAM,GAAvB,MAAM;CACd,GAAU,MAAM,GAAC,UAAU,CA4B7B"} \ No newline at end of file diff --git a/types/src/lib/versions/rfc/v8.d.mts b/types/src/lib/versions/rfc/v8.d.mts index 30f4eca..ac4e066 100644 --- a/types/src/lib/versions/rfc/v8.d.mts +++ b/types/src/lib/versions/rfc/v8.d.mts @@ -1,9 +1,9 @@ /** * Create a version 8 (custom/experimental) UUID - * @param {Object} options - Optional parameters - * @param {Uint8Array} options.data - Custom data to fill the UUID (16 bytes) - * @param {Uint8Array} options.buf - Buffer to write UUID into - * @param {number} options.offset - Offset in buffer to start writing + * @param {object} [options] - Optional parameters + * @param {Uint8Array} [options.data] - Custom data to fill the UUID (16 bytes) + * @param {Uint8Array} [options.buf] - Buffer to write UUID into; when given, it is returned instead of a string + * @param {number} [options.offset] - Offset in buffer to start writing * @returns {string|Uint8Array} UUID string or buffer * @example * // Generate with random data @@ -15,8 +15,8 @@ * v8({ data: customData }); */ export function v8(options?: { - data: Uint8Array; - buf: Uint8Array; - offset: number; + data?: Uint8Array; + buf?: Uint8Array; + offset?: number; }): string | Uint8Array; //# sourceMappingURL=v8.d.mts.map \ No newline at end of file diff --git a/types/src/lib/versions/rfc/v8.d.mts.map b/types/src/lib/versions/rfc/v8.d.mts.map index 92f2317..7e5f457 100644 --- a/types/src/lib/versions/rfc/v8.d.mts.map +++ b/types/src/lib/versions/rfc/v8.d.mts.map @@ -1 +1 @@ -{"version":3,"file":"v8.d.mts","sourceRoot":"","sources":["../../../../../src/lib/versions/rfc/v8.mjs"],"names":[],"mappings":"AA0BA;;;;;;;;;;;;;;;GAeG;AACH,6BAbG;IAA4B,IAAI,EAAxB,UAAU;IACU,GAAG,EAAvB,UAAU;IACM,MAAM,EAAtB,MAAM;CACd,GAAU,MAAM,GAAC,UAAU,CA6B7B"} \ No newline at end of file +{"version":3,"file":"v8.d.mts","sourceRoot":"","sources":["../../../../../src/lib/versions/rfc/v8.mjs"],"names":[],"mappings":"AA0BA;;;;;;;;;;;;;;;GAeG;AACH,6BAbG;IAA6B,IAAI,GAAzB,UAAU;IACW,GAAG,GAAxB,UAAU;IACO,MAAM,GAAvB,MAAM;CACd,GAAU,MAAM,GAAC,UAAU,CA6B7B"} \ No newline at end of file diff --git a/types/src/uuid.d.mts b/types/src/uuid.d.mts index ade242c..cd361ca 100644 --- a/types/src/uuid.d.mts +++ b/types/src/uuid.d.mts @@ -1,3 +1,81 @@ +/** + * The byte container toBuffer() returns: a Buffer in Node, a plain Uint8Array elsewhere. + * `#bytes-type` (package.json `imports`) resolves to a Buffer alias under the `node` + * condition and to a Uint8Array alias otherwise. + */ +export type Bytes = import("#bytes-type").Bytes; +/** + * Options shared by the RFC generators that can write into a caller-supplied buffer. + */ +export type RFCBufferOptions = { + /** + * - Buffer to write the UUID into; when given, the generator returns it instead of a string + */ + buf?: Uint8Array; + /** + * - Offset in `buf` to start writing at (default 0) + */ + offset?: number; +}; +/** + * Options for {@link UUID.v1} and {@link UUID.v6}. `node` is the 6-byte node id (MAC address), + * `clockseq` the 14-bit clock sequence, `msecs` the timestamp in milliseconds since the Unix + * epoch, and `nsecs` additional 100-nanosecond intervals. + */ +export type TimeOptions = RFCBufferOptions & { + node?: ArrayLike; + clockseq?: number; + msecs?: number; + nsecs?: number; +}; +/** + * Options for {@link UUID.v4}. `random` supplies the 16 random bytes instead of generating them. + */ +export type V4Options = RFCBufferOptions & { + random?: Uint8Array; +}; +/** + * Options for {@link UUID.v7}. `msecs` is the timestamp in milliseconds since the Unix epoch. + */ +export type V7Options = RFCBufferOptions & { + msecs?: number; +}; +/** + * Options for {@link UUID.v8}. `data` supplies the 16 bytes of custom data instead of random bytes. + */ +export type V8Options = RFCBufferOptions & { + data?: Uint8Array; +}; +/** + * The byte container toBuffer() returns: a Buffer in Node, a plain Uint8Array elsewhere. + * `#bytes-type` (package.json `imports`) resolves to a Buffer alias under the `node` + * condition and to a Uint8Array alias otherwise. + * @typedef {import("#bytes-type").Bytes} Bytes + */ +/** + * Options shared by the RFC generators that can write into a caller-supplied buffer. + * @typedef {object} RFCBufferOptions + * @property {Uint8Array} [buf] - Buffer to write the UUID into; when given, the generator returns it instead of a string + * @property {number} [offset] - Offset in `buf` to start writing at (default 0) + */ +/** + * Options for {@link UUID.v1} and {@link UUID.v6}. `node` is the 6-byte node id (MAC address), + * `clockseq` the 14-bit clock sequence, `msecs` the timestamp in milliseconds since the Unix + * epoch, and `nsecs` additional 100-nanosecond intervals. + * @typedef {RFCBufferOptions & { node?: ArrayLike, clockseq?: number, msecs?: number, nsecs?: number }} TimeOptions + */ +/** + * Options for {@link UUID.v4}. `random` supplies the 16 random bytes instead of generating them. + * @typedef {RFCBufferOptions & { random?: Uint8Array }} V4Options + */ +/** + * Options for {@link UUID.v7}. `msecs` is the timestamp in milliseconds since the Unix epoch. + * @typedef {RFCBufferOptions & { msecs?: number }} V7Options + */ +/** + * Options for {@link UUID.v8}. `data` supplies the 16 bytes of custom data instead of random bytes. + * @typedef {RFCBufferOptions & { data?: Uint8Array }} V8Options + */ /** * UUID class implementing the new specification */ @@ -6,63 +84,63 @@ export class UUID { * Create a new Issuer Variant UUID * @param {number} issuerID - Issuer ID (0-ISSUER_ID_MASK) * @param {number} version - Version number - * @param {Uint8Array} entropy - Additional entropy data + * @param {Uint8Array|null} [entropy] - Additional entropy data * @returns {UUID} New UUID instance */ - static createIssuerVariant(issuerID: number, version: number, entropy?: Uint8Array): UUID; + static createIssuerVariant(issuerID: number, version: number, entropy?: Uint8Array | null): UUID; /** * Create a new Timestamp Variant UUID - * @param {number|Date} timestamp - Timestamp value (optional, defaults to Date.now()) + * @param {number|Date|null|undefined} timestamp - Timestamp value (null/undefined defaults to the current time) * @param {number} version - Version number - * @param {Uint8Array} entropy - Optional entropy for bits 79-127 + * @param {Uint8Array|null} [entropy] - Optional entropy for bits 79-127 * @returns {UUID} New UUID instance */ - static createTimestampVariant(timestamp: number | Date, version: number, entropy?: Uint8Array): UUID; + static createTimestampVariant(timestamp: number | Date | null | undefined, version: number, entropy?: Uint8Array | null): UUID; /** * Create an issuer-based UUID (short name alias) * @param {number} issuerID - Issuer ID (0-1023) * @param {number} version - Version number - * @param {Uint8Array} entropy - Additional entropy data + * @param {Uint8Array|null} [entropy] - Additional entropy data * @returns {UUID} New UUID instance */ - static issuer(issuerID: number, version: number, entropy?: Uint8Array): UUID; + static issuer(issuerID: number, version: number, entropy?: Uint8Array | null): UUID; /** * Create a timestamp-based UUID (short name alias) - * @param {number|Date} timestamp - Timestamp value (optional, defaults to Date.now()) + * @param {number|Date|null|undefined} timestamp - Timestamp value (null/undefined defaults to the current time) * @param {number} version - Version number - * @param {Uint8Array} entropy - Optional entropy for bits 79-127 + * @param {Uint8Array|null} [entropy] - Optional entropy for bits 79-127 * @returns {UUID} New UUID instance */ - static timestamp(timestamp: number | Date, version: number, entropy?: Uint8Array): UUID; + static timestamp(timestamp: number | Date | null | undefined, version: number, entropy?: Uint8Array | null): UUID; /** * Create Timestamp Variant v1 UUID (ultra-short alias) * Subvariant 00 - Timestamp-based identification (seconds precision) - * @param {number|Date} timestamp - Timestamp value (optional, defaults to Date.now()) - * @param {Uint8Array} entropy - Optional entropy for bits 79-127 + * @param {number|Date|null} [timestamp] - Timestamp value (optional, defaults to the current time) + * @param {Uint8Array|null} [entropy] - Optional entropy for bits 79-127 * @returns {UUID} New UUID instance */ - static TA(timestamp: number | Date, entropy?: Uint8Array): UUID; + static TA(timestamp?: number | Date | null, entropy?: Uint8Array | null): UUID; /** * Create Issuer Variant v1 UUID (ultra-short alias) * Subvariant 01 - Issuer-based identification * @param {number} issuerID - Issuer ID (0-1023) - * @param {Uint8Array} entropy - Additional entropy data + * @param {Uint8Array|null} [entropy] - Additional entropy data * @returns {UUID} New UUID instance */ - static IA(issuerID: number, entropy?: Uint8Array): UUID; + static IA(issuerID: number, entropy?: Uint8Array | null): UUID; /** * Create Timestamp Variant v2 UUID (ultra-short alias) * Subvariant 00 - Timestamp-based identification (milliseconds precision) - * @param {number|Date} timestamp - Timestamp value (optional, defaults to Date.now()) - * @param {Uint8Array} entropy - Optional entropy for bits 79-127 + * @param {number|Date|null} [timestamp] - Timestamp value (optional, defaults to the current time) + * @param {Uint8Array|null} [entropy] - Optional entropy for bits 79-127 * @returns {UUID} New UUID instance */ - static TB(timestamp: number | Date, entropy?: Uint8Array): UUID; + static TB(timestamp?: number | Date | null, entropy?: Uint8Array | null): UUID; /** * Get the shared issuer registry instance - * @returns {Promise} Shared registry instance + * @returns {Promise} Shared registry instance */ - static getRegistry(): Promise; + static getRegistry(): Promise; /** * Register a new issuer in Category A * @param {number} issuerID - Issuer ID (2-255) @@ -99,10 +177,23 @@ export class UUID { static validateDetailed(buffer: Uint8Array): Promise; /** * Generate a version 1 (timestamp) UUID - * @param {Object} options - Optional parameters + * @overload + * @param {TimeOptions & { buf?: undefined }} [options] - Optional parameters * @returns {string} UUID string */ - static v1(options: any): string; + static v1(options?: TimeOptions & { + buf?: undefined; + }): string; + /** + * Generate a version 1 (timestamp) UUID, written into `options.buf` + * @template {Uint8Array} T + * @overload + * @param {TimeOptions & { buf: T }} options - Options with the buffer to write into + * @returns {T} `options.buf` itself, so its type is kept (a Buffer stays a Buffer) + */ + static v1(options: TimeOptions & { + buf: T; + }): T; /** * Generate a version 3 (namespace with MD5) UUID * @param {string} name - Name to hash @@ -112,10 +203,23 @@ export class UUID { static v3(name: string, namespace: string | Uint8Array): string; /** * Generate a version 4 (random) UUID - * @param {Object} options - Optional parameters + * @overload + * @param {V4Options & { buf?: undefined }} [options] - Optional parameters * @returns {string} UUID string */ - static v4(options: any): string; + static v4(options?: V4Options & { + buf?: undefined; + }): string; + /** + * Generate a version 4 (random) UUID, written into `options.buf` + * @template {Uint8Array} T + * @overload + * @param {V4Options & { buf: T }} options - Options with the buffer to write into + * @returns {T} `options.buf` itself, so its type is kept (a Buffer stays a Buffer) + */ + static v4(options: V4Options & { + buf: T; + }): T; /** * Generate a version 5 (namespace with SHA-1) UUID * @param {string} name - Name to hash @@ -125,22 +229,61 @@ export class UUID { static v5(name: string, namespace: string | Uint8Array): string; /** * Generate a version 6 (timestamp, reordered) UUID - * @param {Object} options - Optional parameters + * @overload + * @param {TimeOptions & { buf?: undefined }} [options] - Optional parameters * @returns {string} UUID string */ - static v6(options: any): string; + static v6(options?: TimeOptions & { + buf?: undefined; + }): string; + /** + * Generate a version 6 (timestamp, reordered) UUID, written into `options.buf` + * @template {Uint8Array} T + * @overload + * @param {TimeOptions & { buf: T }} options - Options with the buffer to write into + * @returns {T} `options.buf` itself, so its type is kept (a Buffer stays a Buffer) + */ + static v6(options: TimeOptions & { + buf: T; + }): T; /** * Generate a version 7 (Unix Epoch) UUID - * @param {Object} options - Optional parameters + * @overload + * @param {V7Options & { buf?: undefined }} [options] - Optional parameters * @returns {string} UUID string */ - static v7(options: any): string; + static v7(options?: V7Options & { + buf?: undefined; + }): string; + /** + * Generate a version 7 (Unix Epoch) UUID, written into `options.buf` + * @template {Uint8Array} T + * @overload + * @param {V7Options & { buf: T }} options - Options with the buffer to write into + * @returns {T} `options.buf` itself, so its type is kept (a Buffer stays a Buffer) + */ + static v7(options: V7Options & { + buf: T; + }): T; /** * Generate a version 8 (custom/experimental) UUID - * @param {Object} options - Optional parameters + * @overload + * @param {V8Options & { buf?: undefined }} [options] - Optional parameters * @returns {string} UUID string */ - static v8(options: any): string; + static v8(options?: V8Options & { + buf?: undefined; + }): string; + /** + * Generate a version 8 (custom/experimental) UUID, written into `options.buf` + * @template {Uint8Array} T + * @overload + * @param {V8Options & { buf: T }} options - Options with the buffer to write into + * @returns {T} `options.buf` itself, so its type is kept (a Buffer stays a Buffer) + */ + static v8(options: V8Options & { + buf: T; + }): T; /** * Convert UUID string to byte array * @param {string} uuid - UUID string @@ -149,10 +292,10 @@ export class UUID { static parse(uuid: string): Uint8Array; /** * Convert byte array to UUID string - * @param {Uint8Array|Buffer|Array} bytes - 16-byte array + * @param {ArrayLike} bytes - 16-byte array (Uint8Array, Buffer or plain array) * @returns {string} UUID string */ - static stringify(bytes: Uint8Array | Buffer | any[]): string; + static stringify(bytes: ArrayLike): string; /** * Validate UUID string format * @param {string} uuid - UUID string to validate @@ -161,7 +304,7 @@ export class UUID { static validateRFC(uuid: string): boolean; /** * Detect version/variant identifier of UUID (handles both RFC and custom variants) - * @param {string|Buffer|UUID} uuid - UUID string, buffer, or UUID instance + * @param {string|Uint8Array|UUID} uuid - UUID string, buffer, or UUID instance * @returns {string|number|null} Version identifier (e.g., "TA", "TB", "IA" for custom, 1-8 for RFC, or null if invalid) * @example * UUID.version(uuidString); // => "TA" for Timestamp v1 @@ -169,20 +312,25 @@ export class UUID { * UUID.version(uuidString); // => "IA" for Issuer v1 * UUID.version(uuidString); // => 4 for RFC v4 */ - static version(uuid: string | Buffer | UUID): string | number | null; + static version(uuid: string | Uint8Array | UUID): string | number | null; /** * Detect variant identifier (alias for version()) - * @param {string|Buffer|UUID} uuid - UUID string, buffer, or UUID instance + * @param {string|Uint8Array|UUID} uuid - UUID string, buffer, or UUID instance * @returns {string|number|null} Version identifier * @deprecated Use UUID.version() instead */ - static detectVariant(uuid: string | Buffer | UUID): string | number | null; + static detectVariant(uuid: string | Uint8Array | UUID): string | number | null; /** * Create a new UUID instance * @param {Uint8Array|string|null} data - Optional UUID data to parse */ constructor(data?: Uint8Array | string | null); - _buffer: Uint8Array; + /** + * The 16 UUID bytes. + * @type {Uint8Array} + * @private + */ + private _buffer; /** * Parse UUID from existing data * @param {Uint8Array|string} data - UUID data to parse @@ -197,7 +345,7 @@ export class UUID { private _setTimestamp; /** * Fill remaining bits with entropy while preserving immutable fields - * @param {Uint8Array} entropy - Entropy data + * @param {Uint8Array|null} [entropy] - Entropy data * @private */ private _fillEntropy; @@ -287,9 +435,9 @@ export class UUID { toString(): string; /** * Convert UUID to buffer - * @returns {Buffer} UUID as 16-byte buffer (Node); a Uint8Array copy in environments without Buffer + * @returns {Bytes} UUID as a 16-byte copy: a Node Buffer (a Uint8Array subclass) in Node, a plain Uint8Array in environments without Buffer */ - toBuffer(): Buffer; + toBuffer(): Bytes; /** * Return the primitive value of the UUID (string representation) * This allows UUIDs to be automatically converted to strings when used in string contexts diff --git a/types/src/uuid.d.mts.map b/types/src/uuid.d.mts.map index a122b6e..185cdb0 100644 --- a/types/src/uuid.d.mts.map +++ b/types/src/uuid.d.mts.map @@ -1 +1 @@ -{"version":3,"file":"uuid.d.mts","sourceRoot":"","sources":["../../src/uuid.mjs"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"uuid.d.mts","sourceRoot":"","sources":["../../src/uuid.mjs"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/typings/bytes-node.d.mts b/typings/bytes-node.d.mts new file mode 100644 index 0000000..d90adca --- /dev/null +++ b/typings/bytes-node.d.mts @@ -0,0 +1,27 @@ +/** + * + * @Project: @cldmv/uuid + * @Filename: /typings/bytes-node.d.mts + * @Date: 2026-10-03T18:00:00-07:00 (1791075600) + * @Author: Nate Corcoran + * @Email: + * ----- + * @Last modified by: Nate Corcoran (Shinrai@users.noreply.github.com) + * @Last modified time: 2026-10-03T18:00:00-07:00 (1791075600) + * ----- + * @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. + * + */ + +/** + * The byte container the package returns in Node: a Buffer (a Uint8Array subclass). + * package.json `imports` maps `#bytes-type` here under the `node` condition, which + * TypeScript applies with `module`/`moduleResolution` `node16`/`nodenext`. + * + * Buffer is read from the global scope instead of through `/// `, + * so importing this package never forces Node's globals into a project. With @types/node + * loaded, `Bytes` is Buffer; without it, it falls back to Uint8Array (which Buffer extends). + */ +type NodeBuffer = typeof globalThis extends { Buffer: { alloc(size: number): infer B } } ? B : never; + +export type Bytes = [NodeBuffer] extends [never] ? Uint8Array : NodeBuffer; diff --git a/typings/bytes.d.mts b/typings/bytes.d.mts new file mode 100644 index 0000000..628a37f --- /dev/null +++ b/typings/bytes.d.mts @@ -0,0 +1,21 @@ +/** + * + * @Project: @cldmv/uuid + * @Filename: /typings/bytes.d.mts + * @Date: 2026-10-03T18:00:00-07:00 (1791075600) + * @Author: Nate Corcoran + * @Email: + * ----- + * @Last modified by: Nate Corcoran (Shinrai@users.noreply.github.com) + * @Last modified time: 2026-10-03T18:00:00-07:00 (1791075600) + * ----- + * @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved. + * + */ + +/** + * The byte container the package returns (toBuffer(), the RFC generators' `buf` results) + * outside Node: a plain Uint8Array. package.json `imports` maps `#bytes-type` here unless + * the consumer resolves with the `node` condition (see bytes-node.d.mts). + */ +export type Bytes = Uint8Array;