uniku 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +32 -0
  2. package/build/cuid2/cuid2.d.mts +5 -5
  3. package/build/cuid2/cuid2.d.mts.map +1 -1
  4. package/build/cuid2/cuid2.mjs.map +1 -1
  5. package/build/generators.d.mts +1 -1
  6. package/build/generators.d.mts.map +1 -1
  7. package/build/generators.mjs +1 -1
  8. package/build/generators.mjs.map +1 -1
  9. package/build/ksuid/ksuid.d.mts +6 -6
  10. package/build/ksuid/ksuid.d.mts.map +1 -1
  11. package/build/ksuid/ksuid.mjs.map +1 -1
  12. package/build/nanoid/nanoid.d.mts +2 -2
  13. package/build/nanoid/nanoid.mjs.map +1 -1
  14. package/build/objectid/objectid.d.mts +6 -6
  15. package/build/objectid/objectid.d.mts.map +1 -1
  16. package/build/objectid/objectid.mjs.map +1 -1
  17. package/build/tsid/tsid.d.mts +8 -8
  18. package/build/tsid/tsid.d.mts.map +1 -1
  19. package/build/tsid/tsid.mjs.map +1 -1
  20. package/build/typeid/typeid.d.mts +8 -8
  21. package/build/typeid/typeid.d.mts.map +1 -1
  22. package/build/typeid/typeid.mjs.map +1 -1
  23. package/build/ulid/ulid.d.mts +10 -6
  24. package/build/ulid/ulid.d.mts.map +1 -1
  25. package/build/ulid/ulid.mjs.map +1 -1
  26. package/build/uuid/v4.d.mts +5 -5
  27. package/build/uuid/v4.d.mts.map +1 -1
  28. package/build/uuid/v4.mjs.map +1 -1
  29. package/build/uuid/v7.d.mts +10 -6
  30. package/build/uuid/v7.d.mts.map +1 -1
  31. package/build/uuid/v7.mjs.map +1 -1
  32. package/build/xid/xid.d.mts +31 -0
  33. package/build/xid/xid.d.mts.map +1 -0
  34. package/build/xid/xid.mjs +2 -0
  35. package/build/xid/xid.mjs.map +1 -0
  36. package/package.json +11 -3
  37. package/src/cuid2/cuid2.ts +6 -4
  38. package/src/generators.ts +1 -1
  39. package/src/ksuid/ksuid.ts +7 -0
  40. package/src/nanoid/nanoid.ts +3 -3
  41. package/src/objectid/objectid.ts +7 -0
  42. package/src/tsid/tsid.ts +9 -0
  43. package/src/typeid/typeid.ts +9 -0
  44. package/src/ulid/ulid.ts +11 -0
  45. package/src/uuid/v4.ts +6 -0
  46. package/src/uuid/v7.ts +11 -0
  47. package/src/xid/base32hex.ts +79 -0
  48. package/src/xid/xid.ts +158 -0
@@ -1 +1 @@
1
- {"version":3,"file":"typeid.d.mts","names":[],"sources":["../../src/typeid/typeid.ts"],"mappings":";;;;KAIY,aAAA,GAAgB,aAAA;AAAA,KAEhB,MAAA;EAAA,CACT,MAAA,UAAgB,OAAA,GAAU,aAAA;EAC3B,OAAA,CAAQ,EAAA,WAAa,UAAA;EACrB,SAAA,CAAU,MAAA,UAAgB,KAAA,EAAO,UAAA;EACjC,MAAA,CAAO,EAAA;EACP,QAAA,CAAS,MAAA,UAAgB,IAAA;EACzB,SAAA,CAAU,EAAA;EACV,MAAA,CAAO,EAAA;EACP,MAAA,CAAO,EAAA;EACP,OAAA,CAAQ,EAAA,YAAc,EAAA;AAAA;;;;;;;;;;;;;;;;;;;cAgQX,MAAA,EAAQ,MAAA"}
1
+ {"version":3,"file":"typeid.d.mts","names":[],"sources":["../../src/typeid/typeid.ts"],"mappings":";;;;KAIY,aAAA,GAAgB,aAAA;AAAA,KAEhB,MAAA;gFAET,MAAA,UAAgB,OAAA,GAAU,aAAA,WAJjB;EAMV,OAAA,CAAQ,EAAA,WAAa,UAAA,EANK;EAQ1B,SAAA,CAAU,MAAA,UAAgB,KAAA,EAAO,UAAA,WANnC;EAQE,MAAA,CAAO,EAAA;EAEP,QAAA,CAAS,MAAA,UAAgB,IAAA;EAEzB,SAAA,CAAU,EAAA,mBANuB;EAQjC,MAAA,CAAO,EAAA;EAEP,MAAA,CAAO,EAAA;EAEP,OAAA,CAAQ,EAAA,YAAc,EAAA;AAAA;;;;;;;;;;;;;;;;;;;cAgQX,MAAA,EAAQ,MAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"typeid.mjs","names":[],"sources":["../../src/typeid/typeid.ts"],"sourcesContent":["import { 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 (prefix: string, options?: TypeidOptions): string\n toBytes(id: string): Uint8Array\n fromBytes(prefix: string, bytes: Uint8Array): string\n toUuid(id: string): string\n fromUuid(prefix: string, uuid: string): string\n timestamp(id: string): number\n prefix(id: string): string\n suffix(id: string): string\n isValid(id: unknown): id is string\n}\n\nconst TYPEID_SUFFIX_LENGTH = 26\nconst TYPEID_UUID_BYTE_LENGTH = 16\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('TYPEID_PREFIX_TOO_LONG', 'TypeID prefix must be at most 63 characters')\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 'TYPEID_PREFIX_INVALID_CHARACTER',\n 'TypeID prefix must contain only lowercase ASCII letters and underscores',\n )\n }\n\n if ((i === 0 || i === prefix.length - 1) && !isLowercaseLetter) {\n throw new InvalidInputError('TYPEID_PREFIX_INVALID_BOUNDARY', 'TypeID prefix must start and end with a-z')\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(\n 'TYPEID_SUFFIX_INVALID_CHARACTER',\n `TypeID suffix contains invalid character at position ${index}`,\n )\n }\n\n return value\n}\n\nfunction assertValidSuffixShape(suffix: string): void {\n if (suffix.length !== TYPEID_SUFFIX_LENGTH) {\n throw new ParseError('TYPEID_SUFFIX_INVALID_LENGTH', `TypeID suffix must be 26 characters, got ${suffix.length}`)\n }\n\n if (suffix[0] > '7') {\n throw new ParseError('TYPEID_SUFFIX_OVERFLOW', 'TypeID suffix must encode a 128-bit value')\n }\n}\n\nfunction encodeBytesToSuffix(bytes: Uint8Array): string {\n if (bytes.length !== TYPEID_UUID_BYTE_LENGTH) {\n throw new InvalidInputError('TYPEID_UUID_BYTES_INVALID_LENGTH', `UUID bytes must be 16 bytes, got ${bytes.length}`)\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('TYPEID_UUID_BYTES_INVALID_LENGTH', `UUID bytes must be 16 bytes, got ${bytes.length}`)\n }\n\n if (bytes[6] >> 4 !== 7 || (bytes[8] & 0xc0) !== 0x80) {\n throw new InvalidInputError('TYPEID_UUID_NOT_V7', 'TypeID UUID bytes must encode a UUID v7 value')\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('TYPEID_UUID_NOT_V7', 'TypeID can only wrap UUID v7 values')\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('TYPEID_INVALID_FORMAT', 'TypeID must not start with \"_\"')\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\nfunction typeidFn(prefix: string, options?: TypeidOptions): string {\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
+ {"version":3,"file":"typeid.mjs","names":[],"sources":["../../src/typeid/typeid.ts"],"sourcesContent":["import { 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 /** 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\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('TYPEID_PREFIX_TOO_LONG', 'TypeID prefix must be at most 63 characters')\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 'TYPEID_PREFIX_INVALID_CHARACTER',\n 'TypeID prefix must contain only lowercase ASCII letters and underscores',\n )\n }\n\n if ((i === 0 || i === prefix.length - 1) && !isLowercaseLetter) {\n throw new InvalidInputError('TYPEID_PREFIX_INVALID_BOUNDARY', 'TypeID prefix must start and end with a-z')\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(\n 'TYPEID_SUFFIX_INVALID_CHARACTER',\n `TypeID suffix contains invalid character at position ${index}`,\n )\n }\n\n return value\n}\n\nfunction assertValidSuffixShape(suffix: string): void {\n if (suffix.length !== TYPEID_SUFFIX_LENGTH) {\n throw new ParseError('TYPEID_SUFFIX_INVALID_LENGTH', `TypeID suffix must be 26 characters, got ${suffix.length}`)\n }\n\n if (suffix[0] > '7') {\n throw new ParseError('TYPEID_SUFFIX_OVERFLOW', 'TypeID suffix must encode a 128-bit value')\n }\n}\n\nfunction encodeBytesToSuffix(bytes: Uint8Array): string {\n if (bytes.length !== TYPEID_UUID_BYTE_LENGTH) {\n throw new InvalidInputError('TYPEID_UUID_BYTES_INVALID_LENGTH', `UUID bytes must be 16 bytes, got ${bytes.length}`)\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('TYPEID_UUID_BYTES_INVALID_LENGTH', `UUID bytes must be 16 bytes, got ${bytes.length}`)\n }\n\n if (bytes[6] >> 4 !== 7 || (bytes[8] & 0xc0) !== 0x80) {\n throw new InvalidInputError('TYPEID_UUID_NOT_V7', 'TypeID UUID bytes must encode a UUID v7 value')\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('TYPEID_UUID_NOT_V7', 'TypeID can only wrap UUID v7 values')\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('TYPEID_INVALID_FORMAT', 'TypeID must not start with \"_\"')\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\nfunction typeidFn(prefix: string, options?: TypeidOptions): string {\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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"}
@@ -14,16 +14,20 @@ type UlidOptions = {
14
14
  msecs?: number;
15
15
  };
16
16
  type Ulid = {
17
- (): string;
18
- <TBuf extends Uint8Array = Uint8Array>(options: UlidOptions | undefined, buf: TBuf, offset?: number): TBuf;
19
- (options?: UlidOptions, buf?: undefined, offset?: number): string;
20
- toBytes(id: string): Uint8Array;
21
- fromBytes(bytes: Uint8Array): string;
22
- timestamp(id: string): number;
17
+ /** Generate a time-ordered ULID string. */(): string; /** Generate a ULID with explicit options or write its 16 canonical bytes into a caller-owned buffer. */
18
+ <TBuf extends Uint8Array = Uint8Array>(options: UlidOptions | undefined, buf: TBuf, offset?: number): TBuf; /** Generate a ULID string with optional timestamp or random bytes. */
19
+ (options?: UlidOptions, buf?: undefined, offset?: number): string; /** Convert a ULID string to its canonical 16-byte representation. */
20
+ toBytes(id: string): Uint8Array; /** Convert 16 canonical ULID bytes to a ULID string. */
21
+ fromBytes(bytes: Uint8Array): string; /** Read the embedded Unix timestamp in milliseconds. */
22
+ timestamp(id: string): number; /** Return whether a value is a syntactically valid ULID string. */
23
23
  isValid(id: unknown): id is string; /** The nil ULID (all zeros) */
24
24
  NIL: string; /** The max ULID (maximum valid value) */
25
25
  MAX: string;
26
26
  };
27
+ /**
28
+ * Generate a ULID string or write its 16 canonical bytes into a buffer.
29
+ * ULIDs are URL-safe, carry a millisecond timestamp, and sort by creation time.
30
+ */
27
31
  declare const ulid: Ulid;
28
32
  //#endregion
29
33
  export { BufferError, InvalidInputError, ParseError, Ulid, UlidOptions, UniqueIdError, ulid };
@@ -1 +1 @@
1
- {"version":3,"file":"ulid.d.mts","names":[],"sources":["../../src/ulid/ulid.ts"],"mappings":";;;KAMY,WAAA;;;AAAZ;;EAKE,MAAA,GAAS,UAAA;EAAA;;;;EAKT,KAAA;AAAA;AAAA,KAGU,IAAA;EAAA;EAAA,cAEI,UAAA,GAAa,UAAA,EAAY,OAAA,EAAS,WAAA,cAAyB,GAAA,EAAK,IAAA,EAAM,MAAA,YAAkB,IAAA;EAAA,CACrG,OAAA,GAAU,WAAA,EAAa,GAAA,cAAiB,MAAA;EACzC,OAAA,CAAQ,EAAA,WAAa,UAAA;EACrB,SAAA,CAAU,KAAA,EAAO,UAAA;EACjB,SAAA,CAAU,EAAA;EACV,OAAA,CAAQ,EAAA,YAAc,EAAA;EAEtB,GAAA;EAEA,GAAA;AAAA;AAAA,cA2JW,IAAA,EAAM,IAAA"}
1
+ {"version":3,"file":"ulid.d.mts","names":[],"sources":["../../src/ulid/ulid.ts"],"mappings":";;;KAMY,WAAA;;;AAAZ;;EAKE,MAAA,GAAS,UAAA;EAAA;;;;EAKT,KAAA;AAAA;AAAA,KAGU,IAAA;EAAA;gBAII,UAAA,GAAa,UAAA,EAAY,OAAA,EAAS,WAAA,cAAyB,GAAA,EAAK,IAAA,EAAM,MAAA,YAAkB,IAAA;GAErG,OAAA,GAAU,WAAA,EAAa,GAAA,cAAiB,MAAA;EAEzC,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;;;;;cA+JW,IAAA,EAAM,IAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"ulid.mjs","names":[],"sources":["../../src/ulid/crockford.ts","../../src/ulid/ulid.ts"],"sourcesContent":["/**\n * Crockford's Base32 encoding/decoding for ULID.\n * Alphabet excludes I, L, O, U to avoid confusion with similar-looking characters.\n */\n\nimport { BufferError, ParseError } from '../errors'\n\nconst ENCODING = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'\n\n// Pre-computed decoding 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.\nconst DECODING = new Uint8Array(65536)\nDECODING.fill(255) // 255 = invalid marker\nfor (let i = 0; i < ENCODING.length; i += 1) {\n const upper = ENCODING.charCodeAt(i)\n const lower = ENCODING[i].toLowerCase().charCodeAt(0)\n DECODING[upper] = i\n DECODING[lower] = i\n}\n\nconst TIME_LEN = 10\nconst ULID_LEN = 26\n\nfunction invalidCharError(str: string, index: number): ParseError {\n return new ParseError('ULID_INVALID_CHAR', `Invalid ULID character: ${str[index]}`)\n}\n\nfunction timestampOverflowError(): ParseError {\n return new ParseError('ULID_TIMESTAMP_OVERFLOW', 'ULID timestamp exceeds 48 bits')\n}\n\nfunction decodeTimeChars(str: string): number {\n const firstValue = DECODING[str.charCodeAt(0)]\n if (firstValue === 255) {\n throw invalidCharError(str, 0)\n }\n\n if (firstValue > 7) {\n throw timestampOverflowError()\n }\n\n let time = firstValue\n for (let i = 1; i < TIME_LEN; i += 1) {\n const value = DECODING[str.charCodeAt(i)]\n if (value === 255) {\n throw invalidCharError(str, i)\n }\n\n time = time * 32 + value\n }\n return time\n}\n\n/**\n * Encode a 48-bit timestamp to a 10-character Crockford Base32 string.\n * Uses unrolled division for performance.\n */\nexport function encodeTime(time: number): string {\n // Unrolled encoding - each step divides by 32 and extracts 5 bits\n // Powers of 32: 32^9=0x200000000000, 32^8=0x10000000000, etc.\n return (\n ENCODING[Math.floor(time / 0x200000000000) & 0x1f] +\n ENCODING[Math.floor(time / 0x10000000000) & 0x1f] +\n ENCODING[Math.floor(time / 0x800000000) & 0x1f] +\n ENCODING[Math.floor(time / 0x40000000) & 0x1f] +\n ENCODING[Math.floor(time / 0x2000000) & 0x1f] +\n ENCODING[Math.floor(time / 0x100000) & 0x1f] +\n ENCODING[Math.floor(time / 0x8000) & 0x1f] +\n ENCODING[Math.floor(time / 0x400) & 0x1f] +\n ENCODING[Math.floor(time / 0x20) & 0x1f] +\n ENCODING[time & 0x1f]\n )\n}\n\n/**\n * Encode 10 bytes (80 bits) of random data to a 16-character Crockford Base32 string.\n */\nexport function encodeRandom(bytes: Uint8Array): string {\n // Each character encodes 5 bits. 80 bits = 16 characters.\n // Single concatenation expression for optimal performance.\n return (\n ENCODING[(bytes[0] >> 3) & 0x1f] +\n ENCODING[((bytes[0] << 2) | (bytes[1] >> 6)) & 0x1f] +\n ENCODING[(bytes[1] >> 1) & 0x1f] +\n ENCODING[((bytes[1] << 4) | (bytes[2] >> 4)) & 0x1f] +\n ENCODING[((bytes[2] << 1) | (bytes[3] >> 7)) & 0x1f] +\n ENCODING[(bytes[3] >> 2) & 0x1f] +\n ENCODING[((bytes[3] << 3) | (bytes[4] >> 5)) & 0x1f] +\n ENCODING[bytes[4] & 0x1f] +\n ENCODING[(bytes[5] >> 3) & 0x1f] +\n ENCODING[((bytes[5] << 2) | (bytes[6] >> 6)) & 0x1f] +\n ENCODING[(bytes[6] >> 1) & 0x1f] +\n ENCODING[((bytes[6] << 4) | (bytes[7] >> 4)) & 0x1f] +\n ENCODING[((bytes[7] << 1) | (bytes[8] >> 7)) & 0x1f] +\n ENCODING[(bytes[8] >> 2) & 0x1f] +\n ENCODING[((bytes[8] << 3) | (bytes[9] >> 5)) & 0x1f] +\n ENCODING[bytes[9] & 0x1f]\n )\n}\n\n/**\n * Decode a 10-character ULID timestamp string to Unix epoch milliseconds.\n */\nexport function decodeTime(str: string): number {\n if (str.length !== TIME_LEN) {\n throw new ParseError('ULID_INVALID_LENGTH', `ULID timestamp must be ${TIME_LEN} characters`)\n }\n return decodeTimeChars(str)\n}\n\n/**\n * Decode the timestamp from a full 26-character ULID string.\n */\nexport function decodeUlidTime(str: string): number {\n if (str.length !== ULID_LEN) {\n throw new ParseError('ULID_INVALID_LENGTH', `ULID string must be ${ULID_LEN} characters`)\n }\n return decodeTimeChars(str)\n}\n\n/**\n * Decode a 26-character ULID string to 16 bytes.\n * Inlines all lookups to avoid intermediate array allocation.\n */\nexport function decodeToBytes(str: string): Uint8Array {\n if (str.length !== ULID_LEN) {\n throw new ParseError('ULID_INVALID_LENGTH', `ULID string must be ${ULID_LEN} characters`)\n }\n\n const bytes = new Uint8Array(16)\n\n // Inline all 26 character lookups\n const v0 = DECODING[str.charCodeAt(0)]\n const v1 = DECODING[str.charCodeAt(1)]\n const v2 = DECODING[str.charCodeAt(2)]\n const v3 = DECODING[str.charCodeAt(3)]\n const v4 = DECODING[str.charCodeAt(4)]\n const v5 = DECODING[str.charCodeAt(5)]\n const v6 = DECODING[str.charCodeAt(6)]\n const v7 = DECODING[str.charCodeAt(7)]\n const v8 = DECODING[str.charCodeAt(8)]\n const v9 = DECODING[str.charCodeAt(9)]\n const v10 = DECODING[str.charCodeAt(10)]\n const v11 = DECODING[str.charCodeAt(11)]\n const v12 = DECODING[str.charCodeAt(12)]\n const v13 = DECODING[str.charCodeAt(13)]\n const v14 = DECODING[str.charCodeAt(14)]\n const v15 = DECODING[str.charCodeAt(15)]\n const v16 = DECODING[str.charCodeAt(16)]\n const v17 = DECODING[str.charCodeAt(17)]\n const v18 = DECODING[str.charCodeAt(18)]\n const v19 = DECODING[str.charCodeAt(19)]\n const v20 = DECODING[str.charCodeAt(20)]\n const v21 = DECODING[str.charCodeAt(21)]\n const v22 = DECODING[str.charCodeAt(22)]\n const v23 = DECODING[str.charCodeAt(23)]\n const v24 = DECODING[str.charCodeAt(24)]\n const v25 = DECODING[str.charCodeAt(25)]\n\n // Validate all characters at once (255 = invalid marker, so any invalid\n // character sets the 0x80 bit in the OR of all values)\n if (\n ((v0 |\n v1 |\n v2 |\n v3 |\n v4 |\n v5 |\n v6 |\n v7 |\n v8 |\n v9 |\n v10 |\n v11 |\n v12 |\n v13 |\n v14 |\n v15 |\n v16 |\n v17 |\n v18 |\n v19 |\n v20 |\n v21 |\n v22 |\n v23 |\n v24 |\n v25) &\n 0x80) !==\n 0\n ) {\n // Find the invalid character for error message\n for (let i = 0; i < ULID_LEN; i += 1) {\n if (DECODING[str.charCodeAt(i)] === 255) {\n throw invalidCharError(str, i)\n }\n }\n }\n\n if (v0 > 7) {\n throw timestampOverflowError()\n }\n\n // Timestamp: first 10 characters -> bytes 0-5\n bytes[0] = (v0 << 5) | v1\n bytes[1] = (v2 << 3) | (v3 >> 2)\n bytes[2] = (v3 << 6) | (v4 << 1) | (v5 >> 4)\n bytes[3] = (v5 << 4) | (v6 >> 1)\n bytes[4] = (v6 << 7) | (v7 << 2) | (v8 >> 3)\n bytes[5] = (v8 << 5) | v9\n\n // Random: last 16 characters -> bytes 6-15\n bytes[6] = (v10 << 3) | (v11 >> 2)\n bytes[7] = (v11 << 6) | (v12 << 1) | (v13 >> 4)\n bytes[8] = (v13 << 4) | (v14 >> 1)\n bytes[9] = (v14 << 7) | (v15 << 2) | (v16 >> 3)\n bytes[10] = (v16 << 5) | v17\n bytes[11] = (v18 << 3) | (v19 >> 2)\n bytes[12] = (v19 << 6) | (v20 << 1) | (v21 >> 4)\n bytes[13] = (v21 << 4) | (v22 >> 1)\n bytes[14] = (v22 << 7) | (v23 << 2) | (v24 >> 3)\n bytes[15] = (v24 << 5) | v25\n\n return bytes\n}\n\n/**\n * Encode 16 bytes to a 26-character ULID string.\n */\nexport function bytesToUlid(bytes: Uint8Array): string {\n if (bytes.length !== 16) {\n throw new BufferError('ULID_BYTES_INVALID_LENGTH', `ULID bytes must be exactly 16 bytes, got ${bytes.length}`)\n }\n\n // Timestamp: bytes 0-5 -> 10 characters\n let time = 0\n for (let i = 0; i < 6; i += 1) {\n time = time * 256 + bytes[i]\n }\n const timeStr = encodeTime(time)\n\n // Random: bytes 6-15 -> 16 characters\n const randomStr = encodeRandom(bytes.subarray(6, 16))\n\n return timeStr + randomStr\n}\n","import { incrementBytesInPlace, writeTimestamp48 } from '../common/bytes'\nimport { rng } from '../common/random'\nimport { isIntegerInRange, isWritableRange } from '../common/validation'\nimport { BufferError, InvalidInputError } from '../errors'\nimport { bytesToUlid, decodeToBytes, decodeUlidTime, encodeRandom, encodeTime } from './crockford'\n\nexport type UlidOptions = {\n /**\n * 16 bytes of random data to use for ULID generation.\n * Only the first 10 bytes are used.\n */\n random?: Uint8Array\n /**\n * Timestamp in milliseconds since Unix epoch.\n * Defaults to Date.now().\n */\n msecs?: number\n}\n\nexport type Ulid = {\n (): string\n <TBuf extends Uint8Array = Uint8Array>(options: UlidOptions | undefined, buf: TBuf, offset?: number): TBuf\n (options?: UlidOptions, 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 /** The nil ULID (all zeros) */\n NIL: string\n /** The max ULID (maximum valid value) */\n MAX: string\n}\n\n// Validation regex: first char [0-7] to prevent overflow, rest from Crockford alphabet\nconst ULID_REGEX = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/i\nconst ULID_BYTES = 16\nconst RANDOM_BYTES = 10\nconst MAX_MSECS = 0xffffffffffff\n\ntype UlidState = {\n msecs: number\n lastRandom: Uint8Array\n}\n\n/**\n * Module-level state for maintaining monotonic ordering within the same millisecond.\n *\n * IMPORTANT: This state persists across all ulid() 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 `random` via options.\n * - Tests should mock Date.now() or provide explicit options for deterministic behavior.\n */\nconst state: UlidState = {\n msecs: -Infinity,\n lastRandom: new Uint8Array(RANDOM_BYTES),\n}\n\nfunction writeUlidBytesUnchecked(time: number, random: Uint8Array, buf: Uint8Array, offset: number): void {\n // Timestamp (48-bit big-endian milliseconds since Unix epoch) -> bytes 0-5\n writeTimestamp48(buf, offset, time)\n\n // Random (80 bits) -> bytes 6-15\n for (let i = 0; i < RANDOM_BYTES; i += 1) {\n buf[offset + 6 + i] = random[i]\n }\n}\n\nfunction writeUlidBytes(time: number, random: Uint8Array, buf: Uint8Array, offset: number): void {\n if (!isWritableRange(buf, offset, ULID_BYTES)) {\n throw new BufferError(\n 'ULID_BUFFER_OUT_OF_BOUNDS',\n `ULID byte range ${offset}:${offset + ULID_BYTES - 1} is out of buffer bounds`,\n )\n }\n writeUlidBytesUnchecked(time, random, buf, offset)\n}\n\n/*\n * Overload: no buffer => return a ULID string.\n */\nfunction ulidFn(options?: UlidOptions, buf?: undefined, offset?: number): string\n/*\n * Overload: caller provides a buffer slice to fill with ULID bytes.\n */\nfunction ulidFn<TBuf extends Uint8Array = Uint8Array>(\n options: UlidOptions | undefined,\n buf: TBuf,\n offset?: number,\n): TBuf\nfunction ulidFn<TBuf extends Uint8Array = Uint8Array>(options?: UlidOptions, buf?: TBuf, offset = 0): string | TBuf {\n let time: number\n let random: Uint8Array\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 ULIDs generated within a single request will have the same timestamp.\n * - the monotonic ordering will rely entirely on incrementing the random portion.\n */\n if (options) {\n // Explicit options provided - use them directly without monotonic state\n const optMsecs = options.msecs\n if (optMsecs !== undefined && !isIntegerInRange(optMsecs, 0, MAX_MSECS)) {\n throw new InvalidInputError(\n 'ULID_TIMESTAMP_OUT_OF_RANGE',\n `Timestamp must be an integer between 0 and ${MAX_MSECS}`,\n )\n }\n time = optMsecs ?? Date.now()\n const optRandom = options.random\n if (optRandom) {\n if (optRandom.length < RANDOM_BYTES) {\n throw new InvalidInputError(\n 'ULID_RANDOM_BYTES_TOO_SHORT',\n `Random bytes length must be >= ${RANDOM_BYTES} for ULID`,\n )\n }\n random = optRandom\n } else {\n random = rng()\n }\n } else {\n time = Date.now()\n\n if (time > state.msecs) {\n // New millisecond: generate fresh random\n random = rng()\n state.msecs = time\n state.lastRandom.set(random.subarray(0, RANDOM_BYTES))\n } else {\n // Same millisecond or clock rollback: preserve last timestamp and increment random portion.\n time = state.msecs\n if (!incrementBytesInPlace(state.lastRandom)) {\n state.lastRandom.fill(0xff)\n throw new InvalidInputError(\n 'ULID_RANDOM_OVERFLOW',\n 'ULID random component overflowed while preserving monotonic order',\n )\n }\n random = state.lastRandom\n }\n }\n\n if (buf) {\n writeUlidBytes(time, random, buf, offset)\n return buf\n }\n\n // String mode: encode directly without buffer allocation\n return encodeTime(time) + encodeRandom(random)\n}\n\n/**\n * Generate a ULID string or write the bytes into a buffer.\n *\n * ULID (Universally Unique Lexicographically Sortable Identifier) is a 128-bit\n * identifier with millisecond timestamp precision and 80 bits of randomness.\n * ULIDs are URL-safe, use Crockford's Base32 encoding, and sort lexicographically\n * by creation time.\n *\n * @example\n * ```ts\n * import { ulid } from 'uniku/ulid'\n *\n * const id = ulid()\n * // => \"01HW9T2W9W9YJ3JZ1H4P4M2T8Q\"\n *\n * // Extract timestamp\n * const ts = ulid.timestamp(id)\n * console.log(new Date(ts))\n *\n * // Validate\n * ulid.isValid(id) // true\n *\n * // Convert to/from bytes (16 bytes)\n * const bytes = ulid.toBytes(id)\n * const restored = ulid.fromBytes(bytes)\n * ```\n */\nfunction isValid(id: unknown): id is string {\n return typeof id === 'string' && ULID_REGEX.test(id)\n}\n\nexport const ulid: Ulid = Object.assign(ulidFn, {\n toBytes: (id: string) => decodeToBytes(id),\n fromBytes: (bytes: Uint8Array) => bytesToUlid(bytes),\n timestamp: (id: string) => decodeUlidTime(id),\n isValid,\n NIL: '00000000000000000000000000',\n MAX: '7ZZZZZZZZZZZZZZZZZZZZZZZZZ',\n})\n\nexport { BufferError, InvalidInputError, ParseError, UniqueIdError } from '../errors'\n"],"mappings":"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"}
1
+ {"version":3,"file":"ulid.mjs","names":[],"sources":["../../src/ulid/crockford.ts","../../src/ulid/ulid.ts"],"sourcesContent":["/**\n * Crockford's Base32 encoding/decoding for ULID.\n * Alphabet excludes I, L, O, U to avoid confusion with similar-looking characters.\n */\n\nimport { BufferError, ParseError } from '../errors'\n\nconst ENCODING = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'\n\n// Pre-computed decoding 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.\nconst DECODING = new Uint8Array(65536)\nDECODING.fill(255) // 255 = invalid marker\nfor (let i = 0; i < ENCODING.length; i += 1) {\n const upper = ENCODING.charCodeAt(i)\n const lower = ENCODING[i].toLowerCase().charCodeAt(0)\n DECODING[upper] = i\n DECODING[lower] = i\n}\n\nconst TIME_LEN = 10\nconst ULID_LEN = 26\n\nfunction invalidCharError(str: string, index: number): ParseError {\n return new ParseError('ULID_INVALID_CHAR', `Invalid ULID character: ${str[index]}`)\n}\n\nfunction timestampOverflowError(): ParseError {\n return new ParseError('ULID_TIMESTAMP_OVERFLOW', 'ULID timestamp exceeds 48 bits')\n}\n\nfunction decodeTimeChars(str: string): number {\n const firstValue = DECODING[str.charCodeAt(0)]\n if (firstValue === 255) {\n throw invalidCharError(str, 0)\n }\n\n if (firstValue > 7) {\n throw timestampOverflowError()\n }\n\n let time = firstValue\n for (let i = 1; i < TIME_LEN; i += 1) {\n const value = DECODING[str.charCodeAt(i)]\n if (value === 255) {\n throw invalidCharError(str, i)\n }\n\n time = time * 32 + value\n }\n return time\n}\n\n/**\n * Encode a 48-bit timestamp to a 10-character Crockford Base32 string.\n * Uses unrolled division for performance.\n */\nexport function encodeTime(time: number): string {\n // Unrolled encoding - each step divides by 32 and extracts 5 bits\n // Powers of 32: 32^9=0x200000000000, 32^8=0x10000000000, etc.\n return (\n ENCODING[Math.floor(time / 0x200000000000) & 0x1f] +\n ENCODING[Math.floor(time / 0x10000000000) & 0x1f] +\n ENCODING[Math.floor(time / 0x800000000) & 0x1f] +\n ENCODING[Math.floor(time / 0x40000000) & 0x1f] +\n ENCODING[Math.floor(time / 0x2000000) & 0x1f] +\n ENCODING[Math.floor(time / 0x100000) & 0x1f] +\n ENCODING[Math.floor(time / 0x8000) & 0x1f] +\n ENCODING[Math.floor(time / 0x400) & 0x1f] +\n ENCODING[Math.floor(time / 0x20) & 0x1f] +\n ENCODING[time & 0x1f]\n )\n}\n\n/**\n * Encode 10 bytes (80 bits) of random data to a 16-character Crockford Base32 string.\n */\nexport function encodeRandom(bytes: Uint8Array): string {\n // Each character encodes 5 bits. 80 bits = 16 characters.\n // Single concatenation expression for optimal performance.\n return (\n ENCODING[(bytes[0] >> 3) & 0x1f] +\n ENCODING[((bytes[0] << 2) | (bytes[1] >> 6)) & 0x1f] +\n ENCODING[(bytes[1] >> 1) & 0x1f] +\n ENCODING[((bytes[1] << 4) | (bytes[2] >> 4)) & 0x1f] +\n ENCODING[((bytes[2] << 1) | (bytes[3] >> 7)) & 0x1f] +\n ENCODING[(bytes[3] >> 2) & 0x1f] +\n ENCODING[((bytes[3] << 3) | (bytes[4] >> 5)) & 0x1f] +\n ENCODING[bytes[4] & 0x1f] +\n ENCODING[(bytes[5] >> 3) & 0x1f] +\n ENCODING[((bytes[5] << 2) | (bytes[6] >> 6)) & 0x1f] +\n ENCODING[(bytes[6] >> 1) & 0x1f] +\n ENCODING[((bytes[6] << 4) | (bytes[7] >> 4)) & 0x1f] +\n ENCODING[((bytes[7] << 1) | (bytes[8] >> 7)) & 0x1f] +\n ENCODING[(bytes[8] >> 2) & 0x1f] +\n ENCODING[((bytes[8] << 3) | (bytes[9] >> 5)) & 0x1f] +\n ENCODING[bytes[9] & 0x1f]\n )\n}\n\n/**\n * Decode a 10-character ULID timestamp string to Unix epoch milliseconds.\n */\nexport function decodeTime(str: string): number {\n if (str.length !== TIME_LEN) {\n throw new ParseError('ULID_INVALID_LENGTH', `ULID timestamp must be ${TIME_LEN} characters`)\n }\n return decodeTimeChars(str)\n}\n\n/**\n * Decode the timestamp from a full 26-character ULID string.\n */\nexport function decodeUlidTime(str: string): number {\n if (str.length !== ULID_LEN) {\n throw new ParseError('ULID_INVALID_LENGTH', `ULID string must be ${ULID_LEN} characters`)\n }\n return decodeTimeChars(str)\n}\n\n/**\n * Decode a 26-character ULID string to 16 bytes.\n * Inlines all lookups to avoid intermediate array allocation.\n */\nexport function decodeToBytes(str: string): Uint8Array {\n if (str.length !== ULID_LEN) {\n throw new ParseError('ULID_INVALID_LENGTH', `ULID string must be ${ULID_LEN} characters`)\n }\n\n const bytes = new Uint8Array(16)\n\n // Inline all 26 character lookups\n const v0 = DECODING[str.charCodeAt(0)]\n const v1 = DECODING[str.charCodeAt(1)]\n const v2 = DECODING[str.charCodeAt(2)]\n const v3 = DECODING[str.charCodeAt(3)]\n const v4 = DECODING[str.charCodeAt(4)]\n const v5 = DECODING[str.charCodeAt(5)]\n const v6 = DECODING[str.charCodeAt(6)]\n const v7 = DECODING[str.charCodeAt(7)]\n const v8 = DECODING[str.charCodeAt(8)]\n const v9 = DECODING[str.charCodeAt(9)]\n const v10 = DECODING[str.charCodeAt(10)]\n const v11 = DECODING[str.charCodeAt(11)]\n const v12 = DECODING[str.charCodeAt(12)]\n const v13 = DECODING[str.charCodeAt(13)]\n const v14 = DECODING[str.charCodeAt(14)]\n const v15 = DECODING[str.charCodeAt(15)]\n const v16 = DECODING[str.charCodeAt(16)]\n const v17 = DECODING[str.charCodeAt(17)]\n const v18 = DECODING[str.charCodeAt(18)]\n const v19 = DECODING[str.charCodeAt(19)]\n const v20 = DECODING[str.charCodeAt(20)]\n const v21 = DECODING[str.charCodeAt(21)]\n const v22 = DECODING[str.charCodeAt(22)]\n const v23 = DECODING[str.charCodeAt(23)]\n const v24 = DECODING[str.charCodeAt(24)]\n const v25 = DECODING[str.charCodeAt(25)]\n\n // Validate all characters at once (255 = invalid marker, so any invalid\n // character sets the 0x80 bit in the OR of all values)\n if (\n ((v0 |\n v1 |\n v2 |\n v3 |\n v4 |\n v5 |\n v6 |\n v7 |\n v8 |\n v9 |\n v10 |\n v11 |\n v12 |\n v13 |\n v14 |\n v15 |\n v16 |\n v17 |\n v18 |\n v19 |\n v20 |\n v21 |\n v22 |\n v23 |\n v24 |\n v25) &\n 0x80) !==\n 0\n ) {\n // Find the invalid character for error message\n for (let i = 0; i < ULID_LEN; i += 1) {\n if (DECODING[str.charCodeAt(i)] === 255) {\n throw invalidCharError(str, i)\n }\n }\n }\n\n if (v0 > 7) {\n throw timestampOverflowError()\n }\n\n // Timestamp: first 10 characters -> bytes 0-5\n bytes[0] = (v0 << 5) | v1\n bytes[1] = (v2 << 3) | (v3 >> 2)\n bytes[2] = (v3 << 6) | (v4 << 1) | (v5 >> 4)\n bytes[3] = (v5 << 4) | (v6 >> 1)\n bytes[4] = (v6 << 7) | (v7 << 2) | (v8 >> 3)\n bytes[5] = (v8 << 5) | v9\n\n // Random: last 16 characters -> bytes 6-15\n bytes[6] = (v10 << 3) | (v11 >> 2)\n bytes[7] = (v11 << 6) | (v12 << 1) | (v13 >> 4)\n bytes[8] = (v13 << 4) | (v14 >> 1)\n bytes[9] = (v14 << 7) | (v15 << 2) | (v16 >> 3)\n bytes[10] = (v16 << 5) | v17\n bytes[11] = (v18 << 3) | (v19 >> 2)\n bytes[12] = (v19 << 6) | (v20 << 1) | (v21 >> 4)\n bytes[13] = (v21 << 4) | (v22 >> 1)\n bytes[14] = (v22 << 7) | (v23 << 2) | (v24 >> 3)\n bytes[15] = (v24 << 5) | v25\n\n return bytes\n}\n\n/**\n * Encode 16 bytes to a 26-character ULID string.\n */\nexport function bytesToUlid(bytes: Uint8Array): string {\n if (bytes.length !== 16) {\n throw new BufferError('ULID_BYTES_INVALID_LENGTH', `ULID bytes must be exactly 16 bytes, got ${bytes.length}`)\n }\n\n // Timestamp: bytes 0-5 -> 10 characters\n let time = 0\n for (let i = 0; i < 6; i += 1) {\n time = time * 256 + bytes[i]\n }\n const timeStr = encodeTime(time)\n\n // Random: bytes 6-15 -> 16 characters\n const randomStr = encodeRandom(bytes.subarray(6, 16))\n\n return timeStr + randomStr\n}\n","import { incrementBytesInPlace, writeTimestamp48 } from '../common/bytes'\nimport { rng } from '../common/random'\nimport { isIntegerInRange, isWritableRange } from '../common/validation'\nimport { BufferError, InvalidInputError } from '../errors'\nimport { bytesToUlid, decodeToBytes, decodeUlidTime, encodeRandom, encodeTime } from './crockford'\n\nexport type UlidOptions = {\n /**\n * 16 bytes of random data to use for ULID generation.\n * Only the first 10 bytes are used.\n */\n random?: Uint8Array\n /**\n * Timestamp in milliseconds since Unix epoch.\n * Defaults to Date.now().\n */\n msecs?: number\n}\n\nexport type Ulid = {\n /** Generate a time-ordered ULID string. */\n (): string\n /** Generate a ULID with explicit options or write its 16 canonical bytes into a caller-owned buffer. */\n <TBuf extends Uint8Array = Uint8Array>(options: UlidOptions | undefined, buf: TBuf, offset?: number): TBuf\n /** Generate a ULID string with optional timestamp or random bytes. */\n (options?: UlidOptions, buf?: undefined, offset?: number): string\n /** Convert a ULID string to its canonical 16-byte representation. */\n toBytes(id: string): Uint8Array\n /** Convert 16 canonical ULID bytes to a ULID 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 ULID string. */\n isValid(id: unknown): id is string\n /** The nil ULID (all zeros) */\n NIL: string\n /** The max ULID (maximum valid value) */\n MAX: string\n}\n\n// Validation regex: first char [0-7] to prevent overflow, rest from Crockford alphabet\nconst ULID_REGEX = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/i\nconst ULID_BYTES = 16\nconst RANDOM_BYTES = 10\nconst MAX_MSECS = 0xffffffffffff\n\ntype UlidState = {\n msecs: number\n lastRandom: Uint8Array\n}\n\n/**\n * Module-level state for maintaining monotonic ordering within the same millisecond.\n *\n * IMPORTANT: This state persists across all ulid() 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 `random` via options.\n * - Tests should mock Date.now() or provide explicit options for deterministic behavior.\n */\nconst state: UlidState = {\n msecs: -Infinity,\n lastRandom: new Uint8Array(RANDOM_BYTES),\n}\n\nfunction writeUlidBytesUnchecked(time: number, random: Uint8Array, buf: Uint8Array, offset: number): void {\n // Timestamp (48-bit big-endian milliseconds since Unix epoch) -> bytes 0-5\n writeTimestamp48(buf, offset, time)\n\n // Random (80 bits) -> bytes 6-15\n for (let i = 0; i < RANDOM_BYTES; i += 1) {\n buf[offset + 6 + i] = random[i]\n }\n}\n\nfunction writeUlidBytes(time: number, random: Uint8Array, buf: Uint8Array, offset: number): void {\n if (!isWritableRange(buf, offset, ULID_BYTES)) {\n throw new BufferError(\n 'ULID_BUFFER_OUT_OF_BOUNDS',\n `ULID byte range ${offset}:${offset + ULID_BYTES - 1} is out of buffer bounds`,\n )\n }\n writeUlidBytesUnchecked(time, random, buf, offset)\n}\n\n/*\n * Overload: no buffer => return a ULID string.\n */\nfunction ulidFn(options?: UlidOptions, buf?: undefined, offset?: number): string\n/*\n * Overload: caller provides a buffer slice to fill with ULID bytes.\n */\nfunction ulidFn<TBuf extends Uint8Array = Uint8Array>(\n options: UlidOptions | undefined,\n buf: TBuf,\n offset?: number,\n): TBuf\nfunction ulidFn<TBuf extends Uint8Array = Uint8Array>(options?: UlidOptions, buf?: TBuf, offset = 0): string | TBuf {\n let time: number\n let random: Uint8Array\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 ULIDs generated within a single request will have the same timestamp.\n * - the monotonic ordering will rely entirely on incrementing the random portion.\n */\n if (options) {\n // Explicit options provided - use them directly without monotonic state\n const optMsecs = options.msecs\n if (optMsecs !== undefined && !isIntegerInRange(optMsecs, 0, MAX_MSECS)) {\n throw new InvalidInputError(\n 'ULID_TIMESTAMP_OUT_OF_RANGE',\n `Timestamp must be an integer between 0 and ${MAX_MSECS}`,\n )\n }\n time = optMsecs ?? Date.now()\n const optRandom = options.random\n if (optRandom) {\n if (optRandom.length < RANDOM_BYTES) {\n throw new InvalidInputError(\n 'ULID_RANDOM_BYTES_TOO_SHORT',\n `Random bytes length must be >= ${RANDOM_BYTES} for ULID`,\n )\n }\n random = optRandom\n } else {\n random = rng()\n }\n } else {\n time = Date.now()\n\n if (time > state.msecs) {\n // New millisecond: generate fresh random\n random = rng()\n state.msecs = time\n state.lastRandom.set(random.subarray(0, RANDOM_BYTES))\n } else {\n // Same millisecond or clock rollback: preserve last timestamp and increment random portion.\n time = state.msecs\n if (!incrementBytesInPlace(state.lastRandom)) {\n state.lastRandom.fill(0xff)\n throw new InvalidInputError(\n 'ULID_RANDOM_OVERFLOW',\n 'ULID random component overflowed while preserving monotonic order',\n )\n }\n random = state.lastRandom\n }\n }\n\n if (buf) {\n writeUlidBytes(time, random, buf, offset)\n return buf\n }\n\n // String mode: encode directly without buffer allocation\n return encodeTime(time) + encodeRandom(random)\n}\n\n/**\n * Generate a ULID string or write the bytes into a buffer.\n *\n * ULID (Universally Unique Lexicographically Sortable Identifier) is a 128-bit\n * identifier with millisecond timestamp precision and 80 bits of randomness.\n * ULIDs are URL-safe, use Crockford's Base32 encoding, and sort lexicographically\n * by creation time.\n *\n * @example\n * ```ts\n * import { ulid } from 'uniku/ulid'\n *\n * const id = ulid()\n * // => \"01HW9T2W9W9YJ3JZ1H4P4M2T8Q\"\n *\n * // Extract timestamp\n * const ts = ulid.timestamp(id)\n * console.log(new Date(ts))\n *\n * // Validate\n * ulid.isValid(id) // true\n *\n * // Convert to/from bytes (16 bytes)\n * const bytes = ulid.toBytes(id)\n * const restored = ulid.fromBytes(bytes)\n * ```\n */\nfunction isValid(id: unknown): id is string {\n return typeof id === 'string' && ULID_REGEX.test(id)\n}\n\n/**\n * Generate a ULID string or write its 16 canonical bytes into a buffer.\n * ULIDs are URL-safe, carry a millisecond timestamp, and sort by creation time.\n */\nexport const ulid: Ulid = Object.assign(ulidFn, {\n toBytes: (id: string) => decodeToBytes(id),\n fromBytes: (bytes: Uint8Array) => bytesToUlid(bytes),\n timestamp: (id: string) => decodeUlidTime(id),\n isValid,\n NIL: '00000000000000000000000000',\n MAX: '7ZZZZZZZZZZZZZZZZZZZZZZZZZ',\n})\n\nexport { BufferError, InvalidInputError, ParseError, UniqueIdError } from '../errors'\n"],"mappings":"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"}
@@ -8,11 +8,11 @@ type UuidV4Options = {
8
8
  random?: Uint8Array;
9
9
  };
10
10
  type UuidV4 = {
11
- (): string;
12
- <TBuf extends Uint8Array = Uint8Array>(options: UuidV4Options | undefined, buf: TBuf, offset?: number): TBuf;
13
- (options?: UuidV4Options, buf?: undefined, offset?: number): string;
14
- toBytes(id: string): Uint8Array;
15
- fromBytes(bytes: Uint8Array): string;
11
+ /** Generate a random UUID v4 string. */(): string; /** Generate a UUID v4 with explicit options or write its 16 canonical bytes into a caller-owned buffer. */
12
+ <TBuf extends Uint8Array = Uint8Array>(options: UuidV4Options | undefined, buf: TBuf, offset?: number): TBuf; /** Generate a UUID v4 string with optional deterministic random bytes. */
13
+ (options?: UuidV4Options, buf?: undefined, offset?: number): string; /** Convert a UUID v4 string to its canonical 16-byte representation. */
14
+ toBytes(id: string): Uint8Array; /** Convert 16 canonical UUID bytes to a UUID v4 string. */
15
+ fromBytes(bytes: Uint8Array): string; /** Return whether a value is a syntactically valid UUID v4 string. */
16
16
  isValid(id: unknown): id is string; /** The nil UUID (all zeros) */
17
17
  NIL: string; /** The max UUID (all ones) */
18
18
  MAX: string;
@@ -1 +1 @@
1
- {"version":3,"file":"v4.d.mts","names":[],"sources":["../../src/uuid/v4.ts"],"mappings":";;;KASY,aAAA;;;AAAZ;EAIE,MAAA,GAAS,UAAA;AAAA;AAAA,KAGC,MAAA;EAAA;EAAA,cAEI,UAAA,GAAa,UAAA,EAAY,OAAA,EAAS,aAAA,cAA2B,GAAA,EAAK,IAAA,EAAM,MAAA,YAAkB,IAAA;EAAA,CACvG,OAAA,GAAU,aAAA,EAAe,GAAA,cAAiB,MAAA;EAC3C,OAAA,CAAQ,EAAA,WAAa,UAAA;EACrB,SAAA,CAAU,KAAA,EAAO,UAAA;EACjB,OAAA,CAAQ,EAAA,YAAc,EAAA;EAEtB,GAAA;EAEA,GAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;cAiFW,MAAA,EAAQ,MAAA"}
1
+ {"version":3,"file":"v4.d.mts","names":[],"sources":["../../src/uuid/v4.ts"],"mappings":";;;KASY,aAAA;;;AAAZ;EAIE,MAAA,GAAS,UAAA;AAAA;AAAA,KAGC,MAAA;EAHD,oDAGC;EAAA,cAII,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,OAAA,CAAQ,EAAA,YAAc,EAAA,YAFL;EAIjB,GAAA;EAEA,GAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;cAiFW,MAAA,EAAQ,MAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"v4.mjs","names":[],"sources":["../../src/uuid/v4.ts"],"sourcesContent":["import { rng } from '../common/random'\nimport { isWritableRange } from '../common/validation'\nimport { BufferError, InvalidInputError } from '../errors'\nimport { formatUuid, formatUuidUnchecked, parseUuid } from './common/uuid'\n\nconst randomUUID = /*@__PURE__*/ globalThis.crypto.randomUUID.bind(globalThis.crypto)\nconst UUID_BYTES = 16\nconst reusableBuf = new Uint8Array(UUID_BYTES)\n\nexport type UuidV4Options = {\n /**\n * 16 bytes of random data to use for UUID generation.\n */\n random?: Uint8Array\n}\n\nexport type UuidV4 = {\n (): string\n <TBuf extends Uint8Array = Uint8Array>(options: UuidV4Options | undefined, buf: TBuf, offset?: number): TBuf\n (options?: UuidV4Options, buf?: undefined, offset?: number): string\n toBytes(id: string): Uint8Array\n fromBytes(bytes: Uint8Array): 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_V4_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i\n\nfunction writeV4BytesUnchecked(rnds: Uint8Array, buf: Uint8Array, offset: number): void {\n // Copy 16 UUID bytes into the provided buffer slice.\n for (let i = 0; i < UUID_BYTES; i += 1) {\n buf[offset + i] = rnds[i]\n }\n\n // Set RFC 4122 version (4) and variant (10xx) bits on owned output only.\n buf[offset + 6] = (buf[offset + 6] & 0x0f) | 0x40\n buf[offset + 8] = (buf[offset + 8] & 0x3f) | 0x80\n}\n\n/*\n * Overload: no buffer => return a UUID string.\n */\nfunction v4(options?: UuidV4Options, buf?: undefined, offset?: number): string\n/*\n * Overload: caller provides a buffer slice to fill with UUID bytes.\n */\nfunction v4<TBuf extends Uint8Array = Uint8Array>(options: UuidV4Options | undefined, buf: TBuf, offset?: number): TBuf\nfunction v4<TBuf extends Uint8Array = Uint8Array>(options?: UuidV4Options, buf?: TBuf, offset?: number): string | TBuf {\n if (!buf && !options) {\n return randomUUID()\n }\n\n return _v4(options, buf, offset)\n}\n\nfunction _v4<TBuf extends Uint8Array = Uint8Array>(\n options?: UuidV4Options,\n buf?: TBuf,\n offset?: number,\n): string | TBuf {\n const random = options?.random\n if (random && random.length < UUID_BYTES) {\n throw new InvalidInputError('UUID_RANDOM_BYTES_TOO_SHORT', `Random bytes length must be >= ${UUID_BYTES}`)\n }\n\n const outputOffset = buf ? (offset ?? 0) : 0\n if (buf && !isWritableRange(buf, outputOffset, UUID_BYTES)) {\n throw new BufferError(\n 'UUID_BUFFER_OUT_OF_BOUNDS',\n `UUID byte range ${outputOffset}:${outputOffset + UUID_BYTES - 1} is out of buffer bounds`,\n )\n }\n\n const output = buf ?? reusableBuf\n writeV4BytesUnchecked(random ?? rng(), output, outputOffset)\n return buf ?? formatUuidUnchecked(output)\n}\n\nfunction isValid(id: unknown): id is string {\n return typeof id === 'string' && UUID_V4_REGEX.test(id)\n}\n\n/**\n * Generate a UUID v4 string or write the bytes into a buffer.\n *\n * UUID v4 is a purely random UUID with 122 bits of entropy. It's the most\n * widely compatible UUID format, supported by virtually all databases and systems.\n * Use when you need maximum compatibility and don't require time-ordering.\n *\n * @example\n * ```ts\n * import { uuidv4 } from 'uniku/uuid/v4'\n *\n * const id = uuidv4()\n * // => \"550e8400-e29b-41d4-a716-446655440000\"\n *\n * // Validate\n * uuidv4.isValid(id) // true\n *\n * // Convert to/from bytes (16 bytes)\n * const bytes = uuidv4.toBytes(id)\n * const restored = uuidv4.fromBytes(bytes)\n * ```\n */\nexport const uuidv4: UuidV4 = Object.assign(v4, {\n toBytes: parseUuid,\n fromBytes: formatUuid,\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":"uPAKA,MAAM,EAA2B,WAAW,OAAO,WAAW,KAAK,WAAW,MAAM,EAE9E,EAAc,IAAI,WAAW,EAAU,EAsBvC,EAAgB,yEAEtB,SAAS,EAAsB,EAAkB,EAAiB,EAAsB,CAEtF,IAAK,IAAI,EAAI,EAAG,EAAI,GAAY,GAAK,EACnC,EAAI,EAAS,GAAK,EAAK,GAIzB,EAAI,EAAS,GAAM,EAAI,EAAS,GAAK,GAAQ,GAC7C,EAAI,EAAS,GAAM,EAAI,EAAS,GAAK,GAAQ,GAC/C,CAUA,SAAS,EAAyC,EAAyB,EAAY,EAAgC,CAKrH,MAJI,CAAC,GAAO,CAAC,EACJ,EAAW,EAGb,EAAI,EAAS,EAAK,CAAM,CACjC,CAEA,SAAS,EACP,EACA,EACA,EACe,CACf,IAAM,EAAS,GAAS,OACxB,GAAI,GAAU,EAAO,OAAS,GAC5B,MAAM,IAAI,EAAkB,8BAA+B,mCAA8C,EAG3G,IAAM,EAAe,EAAO,GAAU,EAAK,EAC3C,GAAI,GAAO,CAAC,EAAgB,EAAK,EAAc,EAAU,EACvD,MAAM,IAAI,EACR,4BACA,mBAAmB,EAAa,GAAG,EAAe,GAAa,EAAE,yBACnE,EAGF,IAAM,EAAS,GAAO,EAEtB,OADA,EAAsB,GAAU,EAAI,EAAG,EAAQ,CAAY,EACpD,GAAO,EAAoB,CAAM,CAC1C,CAEA,SAAS,EAAQ,EAA2B,CAC1C,OAAO,OAAO,GAAO,UAAY,EAAc,KAAK,CAAE,CACxD,CAwBA,MAAa,EAAiB,OAAO,OAAO,EAAI,CAC9C,QAAS,EACT,UAAW,EACX,UACA,IAAK,uCACL,IAAK,sCACP,CAAC"}
1
+ {"version":3,"file":"v4.mjs","names":[],"sources":["../../src/uuid/v4.ts"],"sourcesContent":["import { rng } from '../common/random'\nimport { isWritableRange } from '../common/validation'\nimport { BufferError, InvalidInputError } from '../errors'\nimport { formatUuid, formatUuidUnchecked, parseUuid } from './common/uuid'\n\nconst randomUUID = /*@__PURE__*/ globalThis.crypto.randomUUID.bind(globalThis.crypto)\nconst UUID_BYTES = 16\nconst reusableBuf = new Uint8Array(UUID_BYTES)\n\nexport type UuidV4Options = {\n /**\n * 16 bytes of random data to use for UUID generation.\n */\n random?: Uint8Array\n}\n\nexport type UuidV4 = {\n /** Generate a random UUID v4 string. */\n (): string\n /** Generate a UUID v4 with explicit options or write its 16 canonical bytes into a caller-owned buffer. */\n <TBuf extends Uint8Array = Uint8Array>(options: UuidV4Options | undefined, buf: TBuf, offset?: number): TBuf\n /** Generate a UUID v4 string with optional deterministic random bytes. */\n (options?: UuidV4Options, buf?: undefined, offset?: number): string\n /** Convert a UUID v4 string to its canonical 16-byte representation. */\n toBytes(id: string): Uint8Array\n /** Convert 16 canonical UUID bytes to a UUID v4 string. */\n fromBytes(bytes: Uint8Array): string\n /** Return whether a value is a syntactically valid UUID v4 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_V4_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i\n\nfunction writeV4BytesUnchecked(rnds: Uint8Array, buf: Uint8Array, offset: number): void {\n // Copy 16 UUID bytes into the provided buffer slice.\n for (let i = 0; i < UUID_BYTES; i += 1) {\n buf[offset + i] = rnds[i]\n }\n\n // Set RFC 4122 version (4) and variant (10xx) bits on owned output only.\n buf[offset + 6] = (buf[offset + 6] & 0x0f) | 0x40\n buf[offset + 8] = (buf[offset + 8] & 0x3f) | 0x80\n}\n\n/*\n * Overload: no buffer => return a UUID string.\n */\nfunction v4(options?: UuidV4Options, buf?: undefined, offset?: number): string\n/*\n * Overload: caller provides a buffer slice to fill with UUID bytes.\n */\nfunction v4<TBuf extends Uint8Array = Uint8Array>(options: UuidV4Options | undefined, buf: TBuf, offset?: number): TBuf\nfunction v4<TBuf extends Uint8Array = Uint8Array>(options?: UuidV4Options, buf?: TBuf, offset?: number): string | TBuf {\n if (!buf && !options) {\n return randomUUID()\n }\n\n return _v4(options, buf, offset)\n}\n\nfunction _v4<TBuf extends Uint8Array = Uint8Array>(\n options?: UuidV4Options,\n buf?: TBuf,\n offset?: number,\n): string | TBuf {\n const random = options?.random\n if (random && random.length < UUID_BYTES) {\n throw new InvalidInputError('UUID_RANDOM_BYTES_TOO_SHORT', `Random bytes length must be >= ${UUID_BYTES}`)\n }\n\n const outputOffset = buf ? (offset ?? 0) : 0\n if (buf && !isWritableRange(buf, outputOffset, UUID_BYTES)) {\n throw new BufferError(\n 'UUID_BUFFER_OUT_OF_BOUNDS',\n `UUID byte range ${outputOffset}:${outputOffset + UUID_BYTES - 1} is out of buffer bounds`,\n )\n }\n\n const output = buf ?? reusableBuf\n writeV4BytesUnchecked(random ?? rng(), output, outputOffset)\n return buf ?? formatUuidUnchecked(output)\n}\n\nfunction isValid(id: unknown): id is string {\n return typeof id === 'string' && UUID_V4_REGEX.test(id)\n}\n\n/**\n * Generate a UUID v4 string or write the bytes into a buffer.\n *\n * UUID v4 is a purely random UUID with 122 bits of entropy. It's the most\n * widely compatible UUID format, supported by virtually all databases and systems.\n * Use when you need maximum compatibility and don't require time-ordering.\n *\n * @example\n * ```ts\n * import { uuidv4 } from 'uniku/uuid/v4'\n *\n * const id = uuidv4()\n * // => \"550e8400-e29b-41d4-a716-446655440000\"\n *\n * // Validate\n * uuidv4.isValid(id) // true\n *\n * // Convert to/from bytes (16 bytes)\n * const bytes = uuidv4.toBytes(id)\n * const restored = uuidv4.fromBytes(bytes)\n * ```\n */\nexport const uuidv4: UuidV4 = Object.assign(v4, {\n toBytes: parseUuid,\n fromBytes: formatUuid,\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":"uPAKA,MAAM,EAA2B,WAAW,OAAO,WAAW,KAAK,WAAW,MAAM,EAE9E,EAAc,IAAI,WAAW,EAAU,EA4BvC,EAAgB,yEAEtB,SAAS,EAAsB,EAAkB,EAAiB,EAAsB,CAEtF,IAAK,IAAI,EAAI,EAAG,EAAI,GAAY,GAAK,EACnC,EAAI,EAAS,GAAK,EAAK,GAIzB,EAAI,EAAS,GAAM,EAAI,EAAS,GAAK,GAAQ,GAC7C,EAAI,EAAS,GAAM,EAAI,EAAS,GAAK,GAAQ,GAC/C,CAUA,SAAS,EAAyC,EAAyB,EAAY,EAAgC,CAKrH,MAJI,CAAC,GAAO,CAAC,EACJ,EAAW,EAGb,EAAI,EAAS,EAAK,CAAM,CACjC,CAEA,SAAS,EACP,EACA,EACA,EACe,CACf,IAAM,EAAS,GAAS,OACxB,GAAI,GAAU,EAAO,OAAS,GAC5B,MAAM,IAAI,EAAkB,8BAA+B,mCAA8C,EAG3G,IAAM,EAAe,EAAO,GAAU,EAAK,EAC3C,GAAI,GAAO,CAAC,EAAgB,EAAK,EAAc,EAAU,EACvD,MAAM,IAAI,EACR,4BACA,mBAAmB,EAAa,GAAG,EAAe,GAAa,EAAE,yBACnE,EAGF,IAAM,EAAS,GAAO,EAEtB,OADA,EAAsB,GAAU,EAAI,EAAG,EAAQ,CAAY,EACpD,GAAO,EAAoB,CAAM,CAC1C,CAEA,SAAS,EAAQ,EAA2B,CAC1C,OAAO,OAAO,GAAO,UAAY,EAAc,KAAK,CAAE,CACxD,CAwBA,MAAa,EAAiB,OAAO,OAAO,EAAI,CAC9C,QAAS,EACT,UAAW,EACX,UACA,IAAK,uCACL,IAAK,sCACP,CAAC"}
@@ -7,6 +7,10 @@ type UuidV7Options = {
7
7
  * Note: Several bytes will be overwritten with timestamp, version, and variant data.
8
8
  */
9
9
  random?: Uint8Array;
10
+ /**
11
+ * Timestamp in milliseconds since Unix epoch.
12
+ * Defaults to Date.now().
13
+ */
10
14
  msecs?: number;
11
15
  /**
12
16
  * Unsigned 32-bit sequence value.
@@ -14,12 +18,12 @@ type UuidV7Options = {
14
18
  seq?: number;
15
19
  };
16
20
  type UuidV7 = {
17
- (): string;
18
- <TBuf extends Uint8Array = Uint8Array>(options: UuidV7Options | undefined, buf: TBuf, offset?: number): TBuf;
19
- (options?: UuidV7Options, buf?: undefined, offset?: number): string;
20
- toBytes(id: string): Uint8Array;
21
- fromBytes(bytes: Uint8Array): string;
22
- timestamp(id: string): number;
21
+ /** Generate a time-ordered UUID v7 string. */(): string; /** Generate a UUID v7 with explicit options or write its 16 canonical bytes into a caller-owned buffer. */
22
+ <TBuf extends Uint8Array = Uint8Array>(options: UuidV7Options | undefined, buf: TBuf, offset?: number): TBuf; /** Generate a UUID v7 string with optional timestamp, sequence, or random bytes. */
23
+ (options?: UuidV7Options, buf?: undefined, offset?: number): string; /** Convert a UUID v7 string to its canonical 16-byte representation. */
24
+ toBytes(id: string): Uint8Array; /** Convert 16 canonical UUID bytes to a UUID v7 string. */
25
+ fromBytes(bytes: Uint8Array): string; /** Read the embedded Unix timestamp in milliseconds. */
26
+ timestamp(id: string): number; /** Return whether a value is a syntactically valid UUID v7 string. */
23
27
  isValid(id: unknown): id is string; /** The nil UUID (all zeros) */
24
28
  NIL: string; /** The max UUID (all ones) */
25
29
  MAX: string;
@@ -1 +1 @@
1
- {"version":3,"file":"v7.d.mts","names":[],"sources":["../../src/uuid/v7.ts"],"mappings":";;;KAKY,aAAA;;;AAAZ;;EAKE,MAAA,GAAS,UAAA;EACT,KAAA;;;;EAIA,GAAA;AAAA;AAAA,KAGU,MAAA;EAAA;EAAA,cAEI,UAAA,GAAa,UAAA,EAAY,OAAA,EAAS,aAAA,cAA2B,GAAA,EAAK,IAAA,EAAM,MAAA,YAAkB,IAAA;EAAA,CACvG,OAAA,GAAU,aAAA,EAAe,GAAA,cAAiB,MAAA;EAC3C,OAAA,CAAQ,EAAA,WAAa,UAAA;EACrB,SAAA,CAAU,KAAA,EAAO,UAAA;EACjB,SAAA,CAAU,EAAA;EACV,OAAA,CAAQ,EAAA,YAAc,EAAA;EAEtB,GAAA;EAEA,GAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;cA2KW,MAAA,EAAQ,MAAA"}
1
+ {"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,GAAA;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;AA2KF;;;;AAAqB;;;;cAAR,MAAA,EAAQ,MAAA"}
@@ -1 +1 @@
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 msecs?: number\n /**\n * Unsigned 32-bit sequence value.\n */\n seq?: number\n}\n\nexport type UuidV7 = {\n (): string\n <TBuf extends Uint8Array = Uint8Array>(options: UuidV7Options | undefined, buf: TBuf, offset?: number): TBuf\n (options?: UuidV7Options, 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 /** 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 'UUID_BUFFER_OUT_OF_BOUNDS',\n `UUID byte range ${offset}:${offset + UUID_BYTES - 1} is out of buffer bounds`,\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(\n 'UUID_TIMESTAMP_OUT_OF_RANGE',\n `Timestamp must be an integer between 0 and ${MAX_MSECS}`,\n )\n }\n const optSeq = options.seq\n if (optSeq !== undefined && !isIntegerInRange(optSeq, 0, MAX_SEQ)) {\n throw new InvalidInputError('UUID_SEQUENCE_OUT_OF_RANGE', `Sequence must be an integer between 0 and ${MAX_SEQ}`)\n }\n const optRandom = options.random\n if (optRandom && optRandom.length < UUID_BYTES) {\n throw new InvalidInputError('UUID_RANDOM_BYTES_TOO_SHORT', `Random bytes length must be >= ${UUID_BYTES}`)\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":"8PAgCA,MAAM,EAAgB,yEAEhB,EAAY,eACZ,EAAU,WAIV,EAAc,IAAI,WAAW,EAAU,EAevC,EAAiB,CAAE,MAAO,KAAW,IAAK,CAAE,EAElD,SAAS,EAAsB,EAAkB,EAAe,EAAa,EAAiB,EAAsB,CAGlH,EAAI,KAAa,EAAQ,cAAiB,IAC1C,EAAI,KAAa,EAAQ,WAAe,IACxC,EAAI,KAAa,EAAQ,SAAa,IACtC,EAAI,KAAa,EAAQ,MAAW,IACpC,EAAI,KAAa,EAAQ,IAAS,IAClC,EAAI,KAAY,EAAQ,IAGxB,EAAI,KAAY,IAAS,IAAQ,GAAM,GACvC,EAAI,KAAa,IAAQ,GAAM,IAC/B,EAAI,KAAY,IAAS,IAAQ,GAAM,GACvC,EAAI,KAAa,IAAQ,EAAK,IAE9B,EAAI,KAAc,GAAO,EAAK,IAAS,EAAK,IAAM,EAClD,EAAI,KAAY,EAAK,IACrB,EAAI,KAAY,EAAK,IACrB,EAAI,KAAY,EAAK,IACrB,EAAI,KAAY,EAAK,IACrB,EAAI,KAAY,EAAK,GACvB,CAEA,SAAS,EAAa,EAAkB,EAAe,EAAa,EAAiB,EAAsB,CACzG,GAAI,CAAC,EAAgB,EAAK,EAAQ,EAAU,EAC1C,MAAM,IAAI,EACR,4BACA,mBAAmB,EAAO,GAAG,EAAS,GAAa,EAAE,yBACvD,EAEF,EAAsB,EAAM,EAAO,EAAK,EAAK,CAAM,CACrD,CAEA,SAAS,EACP,EACA,EACA,EAAS,EACM,CACf,IAAM,EAAW,EAAQ,MACzB,GAAI,IAAa,IAAA,IAAa,CAAC,EAAiB,EAAU,EAAG,CAAS,EACpE,MAAM,IAAI,EACR,8BACA,8CAA8C,GAChD,EAEF,IAAM,EAAS,EAAQ,IACvB,GAAI,IAAW,IAAA,IAAa,CAAC,EAAiB,EAAQ,EAAG,CAAO,EAC9D,MAAM,IAAI,EAAkB,6BAA8B,6CAA6C,GAAS,EAElH,IAAM,EAAY,EAAQ,OAC1B,GAAI,GAAa,EAAU,OAAS,GAClC,MAAM,IAAI,EAAkB,8BAA+B,mCAA8C,EAG3G,IAAM,EAAO,GAAa,EAAI,EACxB,EAAQ,GAAY,KAAK,IAAI,EAE7B,EAAM,GAAW,EAAK,IAAM,GAAO,EAAK,IAAM,GAAO,EAAK,IAAM,EAAK,EAAK,GAOhF,OALI,GACF,EAAa,EAAM,EAAO,EAAK,EAAK,CAAM,EACnC,IAET,EAAsB,EAAM,EAAO,EAAK,EAAa,CAAC,EAC/C,EAAoB,CAAW,EACxC,CAUA,SAAS,EAAyC,EAAyB,EAAY,EAAgC,CACrH,GAAI,EACF,OAAO,EAAc,EAAS,EAAK,CAAM,EAI3C,IAAM,EAAM,KAAK,IAAI,EACf,EAAO,EAAI,EAmBjB,OAhBI,EAAM,EAAM,OACd,EAAM,IAAO,EAAK,IAAM,GAAO,EAAK,IAAM,GAAO,EAAK,IAAM,EAAK,EAAK,GACtE,EAAM,MAAQ,IAEd,EAAM,IAAO,EAAM,IAAM,EAAK,EAC1B,EAAM,IAAM,IACd,EAAM,IAAM,EACZ,EAAM,UAIN,GACF,EAAa,EAAM,EAAM,MAAO,EAAM,IAAK,EAAK,GAAU,CAAC,EACpD,IAET,EAAsB,EAAM,EAAM,MAAO,EAAM,IAAK,EAAa,CAAC,EAC3D,EAAoB,CAAW,EACxC,CAEA,SAAS,EAAU,EAAoB,CACrC,IAAM,EAAQ,EAAU,CAAE,EACtB,EAAQ,EACZ,IAAK,IAAI,EAAI,EAAG,EAAI,EAAG,GAAK,EAC1B,EAAQ,EAAQ,IAAM,EAAM,GAE9B,OAAO,CACT,CAEA,SAAS,EAAQ,EAA2B,CAC1C,OAAO,OAAO,GAAO,UAAY,EAAc,KAAK,CAAE,CACxD,CA4BA,MAAa,EAAiB,OAAO,OAAO,EAAI,CAC9C,QAAS,EACT,UAAW,EACX,YACA,UACA,IAAK,uCACL,IAAK,sCACP,CAAC"}
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 sequence value.\n */\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, sequence, 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 'UUID_BUFFER_OUT_OF_BOUNDS',\n `UUID byte range ${offset}:${offset + UUID_BYTES - 1} is out of buffer bounds`,\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(\n 'UUID_TIMESTAMP_OUT_OF_RANGE',\n `Timestamp must be an integer between 0 and ${MAX_MSECS}`,\n )\n }\n const optSeq = options.seq\n if (optSeq !== undefined && !isIntegerInRange(optSeq, 0, MAX_SEQ)) {\n throw new InvalidInputError('UUID_SEQUENCE_OUT_OF_RANGE', `Sequence must be an integer between 0 and ${MAX_SEQ}`)\n }\n const optRandom = options.random\n if (optRandom && optRandom.length < UUID_BYTES) {\n throw new InvalidInputError('UUID_RANDOM_BYTES_TOO_SHORT', `Random bytes length must be >= ${UUID_BYTES}`)\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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"}
@@ -0,0 +1,31 @@
1
+ import { i as UniqueIdError, n as InvalidInputError, r as ParseError, t as BufferError } from "../errors-Dgoyi-ci.mjs";
2
+
3
+ //#region src/xid/xid.d.ts
4
+ type XidOptions = {
5
+ /** First three bytes used as the XID machine identity. */machineId?: Uint8Array; /** 16-bit process identity. */
6
+ processId?: number; /** Unix timestamp in seconds. Defaults to the current second. */
7
+ secs?: number; /** 24-bit counter. Explicit values do not consume shared state. */
8
+ counter?: number;
9
+ };
10
+ type Xid = {
11
+ (): string;
12
+ <TBuf extends Uint8Array = Uint8Array>(options: XidOptions | undefined, buf: TBuf, offset?: number): TBuf;
13
+ (options?: XidOptions, buf?: undefined, offset?: number): string;
14
+ toBytes(id: string): Uint8Array;
15
+ fromBytes(bytes: Uint8Array): string;
16
+ timestamp(id: string): number;
17
+ isValid(id: unknown): id is string;
18
+ NIL: string;
19
+ MAX: string;
20
+ };
21
+ /**
22
+ * Generate a 20-character rs/xid-compatible identifier.
23
+ *
24
+ * XID embeds seconds, a lazily-random per-runtime identity, and a shared
25
+ * always-incrementing counter. In Cloudflare Workers, time is frozen during a
26
+ * request, so the counter preserves ordering for IDs made in that request.
27
+ */
28
+ declare const xid: Xid;
29
+ //#endregion
30
+ export { BufferError, InvalidInputError, ParseError, UniqueIdError, Xid, XidOptions, xid };
31
+ //# sourceMappingURL=xid.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xid.d.mts","names":[],"sources":["../../src/xid/xid.ts"],"mappings":";;;KAaY,UAAA;4DAEV,SAAA,GAAY,UAAA,EAFd;EAIE,SAAA;EAEA,IAAA;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;;;;;;;;cAmHW,GAAA,EAAK,GAAA"}
@@ -0,0 +1,2 @@
1
+ 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";const l=`0123456789abcdefghijklmnopqrstuv`,u=new Uint8Array(65536);u.fill(255);for(let e=0;e<32;e+=1)u[l.charCodeAt(e)]=e;function d(e){if(e.length!==12)throw new i(`XID_BYTES_INVALID_LENGTH`,`XID bytes must be exactly 12 bytes, got ${e.length}`);return l[e[0]>>3]+l[(e[0]<<2|e[1]>>6)&31]+l[e[1]>>1&31]+l[(e[1]<<4|e[2]>>4)&31]+l[(e[2]<<1|e[3]>>7)&31]+l[e[3]>>2&31]+l[(e[3]<<3|e[4]>>5)&31]+l[e[4]&31]+l[e[5]>>3]+l[(e[5]<<2|e[6]>>6)&31]+l[e[6]>>1&31]+l[(e[6]<<4|e[7]>>4)&31]+l[(e[7]<<1|e[8]>>7)&31]+l[e[8]>>2&31]+l[(e[8]<<3|e[9]>>5)&31]+l[e[9]&31]+l[e[10]>>3]+l[(e[10]<<2|e[11]>>6)&31]+l[e[11]>>1&31]+l[e[11]<<4&31]}function f(e){if(e.length!==20)throw new o(`XID_INVALID_LENGTH`,`XID string must be 20 characters, got ${e.length}`);let t=new Uint8Array(20);for(let n=0;n<20;n+=1){let r=u[e.charCodeAt(n)];if(r===255)throw new o(`XID_INVALID_CHAR`,`Invalid XID character: ${e[n]}`);t[n]=r}if(t[19]!==0&&t[19]!==16)throw new o(`XID_NON_CANONICAL`,`XID trailing bits must be canonically encoded`);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 p=4294967295,m=65535,h=16777215,g=/^[0-9a-v]{19}[0g]$/,_={machineId:void 0,processId:void 0,counter:void 0};function v(e){return t(e).slice()}function y(){_.machineId===void 0&&(_.machineId=v(3)),_.processId===void 0&&(_.processId=e()&m)}function b(){return _.counter===void 0&&(_.counter=e()&h),_.counter=_.counter+1&h,_.counter}function x(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 S(e){if(e.machineId!==void 0&&e.machineId.length<3)throw new a(`XID_MACHINE_ID_BYTES_TOO_SHORT`,`Machine ID bytes length must be >= 3 for XID`);if(e.processId!==void 0&&!r(e.processId,0,m))throw new a(`XID_PROCESS_ID_OUT_OF_RANGE`,`Process ID must be between 0 and ${m}`);if(e.secs!==void 0&&!r(e.secs,0,p))throw new a(`XID_TIMESTAMP_OUT_OF_RANGE`,`Timestamp must be between 0 and ${p}`);if(e.counter!==void 0&&!r(e.counter,0,h))throw new a(`XID_COUNTER_OUT_OF_RANGE`,`Counter must be between 0 and ${h}`)}function C(e,t,r=0){e!==void 0&&S(e);let a=e?.secs??Math.floor(Date.now()/1e3);(e?.machineId===void 0||e.processId===void 0)&&y();let o=e?.machineId??_.machineId,s=e?.processId??_.processId,c=e?.counter??b();if(t!==void 0){if(!n(t,r,12))throw new i(`XID_BUFFER_OUT_OF_BOUNDS`,`XID byte range ${r}:${r+11} is out of buffer bounds`);return x(a,o,s,c,t,r),t}let l=new Uint8Array(12);return x(a,o,s,c,l,0),d(l)}function w(e){return f(e)}function T(e){return d(e)}function E(e){let t=f(e);return((t[0]<<24|t[1]<<16|t[2]<<8|t[3])>>>0)*1e3}function D(e){return typeof e==`string`&&g.test(e)}const O=Object.assign(C,{toBytes:w,fromBytes:T,timestamp:E,isValid:D,NIL:`0`.repeat(20),MAX:d(new Uint8Array(12).fill(255))});export{i as BufferError,a as InvalidInputError,o as ParseError,s as UniqueIdError,O as xid};
2
+ //# sourceMappingURL=xid.mjs.map
@@ -0,0 +1 @@
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 XID_BYTES = 12\nconst XID_LENGTH = 20\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(\n 'XID_BYTES_INVALID_LENGTH',\n `XID bytes must be exactly ${XID_BYTES} bytes, got ${bytes.length}`,\n )\n }\n\n return (\n ENCODING[bytes[0] >> 3] +\n ENCODING[((bytes[0] << 2) | (bytes[1] >> 6)) & 0x1f] +\n ENCODING[(bytes[1] >> 1) & 0x1f] +\n ENCODING[((bytes[1] << 4) | (bytes[2] >> 4)) & 0x1f] +\n ENCODING[((bytes[2] << 1) | (bytes[3] >> 7)) & 0x1f] +\n ENCODING[(bytes[3] >> 2) & 0x1f] +\n ENCODING[((bytes[3] << 3) | (bytes[4] >> 5)) & 0x1f] +\n ENCODING[bytes[4] & 0x1f] +\n ENCODING[bytes[5] >> 3] +\n ENCODING[((bytes[5] << 2) | (bytes[6] >> 6)) & 0x1f] +\n ENCODING[(bytes[6] >> 1) & 0x1f] +\n ENCODING[((bytes[6] << 4) | (bytes[7] >> 4)) & 0x1f] +\n ENCODING[((bytes[7] << 1) | (bytes[8] >> 7)) & 0x1f] +\n ENCODING[(bytes[8] >> 2) & 0x1f] +\n ENCODING[((bytes[8] << 3) | (bytes[9] >> 5)) & 0x1f] +\n ENCODING[bytes[9] & 0x1f] +\n ENCODING[bytes[10] >> 3] +\n ENCODING[((bytes[10] << 2) | (bytes[11] >> 6)) & 0x1f] +\n ENCODING[(bytes[11] >> 1) & 0x1f] +\n ENCODING[(bytes[11] << 4) & 0x1f]\n )\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('XID_INVALID_LENGTH', `XID string must be ${XID_LENGTH} characters, got ${id.length}`)\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('XID_INVALID_CHAR', `Invalid XID character: ${id[i]}`)\n }\n values[i] = value\n }\n\n if (values[19] !== 0 && values[19] !== 16) {\n throw new ParseError('XID_NON_CANONICAL', 'XID trailing bits must be canonically encoded')\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 { isIntegerInRange, isWritableRange } from '../common/validation'\nimport { BufferError, InvalidInputError } from '../errors'\nimport { decodeBase32Hex, encodeBase32Hex } 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]$/\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 /** Unix timestamp in seconds. Defaults to the current second. */\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 'XID_MACHINE_ID_BYTES_TOO_SHORT',\n `Machine ID bytes length must be >= ${MACHINE_ID_BYTES} for XID`,\n )\n }\n if (options.processId !== undefined && !isIntegerInRange(options.processId, 0, MAX_PROCESS_ID)) {\n throw new InvalidInputError('XID_PROCESS_ID_OUT_OF_RANGE', `Process ID must be between 0 and ${MAX_PROCESS_ID}`)\n }\n if (options.secs !== undefined && !isIntegerInRange(options.secs, 0, MAX_SECS)) {\n throw new InvalidInputError('XID_TIMESTAMP_OUT_OF_RANGE', `Timestamp must be between 0 and ${MAX_SECS}`)\n }\n if (options.counter !== undefined && !isIntegerInRange(options.counter, 0, MAX_COUNTER)) {\n throw new InvalidInputError('XID_COUNTER_OUT_OF_RANGE', `Counter must be between 0 and ${MAX_COUNTER}`)\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) validateOptions(options)\n\n const secs = options?.secs ?? 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(\n 'XID_BUFFER_OUT_OF_BOUNDS',\n `XID byte range ${offset}:${offset + 11} is out of buffer bounds`,\n )\n }\n writeXidBytesUnchecked(secs, machineId, processId, counter, buf, offset)\n return buf\n }\n\n const bytes = new Uint8Array(XID_BYTES)\n writeXidBytesUnchecked(secs, machineId, processId, counter, bytes, 0)\n return encodeBase32Hex(bytes)\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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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "uniku",
4
- "version": "0.3.1",
4
+ "version": "0.4.0",
5
5
  "description": "Minimal, tree-shakeable unique ID generators for every JavaScript runtime",
6
6
  "author": {
7
7
  "name": "Alberto Schiabel",
@@ -28,6 +28,7 @@
28
28
  "nanoid",
29
29
  "ksuid",
30
30
  "objectid",
31
+ "xid",
31
32
  "mongodb",
32
33
  "tsid",
33
34
  "snowflake",
@@ -110,6 +111,11 @@
110
111
  "import": "./build/tsid/tsid.mjs",
111
112
  "default": "./build/tsid/tsid.mjs"
112
113
  },
114
+ "./xid": {
115
+ "types": "./build/xid/xid.d.mts",
116
+ "import": "./build/xid/xid.mjs",
117
+ "default": "./build/xid/xid.mjs"
118
+ },
113
119
  "./errors": {
114
120
  "types": "./build/errors.d.mts",
115
121
  "import": "./build/errors.mjs",
@@ -130,13 +136,15 @@
130
136
  "@owpz/ksuid": "^25.7.20",
131
137
  "@paralleldrive/cuid2": "^3.3.0",
132
138
  "@types/bun": "^1.3.14",
133
- "effect": "4.0.0-beta.93",
134
139
  "bson": "^7.3.1",
140
+ "effect": "4.0.0-beta.93",
135
141
  "nanoid": "^5.1.16",
142
+ "nexid": "^2.1.0",
136
143
  "tsid-ts": "^0.0.9",
137
144
  "typeid-js": "1.2.0",
138
145
  "ulid": "3.0.2",
139
- "uuid": "14.0.1"
146
+ "uuid": "14.0.1",
147
+ "xid-ts": "^1.3.0"
140
148
  },
141
149
  "scripts": {
142
150
  "clean": "rimraf build .turbo",
@@ -18,7 +18,9 @@ export type Cuid2Options = {
18
18
  }
19
19
 
20
20
  export type Cuid2 = {
21
+ /** Generate a CUID v2 string. */
21
22
  (options?: Cuid2Options): string
23
+ /** Return whether a value is a syntactically valid CUID v2 string. */
22
24
  isValid(id: unknown): id is string
23
25
  }
24
26
 
@@ -181,13 +183,13 @@ function isValid(id: unknown): id is string {
181
183
  }
182
184
 
183
185
  /**
184
- * Generate a CUID2 string.
186
+ * Generate a CUID v2 string.
185
187
  *
186
- * CUID2 is a secure, collision-resistant identifier that hashes multiple
188
+ * CUID v2 is a secure, collision-resistant identifier that hashes multiple
187
189
  * entropy sources using SHA3-512. Unlike time-ordered IDs (ULID, UUID v7),
188
- * CUID2 prevents enumeration attacks by making IDs non-predictable.
190
+ * CUID v2 prevents enumeration attacks by making IDs non-predictable.
189
191
  *
190
- * Note: CUID2 does not provide toBytes/fromBytes because it is a string-native
192
+ * Note: CUID v2 does not provide toBytes/fromBytes because it is a string-native
191
193
  * format with no canonical binary representation (unlike UUID's 16-byte format).
192
194
  *
193
195
  * @example
package/src/generators.ts CHANGED
@@ -9,7 +9,7 @@
9
9
  // Plain `as const` (not `as const satisfies readonly string[]`): the `satisfies`
10
10
  // wrapper defeats isolatedDeclarations' trivial declaration emit for this export.
11
11
  // All members are string literals, so the shape guard adds nothing here anyway.
12
- export const ID_GENERATORS = ['uuid', 'ulid', 'typeid', 'nanoid', 'cuid', 'ksuid', 'objectid', 'tsid'] as const
12
+ export const ID_GENERATORS = ['uuid', 'ulid', 'typeid', 'nanoid', 'cuid', 'ksuid', 'objectid', 'tsid', 'xid'] as const
13
13
 
14
14
  /**
15
15
  * The union of ID generators supported by uniku, derived from {@link ID_GENERATORS}.
@@ -45,12 +45,19 @@ export type KsuidOptions = {
45
45
  }
46
46
 
47
47
  export type Ksuid = {
48
+ /** Generate a time-ordered KSUID string. */
48
49
  (): string
50
+ /** Generate a KSUID with explicit options or write its 20 canonical bytes into a caller-owned buffer. */
49
51
  <TBuf extends Uint8Array = Uint8Array>(options: KsuidOptions | undefined, buf: TBuf, offset?: number): TBuf
52
+ /** Generate a KSUID string with optional timestamp or random payload bytes. */
50
53
  (options?: KsuidOptions, buf?: undefined, offset?: number): string
54
+ /** Convert a KSUID string to its canonical 20-byte representation. */
51
55
  toBytes(id: string): Uint8Array
56
+ /** Convert 20 canonical KSUID bytes to a KSUID string. */
52
57
  fromBytes(bytes: Uint8Array): string
58
+ /** Read the embedded Unix timestamp in milliseconds. */
53
59
  timestamp(id: string): number
60
+ /** Return whether a value is a syntactically valid KSUID string. */
54
61
  isValid(id: unknown): id is string
55
62
  /** The nil KSUID (all zeros) */
56
63
  NIL: string
@@ -55,11 +55,11 @@ export type NanoidOptions = {
55
55
  }
56
56
 
57
57
  export type Nanoid = {
58
- /** Generate nanoid with default settings */
58
+ /** Generate a Nanoid with the default URL-safe alphabet and 21-character length. */
59
59
  (): string
60
- /** Generate nanoid with custom size */
60
+ /** Generate a Nanoid with the default alphabet and a custom length. */
61
61
  (size: number): string
62
- /** Generate nanoid with options */
62
+ /** Generate a Nanoid with a custom alphabet, length, or deterministic random bytes. */
63
63
  (options: NanoidOptions): string
64
64
  /**
65
65
  * Validate a nanoid string against the default URL-safe alphabet.
@@ -42,12 +42,19 @@ export type ObjectIdOptions = {
42
42
  }
43
43
 
44
44
  export type ObjectId = {
45
+ /** Generate a MongoDB-compatible ObjectID string. */
45
46
  (): string
47
+ /** Generate an ObjectID with explicit options or write its 12 canonical bytes into a caller-owned buffer. */
46
48
  <TBuf extends Uint8Array = Uint8Array>(options: ObjectIdOptions | undefined, buf: TBuf, offset?: number): TBuf
49
+ /** Generate an ObjectID string with optional timestamp, random field, or counter. */
47
50
  (options?: ObjectIdOptions, buf?: undefined, offset?: number): string
51
+ /** Convert an ObjectID string to its canonical 12-byte representation. */
48
52
  toBytes(id: string): Uint8Array
53
+ /** Convert 12 canonical ObjectID bytes to an ObjectID string. */
49
54
  fromBytes(bytes: Uint8Array): string
55
+ /** Read the embedded Unix timestamp in milliseconds. */
50
56
  timestamp(id: string): number
57
+ /** Return whether a value is a syntactically valid ObjectID string. */
51
58
  isValid(id: unknown): id is string
52
59
  /** The nil ObjectID (all zeros) */
53
60
  NIL: string