@smonn/ids 0.8.0 → 0.9.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 (71) hide show
  1. package/README.md +210 -32
  2. package/dist/adapter-types-BY-wrYYB.mjs +27 -0
  3. package/dist/adapter-types-BY-wrYYB.mjs.map +1 -0
  4. package/dist/adapter-types-unUcmMXC.d.mts +20 -0
  5. package/dist/adapter-types-unUcmMXC.d.mts.map +1 -0
  6. package/dist/cli.mjs +342 -71
  7. package/dist/cli.mjs.map +1 -1
  8. package/dist/{codec-shell-DH-UO4UR.mjs → codec-shell-CW2sD6BU.mjs} +6 -5
  9. package/dist/codec-shell-CW2sD6BU.mjs.map +1 -0
  10. package/dist/drizzle.d.mts +33 -2
  11. package/dist/drizzle.d.mts.map +1 -0
  12. package/dist/drizzle.mjs +2 -3
  13. package/dist/drizzle.mjs.map +1 -1
  14. package/dist/express.d.mts +2 -5
  15. package/dist/express.d.mts.map +1 -1
  16. package/dist/express.mjs +3 -8
  17. package/dist/express.mjs.map +1 -1
  18. package/dist/fastify.d.mts +2 -5
  19. package/dist/fastify.d.mts.map +1 -1
  20. package/dist/fastify.mjs +3 -8
  21. package/dist/fastify.mjs.map +1 -1
  22. package/dist/hono.d.mts +2 -5
  23. package/dist/hono.d.mts.map +1 -1
  24. package/dist/hono.mjs +3 -8
  25. package/dist/hono.mjs.map +1 -1
  26. package/dist/index.mjs +1 -1
  27. package/dist/key-material-gOnqTNoV.mjs +137 -0
  28. package/dist/key-material-gOnqTNoV.mjs.map +1 -0
  29. package/dist/kysely.d.mts +1 -1
  30. package/dist/kysely.mjs +2 -3
  31. package/dist/kysely.mjs.map +1 -1
  32. package/dist/{opaque-uvjOFY_0.mjs → opaque-BpqxV8oB.mjs} +12 -48
  33. package/dist/opaque-BpqxV8oB.mjs.map +1 -0
  34. package/dist/opaque.d.mts +8 -0
  35. package/dist/opaque.d.mts.map +1 -1
  36. package/dist/opaque.mjs +1 -1
  37. package/dist/prisma.d.mts +4 -18
  38. package/dist/prisma.d.mts.map +1 -1
  39. package/dist/prisma.mjs +3 -5
  40. package/dist/prisma.mjs.map +1 -1
  41. package/dist/{reverse-BgFU6JHw.mjs → reverse-d5uEoIET.mjs} +5 -7
  42. package/dist/reverse-d5uEoIET.mjs.map +1 -0
  43. package/dist/reverse.d.mts.map +1 -1
  44. package/dist/reverse.mjs +1 -1
  45. package/dist/rng-CPJOx_nE.mjs +9 -0
  46. package/dist/rng-CPJOx_nE.mjs.map +1 -0
  47. package/dist/signed-BnRSC03a.mjs +207 -0
  48. package/dist/signed-BnRSC03a.mjs.map +1 -0
  49. package/dist/signed.d.mts.map +1 -1
  50. package/dist/signed.mjs +1 -255
  51. package/dist/{timestamp-B5_UCzc6.mjs → timestamp-BbZL8hwg.mjs} +5 -5
  52. package/dist/{timestamp-B5_UCzc6.mjs.map → timestamp-BbZL8hwg.mjs.map} +1 -1
  53. package/dist/{timestamp-bytes-BBY7JI33.mjs → timestamp-bytes-DoFjLjDp.mjs} +3 -2
  54. package/dist/timestamp-bytes-DoFjLjDp.mjs.map +1 -0
  55. package/dist/{wrapped-0vL72Nje.mjs → wrapped-BI9UXnAm.mjs} +33 -62
  56. package/dist/wrapped-BI9UXnAm.mjs.map +1 -0
  57. package/dist/wrapped.d.mts.map +1 -1
  58. package/dist/wrapped.mjs +1 -1
  59. package/package.json +5 -5
  60. package/dist/adapter-types-oHCCSgOO.d.mts +0 -12
  61. package/dist/adapter-types-oHCCSgOO.d.mts.map +0 -1
  62. package/dist/bytes-lhzKVaBV.mjs +0 -53
  63. package/dist/bytes-lhzKVaBV.mjs.map +0 -1
  64. package/dist/codec-shell-DH-UO4UR.mjs.map +0 -1
  65. package/dist/drizzle-CeSni5PB.d.mts +0 -44
  66. package/dist/drizzle-CeSni5PB.d.mts.map +0 -1
  67. package/dist/opaque-uvjOFY_0.mjs.map +0 -1
  68. package/dist/reverse-BgFU6JHw.mjs.map +0 -1
  69. package/dist/signed.mjs.map +0 -1
  70. package/dist/timestamp-bytes-BBY7JI33.mjs.map +0 -1
  71. package/dist/wrapped-0vL72Nje.mjs.map +0 -1
package/dist/cli.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.mjs","names":["parseKeyFormatFlag"],"sources":["../src/cli/codec-options.ts","../src/cli/format.ts","../src/cli/constants.ts","../src/cli/flags.ts","../src/cli/opaque-key.ts","../src/cli/commands/generate.ts","../src/cli/wrapping-key.ts","../src/cli/usage.ts","../src/cli/commands/inspect.ts","../src/cli/commands/keygen.ts","../src/cli.ts","../bin/cli.ts"],"sourcesContent":["import type { TimestampOptions } from \"../timestamp.js\";\nimport type { RunOpts } from \"./types.js\";\n\nexport function codecOpts(opts: RunOpts): Partial<TimestampOptions> {\n // CLI invocations are intentionally ephemeral: one codec per run, never\n // retained, so this is not the duplicate-brand warning case.\n const o: Partial<TimestampOptions> = { allowDuplicateBrand: true };\n if (opts.now !== undefined) o.now = opts.now;\n if (opts.rng !== undefined) o.rng = opts.rng;\n return o;\n}\n","import { isIdsError } from \"../error.js\";\nimport type { Id } from \"../types.js\";\n\ntype InspectOutput = {\n brand: string;\n timestamp: Date;\n canonical: Id<string>;\n input: string;\n nowMs: number;\n};\n\ntype WrappedInspectOutput = {\n brand: string;\n lookupKey: number | bigint;\n canonical: Id<string>;\n input: string;\n};\n\nexport function formatCliError(err: unknown): string {\n return isIdsError(err)\n ? `${err.code}: ${err.message}`\n : err instanceof Error\n ? err.message\n : String(err);\n}\n\nexport function formatWrappedInspectOutput(result: WrappedInspectOutput): string {\n const inputLine = describeInputForm(result.input, result.canonical);\n return [\n `brand: ${result.brand}`,\n `lookup-key: ${result.lookupKey.toString()}`,\n `canonical: ${result.canonical}`,\n `input: ${inputLine}`,\n \"\",\n ].join(\"\\n\");\n}\n\nexport function formatInspectOutput(result: InspectOutput): string {\n const relative = formatRelative(result.timestamp.getTime(), result.nowMs);\n const inputLine = describeInputForm(result.input, result.canonical);\n return [\n `brand: ${result.brand}`,\n `timestamp: ${result.timestamp.toISOString()} (${relative})`,\n `canonical: ${result.canonical}`,\n `input: ${inputLine}`,\n \"\",\n ].join(\"\\n\");\n}\n\nexport function describeInputForm(input: string, canonical: Id<string>): string {\n if (input === canonical) return \"canonical\";\n const notes: string[] = [];\n if (input !== input.toLowerCase()) notes.push(\"was uppercase\");\n if (/[ilo]/i.test(input.slice(4))) notes.push(\"used Crockford aliases\");\n return `not canonical (${notes.join(\" + \")})`;\n}\n\nconst msPerSecond = 1000;\nconst msPerMinute = 60 * msPerSecond;\nconst msPerHour = 60 * msPerMinute;\nconst msPerDay = 24 * msPerHour;\nconst daysPerMonth = 30.44;\nconst monthsPerYear = 12;\n\nexport function formatRelative(thenMs: number, nowMs: number): string {\n const diff = nowMs - thenMs;\n const abs = Math.abs(diff);\n const suffix = diff < 0 ? \"from now\" : \"ago\";\n\n const head = headUnits(abs);\n return head === \"\" ? \"just now\" : `${head} ${suffix}`;\n}\n\nfunction headUnits(abs: number): string {\n if (abs < msPerMinute) return \"\";\n if (abs < msPerHour) return unit(Math.round(abs / msPerMinute), \"minute\");\n if (abs < msPerDay) return unit(Math.round(abs / msPerHour), \"hour\");\n if (abs < msPerDay * daysPerMonth) return unit(Math.round(abs / msPerDay), \"day\");\n\n const totalMonths = Math.round(abs / (msPerDay * daysPerMonth));\n if (totalMonths < monthsPerYear) return unit(totalMonths, \"month\");\n\n const years = Math.floor(totalMonths / monthsPerYear);\n const months = totalMonths % monthsPerYear;\n return months === 0 ? unit(years, \"year\") : `${unit(years, \"year\")} ${unit(months, \"month\")}`;\n}\n\nfunction unit(n: number, name: string): string {\n return `${n} ${n === 1 ? name : `${name}s`}`;\n}\n","export const maxGenerateCount = 10_000;\n","import { maxGenerateCount } from \"./constants.js\";\n\nexport type ParsedFlags = {\n flags: Set<string>;\n values: Map<string, string>;\n positionals: string[];\n errors: string[];\n};\n\nfunction splitFlagToken(arg: string): { flag: string; inlineValue: string | undefined } {\n const eq = arg.indexOf(\"=\");\n if (eq <= 0) return { flag: arg, inlineValue: undefined };\n return { flag: arg.slice(0, eq), inlineValue: arg.slice(eq + 1) };\n}\n\nexport function splitFlags(args: ReadonlyArray<string>): ParsedFlags {\n const flags = new Set<string>();\n const values = new Map<string, string>();\n const positionals: string[] = [];\n const errors: string[] = [];\n const seenFlags = new Set<string>();\n const valueFlags = new Set([\"--count\", \"-c\", \"--bits\", \"--key-format\", \"--kind\"]);\n const addFlag = (flag: string) => {\n const canonical = canonicalFlag(flag);\n if (seenFlags.has(canonical)) errors.push(`duplicate flag: ${canonical}`);\n seenFlags.add(canonical);\n flags.add(flag);\n };\n for (let i = 0; i < args.length; i++) {\n const raw = args[i]!;\n const { flag, inlineValue } = splitFlagToken(raw);\n if (flag === \"--opaque\" || flag === \"--wrapped\" || flag === \"--reverse\") {\n addFlag(flag);\n if (inlineValue !== undefined) errors.push(`flag does not take a value: ${flag}`);\n continue;\n }\n if (valueFlags.has(flag)) {\n if (inlineValue !== undefined) {\n addFlag(flag);\n values.set(flag, inlineValue);\n continue;\n }\n const value = args[i + 1];\n if (value === undefined || value.startsWith(\"-\")) {\n addFlag(flag);\n values.set(flag, \"\");\n continue;\n }\n addFlag(flag);\n values.set(flag, value);\n i++;\n continue;\n }\n if (flag.startsWith(\"-\")) {\n addFlag(flag);\n continue;\n }\n positionals.push(raw);\n }\n return { flags, values, positionals, errors };\n}\n\nfunction canonicalFlag(flag: string): string {\n if (flag === \"-c\") return \"--count\";\n return flag;\n}\n\nconst knownFlags = new Set([\n \"--opaque\",\n \"--wrapped\",\n \"--reverse\",\n \"--kind\",\n \"--key-format\",\n \"--count\",\n \"-c\",\n \"--bits\",\n]);\n\nexport function unsupportedFlagForCommand(\n command: string,\n flags: Set<string>,\n allowed: Set<string>,\n): string | undefined {\n for (const flag of flags) {\n if (!allowed.has(flag)) {\n return knownFlags.has(flag)\n ? `unsupported flag for ${command}: ${flag}`\n : `unsupported flag: ${flag}`;\n }\n }\n return undefined;\n}\n\nexport function parseCount(values: Map<string, string>): number | string {\n const raw = values.get(\"--count\") ?? values.get(\"-c\");\n if (raw === undefined) return 1;\n if (raw === \"\") return \"--count requires a value\";\n if (!/^[1-9][0-9]*$/.test(raw)) return `--count must be a positive integer, got '${raw}'`;\n const count = Number.parseInt(raw, 10);\n if (!Number.isSafeInteger(count) || count > maxGenerateCount) {\n return `--count must be at most ${maxGenerateCount}, got '${raw}'`;\n }\n return count;\n}\n\nexport function parseBits(values: Map<string, string>): number | string {\n const raw = values.get(\"--bits\");\n if (raw === undefined) return 256;\n if (raw === \"\") return \"--bits requires a value\";\n if (raw === \"128\") return 128;\n if (raw === \"192\") return 192;\n if (raw === \"256\") return 256;\n return `--bits must be 128, 192, or 256, got '${raw}'`;\n}\n\nexport type WrappedKindValue = \"u32\" | \"i32\" | \"u64\" | \"i64\";\n\nexport function parseKind(values: Map<string, string>): WrappedKindValue | string | undefined {\n const raw = values.get(\"--kind\");\n if (raw === undefined) return undefined;\n if (raw === \"\") return \"--kind requires a value\";\n if (raw === \"u32\" || raw === \"i32\" || raw === \"u64\" || raw === \"i64\") return raw;\n return `--kind must be u32, i32, u64, or i64, got '${raw}'`;\n}\n\nexport function isKindError(result: WrappedKindValue | string): result is string {\n return result !== \"u32\" && result !== \"i32\" && result !== \"u64\" && result !== \"i64\";\n}\n","import {\n decodeOpaqueKey,\n importOpaqueKey,\n type OpaqueKey,\n type OpaqueKeyFormat,\n} from \"../opaque.js\";\nimport type { RunOpts } from \"./types.js\";\n\nexport function isKeyFormatError(result: OpaqueKeyFormat | string): result is string {\n return result !== \"hex\" && result !== \"base64url\";\n}\n\nfunction parseKeyFormatFlag(values: Map<string, string>): OpaqueKeyFormat | string | undefined {\n const fromFlag = values.get(\"--key-format\");\n if (fromFlag === undefined) return undefined;\n if (fromFlag === \"\") return \"--key-format requires a value\";\n if (fromFlag === \"hex\" || fromFlag === \"base64url\") return fromFlag;\n return `--key-format must be hex or base64url, got '${fromFlag}'`;\n}\n\nexport function parseKeygenFormat(values: Map<string, string>): OpaqueKeyFormat | string {\n const fromFlag = parseKeyFormatFlag(values);\n if (fromFlag === undefined) return \"hex\";\n return fromFlag;\n}\n\nexport function parseOpaqueKeyFormat(\n values: Map<string, string>,\n opts: RunOpts,\n): OpaqueKeyFormat | string {\n const fromFlag = parseKeyFormatFlag(values);\n if (fromFlag !== undefined) return fromFlag;\n const env = opts.env ?? process.env;\n const fromEnv = env.IDS_KEY_FORMAT;\n if (fromEnv === undefined || fromEnv === \"\") return \"hex\";\n if (fromEnv === \"hex\" || fromEnv === \"base64url\") return fromEnv;\n return `IDS_KEY_FORMAT must be hex or base64url, got '${fromEnv}'`;\n}\n\nexport async function loadOpaqueKey(\n opts: RunOpts,\n format: OpaqueKeyFormat,\n): Promise<OpaqueKey | string> {\n const env = opts.env ?? process.env;\n const raw = env.IDS_KEY;\n if (raw === undefined || raw === \"\") return \"missing IDS_KEY environment variable\";\n try {\n return importOpaqueKey(decodeOpaqueKey(raw, format));\n } catch (err) {\n return (err as Error).message;\n }\n}\n","import { createTimestampId } from \"../../timestamp.js\";\nimport { createOpaqueTimestampId, type OpaqueKeyFormat } from \"../../opaque.js\";\nimport { createReverseTimestampId } from \"../../reverse.js\";\nimport { codecOpts } from \"../codec-options.js\";\nimport { formatCliError } from \"../format.js\";\nimport { parseCount, splitFlags, unsupportedFlagForCommand } from \"../flags.js\";\nimport { isKeyFormatError, loadOpaqueKey, parseOpaqueKeyFormat } from \"../opaque-key.js\";\nimport type { RunOpts } from \"../types.js\";\n\nexport function runGenerate(args: ReadonlyArray<string>, opts: RunOpts): Promise<number> {\n const { flags, values, positionals, errors } = splitFlags(args);\n const unsupported = unsupportedFlagForCommand(\n \"generate\",\n flags,\n new Set([\"--count\", \"-c\", \"--opaque\", \"--reverse\", \"--key-format\"]),\n );\n if (unsupported !== undefined) {\n opts.stderr(unsupported + \"\\n\");\n return Promise.resolve(1);\n }\n if (errors[0] !== undefined) {\n opts.stderr(errors[0] + \"\\n\");\n return Promise.resolve(1);\n }\n const extra = positionals[1];\n if (extra !== undefined) {\n opts.stderr(`unexpected argument: ${extra}\\n`);\n return Promise.resolve(1);\n }\n const [brand] = positionals;\n const count = parseCount(values);\n if (typeof count === \"string\") {\n opts.stderr(count + \"\\n\");\n return Promise.resolve(1);\n }\n const opaque = flags.has(\"--opaque\");\n const reverse = flags.has(\"--reverse\");\n if (reverse && opaque) {\n opts.stderr(\"cannot use --reverse and --opaque together\\n\");\n return Promise.resolve(1);\n }\n if (!opaque && flags.has(\"--key-format\")) {\n opts.stderr(\"--key-format requires --opaque\\n\");\n return Promise.resolve(1);\n }\n if (opaque) {\n const format = parseOpaqueKeyFormat(values, opts);\n if (isKeyFormatError(format)) {\n opts.stderr(format + \"\\n\");\n return Promise.resolve(1);\n }\n return runOpaqueGenerate(brand ?? \"\", count, format, opts);\n }\n if (reverse) {\n let codec;\n try {\n codec = createReverseTimestampId(brand ?? \"\", codecOpts(opts));\n } catch (err) {\n opts.stderr(formatCliError(err) + \"\\n\");\n return Promise.resolve(1);\n }\n for (let i = 0; i < count; i++) opts.stdout(codec.generate() + \"\\n\");\n return Promise.resolve(0);\n }\n let codec;\n try {\n codec = createTimestampId(brand ?? \"\", codecOpts(opts));\n } catch (err) {\n opts.stderr(formatCliError(err) + \"\\n\");\n return Promise.resolve(1);\n }\n for (let i = 0; i < count; i++) opts.stdout(codec.generate() + \"\\n\");\n return Promise.resolve(0);\n}\n\nasync function runOpaqueGenerate(\n brand: string,\n count: number,\n format: OpaqueKeyFormat,\n opts: RunOpts,\n): Promise<number> {\n const keyResult = await loadOpaqueKey(opts, format);\n if (typeof keyResult === \"string\") {\n opts.stderr(keyResult + \"\\n\");\n return 1;\n }\n let codec;\n try {\n codec = createOpaqueTimestampId(brand, { key: keyResult, ...codecOpts(opts) });\n } catch (err) {\n opts.stderr(formatCliError(err) + \"\\n\");\n return 1;\n }\n for (let i = 0; i < count; i++) opts.stdout((await codec.generate()) + \"\\n\");\n return 0;\n}\n","import {\n decodeWrappingKey,\n importWrappingKey,\n type WrappingKey,\n type WrappingKeyFormat,\n} from \"../wrapped.js\";\nimport type { RunOpts } from \"./types.js\";\n\nfunction parseKeyFormatFlag(values: Map<string, string>): WrappingKeyFormat | string | undefined {\n const fromFlag = values.get(\"--key-format\");\n if (fromFlag === undefined) return undefined;\n if (fromFlag === \"\") return \"--key-format requires a value\";\n if (fromFlag === \"hex\" || fromFlag === \"base64url\") return fromFlag;\n return `--key-format must be hex or base64url, got '${fromFlag}'`;\n}\n\nexport function parseWrappingKeyFormat(\n values: Map<string, string>,\n opts: RunOpts,\n): WrappingKeyFormat | string {\n const fromFlag = parseKeyFormatFlag(values);\n if (fromFlag !== undefined) return fromFlag;\n const env = opts.env ?? process.env;\n const fromEnv = env.IDS_WRAPPING_KEY_FORMAT;\n if (fromEnv === undefined || fromEnv === \"\") return \"hex\";\n if (fromEnv === \"hex\" || fromEnv === \"base64url\") return fromEnv;\n return `IDS_WRAPPING_KEY_FORMAT must be hex or base64url, got '${fromEnv}'`;\n}\n\nexport async function loadWrappingKey(\n opts: RunOpts,\n format: WrappingKeyFormat,\n): Promise<WrappingKey | string> {\n const env = opts.env ?? process.env;\n const raw = env.IDS_WRAPPING_KEY;\n if (raw === undefined || raw === \"\") return \"missing IDS_WRAPPING_KEY environment variable\";\n try {\n return importWrappingKey(decodeWrappingKey(raw, format));\n } catch (err) {\n return (err as Error).message;\n }\n}\n","import { maxGenerateCount } from \"./constants.js\";\n\nexport function usage(): string {\n return [\n \"Usage: ids <subcommand> [args]\",\n \"\",\n \"Subcommands:\",\n \" inspect, i <id> [--opaque] [--wrapped --kind u32|i32|u64|i64] [--reverse] [--key-format hex|base64url]\",\n \" Decode an ID and print brand, timestamp (or lookup key), and canonical form.\",\n \" --opaque reads the AES key from IDS_KEY (hex by default; IDS_KEY_FORMAT or --key-format).\",\n \" --wrapped reads the wrapping key from IDS_WRAPPING_KEY (hex by default; IDS_WRAPPING_KEY_FORMAT or --key-format).\",\n \" --kind is required with --wrapped: u32, i32, u64, or i64.\",\n \" --reverse decodes a Reverse Timestamp ID (newest-first sort order).\",\n \" generate, g <brand> [--count, -c N] [--opaque] [--reverse] [--key-format hex|base64url]\",\n ` Mint 1..${maxGenerateCount} canonical IDs for the given brand.`,\n \" --opaque reads the AES key from IDS_KEY (hex by default; IDS_KEY_FORMAT or --key-format).\",\n \" --reverse mints Reverse Timestamp IDs (newest-first sort order).\",\n \" keygen, k [--wrapped] [--bits 128|192|256] [--key-format hex|base64url]\",\n \" Emit a random AES key for importOpaqueKey (stdout only).\",\n \" --wrapped emits a wrapping key for importWrappingKey instead (IDS_WRAPPING_KEY).\",\n \"\",\n ].join(\"\\n\");\n}\n","import { createTimestampId } from \"../../timestamp.js\";\nimport { createOpaqueTimestampId, type OpaqueKeyFormat } from \"../../opaque.js\";\nimport { createReverseTimestampId } from \"../../reverse.js\";\nimport { createWrappedKeyId, type WrappingKey } from \"../../wrapped.js\";\nimport { codecOpts } from \"../codec-options.js\";\nimport { formatCliError, formatInspectOutput, formatWrappedInspectOutput } from \"../format.js\";\nimport {\n isKindError,\n parseKind,\n splitFlags,\n unsupportedFlagForCommand,\n type WrappedKindValue,\n} from \"../flags.js\";\nimport { isKeyFormatError, loadOpaqueKey, parseOpaqueKeyFormat } from \"../opaque-key.js\";\nimport { loadWrappingKey, parseWrappingKeyFormat } from \"../wrapping-key.js\";\nimport type { RunOpts } from \"../types.js\";\nimport { usage } from \"../usage.js\";\n\nexport function runInspect(args: ReadonlyArray<string>, opts: RunOpts): Promise<number> {\n const { flags, values, positionals, errors } = splitFlags(args);\n const unsupported = unsupportedFlagForCommand(\n \"inspect\",\n flags,\n new Set([\"--opaque\", \"--wrapped\", \"--reverse\", \"--kind\", \"--key-format\"]),\n );\n if (unsupported !== undefined) {\n opts.stderr(unsupported + \"\\n\");\n return Promise.resolve(1);\n }\n if (errors[0] !== undefined) {\n opts.stderr(errors[0] + \"\\n\");\n return Promise.resolve(1);\n }\n const [input] = positionals;\n if (input === undefined) {\n opts.stderr(usage());\n return Promise.resolve(1);\n }\n const extra = positionals[1];\n if (extra !== undefined) {\n opts.stderr(`unexpected argument: ${extra}\\n`);\n return Promise.resolve(1);\n }\n const opaque = flags.has(\"--opaque\");\n const wrapped = flags.has(\"--wrapped\");\n const reverse = flags.has(\"--reverse\");\n if (opaque && wrapped) {\n opts.stderr(\"cannot use --wrapped and --opaque together\\n\");\n return Promise.resolve(1);\n }\n if (reverse && opaque) {\n opts.stderr(\"cannot use --reverse and --opaque together\\n\");\n return Promise.resolve(1);\n }\n if (reverse && wrapped) {\n opts.stderr(\"cannot use --reverse and --wrapped together\\n\");\n return Promise.resolve(1);\n }\n if (!opaque && !wrapped && flags.has(\"--key-format\")) {\n opts.stderr(\"--key-format requires --opaque or --wrapped\\n\");\n return Promise.resolve(1);\n }\n const brand = input.slice(0, 3).toLowerCase();\n if (wrapped) {\n const kind = parseKind(values);\n if (kind === undefined) {\n opts.stderr(\"--kind is required with --wrapped\\n\");\n return Promise.resolve(1);\n }\n if (isKindError(kind)) {\n opts.stderr(kind + \"\\n\");\n return Promise.resolve(1);\n }\n const format = parseWrappingKeyFormat(values, opts);\n if (isKeyFormatError(format)) {\n opts.stderr(format + \"\\n\");\n return Promise.resolve(1);\n }\n return runWrappedInspect(brand, input, kind, format, opts);\n }\n if (opaque) {\n const format = parseOpaqueKeyFormat(values, opts);\n if (isKeyFormatError(format)) {\n opts.stderr(format + \"\\n\");\n return Promise.resolve(1);\n }\n return runOpaqueInspect(brand, input, format, opts);\n }\n if (reverse) {\n let reverseCodec;\n try {\n reverseCodec = createReverseTimestampId(brand, codecOpts(opts));\n } catch (err) {\n opts.stderr(formatCliError(err) + \"\\n\");\n return Promise.resolve(1);\n }\n const reverseValidation = reverseCodec[\"~standard\"].validate(input);\n if (reverseValidation.issues) {\n opts.stderr(reverseValidation.issues[0]!.message + \"\\n\");\n return Promise.resolve(1);\n }\n const reverseCanonical = reverseValidation.value;\n const reverseTimestamp = reverseCodec.extractTimestamp(reverseCanonical);\n const reverseNowMs = (opts.now ?? Date.now)();\n opts.stdout(\n formatInspectOutput({\n brand,\n timestamp: reverseTimestamp,\n canonical: reverseCanonical,\n input,\n nowMs: reverseNowMs,\n }),\n );\n return Promise.resolve(0);\n }\n let codec;\n try {\n codec = createTimestampId(brand, codecOpts(opts));\n } catch (err) {\n opts.stderr(formatCliError(err) + \"\\n\");\n return Promise.resolve(1);\n }\n const validation = codec[\"~standard\"].validate(input);\n if (validation.issues) {\n opts.stderr(validation.issues[0]!.message + \"\\n\");\n return Promise.resolve(1);\n }\n const canonical = validation.value;\n const timestamp = codec.extractTimestamp(canonical);\n const nowMs = (opts.now ?? Date.now)();\n opts.stdout(\n formatInspectOutput({\n brand,\n timestamp,\n canonical,\n input,\n nowMs,\n }),\n );\n return Promise.resolve(0);\n}\n\nasync function runWrappedInspect(\n brand: string,\n input: string,\n kind: WrappedKindValue,\n format: string,\n opts: RunOpts,\n): Promise<number> {\n const keyResult = await loadWrappingKey(opts, format as \"hex\" | \"base64url\");\n if (typeof keyResult === \"string\") {\n opts.stderr(keyResult + \"\\n\");\n return 1;\n }\n let codec;\n try {\n codec = createWrappedKeyId(brand, {\n kind,\n keys: [keyResult as WrappingKey],\n allowDuplicateBrand: true,\n });\n } catch (err) {\n opts.stderr(formatCliError(err) + \"\\n\");\n return 1;\n }\n const validation = codec[\"~standard\"].validate(input);\n if (validation.issues) {\n opts.stderr(validation.issues[0]!.message + \"\\n\");\n return 1;\n }\n const canonical = validation.value;\n let lookupKey;\n try {\n lookupKey = await codec.unwrap(canonical);\n } catch (err) {\n opts.stderr(formatCliError(err) + \"\\n\");\n return 1;\n }\n opts.stdout(\n formatWrappedInspectOutput({\n brand,\n lookupKey,\n canonical,\n input,\n }),\n );\n return 0;\n}\n\nasync function runOpaqueInspect(\n brand: string,\n input: string,\n format: OpaqueKeyFormat,\n opts: RunOpts,\n): Promise<number> {\n const keyResult = await loadOpaqueKey(opts, format);\n if (typeof keyResult === \"string\") {\n opts.stderr(keyResult + \"\\n\");\n return 1;\n }\n let codec;\n try {\n codec = createOpaqueTimestampId(brand, { key: keyResult, ...codecOpts(opts) });\n } catch (err) {\n opts.stderr(formatCliError(err) + \"\\n\");\n return 1;\n }\n const validation = codec[\"~standard\"].validate(input);\n if (validation.issues) {\n opts.stderr(validation.issues[0]!.message + \"\\n\");\n return 1;\n }\n const canonical = validation.value;\n const timestamp = await codec.extractTimestamp(canonical);\n const nowMs = (opts.now ?? Date.now)();\n opts.stderr(\n \"note: timestamp assumes IDS_KEY matches the key used at generation; a wrong key yields a plausible but incorrect timestamp\\n\",\n );\n opts.stdout(\n formatInspectOutput({\n brand,\n timestamp,\n canonical,\n input,\n nowMs,\n }),\n );\n return 0;\n}\n","import { encodeOpaqueKey } from \"../../opaque.js\";\nimport { encodeWrappingKey } from \"../../wrapped.js\";\nimport { parseBits, splitFlags, unsupportedFlagForCommand } from \"../flags.js\";\nimport { isKeyFormatError, parseKeygenFormat } from \"../opaque-key.js\";\nimport type { RunOpts } from \"../types.js\";\n\nexport function runKeygen(args: ReadonlyArray<string>, opts: RunOpts): Promise<number> {\n const { flags, values, positionals, errors } = splitFlags(args);\n const unsupported = unsupportedFlagForCommand(\n \"keygen\",\n flags,\n new Set([\"--wrapped\", \"--bits\", \"--key-format\"]),\n );\n if (unsupported !== undefined) {\n opts.stderr(unsupported + \"\\n\");\n return Promise.resolve(1);\n }\n if (errors[0] !== undefined) {\n opts.stderr(errors[0] + \"\\n\");\n return Promise.resolve(1);\n }\n const extra = positionals[0];\n if (extra !== undefined) {\n opts.stderr(`unexpected argument: ${extra}\\n`);\n return Promise.resolve(1);\n }\n const bits = parseBits(values);\n if (typeof bits === \"string\") {\n opts.stderr(bits + \"\\n\");\n return Promise.resolve(1);\n }\n const format = parseKeygenFormat(values);\n if (isKeyFormatError(format)) {\n opts.stderr(format + \"\\n\");\n return Promise.resolve(1);\n }\n const bytes = new Uint8Array(bits / 8);\n crypto.getRandomValues(bytes);\n const wrapped = flags.has(\"--wrapped\");\n opts.stdout((wrapped ? encodeWrappingKey(bytes, format) : encodeOpaqueKey(bytes, format)) + \"\\n\");\n return Promise.resolve(0);\n}\n","import { runGenerate } from \"./cli/commands/generate.js\";\nimport { runInspect } from \"./cli/commands/inspect.js\";\nimport { runKeygen } from \"./cli/commands/keygen.js\";\nimport type { CommandHandler, RunOpts } from \"./cli/types.js\";\nimport { usage } from \"./cli/usage.js\";\n\nexport type { RunOpts } from \"./cli/types.js\";\n\ntype Command = {\n names: ReadonlyArray<string>;\n run: CommandHandler;\n};\n\nconst commands: ReadonlyArray<Command> = [\n { names: [\"generate\", \"g\"], run: runGenerate },\n { names: [\"inspect\", \"i\"], run: runInspect },\n { names: [\"keygen\", \"k\"], run: runKeygen },\n];\n\nexport async function run(opts: RunOpts): Promise<number> {\n const [subcommand, ...rest] = opts.argv;\n const command = commands.find((candidate) => candidate.names.includes(subcommand ?? \"\"));\n if (command !== undefined) return command.run(rest, opts);\n if (subcommand === undefined || subcommand === \"--help\" || subcommand === \"-h\") {\n opts.stdout(usage());\n return 0;\n }\n opts.stderr(usage());\n return 1;\n}\n","#!/usr/bin/env node\nimport { run } from \"../src/cli.js\";\n\nprocess.exitCode = await run({\n argv: process.argv.slice(2),\n stdout: (s) => process.stdout.write(s),\n stderr: (s) => process.stderr.write(s),\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli/codec-options.ts","../src/cli/format.ts","../src/cli/constants.ts","../src/cli/flags.ts","../src/cli/key-io.ts","../src/cli/opaque-key.ts","../src/cli/signing-key.ts","../src/cli/commands/generate.ts","../src/cli/wrapping-key.ts","../src/cli/usage.ts","../src/cli/commands/inspect.ts","../src/cli/variants.ts","../src/cli/dispatch.ts","../src/cli/commands/keygen.ts","../src/cli.ts","../bin/cli.ts"],"sourcesContent":["import type { TimestampOptions } from \"../timestamp.js\";\nimport type { RunOpts } from \"./types.js\";\n\nexport function codecOpts(opts: RunOpts): Partial<TimestampOptions> {\n // CLI invocations are intentionally ephemeral: one codec per run, never\n // retained, so this is not the duplicate-brand warning case.\n const o: Partial<TimestampOptions> = { allowDuplicateBrand: true };\n if (opts.now !== undefined) o.now = opts.now;\n if (opts.rng !== undefined) o.rng = opts.rng;\n return o;\n}\n","import { isIdsError } from \"../error.js\";\nimport type { Id } from \"../types.js\";\n\ntype InspectOutput = {\n brand: string;\n timestamp: Date;\n canonical: Id<string>;\n input: string;\n nowMs: number;\n};\n\ntype SignedInspectOutput = InspectOutput & {\n verification: \"ok\" | \"failed\" | \"unavailable\";\n};\n\ntype WrappedInspectOutput = {\n brand: string;\n lookupKey: number | bigint;\n canonical: Id<string>;\n input: string;\n};\n\nexport function formatCliError(err: unknown): string {\n return isIdsError(err)\n ? `${err.code}: ${err.message}`\n : err instanceof Error\n ? err.message\n : String(err);\n}\n\nexport function formatWrappedInspectOutput(result: WrappedInspectOutput): string {\n const inputLine = describeInputForm(result.input, result.canonical);\n return [\n `brand: ${result.brand}`,\n `lookup-key: ${result.lookupKey.toString()}`,\n `canonical: ${result.canonical}`,\n `input: ${inputLine}`,\n \"\",\n ].join(\"\\n\");\n}\n\nexport function formatSignedInspectOutput(result: SignedInspectOutput): string {\n const relative = formatRelative(result.timestamp.getTime(), result.nowMs);\n const inputLine = describeInputForm(result.input, result.canonical);\n const lines = [\n `brand: ${result.brand}`,\n `timestamp: ${result.timestamp.toISOString()} (${relative})`,\n ];\n // \"verification:\" is the spec-mandated key name; the extra chars vs. other labels are intentional.\n lines.push(`verification: ${result.verification}`);\n lines.push(`canonical: ${result.canonical}`, `input: ${inputLine}`, \"\");\n return lines.join(\"\\n\");\n}\n\nexport function formatInspectOutput(result: InspectOutput): string {\n const relative = formatRelative(result.timestamp.getTime(), result.nowMs);\n const inputLine = describeInputForm(result.input, result.canonical);\n return [\n `brand: ${result.brand}`,\n `timestamp: ${result.timestamp.toISOString()} (${relative})`,\n `canonical: ${result.canonical}`,\n `input: ${inputLine}`,\n \"\",\n ].join(\"\\n\");\n}\n\nfunction describeInputForm(input: string, canonical: Id<string>): string {\n if (input === canonical) return \"canonical\";\n const notes: string[] = [];\n if (input !== input.toLowerCase()) notes.push(\"was uppercase\");\n if (/[ilo]/i.test(input.slice(4))) notes.push(\"used Crockford aliases\");\n return `not canonical (${notes.join(\" + \")})`;\n}\n\nconst msPerSecond = 1000;\nconst msPerMinute = 60 * msPerSecond;\nconst msPerHour = 60 * msPerMinute;\nconst msPerDay = 24 * msPerHour;\nconst daysPerMonth = 30.44;\nconst monthsPerYear = 12;\n\nfunction formatRelative(thenMs: number, nowMs: number): string {\n const diff = nowMs - thenMs;\n const abs = Math.abs(diff);\n const suffix = diff < 0 ? \"from now\" : \"ago\";\n\n const head = headUnits(abs);\n return head === \"\" ? \"just now\" : `${head} ${suffix}`;\n}\n\nfunction headUnits(abs: number): string {\n if (abs < msPerMinute) return \"\";\n if (abs < msPerHour) return unit(Math.round(abs / msPerMinute), \"minute\");\n if (abs < msPerDay) return unit(Math.round(abs / msPerHour), \"hour\");\n if (abs < msPerDay * daysPerMonth) return unit(Math.round(abs / msPerDay), \"day\");\n\n const totalMonths = Math.round(abs / (msPerDay * daysPerMonth));\n if (totalMonths < monthsPerYear) return unit(totalMonths, \"month\");\n\n const years = Math.floor(totalMonths / monthsPerYear);\n const months = totalMonths % monthsPerYear;\n return months === 0 ? unit(years, \"year\") : `${unit(years, \"year\")} ${unit(months, \"month\")}`;\n}\n\nfunction unit(n: number, name: string): string {\n return `${n} ${n === 1 ? name : `${name}s`}`;\n}\n","export const maxGenerateCount = 10_000;\n","import { maxGenerateCount } from \"./constants.js\";\n\nexport type ParsedFlags = {\n flags: Set<string>;\n values: Map<string, string>;\n positionals: string[];\n errors: string[];\n};\n\nfunction splitFlagToken(arg: string): { flag: string; inlineValue: string | undefined } {\n const eq = arg.indexOf(\"=\");\n if (eq <= 0) return { flag: arg, inlineValue: undefined };\n return { flag: arg.slice(0, eq), inlineValue: arg.slice(eq + 1) };\n}\n\nexport function splitFlags(args: ReadonlyArray<string>, valueFlags: Set<string>): ParsedFlags {\n const flags = new Set<string>();\n const values = new Map<string, string>();\n const positionals: string[] = [];\n const errors: string[] = [];\n const seenFlags = new Set<string>();\n const addFlag = (flag: string) => {\n const canonical = canonicalFlag(flag);\n if (seenFlags.has(canonical)) errors.push(`duplicate flag: ${canonical}`);\n seenFlags.add(canonical);\n flags.add(flag);\n };\n for (let i = 0; i < args.length; i++) {\n const raw = args[i]!;\n const { flag, inlineValue } = splitFlagToken(raw);\n if (valueFlags.has(flag)) {\n if (inlineValue !== undefined) {\n addFlag(flag);\n values.set(flag, inlineValue);\n continue;\n }\n const value = args[i + 1];\n if (value === undefined || value.startsWith(\"-\")) {\n addFlag(flag);\n values.set(flag, \"\");\n continue;\n }\n addFlag(flag);\n values.set(flag, value);\n i++;\n continue;\n }\n if (flag.startsWith(\"-\")) {\n addFlag(flag);\n if (inlineValue !== undefined) errors.push(`flag does not take a value: ${flag}`);\n continue;\n }\n positionals.push(raw);\n }\n return { flags, values, positionals, errors };\n}\n\nfunction canonicalFlag(flag: string): string {\n if (flag === \"-c\") return \"--count\";\n return flag;\n}\n\nconst knownFlags = new Set([\n \"--opaque\",\n \"--wrapped\",\n \"--reverse\",\n \"--signed\",\n \"--kind\",\n \"--key-format\",\n \"--count\",\n \"-c\",\n \"--bits\",\n]);\n\nexport function unsupportedFlagForCommand(\n command: string,\n flags: Set<string>,\n allowed: Set<string>,\n): string | undefined {\n for (const flag of flags) {\n if (!allowed.has(flag)) {\n return knownFlags.has(flag)\n ? `unsupported flag for ${command}: ${flag}`\n : `unsupported flag: ${flag}`;\n }\n }\n return undefined;\n}\n\nexport function parseCount(values: Map<string, string>): number | string {\n const raw = values.get(\"--count\") ?? values.get(\"-c\");\n if (raw === undefined) return 1;\n if (raw === \"\") return \"--count requires a value\";\n if (!/^[1-9][0-9]*$/.test(raw)) return `--count must be a positive integer, got '${raw}'`;\n const count = Number.parseInt(raw, 10);\n if (!Number.isSafeInteger(count) || count > maxGenerateCount) {\n return `--count must be at most ${maxGenerateCount}, got '${raw}'`;\n }\n return count;\n}\n\nexport function parseBits(values: Map<string, string>): number | string {\n const raw = values.get(\"--bits\");\n if (raw === undefined) return 256;\n if (raw === \"\") return \"--bits requires a value\";\n if (raw === \"128\") return 128;\n if (raw === \"192\") return 192;\n if (raw === \"256\") return 256;\n return `--bits must be 128, 192, or 256, got '${raw}'`;\n}\n\nexport type WrappedKindValue = \"u32\" | \"i32\" | \"u64\" | \"i64\";\n\nexport function parseKind(values: Map<string, string>): WrappedKindValue | string | undefined {\n const raw = values.get(\"--kind\");\n if (raw === undefined) return undefined;\n if (raw === \"\") return \"--kind requires a value\";\n if (raw === \"u32\" || raw === \"i32\" || raw === \"u64\" || raw === \"i64\") return raw;\n return `--kind must be u32, i32, u64, or i64, got '${raw}'`;\n}\n\nexport function isKindError(result: WrappedKindValue | string): result is string {\n return result !== \"u32\" && result !== \"i32\" && result !== \"u64\" && result !== \"i64\";\n}\n","import type { RunOpts } from \"./types.js\";\n\nexport type KeyFormat = \"hex\" | \"base64url\";\n\nexport type KeyFacet<K> = {\n envVar: string;\n formatEnvVar: string;\n // Not yet consumed by any helper here; the keygen-delegation chunk wires it.\n encode: (bytes: Uint8Array, format: KeyFormat) => string;\n decode: (raw: string, format: KeyFormat) => Uint8Array;\n import: (bytes: Uint8Array) => K | Promise<K>;\n};\n\nexport function isKeyFormatError(result: KeyFormat | string): result is string {\n return result !== \"hex\" && result !== \"base64url\";\n}\n\nfunction parseKeyFormatFlag(values: Map<string, string>): KeyFormat | string | undefined {\n const fromFlag = values.get(\"--key-format\");\n if (fromFlag === undefined) return undefined;\n if (fromFlag === \"\") return \"--key-format requires a value\";\n if (fromFlag === \"hex\" || fromFlag === \"base64url\") return fromFlag;\n return `--key-format must be hex or base64url, got '${fromFlag}'`;\n}\n\nexport function parseKeyFormatFromFlag(values: Map<string, string>): KeyFormat | string {\n const fromFlag = parseKeyFormatFlag(values);\n if (fromFlag === undefined) return \"hex\";\n return fromFlag;\n}\n\nexport function parseKeyFormat(\n values: Map<string, string>,\n opts: RunOpts,\n facet: Pick<KeyFacet<unknown>, \"formatEnvVar\">,\n): KeyFormat | string {\n const fromFlag = parseKeyFormatFlag(values);\n if (fromFlag !== undefined) return fromFlag;\n const env = opts.env ?? process.env;\n const fromEnv = env[facet.formatEnvVar];\n if (fromEnv === undefined || fromEnv === \"\") return \"hex\";\n if (fromEnv === \"hex\" || fromEnv === \"base64url\") return fromEnv;\n return `${facet.formatEnvVar} must be hex or base64url, got '${fromEnv}'`;\n}\n\nexport async function loadKey<K>(\n opts: RunOpts,\n format: KeyFormat,\n facet: Pick<KeyFacet<K>, \"envVar\" | \"decode\" | \"import\">,\n): Promise<K | string> {\n const env = opts.env ?? process.env;\n const raw = env[facet.envVar];\n if (raw === undefined || raw === \"\") return `missing ${facet.envVar} environment variable`;\n try {\n return await facet.import(facet.decode(raw, format));\n } catch (err) {\n return (err as Error).message;\n }\n}\n","import {\n decodeOpaqueKey,\n importOpaqueKey,\n type OpaqueKey,\n type OpaqueKeyFormat,\n} from \"../opaque.js\";\nimport { loadKey, parseKeyFormat } from \"./key-io.js\";\nimport type { RunOpts } from \"./types.js\";\n\nconst opaqueFacet = {\n envVar: \"IDS_KEY\",\n formatEnvVar: \"IDS_KEY_FORMAT\",\n decode: decodeOpaqueKey,\n import: importOpaqueKey,\n};\n\nexport function parseOpaqueKeyFormat(\n values: Map<string, string>,\n opts: RunOpts,\n): OpaqueKeyFormat | string {\n return parseKeyFormat(values, opts, opaqueFacet);\n}\n\nexport async function loadOpaqueKey(\n opts: RunOpts,\n format: OpaqueKeyFormat,\n): Promise<OpaqueKey | string> {\n return loadKey(opts, format, opaqueFacet);\n}\n","import {\n decodeSigningKey,\n importSigningKey,\n type SigningKey,\n type SigningKeyFormat,\n} from \"../signed.js\";\nimport { loadKey, parseKeyFormat } from \"./key-io.js\";\nimport type { RunOpts } from \"./types.js\";\n\nconst signingFacet = {\n envVar: \"IDS_SIGNING_KEY\",\n formatEnvVar: \"IDS_SIGNING_KEY_FORMAT\",\n decode: decodeSigningKey,\n import: importSigningKey,\n};\n\nexport function parseSigningKeyFormat(\n values: Map<string, string>,\n opts: RunOpts,\n): SigningKeyFormat | string {\n return parseKeyFormat(values, opts, signingFacet);\n}\n\nexport async function loadSigningKey(\n opts: RunOpts,\n format: SigningKeyFormat,\n): Promise<SigningKey | string> {\n return loadKey(opts, format, signingFacet);\n}\n","import { createTimestampId } from \"../../timestamp.js\";\nimport { createOpaqueTimestampId, type OpaqueKeyFormat } from \"../../opaque.js\";\nimport { createReverseTimestampId } from \"../../reverse.js\";\nimport { createSignedTimestampId } from \"../../signed.js\";\nimport { codecOpts } from \"../codec-options.js\";\nimport { formatCliError } from \"../format.js\";\nimport { parseCount, splitFlags, unsupportedFlagForCommand } from \"../flags.js\";\nimport { isKeyFormatError } from \"../key-io.js\";\nimport { loadOpaqueKey, parseOpaqueKeyFormat } from \"../opaque-key.js\";\nimport { loadSigningKey, parseSigningKeyFormat } from \"../signing-key.js\";\nimport type { SigningKeyFormat } from \"../../signed.js\";\nimport type { RunOpts } from \"../types.js\";\n\nexport function runGenerate(args: ReadonlyArray<string>, opts: RunOpts): Promise<number> {\n const { flags, values, positionals, errors } = splitFlags(\n args,\n new Set([\"--count\", \"-c\", \"--bits\", \"--key-format\", \"--kind\"]),\n );\n const unsupported = unsupportedFlagForCommand(\n \"generate\",\n flags,\n new Set([\"--count\", \"-c\", \"--opaque\", \"--reverse\", \"--signed\", \"--key-format\"]),\n );\n if (unsupported !== undefined) {\n opts.stderr(unsupported + \"\\n\");\n return Promise.resolve(1);\n }\n if (errors[0] !== undefined) {\n opts.stderr(errors[0] + \"\\n\");\n return Promise.resolve(1);\n }\n const extra = positionals[1];\n if (extra !== undefined) {\n opts.stderr(`unexpected argument: ${extra}\\n`);\n return Promise.resolve(1);\n }\n const [brand] = positionals;\n const count = parseCount(values);\n if (typeof count === \"string\") {\n opts.stderr(count + \"\\n\");\n return Promise.resolve(1);\n }\n const opaque = flags.has(\"--opaque\");\n const reverse = flags.has(\"--reverse\");\n const signed = flags.has(\"--signed\");\n if (reverse && opaque) {\n opts.stderr(\"cannot use --reverse and --opaque together\\n\");\n return Promise.resolve(1);\n }\n if (signed && opaque) {\n opts.stderr(\"cannot use --signed and --opaque together\\n\");\n return Promise.resolve(1);\n }\n if (signed && reverse) {\n opts.stderr(\"cannot use --signed and --reverse together\\n\");\n return Promise.resolve(1);\n }\n if (!opaque && !signed && flags.has(\"--key-format\")) {\n opts.stderr(\"--key-format requires --opaque or --signed\\n\");\n return Promise.resolve(1);\n }\n if (opaque) {\n const format = parseOpaqueKeyFormat(values, opts);\n if (isKeyFormatError(format)) {\n opts.stderr(format + \"\\n\");\n return Promise.resolve(1);\n }\n return runOpaqueGenerate(brand ?? \"\", count, format, opts);\n }\n if (signed) {\n const format = parseSigningKeyFormat(values, opts);\n if (isKeyFormatError(format)) {\n opts.stderr(format + \"\\n\");\n return Promise.resolve(1);\n }\n return runSignedGenerate(brand ?? \"\", count, format, opts);\n }\n if (reverse) {\n let codec;\n try {\n codec = createReverseTimestampId(brand ?? \"\", codecOpts(opts));\n } catch (err) {\n opts.stderr(formatCliError(err) + \"\\n\");\n return Promise.resolve(1);\n }\n for (let i = 0; i < count; i++) opts.stdout(codec.generate() + \"\\n\");\n return Promise.resolve(0);\n }\n let codec;\n try {\n codec = createTimestampId(brand ?? \"\", codecOpts(opts));\n } catch (err) {\n opts.stderr(formatCliError(err) + \"\\n\");\n return Promise.resolve(1);\n }\n for (let i = 0; i < count; i++) opts.stdout(codec.generate() + \"\\n\");\n return Promise.resolve(0);\n}\n\nasync function runOpaqueGenerate(\n brand: string,\n count: number,\n format: OpaqueKeyFormat,\n opts: RunOpts,\n): Promise<number> {\n const keyResult = await loadOpaqueKey(opts, format);\n if (typeof keyResult === \"string\") {\n opts.stderr(keyResult + \"\\n\");\n return 1;\n }\n let codec;\n try {\n codec = createOpaqueTimestampId(brand, { key: keyResult, ...codecOpts(opts) });\n } catch (err) {\n opts.stderr(formatCliError(err) + \"\\n\");\n return 1;\n }\n for (let i = 0; i < count; i++) opts.stdout((await codec.generate()) + \"\\n\");\n return 0;\n}\n\nasync function runSignedGenerate(\n brand: string,\n count: number,\n format: SigningKeyFormat,\n opts: RunOpts,\n): Promise<number> {\n const keyResult = await loadSigningKey(opts, format);\n if (typeof keyResult === \"string\") {\n opts.stderr(keyResult + \"\\n\");\n return 1;\n }\n let codec;\n try {\n codec = createSignedTimestampId(brand, {\n keys: [keyResult],\n allowDuplicateBrand: true,\n ...codecOpts(opts),\n });\n } catch (err) {\n opts.stderr(formatCliError(err) + \"\\n\");\n return 1;\n }\n for (let i = 0; i < count; i++) opts.stdout((await codec.generate()) + \"\\n\");\n return 0;\n}\n","import {\n decodeWrappingKey,\n importWrappingKey,\n type WrappingKey,\n type WrappingKeyFormat,\n} from \"../wrapped.js\";\nimport { loadKey, parseKeyFormat } from \"./key-io.js\";\nimport type { RunOpts } from \"./types.js\";\n\nconst wrappingFacet = {\n envVar: \"IDS_WRAPPING_KEY\",\n formatEnvVar: \"IDS_WRAPPING_KEY_FORMAT\",\n decode: decodeWrappingKey,\n import: importWrappingKey,\n};\n\nexport function parseWrappingKeyFormat(\n values: Map<string, string>,\n opts: RunOpts,\n): WrappingKeyFormat | string {\n return parseKeyFormat(values, opts, wrappingFacet);\n}\n\nexport async function loadWrappingKey(\n opts: RunOpts,\n format: WrappingKeyFormat,\n): Promise<WrappingKey | string> {\n return loadKey(opts, format, wrappingFacet);\n}\n","import { maxGenerateCount } from \"./constants.js\";\n\nexport function usage(): string {\n return [\n \"Usage: ids <subcommand> [args]\",\n \"\",\n \"Subcommands:\",\n \" inspect, i <id> [--opaque] [--wrapped --kind u32|i32|u64|i64] [--reverse] [--signed] [--key-format hex|base64url]\",\n \" Decode an ID and print brand, timestamp (or lookup key), and canonical form.\",\n \" --opaque reads the AES key from IDS_KEY (hex by default; IDS_KEY_FORMAT or --key-format).\",\n \" --wrapped reads the wrapping key from IDS_WRAPPING_KEY (hex by default; IDS_WRAPPING_KEY_FORMAT or --key-format).\",\n \" --kind is required with --wrapped: u32, i32, u64, or i64.\",\n \" --reverse decodes a Reverse Timestamp ID (newest-first sort order).\",\n \" --signed decodes a Signed Timestamp ID; reads signing key from IDS_SIGNING_KEY (hex by default; IDS_SIGNING_KEY_FORMAT or --key-format).\",\n \" Without IDS_SIGNING_KEY, --signed prints the timestamp only (no verification). With IDS_SIGNING_KEY, prints verification: ok or failed.\",\n \" generate, g <brand> [--count, -c N] [--opaque] [--reverse] [--signed] [--key-format hex|base64url]\",\n ` Mint 1..${maxGenerateCount} canonical IDs for the given brand.`,\n \" --opaque reads the AES key from IDS_KEY (hex by default; IDS_KEY_FORMAT or --key-format).\",\n \" --reverse mints Reverse Timestamp IDs (newest-first sort order).\",\n \" --signed mints Signed Timestamp IDs; reads signing key from IDS_SIGNING_KEY (hex by default; IDS_SIGNING_KEY_FORMAT or --key-format).\",\n \" keygen, k [--wrapped] [--signed] [--bits 128|192|256] [--key-format hex|base64url]\",\n \" Emit a random key for importOpaqueKey, importWrappingKey, or importSigningKey (stdout only).\",\n \" --wrapped emits a wrapping key for importWrappingKey instead (IDS_WRAPPING_KEY).\",\n \" --signed emits a signing key for importSigningKey instead (IDS_SIGNING_KEY; hex by default; IDS_SIGNING_KEY_FORMAT or --key-format).\",\n \"\",\n ].join(\"\\n\");\n}\n","import { createTimestampId } from \"../../timestamp.js\";\nimport { createOpaqueTimestampId, type OpaqueKeyFormat } from \"../../opaque.js\";\nimport { createReverseTimestampId } from \"../../reverse.js\";\nimport { createSignedTimestampId } from \"../../signed.js\";\nimport { createWrappedKeyId, type WrappingKey } from \"../../wrapped.js\";\nimport { codecOpts } from \"../codec-options.js\";\nimport {\n formatCliError,\n formatInspectOutput,\n formatSignedInspectOutput,\n formatWrappedInspectOutput,\n} from \"../format.js\";\nimport {\n isKindError,\n parseKind,\n splitFlags,\n unsupportedFlagForCommand,\n type WrappedKindValue,\n} from \"../flags.js\";\nimport { isKeyFormatError } from \"../key-io.js\";\nimport { loadOpaqueKey, parseOpaqueKeyFormat } from \"../opaque-key.js\";\nimport { loadSigningKey, parseSigningKeyFormat } from \"../signing-key.js\";\nimport type { SigningKeyFormat } from \"../../signed.js\";\nimport { loadWrappingKey, parseWrappingKeyFormat } from \"../wrapping-key.js\";\nimport type { RunOpts } from \"../types.js\";\nimport { usage } from \"../usage.js\";\n\nexport function runInspect(args: ReadonlyArray<string>, opts: RunOpts): Promise<number> {\n const { flags, values, positionals, errors } = splitFlags(\n args,\n new Set([\"--count\", \"-c\", \"--bits\", \"--key-format\", \"--kind\"]),\n );\n const unsupported = unsupportedFlagForCommand(\n \"inspect\",\n flags,\n new Set([\"--opaque\", \"--wrapped\", \"--reverse\", \"--signed\", \"--kind\", \"--key-format\"]),\n );\n if (unsupported !== undefined) {\n opts.stderr(unsupported + \"\\n\");\n return Promise.resolve(1);\n }\n if (errors[0] !== undefined) {\n opts.stderr(errors[0] + \"\\n\");\n return Promise.resolve(1);\n }\n const [input] = positionals;\n if (input === undefined) {\n opts.stderr(usage());\n return Promise.resolve(1);\n }\n const extra = positionals[1];\n if (extra !== undefined) {\n opts.stderr(`unexpected argument: ${extra}\\n`);\n return Promise.resolve(1);\n }\n const opaque = flags.has(\"--opaque\");\n const wrapped = flags.has(\"--wrapped\");\n const reverse = flags.has(\"--reverse\");\n const signed = flags.has(\"--signed\");\n if (opaque && wrapped) {\n opts.stderr(\"cannot use --wrapped and --opaque together\\n\");\n return Promise.resolve(1);\n }\n if (reverse && opaque) {\n opts.stderr(\"cannot use --reverse and --opaque together\\n\");\n return Promise.resolve(1);\n }\n if (reverse && wrapped) {\n opts.stderr(\"cannot use --reverse and --wrapped together\\n\");\n return Promise.resolve(1);\n }\n if (signed && opaque) {\n opts.stderr(\"cannot use --signed and --opaque together\\n\");\n return Promise.resolve(1);\n }\n if (signed && wrapped) {\n opts.stderr(\"cannot use --signed and --wrapped together\\n\");\n return Promise.resolve(1);\n }\n if (signed && reverse) {\n opts.stderr(\"cannot use --signed and --reverse together\\n\");\n return Promise.resolve(1);\n }\n if (!opaque && !wrapped && !signed && flags.has(\"--key-format\")) {\n opts.stderr(\"--key-format requires --opaque, --wrapped, or --signed\\n\");\n return Promise.resolve(1);\n }\n const brand = input.slice(0, 3).toLowerCase();\n if (wrapped) {\n const kind = parseKind(values);\n if (kind === undefined) {\n opts.stderr(\"--kind is required with --wrapped\\n\");\n return Promise.resolve(1);\n }\n if (isKindError(kind)) {\n opts.stderr(kind + \"\\n\");\n return Promise.resolve(1);\n }\n const format = parseWrappingKeyFormat(values, opts);\n if (isKeyFormatError(format)) {\n opts.stderr(format + \"\\n\");\n return Promise.resolve(1);\n }\n return runWrappedInspect(brand, input, kind, format, opts);\n }\n if (opaque) {\n const format = parseOpaqueKeyFormat(values, opts);\n if (isKeyFormatError(format)) {\n opts.stderr(format + \"\\n\");\n return Promise.resolve(1);\n }\n return runOpaqueInspect(brand, input, format, opts);\n }\n if (signed) {\n const format = parseSigningKeyFormat(values, opts);\n if (isKeyFormatError(format)) {\n opts.stderr(format + \"\\n\");\n return Promise.resolve(1);\n }\n return runSignedInspect(brand, input, format, opts);\n }\n if (reverse) {\n let reverseCodec;\n try {\n reverseCodec = createReverseTimestampId(brand, codecOpts(opts));\n } catch (err) {\n opts.stderr(formatCliError(err) + \"\\n\");\n return Promise.resolve(1);\n }\n const reverseValidation = reverseCodec[\"~standard\"].validate(input);\n if (reverseValidation.issues) {\n opts.stderr(reverseValidation.issues[0]!.message + \"\\n\");\n return Promise.resolve(1);\n }\n const reverseCanonical = reverseValidation.value;\n const reverseTimestamp = reverseCodec.extractTimestamp(reverseCanonical);\n const reverseNowMs = (opts.now ?? Date.now)();\n opts.stdout(\n formatInspectOutput({\n brand,\n timestamp: reverseTimestamp,\n canonical: reverseCanonical,\n input,\n nowMs: reverseNowMs,\n }),\n );\n return Promise.resolve(0);\n }\n let codec;\n try {\n codec = createTimestampId(brand, codecOpts(opts));\n } catch (err) {\n opts.stderr(formatCliError(err) + \"\\n\");\n return Promise.resolve(1);\n }\n const validation = codec[\"~standard\"].validate(input);\n if (validation.issues) {\n opts.stderr(validation.issues[0]!.message + \"\\n\");\n return Promise.resolve(1);\n }\n const canonical = validation.value;\n const timestamp = codec.extractTimestamp(canonical);\n const nowMs = (opts.now ?? Date.now)();\n opts.stdout(\n formatInspectOutput({\n brand,\n timestamp,\n canonical,\n input,\n nowMs,\n }),\n );\n return Promise.resolve(0);\n}\n\nasync function runWrappedInspect(\n brand: string,\n input: string,\n kind: WrappedKindValue,\n format: string,\n opts: RunOpts,\n): Promise<number> {\n const keyResult = await loadWrappingKey(opts, format as \"hex\" | \"base64url\");\n if (typeof keyResult === \"string\") {\n opts.stderr(keyResult + \"\\n\");\n return 1;\n }\n let codec;\n try {\n codec = createWrappedKeyId(brand, {\n kind,\n keys: [keyResult as WrappingKey],\n allowDuplicateBrand: true,\n });\n } catch (err) {\n opts.stderr(formatCliError(err) + \"\\n\");\n return 1;\n }\n const validation = codec[\"~standard\"].validate(input);\n if (validation.issues) {\n opts.stderr(validation.issues[0]!.message + \"\\n\");\n return 1;\n }\n const canonical = validation.value;\n let lookupKey;\n try {\n lookupKey = await codec.unwrap(canonical);\n } catch (err) {\n opts.stderr(formatCliError(err) + \"\\n\");\n return 1;\n }\n opts.stdout(\n formatWrappedInspectOutput({\n brand,\n lookupKey,\n canonical,\n input,\n }),\n );\n return 0;\n}\n\nasync function runOpaqueInspect(\n brand: string,\n input: string,\n format: OpaqueKeyFormat,\n opts: RunOpts,\n): Promise<number> {\n const keyResult = await loadOpaqueKey(opts, format);\n if (typeof keyResult === \"string\") {\n opts.stderr(keyResult + \"\\n\");\n return 1;\n }\n let codec;\n try {\n codec = createOpaqueTimestampId(brand, { key: keyResult, ...codecOpts(opts) });\n } catch (err) {\n opts.stderr(formatCliError(err) + \"\\n\");\n return 1;\n }\n const validation = codec[\"~standard\"].validate(input);\n if (validation.issues) {\n opts.stderr(validation.issues[0]!.message + \"\\n\");\n return 1;\n }\n const canonical = validation.value;\n const timestamp = await codec.extractTimestamp(canonical);\n const nowMs = (opts.now ?? Date.now)();\n opts.stderr(\n \"note: timestamp assumes IDS_KEY matches the key used at generation; a wrong key yields a plausible but incorrect timestamp\\n\",\n );\n opts.stdout(\n formatInspectOutput({\n brand,\n timestamp,\n canonical,\n input,\n nowMs,\n }),\n );\n return 0;\n}\n\nasync function runSignedInspect(\n brand: string,\n input: string,\n format: SigningKeyFormat,\n opts: RunOpts,\n): Promise<number> {\n let structCodec;\n try {\n structCodec = createTimestampId(brand, codecOpts(opts));\n } catch (err) {\n opts.stderr(formatCliError(err) + \"\\n\");\n return 1;\n }\n const validation = structCodec[\"~standard\"].validate(input);\n if (validation.issues) {\n opts.stderr(validation.issues[0]!.message + \"\\n\");\n return 1;\n }\n const canonical = validation.value;\n const timestamp = structCodec.extractTimestamp(canonical);\n const nowMs = (opts.now ?? Date.now)();\n\n const keyResult = await loadSigningKey(opts, format);\n if (typeof keyResult === \"string\") {\n opts.stdout(\n formatSignedInspectOutput({\n brand,\n timestamp,\n canonical,\n input,\n nowMs,\n verification: \"unavailable\",\n }),\n );\n opts.stderr(keyResult + \"\\n\");\n return 1;\n }\n // Brand was already validated by createTimestampId above; single key is non-empty and\n // non-duplicate by construction; allowDuplicateBrand silences the registry check. Cannot throw.\n const signedCodec = createSignedTimestampId(brand, {\n keys: [keyResult],\n allowDuplicateBrand: true,\n ...codecOpts(opts),\n });\n const verifyResult = await signedCodec.safeVerify(input);\n if (!verifyResult.ok) {\n /* v8 ignore next 4 -- defensive: both codecs share the same wire parse so ParseError\n is unreachable after the createTimestampId pre-validation above passes */\n if (verifyResult.error !== \"verification_failed\") {\n opts.stderr(verifyResult.error + \"\\n\");\n return 1;\n }\n opts.stdout(\n formatSignedInspectOutput({\n brand,\n timestamp,\n canonical,\n input,\n nowMs,\n verification: \"failed\",\n }),\n );\n opts.stderr(\"verification_failed: verification failed\\n\");\n return 1;\n }\n opts.stdout(\n formatSignedInspectOutput({\n brand,\n timestamp,\n canonical: verifyResult.id,\n input,\n nowMs,\n verification: \"ok\",\n }),\n );\n return 0;\n}\n","import {\n createOpaqueTimestampId,\n decodeOpaqueKey,\n encodeOpaqueKey,\n importOpaqueKey,\n type OpaqueKey,\n} from \"../opaque.js\";\nimport { createReverseTimestampId } from \"../reverse.js\";\nimport {\n createSignedTimestampId,\n decodeSigningKey,\n encodeSigningKey,\n importSigningKey,\n type SigningKey,\n} from \"../signed.js\";\nimport { createTimestampId } from \"../timestamp.js\";\nimport {\n createWrappedKeyId,\n decodeWrappingKey,\n encodeWrappingKey,\n importWrappingKey,\n type WrappingKey,\n} from \"../wrapped.js\";\nimport type { IdCodec } from \"../adapter-types.js\";\nimport { codecOpts } from \"./codec-options.js\";\nimport { isKindError, parseKind } from \"./flags.js\";\nimport { formatCliError } from \"./format.js\";\nimport type { KeyFacet } from \"./key-io.js\";\nimport type { RunOpts } from \"./types.js\";\n\ntype InspectMode = \"readable\" | \"keyed-readable\" | \"unwrap\" | \"verify\";\n\nexport type Descriptor = {\n flag?: string;\n key?: KeyFacet<unknown>;\n construct: (\n brand: string,\n opts: RunOpts,\n key?: unknown,\n values?: Map<string, string>,\n ) => IdCodec<string> | string;\n inspectMode: InspectMode;\n extraFlags?: readonly string[];\n};\n\nexport type Policy = {\n default: Descriptor;\n selectable: readonly Descriptor[];\n intrinsicFlags: readonly string[];\n};\n\nexport const timestampVariant: Descriptor = {\n inspectMode: \"readable\",\n construct(brand, opts) {\n try {\n return createTimestampId(brand, codecOpts(opts));\n } catch (err) {\n return formatCliError(err);\n }\n },\n};\n\nexport const opaqueVariant: Descriptor = {\n flag: \"--opaque\",\n key: {\n envVar: \"IDS_KEY\",\n formatEnvVar: \"IDS_KEY_FORMAT\",\n encode: encodeOpaqueKey,\n decode: decodeOpaqueKey,\n import: importOpaqueKey,\n },\n inspectMode: \"keyed-readable\",\n construct(brand, opts, key) {\n try {\n return createOpaqueTimestampId(brand, { key: key as OpaqueKey, ...codecOpts(opts) });\n } catch (err) {\n return formatCliError(err);\n }\n },\n};\n\nexport const reverseVariant: Descriptor = {\n flag: \"--reverse\",\n inspectMode: \"readable\",\n construct(brand, opts) {\n try {\n return createReverseTimestampId(brand, codecOpts(opts));\n } catch (err) {\n return formatCliError(err);\n }\n },\n};\n\nexport const wrappedVariant: Descriptor = {\n flag: \"--wrapped\",\n key: {\n envVar: \"IDS_WRAPPING_KEY\",\n formatEnvVar: \"IDS_WRAPPING_KEY_FORMAT\",\n encode: encodeWrappingKey,\n decode: decodeWrappingKey,\n import: importWrappingKey,\n },\n inspectMode: \"unwrap\",\n extraFlags: [\"--kind\"],\n construct(brand, _opts, key, values) {\n const kind = parseKind(values ?? new Map());\n if (kind === undefined) return \"--kind is required with --wrapped\";\n if (isKindError(kind)) return kind;\n try {\n return createWrappedKeyId(brand, {\n kind,\n keys: [key as WrappingKey],\n allowDuplicateBrand: true,\n });\n } catch (err) {\n return formatCliError(err);\n }\n },\n};\n\nexport const signedVariant: Descriptor = {\n flag: \"--signed\",\n key: {\n envVar: \"IDS_SIGNING_KEY\",\n formatEnvVar: \"IDS_SIGNING_KEY_FORMAT\",\n encode: encodeSigningKey,\n decode: decodeSigningKey,\n import: importSigningKey,\n },\n inspectMode: \"verify\",\n construct(brand, opts, key) {\n try {\n return createSignedTimestampId(brand, {\n keys: [key as SigningKey],\n ...codecOpts(opts),\n });\n } catch (err) {\n return formatCliError(err);\n }\n },\n};\n\n// Determines which flag name appears first in \"cannot use --A and --B together\"\n// messages when two selectable variant flags conflict. Signed always leads;\n// remaining three follow registry insertion order (reverse, wrapped, opaque).\nexport const conflictPriorityOrder: readonly Descriptor[] = [\n signedVariant,\n reverseVariant,\n wrappedVariant,\n opaqueVariant,\n];\n\nexport const generatePolicy: Policy = {\n default: timestampVariant,\n selectable: [opaqueVariant, reverseVariant, signedVariant],\n intrinsicFlags: [\"--count\", \"-c\"],\n};\n\nexport const inspectPolicy: Policy = {\n default: timestampVariant,\n selectable: [reverseVariant, wrappedVariant, opaqueVariant, signedVariant],\n intrinsicFlags: [],\n};\n\nexport const keygenPolicy: Policy = {\n default: opaqueVariant,\n selectable: [wrappedVariant, signedVariant],\n intrinsicFlags: [\"--bits\"],\n};\n","import type { IdCodec } from \"../adapter-types.js\";\nimport { isKeyFormatError, loadKey, parseKeyFormat } from \"./key-io.js\";\nimport type { RunOpts } from \"./types.js\";\nimport { conflictPriorityOrder, type Descriptor, type Policy } from \"./variants.js\";\n\nexport function deriveAllowedFlags(policy: Policy): Set<string> {\n const flags = new Set<string>(policy.intrinsicFlags);\n let hasKeyed = policy.default.key !== undefined;\n for (const v of policy.selectable) {\n if (v.flag !== undefined) flags.add(v.flag);\n if (v.key !== undefined) hasKeyed = true;\n if (v.extraFlags !== undefined) {\n for (const f of v.extraFlags) flags.add(f);\n }\n }\n if (hasKeyed) flags.add(\"--key-format\");\n return flags;\n}\n\nexport function resolveVariant(policy: Policy, flags: Set<string>): Descriptor | string {\n const selected = conflictPriorityOrder.filter(\n (v) => policy.selectable.includes(v) && v.flag !== undefined && flags.has(v.flag),\n );\n if (selected.length === 0) return policy.default;\n if (selected.length === 1) return selected[0]!;\n return `cannot use ${selected[0]!.flag} and ${selected[1]!.flag} together`;\n}\n\nexport async function buildCodec(\n variant: Descriptor,\n brand: string,\n values: Map<string, string>,\n opts: RunOpts,\n): Promise<IdCodec<string> | string> {\n let key: unknown;\n if (variant.key !== undefined) {\n const format = parseKeyFormat(values, opts, variant.key);\n if (isKeyFormatError(format)) return format;\n const keyResult = await loadKey(opts, format, variant.key);\n if (typeof keyResult === \"string\") return keyResult;\n key = keyResult;\n }\n return variant.construct(brand, opts, key, values);\n}\n","import { deriveAllowedFlags, resolveVariant } from \"../dispatch.js\";\nimport { parseBits, splitFlags, unsupportedFlagForCommand } from \"../flags.js\";\nimport { isKeyFormatError, parseKeyFormatFromFlag } from \"../key-io.js\";\nimport type { RunOpts } from \"../types.js\";\nimport { keygenPolicy } from \"../variants.js\";\n\nexport function runKeygen(args: ReadonlyArray<string>, opts: RunOpts): Promise<number> {\n const allowedFlags = deriveAllowedFlags(keygenPolicy);\n const variantExtraFlags = new Set(keygenPolicy.selectable.flatMap((v) => v.extraFlags ?? []));\n const { flags, values, positionals, errors } = splitFlags(args, allowedFlags);\n const unsupported = unsupportedFlagForCommand(\n \"keygen\",\n flags,\n new Set([...allowedFlags].filter((f) => !variantExtraFlags.has(f))),\n );\n if (unsupported !== undefined) {\n opts.stderr(unsupported + \"\\n\");\n return Promise.resolve(1);\n }\n if (errors[0] !== undefined) {\n opts.stderr(errors[0] + \"\\n\");\n return Promise.resolve(1);\n }\n const extra = positionals[0];\n if (extra !== undefined) {\n opts.stderr(`unexpected argument: ${extra}\\n`);\n return Promise.resolve(1);\n }\n const variant = resolveVariant(keygenPolicy, flags);\n if (typeof variant === \"string\") {\n opts.stderr(variant + \"\\n\");\n return Promise.resolve(1);\n }\n const bits = parseBits(values);\n if (typeof bits === \"string\") {\n opts.stderr(bits + \"\\n\");\n return Promise.resolve(1);\n }\n const format = parseKeyFormatFromFlag(values);\n if (isKeyFormatError(format)) {\n opts.stderr(format + \"\\n\");\n return Promise.resolve(1);\n }\n /* v8 ignore next 4 -- defensive guard; all keygenPolicy variants have key defined */\n if (variant.key === undefined) {\n opts.stderr(\"internal: keygen policy variant has no key facet\\n\");\n return Promise.resolve(1);\n }\n const bytes = new Uint8Array(bits / 8);\n crypto.getRandomValues(bytes);\n opts.stdout(variant.key.encode(bytes, format) + \"\\n\");\n return Promise.resolve(0);\n}\n","import { runGenerate } from \"./cli/commands/generate.js\";\nimport { runInspect } from \"./cli/commands/inspect.js\";\nimport { runKeygen } from \"./cli/commands/keygen.js\";\nimport type { CommandHandler, RunOpts } from \"./cli/types.js\";\nimport { usage } from \"./cli/usage.js\";\n\nexport type { RunOpts } from \"./cli/types.js\";\n\ntype Command = {\n names: ReadonlyArray<string>;\n run: CommandHandler;\n};\n\nconst commands: ReadonlyArray<Command> = [\n { names: [\"generate\", \"g\"], run: runGenerate },\n { names: [\"inspect\", \"i\"], run: runInspect },\n { names: [\"keygen\", \"k\"], run: runKeygen },\n];\n\nexport async function run(opts: RunOpts): Promise<number> {\n const [subcommand, ...rest] = opts.argv;\n const command = commands.find((candidate) => candidate.names.includes(subcommand ?? \"\"));\n if (command !== undefined) return command.run(rest, opts);\n if (subcommand === undefined || subcommand === \"--help\" || subcommand === \"-h\") {\n opts.stdout(usage());\n return 0;\n }\n opts.stderr(usage());\n return 1;\n}\n","#!/usr/bin/env node\nimport { run } from \"../src/cli.js\";\n\nprocess.exitCode = await run({\n argv: process.argv.slice(2),\n stdout: (s) => process.stdout.write(s),\n stderr: (s) => process.stderr.write(s),\n});\n"],"mappings":"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"}
@@ -8,9 +8,9 @@ function validateBrand(brand) {
8
8
  //#endregion
9
9
  //#region src/base32.ts
10
10
  const alphabet = "0123456789abcdefghjkmnpqrstvwxyz";
11
- const valueToCharCode = new Uint8Array(32);
11
+ const valueToCharCode = /* @__PURE__ */ new Uint8Array(32);
12
12
  for (let i = 0; i < 32; i++) valueToCharCode[i] = alphabet.charCodeAt(i);
13
- const charCodeToValue = new Uint8Array(256).fill(255);
13
+ const charCodeToValue = (/* @__PURE__ */ new Uint8Array(256)).fill(255);
14
14
  for (let i = 0; i < 32; i++) charCodeToValue[alphabet.charCodeAt(i)] = i;
15
15
  function encodeBase32(bytes) {
16
16
  const codes = new Array(Math.floor(bytes.length * 8 / 5) + 1);
@@ -64,6 +64,7 @@ function payloadBytesFromId(prefix, id) {
64
64
  }
65
65
  const payloadBase32Length = Math.ceil(128 / 5);
66
66
  const base32CharClass = "[0-9a-hjkmnp-tv-z]";
67
+ const base32FinalCharClass = "[048cgmrw]";
67
68
  //#endregion
68
69
  //#region src/registry.ts
69
70
  const registeredBrands = /* @__PURE__ */ new Set();
@@ -82,7 +83,7 @@ function registerBrand(brand, allowDuplicateBrand) {
82
83
  const replacePattern = /[ilo]/g;
83
84
  const aliasTestPattern = /[ilo]/;
84
85
  const replacer = (match) => match === "o" ? "0" : "1";
85
- const base32Pattern = new RegExp(`^[${alphabet}]{${payloadBase32Length}}$`);
86
+ const base32Pattern = new RegExp(`^[${alphabet}]{${payloadBase32Length - 1}}${base32FinalCharClass}$`);
86
87
  function safeParse(prefix, value) {
87
88
  if (typeof value !== "string") return {
88
89
  ok: false,
@@ -135,7 +136,7 @@ function wireMethods(prefix) {
135
136
  safeParse: (value) => safeParse(prefix, value),
136
137
  toJsonSchema: (brand, example) => ({
137
138
  type: "string",
138
- pattern: `^${prefix}${base32CharClass}{${payloadBase32Length}}$`,
139
+ pattern: `^${prefix}${base32CharClass}{${payloadBase32Length - 1}}${base32FinalCharClass}$`,
139
140
  description: `Branded ID for '${brand}'`,
140
141
  example
141
142
  }),
@@ -149,4 +150,4 @@ function wireMethods(prefix) {
149
150
  //#endregion
150
151
  export { toWireId as a, payloadBytesFromId as i, registerBrand as n, decodeBase32 as o, payloadBase32Length as r, validateBrand as s, wireMethods as t };
151
152
 
152
- //# sourceMappingURL=codec-shell-DH-UO4UR.mjs.map
153
+ //# sourceMappingURL=codec-shell-CW2sD6BU.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codec-shell-CW2sD6BU.mjs","names":[],"sources":["../src/brand.ts","../src/base32.ts","../src/wire/envelope.ts","../src/wire/invariants.ts","../src/registry.ts","../src/wire/parse.ts","../src/wire/codec-shell.ts"],"sourcesContent":["import { IdsError } from \"./error.js\";\n\nconst brandPattern = /^[a-z]{3}$/;\n\n/** Validates a three-character lowercase brand. Throws on invalid input. */\nexport function validateBrand(brand: string): void {\n if (!brandPattern.test(brand)) {\n throw new IdsError(\"invalid_brand\", \"invalid brand: expected three lowercase a-z characters\");\n }\n}\n","/*\n This is based on Crockford's Base32 spec: https://www.crockford.com/base32.html\n One difference is that it uses lowercase instead of uppercase when encoding.\n\n These functions are internal: codec constructors guarantee that input is a\n 16-byte buffer for encode, or a string of characters drawn from the alphabet\n for decode. Invalid input produces silent garbage rather than a thrown error,\n consistent with the trust-the-type rule in ADR-0003.\n*/\n\nexport const alphabet = \"0123456789abcdefghjkmnpqrstvwxyz\";\n\n// 0–31 → ASCII char code, for write-into-codes-then-fromCharCode encoding.\nconst valueToCharCode = new Uint8Array(32);\nfor (let i = 0; i < 32; i++) valueToCharCode[i] = alphabet.charCodeAt(i);\n\n// charCode → 0–31 value. Canonical lowercase only; upstream resolves case and\n// o/i/l aliases before any string reaches decodeBase32.\nconst INVALID = 0xff;\nconst charCodeToValue = new Uint8Array(256).fill(INVALID);\nfor (let i = 0; i < alphabet.length; i++) charCodeToValue[alphabet.charCodeAt(i)] = i;\n\nexport function encodeBase32(bytes: Uint8Array): string {\n // Build an Array<number> of char codes and pass it to fromCharCode.apply.\n // Faster than `result += char` (avoids cons-string overhead) and than\n // Uint8Array variants (apply has a fast path for plain Arrays).\n // oxlint-disable-next-line no-new-array\n const codes = new Array<number>(Math.floor((bytes.length * 8) / 5) + 1);\n let chi = 0;\n let bits = 0;\n let value = 0;\n\n for (let i = 0; i < bytes.length; i++) {\n value = (value << 8) | bytes[i]!;\n bits += 8;\n while (bits >= 5) {\n bits -= 5;\n codes[chi++] = valueToCharCode[(value >>> bits) & 0x1f]!;\n }\n }\n codes[chi] = valueToCharCode[(value << (5 - bits)) & 0x1f]!;\n return String.fromCharCode.apply(null, codes);\n}\n\nexport function decodeBase32(str: string): Uint8Array {\n const result = new Uint8Array(Math.floor((str.length * 5) / 8));\n let bits = 0;\n let value = 0;\n let index = 0;\n\n for (let i = 0; i < str.length; i++) {\n const v = charCodeToValue[str.charCodeAt(i)]!;\n value = (value << 5) | v;\n bits += 5;\n if (bits >= 8) {\n bits -= 8;\n result[index++] = (value >>> bits) & 0xff;\n }\n }\n return result;\n}\n","import { decodeBase32, encodeBase32 } from \"../base32.js\";\nimport type { Id, Prefix } from \"../types.js\";\n\n/** Encodes a 16-byte payload as lowercase Crockford base32 (26 chars). */\nfunction encodePayload(bytes: Uint8Array): string {\n return encodeBase32(bytes);\n}\n\n/** Decodes a 26-char base32 payload suffix to 16 bytes. Trust-the-type. */\nfunction decodePayload(base32: string): Uint8Array {\n return decodeBase32(base32);\n}\n\n/** Composes a canonical wire ID from a prefix and 16-byte payload. */\nexport function toWireId<Brand extends string>(\n prefix: Prefix<Brand>,\n payload: Uint8Array,\n): Id<Brand> {\n return (prefix + encodePayload(payload)) as Id<Brand>;\n}\n\n/** Decodes the full 16-byte payload from a trusted wire ID. */\nexport function payloadBytesFromId<Brand extends string>(\n prefix: Prefix<Brand>,\n id: Id<Brand>,\n): Uint8Array {\n return decodePayload(id.slice(prefix.length));\n}\n","// Payload is always 16 bytes on the wire (every codec). 16 bytes → 26 Crockford\n// base32 chars. ADR-0002 codifies this as the shared wire-format invariant.\nexport const payloadByteLength: number = 16;\nexport const payloadBase32Length: number = Math.ceil((payloadByteLength * 8) / 5);\n\n// Compact regex character class for the canonical lowercase Crockford alphabet\n// (`0123456789abcdefghjkmnpqrstvwxyz` — excludes i, l, o, u). Used in the JSON\n// Schema `pattern`, which describes the canonical wire form only (ADR-0003).\nexport const base32CharClass: string = \"[0-9a-hjkmnp-tv-z]\";\n\n// The 8 alphabet values at indices divisible by 4 (low 2 bits = 00) that satisfy the\n// canonical padding-bit constraint for a 130-bit encoding of 16 bytes. ADR-0003.\nexport const base32FinalCharClass: string = \"[048cgmrw]\";\n","const registeredBrands = new Set<string>();\nconst warnedBrands = new Set<string>();\n\nexport function registerBrand(brand: string, allowDuplicateBrand: boolean | undefined): void {\n if (\n typeof process === \"undefined\" ||\n process.env.NODE_ENV === \"production\" ||\n allowDuplicateBrand\n ) {\n return;\n }\n\n if (registeredBrands.has(brand)) {\n if (!warnedBrands.has(brand)) {\n console.warn(\n `[@smonn/ids] brand \"${brand}\" was registered more than once — this usually indicates a bundling or import bug, or that more than one codec variant is using the same brand. Pass { allowDuplicateBrand: true } to silence.`,\n );\n warnedBrands.add(brand);\n }\n } else {\n registeredBrands.add(brand);\n }\n}\n","import { alphabet } from \"../base32.js\";\nimport type { Id, ParseError, ParseResult, Prefix } from \"../types.js\";\nimport { base32FinalCharClass, payloadBase32Length } from \"./invariants.js\";\n\nconst replacePattern = /[ilo]/g;\nconst aliasTestPattern = /[ilo]/;\nconst replacer = (match: string): string => (match === \"o\" ? \"0\" : \"1\");\nconst base32Pattern = new RegExp(\n `^[${alphabet}]{${payloadBase32Length - 1}}${base32FinalCharClass}$`,\n);\n\nexport function safeParse<Brand extends string>(\n prefix: Prefix<Brand>,\n value: unknown,\n): ParseResult<Brand> {\n if (typeof value !== \"string\") return { ok: false, error: \"not_string\" };\n const lowercase = value.toLowerCase();\n if (!lowercase.startsWith(prefix)) return { ok: false, error: \"invalid_prefix\" };\n\n const sliced = lowercase.slice(prefix.length);\n const base32 = aliasTestPattern.test(sliced)\n ? sliced.replaceAll(replacePattern, replacer)\n : sliced;\n\n if (!base32Pattern.test(base32)) return { ok: false, error: \"invalid_base32\" };\n\n const id = (prefix + base32) as Id<Brand>;\n return { ok: true, id };\n}\n\nexport function is<Brand extends string>(\n prefix: Prefix<Brand>,\n value: unknown,\n): value is Id<Brand> {\n if (typeof value !== \"string\") return false;\n if (!value.startsWith(prefix)) return false;\n return base32Pattern.test(value.slice(prefix.length));\n}\n\nfunction errorMessage<Brand extends string>(prefix: Prefix<Brand>, error: ParseError): string {\n switch (error) {\n case \"not_string\":\n return \"expected string\";\n case \"invalid_prefix\":\n return `expected prefix '${prefix}'`;\n case \"invalid_base32\":\n return \"invalid base32 payload\";\n }\n}\n\nexport function standardValidate<Brand extends string>(\n prefix: Prefix<Brand>,\n value: unknown,\n):\n | { readonly value: Id<Brand>; readonly issues?: undefined }\n | { readonly issues: ReadonlyArray<{ readonly message: string }> } {\n const result = safeParse(prefix, value);\n if (result.ok) return { value: result.id };\n return { issues: [{ message: errorMessage(prefix, result.error) }] };\n}\n","import { IdsError } from \"../error.js\";\nimport type { Id, JsonSchema, ParseResult, Prefix, StandardSchemaProps } from \"../types.js\";\nimport { base32CharClass, base32FinalCharClass, payloadBase32Length } from \"./invariants.js\";\nimport { is, safeParse, standardValidate } from \"./parse.js\";\n\ntype WireMethods<Brand extends string> = {\n is: (value: unknown) => value is Id<Brand>;\n parse: (value: unknown) => Id<Brand>;\n safeParse: (value: unknown) => ParseResult<Brand>;\n toJsonSchema: (brand: Brand, example: string) => JsonSchema;\n \"~standard\": StandardSchemaProps<Brand>;\n};\n\n/** Wire-only methods shared by every codec variant for a fixed prefix. */\nexport function wireMethods<Brand extends string>(prefix: Prefix<Brand>): WireMethods<Brand> {\n const standard: StandardSchemaProps<Brand> = {\n version: 1,\n vendor: \"@smonn/ids\",\n validate: (value: unknown) => standardValidate(prefix, value),\n };\n return {\n is: (value: unknown): value is Id<Brand> => is(prefix, value),\n parse: (value: unknown): Id<Brand> => {\n const result = safeParse(prefix, value);\n if (result.ok) return result.id;\n throw new IdsError(\"invalid_id\", `invalid ID: ${result.error}`, { cause: result.error });\n },\n safeParse: (value: unknown): ParseResult<Brand> => safeParse(prefix, value),\n toJsonSchema: (brand: Brand, example: string): JsonSchema => ({\n type: \"string\",\n pattern: `^${prefix}${base32CharClass}{${payloadBase32Length - 1}}${base32FinalCharClass}$`,\n description: `Branded ID for '${brand}'`,\n example,\n }),\n \"~standard\": standard,\n };\n}\n"],"mappings":"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"}
@@ -1,3 +1,34 @@
1
1
  import { n as IdsErrorCode, r as isIdsError, t as IdsError } from "./error-DTr4i6Ic.mjs";
2
- import { n as idColumn, t as IdColumnCodec } from "./drizzle-CeSni5PB.mjs";
3
- export { IdColumnCodec, IdsError, type IdsErrorCode, idColumn, isIdsError };
2
+ import { t as Id } from "./types-g7CiQDyE.mjs";
3
+ import { n as IdColumnCodec } from "./adapter-types-unUcmMXC.mjs";
4
+ import { ConvertCustomConfig, PgCustomColumnBuilder } from "drizzle-orm/pg-core";
5
+
6
+ //#region src/drizzle.d.ts
7
+ /**
8
+ * Drizzle custom column type that stores an `Id<Brand>` as a canonical `text` value.
9
+ *
10
+ * **Write path:** passes the `Id<Brand>` directly to the driver — it is already
11
+ * the canonical string form.
12
+ *
13
+ * **Read path:** normalises the raw DB string via `codec.safeParse()`, not strict
14
+ * `is()`. Data at rest should already be canonical per ADR-0003, but `safeParse`
15
+ * is a safe boundary in case stale non-canonical values exist. Throws if the
16
+ * value from the database does not parse as a valid `Id<Brand>`.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import { idColumn } from "@smonn/ids/drizzle";
21
+ * import { createTimestampId } from "@smonn/ids";
22
+ *
23
+ * const usr = createTimestampId("usr");
24
+ * export const users = pgTable("users", { id: idColumn(usr).primaryKey() });
25
+ * // users.id is Id<"usr"> end-to-end
26
+ * ```
27
+ */
28
+ declare function idColumn<Brand extends string>(codec: IdColumnCodec<Brand>): PgCustomColumnBuilder<ConvertCustomConfig<"", {
29
+ data: Id<Brand>;
30
+ driverData: string;
31
+ }>>;
32
+ //#endregion
33
+ export { type IdColumnCodec, IdsError, type IdsErrorCode, idColumn, isIdsError };
34
+ //# sourceMappingURL=drizzle.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drizzle.d.mts","names":[],"sources":["../src/drizzle.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmCgB,QAAA,uBACd,KAAA,EAAO,aAAA,CAAc,KAAA,IACpB,qBAAA,CAAsB,mBAAA;EAA0B,IAAA,EAAM,EAAA,CAAG,KAAA;EAAQ,UAAA;AAAA"}
package/dist/drizzle.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  import { n as isIdsError, t as IdsError } from "./error-Cp5qYZcv.mjs";
2
+ import { t as readIdColumn } from "./adapter-types-BY-wrYYB.mjs";
2
3
  import { customType } from "drizzle-orm/pg-core";
3
4
  //#region src/drizzle.ts
4
5
  /**
@@ -31,9 +32,7 @@ function idColumn(codec) {
31
32
  return value;
32
33
  },
33
34
  fromDriver(value) {
34
- const result = codec.safeParse(value);
35
- if (!result.ok) throw new IdsError("invalid_id", `invalid ID from database: ${result.error}`, { cause: result.error });
36
- return result.id;
35
+ return readIdColumn(codec, value);
37
36
  }
38
37
  })();
39
38
  }
@@ -1 +1 @@
1
- {"version":3,"file":"drizzle.mjs","names":[],"sources":["../src/drizzle.ts"],"sourcesContent":["import {\n customType,\n type ConvertCustomConfig,\n type PgCustomColumnBuilder,\n} from \"drizzle-orm/pg-core\";\nimport { IdsError, isIdsError, type IdsErrorCode } from \"./error.js\";\nimport type { Id, ParseResult } from \"./types.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 };\n\n/**\n * Minimum codec interface required by the Drizzle adapter.\n *\n * Any codec variant satisfies this type — TimestampCodec, OpaqueTimestampCodec,\n * and WrappedKeyCodec all expose `safeParse`. The adapter never calls\n * `extractTimestamp`, `wrap`/`unwrap`, or any key-dependent method.\n *\n * Kysely and Prisma adapter issues should use this same codec contract shape.\n */\nexport type IdColumnCodec<Brand extends string> = {\n safeParse(value: unknown): ParseResult<Brand>;\n};\n\n/**\n * Drizzle custom column type that stores an `Id<Brand>` as a canonical `text` value.\n *\n * **Write path:** passes the `Id<Brand>` directly to the driver — it is already\n * the canonical string form.\n *\n * **Read path:** normalises the raw DB string via `codec.safeParse()`, not strict\n * `is()`. Data at rest should already be canonical per ADR-0003, but `safeParse`\n * is a safe boundary in case stale non-canonical values exist. Throws if the\n * value from the database does not parse as a valid `Id<Brand>`.\n *\n * @example\n * ```ts\n * import { idColumn } from \"@smonn/ids/drizzle\";\n * import { createTimestampId } from \"@smonn/ids\";\n *\n * const usr = createTimestampId(\"usr\");\n * export const users = pgTable(\"users\", { id: idColumn(usr).primaryKey() });\n * // users.id is Id<\"usr\"> end-to-end\n * ```\n */\nexport function idColumn<Brand extends string>(\n codec: IdColumnCodec<Brand>,\n): PgCustomColumnBuilder<ConvertCustomConfig<\"\", { data: Id<Brand>; driverData: string }>> {\n return customType<{ data: Id<Brand>; driverData: string }>({\n dataType() {\n return \"text\";\n },\n toDriver(value: Id<Brand>): string {\n return value;\n },\n fromDriver(value: string): Id<Brand> {\n const result = codec.safeParse(value);\n if (!result.ok) {\n throw new IdsError(\"invalid_id\", `invalid ID from database: ${result.error}`, {\n cause: result.error,\n });\n }\n return result.id;\n },\n })();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA6CA,SAAgB,SACd,OACyF;CACzF,OAAO,WAAoD;EACzD,WAAW;GACT,OAAO;EACT;EACA,SAAS,OAA0B;GACjC,OAAO;EACT;EACA,WAAW,OAA0B;GACnC,MAAM,SAAS,MAAM,UAAU,KAAK;GACpC,IAAI,CAAC,OAAO,IACV,MAAM,IAAI,SAAS,cAAc,6BAA6B,OAAO,SAAS,EAC5E,OAAO,OAAO,MAChB,CAAC;GAEH,OAAO,OAAO;EAChB;CACF,CAAC,CAAC,CAAC;AACL"}
1
+ {"version":3,"file":"drizzle.mjs","names":[],"sources":["../src/drizzle.ts"],"sourcesContent":["import {\n customType,\n type ConvertCustomConfig,\n type PgCustomColumnBuilder,\n} from \"drizzle-orm/pg-core\";\nimport { IdsError, isIdsError, type IdsErrorCode } from \"./error.js\";\nimport { readIdColumn, type IdColumnCodec } from \"./adapter-types.js\";\nimport type { Id } from \"./types.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 };\n\nexport type { IdColumnCodec };\n\n/**\n * Drizzle custom column type that stores an `Id<Brand>` as a canonical `text` value.\n *\n * **Write path:** passes the `Id<Brand>` directly to the driver — it is already\n * the canonical string form.\n *\n * **Read path:** normalises the raw DB string via `codec.safeParse()`, not strict\n * `is()`. Data at rest should already be canonical per ADR-0003, but `safeParse`\n * is a safe boundary in case stale non-canonical values exist. Throws if the\n * value from the database does not parse as a valid `Id<Brand>`.\n *\n * @example\n * ```ts\n * import { idColumn } from \"@smonn/ids/drizzle\";\n * import { createTimestampId } from \"@smonn/ids\";\n *\n * const usr = createTimestampId(\"usr\");\n * export const users = pgTable(\"users\", { id: idColumn(usr).primaryKey() });\n * // users.id is Id<\"usr\"> end-to-end\n * ```\n */\nexport function idColumn<Brand extends string>(\n codec: IdColumnCodec<Brand>,\n): PgCustomColumnBuilder<ConvertCustomConfig<\"\", { data: Id<Brand>; driverData: string }>> {\n return customType<{ data: Id<Brand>; driverData: string }>({\n dataType() {\n return \"text\";\n },\n toDriver(value: Id<Brand>): string {\n return value;\n },\n fromDriver(value: string): Id<Brand> {\n return readIdColumn(codec, value);\n },\n })();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAmCA,SAAgB,SACd,OACyF;CACzF,OAAO,WAAoD;EACzD,WAAW;GACT,OAAO;EACT;EACA,SAAS,OAA0B;GACjC,OAAO;EACT;EACA,WAAW,OAA0B;GACnC,OAAO,aAAa,OAAO,KAAK;EAClC;CACF,CAAC,CAAC,CAAC;AACL"}
@@ -1,11 +1,8 @@
1
- import { i as ParseResult, t as Id } from "./types-g7CiQDyE.mjs";
2
- import { t as IdParamFailure } from "./adapter-types-oHCCSgOO.mjs";
1
+ import { t as Id } from "./types-g7CiQDyE.mjs";
2
+ import { r as IdParamFailure, t as IdCodec } from "./adapter-types-unUcmMXC.mjs";
3
3
  import { NextFunction, Request, Response } from "express";
4
4
 
5
5
  //#region src/express.d.ts
6
- type IdCodec<Brand extends string> = {
7
- safeParse(value: unknown): ParseResult<Brand>;
8
- };
9
6
  /**
10
7
  * Typed error forwarded to Express's error pipeline (`next(err)`) on validation failure.
11
8
  * Inspect `err.reason` and `err.status` in error-handling middleware.
@@ -1 +1 @@
1
- {"version":3,"file":"express.d.mts","names":[],"sources":["../src/express.ts"],"mappings":";;;;;KAMK,OAAA;EACH,SAAA,CAAU,KAAA,YAAiB,WAAA,CAAY,KAAA;AAAA;;;;;cAO5B,YAAA,SAAqB,KAAA;EAAA,SACvB,MAAA;EAAA,SACA,MAAA;EAET,WAAA,CAAY,MAAA,kCAAwC,MAAA;AAAA;AAJtD;AAAA,KAaY,cAAA;;;;;EAKV,OAAA,IAAW,OAAA,EAAS,cAAA,EAAgB,GAAA,EAAK,OAAA,EAAS,GAAA,EAAK,QAAA,EAAU,IAAA,EAAM,YAAA;;;;;EAKvE,MAAA;IAAW,cAAA;IAAyB,SAAA;EAAA;AAAA;;;;;;;;;;;;;;;;;;;AAAA;AAmDtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAgB,OAAA,gDACd,SAAA,EAAW,QAAA,EACX,KAAA,EAAO,OAAA,CAAQ,KAAA,GACf,OAAA,GAAU,cAAA,IACR,GAAA,EAAK,OAAA,EAAS,GAAA,EAAK,QAAA,UAAkB,MAAA,CAAO,QAAA,EAAU,EAAA,CAAG,KAAA,KAAU,IAAA,EAAM,YAAA"}
1
+ {"version":3,"file":"express.d.mts","names":[],"sources":["../src/express.ts"],"mappings":";;;;;;AAUA;;;cAAa,YAAA,SAAqB,KAAA;EAAA,SACvB,MAAA;EAAA,SACA,MAAA;EAET,WAAA,CAAY,MAAA,kCAAwC,MAAA;AAAA;;KAS1C,cAAA;EAT0C;AAAA;AAStD;;EAKE,OAAA,IAAW,OAAA,EAAS,cAAA,EAAgB,GAAA,EAAK,OAAA,EAAS,GAAA,EAAK,QAAA,EAAU,IAAA,EAAM,YAAA;;;;;EAKvE,MAAA;IAAW,cAAA;IAAyB,SAAA;EAAA;AAAA;;;;;;;;;;;AAAA;AAmDtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAI6E;iBAJ7D,OAAA,gDACd,SAAA,EAAW,QAAA,EACX,KAAA,EAAO,OAAA,CAAQ,KAAA,GACf,OAAA,GAAU,cAAA,IACR,GAAA,EAAK,OAAA,EAAS,GAAA,EAAK,QAAA,UAAkB,MAAA,CAAO,QAAA,EAAU,EAAA,CAAG,KAAA,KAAU,IAAA,EAAM,YAAA"}
package/dist/express.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ import { n as resolveIdParamFailure } from "./adapter-types-BY-wrYYB.mjs";
1
2
  //#region src/express.ts
2
3
  /**
3
4
  * Typed error forwarded to Express's error pipeline (`next(err)`) on validation failure.
@@ -66,18 +67,12 @@ function idParam(paramName, codec, options) {
66
67
  const raw = req.params[paramName];
67
68
  const result = codec.safeParse(raw);
68
69
  if (!result.ok) {
69
- const reason = result.error === "invalid_prefix" ? "brand_mismatch" : "malformed";
70
- const defaultStatus = reason === "brand_mismatch" ? 404 : 400;
71
- const status = options?.status?.[reason] ?? defaultStatus;
72
- const failure = {
73
- reason,
74
- status
75
- };
70
+ const failure = resolveIdParamFailure(result.error, options);
76
71
  if (options?.onError) {
77
72
  options.onError(failure, req, res, next);
78
73
  return;
79
74
  }
80
- next(new IdParamError(reason, status));
75
+ next(new IdParamError(failure.reason, failure.status));
81
76
  return;
82
77
  }
83
78
  res.locals[paramName] = result.id;
@@ -1 +1 @@
1
- {"version":3,"file":"express.mjs","names":[],"sources":["../src/express.ts"],"sourcesContent":["import type { NextFunction, Request, Response } from \"express\";\nimport type { IdParamFailure } from \"./adapter-types.js\";\nimport type { Id, ParseResult } from \"./types.js\";\n\nexport type { IdParamFailure };\n\ntype IdCodec<Brand extends string> = {\n safeParse(value: unknown): ParseResult<Brand>;\n};\n\n/**\n * Typed error forwarded to Express's error pipeline (`next(err)`) on validation failure.\n * Inspect `err.reason` and `err.status` in error-handling middleware.\n */\nexport class IdParamError extends Error {\n readonly status: number;\n readonly reason: \"brand_mismatch\" | \"malformed\";\n\n constructor(reason: \"brand_mismatch\" | \"malformed\", status: number) {\n super(`ID validation failed: ${reason}`);\n this.name = \"IdParamError\";\n this.reason = reason;\n this.status = status;\n }\n}\n\n/** Options for `idParam`. All fields are optional. */\nexport type IdParamOptions = {\n /**\n * Called instead of forwarding to `next(err)` when provided. The hook owns the response\n * entirely — the adapter does not call `next(err)` itself.\n */\n onError?: (failure: IdParamFailure, req: Request, res: Response, next: NextFunction) => void;\n /**\n * Remap the default HTTP status for a failure reason without a full handler.\n * e.g. `{ brand_mismatch: 400 }` treats both failure kinds as 400.\n */\n status?: { brand_mismatch?: number; malformed?: number };\n};\n\n/**\n * Express middleware that validates a named route param against a codec via `safeParse`.\n *\n * **Default (no options):** calls `next(err)` with an `IdParamError` carrying `status` and `reason`,\n * so the app's existing error-handling middleware controls rendering. The adapter does not write\n * a response body itself.\n *\n * **`options.onError`:** when provided, the hook owns the response entirely — the adapter does\n * not call `next(err)`.\n *\n * **`options.status`:** remaps the default HTTP status for a reason without a full handler.\n *\n * - **Brand mismatch (`invalid_prefix`) → `reason: \"brand_mismatch\"`, default 404**\n * - **Malformed or missing ID → `reason: \"malformed\"`, default 400**\n *\n * On success, stores the canonical `Id<Brand>` in `res.locals` under `paramName`\n * and calls `next()`.\n *\n * @example\n * ```ts\n * import { idParam, IdParamError } from \"@smonn/ids/express\";\n * import { createTimestampId } from \"@smonn/ids\";\n *\n * const usr = createTimestampId(\"usr\");\n *\n * // Default: forwards error to app error-handling middleware\n * app.get(\"/users/:id\", idParam(\"id\", usr), (req, res) => {\n * const id = res.locals.id; // Id<\"usr\">, canonical\n * });\n *\n * // Error-handling middleware receives the typed error\n * app.use((err, req, res, next) => {\n * if (err instanceof IdParamError) {\n * res.status(err.status).json({ error: err.reason });\n * return;\n * }\n * next(err);\n * });\n *\n * // Override: consumer fully owns the response\n * app.get(\"/orgs/:id\", idParam(\"id\", org, {\n * onError: (failure, req, res) => res.status(failure.status).json({ error: failure.reason }),\n * }), handler);\n *\n * // Or a lightweight status remap without a full handler\n * app.get(\"/things/:id\", idParam(\"id\", thing, { status: { brand_mismatch: 400 } }), handler);\n * ```\n */\nexport function idParam<ParamKey extends string, Brand extends string>(\n paramName: ParamKey,\n codec: IdCodec<Brand>,\n options?: IdParamOptions,\n): (req: Request, res: Response<unknown, Record<ParamKey, Id<Brand>>>, next: NextFunction) => void {\n return (req, res, next): void => {\n const raw = req.params[paramName];\n const result = codec.safeParse(raw);\n if (!result.ok) {\n const reason =\n result.error === \"invalid_prefix\" ? (\"brand_mismatch\" as const) : (\"malformed\" as const);\n const defaultStatus = reason === \"brand_mismatch\" ? 404 : 400;\n const status = options?.status?.[reason] ?? defaultStatus;\n const failure: IdParamFailure = { reason, status };\n if (options?.onError) {\n options.onError(failure, req, res, next);\n return;\n }\n next(new IdParamError(reason, status));\n return;\n }\n (res.locals as Record<string, unknown>)[paramName] = result.id;\n next();\n };\n}\n"],"mappings":";;;;;AAcA,IAAa,eAAb,cAAkC,MAAM;CACtC;CACA;CAEA,YAAY,QAAwC,QAAgB;EAClE,MAAM,yBAAyB,QAAQ;EACvC,KAAK,OAAO;EACZ,KAAK,SAAS;EACd,KAAK,SAAS;CAChB;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgEA,SAAgB,QACd,WACA,OACA,SACiG;CACjG,QAAQ,KAAK,KAAK,SAAe;EAC/B,MAAM,MAAM,IAAI,OAAO;EACvB,MAAM,SAAS,MAAM,UAAU,GAAG;EAClC,IAAI,CAAC,OAAO,IAAI;GACd,MAAM,SACJ,OAAO,UAAU,mBAAoB,mBAA8B;GACrE,MAAM,gBAAgB,WAAW,mBAAmB,MAAM;GAC1D,MAAM,SAAS,SAAS,SAAS,WAAW;GAC5C,MAAM,UAA0B;IAAE;IAAQ;GAAO;GACjD,IAAI,SAAS,SAAS;IACpB,QAAQ,QAAQ,SAAS,KAAK,KAAK,IAAI;IACvC;GACF;GACA,KAAK,IAAI,aAAa,QAAQ,MAAM,CAAC;GACrC;EACF;EACA,IAAK,OAAmC,aAAa,OAAO;EAC5D,KAAK;CACP;AACF"}
1
+ {"version":3,"file":"express.mjs","names":[],"sources":["../src/express.ts"],"sourcesContent":["import type { NextFunction, Request, Response } from \"express\";\nimport { type IdCodec, type IdParamFailure, resolveIdParamFailure } from \"./adapter-types.js\";\nimport type { Id } from \"./types.js\";\n\nexport type { IdParamFailure };\n\n/**\n * Typed error forwarded to Express's error pipeline (`next(err)`) on validation failure.\n * Inspect `err.reason` and `err.status` in error-handling middleware.\n */\nexport class IdParamError extends Error {\n readonly status: number;\n readonly reason: \"brand_mismatch\" | \"malformed\";\n\n constructor(reason: \"brand_mismatch\" | \"malformed\", status: number) {\n super(`ID validation failed: ${reason}`);\n this.name = \"IdParamError\";\n this.reason = reason;\n this.status = status;\n }\n}\n\n/** Options for `idParam`. All fields are optional. */\nexport type IdParamOptions = {\n /**\n * Called instead of forwarding to `next(err)` when provided. The hook owns the response\n * entirely — the adapter does not call `next(err)` itself.\n */\n onError?: (failure: IdParamFailure, req: Request, res: Response, next: NextFunction) => void;\n /**\n * Remap the default HTTP status for a failure reason without a full handler.\n * e.g. `{ brand_mismatch: 400 }` treats both failure kinds as 400.\n */\n status?: { brand_mismatch?: number; malformed?: number };\n};\n\n/**\n * Express middleware that validates a named route param against a codec via `safeParse`.\n *\n * **Default (no options):** calls `next(err)` with an `IdParamError` carrying `status` and `reason`,\n * so the app's existing error-handling middleware controls rendering. The adapter does not write\n * a response body itself.\n *\n * **`options.onError`:** when provided, the hook owns the response entirely — the adapter does\n * not call `next(err)`.\n *\n * **`options.status`:** remaps the default HTTP status for a reason without a full handler.\n *\n * - **Brand mismatch (`invalid_prefix`) → `reason: \"brand_mismatch\"`, default 404**\n * - **Malformed or missing ID → `reason: \"malformed\"`, default 400**\n *\n * On success, stores the canonical `Id<Brand>` in `res.locals` under `paramName`\n * and calls `next()`.\n *\n * @example\n * ```ts\n * import { idParam, IdParamError } from \"@smonn/ids/express\";\n * import { createTimestampId } from \"@smonn/ids\";\n *\n * const usr = createTimestampId(\"usr\");\n *\n * // Default: forwards error to app error-handling middleware\n * app.get(\"/users/:id\", idParam(\"id\", usr), (req, res) => {\n * const id = res.locals.id; // Id<\"usr\">, canonical\n * });\n *\n * // Error-handling middleware receives the typed error\n * app.use((err, req, res, next) => {\n * if (err instanceof IdParamError) {\n * res.status(err.status).json({ error: err.reason });\n * return;\n * }\n * next(err);\n * });\n *\n * // Override: consumer fully owns the response\n * app.get(\"/orgs/:id\", idParam(\"id\", org, {\n * onError: (failure, req, res) => res.status(failure.status).json({ error: failure.reason }),\n * }), handler);\n *\n * // Or a lightweight status remap without a full handler\n * app.get(\"/things/:id\", idParam(\"id\", thing, { status: { brand_mismatch: 400 } }), handler);\n * ```\n */\nexport function idParam<ParamKey extends string, Brand extends string>(\n paramName: ParamKey,\n codec: IdCodec<Brand>,\n options?: IdParamOptions,\n): (req: Request, res: Response<unknown, Record<ParamKey, Id<Brand>>>, next: NextFunction) => void {\n return (req, res, next): void => {\n const raw = req.params[paramName];\n const result = codec.safeParse(raw);\n if (!result.ok) {\n const failure = resolveIdParamFailure(result.error, options);\n if (options?.onError) {\n options.onError(failure, req, res, next);\n return;\n }\n next(new IdParamError(failure.reason, failure.status));\n return;\n }\n (res.locals as Record<string, unknown>)[paramName] = result.id;\n next();\n };\n}\n"],"mappings":";;;;;;AAUA,IAAa,eAAb,cAAkC,MAAM;CACtC;CACA;CAEA,YAAY,QAAwC,QAAgB;EAClE,MAAM,yBAAyB,QAAQ;EACvC,KAAK,OAAO;EACZ,KAAK,SAAS;EACd,KAAK,SAAS;CAChB;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgEA,SAAgB,QACd,WACA,OACA,SACiG;CACjG,QAAQ,KAAK,KAAK,SAAe;EAC/B,MAAM,MAAM,IAAI,OAAO;EACvB,MAAM,SAAS,MAAM,UAAU,GAAG;EAClC,IAAI,CAAC,OAAO,IAAI;GACd,MAAM,UAAU,sBAAsB,OAAO,OAAO,OAAO;GAC3D,IAAI,SAAS,SAAS;IACpB,QAAQ,QAAQ,SAAS,KAAK,KAAK,IAAI;IACvC;GACF;GACA,KAAK,IAAI,aAAa,QAAQ,QAAQ,QAAQ,MAAM,CAAC;GACrD;EACF;EACA,IAAK,OAAmC,aAAa,OAAO;EAC5D,KAAK;CACP;AACF"}
@@ -1,11 +1,8 @@
1
- import { i as ParseResult, t as Id } from "./types-g7CiQDyE.mjs";
2
- import { t as IdParamFailure } from "./adapter-types-oHCCSgOO.mjs";
1
+ import { t as Id } from "./types-g7CiQDyE.mjs";
2
+ import { r as IdParamFailure, t as IdCodec } from "./adapter-types-unUcmMXC.mjs";
3
3
  import { FastifyReply, FastifyRequest } from "fastify";
4
4
 
5
5
  //#region src/fastify.d.ts
6
- type IdCodec<Brand extends string> = {
7
- safeParse(value: unknown): ParseResult<Brand>;
8
- };
9
6
  /**
10
7
  * Typed error thrown into Fastify's `setErrorHandler` on validation failure.
11
8
  * Inspect `err.reason` and `err.statusCode` in your error handler.
@@ -1 +1 @@
1
- {"version":3,"file":"fastify.d.mts","names":[],"sources":["../src/fastify.ts"],"mappings":";;;;;KAMK,OAAA;EACH,SAAA,CAAU,KAAA,YAAiB,WAAA,CAAY,KAAA;AAAA;;;;;cAO5B,YAAA,SAAqB,KAAA;EAAA,SACvB,UAAA;EAAA,SACA,MAAA;EAET,WAAA,CAAY,MAAA,kCAAwC,UAAA;AAAA;AAJtD;AAAA,KAaY,cAAA;;;;;EAKV,OAAA,IACE,OAAA,EAAS,cAAA,EACT,OAAA,EAAS,cAAA,EACT,KAAA,EAAO,YAAA,YACG,OAAA;;;;;EAKZ,MAAA;IAAW,cAAA;IAAyB,SAAA;EAAA;AAAA;;;;;;;;;;;;;;;;;;AAAA;AA6DtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAOK;;;;;;iBAPW,OAAA,gDACd,SAAA,EAAW,QAAA,EACX,KAAA,EAAO,OAAA,CAAQ,KAAA,GACf,OAAA,GAAU,cAAA,IAEV,OAAA,EAAS,cAAA;EAAiB,MAAA,EAAQ,MAAA,SAAe,EAAA,CAAG,KAAA;AAAA,IACpD,KAAA,EAAO,YAAA,KACJ,OAAA"}
1
+ {"version":3,"file":"fastify.d.mts","names":[],"sources":["../src/fastify.ts"],"mappings":";;;;;;AAUA;;;cAAa,YAAA,SAAqB,KAAA;EAAA,SACvB,UAAA;EAAA,SACA,MAAA;EAET,WAAA,CAAY,MAAA,kCAAwC,UAAA;AAAA;;KAS1C,cAAA;EAT0C;AAAA;AAStD;;EAKE,OAAA,IACE,OAAA,EAAS,cAAA,EACT,OAAA,EAAS,cAAA,EACT,KAAA,EAAO,YAAA,YACG,OAAA;;;;;EAKZ,MAAA;IAAW,cAAA;IAAyB,SAAA;EAAA;AAAA;;;;;;;;;;AAAA;AA6DtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAOK;;;;;;;;;;;;;;iBAPW,OAAA,gDACd,SAAA,EAAW,QAAA,EACX,KAAA,EAAO,OAAA,CAAQ,KAAA,GACf,OAAA,GAAU,cAAA,IAEV,OAAA,EAAS,cAAA;EAAiB,MAAA,EAAQ,MAAA,SAAe,EAAA,CAAG,KAAA;AAAA,IACpD,KAAA,EAAO,YAAA,KACJ,OAAA"}
package/dist/fastify.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ import { n as resolveIdParamFailure } from "./adapter-types-BY-wrYYB.mjs";
1
2
  //#region src/fastify.ts
2
3
  /**
3
4
  * Typed error thrown into Fastify's `setErrorHandler` on validation failure.
@@ -76,18 +77,12 @@ function idParam(paramName, codec, options) {
76
77
  const raw = request.params[paramName];
77
78
  const result = codec.safeParse(raw);
78
79
  if (!result.ok) {
79
- const reason = result.error === "invalid_prefix" ? "brand_mismatch" : "malformed";
80
- const defaultStatus = reason === "brand_mismatch" ? 404 : 400;
81
- const status = options?.status?.[reason] ?? defaultStatus;
82
- const failure = {
83
- reason,
84
- status
85
- };
80
+ const failure = resolveIdParamFailure(result.error, options);
86
81
  if (options?.onError) {
87
82
  await options.onError(failure, request, reply);
88
83
  return;
89
84
  }
90
- throw new IdParamError(reason, status);
85
+ throw new IdParamError(failure.reason, failure.status);
91
86
  }
92
87
  request.params[paramName] = result.id;
93
88
  };
@@ -1 +1 @@
1
- {"version":3,"file":"fastify.mjs","names":[],"sources":["../src/fastify.ts"],"sourcesContent":["import type { FastifyReply, FastifyRequest } from \"fastify\";\nimport type { IdParamFailure } from \"./adapter-types.js\";\nimport type { Id, ParseResult } from \"./types.js\";\n\nexport type { IdParamFailure };\n\ntype IdCodec<Brand extends string> = {\n safeParse(value: unknown): ParseResult<Brand>;\n};\n\n/**\n * Typed error thrown into Fastify's `setErrorHandler` on validation failure.\n * Inspect `err.reason` and `err.statusCode` in your error handler.\n */\nexport class IdParamError extends Error {\n readonly statusCode: number;\n readonly reason: \"brand_mismatch\" | \"malformed\";\n\n constructor(reason: \"brand_mismatch\" | \"malformed\", statusCode: number) {\n super(`ID validation failed: ${reason}`);\n this.name = \"IdParamError\";\n this.reason = reason;\n this.statusCode = statusCode;\n }\n}\n\n/** Options for `idParam`. All fields are optional. */\nexport type IdParamOptions = {\n /**\n * Called instead of throwing when provided. The hook owns the response entirely —\n * the adapter does not throw.\n */\n onError?: (\n failure: IdParamFailure,\n request: FastifyRequest,\n reply: FastifyReply,\n ) => void | Promise<void>;\n /**\n * Remap the default HTTP status for a failure reason without a full handler.\n * e.g. `{ brand_mismatch: 400 }` treats both failure kinds as 400.\n */\n status?: { brand_mismatch?: number; malformed?: number };\n};\n\n/**\n * Fastify `preHandler` hook factory that validates a named route param against a codec via `safeParse`.\n *\n * **Default (no options):** throws `IdParamError` carrying `statusCode` and `reason` so the app's\n * existing `setErrorHandler` controls rendering. The adapter does not write a response body itself.\n *\n * **`options.onError`:** when provided, the hook calls `onError` and does not throw; the consumer\n * fully owns the response via `reply`.\n *\n * **`options.status`:** remaps the default HTTP status for a reason without a full handler.\n *\n * - **Brand mismatch (`invalid_prefix`) → `reason: \"brand_mismatch\"`, default 404**\n * - **Malformed or missing ID → `reason: \"malformed\"`, default 400**\n *\n * On success, stores the canonical `Id<Brand>` in `request.params` under `paramName`.\n *\n * **Return type note:** the returned hook is typed as\n * `(request: FastifyRequest<{ Params: Record<string, Id<Brand>> }>, reply: FastifyReply) => Promise<void>`.\n * Assigning it to a Fastify `preHandler` slot is backward-compatible (method-signature bivariance applies).\n * However, a locally-annotated variable typed as the bare `(request: FastifyRequest, reply: FastifyReply) => Promise<void>`\n * will produce a TypeScript error under `--strictFunctionTypes` because function parameter types are contravariant.\n * Use `preHandler` assignment or let TypeScript infer the type to avoid this.\n *\n * @example\n * ```ts\n * import { idParam, IdParamError } from \"@smonn/ids/fastify\";\n * import { createTimestampId } from \"@smonn/ids\";\n *\n * const usr = createTimestampId(\"usr\");\n *\n * // Default: throws IdParamError → setErrorHandler renders it\n * fastify.get(\"/users/:id\", { preHandler: idParam(\"id\", usr) }, (request, reply) => {\n * const id = request.params.id; // Id<\"usr\">, canonical\n * });\n *\n * // Error handler receives the typed error\n * fastify.setErrorHandler((err, request, reply) => {\n * if (err instanceof IdParamError) {\n * reply.status(err.statusCode).send({ error: err.reason });\n * return;\n * }\n * reply.send(err);\n * });\n *\n * // Override: consumer fully owns the error response\n * fastify.get(\"/orgs/:id\", {\n * preHandler: idParam(\"id\", org, {\n * onError: (failure, request, reply) =>\n * reply.status(failure.status).send({ error: failure.reason }),\n * }),\n * }, handler);\n *\n * // Or a lightweight status remap without a full handler\n * fastify.get(\"/things/:id\", {\n * preHandler: idParam(\"id\", thing, { status: { brand_mismatch: 400 } }),\n * }, handler);\n * ```\n */\nexport function idParam<ParamKey extends string, Brand extends string>(\n paramName: ParamKey,\n codec: IdCodec<Brand>,\n options?: IdParamOptions,\n): (\n request: FastifyRequest<{ Params: Record<string, Id<Brand>> }>,\n reply: FastifyReply,\n) => Promise<void> {\n return async (request, reply): Promise<void> => {\n const raw = request.params[paramName];\n const result = codec.safeParse(raw);\n if (!result.ok) {\n const reason =\n result.error === \"invalid_prefix\" ? (\"brand_mismatch\" as const) : (\"malformed\" as const);\n const defaultStatus = reason === \"brand_mismatch\" ? 404 : 400;\n const status = options?.status?.[reason] ?? defaultStatus;\n const failure: IdParamFailure = { reason, status };\n if (options?.onError) {\n await options.onError(failure, request, reply);\n return;\n }\n throw new IdParamError(reason, status);\n }\n request.params[paramName] = result.id;\n };\n}\n"],"mappings":";;;;;AAcA,IAAa,eAAb,cAAkC,MAAM;CACtC;CACA;CAEA,YAAY,QAAwC,YAAoB;EACtE,MAAM,yBAAyB,QAAQ;EACvC,KAAK,OAAO;EACZ,KAAK,SAAS;EACd,KAAK,aAAa;CACpB;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8EA,SAAgB,QACd,WACA,OACA,SAIiB;CACjB,OAAO,OAAO,SAAS,UAAyB;EAC9C,MAAM,MAAM,QAAQ,OAAO;EAC3B,MAAM,SAAS,MAAM,UAAU,GAAG;EAClC,IAAI,CAAC,OAAO,IAAI;GACd,MAAM,SACJ,OAAO,UAAU,mBAAoB,mBAA8B;GACrE,MAAM,gBAAgB,WAAW,mBAAmB,MAAM;GAC1D,MAAM,SAAS,SAAS,SAAS,WAAW;GAC5C,MAAM,UAA0B;IAAE;IAAQ;GAAO;GACjD,IAAI,SAAS,SAAS;IACpB,MAAM,QAAQ,QAAQ,SAAS,SAAS,KAAK;IAC7C;GACF;GACA,MAAM,IAAI,aAAa,QAAQ,MAAM;EACvC;EACA,QAAQ,OAAO,aAAa,OAAO;CACrC;AACF"}
1
+ {"version":3,"file":"fastify.mjs","names":[],"sources":["../src/fastify.ts"],"sourcesContent":["import type { FastifyReply, FastifyRequest } from \"fastify\";\nimport { type IdCodec, type IdParamFailure, resolveIdParamFailure } from \"./adapter-types.js\";\nimport type { Id } from \"./types.js\";\n\nexport type { IdParamFailure };\n\n/**\n * Typed error thrown into Fastify's `setErrorHandler` on validation failure.\n * Inspect `err.reason` and `err.statusCode` in your error handler.\n */\nexport class IdParamError extends Error {\n readonly statusCode: number;\n readonly reason: \"brand_mismatch\" | \"malformed\";\n\n constructor(reason: \"brand_mismatch\" | \"malformed\", statusCode: number) {\n super(`ID validation failed: ${reason}`);\n this.name = \"IdParamError\";\n this.reason = reason;\n this.statusCode = statusCode;\n }\n}\n\n/** Options for `idParam`. All fields are optional. */\nexport type IdParamOptions = {\n /**\n * Called instead of throwing when provided. The hook owns the response entirely —\n * the adapter does not throw.\n */\n onError?: (\n failure: IdParamFailure,\n request: FastifyRequest,\n reply: FastifyReply,\n ) => void | Promise<void>;\n /**\n * Remap the default HTTP status for a failure reason without a full handler.\n * e.g. `{ brand_mismatch: 400 }` treats both failure kinds as 400.\n */\n status?: { brand_mismatch?: number; malformed?: number };\n};\n\n/**\n * Fastify `preHandler` hook factory that validates a named route param against a codec via `safeParse`.\n *\n * **Default (no options):** throws `IdParamError` carrying `statusCode` and `reason` so the app's\n * existing `setErrorHandler` controls rendering. The adapter does not write a response body itself.\n *\n * **`options.onError`:** when provided, the hook calls `onError` and does not throw; the consumer\n * fully owns the response via `reply`.\n *\n * **`options.status`:** remaps the default HTTP status for a reason without a full handler.\n *\n * - **Brand mismatch (`invalid_prefix`) → `reason: \"brand_mismatch\"`, default 404**\n * - **Malformed or missing ID → `reason: \"malformed\"`, default 400**\n *\n * On success, stores the canonical `Id<Brand>` in `request.params` under `paramName`.\n *\n * **Return type note:** the returned hook is typed as\n * `(request: FastifyRequest<{ Params: Record<string, Id<Brand>> }>, reply: FastifyReply) => Promise<void>`.\n * Assigning it to a Fastify `preHandler` slot is backward-compatible (method-signature bivariance applies).\n * However, a locally-annotated variable typed as the bare `(request: FastifyRequest, reply: FastifyReply) => Promise<void>`\n * will produce a TypeScript error under `--strictFunctionTypes` because function parameter types are contravariant.\n * Use `preHandler` assignment or let TypeScript infer the type to avoid this.\n *\n * @example\n * ```ts\n * import { idParam, IdParamError } from \"@smonn/ids/fastify\";\n * import { createTimestampId } from \"@smonn/ids\";\n *\n * const usr = createTimestampId(\"usr\");\n *\n * // Default: throws IdParamError → setErrorHandler renders it\n * fastify.get(\"/users/:id\", { preHandler: idParam(\"id\", usr) }, (request, reply) => {\n * const id = request.params.id; // Id<\"usr\">, canonical\n * });\n *\n * // Error handler receives the typed error\n * fastify.setErrorHandler((err, request, reply) => {\n * if (err instanceof IdParamError) {\n * reply.status(err.statusCode).send({ error: err.reason });\n * return;\n * }\n * reply.send(err);\n * });\n *\n * // Override: consumer fully owns the error response\n * fastify.get(\"/orgs/:id\", {\n * preHandler: idParam(\"id\", org, {\n * onError: (failure, request, reply) =>\n * reply.status(failure.status).send({ error: failure.reason }),\n * }),\n * }, handler);\n *\n * // Or a lightweight status remap without a full handler\n * fastify.get(\"/things/:id\", {\n * preHandler: idParam(\"id\", thing, { status: { brand_mismatch: 400 } }),\n * }, handler);\n * ```\n */\nexport function idParam<ParamKey extends string, Brand extends string>(\n paramName: ParamKey,\n codec: IdCodec<Brand>,\n options?: IdParamOptions,\n): (\n request: FastifyRequest<{ Params: Record<string, Id<Brand>> }>,\n reply: FastifyReply,\n) => Promise<void> {\n return async (request, reply): Promise<void> => {\n const raw = request.params[paramName];\n const result = codec.safeParse(raw);\n if (!result.ok) {\n const failure = resolveIdParamFailure(result.error, options);\n if (options?.onError) {\n await options.onError(failure, request, reply);\n return;\n }\n throw new IdParamError(failure.reason, failure.status);\n }\n request.params[paramName] = result.id;\n };\n}\n"],"mappings":";;;;;;AAUA,IAAa,eAAb,cAAkC,MAAM;CACtC;CACA;CAEA,YAAY,QAAwC,YAAoB;EACtE,MAAM,yBAAyB,QAAQ;EACvC,KAAK,OAAO;EACZ,KAAK,SAAS;EACd,KAAK,aAAa;CACpB;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8EA,SAAgB,QACd,WACA,OACA,SAIiB;CACjB,OAAO,OAAO,SAAS,UAAyB;EAC9C,MAAM,MAAM,QAAQ,OAAO;EAC3B,MAAM,SAAS,MAAM,UAAU,GAAG;EAClC,IAAI,CAAC,OAAO,IAAI;GACd,MAAM,UAAU,sBAAsB,OAAO,OAAO,OAAO;GAC3D,IAAI,SAAS,SAAS;IACpB,MAAM,QAAQ,QAAQ,SAAS,SAAS,KAAK;IAC7C;GACF;GACA,MAAM,IAAI,aAAa,QAAQ,QAAQ,QAAQ,MAAM;EACvD;EACA,QAAQ,OAAO,aAAa,OAAO;CACrC;AACF"}
package/dist/hono.d.mts CHANGED
@@ -1,11 +1,8 @@
1
- import { i as ParseResult, t as Id } from "./types-g7CiQDyE.mjs";
2
- import { t as IdParamFailure } from "./adapter-types-oHCCSgOO.mjs";
1
+ import { t as Id } from "./types-g7CiQDyE.mjs";
2
+ import { r as IdParamFailure, t as IdCodec } from "./adapter-types-unUcmMXC.mjs";
3
3
  import { Context, MiddlewareHandler } from "hono";
4
4
 
5
5
  //#region src/hono.d.ts
6
- type IdCodec<Brand extends string> = {
7
- safeParse(value: unknown): ParseResult<Brand>;
8
- };
9
6
  /** Options for `idParam`. All fields are optional. */
10
7
  type IdParamOptions = {
11
8
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"hono.d.mts","names":[],"sources":["../src/hono.ts"],"mappings":";;;;;KAOK,OAAA;EACH,SAAA,CAAU,KAAA,YAAiB,WAAA,CAAY,KAAA;AAAA;;KAI7B,cAAA;;;;;EAKV,OAAA,IAAW,OAAA,EAAS,cAAA,EAAgB,CAAA,EAAG,OAAA,KAAY,QAAA,GAAW,OAAA,CAAQ,QAAA;EAT/B;AAAA;AAIzC;;EAUE,MAAA;IAAW,cAAA;IAAyB,SAAA;EAAA;AAAA;;;;;;;;;;;;;;;;AAAA;AAyCtC;;;;;;;;;;;;;;;;;;;;;;iBAAgB,OAAA,gDACd,SAAA,EAAW,QAAA,EACX,KAAA,EAAO,OAAA,CAAQ,KAAA,GACf,OAAA,GAAU,cAAA,GACT,iBAAA;EAAoB,SAAA,EAAW,MAAA,CAAO,QAAA,EAAU,EAAA,CAAG,KAAA;AAAA"}
1
+ {"version":3,"file":"hono.d.mts","names":[],"sources":["../src/hono.ts"],"mappings":";;;;;;KAQY,cAAA;EAAA;;;;EAKV,OAAA,IAAW,OAAA,EAAS,cAAA,EAAgB,CAAA,EAAG,OAAA,KAAY,QAAA,GAAW,OAAA,CAAQ,QAAA;;;;;EAKtE,MAAA;IAAW,cAAA;IAAyB,SAAA;EAAA;AAAA;;;;;;;;AAAA;AAyCtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAgB,OAAA,gDACd,SAAA,EAAW,QAAA,EACX,KAAA,EAAO,OAAA,CAAQ,KAAA,GACf,OAAA,GAAU,cAAA,GACT,iBAAA;EAAoB,SAAA,EAAW,MAAA,CAAO,QAAA,EAAU,EAAA,CAAG,KAAA;AAAA"}
package/dist/hono.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ import { n as resolveIdParamFailure } from "./adapter-types-BY-wrYYB.mjs";
1
2
  import { HTTPException } from "hono/http-exception";
2
3
  //#region src/hono.ts
3
4
  /**
@@ -43,15 +44,9 @@ function idParam(paramName, codec, options) {
43
44
  const raw = c.req.param(paramName);
44
45
  const result = codec.safeParse(raw);
45
46
  if (!result.ok) {
46
- const reason = result.error === "invalid_prefix" ? "brand_mismatch" : "malformed";
47
- const defaultStatus = reason === "brand_mismatch" ? 404 : 400;
48
- const status = options?.status?.[reason] ?? defaultStatus;
49
- const failure = {
50
- reason,
51
- status
52
- };
47
+ const failure = resolveIdParamFailure(result.error, options);
53
48
  if (options?.onError) return options.onError(failure, c);
54
- throw new HTTPException(status);
49
+ throw new HTTPException(failure.status);
55
50
  }
56
51
  c.set(paramName, result.id);
57
52
  await next();