@smonn/ids 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/{adapter-types-BY-wrYYB.mjs → adapter-types-7wWdELSh.mjs} +2 -2
- package/dist/adapter-types-7wWdELSh.mjs.map +1 -0
- package/dist/{adapter-types-unUcmMXC.d.mts → adapter-types-CdYJM6Sf.d.mts} +2 -2
- package/dist/adapter-types-CdYJM6Sf.d.mts.map +1 -0
- package/dist/cli.mjs +8 -7
- package/dist/cli.mjs.map +1 -1
- package/dist/{codec-shell-CW2sD6BU.mjs → codec-shell-DvrTDa65.mjs} +4 -4
- package/dist/codec-shell-DvrTDa65.mjs.map +1 -0
- package/dist/{digest-D-H1Tswt.mjs → digest-CknNw2wa.mjs} +9 -9
- package/dist/digest-CknNw2wa.mjs.map +1 -0
- package/dist/digest.d.mts +4 -4
- package/dist/digest.d.mts.map +1 -1
- package/dist/digest.mjs +1 -1
- package/dist/drizzle.d.mts +2 -2
- package/dist/drizzle.d.mts.map +1 -1
- package/dist/drizzle.mjs +2 -2
- package/dist/drizzle.mjs.map +1 -1
- package/dist/express.d.mts +2 -2
- package/dist/express.d.mts.map +1 -1
- package/dist/express.mjs +2 -2
- package/dist/express.mjs.map +1 -1
- package/dist/fastify.d.mts +3 -3
- package/dist/fastify.d.mts.map +1 -1
- package/dist/fastify.mjs +3 -3
- package/dist/fastify.mjs.map +1 -1
- package/dist/hono.d.mts +5 -4
- package/dist/hono.d.mts.map +1 -1
- package/dist/hono.mjs +4 -3
- package/dist/hono.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{key-material-gOnqTNoV.mjs → key-material-f29JIyrz.mjs} +3 -3
- package/dist/key-material-f29JIyrz.mjs.map +1 -0
- package/dist/kysely.d.mts +2 -2
- package/dist/kysely.d.mts.map +1 -1
- package/dist/kysely.mjs +2 -2
- package/dist/kysely.mjs.map +1 -1
- package/dist/{opaque-BpqxV8oB.mjs → opaque-ayT0KdCt.mjs} +8 -8
- package/dist/opaque-ayT0KdCt.mjs.map +1 -0
- package/dist/opaque.d.mts +3 -3
- package/dist/opaque.d.mts.map +1 -1
- package/dist/opaque.mjs +1 -1
- package/dist/prisma.d.mts +2 -2
- package/dist/prisma.d.mts.map +1 -1
- package/dist/prisma.mjs +2 -2
- package/dist/prisma.mjs.map +1 -1
- package/dist/{reverse-d5uEoIET.mjs → reverse-BRZRc1_U.mjs} +6 -6
- package/dist/reverse-BRZRc1_U.mjs.map +1 -0
- package/dist/reverse.d.mts +1 -1
- package/dist/reverse.d.mts.map +1 -1
- package/dist/reverse.mjs +1 -1
- package/dist/{rng-CPJOx_nE.mjs → rng-DHxioKyI.mjs} +2 -2
- package/dist/rng-DHxioKyI.mjs.map +1 -0
- package/dist/{signed-BnRSC03a.mjs → signed-C8OMt3TJ.mjs} +10 -10
- package/dist/signed-C8OMt3TJ.mjs.map +1 -0
- package/dist/signed.d.mts +4 -4
- package/dist/signed.d.mts.map +1 -1
- package/dist/signed.mjs +1 -1
- package/dist/{timestamp-BbZL8hwg.mjs → timestamp-DBwVjDkg.mjs} +5 -5
- package/dist/timestamp-DBwVjDkg.mjs.map +1 -0
- package/dist/{timestamp-bytes-DoFjLjDp.mjs → timestamp-bytes-DvhWHDa-.mjs} +2 -2
- package/dist/timestamp-bytes-DvhWHDa-.mjs.map +1 -0
- package/dist/{wrapped-BI9UXnAm.mjs → wrapped-CDTiPwNM.mjs} +29 -12
- package/dist/wrapped-CDTiPwNM.mjs.map +1 -0
- package/dist/wrapped.d.mts +3 -3
- package/dist/wrapped.d.mts.map +1 -1
- package/dist/wrapped.mjs +1 -1
- package/package.json +3 -2
- package/dist/adapter-types-BY-wrYYB.mjs.map +0 -1
- package/dist/adapter-types-unUcmMXC.d.mts.map +0 -1
- package/dist/codec-shell-CW2sD6BU.mjs.map +0 -1
- package/dist/digest-D-H1Tswt.mjs.map +0 -1
- package/dist/key-material-gOnqTNoV.mjs.map +0 -1
- package/dist/opaque-BpqxV8oB.mjs.map +0 -1
- package/dist/reverse-d5uEoIET.mjs.map +0 -1
- package/dist/rng-CPJOx_nE.mjs.map +0 -1
- package/dist/signed-BnRSC03a.mjs.map +0 -1
- package/dist/timestamp-BbZL8hwg.mjs.map +0 -1
- package/dist/timestamp-bytes-DoFjLjDp.mjs.map +0 -1
- package/dist/wrapped-BI9UXnAm.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Public-facing branded IDs for TypeScript apps. Type-safe, sortable, and codec-pl
|
|
|
8
8
|
pnpm add @smonn/ids
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
Each ID looks like `
|
|
11
|
+
Each ID looks like `usr_01h7b3k9rqxn4cw3p9r8t2sgkw`: a three-letter brand, an
|
|
12
12
|
underscore, then 26 Crockford base32 characters of payload. The default
|
|
13
13
|
Timestamp codec encodes a 48-bit millisecond Unix timestamp followed by 80
|
|
14
14
|
random bits — the same byte layout as a [ULID](https://github.com/ulid/spec).
|
|
@@ -21,7 +21,7 @@ import { type Id, createTimestampId } from "@smonn/ids";
|
|
|
21
21
|
const users = createTimestampId("usr");
|
|
22
22
|
|
|
23
23
|
// Generate — sortable by creation time via ORDER BY id
|
|
24
|
-
const id = users.generate(); // "
|
|
24
|
+
const id = users.generate(); // "usr_01h7b3k9rqxn4cw3p9r8t2sgkw"
|
|
25
25
|
|
|
26
26
|
// Branded: Id<"usr"> and Id<"org"> are not interchangeable
|
|
27
27
|
function loadUser(id: Id<"usr">) {
|
|
@@ -29,9 +29,9 @@ function loadUser(id: Id<"usr">) {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
// Validate untrusted input — lenient in, canonical out
|
|
32
|
-
const r = users.safeParse("
|
|
32
|
+
const r = users.safeParse("USR_01H7B3K9RQXN1CW3P9R8T2SGKW");
|
|
33
33
|
if (r.ok) {
|
|
34
|
-
r.id; // "
|
|
34
|
+
r.id; // "usr_01h7b3k9rqxn1cw3p9r8t2sgkw" as Id<"usr">
|
|
35
35
|
}
|
|
36
36
|
```
|
|
37
37
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as IdsError } from "./error-Cp5qYZcv.mjs";
|
|
2
|
-
//#region src/adapter-types.ts
|
|
2
|
+
//#region src/adapters/adapter-types.ts
|
|
3
3
|
/** Parses `value` as `Id<Brand>` via `codec.safeParse`; throws `IdsError("invalid_id")` on failure. Shared read helper for ORM adapters. */
|
|
4
4
|
function readIdColumn(codec, value) {
|
|
5
5
|
const result = codec.safeParse(value);
|
|
@@ -24,4 +24,4 @@ function resolveIdParamFailure(error, options) {
|
|
|
24
24
|
//#endregion
|
|
25
25
|
export { resolveIdParamFailure as n, readIdColumn as t };
|
|
26
26
|
|
|
27
|
-
//# sourceMappingURL=adapter-types-
|
|
27
|
+
//# sourceMappingURL=adapter-types-7wWdELSh.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter-types-7wWdELSh.mjs","names":[],"sources":["../src/adapters/adapter-types.ts"],"sourcesContent":["import { IdsError } from \"../error.js\";\nimport type { Id, ParseError, ParseResult } from \"../types.js\";\n\n/** Discriminated failure value passed to `onError` and emitted to the framework's error handler. */\nexport type IdParamFailure =\n | { readonly reason: \"brand_mismatch\"; readonly status: number }\n | { readonly reason: \"malformed\"; readonly status: number };\n\n/** Minimum structural type required by web and ORM adapters. Any codec variant satisfies this — all expose `safeParse`. Adapters only ever call `safeParse` — never key-dependent methods like `extractTimestamp`, `wrap`, or `unwrap`. */\nexport type IdCodec<Brand extends string> = {\n safeParse(value: unknown): ParseResult<Brand>;\n};\n\n/** Re-exported from ORM adapter subpaths (`@smonn/ids/drizzle`, `@smonn/ids/prisma`, `@smonn/ids/kysely`) under the public name; structurally identical to {@link IdCodec}. */\nexport type IdColumnCodec<Brand extends string> = IdCodec<Brand>;\n\n/** Parses `value` as `Id<Brand>` via `codec.safeParse`; throws `IdsError(\"invalid_id\")` on failure. Shared read helper for ORM adapters. */\nexport function readIdColumn<Brand extends string>(\n codec: IdCodec<Brand>,\n value: unknown,\n): 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 * Maps a `ParseError` to `{ reason, status }` for web adapter failure handling.\n *\n * - `invalid_prefix` → `brand_mismatch` / default 404\n * - anything else → `malformed` / default 400\n * - `options.status[reason]` overrides the default for that reason\n */\nexport function resolveIdParamFailure(\n error: ParseError,\n options?: { status?: { brand_mismatch?: number; malformed?: number } },\n): IdParamFailure {\n const reason = 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 return { reason, status };\n}\n"],"mappings":";;;AAiBA,SAAgB,aACd,OACA,OACW;CACX,MAAM,SAAS,MAAM,UAAU,KAAK;CACpC,IAAI,CAAC,OAAO,IACV,MAAM,IAAI,SAAS,cAAc,6BAA6B,OAAO,SAAS,EAC5E,OAAO,OAAO,MAChB,CAAC;CAEH,OAAO,OAAO;AAChB;;;;;;;;AASA,SAAgB,sBACd,OACA,SACgB;CAChB,MAAM,SAAS,UAAU,mBAAoB,mBAA8B;CAC3E,MAAM,gBAAgB,WAAW,mBAAmB,MAAM;CAE1D,OAAO;EAAE;EAAQ,QADF,SAAS,SAAS,WAAW;CACpB;AAC1B"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { i as ParseResult } from "./types-g7CiQDyE.mjs";
|
|
2
2
|
|
|
3
|
-
//#region src/adapter-types.d.ts
|
|
3
|
+
//#region src/adapters/adapter-types.d.ts
|
|
4
4
|
/** Discriminated failure value passed to `onError` and emitted to the framework's error handler. */
|
|
5
5
|
type IdParamFailure = {
|
|
6
6
|
readonly reason: "brand_mismatch";
|
|
@@ -17,4 +17,4 @@ type IdCodec<Brand extends string> = {
|
|
|
17
17
|
type IdColumnCodec<Brand extends string> = IdCodec<Brand>;
|
|
18
18
|
//#endregion
|
|
19
19
|
export { IdColumnCodec as n, IdParamFailure as r, IdCodec as t };
|
|
20
|
-
//# sourceMappingURL=adapter-types-
|
|
20
|
+
//# sourceMappingURL=adapter-types-CdYJM6Sf.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter-types-CdYJM6Sf.d.mts","names":[],"sources":["../src/adapters/adapter-types.ts"],"mappings":";;;;KAIY,cAAA;EAAA,SACG,MAAA;EAAA,SAAmC,MAAA;AAAA;EAAA,SACnC,MAAA;EAAA,SAA8B,MAAA;AAAA;;KAGjC,OAAA;EACV,SAAA,CAAU,KAAA,YAAiB,WAAA,CAAY,KAAA;AAAA;AADzC;AAAA,KAKY,aAAA,yBAAsC,OAAA,CAAQ,KAAA"}
|
package/dist/cli.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { n as isIdsError } from "./error-Cp5qYZcv.mjs";
|
|
3
|
-
import { t as createTimestampId } from "./timestamp-
|
|
4
|
-
import { i as importOpaqueKey, n as decodeOpaqueKey, r as encodeOpaqueKey, t as createOpaqueTimestampId } from "./opaque-
|
|
5
|
-
import { t as createReverseTimestampId } from "./reverse-
|
|
6
|
-
import { i as importSigningKey, n as decodeSigningKey, r as encodeSigningKey, t as createSignedTimestampId } from "./signed-
|
|
7
|
-
import { i as importWrappingKey, n as decodeWrappingKey, r as encodeWrappingKey, t as createWrappedKeyId } from "./wrapped-
|
|
8
|
-
import { i as importDigestKey, n as decodeDigestKey, r as encodeDigestKey, t as createDigestId } from "./digest-
|
|
3
|
+
import { t as createTimestampId } from "./timestamp-DBwVjDkg.mjs";
|
|
4
|
+
import { i as importOpaqueKey, n as decodeOpaqueKey, r as encodeOpaqueKey, t as createOpaqueTimestampId } from "./opaque-ayT0KdCt.mjs";
|
|
5
|
+
import { t as createReverseTimestampId } from "./reverse-BRZRc1_U.mjs";
|
|
6
|
+
import { i as importSigningKey, n as decodeSigningKey, r as encodeSigningKey, t as createSignedTimestampId } from "./signed-C8OMt3TJ.mjs";
|
|
7
|
+
import { i as importWrappingKey, n as decodeWrappingKey, r as encodeWrappingKey, t as createWrappedKeyId } from "./wrapped-CDTiPwNM.mjs";
|
|
8
|
+
import { i as importDigestKey, n as decodeDigestKey, r as encodeDigestKey, t as createDigestId } from "./digest-CknNw2wa.mjs";
|
|
9
9
|
//#region src/cli/key-io.ts
|
|
10
10
|
function isKeyFormatError(result) {
|
|
11
11
|
return result !== "hex" && result !== "base64url";
|
|
@@ -605,6 +605,7 @@ async function runInspect(args, opts) {
|
|
|
605
605
|
case "readable": {
|
|
606
606
|
const timestamp = codecOrError.extractTimestamp(canonical);
|
|
607
607
|
const nowMs = (opts.now ?? Date.now)();
|
|
608
|
+
opts.stderr("note: timestamp assumes a plaintext Timestamp ID; if this ID was Opaque-encoded, the timestamp is meaningless — re-run with --opaque and the correct IDS_KEY\n");
|
|
608
609
|
opts.stdout(formatInspectOutput({
|
|
609
610
|
brand,
|
|
610
611
|
timestamp,
|
|
@@ -727,7 +728,7 @@ function runKeygen(args, opts) {
|
|
|
727
728
|
return Promise.resolve(0);
|
|
728
729
|
}
|
|
729
730
|
//#endregion
|
|
730
|
-
//#region src/cli.ts
|
|
731
|
+
//#region src/cli/index.ts
|
|
731
732
|
const commands = [
|
|
732
733
|
{
|
|
733
734
|
names: ["generate", "g"],
|
package/dist/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli/key-io.ts","../src/cli/codec-options.ts","../src/cli/constants.ts","../src/cli/flags.ts","../src/cli/format.ts","../src/cli/variants.ts","../src/cli/dispatch.ts","../src/cli/commands/generate.ts","../src/cli/usage.ts","../src/cli/commands/inspect.ts","../src/cli/commands/keygen.ts","../src/cli.ts","../bin/cli.ts"],"sourcesContent":["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 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","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 \"--digest\",\n \"--ns\",\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\nexport function parseNs(values: Map<string, string>): string | undefined {\n const raw = values.get(\"--ns\");\n if (raw === undefined) return undefined;\n if (raw === \"\") return \"--ns requires a value\";\n return raw;\n}\n\nexport function isNsError(result: string): boolean {\n return result === \"--ns requires a value\";\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","import {\n createDigestId,\n decodeDigestKey,\n encodeDigestKey,\n importDigestKey,\n type DigestKey,\n} from \"../digest.js\";\nimport {\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, isNsError, parseKind, parseNs } 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\" | \"unsupported\";\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> & { generate?(): string | Promise<string> }) | string;\n inspectMode: InspectMode;\n extraFlags?: readonly string[];\n};\n\nexport type GeneratorDescriptor = {\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> & { generate(): string | Promise<string> }) | string;\n inspectMode: InspectMode;\n extraFlags?: readonly string[];\n};\n\nexport type Policy<D extends Descriptor = Descriptor> = {\n default: D;\n selectable: readonly D[];\n intrinsicFlags: readonly string[];\n};\n\nexport type GeneratePolicy = Policy<GeneratorDescriptor>;\n\nexport const timestampVariant: GeneratorDescriptor = {\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: GeneratorDescriptor = {\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: GeneratorDescriptor = {\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: GeneratorDescriptor = {\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\nexport const digestVariant: GeneratorDescriptor = {\n flag: \"--digest\",\n key: {\n envVar: \"IDS_DIGEST_KEY\",\n formatEnvVar: \"IDS_DIGEST_KEY_FORMAT\",\n encode: encodeDigestKey,\n decode: decodeDigestKey,\n import: importDigestKey,\n },\n // Digest is one-way: inspect --digest is unsupported by design, so digestVariant is omitted\n // from inspectPolicy.selectable. \"unsupported\" documents that there is no inspect path.\n inspectMode: \"unsupported\",\n extraFlags: [\"--ns\"],\n construct(brand, opts, key, values) {\n const ns = parseNs(values ?? new Map());\n if (ns === undefined) return \"--ns is required with --digest\";\n if (isNsError(ns)) return ns;\n try {\n const codec = createDigestId(brand, { ns, key: key as DigestKey, allowDuplicateBrand: true });\n return {\n safeParse: (v: unknown) => codec.safeParse(v),\n generate(): Promise<string> {\n const reader = opts.readStdin ?? (() => Promise.resolve(\"\"));\n return reader().then((material) => codec.digest(material));\n },\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 follow registry insertion order (digest, reverse, wrapped, opaque).\nexport const conflictPriorityOrder: readonly Descriptor[] = [\n signedVariant,\n digestVariant,\n reverseVariant,\n wrappedVariant,\n opaqueVariant,\n];\n\nexport const generatePolicy: GeneratePolicy = {\n default: timestampVariant,\n selectable: [opaqueVariant, reverseVariant, signedVariant, digestVariant],\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, digestVariant],\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 {\n conflictPriorityOrder,\n type Descriptor,\n type GeneratorDescriptor,\n type Policy,\n} 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<D extends Descriptor>(\n policy: Policy<D>,\n flags: Set<string>,\n): D | string {\n const selected = conflictPriorityOrder.filter(\n (v): v is D =>\n policy.selectable.some((d) => d === 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: GeneratorDescriptor,\n brand: string,\n values: Map<string, string>,\n opts: RunOpts,\n): Promise<(IdCodec<string> & { generate(): string | Promise<string> }) | string>;\nexport async function buildCodec(\n variant: Descriptor,\n brand: string,\n values: Map<string, string>,\n opts: RunOpts,\n): Promise<IdCodec<string> | string>;\nexport async function buildCodec(\n variant: Descriptor,\n brand: string,\n values: Map<string, string>,\n opts: RunOpts,\n): Promise<(IdCodec<string> & { generate?(): string | Promise<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 { buildCodec, deriveAllowedFlags, resolveVariant } from \"../dispatch.js\";\nimport { parseCount, splitFlags, unsupportedFlagForCommand } from \"../flags.js\";\nimport type { RunOpts } from \"../types.js\";\nimport { generatePolicy } from \"../variants.js\";\n\nlet stdinCache: Promise<string> | undefined;\n/* v8 ignore next 12 -- reads from process.stdin; not exercised in unit tests, only in the real binary */\nfunction readProcessStdin(): Promise<string> {\n if (stdinCache === undefined) {\n stdinCache = new Promise<string>((resolve) => {\n const chunks: string[] = [];\n process.stdin.setEncoding(\"utf8\");\n process.stdin.on(\"data\", (chunk: string) => chunks.push(chunk));\n process.stdin.on(\"end\", () => resolve(chunks.join(\"\")));\n process.stdin.resume();\n });\n }\n return stdinCache;\n}\n\nexport async function runGenerate(args: ReadonlyArray<string>, opts: RunOpts): Promise<number> {\n const allowedFlags = deriveAllowedFlags(generatePolicy);\n const selectorFlags = new Set(\n generatePolicy.selectable.map((v) => v.flag).filter((f): f is string => f !== undefined),\n );\n const valueFlags = new Set([...allowedFlags].filter((f) => !selectorFlags.has(f)));\n const { flags, values, positionals, errors } = splitFlags(args, valueFlags);\n const unsupported = unsupportedFlagForCommand(\"generate\", flags, allowedFlags);\n if (unsupported !== undefined) {\n opts.stderr(unsupported + \"\\n\");\n return 1;\n }\n if (errors[0] !== undefined) {\n opts.stderr(errors[0] + \"\\n\");\n return 1;\n }\n const extra = positionals[1];\n if (extra !== undefined) {\n opts.stderr(`unexpected argument: ${extra}\\n`);\n return 1;\n }\n const [brand] = positionals;\n const count = parseCount(values);\n if (typeof count === \"string\") {\n opts.stderr(count + \"\\n\");\n return 1;\n }\n const variant = resolveVariant(generatePolicy, flags);\n if (typeof variant === \"string\") {\n opts.stderr(variant + \"\\n\");\n return 1;\n }\n if (variant.key === undefined && flags.has(\"--key-format\")) {\n opts.stderr(\"--key-format requires --opaque, --signed, or --digest\\n\");\n return 1;\n }\n if (flags.has(\"--digest\") && count > 1) {\n opts.stderr(\n \"--count N > 1 is rejected with --digest: same material always produces the same ID\\n\",\n );\n return 1;\n }\n const optsWithStdin: RunOpts = { ...opts, readStdin: opts.readStdin ?? readProcessStdin };\n const codec = await buildCodec(variant, brand ?? \"\", values, optsWithStdin);\n if (typeof codec === \"string\") {\n opts.stderr(codec + \"\\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 { 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 \" Note: --digest is not supported for inspect (Digest IDs are one-way; there is no reverse path).\",\n \" generate, g <brand> [--count, -c N] [--opaque] [--reverse] [--signed] [--digest --ns <ns>] [--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 \" --digest mints a deterministic Digest ID from material read on stdin.\",\n \" --ns <ns> is required: the namespace domain separator (non-secret, non-empty).\",\n \" Reads the digest key from IDS_DIGEST_KEY (hex by default; IDS_DIGEST_KEY_FORMAT or --key-format).\",\n \" Same material + ns + key always produces the same ID. Digest IDs are one-way.\",\n \" --count N > 1 is rejected: same material always produces the same ID.\",\n \" keygen, k [--wrapped] [--signed] [--digest] [--bits 128|192|256] [--key-format hex|base64url]\",\n \" Emit a random key for importOpaqueKey, importWrappingKey, importSigningKey, or importDigestKey (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 \" --digest emits a digest key for importDigestKey instead (IDS_DIGEST_KEY; hex by default; IDS_DIGEST_KEY_FORMAT or --key-format).\",\n \"\",\n ].join(\"\\n\");\n}\n","import { createTimestampId } from \"../../timestamp.js\";\nimport type { Id, StandardSchemaProps } from \"../../types.js\";\nimport type { SafeVerifyResult } from \"../../signed.js\";\nimport { codecOpts } from \"../codec-options.js\";\nimport { buildCodec, deriveAllowedFlags, resolveVariant } from \"../dispatch.js\";\nimport {\n formatCliError,\n formatInspectOutput,\n formatSignedInspectOutput,\n formatWrappedInspectOutput,\n} from \"../format.js\";\nimport { splitFlags, unsupportedFlagForCommand } from \"../flags.js\";\nimport { isKeyFormatError, parseKeyFormat } from \"../key-io.js\";\nimport type { RunOpts } from \"../types.js\";\nimport { usage } from \"../usage.js\";\nimport { inspectPolicy } from \"../variants.js\";\n\ntype WithValidate = { \"~standard\": StandardSchemaProps<string> };\ntype WithExtractTimestamp = { extractTimestamp(id: Id<string>): Date };\ntype WithAsyncExtractTimestamp = { extractTimestamp(id: Id<string>): Promise<Date> };\ntype WithUnwrap = { unwrap(id: Id<string>): Promise<number | bigint> };\ntype WithSafeVerify = { safeVerify(id: string): Promise<SafeVerifyResult<string>> };\n\nexport async function runInspect(args: ReadonlyArray<string>, opts: RunOpts): Promise<number> {\n const allowedFlags = deriveAllowedFlags(inspectPolicy);\n const selectorFlags = new Set(\n inspectPolicy.selectable.map((v) => v.flag).filter((f): f is string => f !== undefined),\n );\n const valueFlags = new Set([...allowedFlags].filter((f) => !selectorFlags.has(f)));\n const { flags, values, positionals, errors } = splitFlags(args, valueFlags);\n\n const unsupported = unsupportedFlagForCommand(\"inspect\", flags, allowedFlags);\n if (unsupported !== undefined) {\n opts.stderr(unsupported + \"\\n\");\n return 1;\n }\n if (errors[0] !== undefined) {\n opts.stderr(errors[0] + \"\\n\");\n return 1;\n }\n const [input] = positionals;\n if (input === undefined) {\n opts.stderr(usage());\n return 1;\n }\n const extra = positionals[1];\n if (extra !== undefined) {\n opts.stderr(`unexpected argument: ${extra}\\n`);\n return 1;\n }\n\n const variant = resolveVariant(inspectPolicy, flags);\n if (typeof variant === \"string\") {\n opts.stderr(variant + \"\\n\");\n return 1;\n }\n if (variant.key === undefined && flags.has(\"--key-format\")) {\n opts.stderr(\"--key-format requires --opaque, --wrapped, or --signed\\n\");\n return 1;\n }\n\n const brand = input.slice(0, 3).toLowerCase();\n\n // \"verify\" (--signed) mode: the timestamp is plaintext and must be extractable even when\n // the signing key is unavailable. Structural parse happens before key loading so that:\n // bad key format → stderr only, stdout = \"\" (no timestamp shown)\n // invalid payload → stderr only, stdout = \"\" (no timestamp shown)\n // key missing/malformed → stdout has timestamp + \"verification: unavailable\"\n let verifyTimestamp: Date | undefined;\n let verifyCanonical: Id<string> | undefined;\n let verifyNowMs: number | undefined;\n if (variant.inspectMode === \"verify\") {\n const fmtCheck = parseKeyFormat(values, opts, variant.key!);\n if (isKeyFormatError(fmtCheck)) {\n opts.stderr(fmtCheck + \"\\n\");\n return 1;\n }\n let tsCodec: WithValidate & WithExtractTimestamp;\n try {\n tsCodec = createTimestampId(brand, codecOpts(opts)) as unknown as WithValidate &\n WithExtractTimestamp;\n } catch (err) {\n opts.stderr(formatCliError(err) + \"\\n\");\n return 1;\n }\n const structValidation = tsCodec[\"~standard\"].validate(input);\n if (structValidation.issues) {\n opts.stderr(structValidation.issues[0]!.message + \"\\n\");\n return 1;\n }\n verifyCanonical = structValidation.value;\n verifyTimestamp = tsCodec.extractTimestamp(verifyCanonical);\n verifyNowMs = (opts.now ?? Date.now)();\n }\n\n const codecOrError = await buildCodec(variant, brand, values, opts);\n if (typeof codecOrError === \"string\") {\n if (variant.inspectMode === \"verify\") {\n opts.stdout(\n formatSignedInspectOutput({\n brand,\n timestamp: verifyTimestamp!,\n canonical: verifyCanonical!,\n input,\n nowMs: verifyNowMs!,\n verification: \"unavailable\",\n }),\n );\n }\n opts.stderr(codecOrError + \"\\n\");\n return 1;\n }\n\n // Structural validation for non-verify cases (verify already validated above)\n let canonical: Id<string> | undefined;\n if (variant.inspectMode !== \"verify\") {\n const validation = (codecOrError as unknown as WithValidate)[\"~standard\"].validate(input);\n if (validation.issues) {\n opts.stderr(validation.issues[0]!.message + \"\\n\");\n return 1;\n }\n canonical = validation.value;\n }\n\n // Back half: switch on inspectMode for output shapes\n switch (variant.inspectMode) {\n case \"readable\": {\n const timestamp = (codecOrError as unknown as WithExtractTimestamp).extractTimestamp(\n canonical!,\n );\n const nowMs = (opts.now ?? Date.now)();\n opts.stdout(formatInspectOutput({ brand, timestamp, canonical: canonical!, input, nowMs }));\n return 0;\n }\n case \"keyed-readable\": {\n const timestamp = await (\n codecOrError as unknown as WithAsyncExtractTimestamp\n ).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(formatInspectOutput({ brand, timestamp, canonical: canonical!, input, nowMs }));\n return 0;\n }\n case \"unwrap\": {\n let lookupKey: number | bigint;\n try {\n lookupKey = await (codecOrError as unknown as WithUnwrap).unwrap(canonical!);\n } catch (err) {\n opts.stderr(formatCliError(err) + \"\\n\");\n return 1;\n }\n opts.stdout(formatWrappedInspectOutput({ brand, lookupKey, canonical: canonical!, input }));\n return 0;\n }\n case \"verify\": {\n const verifyResult = await (codecOrError as unknown as WithSafeVerify).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: verifyTimestamp!,\n canonical: verifyCanonical!,\n input,\n nowMs: verifyNowMs!,\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: verifyTimestamp!,\n canonical: verifyResult.id,\n input,\n nowMs: verifyNowMs!,\n verification: \"ok\",\n }),\n );\n return 0;\n }\n /* v8 ignore next 5 -- defensive: digestVariant is the only \"unsupported\" variant and it is\n excluded from inspectPolicy.selectable, so resolveVariant can never return it here. The\n branch exists for TypeScript exhaustiveness. */\n case \"unsupported\": {\n opts.stderr(\"unsupported flag for inspect: --digest\\n\");\n return 1;\n }\n }\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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"}
|
|
1
|
+
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli/key-io.ts","../src/cli/codec-options.ts","../src/cli/constants.ts","../src/cli/flags.ts","../src/cli/format.ts","../src/cli/variants.ts","../src/cli/dispatch.ts","../src/cli/commands/generate.ts","../src/cli/usage.ts","../src/cli/commands/inspect.ts","../src/cli/commands/keygen.ts","../src/cli/index.ts","../bin/cli.ts"],"sourcesContent":["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 type { TimestampOptions } from \"../codecs/timestamp/index.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","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 \"--digest\",\n \"--ns\",\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\nexport function parseNs(values: Map<string, string>): string | undefined {\n const raw = values.get(\"--ns\");\n if (raw === undefined) return undefined;\n if (raw === \"\") return \"--ns requires a value\";\n return raw;\n}\n\nexport function isNsError(result: string): boolean {\n return result === \"--ns requires a value\";\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","import {\n createDigestId,\n decodeDigestKey,\n encodeDigestKey,\n importDigestKey,\n type DigestKey,\n} from \"../codecs/digest/index.js\";\nimport {\n createOpaqueTimestampId,\n decodeOpaqueKey,\n encodeOpaqueKey,\n importOpaqueKey,\n type OpaqueKey,\n} from \"../codecs/opaque/index.js\";\nimport { createReverseTimestampId } from \"../codecs/reverse/index.js\";\nimport {\n createSignedTimestampId,\n decodeSigningKey,\n encodeSigningKey,\n importSigningKey,\n type SigningKey,\n} from \"../codecs/signed/index.js\";\nimport { createTimestampId } from \"../codecs/timestamp/index.js\";\nimport {\n createWrappedKeyId,\n decodeWrappingKey,\n encodeWrappingKey,\n importWrappingKey,\n type WrappingKey,\n} from \"../codecs/wrapped/index.js\";\nimport type { IdCodec } from \"../adapters/adapter-types.js\";\nimport { codecOpts } from \"./codec-options.js\";\nimport { isKindError, isNsError, parseKind, parseNs } 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\" | \"unsupported\";\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> & { generate?(): string | Promise<string> }) | string;\n inspectMode: InspectMode;\n extraFlags?: readonly string[];\n};\n\nexport type GeneratorDescriptor = {\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> & { generate(): string | Promise<string> }) | string;\n inspectMode: InspectMode;\n extraFlags?: readonly string[];\n};\n\nexport type Policy<D extends Descriptor = Descriptor> = {\n default: D;\n selectable: readonly D[];\n intrinsicFlags: readonly string[];\n};\n\nexport type GeneratePolicy = Policy<GeneratorDescriptor>;\n\nexport const timestampVariant: GeneratorDescriptor = {\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: GeneratorDescriptor = {\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: GeneratorDescriptor = {\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: GeneratorDescriptor = {\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\nexport const digestVariant: GeneratorDescriptor = {\n flag: \"--digest\",\n key: {\n envVar: \"IDS_DIGEST_KEY\",\n formatEnvVar: \"IDS_DIGEST_KEY_FORMAT\",\n encode: encodeDigestKey,\n decode: decodeDigestKey,\n import: importDigestKey,\n },\n // Digest is one-way: inspect --digest is unsupported by design, so digestVariant is omitted\n // from inspectPolicy.selectable. \"unsupported\" documents that there is no inspect path.\n inspectMode: \"unsupported\",\n extraFlags: [\"--ns\"],\n construct(brand, opts, key, values) {\n const ns = parseNs(values ?? new Map());\n if (ns === undefined) return \"--ns is required with --digest\";\n if (isNsError(ns)) return ns;\n try {\n const codec = createDigestId(brand, { ns, key: key as DigestKey, allowDuplicateBrand: true });\n return {\n safeParse: (v: unknown) => codec.safeParse(v),\n generate(): Promise<string> {\n const reader = opts.readStdin ?? (() => Promise.resolve(\"\"));\n return reader().then((material) => codec.digest(material));\n },\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 follow registry insertion order (digest, reverse, wrapped, opaque).\nexport const conflictPriorityOrder: readonly Descriptor[] = [\n signedVariant,\n digestVariant,\n reverseVariant,\n wrappedVariant,\n opaqueVariant,\n];\n\nexport const generatePolicy: GeneratePolicy = {\n default: timestampVariant,\n selectable: [opaqueVariant, reverseVariant, signedVariant, digestVariant],\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, digestVariant],\n intrinsicFlags: [\"--bits\"],\n};\n","import type { IdCodec } from \"../adapters/adapter-types.js\";\nimport { isKeyFormatError, loadKey, parseKeyFormat } from \"./key-io.js\";\nimport type { RunOpts } from \"./types.js\";\nimport {\n conflictPriorityOrder,\n type Descriptor,\n type GeneratorDescriptor,\n type Policy,\n} 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<D extends Descriptor>(\n policy: Policy<D>,\n flags: Set<string>,\n): D | string {\n const selected = conflictPriorityOrder.filter(\n (v): v is D =>\n policy.selectable.some((d) => d === 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: GeneratorDescriptor,\n brand: string,\n values: Map<string, string>,\n opts: RunOpts,\n): Promise<(IdCodec<string> & { generate(): string | Promise<string> }) | string>;\nexport async function buildCodec(\n variant: Descriptor,\n brand: string,\n values: Map<string, string>,\n opts: RunOpts,\n): Promise<IdCodec<string> | string>;\nexport async function buildCodec(\n variant: Descriptor,\n brand: string,\n values: Map<string, string>,\n opts: RunOpts,\n): Promise<(IdCodec<string> & { generate?(): string | Promise<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 { buildCodec, deriveAllowedFlags, resolveVariant } from \"../dispatch.js\";\nimport { parseCount, splitFlags, unsupportedFlagForCommand } from \"../flags.js\";\nimport type { RunOpts } from \"../types.js\";\nimport { generatePolicy } from \"../variants.js\";\n\nlet stdinCache: Promise<string> | undefined;\n/* v8 ignore next 12 -- reads from process.stdin; not exercised in unit tests, only in the real binary */\nfunction readProcessStdin(): Promise<string> {\n if (stdinCache === undefined) {\n stdinCache = new Promise<string>((resolve) => {\n const chunks: string[] = [];\n process.stdin.setEncoding(\"utf8\");\n process.stdin.on(\"data\", (chunk: string) => chunks.push(chunk));\n process.stdin.on(\"end\", () => resolve(chunks.join(\"\")));\n process.stdin.resume();\n });\n }\n return stdinCache;\n}\n\nexport async function runGenerate(args: ReadonlyArray<string>, opts: RunOpts): Promise<number> {\n const allowedFlags = deriveAllowedFlags(generatePolicy);\n const selectorFlags = new Set(\n generatePolicy.selectable.map((v) => v.flag).filter((f): f is string => f !== undefined),\n );\n const valueFlags = new Set([...allowedFlags].filter((f) => !selectorFlags.has(f)));\n const { flags, values, positionals, errors } = splitFlags(args, valueFlags);\n const unsupported = unsupportedFlagForCommand(\"generate\", flags, allowedFlags);\n if (unsupported !== undefined) {\n opts.stderr(unsupported + \"\\n\");\n return 1;\n }\n if (errors[0] !== undefined) {\n opts.stderr(errors[0] + \"\\n\");\n return 1;\n }\n const extra = positionals[1];\n if (extra !== undefined) {\n opts.stderr(`unexpected argument: ${extra}\\n`);\n return 1;\n }\n const [brand] = positionals;\n const count = parseCount(values);\n if (typeof count === \"string\") {\n opts.stderr(count + \"\\n\");\n return 1;\n }\n const variant = resolveVariant(generatePolicy, flags);\n if (typeof variant === \"string\") {\n opts.stderr(variant + \"\\n\");\n return 1;\n }\n if (variant.key === undefined && flags.has(\"--key-format\")) {\n opts.stderr(\"--key-format requires --opaque, --signed, or --digest\\n\");\n return 1;\n }\n if (flags.has(\"--digest\") && count > 1) {\n opts.stderr(\n \"--count N > 1 is rejected with --digest: same material always produces the same ID\\n\",\n );\n return 1;\n }\n const optsWithStdin: RunOpts = { ...opts, readStdin: opts.readStdin ?? readProcessStdin };\n const codec = await buildCodec(variant, brand ?? \"\", values, optsWithStdin);\n if (typeof codec === \"string\") {\n opts.stderr(codec + \"\\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 { 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 \" Note: --digest is not supported for inspect (Digest IDs are one-way; there is no reverse path).\",\n \" generate, g <brand> [--count, -c N] [--opaque] [--reverse] [--signed] [--digest --ns <ns>] [--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 \" --digest mints a deterministic Digest ID from material read on stdin.\",\n \" --ns <ns> is required: the namespace domain separator (non-secret, non-empty).\",\n \" Reads the digest key from IDS_DIGEST_KEY (hex by default; IDS_DIGEST_KEY_FORMAT or --key-format).\",\n \" Same material + ns + key always produces the same ID. Digest IDs are one-way.\",\n \" --count N > 1 is rejected: same material always produces the same ID.\",\n \" keygen, k [--wrapped] [--signed] [--digest] [--bits 128|192|256] [--key-format hex|base64url]\",\n \" Emit a random key for importOpaqueKey, importWrappingKey, importSigningKey, or importDigestKey (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 \" --digest emits a digest key for importDigestKey instead (IDS_DIGEST_KEY; hex by default; IDS_DIGEST_KEY_FORMAT or --key-format).\",\n \"\",\n ].join(\"\\n\");\n}\n","import { createTimestampId } from \"../../codecs/timestamp/index.js\";\nimport type { Id, StandardSchemaProps } from \"../../types.js\";\nimport type { SafeVerifyResult } from \"../../codecs/signed/index.js\";\nimport { codecOpts } from \"../codec-options.js\";\nimport { buildCodec, deriveAllowedFlags, resolveVariant } from \"../dispatch.js\";\nimport {\n formatCliError,\n formatInspectOutput,\n formatSignedInspectOutput,\n formatWrappedInspectOutput,\n} from \"../format.js\";\nimport { splitFlags, unsupportedFlagForCommand } from \"../flags.js\";\nimport { isKeyFormatError, parseKeyFormat } from \"../key-io.js\";\nimport type { RunOpts } from \"../types.js\";\nimport { usage } from \"../usage.js\";\nimport { inspectPolicy } from \"../variants.js\";\n\ntype WithValidate = { \"~standard\": StandardSchemaProps<string> };\ntype WithExtractTimestamp = { extractTimestamp(id: Id<string>): Date };\ntype WithAsyncExtractTimestamp = { extractTimestamp(id: Id<string>): Promise<Date> };\ntype WithUnwrap = { unwrap(id: Id<string>): Promise<number | bigint> };\ntype WithSafeVerify = { safeVerify(id: string): Promise<SafeVerifyResult<string>> };\n\nexport async function runInspect(args: ReadonlyArray<string>, opts: RunOpts): Promise<number> {\n const allowedFlags = deriveAllowedFlags(inspectPolicy);\n const selectorFlags = new Set(\n inspectPolicy.selectable.map((v) => v.flag).filter((f): f is string => f !== undefined),\n );\n const valueFlags = new Set([...allowedFlags].filter((f) => !selectorFlags.has(f)));\n const { flags, values, positionals, errors } = splitFlags(args, valueFlags);\n\n const unsupported = unsupportedFlagForCommand(\"inspect\", flags, allowedFlags);\n if (unsupported !== undefined) {\n opts.stderr(unsupported + \"\\n\");\n return 1;\n }\n if (errors[0] !== undefined) {\n opts.stderr(errors[0] + \"\\n\");\n return 1;\n }\n const [input] = positionals;\n if (input === undefined) {\n opts.stderr(usage());\n return 1;\n }\n const extra = positionals[1];\n if (extra !== undefined) {\n opts.stderr(`unexpected argument: ${extra}\\n`);\n return 1;\n }\n\n const variant = resolveVariant(inspectPolicy, flags);\n if (typeof variant === \"string\") {\n opts.stderr(variant + \"\\n\");\n return 1;\n }\n if (variant.key === undefined && flags.has(\"--key-format\")) {\n opts.stderr(\"--key-format requires --opaque, --wrapped, or --signed\\n\");\n return 1;\n }\n\n const brand = input.slice(0, 3).toLowerCase();\n\n // \"verify\" (--signed) mode: the timestamp is plaintext and must be extractable even when\n // the signing key is unavailable. Structural parse happens before key loading so that:\n // bad key format → stderr only, stdout = \"\" (no timestamp shown)\n // invalid payload → stderr only, stdout = \"\" (no timestamp shown)\n // key missing/malformed → stdout has timestamp + \"verification: unavailable\"\n let verifyTimestamp: Date | undefined;\n let verifyCanonical: Id<string> | undefined;\n let verifyNowMs: number | undefined;\n if (variant.inspectMode === \"verify\") {\n const fmtCheck = parseKeyFormat(values, opts, variant.key!);\n if (isKeyFormatError(fmtCheck)) {\n opts.stderr(fmtCheck + \"\\n\");\n return 1;\n }\n let tsCodec: WithValidate & WithExtractTimestamp;\n try {\n tsCodec = createTimestampId(brand, codecOpts(opts)) as unknown as WithValidate &\n WithExtractTimestamp;\n } catch (err) {\n opts.stderr(formatCliError(err) + \"\\n\");\n return 1;\n }\n const structValidation = tsCodec[\"~standard\"].validate(input);\n if (structValidation.issues) {\n opts.stderr(structValidation.issues[0]!.message + \"\\n\");\n return 1;\n }\n verifyCanonical = structValidation.value;\n verifyTimestamp = tsCodec.extractTimestamp(verifyCanonical);\n verifyNowMs = (opts.now ?? Date.now)();\n }\n\n const codecOrError = await buildCodec(variant, brand, values, opts);\n if (typeof codecOrError === \"string\") {\n if (variant.inspectMode === \"verify\") {\n opts.stdout(\n formatSignedInspectOutput({\n brand,\n timestamp: verifyTimestamp!,\n canonical: verifyCanonical!,\n input,\n nowMs: verifyNowMs!,\n verification: \"unavailable\",\n }),\n );\n }\n opts.stderr(codecOrError + \"\\n\");\n return 1;\n }\n\n // Structural validation for non-verify cases (verify already validated above)\n let canonical: Id<string> | undefined;\n if (variant.inspectMode !== \"verify\") {\n const validation = (codecOrError as unknown as WithValidate)[\"~standard\"].validate(input);\n if (validation.issues) {\n opts.stderr(validation.issues[0]!.message + \"\\n\");\n return 1;\n }\n canonical = validation.value;\n }\n\n // Back half: switch on inspectMode for output shapes\n switch (variant.inspectMode) {\n case \"readable\": {\n const timestamp = (codecOrError as unknown as WithExtractTimestamp).extractTimestamp(\n canonical!,\n );\n const nowMs = (opts.now ?? Date.now)();\n opts.stderr(\n \"note: timestamp assumes a plaintext Timestamp ID; if this ID was Opaque-encoded, the timestamp is meaningless — re-run with --opaque and the correct IDS_KEY\\n\",\n );\n opts.stdout(formatInspectOutput({ brand, timestamp, canonical: canonical!, input, nowMs }));\n return 0;\n }\n case \"keyed-readable\": {\n const timestamp = await (\n codecOrError as unknown as WithAsyncExtractTimestamp\n ).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(formatInspectOutput({ brand, timestamp, canonical: canonical!, input, nowMs }));\n return 0;\n }\n case \"unwrap\": {\n let lookupKey: number | bigint;\n try {\n lookupKey = await (codecOrError as unknown as WithUnwrap).unwrap(canonical!);\n } catch (err) {\n opts.stderr(formatCliError(err) + \"\\n\");\n return 1;\n }\n opts.stdout(formatWrappedInspectOutput({ brand, lookupKey, canonical: canonical!, input }));\n return 0;\n }\n case \"verify\": {\n const verifyResult = await (codecOrError as unknown as WithSafeVerify).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: verifyTimestamp!,\n canonical: verifyCanonical!,\n input,\n nowMs: verifyNowMs!,\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: verifyTimestamp!,\n canonical: verifyResult.id,\n input,\n nowMs: verifyNowMs!,\n verification: \"ok\",\n }),\n );\n return 0;\n }\n /* v8 ignore next 5 -- defensive: digestVariant is the only \"unsupported\" variant and it is\n excluded from inspectPolicy.selectable, so resolveVariant can never return it here. The\n branch exists for TypeScript exhaustiveness. */\n case \"unsupported\": {\n opts.stderr(\"unsupported flag for inspect: --digest\\n\");\n return 1;\n }\n }\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 \"./commands/generate.js\";\nimport { runInspect } from \"./commands/inspect.js\";\nimport { runKeygen } from \"./commands/keygen.js\";\nimport type { CommandHandler, RunOpts } from \"./types.js\";\nimport { usage } from \"./usage.js\";\n\nexport type { RunOpts } from \"./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/index.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":";;;;;;;;;AAaA,SAAgB,iBAAiB,QAA8C;CAC7E,OAAO,WAAW,SAAS,WAAW;AACxC;AAEA,SAAS,mBAAmB,QAA6D;CACvF,MAAM,WAAW,OAAO,IAAI,cAAc;CAC1C,IAAI,aAAa,KAAA,GAAW,OAAO,KAAA;CACnC,IAAI,aAAa,IAAI,OAAO;CAC5B,IAAI,aAAa,SAAS,aAAa,aAAa,OAAO;CAC3D,OAAO,+CAA+C,SAAS;AACjE;AAEA,SAAgB,uBAAuB,QAAiD;CACtF,MAAM,WAAW,mBAAmB,MAAM;CAC1C,IAAI,aAAa,KAAA,GAAW,OAAO;CACnC,OAAO;AACT;AAEA,SAAgB,eACd,QACA,MACA,OACoB;CACpB,MAAM,WAAW,mBAAmB,MAAM;CAC1C,IAAI,aAAa,KAAA,GAAW,OAAO;CAEnC,MAAM,WADM,KAAK,OAAO,QAAQ,IAAA,CACZ,MAAM;CAC1B,IAAI,YAAY,KAAA,KAAa,YAAY,IAAI,OAAO;CACpD,IAAI,YAAY,SAAS,YAAY,aAAa,OAAO;CACzD,OAAO,GAAG,MAAM,aAAa,kCAAkC,QAAQ;AACzE;AAEA,eAAsB,QACpB,MACA,QACA,OACqB;CAErB,MAAM,OADM,KAAK,OAAO,QAAQ,IAAA,CAChB,MAAM;CACtB,IAAI,QAAQ,KAAA,KAAa,QAAQ,IAAI,OAAO,WAAW,MAAM,OAAO;CACpE,IAAI;EACF,OAAO,MAAM,MAAM,OAAO,MAAM,OAAO,KAAK,MAAM,CAAC;CACrD,SAAS,KAAK;EACZ,OAAQ,IAAc;CACxB;AACF;;;ACvDA,SAAgB,UAAU,MAA0C;CAGlE,MAAM,IAA+B,EAAE,qBAAqB,KAAK;CACjE,IAAI,KAAK,QAAQ,KAAA,GAAW,EAAE,MAAM,KAAK;CACzC,IAAI,KAAK,QAAQ,KAAA,GAAW,EAAE,MAAM,KAAK;CACzC,OAAO;AACT;;;ACVA,MAAa,mBAAmB;;;ACShC,SAAS,eAAe,KAAgE;CACtF,MAAM,KAAK,IAAI,QAAQ,GAAG;CAC1B,IAAI,MAAM,GAAG,OAAO;EAAE,MAAM;EAAK,aAAa,KAAA;CAAU;CACxD,OAAO;EAAE,MAAM,IAAI,MAAM,GAAG,EAAE;EAAG,aAAa,IAAI,MAAM,KAAK,CAAC;CAAE;AAClE;AAEA,SAAgB,WAAW,MAA6B,YAAsC;CAC5F,MAAM,wBAAQ,IAAI,IAAY;CAC9B,MAAM,yBAAS,IAAI,IAAoB;CACvC,MAAM,cAAwB,CAAC;CAC/B,MAAM,SAAmB,CAAC;CAC1B,MAAM,4BAAY,IAAI,IAAY;CAClC,MAAM,WAAW,SAAiB;EAChC,MAAM,YAAY,cAAc,IAAI;EACpC,IAAI,UAAU,IAAI,SAAS,GAAG,OAAO,KAAK,mBAAmB,WAAW;EACxE,UAAU,IAAI,SAAS;EACvB,MAAM,IAAI,IAAI;CAChB;CACA,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,MAAM,KAAK;EACjB,MAAM,EAAE,MAAM,gBAAgB,eAAe,GAAG;EAChD,IAAI,WAAW,IAAI,IAAI,GAAG;GACxB,IAAI,gBAAgB,KAAA,GAAW;IAC7B,QAAQ,IAAI;IACZ,OAAO,IAAI,MAAM,WAAW;IAC5B;GACF;GACA,MAAM,QAAQ,KAAK,IAAI;GACvB,IAAI,UAAU,KAAA,KAAa,MAAM,WAAW,GAAG,GAAG;IAChD,QAAQ,IAAI;IACZ,OAAO,IAAI,MAAM,EAAE;IACnB;GACF;GACA,QAAQ,IAAI;GACZ,OAAO,IAAI,MAAM,KAAK;GACtB;GACA;EACF;EACA,IAAI,KAAK,WAAW,GAAG,GAAG;GACxB,QAAQ,IAAI;GACZ,IAAI,gBAAgB,KAAA,GAAW,OAAO,KAAK,+BAA+B,MAAM;GAChF;EACF;EACA,YAAY,KAAK,GAAG;CACtB;CACA,OAAO;EAAE;EAAO;EAAQ;EAAa;CAAO;AAC9C;AAEA,SAAS,cAAc,MAAsB;CAC3C,IAAI,SAAS,MAAM,OAAO;CAC1B,OAAO;AACT;AAEA,MAAM,6BAAa,IAAI,IAAI;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,SAAgB,0BACd,SACA,OACA,SACoB;CACpB,KAAK,MAAM,QAAQ,OACjB,IAAI,CAAC,QAAQ,IAAI,IAAI,GACnB,OAAO,WAAW,IAAI,IAAI,IACtB,wBAAwB,QAAQ,IAAI,SACpC,qBAAqB;AAI/B;AAEA,SAAgB,WAAW,QAA8C;CACvE,MAAM,MAAM,OAAO,IAAI,SAAS,KAAK,OAAO,IAAI,IAAI;CACpD,IAAI,QAAQ,KAAA,GAAW,OAAO;CAC9B,IAAI,QAAQ,IAAI,OAAO;CACvB,IAAI,CAAC,gBAAgB,KAAK,GAAG,GAAG,OAAO,4CAA4C,IAAI;CACvF,MAAM,QAAQ,OAAO,SAAS,KAAK,EAAE;CACrC,IAAI,CAAC,OAAO,cAAc,KAAK,KAAK,QAAA,KAClC,OAAO,2BAA2B,iBAAiB,SAAS,IAAI;CAElE,OAAO;AACT;AAEA,SAAgB,UAAU,QAA8C;CACtE,MAAM,MAAM,OAAO,IAAI,QAAQ;CAC/B,IAAI,QAAQ,KAAA,GAAW,OAAO;CAC9B,IAAI,QAAQ,IAAI,OAAO;CACvB,IAAI,QAAQ,OAAO,OAAO;CAC1B,IAAI,QAAQ,OAAO,OAAO;CAC1B,IAAI,QAAQ,OAAO,OAAO;CAC1B,OAAO,yCAAyC,IAAI;AACtD;AAIA,SAAgB,UAAU,QAAoE;CAC5F,MAAM,MAAM,OAAO,IAAI,QAAQ;CAC/B,IAAI,QAAQ,KAAA,GAAW,OAAO,KAAA;CAC9B,IAAI,QAAQ,IAAI,OAAO;CACvB,IAAI,QAAQ,SAAS,QAAQ,SAAS,QAAQ,SAAS,QAAQ,OAAO,OAAO;CAC7E,OAAO,8CAA8C,IAAI;AAC3D;AAEA,SAAgB,YAAY,QAAqD;CAC/E,OAAO,WAAW,SAAS,WAAW,SAAS,WAAW,SAAS,WAAW;AAChF;AAEA,SAAgB,QAAQ,QAAiD;CACvE,MAAM,MAAM,OAAO,IAAI,MAAM;CAC7B,IAAI,QAAQ,KAAA,GAAW,OAAO,KAAA;CAC9B,IAAI,QAAQ,IAAI,OAAO;CACvB,OAAO;AACT;AAEA,SAAgB,UAAU,QAAyB;CACjD,OAAO,WAAW;AACpB;;;AClHA,SAAgB,eAAe,KAAsB;CACnD,OAAO,WAAW,GAAG,IACjB,GAAG,IAAI,KAAK,IAAI,IAAI,YACpB,eAAe,QACb,IAAI,UACJ,OAAO,GAAG;AAClB;AAEA,SAAgB,2BAA2B,QAAsC;CAC/E,MAAM,YAAY,kBAAkB,OAAO,OAAO,OAAO,SAAS;CAClE,OAAO;EACL,eAAe,OAAO;EACtB,eAAe,OAAO,UAAU,SAAS;EACzC,eAAe,OAAO;EACtB,eAAe;EACf;CACF,CAAC,CAAC,KAAK,IAAI;AACb;AAEA,SAAgB,0BAA0B,QAAqC;CAC7E,MAAM,WAAW,eAAe,OAAO,UAAU,QAAQ,GAAG,OAAO,KAAK;CACxE,MAAM,YAAY,kBAAkB,OAAO,OAAO,OAAO,SAAS;CAClE,MAAM,QAAQ,CACZ,cAAc,OAAO,SACrB,cAAc,OAAO,UAAU,YAAY,EAAE,IAAI,SAAS,EAC5D;CAEA,MAAM,KAAK,iBAAiB,OAAO,cAAc;CACjD,MAAM,KAAK,cAAc,OAAO,aAAa,cAAc,aAAa,EAAE;CAC1E,OAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAgB,oBAAoB,QAA+B;CACjE,MAAM,WAAW,eAAe,OAAO,UAAU,QAAQ,GAAG,OAAO,KAAK;CACxE,MAAM,YAAY,kBAAkB,OAAO,OAAO,OAAO,SAAS;CAClE,OAAO;EACL,cAAc,OAAO;EACrB,cAAc,OAAO,UAAU,YAAY,EAAE,IAAI,SAAS;EAC1D,cAAc,OAAO;EACrB,cAAc;EACd;CACF,CAAC,CAAC,KAAK,IAAI;AACb;AAEA,SAAS,kBAAkB,OAAe,WAA+B;CACvE,IAAI,UAAU,WAAW,OAAO;CAChC,MAAM,QAAkB,CAAC;CACzB,IAAI,UAAU,MAAM,YAAY,GAAG,MAAM,KAAK,eAAe;CAC7D,IAAI,SAAS,KAAK,MAAM,MAAM,CAAC,CAAC,GAAG,MAAM,KAAK,wBAAwB;CACtE,OAAO,kBAAkB,MAAM,KAAK,KAAK,EAAE;AAC7C;AAGA,MAAM,cAAc,KAAK;AACzB,MAAM,YAAY,KAAK;AACvB,MAAM,WAAW,KAAK;AACtB,MAAM,eAAe;AACrB,MAAM,gBAAgB;AAEtB,SAAS,eAAe,QAAgB,OAAuB;CAC7D,MAAM,OAAO,QAAQ;CACrB,MAAM,MAAM,KAAK,IAAI,IAAI;CACzB,MAAM,SAAS,OAAO,IAAI,aAAa;CAEvC,MAAM,OAAO,UAAU,GAAG;CAC1B,OAAO,SAAS,KAAK,aAAa,GAAG,KAAK,GAAG;AAC/C;AAEA,SAAS,UAAU,KAAqB;CACtC,IAAI,MAAM,aAAa,OAAO;CAC9B,IAAI,MAAM,WAAW,OAAO,KAAK,KAAK,MAAM,MAAM,WAAW,GAAG,QAAQ;CACxE,IAAI,MAAM,UAAU,OAAO,KAAK,KAAK,MAAM,MAAM,SAAS,GAAG,MAAM;CACnE,IAAI,MAAM,WAAW,cAAc,OAAO,KAAK,KAAK,MAAM,MAAM,QAAQ,GAAG,KAAK;CAEhF,MAAM,cAAc,KAAK,MAAM,OAAO,WAAW,aAAa;CAC9D,IAAI,cAAc,eAAe,OAAO,KAAK,aAAa,OAAO;CAEjE,MAAM,QAAQ,KAAK,MAAM,cAAc,aAAa;CACpD,MAAM,SAAS,cAAc;CAC7B,OAAO,WAAW,IAAI,KAAK,OAAO,MAAM,IAAI,GAAG,KAAK,OAAO,MAAM,EAAE,GAAG,KAAK,QAAQ,OAAO;AAC5F;AAEA,SAAS,KAAK,GAAW,MAAsB;CAC7C,OAAO,GAAG,EAAE,GAAG,MAAM,IAAI,OAAO,GAAG,KAAK;AAC1C;;;ACjCA,MAAa,mBAAwC;CACnD,aAAa;CACb,UAAU,OAAO,MAAM;EACrB,IAAI;GACF,OAAO,kBAAkB,OAAO,UAAU,IAAI,CAAC;EACjD,SAAS,KAAK;GACZ,OAAO,eAAe,GAAG;EAC3B;CACF;AACF;AAEA,MAAa,gBAAqC;CAChD,MAAM;CACN,KAAK;EACH,QAAQ;EACR,cAAc;EACd,QAAQ;EACR,QAAQ;EACR,QAAQ;CACV;CACA,aAAa;CACb,UAAU,OAAO,MAAM,KAAK;EAC1B,IAAI;GACF,OAAO,wBAAwB,OAAO;IAAO;IAAkB,GAAG,UAAU,IAAI;GAAE,CAAC;EACrF,SAAS,KAAK;GACZ,OAAO,eAAe,GAAG;EAC3B;CACF;AACF;AAEA,MAAa,iBAAsC;CACjD,MAAM;CACN,aAAa;CACb,UAAU,OAAO,MAAM;EACrB,IAAI;GACF,OAAO,yBAAyB,OAAO,UAAU,IAAI,CAAC;EACxD,SAAS,KAAK;GACZ,OAAO,eAAe,GAAG;EAC3B;CACF;AACF;AAEA,MAAa,iBAA6B;CACxC,MAAM;CACN,KAAK;EACH,QAAQ;EACR,cAAc;EACd,QAAQ;EACR,QAAQ;EACR,QAAQ;CACV;CACA,aAAa;CACb,YAAY,CAAC,QAAQ;CACrB,UAAU,OAAO,OAAO,KAAK,QAAQ;EACnC,MAAM,OAAO,UAAU,0BAAU,IAAI,IAAI,CAAC;EAC1C,IAAI,SAAS,KAAA,GAAW,OAAO;EAC/B,IAAI,YAAY,IAAI,GAAG,OAAO;EAC9B,IAAI;GACF,OAAO,mBAAmB,OAAO;IAC/B;IACA,MAAM,CAAC,GAAkB;IACzB,qBAAqB;GACvB,CAAC;EACH,SAAS,KAAK;GACZ,OAAO,eAAe,GAAG;EAC3B;CACF;AACF;AAEA,MAAa,gBAAqC;CAChD,MAAM;CACN,KAAK;EACH,QAAQ;EACR,cAAc;EACd,QAAQ;EACR,QAAQ;EACR,QAAQ;CACV;CACA,aAAa;CACb,UAAU,OAAO,MAAM,KAAK;EAC1B,IAAI;GACF,OAAO,wBAAwB,OAAO;IACpC,MAAM,CAAC,GAAiB;IACxB,GAAG,UAAU,IAAI;GACnB,CAAC;EACH,SAAS,KAAK;GACZ,OAAO,eAAe,GAAG;EAC3B;CACF;AACF;AAEA,MAAa,gBAAqC;CAChD,MAAM;CACN,KAAK;EACH,QAAQ;EACR,cAAc;EACd,QAAQ;EACR,QAAQ;EACR,QAAQ;CACV;CAGA,aAAa;CACb,YAAY,CAAC,MAAM;CACnB,UAAU,OAAO,MAAM,KAAK,QAAQ;EAClC,MAAM,KAAK,QAAQ,0BAAU,IAAI,IAAI,CAAC;EACtC,IAAI,OAAO,KAAA,GAAW,OAAO;EAC7B,IAAI,UAAU,EAAE,GAAG,OAAO;EAC1B,IAAI;GACF,MAAM,QAAQ,eAAe,OAAO;IAAE;IAAS;IAAkB,qBAAqB;GAAK,CAAC;GAC5F,OAAO;IACL,YAAY,MAAe,MAAM,UAAU,CAAC;IAC5C,WAA4B;KAE1B,QADe,KAAK,oBAAoB,QAAQ,QAAQ,EAAE,GAAA,CAC5C,CAAC,CAAC,MAAM,aAAa,MAAM,OAAO,QAAQ,CAAC;IAC3D;GACF;EACF,SAAS,KAAK;GACZ,OAAO,eAAe,GAAG;EAC3B;CACF;AACF;AAKA,MAAa,wBAA+C;CAC1D;CACA;CACA;CACA;CACA;AACF;AAEA,MAAa,iBAAiC;CAC5C,SAAS;CACT,YAAY;EAAC;EAAe;EAAgB;EAAe;CAAa;CACxE,gBAAgB,CAAC,WAAW,IAAI;AAClC;AAEA,MAAa,gBAAwB;CACnC,SAAS;CACT,YAAY;EAAC;EAAgB;EAAgB;EAAe;CAAa;CACzE,gBAAgB,CAAC;AACnB;AAEA,MAAa,eAAuB;CAClC,SAAS;CACT,YAAY;EAAC;EAAgB;EAAe;CAAa;CACzD,gBAAgB,CAAC,QAAQ;AAC3B;;;ACrNA,SAAgB,mBAAmB,QAA6B;CAC9D,MAAM,QAAQ,IAAI,IAAY,OAAO,cAAc;CACnD,IAAI,WAAW,OAAO,QAAQ,QAAQ,KAAA;CACtC,KAAK,MAAM,KAAK,OAAO,YAAY;EACjC,IAAI,EAAE,SAAS,KAAA,GAAW,MAAM,IAAI,EAAE,IAAI;EAC1C,IAAI,EAAE,QAAQ,KAAA,GAAW,WAAW;EACpC,IAAI,EAAE,eAAe,KAAA,GACnB,KAAK,MAAM,KAAK,EAAE,YAAY,MAAM,IAAI,CAAC;CAE7C;CACA,IAAI,UAAU,MAAM,IAAI,cAAc;CACtC,OAAO;AACT;AAEA,SAAgB,eACd,QACA,OACY;CACZ,MAAM,WAAW,sBAAsB,QACpC,MACC,OAAO,WAAW,MAAM,MAAM,MAAM,CAAC,KAAK,EAAE,SAAS,KAAA,KAAa,MAAM,IAAI,EAAE,IAAI,CACtF;CACA,IAAI,SAAS,WAAW,GAAG,OAAO,OAAO;CACzC,IAAI,SAAS,WAAW,GAAG,OAAO,SAAS;CAC3C,OAAO,cAAc,SAAS,EAAE,CAAE,KAAK,OAAO,SAAS,EAAE,CAAE,KAAK;AAClE;AAcA,eAAsB,WACpB,SACA,OACA,QACA,MACiF;CACjF,IAAI;CACJ,IAAI,QAAQ,QAAQ,KAAA,GAAW;EAC7B,MAAM,SAAS,eAAe,QAAQ,MAAM,QAAQ,GAAG;EACvD,IAAI,iBAAiB,MAAM,GAAG,OAAO;EACrC,MAAM,YAAY,MAAM,QAAQ,MAAM,QAAQ,QAAQ,GAAG;EACzD,IAAI,OAAO,cAAc,UAAU,OAAO;EAC1C,MAAM;CACR;CACA,OAAO,QAAQ,UAAU,OAAO,MAAM,KAAK,MAAM;AACnD;;;AC3DA,IAAI;;AAEJ,SAAS,mBAAoC;CAC3C,IAAI,eAAe,KAAA,GACjB,aAAa,IAAI,SAAiB,YAAY;EAC5C,MAAM,SAAmB,CAAC;EAC1B,QAAQ,MAAM,YAAY,MAAM;EAChC,QAAQ,MAAM,GAAG,SAAS,UAAkB,OAAO,KAAK,KAAK,CAAC;EAC9D,QAAQ,MAAM,GAAG,aAAa,QAAQ,OAAO,KAAK,EAAE,CAAC,CAAC;EACtD,QAAQ,MAAM,OAAO;CACvB,CAAC;CAEH,OAAO;AACT;AAEA,eAAsB,YAAY,MAA6B,MAAgC;CAC7F,MAAM,eAAe,mBAAmB,cAAc;CACtD,MAAM,gBAAgB,IAAI,IACxB,eAAe,WAAW,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,QAAQ,MAAmB,MAAM,KAAA,CAAS,CACzF;CAEA,MAAM,EAAE,OAAO,QAAQ,aAAa,WAAW,WAAW,MAAM,IADzC,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC,QAAQ,MAAM,CAAC,cAAc,IAAI,CAAC,CAAC,CACP,CAAC;CAC1E,MAAM,cAAc,0BAA0B,YAAY,OAAO,YAAY;CAC7E,IAAI,gBAAgB,KAAA,GAAW;EAC7B,KAAK,OAAO,cAAc,IAAI;EAC9B,OAAO;CACT;CACA,IAAI,OAAO,OAAO,KAAA,GAAW;EAC3B,KAAK,OAAO,OAAO,KAAK,IAAI;EAC5B,OAAO;CACT;CACA,MAAM,QAAQ,YAAY;CAC1B,IAAI,UAAU,KAAA,GAAW;EACvB,KAAK,OAAO,wBAAwB,MAAM,GAAG;EAC7C,OAAO;CACT;CACA,MAAM,CAAC,SAAS;CAChB,MAAM,QAAQ,WAAW,MAAM;CAC/B,IAAI,OAAO,UAAU,UAAU;EAC7B,KAAK,OAAO,QAAQ,IAAI;EACxB,OAAO;CACT;CACA,MAAM,UAAU,eAAe,gBAAgB,KAAK;CACpD,IAAI,OAAO,YAAY,UAAU;EAC/B,KAAK,OAAO,UAAU,IAAI;EAC1B,OAAO;CACT;CACA,IAAI,QAAQ,QAAQ,KAAA,KAAa,MAAM,IAAI,cAAc,GAAG;EAC1D,KAAK,OAAO,yDAAyD;EACrE,OAAO;CACT;CACA,IAAI,MAAM,IAAI,UAAU,KAAK,QAAQ,GAAG;EACtC,KAAK,OACH,sFACF;EACA,OAAO;CACT;CACA,MAAM,gBAAyB;EAAE,GAAG;EAAM,WAAW,KAAK,aAAa;CAAiB;CACxF,MAAM,QAAQ,MAAM,WAAW,SAAS,SAAS,IAAI,QAAQ,aAAa;CAC1E,IAAI,OAAO,UAAU,UAAU;EAC7B,KAAK,OAAO,QAAQ,IAAI;EACxB,OAAO;CACT;CACA,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,KAAK,KAAK,OAAQ,MAAM,MAAM,SAAS,IAAK,IAAI;CAC3E,OAAO;AACT;;;ACpEA,SAAgB,QAAgB;CAC9B,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,eAAe,iBAAiB;EAChC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,KAAK,IAAI;AACb;;;ACVA,eAAsB,WAAW,MAA6B,MAAgC;CAC5F,MAAM,eAAe,mBAAmB,aAAa;CACrD,MAAM,gBAAgB,IAAI,IACxB,cAAc,WAAW,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,QAAQ,MAAmB,MAAM,KAAA,CAAS,CACxF;CAEA,MAAM,EAAE,OAAO,QAAQ,aAAa,WAAW,WAAW,MAAM,IADzC,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC,QAAQ,MAAM,CAAC,cAAc,IAAI,CAAC,CAAC,CACP,CAAC;CAE1E,MAAM,cAAc,0BAA0B,WAAW,OAAO,YAAY;CAC5E,IAAI,gBAAgB,KAAA,GAAW;EAC7B,KAAK,OAAO,cAAc,IAAI;EAC9B,OAAO;CACT;CACA,IAAI,OAAO,OAAO,KAAA,GAAW;EAC3B,KAAK,OAAO,OAAO,KAAK,IAAI;EAC5B,OAAO;CACT;CACA,MAAM,CAAC,SAAS;CAChB,IAAI,UAAU,KAAA,GAAW;EACvB,KAAK,OAAO,MAAM,CAAC;EACnB,OAAO;CACT;CACA,MAAM,QAAQ,YAAY;CAC1B,IAAI,UAAU,KAAA,GAAW;EACvB,KAAK,OAAO,wBAAwB,MAAM,GAAG;EAC7C,OAAO;CACT;CAEA,MAAM,UAAU,eAAe,eAAe,KAAK;CACnD,IAAI,OAAO,YAAY,UAAU;EAC/B,KAAK,OAAO,UAAU,IAAI;EAC1B,OAAO;CACT;CACA,IAAI,QAAQ,QAAQ,KAAA,KAAa,MAAM,IAAI,cAAc,GAAG;EAC1D,KAAK,OAAO,0DAA0D;EACtE,OAAO;CACT;CAEA,MAAM,QAAQ,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,YAAY;CAO5C,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI,QAAQ,gBAAgB,UAAU;EACpC,MAAM,WAAW,eAAe,QAAQ,MAAM,QAAQ,GAAI;EAC1D,IAAI,iBAAiB,QAAQ,GAAG;GAC9B,KAAK,OAAO,WAAW,IAAI;GAC3B,OAAO;EACT;EACA,IAAI;EACJ,IAAI;GACF,UAAU,kBAAkB,OAAO,UAAU,IAAI,CAAC;EAEpD,SAAS,KAAK;GACZ,KAAK,OAAO,eAAe,GAAG,IAAI,IAAI;GACtC,OAAO;EACT;EACA,MAAM,mBAAmB,QAAQ,YAAY,CAAC,SAAS,KAAK;EAC5D,IAAI,iBAAiB,QAAQ;GAC3B,KAAK,OAAO,iBAAiB,OAAO,EAAE,CAAE,UAAU,IAAI;GACtD,OAAO;EACT;EACA,kBAAkB,iBAAiB;EACnC,kBAAkB,QAAQ,iBAAiB,eAAe;EAC1D,eAAe,KAAK,OAAO,KAAK,IAAA,CAAK;CACvC;CAEA,MAAM,eAAe,MAAM,WAAW,SAAS,OAAO,QAAQ,IAAI;CAClE,IAAI,OAAO,iBAAiB,UAAU;EACpC,IAAI,QAAQ,gBAAgB,UAC1B,KAAK,OACH,0BAA0B;GACxB;GACA,WAAW;GACX,WAAW;GACX;GACA,OAAO;GACP,cAAc;EAChB,CAAC,CACH;EAEF,KAAK,OAAO,eAAe,IAAI;EAC/B,OAAO;CACT;CAGA,IAAI;CACJ,IAAI,QAAQ,gBAAgB,UAAU;EACpC,MAAM,aAAc,aAAyC,YAAY,CAAC,SAAS,KAAK;EACxF,IAAI,WAAW,QAAQ;GACrB,KAAK,OAAO,WAAW,OAAO,EAAE,CAAE,UAAU,IAAI;GAChD,OAAO;EACT;EACA,YAAY,WAAW;CACzB;CAGA,QAAQ,QAAQ,aAAhB;EACE,KAAK,YAAY;GACf,MAAM,YAAa,aAAiD,iBAClE,SACF;GACA,MAAM,SAAS,KAAK,OAAO,KAAK,IAAA,CAAK;GACrC,KAAK,OACH,gKACF;GACA,KAAK,OAAO,oBAAoB;IAAE;IAAO;IAAsB;IAAY;IAAO;GAAM,CAAC,CAAC;GAC1F,OAAO;EACT;EACA,KAAK,kBAAkB;GACrB,MAAM,YAAY,MAChB,aACA,iBAAiB,SAAU;GAC7B,MAAM,SAAS,KAAK,OAAO,KAAK,IAAA,CAAK;GACrC,KAAK,OACH,8HACF;GACA,KAAK,OAAO,oBAAoB;IAAE;IAAO;IAAsB;IAAY;IAAO;GAAM,CAAC,CAAC;GAC1F,OAAO;EACT;EACA,KAAK,UAAU;GACb,IAAI;GACJ,IAAI;IACF,YAAY,MAAO,aAAuC,OAAO,SAAU;GAC7E,SAAS,KAAK;IACZ,KAAK,OAAO,eAAe,GAAG,IAAI,IAAI;IACtC,OAAO;GACT;GACA,KAAK,OAAO,2BAA2B;IAAE;IAAO;IAAsB;IAAY;GAAM,CAAC,CAAC;GAC1F,OAAO;EACT;EACA,KAAK,UAAU;GACb,MAAM,eAAe,MAAO,aAA2C,WAAW,KAAK;GACvF,IAAI,CAAC,aAAa,IAAI;;;IAGpB,IAAI,aAAa,UAAU,uBAAuB;KAChD,KAAK,OAAO,aAAa,QAAQ,IAAI;KACrC,OAAO;IACT;IACA,KAAK,OACH,0BAA0B;KACxB;KACA,WAAW;KACX,WAAW;KACX;KACA,OAAO;KACP,cAAc;IAChB,CAAC,CACH;IACA,KAAK,OAAO,4CAA4C;IACxD,OAAO;GACT;GACA,KAAK,OACH,0BAA0B;IACxB;IACA,WAAW;IACX,WAAW,aAAa;IACxB;IACA,OAAO;IACP,cAAc;GAChB,CAAC,CACH;GACA,OAAO;EACT;;;;EAIA,KAAK;GACH,KAAK,OAAO,0CAA0C;GACtD,OAAO;CAEX;AACF;;;ACnMA,SAAgB,UAAU,MAA6B,MAAgC;CACrF,MAAM,eAAe,mBAAmB,YAAY;CACpD,MAAM,oBAAoB,IAAI,IAAI,aAAa,WAAW,SAAS,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC;CAC5F,MAAM,EAAE,OAAO,QAAQ,aAAa,WAAW,WAAW,MAAM,YAAY;CAC5E,MAAM,cAAc,0BAClB,UACA,OACA,IAAI,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC,QAAQ,MAAM,CAAC,kBAAkB,IAAI,CAAC,CAAC,CAAC,CACpE;CACA,IAAI,gBAAgB,KAAA,GAAW;EAC7B,KAAK,OAAO,cAAc,IAAI;EAC9B,OAAO,QAAQ,QAAQ,CAAC;CAC1B;CACA,IAAI,OAAO,OAAO,KAAA,GAAW;EAC3B,KAAK,OAAO,OAAO,KAAK,IAAI;EAC5B,OAAO,QAAQ,QAAQ,CAAC;CAC1B;CACA,MAAM,QAAQ,YAAY;CAC1B,IAAI,UAAU,KAAA,GAAW;EACvB,KAAK,OAAO,wBAAwB,MAAM,GAAG;EAC7C,OAAO,QAAQ,QAAQ,CAAC;CAC1B;CACA,MAAM,UAAU,eAAe,cAAc,KAAK;CAClD,IAAI,OAAO,YAAY,UAAU;EAC/B,KAAK,OAAO,UAAU,IAAI;EAC1B,OAAO,QAAQ,QAAQ,CAAC;CAC1B;CACA,MAAM,OAAO,UAAU,MAAM;CAC7B,IAAI,OAAO,SAAS,UAAU;EAC5B,KAAK,OAAO,OAAO,IAAI;EACvB,OAAO,QAAQ,QAAQ,CAAC;CAC1B;CACA,MAAM,SAAS,uBAAuB,MAAM;CAC5C,IAAI,iBAAiB,MAAM,GAAG;EAC5B,KAAK,OAAO,SAAS,IAAI;EACzB,OAAO,QAAQ,QAAQ,CAAC;CAC1B;;CAEA,IAAI,QAAQ,QAAQ,KAAA,GAAW;EAC7B,KAAK,OAAO,oDAAoD;EAChE,OAAO,QAAQ,QAAQ,CAAC;CAC1B;CACA,MAAM,QAAQ,IAAI,WAAW,OAAO,CAAC;CACrC,OAAO,gBAAgB,KAAK;CAC5B,KAAK,OAAO,QAAQ,IAAI,OAAO,OAAO,MAAM,IAAI,IAAI;CACpD,OAAO,QAAQ,QAAQ,CAAC;AAC1B;;;ACvCA,MAAM,WAAmC;CACvC;EAAE,OAAO,CAAC,YAAY,GAAG;EAAG,KAAK;CAAY;CAC7C;EAAE,OAAO,CAAC,WAAW,GAAG;EAAG,KAAK;CAAW;CAC3C;EAAE,OAAO,CAAC,UAAU,GAAG;EAAG,KAAK;CAAU;AAC3C;AAEA,eAAsB,IAAI,MAAgC;CACxD,MAAM,CAAC,YAAY,GAAG,QAAQ,KAAK;CACnC,MAAM,UAAU,SAAS,MAAM,cAAc,UAAU,MAAM,SAAS,cAAc,EAAE,CAAC;CACvF,IAAI,YAAY,KAAA,GAAW,OAAO,QAAQ,IAAI,MAAM,IAAI;CACxD,IAAI,eAAe,KAAA,KAAa,eAAe,YAAY,eAAe,MAAM;EAC9E,KAAK,OAAO,MAAM,CAAC;EACnB,OAAO;CACT;CACA,KAAK,OAAO,MAAM,CAAC;CACnB,OAAO;AACT;;;AC1BA,QAAQ,WAAW,MAAM,IAAI;CAC3B,MAAM,QAAQ,KAAK,MAAM,CAAC;CAC1B,SAAS,MAAM,QAAQ,OAAO,MAAM,CAAC;CACrC,SAAS,MAAM,QAAQ,OAAO,MAAM,CAAC;AACvC,CAAC"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { t as IdsError } from "./error-Cp5qYZcv.mjs";
|
|
2
|
-
//#region src/brand.ts
|
|
2
|
+
//#region src/codecs/_kernel/brand.ts
|
|
3
3
|
const brandPattern = /^[a-z]{3}$/;
|
|
4
4
|
/** Validates a three-character lowercase brand. Throws on invalid input. */
|
|
5
5
|
function validateBrand(brand) {
|
|
6
6
|
if (!brandPattern.test(brand)) throw new IdsError("invalid_brand", "invalid brand: expected three lowercase a-z characters");
|
|
7
7
|
}
|
|
8
8
|
//#endregion
|
|
9
|
-
//#region src/base32.ts
|
|
9
|
+
//#region src/wire/base32.ts
|
|
10
10
|
const alphabet = "0123456789abcdefghjkmnpqrstvwxyz";
|
|
11
11
|
const valueToCharCode = /* @__PURE__ */ new Uint8Array(32);
|
|
12
12
|
for (let i = 0; i < 32; i++) valueToCharCode[i] = alphabet.charCodeAt(i);
|
|
@@ -66,7 +66,7 @@ const payloadBase32Length = Math.ceil(128 / 5);
|
|
|
66
66
|
const base32CharClass = "[0-9a-hjkmnp-tv-z]";
|
|
67
67
|
const base32FinalCharClass = "[048cgmrw]";
|
|
68
68
|
//#endregion
|
|
69
|
-
//#region src/registry.ts
|
|
69
|
+
//#region src/codecs/_kernel/registry.ts
|
|
70
70
|
const registeredBrands = /* @__PURE__ */ new Set();
|
|
71
71
|
const warnedBrands = /* @__PURE__ */ new Set();
|
|
72
72
|
function registerBrand(brand, allowDuplicateBrand) {
|
|
@@ -150,4 +150,4 @@ function wireMethods(prefix) {
|
|
|
150
150
|
//#endregion
|
|
151
151
|
export { toWireId as a, payloadBytesFromId as i, registerBrand as n, decodeBase32 as o, payloadBase32Length as r, validateBrand as s, wireMethods as t };
|
|
152
152
|
|
|
153
|
-
//# sourceMappingURL=codec-shell-
|
|
153
|
+
//# sourceMappingURL=codec-shell-DvrTDa65.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codec-shell-DvrTDa65.mjs","names":[],"sources":["../src/codecs/_kernel/brand.ts","../src/wire/base32.ts","../src/wire/envelope.ts","../src/wire/invariants.ts","../src/codecs/_kernel/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":";;AAEA,MAAM,eAAe;;AAGrB,SAAgB,cAAc,OAAqB;CACjD,IAAI,CAAC,aAAa,KAAK,KAAK,GAC1B,MAAM,IAAI,SAAS,iBAAiB,wDAAwD;AAEhG;;;ACCA,MAAa,WAAW;AAGxB,MAAM,kCAAkB,IAAI,WAAW,EAAE;AACzC,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK,gBAAgB,KAAK,SAAS,WAAW,CAAC;AAKvE,MAAM,mCAAkB,IAAI,WAAW,GAAG,EAAA,CAAE,KAAK,GAAO;AACxD,KAAK,IAAI,IAAI,GAAG,IAAI,IAAiB,KAAK,gBAAgB,SAAS,WAAW,CAAC,KAAK;AAEpF,SAAgB,aAAa,OAA2B;CAKtD,MAAM,QAAQ,IAAI,MAAc,KAAK,MAAO,MAAM,SAAS,IAAK,CAAC,IAAI,CAAC;CACtE,IAAI,MAAM;CACV,IAAI,OAAO;CACX,IAAI,QAAQ;CAEZ,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,QAAS,SAAS,IAAK,MAAM;EAC7B,QAAQ;EACR,OAAO,QAAQ,GAAG;GAChB,QAAQ;GACR,MAAM,SAAS,gBAAiB,UAAU,OAAQ;EACpD;CACF;CACA,MAAM,OAAO,gBAAiB,SAAU,IAAI,OAAS;CACrD,OAAO,OAAO,aAAa,MAAM,MAAM,KAAK;AAC9C;AAEA,SAAgB,aAAa,KAAyB;CACpD,MAAM,SAAS,IAAI,WAAW,KAAK,MAAO,IAAI,SAAS,IAAK,CAAC,CAAC;CAC9D,IAAI,OAAO;CACX,IAAI,QAAQ;CACZ,IAAI,QAAQ;CAEZ,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;EACnC,MAAM,IAAI,gBAAgB,IAAI,WAAW,CAAC;EAC1C,QAAS,SAAS,IAAK;EACvB,QAAQ;EACR,IAAI,QAAQ,GAAG;GACb,QAAQ;GACR,OAAO,WAAY,UAAU,OAAQ;EACvC;CACF;CACA,OAAO;AACT;;;;ACxDA,SAAS,cAAc,OAA2B;CAChD,OAAO,aAAa,KAAK;AAC3B;;AAGA,SAAS,cAAc,QAA4B;CACjD,OAAO,aAAa,MAAM;AAC5B;;AAGA,SAAgB,SACd,QACA,SACW;CACX,OAAQ,SAAS,cAAc,OAAO;AACxC;;AAGA,SAAgB,mBACd,QACA,IACY;CACZ,OAAO,cAAc,GAAG,MAAM,OAAO,MAAM,CAAC;AAC9C;ACxBA,MAAa,sBAA8B,KAAK,KAAA,MAA+B,CAAC;AAKhF,MAAa,kBAA0B;AAIvC,MAAa,uBAA+B;;;ACZ5C,MAAM,mCAAmB,IAAI,IAAY;AACzC,MAAM,+BAAe,IAAI,IAAY;AAErC,SAAgB,cAAc,OAAe,qBAAgD;CAC3F,IACE,OAAO,YAAY,eACnB,QAAQ,IAAI,aAAa,gBACzB,qBAEA;CAGF,IAAI,iBAAiB,IAAI,KAAK;MACxB,CAAC,aAAa,IAAI,KAAK,GAAG;GAC5B,QAAQ,KACN,uBAAuB,MAAM,+LAC/B;GACA,aAAa,IAAI,KAAK;EACxB;QAEA,iBAAiB,IAAI,KAAK;AAE9B;;;AClBA,MAAM,iBAAiB;AACvB,MAAM,mBAAmB;AACzB,MAAM,YAAY,UAA2B,UAAU,MAAM,MAAM;AACnE,MAAM,gBAAgB,IAAI,OACxB,KAAK,SAAS,IAAI,sBAAsB,EAAE,GAAG,qBAAqB,EACpE;AAEA,SAAgB,UACd,QACA,OACoB;CACpB,IAAI,OAAO,UAAU,UAAU,OAAO;EAAE,IAAI;EAAO,OAAO;CAAa;CACvE,MAAM,YAAY,MAAM,YAAY;CACpC,IAAI,CAAC,UAAU,WAAW,MAAM,GAAG,OAAO;EAAE,IAAI;EAAO,OAAO;CAAiB;CAE/E,MAAM,SAAS,UAAU,MAAM,OAAO,MAAM;CAC5C,MAAM,SAAS,iBAAiB,KAAK,MAAM,IACvC,OAAO,WAAW,gBAAgB,QAAQ,IAC1C;CAEJ,IAAI,CAAC,cAAc,KAAK,MAAM,GAAG,OAAO;EAAE,IAAI;EAAO,OAAO;CAAiB;CAG7E,OAAO;EAAE,IAAI;EAAM,IADP,SAAS;CACC;AACxB;AAEA,SAAgB,GACd,QACA,OACoB;CACpB,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,IAAI,CAAC,MAAM,WAAW,MAAM,GAAG,OAAO;CACtC,OAAO,cAAc,KAAK,MAAM,MAAM,OAAO,MAAM,CAAC;AACtD;AAEA,SAAS,aAAmC,QAAuB,OAA2B;CAC5F,QAAQ,OAAR;EACE,KAAK,cACH,OAAO;EACT,KAAK,kBACH,OAAO,oBAAoB,OAAO;EACpC,KAAK,kBACH,OAAO;CACX;AACF;AAEA,SAAgB,iBACd,QACA,OAGmE;CACnE,MAAM,SAAS,UAAU,QAAQ,KAAK;CACtC,IAAI,OAAO,IAAI,OAAO,EAAE,OAAO,OAAO,GAAG;CACzC,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,aAAa,QAAQ,OAAO,KAAK,EAAE,CAAC,EAAE;AACrE;;;;AC7CA,SAAgB,YAAkC,QAA2C;CAM3F,OAAO;EACL,KAAK,UAAuC,GAAG,QAAQ,KAAK;EAC5D,QAAQ,UAA8B;GACpC,MAAM,SAAS,UAAU,QAAQ,KAAK;GACtC,IAAI,OAAO,IAAI,OAAO,OAAO;GAC7B,MAAM,IAAI,SAAS,cAAc,eAAe,OAAO,SAAS,EAAE,OAAO,OAAO,MAAM,CAAC;EACzF;EACA,YAAY,UAAuC,UAAU,QAAQ,KAAK;EAC1E,eAAe,OAAc,aAAiC;GAC5D,MAAM;GACN,SAAS,IAAI,SAAS,gBAAgB,GAAG,sBAAsB,EAAE,GAAG,qBAAqB;GACzF,aAAa,mBAAmB,MAAM;GACtC;EACF;EACA,aAAa;GAlBb,SAAS;GACT,QAAQ;GACR,WAAW,UAAmB,iBAAiB,QAAQ,KAAK;EAgBxC;CACtB;AACF"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as IdsError } from "./error-Cp5qYZcv.mjs";
|
|
2
|
-
import { a as toWireId, n as registerBrand, r as payloadBase32Length, s as validateBrand, t as wireMethods } from "./codec-shell-
|
|
3
|
-
import { i as encodeKeyMaterial, r as decodeKeyMaterial, t as assertValidKeyMaterialByteLength } from "./key-material-
|
|
4
|
-
//#region src/
|
|
2
|
+
import { a as toWireId, n as registerBrand, r as payloadBase32Length, s as validateBrand, t as wireMethods } from "./codec-shell-DvrTDa65.mjs";
|
|
3
|
+
import { i as encodeKeyMaterial, r as decodeKeyMaterial, t as assertValidKeyMaterialByteLength } from "./key-material-f29JIyrz.mjs";
|
|
4
|
+
//#region src/codecs/digest/layout.ts
|
|
5
5
|
const encoder = new TextEncoder();
|
|
6
6
|
function writeLen32(value, target, offset) {
|
|
7
7
|
target[offset] = value >>> 24 & 255;
|
|
@@ -36,14 +36,14 @@ function createDigestLayoutOps(prefix, brand, ns, hmacKey) {
|
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
38
|
//#endregion
|
|
39
|
-
//#region src/digest
|
|
40
|
-
const hmacInfo = new TextEncoder().encode("ids/digest/hmac");
|
|
39
|
+
//#region src/codecs/digest/key.ts
|
|
40
|
+
const hmacInfo = new TextEncoder().encode("@smonn/ids/digest/hmac");
|
|
41
41
|
const internals = /* @__PURE__ */ new WeakMap();
|
|
42
42
|
/**
|
|
43
43
|
* Import raw operator key material into a {@link DigestKey} handle.
|
|
44
44
|
*
|
|
45
45
|
* Derives a single HMAC-SHA-256 key via HKDF under the domain-separation label
|
|
46
|
-
*
|
|
46
|
+
* `@smonn/ids/digest/hmac`. Accepts 16, 24, or 32 bytes. To store or transport key
|
|
47
47
|
* material, use {@link encodeDigestKey} / {@link decodeDigestKey}
|
|
48
48
|
* (`"hex"` or `"base64url"` — not Crockford base32).
|
|
49
49
|
*
|
|
@@ -82,7 +82,7 @@ function decodeDigestKey(encoded, format) {
|
|
|
82
82
|
return decodeKeyMaterial(encoded, format, "digest", "digest");
|
|
83
83
|
}
|
|
84
84
|
/**
|
|
85
|
-
* Returns the derived HMAC CryptoKey held inside the handle.
|
|
85
|
+
* Returns the derived HMAC webcrypto.CryptoKey held inside the handle.
|
|
86
86
|
*
|
|
87
87
|
* Intentional module-internal escape hatch for codec implementations.
|
|
88
88
|
* Not re-exported from `@smonn/ids/digest`; external callers cannot reach this.
|
|
@@ -107,7 +107,7 @@ async function deriveHmacKey(bytes) {
|
|
|
107
107
|
}, false, ["sign"]);
|
|
108
108
|
}
|
|
109
109
|
//#endregion
|
|
110
|
-
//#region src/digest.ts
|
|
110
|
+
//#region src/codecs/digest/index.ts
|
|
111
111
|
/**
|
|
112
112
|
* Construct a {@link DigestCodec} for `brand`.
|
|
113
113
|
*
|
|
@@ -144,4 +144,4 @@ function createDigestId(brand, opts) {
|
|
|
144
144
|
//#endregion
|
|
145
145
|
export { importDigestKey as i, decodeDigestKey as n, encodeDigestKey as r, createDigestId as t };
|
|
146
146
|
|
|
147
|
-
//# sourceMappingURL=digest-
|
|
147
|
+
//# sourceMappingURL=digest-CknNw2wa.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"digest-CknNw2wa.mjs","names":[],"sources":["../src/codecs/digest/layout.ts","../src/codecs/digest/key.ts","../src/codecs/digest/index.ts"],"sourcesContent":["import type { webcrypto } from \"node:crypto\";\nimport type { Id, Prefix } from \"../../types.js\";\nimport { toWireId } from \"../../wire/envelope.js\";\nimport { payloadBase32Length, payloadByteLength } from \"../../wire/invariants.js\";\n\nconst encoder = new TextEncoder();\n\nfunction writeLen32(value: number, target: Uint8Array, offset: number): void {\n target[offset] = (value >>> 24) & 0xff;\n target[offset + 1] = (value >>> 16) & 0xff;\n target[offset + 2] = (value >>> 8) & 0xff;\n target[offset + 3] = value & 0xff;\n}\n\nfunction buildMessage(\n brandBytes: Uint8Array,\n nsBytes: Uint8Array,\n material: Uint8Array,\n): Uint8Array {\n const msgLen = 4 + brandBytes.length + 4 + nsBytes.length + material.length;\n const message = new Uint8Array(msgLen);\n let offset = 0;\n writeLen32(brandBytes.length, message, offset);\n offset += 4;\n message.set(brandBytes, offset);\n offset += brandBytes.length;\n writeLen32(nsBytes.length, message, offset);\n offset += 4;\n message.set(nsBytes, offset);\n offset += nsBytes.length;\n message.set(material, offset);\n return message;\n}\n\nexport function createDigestLayoutOps<Brand extends string>(\n prefix: Prefix<Brand>,\n brand: Brand,\n ns: string,\n hmacKey: webcrypto.CryptoKey,\n) {\n const brandBytes = encoder.encode(brand);\n const nsBytes = encoder.encode(ns);\n\n return {\n digest: async (material: string | Uint8Array): Promise<Id<Brand>> => {\n const materialBytes = typeof material === \"string\" ? encoder.encode(material) : material;\n const message = buildMessage(brandBytes, nsBytes, materialBytes);\n const hmacOutput = new Uint8Array(\n await crypto.subtle.sign(\"HMAC\", hmacKey, message as Uint8Array<ArrayBuffer>),\n );\n const payload = hmacOutput.subarray(0, payloadByteLength);\n return toWireId(prefix, payload);\n },\n exampleWireId: (): Id<Brand> => (prefix + \"0\".repeat(payloadBase32Length)) as Id<Brand>,\n };\n}\n","import type { webcrypto } from \"node:crypto\";\nimport {\n assertValidKeyMaterialByteLength,\n decodeKeyMaterial,\n encodeKeyMaterial,\n} from \"../_kernel/key-material.js\";\n\n/** Wire encoding for digest operator key material (not Crockford base32). */\nexport type DigestKeyFormat = \"hex\" | \"base64url\";\n\nconst hmacInfo = new TextEncoder().encode(\"@smonn/ids/digest/hmac\");\n\ndeclare const digestKeyBrand: unique symbol;\n\n/**\n * Opaque imported handle for one operator Digest key.\n *\n * Holds a single HMAC-SHA-256 key derived via HKDF under the domain-separation\n * label `@smonn/ids/digest/hmac`. The underlying `webcrypto.CryptoKey` is held internally and\n * never exposed to callers. Obtain handles via {@link importDigestKey} and pass\n * them to `createDigestId` as the `key` option.\n *\n * Unlike the other keyed codecs, the Digest codec holds exactly one key — there\n * is no keyring. Re-keying is a deliberate, breaking operator action (every ID\n * changes), never an in-band rotation.\n *\n * Distinct from the **Opaque key**, **Wrapping key**, and **Signing key** — the\n * same raw bytes imported as a `DigestKey` are cryptographically independent of\n * any other codec's key.\n */\nexport type DigestKey = {\n readonly [digestKeyBrand]: \"DigestKey\";\n};\n\ntype DigestKeyInternals = {\n hmacKey: webcrypto.CryptoKey;\n};\n\nconst internals = new WeakMap<DigestKey, DigestKeyInternals>();\n\n/**\n * Import raw operator key material into a {@link DigestKey} handle.\n *\n * Derives a single HMAC-SHA-256 key via HKDF under the domain-separation label\n * `@smonn/ids/digest/hmac`. Accepts 16, 24, or 32 bytes. To store or transport key\n * material, use {@link encodeDigestKey} / {@link decodeDigestKey}\n * (`\"hex\"` or `\"base64url\"` — not Crockford base32).\n *\n * @param bytes - 16, 24, or 32 raw key bytes.\n * @throws {IdsError} `invalid_key_length` if `bytes.length` is not 16, 24, or 32.\n */\nexport async function importDigestKey(bytes: Uint8Array): Promise<DigestKey> {\n assertValidKeyMaterialByteLength(bytes.length, \"digest\");\n const hmacKey = await deriveHmacKey(bytes);\n const key = Object.freeze({}) as DigestKey;\n internals.set(key, { hmacKey });\n return key;\n}\n\n/**\n * Encode raw digest operator key material for storage in env vars or secret managers.\n *\n * Supports `\"hex\"` (lowercase) and `\"base64url\"`. Output round-trips through\n * {@link decodeDigestKey} back to the original bytes.\n *\n * @throws {IdsError} `invalid_key_format` if `format` is not `\"hex\"` or `\"base64url\"`.\n * @throws {IdsError} `invalid_key_length` if `bytes.length` is not 16, 24, or 32.\n */\nexport function encodeDigestKey(bytes: Uint8Array, format: DigestKeyFormat): string {\n return encodeKeyMaterial(bytes, format, \"digest\", \"digest\");\n}\n\n/**\n * Decode key material emitted by {@link encodeDigestKey} back to raw bytes.\n *\n * The result can be passed directly to {@link importDigestKey}.\n *\n * @throws {IdsError} `invalid_key_format` if `format` is not `\"hex\"` or `\"base64url\"`.\n * @throws {IdsError} `invalid_key_encoding` if the string is malformed for its format.\n * @throws {IdsError} `invalid_key_length` if the decoded bytes are not 16, 24, or 32 bytes.\n */\nexport function decodeDigestKey(encoded: string, format: DigestKeyFormat): Uint8Array {\n return decodeKeyMaterial(encoded, format, \"digest\", \"digest\");\n}\n\n/**\n * Returns the derived HMAC webcrypto.CryptoKey held inside the handle.\n *\n * Intentional module-internal escape hatch for codec implementations.\n * Not re-exported from `@smonn/ids/digest`; external callers cannot reach this.\n */\nexport function getDigestKeyHmacKey(key: DigestKey): webcrypto.CryptoKey {\n const keyInternals = internals.get(key);\n /* v8 ignore next -- defensive guard; only reachable with a forged DigestKey handle */\n if (keyInternals === undefined) throw new Error(\"invalid digest key\");\n return keyInternals.hmacKey;\n}\n\nasync function deriveHmacKey(bytes: Uint8Array): Promise<webcrypto.CryptoKey> {\n const base = await crypto.subtle.importKey(\n \"raw\",\n bytes as Uint8Array<ArrayBuffer>,\n \"HKDF\",\n false,\n [\"deriveKey\"],\n );\n return crypto.subtle.deriveKey(\n { name: \"HKDF\", hash: \"SHA-256\", salt: new Uint8Array(), info: hmacInfo },\n base,\n { name: \"HMAC\", hash: \"SHA-256\", length: 256 },\n false,\n [\"sign\"],\n );\n}\n","import { validateBrand } from \"../_kernel/brand.js\";\nimport { IdsError, isIdsError, type IdsErrorCode } from \"../../error.js\";\nimport { createDigestLayoutOps } from \"./layout.js\";\nimport { registerBrand } from \"../_kernel/registry.js\";\nimport type { Id, JsonSchema, ParseResult, Prefix, StandardSchemaProps } from \"../../types.js\";\nimport { wireMethods } from \"../../wire/codec-shell.js\";\nimport {\n decodeDigestKey,\n encodeDigestKey,\n getDigestKeyHmacKey,\n importDigestKey,\n type DigestKey,\n type DigestKeyFormat,\n} from \"./key.js\";\n\n/** {@link IdsError} class, {@link isIdsError} type guard, and {@link IdsErrorCode} union — re-exported from `\"@smonn/ids\"` for convenience. */\nexport { IdsError, isIdsError, type IdsErrorCode };\nexport { decodeDigestKey, encodeDigestKey, importDigestKey, type DigestKey, type DigestKeyFormat };\n\n/**\n * Configuration options for a Digest codec instance.\n */\nexport type DigestOptions = {\n /**\n * Non-secret, required namespace. The same material under a different\n * `ns` yields a different ID, so one key can serve multiple unlinkable namespaces.\n * Must be non-empty and not whitespace-only.\n */\n ns: string;\n /**\n * Single operator digest key. The Digest codec holds exactly one key — there\n * is no keyring. Re-keying is a deliberate, breaking operator action.\n */\n key: DigestKey;\n /** If true, silences the duplicate-brand warning in non-production environments. */\n allowDuplicateBrand?: boolean;\n};\n\n/**\n * Codec returned by {@link createDigestId}.\n *\n * Maps caller **material** to a stable public ID under one **Digest key**:\n * the same material always yields the same ID, and the material cannot be\n * recovered from the ID (**equality leakage** is the intended property).\n *\n * - `digest` is async (WebCrypto HMAC).\n * - `is`, `parse`, `safeParse`, `toJsonSchema`, and `~standard` are synchronous\n * and require no key material — they validate prefix and base32 shape only.\n * - There is no reverse method (`unwrap`, `verify`, `extractTimestamp`) — the\n * codec is one-way by definition.\n */\nexport type DigestCodec<Brand extends string> = {\n /**\n * Digest `material` into a stable canonical {@link Id}.\n *\n * The same `(brand, ns, key, material)` tuple always returns the same ID.\n * Strings are UTF-8 encoded; byte arrays are used as-is.\n */\n digest(material: string | Uint8Array): Promise<Id<Brand>>;\n /** Strict type guard: `true` only for already-canonical `Id<Brand>` strings. */\n is(value: unknown): value is Id<Brand>;\n /** Normalise to canonical form, or throw on parse failure. */\n parse(value: unknown): Id<Brand>;\n /** Normalise to canonical form, or return `{ ok: false, error }`. */\n safeParse(value: unknown): ParseResult<Brand>;\n /** JSON Schema for the canonical wire form (`pattern` is canonical-only). */\n toJsonSchema(): JsonSchema;\n /** Standard Schema validate entry point. */\n readonly \"~standard\": StandardSchemaProps<Brand>;\n};\n\n/**\n * Construct a {@link DigestCodec} for `brand`.\n *\n * `opts.ns` is the required namespace — the same material under a\n * different `ns` yields a different ID. `opts.key` is the single operator\n * Digest key; there is no keyring.\n *\n * @example\n * ```ts\n * const key = await importDigestKey(new Uint8Array(32));\n * const idk = createDigestId(\"idk\", { ns: \"checkout\", key });\n *\n * const id = await idk.digest(\"order-123\"); // Id<\"idk\">\n * idk.is(id); // true\n * ```\n */\nexport function createDigestId<Brand extends string>(\n brand: Brand,\n opts: DigestOptions,\n): DigestCodec<Brand> {\n validateBrand(brand);\n registerBrand(brand, opts.allowDuplicateBrand);\n\n if (typeof opts.ns !== \"string\" || opts.ns.trim() === \"\") {\n throw new IdsError(\n \"invalid_namespace\",\n \"invalid namespace: ns must be a non-empty, non-whitespace string\",\n );\n }\n\n const hmacKey = getDigestKeyHmacKey(opts.key);\n const prefix: Prefix<Brand> = `${brand}_`;\n const wire = wireMethods(prefix);\n const layout = createDigestLayoutOps(prefix, brand, opts.ns, hmacKey);\n\n return {\n digest: layout.digest,\n is: wire.is,\n parse: wire.parse,\n safeParse: wire.safeParse,\n toJsonSchema: () => wire.toJsonSchema(brand, layout.exampleWireId()),\n \"~standard\": wire[\"~standard\"],\n };\n}\n"],"mappings":"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"}
|
package/dist/digest.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as IdsErrorCode, r as isIdsError, t as IdsError } from "./error-JIPylU_E.mjs";
|
|
2
2
|
import { a as StandardSchemaProps, i as ParseResult, n as JsonSchema, t as Id } from "./types-g7CiQDyE.mjs";
|
|
3
3
|
|
|
4
|
-
//#region src/digest
|
|
4
|
+
//#region src/codecs/digest/key.d.ts
|
|
5
5
|
/** Wire encoding for digest operator key material (not Crockford base32). */
|
|
6
6
|
type DigestKeyFormat = "hex" | "base64url";
|
|
7
7
|
declare const digestKeyBrand: unique symbol;
|
|
@@ -9,7 +9,7 @@ declare const digestKeyBrand: unique symbol;
|
|
|
9
9
|
* Opaque imported handle for one operator Digest key.
|
|
10
10
|
*
|
|
11
11
|
* Holds a single HMAC-SHA-256 key derived via HKDF under the domain-separation
|
|
12
|
-
* label
|
|
12
|
+
* label `@smonn/ids/digest/hmac`. The underlying `webcrypto.CryptoKey` is held internally and
|
|
13
13
|
* never exposed to callers. Obtain handles via {@link importDigestKey} and pass
|
|
14
14
|
* them to `createDigestId` as the `key` option.
|
|
15
15
|
*
|
|
@@ -28,7 +28,7 @@ type DigestKey = {
|
|
|
28
28
|
* Import raw operator key material into a {@link DigestKey} handle.
|
|
29
29
|
*
|
|
30
30
|
* Derives a single HMAC-SHA-256 key via HKDF under the domain-separation label
|
|
31
|
-
*
|
|
31
|
+
* `@smonn/ids/digest/hmac`. Accepts 16, 24, or 32 bytes. To store or transport key
|
|
32
32
|
* material, use {@link encodeDigestKey} / {@link decodeDigestKey}
|
|
33
33
|
* (`"hex"` or `"base64url"` — not Crockford base32).
|
|
34
34
|
*
|
|
@@ -57,7 +57,7 @@ declare function encodeDigestKey(bytes: Uint8Array, format: DigestKeyFormat): st
|
|
|
57
57
|
*/
|
|
58
58
|
declare function decodeDigestKey(encoded: string, format: DigestKeyFormat): Uint8Array;
|
|
59
59
|
//#endregion
|
|
60
|
-
//#region src/digest.d.ts
|
|
60
|
+
//#region src/codecs/digest/index.d.ts
|
|
61
61
|
/**
|
|
62
62
|
* Configuration options for a Digest codec instance.
|
|
63
63
|
*/
|
package/dist/digest.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"digest.d.mts","names":[],"sources":["../src/digest
|
|
1
|
+
{"version":3,"file":"digest.d.mts","names":[],"sources":["../src/codecs/digest/key.ts","../src/codecs/digest/index.ts"],"mappings":";;;;;KAQY,eAAA;AAAA,cAIE,cAAA;AAJd;;;;AAAY;AAA0B;;;;AAIxB;AAkBd;;;;AACY;AAoBZ;AA3CA,KAsBY,SAAA;EAAA,UACA,cAAA;AAAA;;;;;;;;;;AAoBsD;AAiBlE;iBAjBsB,eAAA,CAAgB,KAAA,EAAO,UAAA,GAAa,OAAA,CAAQ,SAAA;;;;;;;;AAiBP;AAa3D;iBAbgB,eAAA,CAAgB,KAAA,EAAO,UAAA,EAAY,MAAA,EAAQ,eAAA;;;;;;;;AAagB;;iBAA3D,eAAA,CAAgB,OAAA,UAAiB,MAAA,EAAQ,eAAA,GAAkB,UAAA;;;;;AAzE/D;KCcA,aAAA;EDVE;;;AAAA;AAkBd;ECFE,EAAA;;;ADGU;AAoBZ;EClBE,GAAA,EAAK,SAAA;EAEL,mBAAA;AAAA;;;;;;;;;ADgBgE;AAiBlE;;;;KCjBY,WAAA;;;;;ADiB+C;AAa3D;ECvBE,MAAA,CAAO,QAAA,WAAmB,UAAA,GAAa,OAAA,CAAQ,EAAA,CAAG,KAAA;EAElD,EAAA,CAAG,KAAA,YAAiB,KAAA,IAAS,EAAA,CAAG,KAAA;EAEhC,KAAA,CAAM,KAAA,YAAiB,EAAA,CAAG,KAAA;EAE1B,SAAA,CAAU,KAAA,YAAiB,WAAA,CAAY,KAAA,GDiBkC;ECfzE,YAAA,IAAgB,UAAA;WAEP,WAAA,EAAa,mBAAA,CAAoB,KAAA;AAAA;AA9C5C;;;;;;;;;AAaE;AAgBF;;;;;;AA7BA,iBAiEgB,cAAA,uBACd,KAAA,EAAO,KAAA,EACP,IAAA,EAAM,aAAA,GACL,WAAA,CAAY,KAAA"}
|
package/dist/digest.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { n as isIdsError, t as IdsError } from "./error-Cp5qYZcv.mjs";
|
|
2
|
-
import { i as importDigestKey, n as decodeDigestKey, r as encodeDigestKey, t as createDigestId } from "./digest-
|
|
2
|
+
import { i as importDigestKey, n as decodeDigestKey, r as encodeDigestKey, t as createDigestId } from "./digest-CknNw2wa.mjs";
|
|
3
3
|
export { IdsError, createDigestId, decodeDigestKey, encodeDigestKey, importDigestKey, isIdsError };
|
package/dist/drizzle.d.mts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { n as IdsErrorCode, r as isIdsError, t as IdsError } from "./error-JIPylU_E.mjs";
|
|
2
2
|
import { t as Id } from "./types-g7CiQDyE.mjs";
|
|
3
|
-
import { n as IdColumnCodec } from "./adapter-types-
|
|
3
|
+
import { n as IdColumnCodec } from "./adapter-types-CdYJM6Sf.mjs";
|
|
4
4
|
import { ConvertCustomConfig, PgCustomColumnBuilder } from "drizzle-orm/pg-core";
|
|
5
5
|
|
|
6
|
-
//#region src/drizzle.d.ts
|
|
6
|
+
//#region src/adapters/drizzle.d.ts
|
|
7
7
|
/**
|
|
8
8
|
* Drizzle custom column type that stores an `Id<Brand>` as a canonical `text` value.
|
|
9
9
|
*
|
package/dist/drizzle.d.mts.map
CHANGED
|
@@ -1 +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"}
|
|
1
|
+
{"version":3,"file":"drizzle.d.mts","names":[],"sources":["../src/adapters/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,7 +1,7 @@
|
|
|
1
1
|
import { n as isIdsError, t as IdsError } from "./error-Cp5qYZcv.mjs";
|
|
2
|
-
import { t as readIdColumn } from "./adapter-types-
|
|
2
|
+
import { t as readIdColumn } from "./adapter-types-7wWdELSh.mjs";
|
|
3
3
|
import { customType } from "drizzle-orm/pg-core";
|
|
4
|
-
//#region src/drizzle.ts
|
|
4
|
+
//#region src/adapters/drizzle.ts
|
|
5
5
|
/**
|
|
6
6
|
* Drizzle custom column type that stores an `Id<Brand>` as a canonical `text` value.
|
|
7
7
|
*
|