@smonn/ids 0.13.1 → 0.14.1

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 (60) hide show
  1. package/README.md +17 -5
  2. package/dist/{adapter-types-CIc-4O-P.d.mts → adapter-types-Bia_w9sg.d.mts} +2 -2
  3. package/dist/{adapter-types-CIc-4O-P.d.mts.map → adapter-types-Bia_w9sg.d.mts.map} +1 -1
  4. package/dist/cli.mjs +82 -15
  5. package/dist/cli.mjs.map +1 -1
  6. package/dist/{codec-shell-C2NKQEx2.mjs → codec-shell-BRZkuQeP.mjs} +89 -7
  7. package/dist/codec-shell-BRZkuQeP.mjs.map +1 -0
  8. package/dist/{digest-DsGeXfk3.mjs → digest-CLJEGBxo.mjs} +7 -4
  9. package/dist/{digest-DsGeXfk3.mjs.map → digest-CLJEGBxo.mjs.map} +1 -1
  10. package/dist/digest.d.mts +19 -2
  11. package/dist/digest.d.mts.map +1 -1
  12. package/dist/digest.mjs +1 -1
  13. package/dist/drizzle.d.mts +3 -3
  14. package/dist/{error-Dqyho9vp.d.mts → error-CifcKKOG.d.mts} +2 -2
  15. package/dist/{error-Dqyho9vp.d.mts.map → error-CifcKKOG.d.mts.map} +1 -1
  16. package/dist/express.d.mts +2 -2
  17. package/dist/fastify.d.mts +2 -2
  18. package/dist/graphql.d.mts +2 -2
  19. package/dist/hono.d.mts +2 -2
  20. package/dist/index.d.mts +19 -2
  21. package/dist/index.d.mts.map +1 -1
  22. package/dist/index.mjs +1 -1
  23. package/dist/{key-material-DvjACe89.mjs → key-material-1wOKJ1o-.mjs} +2 -2
  24. package/dist/{key-material-DvjACe89.mjs.map → key-material-1wOKJ1o-.mjs.map} +1 -1
  25. package/dist/kysely.d.mts +3 -3
  26. package/dist/mikro-orm.d.mts +3 -3
  27. package/dist/nestjs.d.mts +2 -2
  28. package/dist/{opaque-BW3Uzeeb.mjs → opaque-COAcIIY4.mjs} +14 -5
  29. package/dist/opaque-COAcIIY4.mjs.map +1 -0
  30. package/dist/opaque.d.mts +26 -2
  31. package/dist/opaque.d.mts.map +1 -1
  32. package/dist/opaque.mjs +1 -1
  33. package/dist/prisma.d.mts +3 -3
  34. package/dist/{reverse-BW8g_cln.mjs → reverse-CT-El3hi.mjs} +7 -4
  35. package/dist/{reverse-BW8g_cln.mjs.map → reverse-CT-El3hi.mjs.map} +1 -1
  36. package/dist/reverse.d.mts +19 -2
  37. package/dist/reverse.d.mts.map +1 -1
  38. package/dist/reverse.mjs +1 -1
  39. package/dist/{rng-BHFxX1Fc.mjs → rng-6GyNT4zS.mjs} +2 -2
  40. package/dist/{rng-BHFxX1Fc.mjs.map → rng-6GyNT4zS.mjs.map} +1 -1
  41. package/dist/{signed-BTz3ZFYE.mjs → signed-Dkdteu1y.mjs} +8 -5
  42. package/dist/{signed-BTz3ZFYE.mjs.map → signed-Dkdteu1y.mjs.map} +1 -1
  43. package/dist/signed.d.mts +19 -2
  44. package/dist/signed.d.mts.map +1 -1
  45. package/dist/signed.mjs +1 -1
  46. package/dist/{timestamp-CleAIdZI.mjs → timestamp-RXXwHfHO.mjs} +7 -4
  47. package/dist/{timestamp-CleAIdZI.mjs.map → timestamp-RXXwHfHO.mjs.map} +1 -1
  48. package/dist/typeorm.d.mts +2 -2
  49. package/dist/{types-wplmOgOK.d.mts → types-hGBnCpJj.d.mts} +3 -3
  50. package/dist/{types-wplmOgOK.d.mts.map → types-hGBnCpJj.d.mts.map} +1 -1
  51. package/dist/{wrapped-DPlsv1x-.mjs → wrapped-Oj2hC1vB.mjs} +15 -4
  52. package/dist/wrapped-Oj2hC1vB.mjs.map +1 -0
  53. package/dist/wrapped.d.mts +27 -2
  54. package/dist/wrapped.d.mts.map +1 -1
  55. package/dist/wrapped.mjs +1 -1
  56. package/package.json +3 -2
  57. package/spec/vectors.json +97 -0
  58. package/dist/codec-shell-C2NKQEx2.mjs.map +0 -1
  59. package/dist/opaque-BW3Uzeeb.mjs.map +0 -1
  60. package/dist/wrapped-DPlsv1x-.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"rng-BHFxX1Fc.mjs","names":[],"sources":["../src/wire/timestamp-bytes.ts","../src/codecs/_kernel/rng.ts"],"sourcesContent":["import { decodeBase32 } from \"./base32.js\";\n\n// Timestamp byte layout: first N bytes of the plaintext payload encode a\n// big-endian Unix-ms timestamp. Shared by timestamp-family layouts.\nexport const timestampByteLength: number = 6;\n\nconst timestampBase32Length: number = Math.ceil((timestampByteLength * 8) / 5);\n\n/** Write the timestamp in big-endian; encoded via mod-256 to avoid 32-bit bitwise coercion. */\nexport function writeTimestamp(ms: number, buffer: Uint8Array): void {\n if (Number.isNaN(ms)) throw new Error(\"timestamp is not a number\");\n if (!Number.isInteger(ms)) throw new Error(\"timestamp is not an integer\");\n if (ms < 0) throw new Error(\"timestamp is negative\");\n if (ms >= 2 ** (timestampByteLength * 8)) {\n throw new Error(\"timestamp exceeds 48-bit range\");\n }\n for (let i = timestampByteLength - 1; i >= 0; i--) {\n buffer[i] = ms % 256;\n ms = Math.floor(ms / 256);\n }\n}\n\n/** Decode the first `timestampByteLength` bytes of a buffer as a big-endian unsigned millisecond timestamp. */\nexport function readTimestampMs(buffer: Uint8Array): number {\n let ms = 0;\n for (let i = 0; i < timestampByteLength; i++) ms = ms * 256 + buffer[i]!;\n return ms;\n}\n\n/** Decodes ms from the first 10 base32 chars of a payload suffix (partial decode). */\nexport function readTimestampMsFromBase32Suffix(base32Suffix: string): number {\n return readTimestampMs(decodeBase32(base32Suffix.slice(0, timestampBase32Length)));\n}\n","/** Default RNG: writes cryptographically random bytes via `crypto.getRandomValues`. */\nexport function defaultRng(target: Uint8Array): void {\n crypto.getRandomValues(target as Uint8Array<ArrayBuffer>);\n}\n\n// hex charCode → 0–15 nibble, for harvesting bytes out of a UUIDv4 string.\n// Covers ['0'-'9' = 48–57] and ['a'-'f' = 97–102]; randomUUID is lowercase per spec.\nconst hexCharCodeToNibble = new Uint8Array(128);\nfor (let i = 0; i < 10; i++) hexCharCodeToNibble[48 + i] = i;\nfor (let i = 0; i < 6; i++) hexCharCodeToNibble[97 + i] = 10 + i;\n\n/**\n * Fast RNG for the 10-byte random tail shared by the plaintext timestamp layouts\n * (Timestamp and Reverse Timestamp codecs). Writes exactly `target[0..9]`.\n *\n * `crypto.randomUUID()` is ~7× faster than `crypto.getRandomValues` in Node 24\n * (~84 ns vs ~610 ns for a 16-byte fill — the UUID path has a tight fixed-format\n * fast path). A UUIDv4 string carries 122 cryptographically-random bits; we\n * harvest 10 fully-random bytes from positions where no version (hex 12) or\n * variant (hex 16) bits sit. String layout: `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`\n * — bytes 0–5 are string[0..7]+string[9..12], bytes 6–9 are string[24..31].\n *\n * Security-equivalent to `defaultRng` for a 10-byte tail (both are CSPRNG-backed,\n * fully-random bytes); the only difference is throughput.\n */\nexport function fastTenByteRng(target: Uint8Array): void {\n const s = crypto.randomUUID();\n target[0] = (hexCharCodeToNibble[s.charCodeAt(0)]! << 4) | hexCharCodeToNibble[s.charCodeAt(1)]!;\n target[1] = (hexCharCodeToNibble[s.charCodeAt(2)]! << 4) | hexCharCodeToNibble[s.charCodeAt(3)]!;\n target[2] = (hexCharCodeToNibble[s.charCodeAt(4)]! << 4) | hexCharCodeToNibble[s.charCodeAt(5)]!;\n target[3] = (hexCharCodeToNibble[s.charCodeAt(6)]! << 4) | hexCharCodeToNibble[s.charCodeAt(7)]!;\n target[4] = (hexCharCodeToNibble[s.charCodeAt(9)]! << 4) | hexCharCodeToNibble[s.charCodeAt(10)]!;\n target[5] =\n (hexCharCodeToNibble[s.charCodeAt(11)]! << 4) | hexCharCodeToNibble[s.charCodeAt(12)]!;\n target[6] =\n (hexCharCodeToNibble[s.charCodeAt(24)]! << 4) | hexCharCodeToNibble[s.charCodeAt(25)]!;\n target[7] =\n (hexCharCodeToNibble[s.charCodeAt(26)]! << 4) | hexCharCodeToNibble[s.charCodeAt(27)]!;\n target[8] =\n (hexCharCodeToNibble[s.charCodeAt(28)]! << 4) | hexCharCodeToNibble[s.charCodeAt(29)]!;\n target[9] =\n (hexCharCodeToNibble[s.charCodeAt(30)]! << 4) | hexCharCodeToNibble[s.charCodeAt(31)]!;\n}\n"],"mappings":";AAMA,MAAM,wBAAgC,KAAK,KAAA,KAAiC,CAAC;;AAG7E,SAAgB,eAAe,IAAY,QAA0B;CACnE,IAAI,OAAO,MAAM,EAAE,GAAG,MAAM,IAAI,MAAM,2BAA2B;CACjE,IAAI,CAAC,OAAO,UAAU,EAAE,GAAG,MAAM,IAAI,MAAM,6BAA6B;CACxE,IAAI,KAAK,GAAG,MAAM,IAAI,MAAM,uBAAuB;CACnD,IAAI,MAAM,KAAA,IACR,MAAM,IAAI,MAAM,gCAAgC;CAElD,KAAK,IAAI,IAAA,GAA6B,KAAK,GAAG,KAAK;EACjD,OAAO,KAAK,KAAK;EACjB,KAAK,KAAK,MAAM,KAAK,GAAG;CAC1B;AACF;;AAGA,SAAgB,gBAAgB,QAA4B;CAC1D,IAAI,KAAK;CACT,KAAK,IAAI,IAAI,GAAG,IAAA,GAAyB,KAAK,KAAK,KAAK,MAAM,OAAO;CACrE,OAAO;AACT;;AAGA,SAAgB,gCAAgC,cAA8B;CAC5E,OAAO,gBAAgB,aAAa,aAAa,MAAM,GAAG,qBAAqB,CAAC,CAAC;AACnF;;;;AC/BA,SAAgB,WAAW,QAA0B;CACnD,OAAO,gBAAgB,MAAiC;AAC1D;AAIA,MAAM,sCAAsB,IAAI,WAAW,GAAG;AAC9C,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK,oBAAoB,KAAK,KAAK;AAC3D,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK,oBAAoB,KAAK,KAAK,KAAK;;;;;;;;;;;;;;;AAgB/D,SAAgB,eAAe,QAA0B;CACvD,MAAM,IAAI,OAAO,WAAW;CAC5B,OAAO,KAAM,oBAAoB,EAAE,WAAW,CAAC,MAAO,IAAK,oBAAoB,EAAE,WAAW,CAAC;CAC7F,OAAO,KAAM,oBAAoB,EAAE,WAAW,CAAC,MAAO,IAAK,oBAAoB,EAAE,WAAW,CAAC;CAC7F,OAAO,KAAM,oBAAoB,EAAE,WAAW,CAAC,MAAO,IAAK,oBAAoB,EAAE,WAAW,CAAC;CAC7F,OAAO,KAAM,oBAAoB,EAAE,WAAW,CAAC,MAAO,IAAK,oBAAoB,EAAE,WAAW,CAAC;CAC7F,OAAO,KAAM,oBAAoB,EAAE,WAAW,CAAC,MAAO,IAAK,oBAAoB,EAAE,WAAW,EAAE;CAC9F,OAAO,KACJ,oBAAoB,EAAE,WAAW,EAAE,MAAO,IAAK,oBAAoB,EAAE,WAAW,EAAE;CACrF,OAAO,KACJ,oBAAoB,EAAE,WAAW,EAAE,MAAO,IAAK,oBAAoB,EAAE,WAAW,EAAE;CACrF,OAAO,KACJ,oBAAoB,EAAE,WAAW,EAAE,MAAO,IAAK,oBAAoB,EAAE,WAAW,EAAE;CACrF,OAAO,KACJ,oBAAoB,EAAE,WAAW,EAAE,MAAO,IAAK,oBAAoB,EAAE,WAAW,EAAE;CACrF,OAAO,KACJ,oBAAoB,EAAE,WAAW,EAAE,MAAO,IAAK,oBAAoB,EAAE,WAAW,EAAE;AACvF"}
1
+ {"version":3,"file":"rng-6GyNT4zS.mjs","names":[],"sources":["../src/wire/timestamp-bytes.ts","../src/codecs/_kernel/rng.ts"],"sourcesContent":["import { decodeBase32 } from \"./base32.js\";\n\n// Timestamp byte layout: first N bytes of the plaintext payload encode a\n// big-endian Unix-ms timestamp. Shared by timestamp-family layouts.\nexport const timestampByteLength: number = 6;\n\nconst timestampBase32Length: number = Math.ceil((timestampByteLength * 8) / 5);\n\n/** Write the timestamp in big-endian; encoded via mod-256 to avoid 32-bit bitwise coercion. */\nexport function writeTimestamp(ms: number, buffer: Uint8Array): void {\n if (Number.isNaN(ms)) throw new Error(\"timestamp is not a number\");\n if (!Number.isInteger(ms)) throw new Error(\"timestamp is not an integer\");\n if (ms < 0) throw new Error(\"timestamp is negative\");\n if (ms >= 2 ** (timestampByteLength * 8)) {\n throw new Error(\"timestamp exceeds 48-bit range\");\n }\n for (let i = timestampByteLength - 1; i >= 0; i--) {\n buffer[i] = ms % 256;\n ms = Math.floor(ms / 256);\n }\n}\n\n/** Decode the first `timestampByteLength` bytes of a buffer as a big-endian unsigned millisecond timestamp. */\nexport function readTimestampMs(buffer: Uint8Array): number {\n let ms = 0;\n for (let i = 0; i < timestampByteLength; i++) ms = ms * 256 + buffer[i]!;\n return ms;\n}\n\n/** Decodes ms from the first 10 base32 chars of a payload suffix (partial decode). */\nexport function readTimestampMsFromBase32Suffix(base32Suffix: string): number {\n return readTimestampMs(decodeBase32(base32Suffix.slice(0, timestampBase32Length)));\n}\n","/** Default RNG: writes cryptographically random bytes via `crypto.getRandomValues`. */\nexport function defaultRng(target: Uint8Array): void {\n crypto.getRandomValues(target as Uint8Array<ArrayBuffer>);\n}\n\n// hex charCode → 0–15 nibble, for harvesting bytes out of a UUIDv4 string.\n// Covers ['0'-'9' = 48–57] and ['a'-'f' = 97–102]; randomUUID is lowercase per spec.\nconst hexCharCodeToNibble = new Uint8Array(128);\nfor (let i = 0; i < 10; i++) hexCharCodeToNibble[48 + i] = i;\nfor (let i = 0; i < 6; i++) hexCharCodeToNibble[97 + i] = 10 + i;\n\n/**\n * Fast RNG for the 10-byte random tail shared by the plaintext timestamp layouts\n * (Timestamp and Reverse Timestamp codecs). Writes exactly `target[0..9]`.\n *\n * `crypto.randomUUID()` is ~7× faster than `crypto.getRandomValues` in Node 24\n * (~84 ns vs ~610 ns for a 16-byte fill — the UUID path has a tight fixed-format\n * fast path). A UUIDv4 string carries 122 cryptographically-random bits; we\n * harvest 10 fully-random bytes from positions where no version (hex 12) or\n * variant (hex 16) bits sit. String layout: `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`\n * — bytes 0–5 are string[0..7]+string[9..12], bytes 6–9 are string[24..31].\n *\n * Security-equivalent to `defaultRng` for a 10-byte tail (both are CSPRNG-backed,\n * fully-random bytes); the only difference is throughput.\n */\nexport function fastTenByteRng(target: Uint8Array): void {\n const s = crypto.randomUUID();\n target[0] = (hexCharCodeToNibble[s.charCodeAt(0)]! << 4) | hexCharCodeToNibble[s.charCodeAt(1)]!;\n target[1] = (hexCharCodeToNibble[s.charCodeAt(2)]! << 4) | hexCharCodeToNibble[s.charCodeAt(3)]!;\n target[2] = (hexCharCodeToNibble[s.charCodeAt(4)]! << 4) | hexCharCodeToNibble[s.charCodeAt(5)]!;\n target[3] = (hexCharCodeToNibble[s.charCodeAt(6)]! << 4) | hexCharCodeToNibble[s.charCodeAt(7)]!;\n target[4] = (hexCharCodeToNibble[s.charCodeAt(9)]! << 4) | hexCharCodeToNibble[s.charCodeAt(10)]!;\n target[5] =\n (hexCharCodeToNibble[s.charCodeAt(11)]! << 4) | hexCharCodeToNibble[s.charCodeAt(12)]!;\n target[6] =\n (hexCharCodeToNibble[s.charCodeAt(24)]! << 4) | hexCharCodeToNibble[s.charCodeAt(25)]!;\n target[7] =\n (hexCharCodeToNibble[s.charCodeAt(26)]! << 4) | hexCharCodeToNibble[s.charCodeAt(27)]!;\n target[8] =\n (hexCharCodeToNibble[s.charCodeAt(28)]! << 4) | hexCharCodeToNibble[s.charCodeAt(29)]!;\n target[9] =\n (hexCharCodeToNibble[s.charCodeAt(30)]! << 4) | hexCharCodeToNibble[s.charCodeAt(31)]!;\n}\n"],"mappings":";AAMA,MAAM,wBAAgC,KAAK,KAAA,KAAiC,CAAC;;AAG7E,SAAgB,eAAe,IAAY,QAA0B;CACnE,IAAI,OAAO,MAAM,EAAE,GAAG,MAAM,IAAI,MAAM,2BAA2B;CACjE,IAAI,CAAC,OAAO,UAAU,EAAE,GAAG,MAAM,IAAI,MAAM,6BAA6B;CACxE,IAAI,KAAK,GAAG,MAAM,IAAI,MAAM,uBAAuB;CACnD,IAAI,MAAM,KAAA,IACR,MAAM,IAAI,MAAM,gCAAgC;CAElD,KAAK,IAAI,IAAA,GAA6B,KAAK,GAAG,KAAK;EACjD,OAAO,KAAK,KAAK;EACjB,KAAK,KAAK,MAAM,KAAK,GAAG;CAC1B;AACF;;AAGA,SAAgB,gBAAgB,QAA4B;CAC1D,IAAI,KAAK;CACT,KAAK,IAAI,IAAI,GAAG,IAAA,GAAyB,KAAK,KAAK,KAAK,MAAM,OAAO;CACrE,OAAO;AACT;;AAGA,SAAgB,gCAAgC,cAA8B;CAC5E,OAAO,gBAAgB,aAAa,aAAa,MAAM,GAAG,qBAAqB,CAAC,CAAC;AACnF;;;;AC/BA,SAAgB,WAAW,QAA0B;CACnD,OAAO,gBAAgB,MAAiC;AAC1D;AAIA,MAAM,sCAAsB,IAAI,WAAW,GAAG;AAC9C,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK,oBAAoB,KAAK,KAAK;AAC3D,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK,oBAAoB,KAAK,KAAK,KAAK;;;;;;;;;;;;;;;AAgB/D,SAAgB,eAAe,QAA0B;CACvD,MAAM,IAAI,OAAO,WAAW;CAC5B,OAAO,KAAM,oBAAoB,EAAE,WAAW,CAAC,MAAO,IAAK,oBAAoB,EAAE,WAAW,CAAC;CAC7F,OAAO,KAAM,oBAAoB,EAAE,WAAW,CAAC,MAAO,IAAK,oBAAoB,EAAE,WAAW,CAAC;CAC7F,OAAO,KAAM,oBAAoB,EAAE,WAAW,CAAC,MAAO,IAAK,oBAAoB,EAAE,WAAW,CAAC;CAC7F,OAAO,KAAM,oBAAoB,EAAE,WAAW,CAAC,MAAO,IAAK,oBAAoB,EAAE,WAAW,CAAC;CAC7F,OAAO,KAAM,oBAAoB,EAAE,WAAW,CAAC,MAAO,IAAK,oBAAoB,EAAE,WAAW,EAAE;CAC9F,OAAO,KACJ,oBAAoB,EAAE,WAAW,EAAE,MAAO,IAAK,oBAAoB,EAAE,WAAW,EAAE;CACrF,OAAO,KACJ,oBAAoB,EAAE,WAAW,EAAE,MAAO,IAAK,oBAAoB,EAAE,WAAW,EAAE;CACrF,OAAO,KACJ,oBAAoB,EAAE,WAAW,EAAE,MAAO,IAAK,oBAAoB,EAAE,WAAW,EAAE;CACrF,OAAO,KACJ,oBAAoB,EAAE,WAAW,EAAE,MAAO,IAAK,oBAAoB,EAAE,WAAW,EAAE;CACrF,OAAO,KACJ,oBAAoB,EAAE,WAAW,EAAE,MAAO,IAAK,oBAAoB,EAAE,WAAW,EAAE;AACvF"}
@@ -1,7 +1,7 @@
1
1
  import { t as IdsError } from "./error-Cp5qYZcv.mjs";
2
- import { a as toWireId, i as payloadBytesFromId, n as registerBrand, r as payloadBase32Length, s as validateBrand, t as wireMethods } from "./codec-shell-C2NKQEx2.mjs";
3
- import { a as writeTimestamp, i as readTimestampMsFromBase32Suffix, t as defaultRng } from "./rng-BHFxX1Fc.mjs";
4
- import { c as timingSafeEqual, i as encodeKeyMaterial, n as assertValidKeyring, o as deriveKey, r as decodeKeyMaterial, t as assertValidKeyMaterialByteLength } from "./key-material-DvjACe89.mjs";
2
+ import { a as toWireId, i as payloadBytesFromId, n as registerBrand, r as payloadBase32Length, s as validateBrand, t as wireMethods } from "./codec-shell-BRZkuQeP.mjs";
3
+ import { a as writeTimestamp, i as readTimestampMsFromBase32Suffix, t as defaultRng } from "./rng-6GyNT4zS.mjs";
4
+ import { c as timingSafeEqual, i as encodeKeyMaterial, n as assertValidKeyring, o as deriveKey, r as decodeKeyMaterial, t as assertValidKeyMaterialByteLength } from "./key-material-1wOKJ1o-.mjs";
5
5
  const tagByteLength = 5;
6
6
  const randomOffset = 6;
7
7
  const tagOffset = 11;
@@ -176,10 +176,13 @@ function createSignedTimestampId(brand, opts) {
176
176
  parse: wire.parse,
177
177
  safeParse: wire.safeParse,
178
178
  toJsonSchema: () => wire.toJsonSchema(brand, layout.exampleWireId()),
179
- "~standard": wire["~standard"]
179
+ "~standard": wire["~standard"],
180
+ toUUID: wire.toUUID,
181
+ fromUUID: wire.fromUUID,
182
+ safeFromUUID: wire.safeFromUUID
180
183
  };
181
184
  }
182
185
  //#endregion
183
186
  export { importSigningKey as i, decodeSigningKey as n, encodeSigningKey as r, createSignedTimestampId as t };
184
187
 
185
- //# sourceMappingURL=signed-BTz3ZFYE.mjs.map
188
+ //# sourceMappingURL=signed-Dkdteu1y.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"signed-BTz3ZFYE.mjs","names":[],"sources":["../src/codecs/signed/layout.ts","../src/codecs/signed/key.ts","../src/codecs/signed/index.ts"],"sourcesContent":["import type { webcrypto } from \"node:crypto\";\nimport type { Id, LayoutOps, Prefix } from \"../../types.js\";\nimport { timingSafeEqual } from \"../_kernel/crypto.js\";\nimport { payloadBytesFromId, toWireId } from \"../../wire/envelope.js\";\nimport { payloadBase32Length, payloadByteLength } from \"../../wire/invariants.js\";\nimport {\n readTimestampMsFromBase32Suffix,\n timestampByteLength,\n writeTimestamp,\n} from \"../../wire/timestamp-bytes.js\";\n\nconst randomByteLength = 5;\nconst tagByteLength = 5;\nconst randomOffset = timestampByteLength; // 6\nconst tagOffset = randomOffset + randomByteLength; // 11\nconst signedContentByteLength = randomOffset + randomByteLength; // 11 (ts6 ‖ rand5)\n\nasync function computeTag(\n hmacKey: webcrypto.CryptoKey,\n brandBytes: Uint8Array,\n signedContent: Uint8Array,\n): Promise<Uint8Array> {\n const message = new Uint8Array(brandBytes.length + signedContent.length);\n message.set(brandBytes, 0);\n message.set(signedContent, brandBytes.length);\n const signature = new Uint8Array(\n await crypto.subtle.sign(\"HMAC\", hmacKey, message as Uint8Array<ArrayBuffer>),\n );\n return signature.subarray(0, tagByteLength);\n}\n\nexport function createSignedTimestampLayoutOps<Brand extends string>(\n prefix: Prefix<Brand>,\n brand: Brand,\n rng: (target: Uint8Array) => void,\n hmacKeys: readonly webcrypto.CryptoKey[],\n): LayoutOps<Brand> & {\n generateAt(ms: number): Promise<Id<Brand>>;\n tryVerify(id: Id<Brand>): Promise<boolean>;\n extractTimestamp(id: Id<Brand>): Date;\n minIdForTime(ms: number): Id<Brand>;\n maxIdForTime(ms: number): Id<Brand>;\n} {\n const signKey = hmacKeys[0]!;\n const brandBytes = new TextEncoder().encode(brand);\n const syncBuffer = new Uint8Array(payloadByteLength);\n\n return {\n generateAt: async (ms: number): Promise<Id<Brand>> => {\n const buffer = new Uint8Array(payloadByteLength);\n writeTimestamp(ms, buffer);\n rng(buffer.subarray(randomOffset, tagOffset));\n const tag = await computeTag(\n signKey,\n brandBytes,\n buffer.subarray(0, signedContentByteLength),\n );\n buffer.set(tag, tagOffset);\n return toWireId(prefix, buffer);\n },\n tryVerify: async (id: Id<Brand>): Promise<boolean> => {\n const payload = payloadBytesFromId(prefix, id);\n const storedTag = payload.subarray(tagOffset, payloadByteLength);\n const signedContent = payload.subarray(0, signedContentByteLength);\n for (const hmacKey of hmacKeys) {\n const expected = await computeTag(hmacKey, brandBytes, signedContent);\n if (timingSafeEqual(storedTag, expected)) return true;\n }\n return false;\n },\n extractTimestamp: (id: Id<Brand>): Date =>\n new Date(readTimestampMsFromBase32Suffix(id.slice(prefix.length))),\n minIdForTime: (ms: number): Id<Brand> => {\n writeTimestamp(ms, syncBuffer);\n syncBuffer.fill(0x00, randomOffset, payloadByteLength);\n return toWireId(prefix, syncBuffer);\n },\n maxIdForTime: (ms: number): Id<Brand> => {\n writeTimestamp(ms, syncBuffer);\n syncBuffer.fill(0xff, randomOffset, payloadByteLength);\n return toWireId(prefix, syncBuffer);\n },\n exampleWireId: (_ms?: number): Id<Brand> =>\n (prefix + \"0\".repeat(payloadBase32Length)) as Id<Brand>,\n };\n}\n","import type { webcrypto } from \"node:crypto\";\nimport { deriveKey, timingSafeEqual } from \"../_kernel/crypto.js\";\nimport {\n assertValidKeyMaterialByteLength,\n assertValidKeyring,\n decodeKeyMaterial,\n encodeKeyMaterial,\n} from \"../_kernel/key-material.js\";\n\nexport { assertValidKeyring };\n\n/** Wire encoding for signing key raw key bytes (not Crockford base32). */\nexport type SigningKeyFormat = \"hex\" | \"base64url\";\n\nconst hmacInfo = new TextEncoder().encode(\"@smonn/ids/signed/hmac\");\n\ndeclare const signingKeyBrand: unique symbol;\n\n/**\n * Opaque imported handle for one operator signing key.\n *\n * Holds a single HMAC-SHA-256 key derived via HKDF under the domain-separation\n * label `@smonn/ids/signed/hmac`. The underlying `webcrypto.CryptoKey` is held\n * internally and never exposed to callers. Obtain handles via\n * {@link importSigningKey} and pass them to `createSignedTimestampId` as the\n * `keys` signing keyring.\n *\n * Distinct from both the **Opaque key** and the **Wrapping key** — the same\n * raw key material must not silently serve multiple codecs without an explicit import.\n */\nexport type SigningKey = {\n readonly [signingKeyBrand]: \"SigningKey\";\n};\n\ntype SigningKeyInternals = {\n keyDigest: Uint8Array;\n hmacKey: webcrypto.CryptoKey;\n};\n\nconst internals = new WeakMap<SigningKey, SigningKeyInternals>();\n\n/**\n * Import raw operator key material into a {@link SigningKey} handle.\n *\n * Derives a single HMAC-SHA-256 key via HKDF under the domain-separation label\n * `@smonn/ids/signed/hmac`. Accepts 16, 24, or 32 bytes. To store or\n * transport key material, use {@link encodeSigningKey} / {@link decodeSigningKey}\n * (`\"hex\"` or `\"base64url\"` — not Crockford base32).\n *\n * @param bytes - 16, 24, or 32 raw key bytes.\n * @throws {IdsError} `invalid_key_length` if `bytes.length` is not 16, 24, or 32.\n */\nexport async function importSigningKey(bytes: Uint8Array): Promise<SigningKey> {\n assertValidKeyMaterialByteLength(bytes.length, \"signing\");\n const [hmacKey, digestBuffer] = await Promise.all([\n deriveKey(bytes, hmacInfo, { name: \"HMAC\", hash: \"SHA-256\", length: 256 }, [\"sign\", \"verify\"]),\n crypto.subtle.digest(\"SHA-256\", bytes as Uint8Array<ArrayBuffer>),\n ]);\n const key = Object.freeze({}) as SigningKey;\n internals.set(key, { keyDigest: new Uint8Array(digestBuffer), hmacKey });\n return key;\n}\n\n/**\n * Encode raw signing operator key material for storage in env vars or secret managers.\n *\n * Supports `\"hex\"` (lowercase) and `\"base64url\"`. Output round-trips through\n * {@link decodeSigningKey} back to the original bytes.\n *\n * @throws {IdsError} `invalid_key_format` if `format` is not `\"hex\"` or `\"base64url\"`.\n * @throws {IdsError} `invalid_key_length` if `bytes.length` is not 16, 24, or 32.\n */\nexport function encodeSigningKey(bytes: Uint8Array, format: SigningKeyFormat): string {\n return encodeKeyMaterial(bytes, format, \"signing\", \"signing\");\n}\n\n/**\n * Decode key material emitted by {@link encodeSigningKey} back to raw bytes.\n *\n * The result can be passed directly to {@link importSigningKey}.\n *\n * @throws {IdsError} `invalid_key_format` if `format` is not `\"hex\"` or `\"base64url\"`.\n * @throws {IdsError} `invalid_key_encoding` if the string is malformed for its format.\n * @throws {IdsError} `invalid_key_length` if the decoded bytes are not 16, 24, or 32 bytes.\n */\nexport function decodeSigningKey(encoded: string, format: SigningKeyFormat): Uint8Array {\n return decodeKeyMaterial(encoded, format, \"signing\", \"signing\");\n}\n\n/**\n * Returns true when two handles were imported from the same raw key material.\n *\n * Uses a constant-time comparison so duplicate detection over key material does\n * not leak the position of the first differing byte through a timing side channel.\n */\nexport function signingKeysEqual(a: SigningKey, b: SigningKey): boolean {\n return timingSafeEqual(getSigningKeyInternals(a).keyDigest, getSigningKeyInternals(b).keyDigest);\n}\n\n/**\n * Returns the derived HMAC webcrypto.CryptoKey held inside the handle.\n *\n * Intentional module-internal escape hatch for codec implementations (e.g. `createSignedTimestampId`).\n * Not re-exported from `@smonn/ids/signed`; external callers cannot reach this.\n */\nexport function getSigningKeyHmacKey(key: SigningKey): webcrypto.CryptoKey {\n return getSigningKeyInternals(key).hmacKey;\n}\n\nfunction getSigningKeyInternals(key: SigningKey): SigningKeyInternals {\n const keyInternals = internals.get(key);\n if (keyInternals === undefined) {\n throw new Error(\"invalid signing key\");\n }\n return keyInternals;\n}\n","import { validateBrand } from \"../_kernel/brand.js\";\nimport { IdsError } from \"../../error.js\";\nimport { createSignedTimestampLayoutOps } from \"./layout.js\";\nimport { registerBrand } from \"../_kernel/registry.js\";\nimport { defaultRng } from \"../_kernel/rng.js\";\nimport type {\n Id,\n JsonSchema,\n ParseError,\n ParseResult,\n Prefix,\n StandardSchemaProps,\n ValidBrand,\n} from \"../../types.js\";\nimport { wireMethods } from \"../../wire/codec-shell.js\";\nimport {\n assertValidKeyring,\n decodeSigningKey,\n encodeSigningKey,\n getSigningKeyHmacKey,\n importSigningKey,\n signingKeysEqual,\n type SigningKey,\n type SigningKeyFormat,\n} from \"./key.js\";\n\n/** {@link IdsError} class, {@link isIdsError} type guard, and {@link IdsErrorCode} union — re-exported from `\"@smonn/ids\"` for convenience. */\nexport { IdsError, isIdsError, type IdsErrorCode } from \"../../error.js\";\nexport {\n decodeSigningKey,\n encodeSigningKey,\n importSigningKey,\n type SigningKey,\n type SigningKeyFormat,\n};\n\n/**\n * Configuration options for a Signed Timestamp codec instance.\n */\nexport type SignedTimestampOptions = {\n /**\n * Non-empty ordered signing keyring. The first entry is current — the only one\n * `generate` / `generateAt` sign with. `verify` / `safeVerify` trial every entry\n * until the tag matches. Duplicate raw secrets are rejected at construction.\n */\n keys: [SigningKey, ...SigningKey[]];\n /** Returns the current timestamp in milliseconds. Defaults to `Date.now`. */\n now?: () => number;\n /** Writes 5 random bytes into `target` for the random tail. Defaults to `crypto.getRandomValues`. */\n rng?: (target: Uint8Array) => void;\n /** If true, silences the duplicate-brand warning in non-production environments. */\n allowDuplicateBrand?: boolean;\n};\n\n/**\n * Result returned by {@link SignedTimestampCodec.safeVerify}.\n *\n * On success, `id` is the canonical {@link Id}.\n * On failure, `error` is a {@link ParseError} for structural problems or\n * `\"verification_failed\"` when the HMAC tag does not match any entry in the\n * signing keyring.\n */\nexport type SafeVerifyResult<Brand extends string> =\n | { ok: true; id: Id<Brand> }\n | { ok: false; error: ParseError | \"verification_failed\" };\n\n/**\n * Codec returned by {@link createSignedTimestampId}.\n *\n * Keeps the 6-byte millisecond timestamp **readable and sortable** like the\n * Timestamp codec, but replaces half of the 10-byte random tail with a truncated\n * HMAC tag, making IDs **tamper-evident and verifiable without a database lookup**.\n *\n * Byte layout: `ts6 ‖ rand5 ‖ tag5` where the 40-bit tag =\n * `trunc(HMAC-SHA256(hmacKey, brand ‖ ts6 ‖ rand5), 40)`.\n *\n * - Async (HMAC): `generate`, `generateAt`, `verify`, `safeVerify`.\n * - Sync (no key / plaintext timestamp): all other methods.\n */\nexport type SignedTimestampCodec<Brand extends string> = {\n /** Produces a canonical ID signed with the current (first) key. */\n generate(): Promise<Id<Brand>>;\n /**\n * Produces a canonical ID with timestamp from `date`, signed with the current key.\n * Throws on invalid dates.\n */\n generateAt(date: Date): Promise<Id<Brand>>;\n /**\n * Recomputes the HMAC tag across every keyring entry.\n *\n * Throws `IdsError` with `code: \"verification_failed\"` if no entry matches.\n * Tamper of the brand, timestamp bytes, or random bytes all fail here.\n */\n verify(id: Id<Brand>): Promise<void>;\n /**\n * Non-throwing path for untrusted input.\n *\n * Structurally parses `input` first (same rules as {@link safeParse}), then\n * verifies the HMAC tag. Returns `{ ok: false, error }` on any failure —\n * {@link ParseError} for structural problems or `\"verification_failed\"` for tag\n * mismatch — without throwing.\n */\n safeVerify(input: unknown): Promise<SafeVerifyResult<Brand>>;\n /**\n * Decodes the creation `Date` from an `Id<Brand>`.\n * Sync — the 6-byte timestamp is plaintext. Trusts the type; use `safeParse()` at boundaries first.\n *\n * Best-effort: the timestamp is returned **without checking the HMAC tag** — a tampered\n * or unsigned ID yields the attacker-controlled timestamp without error. Call\n * `verify()` / `safeVerify()` first if you need an authenticated timestamp.\n */\n extractTimestamp(id: Id<Brand>): Date;\n /**\n * Tight lower bound sentinel for range scans (`ts(t) ‖ 0x00×10`).\n * **Not verifiable** — carries no valid tag.\n */\n minIdForTime(date: Date): Id<Brand>;\n /**\n * Tight upper bound sentinel for range scans (`ts(t) ‖ 0xff×10`).\n * **Not verifiable** — carries no valid tag.\n */\n maxIdForTime(date: Date): Id<Brand>;\n /**\n * Strict type guard: `true` only for already-canonical `Id<Brand>` strings.\n * For untrusted input, use `safeParse()` or `safeVerify()` instead.\n */\n is(value: unknown): value is Id<Brand>;\n /** Normalise to canonical form, or throw on parse failure. */\n parse(value: unknown): Id<Brand>;\n /** Normalise to canonical form, or return `{ ok: false, error }`. */\n safeParse(value: unknown): ParseResult<Brand>;\n /**\n * JSON Schema for the canonical wire form. The `pattern` matches the canonical stored\n * form only and is deliberately stricter than `parse()`/`safeParse()`, which accept\n * uppercase letters and Crockford aliases (`o`/`i`/`l`) before normalising. See ADR-0003.\n */\n toJsonSchema(): JsonSchema;\n /** Standard Schema validate entry point. */\n readonly \"~standard\": StandardSchemaProps<Brand>;\n};\n\n/**\n * Construct a {@link SignedTimestampCodec} for `brand`.\n *\n * `opts.keys` is a non-empty ordered signing keyring — the first entry is current\n * (used by `generate` / `generateAt`); all entries are tried on `verify` /\n * `safeVerify`; duplicate operator secrets are rejected at construction.\n *\n * @example\n * ```ts\n * const key = await importSigningKey(new Uint8Array(32));\n * const usr = createSignedTimestampId(\"usr\", { keys: [key] });\n *\n * const id = await usr.generate(); // Id<\"usr\">\n * await usr.verify(id); // passes\n * usr.extractTimestamp(id); // Date — sync, timestamp is plaintext\n * ```\n */\nexport function createSignedTimestampId<Brand extends string>(\n brand: Brand & ValidBrand<Brand>,\n opts: SignedTimestampOptions,\n): SignedTimestampCodec<Brand> {\n validateBrand(brand);\n registerBrand(brand, opts.allowDuplicateBrand);\n assertValidKeyring(opts.keys, signingKeysEqual, \"signing\");\n\n const hmacKeys = opts.keys.map(getSigningKeyHmacKey);\n const now = opts.now ?? Date.now;\n const rng = opts.rng ?? defaultRng;\n const prefix: Prefix<Brand> = `${brand}_`;\n const wire = wireMethods(prefix);\n const layout = createSignedTimestampLayoutOps(prefix, brand, rng, hmacKeys);\n\n return {\n generate: () => layout.generateAt(now()),\n generateAt: (date: Date) => layout.generateAt(date.getTime()),\n verify: async (id) => {\n const ok = await layout.tryVerify(id);\n if (!ok) throw new IdsError(\"verification_failed\", \"verification failed\");\n },\n safeVerify: async (input) => {\n const parsed = wire.safeParse(input);\n if (!parsed.ok) return parsed;\n const ok = await layout.tryVerify(parsed.id);\n if (!ok) return { ok: false, error: \"verification_failed\" };\n return { ok: true, id: parsed.id };\n },\n extractTimestamp: layout.extractTimestamp,\n minIdForTime: (date: Date) => layout.minIdForTime(date.getTime()),\n maxIdForTime: (date: Date) => layout.maxIdForTime(date.getTime()),\n is: wire.is,\n parse: wire.parse,\n safeParse: wire.safeParse,\n toJsonSchema: () => wire.toJsonSchema(brand, layout.exampleWireId()),\n \"~standard\": wire[\"~standard\"],\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"signed-Dkdteu1y.mjs","names":[],"sources":["../src/codecs/signed/layout.ts","../src/codecs/signed/key.ts","../src/codecs/signed/index.ts"],"sourcesContent":["import type { webcrypto } from \"node:crypto\";\nimport type { Id, LayoutOps, Prefix } from \"../../types.js\";\nimport { timingSafeEqual } from \"../_kernel/crypto.js\";\nimport { payloadBytesFromId, toWireId } from \"../../wire/envelope.js\";\nimport { payloadBase32Length, payloadByteLength } from \"../../wire/invariants.js\";\nimport {\n readTimestampMsFromBase32Suffix,\n timestampByteLength,\n writeTimestamp,\n} from \"../../wire/timestamp-bytes.js\";\n\nconst randomByteLength = 5;\nconst tagByteLength = 5;\nconst randomOffset = timestampByteLength; // 6\nconst tagOffset = randomOffset + randomByteLength; // 11\nconst signedContentByteLength = randomOffset + randomByteLength; // 11 (ts6 ‖ rand5)\n\nasync function computeTag(\n hmacKey: webcrypto.CryptoKey,\n brandBytes: Uint8Array,\n signedContent: Uint8Array,\n): Promise<Uint8Array> {\n const message = new Uint8Array(brandBytes.length + signedContent.length);\n message.set(brandBytes, 0);\n message.set(signedContent, brandBytes.length);\n const signature = new Uint8Array(\n await crypto.subtle.sign(\"HMAC\", hmacKey, message as Uint8Array<ArrayBuffer>),\n );\n return signature.subarray(0, tagByteLength);\n}\n\nexport function createSignedTimestampLayoutOps<Brand extends string>(\n prefix: Prefix<Brand>,\n brand: Brand,\n rng: (target: Uint8Array) => void,\n hmacKeys: readonly webcrypto.CryptoKey[],\n): LayoutOps<Brand> & {\n generateAt(ms: number): Promise<Id<Brand>>;\n tryVerify(id: Id<Brand>): Promise<boolean>;\n extractTimestamp(id: Id<Brand>): Date;\n minIdForTime(ms: number): Id<Brand>;\n maxIdForTime(ms: number): Id<Brand>;\n} {\n const signKey = hmacKeys[0]!;\n const brandBytes = new TextEncoder().encode(brand);\n const syncBuffer = new Uint8Array(payloadByteLength);\n\n return {\n generateAt: async (ms: number): Promise<Id<Brand>> => {\n const buffer = new Uint8Array(payloadByteLength);\n writeTimestamp(ms, buffer);\n rng(buffer.subarray(randomOffset, tagOffset));\n const tag = await computeTag(\n signKey,\n brandBytes,\n buffer.subarray(0, signedContentByteLength),\n );\n buffer.set(tag, tagOffset);\n return toWireId(prefix, buffer);\n },\n tryVerify: async (id: Id<Brand>): Promise<boolean> => {\n const payload = payloadBytesFromId(prefix, id);\n const storedTag = payload.subarray(tagOffset, payloadByteLength);\n const signedContent = payload.subarray(0, signedContentByteLength);\n for (const hmacKey of hmacKeys) {\n const expected = await computeTag(hmacKey, brandBytes, signedContent);\n if (timingSafeEqual(storedTag, expected)) return true;\n }\n return false;\n },\n extractTimestamp: (id: Id<Brand>): Date =>\n new Date(readTimestampMsFromBase32Suffix(id.slice(prefix.length))),\n minIdForTime: (ms: number): Id<Brand> => {\n writeTimestamp(ms, syncBuffer);\n syncBuffer.fill(0x00, randomOffset, payloadByteLength);\n return toWireId(prefix, syncBuffer);\n },\n maxIdForTime: (ms: number): Id<Brand> => {\n writeTimestamp(ms, syncBuffer);\n syncBuffer.fill(0xff, randomOffset, payloadByteLength);\n return toWireId(prefix, syncBuffer);\n },\n exampleWireId: (_ms?: number): Id<Brand> =>\n (prefix + \"0\".repeat(payloadBase32Length)) as Id<Brand>,\n };\n}\n","import type { webcrypto } from \"node:crypto\";\nimport { deriveKey, timingSafeEqual } from \"../_kernel/crypto.js\";\nimport {\n assertValidKeyMaterialByteLength,\n assertValidKeyring,\n decodeKeyMaterial,\n encodeKeyMaterial,\n} from \"../_kernel/key-material.js\";\n\nexport { assertValidKeyring };\n\n/** Wire encoding for signing key raw key bytes (not Crockford base32). */\nexport type SigningKeyFormat = \"hex\" | \"base64url\";\n\nconst hmacInfo = new TextEncoder().encode(\"@smonn/ids/signed/hmac\");\n\ndeclare const signingKeyBrand: unique symbol;\n\n/**\n * Opaque imported handle for one operator signing key.\n *\n * Holds a single HMAC-SHA-256 key derived via HKDF under the domain-separation\n * label `@smonn/ids/signed/hmac`. The underlying `webcrypto.CryptoKey` is held\n * internally and never exposed to callers. Obtain handles via\n * {@link importSigningKey} and pass them to `createSignedTimestampId` as the\n * `keys` signing keyring.\n *\n * Distinct from both the **Opaque key** and the **Wrapping key** — the same\n * raw key material must not silently serve multiple codecs without an explicit import.\n */\nexport type SigningKey = {\n readonly [signingKeyBrand]: \"SigningKey\";\n};\n\ntype SigningKeyInternals = {\n keyDigest: Uint8Array;\n hmacKey: webcrypto.CryptoKey;\n};\n\nconst internals = new WeakMap<SigningKey, SigningKeyInternals>();\n\n/**\n * Import raw operator key material into a {@link SigningKey} handle.\n *\n * Derives a single HMAC-SHA-256 key via HKDF under the domain-separation label\n * `@smonn/ids/signed/hmac`. Accepts 16, 24, or 32 bytes. To store or\n * transport key material, use {@link encodeSigningKey} / {@link decodeSigningKey}\n * (`\"hex\"` or `\"base64url\"` — not Crockford base32).\n *\n * @param bytes - 16, 24, or 32 raw key bytes.\n * @throws {IdsError} `invalid_key_length` if `bytes.length` is not 16, 24, or 32.\n */\nexport async function importSigningKey(bytes: Uint8Array): Promise<SigningKey> {\n assertValidKeyMaterialByteLength(bytes.length, \"signing\");\n const [hmacKey, digestBuffer] = await Promise.all([\n deriveKey(bytes, hmacInfo, { name: \"HMAC\", hash: \"SHA-256\", length: 256 }, [\"sign\", \"verify\"]),\n crypto.subtle.digest(\"SHA-256\", bytes as Uint8Array<ArrayBuffer>),\n ]);\n const key = Object.freeze({}) as SigningKey;\n internals.set(key, { keyDigest: new Uint8Array(digestBuffer), hmacKey });\n return key;\n}\n\n/**\n * Encode raw signing operator key material for storage in env vars or secret managers.\n *\n * Supports `\"hex\"` (lowercase) and `\"base64url\"`. Output round-trips through\n * {@link decodeSigningKey} back to the original bytes.\n *\n * @throws {IdsError} `invalid_key_format` if `format` is not `\"hex\"` or `\"base64url\"`.\n * @throws {IdsError} `invalid_key_length` if `bytes.length` is not 16, 24, or 32.\n */\nexport function encodeSigningKey(bytes: Uint8Array, format: SigningKeyFormat): string {\n return encodeKeyMaterial(bytes, format, \"signing\", \"signing\");\n}\n\n/**\n * Decode key material emitted by {@link encodeSigningKey} back to raw bytes.\n *\n * The result can be passed directly to {@link importSigningKey}.\n *\n * @throws {IdsError} `invalid_key_format` if `format` is not `\"hex\"` or `\"base64url\"`.\n * @throws {IdsError} `invalid_key_encoding` if the string is malformed for its format.\n * @throws {IdsError} `invalid_key_length` if the decoded bytes are not 16, 24, or 32 bytes.\n */\nexport function decodeSigningKey(encoded: string, format: SigningKeyFormat): Uint8Array {\n return decodeKeyMaterial(encoded, format, \"signing\", \"signing\");\n}\n\n/**\n * Returns true when two handles were imported from the same raw key material.\n *\n * Uses a constant-time comparison so duplicate detection over key material does\n * not leak the position of the first differing byte through a timing side channel.\n */\nexport function signingKeysEqual(a: SigningKey, b: SigningKey): boolean {\n return timingSafeEqual(getSigningKeyInternals(a).keyDigest, getSigningKeyInternals(b).keyDigest);\n}\n\n/**\n * Returns the derived HMAC webcrypto.CryptoKey held inside the handle.\n *\n * Intentional module-internal escape hatch for codec implementations (e.g. `createSignedTimestampId`).\n * Not re-exported from `@smonn/ids/signed`; external callers cannot reach this.\n */\nexport function getSigningKeyHmacKey(key: SigningKey): webcrypto.CryptoKey {\n return getSigningKeyInternals(key).hmacKey;\n}\n\nfunction getSigningKeyInternals(key: SigningKey): SigningKeyInternals {\n const keyInternals = internals.get(key);\n if (keyInternals === undefined) {\n throw new Error(\"invalid signing key\");\n }\n return keyInternals;\n}\n","import { validateBrand } from \"../_kernel/brand.js\";\nimport { IdsError } from \"../../error.js\";\nimport { createSignedTimestampLayoutOps } from \"./layout.js\";\nimport { registerBrand } from \"../_kernel/registry.js\";\nimport { defaultRng } from \"../_kernel/rng.js\";\nimport type {\n Id,\n JsonSchema,\n ParseError,\n ParseResult,\n Prefix,\n StandardSchemaProps,\n ValidBrand,\n} from \"../../types.js\";\nimport { wireMethods } from \"../../wire/codec-shell.js\";\nimport {\n assertValidKeyring,\n decodeSigningKey,\n encodeSigningKey,\n getSigningKeyHmacKey,\n importSigningKey,\n signingKeysEqual,\n type SigningKey,\n type SigningKeyFormat,\n} from \"./key.js\";\n\n/** {@link IdsError} class, {@link isIdsError} type guard, and {@link IdsErrorCode} union — re-exported from `\"@smonn/ids\"` for convenience. */\nexport { IdsError, isIdsError, type IdsErrorCode } from \"../../error.js\";\nexport {\n decodeSigningKey,\n encodeSigningKey,\n importSigningKey,\n type SigningKey,\n type SigningKeyFormat,\n};\n\n/**\n * Configuration options for a Signed Timestamp codec instance.\n */\nexport type SignedTimestampOptions = {\n /**\n * Non-empty ordered signing keyring. The first entry is current — the only one\n * `generate` / `generateAt` sign with. `verify` / `safeVerify` trial every entry\n * until the tag matches. Duplicate raw secrets are rejected at construction.\n */\n keys: [SigningKey, ...SigningKey[]];\n /** Returns the current timestamp in milliseconds. Defaults to `Date.now`. */\n now?: () => number;\n /** Writes 5 random bytes into `target` for the random tail. Defaults to `crypto.getRandomValues`. */\n rng?: (target: Uint8Array) => void;\n /** If true, silences the duplicate-brand warning in non-production environments. */\n allowDuplicateBrand?: boolean;\n};\n\n/**\n * Result returned by {@link SignedTimestampCodec.safeVerify}.\n *\n * On success, `id` is the canonical {@link Id}.\n * On failure, `error` is a {@link ParseError} for structural problems or\n * `\"verification_failed\"` when the HMAC tag does not match any entry in the\n * signing keyring.\n */\nexport type SafeVerifyResult<Brand extends string> =\n | { ok: true; id: Id<Brand> }\n | { ok: false; error: ParseError | \"verification_failed\" };\n\n/**\n * Codec returned by {@link createSignedTimestampId}.\n *\n * Keeps the 6-byte millisecond timestamp **readable and sortable** like the\n * Timestamp codec, but replaces half of the 10-byte random tail with a truncated\n * HMAC tag, making IDs **tamper-evident and verifiable without a database lookup**.\n *\n * Byte layout: `ts6 ‖ rand5 ‖ tag5` where the 40-bit tag =\n * `trunc(HMAC-SHA256(hmacKey, brand ‖ ts6 ‖ rand5), 40)`.\n *\n * - Async (HMAC): `generate`, `generateAt`, `verify`, `safeVerify`.\n * - Sync (no key / plaintext timestamp): all other methods.\n */\nexport type SignedTimestampCodec<Brand extends string> = {\n /** Produces a canonical ID signed with the current (first) key. */\n generate(): Promise<Id<Brand>>;\n /**\n * Produces a canonical ID with timestamp from `date`, signed with the current key.\n * Throws on invalid dates.\n */\n generateAt(date: Date): Promise<Id<Brand>>;\n /**\n * Recomputes the HMAC tag across every keyring entry.\n *\n * Throws `IdsError` with `code: \"verification_failed\"` if no entry matches.\n * Tamper of the brand, timestamp bytes, or random bytes all fail here.\n */\n verify(id: Id<Brand>): Promise<void>;\n /**\n * Non-throwing path for untrusted input.\n *\n * Structurally parses `input` first (same rules as {@link safeParse}), then\n * verifies the HMAC tag. Returns `{ ok: false, error }` on any failure —\n * {@link ParseError} for structural problems or `\"verification_failed\"` for tag\n * mismatch — without throwing.\n */\n safeVerify(input: unknown): Promise<SafeVerifyResult<Brand>>;\n /**\n * Decodes the creation `Date` from an `Id<Brand>`.\n * Sync — the 6-byte timestamp is plaintext. Trusts the type; use `safeParse()` at boundaries first.\n *\n * Best-effort: the timestamp is returned **without checking the HMAC tag** — a tampered\n * or unsigned ID yields the attacker-controlled timestamp without error. Call\n * `verify()` / `safeVerify()` first if you need an authenticated timestamp.\n */\n extractTimestamp(id: Id<Brand>): Date;\n /**\n * Tight lower bound sentinel for range scans (`ts(t) ‖ 0x00×10`).\n * **Not verifiable** — carries no valid tag.\n */\n minIdForTime(date: Date): Id<Brand>;\n /**\n * Tight upper bound sentinel for range scans (`ts(t) ‖ 0xff×10`).\n * **Not verifiable** — carries no valid tag.\n */\n maxIdForTime(date: Date): Id<Brand>;\n /**\n * Strict type guard: `true` only for already-canonical `Id<Brand>` strings.\n * For untrusted input, use `safeParse()` or `safeVerify()` instead.\n */\n is(value: unknown): value is Id<Brand>;\n /** Normalise to canonical form, or throw on parse failure. */\n parse(value: unknown): Id<Brand>;\n /** Normalise to canonical form, or return `{ ok: false, error }`. */\n safeParse(value: unknown): ParseResult<Brand>;\n /**\n * JSON Schema for the canonical wire form. The `pattern` matches the canonical stored\n * form only and is deliberately stricter than `parse()`/`safeParse()`, which accept\n * uppercase letters and Crockford aliases (`o`/`i`/`l`) before normalising. See ADR-0003.\n */\n toJsonSchema(): JsonSchema;\n /** Standard Schema validate entry point. */\n readonly \"~standard\": StandardSchemaProps<Brand>;\n /**\n * Converts a trusted `Id<Brand>` to an RFC 9562 canonical (lowercase, hyphenated)\n * UUID string by reinterpreting the 16-byte payload verbatim. Total — cannot fail.\n * Returns a plain `string` (brand is shed). See ADR-0024.\n */\n toUUID(id: Id<Brand>): string;\n /**\n * Parses a UUID string into an `Id<Brand>`. Accepts case-insensitive `8-4-4-4-12`\n * hyphenated form only. Throws `IdsError` with `code: \"invalid_id\"` on bad input.\n * See ADR-0024.\n */\n fromUUID(value: string): Id<Brand>;\n /**\n * Non-throwing UUID parse. Returns `{ ok: true, id }` or\n * `{ ok: false, error: \"not_string\" | \"invalid_uuid\" }`. See ADR-0024.\n */\n safeFromUUID(value: unknown): ParseResult<Brand>;\n};\n\n/**\n * Construct a {@link SignedTimestampCodec} for `brand`.\n *\n * `opts.keys` is a non-empty ordered signing keyring — the first entry is current\n * (used by `generate` / `generateAt`); all entries are tried on `verify` /\n * `safeVerify`; duplicate operator secrets are rejected at construction.\n *\n * @example\n * ```ts\n * const key = await importSigningKey(new Uint8Array(32));\n * const usr = createSignedTimestampId(\"usr\", { keys: [key] });\n *\n * const id = await usr.generate(); // Id<\"usr\">\n * await usr.verify(id); // passes\n * usr.extractTimestamp(id); // Date — sync, timestamp is plaintext\n * ```\n */\nexport function createSignedTimestampId<Brand extends string>(\n brand: Brand & ValidBrand<Brand>,\n opts: SignedTimestampOptions,\n): SignedTimestampCodec<Brand> {\n validateBrand(brand);\n registerBrand(brand, opts.allowDuplicateBrand);\n assertValidKeyring(opts.keys, signingKeysEqual, \"signing\");\n\n const hmacKeys = opts.keys.map(getSigningKeyHmacKey);\n const now = opts.now ?? Date.now;\n const rng = opts.rng ?? defaultRng;\n const prefix: Prefix<Brand> = `${brand}_`;\n const wire = wireMethods(prefix);\n const layout = createSignedTimestampLayoutOps(prefix, brand, rng, hmacKeys);\n\n return {\n generate: () => layout.generateAt(now()),\n generateAt: (date: Date) => layout.generateAt(date.getTime()),\n verify: async (id) => {\n const ok = await layout.tryVerify(id);\n if (!ok) throw new IdsError(\"verification_failed\", \"verification failed\");\n },\n safeVerify: async (input) => {\n const parsed = wire.safeParse(input);\n if (!parsed.ok) return parsed;\n const ok = await layout.tryVerify(parsed.id);\n if (!ok) return { ok: false, error: \"verification_failed\" };\n return { ok: true, id: parsed.id };\n },\n extractTimestamp: layout.extractTimestamp,\n minIdForTime: (date: Date) => layout.minIdForTime(date.getTime()),\n maxIdForTime: (date: Date) => layout.maxIdForTime(date.getTime()),\n is: wire.is,\n parse: wire.parse,\n safeParse: wire.safeParse,\n toJsonSchema: () => wire.toJsonSchema(brand, layout.exampleWireId()),\n \"~standard\": wire[\"~standard\"],\n toUUID: wire.toUUID,\n fromUUID: wire.fromUUID,\n safeFromUUID: wire.safeFromUUID,\n };\n}\n"],"mappings":"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"}
package/dist/signed.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { a as StandardSchemaProps, i as ParseResult, n as JsonSchema, o as ValidBrand, r as ParseError, t as Id } from "./types-wplmOgOK.mjs";
2
- import { n as IdsErrorCode, r as isIdsError, t as IdsError } from "./error-Dqyho9vp.mjs";
1
+ import { a as StandardSchemaProps, i as ParseResult, n as JsonSchema, o as ValidBrand, r as ParseError, t as Id } from "./types-hGBnCpJj.mjs";
2
+ import { n as IdsErrorCode, r as isIdsError, t as IdsError } from "./error-CifcKKOG.mjs";
3
3
 
4
4
  //#region src/codecs/signed/key.d.ts
5
5
  /** Wire encoding for signing key raw key bytes (not Crockford base32). */
@@ -152,6 +152,23 @@ type SignedTimestampCodec<Brand extends string> = {
152
152
  */
153
153
  toJsonSchema(): JsonSchema; /** Standard Schema validate entry point. */
154
154
  readonly "~standard": StandardSchemaProps<Brand>;
155
+ /**
156
+ * Converts a trusted `Id<Brand>` to an RFC 9562 canonical (lowercase, hyphenated)
157
+ * UUID string by reinterpreting the 16-byte payload verbatim. Total — cannot fail.
158
+ * Returns a plain `string` (brand is shed). See ADR-0024.
159
+ */
160
+ toUUID(id: Id<Brand>): string;
161
+ /**
162
+ * Parses a UUID string into an `Id<Brand>`. Accepts case-insensitive `8-4-4-4-12`
163
+ * hyphenated form only. Throws `IdsError` with `code: "invalid_id"` on bad input.
164
+ * See ADR-0024.
165
+ */
166
+ fromUUID(value: string): Id<Brand>;
167
+ /**
168
+ * Non-throwing UUID parse. Returns `{ ok: true, id }` or
169
+ * `{ ok: false, error: "not_string" | "invalid_uuid" }`. See ADR-0024.
170
+ */
171
+ safeFromUUID(value: unknown): ParseResult<Brand>;
155
172
  };
156
173
  /**
157
174
  * Construct a {@link SignedTimestampCodec} for `brand`.
@@ -1 +1 @@
1
- {"version":3,"file":"signed.d.mts","names":[],"sources":["../src/codecs/signed/key.ts","../src/codecs/signed/index.ts"],"mappings":";;;;;KAYY,gBAAA;AAAA,cAIE,eAAA;;;AAJF;AAA2B;;;;AAIzB;AAcd;;;;KAAY,UAAA;EAAA,UACA,eAAA;AAAA;;;;;;;;;;;;iBAqBU,gBAAA,CAAiB,KAAA,EAAO,UAAA,GAAa,OAAA,CAAQ,UAAA;AAoBnE;;;;;;;;;AAAA,iBAAgB,gBAAA,CAAiB,KAAA,EAAO,UAAA,EAAY,MAAA,EAAQ,gBAAA;AAa5D;;;;;;;;;AAAA,iBAAgB,gBAAA,CAAiB,OAAA,UAAiB,MAAA,EAAQ,gBAAA,GAAmB,UAAA;;;;;;KC9CjE,sBAAA;ED3B2B;;;;AAIzB;EC6BZ,IAAA,GAAO,UAAA,KAAe,UAAA,KDfZ;ECiBV,GAAA,iBDhBU;ECkBV,GAAA,IAAO,MAAA,EAAQ,UAAA,WDGjB;ECDE,mBAAA;AAAA;;;;;;;;;KAWU,gBAAA;EACN,EAAA;EAAU,EAAA,EAAI,EAAA,CAAG,KAAA;AAAA;EACjB,EAAA;EAAW,KAAA,EAAO,UAAA;AAAA;;;;;;ADQoC;AAa5D;;;;;;;KCNY,oBAAA;EDMiE,mECJ3E,QAAA,IAAY,OAAA,CAAQ,EAAA,CAAG,KAAA;;;;AA1CzB;EA+CE,UAAA,CAAW,IAAA,EAAM,IAAA,GAAO,OAAA,CAAQ,EAAA,CAAG,KAAA;;;;;;;EAOnC,MAAA,CAAO,EAAA,EAAI,EAAA,CAAG,KAAA,IAAS,OAAA;;;;;;;;;EASvB,UAAA,CAAW,KAAA,YAAiB,OAAA,CAAQ,gBAAA,CAAiB,KAAA;EAxCvD;;;;;;;;EAiDE,gBAAA,CAAiB,EAAA,EAAI,EAAA,CAAG,KAAA,IAAS,IAAA;;;;;EAKjC,YAAA,CAAa,IAAA,EAAM,IAAA,GAAO,EAAA,CAAG,KAAA;;;;AApDP;EAyDtB,YAAA,CAAa,IAAA,EAAM,IAAA,GAAO,EAAA,CAAG,KAAA;EA1CnB;;;;EA+CV,EAAA,CAAG,KAAA,YAAiB,KAAA,IAAS,EAAA,CAAG,KAAA;EAEhC,KAAA,CAAM,KAAA,YAAiB,EAAA,CAAG,KAAA;EAE1B,SAAA,CAAU,KAAA,YAAiB,WAAA,CAAY,KAAA;;;;;;EAMvC,YAAA,IAAgB,UAAA;WAEP,WAAA,EAAa,mBAAA,CAAoB,KAAA;AAAA;;;;;;;;;;;;;;;;;;iBAoB5B,uBAAA,uBACd,KAAA,EAAO,KAAA,GAAQ,UAAA,CAAW,KAAA,GAC1B,IAAA,EAAM,sBAAA,GACL,oBAAA,CAAqB,KAAA"}
1
+ {"version":3,"file":"signed.d.mts","names":[],"sources":["../src/codecs/signed/key.ts","../src/codecs/signed/index.ts"],"mappings":";;;;;KAYY,gBAAA;AAAA,cAIE,eAAA;;;AAJF;AAA2B;;;;AAIzB;AAcd;;;;KAAY,UAAA;EAAA,UACA,eAAA;AAAA;;;;;;;;;;;;iBAqBU,gBAAA,CAAiB,KAAA,EAAO,UAAA,GAAa,OAAA,CAAQ,UAAA;AAoBnE;;;;;;;;;AAAA,iBAAgB,gBAAA,CAAiB,KAAA,EAAO,UAAA,EAAY,MAAA,EAAQ,gBAAA;AAa5D;;;;;;;;;AAAA,iBAAgB,gBAAA,CAAiB,OAAA,UAAiB,MAAA,EAAQ,gBAAA,GAAmB,UAAA;;;;;;KC9CjE,sBAAA;ED3B2B;;;;AAIzB;EC6BZ,IAAA,GAAO,UAAA,KAAe,UAAA,KDfZ;ECiBV,GAAA,iBDhBU;ECkBV,GAAA,IAAO,MAAA,EAAQ,UAAA,WDGjB;ECDE,mBAAA;AAAA;;;;;;;;;KAWU,gBAAA;EACN,EAAA;EAAU,EAAA,EAAI,EAAA,CAAG,KAAA;AAAA;EACjB,EAAA;EAAW,KAAA,EAAO,UAAA;AAAA;;;;;;ADQoC;AAa5D;;;;;;;KCNY,oBAAA;EDMiE,mECJ3E,QAAA,IAAY,OAAA,CAAQ,EAAA,CAAG,KAAA;;;;AA1CzB;EA+CE,UAAA,CAAW,IAAA,EAAM,IAAA,GAAO,OAAA,CAAQ,EAAA,CAAG,KAAA;;;;;;;EAOnC,MAAA,CAAO,EAAA,EAAI,EAAA,CAAG,KAAA,IAAS,OAAA;;;;;;;;;EASvB,UAAA,CAAW,KAAA,YAAiB,OAAA,CAAQ,gBAAA,CAAiB,KAAA;EAxCvD;;;;;;;;EAiDE,gBAAA,CAAiB,EAAA,EAAI,EAAA,CAAG,KAAA,IAAS,IAAA;;;;;EAKjC,YAAA,CAAa,IAAA,EAAM,IAAA,GAAO,EAAA,CAAG,KAAA;;;;AApDP;EAyDtB,YAAA,CAAa,IAAA,EAAM,IAAA,GAAO,EAAA,CAAG,KAAA;EA1CnB;;;;EA+CV,EAAA,CAAG,KAAA,YAAiB,KAAA,IAAS,EAAA,CAAG,KAAA;EAEhC,KAAA,CAAM,KAAA,YAAiB,EAAA,CAAG,KAAA;EAE1B,SAAA,CAAU,KAAA,YAAiB,WAAA,CAAY,KAAA;;;;;;EAMvC,YAAA,IAAgB,UAAA;WAEP,WAAA,EAAa,mBAAA,CAAoB,KAAA;;;;;;EAM1C,MAAA,CAAO,EAAA,EAAI,EAAA,CAAG,KAAA;;;;;;EAMd,QAAA,CAAS,KAAA,WAAgB,EAAA,CAAG,KAAA;;;;;EAK5B,YAAA,CAAa,KAAA,YAAiB,WAAA,CAAY,KAAA;AAAA;;;;;;;;;;;;;;;;;;iBAoB5B,uBAAA,uBACd,KAAA,EAAO,KAAA,GAAQ,UAAA,CAAW,KAAA,GAC1B,IAAA,EAAM,sBAAA,GACL,oBAAA,CAAqB,KAAA"}
package/dist/signed.mjs CHANGED
@@ -1,3 +1,3 @@
1
1
  import { n as isIdsError, t as IdsError } from "./error-Cp5qYZcv.mjs";
2
- import { i as importSigningKey, n as decodeSigningKey, r as encodeSigningKey, t as createSignedTimestampId } from "./signed-BTz3ZFYE.mjs";
2
+ import { i as importSigningKey, n as decodeSigningKey, r as encodeSigningKey, t as createSignedTimestampId } from "./signed-Dkdteu1y.mjs";
3
3
  export { IdsError, createSignedTimestampId, decodeSigningKey, encodeSigningKey, importSigningKey, isIdsError };
@@ -1,5 +1,5 @@
1
- import { a as toWireId, n as registerBrand, s as validateBrand, t as wireMethods } from "./codec-shell-C2NKQEx2.mjs";
2
- import { a as writeTimestamp, i as readTimestampMsFromBase32Suffix, n as fastTenByteRng } from "./rng-BHFxX1Fc.mjs";
1
+ import { a as toWireId, n as registerBrand, s as validateBrand, t as wireMethods } from "./codec-shell-BRZkuQeP.mjs";
2
+ import { a as writeTimestamp, i as readTimestampMsFromBase32Suffix, n as fastTenByteRng } from "./rng-6GyNT4zS.mjs";
3
3
  //#region src/codecs/timestamp/layout.ts
4
4
  const randomByteLength = 10;
5
5
  /** Writes a 16-byte timestamp-layout payload into codec-owned scratch. */
@@ -79,10 +79,13 @@ function createTimestampId(brand, opts = {}) {
79
79
  minIdForTime: (date) => layout.minIdForTime(date.getTime()),
80
80
  maxIdForTime: (date) => layout.maxIdForTime(date.getTime()),
81
81
  toJsonSchema: () => wire.toJsonSchema(brand, layout.exampleWireId()),
82
- "~standard": wire["~standard"]
82
+ "~standard": wire["~standard"],
83
+ toUUID: wire.toUUID,
84
+ fromUUID: wire.fromUUID,
85
+ safeFromUUID: wire.safeFromUUID
83
86
  };
84
87
  }
85
88
  //#endregion
86
89
  export { createTimestampId as t };
87
90
 
88
- //# sourceMappingURL=timestamp-CleAIdZI.mjs.map
91
+ //# sourceMappingURL=timestamp-RXXwHfHO.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"timestamp-CleAIdZI.mjs","names":[],"sources":["../src/codecs/timestamp/layout.ts","../src/codecs/timestamp/index.ts"],"sourcesContent":["import type { Id, LayoutOps, Prefix } from \"../../types.js\";\nimport { toWireId } from \"../../wire/envelope.js\";\nimport { payloadByteLength } from \"../../wire/invariants.js\";\nimport {\n readTimestampMsFromBase32Suffix,\n timestampByteLength,\n writeTimestamp,\n} from \"../../wire/timestamp-bytes.js\";\n\nconst randomByteLength: number = payloadByteLength - timestampByteLength;\n\n/** Writes a 16-byte timestamp-layout payload into codec-owned scratch. */\nfunction buildPayload(\n ms: number,\n rng: (target: Uint8Array) => void,\n buffer: Uint8Array,\n randomView: Uint8Array,\n): void {\n writeTimestamp(ms, buffer);\n rng(randomView);\n}\n\n/** Writes sentinel min/max random bytes into codec-owned scratch. */\nfunction buildSentinelPayload(\n ms: number,\n fill: number,\n buffer: Uint8Array,\n randomView: Uint8Array,\n): void {\n writeTimestamp(ms, buffer);\n randomView.fill(fill);\n}\n\n/** Decodes the creation timestamp from a trusted wire ID. */\nfunction extractTimestampFromId<Brand extends string>(prefix: Prefix<Brand>, id: Id<Brand>): Date {\n return new Date(readTimestampMsFromBase32Suffix(id.slice(prefix.length)));\n}\n\n/** Layout ops binder for the Timestamp variant. `extractTimestampFromId` is module-private; the binder exposes `extractTimestamp` for the codec constructor. */\nexport function createTimestampLayoutOps<Brand extends string>(\n prefix: Prefix<Brand>,\n rng: (target: Uint8Array) => void,\n): LayoutOps<Brand> & {\n generateAt(ms: number): Id<Brand>;\n extractTimestamp(id: Id<Brand>): Date;\n minIdForTime(ms: number): Id<Brand>;\n maxIdForTime(ms: number): Id<Brand>;\n} {\n // Per-codec scratch buffer. Shared across generateAt(), minIdForTime(),\n // maxIdForTime(), and exampleWireId() — all are synchronous and overwrite both\n // the timestamp and random slices before encoding, so successive callers see\n // their own freshly-written bytes. toWireId reads the buffer and returns an\n // independent string, so the caller never sees the buffer itself.\n const buffer = new Uint8Array(payloadByteLength);\n const randomView = new Uint8Array(buffer.buffer, timestampByteLength, randomByteLength);\n\n return {\n generateAt: (ms: number): Id<Brand> => {\n buildPayload(ms, rng, buffer, randomView);\n return toWireId(prefix, buffer);\n },\n extractTimestamp: (id: Id<Brand>): Date => extractTimestampFromId(prefix, id),\n minIdForTime: (ms: number): Id<Brand> => {\n buildSentinelPayload(ms, 0x00, buffer, randomView);\n return toWireId(prefix, buffer);\n },\n maxIdForTime: (ms: number): Id<Brand> => {\n buildSentinelPayload(ms, 0xff, buffer, randomView);\n return toWireId(prefix, buffer);\n },\n exampleWireId: (ms?: number): Id<Brand> => {\n buildPayload(ms ?? Date.now(), rng, buffer, randomView);\n return toWireId(prefix, buffer);\n },\n };\n}\n","import { validateBrand } from \"../_kernel/brand.js\";\nimport { createTimestampLayoutOps } from \"./layout.js\";\nimport { registerBrand } from \"../_kernel/registry.js\";\nimport { fastTenByteRng } from \"../_kernel/rng.js\";\nimport type {\n Id,\n JsonSchema,\n ParseResult,\n Prefix,\n StandardSchemaProps,\n ValidBrand,\n} from \"../../types.js\";\nimport { wireMethods } from \"../../wire/codec-shell.js\";\n\n/**\n * Configuration options for a codec instance.\n */\nexport type TimestampOptions = {\n /** Returns the current timestamp in milliseconds. Defaults to `Date.now`. */\n now?: () => number;\n /** Writes random bytes into `target` for ID generation. Defaults to a `crypto.randomUUID` fast path. */\n rng?: (target: Uint8Array) => void;\n /** If true, silences the duplicate-brand warning in non-production environments. */\n allowDuplicateBrand?: boolean;\n};\n\ntype ResolvedTimestampOptions = Required<Pick<TimestampOptions, \"now\" | \"rng\">> &\n Pick<TimestampOptions, \"allowDuplicateBrand\">;\n\n/**\n * A brand-scoped codec for generating and validating public-facing IDs.\n *\n * Wire format: `{brand}_` plus 26 lowercase Crockford base32 characters encoding a\n * 16-byte payload (6-byte ms timestamp + 10 random bytes). IDs sort by creation\n * time in ascending order.\n *\n * For encrypted IDs, use `createOpaqueTimestampId` from `@smonn/ids/opaque`.\n */\nexport type TimestampCodec<Brand extends string> = {\n /** Produces a new canonical ID using the codec's `now` and `rng`. */\n generate(): Id<Brand>;\n /** Produces a new canonical ID with timestamp bytes from `date` and a fresh random tail. Throws on invalid dates. */\n generateAt(date: Date): Id<Brand>;\n /**\n * Strict type guard: `true` only for already-canonical strings for this brand.\n * For untrusted input, use `safeParse()` or `parse()` instead. See ADR-0003.\n */\n is(value: unknown): value is Id<Brand>;\n /**\n * Lenient parse: normalises case and Crockford aliases, returns canonical `Id<Brand>`, or throws.\n */\n parse(value: unknown): Id<Brand>;\n /**\n * Lenient parse without throwing: normalises to canonical form, or returns `{ ok: false, error }`.\n */\n safeParse(value: unknown): ParseResult<Brand>;\n /**\n * Decodes the creation `Date` from an `Id<Brand>`. Trusts the type — use `safeParse()` at boundaries first. See ADR-0002.\n *\n * Best-effort: decodes the timestamp bytes in the payload without any additional\n * verification. An ID that bypassed `safeParse()` (e.g. via a type assertion)\n * may return a plausible-looking but incorrect `Date`.\n */\n extractTimestamp(id: Id<Brand>): Date;\n /** Tight lower bound for any ID generated at `date` (random portion `0x00`). Throws on invalid dates. */\n minIdForTime(date: Date): Id<Brand>;\n /** Tight upper bound for any ID generated at `date` (random portion `0xff`). Throws on invalid dates. */\n maxIdForTime(date: Date): Id<Brand>;\n /**\n * JSON Schema for the canonical wire form. The `pattern` matches the canonical stored\n * form only and is deliberately stricter than `parse()`/`safeParse()`, which accept\n * uppercase letters and Crockford aliases (`o`/`i`/`l`) before normalising. See ADR-0003.\n */\n toJsonSchema(): JsonSchema;\n /** Standard Schema validate entry point. */\n readonly \"~standard\": StandardSchemaProps<Brand>;\n};\n\nconst defaultTimestampOptions: ResolvedTimestampOptions = {\n now: Date.now,\n // crypto.randomUUID harvest fast path (~7× faster than crypto.getRandomValues);\n // see fastTenByteRng. The Reverse Timestamp codec shares the identical 10-byte\n // random tail and the same default.\n rng: fastTenByteRng,\n};\n\n/**\n * Creates a codec for `brand` (three lowercase a–z characters).\n *\n * @param brand - Entity type brand validated once at construction.\n * @param opts - Optional `now`, `rng`, and `allowDuplicateBrand` overrides.\n * @example\n * ```ts\n * const users = createTimestampId(\"usr\");\n *\n * const id = users.generate(); // Id<\"usr\">\n * users.extractTimestamp(id); // Date\n * ```\n */\nexport function createTimestampId<Brand extends string>(\n brand: Brand & ValidBrand<Brand>,\n opts: TimestampOptions = {},\n): TimestampCodec<Brand> {\n validateBrand(brand);\n registerBrand(brand, opts.allowDuplicateBrand);\n\n const options = {\n now: opts.now ?? defaultTimestampOptions.now,\n rng: opts.rng ?? defaultTimestampOptions.rng,\n } satisfies ResolvedTimestampOptions;\n\n const prefix: Prefix<Brand> = `${brand}_`;\n const wire = wireMethods(prefix);\n const layout = createTimestampLayoutOps(prefix, options.rng);\n\n return {\n generate: () => layout.generateAt(options.now()),\n generateAt: (date: Date) => layout.generateAt(date.getTime()),\n is: wire.is,\n parse: wire.parse,\n safeParse: wire.safeParse,\n extractTimestamp: layout.extractTimestamp,\n minIdForTime: (date: Date) => layout.minIdForTime(date.getTime()),\n maxIdForTime: (date: Date) => layout.maxIdForTime(date.getTime()),\n toJsonSchema: () => wire.toJsonSchema(brand, layout.exampleWireId()),\n \"~standard\": wire[\"~standard\"],\n };\n}\n"],"mappings":";;;AASA,MAAM,mBAAA;;AAGN,SAAS,aACP,IACA,KACA,QACA,YACM;CACN,eAAe,IAAI,MAAM;CACzB,IAAI,UAAU;AAChB;;AAGA,SAAS,qBACP,IACA,MACA,QACA,YACM;CACN,eAAe,IAAI,MAAM;CACzB,WAAW,KAAK,IAAI;AACtB;;AAGA,SAAS,uBAA6C,QAAuB,IAAqB;CAChG,OAAO,IAAI,KAAK,gCAAgC,GAAG,MAAM,OAAO,MAAM,CAAC,CAAC;AAC1E;;AAGA,SAAgB,yBACd,QACA,KAMA;CAMA,MAAM,yBAAS,IAAI,WAAA,EAA4B;CAC/C,MAAM,aAAa,IAAI,WAAW,OAAO,QAAA,GAA6B,gBAAgB;CAEtF,OAAO;EACL,aAAa,OAA0B;GACrC,aAAa,IAAI,KAAK,QAAQ,UAAU;GACxC,OAAO,SAAS,QAAQ,MAAM;EAChC;EACA,mBAAmB,OAAwB,uBAAuB,QAAQ,EAAE;EAC5E,eAAe,OAA0B;GACvC,qBAAqB,IAAI,GAAM,QAAQ,UAAU;GACjD,OAAO,SAAS,QAAQ,MAAM;EAChC;EACA,eAAe,OAA0B;GACvC,qBAAqB,IAAI,KAAM,QAAQ,UAAU;GACjD,OAAO,SAAS,QAAQ,MAAM;EAChC;EACA,gBAAgB,OAA2B;GACzC,aAAa,MAAM,KAAK,IAAI,GAAG,KAAK,QAAQ,UAAU;GACtD,OAAO,SAAS,QAAQ,MAAM;EAChC;CACF;AACF;;;ACGA,MAAM,0BAAoD;CACxD,KAAK,KAAK;CAIV,KAAK;AACP;;;;;;;;;;;;;;AAeA,SAAgB,kBACd,OACA,OAAyB,CAAC,GACH;CACvB,cAAc,KAAK;CACnB,cAAc,OAAO,KAAK,mBAAmB;CAE7C,MAAM,UAAU;EACd,KAAK,KAAK,OAAO,wBAAwB;EACzC,KAAK,KAAK,OAAO,wBAAwB;CAC3C;CAEA,MAAM,SAAwB,GAAG,MAAM;CACvC,MAAM,OAAO,YAAY,MAAM;CAC/B,MAAM,SAAS,yBAAyB,QAAQ,QAAQ,GAAG;CAE3D,OAAO;EACL,gBAAgB,OAAO,WAAW,QAAQ,IAAI,CAAC;EAC/C,aAAa,SAAe,OAAO,WAAW,KAAK,QAAQ,CAAC;EAC5D,IAAI,KAAK;EACT,OAAO,KAAK;EACZ,WAAW,KAAK;EAChB,kBAAkB,OAAO;EACzB,eAAe,SAAe,OAAO,aAAa,KAAK,QAAQ,CAAC;EAChE,eAAe,SAAe,OAAO,aAAa,KAAK,QAAQ,CAAC;EAChE,oBAAoB,KAAK,aAAa,OAAO,OAAO,cAAc,CAAC;EACnE,aAAa,KAAK;CACpB;AACF"}
1
+ {"version":3,"file":"timestamp-RXXwHfHO.mjs","names":[],"sources":["../src/codecs/timestamp/layout.ts","../src/codecs/timestamp/index.ts"],"sourcesContent":["import type { Id, LayoutOps, Prefix } from \"../../types.js\";\nimport { toWireId } from \"../../wire/envelope.js\";\nimport { payloadByteLength } from \"../../wire/invariants.js\";\nimport {\n readTimestampMsFromBase32Suffix,\n timestampByteLength,\n writeTimestamp,\n} from \"../../wire/timestamp-bytes.js\";\n\nconst randomByteLength: number = payloadByteLength - timestampByteLength;\n\n/** Writes a 16-byte timestamp-layout payload into codec-owned scratch. */\nfunction buildPayload(\n ms: number,\n rng: (target: Uint8Array) => void,\n buffer: Uint8Array,\n randomView: Uint8Array,\n): void {\n writeTimestamp(ms, buffer);\n rng(randomView);\n}\n\n/** Writes sentinel min/max random bytes into codec-owned scratch. */\nfunction buildSentinelPayload(\n ms: number,\n fill: number,\n buffer: Uint8Array,\n randomView: Uint8Array,\n): void {\n writeTimestamp(ms, buffer);\n randomView.fill(fill);\n}\n\n/** Decodes the creation timestamp from a trusted wire ID. */\nfunction extractTimestampFromId<Brand extends string>(prefix: Prefix<Brand>, id: Id<Brand>): Date {\n return new Date(readTimestampMsFromBase32Suffix(id.slice(prefix.length)));\n}\n\n/** Layout ops binder for the Timestamp variant. `extractTimestampFromId` is module-private; the binder exposes `extractTimestamp` for the codec constructor. */\nexport function createTimestampLayoutOps<Brand extends string>(\n prefix: Prefix<Brand>,\n rng: (target: Uint8Array) => void,\n): LayoutOps<Brand> & {\n generateAt(ms: number): Id<Brand>;\n extractTimestamp(id: Id<Brand>): Date;\n minIdForTime(ms: number): Id<Brand>;\n maxIdForTime(ms: number): Id<Brand>;\n} {\n // Per-codec scratch buffer. Shared across generateAt(), minIdForTime(),\n // maxIdForTime(), and exampleWireId() — all are synchronous and overwrite both\n // the timestamp and random slices before encoding, so successive callers see\n // their own freshly-written bytes. toWireId reads the buffer and returns an\n // independent string, so the caller never sees the buffer itself.\n const buffer = new Uint8Array(payloadByteLength);\n const randomView = new Uint8Array(buffer.buffer, timestampByteLength, randomByteLength);\n\n return {\n generateAt: (ms: number): Id<Brand> => {\n buildPayload(ms, rng, buffer, randomView);\n return toWireId(prefix, buffer);\n },\n extractTimestamp: (id: Id<Brand>): Date => extractTimestampFromId(prefix, id),\n minIdForTime: (ms: number): Id<Brand> => {\n buildSentinelPayload(ms, 0x00, buffer, randomView);\n return toWireId(prefix, buffer);\n },\n maxIdForTime: (ms: number): Id<Brand> => {\n buildSentinelPayload(ms, 0xff, buffer, randomView);\n return toWireId(prefix, buffer);\n },\n exampleWireId: (ms?: number): Id<Brand> => {\n buildPayload(ms ?? Date.now(), rng, buffer, randomView);\n return toWireId(prefix, buffer);\n },\n };\n}\n","import { validateBrand } from \"../_kernel/brand.js\";\nimport { createTimestampLayoutOps } from \"./layout.js\";\nimport { registerBrand } from \"../_kernel/registry.js\";\nimport { fastTenByteRng } from \"../_kernel/rng.js\";\nimport type {\n Id,\n JsonSchema,\n ParseResult,\n Prefix,\n StandardSchemaProps,\n ValidBrand,\n} from \"../../types.js\";\nimport { wireMethods } from \"../../wire/codec-shell.js\";\n\n/**\n * Configuration options for a codec instance.\n */\nexport type TimestampOptions = {\n /** Returns the current timestamp in milliseconds. Defaults to `Date.now`. */\n now?: () => number;\n /** Writes random bytes into `target` for ID generation. Defaults to a `crypto.randomUUID` fast path. */\n rng?: (target: Uint8Array) => void;\n /** If true, silences the duplicate-brand warning in non-production environments. */\n allowDuplicateBrand?: boolean;\n};\n\ntype ResolvedTimestampOptions = Required<Pick<TimestampOptions, \"now\" | \"rng\">> &\n Pick<TimestampOptions, \"allowDuplicateBrand\">;\n\n/**\n * A brand-scoped codec for generating and validating public-facing IDs.\n *\n * Wire format: `{brand}_` plus 26 lowercase Crockford base32 characters encoding a\n * 16-byte payload (6-byte ms timestamp + 10 random bytes). IDs sort by creation\n * time in ascending order.\n *\n * For encrypted IDs, use `createOpaqueTimestampId` from `@smonn/ids/opaque`.\n */\nexport type TimestampCodec<Brand extends string> = {\n /** Produces a new canonical ID using the codec's `now` and `rng`. */\n generate(): Id<Brand>;\n /** Produces a new canonical ID with timestamp bytes from `date` and a fresh random tail. Throws on invalid dates. */\n generateAt(date: Date): Id<Brand>;\n /**\n * Strict type guard: `true` only for already-canonical strings for this brand.\n * For untrusted input, use `safeParse()` or `parse()` instead. See ADR-0003.\n */\n is(value: unknown): value is Id<Brand>;\n /**\n * Lenient parse: normalises case and Crockford aliases, returns canonical `Id<Brand>`, or throws.\n */\n parse(value: unknown): Id<Brand>;\n /**\n * Lenient parse without throwing: normalises to canonical form, or returns `{ ok: false, error }`.\n */\n safeParse(value: unknown): ParseResult<Brand>;\n /**\n * Decodes the creation `Date` from an `Id<Brand>`. Trusts the type — use `safeParse()` at boundaries first. See ADR-0002.\n *\n * Best-effort: decodes the timestamp bytes in the payload without any additional\n * verification. An ID that bypassed `safeParse()` (e.g. via a type assertion)\n * may return a plausible-looking but incorrect `Date`.\n */\n extractTimestamp(id: Id<Brand>): Date;\n /** Tight lower bound for any ID generated at `date` (random portion `0x00`). Throws on invalid dates. */\n minIdForTime(date: Date): Id<Brand>;\n /** Tight upper bound for any ID generated at `date` (random portion `0xff`). Throws on invalid dates. */\n maxIdForTime(date: Date): Id<Brand>;\n /**\n * JSON Schema for the canonical wire form. The `pattern` matches the canonical stored\n * form only and is deliberately stricter than `parse()`/`safeParse()`, which accept\n * uppercase letters and Crockford aliases (`o`/`i`/`l`) before normalising. See ADR-0003.\n */\n toJsonSchema(): JsonSchema;\n /** Standard Schema validate entry point. */\n readonly \"~standard\": StandardSchemaProps<Brand>;\n /**\n * Converts a trusted `Id<Brand>` to an RFC 9562 canonical (lowercase, hyphenated)\n * UUID string by reinterpreting the 16-byte payload verbatim. Total — cannot fail.\n * Returns a plain `string` (brand is shed). See ADR-0024.\n */\n toUUID(id: Id<Brand>): string;\n /**\n * Parses a UUID string into an `Id<Brand>`. Accepts case-insensitive `8-4-4-4-12`\n * hyphenated form only. Throws `IdsError` with `code: \"invalid_id\"` on bad input.\n * See ADR-0024.\n */\n fromUUID(value: string): Id<Brand>;\n /**\n * Non-throwing UUID parse. Returns `{ ok: true, id }` or\n * `{ ok: false, error: \"not_string\" | \"invalid_uuid\" }`. See ADR-0024.\n */\n safeFromUUID(value: unknown): ParseResult<Brand>;\n};\n\nconst defaultTimestampOptions: ResolvedTimestampOptions = {\n now: Date.now,\n // crypto.randomUUID harvest fast path (~7× faster than crypto.getRandomValues);\n // see fastTenByteRng. The Reverse Timestamp codec shares the identical 10-byte\n // random tail and the same default.\n rng: fastTenByteRng,\n};\n\n/**\n * Creates a codec for `brand` (three lowercase a–z characters).\n *\n * @param brand - Entity type brand validated once at construction.\n * @param opts - Optional `now`, `rng`, and `allowDuplicateBrand` overrides.\n * @example\n * ```ts\n * const users = createTimestampId(\"usr\");\n *\n * const id = users.generate(); // Id<\"usr\">\n * users.extractTimestamp(id); // Date\n * ```\n */\nexport function createTimestampId<Brand extends string>(\n brand: Brand & ValidBrand<Brand>,\n opts: TimestampOptions = {},\n): TimestampCodec<Brand> {\n validateBrand(brand);\n registerBrand(brand, opts.allowDuplicateBrand);\n\n const options = {\n now: opts.now ?? defaultTimestampOptions.now,\n rng: opts.rng ?? defaultTimestampOptions.rng,\n } satisfies ResolvedTimestampOptions;\n\n const prefix: Prefix<Brand> = `${brand}_`;\n const wire = wireMethods(prefix);\n const layout = createTimestampLayoutOps(prefix, options.rng);\n\n return {\n generate: () => layout.generateAt(options.now()),\n generateAt: (date: Date) => layout.generateAt(date.getTime()),\n is: wire.is,\n parse: wire.parse,\n safeParse: wire.safeParse,\n extractTimestamp: layout.extractTimestamp,\n minIdForTime: (date: Date) => layout.minIdForTime(date.getTime()),\n maxIdForTime: (date: Date) => layout.maxIdForTime(date.getTime()),\n toJsonSchema: () => wire.toJsonSchema(brand, layout.exampleWireId()),\n \"~standard\": wire[\"~standard\"],\n toUUID: wire.toUUID,\n fromUUID: wire.fromUUID,\n safeFromUUID: wire.safeFromUUID,\n };\n}\n"],"mappings":";;;AASA,MAAM,mBAAA;;AAGN,SAAS,aACP,IACA,KACA,QACA,YACM;CACN,eAAe,IAAI,MAAM;CACzB,IAAI,UAAU;AAChB;;AAGA,SAAS,qBACP,IACA,MACA,QACA,YACM;CACN,eAAe,IAAI,MAAM;CACzB,WAAW,KAAK,IAAI;AACtB;;AAGA,SAAS,uBAA6C,QAAuB,IAAqB;CAChG,OAAO,IAAI,KAAK,gCAAgC,GAAG,MAAM,OAAO,MAAM,CAAC,CAAC;AAC1E;;AAGA,SAAgB,yBACd,QACA,KAMA;CAMA,MAAM,yBAAS,IAAI,WAAA,EAA4B;CAC/C,MAAM,aAAa,IAAI,WAAW,OAAO,QAAA,GAA6B,gBAAgB;CAEtF,OAAO;EACL,aAAa,OAA0B;GACrC,aAAa,IAAI,KAAK,QAAQ,UAAU;GACxC,OAAO,SAAS,QAAQ,MAAM;EAChC;EACA,mBAAmB,OAAwB,uBAAuB,QAAQ,EAAE;EAC5E,eAAe,OAA0B;GACvC,qBAAqB,IAAI,GAAM,QAAQ,UAAU;GACjD,OAAO,SAAS,QAAQ,MAAM;EAChC;EACA,eAAe,OAA0B;GACvC,qBAAqB,IAAI,KAAM,QAAQ,UAAU;GACjD,OAAO,SAAS,QAAQ,MAAM;EAChC;EACA,gBAAgB,OAA2B;GACzC,aAAa,MAAM,KAAK,IAAI,GAAG,KAAK,QAAQ,UAAU;GACtD,OAAO,SAAS,QAAQ,MAAM;EAChC;CACF;AACF;;;ACoBA,MAAM,0BAAoD;CACxD,KAAK,KAAK;CAIV,KAAK;AACP;;;;;;;;;;;;;;AAeA,SAAgB,kBACd,OACA,OAAyB,CAAC,GACH;CACvB,cAAc,KAAK;CACnB,cAAc,OAAO,KAAK,mBAAmB;CAE7C,MAAM,UAAU;EACd,KAAK,KAAK,OAAO,wBAAwB;EACzC,KAAK,KAAK,OAAO,wBAAwB;CAC3C;CAEA,MAAM,SAAwB,GAAG,MAAM;CACvC,MAAM,OAAO,YAAY,MAAM;CAC/B,MAAM,SAAS,yBAAyB,QAAQ,QAAQ,GAAG;CAE3D,OAAO;EACL,gBAAgB,OAAO,WAAW,QAAQ,IAAI,CAAC;EAC/C,aAAa,SAAe,OAAO,WAAW,KAAK,QAAQ,CAAC;EAC5D,IAAI,KAAK;EACT,OAAO,KAAK;EACZ,WAAW,KAAK;EAChB,kBAAkB,OAAO;EACzB,eAAe,SAAe,OAAO,aAAa,KAAK,QAAQ,CAAC;EAChE,eAAe,SAAe,OAAO,aAAa,KAAK,QAAQ,CAAC;EAChE,oBAAoB,KAAK,aAAa,OAAO,OAAO,cAAc,CAAC;EACnE,aAAa,KAAK;EAClB,QAAQ,KAAK;EACb,UAAU,KAAK;EACf,cAAc,KAAK;CACrB;AACF"}
@@ -1,5 +1,5 @@
1
- import { n as IdColumnCodec } from "./adapter-types-CIc-4O-P.mjs";
2
- import { n as IdsErrorCode, r as isIdsError, t as IdsError } from "./error-Dqyho9vp.mjs";
1
+ import { n as IdColumnCodec } from "./adapter-types-Bia_w9sg.mjs";
2
+ import { n as IdsErrorCode, r as isIdsError, t as IdsError } from "./error-CifcKKOG.mjs";
3
3
  import { ValueTransformer } from "typeorm";
4
4
 
5
5
  //#region src/adapters/typeorm.d.ts
@@ -22,8 +22,8 @@ declare const idBrand: unique symbol;
22
22
  type Id<Brand extends string> = `${Prefix<Brand>}${string}` & {
23
23
  readonly [idBrand]: Brand;
24
24
  };
25
- /** Parse failure reason returned by `safeParse()`. */
26
- type ParseError = "not_string" | "invalid_prefix" | "invalid_base32";
25
+ /** Parse failure reason returned by `safeParse()` and `safeFromUUID()`. */
26
+ type ParseError = "not_string" | "invalid_prefix" | "invalid_base32" | "invalid_uuid";
27
27
  /** Result of `safeParse()`: canonical `Id<Brand>` or a `ParseError`. */
28
28
  type ParseResult<Brand extends string> = {
29
29
  ok: true;
@@ -60,4 +60,4 @@ type StandardSchemaProps<Brand extends string> = {
60
60
  };
61
61
  //#endregion
62
62
  export { StandardSchemaProps as a, ParseResult as i, JsonSchema as n, ValidBrand as o, ParseError as r, Id as t };
63
- //# sourceMappingURL=types-wplmOgOK.d.mts.map
63
+ //# sourceMappingURL=types-hGBnCpJj.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types-wplmOgOK.d.mts","names":[],"sources":["../src/types.ts"],"mappings":";KAAK,SAAA;;;;;AAAA;AA0CL;;;;;;;;;KAAY,UAAA,oCAA8C,CAAA,GACtD,CAAA,GACA,CAAA,6BAA8B,SAAA,oBAA6B,SAAA,oBAA6B,SAAA,KACtF,CAAA;;KAIM,MAAA,4BAAkC,KAAA;AAAA,cAEhC,OAAA;;KAGF,EAAA,4BAA8B,MAAA,CAAO,KAAA;EAAA,UACrC,OAAA,GAAU,KAAA;AAAA;;KAIV,UAAA;;KAGA,WAAA;EACN,EAAA;EAAU,EAAA,EAAI,EAAA,CAAG,KAAA;AAAA;EACjB,EAAA;EAAW,KAAA,EAAO,UAAA;AAAA;;KAGZ,UAAA;EAAA,SACD,IAAA;EAAA,SACA,OAAA;EAAA,SACA,WAAA;EAAA,SACA,OAAA;AAAA;;KASC,mBAAA;EAAA,SACD,OAAA;EAAA,SACA,MAAA;EAAA,SACA,QAAA,GACP,KAAA,WACA,OAAA;IAAA,SAAqB,cAAA,GAAiB,MAAA;EAAA;IAAA,SAEzB,KAAA,EAAO,EAAA,CAAG,KAAA;IAAA,SAAiB,MAAA;EAAA;IAAA,SAC3B,MAAA,EAAQ,aAAA;MAAA,SAAyB,OAAA;IAAA;EAAA;EAAA,SACvC,KAAA;IAAA,SAAmB,KAAA;IAAA,SAAyB,MAAA,EAAQ,EAAA,CAAG,KAAA;EAAA;AAAA"}
1
+ {"version":3,"file":"types-hGBnCpJj.d.mts","names":[],"sources":["../src/types.ts"],"mappings":";KAAK,SAAA;;;;;AAAA;AA0CL;;;;;;;;;KAAY,UAAA,oCAA8C,CAAA,GACtD,CAAA,GACA,CAAA,6BAA8B,SAAA,oBAA6B,SAAA,oBAA6B,SAAA,KACtF,CAAA;;KAIM,MAAA,4BAAkC,KAAA;AAAA,cAEhC,OAAA;;KAGF,EAAA,4BAA8B,MAAA,CAAO,KAAA;EAAA,UACrC,OAAA,GAAU,KAAA;AAAA;;KAIV,UAAA;;KAGA,WAAA;EACN,EAAA;EAAU,EAAA,EAAI,EAAA,CAAG,KAAA;AAAA;EACjB,EAAA;EAAW,KAAA,EAAO,UAAA;AAAA;;KAGZ,UAAA;EAAA,SACD,IAAA;EAAA,SACA,OAAA;EAAA,SACA,WAAA;EAAA,SACA,OAAA;AAAA;;KASC,mBAAA;EAAA,SACD,OAAA;EAAA,SACA,MAAA;EAAA,SACA,QAAA,GACP,KAAA,WACA,OAAA;IAAA,SAAqB,cAAA,GAAiB,MAAA;EAAA;IAAA,SAEzB,KAAA,EAAO,EAAA,CAAG,KAAA;IAAA,SAAiB,MAAA;EAAA;IAAA,SAC3B,MAAA,EAAQ,aAAA;MAAA,SAAyB,OAAA;IAAA;EAAA;EAAA,SACvC,KAAA;IAAA,SAAmB,KAAA;IAAA,SAAyB,MAAA,EAAQ,EAAA,CAAG,KAAA;EAAA;AAAA"}
@@ -1,6 +1,6 @@
1
1
  import { t as IdsError } from "./error-Cp5qYZcv.mjs";
2
- import { a as toWireId, i as payloadBytesFromId, n as registerBrand, r as payloadBase32Length, s as validateBrand, t as wireMethods } from "./codec-shell-C2NKQEx2.mjs";
3
- import { a as decryptPayload, c as timingSafeEqual, i as encodeKeyMaterial, l as writeLen32, n as assertValidKeyring, o as deriveKey, r as decodeKeyMaterial, s as encryptPayload, t as assertValidKeyMaterialByteLength } from "./key-material-DvjACe89.mjs";
2
+ import { a as toWireId, i as payloadBytesFromId, n as registerBrand, r as payloadBase32Length, s as validateBrand, t as wireMethods } from "./codec-shell-BRZkuQeP.mjs";
3
+ import { a as decryptPayload, c as timingSafeEqual, i as encodeKeyMaterial, l as writeLen32, n as assertValidKeyring, o as deriveKey, r as decodeKeyMaterial, s as encryptPayload, t as assertValidKeyMaterialByteLength } from "./key-material-1wOKJ1o-.mjs";
4
4
  //#region src/codecs/wrapped/layout.ts
5
5
  const laneByteLength = 8;
6
6
  const tagByteLength = 8;
@@ -137,6 +137,7 @@ const internals = /* @__PURE__ */ new WeakMap();
137
137
  * {@link decodeWrappingKey} (`"hex"` or `"base64url"` — not Crockford base32).
138
138
  *
139
139
  * @param bytes - 16, 24, or 32 raw key bytes.
140
+ * @throws {IdsError} `invalid_key_length` if `bytes.length` is not 16, 24, or 32.
140
141
  */
141
142
  async function importWrappingKey(bytes) {
142
143
  assertValidKeyMaterialByteLength(bytes.length, "wrapping");
@@ -165,6 +166,9 @@ async function importWrappingKey(bytes) {
165
166
  *
166
167
  * Supports `"hex"` (lowercase) and `"base64url"`. Output round-trips through
167
168
  * {@link decodeWrappingKey} back to the original bytes.
169
+ *
170
+ * @throws {IdsError} `invalid_key_format` if `format` is not `"hex"` or `"base64url"`.
171
+ * @throws {IdsError} `invalid_key_length` if `bytes.length` is not 16, 24, or 32.
168
172
  */
169
173
  function encodeWrappingKey(bytes, format) {
170
174
  return encodeKeyMaterial(bytes, format, "wrapping", "wrapping");
@@ -173,6 +177,10 @@ function encodeWrappingKey(bytes, format) {
173
177
  * Decode key material emitted by {@link encodeWrappingKey} back to raw bytes.
174
178
  *
175
179
  * The result can be passed directly to {@link importWrappingKey}.
180
+ *
181
+ * @throws {IdsError} `invalid_key_format` if `format` is not `"hex"` or `"base64url"`.
182
+ * @throws {IdsError} `invalid_key_encoding` if the string is malformed for its format.
183
+ * @throws {IdsError} `invalid_key_length` if the decoded bytes are not 16, 24, or 32 bytes.
176
184
  */
177
185
  function decodeWrappingKey(encoded, format) {
178
186
  return decodeKeyMaterial(encoded, format, "wrapping", "wrapping");
@@ -290,10 +298,13 @@ function createWrappedKeyId(brand, opts) {
290
298
  parse: wire.parse,
291
299
  safeParse: wire.safeParse,
292
300
  toJsonSchema: () => wire.toJsonSchema(brand, layout.exampleWireId()),
293
- "~standard": wire["~standard"]
301
+ "~standard": wire["~standard"],
302
+ toUUID: wire.toUUID,
303
+ fromUUID: wire.fromUUID,
304
+ safeFromUUID: wire.safeFromUUID
294
305
  };
295
306
  }
296
307
  //#endregion
297
308
  export { importWrappingKey as i, decodeWrappingKey as n, encodeWrappingKey as r, createWrappedKeyId as t };
298
309
 
299
- //# sourceMappingURL=wrapped-DPlsv1x-.mjs.map
310
+ //# sourceMappingURL=wrapped-Oj2hC1vB.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrapped-Oj2hC1vB.mjs","names":[],"sources":["../src/codecs/wrapped/layout.ts","../src/codecs/wrapped/key.ts","../src/codecs/wrapped/index.ts"],"sourcesContent":["import type { webcrypto } from \"node:crypto\";\nimport type { Id, LayoutOps, Prefix } from \"../../types.js\";\nimport { decryptPayload, encryptPayload, timingSafeEqual } from \"../_kernel/crypto.js\";\nimport { writeLen32 } from \"../_kernel/bytes.js\";\nimport { payloadBytesFromId, toWireId } from \"../../wire/envelope.js\";\nimport { payloadBase32Length, payloadByteLength } from \"../../wire/invariants.js\";\n\nconst laneByteLength = 8;\nconst tagByteLength = 8;\n\ntype LayoutWrappingKey = {\n aesKey: webcrypto.CryptoKey;\n hmacKey: webcrypto.CryptoKey;\n};\n\ntype LayoutWrappedKind = \"u32\" | \"i32\" | \"u64\" | \"i64\";\ntype LayoutLookupKey<K extends LayoutWrappedKind> = K extends \"u32\" | \"i32\" ? number : bigint;\n\nfunction writeU32Lane(value: number, lane: Uint8Array): void {\n lane[0] = 0;\n lane[1] = 0;\n lane[2] = 0;\n lane[3] = 0;\n lane[4] = (value >>> 24) & 0xff;\n lane[5] = (value >>> 16) & 0xff;\n lane[6] = (value >>> 8) & 0xff;\n lane[7] = value & 0xff;\n}\n\nfunction readU32Lane(lane: Uint8Array): number | null {\n for (let i = 0; i < 4; i++) {\n if (lane[i] !== 0) return null;\n }\n return ((lane[4]! << 24) | (lane[5]! << 16) | (lane[6]! << 8) | lane[7]!) >>> 0;\n}\n\nfunction writeI32Lane(value: number, lane: Uint8Array): void {\n lane.fill(value < 0 ? 0xff : 0x00, 0, 4);\n new DataView(lane.buffer, lane.byteOffset, lane.byteLength).setInt32(4, value, false);\n}\n\nfunction readI32Lane(lane: Uint8Array): number | null {\n const signExtension = (lane[4]! & 0x80) === 0 ? 0x00 : 0xff;\n for (let i = 0; i < 4; i++) {\n if (lane[i] !== signExtension) return null;\n }\n return new DataView(lane.buffer, lane.byteOffset, lane.byteLength).getInt32(4, false);\n}\n\nfunction writeU64Lane(value: bigint, lane: Uint8Array): void {\n new DataView(lane.buffer, lane.byteOffset, lane.byteLength).setBigUint64(0, value, false);\n}\n\nfunction readU64Lane(lane: Uint8Array): bigint {\n return new DataView(lane.buffer, lane.byteOffset, lane.byteLength).getBigUint64(0, false);\n}\n\nfunction writeI64Lane(value: bigint, lane: Uint8Array): void {\n new DataView(lane.buffer, lane.byteOffset, lane.byteLength).setBigInt64(0, value, false);\n}\n\nfunction readI64Lane(lane: Uint8Array): bigint {\n return new DataView(lane.buffer, lane.byteOffset, lane.byteLength).getBigInt64(0, false);\n}\n\nfunction writeLane<K extends LayoutWrappedKind>(\n kind: K,\n value: LayoutLookupKey<K>,\n lane: Uint8Array,\n): void {\n if (kind === \"i32\") {\n writeI32Lane(value as number, lane);\n return;\n }\n if (kind === \"u64\") {\n writeU64Lane(value as bigint, lane);\n return;\n }\n if (kind === \"i64\") {\n writeI64Lane(value as bigint, lane);\n return;\n }\n writeU32Lane(value as number, lane);\n}\n\nfunction readLane<K extends LayoutWrappedKind>(\n kind: K,\n lane: Uint8Array,\n): LayoutLookupKey<K> | null {\n if (kind === \"u64\") return readU64Lane(lane) as LayoutLookupKey<K>;\n if (kind === \"i64\") return readI64Lane(lane) as LayoutLookupKey<K>;\n const value = kind === \"i32\" ? readI32Lane(lane) : readU32Lane(lane);\n return value as LayoutLookupKey<K> | null;\n}\n\n/**\n * Precomputed HMAC-message template for a fixed (brand, kind) pair.\n *\n * The message is `len32(brand) ‖ brand ‖ len32(kind) ‖ kind ‖ lane`. Everything\n * except the trailing 8-byte lane is constant for the life of the codec, so we\n * build it once at construction. `brand`/`kind` are never re-encoded and no\n * `TextEncoder` is allocated on the `wrap` / `unwrap` hot paths.\n */\ntype HmacMessageTemplate = {\n /** Full-length buffer with the constant prefix written and the lane region zeroed. */\n readonly buffer: Uint8Array;\n /** Byte offset where the lane is copied in on each call. */\n readonly laneOffset: number;\n};\n\nfunction createHmacMessageTemplate(brand: string, kind: LayoutWrappedKind): HmacMessageTemplate {\n const encoder = new TextEncoder();\n const brandBytes = encoder.encode(brand);\n const kindBytes = encoder.encode(kind);\n const laneOffset = 4 + brandBytes.length + 4 + kindBytes.length;\n const buffer = new Uint8Array(laneOffset + laneByteLength);\n let offset = 0;\n writeLen32(brandBytes.length, buffer, offset);\n offset += 4;\n buffer.set(brandBytes, offset);\n offset += brandBytes.length;\n writeLen32(kindBytes.length, buffer, offset);\n offset += 4;\n buffer.set(kindBytes, offset);\n return { buffer, laneOffset };\n}\n\n/** Materialise the HMAC message for `lane`. Fresh buffer per call → safe under concurrent async signs. */\nfunction hmacMessage(template: HmacMessageTemplate, lane: Uint8Array): Uint8Array {\n const message = template.buffer.slice();\n message.set(lane, template.laneOffset);\n return message;\n}\n\nasync function computeTag(\n key: LayoutWrappingKey,\n template: HmacMessageTemplate,\n lane: Uint8Array,\n): Promise<Uint8Array> {\n const signature = new Uint8Array(\n await crypto.subtle.sign(\n \"HMAC\",\n key.hmacKey,\n hmacMessage(template, lane) as Uint8Array<ArrayBuffer>,\n ),\n );\n return signature.subarray(0, tagByteLength);\n}\n\nfunction buildPlaintext(lane: Uint8Array, tag: Uint8Array): Uint8Array {\n const plaintext = new Uint8Array(payloadByteLength);\n plaintext.set(lane, 0);\n plaintext.set(tag, laneByteLength);\n return plaintext;\n}\n\nasync function wrapLookupKey<Brand extends string, Kind extends LayoutWrappedKind>(\n prefix: Prefix<Brand>,\n template: HmacMessageTemplate,\n key: LayoutWrappingKey,\n kind: Kind,\n lookupKey: LayoutLookupKey<Kind>,\n): Promise<Id<Brand>> {\n const lane = new Uint8Array(laneByteLength);\n writeLane(kind, lookupKey, lane);\n const tag = await computeTag(key, template, lane);\n const encrypted = await encryptPayload(key.aesKey, buildPlaintext(lane, tag));\n return toWireId(prefix, encrypted);\n}\n\nasync function tryUnwrapLookupKey<Brand extends string, Kind extends LayoutWrappedKind>(\n prefix: Prefix<Brand>,\n template: HmacMessageTemplate,\n key: LayoutWrappingKey,\n kind: Kind,\n id: Id<Brand>,\n): Promise<LayoutLookupKey<Kind> | null> {\n const plaintext = await decryptPayload(key.aesKey, payloadBytesFromId(prefix, id));\n const lane = plaintext.subarray(0, laneByteLength);\n const tag = plaintext.subarray(laneByteLength, payloadByteLength);\n const expected = await computeTag(key, template, lane);\n if (!timingSafeEqual(tag, expected)) return null;\n return readLane(kind, lane);\n}\n\nfunction schemaExample<Brand extends string>(prefix: Prefix<Brand>): string {\n return prefix + \"0\".repeat(payloadBase32Length);\n}\n\nexport function createWrappedLayoutOps<Brand extends string, Kind extends LayoutWrappedKind>(\n prefix: Prefix<Brand>,\n brand: Brand,\n kind: Kind,\n keys: readonly LayoutWrappingKey[],\n): LayoutOps<Brand> & {\n wrap(lookupKey: LayoutLookupKey<Kind>): Promise<Id<Brand>>;\n tryUnwrap(id: Id<Brand>): Promise<LayoutLookupKey<Kind> | null>;\n} {\n const wrapKey = keys[0]!;\n // brand + kind are fixed for the codec's lifetime; encode them and build the\n // HMAC-message prefix once instead of on every wrap / unwrap-trial.\n const template = createHmacMessageTemplate(brand, kind);\n return {\n wrap: (lookupKey: LayoutLookupKey<Kind>): Promise<Id<Brand>> =>\n wrapLookupKey(prefix, template, wrapKey, kind, lookupKey),\n tryUnwrap: async (id: Id<Brand>): Promise<LayoutLookupKey<Kind> | null> => {\n for (const key of keys) {\n const lookupKey = await tryUnwrapLookupKey(prefix, template, key, kind, id);\n if (lookupKey !== null) return lookupKey;\n }\n return null;\n },\n exampleWireId: (_ms?: number): Id<Brand> => schemaExample(prefix) as Id<Brand>,\n };\n}\n","import type { webcrypto } from \"node:crypto\";\nimport { deriveKey, timingSafeEqual } from \"../_kernel/crypto.js\";\nimport {\n assertValidKeyMaterialByteLength,\n assertValidKeyring,\n decodeKeyMaterial,\n encodeKeyMaterial,\n} from \"../_kernel/key-material.js\";\n\nexport { assertValidKeyring };\n\n/** Wire encoding for wrapping operator secret bytes (not Crockford base32). */\nexport type WrappingKeyFormat = \"hex\" | \"base64url\";\n\nconst aesInfo = new TextEncoder().encode(\"@smonn/ids/wrapped/aes\");\nconst hmacInfo = new TextEncoder().encode(\"@smonn/ids/wrapped/hmac\");\n\ndeclare const wrappingKeyBrand: unique symbol;\n\n/**\n * Opaque imported handle for one operator wrapping secret.\n *\n * Holds derived AES and HMAC subkeys internally; callers never access subkeys\n * or raw `webcrypto.CryptoKey` values directly. Obtain handles via {@link importWrappingKey}\n * and pass them to `createWrappedKeyId` as the `keys` wrapping keyring.\n *\n * Distinct from the **Opaque key** used by `@smonn/ids/opaque` — one raw\n * secret must not silently serve both codecs without an explicit import.\n */\nexport type WrappingKey = {\n readonly [wrappingKeyBrand]: \"WrappingKey\";\n};\n\ntype WrappingKeyInternals = {\n keyDigest: Uint8Array;\n aesKey: webcrypto.CryptoKey;\n hmacKey: webcrypto.CryptoKey;\n};\n\nexport type WrappingKeyMaterial = {\n aesKey: webcrypto.CryptoKey;\n hmacKey: webcrypto.CryptoKey;\n};\n\nconst internals = new WeakMap<WrappingKey, WrappingKeyInternals>();\n\n/**\n * Import raw operator secret bytes into a {@link WrappingKey} handle.\n *\n * One raw secret derives into AES and HMAC subkeys held inside the returned\n * handle. Accepts 16, 24, or 32 bytes (AES-128 / AES-192 / AES-256 strength).\n * To store or transport key material, use {@link encodeWrappingKey} /\n * {@link decodeWrappingKey} (`\"hex\"` or `\"base64url\"` — not Crockford base32).\n *\n * @param bytes - 16, 24, or 32 raw key bytes.\n * @throws {IdsError} `invalid_key_length` if `bytes.length` is not 16, 24, or 32.\n */\nexport async function importWrappingKey(bytes: Uint8Array): Promise<WrappingKey> {\n assertValidKeyMaterialByteLength(bytes.length, \"wrapping\");\n const [aesKey, hmacKey, digestBuffer] = await Promise.all([\n deriveKey(bytes, aesInfo, { name: \"AES-CBC\", length: 256 }, [\"encrypt\", \"decrypt\"]),\n deriveKey(bytes, hmacInfo, { name: \"HMAC\", hash: \"SHA-256\", length: 256 }, [\"sign\", \"verify\"]),\n crypto.subtle.digest(\"SHA-256\", bytes as Uint8Array<ArrayBuffer>),\n ]);\n const key = Object.freeze({}) as WrappingKey;\n internals.set(key, {\n keyDigest: new Uint8Array(digestBuffer),\n aesKey,\n hmacKey,\n });\n return key;\n}\n\n/**\n * Encode raw wrapping operator secret bytes for storage in env vars or secret managers.\n *\n * Supports `\"hex\"` (lowercase) and `\"base64url\"`. Output round-trips through\n * {@link decodeWrappingKey} back to the original bytes.\n *\n * @throws {IdsError} `invalid_key_format` if `format` is not `\"hex\"` or `\"base64url\"`.\n * @throws {IdsError} `invalid_key_length` if `bytes.length` is not 16, 24, or 32.\n */\nexport function encodeWrappingKey(bytes: Uint8Array, format: WrappingKeyFormat): string {\n return encodeKeyMaterial(bytes, format, \"wrapping\", \"wrapping\");\n}\n\n/**\n * Decode key material emitted by {@link encodeWrappingKey} back to raw bytes.\n *\n * The result can be passed directly to {@link importWrappingKey}.\n *\n * @throws {IdsError} `invalid_key_format` if `format` is not `\"hex\"` or `\"base64url\"`.\n * @throws {IdsError} `invalid_key_encoding` if the string is malformed for its format.\n * @throws {IdsError} `invalid_key_length` if the decoded bytes are not 16, 24, or 32 bytes.\n */\nexport function decodeWrappingKey(encoded: string, format: WrappingKeyFormat): Uint8Array {\n return decodeKeyMaterial(encoded, format, \"wrapping\", \"wrapping\");\n}\n\n/**\n * Returns true when two handles were imported from the same raw operator secret.\n *\n * Uses a constant-time comparison so duplicate detection over key material does\n * not leak the position of the first differing byte through a timing side channel.\n */\nexport function wrappingKeysEqual(a: WrappingKey, b: WrappingKey): boolean {\n return timingSafeEqual(\n getWrappingKeyInternals(a).keyDigest,\n getWrappingKeyInternals(b).keyDigest,\n );\n}\n\nexport function getWrappingKeyMaterial(key: WrappingKey): WrappingKeyMaterial {\n const keyInternals = getWrappingKeyInternals(key);\n return {\n aesKey: keyInternals.aesKey,\n hmacKey: keyInternals.hmacKey,\n };\n}\n\nfunction getWrappingKeyInternals(key: WrappingKey): WrappingKeyInternals {\n const keyInternals = internals.get(key);\n if (keyInternals === undefined) {\n throw new Error(\"invalid wrapping key\");\n }\n return keyInternals;\n}\n","import { validateBrand } from \"../_kernel/brand.js\";\nimport { IdsError } from \"../../error.js\";\nimport { createWrappedLayoutOps } from \"./layout.js\";\nimport { registerBrand } from \"../_kernel/registry.js\";\nimport type {\n Id,\n JsonSchema,\n ParseError,\n ParseResult,\n Prefix,\n StandardSchemaProps,\n ValidBrand,\n} from \"../../types.js\";\nimport { wireMethods } from \"../../wire/codec-shell.js\";\nimport {\n assertValidKeyring,\n decodeWrappingKey,\n encodeWrappingKey,\n getWrappingKeyMaterial,\n importWrappingKey,\n type WrappingKey,\n type WrappingKeyFormat,\n wrappingKeysEqual,\n} from \"./key.js\";\n\n/** {@link IdsError} class, {@link isIdsError} type guard, and {@link IdsErrorCode} union — re-exported from `\"@smonn/ids\"` for convenience. */\nexport { IdsError, isIdsError, type IdsErrorCode } from \"../../error.js\";\nexport {\n decodeWrappingKey,\n encodeWrappingKey,\n importWrappingKey,\n type WrappingKey,\n type WrappingKeyFormat,\n};\n\n/**\n * Integer kind for a {@link WrappedKeyCodec}, fixed at construction time.\n *\n * - `\"u32\"` — unsigned 32-bit integer; JS type `number`, range `[0, 4 294 967 295]`.\n * - `\"i32\"` — signed 32-bit integer; JS type `number`, range `[-2 147 483 648, 2 147 483 647]`.\n * - `\"u64\"` — unsigned 64-bit integer; JS type `bigint`, range `[0n, 18 446 744 073 709 551 615n]`.\n * - `\"i64\"` — signed 64-bit integer; JS type `bigint`, range `[-9 223 372 036 854 775 808n, 9 223 372 036 854 775 807n]`.\n *\n * 32-bit kinds use safe JavaScript `number` values; 64-bit kinds always use `bigint`\n * even when the magnitude would fit in a `number`, preventing silent truncation or sign erasure.\n */\nexport type WrappedKind = \"u32\" | \"i32\" | \"u64\" | \"i64\";\n\ntype LookupKeyForKind<K extends WrappedKind> = K extends \"u32\" | \"i32\" ? number : bigint;\n\n/**\n * Result returned by {@link WrappedKeyCodec.safeUnwrap}.\n *\n * On success, `id` is the canonical {@link Id} and `lookupKey` is the recovered\n * integer (`number` for 32-bit kinds, `bigint` for 64-bit kinds).\n * On failure, `error` is a {@link ParseError} for structural problems or\n * `\"verification_failed\"` when the payload is structurally valid but the\n * verification tag does not match any entry in the wrapping keyring.\n */\nexport type UnwrapResult<Brand extends string, Kind extends WrappedKind> =\n | { ok: true; id: Id<Brand>; lookupKey: LookupKeyForKind<Kind> }\n | { ok: false; error: ParseError | \"verification_failed\" };\n\n/**\n * Codec returned by {@link createWrappedKeyId}.\n *\n * Wraps a caller-owned integer **lookup key** into a public {@link Id} and\n * recovers it on unwrap. The codec is deterministic under fixed key material:\n * the same lookup key always yields the same public ID (**equality leakage**).\n *\n * - `wrap` / `unwrap` / `safeUnwrap` are async (WebCrypto).\n * - `is`, `parse`, `safeParse`, and `toJsonSchema` are synchronous and require\n * no key material — they validate prefix and base32 shape only.\n * - The `Kind` type parameter drives value types at the TypeScript boundary:\n * `u32` / `i32` → `number`; `u64` / `i64` → `bigint`.\n *\n * @remarks\n * **Security properties (correctness-grade verification, not AEAD):**\n *\n * - The construction is deterministic — the same lookup key always yields the\n * same public ID (**equality leakage**).\n * - The verification tag is a fixed **64-bit (8-byte) truncation** of a\n * domain-separated HMAC over the brand, kind, and lookup key lane.\n * - False-accept rate is approximately `keyring_size / 2^64` per `unwrap`\n * trial — correctness-grade verification, not AEAD-strength origin\n * authentication.\n * - Consumers requiring full AEAD guarantees must use a different construction.\n */\nexport type WrappedKeyCodec<Brand extends string, Kind extends WrappedKind> = {\n /**\n * Wrap `lookupKey` into a public ID using the current (first) wrapping key.\n *\n * Throws if `lookupKey` is out of range or the wrong JS type for `Kind`.\n */\n wrap(lookupKey: LookupKeyForKind<Kind>): Promise<Id<Brand>>;\n /**\n * Verify the payload of a trusted `Id<Brand>` and return the lookup key.\n *\n * Throws `IdsError` with `code: \"verification_failed\"` if no entry in the\n * wrapping keyring matches the payload tag. Use {@link safeUnwrap} for\n * untrusted input.\n */\n unwrap(id: Id<Brand>): Promise<LookupKeyForKind<Kind>>;\n /**\n * Non-throwing path for untrusted input.\n *\n * Structurally parses `input` first (same rules as {@link safeParse}), then\n * verifies the payload. Returns `{ ok: false, error }` on any failure —\n * `ParseError` for structural problems or `\"verification_failed\"` for tag\n * mismatch — without throwing. Tamper, wrong keyring, and revoked-key cases\n * all surface as `\"verification_failed\"`.\n */\n safeUnwrap(input: unknown): Promise<UnwrapResult<Brand, Kind>>;\n /** Strict type guard: `true` only for already-canonical `Id<Brand>` strings. */\n is(value: unknown): value is Id<Brand>;\n /** Normalise to canonical form, or throw on parse failure. */\n parse(value: unknown): Id<Brand>;\n /** Normalise to canonical form, or return `{ ok: false, error }`. */\n safeParse(value: unknown): ParseResult<Brand>;\n toJsonSchema(): JsonSchema;\n readonly \"~standard\": StandardSchemaProps<Brand>;\n /**\n * Converts a trusted `Id<Brand>` to an RFC 9562 canonical (lowercase, hyphenated)\n * UUID string by reinterpreting the 16-byte payload verbatim. Total — cannot fail.\n * Returns a plain `string` (brand is shed). See ADR-0024.\n */\n toUUID(id: Id<Brand>): string;\n /**\n * Parses a UUID string into an `Id<Brand>`. Accepts case-insensitive `8-4-4-4-12`\n * hyphenated form only. Throws `IdsError` with `code: \"invalid_id\"` on bad input.\n * See ADR-0024.\n */\n fromUUID(value: string): Id<Brand>;\n /**\n * Non-throwing UUID parse. Returns `{ ok: true, id }` or\n * `{ ok: false, error: \"not_string\" | \"invalid_uuid\" }`. See ADR-0024.\n */\n safeFromUUID(value: unknown): ParseResult<Brand>;\n};\n\n/**\n * Construction options for {@link createWrappedKeyId}.\n */\nexport type WrappedKeyOptions<K extends WrappedKind> = {\n /** Integer kind for the codec — fixed for the lifetime of the codec. Drives the JS value type (`number` for 32-bit, `bigint` for 64-bit). */\n kind: K;\n /** Non-empty ordered wrapping keyring. The first entry is current (used by `wrap`); all entries are tried on `unwrap`. Duplicate operator secrets are rejected at construction. */\n keys: [WrappingKey, ...WrappingKey[]];\n /** If true, silences the duplicate-brand warning in non-production environments. */\n allowDuplicateBrand?: boolean;\n};\n\nconst u32Max = 0xffff_ffff;\nconst i32Min = -0x8000_0000;\nconst i32Max = 0x7fff_ffff;\nconst u64Max = 0xffff_ffff_ffff_ffffn;\nconst i64Min = -(1n << 63n);\nconst i64Max = (1n << 63n) - 1n;\n\nfunction assertSupportedKind(kind: WrappedKind): asserts kind is WrappedKind {\n if (kind !== \"u32\" && kind !== \"i32\" && kind !== \"u64\" && kind !== \"i64\") {\n throw new IdsError(\"invalid_kind\", \"invalid wrapped key kind: expected u32, i32, u64, or i64\");\n }\n}\n\nfunction assertU32LookupKey(lookupKey: unknown): asserts lookupKey is number {\n if (\n typeof lookupKey !== \"number\" ||\n !Number.isInteger(lookupKey) ||\n Object.is(lookupKey, -0) ||\n lookupKey < 0 ||\n lookupKey > u32Max\n ) {\n throw new IdsError(\n \"invalid_lookup_key\",\n `invalid u32 lookup key: expected integer in [0, ${u32Max}], got ${lookupKey}`,\n );\n }\n}\n\nfunction assertI32LookupKey(lookupKey: unknown): asserts lookupKey is number {\n if (\n typeof lookupKey !== \"number\" ||\n !Number.isInteger(lookupKey) ||\n Object.is(lookupKey, -0) ||\n lookupKey < i32Min ||\n lookupKey > i32Max\n ) {\n throw new IdsError(\n \"invalid_lookup_key\",\n `invalid i32 lookup key: expected integer in [${i32Min}, ${i32Max}], got ${lookupKey}`,\n );\n }\n}\n\nfunction assertU64LookupKey(lookupKey: unknown): asserts lookupKey is bigint {\n if (typeof lookupKey !== \"bigint\" || lookupKey < 0n || lookupKey > u64Max) {\n throw new IdsError(\n \"invalid_lookup_key\",\n `invalid u64 lookup key: expected bigint in [0, ${u64Max}], got ${lookupKey}`,\n );\n }\n}\n\nfunction assertI64LookupKey(lookupKey: unknown): asserts lookupKey is bigint {\n if (typeof lookupKey !== \"bigint\" || lookupKey < i64Min || lookupKey > i64Max) {\n throw new IdsError(\n \"invalid_lookup_key\",\n `invalid i64 lookup key: expected bigint in [${i64Min}, ${i64Max}], got ${lookupKey}`,\n );\n }\n}\n\nfunction assertLookupKey<Kind extends WrappedKind>(\n kind: Kind,\n lookupKey: unknown,\n): asserts lookupKey is LookupKeyForKind<Kind> {\n if (kind === \"i32\") {\n assertI32LookupKey(lookupKey);\n return;\n }\n if (kind === \"u64\") {\n assertU64LookupKey(lookupKey);\n return;\n }\n if (kind === \"i64\") {\n assertI64LookupKey(lookupKey);\n return;\n }\n assertU32LookupKey(lookupKey);\n}\n\n/**\n * Construct a {@link WrappedKeyCodec} for `brand` and the given `kind`.\n *\n * `opts.kind` fixes the integer type at construction time — one brand, one\n * kind. `opts.keys` is a non-empty ordered wrapping keyring: the first entry\n * is current (used by `wrap`); all entries are tried on `unwrap`; duplicate\n * operator secrets are rejected at construction.\n *\n * @example\n * ```ts\n * const key = await importWrappingKey(new Uint8Array(32));\n * const invoices = createWrappedKeyId(\"inv\", { kind: \"u32\", keys: [key] });\n *\n * const id = await invoices.wrap(42); // Id<\"inv\">\n * await invoices.unwrap(id); // 42\n * ```\n */\nexport function createWrappedKeyId<Brand extends string, Kind extends WrappedKind>(\n brand: Brand & ValidBrand<Brand>,\n opts: WrappedKeyOptions<Kind>,\n): WrappedKeyCodec<Brand, Kind> {\n validateBrand(brand);\n registerBrand(brand, opts.allowDuplicateBrand);\n assertSupportedKind(opts.kind);\n assertValidKeyring(opts.keys, wrappingKeysEqual, \"wrapping\");\n const layoutKeys = opts.keys.map(getWrappingKeyMaterial);\n\n const prefix: Prefix<Brand> = `${brand}_`;\n const wire = wireMethods(prefix);\n const layout = createWrappedLayoutOps(prefix, brand, opts.kind, layoutKeys);\n\n return {\n wrap: async (lookupKey) => {\n assertLookupKey(opts.kind, lookupKey);\n return layout.wrap(lookupKey);\n },\n unwrap: async (id) => {\n const lookupKey = await layout.tryUnwrap(id);\n if (lookupKey === null) {\n throw new IdsError(\"verification_failed\", \"verification failed\");\n }\n return lookupKey;\n },\n safeUnwrap: async (input) => {\n const parsed = wire.safeParse(input);\n if (!parsed.ok) return parsed;\n const lookupKey = await layout.tryUnwrap(parsed.id);\n if (lookupKey === null) return { ok: false, error: \"verification_failed\" };\n return { ok: true, id: parsed.id, lookupKey };\n },\n is: wire.is,\n parse: wire.parse,\n safeParse: wire.safeParse,\n toJsonSchema: () => wire.toJsonSchema(brand, layout.exampleWireId()),\n \"~standard\": wire[\"~standard\"],\n toUUID: wire.toUUID,\n fromUUID: wire.fromUUID,\n safeFromUUID: wire.safeFromUUID,\n };\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { a as StandardSchemaProps, i as ParseResult, n as JsonSchema, o as ValidBrand, r as ParseError, t as Id } from "./types-wplmOgOK.mjs";
2
- import { n as IdsErrorCode, r as isIdsError, t as IdsError } from "./error-Dqyho9vp.mjs";
1
+ import { a as StandardSchemaProps, i as ParseResult, n as JsonSchema, o as ValidBrand, r as ParseError, t as Id } from "./types-hGBnCpJj.mjs";
2
+ import { n as IdsErrorCode, r as isIdsError, t as IdsError } from "./error-CifcKKOG.mjs";
3
3
 
4
4
  //#region src/codecs/wrapped/key.d.ts
5
5
  /** Wire encoding for wrapping operator secret bytes (not Crockford base32). */
@@ -27,6 +27,7 @@ type WrappingKey = {
27
27
  * {@link decodeWrappingKey} (`"hex"` or `"base64url"` — not Crockford base32).
28
28
  *
29
29
  * @param bytes - 16, 24, or 32 raw key bytes.
30
+ * @throws {IdsError} `invalid_key_length` if `bytes.length` is not 16, 24, or 32.
30
31
  */
31
32
  declare function importWrappingKey(bytes: Uint8Array): Promise<WrappingKey>;
32
33
  /**
@@ -34,12 +35,19 @@ declare function importWrappingKey(bytes: Uint8Array): Promise<WrappingKey>;
34
35
  *
35
36
  * Supports `"hex"` (lowercase) and `"base64url"`. Output round-trips through
36
37
  * {@link decodeWrappingKey} back to the original bytes.
38
+ *
39
+ * @throws {IdsError} `invalid_key_format` if `format` is not `"hex"` or `"base64url"`.
40
+ * @throws {IdsError} `invalid_key_length` if `bytes.length` is not 16, 24, or 32.
37
41
  */
38
42
  declare function encodeWrappingKey(bytes: Uint8Array, format: WrappingKeyFormat): string;
39
43
  /**
40
44
  * Decode key material emitted by {@link encodeWrappingKey} back to raw bytes.
41
45
  *
42
46
  * The result can be passed directly to {@link importWrappingKey}.
47
+ *
48
+ * @throws {IdsError} `invalid_key_format` if `format` is not `"hex"` or `"base64url"`.
49
+ * @throws {IdsError} `invalid_key_encoding` if the string is malformed for its format.
50
+ * @throws {IdsError} `invalid_key_length` if the decoded bytes are not 16, 24, or 32 bytes.
43
51
  */
44
52
  declare function decodeWrappingKey(encoded: string, format: WrappingKeyFormat): Uint8Array;
45
53
  //#endregion
@@ -129,6 +137,23 @@ type WrappedKeyCodec<Brand extends string, Kind extends WrappedKind> = {
129
137
  safeParse(value: unknown): ParseResult<Brand>;
130
138
  toJsonSchema(): JsonSchema;
131
139
  readonly "~standard": StandardSchemaProps<Brand>;
140
+ /**
141
+ * Converts a trusted `Id<Brand>` to an RFC 9562 canonical (lowercase, hyphenated)
142
+ * UUID string by reinterpreting the 16-byte payload verbatim. Total — cannot fail.
143
+ * Returns a plain `string` (brand is shed). See ADR-0024.
144
+ */
145
+ toUUID(id: Id<Brand>): string;
146
+ /**
147
+ * Parses a UUID string into an `Id<Brand>`. Accepts case-insensitive `8-4-4-4-12`
148
+ * hyphenated form only. Throws `IdsError` with `code: "invalid_id"` on bad input.
149
+ * See ADR-0024.
150
+ */
151
+ fromUUID(value: string): Id<Brand>;
152
+ /**
153
+ * Non-throwing UUID parse. Returns `{ ok: true, id }` or
154
+ * `{ ok: false, error: "not_string" | "invalid_uuid" }`. See ADR-0024.
155
+ */
156
+ safeFromUUID(value: unknown): ParseResult<Brand>;
132
157
  };
133
158
  /**
134
159
  * Construction options for {@link createWrappedKeyId}.
@@ -1 +1 @@
1
- {"version":3,"file":"wrapped.d.mts","names":[],"sources":["../src/codecs/wrapped/key.ts","../src/codecs/wrapped/index.ts"],"mappings":";;;;;KAYY,iBAAA;AAAA,cAKE,gBAAA;;;AALF;AAA4B;;;;AAK1B;AAYd;;KAAY,WAAA;EAAA,UACA,gBAAA;AAAA;;;;;;;;;;AA0BwD;iBAA9C,iBAAA,CAAkB,KAAA,EAAO,UAAA,GAAa,OAAA,CAAQ,WAAA;;;;;;;iBAsBpD,iBAAA,CAAkB,KAAA,EAAO,UAAA,EAAY,MAAA,EAAQ,iBAAA;;AAAA;AAS7D;;;iBAAgB,iBAAA,CAAkB,OAAA,UAAiB,MAAA,EAAQ,iBAAA,GAAoB,UAAA;;;;;;AA3EnE;AAA4B;;;;AAK1B;AAYd;;KCiBY,WAAA;AAAA,KAEP,gBAAA,WAA2B,WAAA,IAAe,CAAA;ADlBnC;AA0BZ;;;;;;;;AA1BY,KC6BA,YAAA,oCAAgD,WAAA;EACtD,EAAA;EAAU,EAAA,EAAI,EAAA,CAAG,KAAA;EAAQ,SAAA,EAAW,gBAAA,CAAiB,IAAA;AAAA;EACrD,EAAA;EAAW,KAAA,EAAO,UAAA;AAAA;;;;;ADiBqC;AAS7D;;;;;;;;;AAA+E;;;;ACzC/E;;;;AAAY;AAAsC;;KA0CtC,eAAA,oCAAmD,WAAA;;;AAxChB;AAW/C;;EAmCE,IAAA,CAAK,SAAA,EAAW,gBAAA,CAAiB,IAAA,IAAQ,OAAA,CAAQ,EAAA,CAAG,KAAA;;;;;;;;EAQpD,MAAA,CAAO,EAAA,EAAI,EAAA,CAAG,KAAA,IAAS,OAAA,CAAQ,gBAAA,CAAiB,IAAA;;;;;;;;;;EAUhD,UAAA,CAAW,KAAA,YAAiB,OAAA,CAAQ,YAAA,CAAa,KAAA,EAAO,IAAA;EAExD,EAAA,CAAG,KAAA,YAAiB,KAAA,IAAS,EAAA,CAAG,KAAA;EAEhC,KAAA,CAAM,KAAA,YAAiB,EAAA,CAAG,KAAA,GAvDJ;EAyDtB,SAAA,CAAU,KAAA,YAAiB,WAAA,CAAY,KAAA;EACvC,YAAA,IAAgB,UAAA;EAAA,SACP,WAAA,EAAa,mBAAA,CAAoB,KAAA;AAAA;;;;KAMhC,iBAAA,WAA4B,WAAA;+IAEtC,IAAA,EAAM,CAAA;EAEN,IAAA,GAAO,WAAA,KAAgB,WAAA;EAEvB,mBAAA;AAAA;;;;;;;;;;;;;;;;;;iBAoGc,kBAAA,oCAAsD,WAAA,EACpE,KAAA,EAAO,KAAA,GAAQ,UAAA,CAAW,KAAA,GAC1B,IAAA,EAAM,iBAAA,CAAkB,IAAA,IACvB,eAAA,CAAgB,KAAA,EAAO,IAAA"}
1
+ {"version":3,"file":"wrapped.d.mts","names":[],"sources":["../src/codecs/wrapped/key.ts","../src/codecs/wrapped/index.ts"],"mappings":";;;;;KAYY,iBAAA;AAAA,cAKE,gBAAA;;;AALF;AAA4B;;;;AAK1B;AAYd;;KAAY,WAAA;EAAA,UACA,gBAAA;AAAA;;;;;;;;;;AA2BwD;AAyBpE;iBAzBsB,iBAAA,CAAkB,KAAA,EAAO,UAAA,GAAa,OAAA,CAAQ,WAAA;;;;;;;;AAyBP;AAa7D;iBAbgB,iBAAA,CAAkB,KAAA,EAAO,UAAA,EAAY,MAAA,EAAQ,iBAAA;;;;;;;;AAakB;;iBAA/D,iBAAA,CAAkB,OAAA,UAAiB,MAAA,EAAQ,iBAAA,GAAoB,UAAA;;;;;;AAnFnE;AAA4B;;;;AAK1B;AAYd;;KCiBY,WAAA;AAAA,KAEP,gBAAA,WAA2B,WAAA,IAAe,CAAA;ADlBnC;AA2BZ;;;;;;;;AA3BY,KC6BA,YAAA,oCAAgD,WAAA;EACtD,EAAA;EAAU,EAAA,EAAI,EAAA,CAAG,KAAA;EAAQ,SAAA,EAAW,gBAAA,CAAiB,IAAA;AAAA;EACrD,EAAA;EAAW,KAAA,EAAO,UAAA;AAAA;;;;;ADqBqC;AAa7D;;;;;;;;;AAA+E;;;;ACjD/E;;;;AAAY;AAAsC;;KA0CtC,eAAA,oCAAmD,WAAA;;;AAxChB;AAW/C;;EAmCE,IAAA,CAAK,SAAA,EAAW,gBAAA,CAAiB,IAAA,IAAQ,OAAA,CAAQ,EAAA,CAAG,KAAA;;;;;;;;EAQpD,MAAA,CAAO,EAAA,EAAI,EAAA,CAAG,KAAA,IAAS,OAAA,CAAQ,gBAAA,CAAiB,IAAA;;;;;;;;;;EAUhD,UAAA,CAAW,KAAA,YAAiB,OAAA,CAAQ,YAAA,CAAa,KAAA,EAAO,IAAA;EAExD,EAAA,CAAG,KAAA,YAAiB,KAAA,IAAS,EAAA,CAAG,KAAA;EAEhC,KAAA,CAAM,KAAA,YAAiB,EAAA,CAAG,KAAA,GAvDJ;EAyDtB,SAAA,CAAU,KAAA,YAAiB,WAAA,CAAY,KAAA;EACvC,YAAA,IAAgB,UAAA;EAAA,SACP,WAAA,EAAa,mBAAA,CAAoB,KAAA;;;;;;EAM1C,MAAA,CAAO,EAAA,EAAI,EAAA,CAAG,KAAA;;;;;;EAMd,QAAA,CAAS,KAAA,WAAgB,EAAA,CAAG,KAAA;;;;;EAK5B,YAAA,CAAa,KAAA,YAAiB,WAAA,CAAY,KAAA;AAAA;;;;KAMhC,iBAAA,WAA4B,WAAA;+IAEtC,IAAA,EAAM,CAAA;EAEN,IAAA,GAAO,WAAA,KAAgB,WAAA;EAEvB,mBAAA;AAAA;;;;;;;;;;;;;;;;;;iBAoGc,kBAAA,oCAAsD,WAAA,EACpE,KAAA,EAAO,KAAA,GAAQ,UAAA,CAAW,KAAA,GAC1B,IAAA,EAAM,iBAAA,CAAkB,IAAA,IACvB,eAAA,CAAgB,KAAA,EAAO,IAAA"}
package/dist/wrapped.mjs CHANGED
@@ -1,3 +1,3 @@
1
1
  import { n as isIdsError, t as IdsError } from "./error-Cp5qYZcv.mjs";
2
- import { i as importWrappingKey, n as decodeWrappingKey, r as encodeWrappingKey, t as createWrappedKeyId } from "./wrapped-DPlsv1x-.mjs";
2
+ import { i as importWrappingKey, n as decodeWrappingKey, r as encodeWrappingKey, t as createWrappedKeyId } from "./wrapped-Oj2hC1vB.mjs";
3
3
  export { IdsError, createWrappedKeyId, decodeWrappingKey, encodeWrappingKey, importWrappingKey, isIdsError };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smonn/ids",
3
- "version": "0.13.1",
3
+ "version": "0.14.1",
4
4
  "license": "MIT",
5
5
  "author": "Simon Ingeson (https://github.com/smonn)",
6
6
  "repository": {
@@ -11,7 +11,8 @@
11
11
  "ids": "./dist/cli.mjs"
12
12
  },
13
13
  "files": [
14
- "dist"
14
+ "dist",
15
+ "spec/vectors.json"
15
16
  ],
16
17
  "type": "module",
17
18
  "types": "./dist/index.d.mts",