🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

uniku

Package Overview
Dependencies
Maintainers
1
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

uniku - npm Package Compare versions

Comparing version
0.5.0
to
1.0.0-rc.0
+1
build/cuid/v2.d.mts.map
{"version":3,"file":"v2.d.mts","names":[],"sources":["../../src/cuid/v2.ts"],"mappings":";KAIY,aAAA;EAAZ;;;;EAKE,MAAA;;;;AAOS;AAGX;;EAHE,MAAA,GAAS,UAAA;AAAA;AAAA,KAGC,MAAA;oCAET,OAAA,GAAU,aAAA;EAEX,OAAA,CAAQ,EAAA,YAAc,EAAA;AAAA;AAAA;AAiMxB;;;;AAAqB;;;;;;;;;;;;;;;;;;;;;;;;AAjMG,cAiMX,MAAA,EAAQ,MAAA"}
{"version":3,"file":"v2.mjs","names":[],"sources":["../../src/cuid/v2.ts"],"sourcesContent":["import { sha3_512 } from '@noble/hashes/sha3.js'\nimport { randomUint32 } from '../common/random'\nimport { InvalidInputError } from '../errors'\n\nexport type CuidV2Options = {\n /**\n * Length of the generated ID (2-32 characters).\n * Default: 24\n */\n length?: number\n /**\n * Custom random bytes for deterministic testing.\n * Must be at least 1 byte. For adequate entropy, use at least 16 bytes.\n * Note: The fingerprint always uses cryptographically secure random bytes,\n * regardless of this option.\n */\n random?: Uint8Array\n}\n\nexport type CuidV2 = {\n /** Generate a CUID v2 string. */\n (options?: CuidV2Options): string\n /** Return whether a value is a syntactically valid CUID v2 string. */\n isValid(id: unknown): id is string\n}\n\nconst DEFAULT_LENGTH = 24\nconst MAX_LENGTH = 32\nconst MIN_LENGTH = 2\n\n// Maximum initial counter value from cuid2 spec - provides ~29 bits of\n// initial entropy to prevent cross-process collisions at startup\nconst INITIAL_COUNT_MAX = 476782367\n\n// Validation regex: first char must be a-z, rest can be a-z or 0-9\nconst CUID2_REGEX = /^[a-z][0-9a-z]+$/\n\n// Base36 alphabet\nconst ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz'\nconst LETTER_ALPHABET = 'abcdefghijklmnopqrstuvwxyz'\n\n// Reusable TextEncoder instance (stateless, safe to share)\nconst textEncoder = new TextEncoder()\n\n/**\n * Module-level state for counter and fingerprint.\n * Counter is initialized lazily on first call to prevent unnecessary crypto operations.\n * Fingerprint is also generated lazily on first call.\n */\nconst state: { counter: number | undefined; fingerprint: string | undefined } = {\n counter: undefined,\n fingerprint: undefined,\n}\n\n/**\n * Initialize counter using crypto for consistency with other entropy sources.\n */\nfunction initializeCounter(): number {\n return randomUint32() % (INITIAL_COUNT_MAX + 1)\n}\n\n// --- Base36 utilities ---\n\nfunction bufToBigInt(buf: Uint8Array): bigint {\n let value = 0n\n for (const byte of buf) {\n value = value * 256n + BigInt(byte)\n }\n return value\n}\n\nfunction bigIntToBase36(value: bigint): string {\n if (value === 0n) return '0'\n const chars: string[] = []\n while (value > 0n) {\n chars.push(ALPHABET[Number(value % 36n)])\n value = value / 36n\n }\n return chars.reverse().join('')\n}\n\nfunction randomLetter(random: () => number): string {\n return LETTER_ALPHABET[Math.floor(random() * 26)]\n}\n\nfunction createEntropy(length: number, random: () => number): string {\n const chars = new Array<string>(length)\n for (let i = 0; i < length; i++) {\n chars[i] = ALPHABET[Math.floor(random() * 36)]\n }\n return chars.join('')\n}\n\n// --- SHA3 hash wrapper ---\n\nfunction hash(input: string): Uint8Array {\n return sha3_512(textEncoder.encode(input))\n}\n\n// --- Fingerprint generation ---\n\nconst BIG_LENGTH = 32\n\nfunction createFingerprint(): string {\n // Always use CSPRNG for fingerprint to ensure security regardless of custom random option\n const random = getCryptoRandom\n const globals = Object.keys(globalThis).toString()\n const sourceString = globals + createEntropy(BIG_LENGTH, random)\n const hashed = hash(sourceString)\n return bigIntToBase36(bufToBigInt(hashed)).slice(1, BIG_LENGTH + 1)\n}\n\n// --- Random function factory ---\n\n/**\n * Get a random number in [0, 1) using CUID2's own random pool.\n */\nfunction getCryptoRandom(): number {\n return randomUint32() / 0x100000000\n}\n\nfunction getRandomFn(random?: Uint8Array): () => number {\n if (random) {\n if (random.length === 0) {\n throw new InvalidInputError('RANDOM_BYTES_TOO_SHORT', 'Random byte array cannot be empty', {\n strategy: 'cuid',\n })\n }\n let index = 0\n return () => {\n const value = random[index % random.length] / 256\n index += 1\n return value\n }\n }\n return getCryptoRandom\n}\n\n// --- Main generator ---\n\nfunction cuidv2Fn(options?: CuidV2Options): string {\n const requestedLength = options?.length\n\n if (\n requestedLength !== undefined &&\n (!Number.isInteger(requestedLength) || requestedLength < MIN_LENGTH || requestedLength > MAX_LENGTH)\n ) {\n throw new InvalidInputError(\n 'LENGTH_OUT_OF_RANGE',\n `CUID2 length must be between ${MIN_LENGTH} and ${MAX_LENGTH}. Received: ${requestedLength}`,\n { strategy: 'cuid' },\n )\n }\n const length = requestedLength ?? DEFAULT_LENGTH\n\n const random = getRandomFn(options?.random)\n\n // Initialize counter lazily on first call\n if (state.counter === undefined) {\n state.counter = initializeCounter()\n }\n\n // Initialize fingerprint lazily on first call (always uses CSPRNG)\n if (state.fingerprint === undefined) {\n state.fingerprint = createFingerprint()\n }\n\n const firstLetter = randomLetter(random)\n const time = Date.now().toString(36)\n state.counter += 1\n const count = state.counter.toString(36)\n const salt = createEntropy(length, random)\n\n const hashInput = time + salt + count + state.fingerprint\n const hashed = hash(hashInput)\n const base36Hash = bigIntToBase36(bufToBigInt(hashed))\n\n // Drop first char of hash to avoid histogram bias, prepend random letter\n return firstLetter + base36Hash.slice(1, length)\n}\n\n// --- Validation (type guard) ---\n\nfunction isValid(id: unknown): id is string {\n return typeof id === 'string' && id.length >= MIN_LENGTH && id.length <= MAX_LENGTH && CUID2_REGEX.test(id)\n}\n\n/**\n * Generate a CUID v2 string.\n *\n * CUID v2 is a secure, collision-resistant identifier that hashes multiple\n * entropy sources using SHA3-512. Unlike time-ordered IDs (ULID, UUID v7),\n * CUID v2 prevents enumeration attacks by making IDs non-predictable.\n *\n * Note: CUID v2 does not provide toBytes/fromBytes because it is a string-native\n * format with no canonical binary representation (unlike UUID's 16-byte format).\n *\n * @example\n * ```ts\n * import { cuidv2 } from 'uniku/cuid/v2'\n *\n * const id = cuidv2()\n * // => \"pfh0haxfpzowht3oi213cqos\"\n *\n * // Custom length\n * const shortId = cuidv2({ length: 10 })\n * // => \"tz4a98xxat\"\n *\n * // Validation (type guard)\n * const maybeId: unknown = getUserInput()\n * if (cuidv2.isValid(maybeId)) {\n * console.log(maybeId.length) // TypeScript knows maybeId is string\n * }\n * ```\n *\n */\nexport const cuidv2: CuidV2 = Object.assign(cuidv2Fn, {\n isValid,\n})\n"],"mappings":"8IA0BA,MASM,EAAc,mBAGd,EAAW,uCAIX,EAAc,IAAI,YAOlB,EAA0E,CAC9E,QAAS,IAAA,GACT,YAAa,IAAA,EACf,EAKA,SAAS,GAA4B,CACnC,OAAO,EAAa,EAAK,SAC3B,CAIA,SAAS,EAAY,EAAyB,CAC5C,IAAI,EAAQ,GACZ,IAAK,IAAM,KAAQ,EACjB,EAAQ,EAAQ,KAAO,OAAO,CAAI,EAEpC,OAAO,CACT,CAEA,SAAS,EAAe,EAAuB,CAC7C,GAAI,IAAU,GAAI,MAAO,IACzB,IAAM,EAAkB,CAAC,EACzB,KAAO,EAAQ,IACb,EAAM,KAAK,EAAS,OAAO,EAAQ,GAAG,EAAE,EACxC,GAAgB,IAElB,OAAO,EAAM,QAAQ,CAAC,CAAC,KAAK,EAAE,CAChC,CAEA,SAAS,EAAa,EAA8B,CAClD,MAAO,6BAAgB,KAAK,MAAM,EAAO,EAAI,EAAE,EACjD,CAEA,SAAS,EAAc,EAAgB,EAA8B,CACnE,IAAM,EAAY,MAAc,CAAM,EACtC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,IAC1B,EAAM,GAAK,EAAS,KAAK,MAAM,EAAO,EAAI,EAAE,GAE9C,OAAO,EAAM,KAAK,EAAE,CACtB,CAIA,SAAS,EAAK,EAA2B,CACvC,OAAO,EAAS,EAAY,OAAO,CAAK,CAAC,CAC3C,CAMA,SAAS,GAA4B,CAEnC,IAAM,EAAS,EAIf,OAAO,EAAe,EADP,EAFC,OAAO,KAAK,UAAU,CAAC,CAAC,SACb,EAAI,EAAc,GAAY,CAAM,CAExB,CAAC,CAAC,CAAC,CAAC,MAAM,EAAG,EAAc,CACpE,CAOA,SAAS,GAA0B,CACjC,OAAO,EAAa,EAAI,UAC1B,CAEA,SAAS,EAAY,EAAmC,CACtD,GAAI,EAAQ,CACV,GAAI,EAAO,SAAW,EACpB,MAAM,IAAI,EAAkB,yBAA0B,oCAAqC,CACzF,SAAU,MACZ,CAAC,EAEH,IAAI,EAAQ,EACZ,UAAa,CACX,IAAM,EAAQ,EAAO,EAAQ,EAAO,QAAU,IAE9C,MADA,IAAS,EACF,CACT,CACF,CACA,OAAO,CACT,CAIA,SAAS,EAAS,EAAiC,CACjD,IAAM,EAAkB,GAAS,OAEjC,GACE,IAAoB,IAAA,KACnB,CAAC,OAAO,UAAU,CAAe,GAAK,EAAkB,GAAc,EAAkB,IAEzF,MAAM,IAAI,EACR,sBACA,oDAA2E,IAC3E,CAAE,SAAU,MAAO,CACrB,EAEF,IAAM,EAAS,GAAmB,GAE5B,EAAS,EAAY,GAAS,MAAM,EAGtC,EAAM,UAAY,IAAA,KACpB,EAAM,QAAU,EAAkB,GAIhC,EAAM,cAAgB,IAAA,KACxB,EAAM,YAAc,EAAkB,GAGxC,IAAM,EAAc,EAAa,CAAM,EACjC,EAAO,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE,EACnC,EAAM,SAAW,EACjB,IAAM,EAAQ,EAAM,QAAQ,SAAS,EAAE,EAQvC,OAAO,EAHY,EAAe,EADnB,EADG,EAFL,EAAc,EAAQ,CAEP,EAAI,EAAQ,EAAM,WAEK,CAAC,CAGtB,CAAC,CAAC,MAAM,EAAG,CAAM,CACjD,CAIA,SAAS,EAAQ,EAA2B,CAC1C,OAAO,OAAO,GAAO,UAAY,EAAG,QAAU,GAAc,EAAG,QAAU,IAAc,EAAY,KAAK,CAAE,CAC5G,CA+BA,MAAa,EAAiB,OAAO,OAAO,EAAU,CACpD,SACF,CAAC"}
{"version":3,"file":"errors.d.mts","names":[],"sources":["../src/errors.ts"],"mappings":";;;;;AAWA;;;;AAyBE;cAzBW,WAAA;;;;AAgCmB;KAApB,SAAA,WAAoB,WAAA;;;;KAKpB,oBAAA;EAeZ;;;;;EAAA,SATW,QAAA,GAAW,WAAA;AAAA;;;;;;;uBASA,aAAA,SAAsB,KAAA;EAAA,kBACxB,IAAA;EAAA,kBACA,IAAA,EAAM,SAAA;;WAGf,QAAA,GAAW,WAAA;EAEpB,WAAA,CAAY,OAAA,UAAiB,OAAA,GAAU,oBAAA;AAAA;AAAA;AAUzC;;AAVyC,cAU5B,iBAAA,SAA0B,aAAA;EAAA,SAInC,IAAA,EAAe,SAAA;EAAA,SAHR,IAAA;EAET,WAAA,CACE,IAAA,EAAe,SAAA,EACf,OAAA,UACA,OAAA,GAAU,oBAAA;AAAA;;;;cASD,UAAA,SAAmB,aAAA;EAAA,SAI5B,IAAA,EAAe,SAAA;EAAA,SAHR,IAAA;EAET,WAAA,CACE,IAAA,EAAe,SAAA,EACf,OAAA,UACA,OAAA,GAAU,oBAAA;AAAA;;;;cASD,WAAA,SAAoB,aAAA;EAAA,SAI7B,IAAA,EAAe,SAAA;EAAA,SAHR,IAAA;EAET,WAAA,CACE,IAAA,EAAe,SAAA,EACf,OAAA,UACA,OAAA,GAAU,oBAAA;AAAA"}
import{t as e}from"./validation-CTNpXm94.mjs";import{InvalidInputError as t}from"./errors.mjs";function n(n,r,i,a){let{msecs:o}=n;if(o!==void 0){let n=r*1e3,s=i*1e3+999;if(!e(o,n,s))throw new t(`TIMESTAMP_OUT_OF_RANGE`,`Timestamp must be an integer between ${n} and ${s} milliseconds`,{strategy:a});return Math.floor(o/1e3)}}export{n as t};
//# sourceMappingURL=timestamp-DnsO0h7C.mjs.map
{"version":3,"file":"timestamp-DnsO0h7C.mjs","names":[],"sources":["../src/common/timestamp.ts"],"sourcesContent":["import { InvalidInputError } from '../errors'\nimport type { IdGenerator } from '../generators'\nimport { isIntegerInRange } from './validation'\n\n/**\n * Timestamp options accepted by second-precision generators (ksuid, objectid,\n * xid).\n */\nexport type TimestampOptions = {\n /**\n * Timestamp in milliseconds since the Unix epoch.\n * The generator stores whole seconds, so sub-second precision is truncated.\n */\n msecs?: number\n}\n\n/**\n * Resolve a caller-provided millisecond timestamp to whole seconds since the\n * Unix epoch, or `undefined` when no timestamp was supplied.\n */\nexport function resolveTimestampSecs(\n options: TimestampOptions,\n minSecs: number,\n maxSecs: number,\n strategy: IdGenerator,\n): number | undefined {\n const { msecs } = options\n\n if (msecs !== undefined) {\n const minMsecs = minSecs * 1000\n const maxMsecs = maxSecs * 1000 + 999\n if (!isIntegerInRange(msecs, minMsecs, maxMsecs)) {\n throw new InvalidInputError(\n 'TIMESTAMP_OUT_OF_RANGE',\n `Timestamp must be an integer between ${minMsecs} and ${maxMsecs} milliseconds`,\n { strategy },\n )\n }\n return Math.floor(msecs / 1000)\n }\n\n return undefined\n}\n"],"mappings":"+FAoBA,SAAgB,EACd,EACA,EACA,EACA,EACoB,CACpB,GAAM,CAAE,SAAU,EAElB,GAAI,IAAU,IAAA,GAAW,CACvB,IAAM,EAAW,EAAU,IACrB,EAAW,EAAU,IAAO,IAClC,GAAI,CAAC,EAAiB,EAAO,EAAU,CAAQ,EAC7C,MAAM,IAAI,EACR,yBACA,wCAAwC,EAAS,OAAO,EAAS,eACjE,CAAE,UAAS,CACb,EAEF,OAAO,KAAK,MAAM,EAAQ,GAAI,CAChC,CAGF"}
+52
-2

@@ -1,2 +0,52 @@

import { Cuid2, Cuid2Options, cuid2 } from "../cuid2/cuid2.mjs";
export { type Cuid2 as CuidV2, type Cuid2Options as CuidV2Options, cuid2 as cuidv2 };
//#region src/cuid/v2.d.ts
type CuidV2Options = {
/**
* Length of the generated ID (2-32 characters).
* Default: 24
*/
length?: number;
/**
* Custom random bytes for deterministic testing.
* Must be at least 1 byte. For adequate entropy, use at least 16 bytes.
* Note: The fingerprint always uses cryptographically secure random bytes,
* regardless of this option.
*/
random?: Uint8Array;
};
type CuidV2 = {
/** Generate a CUID v2 string. */(options?: CuidV2Options): string; /** Return whether a value is a syntactically valid CUID v2 string. */
isValid(id: unknown): id is string;
};
/**
* Generate a CUID v2 string.
*
* CUID v2 is a secure, collision-resistant identifier that hashes multiple
* entropy sources using SHA3-512. Unlike time-ordered IDs (ULID, UUID v7),
* CUID v2 prevents enumeration attacks by making IDs non-predictable.
*
* Note: CUID v2 does not provide toBytes/fromBytes because it is a string-native
* format with no canonical binary representation (unlike UUID's 16-byte format).
*
* @example
* ```ts
* import { cuidv2 } from 'uniku/cuid/v2'
*
* const id = cuidv2()
* // => "pfh0haxfpzowht3oi213cqos"
*
* // Custom length
* const shortId = cuidv2({ length: 10 })
* // => "tz4a98xxat"
*
* // Validation (type guard)
* const maybeId: unknown = getUserInput()
* if (cuidv2.isValid(maybeId)) {
* console.log(maybeId.length) // TypeScript knows maybeId is string
* }
* ```
*
*/
declare const cuidv2: CuidV2;
//#endregion
export { CuidV2, CuidV2Options, cuidv2 };
//# sourceMappingURL=v2.d.mts.map
+2
-1

@@ -1,1 +0,2 @@

import{cuid2 as e}from"../cuid2/cuid2.mjs";export{e as cuidv2};
import{n as e}from"../random-Chp-Nkzi.mjs";import{InvalidInputError as t}from"../errors.mjs";import{sha3_512 as n}from"@noble/hashes/sha3.js";const r=/^[a-z][0-9a-z]+$/,i=`0123456789abcdefghijklmnopqrstuvwxyz`,a=new TextEncoder,o={counter:void 0,fingerprint:void 0};function s(){return e()%476782368}function c(e){let t=0n;for(let n of e)t=t*256n+BigInt(n);return t}function l(e){if(e===0n)return`0`;let t=[];for(;e>0n;)t.push(i[Number(e%36n)]),e/=36n;return t.reverse().join(``)}function u(e){return`abcdefghijklmnopqrstuvwxyz`[Math.floor(e()*26)]}function d(e,t){let n=Array(e);for(let r=0;r<e;r++)n[r]=i[Math.floor(t()*36)];return n.join(``)}function f(e){return n(a.encode(e))}function p(){let e=m;return l(c(f(Object.keys(globalThis).toString()+d(32,e)))).slice(1,33)}function m(){return e()/4294967296}function h(e){if(e){if(e.length===0)throw new t(`RANDOM_BYTES_TOO_SHORT`,`Random byte array cannot be empty`,{strategy:`cuid`});let n=0;return()=>{let t=e[n%e.length]/256;return n+=1,t}}return m}function g(e){let n=e?.length;if(n!==void 0&&(!Number.isInteger(n)||n<2||n>32))throw new t(`LENGTH_OUT_OF_RANGE`,`CUID2 length must be between 2 and 32. Received: ${n}`,{strategy:`cuid`});let r=n??24,i=h(e?.random);o.counter===void 0&&(o.counter=s()),o.fingerprint===void 0&&(o.fingerprint=p());let a=u(i),m=Date.now().toString(36);o.counter+=1;let g=o.counter.toString(36);return a+l(c(f(m+d(r,i)+g+o.fingerprint))).slice(1,r)}function _(e){return typeof e==`string`&&e.length>=2&&e.length<=32&&r.test(e)}const v=Object.assign(g,{isValid:_});export{v as cuidv2};
//# sourceMappingURL=v2.mjs.map

@@ -1,2 +0,67 @@

import { a as ParseError, i as InvalidInputError, n as ERROR_CODES, o as UniqueIdError, r as ErrorCode, s as UniqueIdErrorOptions, t as BufferError } from "./errors-Da-8dh4J.mjs";
export { BufferError, ERROR_CODES, ErrorCode, InvalidInputError, ParseError, UniqueIdError, UniqueIdErrorOptions };
import { n as IdGenerator } from "./generators-BfJLt7Qf.mjs";
//#region src/errors.d.ts
/**
* The canonical, ordered list of machine-readable error codes emitted by
* uniku's public API.
*
* Codes describe the failure independently of an ID format. Use an error's
* `strategy` field when the generator that raised it matters.
*/
declare const ERROR_CODES: readonly ["TIMESTAMP_OUT_OF_RANGE", "CONFLICTING_OPTIONS", "COUNTER_OUT_OF_RANGE", "NODE_OUT_OF_RANGE", "NODE_BITS_OUT_OF_RANGE", "EPOCH_INVALID", "PROCESS_ID_OUT_OF_RANGE", "MACHINE_ID_BYTES_TOO_SHORT", "RANDOM_BYTES_TOO_SHORT", "RANDOM_OVERFLOW", "LENGTH_OUT_OF_RANGE", "ALPHABET_OUT_OF_RANGE", "ALPHABET_INVALID_CHAR", "ALPHABET_DUPLICATE", "PREFIX_TOO_LONG", "PREFIX_INVALID_CHAR", "PREFIX_INVALID_BOUNDARY", "UUID_NOT_V7", "BYTES_INVALID_LENGTH", "BUFFER_OUT_OF_BOUNDS", "INVALID_CHAR", "INVALID_LENGTH", "INVALID_FORMAT", "NON_CANONICAL", "VALUE_OUT_OF_RANGE"];
/**
* A machine-readable error code emitted by uniku, derived from
* {@link ERROR_CODES}.
*/
type ErrorCode = (typeof ERROR_CODES)[number];
/**
* Extra context carried by every uniku error.
*/
type UniqueIdErrorOptions = {
/**
* The ID strategy whose public boundary raised the error.
* Error codes are strategy-agnostic (e.g. `TIMESTAMP_OUT_OF_RANGE`), so this
* field attributes the failure to the generator that produced it.
*/
readonly strategy?: IdGenerator;
};
/**
* Base error for all uniku errors.
* Provides `_tag` for discriminated matching (compatible with Effect's `catchTag`),
* `code` for machine-readable error identification, and `strategy` to attribute
* unified codes to the ID generator that raised them.
*/
declare abstract class UniqueIdError extends Error {
abstract readonly _tag: string;
abstract readonly code: ErrorCode;
/** The ID strategy whose public boundary raised the error. */
readonly strategy?: IdGenerator;
constructor(message: string, options?: UniqueIdErrorOptions);
}
/**
* Thrown when generator arguments are invalid (bad size, alphabet, length, timestamp, version).
*/
declare class InvalidInputError extends UniqueIdError {
readonly code: ErrorCode;
readonly _tag = "InvalidInputError";
constructor(code: ErrorCode, message: string, options?: UniqueIdErrorOptions);
}
/**
* Thrown when parsing/decoding an ID string that has invalid format or characters.
*/
declare class ParseError extends UniqueIdError {
readonly code: ErrorCode;
readonly _tag = "ParseError";
constructor(code: ErrorCode, message: string, options?: UniqueIdErrorOptions);
}
/**
* Thrown when a byte array or buffer is too short or an offset is out of bounds.
*/
declare class BufferError extends UniqueIdError {
readonly code: ErrorCode;
readonly _tag = "BufferError";
constructor(code: ErrorCode, message: string, options?: UniqueIdErrorOptions);
}
//#endregion
export { BufferError, ERROR_CODES, ErrorCode, InvalidInputError, ParseError, UniqueIdError, UniqueIdErrorOptions };
//# sourceMappingURL=errors.d.mts.map

@@ -1,2 +0,2 @@

import { a as ParseError, i as InvalidInputError, o as UniqueIdError, t as BufferError } from "../errors-Da-8dh4J.mjs";
import { BufferError, InvalidInputError, ParseError, UniqueIdError } from "../errors.mjs";

@@ -15,8 +15,2 @@ //#region src/ksuid/ksuid.d.ts

msecs?: number;
/**
* Timestamp in seconds since the Unix epoch.
*
* @deprecated Use `msecs` instead. Will be removed at v1-rc.
*/
secs?: number;
};

@@ -23,0 +17,0 @@ type Ksuid = {

@@ -1,1 +0,1 @@

{"version":3,"file":"ksuid.d.mts","names":[],"sources":["../../src/ksuid/ksuid.ts"],"mappings":";;;KAkCY,YAAA;;;AAAZ;EAIE,MAAA,GAAS,UAAA;;;;;;EAMT,KAAA;EAOA;AAAA;AAGF;;;EAHE,IAAA;AAAA;AAAA,KAGU,KAAA;;gBAII,UAAA,GAAa,UAAA,EAAY,OAAA,EAAS,YAAA,cAA0B,GAAA,EAAK,IAAA,EAAM,MAAA,YAAkB,IAAA;GAEtG,OAAA,GAAU,YAAA,EAAc,GAAA,cAAiB,MAAA,oBAIzB;EAFjB,OAAA,CAAQ,EAAA,WAAa,UAAA;EAErB,SAAA,CAAU,KAAA,EAAO,UAAA;EAEjB,SAAA,CAAU,EAAA;EAEV,OAAA,CAAQ,EAAA,YAAc,EAAA;EAEtB,GAAA;EAEA,GAAA;AAAA;;;;;cA8HW,KAAA,EAAO,KAAA"}
{"version":3,"file":"ksuid.d.mts","names":[],"sources":["../../src/ksuid/ksuid.ts"],"mappings":";;;KAkCY,YAAA;;;AAAZ;EAIE,MAAA,GAAS,UAAA;;;;;;EAMT,KAAA;AAAA;AAAA,KAGU,KAAA;EAAA;gBAII,UAAA,GAAa,UAAA,EAAY,OAAA,EAAS,YAAA,cAA0B,GAAA,EAAK,IAAA,EAAM,MAAA,YAAkB,IAAA;GAEtG,OAAA,GAAU,YAAA,EAAc,GAAA,cAAiB,MAAA;EAE1C,OAAA,CAAQ,EAAA,WAAa,UAAA;EAErB,SAAA,CAAU,KAAA,EAAO,UAAA,WAAA;EAEjB,SAAA,CAAU,EAAA;EAEV,OAAA,CAAQ,EAAA,YAAc,EAAA;EAEtB,GAAA;EAEA,GAAA;AAAA;;;;;cA8HW,KAAA,EAAO,KAAA"}

@@ -1,2 +0,2 @@

import{r as e}from"../random-Chp-Nkzi.mjs";import{n as t}from"../validation-CTNpXm94.mjs";import{BufferError as n,InvalidInputError as r,ParseError as i,UniqueIdError as a}from"../errors.mjs";import{n as o}from"../bytes-xqWxFYsM.mjs";import{t as s}from"../timestamp-ChrSuQCR.mjs";const c=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`,l=62n,u=(1n<<160n)-1n,d=new Uint8Array(65536);d.fill(255);for(let e=0;e<62;e+=1)d[c.charCodeAt(e)]=e;function f(e){if(e.length<20)throw new n(`BYTES_INVALID_LENGTH`,`KSUID bytes must be at least 20 bytes, got ${e.length}`,{strategy:`ksuid`});let t=0n;for(let n=0;n<20;n+=1)t=t<<8n|BigInt(e[n]);let r=``;for(;t>0n;){let e=t%l;t/=l,r=c[Number(e)]+r}return r.padStart(27,`0`)}function p(e){if(e.length!==27)throw new i(`INVALID_LENGTH`,`KSUID string must be 27 characters, got ${e.length}`,{strategy:`ksuid`});let t=0n;for(let n=0;n<27;n+=1){let r=d[e.charCodeAt(n)];if(r===255)throw new i(`INVALID_CHAR`,`Invalid KSUID character: ${e[n]}`,{strategy:`ksuid`});t=t*l+BigInt(r)}if(t>u)throw new i(`VALUE_OUT_OF_RANGE`,`KSUID string exceeds 160-bit range`,{strategy:`ksuid`});let n=new Uint8Array(20);for(let e=19;e>=0;--e)n[e]=Number(t&255n),t>>=8n;return n}const m=14e8,h=f(new Uint8Array(20).fill(255)),g=/^[0-9A-Za-z]{27}$/;function _(e,t,n,r){o(n,r,e);for(let e=0;e<16;e+=1)n[r+4+e]=t[e]}function v(i,a,o=0){let c=i?.random;if(c&&c.length<16)throw new r(`RANDOM_BYTES_TOO_SHORT`,`Random bytes length must be >= 16 for KSUID`,{strategy:`ksuid`});let l,u=i===void 0?void 0:s(i,m,5694967295,`ksuid`);l=u===void 0?Math.floor(Date.now()/1e3)-m:u-m;let d=c??e();if(a){if(!t(a,o,20))throw new n(`BUFFER_OUT_OF_BOUNDS`,`KSUID byte range ${o}:${o+20-1} is out of buffer bounds`,{strategy:`ksuid`});return _(l,d,a,o),a}let p=new Uint8Array(20);return _(l,d,p,0),f(p)}function y(e){return p(e)}function b(e){if(e.length!==20)throw new n(`BYTES_INVALID_LENGTH`,`KSUID bytes must be exactly 20 bytes, got ${e.length}`,{strategy:`ksuid`});return f(e)}function x(e){let t=p(e);return(((t[0]<<24|t[1]<<16|t[2]<<8|t[3])>>>0)+m)*1e3}function S(e){return typeof e==`string`&&e.length===27&&g.test(e)&&e<=h}const C=Object.assign(v,{toBytes:y,fromBytes:b,timestamp:x,isValid:S,NIL:`000000000000000000000000000`,MAX:h});export{n as BufferError,r as InvalidInputError,i as ParseError,a as UniqueIdError,C as ksuid};
import{r as e}from"../random-Chp-Nkzi.mjs";import{n as t}from"../validation-CTNpXm94.mjs";import{BufferError as n,InvalidInputError as r,ParseError as i,UniqueIdError as a}from"../errors.mjs";import{n as o}from"../bytes-xqWxFYsM.mjs";import{t as s}from"../timestamp-DnsO0h7C.mjs";const c=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`,l=62n,u=(1n<<160n)-1n,d=new Uint8Array(65536);d.fill(255);for(let e=0;e<62;e+=1)d[c.charCodeAt(e)]=e;function f(e){if(e.length<20)throw new n(`BYTES_INVALID_LENGTH`,`KSUID bytes must be at least 20 bytes, got ${e.length}`,{strategy:`ksuid`});let t=0n;for(let n=0;n<20;n+=1)t=t<<8n|BigInt(e[n]);let r=``;for(;t>0n;){let e=t%l;t/=l,r=c[Number(e)]+r}return r.padStart(27,`0`)}function p(e){if(e.length!==27)throw new i(`INVALID_LENGTH`,`KSUID string must be 27 characters, got ${e.length}`,{strategy:`ksuid`});let t=0n;for(let n=0;n<27;n+=1){let r=d[e.charCodeAt(n)];if(r===255)throw new i(`INVALID_CHAR`,`Invalid KSUID character: ${e[n]}`,{strategy:`ksuid`});t=t*l+BigInt(r)}if(t>u)throw new i(`VALUE_OUT_OF_RANGE`,`KSUID string exceeds 160-bit range`,{strategy:`ksuid`});let n=new Uint8Array(20);for(let e=19;e>=0;--e)n[e]=Number(t&255n),t>>=8n;return n}const m=14e8,h=f(new Uint8Array(20).fill(255)),g=/^[0-9A-Za-z]{27}$/;function _(e,t,n,r){o(n,r,e);for(let e=0;e<16;e+=1)n[r+4+e]=t[e]}function v(i,a,o=0){let c=i?.random;if(c&&c.length<16)throw new r(`RANDOM_BYTES_TOO_SHORT`,`Random bytes length must be >= 16 for KSUID`,{strategy:`ksuid`});let l,u=i===void 0?void 0:s(i,m,5694967295,`ksuid`);l=u===void 0?Math.floor(Date.now()/1e3)-m:u-m;let d=c??e();if(a){if(!t(a,o,20))throw new n(`BUFFER_OUT_OF_BOUNDS`,`KSUID byte range ${o}:${o+20-1} is out of buffer bounds`,{strategy:`ksuid`});return _(l,d,a,o),a}let p=new Uint8Array(20);return _(l,d,p,0),f(p)}function y(e){return p(e)}function b(e){if(e.length!==20)throw new n(`BYTES_INVALID_LENGTH`,`KSUID bytes must be exactly 20 bytes, got ${e.length}`,{strategy:`ksuid`});return f(e)}function x(e){let t=p(e);return(((t[0]<<24|t[1]<<16|t[2]<<8|t[3])>>>0)+m)*1e3}function S(e){return typeof e==`string`&&e.length===27&&g.test(e)&&e<=h}const C=Object.assign(v,{toBytes:y,fromBytes:b,timestamp:x,isValid:S,NIL:`000000000000000000000000000`,MAX:h});export{n as BufferError,r as InvalidInputError,i as ParseError,a as UniqueIdError,C as ksuid};
//# sourceMappingURL=ksuid.mjs.map

@@ -1,1 +0,1 @@

{"version":3,"file":"ksuid.mjs","names":["KSUID_BYTES","KSUID_STRING_LEN"],"sources":["../../src/ksuid/base62.ts","../../src/ksuid/ksuid.ts"],"sourcesContent":["import { BufferError, ParseError } from '../errors'\n\n/**\n * Base62 encoding/decoding for KSUID.\n * Alphabet: 0-9A-Za-z (standard Base62 ordering)\n *\n * KSUID binary format: 20 bytes (160 bits)\n * - 4 bytes: timestamp (seconds since KSUID epoch)\n * - 16 bytes: payload (cryptographically random)\n *\n * String format: 27 characters of Base62\n */\n\n// Base62 alphabet: digits (0-9), uppercase (A-Z), lowercase (a-z)\nconst BASE62_ALPHABET = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'\nconst BASE = 62n\nconst MAX_KSUID_VALUE = (1n << 160n) - 1n\nconst KSUID_BYTES = 20\nconst KSUID_STRING_LEN = 27\n\n// Pre-computed decode table covering every UTF-16 code unit charCodeAt can\n// return, so lookups never go out of bounds and a single `=== 255` check\n// rejects invalid input (including non-ASCII) without a per-character range\n// check. Costs 64 KiB once at module load; valid inputs only touch the first\n// 128 bytes, so cache behavior is unaffected.\n// Note: Base62 is case-sensitive - 'A' (value 10) and 'a' (value 36) are different\nconst DECODING = new Uint8Array(65536)\nDECODING.fill(255) // 255 = invalid marker\n\nfor (let i = 0; i < BASE62_ALPHABET.length; i += 1) {\n DECODING[BASE62_ALPHABET.charCodeAt(i)] = i\n}\n\n/**\n * Encode a 20-byte KSUID to a 27-character Base62 string.\n *\n * Algorithm: Convert the 160-bit number to base 62 using BigInt.\n * V8 has highly optimized BigInt operations for this size.\n */\nexport function encodeBase62(bytes: Uint8Array): string {\n if (bytes.length < KSUID_BYTES) {\n throw new BufferError(\n 'BYTES_INVALID_LENGTH',\n `KSUID bytes must be at least ${KSUID_BYTES} bytes, got ${bytes.length}`,\n { strategy: 'ksuid' },\n )\n }\n\n // Convert bytes to BigInt (big-endian)\n let num = 0n\n for (let i = 0; i < KSUID_BYTES; i += 1) {\n num = (num << 8n) | BigInt(bytes[i])\n }\n\n // Convert to Base62 string (build from right to left)\n // Direct string concatenation is faster than array + join in V8\n let encoded = ''\n while (num > 0n) {\n const remainder = num % BASE\n num = num / BASE\n encoded = BASE62_ALPHABET[Number(remainder)] + encoded\n }\n\n // Pad the result with the zero-character ('0') to ensure a fixed length\n return encoded.padStart(KSUID_STRING_LEN, '0')\n}\n\n/**\n * Decode a 27-character Base62 string to a 20-byte KSUID.\n *\n * Algorithm: Convert Base62 string to BigInt, then to bytes.\n * V8 has highly optimized BigInt operations.\n */\nexport function decodeBase62(str: string): Uint8Array {\n if (str.length !== KSUID_STRING_LEN) {\n throw new ParseError('INVALID_LENGTH', `KSUID string must be ${KSUID_STRING_LEN} characters, got ${str.length}`, {\n strategy: 'ksuid',\n })\n }\n\n // Convert Base62 string to BigInt\n let num = 0n\n for (let i = 0; i < KSUID_STRING_LEN; i += 1) {\n const value = DECODING[str.charCodeAt(i)]\n if (value === 255) {\n throw new ParseError('INVALID_CHAR', `Invalid KSUID character: ${str[i]}`, { strategy: 'ksuid' })\n }\n num = num * BASE + BigInt(value)\n }\n\n if (num > MAX_KSUID_VALUE) {\n throw new ParseError('VALUE_OUT_OF_RANGE', 'KSUID string exceeds 160-bit range', { strategy: 'ksuid' })\n }\n\n // Convert BigInt to bytes (big-endian)\n const bytes = new Uint8Array(KSUID_BYTES)\n for (let i = KSUID_BYTES - 1; i >= 0; i -= 1) {\n bytes[i] = Number(num & 0xffn)\n num = num >> 8n\n }\n\n return bytes\n}\n","import { writeTimestamp32 } from '../common/bytes'\nimport { rng } from '../common/random'\nimport { resolveTimestampSecs } from '../common/timestamp'\nimport { isWritableRange } from '../common/validation'\nimport { BufferError, InvalidInputError } from '../errors'\nimport { decodeBase62, encodeBase62 } from './base62'\n\n/**\n * KSUID (K-Sortable Unique Identifier)\n *\n * A 160-bit identifier consisting of:\n * - 4 bytes: timestamp (seconds since KSUID epoch: May 13, 2014)\n * - 16 bytes: cryptographically random payload\n *\n * Encoded as a 27-character Base62 string.\n */\n\n// KSUID epoch: May 13, 2014 00:00:00 UTC (Unix timestamp in seconds)\nconst KSUID_EPOCH = 1400000000\n\nconst KSUID_BYTES = 20\nconst KSUID_STRING_LEN = 27\nconst TIMESTAMP_BYTES = 4\nconst PAYLOAD_BYTES = 16\nconst KSUID_MAX_SECS = KSUID_EPOCH + 0xffffffff\n// 2^160 - 1 in Base62 ('aWgEPTl1tmebfsQzFP4bxwgy80V'), derived from the\n// encoder so it cannot drift from the decoder's 160-bit overflow bound.\nconst KSUID_MAX_STRING = encodeBase62(new Uint8Array(KSUID_BYTES).fill(0xff))\n\n// Validation regex: 27 alphanumeric characters\n// Note: Both cases are valid Base62 characters, but they decode to different values\n// (e.g., 'A' = 10, 'a' = 36). The regex validates format, not semantic equivalence.\nconst KSUID_REGEX = /^[0-9A-Za-z]{27}$/\n\nexport type KsuidOptions = {\n /**\n * 16 bytes of random data to use for KSUID payload.\n */\n random?: Uint8Array\n /**\n * Timestamp in milliseconds since the Unix epoch.\n * Defaults to Date.now().\n * KSUID stores whole seconds, so sub-second precision is truncated.\n */\n msecs?: number\n /**\n * Timestamp in seconds since the Unix epoch.\n *\n * @deprecated Use `msecs` instead. Will be removed at v1-rc.\n */\n // TODO(v1-rc): remove this alias (tracked in docs/STABILITY.md).\n secs?: number\n}\n\nexport type Ksuid = {\n /** Generate a time-ordered KSUID string. */\n (): string\n /** Generate a KSUID with explicit options or write its 20 canonical bytes into a caller-owned buffer. */\n <TBuf extends Uint8Array = Uint8Array>(options: KsuidOptions | undefined, buf: TBuf, offset?: number): TBuf\n /** Generate a KSUID string with optional timestamp or random payload bytes. */\n (options?: KsuidOptions, buf?: undefined, offset?: number): string\n /** Convert a KSUID string to its canonical 20-byte representation. */\n toBytes(id: string): Uint8Array\n /** Convert 20 canonical KSUID bytes to a KSUID string. */\n fromBytes(bytes: Uint8Array): string\n /** Read the embedded Unix timestamp in milliseconds. */\n timestamp(id: string): number\n /** Return whether a value is a syntactically valid KSUID string. */\n isValid(id: unknown): id is string\n /** The nil KSUID (all zeros) */\n NIL: string\n /** The max KSUID (maximum valid value) */\n MAX: string\n}\n\n/**\n * Write already-validated KSUID fields to a buffer.\n */\nfunction writeKsuidBytesUnchecked(timestamp: number, payload: Uint8Array, buf: Uint8Array, offset: number): void {\n // Timestamp (32-bit big-endian seconds since KSUID epoch) -> bytes 0-3\n writeTimestamp32(buf, offset, timestamp)\n\n // Payload (128 bits) -> bytes 4-19\n for (let i = 0; i < PAYLOAD_BYTES; i += 1) {\n buf[offset + TIMESTAMP_BYTES + i] = payload[i]\n }\n}\n\n/*\n * Overload: no buffer => return a KSUID string.\n */\nfunction ksuidFn(options?: KsuidOptions, buf?: undefined, offset?: number): string\n/*\n * Overload: caller provides a buffer slice to fill with KSUID bytes.\n */\nfunction ksuidFn<TBuf extends Uint8Array = Uint8Array>(\n options: KsuidOptions | undefined,\n buf: TBuf,\n offset?: number,\n): TBuf\nfunction ksuidFn<TBuf extends Uint8Array = Uint8Array>(options?: KsuidOptions, buf?: TBuf, offset = 0): string | TBuf {\n const random = options?.random\n if (random && random.length < PAYLOAD_BYTES) {\n throw new InvalidInputError('RANDOM_BYTES_TOO_SHORT', 'Random bytes length must be >= 16 for KSUID', {\n strategy: 'ksuid',\n })\n }\n\n let timestamp: number\n const secs = options === undefined ? undefined : resolveTimestampSecs(options, KSUID_EPOCH, KSUID_MAX_SECS, 'ksuid')\n if (secs !== undefined) {\n timestamp = secs - KSUID_EPOCH\n } else {\n /**\n * Note: by default, Cloudflare Workers \"freezes\" time during request handling to prevent\n * side-channel attacks. This means that Date.now() will return the same value for the entire\n * duration of a request.\n * Implications:\n * - all KSUIDs generated within a single request will have the same timestamp.\n */\n timestamp = Math.floor(Date.now() / 1000) - KSUID_EPOCH\n }\n\n const payload = random ?? rng()\n\n if (buf) {\n if (!isWritableRange(buf, offset, KSUID_BYTES)) {\n throw new BufferError(\n 'BUFFER_OUT_OF_BOUNDS',\n `KSUID byte range ${offset}:${offset + KSUID_BYTES - 1} is out of buffer bounds`,\n { strategy: 'ksuid' },\n )\n }\n writeKsuidBytesUnchecked(timestamp, payload, buf, offset)\n return buf\n }\n\n const bytes = new Uint8Array(KSUID_BYTES)\n writeKsuidBytesUnchecked(timestamp, payload, bytes, 0)\n\n // String mode: create bytes then encode to Base62\n return encodeBase62(bytes)\n}\n\n/**\n * Convert a KSUID string to 20 bytes.\n *\n * Note: Base62 is case-sensitive. 'A' (value 10) and 'a' (value 36) decode\n * to different byte values. This function accepts both cases as valid input.\n */\nfunction toBytes(id: string): Uint8Array {\n return decodeBase62(id)\n}\n\n/**\n * Convert 20 bytes to a KSUID string.\n */\nfunction fromBytes(bytes: Uint8Array): string {\n if (bytes.length !== KSUID_BYTES) {\n throw new BufferError(\n 'BYTES_INVALID_LENGTH',\n `KSUID bytes must be exactly ${KSUID_BYTES} bytes, got ${bytes.length}`,\n { strategy: 'ksuid' },\n )\n }\n return encodeBase62(bytes)\n}\n\n/**\n * Extract the timestamp from a KSUID string.\n * Returns Unix timestamp in milliseconds for API consistency with ulid/uuidv7.\n * Note: KSUID only has second precision, so the returned value will always end in 000.\n */\nfunction timestamp(id: string): number {\n const bytes = decodeBase62(id)\n // First 4 bytes are big-endian timestamp (seconds since KSUID epoch)\n const secs = ((bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]) >>> 0\n // Add KSUID epoch and convert to milliseconds\n return (secs + KSUID_EPOCH) * 1000\n}\n\n/**\n * Validate a KSUID string format and 160-bit numeric range.\n */\nfunction isValid(id: unknown): id is string {\n return (\n typeof id === 'string' &&\n id.length === KSUID_STRING_LEN &&\n KSUID_REGEX.test(id) &&\n // Fixed-length Base62 strings preserve numeric order because the alphabet is ASCII-sorted.\n id <= KSUID_MAX_STRING\n )\n}\n\n/**\n * Generate a KSUID string or write the bytes into a buffer.\n * Also includes helpers to convert to and from byte arrays.\n */\nexport const ksuid: Ksuid = Object.assign(ksuidFn, {\n toBytes,\n fromBytes,\n timestamp,\n isValid,\n NIL: '000000000000000000000000000',\n MAX: KSUID_MAX_STRING,\n})\n\nexport { BufferError, InvalidInputError, ParseError, UniqueIdError } from '../errors'\n"],"mappings":"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"}
{"version":3,"file":"ksuid.mjs","names":["KSUID_BYTES","KSUID_STRING_LEN"],"sources":["../../src/ksuid/base62.ts","../../src/ksuid/ksuid.ts"],"sourcesContent":["import { BufferError, ParseError } from '../errors'\n\n/**\n * Base62 encoding/decoding for KSUID.\n * Alphabet: 0-9A-Za-z (standard Base62 ordering)\n *\n * KSUID binary format: 20 bytes (160 bits)\n * - 4 bytes: timestamp (seconds since KSUID epoch)\n * - 16 bytes: payload (cryptographically random)\n *\n * String format: 27 characters of Base62\n */\n\n// Base62 alphabet: digits (0-9), uppercase (A-Z), lowercase (a-z)\nconst BASE62_ALPHABET = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'\nconst BASE = 62n\nconst MAX_KSUID_VALUE = (1n << 160n) - 1n\nconst KSUID_BYTES = 20\nconst KSUID_STRING_LEN = 27\n\n// Pre-computed decode table covering every UTF-16 code unit charCodeAt can\n// return, so lookups never go out of bounds and a single `=== 255` check\n// rejects invalid input (including non-ASCII) without a per-character range\n// check. Costs 64 KiB once at module load; valid inputs only touch the first\n// 128 bytes, so cache behavior is unaffected.\n// Note: Base62 is case-sensitive - 'A' (value 10) and 'a' (value 36) are different\nconst DECODING = new Uint8Array(65536)\nDECODING.fill(255) // 255 = invalid marker\n\nfor (let i = 0; i < BASE62_ALPHABET.length; i += 1) {\n DECODING[BASE62_ALPHABET.charCodeAt(i)] = i\n}\n\n/**\n * Encode a 20-byte KSUID to a 27-character Base62 string.\n *\n * Algorithm: Convert the 160-bit number to base 62 using BigInt.\n * V8 has highly optimized BigInt operations for this size.\n */\nexport function encodeBase62(bytes: Uint8Array): string {\n if (bytes.length < KSUID_BYTES) {\n throw new BufferError(\n 'BYTES_INVALID_LENGTH',\n `KSUID bytes must be at least ${KSUID_BYTES} bytes, got ${bytes.length}`,\n { strategy: 'ksuid' },\n )\n }\n\n // Convert bytes to BigInt (big-endian)\n let num = 0n\n for (let i = 0; i < KSUID_BYTES; i += 1) {\n num = (num << 8n) | BigInt(bytes[i])\n }\n\n // Convert to Base62 string (build from right to left)\n // Direct string concatenation is faster than array + join in V8\n let encoded = ''\n while (num > 0n) {\n const remainder = num % BASE\n num = num / BASE\n encoded = BASE62_ALPHABET[Number(remainder)] + encoded\n }\n\n // Pad the result with the zero-character ('0') to ensure a fixed length\n return encoded.padStart(KSUID_STRING_LEN, '0')\n}\n\n/**\n * Decode a 27-character Base62 string to a 20-byte KSUID.\n *\n * Algorithm: Convert Base62 string to BigInt, then to bytes.\n * V8 has highly optimized BigInt operations.\n */\nexport function decodeBase62(str: string): Uint8Array {\n if (str.length !== KSUID_STRING_LEN) {\n throw new ParseError('INVALID_LENGTH', `KSUID string must be ${KSUID_STRING_LEN} characters, got ${str.length}`, {\n strategy: 'ksuid',\n })\n }\n\n // Convert Base62 string to BigInt\n let num = 0n\n for (let i = 0; i < KSUID_STRING_LEN; i += 1) {\n const value = DECODING[str.charCodeAt(i)]\n if (value === 255) {\n throw new ParseError('INVALID_CHAR', `Invalid KSUID character: ${str[i]}`, { strategy: 'ksuid' })\n }\n num = num * BASE + BigInt(value)\n }\n\n if (num > MAX_KSUID_VALUE) {\n throw new ParseError('VALUE_OUT_OF_RANGE', 'KSUID string exceeds 160-bit range', { strategy: 'ksuid' })\n }\n\n // Convert BigInt to bytes (big-endian)\n const bytes = new Uint8Array(KSUID_BYTES)\n for (let i = KSUID_BYTES - 1; i >= 0; i -= 1) {\n bytes[i] = Number(num & 0xffn)\n num = num >> 8n\n }\n\n return bytes\n}\n","import { writeTimestamp32 } from '../common/bytes'\nimport { rng } from '../common/random'\nimport { resolveTimestampSecs } from '../common/timestamp'\nimport { isWritableRange } from '../common/validation'\nimport { BufferError, InvalidInputError } from '../errors'\nimport { decodeBase62, encodeBase62 } from './base62'\n\n/**\n * KSUID (K-Sortable Unique Identifier)\n *\n * A 160-bit identifier consisting of:\n * - 4 bytes: timestamp (seconds since KSUID epoch: May 13, 2014)\n * - 16 bytes: cryptographically random payload\n *\n * Encoded as a 27-character Base62 string.\n */\n\n// KSUID epoch: May 13, 2014 00:00:00 UTC (Unix timestamp in seconds)\nconst KSUID_EPOCH = 1400000000\n\nconst KSUID_BYTES = 20\nconst KSUID_STRING_LEN = 27\nconst TIMESTAMP_BYTES = 4\nconst PAYLOAD_BYTES = 16\nconst KSUID_MAX_SECS = KSUID_EPOCH + 0xffffffff\n// 2^160 - 1 in Base62 ('aWgEPTl1tmebfsQzFP4bxwgy80V'), derived from the\n// encoder so it cannot drift from the decoder's 160-bit overflow bound.\nconst KSUID_MAX_STRING = encodeBase62(new Uint8Array(KSUID_BYTES).fill(0xff))\n\n// Validation regex: 27 alphanumeric characters\n// Note: Both cases are valid Base62 characters, but they decode to different values\n// (e.g., 'A' = 10, 'a' = 36). The regex validates format, not semantic equivalence.\nconst KSUID_REGEX = /^[0-9A-Za-z]{27}$/\n\nexport type KsuidOptions = {\n /**\n * 16 bytes of random data to use for KSUID payload.\n */\n random?: Uint8Array\n /**\n * Timestamp in milliseconds since the Unix epoch.\n * Defaults to Date.now().\n * KSUID stores whole seconds, so sub-second precision is truncated.\n */\n msecs?: number\n}\n\nexport type Ksuid = {\n /** Generate a time-ordered KSUID string. */\n (): string\n /** Generate a KSUID with explicit options or write its 20 canonical bytes into a caller-owned buffer. */\n <TBuf extends Uint8Array = Uint8Array>(options: KsuidOptions | undefined, buf: TBuf, offset?: number): TBuf\n /** Generate a KSUID string with optional timestamp or random payload bytes. */\n (options?: KsuidOptions, buf?: undefined, offset?: number): string\n /** Convert a KSUID string to its canonical 20-byte representation. */\n toBytes(id: string): Uint8Array\n /** Convert 20 canonical KSUID bytes to a KSUID string. */\n fromBytes(bytes: Uint8Array): string\n /** Read the embedded Unix timestamp in milliseconds. */\n timestamp(id: string): number\n /** Return whether a value is a syntactically valid KSUID string. */\n isValid(id: unknown): id is string\n /** The nil KSUID (all zeros) */\n NIL: string\n /** The max KSUID (maximum valid value) */\n MAX: string\n}\n\n/**\n * Write already-validated KSUID fields to a buffer.\n */\nfunction writeKsuidBytesUnchecked(timestamp: number, payload: Uint8Array, buf: Uint8Array, offset: number): void {\n // Timestamp (32-bit big-endian seconds since KSUID epoch) -> bytes 0-3\n writeTimestamp32(buf, offset, timestamp)\n\n // Payload (128 bits) -> bytes 4-19\n for (let i = 0; i < PAYLOAD_BYTES; i += 1) {\n buf[offset + TIMESTAMP_BYTES + i] = payload[i]\n }\n}\n\n/*\n * Overload: no buffer => return a KSUID string.\n */\nfunction ksuidFn(options?: KsuidOptions, buf?: undefined, offset?: number): string\n/*\n * Overload: caller provides a buffer slice to fill with KSUID bytes.\n */\nfunction ksuidFn<TBuf extends Uint8Array = Uint8Array>(\n options: KsuidOptions | undefined,\n buf: TBuf,\n offset?: number,\n): TBuf\nfunction ksuidFn<TBuf extends Uint8Array = Uint8Array>(options?: KsuidOptions, buf?: TBuf, offset = 0): string | TBuf {\n const random = options?.random\n if (random && random.length < PAYLOAD_BYTES) {\n throw new InvalidInputError('RANDOM_BYTES_TOO_SHORT', 'Random bytes length must be >= 16 for KSUID', {\n strategy: 'ksuid',\n })\n }\n\n let timestamp: number\n const secs = options === undefined ? undefined : resolveTimestampSecs(options, KSUID_EPOCH, KSUID_MAX_SECS, 'ksuid')\n if (secs !== undefined) {\n timestamp = secs - KSUID_EPOCH\n } else {\n /**\n * Note: by default, Cloudflare Workers \"freezes\" time during request handling to prevent\n * side-channel attacks. This means that Date.now() will return the same value for the entire\n * duration of a request.\n * Implications:\n * - all KSUIDs generated within a single request will have the same timestamp.\n */\n timestamp = Math.floor(Date.now() / 1000) - KSUID_EPOCH\n }\n\n const payload = random ?? rng()\n\n if (buf) {\n if (!isWritableRange(buf, offset, KSUID_BYTES)) {\n throw new BufferError(\n 'BUFFER_OUT_OF_BOUNDS',\n `KSUID byte range ${offset}:${offset + KSUID_BYTES - 1} is out of buffer bounds`,\n { strategy: 'ksuid' },\n )\n }\n writeKsuidBytesUnchecked(timestamp, payload, buf, offset)\n return buf\n }\n\n const bytes = new Uint8Array(KSUID_BYTES)\n writeKsuidBytesUnchecked(timestamp, payload, bytes, 0)\n\n // String mode: create bytes then encode to Base62\n return encodeBase62(bytes)\n}\n\n/**\n * Convert a KSUID string to 20 bytes.\n *\n * Note: Base62 is case-sensitive. 'A' (value 10) and 'a' (value 36) decode\n * to different byte values. This function accepts both cases as valid input.\n */\nfunction toBytes(id: string): Uint8Array {\n return decodeBase62(id)\n}\n\n/**\n * Convert 20 bytes to a KSUID string.\n */\nfunction fromBytes(bytes: Uint8Array): string {\n if (bytes.length !== KSUID_BYTES) {\n throw new BufferError(\n 'BYTES_INVALID_LENGTH',\n `KSUID bytes must be exactly ${KSUID_BYTES} bytes, got ${bytes.length}`,\n { strategy: 'ksuid' },\n )\n }\n return encodeBase62(bytes)\n}\n\n/**\n * Extract the timestamp from a KSUID string.\n * Returns Unix timestamp in milliseconds for API consistency with ulid/uuidv7.\n * Note: KSUID only has second precision, so the returned value will always end in 000.\n */\nfunction timestamp(id: string): number {\n const bytes = decodeBase62(id)\n // First 4 bytes are big-endian timestamp (seconds since KSUID epoch)\n const secs = ((bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]) >>> 0\n // Add KSUID epoch and convert to milliseconds\n return (secs + KSUID_EPOCH) * 1000\n}\n\n/**\n * Validate a KSUID string format and 160-bit numeric range.\n */\nfunction isValid(id: unknown): id is string {\n return (\n typeof id === 'string' &&\n id.length === KSUID_STRING_LEN &&\n KSUID_REGEX.test(id) &&\n // Fixed-length Base62 strings preserve numeric order because the alphabet is ASCII-sorted.\n id <= KSUID_MAX_STRING\n )\n}\n\n/**\n * Generate a KSUID string or write the bytes into a buffer.\n * Also includes helpers to convert to and from byte arrays.\n */\nexport const ksuid: Ksuid = Object.assign(ksuidFn, {\n toBytes,\n fromBytes,\n timestamp,\n isValid,\n NIL: '000000000000000000000000000',\n MAX: KSUID_MAX_STRING,\n})\n\nexport { BufferError, InvalidInputError, ParseError, UniqueIdError } from '../errors'\n"],"mappings":"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"}

@@ -1,2 +0,2 @@

import { i as InvalidInputError, o as UniqueIdError } from "../errors-Da-8dh4J.mjs";
import { InvalidInputError, UniqueIdError } from "../errors.mjs";

@@ -22,8 +22,2 @@ //#region src/nanoid/nanoid.d.ts

length?: number;
/**
* Length of generated ID.
*
* @deprecated Use `length` instead. Will be removed at v1-rc.
*/
size?: number;
};

@@ -30,0 +24,0 @@ type Nanoid = {

@@ -1,1 +0,1 @@

{"version":3,"file":"nanoid.d.mts","names":[],"sources":["../../src/nanoid/nanoid.ts"],"mappings":";;;;cAGa,YAAA;AAAA,KAqCD,aAAA;EArCZ;;;;AAAa;EA2CX,MAAA,GAAS,UAAA;EANC;;;;EAWV,QAAA;;;;EAIA,MAAA;EAOA;AAGF;;;;EAHE,IAAA;AAAA;AAAA,KAGU,MAAA;;GAIT,IAAA,mBAOqB;EAAA,CALrB,OAAA,EAAS,aAAA;EA8MS;;;AAAA;EAzMnB,OAAA,CAAQ,EAAA,YAAc,EAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAyMX,MAAA,EAAQ,MAAA"}
{"version":3,"file":"nanoid.d.mts","names":[],"sources":["../../src/nanoid/nanoid.ts"],"mappings":";;;;cAGa,YAAA;AAAA,KAqCD,aAAA;EArCZ;;;;AAAa;EA2CX,MAAA,GAAS,UAAA;EANC;;;;EAWV,QAAA;;;;EAIA,MAAA;AAAA;AAAA,KAGU,MAAA;;GAIT,IAAA;GAEA,OAAA,EAAS,aAAA;;;;AAKY;EAAtB,OAAA,CAAQ,EAAA,YAAc,EAAA;AAAA;;;AAoMH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAAR,MAAA,EAAQ,MAAA"}

@@ -1,2 +0,2 @@

import{InvalidInputError as e,UniqueIdError as t}from"../errors.mjs";const n=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-`,r=2048,i=/^[A-Za-z0-9_-]+$/,a=new TextDecoder;let o,s=``,c=0;function l(e){let t=Math.min(e*128,65536);if((!o||o.length<t)&&(o=new Uint8Array(t)),c+e>s.length){crypto.getRandomValues(o);for(let e=0;e<o.length;e++)o[e]=n.charCodeAt(o[e]&63);s=a.decode(o),c=0}}function u(e){l(e);let t=s.substring(c,c+e);return c+=e,t}function d(t){if(t.length<2)throw new e(`ALPHABET_OUT_OF_RANGE`,`Alphabet must contain at least 2 characters`,{strategy:`nanoid`});if(t.length>256)throw new e(`ALPHABET_OUT_OF_RANGE`,`Alphabet must not exceed 256 characters`,{strategy:`nanoid`});let n=new Set;for(let r of t){let t=r.charCodeAt(0);if(t<32||t>126)throw new e(`ALPHABET_INVALID_CHAR`,`Alphabet must contain only printable ASCII characters (32-126)`,{strategy:`nanoid`});if(n.has(r))throw new e(`ALPHABET_DUPLICATE`,`Duplicate character in alphabet: "${r}"`,{strategy:`nanoid`});n.add(r)}}function f(t){if(!Number.isInteger(t)||t<0)throw new e(`LENGTH_OUT_OF_RANGE`,`Length must be a non-negative integer`,{strategy:`nanoid`});if(t>r)throw new e(`LENGTH_OUT_OF_RANGE`,`Length must not exceed ${r}`,{strategy:`nanoid`})}function p(t){if(t===void 0)return u(21);let r=21,i=n,a;if(typeof t==`number`)r=t;else{if(t.length!==void 0&&t.size!==void 0)throw new e(`CONFLICTING_OPTIONS`,"Pass only one of `length` or `size`, not both",{strategy:`nanoid`});r=t.length??t.size??21,i=t.alphabet??`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-`,a=t.random,t.alphabet!==void 0&&d(i)}if(f(r),r===0)return``;if(i===`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-`&&a===void 0)return u(r);let o=i.length;if(!(o&o-1)){let t=o-1;if(a&&a.length<r)throw new e(`RANDOM_BYTES_TOO_SHORT`,`Insufficient random bytes: need ${r}, have ${a.length}`,{strategy:`nanoid`});let n=a?.subarray(0,r)??globalThis.crypto.getRandomValues(new Uint8Array(r)),s=``;for(let e=0;e<r;e++)s+=i[n[e]&t];return s}let s=(2<<31-Math.clz32(o-1|1))-1,c=Math.ceil(1.6*s*r/o),l=``,p=0;for(;l.length<r;){let t;if(a){if(a.length-p<c)throw new e(`RANDOM_BYTES_TOO_SHORT`,`Insufficient random bytes: need at least ${c} more, have ${a.length-p}`,{strategy:`nanoid`});t=a.subarray(p,p+c),p+=c}else t=globalThis.crypto.getRandomValues(new Uint8Array(c));for(let e=0;e<t.length&&l.length<r;e++){let n=t[e]&s;n<o&&(l+=i[n])}}return l}function m(e){return typeof e==`string`&&e.length>0&&i.test(e)}const h=Object.assign(p,{isValid:m});export{e as InvalidInputError,n as URL_ALPHABET,t as UniqueIdError,h as nanoid};
import{InvalidInputError as e,UniqueIdError as t}from"../errors.mjs";const n=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-`,r=2048,i=/^[A-Za-z0-9_-]+$/,a=new TextDecoder;let o,s=``,c=0;function l(e){let t=Math.min(e*128,65536);if((!o||o.length<t)&&(o=new Uint8Array(t)),c+e>s.length){crypto.getRandomValues(o);for(let e=0;e<o.length;e++)o[e]=n.charCodeAt(o[e]&63);s=a.decode(o),c=0}}function u(e){l(e);let t=s.substring(c,c+e);return c+=e,t}function d(t){if(t.length<2)throw new e(`ALPHABET_OUT_OF_RANGE`,`Alphabet must contain at least 2 characters`,{strategy:`nanoid`});if(t.length>256)throw new e(`ALPHABET_OUT_OF_RANGE`,`Alphabet must not exceed 256 characters`,{strategy:`nanoid`});let n=new Set;for(let r of t){let t=r.charCodeAt(0);if(t<32||t>126)throw new e(`ALPHABET_INVALID_CHAR`,`Alphabet must contain only printable ASCII characters (32-126)`,{strategy:`nanoid`});if(n.has(r))throw new e(`ALPHABET_DUPLICATE`,`Duplicate character in alphabet: "${r}"`,{strategy:`nanoid`});n.add(r)}}function f(t){if(!Number.isInteger(t)||t<0)throw new e(`LENGTH_OUT_OF_RANGE`,`Length must be a non-negative integer`,{strategy:`nanoid`});if(t>r)throw new e(`LENGTH_OUT_OF_RANGE`,`Length must not exceed ${r}`,{strategy:`nanoid`})}function p(t){if(t===void 0)return u(21);let r=21,i=n,a;if(typeof t==`number`?r=t:(r=t.length??21,i=t.alphabet??`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-`,a=t.random,t.alphabet!==void 0&&d(i)),f(r),r===0)return``;if(i===`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-`&&a===void 0)return u(r);let o=i.length;if(!(o&o-1)){let t=o-1;if(a&&a.length<r)throw new e(`RANDOM_BYTES_TOO_SHORT`,`Insufficient random bytes: need ${r}, have ${a.length}`,{strategy:`nanoid`});let n=a?.subarray(0,r)??globalThis.crypto.getRandomValues(new Uint8Array(r)),s=``;for(let e=0;e<r;e++)s+=i[n[e]&t];return s}let s=(2<<31-Math.clz32(o-1|1))-1,c=Math.ceil(1.6*s*r/o),l=``,p=0;for(;l.length<r;){let t;if(a){if(a.length-p<c)throw new e(`RANDOM_BYTES_TOO_SHORT`,`Insufficient random bytes: need at least ${c} more, have ${a.length-p}`,{strategy:`nanoid`});t=a.subarray(p,p+c),p+=c}else t=globalThis.crypto.getRandomValues(new Uint8Array(c));for(let e=0;e<t.length&&l.length<r;e++){let n=t[e]&s;n<o&&(l+=i[n])}}return l}function m(e){return typeof e==`string`&&e.length>0&&i.test(e)}const h=Object.assign(p,{isValid:m});export{e as InvalidInputError,n as URL_ALPHABET,t as UniqueIdError,h as nanoid};
//# sourceMappingURL=nanoid.mjs.map

@@ -1,1 +0,1 @@

{"version":3,"file":"nanoid.mjs","names":[],"sources":["../../src/nanoid/nanoid.ts"],"sourcesContent":["import { InvalidInputError } from '../errors'\n\n/** Default URL-safe alphabet (64 characters): A-Z, a-z, 0-9, underscore, hyphen */\nexport const URL_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-'\n\nconst DEFAULT_SIZE = 21\nconst MAX_SIZE = 2048\nconst NANOID_REGEX = /^[A-Za-z0-9_-]+$/\n\n// Keep Nanoid's private pool for its default hot path. Translate random bytes\n// into URL-safe ASCII once per refill, then serve IDs as sequential substrings.\nconst POOL_SIZE_MULTIPLIER = 128\nconst MAX_POOL_SIZE = 65_536\nconst ASCII_DECODER = new TextDecoder()\nlet poolBytes: Uint8Array | undefined\nlet characterPool = ''\nlet poolOffset = 0\n\nfunction fillPool(bytes: number): void {\n const size = Math.min(bytes * POOL_SIZE_MULTIPLIER, MAX_POOL_SIZE)\n if (!poolBytes || poolBytes.length < size) {\n poolBytes = new Uint8Array(size)\n }\n if (poolOffset + bytes > characterPool.length) {\n crypto.getRandomValues(poolBytes)\n for (let i = 0; i < poolBytes.length; i++) {\n poolBytes[i] = URL_ALPHABET.charCodeAt(poolBytes[i] & 63)\n }\n characterPool = ASCII_DECODER.decode(poolBytes)\n poolOffset = 0\n }\n}\n\nfunction defaultAlphabetFromPool(size: number): string {\n fillPool(size)\n const id = characterPool.substring(poolOffset, poolOffset + size)\n poolOffset += size\n return id\n}\n\nexport type NanoidOptions = {\n /**\n * Random bytes for deterministic output (testing).\n * For power-of-2 alphabets (2, 4, 8, 16, 32, 64, 128, 256): exactly `length` bytes needed.\n * For other alphabets: ~length * 2 bytes needed (rejection sampling).\n */\n random?: Uint8Array\n /**\n * Custom alphabet to use. Default: URL-safe A-Za-z0-9_-\n * Must be 2-256 printable ASCII characters (32-126) with no duplicates.\n */\n alphabet?: string\n /**\n * Length of generated ID. Default: 21. Maximum: 2048.\n */\n length?: number\n /**\n * Length of generated ID.\n *\n * @deprecated Use `length` instead. Will be removed at v1-rc.\n */\n // TODO(v1-rc): remove this alias (tracked in docs/STABILITY.md).\n size?: number\n}\n\nexport type Nanoid = {\n /** Generate a Nanoid with the default URL-safe alphabet and 21-character length. */\n (): string\n /** Generate a Nanoid with the default alphabet and a custom length. */\n (size: number): string\n /** Generate a Nanoid with a custom alphabet, length, or deterministic random bytes. */\n (options: NanoidOptions): string\n /**\n * Validate a nanoid string against the default URL-safe alphabet.\n * Note: Does not validate IDs generated with custom alphabets.\n */\n isValid(id: unknown): id is string\n}\n\n/**\n * Validate alphabet: 2-256 printable ASCII chars, no duplicates\n */\nfunction validateAlphabet(alphabet: string): void {\n if (alphabet.length < 2) {\n throw new InvalidInputError('ALPHABET_OUT_OF_RANGE', 'Alphabet must contain at least 2 characters', {\n strategy: 'nanoid',\n })\n }\n if (alphabet.length > 256) {\n throw new InvalidInputError('ALPHABET_OUT_OF_RANGE', 'Alphabet must not exceed 256 characters', {\n strategy: 'nanoid',\n })\n }\n const seen = new Set<string>()\n for (const char of alphabet) {\n const code = char.charCodeAt(0)\n if (code < 32 || code > 126) {\n throw new InvalidInputError(\n 'ALPHABET_INVALID_CHAR',\n 'Alphabet must contain only printable ASCII characters (32-126)',\n {\n strategy: 'nanoid',\n },\n )\n }\n if (seen.has(char)) {\n throw new InvalidInputError('ALPHABET_DUPLICATE', `Duplicate character in alphabet: \"${char}\"`, {\n strategy: 'nanoid',\n })\n }\n seen.add(char)\n }\n}\n\n/**\n * Validate length parameter\n */\nfunction validateLength(size: number): void {\n if (!Number.isInteger(size) || size < 0) {\n throw new InvalidInputError('LENGTH_OUT_OF_RANGE', 'Length must be a non-negative integer', { strategy: 'nanoid' })\n }\n if (size > MAX_SIZE) {\n throw new InvalidInputError('LENGTH_OUT_OF_RANGE', `Length must not exceed ${MAX_SIZE}`, { strategy: 'nanoid' })\n }\n}\n\n// Overloads\nfunction nanoidFn(): string\nfunction nanoidFn(size: number): string\nfunction nanoidFn(options: NanoidOptions): string\nfunction nanoidFn(sizeOrOptions?: number | NanoidOptions): string {\n // ULTRA-FAST PATH: No arguments = default nanoid\n // Uses simple pooled random bytes (npm nanoid style) for best performance\n if (sizeOrOptions === undefined) {\n return defaultAlphabetFromPool(DEFAULT_SIZE)\n }\n\n let size = DEFAULT_SIZE\n let alphabet = URL_ALPHABET\n let randomBytes: Uint8Array | undefined\n\n if (typeof sizeOrOptions === 'number') {\n size = sizeOrOptions\n } else {\n if (sizeOrOptions.length !== undefined && sizeOrOptions.size !== undefined) {\n throw new InvalidInputError('CONFLICTING_OPTIONS', 'Pass only one of `length` or `size`, not both', {\n strategy: 'nanoid',\n })\n }\n size = sizeOrOptions.length ?? sizeOrOptions.size ?? DEFAULT_SIZE\n alphabet = sizeOrOptions.alphabet ?? URL_ALPHABET\n randomBytes = sizeOrOptions.random\n if (sizeOrOptions.alphabet !== undefined) {\n validateAlphabet(alphabet)\n }\n }\n\n validateLength(size)\n\n if (size === 0) return ''\n\n if (alphabet === URL_ALPHABET && randomBytes === undefined) {\n return defaultAlphabetFromPool(size)\n }\n\n const alphabetLen = alphabet.length\n\n // FAST PATH: Power-of-2 alphabet (includes default 64-char)\n // No rejection needed - each byte maps directly to a character\n if ((alphabetLen & (alphabetLen - 1)) === 0) {\n const mask = alphabetLen - 1\n if (randomBytes && randomBytes.length < size) {\n throw new InvalidInputError(\n 'RANDOM_BYTES_TOO_SHORT',\n `Insufficient random bytes: need ${size}, have ${randomBytes.length}`,\n { strategy: 'nanoid' },\n )\n }\n const bytes = randomBytes?.subarray(0, size) ?? globalThis.crypto.getRandomValues(new Uint8Array(size))\n let id = ''\n for (let i = 0; i < size; i++) {\n id += alphabet[bytes[i] & mask]\n }\n return id\n }\n\n // SLOW PATH: Rejection sampling for non-power-of-2 alphabets\n // Calculate mask: smallest power-of-2 minus 1 that covers alphabet size\n const mask = (2 << (31 - Math.clz32((alphabetLen - 1) | 1))) - 1\n // Calculate step: random bytes per batch (1.6x accounts for rejection)\n const step = Math.ceil((1.6 * mask * size) / alphabetLen)\n\n let id = ''\n let randomOffset = 0\n\n while (id.length < size) {\n let bytes: Uint8Array\n if (randomBytes) {\n if (randomBytes.length - randomOffset < step) {\n throw new InvalidInputError(\n 'RANDOM_BYTES_TOO_SHORT',\n `Insufficient random bytes: need at least ${step} more, have ${randomBytes.length - randomOffset}`,\n { strategy: 'nanoid' },\n )\n }\n bytes = randomBytes.subarray(randomOffset, randomOffset + step)\n randomOffset += step\n } else {\n bytes = globalThis.crypto.getRandomValues(new Uint8Array(step))\n }\n\n for (let i = 0; i < bytes.length && id.length < size; i++) {\n const index = bytes[i] & mask\n if (index < alphabetLen) {\n id += alphabet[index]\n }\n // Otherwise reject and continue (no modulo bias)\n }\n }\n\n return id\n}\n\n/**\n * Validate a nanoid string against the default URL-safe alphabet.\n * Note: Does not validate IDs generated with custom alphabets.\n */\nfunction isValid(id: unknown): id is string {\n return typeof id === 'string' && id.length > 0 && NANOID_REGEX.test(id)\n}\n\n/**\n * Generate a URL-friendly unique string ID.\n *\n * Nanoid is a tiny, secure, URL-friendly unique string ID generator.\n * It uses a URL-safe alphabet (A-Za-z0-9_-) and generates 21-character\n * IDs by default with 126 bits of entropy.\n *\n * Unlike UUID v7 or ULID, nanoid is NOT time-ordered. Use it for:\n * - URL shorteners\n * - Session tokens\n * - Invite codes\n * - Any case where you need short, random IDs\n *\n * @example Basic usage\n * ```ts\n * import { nanoid } from 'uniku/nanoid'\n *\n * const id = nanoid()\n * // => \"V1StGXR8_Z5jdHi6B-myT\"\n * ```\n *\n * @example Custom length\n * ```ts\n * const shortId = nanoid(10)\n * // => \"IRFa-VaY2b\"\n * ```\n *\n * @example Custom alphabet (hex)\n * ```ts\n * const hexId = nanoid({ alphabet: '0123456789abcdef', length: 12 })\n * // => \"4f90d13a42bc\"\n * ```\n *\n * @example Validation\n * ```ts\n * const maybeId: unknown = getUserInput()\n * if (nanoid.isValid(maybeId)) {\n * // TypeScript knows maybeId is string\n * console.log(maybeId.length)\n * }\n * ```\n *\n * @throws {InvalidInputError} Length must be between 0 and 2048\n * @throws {InvalidInputError} Alphabet must contain 2-256 unique printable ASCII characters\n * @throws {InvalidInputError} Insufficient random bytes for requested length\n */\nexport const nanoid: Nanoid = Object.assign(nanoidFn, {\n isValid,\n})\n\nexport { InvalidInputError, UniqueIdError } from '../errors'\n"],"mappings":"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"}
{"version":3,"file":"nanoid.mjs","names":[],"sources":["../../src/nanoid/nanoid.ts"],"sourcesContent":["import { InvalidInputError } from '../errors'\n\n/** Default URL-safe alphabet (64 characters): A-Z, a-z, 0-9, underscore, hyphen */\nexport const URL_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-'\n\nconst DEFAULT_SIZE = 21\nconst MAX_SIZE = 2048\nconst NANOID_REGEX = /^[A-Za-z0-9_-]+$/\n\n// Keep Nanoid's private pool for its default hot path. Translate random bytes\n// into URL-safe ASCII once per refill, then serve IDs as sequential substrings.\nconst POOL_SIZE_MULTIPLIER = 128\nconst MAX_POOL_SIZE = 65_536\nconst ASCII_DECODER = new TextDecoder()\nlet poolBytes: Uint8Array | undefined\nlet characterPool = ''\nlet poolOffset = 0\n\nfunction fillPool(bytes: number): void {\n const size = Math.min(bytes * POOL_SIZE_MULTIPLIER, MAX_POOL_SIZE)\n if (!poolBytes || poolBytes.length < size) {\n poolBytes = new Uint8Array(size)\n }\n if (poolOffset + bytes > characterPool.length) {\n crypto.getRandomValues(poolBytes)\n for (let i = 0; i < poolBytes.length; i++) {\n poolBytes[i] = URL_ALPHABET.charCodeAt(poolBytes[i] & 63)\n }\n characterPool = ASCII_DECODER.decode(poolBytes)\n poolOffset = 0\n }\n}\n\nfunction defaultAlphabetFromPool(size: number): string {\n fillPool(size)\n const id = characterPool.substring(poolOffset, poolOffset + size)\n poolOffset += size\n return id\n}\n\nexport type NanoidOptions = {\n /**\n * Random bytes for deterministic output (testing).\n * For power-of-2 alphabets (2, 4, 8, 16, 32, 64, 128, 256): exactly `length` bytes needed.\n * For other alphabets: ~length * 2 bytes needed (rejection sampling).\n */\n random?: Uint8Array\n /**\n * Custom alphabet to use. Default: URL-safe A-Za-z0-9_-\n * Must be 2-256 printable ASCII characters (32-126) with no duplicates.\n */\n alphabet?: string\n /**\n * Length of generated ID. Default: 21. Maximum: 2048.\n */\n length?: number\n}\n\nexport type Nanoid = {\n /** Generate a Nanoid with the default URL-safe alphabet and 21-character length. */\n (): string\n /** Generate a Nanoid with the default alphabet and a custom length. */\n (size: number): string\n /** Generate a Nanoid with a custom alphabet, length, or deterministic random bytes. */\n (options: NanoidOptions): string\n /**\n * Validate a nanoid string against the default URL-safe alphabet.\n * Note: Does not validate IDs generated with custom alphabets.\n */\n isValid(id: unknown): id is string\n}\n\n/**\n * Validate alphabet: 2-256 printable ASCII chars, no duplicates\n */\nfunction validateAlphabet(alphabet: string): void {\n if (alphabet.length < 2) {\n throw new InvalidInputError('ALPHABET_OUT_OF_RANGE', 'Alphabet must contain at least 2 characters', {\n strategy: 'nanoid',\n })\n }\n if (alphabet.length > 256) {\n throw new InvalidInputError('ALPHABET_OUT_OF_RANGE', 'Alphabet must not exceed 256 characters', {\n strategy: 'nanoid',\n })\n }\n const seen = new Set<string>()\n for (const char of alphabet) {\n const code = char.charCodeAt(0)\n if (code < 32 || code > 126) {\n throw new InvalidInputError(\n 'ALPHABET_INVALID_CHAR',\n 'Alphabet must contain only printable ASCII characters (32-126)',\n {\n strategy: 'nanoid',\n },\n )\n }\n if (seen.has(char)) {\n throw new InvalidInputError('ALPHABET_DUPLICATE', `Duplicate character in alphabet: \"${char}\"`, {\n strategy: 'nanoid',\n })\n }\n seen.add(char)\n }\n}\n\n/**\n * Validate length parameter\n */\nfunction validateLength(size: number): void {\n if (!Number.isInteger(size) || size < 0) {\n throw new InvalidInputError('LENGTH_OUT_OF_RANGE', 'Length must be a non-negative integer', { strategy: 'nanoid' })\n }\n if (size > MAX_SIZE) {\n throw new InvalidInputError('LENGTH_OUT_OF_RANGE', `Length must not exceed ${MAX_SIZE}`, { strategy: 'nanoid' })\n }\n}\n\n// Overloads\nfunction nanoidFn(): string\nfunction nanoidFn(size: number): string\nfunction nanoidFn(options: NanoidOptions): string\nfunction nanoidFn(sizeOrOptions?: number | NanoidOptions): string {\n // ULTRA-FAST PATH: No arguments = default nanoid\n // Uses simple pooled random bytes (npm nanoid style) for best performance\n if (sizeOrOptions === undefined) {\n return defaultAlphabetFromPool(DEFAULT_SIZE)\n }\n\n let size = DEFAULT_SIZE\n let alphabet = URL_ALPHABET\n let randomBytes: Uint8Array | undefined\n\n if (typeof sizeOrOptions === 'number') {\n size = sizeOrOptions\n } else {\n size = sizeOrOptions.length ?? DEFAULT_SIZE\n alphabet = sizeOrOptions.alphabet ?? URL_ALPHABET\n randomBytes = sizeOrOptions.random\n if (sizeOrOptions.alphabet !== undefined) {\n validateAlphabet(alphabet)\n }\n }\n\n validateLength(size)\n\n if (size === 0) return ''\n\n if (alphabet === URL_ALPHABET && randomBytes === undefined) {\n return defaultAlphabetFromPool(size)\n }\n\n const alphabetLen = alphabet.length\n\n // FAST PATH: Power-of-2 alphabet (includes default 64-char)\n // No rejection needed - each byte maps directly to a character\n if ((alphabetLen & (alphabetLen - 1)) === 0) {\n const mask = alphabetLen - 1\n if (randomBytes && randomBytes.length < size) {\n throw new InvalidInputError(\n 'RANDOM_BYTES_TOO_SHORT',\n `Insufficient random bytes: need ${size}, have ${randomBytes.length}`,\n { strategy: 'nanoid' },\n )\n }\n const bytes = randomBytes?.subarray(0, size) ?? globalThis.crypto.getRandomValues(new Uint8Array(size))\n let id = ''\n for (let i = 0; i < size; i++) {\n id += alphabet[bytes[i] & mask]\n }\n return id\n }\n\n // SLOW PATH: Rejection sampling for non-power-of-2 alphabets\n // Calculate mask: smallest power-of-2 minus 1 that covers alphabet size\n const mask = (2 << (31 - Math.clz32((alphabetLen - 1) | 1))) - 1\n // Calculate step: random bytes per batch (1.6x accounts for rejection)\n const step = Math.ceil((1.6 * mask * size) / alphabetLen)\n\n let id = ''\n let randomOffset = 0\n\n while (id.length < size) {\n let bytes: Uint8Array\n if (randomBytes) {\n if (randomBytes.length - randomOffset < step) {\n throw new InvalidInputError(\n 'RANDOM_BYTES_TOO_SHORT',\n `Insufficient random bytes: need at least ${step} more, have ${randomBytes.length - randomOffset}`,\n { strategy: 'nanoid' },\n )\n }\n bytes = randomBytes.subarray(randomOffset, randomOffset + step)\n randomOffset += step\n } else {\n bytes = globalThis.crypto.getRandomValues(new Uint8Array(step))\n }\n\n for (let i = 0; i < bytes.length && id.length < size; i++) {\n const index = bytes[i] & mask\n if (index < alphabetLen) {\n id += alphabet[index]\n }\n // Otherwise reject and continue (no modulo bias)\n }\n }\n\n return id\n}\n\n/**\n * Validate a nanoid string against the default URL-safe alphabet.\n * Note: Does not validate IDs generated with custom alphabets.\n */\nfunction isValid(id: unknown): id is string {\n return typeof id === 'string' && id.length > 0 && NANOID_REGEX.test(id)\n}\n\n/**\n * Generate a URL-friendly unique string ID.\n *\n * Nanoid is a tiny, secure, URL-friendly unique string ID generator.\n * It uses a URL-safe alphabet (A-Za-z0-9_-) and generates 21-character\n * IDs by default with 126 bits of entropy.\n *\n * Unlike UUID v7 or ULID, nanoid is NOT time-ordered. Use it for:\n * - URL shorteners\n * - Session tokens\n * - Invite codes\n * - Any case where you need short, random IDs\n *\n * @example Basic usage\n * ```ts\n * import { nanoid } from 'uniku/nanoid'\n *\n * const id = nanoid()\n * // => \"V1StGXR8_Z5jdHi6B-myT\"\n * ```\n *\n * @example Custom length\n * ```ts\n * const shortId = nanoid(10)\n * // => \"IRFa-VaY2b\"\n * ```\n *\n * @example Custom alphabet (hex)\n * ```ts\n * const hexId = nanoid({ alphabet: '0123456789abcdef', length: 12 })\n * // => \"4f90d13a42bc\"\n * ```\n *\n * @example Validation\n * ```ts\n * const maybeId: unknown = getUserInput()\n * if (nanoid.isValid(maybeId)) {\n * // TypeScript knows maybeId is string\n * console.log(maybeId.length)\n * }\n * ```\n *\n * @throws {InvalidInputError} Length must be between 0 and 2048\n * @throws {InvalidInputError} Alphabet must contain 2-256 unique printable ASCII characters\n * @throws {InvalidInputError} Insufficient random bytes for requested length\n */\nexport const nanoid: Nanoid = Object.assign(nanoidFn, {\n isValid,\n})\n\nexport { InvalidInputError, UniqueIdError } from '../errors'\n"],"mappings":"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"}

@@ -1,2 +0,2 @@

import { a as ParseError, i as InvalidInputError, o as UniqueIdError, t as BufferError } from "../errors-Da-8dh4J.mjs";
import { BufferError, InvalidInputError, ParseError, UniqueIdError } from "../errors.mjs";

@@ -16,8 +16,2 @@ //#region src/objectid/objectid.d.ts

/**
* Timestamp in seconds since the Unix epoch.
*
* @deprecated Use `msecs` instead. Will be removed at v1-rc.
*/
secs?: number;
/**
* 24-bit counter value (0 to 0xFFFFFF).

@@ -24,0 +18,0 @@ */

@@ -1,1 +0,1 @@

{"version":3,"file":"objectid.d.mts","names":[],"sources":["../../src/objectid/objectid.ts"],"mappings":";;;KA4BY,eAAA;;;AAAZ;EAIE,MAAA,GAAS,UAAA;;;;;;EAMT,KAAA;;;AAWA;AAGF;;EAPE,IAAA;;;;EAIA,OAAA;AAAA;AAAA,KAGU,QAAA;mEAUO;EAAA,cANH,UAAA,GAAa,UAAA,EAAY,OAAA,EAAS,eAAA,cAA6B,GAAA,EAAK,IAAA,EAAM,MAAA,YAAkB,IAAA;GAEzG,OAAA,GAAU,eAAA,EAAiB,GAAA,cAAiB,MAAA;EAE7C,OAAA,CAAQ,EAAA,WAAa,UAAA;EAErB,SAAA,CAAU,KAAA,EAAO,UAAA;EAEjB,SAAA,CAAU,EAAA;EAEV,OAAA,CAAQ,EAAA,YAAc,EAAA;EAEtB,GAAA;EAEA,GAAA;AAAA;;;;;;;;;;;;;AAAA;AAsNF;;;;AAAuB;;;;;;;;;;cAAV,QAAA,EAAU,QAAA"}
{"version":3,"file":"objectid.d.mts","names":[],"sources":["../../src/objectid/objectid.ts"],"mappings":";;;KA4BY,eAAA;;;AAAZ;EAIE,MAAA,GAAS,UAAA;;;;;;EAMT,KAAA;EAIA;AAAA;AAGF;EAHE,OAAA;AAAA;AAAA,KAGU,QAAA;;gBAII,UAAA,GAAa,UAAA,EAAY,OAAA,EAAS,eAAA,cAA6B,GAAA,EAAK,IAAA,EAAM,MAAA,YAAkB,IAAA;GAEzG,OAAA,GAAU,eAAA,EAAiB,GAAA,cAAiB,MAAA;EAE7C,OAAA,CAAQ,EAAA,WAAa,UAAA,EAEJ;EAAjB,SAAA,CAAU,KAAA,EAAO,UAAA;EAEjB,SAAA,CAAU,EAAA;EAEV,OAAA,CAAQ,EAAA,YAAc,EAAA;EAEtB,GAAA;EAEA,GAAA;AAAA;;;;;;;;;;;;;;;;;;AAAA;AAsNF;;;;AAAuB;;;;;cAAV,QAAA,EAAU,QAAA"}

@@ -1,2 +0,2 @@

import{n as e,t}from"../random-Chp-Nkzi.mjs";import{n,t as r}from"../validation-CTNpXm94.mjs";import{BufferError as i,InvalidInputError as a,ParseError as o,UniqueIdError as s}from"../errors.mjs";import{n as c}from"../bytes-xqWxFYsM.mjs";import{t as l}from"../timestamp-ChrSuQCR.mjs";const u=`0123456789abcdef`,d=Array.from({length:256},(e,t)=>u[t>>4&15]+u[t&15]),f=new Uint8Array(65536);f.fill(255);for(let e=0;e<=9;e+=1)f[48+e]=e;for(let e=0;e<6;e+=1)f[97+e]=10+e,f[65+e]=10+e;function p(e){if(e.length<12)throw new i(`BYTES_INVALID_LENGTH`,`ObjectID bytes must be at least 12 bytes, got ${e.length}`,{strategy:`objectid`});let t=``;for(let n=0;n<12;n+=1)t+=d[e[n]];return t}function m(e){if(e.length!==24)throw new o(`INVALID_LENGTH`,`ObjectID string must be 24 characters, got ${e.length}`,{strategy:`objectid`});let t=new Uint8Array(12);for(let n=0;n<12;n+=1){let r=n*2,i=r+1,a=f[e.charCodeAt(r)],s=f[e.charCodeAt(i)];if(a===255)throw new o(`INVALID_CHAR`,`Invalid ObjectID character: ${e[r]}`,{strategy:`objectid`});if(s===255)throw new o(`INVALID_CHAR`,`Invalid ObjectID character: ${e[i]}`,{strategy:`objectid`});t[n]=a<<4|s}return t}const h=16777215,g=/^[0-9a-f]{24}$/i,_={random:void 0,counter:void 0};function v(){let e=new Uint8Array(5);return e.set(t(5)),e}function y(e,t,n,r,i){c(r,i,e);for(let e=0;e<5;e+=1)r[i+4+e]=t[e];r[i+4+5]=n>>>16&255,r[i+4+5+1]=n>>>8&255,r[i+4+5+3-1]=n&255}function b(t,o,s=0){let c,u,d;if(t){let n=t.random;if(n&&n.length<5)throw new a(`RANDOM_BYTES_TOO_SHORT`,`Random bytes length must be >= 5 for ObjectID`,{strategy:`objectid`});let i=l(t,0,4294967295,`objectid`),o=t.counter;if(o!==void 0&&!r(o,0,h))throw new a(`COUNTER_OUT_OF_RANGE`,`Counter must be between 0 and ${h}`,{strategy:`objectid`});c=i??Math.floor(Date.now()/1e3),u=n??v(),d=o??e()&h}else _.random===void 0&&(_.random=v()),_.counter===void 0&&(_.counter=e()&h),c=Math.floor(Date.now()/1e3),u=_.random,_.counter=_.counter+1&h,d=_.counter;if(o){if(!n(o,s,12))throw new i(`BUFFER_OUT_OF_BOUNDS`,`ObjectID byte range ${s}:${s+12-1} is out of buffer bounds`,{strategy:`objectid`});return y(c,u,d,o,s),o}let f=new Uint8Array(12);return y(c,u,d,f,0),p(f)}function x(e){return m(e)}function S(e){if(e.length!==12)throw new i(`BYTES_INVALID_LENGTH`,`ObjectID bytes must be exactly 12 bytes, got ${e.length}`,{strategy:`objectid`});return p(e)}function C(e){let t=m(e);return((t[0]<<24|t[1]<<16|t[2]<<8|t[3])>>>0)*1e3}function w(e){return typeof e==`string`&&g.test(e)}const T=Object.assign(b,{toBytes:x,fromBytes:S,timestamp:C,isValid:w,NIL:`0`.repeat(24),MAX:`f`.repeat(24)});export{i as BufferError,a as InvalidInputError,o as ParseError,s as UniqueIdError,T as objectid};
import{n as e,t}from"../random-Chp-Nkzi.mjs";import{n,t as r}from"../validation-CTNpXm94.mjs";import{BufferError as i,InvalidInputError as a,ParseError as o,UniqueIdError as s}from"../errors.mjs";import{n as c}from"../bytes-xqWxFYsM.mjs";import{t as l}from"../timestamp-DnsO0h7C.mjs";const u=`0123456789abcdef`,d=Array.from({length:256},(e,t)=>u[t>>4&15]+u[t&15]),f=new Uint8Array(65536);f.fill(255);for(let e=0;e<=9;e+=1)f[48+e]=e;for(let e=0;e<6;e+=1)f[97+e]=10+e,f[65+e]=10+e;function p(e){if(e.length<12)throw new i(`BYTES_INVALID_LENGTH`,`ObjectID bytes must be at least 12 bytes, got ${e.length}`,{strategy:`objectid`});let t=``;for(let n=0;n<12;n+=1)t+=d[e[n]];return t}function m(e){if(e.length!==24)throw new o(`INVALID_LENGTH`,`ObjectID string must be 24 characters, got ${e.length}`,{strategy:`objectid`});let t=new Uint8Array(12);for(let n=0;n<12;n+=1){let r=n*2,i=r+1,a=f[e.charCodeAt(r)],s=f[e.charCodeAt(i)];if(a===255)throw new o(`INVALID_CHAR`,`Invalid ObjectID character: ${e[r]}`,{strategy:`objectid`});if(s===255)throw new o(`INVALID_CHAR`,`Invalid ObjectID character: ${e[i]}`,{strategy:`objectid`});t[n]=a<<4|s}return t}const h=16777215,g=/^[0-9a-f]{24}$/i,_={random:void 0,counter:void 0};function v(){let e=new Uint8Array(5);return e.set(t(5)),e}function y(e,t,n,r,i){c(r,i,e);for(let e=0;e<5;e+=1)r[i+4+e]=t[e];r[i+4+5]=n>>>16&255,r[i+4+5+1]=n>>>8&255,r[i+4+5+3-1]=n&255}function b(t,o,s=0){let c,u,d;if(t){let n=t.random;if(n&&n.length<5)throw new a(`RANDOM_BYTES_TOO_SHORT`,`Random bytes length must be >= 5 for ObjectID`,{strategy:`objectid`});let i=l(t,0,4294967295,`objectid`),o=t.counter;if(o!==void 0&&!r(o,0,h))throw new a(`COUNTER_OUT_OF_RANGE`,`Counter must be between 0 and ${h}`,{strategy:`objectid`});c=i??Math.floor(Date.now()/1e3),u=n??v(),d=o??e()&h}else _.random===void 0&&(_.random=v()),_.counter===void 0&&(_.counter=e()&h),c=Math.floor(Date.now()/1e3),u=_.random,_.counter=_.counter+1&h,d=_.counter;if(o){if(!n(o,s,12))throw new i(`BUFFER_OUT_OF_BOUNDS`,`ObjectID byte range ${s}:${s+12-1} is out of buffer bounds`,{strategy:`objectid`});return y(c,u,d,o,s),o}let f=new Uint8Array(12);return y(c,u,d,f,0),p(f)}function x(e){return m(e)}function S(e){if(e.length!==12)throw new i(`BYTES_INVALID_LENGTH`,`ObjectID bytes must be exactly 12 bytes, got ${e.length}`,{strategy:`objectid`});return p(e)}function C(e){let t=m(e);return((t[0]<<24|t[1]<<16|t[2]<<8|t[3])>>>0)*1e3}function w(e){return typeof e==`string`&&g.test(e)}const T=Object.assign(b,{toBytes:x,fromBytes:S,timestamp:C,isValid:w,NIL:`0`.repeat(24),MAX:`f`.repeat(24)});export{i as BufferError,a as InvalidInputError,o as ParseError,s as UniqueIdError,T as objectid};
//# sourceMappingURL=objectid.mjs.map

@@ -1,1 +0,1 @@

{"version":3,"file":"objectid.mjs","names":["OBJECTID_BYTES"],"sources":["../../src/objectid/hex.ts","../../src/objectid/objectid.ts"],"sourcesContent":["import { BufferError, ParseError } from '../errors'\n\n/**\n * Hex encoding/decoding for ObjectID.\n * Alphabet: 0-9a-f (lowercase on encode, case-insensitive on decode)\n *\n * ObjectID binary format: 12 bytes (96 bits)\n * - 4 bytes: big-endian Unix timestamp in seconds\n * - 5 bytes: per-process random value\n * - 3 bytes: big-endian counter\n *\n * String format: 24 characters of hex\n */\n\nconst HEX_CHARS = '0123456789abcdef'\nconst OBJECTID_BYTES = 12\nconst OBJECTID_STRING_LEN = 24\n\n// Pre-computed encode table: byte value (0-255) -> 2-char lowercase hex string.\nconst ENCODE_TABLE: string[] = Array.from(\n { length: 256 },\n (_, byte) => HEX_CHARS[(byte >> 4) & 0xf] + HEX_CHARS[byte & 0xf],\n)\n\n// Pre-computed decode table covering every UTF-16 code unit charCodeAt can\n// return, so lookups never go out of bounds and a single `=== 255` check\n// rejects invalid input (including non-ASCII) without a per-character range\n// check. Costs 128 KiB once at module load; valid inputs only touch the first\n// 128 bytes, so cache behavior is unaffected.\n// Note: unlike Base62, hex decoding is case-insensitive - 'a' and 'A' both decode to 10.\nconst DECODING = new Uint8Array(65536)\nDECODING.fill(255) // 255 = invalid marker\n\nfor (let i = 0; i <= 9; i += 1) {\n DECODING['0'.charCodeAt(0) + i] = i\n}\nfor (let i = 0; i < 6; i += 1) {\n DECODING['a'.charCodeAt(0) + i] = 10 + i\n DECODING['A'.charCodeAt(0) + i] = 10 + i\n}\n\n/**\n * Encode 12 ObjectID bytes to a 24-character lowercase hex string.\n */\nexport function encodeObjectIdHex(bytes: Uint8Array): string {\n if (bytes.length < OBJECTID_BYTES) {\n throw new BufferError(\n 'BYTES_INVALID_LENGTH',\n `ObjectID bytes must be at least ${OBJECTID_BYTES} bytes, got ${bytes.length}`,\n { strategy: 'objectid' },\n )\n }\n\n let encoded = ''\n for (let i = 0; i < OBJECTID_BYTES; i += 1) {\n encoded += ENCODE_TABLE[bytes[i]]\n }\n return encoded\n}\n\n/**\n * Decode a 24-character hex string to 12 ObjectID bytes.\n */\nexport function decodeObjectIdHex(str: string): Uint8Array {\n if (str.length !== OBJECTID_STRING_LEN) {\n throw new ParseError(\n 'INVALID_LENGTH',\n `ObjectID string must be ${OBJECTID_STRING_LEN} characters, got ${str.length}`,\n { strategy: 'objectid' },\n )\n }\n\n const bytes = new Uint8Array(OBJECTID_BYTES)\n for (let i = 0; i < OBJECTID_BYTES; i += 1) {\n const hiIndex = i * 2\n const loIndex = hiIndex + 1\n const hi = DECODING[str.charCodeAt(hiIndex)]\n const lo = DECODING[str.charCodeAt(loIndex)]\n\n if (hi === 255) {\n throw new ParseError('INVALID_CHAR', `Invalid ObjectID character: ${str[hiIndex]}`, { strategy: 'objectid' })\n }\n if (lo === 255) {\n throw new ParseError('INVALID_CHAR', `Invalid ObjectID character: ${str[loIndex]}`, { strategy: 'objectid' })\n }\n\n bytes[i] = (hi << 4) | lo\n }\n\n return bytes\n}\n","import { writeTimestamp32 } from '../common/bytes'\nimport { randomBytes, randomUint32 } from '../common/random'\nimport { resolveTimestampSecs } from '../common/timestamp'\nimport { isIntegerInRange, isWritableRange } from '../common/validation'\nimport { BufferError, InvalidInputError } from '../errors'\nimport { decodeObjectIdHex, encodeObjectIdHex } from './hex'\n\n/**\n * MongoDB ObjectID\n *\n * A 96-bit (12-byte) identifier consisting of:\n * - 4 bytes: big-endian Unix timestamp in seconds\n * - 5 bytes: per-process random value\n * - 3 bytes: big-endian counter, always incrementing (wraps at 0xFFFFFF back to 0)\n *\n * Encoded as a 24-character lowercase hex string.\n */\n\nconst OBJECTID_BYTES = 12\nconst TIMESTAMP_BYTES = 4\nconst RANDOM_BYTES = 5\nconst COUNTER_BYTES = 3\nconst MAX_SECS = 0xffffffff\nconst MAX_COUNTER = 0xffffff\n\n// Validation regex: case-insensitive per KTD7, matching bson's ObjectId.isValid()\nconst OBJECTID_REGEX = /^[0-9a-f]{24}$/i\n\nexport type ObjectIdOptions = {\n /**\n * 5 bytes of random data to use for the ObjectID's random field.\n */\n random?: Uint8Array\n /**\n * Timestamp in milliseconds since the Unix epoch.\n * Defaults to Date.now().\n * ObjectID stores whole seconds, so sub-second precision is truncated.\n */\n msecs?: number\n /**\n * Timestamp in seconds since the Unix epoch.\n *\n * @deprecated Use `msecs` instead. Will be removed at v1-rc.\n */\n // TODO(v1-rc): remove this alias (tracked in docs/STABILITY.md).\n secs?: number\n /**\n * 24-bit counter value (0 to 0xFFFFFF).\n */\n counter?: number\n}\n\nexport type ObjectId = {\n /** Generate a MongoDB-compatible ObjectID string. */\n (): string\n /** Generate an ObjectID with explicit options or write its 12 canonical bytes into a caller-owned buffer. */\n <TBuf extends Uint8Array = Uint8Array>(options: ObjectIdOptions | undefined, buf: TBuf, offset?: number): TBuf\n /** Generate an ObjectID string with optional timestamp, random field, or counter. */\n (options?: ObjectIdOptions, buf?: undefined, offset?: number): string\n /** Convert an ObjectID string to its canonical 12-byte representation. */\n toBytes(id: string): Uint8Array\n /** Convert 12 canonical ObjectID bytes to an ObjectID string. */\n fromBytes(bytes: Uint8Array): string\n /** Read the embedded Unix timestamp in milliseconds. */\n timestamp(id: string): number\n /** Return whether a value is a syntactically valid ObjectID string. */\n isValid(id: unknown): id is string\n /** The nil ObjectID (all zeros) */\n NIL: string\n /** The max ObjectID (all 0xff) */\n MAX: string\n}\n\ntype ObjectIdState = {\n random: Uint8Array | undefined\n counter: number | undefined\n}\n\n/**\n * Module-level state for the per-process random value and the always-incrementing counter.\n *\n * IMPORTANT: This state persists across all objectid() calls in the module's lifetime.\n * - In serverless/edge functions with warm starts, state persists between invocations.\n * Unlike ULID/UUIDv7's per-timestamp sequence reset, the counter continuing to climb\n * across warm starts is exactly the anti-collision behavior the ObjectID spec intends.\n * - For isolated state, pass explicit `random`, `msecs`, or `counter` via options.\n * - Tests should mock Date.now() or provide explicit options for deterministic behavior.\n */\nconst state: ObjectIdState = {\n random: undefined,\n counter: undefined,\n}\n\n/**\n * Draw 5 fresh random bytes into a newly-owned buffer, copying immediately so the\n * result is unaffected by any later pool refill triggered by other random draws\n * (e.g. the counter's `randomUint32()` call) before these bytes are consumed.\n */\nfunction freshRandom(): Uint8Array {\n const bytes = new Uint8Array(RANDOM_BYTES)\n bytes.set(randomBytes(RANDOM_BYTES))\n return bytes\n}\n\nfunction writeObjectIdBytesUnchecked(\n secs: number,\n random: Uint8Array,\n counter: number,\n buf: Uint8Array,\n offset: number,\n): void {\n // Timestamp (32-bit big-endian seconds since Unix epoch) -> bytes 0-3\n writeTimestamp32(buf, offset, secs)\n\n // Random (5 bytes) -> bytes 4-8\n for (let i = 0; i < RANDOM_BYTES; i += 1) {\n buf[offset + TIMESTAMP_BYTES + i] = random[i]\n }\n\n // Counter (24-bit big-endian) -> bytes 9-11\n buf[offset + TIMESTAMP_BYTES + RANDOM_BYTES] = (counter >>> 16) & 0xff\n buf[offset + TIMESTAMP_BYTES + RANDOM_BYTES + 1] = (counter >>> 8) & 0xff\n buf[offset + TIMESTAMP_BYTES + RANDOM_BYTES + COUNTER_BYTES - 1] = counter & 0xff\n}\n\n/*\n * Overload: no buffer => return an ObjectID string.\n */\nfunction objectIdFn(options?: ObjectIdOptions, buf?: undefined, offset?: number): string\n/*\n * Overload: caller provides a buffer slice to fill with ObjectID bytes.\n */\nfunction objectIdFn<TBuf extends Uint8Array = Uint8Array>(\n options: ObjectIdOptions | undefined,\n buf: TBuf,\n offset?: number,\n): TBuf\nfunction objectIdFn<TBuf extends Uint8Array = Uint8Array>(\n options?: ObjectIdOptions,\n buf?: TBuf,\n offset = 0,\n): string | TBuf {\n let secs: number\n let random: Uint8Array\n let counter: number\n\n if (options) {\n const optRandom = options.random\n if (optRandom && optRandom.length < RANDOM_BYTES) {\n throw new InvalidInputError(\n 'RANDOM_BYTES_TOO_SHORT',\n `Random bytes length must be >= ${RANDOM_BYTES} for ObjectID`,\n {\n strategy: 'objectid',\n },\n )\n }\n\n const optSecs = resolveTimestampSecs(options, 0, MAX_SECS, 'objectid')\n\n const optCounter = options.counter\n if (optCounter !== undefined && !isIntegerInRange(optCounter, 0, MAX_COUNTER)) {\n throw new InvalidInputError('COUNTER_OUT_OF_RANGE', `Counter must be between 0 and ${MAX_COUNTER}`, {\n strategy: 'objectid',\n })\n }\n\n // Options bypass persistent state entirely: every field is sourced fresh (given\n // value, or an independently-defaulted one), never read from or written to\n // `state` (see KTD2). This is what makes options-based generation deterministic\n // when all three fields are supplied.\n secs = optSecs ?? Math.floor(Date.now() / 1000)\n random = optRandom ?? freshRandom()\n counter = optCounter ?? randomUint32() & MAX_COUNTER\n } else {\n // Lazily initialize persistent state on first no-option call.\n if (state.random === undefined) {\n state.random = freshRandom()\n }\n if (state.counter === undefined) {\n state.counter = randomUint32() & MAX_COUNTER\n }\n\n /**\n * Note: by default, Cloudflare Workers \"freezes\" time during request handling to prevent\n * side-channel attacks. This means that Date.now() will return the same value for the entire\n * duration of a request.\n * Implications:\n * - all ObjectIDs generated within a single request will share the same timestamp.\n * - monotonic ordering relies entirely on the ever-incrementing counter.\n */\n secs = Math.floor(Date.now() / 1000)\n random = state.random\n state.counter = (state.counter + 1) & MAX_COUNTER\n counter = state.counter\n }\n\n if (buf) {\n if (!isWritableRange(buf, offset, OBJECTID_BYTES)) {\n throw new BufferError(\n 'BUFFER_OUT_OF_BOUNDS',\n `ObjectID byte range ${offset}:${offset + OBJECTID_BYTES - 1} is out of buffer bounds`,\n { strategy: 'objectid' },\n )\n }\n writeObjectIdBytesUnchecked(secs, random, counter, buf, offset)\n return buf\n }\n\n const bytes = new Uint8Array(OBJECTID_BYTES)\n writeObjectIdBytesUnchecked(secs, random, counter, bytes, 0)\n return encodeObjectIdHex(bytes)\n}\n\n/**\n * Convert an ObjectID hex string to 12 bytes.\n */\nfunction toBytes(id: string): Uint8Array {\n return decodeObjectIdHex(id)\n}\n\n/**\n * Convert 12 bytes to an ObjectID hex string.\n */\nfunction fromBytes(bytes: Uint8Array): string {\n if (bytes.length !== OBJECTID_BYTES) {\n throw new BufferError(\n 'BYTES_INVALID_LENGTH',\n `ObjectID bytes must be exactly ${OBJECTID_BYTES} bytes, got ${bytes.length}`,\n { strategy: 'objectid' },\n )\n }\n return encodeObjectIdHex(bytes)\n}\n\n/**\n * Extract the timestamp from an ObjectID string.\n * Returns Unix timestamp in milliseconds for API consistency with ulid/uuidv7/ksuid.\n * Note: ObjectID only has second precision, so the returned value will always end in 000.\n */\nfunction timestamp(id: string): number {\n const bytes = decodeObjectIdHex(id)\n // First 4 bytes are big-endian timestamp (seconds since Unix epoch)\n const secs = ((bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]) >>> 0\n return secs * 1000\n}\n\n/**\n * Validate an ObjectID string format.\n * Case-insensitive (KTD7), matching bson's ObjectId.isValid() and this repo's existing\n * convention (ulid, ksuid) of accepting mixed-case input for parsing, even though\n * generation always emits lowercase (matching MongoDB driver output).\n */\nfunction isValid(id: unknown): id is string {\n return typeof id === 'string' && OBJECTID_REGEX.test(id)\n}\n\n/**\n * Generate a MongoDB ObjectID string or write the bytes into a buffer.\n *\n * ObjectID is a 12-byte identifier consisting of a 4-byte timestamp, a 5-byte\n * per-process random value, and a 3-byte always-incrementing counter, encoded\n * as a 24-character lowercase hex string. It is time-ordered and compatible\n * with MongoDB's own ObjectID implementation.\n *\n * @example\n * ```ts\n * import { objectid } from 'uniku/objectid'\n *\n * const id = objectid()\n * // => \"667c3f2a1e2b3c4d5e6f7081\"\n *\n * // Extract timestamp\n * const ts = objectid.timestamp(id)\n * console.log(new Date(ts))\n *\n * // Validate\n * objectid.isValid(id) // true\n *\n * // Convert to/from bytes (12 bytes)\n * const bytes = objectid.toBytes(id)\n * const restored = objectid.fromBytes(bytes)\n * ```\n */\nexport const objectid: ObjectId = Object.assign(objectIdFn, {\n toBytes,\n fromBytes,\n timestamp,\n isValid,\n NIL: '0'.repeat(24),\n MAX: 'f'.repeat(24),\n})\n\nexport { BufferError, InvalidInputError, ParseError, UniqueIdError } from '../errors'\n"],"mappings":"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"}
{"version":3,"file":"objectid.mjs","names":["OBJECTID_BYTES"],"sources":["../../src/objectid/hex.ts","../../src/objectid/objectid.ts"],"sourcesContent":["import { BufferError, ParseError } from '../errors'\n\n/**\n * Hex encoding/decoding for ObjectID.\n * Alphabet: 0-9a-f (lowercase on encode, case-insensitive on decode)\n *\n * ObjectID binary format: 12 bytes (96 bits)\n * - 4 bytes: big-endian Unix timestamp in seconds\n * - 5 bytes: per-process random value\n * - 3 bytes: big-endian counter\n *\n * String format: 24 characters of hex\n */\n\nconst HEX_CHARS = '0123456789abcdef'\nconst OBJECTID_BYTES = 12\nconst OBJECTID_STRING_LEN = 24\n\n// Pre-computed encode table: byte value (0-255) -> 2-char lowercase hex string.\nconst ENCODE_TABLE: string[] = Array.from(\n { length: 256 },\n (_, byte) => HEX_CHARS[(byte >> 4) & 0xf] + HEX_CHARS[byte & 0xf],\n)\n\n// Pre-computed decode table covering every UTF-16 code unit charCodeAt can\n// return, so lookups never go out of bounds and a single `=== 255` check\n// rejects invalid input (including non-ASCII) without a per-character range\n// check. Costs 128 KiB once at module load; valid inputs only touch the first\n// 128 bytes, so cache behavior is unaffected.\n// Note: unlike Base62, hex decoding is case-insensitive - 'a' and 'A' both decode to 10.\nconst DECODING = new Uint8Array(65536)\nDECODING.fill(255) // 255 = invalid marker\n\nfor (let i = 0; i <= 9; i += 1) {\n DECODING['0'.charCodeAt(0) + i] = i\n}\nfor (let i = 0; i < 6; i += 1) {\n DECODING['a'.charCodeAt(0) + i] = 10 + i\n DECODING['A'.charCodeAt(0) + i] = 10 + i\n}\n\n/**\n * Encode 12 ObjectID bytes to a 24-character lowercase hex string.\n */\nexport function encodeObjectIdHex(bytes: Uint8Array): string {\n if (bytes.length < OBJECTID_BYTES) {\n throw new BufferError(\n 'BYTES_INVALID_LENGTH',\n `ObjectID bytes must be at least ${OBJECTID_BYTES} bytes, got ${bytes.length}`,\n { strategy: 'objectid' },\n )\n }\n\n let encoded = ''\n for (let i = 0; i < OBJECTID_BYTES; i += 1) {\n encoded += ENCODE_TABLE[bytes[i]]\n }\n return encoded\n}\n\n/**\n * Decode a 24-character hex string to 12 ObjectID bytes.\n */\nexport function decodeObjectIdHex(str: string): Uint8Array {\n if (str.length !== OBJECTID_STRING_LEN) {\n throw new ParseError(\n 'INVALID_LENGTH',\n `ObjectID string must be ${OBJECTID_STRING_LEN} characters, got ${str.length}`,\n { strategy: 'objectid' },\n )\n }\n\n const bytes = new Uint8Array(OBJECTID_BYTES)\n for (let i = 0; i < OBJECTID_BYTES; i += 1) {\n const hiIndex = i * 2\n const loIndex = hiIndex + 1\n const hi = DECODING[str.charCodeAt(hiIndex)]\n const lo = DECODING[str.charCodeAt(loIndex)]\n\n if (hi === 255) {\n throw new ParseError('INVALID_CHAR', `Invalid ObjectID character: ${str[hiIndex]}`, { strategy: 'objectid' })\n }\n if (lo === 255) {\n throw new ParseError('INVALID_CHAR', `Invalid ObjectID character: ${str[loIndex]}`, { strategy: 'objectid' })\n }\n\n bytes[i] = (hi << 4) | lo\n }\n\n return bytes\n}\n","import { writeTimestamp32 } from '../common/bytes'\nimport { randomBytes, randomUint32 } from '../common/random'\nimport { resolveTimestampSecs } from '../common/timestamp'\nimport { isIntegerInRange, isWritableRange } from '../common/validation'\nimport { BufferError, InvalidInputError } from '../errors'\nimport { decodeObjectIdHex, encodeObjectIdHex } from './hex'\n\n/**\n * MongoDB ObjectID\n *\n * A 96-bit (12-byte) identifier consisting of:\n * - 4 bytes: big-endian Unix timestamp in seconds\n * - 5 bytes: per-process random value\n * - 3 bytes: big-endian counter, always incrementing (wraps at 0xFFFFFF back to 0)\n *\n * Encoded as a 24-character lowercase hex string.\n */\n\nconst OBJECTID_BYTES = 12\nconst TIMESTAMP_BYTES = 4\nconst RANDOM_BYTES = 5\nconst COUNTER_BYTES = 3\nconst MAX_SECS = 0xffffffff\nconst MAX_COUNTER = 0xffffff\n\n// Validation regex: case-insensitive per KTD7, matching bson's ObjectId.isValid()\nconst OBJECTID_REGEX = /^[0-9a-f]{24}$/i\n\nexport type ObjectIdOptions = {\n /**\n * 5 bytes of random data to use for the ObjectID's random field.\n */\n random?: Uint8Array\n /**\n * Timestamp in milliseconds since the Unix epoch.\n * Defaults to Date.now().\n * ObjectID stores whole seconds, so sub-second precision is truncated.\n */\n msecs?: number\n /**\n * 24-bit counter value (0 to 0xFFFFFF).\n */\n counter?: number\n}\n\nexport type ObjectId = {\n /** Generate a MongoDB-compatible ObjectID string. */\n (): string\n /** Generate an ObjectID with explicit options or write its 12 canonical bytes into a caller-owned buffer. */\n <TBuf extends Uint8Array = Uint8Array>(options: ObjectIdOptions | undefined, buf: TBuf, offset?: number): TBuf\n /** Generate an ObjectID string with optional timestamp, random field, or counter. */\n (options?: ObjectIdOptions, buf?: undefined, offset?: number): string\n /** Convert an ObjectID string to its canonical 12-byte representation. */\n toBytes(id: string): Uint8Array\n /** Convert 12 canonical ObjectID bytes to an ObjectID string. */\n fromBytes(bytes: Uint8Array): string\n /** Read the embedded Unix timestamp in milliseconds. */\n timestamp(id: string): number\n /** Return whether a value is a syntactically valid ObjectID string. */\n isValid(id: unknown): id is string\n /** The nil ObjectID (all zeros) */\n NIL: string\n /** The max ObjectID (all 0xff) */\n MAX: string\n}\n\ntype ObjectIdState = {\n random: Uint8Array | undefined\n counter: number | undefined\n}\n\n/**\n * Module-level state for the per-process random value and the always-incrementing counter.\n *\n * IMPORTANT: This state persists across all objectid() calls in the module's lifetime.\n * - In serverless/edge functions with warm starts, state persists between invocations.\n * Unlike ULID/UUIDv7's per-timestamp sequence reset, the counter continuing to climb\n * across warm starts is exactly the anti-collision behavior the ObjectID spec intends.\n * - For isolated state, pass explicit `random`, `msecs`, or `counter` via options.\n * - Tests should mock Date.now() or provide explicit options for deterministic behavior.\n */\nconst state: ObjectIdState = {\n random: undefined,\n counter: undefined,\n}\n\n/**\n * Draw 5 fresh random bytes into a newly-owned buffer, copying immediately so the\n * result is unaffected by any later pool refill triggered by other random draws\n * (e.g. the counter's `randomUint32()` call) before these bytes are consumed.\n */\nfunction freshRandom(): Uint8Array {\n const bytes = new Uint8Array(RANDOM_BYTES)\n bytes.set(randomBytes(RANDOM_BYTES))\n return bytes\n}\n\nfunction writeObjectIdBytesUnchecked(\n secs: number,\n random: Uint8Array,\n counter: number,\n buf: Uint8Array,\n offset: number,\n): void {\n // Timestamp (32-bit big-endian seconds since Unix epoch) -> bytes 0-3\n writeTimestamp32(buf, offset, secs)\n\n // Random (5 bytes) -> bytes 4-8\n for (let i = 0; i < RANDOM_BYTES; i += 1) {\n buf[offset + TIMESTAMP_BYTES + i] = random[i]\n }\n\n // Counter (24-bit big-endian) -> bytes 9-11\n buf[offset + TIMESTAMP_BYTES + RANDOM_BYTES] = (counter >>> 16) & 0xff\n buf[offset + TIMESTAMP_BYTES + RANDOM_BYTES + 1] = (counter >>> 8) & 0xff\n buf[offset + TIMESTAMP_BYTES + RANDOM_BYTES + COUNTER_BYTES - 1] = counter & 0xff\n}\n\n/*\n * Overload: no buffer => return an ObjectID string.\n */\nfunction objectIdFn(options?: ObjectIdOptions, buf?: undefined, offset?: number): string\n/*\n * Overload: caller provides a buffer slice to fill with ObjectID bytes.\n */\nfunction objectIdFn<TBuf extends Uint8Array = Uint8Array>(\n options: ObjectIdOptions | undefined,\n buf: TBuf,\n offset?: number,\n): TBuf\nfunction objectIdFn<TBuf extends Uint8Array = Uint8Array>(\n options?: ObjectIdOptions,\n buf?: TBuf,\n offset = 0,\n): string | TBuf {\n let secs: number\n let random: Uint8Array\n let counter: number\n\n if (options) {\n const optRandom = options.random\n if (optRandom && optRandom.length < RANDOM_BYTES) {\n throw new InvalidInputError(\n 'RANDOM_BYTES_TOO_SHORT',\n `Random bytes length must be >= ${RANDOM_BYTES} for ObjectID`,\n {\n strategy: 'objectid',\n },\n )\n }\n\n const optSecs = resolveTimestampSecs(options, 0, MAX_SECS, 'objectid')\n\n const optCounter = options.counter\n if (optCounter !== undefined && !isIntegerInRange(optCounter, 0, MAX_COUNTER)) {\n throw new InvalidInputError('COUNTER_OUT_OF_RANGE', `Counter must be between 0 and ${MAX_COUNTER}`, {\n strategy: 'objectid',\n })\n }\n\n // Options bypass persistent state entirely: every field is sourced fresh (given\n // value, or an independently-defaulted one), never read from or written to\n // `state` (see KTD2). This is what makes options-based generation deterministic\n // when all three fields are supplied.\n secs = optSecs ?? Math.floor(Date.now() / 1000)\n random = optRandom ?? freshRandom()\n counter = optCounter ?? randomUint32() & MAX_COUNTER\n } else {\n // Lazily initialize persistent state on first no-option call.\n if (state.random === undefined) {\n state.random = freshRandom()\n }\n if (state.counter === undefined) {\n state.counter = randomUint32() & MAX_COUNTER\n }\n\n /**\n * Note: by default, Cloudflare Workers \"freezes\" time during request handling to prevent\n * side-channel attacks. This means that Date.now() will return the same value for the entire\n * duration of a request.\n * Implications:\n * - all ObjectIDs generated within a single request will share the same timestamp.\n * - monotonic ordering relies entirely on the ever-incrementing counter.\n */\n secs = Math.floor(Date.now() / 1000)\n random = state.random\n state.counter = (state.counter + 1) & MAX_COUNTER\n counter = state.counter\n }\n\n if (buf) {\n if (!isWritableRange(buf, offset, OBJECTID_BYTES)) {\n throw new BufferError(\n 'BUFFER_OUT_OF_BOUNDS',\n `ObjectID byte range ${offset}:${offset + OBJECTID_BYTES - 1} is out of buffer bounds`,\n { strategy: 'objectid' },\n )\n }\n writeObjectIdBytesUnchecked(secs, random, counter, buf, offset)\n return buf\n }\n\n const bytes = new Uint8Array(OBJECTID_BYTES)\n writeObjectIdBytesUnchecked(secs, random, counter, bytes, 0)\n return encodeObjectIdHex(bytes)\n}\n\n/**\n * Convert an ObjectID hex string to 12 bytes.\n */\nfunction toBytes(id: string): Uint8Array {\n return decodeObjectIdHex(id)\n}\n\n/**\n * Convert 12 bytes to an ObjectID hex string.\n */\nfunction fromBytes(bytes: Uint8Array): string {\n if (bytes.length !== OBJECTID_BYTES) {\n throw new BufferError(\n 'BYTES_INVALID_LENGTH',\n `ObjectID bytes must be exactly ${OBJECTID_BYTES} bytes, got ${bytes.length}`,\n { strategy: 'objectid' },\n )\n }\n return encodeObjectIdHex(bytes)\n}\n\n/**\n * Extract the timestamp from an ObjectID string.\n * Returns Unix timestamp in milliseconds for API consistency with ulid/uuidv7/ksuid.\n * Note: ObjectID only has second precision, so the returned value will always end in 000.\n */\nfunction timestamp(id: string): number {\n const bytes = decodeObjectIdHex(id)\n // First 4 bytes are big-endian timestamp (seconds since Unix epoch)\n const secs = ((bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]) >>> 0\n return secs * 1000\n}\n\n/**\n * Validate an ObjectID string format.\n * Case-insensitive (KTD7), matching bson's ObjectId.isValid() and this repo's existing\n * convention (ulid, ksuid) of accepting mixed-case input for parsing, even though\n * generation always emits lowercase (matching MongoDB driver output).\n */\nfunction isValid(id: unknown): id is string {\n return typeof id === 'string' && OBJECTID_REGEX.test(id)\n}\n\n/**\n * Generate a MongoDB ObjectID string or write the bytes into a buffer.\n *\n * ObjectID is a 12-byte identifier consisting of a 4-byte timestamp, a 5-byte\n * per-process random value, and a 3-byte always-incrementing counter, encoded\n * as a 24-character lowercase hex string. It is time-ordered and compatible\n * with MongoDB's own ObjectID implementation.\n *\n * @example\n * ```ts\n * import { objectid } from 'uniku/objectid'\n *\n * const id = objectid()\n * // => \"667c3f2a1e2b3c4d5e6f7081\"\n *\n * // Extract timestamp\n * const ts = objectid.timestamp(id)\n * console.log(new Date(ts))\n *\n * // Validate\n * objectid.isValid(id) // true\n *\n * // Convert to/from bytes (12 bytes)\n * const bytes = objectid.toBytes(id)\n * const restored = objectid.fromBytes(bytes)\n * ```\n */\nexport const objectid: ObjectId = Object.assign(objectIdFn, {\n toBytes,\n fromBytes,\n timestamp,\n isValid,\n NIL: '0'.repeat(24),\n MAX: 'f'.repeat(24),\n})\n\nexport { BufferError, InvalidInputError, ParseError, UniqueIdError } from '../errors'\n"],"mappings":"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"}

@@ -1,2 +0,2 @@

import { a as ParseError, i as InvalidInputError, o as UniqueIdError, t as BufferError } from "../errors-Da-8dh4J.mjs";
import { BufferError, InvalidInputError, ParseError, UniqueIdError } from "../errors.mjs";

@@ -3,0 +3,0 @@ //#region src/tsid/tsid.d.ts

@@ -1,2 +0,2 @@

import { a as ParseError, i as InvalidInputError, o as UniqueIdError, t as BufferError } from "../errors-Da-8dh4J.mjs";
import { BufferError, InvalidInputError, ParseError, UniqueIdError } from "../errors.mjs";
import { UuidV7Options } from "../uuid/v7.mjs";

@@ -3,0 +3,0 @@

@@ -1,1 +0,1 @@

{"version":3,"file":"typeid.d.mts","names":[],"sources":["../../src/typeid/typeid.ts"],"mappings":";;;;KAKY,aAAA,GAAgB,aAAA;AAAA,KAEhB,MAAA;gFAET,MAAA,UAAgB,OAAA,GAAU,aAAA,WAJjB;EAAA,cAMI,UAAA,GAAa,UAAA,EACzB,MAAA,UACA,OAAA,EAAS,aAAA,cACT,GAAA,EAAK,IAAA,EACL,MAAA,YACC,IAAA,EAXuB;EAAA,CAazB,MAAA,UAAgB,OAAA,GAAU,aAAA,EAAe,GAAA,cAAiB,MAAA,oBAX7D;EAaE,OAAA,CAAQ,EAAA,WAAa,UAAA;EAErB,SAAA,CAAU,MAAA,UAAgB,KAAA,EAAO,UAAA;EAEjC,MAAA,CAAO,EAAA;EAEP,QAAA,CAAS,MAAA,UAAgB,IAAA;EAEzB,SAAA,CAAU,EAAA;EAEV,MAAA,CAAO,EAAA,mBAR0B;EAUjC,MAAA,CAAO,EAAA;EAEP,OAAA,CAAQ,EAAA,YAAc,EAAA;AAAA;;;;;;;;;;;;;;;;;;;cAgVX,MAAA,EAAQ,MAAA"}
{"version":3,"file":"typeid.d.mts","names":[],"sources":["../../src/typeid/typeid.ts"],"mappings":";;;;KAKY,aAAA,GAAgB,aAAA;AAAA,KAEhB,MAAA;gFAET,MAAA,UAAgB,OAAA,GAAU,aAAA,WAJjB;EAAA,cAMI,UAAA,GAAa,UAAA,EACzB,MAAA,UACA,OAAA,EAAS,aAAA,cACT,GAAA,EAAK,IAAA,EACL,MAAA,YACC,IAAA,EAXuB;EAAA,CAazB,MAAA,UAAgB,OAAA,GAAU,aAAA,EAAe,GAAA,cAAiB,MAAA,oBAX7D;EAaE,OAAA,CAAQ,EAAA,WAAa,UAAA;EAErB,SAAA,CAAU,MAAA,UAAgB,KAAA,EAAO,UAAA;EAEjC,MAAA,CAAO,EAAA;EAEP,QAAA,CAAS,MAAA,UAAgB,IAAA;EAEzB,SAAA,CAAU,EAAA;EAEV,MAAA,CAAO,EAAA,mBAR0B;EAUjC,MAAA,CAAO,EAAA;EAEP,OAAA,CAAQ,EAAA,YAAc,EAAA;AAAA;;;;;;;;;;;;;;;;;;;cA2UX,MAAA,EAAQ,MAAA"}

@@ -1,2 +0,2 @@

import{n as e,t}from"../validation-CTNpXm94.mjs";import{BufferError as n,InvalidInputError as r,ParseError as i,UniqueIdError as a}from"../errors.mjs";import{uuidv7 as o}from"../uuid/v7.mjs";const s=0xffffffffffff,c=4294967295,l=`0123456789abcdefghjkmnpqrstvwxyz`,u=Array.from({length:128},()=>-1);for(let e=0;e<32;e+=1)u[l.charCodeAt(e)]=e;function d(e){if(e.length!==0){if(e.length>63)throw new r(`PREFIX_TOO_LONG`,`TypeID prefix must be at most 63 characters`,{strategy:`typeid`});for(let t=0;t<e.length;t+=1){let n=e.charCodeAt(t),i=n>=97&&n<=122;if(!i&&n!==95)throw new r(`PREFIX_INVALID_CHAR`,`TypeID prefix must contain only lowercase ASCII letters and underscores`,{strategy:`typeid`});if((t===0||t===e.length-1)&&!i)throw new r(`PREFIX_INVALID_BOUNDARY`,`TypeID prefix must start and end with a-z`,{strategy:`typeid`})}}}function f(e,t){let n=e.charCodeAt(t),r=n<u.length?u[n]:-1;if(r===-1)throw new i(`INVALID_CHAR`,`TypeID suffix contains invalid character at position ${t}`,{strategy:`typeid`});return r}function p(e){if(e.length!==26)throw new i(`INVALID_LENGTH`,`TypeID suffix must be 26 characters, got ${e.length}`,{strategy:`typeid`});if(e[0]>`7`)throw new i(`VALUE_OUT_OF_RANGE`,`TypeID suffix must encode a 128-bit value`,{strategy:`typeid`})}function m(e){if(e.length!==16)throw new r(`BYTES_INVALID_LENGTH`,`UUID bytes must be 16 bytes, got ${e.length}`,{strategy:`typeid`});return l[(e[0]&224)>>5]+l[e[0]&31]+l[(e[1]&248)>>3]+l[(e[1]&7)<<2|(e[2]&192)>>6]+l[(e[2]&62)>>1]+l[(e[2]&1)<<4|(e[3]&240)>>4]+l[(e[3]&15)<<1|(e[4]&128)>>7]+l[(e[4]&124)>>2]+l[(e[4]&3)<<3|(e[5]&224)>>5]+l[e[5]&31]+l[(e[6]&248)>>3]+l[(e[6]&7)<<2|(e[7]&192)>>6]+l[(e[7]&62)>>1]+l[(e[7]&1)<<4|(e[8]&240)>>4]+l[(e[8]&15)<<1|(e[9]&128)>>7]+l[(e[9]&124)>>2]+l[(e[9]&3)<<3|(e[10]&224)>>5]+l[e[10]&31]+l[(e[11]&248)>>3]+l[(e[11]&7)<<2|(e[12]&192)>>6]+l[(e[12]&62)>>1]+l[(e[12]&1)<<4|(e[13]&240)>>4]+l[(e[13]&15)<<1|(e[14]&128)>>7]+l[(e[14]&124)>>2]+l[(e[14]&3)<<3|(e[15]&224)>>5]+l[e[15]&31]}function h(e){p(e);let t=Array(26);for(let n=0;n<26;n+=1)t[n]=f(e,n);let n=new Uint8Array(16);return n[0]=t[0]<<5|t[1],n[1]=t[2]<<3|t[3]>>2,n[2]=(t[3]&3)<<6|t[4]<<1|t[5]>>4,n[3]=(t[5]&15)<<4|t[6]>>1,n[4]=(t[6]&1)<<7|t[7]<<2|t[8]>>3,n[5]=(t[8]&7)<<5|t[9],n[6]=t[10]<<3|t[11]>>2,n[7]=(t[11]&3)<<6|t[12]<<1|t[13]>>4,n[8]=(t[13]&15)<<4|t[14]>>1,n[9]=(t[14]&1)<<7|t[15]<<2|t[16]>>3,n[10]=(t[16]&7)<<5|t[17],n[11]=t[18]<<3|t[19]>>2,n[12]=(t[19]&3)<<6|t[20]<<1|t[21]>>4,n[13]=(t[21]&15)<<4|t[22]>>1,n[14]=(t[22]&1)<<7|t[23]<<2|t[24]>>3,n[15]=(t[24]&7)<<5|t[25],n}function g(e){if(e.length!==16)throw new r(`BYTES_INVALID_LENGTH`,`UUID bytes must be 16 bytes, got ${e.length}`,{strategy:`typeid`});if(e[6]>>4!=7||(e[8]&192)!=128)throw new r(`UUID_NOT_V7`,`TypeID UUID bytes must encode a UUID v7 value`,{strategy:`typeid`})}function _(e){let t=h(e);return g(t),t}function v(e){if(!o.isValid(e))throw new r(`UUID_NOT_V7`,`TypeID can only wrap UUID v7 values`,{strategy:`typeid`});return o.toBytes(e)}function y(e){let t=e.lastIndexOf(`_`);if(t===0)throw new i(`INVALID_FORMAT`,`TypeID must not start with "_"`,{strategy:`typeid`});let n=t===-1?``:e.slice(0,t),r=t===-1?e:e.slice(t+1);return d(n),{prefix:n,suffix:r,bytes:_(r)}}function b(e,t){return e===``?t:`${e}_${t}`}function x(e,t){return d(e),g(t),b(e,m(t))}function S(e){let t=0;for(let n=0;n<6;n+=1)t=t*256+e[n];return t}function C(e){let n=e.msecs;if(n!==void 0&&!t(n,0,s))throw new r(`TIMESTAMP_OUT_OF_RANGE`,`Timestamp must be an integer between 0 and ${s}`,{strategy:`typeid`});if(e.counter!==void 0&&e.seq!==void 0)throw new r(`CONFLICTING_OPTIONS`,"Pass only one of `counter` or `seq`, not both",{strategy:`typeid`});let i=e.counter??e.seq;if(i!==void 0&&!t(i,0,c))throw new r(`COUNTER_OUT_OF_RANGE`,`Counter must be an integer between 0 and ${c}`,{strategy:`typeid`});let a=e.random;if(a&&a.length<16)throw new r(`RANDOM_BYTES_TOO_SHORT`,`Random bytes length must be >= 16`,{strategy:`typeid`})}function w(t,r,i,a=0){if(r!==void 0&&C(r),i){if(!e(i,a,16))throw new n(`BUFFER_OUT_OF_BOUNDS`,`TypeID byte range ${a}:${a+16-1} is out of buffer bounds`,{strategy:`typeid`});return d(t),o(r,i,a)}return x(t,o(r,new Uint8Array(16)))}function T(e){return y(e).bytes}function E(e,t){return x(e,t)}function D(e){return o.fromBytes(T(e))}function O(e,t){return x(e,v(t))}function k(e){return S(y(e).bytes)}function A(e){return y(e).prefix}function j(e){return y(e).suffix}function M(e){if(typeof e!=`string`)return!1;try{y(e)}catch{return!1}return!0}const N=Object.assign(w,{toBytes:T,fromBytes:E,toUuid:D,fromUuid:O,timestamp:k,prefix:A,suffix:j,isValid:M});export{n as BufferError,r as InvalidInputError,i as ParseError,a as UniqueIdError,N as typeid};
import{n as e,t}from"../validation-CTNpXm94.mjs";import{BufferError as n,InvalidInputError as r,ParseError as i,UniqueIdError as a}from"../errors.mjs";import{uuidv7 as o}from"../uuid/v7.mjs";const s=0xffffffffffff,c=4294967295,l=`0123456789abcdefghjkmnpqrstvwxyz`,u=Array.from({length:128},()=>-1);for(let e=0;e<32;e+=1)u[l.charCodeAt(e)]=e;function d(e){if(e.length!==0){if(e.length>63)throw new r(`PREFIX_TOO_LONG`,`TypeID prefix must be at most 63 characters`,{strategy:`typeid`});for(let t=0;t<e.length;t+=1){let n=e.charCodeAt(t),i=n>=97&&n<=122;if(!i&&n!==95)throw new r(`PREFIX_INVALID_CHAR`,`TypeID prefix must contain only lowercase ASCII letters and underscores`,{strategy:`typeid`});if((t===0||t===e.length-1)&&!i)throw new r(`PREFIX_INVALID_BOUNDARY`,`TypeID prefix must start and end with a-z`,{strategy:`typeid`})}}}function f(e,t){let n=e.charCodeAt(t),r=n<u.length?u[n]:-1;if(r===-1)throw new i(`INVALID_CHAR`,`TypeID suffix contains invalid character at position ${t}`,{strategy:`typeid`});return r}function p(e){if(e.length!==26)throw new i(`INVALID_LENGTH`,`TypeID suffix must be 26 characters, got ${e.length}`,{strategy:`typeid`});if(e[0]>`7`)throw new i(`VALUE_OUT_OF_RANGE`,`TypeID suffix must encode a 128-bit value`,{strategy:`typeid`})}function m(e){if(e.length!==16)throw new r(`BYTES_INVALID_LENGTH`,`UUID bytes must be 16 bytes, got ${e.length}`,{strategy:`typeid`});return l[(e[0]&224)>>5]+l[e[0]&31]+l[(e[1]&248)>>3]+l[(e[1]&7)<<2|(e[2]&192)>>6]+l[(e[2]&62)>>1]+l[(e[2]&1)<<4|(e[3]&240)>>4]+l[(e[3]&15)<<1|(e[4]&128)>>7]+l[(e[4]&124)>>2]+l[(e[4]&3)<<3|(e[5]&224)>>5]+l[e[5]&31]+l[(e[6]&248)>>3]+l[(e[6]&7)<<2|(e[7]&192)>>6]+l[(e[7]&62)>>1]+l[(e[7]&1)<<4|(e[8]&240)>>4]+l[(e[8]&15)<<1|(e[9]&128)>>7]+l[(e[9]&124)>>2]+l[(e[9]&3)<<3|(e[10]&224)>>5]+l[e[10]&31]+l[(e[11]&248)>>3]+l[(e[11]&7)<<2|(e[12]&192)>>6]+l[(e[12]&62)>>1]+l[(e[12]&1)<<4|(e[13]&240)>>4]+l[(e[13]&15)<<1|(e[14]&128)>>7]+l[(e[14]&124)>>2]+l[(e[14]&3)<<3|(e[15]&224)>>5]+l[e[15]&31]}function h(e){p(e);let t=Array(26);for(let n=0;n<26;n+=1)t[n]=f(e,n);let n=new Uint8Array(16);return n[0]=t[0]<<5|t[1],n[1]=t[2]<<3|t[3]>>2,n[2]=(t[3]&3)<<6|t[4]<<1|t[5]>>4,n[3]=(t[5]&15)<<4|t[6]>>1,n[4]=(t[6]&1)<<7|t[7]<<2|t[8]>>3,n[5]=(t[8]&7)<<5|t[9],n[6]=t[10]<<3|t[11]>>2,n[7]=(t[11]&3)<<6|t[12]<<1|t[13]>>4,n[8]=(t[13]&15)<<4|t[14]>>1,n[9]=(t[14]&1)<<7|t[15]<<2|t[16]>>3,n[10]=(t[16]&7)<<5|t[17],n[11]=t[18]<<3|t[19]>>2,n[12]=(t[19]&3)<<6|t[20]<<1|t[21]>>4,n[13]=(t[21]&15)<<4|t[22]>>1,n[14]=(t[22]&1)<<7|t[23]<<2|t[24]>>3,n[15]=(t[24]&7)<<5|t[25],n}function g(e){if(e.length!==16)throw new r(`BYTES_INVALID_LENGTH`,`UUID bytes must be 16 bytes, got ${e.length}`,{strategy:`typeid`});if(e[6]>>4!=7||(e[8]&192)!=128)throw new r(`UUID_NOT_V7`,`TypeID UUID bytes must encode a UUID v7 value`,{strategy:`typeid`})}function _(e){let t=h(e);return g(t),t}function v(e){if(!o.isValid(e))throw new r(`UUID_NOT_V7`,`TypeID can only wrap UUID v7 values`,{strategy:`typeid`});return o.toBytes(e)}function y(e){let t=e.lastIndexOf(`_`);if(t===0)throw new i(`INVALID_FORMAT`,`TypeID must not start with "_"`,{strategy:`typeid`});let n=t===-1?``:e.slice(0,t),r=t===-1?e:e.slice(t+1);return d(n),{prefix:n,suffix:r,bytes:_(r)}}function b(e,t){return e===``?t:`${e}_${t}`}function x(e,t){return d(e),g(t),b(e,m(t))}function S(e){let t=0;for(let n=0;n<6;n+=1)t=t*256+e[n];return t}function C(e){let n=e.msecs;if(n!==void 0&&!t(n,0,s))throw new r(`TIMESTAMP_OUT_OF_RANGE`,`Timestamp must be an integer between 0 and ${s}`,{strategy:`typeid`});let i=e.counter;if(i!==void 0&&!t(i,0,c))throw new r(`COUNTER_OUT_OF_RANGE`,`Counter must be an integer between 0 and ${c}`,{strategy:`typeid`});let a=e.random;if(a&&a.length<16)throw new r(`RANDOM_BYTES_TOO_SHORT`,`Random bytes length must be >= 16`,{strategy:`typeid`})}function w(t,r,i,a=0){if(r!==void 0&&C(r),i){if(!e(i,a,16))throw new n(`BUFFER_OUT_OF_BOUNDS`,`TypeID byte range ${a}:${a+16-1} is out of buffer bounds`,{strategy:`typeid`});return d(t),o(r,i,a)}return x(t,o(r,new Uint8Array(16)))}function T(e){return y(e).bytes}function E(e,t){return x(e,t)}function D(e){return o.fromBytes(T(e))}function O(e,t){return x(e,v(t))}function k(e){return S(y(e).bytes)}function A(e){return y(e).prefix}function j(e){return y(e).suffix}function M(e){if(typeof e!=`string`)return!1;try{y(e)}catch{return!1}return!0}const N=Object.assign(w,{toBytes:T,fromBytes:E,toUuid:D,fromUuid:O,timestamp:k,prefix:A,suffix:j,isValid:M});export{n as BufferError,r as InvalidInputError,i as ParseError,a as UniqueIdError,N as typeid};
//# sourceMappingURL=typeid.mjs.map

@@ -1,1 +0,1 @@

{"version":3,"file":"typeid.mjs","names":[],"sources":["../../src/typeid/typeid.ts"],"sourcesContent":["import { isIntegerInRange, isWritableRange } from '../common/validation'\nimport { BufferError, InvalidInputError, ParseError } from '../errors'\nimport type { UuidV7Options } from '../uuid/v7'\nimport { uuidv7 } from '../uuid/v7'\n\nexport type TypeidOptions = UuidV7Options\n\nexport type Typeid = {\n /** Generate a TypeID from a lowercase entity prefix and a UUID v7 suffix. */\n (prefix: string, options?: TypeidOptions): string\n /** Generate a TypeID with explicit options or write its 16 canonical UUID v7 bytes into a caller-owned buffer. */\n <TBuf extends Uint8Array = Uint8Array>(\n prefix: string,\n options: TypeidOptions | undefined,\n buf: TBuf,\n offset?: number,\n ): TBuf\n /** Generate a TypeID string with optional timestamp, counter, or random bytes. */\n (prefix: string, options?: TypeidOptions, buf?: undefined, offset?: number): string\n /** Convert a TypeID's UUID v7 suffix to its canonical 16-byte representation. */\n toBytes(id: string): Uint8Array\n /** Build a TypeID from a prefix and canonical UUID v7 bytes. */\n fromBytes(prefix: string, bytes: Uint8Array): string\n /** Convert a TypeID to its UUID v7 string. */\n toUuid(id: string): string\n /** Build a TypeID from a prefix and UUID v7 string. */\n fromUuid(prefix: string, uuid: string): string\n /** Read the UUID v7 timestamp embedded in a TypeID, in milliseconds. */\n timestamp(id: string): number\n /** Read a TypeID's entity prefix. */\n prefix(id: string): string\n /** Read a TypeID's UUID v7 suffix. */\n suffix(id: string): string\n /** Return whether a value is a syntactically valid TypeID. */\n isValid(id: unknown): id is string\n}\n\nconst TYPEID_SUFFIX_LENGTH = 26\nconst TYPEID_UUID_BYTE_LENGTH = 16\n// 48-bit UUID v7 timestamp capacity, mirrored from uuid/v7 alongside the\n// 32-bit counter capacity, so option validation is attributed to the typeid\n// boundary instead of leaking `strategy: 'uuid'` through delegation.\nconst MAX_MSECS = 0xffffffffffff\nconst MAX_COUNTER = 0xffffffff\nconst TYPEID_ALPHABET = '0123456789abcdefghjkmnpqrstvwxyz'\n\nconst BASE32_DECODE: number[] = Array.from({ length: 128 }, () => -1)\nfor (let i = 0; i < TYPEID_ALPHABET.length; i += 1) {\n BASE32_DECODE[TYPEID_ALPHABET.charCodeAt(i)] = i\n}\n\ntype ParsedTypeid = {\n prefix: string\n suffix: string\n bytes: Uint8Array\n}\n\nfunction assertValidPrefix(prefix: string): void {\n if (prefix.length === 0) {\n return\n }\n\n if (prefix.length > 63) {\n throw new InvalidInputError('PREFIX_TOO_LONG', 'TypeID prefix must be at most 63 characters', {\n strategy: 'typeid',\n })\n }\n\n for (let i = 0; i < prefix.length; i += 1) {\n const code = prefix.charCodeAt(i)\n const isLowercaseLetter = code >= 97 && code <= 122\n const isUnderscore = code === 95\n\n if (!isLowercaseLetter && !isUnderscore) {\n throw new InvalidInputError(\n 'PREFIX_INVALID_CHAR',\n 'TypeID prefix must contain only lowercase ASCII letters and underscores',\n { strategy: 'typeid' },\n )\n }\n\n if ((i === 0 || i === prefix.length - 1) && !isLowercaseLetter) {\n throw new InvalidInputError('PREFIX_INVALID_BOUNDARY', 'TypeID prefix must start and end with a-z', {\n strategy: 'typeid',\n })\n }\n }\n}\n\nfunction decodeSuffixValue(suffix: string, index: number): number {\n const code = suffix.charCodeAt(index)\n const value = code < BASE32_DECODE.length ? BASE32_DECODE[code] : -1\n\n if (value === -1) {\n throw new ParseError('INVALID_CHAR', `TypeID suffix contains invalid character at position ${index}`, {\n strategy: 'typeid',\n })\n }\n\n return value\n}\n\nfunction assertValidSuffixShape(suffix: string): void {\n if (suffix.length !== TYPEID_SUFFIX_LENGTH) {\n throw new ParseError('INVALID_LENGTH', `TypeID suffix must be 26 characters, got ${suffix.length}`, {\n strategy: 'typeid',\n })\n }\n\n if (suffix[0] > '7') {\n throw new ParseError('VALUE_OUT_OF_RANGE', 'TypeID suffix must encode a 128-bit value', {\n strategy: 'typeid',\n })\n }\n}\n\nfunction encodeBytesToSuffix(bytes: Uint8Array): string {\n if (bytes.length !== TYPEID_UUID_BYTE_LENGTH) {\n throw new InvalidInputError('BYTES_INVALID_LENGTH', `UUID bytes must be 16 bytes, got ${bytes.length}`, {\n strategy: 'typeid',\n })\n }\n\n return (\n TYPEID_ALPHABET[(bytes[0] & 0xe0) >> 5] +\n TYPEID_ALPHABET[bytes[0] & 0x1f] +\n TYPEID_ALPHABET[(bytes[1] & 0xf8) >> 3] +\n TYPEID_ALPHABET[((bytes[1] & 0x07) << 2) | ((bytes[2] & 0xc0) >> 6)] +\n TYPEID_ALPHABET[(bytes[2] & 0x3e) >> 1] +\n TYPEID_ALPHABET[((bytes[2] & 0x01) << 4) | ((bytes[3] & 0xf0) >> 4)] +\n TYPEID_ALPHABET[((bytes[3] & 0x0f) << 1) | ((bytes[4] & 0x80) >> 7)] +\n TYPEID_ALPHABET[(bytes[4] & 0x7c) >> 2] +\n TYPEID_ALPHABET[((bytes[4] & 0x03) << 3) | ((bytes[5] & 0xe0) >> 5)] +\n TYPEID_ALPHABET[bytes[5] & 0x1f] +\n TYPEID_ALPHABET[(bytes[6] & 0xf8) >> 3] +\n TYPEID_ALPHABET[((bytes[6] & 0x07) << 2) | ((bytes[7] & 0xc0) >> 6)] +\n TYPEID_ALPHABET[(bytes[7] & 0x3e) >> 1] +\n TYPEID_ALPHABET[((bytes[7] & 0x01) << 4) | ((bytes[8] & 0xf0) >> 4)] +\n TYPEID_ALPHABET[((bytes[8] & 0x0f) << 1) | ((bytes[9] & 0x80) >> 7)] +\n TYPEID_ALPHABET[(bytes[9] & 0x7c) >> 2] +\n TYPEID_ALPHABET[((bytes[9] & 0x03) << 3) | ((bytes[10] & 0xe0) >> 5)] +\n TYPEID_ALPHABET[bytes[10] & 0x1f] +\n TYPEID_ALPHABET[(bytes[11] & 0xf8) >> 3] +\n TYPEID_ALPHABET[((bytes[11] & 0x07) << 2) | ((bytes[12] & 0xc0) >> 6)] +\n TYPEID_ALPHABET[(bytes[12] & 0x3e) >> 1] +\n TYPEID_ALPHABET[((bytes[12] & 0x01) << 4) | ((bytes[13] & 0xf0) >> 4)] +\n TYPEID_ALPHABET[((bytes[13] & 0x0f) << 1) | ((bytes[14] & 0x80) >> 7)] +\n TYPEID_ALPHABET[(bytes[14] & 0x7c) >> 2] +\n TYPEID_ALPHABET[((bytes[14] & 0x03) << 3) | ((bytes[15] & 0xe0) >> 5)] +\n TYPEID_ALPHABET[bytes[15] & 0x1f]\n )\n}\n\nfunction decodeSuffixToBytes(suffix: string): Uint8Array {\n assertValidSuffixShape(suffix)\n\n const values = new Array<number>(TYPEID_SUFFIX_LENGTH)\n for (let i = 0; i < TYPEID_SUFFIX_LENGTH; i += 1) {\n values[i] = decodeSuffixValue(suffix, i)\n }\n\n const bytes = new Uint8Array(TYPEID_UUID_BYTE_LENGTH)\n bytes[0] = (values[0] << 5) | values[1]\n bytes[1] = (values[2] << 3) | (values[3] >> 2)\n bytes[2] = ((values[3] & 0x03) << 6) | (values[4] << 1) | (values[5] >> 4)\n bytes[3] = ((values[5] & 0x0f) << 4) | (values[6] >> 1)\n bytes[4] = ((values[6] & 0x01) << 7) | (values[7] << 2) | (values[8] >> 3)\n bytes[5] = ((values[8] & 0x07) << 5) | values[9]\n bytes[6] = (values[10] << 3) | (values[11] >> 2)\n bytes[7] = ((values[11] & 0x03) << 6) | (values[12] << 1) | (values[13] >> 4)\n bytes[8] = ((values[13] & 0x0f) << 4) | (values[14] >> 1)\n bytes[9] = ((values[14] & 0x01) << 7) | (values[15] << 2) | (values[16] >> 3)\n bytes[10] = ((values[16] & 0x07) << 5) | values[17]\n bytes[11] = (values[18] << 3) | (values[19] >> 2)\n bytes[12] = ((values[19] & 0x03) << 6) | (values[20] << 1) | (values[21] >> 4)\n bytes[13] = ((values[21] & 0x0f) << 4) | (values[22] >> 1)\n bytes[14] = ((values[22] & 0x01) << 7) | (values[23] << 2) | (values[24] >> 3)\n bytes[15] = ((values[24] & 0x07) << 5) | values[25]\n\n return bytes\n}\n\nfunction assertUuidV7Bytes(bytes: Uint8Array): void {\n if (bytes.length !== TYPEID_UUID_BYTE_LENGTH) {\n throw new InvalidInputError('BYTES_INVALID_LENGTH', `UUID bytes must be 16 bytes, got ${bytes.length}`, {\n strategy: 'typeid',\n })\n }\n\n if (bytes[6] >> 4 !== 7 || (bytes[8] & 0xc0) !== 0x80) {\n throw new InvalidInputError('UUID_NOT_V7', 'TypeID UUID bytes must encode a UUID v7 value', {\n strategy: 'typeid',\n })\n }\n}\n\nfunction uuidV7BytesFromSuffix(suffix: string): Uint8Array {\n const bytes = decodeSuffixToBytes(suffix)\n assertUuidV7Bytes(bytes)\n return bytes\n}\n\nfunction uuidV7BytesFromUuid(uuid: string): Uint8Array {\n if (!uuidv7.isValid(uuid)) {\n throw new InvalidInputError('UUID_NOT_V7', 'TypeID can only wrap UUID v7 values', { strategy: 'typeid' })\n }\n\n return uuidv7.toBytes(uuid)\n}\n\nfunction parseTypeid(id: string): ParsedTypeid {\n const separatorIndex = id.lastIndexOf('_')\n\n if (separatorIndex === 0) {\n throw new ParseError('INVALID_FORMAT', 'TypeID must not start with \"_\"', { strategy: 'typeid' })\n }\n\n const prefix = separatorIndex === -1 ? '' : id.slice(0, separatorIndex)\n const suffix = separatorIndex === -1 ? id : id.slice(separatorIndex + 1)\n\n assertValidPrefix(prefix)\n const bytes = uuidV7BytesFromSuffix(suffix)\n\n return { prefix, suffix, bytes }\n}\n\nfunction joinPrefixAndSuffix(prefix: string, suffix: string): string {\n return prefix === '' ? suffix : `${prefix}_${suffix}`\n}\n\nfunction formatTypeidFromUuidV7Bytes(prefix: string, bytes: Uint8Array): string {\n assertValidPrefix(prefix)\n assertUuidV7Bytes(bytes)\n return joinPrefixAndSuffix(prefix, encodeBytesToSuffix(bytes))\n}\n\nfunction timestampFromUuidV7Bytes(bytes: Uint8Array): number {\n let msecs = 0\n for (let i = 0; i < 6; i += 1) {\n msecs = msecs * 256 + bytes[i]\n }\n return msecs\n}\n\n/**\n * Mirror uuid/v7's option validation at the typeid boundary, so failures are\n * attributed to `strategy: 'typeid'` instead of leaking `strategy: 'uuid'`\n * through delegation.\n */\nfunction validateTypeidOptions(options: TypeidOptions): void {\n const msecs = options.msecs\n if (msecs !== undefined && !isIntegerInRange(msecs, 0, MAX_MSECS)) {\n throw new InvalidInputError('TIMESTAMP_OUT_OF_RANGE', `Timestamp must be an integer between 0 and ${MAX_MSECS}`, {\n strategy: 'typeid',\n })\n }\n\n if (options.counter !== undefined && options.seq !== undefined) {\n throw new InvalidInputError('CONFLICTING_OPTIONS', 'Pass only one of `counter` or `seq`, not both', {\n strategy: 'typeid',\n })\n }\n const counter = options.counter ?? options.seq\n if (counter !== undefined && !isIntegerInRange(counter, 0, MAX_COUNTER)) {\n throw new InvalidInputError('COUNTER_OUT_OF_RANGE', `Counter must be an integer between 0 and ${MAX_COUNTER}`, {\n strategy: 'typeid',\n })\n }\n\n const random = options.random\n if (random && random.length < TYPEID_UUID_BYTE_LENGTH) {\n throw new InvalidInputError('RANDOM_BYTES_TOO_SHORT', `Random bytes length must be >= ${TYPEID_UUID_BYTE_LENGTH}`, {\n strategy: 'typeid',\n })\n }\n}\n\nfunction typeidFn(prefix: string, options?: TypeidOptions, buf?: undefined, offset?: number): string\nfunction typeidFn<TBuf extends Uint8Array = Uint8Array>(\n prefix: string,\n options: TypeidOptions | undefined,\n buf: TBuf,\n offset?: number,\n): TBuf\nfunction typeidFn<TBuf extends Uint8Array = Uint8Array>(\n prefix: string,\n options?: TypeidOptions,\n buf?: TBuf,\n offset = 0,\n): string | TBuf {\n if (options !== undefined) {\n validateTypeidOptions(options)\n }\n\n if (buf) {\n if (!isWritableRange(buf, offset, TYPEID_UUID_BYTE_LENGTH)) {\n throw new BufferError(\n 'BUFFER_OUT_OF_BOUNDS',\n `TypeID byte range ${offset}:${offset + TYPEID_UUID_BYTE_LENGTH - 1} is out of buffer bounds`,\n { strategy: 'typeid' },\n )\n }\n assertValidPrefix(prefix)\n return uuidv7(options, buf, offset)\n }\n\n const bytes = uuidv7(options, new Uint8Array(TYPEID_UUID_BYTE_LENGTH))\n return formatTypeidFromUuidV7Bytes(prefix, bytes)\n}\n\nfunction typeidToBytes(id: string): Uint8Array {\n return parseTypeid(id).bytes\n}\n\nfunction typeidFromBytes(prefix: string, bytes: Uint8Array): string {\n return formatTypeidFromUuidV7Bytes(prefix, bytes)\n}\n\nfunction typeidToUuid(id: string): string {\n return uuidv7.fromBytes(typeidToBytes(id))\n}\n\nfunction typeidFromUuid(prefix: string, uuid: string): string {\n return formatTypeidFromUuidV7Bytes(prefix, uuidV7BytesFromUuid(uuid))\n}\n\nfunction timestamp(id: string): number {\n return timestampFromUuidV7Bytes(parseTypeid(id).bytes)\n}\n\nfunction prefix(id: string): string {\n return parseTypeid(id).prefix\n}\n\nfunction suffix(id: string): string {\n return parseTypeid(id).suffix\n}\n\nfunction isValid(id: unknown): id is string {\n if (typeof id !== 'string') {\n return false\n }\n\n try {\n parseTypeid(id)\n } catch {\n return false\n }\n\n return true\n}\n\n/**\n * Generate a TypeID string backed by UUID v7.\n *\n * TypeID combines a lowercase snake_case type prefix with a 26-character\n * modified base32 encoding of a UUID v7, producing sortable domain identifiers\n * such as `user_01h2xcejqtf2nbrexx3vqjhp41`.\n *\n * @example\n * ```ts\n * import { typeid } from 'uniku/typeid'\n *\n * const id = typeid('user')\n * // => \"user_01h2xcejqtf2nbrexx3vqjhp41\"\n *\n * const uuid = typeid.toUuid(id)\n * const restored = typeid.fromUuid('user', uuid)\n * ```\n */\nexport const typeid: Typeid = Object.assign(typeidFn, {\n toBytes: typeidToBytes,\n fromBytes: typeidFromBytes,\n toUuid: typeidToUuid,\n fromUuid: typeidFromUuid,\n timestamp,\n prefix,\n suffix,\n isValid,\n})\n\nexport { BufferError, InvalidInputError, ParseError, UniqueIdError } from '../errors'\n"],"mappings":"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"}
{"version":3,"file":"typeid.mjs","names":[],"sources":["../../src/typeid/typeid.ts"],"sourcesContent":["import { isIntegerInRange, isWritableRange } from '../common/validation'\nimport { BufferError, InvalidInputError, ParseError } from '../errors'\nimport type { UuidV7Options } from '../uuid/v7'\nimport { uuidv7 } from '../uuid/v7'\n\nexport type TypeidOptions = UuidV7Options\n\nexport type Typeid = {\n /** Generate a TypeID from a lowercase entity prefix and a UUID v7 suffix. */\n (prefix: string, options?: TypeidOptions): string\n /** Generate a TypeID with explicit options or write its 16 canonical UUID v7 bytes into a caller-owned buffer. */\n <TBuf extends Uint8Array = Uint8Array>(\n prefix: string,\n options: TypeidOptions | undefined,\n buf: TBuf,\n offset?: number,\n ): TBuf\n /** Generate a TypeID string with optional timestamp, counter, or random bytes. */\n (prefix: string, options?: TypeidOptions, buf?: undefined, offset?: number): string\n /** Convert a TypeID's UUID v7 suffix to its canonical 16-byte representation. */\n toBytes(id: string): Uint8Array\n /** Build a TypeID from a prefix and canonical UUID v7 bytes. */\n fromBytes(prefix: string, bytes: Uint8Array): string\n /** Convert a TypeID to its UUID v7 string. */\n toUuid(id: string): string\n /** Build a TypeID from a prefix and UUID v7 string. */\n fromUuid(prefix: string, uuid: string): string\n /** Read the UUID v7 timestamp embedded in a TypeID, in milliseconds. */\n timestamp(id: string): number\n /** Read a TypeID's entity prefix. */\n prefix(id: string): string\n /** Read a TypeID's UUID v7 suffix. */\n suffix(id: string): string\n /** Return whether a value is a syntactically valid TypeID. */\n isValid(id: unknown): id is string\n}\n\nconst TYPEID_SUFFIX_LENGTH = 26\nconst TYPEID_UUID_BYTE_LENGTH = 16\n// 48-bit UUID v7 timestamp capacity, mirrored from uuid/v7 alongside the\n// 32-bit counter capacity, so option validation is attributed to the typeid\n// boundary instead of leaking `strategy: 'uuid'` through delegation.\nconst MAX_MSECS = 0xffffffffffff\nconst MAX_COUNTER = 0xffffffff\nconst TYPEID_ALPHABET = '0123456789abcdefghjkmnpqrstvwxyz'\n\nconst BASE32_DECODE: number[] = Array.from({ length: 128 }, () => -1)\nfor (let i = 0; i < TYPEID_ALPHABET.length; i += 1) {\n BASE32_DECODE[TYPEID_ALPHABET.charCodeAt(i)] = i\n}\n\ntype ParsedTypeid = {\n prefix: string\n suffix: string\n bytes: Uint8Array\n}\n\nfunction assertValidPrefix(prefix: string): void {\n if (prefix.length === 0) {\n return\n }\n\n if (prefix.length > 63) {\n throw new InvalidInputError('PREFIX_TOO_LONG', 'TypeID prefix must be at most 63 characters', {\n strategy: 'typeid',\n })\n }\n\n for (let i = 0; i < prefix.length; i += 1) {\n const code = prefix.charCodeAt(i)\n const isLowercaseLetter = code >= 97 && code <= 122\n const isUnderscore = code === 95\n\n if (!isLowercaseLetter && !isUnderscore) {\n throw new InvalidInputError(\n 'PREFIX_INVALID_CHAR',\n 'TypeID prefix must contain only lowercase ASCII letters and underscores',\n { strategy: 'typeid' },\n )\n }\n\n if ((i === 0 || i === prefix.length - 1) && !isLowercaseLetter) {\n throw new InvalidInputError('PREFIX_INVALID_BOUNDARY', 'TypeID prefix must start and end with a-z', {\n strategy: 'typeid',\n })\n }\n }\n}\n\nfunction decodeSuffixValue(suffix: string, index: number): number {\n const code = suffix.charCodeAt(index)\n const value = code < BASE32_DECODE.length ? BASE32_DECODE[code] : -1\n\n if (value === -1) {\n throw new ParseError('INVALID_CHAR', `TypeID suffix contains invalid character at position ${index}`, {\n strategy: 'typeid',\n })\n }\n\n return value\n}\n\nfunction assertValidSuffixShape(suffix: string): void {\n if (suffix.length !== TYPEID_SUFFIX_LENGTH) {\n throw new ParseError('INVALID_LENGTH', `TypeID suffix must be 26 characters, got ${suffix.length}`, {\n strategy: 'typeid',\n })\n }\n\n if (suffix[0] > '7') {\n throw new ParseError('VALUE_OUT_OF_RANGE', 'TypeID suffix must encode a 128-bit value', {\n strategy: 'typeid',\n })\n }\n}\n\nfunction encodeBytesToSuffix(bytes: Uint8Array): string {\n if (bytes.length !== TYPEID_UUID_BYTE_LENGTH) {\n throw new InvalidInputError('BYTES_INVALID_LENGTH', `UUID bytes must be 16 bytes, got ${bytes.length}`, {\n strategy: 'typeid',\n })\n }\n\n return (\n TYPEID_ALPHABET[(bytes[0] & 0xe0) >> 5] +\n TYPEID_ALPHABET[bytes[0] & 0x1f] +\n TYPEID_ALPHABET[(bytes[1] & 0xf8) >> 3] +\n TYPEID_ALPHABET[((bytes[1] & 0x07) << 2) | ((bytes[2] & 0xc0) >> 6)] +\n TYPEID_ALPHABET[(bytes[2] & 0x3e) >> 1] +\n TYPEID_ALPHABET[((bytes[2] & 0x01) << 4) | ((bytes[3] & 0xf0) >> 4)] +\n TYPEID_ALPHABET[((bytes[3] & 0x0f) << 1) | ((bytes[4] & 0x80) >> 7)] +\n TYPEID_ALPHABET[(bytes[4] & 0x7c) >> 2] +\n TYPEID_ALPHABET[((bytes[4] & 0x03) << 3) | ((bytes[5] & 0xe0) >> 5)] +\n TYPEID_ALPHABET[bytes[5] & 0x1f] +\n TYPEID_ALPHABET[(bytes[6] & 0xf8) >> 3] +\n TYPEID_ALPHABET[((bytes[6] & 0x07) << 2) | ((bytes[7] & 0xc0) >> 6)] +\n TYPEID_ALPHABET[(bytes[7] & 0x3e) >> 1] +\n TYPEID_ALPHABET[((bytes[7] & 0x01) << 4) | ((bytes[8] & 0xf0) >> 4)] +\n TYPEID_ALPHABET[((bytes[8] & 0x0f) << 1) | ((bytes[9] & 0x80) >> 7)] +\n TYPEID_ALPHABET[(bytes[9] & 0x7c) >> 2] +\n TYPEID_ALPHABET[((bytes[9] & 0x03) << 3) | ((bytes[10] & 0xe0) >> 5)] +\n TYPEID_ALPHABET[bytes[10] & 0x1f] +\n TYPEID_ALPHABET[(bytes[11] & 0xf8) >> 3] +\n TYPEID_ALPHABET[((bytes[11] & 0x07) << 2) | ((bytes[12] & 0xc0) >> 6)] +\n TYPEID_ALPHABET[(bytes[12] & 0x3e) >> 1] +\n TYPEID_ALPHABET[((bytes[12] & 0x01) << 4) | ((bytes[13] & 0xf0) >> 4)] +\n TYPEID_ALPHABET[((bytes[13] & 0x0f) << 1) | ((bytes[14] & 0x80) >> 7)] +\n TYPEID_ALPHABET[(bytes[14] & 0x7c) >> 2] +\n TYPEID_ALPHABET[((bytes[14] & 0x03) << 3) | ((bytes[15] & 0xe0) >> 5)] +\n TYPEID_ALPHABET[bytes[15] & 0x1f]\n )\n}\n\nfunction decodeSuffixToBytes(suffix: string): Uint8Array {\n assertValidSuffixShape(suffix)\n\n const values = new Array<number>(TYPEID_SUFFIX_LENGTH)\n for (let i = 0; i < TYPEID_SUFFIX_LENGTH; i += 1) {\n values[i] = decodeSuffixValue(suffix, i)\n }\n\n const bytes = new Uint8Array(TYPEID_UUID_BYTE_LENGTH)\n bytes[0] = (values[0] << 5) | values[1]\n bytes[1] = (values[2] << 3) | (values[3] >> 2)\n bytes[2] = ((values[3] & 0x03) << 6) | (values[4] << 1) | (values[5] >> 4)\n bytes[3] = ((values[5] & 0x0f) << 4) | (values[6] >> 1)\n bytes[4] = ((values[6] & 0x01) << 7) | (values[7] << 2) | (values[8] >> 3)\n bytes[5] = ((values[8] & 0x07) << 5) | values[9]\n bytes[6] = (values[10] << 3) | (values[11] >> 2)\n bytes[7] = ((values[11] & 0x03) << 6) | (values[12] << 1) | (values[13] >> 4)\n bytes[8] = ((values[13] & 0x0f) << 4) | (values[14] >> 1)\n bytes[9] = ((values[14] & 0x01) << 7) | (values[15] << 2) | (values[16] >> 3)\n bytes[10] = ((values[16] & 0x07) << 5) | values[17]\n bytes[11] = (values[18] << 3) | (values[19] >> 2)\n bytes[12] = ((values[19] & 0x03) << 6) | (values[20] << 1) | (values[21] >> 4)\n bytes[13] = ((values[21] & 0x0f) << 4) | (values[22] >> 1)\n bytes[14] = ((values[22] & 0x01) << 7) | (values[23] << 2) | (values[24] >> 3)\n bytes[15] = ((values[24] & 0x07) << 5) | values[25]\n\n return bytes\n}\n\nfunction assertUuidV7Bytes(bytes: Uint8Array): void {\n if (bytes.length !== TYPEID_UUID_BYTE_LENGTH) {\n throw new InvalidInputError('BYTES_INVALID_LENGTH', `UUID bytes must be 16 bytes, got ${bytes.length}`, {\n strategy: 'typeid',\n })\n }\n\n if (bytes[6] >> 4 !== 7 || (bytes[8] & 0xc0) !== 0x80) {\n throw new InvalidInputError('UUID_NOT_V7', 'TypeID UUID bytes must encode a UUID v7 value', {\n strategy: 'typeid',\n })\n }\n}\n\nfunction uuidV7BytesFromSuffix(suffix: string): Uint8Array {\n const bytes = decodeSuffixToBytes(suffix)\n assertUuidV7Bytes(bytes)\n return bytes\n}\n\nfunction uuidV7BytesFromUuid(uuid: string): Uint8Array {\n if (!uuidv7.isValid(uuid)) {\n throw new InvalidInputError('UUID_NOT_V7', 'TypeID can only wrap UUID v7 values', { strategy: 'typeid' })\n }\n\n return uuidv7.toBytes(uuid)\n}\n\nfunction parseTypeid(id: string): ParsedTypeid {\n const separatorIndex = id.lastIndexOf('_')\n\n if (separatorIndex === 0) {\n throw new ParseError('INVALID_FORMAT', 'TypeID must not start with \"_\"', { strategy: 'typeid' })\n }\n\n const prefix = separatorIndex === -1 ? '' : id.slice(0, separatorIndex)\n const suffix = separatorIndex === -1 ? id : id.slice(separatorIndex + 1)\n\n assertValidPrefix(prefix)\n const bytes = uuidV7BytesFromSuffix(suffix)\n\n return { prefix, suffix, bytes }\n}\n\nfunction joinPrefixAndSuffix(prefix: string, suffix: string): string {\n return prefix === '' ? suffix : `${prefix}_${suffix}`\n}\n\nfunction formatTypeidFromUuidV7Bytes(prefix: string, bytes: Uint8Array): string {\n assertValidPrefix(prefix)\n assertUuidV7Bytes(bytes)\n return joinPrefixAndSuffix(prefix, encodeBytesToSuffix(bytes))\n}\n\nfunction timestampFromUuidV7Bytes(bytes: Uint8Array): number {\n let msecs = 0\n for (let i = 0; i < 6; i += 1) {\n msecs = msecs * 256 + bytes[i]\n }\n return msecs\n}\n\n/**\n * Mirror uuid/v7's option validation at the typeid boundary, so failures are\n * attributed to `strategy: 'typeid'` instead of leaking `strategy: 'uuid'`\n * through delegation.\n */\nfunction validateTypeidOptions(options: TypeidOptions): void {\n const msecs = options.msecs\n if (msecs !== undefined && !isIntegerInRange(msecs, 0, MAX_MSECS)) {\n throw new InvalidInputError('TIMESTAMP_OUT_OF_RANGE', `Timestamp must be an integer between 0 and ${MAX_MSECS}`, {\n strategy: 'typeid',\n })\n }\n\n const counter = options.counter\n if (counter !== undefined && !isIntegerInRange(counter, 0, MAX_COUNTER)) {\n throw new InvalidInputError('COUNTER_OUT_OF_RANGE', `Counter must be an integer between 0 and ${MAX_COUNTER}`, {\n strategy: 'typeid',\n })\n }\n\n const random = options.random\n if (random && random.length < TYPEID_UUID_BYTE_LENGTH) {\n throw new InvalidInputError('RANDOM_BYTES_TOO_SHORT', `Random bytes length must be >= ${TYPEID_UUID_BYTE_LENGTH}`, {\n strategy: 'typeid',\n })\n }\n}\n\nfunction typeidFn(prefix: string, options?: TypeidOptions, buf?: undefined, offset?: number): string\nfunction typeidFn<TBuf extends Uint8Array = Uint8Array>(\n prefix: string,\n options: TypeidOptions | undefined,\n buf: TBuf,\n offset?: number,\n): TBuf\nfunction typeidFn<TBuf extends Uint8Array = Uint8Array>(\n prefix: string,\n options?: TypeidOptions,\n buf?: TBuf,\n offset = 0,\n): string | TBuf {\n if (options !== undefined) {\n validateTypeidOptions(options)\n }\n\n if (buf) {\n if (!isWritableRange(buf, offset, TYPEID_UUID_BYTE_LENGTH)) {\n throw new BufferError(\n 'BUFFER_OUT_OF_BOUNDS',\n `TypeID byte range ${offset}:${offset + TYPEID_UUID_BYTE_LENGTH - 1} is out of buffer bounds`,\n { strategy: 'typeid' },\n )\n }\n assertValidPrefix(prefix)\n return uuidv7(options, buf, offset)\n }\n\n const bytes = uuidv7(options, new Uint8Array(TYPEID_UUID_BYTE_LENGTH))\n return formatTypeidFromUuidV7Bytes(prefix, bytes)\n}\n\nfunction typeidToBytes(id: string): Uint8Array {\n return parseTypeid(id).bytes\n}\n\nfunction typeidFromBytes(prefix: string, bytes: Uint8Array): string {\n return formatTypeidFromUuidV7Bytes(prefix, bytes)\n}\n\nfunction typeidToUuid(id: string): string {\n return uuidv7.fromBytes(typeidToBytes(id))\n}\n\nfunction typeidFromUuid(prefix: string, uuid: string): string {\n return formatTypeidFromUuidV7Bytes(prefix, uuidV7BytesFromUuid(uuid))\n}\n\nfunction timestamp(id: string): number {\n return timestampFromUuidV7Bytes(parseTypeid(id).bytes)\n}\n\nfunction prefix(id: string): string {\n return parseTypeid(id).prefix\n}\n\nfunction suffix(id: string): string {\n return parseTypeid(id).suffix\n}\n\nfunction isValid(id: unknown): id is string {\n if (typeof id !== 'string') {\n return false\n }\n\n try {\n parseTypeid(id)\n } catch {\n return false\n }\n\n return true\n}\n\n/**\n * Generate a TypeID string backed by UUID v7.\n *\n * TypeID combines a lowercase snake_case type prefix with a 26-character\n * modified base32 encoding of a UUID v7, producing sortable domain identifiers\n * such as `user_01h2xcejqtf2nbrexx3vqjhp41`.\n *\n * @example\n * ```ts\n * import { typeid } from 'uniku/typeid'\n *\n * const id = typeid('user')\n * // => \"user_01h2xcejqtf2nbrexx3vqjhp41\"\n *\n * const uuid = typeid.toUuid(id)\n * const restored = typeid.fromUuid('user', uuid)\n * ```\n */\nexport const typeid: Typeid = Object.assign(typeidFn, {\n toBytes: typeidToBytes,\n fromBytes: typeidFromBytes,\n toUuid: typeidToUuid,\n fromUuid: typeidFromUuid,\n timestamp,\n prefix,\n suffix,\n isValid,\n})\n\nexport { BufferError, InvalidInputError, ParseError, UniqueIdError } from '../errors'\n"],"mappings":"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"}

@@ -1,2 +0,2 @@

import { a as ParseError, i as InvalidInputError, o as UniqueIdError, t as BufferError } from "../errors-Da-8dh4J.mjs";
import { BufferError, InvalidInputError, ParseError, UniqueIdError } from "../errors.mjs";

@@ -3,0 +3,0 @@ //#region src/ulid/ulid.d.ts

@@ -1,2 +0,2 @@

import { a as ParseError, i as InvalidInputError, o as UniqueIdError, t as BufferError } from "../errors-Da-8dh4J.mjs";
import { BufferError, InvalidInputError, ParseError, UniqueIdError } from "../errors.mjs";

@@ -3,0 +3,0 @@ //#region src/uuid/v4.d.ts

@@ -1,2 +0,2 @@

import { a as ParseError, i as InvalidInputError, o as UniqueIdError, t as BufferError } from "../errors-Da-8dh4J.mjs";
import { BufferError, InvalidInputError, ParseError, UniqueIdError } from "../errors.mjs";

@@ -19,8 +19,2 @@ //#region src/uuid/v7.d.ts

counter?: number;
/**
* Unsigned 32-bit sequence value.
*
* @deprecated Use `counter` instead. Will be removed at v1-rc.
*/
seq?: number;
};

@@ -27,0 +21,0 @@ type UuidV7 = {

@@ -1,1 +0,1 @@

{"version":3,"file":"v7.d.mts","names":[],"sources":["../../src/uuid/v7.ts"],"mappings":";;;KAKY,aAAA;;;AAAZ;;EAKE,MAAA,GAAS,UAAA;EAAA;;;;EAKT,KAAA;;;AAWA;EAPA,OAAA;EAUU;;;;;EAHV,GAAA;AAAA;AAAA,KAGU,MAAA;4DAUO;EAAA,cANH,UAAA,GAAa,UAAA,EAAY,OAAA,EAAS,aAAA,cAA2B,GAAA,EAAK,IAAA,EAAM,MAAA,YAAkB,IAAA;GAEvG,OAAA,GAAU,aAAA,EAAe,GAAA,cAAiB,MAAA;EAE3C,OAAA,CAAQ,EAAA,WAAa,UAAA;EAErB,SAAA,CAAU,KAAA,EAAO,UAAA;EAEjB,SAAA,CAAU,EAAA;EAEV,OAAA,CAAQ,EAAA,YAAc,EAAA;EAEtB,GAAA;EAEA,GAAA;AAAA;;;;;;;;;;;;;AAAA;AAoLF;;;;AAAqB;;;;;;;;;cAAR,MAAA,EAAQ,MAAA"}
{"version":3,"file":"v7.d.mts","names":[],"sources":["../../src/uuid/v7.ts"],"mappings":";;;KAKY,aAAA;;;AAAZ;;EAKE,MAAA,GAAS,UAAA;EAAA;;;;EAKT,KAAA;EAIA;AAAA;AAGF;EAHE,OAAA;AAAA;AAAA,KAGU,MAAA;;gBAII,UAAA,GAAa,UAAA,EAAY,OAAA,EAAS,aAAA,cAA2B,GAAA,EAAK,IAAA,EAAM,MAAA,YAAkB,IAAA;GAEvG,OAAA,GAAU,aAAA,EAAe,GAAA,cAAiB,MAAA;EAE3C,OAAA,CAAQ,EAAA,WAAa,UAAA,EAEJ;EAAjB,SAAA,CAAU,KAAA,EAAO,UAAA;EAEjB,SAAA,CAAU,EAAA;EAEV,OAAA,CAAQ,EAAA,YAAc,EAAA;EAEtB,GAAA;EAEA,GAAA;AAAA;;;;;;;;;;;;;;;;;;AAAA;AA+KF;;;;AAAqB;;;;cAAR,MAAA,EAAQ,MAAA"}

@@ -1,2 +0,2 @@

import{r as e}from"../random-Chp-Nkzi.mjs";import{n as t,t as n}from"../validation-CTNpXm94.mjs";import{BufferError as r,InvalidInputError as i,ParseError as a,UniqueIdError as o}from"../errors.mjs";import{n as s,r as c,t as l}from"../uuid-BPebYihz.mjs";const u=/^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,d=0xffffffffffff,f=4294967295,p=new Uint8Array(16),m={msecs:-1/0,seq:0};function h(e,t,n,r,i){r[i++]=t/1099511627776&255,r[i++]=t/4294967296&255,r[i++]=t/16777216&255,r[i++]=t/65536&255,r[i++]=t/256&255,r[i++]=t&255,r[i++]=112|n>>>28&15,r[i++]=n>>>20&255,r[i++]=128|n>>>14&63,r[i++]=n>>>6&255,r[i++]=n<<2&255|e[10]&3,r[i++]=e[11],r[i++]=e[12],r[i++]=e[13],r[i++]=e[14],r[i++]=e[15]}function g(e,n,i,a,o){if(!t(a,o,16))throw new r(`BUFFER_OUT_OF_BOUNDS`,`UUID byte range ${o}:${o+16-1} is out of buffer bounds`,{strategy:`uuid`});h(e,n,i,a,o)}function _(t,r,a=0){let o=t.msecs;if(o!==void 0&&!n(o,0,d))throw new i(`TIMESTAMP_OUT_OF_RANGE`,`Timestamp must be an integer between 0 and ${d}`,{strategy:`uuid`});if(t.counter!==void 0&&t.seq!==void 0)throw new i(`CONFLICTING_OPTIONS`,"Pass only one of `counter` or `seq`, not both",{strategy:`uuid`});let c=t.counter??t.seq;if(c!==void 0&&!n(c,0,f))throw new i(`COUNTER_OUT_OF_RANGE`,`Counter must be an integer between 0 and ${f}`,{strategy:`uuid`});let l=t.random;if(l&&l.length<16)throw new i(`RANDOM_BYTES_TOO_SHORT`,`Random bytes length must be >= 16`,{strategy:`uuid`});let u=l??e(),m=o??Date.now(),_=c??u[6]<<23|u[7]<<16|u[8]<<8|u[9];return r?(g(u,m,_,r,a),r):(h(u,m,_,p,0),s(p))}function v(t,n,r){if(t)return _(t,n,r);let i=Date.now(),a=e();return i>m.msecs?(m.seq=a[6]<<23|a[7]<<16|a[8]<<8|a[9],m.msecs=i):(m.seq=m.seq+1|0,m.seq<0&&(m.seq=0,m.msecs++)),n?(g(a,m.msecs,m.seq,n,r??0),n):(h(a,m.msecs,m.seq,p,0),s(p))}function y(e){let t=c(e),n=0;for(let e=0;e<6;e+=1)n=n*256+t[e];return n}function b(e){return typeof e==`string`&&u.test(e)}const x=Object.assign(v,{toBytes:c,fromBytes:l,timestamp:y,isValid:b,NIL:`00000000-0000-0000-0000-000000000000`,MAX:`ffffffff-ffff-ffff-ffff-ffffffffffff`});export{r as BufferError,i as InvalidInputError,a as ParseError,o as UniqueIdError,x as uuidv7};
import{r as e}from"../random-Chp-Nkzi.mjs";import{n as t,t as n}from"../validation-CTNpXm94.mjs";import{BufferError as r,InvalidInputError as i,ParseError as a,UniqueIdError as o}from"../errors.mjs";import{n as s,r as c,t as l}from"../uuid-BPebYihz.mjs";const u=/^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,d=0xffffffffffff,f=4294967295,p=new Uint8Array(16),m={msecs:-1/0,seq:0};function h(e,t,n,r,i){r[i++]=t/1099511627776&255,r[i++]=t/4294967296&255,r[i++]=t/16777216&255,r[i++]=t/65536&255,r[i++]=t/256&255,r[i++]=t&255,r[i++]=112|n>>>28&15,r[i++]=n>>>20&255,r[i++]=128|n>>>14&63,r[i++]=n>>>6&255,r[i++]=n<<2&255|e[10]&3,r[i++]=e[11],r[i++]=e[12],r[i++]=e[13],r[i++]=e[14],r[i++]=e[15]}function g(e,n,i,a,o){if(!t(a,o,16))throw new r(`BUFFER_OUT_OF_BOUNDS`,`UUID byte range ${o}:${o+16-1} is out of buffer bounds`,{strategy:`uuid`});h(e,n,i,a,o)}function _(t,r,a=0){let o=t.msecs;if(o!==void 0&&!n(o,0,d))throw new i(`TIMESTAMP_OUT_OF_RANGE`,`Timestamp must be an integer between 0 and ${d}`,{strategy:`uuid`});let c=t.counter;if(c!==void 0&&!n(c,0,f))throw new i(`COUNTER_OUT_OF_RANGE`,`Counter must be an integer between 0 and ${f}`,{strategy:`uuid`});let l=t.random;if(l&&l.length<16)throw new i(`RANDOM_BYTES_TOO_SHORT`,`Random bytes length must be >= 16`,{strategy:`uuid`});let u=l??e(),m=o??Date.now(),_=c??u[6]<<23|u[7]<<16|u[8]<<8|u[9];return r?(g(u,m,_,r,a),r):(h(u,m,_,p,0),s(p))}function v(t,n,r){if(t)return _(t,n,r);let i=Date.now(),a=e();return i>m.msecs?(m.seq=a[6]<<23|a[7]<<16|a[8]<<8|a[9],m.msecs=i):(m.seq=m.seq+1|0,m.seq<0&&(m.seq=0,m.msecs++)),n?(g(a,m.msecs,m.seq,n,r??0),n):(h(a,m.msecs,m.seq,p,0),s(p))}function y(e){let t=c(e),n=0;for(let e=0;e<6;e+=1)n=n*256+t[e];return n}function b(e){return typeof e==`string`&&u.test(e)}const x=Object.assign(v,{toBytes:c,fromBytes:l,timestamp:y,isValid:b,NIL:`00000000-0000-0000-0000-000000000000`,MAX:`ffffffff-ffff-ffff-ffff-ffffffffffff`});export{r as BufferError,i as InvalidInputError,a as ParseError,o as UniqueIdError,x as uuidv7};
//# sourceMappingURL=v7.mjs.map

@@ -1,1 +0,1 @@

{"version":3,"file":"v7.mjs","names":[],"sources":["../../src/uuid/v7.ts"],"sourcesContent":["import { rng } from '../common/random'\nimport { isIntegerInRange, isWritableRange } from '../common/validation'\nimport { BufferError, InvalidInputError } from '../errors'\nimport { formatUuid, formatUuidUnchecked, parseUuid } from './common/uuid'\n\nexport type UuidV7Options = {\n /**\n * 16 bytes of random data to use for UUID generation.\n * Note: Several bytes will be overwritten with timestamp, version, and variant data.\n */\n random?: Uint8Array\n /**\n * Timestamp in milliseconds since Unix epoch.\n * Defaults to Date.now().\n */\n msecs?: number\n /**\n * Unsigned 32-bit counter value.\n */\n counter?: number\n /**\n * Unsigned 32-bit sequence value.\n *\n * @deprecated Use `counter` instead. Will be removed at v1-rc.\n */\n // TODO(v1-rc): remove this alias (tracked in docs/STABILITY.md).\n seq?: number\n}\n\nexport type UuidV7 = {\n /** Generate a time-ordered UUID v7 string. */\n (): string\n /** Generate a UUID v7 with explicit options or write its 16 canonical bytes into a caller-owned buffer. */\n <TBuf extends Uint8Array = Uint8Array>(options: UuidV7Options | undefined, buf: TBuf, offset?: number): TBuf\n /** Generate a UUID v7 string with optional timestamp, counter, or random bytes. */\n (options?: UuidV7Options, buf?: undefined, offset?: number): string\n /** Convert a UUID v7 string to its canonical 16-byte representation. */\n toBytes(id: string): Uint8Array\n /** Convert 16 canonical UUID bytes to a UUID v7 string. */\n fromBytes(bytes: Uint8Array): string\n /** Read the embedded Unix timestamp in milliseconds. */\n timestamp(id: string): number\n /** Return whether a value is a syntactically valid UUID v7 string. */\n isValid(id: unknown): id is string\n /** The nil UUID (all zeros) */\n NIL: string\n /** The max UUID (all ones) */\n MAX: string\n}\n\nconst UUID_V7_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i\nconst UUID_BYTES = 16\nconst MAX_MSECS = 0xffffffffffff\nconst MAX_SEQ = 0xffffffff\n\n// Reusable buffer for string output path - avoids allocation per call.\n// Safe because bytes are consumed synchronously by formatUuidUnchecked().\nconst reusableBuf = new Uint8Array(UUID_BYTES)\n\ntype V7State = {\n msecs: number\n seq: number\n}\n\n/**\n * Module-level state for maintaining monotonic ordering within the same millisecond.\n *\n * IMPORTANT: This state persists across all uuidv7() calls in the module's lifetime.\n * - In serverless/edge functions with warm starts, state persists between invocations.\n * - For isolated state, pass explicit `msecs` and `seq` via options.\n * - Tests should mock Date.now() or provide explicit options for deterministic behavior.\n */\nconst state: V7State = { msecs: -Infinity, seq: 0 }\n\nfunction writeV7BytesUnchecked(rnds: Uint8Array, msecs: number, seq: number, buf: Uint8Array, offset: number): void {\n // Keep this inline on the UUID v7 hot path. Using writeTimestamp48() here\n // benchmarked slower than the direct byte writes.\n buf[offset++] = (msecs / 0x10000000000) & 0xff\n buf[offset++] = (msecs / 0x100000000) & 0xff\n buf[offset++] = (msecs / 0x1000000) & 0xff\n buf[offset++] = (msecs / 0x10000) & 0xff\n buf[offset++] = (msecs / 0x100) & 0xff\n buf[offset++] = msecs & 0xff\n\n // Set version (7) and variant (10xx), then pack sequence and random tail bytes.\n buf[offset++] = 0x70 | ((seq >>> 28) & 0x0f)\n buf[offset++] = (seq >>> 20) & 0xff\n buf[offset++] = 0x80 | ((seq >>> 14) & 0x3f)\n buf[offset++] = (seq >>> 6) & 0xff\n // Lower seq bits plus 2 random bits to complete the 128-bit payload.\n buf[offset++] = ((seq << 2) & 0xff) | (rnds[10] & 0x03)\n buf[offset++] = rnds[11]\n buf[offset++] = rnds[12]\n buf[offset++] = rnds[13]\n buf[offset++] = rnds[14]\n buf[offset++] = rnds[15]\n}\n\nfunction writeV7Bytes(rnds: Uint8Array, msecs: number, seq: number, buf: Uint8Array, offset: number): void {\n if (!isWritableRange(buf, offset, UUID_BYTES)) {\n throw new BufferError(\n 'BUFFER_OUT_OF_BOUNDS',\n `UUID byte range ${offset}:${offset + UUID_BYTES - 1} is out of buffer bounds`,\n { strategy: 'uuid' },\n )\n }\n writeV7BytesUnchecked(rnds, msecs, seq, buf, offset)\n}\n\nfunction v7WithOptions<TBuf extends Uint8Array = Uint8Array>(\n options: UuidV7Options,\n buf?: TBuf,\n offset = 0,\n): string | TBuf {\n const optMsecs = options.msecs\n if (optMsecs !== undefined && !isIntegerInRange(optMsecs, 0, MAX_MSECS)) {\n throw new InvalidInputError('TIMESTAMP_OUT_OF_RANGE', `Timestamp must be an integer between 0 and ${MAX_MSECS}`, {\n strategy: 'uuid',\n })\n }\n if (options.counter !== undefined && options.seq !== undefined) {\n throw new InvalidInputError('CONFLICTING_OPTIONS', 'Pass only one of `counter` or `seq`, not both', {\n strategy: 'uuid',\n })\n }\n const optSeq = options.counter ?? options.seq\n if (optSeq !== undefined && !isIntegerInRange(optSeq, 0, MAX_SEQ)) {\n throw new InvalidInputError('COUNTER_OUT_OF_RANGE', `Counter must be an integer between 0 and ${MAX_SEQ}`, {\n strategy: 'uuid',\n })\n }\n const optRandom = options.random\n if (optRandom && optRandom.length < UUID_BYTES) {\n throw new InvalidInputError('RANDOM_BYTES_TOO_SHORT', `Random bytes length must be >= ${UUID_BYTES}`, {\n strategy: 'uuid',\n })\n }\n\n const rnds = optRandom ?? rng()\n const msecs = optMsecs ?? Date.now()\n // Derive a 31-bit sequence if not provided by the caller, matching the default hot path.\n const seq = optSeq ?? (rnds[6] << 23) | (rnds[7] << 16) | (rnds[8] << 8) | rnds[9]\n\n if (buf) {\n writeV7Bytes(rnds, msecs, seq, buf, offset)\n return buf\n }\n writeV7BytesUnchecked(rnds, msecs, seq, reusableBuf, 0)\n return formatUuidUnchecked(reusableBuf)\n}\n\n/*\n * Overload: no buffer => return a UUID string.\n */\nfunction v7(options?: UuidV7Options, buf?: undefined, offset?: number): string\n/*\n * Overload: caller provides a buffer slice to fill with UUID bytes.\n */\nfunction v7<TBuf extends Uint8Array = Uint8Array>(options: UuidV7Options | undefined, buf: TBuf, offset?: number): TBuf\nfunction v7<TBuf extends Uint8Array = Uint8Array>(options?: UuidV7Options, buf?: TBuf, offset?: number): string | TBuf {\n if (options) {\n return v7WithOptions(options, buf, offset)\n }\n\n // HOT PATH: Inline state management and byte generation for best performance\n const now = Date.now()\n const rnds = rng()\n\n // Update state (inlined for performance)\n if (now > state.msecs) {\n state.seq = (rnds[6] << 23) | (rnds[7] << 16) | (rnds[8] << 8) | rnds[9]\n state.msecs = now\n } else {\n state.seq = (state.seq + 1) | 0\n if (state.seq < 0) {\n state.seq = 0\n state.msecs++\n }\n }\n\n if (buf) {\n writeV7Bytes(rnds, state.msecs, state.seq, buf, offset ?? 0)\n return buf\n }\n writeV7BytesUnchecked(rnds, state.msecs, state.seq, reusableBuf, 0)\n return formatUuidUnchecked(reusableBuf)\n}\n\nfunction timestamp(id: string): number {\n const bytes = parseUuid(id)\n let msecs = 0\n for (let i = 0; i < 6; i += 1) {\n msecs = msecs * 256 + bytes[i]\n }\n return msecs\n}\n\nfunction isValid(id: unknown): id is string {\n return typeof id === 'string' && UUID_V7_REGEX.test(id)\n}\n\n/**\n * Generate a UUID v7 string or write the bytes into a buffer.\n *\n * UUID v7 is a time-ordered UUID that embeds a Unix timestamp in milliseconds,\n * making IDs naturally sortable by creation time. Ideal for database primary keys\n * where chronological ordering improves index performance.\n *\n * @example\n * ```ts\n * import { uuidv7 } from 'uniku/uuid/v7'\n *\n * const id = uuidv7()\n * // => \"018e5e5c-7c8a-7000-8000-000000000000\"\n *\n * // Extract timestamp\n * const ts = uuidv7.timestamp(id)\n * console.log(new Date(ts))\n *\n * // Validate\n * uuidv7.isValid(id) // true\n *\n * // Convert to/from bytes\n * const bytes = uuidv7.toBytes(id)\n * const restored = uuidv7.fromBytes(bytes)\n * ```\n */\nexport const uuidv7: UuidV7 = Object.assign(v7, {\n toBytes: parseUuid,\n fromBytes: formatUuid,\n timestamp,\n isValid,\n NIL: '00000000-0000-0000-0000-000000000000',\n MAX: 'ffffffff-ffff-ffff-ffff-ffffffffffff',\n})\n\nexport { BufferError, InvalidInputError, ParseError, UniqueIdError } from '../errors'\n"],"mappings":"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"}
{"version":3,"file":"v7.mjs","names":[],"sources":["../../src/uuid/v7.ts"],"sourcesContent":["import { rng } from '../common/random'\nimport { isIntegerInRange, isWritableRange } from '../common/validation'\nimport { BufferError, InvalidInputError } from '../errors'\nimport { formatUuid, formatUuidUnchecked, parseUuid } from './common/uuid'\n\nexport type UuidV7Options = {\n /**\n * 16 bytes of random data to use for UUID generation.\n * Note: Several bytes will be overwritten with timestamp, version, and variant data.\n */\n random?: Uint8Array\n /**\n * Timestamp in milliseconds since Unix epoch.\n * Defaults to Date.now().\n */\n msecs?: number\n /**\n * Unsigned 32-bit counter value.\n */\n counter?: number\n}\n\nexport type UuidV7 = {\n /** Generate a time-ordered UUID v7 string. */\n (): string\n /** Generate a UUID v7 with explicit options or write its 16 canonical bytes into a caller-owned buffer. */\n <TBuf extends Uint8Array = Uint8Array>(options: UuidV7Options | undefined, buf: TBuf, offset?: number): TBuf\n /** Generate a UUID v7 string with optional timestamp, counter, or random bytes. */\n (options?: UuidV7Options, buf?: undefined, offset?: number): string\n /** Convert a UUID v7 string to its canonical 16-byte representation. */\n toBytes(id: string): Uint8Array\n /** Convert 16 canonical UUID bytes to a UUID v7 string. */\n fromBytes(bytes: Uint8Array): string\n /** Read the embedded Unix timestamp in milliseconds. */\n timestamp(id: string): number\n /** Return whether a value is a syntactically valid UUID v7 string. */\n isValid(id: unknown): id is string\n /** The nil UUID (all zeros) */\n NIL: string\n /** The max UUID (all ones) */\n MAX: string\n}\n\nconst UUID_V7_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i\nconst UUID_BYTES = 16\nconst MAX_MSECS = 0xffffffffffff\nconst MAX_SEQ = 0xffffffff\n\n// Reusable buffer for string output path - avoids allocation per call.\n// Safe because bytes are consumed synchronously by formatUuidUnchecked().\nconst reusableBuf = new Uint8Array(UUID_BYTES)\n\ntype V7State = {\n msecs: number\n seq: number\n}\n\n/**\n * Module-level state for maintaining monotonic ordering within the same millisecond.\n *\n * IMPORTANT: This state persists across all uuidv7() calls in the module's lifetime.\n * - In serverless/edge functions with warm starts, state persists between invocations.\n * - For isolated state, pass explicit `msecs` and `counter` via options.\n * - Tests should mock Date.now() or provide explicit options for deterministic behavior.\n */\nconst state: V7State = { msecs: -Infinity, seq: 0 }\n\nfunction writeV7BytesUnchecked(rnds: Uint8Array, msecs: number, seq: number, buf: Uint8Array, offset: number): void {\n // Keep this inline on the UUID v7 hot path. Using writeTimestamp48() here\n // benchmarked slower than the direct byte writes.\n buf[offset++] = (msecs / 0x10000000000) & 0xff\n buf[offset++] = (msecs / 0x100000000) & 0xff\n buf[offset++] = (msecs / 0x1000000) & 0xff\n buf[offset++] = (msecs / 0x10000) & 0xff\n buf[offset++] = (msecs / 0x100) & 0xff\n buf[offset++] = msecs & 0xff\n\n // Set version (7) and variant (10xx), then pack sequence and random tail bytes.\n buf[offset++] = 0x70 | ((seq >>> 28) & 0x0f)\n buf[offset++] = (seq >>> 20) & 0xff\n buf[offset++] = 0x80 | ((seq >>> 14) & 0x3f)\n buf[offset++] = (seq >>> 6) & 0xff\n // Lower seq bits plus 2 random bits to complete the 128-bit payload.\n buf[offset++] = ((seq << 2) & 0xff) | (rnds[10] & 0x03)\n buf[offset++] = rnds[11]\n buf[offset++] = rnds[12]\n buf[offset++] = rnds[13]\n buf[offset++] = rnds[14]\n buf[offset++] = rnds[15]\n}\n\nfunction writeV7Bytes(rnds: Uint8Array, msecs: number, seq: number, buf: Uint8Array, offset: number): void {\n if (!isWritableRange(buf, offset, UUID_BYTES)) {\n throw new BufferError(\n 'BUFFER_OUT_OF_BOUNDS',\n `UUID byte range ${offset}:${offset + UUID_BYTES - 1} is out of buffer bounds`,\n { strategy: 'uuid' },\n )\n }\n writeV7BytesUnchecked(rnds, msecs, seq, buf, offset)\n}\n\nfunction v7WithOptions<TBuf extends Uint8Array = Uint8Array>(\n options: UuidV7Options,\n buf?: TBuf,\n offset = 0,\n): string | TBuf {\n const optMsecs = options.msecs\n if (optMsecs !== undefined && !isIntegerInRange(optMsecs, 0, MAX_MSECS)) {\n throw new InvalidInputError('TIMESTAMP_OUT_OF_RANGE', `Timestamp must be an integer between 0 and ${MAX_MSECS}`, {\n strategy: 'uuid',\n })\n }\n const counter = options.counter\n if (counter !== undefined && !isIntegerInRange(counter, 0, MAX_SEQ)) {\n throw new InvalidInputError('COUNTER_OUT_OF_RANGE', `Counter must be an integer between 0 and ${MAX_SEQ}`, {\n strategy: 'uuid',\n })\n }\n const optRandom = options.random\n if (optRandom && optRandom.length < UUID_BYTES) {\n throw new InvalidInputError('RANDOM_BYTES_TOO_SHORT', `Random bytes length must be >= ${UUID_BYTES}`, {\n strategy: 'uuid',\n })\n }\n\n const rnds = optRandom ?? rng()\n const msecs = optMsecs ?? Date.now()\n // Derive a 31-bit sequence if not provided by the caller, matching the default hot path.\n const seq = counter ?? (rnds[6] << 23) | (rnds[7] << 16) | (rnds[8] << 8) | rnds[9]\n\n if (buf) {\n writeV7Bytes(rnds, msecs, seq, buf, offset)\n return buf\n }\n writeV7BytesUnchecked(rnds, msecs, seq, reusableBuf, 0)\n return formatUuidUnchecked(reusableBuf)\n}\n\n/*\n * Overload: no buffer => return a UUID string.\n */\nfunction v7(options?: UuidV7Options, buf?: undefined, offset?: number): string\n/*\n * Overload: caller provides a buffer slice to fill with UUID bytes.\n */\nfunction v7<TBuf extends Uint8Array = Uint8Array>(options: UuidV7Options | undefined, buf: TBuf, offset?: number): TBuf\nfunction v7<TBuf extends Uint8Array = Uint8Array>(options?: UuidV7Options, buf?: TBuf, offset?: number): string | TBuf {\n if (options) {\n return v7WithOptions(options, buf, offset)\n }\n\n // HOT PATH: Inline state management and byte generation for best performance\n const now = Date.now()\n const rnds = rng()\n\n // Update state (inlined for performance)\n if (now > state.msecs) {\n state.seq = (rnds[6] << 23) | (rnds[7] << 16) | (rnds[8] << 8) | rnds[9]\n state.msecs = now\n } else {\n state.seq = (state.seq + 1) | 0\n if (state.seq < 0) {\n state.seq = 0\n state.msecs++\n }\n }\n\n if (buf) {\n writeV7Bytes(rnds, state.msecs, state.seq, buf, offset ?? 0)\n return buf\n }\n writeV7BytesUnchecked(rnds, state.msecs, state.seq, reusableBuf, 0)\n return formatUuidUnchecked(reusableBuf)\n}\n\nfunction timestamp(id: string): number {\n const bytes = parseUuid(id)\n let msecs = 0\n for (let i = 0; i < 6; i += 1) {\n msecs = msecs * 256 + bytes[i]\n }\n return msecs\n}\n\nfunction isValid(id: unknown): id is string {\n return typeof id === 'string' && UUID_V7_REGEX.test(id)\n}\n\n/**\n * Generate a UUID v7 string or write the bytes into a buffer.\n *\n * UUID v7 is a time-ordered UUID that embeds a Unix timestamp in milliseconds,\n * making IDs naturally sortable by creation time. Ideal for database primary keys\n * where chronological ordering improves index performance.\n *\n * @example\n * ```ts\n * import { uuidv7 } from 'uniku/uuid/v7'\n *\n * const id = uuidv7()\n * // => \"018e5e5c-7c8a-7000-8000-000000000000\"\n *\n * // Extract timestamp\n * const ts = uuidv7.timestamp(id)\n * console.log(new Date(ts))\n *\n * // Validate\n * uuidv7.isValid(id) // true\n *\n * // Convert to/from bytes\n * const bytes = uuidv7.toBytes(id)\n * const restored = uuidv7.fromBytes(bytes)\n * ```\n */\nexport const uuidv7: UuidV7 = Object.assign(v7, {\n toBytes: parseUuid,\n fromBytes: formatUuid,\n timestamp,\n isValid,\n NIL: '00000000-0000-0000-0000-000000000000',\n MAX: 'ffffffff-ffff-ffff-ffff-ffffffffffff',\n})\n\nexport { BufferError, InvalidInputError, ParseError, UniqueIdError } from '../errors'\n"],"mappings":"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"}

@@ -1,2 +0,2 @@

import { a as ParseError, i as InvalidInputError, o as UniqueIdError, t as BufferError } from "../errors-Da-8dh4J.mjs";
import { BufferError, InvalidInputError, ParseError, UniqueIdError } from "../errors.mjs";

@@ -11,9 +11,3 @@ //#region src/xid/xid.d.ts

*/
msecs?: number;
/**
* Unix timestamp in seconds.
*
* @deprecated Use `msecs` instead. Will be removed at v1-rc.
*/
secs?: number; /** 24-bit counter. Explicit values do not consume shared state. */
msecs?: number; /** 24-bit counter. Explicit values do not consume shared state. */
counter?: number;

@@ -20,0 +14,0 @@ };

@@ -1,1 +0,1 @@

{"version":3,"file":"xid.d.mts","names":[],"sources":["../../src/xid/xid.ts"],"mappings":";;;KAiBY,UAAA;4DAEV,SAAA,GAAY,UAAA,EAFd;EAIE,SAAA;;;;;EAKA,KAAA;;;;;AASA;EAFA,IAAA,WAKU;EAHV,OAAA;AAAA;AAAA,KAGU,GAAA;EAAA;EAAA,cAEI,UAAA,GAAa,UAAA,EAAY,OAAA,EAAS,UAAA,cAAwB,GAAA,EAAK,IAAA,EAAM,MAAA,YAAkB,IAAA;EAAA,CACpG,OAAA,GAAU,UAAA,EAAY,GAAA,cAAiB,MAAA;EACxC,OAAA,CAAQ,EAAA,WAAa,UAAA;EACrB,SAAA,CAAU,KAAA,EAAO,UAAA;EACjB,SAAA,CAAU,EAAA;EACV,OAAA,CAAQ,EAAA,YAAc,EAAA;EACtB,GAAA;EACA,GAAA;AAAA;;;;;;;;cAgIW,GAAA,EAAK,GAAA"}
{"version":3,"file":"xid.d.mts","names":[],"sources":["../../src/xid/xid.ts"],"mappings":";;;KAiBY,UAAA;4DAEV,SAAA,GAAY,UAAA,EAFd;EAIE,SAAA;;;;;EAKA,KAAA;EAEA,OAAA;AAAA;AAAA,KAGU,GAAA;EAAA;EAAA,cAEI,UAAA,GAAa,UAAA,EAAY,OAAA,EAAS,UAAA,cAAwB,GAAA,EAAK,IAAA,EAAM,MAAA,YAAkB,IAAA;EAAA,CACpG,OAAA,GAAU,UAAA,EAAY,GAAA,cAAiB,MAAA;EACxC,OAAA,CAAQ,EAAA,WAAa,UAAA;EACrB,SAAA,CAAU,KAAA,EAAO,UAAA;EACjB,SAAA,CAAU,EAAA;EACV,OAAA,CAAQ,EAAA,YAAc,EAAA;EACtB,GAAA;EACA,GAAA;AAAA;;;;;;;;cAgIW,GAAA,EAAK,GAAA"}

@@ -1,2 +0,2 @@

import{n as e,t}from"../random-Chp-Nkzi.mjs";import{n,t as r}from"../validation-CTNpXm94.mjs";import{BufferError as i,InvalidInputError as a,ParseError as o,UniqueIdError as s}from"../errors.mjs";import{n as c}from"../bytes-xqWxFYsM.mjs";import{t as l}from"../timestamp-ChrSuQCR.mjs";const u=`0123456789abcdefghijklmnopqrstuv`,d=Uint8Array.from(u,e=>e.charCodeAt(0)),f=Array(20),p=[,,,,,,],m=new Uint8Array(65536);m.fill(255);for(let e=0;e<32;e+=1)m[u.charCodeAt(e)]=e;function h(e){if(e.length!==12)throw new i(`BYTES_INVALID_LENGTH`,`XID bytes must be exactly 12 bytes, got ${e.length}`,{strategy:`xid`});return f[0]=d[e[0]>>3],f[1]=d[(e[0]<<2|e[1]>>6)&31],f[2]=d[e[1]>>1&31],f[3]=d[(e[1]<<4|e[2]>>4)&31],f[4]=d[(e[2]<<1|e[3]>>7)&31],f[5]=d[e[3]>>2&31],f[6]=d[(e[3]<<3|e[4]>>5)&31],f[7]=d[e[4]&31],f[8]=d[e[5]>>3],f[9]=d[(e[5]<<2|e[6]>>6)&31],f[10]=d[e[6]>>1&31],f[11]=d[(e[6]<<4|e[7]>>4)&31],f[12]=d[(e[7]<<1|e[8]>>7)&31],f[13]=d[e[8]>>2&31],f[14]=d[(e[8]<<3|e[9]>>5)&31],f[15]=d[e[9]&31],f[16]=d[e[10]>>3],f[17]=d[(e[10]<<2|e[11]>>6)&31],f[18]=d[e[11]>>1&31],f[19]=d[e[11]<<4&31],String.fromCharCode(...f)}function g(e,t){let n=t>>>16,r=t>>>8&255,i=t&255;return p[0]=d[(e<<3|n>>5)&31],p[1]=d[n&31],p[2]=d[r>>3],p[3]=d[(r<<2|i>>6)&31],p[4]=d[i>>1&31],p[5]=d[i<<4&31],String.fromCharCode(...p)}function _(e){if(e.length!==20)throw new o(`INVALID_LENGTH`,`XID string must be 20 characters, got ${e.length}`,{strategy:`xid`});let t=new Uint8Array(20);for(let n=0;n<20;n+=1){let r=m[e.charCodeAt(n)];if(r===255)throw new o(`INVALID_CHAR`,`Invalid XID character: ${e[n]}`,{strategy:`xid`});t[n]=r}if(t[19]!==0&&t[19]!==16)throw new o(`NON_CANONICAL`,`XID trailing bits must be canonically encoded`,{strategy:`xid`});return new Uint8Array([t[0]<<3|t[1]>>2,t[1]<<6|t[2]<<1|t[3]>>4,t[3]<<4|t[4]>>1,t[4]<<7|t[5]<<2|t[6]>>3,t[6]<<5|t[7],t[8]<<3|t[9]>>2,t[9]<<6|t[10]<<1|t[11]>>4,t[11]<<4|t[12]>>1,t[12]<<7|t[13]<<2|t[14]>>3,t[14]<<5|t[15],t[16]<<3|t[17]>>2,t[17]<<6|t[18]<<1|t[19]>>4])}const v=65535,y=16777215,b=/^[0-9a-v]{19}[0g]$/,x=new Uint8Array(12);let S=-1,C=``;const w={machineId:void 0,processId:void 0,counter:void 0};function T(e){return t(e).slice()}function E(){w.machineId===void 0&&(w.machineId=T(3)),w.processId===void 0&&(w.processId=e()&v)}function D(){return w.counter===void 0&&(w.counter=e()&y),w.counter=w.counter+1&y,w.counter}function O(e,t,n,r,i,a){c(i,a,e),i.set(t.subarray(0,3),a+4),i[a+7]=n>>>8,i[a+8]=n&255,i[a+9]=r>>>16,i[a+10]=r>>>8&255,i[a+11]=r&255}function k(e){if(e.machineId!==void 0&&e.machineId.length<3)throw new a(`MACHINE_ID_BYTES_TOO_SHORT`,`Machine ID bytes length must be >= 3 for XID`,{strategy:`xid`});if(e.processId!==void 0&&!r(e.processId,0,v))throw new a(`PROCESS_ID_OUT_OF_RANGE`,`Process ID must be between 0 and ${v}`,{strategy:`xid`});if(e.counter!==void 0&&!r(e.counter,0,y))throw new a(`COUNTER_OUT_OF_RANGE`,`Counter must be between 0 and ${y}`,{strategy:`xid`})}function A(e,t,r=0){if(e===void 0&&t===void 0){E();let e=Math.floor(Date.now()/1e3),t=D();return e!==S&&(O(e,w.machineId,w.processId,t,x,0),C=h(x).slice(0,14),S=e),C+g(w.processId&255,t)}e!==void 0&&k(e);let a=(e===void 0?void 0:l(e,0,4294967295,`xid`))??Math.floor(Date.now()/1e3);(e?.machineId===void 0||e.processId===void 0)&&E();let o=e?.machineId??w.machineId,s=e?.processId??w.processId,c=e?.counter??D();if(t!==void 0){if(!n(t,r,12))throw new i(`BUFFER_OUT_OF_BOUNDS`,`XID byte range ${r}:${r+11} is out of buffer bounds`,{strategy:`xid`});return O(a,o,s,c,t,r),t}return O(a,o,s,c,x,0),h(x)}function j(e){return _(e)}function M(e){return h(e)}function N(e){let t=_(e);return((t[0]<<24|t[1]<<16|t[2]<<8|t[3])>>>0)*1e3}function P(e){return typeof e==`string`&&b.test(e)}const F=Object.assign(A,{toBytes:j,fromBytes:M,timestamp:N,isValid:P,NIL:`0`.repeat(20),MAX:h(new Uint8Array(12).fill(255))});export{i as BufferError,a as InvalidInputError,o as ParseError,s as UniqueIdError,F as xid};
import{n as e,t}from"../random-Chp-Nkzi.mjs";import{n,t as r}from"../validation-CTNpXm94.mjs";import{BufferError as i,InvalidInputError as a,ParseError as o,UniqueIdError as s}from"../errors.mjs";import{n as c}from"../bytes-xqWxFYsM.mjs";import{t as l}from"../timestamp-DnsO0h7C.mjs";const u=`0123456789abcdefghijklmnopqrstuv`,d=Uint8Array.from(u,e=>e.charCodeAt(0)),f=Array(20),p=[,,,,,,],m=new Uint8Array(65536);m.fill(255);for(let e=0;e<32;e+=1)m[u.charCodeAt(e)]=e;function h(e){if(e.length!==12)throw new i(`BYTES_INVALID_LENGTH`,`XID bytes must be exactly 12 bytes, got ${e.length}`,{strategy:`xid`});return f[0]=d[e[0]>>3],f[1]=d[(e[0]<<2|e[1]>>6)&31],f[2]=d[e[1]>>1&31],f[3]=d[(e[1]<<4|e[2]>>4)&31],f[4]=d[(e[2]<<1|e[3]>>7)&31],f[5]=d[e[3]>>2&31],f[6]=d[(e[3]<<3|e[4]>>5)&31],f[7]=d[e[4]&31],f[8]=d[e[5]>>3],f[9]=d[(e[5]<<2|e[6]>>6)&31],f[10]=d[e[6]>>1&31],f[11]=d[(e[6]<<4|e[7]>>4)&31],f[12]=d[(e[7]<<1|e[8]>>7)&31],f[13]=d[e[8]>>2&31],f[14]=d[(e[8]<<3|e[9]>>5)&31],f[15]=d[e[9]&31],f[16]=d[e[10]>>3],f[17]=d[(e[10]<<2|e[11]>>6)&31],f[18]=d[e[11]>>1&31],f[19]=d[e[11]<<4&31],String.fromCharCode(...f)}function g(e,t){let n=t>>>16,r=t>>>8&255,i=t&255;return p[0]=d[(e<<3|n>>5)&31],p[1]=d[n&31],p[2]=d[r>>3],p[3]=d[(r<<2|i>>6)&31],p[4]=d[i>>1&31],p[5]=d[i<<4&31],String.fromCharCode(...p)}function _(e){if(e.length!==20)throw new o(`INVALID_LENGTH`,`XID string must be 20 characters, got ${e.length}`,{strategy:`xid`});let t=new Uint8Array(20);for(let n=0;n<20;n+=1){let r=m[e.charCodeAt(n)];if(r===255)throw new o(`INVALID_CHAR`,`Invalid XID character: ${e[n]}`,{strategy:`xid`});t[n]=r}if(t[19]!==0&&t[19]!==16)throw new o(`NON_CANONICAL`,`XID trailing bits must be canonically encoded`,{strategy:`xid`});return new Uint8Array([t[0]<<3|t[1]>>2,t[1]<<6|t[2]<<1|t[3]>>4,t[3]<<4|t[4]>>1,t[4]<<7|t[5]<<2|t[6]>>3,t[6]<<5|t[7],t[8]<<3|t[9]>>2,t[9]<<6|t[10]<<1|t[11]>>4,t[11]<<4|t[12]>>1,t[12]<<7|t[13]<<2|t[14]>>3,t[14]<<5|t[15],t[16]<<3|t[17]>>2,t[17]<<6|t[18]<<1|t[19]>>4])}const v=65535,y=16777215,b=/^[0-9a-v]{19}[0g]$/,x=new Uint8Array(12);let S=-1,C=``;const w={machineId:void 0,processId:void 0,counter:void 0};function T(e){return t(e).slice()}function E(){w.machineId===void 0&&(w.machineId=T(3)),w.processId===void 0&&(w.processId=e()&v)}function D(){return w.counter===void 0&&(w.counter=e()&y),w.counter=w.counter+1&y,w.counter}function O(e,t,n,r,i,a){c(i,a,e),i.set(t.subarray(0,3),a+4),i[a+7]=n>>>8,i[a+8]=n&255,i[a+9]=r>>>16,i[a+10]=r>>>8&255,i[a+11]=r&255}function k(e){if(e.machineId!==void 0&&e.machineId.length<3)throw new a(`MACHINE_ID_BYTES_TOO_SHORT`,`Machine ID bytes length must be >= 3 for XID`,{strategy:`xid`});if(e.processId!==void 0&&!r(e.processId,0,v))throw new a(`PROCESS_ID_OUT_OF_RANGE`,`Process ID must be between 0 and ${v}`,{strategy:`xid`});if(e.counter!==void 0&&!r(e.counter,0,y))throw new a(`COUNTER_OUT_OF_RANGE`,`Counter must be between 0 and ${y}`,{strategy:`xid`})}function A(e,t,r=0){if(e===void 0&&t===void 0){E();let e=Math.floor(Date.now()/1e3),t=D();return e!==S&&(O(e,w.machineId,w.processId,t,x,0),C=h(x).slice(0,14),S=e),C+g(w.processId&255,t)}e!==void 0&&k(e);let a=(e===void 0?void 0:l(e,0,4294967295,`xid`))??Math.floor(Date.now()/1e3);(e?.machineId===void 0||e.processId===void 0)&&E();let o=e?.machineId??w.machineId,s=e?.processId??w.processId,c=e?.counter??D();if(t!==void 0){if(!n(t,r,12))throw new i(`BUFFER_OUT_OF_BOUNDS`,`XID byte range ${r}:${r+11} is out of buffer bounds`,{strategy:`xid`});return O(a,o,s,c,t,r),t}return O(a,o,s,c,x,0),h(x)}function j(e){return _(e)}function M(e){return h(e)}function N(e){let t=_(e);return((t[0]<<24|t[1]<<16|t[2]<<8|t[3])>>>0)*1e3}function P(e){return typeof e==`string`&&b.test(e)}const F=Object.assign(A,{toBytes:j,fromBytes:M,timestamp:N,isValid:P,NIL:`0`.repeat(20),MAX:h(new Uint8Array(12).fill(255))});export{i as BufferError,a as InvalidInputError,o as ParseError,s as UniqueIdError,F as xid};
//# sourceMappingURL=xid.mjs.map

@@ -1,1 +0,1 @@

{"version":3,"file":"xid.mjs","names":["XID_BYTES"],"sources":["../../src/xid/base32hex.ts","../../src/xid/xid.ts"],"sourcesContent":["import { BufferError, ParseError } from '../errors'\n\nconst ENCODING = '0123456789abcdefghijklmnopqrstuv'\nconst ENCODING_CODES = Uint8Array.from(ENCODING, (character) => character.charCodeAt(0))\nconst XID_BYTES = 12\nconst XID_LENGTH = 20\nconst ENCODED = new Array<number>(XID_LENGTH)\nconst COUNTER_SUFFIX = new Array<number>(6)\n\nconst DECODING = new Uint8Array(65536)\nDECODING.fill(255)\nfor (let i = 0; i < ENCODING.length; i += 1) {\n DECODING[ENCODING.charCodeAt(i)] = i\n}\n\n/** Encode the 12 canonical XID bytes as lowercase base32hex. */\nexport function encodeBase32Hex(bytes: Uint8Array): string {\n if (bytes.length !== XID_BYTES) {\n throw new BufferError('BYTES_INVALID_LENGTH', `XID bytes must be exactly ${XID_BYTES} bytes, got ${bytes.length}`, {\n strategy: 'xid',\n })\n }\n\n ENCODED[0] = ENCODING_CODES[bytes[0] >> 3]\n ENCODED[1] = ENCODING_CODES[((bytes[0] << 2) | (bytes[1] >> 6)) & 0x1f]\n ENCODED[2] = ENCODING_CODES[(bytes[1] >> 1) & 0x1f]\n ENCODED[3] = ENCODING_CODES[((bytes[1] << 4) | (bytes[2] >> 4)) & 0x1f]\n ENCODED[4] = ENCODING_CODES[((bytes[2] << 1) | (bytes[3] >> 7)) & 0x1f]\n ENCODED[5] = ENCODING_CODES[(bytes[3] >> 2) & 0x1f]\n ENCODED[6] = ENCODING_CODES[((bytes[3] << 3) | (bytes[4] >> 5)) & 0x1f]\n ENCODED[7] = ENCODING_CODES[bytes[4] & 0x1f]\n ENCODED[8] = ENCODING_CODES[bytes[5] >> 3]\n ENCODED[9] = ENCODING_CODES[((bytes[5] << 2) | (bytes[6] >> 6)) & 0x1f]\n ENCODED[10] = ENCODING_CODES[(bytes[6] >> 1) & 0x1f]\n ENCODED[11] = ENCODING_CODES[((bytes[6] << 4) | (bytes[7] >> 4)) & 0x1f]\n ENCODED[12] = ENCODING_CODES[((bytes[7] << 1) | (bytes[8] >> 7)) & 0x1f]\n ENCODED[13] = ENCODING_CODES[(bytes[8] >> 2) & 0x1f]\n ENCODED[14] = ENCODING_CODES[((bytes[8] << 3) | (bytes[9] >> 5)) & 0x1f]\n ENCODED[15] = ENCODING_CODES[bytes[9] & 0x1f]\n ENCODED[16] = ENCODING_CODES[bytes[10] >> 3]\n ENCODED[17] = ENCODING_CODES[((bytes[10] << 2) | (bytes[11] >> 6)) & 0x1f]\n ENCODED[18] = ENCODING_CODES[(bytes[11] >> 1) & 0x1f]\n ENCODED[19] = ENCODING_CODES[(bytes[11] << 4) & 0x1f]\n return String.fromCharCode(...ENCODED)\n}\n\n/** Encode the six XID characters affected by the 24-bit counter. */\nexport function encodeCounterSuffix(lastIdentityByte: number, counter: number): string {\n const high = counter >>> 16\n const middle = (counter >>> 8) & 0xff\n const low = counter & 0xff\n COUNTER_SUFFIX[0] = ENCODING_CODES[((lastIdentityByte << 3) | (high >> 5)) & 0x1f]\n COUNTER_SUFFIX[1] = ENCODING_CODES[high & 0x1f]\n COUNTER_SUFFIX[2] = ENCODING_CODES[middle >> 3]\n COUNTER_SUFFIX[3] = ENCODING_CODES[((middle << 2) | (low >> 6)) & 0x1f]\n COUNTER_SUFFIX[4] = ENCODING_CODES[(low >> 1) & 0x1f]\n COUNTER_SUFFIX[5] = ENCODING_CODES[(low << 4) & 0x1f]\n return String.fromCharCode(...COUNTER_SUFFIX)\n}\n\n/** Decode a canonical lowercase base32hex XID string to its 12 bytes. */\nexport function decodeBase32Hex(id: string): Uint8Array {\n if (id.length !== XID_LENGTH) {\n throw new ParseError('INVALID_LENGTH', `XID string must be ${XID_LENGTH} characters, got ${id.length}`, {\n strategy: 'xid',\n })\n }\n\n const values = new Uint8Array(XID_LENGTH)\n for (let i = 0; i < XID_LENGTH; i += 1) {\n const value = DECODING[id.charCodeAt(i)]\n if (value === 255) {\n throw new ParseError('INVALID_CHAR', `Invalid XID character: ${id[i]}`, { strategy: 'xid' })\n }\n values[i] = value\n }\n\n if (values[19] !== 0 && values[19] !== 16) {\n throw new ParseError('NON_CANONICAL', 'XID trailing bits must be canonically encoded', { strategy: 'xid' })\n }\n\n return new Uint8Array([\n (values[0] << 3) | (values[1] >> 2),\n (values[1] << 6) | (values[2] << 1) | (values[3] >> 4),\n (values[3] << 4) | (values[4] >> 1),\n (values[4] << 7) | (values[5] << 2) | (values[6] >> 3),\n (values[6] << 5) | values[7],\n (values[8] << 3) | (values[9] >> 2),\n (values[9] << 6) | (values[10] << 1) | (values[11] >> 4),\n (values[11] << 4) | (values[12] >> 1),\n (values[12] << 7) | (values[13] << 2) | (values[14] >> 3),\n (values[14] << 5) | values[15],\n (values[16] << 3) | (values[17] >> 2),\n (values[17] << 6) | (values[18] << 1) | (values[19] >> 4),\n ])\n}\n","import { writeTimestamp32 } from '../common/bytes'\nimport { randomBytes, randomUint32 } from '../common/random'\nimport { resolveTimestampSecs } from '../common/timestamp'\nimport { isIntegerInRange, isWritableRange } from '../common/validation'\nimport { BufferError, InvalidInputError } from '../errors'\nimport { decodeBase32Hex, encodeBase32Hex, encodeCounterSuffix } from './base32hex'\n\nconst XID_BYTES = 12\nconst MACHINE_ID_BYTES = 3\nconst MAX_SECS = 0xffffffff\nconst MAX_PROCESS_ID = 0xffff\nconst MAX_COUNTER = 0xffffff\nconst XID_REGEX = /^[0-9a-v]{19}[0g]$/\nconst stringBuffer = new Uint8Array(XID_BYTES)\nlet cachedPrefixSecs = -1\nlet cachedPrefix = ''\n\nexport type XidOptions = {\n /** First three bytes used as the XID machine identity. */\n machineId?: Uint8Array\n /** 16-bit process identity. */\n processId?: number\n /**\n * Unix timestamp in milliseconds. Defaults to Date.now().\n * XID stores whole seconds, so sub-second precision is truncated.\n */\n msecs?: number\n /**\n * Unix timestamp in seconds.\n *\n * @deprecated Use `msecs` instead. Will be removed at v1-rc.\n */\n // TODO(v1-rc): remove this alias (tracked in docs/STABILITY.md).\n secs?: number\n /** 24-bit counter. Explicit values do not consume shared state. */\n counter?: number\n}\n\nexport type Xid = {\n (): string\n <TBuf extends Uint8Array = Uint8Array>(options: XidOptions | undefined, buf: TBuf, offset?: number): TBuf\n (options?: XidOptions, buf?: undefined, offset?: number): string\n toBytes(id: string): Uint8Array\n fromBytes(bytes: Uint8Array): string\n timestamp(id: string): number\n isValid(id: unknown): id is string\n NIL: string\n MAX: string\n}\n\ntype XidState = {\n machineId: Uint8Array | undefined\n processId: number | undefined\n counter: number | undefined\n}\n\nconst state: XidState = { machineId: undefined, processId: undefined, counter: undefined }\n\n/** Copy pooled bytes before another random draw can refill their backing pool. */\nfunction freshRandom(count: number): Uint8Array {\n return randomBytes(count).slice()\n}\n\nfunction initializeIdentity(): void {\n if (state.machineId === undefined) state.machineId = freshRandom(MACHINE_ID_BYTES)\n if (state.processId === undefined) state.processId = randomUint32() & MAX_PROCESS_ID\n}\n\nfunction nextCounter(): number {\n if (state.counter === undefined) state.counter = randomUint32() & MAX_COUNTER\n state.counter = (state.counter + 1) & MAX_COUNTER\n return state.counter\n}\n\nfunction writeXidBytesUnchecked(\n secs: number,\n machineId: Uint8Array,\n processId: number,\n counter: number,\n buf: Uint8Array,\n offset: number,\n): void {\n writeTimestamp32(buf, offset, secs)\n buf.set(machineId.subarray(0, MACHINE_ID_BYTES), offset + 4)\n buf[offset + 7] = processId >>> 8\n buf[offset + 8] = processId & 0xff\n buf[offset + 9] = counter >>> 16\n buf[offset + 10] = (counter >>> 8) & 0xff\n buf[offset + 11] = counter & 0xff\n}\n\nfunction validateOptions(options: XidOptions): void {\n if (options.machineId !== undefined && options.machineId.length < MACHINE_ID_BYTES) {\n throw new InvalidInputError(\n 'MACHINE_ID_BYTES_TOO_SHORT',\n `Machine ID bytes length must be >= ${MACHINE_ID_BYTES} for XID`,\n { strategy: 'xid' },\n )\n }\n if (options.processId !== undefined && !isIntegerInRange(options.processId, 0, MAX_PROCESS_ID)) {\n throw new InvalidInputError('PROCESS_ID_OUT_OF_RANGE', `Process ID must be between 0 and ${MAX_PROCESS_ID}`, {\n strategy: 'xid',\n })\n }\n if (options.counter !== undefined && !isIntegerInRange(options.counter, 0, MAX_COUNTER)) {\n throw new InvalidInputError('COUNTER_OUT_OF_RANGE', `Counter must be between 0 and ${MAX_COUNTER}`, {\n strategy: 'xid',\n })\n }\n}\n\nfunction xidFn(options?: XidOptions, buf?: undefined, offset?: number): string\nfunction xidFn<TBuf extends Uint8Array = Uint8Array>(options: XidOptions | undefined, buf: TBuf, offset?: number): TBuf\nfunction xidFn<TBuf extends Uint8Array = Uint8Array>(options?: XidOptions, buf?: TBuf, offset = 0): string | TBuf {\n if (options === undefined && buf === undefined) {\n initializeIdentity()\n const secs = Math.floor(Date.now() / 1000)\n const counter = nextCounter()\n if (secs !== cachedPrefixSecs) {\n writeXidBytesUnchecked(secs, state.machineId!, state.processId!, counter, stringBuffer, 0)\n cachedPrefix = encodeBase32Hex(stringBuffer).slice(0, 14)\n cachedPrefixSecs = secs\n }\n return cachedPrefix + encodeCounterSuffix(state.processId! & 0xff, counter)\n }\n\n if (options !== undefined) validateOptions(options)\n\n const resolvedSecs = options === undefined ? undefined : resolveTimestampSecs(options, 0, MAX_SECS, 'xid')\n const secs = resolvedSecs ?? Math.floor(Date.now() / 1000)\n if (options?.machineId === undefined || options.processId === undefined) {\n initializeIdentity()\n }\n const machineId = options?.machineId ?? state.machineId!\n const processId = options?.processId ?? state.processId!\n const counter = options?.counter ?? nextCounter()\n\n if (buf !== undefined) {\n if (!isWritableRange(buf, offset, XID_BYTES)) {\n throw new BufferError('BUFFER_OUT_OF_BOUNDS', `XID byte range ${offset}:${offset + 11} is out of buffer bounds`, {\n strategy: 'xid',\n })\n }\n writeXidBytesUnchecked(secs, machineId, processId, counter, buf, offset)\n return buf\n }\n\n writeXidBytesUnchecked(secs, machineId, processId, counter, stringBuffer, 0)\n return encodeBase32Hex(stringBuffer)\n}\n\nfunction toBytes(id: string): Uint8Array {\n return decodeBase32Hex(id)\n}\n\nfunction fromBytes(bytes: Uint8Array): string {\n return encodeBase32Hex(bytes)\n}\n\nfunction timestamp(id: string): number {\n const bytes = decodeBase32Hex(id)\n return (((bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]) >>> 0) * 1000\n}\n\nfunction isValid(id: unknown): id is string {\n return typeof id === 'string' && XID_REGEX.test(id)\n}\n\n/**\n * Generate a 20-character rs/xid-compatible identifier.\n *\n * XID embeds seconds, a lazily-random per-runtime identity, and a shared\n * always-incrementing counter. In Cloudflare Workers, time is frozen during a\n * request, so the counter preserves ordering for IDs made in that request.\n */\nexport const xid: Xid = Object.assign(xidFn, {\n toBytes,\n fromBytes,\n timestamp,\n isValid,\n NIL: '0'.repeat(20),\n MAX: encodeBase32Hex(new Uint8Array(12).fill(0xff)),\n})\n\nexport { BufferError, InvalidInputError, ParseError, UniqueIdError } from '../errors'\n"],"mappings":"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"}
{"version":3,"file":"xid.mjs","names":["XID_BYTES"],"sources":["../../src/xid/base32hex.ts","../../src/xid/xid.ts"],"sourcesContent":["import { BufferError, ParseError } from '../errors'\n\nconst ENCODING = '0123456789abcdefghijklmnopqrstuv'\nconst ENCODING_CODES = Uint8Array.from(ENCODING, (character) => character.charCodeAt(0))\nconst XID_BYTES = 12\nconst XID_LENGTH = 20\nconst ENCODED = new Array<number>(XID_LENGTH)\nconst COUNTER_SUFFIX = new Array<number>(6)\n\nconst DECODING = new Uint8Array(65536)\nDECODING.fill(255)\nfor (let i = 0; i < ENCODING.length; i += 1) {\n DECODING[ENCODING.charCodeAt(i)] = i\n}\n\n/** Encode the 12 canonical XID bytes as lowercase base32hex. */\nexport function encodeBase32Hex(bytes: Uint8Array): string {\n if (bytes.length !== XID_BYTES) {\n throw new BufferError('BYTES_INVALID_LENGTH', `XID bytes must be exactly ${XID_BYTES} bytes, got ${bytes.length}`, {\n strategy: 'xid',\n })\n }\n\n ENCODED[0] = ENCODING_CODES[bytes[0] >> 3]\n ENCODED[1] = ENCODING_CODES[((bytes[0] << 2) | (bytes[1] >> 6)) & 0x1f]\n ENCODED[2] = ENCODING_CODES[(bytes[1] >> 1) & 0x1f]\n ENCODED[3] = ENCODING_CODES[((bytes[1] << 4) | (bytes[2] >> 4)) & 0x1f]\n ENCODED[4] = ENCODING_CODES[((bytes[2] << 1) | (bytes[3] >> 7)) & 0x1f]\n ENCODED[5] = ENCODING_CODES[(bytes[3] >> 2) & 0x1f]\n ENCODED[6] = ENCODING_CODES[((bytes[3] << 3) | (bytes[4] >> 5)) & 0x1f]\n ENCODED[7] = ENCODING_CODES[bytes[4] & 0x1f]\n ENCODED[8] = ENCODING_CODES[bytes[5] >> 3]\n ENCODED[9] = ENCODING_CODES[((bytes[5] << 2) | (bytes[6] >> 6)) & 0x1f]\n ENCODED[10] = ENCODING_CODES[(bytes[6] >> 1) & 0x1f]\n ENCODED[11] = ENCODING_CODES[((bytes[6] << 4) | (bytes[7] >> 4)) & 0x1f]\n ENCODED[12] = ENCODING_CODES[((bytes[7] << 1) | (bytes[8] >> 7)) & 0x1f]\n ENCODED[13] = ENCODING_CODES[(bytes[8] >> 2) & 0x1f]\n ENCODED[14] = ENCODING_CODES[((bytes[8] << 3) | (bytes[9] >> 5)) & 0x1f]\n ENCODED[15] = ENCODING_CODES[bytes[9] & 0x1f]\n ENCODED[16] = ENCODING_CODES[bytes[10] >> 3]\n ENCODED[17] = ENCODING_CODES[((bytes[10] << 2) | (bytes[11] >> 6)) & 0x1f]\n ENCODED[18] = ENCODING_CODES[(bytes[11] >> 1) & 0x1f]\n ENCODED[19] = ENCODING_CODES[(bytes[11] << 4) & 0x1f]\n return String.fromCharCode(...ENCODED)\n}\n\n/** Encode the six XID characters affected by the 24-bit counter. */\nexport function encodeCounterSuffix(lastIdentityByte: number, counter: number): string {\n const high = counter >>> 16\n const middle = (counter >>> 8) & 0xff\n const low = counter & 0xff\n COUNTER_SUFFIX[0] = ENCODING_CODES[((lastIdentityByte << 3) | (high >> 5)) & 0x1f]\n COUNTER_SUFFIX[1] = ENCODING_CODES[high & 0x1f]\n COUNTER_SUFFIX[2] = ENCODING_CODES[middle >> 3]\n COUNTER_SUFFIX[3] = ENCODING_CODES[((middle << 2) | (low >> 6)) & 0x1f]\n COUNTER_SUFFIX[4] = ENCODING_CODES[(low >> 1) & 0x1f]\n COUNTER_SUFFIX[5] = ENCODING_CODES[(low << 4) & 0x1f]\n return String.fromCharCode(...COUNTER_SUFFIX)\n}\n\n/** Decode a canonical lowercase base32hex XID string to its 12 bytes. */\nexport function decodeBase32Hex(id: string): Uint8Array {\n if (id.length !== XID_LENGTH) {\n throw new ParseError('INVALID_LENGTH', `XID string must be ${XID_LENGTH} characters, got ${id.length}`, {\n strategy: 'xid',\n })\n }\n\n const values = new Uint8Array(XID_LENGTH)\n for (let i = 0; i < XID_LENGTH; i += 1) {\n const value = DECODING[id.charCodeAt(i)]\n if (value === 255) {\n throw new ParseError('INVALID_CHAR', `Invalid XID character: ${id[i]}`, { strategy: 'xid' })\n }\n values[i] = value\n }\n\n if (values[19] !== 0 && values[19] !== 16) {\n throw new ParseError('NON_CANONICAL', 'XID trailing bits must be canonically encoded', { strategy: 'xid' })\n }\n\n return new Uint8Array([\n (values[0] << 3) | (values[1] >> 2),\n (values[1] << 6) | (values[2] << 1) | (values[3] >> 4),\n (values[3] << 4) | (values[4] >> 1),\n (values[4] << 7) | (values[5] << 2) | (values[6] >> 3),\n (values[6] << 5) | values[7],\n (values[8] << 3) | (values[9] >> 2),\n (values[9] << 6) | (values[10] << 1) | (values[11] >> 4),\n (values[11] << 4) | (values[12] >> 1),\n (values[12] << 7) | (values[13] << 2) | (values[14] >> 3),\n (values[14] << 5) | values[15],\n (values[16] << 3) | (values[17] >> 2),\n (values[17] << 6) | (values[18] << 1) | (values[19] >> 4),\n ])\n}\n","import { writeTimestamp32 } from '../common/bytes'\nimport { randomBytes, randomUint32 } from '../common/random'\nimport { resolveTimestampSecs } from '../common/timestamp'\nimport { isIntegerInRange, isWritableRange } from '../common/validation'\nimport { BufferError, InvalidInputError } from '../errors'\nimport { decodeBase32Hex, encodeBase32Hex, encodeCounterSuffix } from './base32hex'\n\nconst XID_BYTES = 12\nconst MACHINE_ID_BYTES = 3\nconst MAX_SECS = 0xffffffff\nconst MAX_PROCESS_ID = 0xffff\nconst MAX_COUNTER = 0xffffff\nconst XID_REGEX = /^[0-9a-v]{19}[0g]$/\nconst stringBuffer = new Uint8Array(XID_BYTES)\nlet cachedPrefixSecs = -1\nlet cachedPrefix = ''\n\nexport type XidOptions = {\n /** First three bytes used as the XID machine identity. */\n machineId?: Uint8Array\n /** 16-bit process identity. */\n processId?: number\n /**\n * Unix timestamp in milliseconds. Defaults to Date.now().\n * XID stores whole seconds, so sub-second precision is truncated.\n */\n msecs?: number\n /** 24-bit counter. Explicit values do not consume shared state. */\n counter?: number\n}\n\nexport type Xid = {\n (): string\n <TBuf extends Uint8Array = Uint8Array>(options: XidOptions | undefined, buf: TBuf, offset?: number): TBuf\n (options?: XidOptions, buf?: undefined, offset?: number): string\n toBytes(id: string): Uint8Array\n fromBytes(bytes: Uint8Array): string\n timestamp(id: string): number\n isValid(id: unknown): id is string\n NIL: string\n MAX: string\n}\n\ntype XidState = {\n machineId: Uint8Array | undefined\n processId: number | undefined\n counter: number | undefined\n}\n\nconst state: XidState = { machineId: undefined, processId: undefined, counter: undefined }\n\n/** Copy pooled bytes before another random draw can refill their backing pool. */\nfunction freshRandom(count: number): Uint8Array {\n return randomBytes(count).slice()\n}\n\nfunction initializeIdentity(): void {\n if (state.machineId === undefined) state.machineId = freshRandom(MACHINE_ID_BYTES)\n if (state.processId === undefined) state.processId = randomUint32() & MAX_PROCESS_ID\n}\n\nfunction nextCounter(): number {\n if (state.counter === undefined) state.counter = randomUint32() & MAX_COUNTER\n state.counter = (state.counter + 1) & MAX_COUNTER\n return state.counter\n}\n\nfunction writeXidBytesUnchecked(\n secs: number,\n machineId: Uint8Array,\n processId: number,\n counter: number,\n buf: Uint8Array,\n offset: number,\n): void {\n writeTimestamp32(buf, offset, secs)\n buf.set(machineId.subarray(0, MACHINE_ID_BYTES), offset + 4)\n buf[offset + 7] = processId >>> 8\n buf[offset + 8] = processId & 0xff\n buf[offset + 9] = counter >>> 16\n buf[offset + 10] = (counter >>> 8) & 0xff\n buf[offset + 11] = counter & 0xff\n}\n\nfunction validateOptions(options: XidOptions): void {\n if (options.machineId !== undefined && options.machineId.length < MACHINE_ID_BYTES) {\n throw new InvalidInputError(\n 'MACHINE_ID_BYTES_TOO_SHORT',\n `Machine ID bytes length must be >= ${MACHINE_ID_BYTES} for XID`,\n { strategy: 'xid' },\n )\n }\n if (options.processId !== undefined && !isIntegerInRange(options.processId, 0, MAX_PROCESS_ID)) {\n throw new InvalidInputError('PROCESS_ID_OUT_OF_RANGE', `Process ID must be between 0 and ${MAX_PROCESS_ID}`, {\n strategy: 'xid',\n })\n }\n if (options.counter !== undefined && !isIntegerInRange(options.counter, 0, MAX_COUNTER)) {\n throw new InvalidInputError('COUNTER_OUT_OF_RANGE', `Counter must be between 0 and ${MAX_COUNTER}`, {\n strategy: 'xid',\n })\n }\n}\n\nfunction xidFn(options?: XidOptions, buf?: undefined, offset?: number): string\nfunction xidFn<TBuf extends Uint8Array = Uint8Array>(options: XidOptions | undefined, buf: TBuf, offset?: number): TBuf\nfunction xidFn<TBuf extends Uint8Array = Uint8Array>(options?: XidOptions, buf?: TBuf, offset = 0): string | TBuf {\n if (options === undefined && buf === undefined) {\n initializeIdentity()\n const secs = Math.floor(Date.now() / 1000)\n const counter = nextCounter()\n if (secs !== cachedPrefixSecs) {\n writeXidBytesUnchecked(secs, state.machineId!, state.processId!, counter, stringBuffer, 0)\n cachedPrefix = encodeBase32Hex(stringBuffer).slice(0, 14)\n cachedPrefixSecs = secs\n }\n return cachedPrefix + encodeCounterSuffix(state.processId! & 0xff, counter)\n }\n\n if (options !== undefined) validateOptions(options)\n\n const resolvedSecs = options === undefined ? undefined : resolveTimestampSecs(options, 0, MAX_SECS, 'xid')\n const secs = resolvedSecs ?? Math.floor(Date.now() / 1000)\n if (options?.machineId === undefined || options.processId === undefined) {\n initializeIdentity()\n }\n const machineId = options?.machineId ?? state.machineId!\n const processId = options?.processId ?? state.processId!\n const counter = options?.counter ?? nextCounter()\n\n if (buf !== undefined) {\n if (!isWritableRange(buf, offset, XID_BYTES)) {\n throw new BufferError('BUFFER_OUT_OF_BOUNDS', `XID byte range ${offset}:${offset + 11} is out of buffer bounds`, {\n strategy: 'xid',\n })\n }\n writeXidBytesUnchecked(secs, machineId, processId, counter, buf, offset)\n return buf\n }\n\n writeXidBytesUnchecked(secs, machineId, processId, counter, stringBuffer, 0)\n return encodeBase32Hex(stringBuffer)\n}\n\nfunction toBytes(id: string): Uint8Array {\n return decodeBase32Hex(id)\n}\n\nfunction fromBytes(bytes: Uint8Array): string {\n return encodeBase32Hex(bytes)\n}\n\nfunction timestamp(id: string): number {\n const bytes = decodeBase32Hex(id)\n return (((bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]) >>> 0) * 1000\n}\n\nfunction isValid(id: unknown): id is string {\n return typeof id === 'string' && XID_REGEX.test(id)\n}\n\n/**\n * Generate a 20-character rs/xid-compatible identifier.\n *\n * XID embeds seconds, a lazily-random per-runtime identity, and a shared\n * always-incrementing counter. In Cloudflare Workers, time is frozen during a\n * request, so the counter preserves ordering for IDs made in that request.\n */\nexport const xid: Xid = Object.assign(xidFn, {\n toBytes,\n fromBytes,\n timestamp,\n isValid,\n NIL: '0'.repeat(20),\n MAX: encodeBase32Hex(new Uint8Array(12).fill(0xff)),\n})\n\nexport { BufferError, InvalidInputError, ParseError, UniqueIdError } from '../errors'\n"],"mappings":"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"}
{
"private": false,
"name": "uniku",
"version": "0.5.0",
"version": "1.0.0-rc.0",
"description": "Minimal, tree-shakeable unique ID generators for every JavaScript runtime",

@@ -84,7 +84,2 @@ "author": {

},
"./cuid2": {
"types": "./build/cuid2/cuid2.d.mts",
"import": "./build/cuid2/cuid2.mjs",
"default": "./build/cuid2/cuid2.mjs"
},
"./cuid/v2": {

@@ -91,0 +86,0 @@ "types": "./build/cuid/v2.d.mts",

@@ -7,5 +7,5 @@ import { InvalidInputError } from '../errors'

* Timestamp options accepted by second-precision generators (ksuid, objectid,
* xid) during the pre-v1 transition to unified millisecond inputs.
* xid).
*/
export type TimestampSecsOptions = {
export type TimestampOptions = {
/**

@@ -16,22 +16,10 @@ * Timestamp in milliseconds since the Unix epoch.

msecs?: number
/**
* Timestamp in seconds since the Unix epoch.
*
* @deprecated Use `msecs` instead. Will be removed at v1-rc.
*/
// TODO(v1-rc): remove this alias (tracked in docs/STABILITY.md).
secs?: number
}
/**
* Resolve caller-provided timestamp options to whole seconds since the Unix
* epoch, or `undefined` when neither option was supplied.
*
* `msecs` is the unified input and is truncated to whole seconds; `secs` is
* the deprecated pre-v1 alias. Passing both is an error.
*
* TODO(v1-rc): drop the `secs` branch once the alias is removed.
* Resolve a caller-provided millisecond timestamp to whole seconds since the
* Unix epoch, or `undefined` when no timestamp was supplied.
*/
export function resolveTimestampSecs(
options: TimestampSecsOptions,
options: TimestampOptions,
minSecs: number,

@@ -41,8 +29,4 @@ maxSecs: number,

): number | undefined {
const { msecs, secs } = options
const { msecs } = options
if (msecs !== undefined && secs !== undefined) {
throw new InvalidInputError('CONFLICTING_OPTIONS', 'Pass only one of `msecs` or `secs`, not both', { strategy })
}
if (msecs !== undefined) {

@@ -61,14 +45,3 @@ const minMsecs = minSecs * 1000

if (secs !== undefined) {
if (!isIntegerInRange(secs, minSecs, maxSecs)) {
throw new InvalidInputError(
'TIMESTAMP_OUT_OF_RANGE',
`Timestamp must be an integer between ${minSecs} and ${maxSecs} seconds`,
{ strategy },
)
}
return secs
}
return undefined
}

@@ -0,9 +1,198 @@

import { sha3_512 } from '@noble/hashes/sha3.js'
import { randomUint32 } from '../common/random'
import { InvalidInputError } from '../errors'
export type CuidV2Options = {
/**
* Length of the generated ID (2-32 characters).
* Default: 24
*/
length?: number
/**
* Custom random bytes for deterministic testing.
* Must be at least 1 byte. For adequate entropy, use at least 16 bytes.
* Note: The fingerprint always uses cryptographically secure random bytes,
* regardless of this option.
*/
random?: Uint8Array
}
export type CuidV2 = {
/** Generate a CUID v2 string. */
(options?: CuidV2Options): string
/** Return whether a value is a syntactically valid CUID v2 string. */
isValid(id: unknown): id is string
}
const DEFAULT_LENGTH = 24
const MAX_LENGTH = 32
const MIN_LENGTH = 2
// Maximum initial counter value from cuid2 spec - provides ~29 bits of
// initial entropy to prevent cross-process collisions at startup
const INITIAL_COUNT_MAX = 476782367
// Validation regex: first char must be a-z, rest can be a-z or 0-9
const CUID2_REGEX = /^[a-z][0-9a-z]+$/
// Base36 alphabet
const ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz'
const LETTER_ALPHABET = 'abcdefghijklmnopqrstuvwxyz'
// Reusable TextEncoder instance (stateless, safe to share)
const textEncoder = new TextEncoder()
/**
* `uniku/cuid/v2` — the canonical, versioned entry point for the CUID2 generator.
* Module-level state for counter and fingerprint.
* Counter is initialized lazily on first call to prevent unnecessary crypto operations.
* Fingerprint is also generated lazily on first call.
*/
const state: { counter: number | undefined; fingerprint: string | undefined } = {
counter: undefined,
fingerprint: undefined,
}
/**
* Initialize counter using crypto for consistency with other entropy sources.
*/
function initializeCounter(): number {
return randomUint32() % (INITIAL_COUNT_MAX + 1)
}
// --- Base36 utilities ---
function bufToBigInt(buf: Uint8Array): bigint {
let value = 0n
for (const byte of buf) {
value = value * 256n + BigInt(byte)
}
return value
}
function bigIntToBase36(value: bigint): string {
if (value === 0n) return '0'
const chars: string[] = []
while (value > 0n) {
chars.push(ALPHABET[Number(value % 36n)])
value = value / 36n
}
return chars.reverse().join('')
}
function randomLetter(random: () => number): string {
return LETTER_ALPHABET[Math.floor(random() * 26)]
}
function createEntropy(length: number, random: () => number): string {
const chars = new Array<string>(length)
for (let i = 0; i < length; i++) {
chars[i] = ALPHABET[Math.floor(random() * 36)]
}
return chars.join('')
}
// --- SHA3 hash wrapper ---
function hash(input: string): Uint8Array {
return sha3_512(textEncoder.encode(input))
}
// --- Fingerprint generation ---
const BIG_LENGTH = 32
function createFingerprint(): string {
// Always use CSPRNG for fingerprint to ensure security regardless of custom random option
const random = getCryptoRandom
const globals = Object.keys(globalThis).toString()
const sourceString = globals + createEntropy(BIG_LENGTH, random)
const hashed = hash(sourceString)
return bigIntToBase36(bufToBigInt(hashed)).slice(1, BIG_LENGTH + 1)
}
// --- Random function factory ---
/**
* Get a random number in [0, 1) using CUID2's own random pool.
*/
function getCryptoRandom(): number {
return randomUint32() / 0x100000000
}
function getRandomFn(random?: Uint8Array): () => number {
if (random) {
if (random.length === 0) {
throw new InvalidInputError('RANDOM_BYTES_TOO_SHORT', 'Random byte array cannot be empty', {
strategy: 'cuid',
})
}
let index = 0
return () => {
const value = random[index % random.length] / 256
index += 1
return value
}
}
return getCryptoRandom
}
// --- Main generator ---
function cuidv2Fn(options?: CuidV2Options): string {
const requestedLength = options?.length
if (
requestedLength !== undefined &&
(!Number.isInteger(requestedLength) || requestedLength < MIN_LENGTH || requestedLength > MAX_LENGTH)
) {
throw new InvalidInputError(
'LENGTH_OUT_OF_RANGE',
`CUID2 length must be between ${MIN_LENGTH} and ${MAX_LENGTH}. Received: ${requestedLength}`,
{ strategy: 'cuid' },
)
}
const length = requestedLength ?? DEFAULT_LENGTH
const random = getRandomFn(options?.random)
// Initialize counter lazily on first call
if (state.counter === undefined) {
state.counter = initializeCounter()
}
// Initialize fingerprint lazily on first call (always uses CSPRNG)
if (state.fingerprint === undefined) {
state.fingerprint = createFingerprint()
}
const firstLetter = randomLetter(random)
const time = Date.now().toString(36)
state.counter += 1
const count = state.counter.toString(36)
const salt = createEntropy(length, random)
const hashInput = time + salt + count + state.fingerprint
const hashed = hash(hashInput)
const base36Hash = bigIntToBase36(bufToBigInt(hashed))
// Drop first char of hash to avoid histogram bias, prepend random letter
return firstLetter + base36Hash.slice(1, length)
}
// --- Validation (type guard) ---
function isValid(id: unknown): id is string {
return typeof id === 'string' && id.length >= MIN_LENGTH && id.length <= MAX_LENGTH && CUID2_REGEX.test(id)
}
/**
* Generate a CUID v2 string.
*
* This mirrors the versioned-subpath convention used by `uniku/uuid/v4` and
* `uniku/uuid/v7`, and supersedes the now-`@deprecated` `uniku/cuid2` entry
* point. It re-exports the single existing implementation under the `cuidv2`
* name — there is no second implementation.
* CUID v2 is a secure, collision-resistant identifier that hashes multiple
* entropy sources using SHA3-512. Unlike time-ordered IDs (ULID, UUID v7),
* CUID v2 prevents enumeration attacks by making IDs non-predictable.
*
* Note: CUID v2 does not provide toBytes/fromBytes because it is a string-native
* format with no canonical binary representation (unlike UUID's 16-byte format).
*
* @example

@@ -16,5 +205,16 @@ * ```ts

*
* cuidv2.isValid(id) // true
* // Custom length
* const shortId = cuidv2({ length: 10 })
* // => "tz4a98xxat"
*
* // Validation (type guard)
* const maybeId: unknown = getUserInput()
* if (cuidv2.isValid(maybeId)) {
* console.log(maybeId.length) // TypeScript knows maybeId is string
* }
* ```
*
*/
export { type Cuid2 as CuidV2, type Cuid2Options as CuidV2Options, cuid2 as cuidv2 } from '../cuid2/cuid2'
export const cuidv2: CuidV2 = Object.assign(cuidv2Fn, {
isValid,
})

@@ -46,9 +46,2 @@ import { writeTimestamp32 } from '../common/bytes'

msecs?: number
/**
* Timestamp in seconds since the Unix epoch.
*
* @deprecated Use `msecs` instead. Will be removed at v1-rc.
*/
// TODO(v1-rc): remove this alias (tracked in docs/STABILITY.md).
secs?: number
}

@@ -55,0 +48,0 @@

@@ -57,9 +57,2 @@ import { InvalidInputError } from '../errors'

length?: number
/**
* Length of generated ID.
*
* @deprecated Use `length` instead. Will be removed at v1-rc.
*/
// TODO(v1-rc): remove this alias (tracked in docs/STABILITY.md).
size?: number
}

@@ -146,8 +139,3 @@

} else {
if (sizeOrOptions.length !== undefined && sizeOrOptions.size !== undefined) {
throw new InvalidInputError('CONFLICTING_OPTIONS', 'Pass only one of `length` or `size`, not both', {
strategy: 'nanoid',
})
}
size = sizeOrOptions.length ?? sizeOrOptions.size ?? DEFAULT_SIZE
size = sizeOrOptions.length ?? DEFAULT_SIZE
alphabet = sizeOrOptions.alphabet ?? URL_ALPHABET

@@ -154,0 +142,0 @@ randomBytes = sizeOrOptions.random

@@ -41,9 +41,2 @@ import { writeTimestamp32 } from '../common/bytes'

/**
* Timestamp in seconds since the Unix epoch.
*
* @deprecated Use `msecs` instead. Will be removed at v1-rc.
*/
// TODO(v1-rc): remove this alias (tracked in docs/STABILITY.md).
secs?: number
/**
* 24-bit counter value (0 to 0xFFFFFF).

@@ -50,0 +43,0 @@ */

@@ -258,8 +258,3 @@ import { isIntegerInRange, isWritableRange } from '../common/validation'

if (options.counter !== undefined && options.seq !== undefined) {
throw new InvalidInputError('CONFLICTING_OPTIONS', 'Pass only one of `counter` or `seq`, not both', {
strategy: 'typeid',
})
}
const counter = options.counter ?? options.seq
const counter = options.counter
if (counter !== undefined && !isIntegerInRange(counter, 0, MAX_COUNTER)) {

@@ -266,0 +261,0 @@ throw new InvalidInputError('COUNTER_OUT_OF_RANGE', `Counter must be an integer between 0 and ${MAX_COUNTER}`, {

@@ -21,9 +21,2 @@ import { rng } from '../common/random'

counter?: number
/**
* Unsigned 32-bit sequence value.
*
* @deprecated Use `counter` instead. Will be removed at v1-rc.
*/
// TODO(v1-rc): remove this alias (tracked in docs/STABILITY.md).
seq?: number
}

@@ -71,3 +64,3 @@

* - In serverless/edge functions with warm starts, state persists between invocations.
* - For isolated state, pass explicit `msecs` and `seq` via options.
* - For isolated state, pass explicit `msecs` and `counter` via options.
* - Tests should mock Date.now() or provide explicit options for deterministic behavior.

@@ -123,9 +116,4 @@ */

}
if (options.counter !== undefined && options.seq !== undefined) {
throw new InvalidInputError('CONFLICTING_OPTIONS', 'Pass only one of `counter` or `seq`, not both', {
strategy: 'uuid',
})
}
const optSeq = options.counter ?? options.seq
if (optSeq !== undefined && !isIntegerInRange(optSeq, 0, MAX_SEQ)) {
const counter = options.counter
if (counter !== undefined && !isIntegerInRange(counter, 0, MAX_SEQ)) {
throw new InvalidInputError('COUNTER_OUT_OF_RANGE', `Counter must be an integer between 0 and ${MAX_SEQ}`, {

@@ -145,3 +133,3 @@ strategy: 'uuid',

// Derive a 31-bit sequence if not provided by the caller, matching the default hot path.
const seq = optSeq ?? (rnds[6] << 23) | (rnds[7] << 16) | (rnds[8] << 8) | rnds[9]
const seq = counter ?? (rnds[6] << 23) | (rnds[7] << 16) | (rnds[8] << 8) | rnds[9]

@@ -148,0 +136,0 @@ if (buf) {

@@ -28,9 +28,2 @@ import { writeTimestamp32 } from '../common/bytes'

msecs?: number
/**
* Unix timestamp in seconds.
*
* @deprecated Use `msecs` instead. Will be removed at v1-rc.
*/
// TODO(v1-rc): remove this alias (tracked in docs/STABILITY.md).
secs?: number
/** 24-bit counter. Explicit values do not consume shared state. */

@@ -37,0 +30,0 @@ counter?: number

import { i as InvalidInputError, o as UniqueIdError } from "../errors-Da-8dh4J.mjs";
//#region src/cuid2/cuid2.d.ts
type Cuid2Options = {
/**
* Length of the generated ID (2-32 characters).
* Default: 24
*/
length?: number;
/**
* Custom random bytes for deterministic testing.
* Must be at least 1 byte. For adequate entropy, use at least 16 bytes.
* Note: The fingerprint always uses cryptographically secure random bytes,
* regardless of this option.
*/
random?: Uint8Array;
};
type Cuid2 = {
/** Generate a CUID v2 string. */(options?: Cuid2Options): string; /** Return whether a value is a syntactically valid CUID v2 string. */
isValid(id: unknown): id is string;
};
/**
* Generate a CUID v2 string.
*
* CUID v2 is a secure, collision-resistant identifier that hashes multiple
* entropy sources using SHA3-512. Unlike time-ordered IDs (ULID, UUID v7),
* CUID v2 prevents enumeration attacks by making IDs non-predictable.
*
* Note: CUID v2 does not provide toBytes/fromBytes because it is a string-native
* format with no canonical binary representation (unlike UUID's 16-byte format).
*
* @example
* ```ts
* import { cuid2 } from 'uniku/cuid2'
*
* const id = cuid2()
* // => "pfh0haxfpzowht3oi213cqos"
*
* // Custom length
* const shortId = cuid2({ length: 10 })
* // => "tz4a98xxat"
*
* // Validation (type guard)
* const maybeId: unknown = getUserInput()
* if (cuid2.isValid(maybeId)) {
* console.log(maybeId.length) // TypeScript knows maybeId is string
* }
* ```
*
* @deprecated Use `cuidv2` from `uniku/cuid/v2` instead. This entry point keeps
* working unchanged, but `uniku/cuid/v2` is the canonical versioned subpath
* (mirroring `uniku/uuid/v4` / `uniku/uuid/v7`).
*/
declare const cuid2: Cuid2;
//#endregion
export { Cuid2, Cuid2Options, InvalidInputError, UniqueIdError, cuid2 };
//# sourceMappingURL=cuid2.d.mts.map
{"version":3,"file":"cuid2.d.mts","names":[],"sources":["../../src/cuid2/cuid2.ts"],"mappings":";;;KAIY,YAAA;;;AAAZ;;EAKE,MAAA;EAOS;;;;;AAAA;EAAT,MAAA,GAAS,UAAA;AAAA;AAAA,KAGC,KAAA;EAEC,kCAAV,OAAA,GAAU,YAAA;EAEX,OAAA,CAAQ,EAAA,YAAc,EAAA;AAAA;;;AAAA;AAoMxB;;;;AAAoB;;;;;;;;;;;;;;;;;;;;;;;;;cAAP,KAAA,EAAO,KAAA"}
import{n as e}from"../random-Chp-Nkzi.mjs";import{InvalidInputError as t,UniqueIdError as n}from"../errors.mjs";import{sha3_512 as r}from"@noble/hashes/sha3.js";const i=/^[a-z][0-9a-z]+$/,a=`0123456789abcdefghijklmnopqrstuvwxyz`,o=new TextEncoder,s={counter:void 0,fingerprint:void 0};function c(){return e()%476782368}function l(e){let t=0n;for(let n of e)t=t*256n+BigInt(n);return t}function u(e){if(e===0n)return`0`;let t=[];for(;e>0n;)t.push(a[Number(e%36n)]),e/=36n;return t.reverse().join(``)}function d(e){return`abcdefghijklmnopqrstuvwxyz`[Math.floor(e()*26)]}function f(e,t){let n=Array(e);for(let r=0;r<e;r++)n[r]=a[Math.floor(t()*36)];return n.join(``)}function p(e){return r(o.encode(e))}function m(){let e=h;return u(l(p(Object.keys(globalThis).toString()+f(32,e)))).slice(1,33)}function h(){return e()/4294967296}function g(e){if(e){if(e.length===0)throw new t(`RANDOM_BYTES_TOO_SHORT`,`Random byte array cannot be empty`,{strategy:`cuid`});let n=0;return()=>{let t=e[n%e.length]/256;return n+=1,t}}return h}function _(e){let n=e?.length;if(n!==void 0&&(!Number.isInteger(n)||n<2||n>32))throw new t(`LENGTH_OUT_OF_RANGE`,`CUID2 length must be between 2 and 32. Received: ${n}`,{strategy:`cuid`});let r=n??24,i=g(e?.random);s.counter===void 0&&(s.counter=c()),s.fingerprint===void 0&&(s.fingerprint=m());let a=d(i),o=Date.now().toString(36);s.counter+=1;let h=s.counter.toString(36);return a+u(l(p(o+f(r,i)+h+s.fingerprint))).slice(1,r)}function v(e){return typeof e==`string`&&e.length>=2&&e.length<=32&&i.test(e)}const y=Object.assign(_,{isValid:v});export{t as InvalidInputError,n as UniqueIdError,y as cuid2};
//# sourceMappingURL=cuid2.mjs.map
{"version":3,"file":"cuid2.mjs","names":[],"sources":["../../src/cuid2/cuid2.ts"],"sourcesContent":["import { sha3_512 } from '@noble/hashes/sha3.js'\nimport { randomUint32 } from '../common/random'\nimport { InvalidInputError } from '../errors'\n\nexport type Cuid2Options = {\n /**\n * Length of the generated ID (2-32 characters).\n * Default: 24\n */\n length?: number\n /**\n * Custom random bytes for deterministic testing.\n * Must be at least 1 byte. For adequate entropy, use at least 16 bytes.\n * Note: The fingerprint always uses cryptographically secure random bytes,\n * regardless of this option.\n */\n random?: Uint8Array\n}\n\nexport type Cuid2 = {\n /** Generate a CUID v2 string. */\n (options?: Cuid2Options): string\n /** Return whether a value is a syntactically valid CUID v2 string. */\n isValid(id: unknown): id is string\n}\n\nconst DEFAULT_LENGTH = 24\nconst MAX_LENGTH = 32\nconst MIN_LENGTH = 2\n\n// Maximum initial counter value from cuid2 spec - provides ~29 bits of\n// initial entropy to prevent cross-process collisions at startup\nconst INITIAL_COUNT_MAX = 476782367\n\n// Validation regex: first char must be a-z, rest can be a-z or 0-9\nconst CUID2_REGEX = /^[a-z][0-9a-z]+$/\n\n// Base36 alphabet\nconst ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz'\nconst LETTER_ALPHABET = 'abcdefghijklmnopqrstuvwxyz'\n\n// Reusable TextEncoder instance (stateless, safe to share)\nconst textEncoder = new TextEncoder()\n\n/**\n * Module-level state for counter and fingerprint.\n * Counter is initialized lazily on first call to prevent unnecessary crypto operations.\n * Fingerprint is also generated lazily on first call.\n */\nconst state: { counter: number | undefined; fingerprint: string | undefined } = {\n counter: undefined,\n fingerprint: undefined,\n}\n\n/**\n * Initialize counter using crypto for consistency with other entropy sources.\n */\nfunction initializeCounter(): number {\n return randomUint32() % (INITIAL_COUNT_MAX + 1)\n}\n\n// --- Base36 utilities ---\n\nfunction bufToBigInt(buf: Uint8Array): bigint {\n let value = 0n\n for (const byte of buf) {\n value = value * 256n + BigInt(byte)\n }\n return value\n}\n\nfunction bigIntToBase36(value: bigint): string {\n if (value === 0n) return '0'\n const chars: string[] = []\n while (value > 0n) {\n chars.push(ALPHABET[Number(value % 36n)])\n value = value / 36n\n }\n return chars.reverse().join('')\n}\n\nfunction randomLetter(random: () => number): string {\n return LETTER_ALPHABET[Math.floor(random() * 26)]\n}\n\nfunction createEntropy(length: number, random: () => number): string {\n const chars = new Array<string>(length)\n for (let i = 0; i < length; i++) {\n chars[i] = ALPHABET[Math.floor(random() * 36)]\n }\n return chars.join('')\n}\n\n// --- SHA3 hash wrapper ---\n\nfunction hash(input: string): Uint8Array {\n return sha3_512(textEncoder.encode(input))\n}\n\n// --- Fingerprint generation ---\n\nconst BIG_LENGTH = 32\n\nfunction createFingerprint(): string {\n // Always use CSPRNG for fingerprint to ensure security regardless of custom random option\n const random = getCryptoRandom\n const globals = Object.keys(globalThis).toString()\n const sourceString = globals + createEntropy(BIG_LENGTH, random)\n const hashed = hash(sourceString)\n return bigIntToBase36(bufToBigInt(hashed)).slice(1, BIG_LENGTH + 1)\n}\n\n// --- Random function factory ---\n\n/**\n * Get a random number in [0, 1) using CUID2's own random pool.\n */\nfunction getCryptoRandom(): number {\n return randomUint32() / 0x100000000\n}\n\nfunction getRandomFn(random?: Uint8Array): () => number {\n if (random) {\n if (random.length === 0) {\n throw new InvalidInputError('RANDOM_BYTES_TOO_SHORT', 'Random byte array cannot be empty', {\n strategy: 'cuid',\n })\n }\n let index = 0\n return () => {\n const value = random[index % random.length] / 256\n index += 1\n return value\n }\n }\n return getCryptoRandom\n}\n\n// --- Main generator ---\n\nfunction cuid2Fn(options?: Cuid2Options): string {\n const requestedLength = options?.length\n\n if (\n requestedLength !== undefined &&\n (!Number.isInteger(requestedLength) || requestedLength < MIN_LENGTH || requestedLength > MAX_LENGTH)\n ) {\n throw new InvalidInputError(\n 'LENGTH_OUT_OF_RANGE',\n `CUID2 length must be between ${MIN_LENGTH} and ${MAX_LENGTH}. Received: ${requestedLength}`,\n { strategy: 'cuid' },\n )\n }\n const length = requestedLength ?? DEFAULT_LENGTH\n\n const random = getRandomFn(options?.random)\n\n // Initialize counter lazily on first call\n if (state.counter === undefined) {\n state.counter = initializeCounter()\n }\n\n // Initialize fingerprint lazily on first call (always uses CSPRNG)\n if (state.fingerprint === undefined) {\n state.fingerprint = createFingerprint()\n }\n\n const firstLetter = randomLetter(random)\n const time = Date.now().toString(36)\n state.counter += 1\n const count = state.counter.toString(36)\n const salt = createEntropy(length, random)\n\n const hashInput = time + salt + count + state.fingerprint\n const hashed = hash(hashInput)\n const base36Hash = bigIntToBase36(bufToBigInt(hashed))\n\n // Drop first char of hash to avoid histogram bias, prepend random letter\n return firstLetter + base36Hash.slice(1, length)\n}\n\n// --- Validation (type guard) ---\n\nfunction isValid(id: unknown): id is string {\n return typeof id === 'string' && id.length >= MIN_LENGTH && id.length <= MAX_LENGTH && CUID2_REGEX.test(id)\n}\n\n/**\n * Generate a CUID v2 string.\n *\n * CUID v2 is a secure, collision-resistant identifier that hashes multiple\n * entropy sources using SHA3-512. Unlike time-ordered IDs (ULID, UUID v7),\n * CUID v2 prevents enumeration attacks by making IDs non-predictable.\n *\n * Note: CUID v2 does not provide toBytes/fromBytes because it is a string-native\n * format with no canonical binary representation (unlike UUID's 16-byte format).\n *\n * @example\n * ```ts\n * import { cuid2 } from 'uniku/cuid2'\n *\n * const id = cuid2()\n * // => \"pfh0haxfpzowht3oi213cqos\"\n *\n * // Custom length\n * const shortId = cuid2({ length: 10 })\n * // => \"tz4a98xxat\"\n *\n * // Validation (type guard)\n * const maybeId: unknown = getUserInput()\n * if (cuid2.isValid(maybeId)) {\n * console.log(maybeId.length) // TypeScript knows maybeId is string\n * }\n * ```\n *\n * @deprecated Use `cuidv2` from `uniku/cuid/v2` instead. This entry point keeps\n * working unchanged, but `uniku/cuid/v2` is the canonical versioned subpath\n * (mirroring `uniku/uuid/v4` / `uniku/uuid/v7`).\n */\nexport const cuid2: Cuid2 = Object.assign(cuid2Fn, {\n isValid,\n})\n\nexport { InvalidInputError, UniqueIdError } from '../errors'\n"],"mappings":"iKA0BA,MASM,EAAc,mBAGd,EAAW,uCAIX,EAAc,IAAI,YAOlB,EAA0E,CAC9E,QAAS,IAAA,GACT,YAAa,IAAA,EACf,EAKA,SAAS,GAA4B,CACnC,OAAO,EAAa,EAAK,SAC3B,CAIA,SAAS,EAAY,EAAyB,CAC5C,IAAI,EAAQ,GACZ,IAAK,IAAM,KAAQ,EACjB,EAAQ,EAAQ,KAAO,OAAO,CAAI,EAEpC,OAAO,CACT,CAEA,SAAS,EAAe,EAAuB,CAC7C,GAAI,IAAU,GAAI,MAAO,IACzB,IAAM,EAAkB,CAAC,EACzB,KAAO,EAAQ,IACb,EAAM,KAAK,EAAS,OAAO,EAAQ,GAAG,EAAE,EACxC,GAAgB,IAElB,OAAO,EAAM,QAAQ,CAAC,CAAC,KAAK,EAAE,CAChC,CAEA,SAAS,EAAa,EAA8B,CAClD,MAAO,6BAAgB,KAAK,MAAM,EAAO,EAAI,EAAE,EACjD,CAEA,SAAS,EAAc,EAAgB,EAA8B,CACnE,IAAM,EAAY,MAAc,CAAM,EACtC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,IAC1B,EAAM,GAAK,EAAS,KAAK,MAAM,EAAO,EAAI,EAAE,GAE9C,OAAO,EAAM,KAAK,EAAE,CACtB,CAIA,SAAS,EAAK,EAA2B,CACvC,OAAO,EAAS,EAAY,OAAO,CAAK,CAAC,CAC3C,CAMA,SAAS,GAA4B,CAEnC,IAAM,EAAS,EAIf,OAAO,EAAe,EADP,EAFC,OAAO,KAAK,UAAU,CAAC,CAAC,SACb,EAAI,EAAc,GAAY,CAAM,CAExB,CAAC,CAAC,CAAC,CAAC,MAAM,EAAG,EAAc,CACpE,CAOA,SAAS,GAA0B,CACjC,OAAO,EAAa,EAAI,UAC1B,CAEA,SAAS,EAAY,EAAmC,CACtD,GAAI,EAAQ,CACV,GAAI,EAAO,SAAW,EACpB,MAAM,IAAI,EAAkB,yBAA0B,oCAAqC,CACzF,SAAU,MACZ,CAAC,EAEH,IAAI,EAAQ,EACZ,UAAa,CACX,IAAM,EAAQ,EAAO,EAAQ,EAAO,QAAU,IAE9C,MADA,IAAS,EACF,CACT,CACF,CACA,OAAO,CACT,CAIA,SAAS,EAAQ,EAAgC,CAC/C,IAAM,EAAkB,GAAS,OAEjC,GACE,IAAoB,IAAA,KACnB,CAAC,OAAO,UAAU,CAAe,GAAK,EAAkB,GAAc,EAAkB,IAEzF,MAAM,IAAI,EACR,sBACA,oDAA2E,IAC3E,CAAE,SAAU,MAAO,CACrB,EAEF,IAAM,EAAS,GAAmB,GAE5B,EAAS,EAAY,GAAS,MAAM,EAGtC,EAAM,UAAY,IAAA,KACpB,EAAM,QAAU,EAAkB,GAIhC,EAAM,cAAgB,IAAA,KACxB,EAAM,YAAc,EAAkB,GAGxC,IAAM,EAAc,EAAa,CAAM,EACjC,EAAO,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE,EACnC,EAAM,SAAW,EACjB,IAAM,EAAQ,EAAM,QAAQ,SAAS,EAAE,EAQvC,OAAO,EAHY,EAAe,EADnB,EADG,EAFL,EAAc,EAAQ,CAEP,EAAI,EAAQ,EAAM,WAEK,CAAC,CAGtB,CAAC,CAAC,MAAM,EAAG,CAAM,CACjD,CAIA,SAAS,EAAQ,EAA2B,CAC1C,OAAO,OAAO,GAAO,UAAY,EAAG,QAAU,GAAc,EAAG,QAAU,IAAc,EAAY,KAAK,CAAE,CAC5G,CAkCA,MAAa,EAAe,OAAO,OAAO,EAAS,CACjD,SACF,CAAC"}
import { n as IdGenerator } from "./generators-BfJLt7Qf.mjs";
//#region src/errors.d.ts
/**
* The canonical, ordered list of machine-readable error codes emitted by
* uniku's public API.
*
* Codes describe the failure independently of an ID format. Use an error's
* `strategy` field when the generator that raised it matters.
*/
declare const ERROR_CODES: readonly ["TIMESTAMP_OUT_OF_RANGE", "CONFLICTING_OPTIONS", "COUNTER_OUT_OF_RANGE", "NODE_OUT_OF_RANGE", "NODE_BITS_OUT_OF_RANGE", "EPOCH_INVALID", "PROCESS_ID_OUT_OF_RANGE", "MACHINE_ID_BYTES_TOO_SHORT", "RANDOM_BYTES_TOO_SHORT", "RANDOM_OVERFLOW", "LENGTH_OUT_OF_RANGE", "ALPHABET_OUT_OF_RANGE", "ALPHABET_INVALID_CHAR", "ALPHABET_DUPLICATE", "PREFIX_TOO_LONG", "PREFIX_INVALID_CHAR", "PREFIX_INVALID_BOUNDARY", "UUID_NOT_V7", "BYTES_INVALID_LENGTH", "BUFFER_OUT_OF_BOUNDS", "INVALID_CHAR", "INVALID_LENGTH", "INVALID_FORMAT", "NON_CANONICAL", "VALUE_OUT_OF_RANGE"];
/**
* A machine-readable error code emitted by uniku, derived from
* {@link ERROR_CODES}.
*/
type ErrorCode = (typeof ERROR_CODES)[number];
/**
* Extra context carried by every uniku error.
*/
type UniqueIdErrorOptions = {
/**
* The ID strategy whose public boundary raised the error.
* Error codes are strategy-agnostic (e.g. `TIMESTAMP_OUT_OF_RANGE`), so this
* field attributes the failure to the generator that produced it.
*/
readonly strategy?: IdGenerator;
};
/**
* Base error for all uniku errors.
* Provides `_tag` for discriminated matching (compatible with Effect's `catchTag`),
* `code` for machine-readable error identification, and `strategy` to attribute
* unified codes to the ID generator that raised them.
*/
declare abstract class UniqueIdError extends Error {
abstract readonly _tag: string;
abstract readonly code: ErrorCode;
/** The ID strategy whose public boundary raised the error. */
readonly strategy?: IdGenerator;
constructor(message: string, options?: UniqueIdErrorOptions);
}
/**
* Thrown when generator arguments are invalid (bad size, alphabet, length, timestamp, version).
*/
declare class InvalidInputError extends UniqueIdError {
readonly code: ErrorCode;
readonly _tag = "InvalidInputError";
constructor(code: ErrorCode, message: string, options?: UniqueIdErrorOptions);
}
/**
* Thrown when parsing/decoding an ID string that has invalid format or characters.
*/
declare class ParseError extends UniqueIdError {
readonly code: ErrorCode;
readonly _tag = "ParseError";
constructor(code: ErrorCode, message: string, options?: UniqueIdErrorOptions);
}
/**
* Thrown when a byte array or buffer is too short or an offset is out of bounds.
*/
declare class BufferError extends UniqueIdError {
readonly code: ErrorCode;
readonly _tag = "BufferError";
constructor(code: ErrorCode, message: string, options?: UniqueIdErrorOptions);
}
//#endregion
export { ParseError as a, InvalidInputError as i, ERROR_CODES as n, UniqueIdError as o, ErrorCode as r, UniqueIdErrorOptions as s, BufferError as t };
//# sourceMappingURL=errors-Da-8dh4J.d.mts.map
{"version":3,"file":"errors-Da-8dh4J.d.mts","names":[],"sources":["../src/errors.ts"],"mappings":";;;;;AAWA;;;;AAyBE;cAzBW,WAAA;;;;AAgCmB;KAApB,SAAA,WAAoB,WAAA;;;;KAKpB,oBAAA;EAeZ;;;;;EAAA,SATW,QAAA,GAAW,WAAA;AAAA;;;;;;;uBASA,aAAA,SAAsB,KAAA;EAAA,kBACxB,IAAA;EAAA,kBACA,IAAA,EAAM,SAAA;;WAGf,QAAA,GAAW,WAAA;EAEpB,WAAA,CAAY,OAAA,UAAiB,OAAA,GAAU,oBAAA;AAAA;AAAA;AAUzC;;AAVyC,cAU5B,iBAAA,SAA0B,aAAA;EAAA,SAInC,IAAA,EAAe,SAAA;EAAA,SAHR,IAAA;EAET,WAAA,CACE,IAAA,EAAe,SAAA,EACf,OAAA,UACA,OAAA,GAAU,oBAAA;AAAA;;;;cASD,UAAA,SAAmB,aAAA;EAAA,SAI5B,IAAA,EAAe,SAAA;EAAA,SAHR,IAAA;EAET,WAAA,CACE,IAAA,EAAe,SAAA,EACf,OAAA,UACA,OAAA,GAAU,oBAAA;AAAA;;;;cASD,WAAA,SAAoB,aAAA;EAAA,SAI7B,IAAA,EAAe,SAAA;EAAA,SAHR,IAAA;EAET,WAAA,CACE,IAAA,EAAe,SAAA,EACf,OAAA,UACA,OAAA,GAAU,oBAAA;AAAA"}
import{t as e}from"./validation-CTNpXm94.mjs";import{InvalidInputError as t}from"./errors.mjs";function n(n,r,i,a){let{msecs:o,secs:s}=n;if(o!==void 0&&s!==void 0)throw new t(`CONFLICTING_OPTIONS`,"Pass only one of `msecs` or `secs`, not both",{strategy:a});if(o!==void 0){let n=r*1e3,s=i*1e3+999;if(!e(o,n,s))throw new t(`TIMESTAMP_OUT_OF_RANGE`,`Timestamp must be an integer between ${n} and ${s} milliseconds`,{strategy:a});return Math.floor(o/1e3)}if(s!==void 0){if(!e(s,r,i))throw new t(`TIMESTAMP_OUT_OF_RANGE`,`Timestamp must be an integer between ${r} and ${i} seconds`,{strategy:a});return s}}export{n as t};
//# sourceMappingURL=timestamp-ChrSuQCR.mjs.map
{"version":3,"file":"timestamp-ChrSuQCR.mjs","names":[],"sources":["../src/common/timestamp.ts"],"sourcesContent":["import { InvalidInputError } from '../errors'\nimport type { IdGenerator } from '../generators'\nimport { isIntegerInRange } from './validation'\n\n/**\n * Timestamp options accepted by second-precision generators (ksuid, objectid,\n * xid) during the pre-v1 transition to unified millisecond inputs.\n */\nexport type TimestampSecsOptions = {\n /**\n * Timestamp in milliseconds since the Unix epoch.\n * The generator stores whole seconds, so sub-second precision is truncated.\n */\n msecs?: number\n /**\n * Timestamp in seconds since the Unix epoch.\n *\n * @deprecated Use `msecs` instead. Will be removed at v1-rc.\n */\n // TODO(v1-rc): remove this alias (tracked in docs/STABILITY.md).\n secs?: number\n}\n\n/**\n * Resolve caller-provided timestamp options to whole seconds since the Unix\n * epoch, or `undefined` when neither option was supplied.\n *\n * `msecs` is the unified input and is truncated to whole seconds; `secs` is\n * the deprecated pre-v1 alias. Passing both is an error.\n *\n * TODO(v1-rc): drop the `secs` branch once the alias is removed.\n */\nexport function resolveTimestampSecs(\n options: TimestampSecsOptions,\n minSecs: number,\n maxSecs: number,\n strategy: IdGenerator,\n): number | undefined {\n const { msecs, secs } = options\n\n if (msecs !== undefined && secs !== undefined) {\n throw new InvalidInputError('CONFLICTING_OPTIONS', 'Pass only one of `msecs` or `secs`, not both', { strategy })\n }\n\n if (msecs !== undefined) {\n const minMsecs = minSecs * 1000\n const maxMsecs = maxSecs * 1000 + 999\n if (!isIntegerInRange(msecs, minMsecs, maxMsecs)) {\n throw new InvalidInputError(\n 'TIMESTAMP_OUT_OF_RANGE',\n `Timestamp must be an integer between ${minMsecs} and ${maxMsecs} milliseconds`,\n { strategy },\n )\n }\n return Math.floor(msecs / 1000)\n }\n\n if (secs !== undefined) {\n if (!isIntegerInRange(secs, minSecs, maxSecs)) {\n throw new InvalidInputError(\n 'TIMESTAMP_OUT_OF_RANGE',\n `Timestamp must be an integer between ${minSecs} and ${maxSecs} seconds`,\n { strategy },\n )\n }\n return secs\n }\n\n return undefined\n}\n"],"mappings":"+FAgCA,SAAgB,EACd,EACA,EACA,EACA,EACoB,CACpB,GAAM,CAAE,QAAO,QAAS,EAExB,GAAI,IAAU,IAAA,IAAa,IAAS,IAAA,GAClC,MAAM,IAAI,EAAkB,sBAAuB,+CAAgD,CAAE,UAAS,CAAC,EAGjH,GAAI,IAAU,IAAA,GAAW,CACvB,IAAM,EAAW,EAAU,IACrB,EAAW,EAAU,IAAO,IAClC,GAAI,CAAC,EAAiB,EAAO,EAAU,CAAQ,EAC7C,MAAM,IAAI,EACR,yBACA,wCAAwC,EAAS,OAAO,EAAS,eACjE,CAAE,UAAS,CACb,EAEF,OAAO,KAAK,MAAM,EAAQ,GAAI,CAChC,CAEA,GAAI,IAAS,IAAA,GAAW,CACtB,GAAI,CAAC,EAAiB,EAAM,EAAS,CAAO,EAC1C,MAAM,IAAI,EACR,yBACA,wCAAwC,EAAQ,OAAO,EAAQ,UAC/D,CAAE,UAAS,CACb,EAEF,OAAO,CACT,CAGF"}
import { sha3_512 } from '@noble/hashes/sha3.js'
import { randomUint32 } from '../common/random'
import { InvalidInputError } from '../errors'
export type Cuid2Options = {
/**
* Length of the generated ID (2-32 characters).
* Default: 24
*/
length?: number
/**
* Custom random bytes for deterministic testing.
* Must be at least 1 byte. For adequate entropy, use at least 16 bytes.
* Note: The fingerprint always uses cryptographically secure random bytes,
* regardless of this option.
*/
random?: Uint8Array
}
export type Cuid2 = {
/** Generate a CUID v2 string. */
(options?: Cuid2Options): string
/** Return whether a value is a syntactically valid CUID v2 string. */
isValid(id: unknown): id is string
}
const DEFAULT_LENGTH = 24
const MAX_LENGTH = 32
const MIN_LENGTH = 2
// Maximum initial counter value from cuid2 spec - provides ~29 bits of
// initial entropy to prevent cross-process collisions at startup
const INITIAL_COUNT_MAX = 476782367
// Validation regex: first char must be a-z, rest can be a-z or 0-9
const CUID2_REGEX = /^[a-z][0-9a-z]+$/
// Base36 alphabet
const ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz'
const LETTER_ALPHABET = 'abcdefghijklmnopqrstuvwxyz'
// Reusable TextEncoder instance (stateless, safe to share)
const textEncoder = new TextEncoder()
/**
* Module-level state for counter and fingerprint.
* Counter is initialized lazily on first call to prevent unnecessary crypto operations.
* Fingerprint is also generated lazily on first call.
*/
const state: { counter: number | undefined; fingerprint: string | undefined } = {
counter: undefined,
fingerprint: undefined,
}
/**
* Initialize counter using crypto for consistency with other entropy sources.
*/
function initializeCounter(): number {
return randomUint32() % (INITIAL_COUNT_MAX + 1)
}
// --- Base36 utilities ---
function bufToBigInt(buf: Uint8Array): bigint {
let value = 0n
for (const byte of buf) {
value = value * 256n + BigInt(byte)
}
return value
}
function bigIntToBase36(value: bigint): string {
if (value === 0n) return '0'
const chars: string[] = []
while (value > 0n) {
chars.push(ALPHABET[Number(value % 36n)])
value = value / 36n
}
return chars.reverse().join('')
}
function randomLetter(random: () => number): string {
return LETTER_ALPHABET[Math.floor(random() * 26)]
}
function createEntropy(length: number, random: () => number): string {
const chars = new Array<string>(length)
for (let i = 0; i < length; i++) {
chars[i] = ALPHABET[Math.floor(random() * 36)]
}
return chars.join('')
}
// --- SHA3 hash wrapper ---
function hash(input: string): Uint8Array {
return sha3_512(textEncoder.encode(input))
}
// --- Fingerprint generation ---
const BIG_LENGTH = 32
function createFingerprint(): string {
// Always use CSPRNG for fingerprint to ensure security regardless of custom random option
const random = getCryptoRandom
const globals = Object.keys(globalThis).toString()
const sourceString = globals + createEntropy(BIG_LENGTH, random)
const hashed = hash(sourceString)
return bigIntToBase36(bufToBigInt(hashed)).slice(1, BIG_LENGTH + 1)
}
// --- Random function factory ---
/**
* Get a random number in [0, 1) using CUID2's own random pool.
*/
function getCryptoRandom(): number {
return randomUint32() / 0x100000000
}
function getRandomFn(random?: Uint8Array): () => number {
if (random) {
if (random.length === 0) {
throw new InvalidInputError('RANDOM_BYTES_TOO_SHORT', 'Random byte array cannot be empty', {
strategy: 'cuid',
})
}
let index = 0
return () => {
const value = random[index % random.length] / 256
index += 1
return value
}
}
return getCryptoRandom
}
// --- Main generator ---
function cuid2Fn(options?: Cuid2Options): string {
const requestedLength = options?.length
if (
requestedLength !== undefined &&
(!Number.isInteger(requestedLength) || requestedLength < MIN_LENGTH || requestedLength > MAX_LENGTH)
) {
throw new InvalidInputError(
'LENGTH_OUT_OF_RANGE',
`CUID2 length must be between ${MIN_LENGTH} and ${MAX_LENGTH}. Received: ${requestedLength}`,
{ strategy: 'cuid' },
)
}
const length = requestedLength ?? DEFAULT_LENGTH
const random = getRandomFn(options?.random)
// Initialize counter lazily on first call
if (state.counter === undefined) {
state.counter = initializeCounter()
}
// Initialize fingerprint lazily on first call (always uses CSPRNG)
if (state.fingerprint === undefined) {
state.fingerprint = createFingerprint()
}
const firstLetter = randomLetter(random)
const time = Date.now().toString(36)
state.counter += 1
const count = state.counter.toString(36)
const salt = createEntropy(length, random)
const hashInput = time + salt + count + state.fingerprint
const hashed = hash(hashInput)
const base36Hash = bigIntToBase36(bufToBigInt(hashed))
// Drop first char of hash to avoid histogram bias, prepend random letter
return firstLetter + base36Hash.slice(1, length)
}
// --- Validation (type guard) ---
function isValid(id: unknown): id is string {
return typeof id === 'string' && id.length >= MIN_LENGTH && id.length <= MAX_LENGTH && CUID2_REGEX.test(id)
}
/**
* Generate a CUID v2 string.
*
* CUID v2 is a secure, collision-resistant identifier that hashes multiple
* entropy sources using SHA3-512. Unlike time-ordered IDs (ULID, UUID v7),
* CUID v2 prevents enumeration attacks by making IDs non-predictable.
*
* Note: CUID v2 does not provide toBytes/fromBytes because it is a string-native
* format with no canonical binary representation (unlike UUID's 16-byte format).
*
* @example
* ```ts
* import { cuid2 } from 'uniku/cuid2'
*
* const id = cuid2()
* // => "pfh0haxfpzowht3oi213cqos"
*
* // Custom length
* const shortId = cuid2({ length: 10 })
* // => "tz4a98xxat"
*
* // Validation (type guard)
* const maybeId: unknown = getUserInput()
* if (cuid2.isValid(maybeId)) {
* console.log(maybeId.length) // TypeScript knows maybeId is string
* }
* ```
*
* @deprecated Use `cuidv2` from `uniku/cuid/v2` instead. This entry point keeps
* working unchanged, but `uniku/cuid/v2` is the canonical versioned subpath
* (mirroring `uniku/uuid/v4` / `uniku/uuid/v7`).
*/
export const cuid2: Cuid2 = Object.assign(cuid2Fn, {
isValid,
})
export { InvalidInputError, UniqueIdError } from '../errors'