@cardanowall/sdk-ts 0.1.0 → 0.3.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 +14 -14
- package/dist/client/index.cjs +1621 -1538
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +52 -52
- package/dist/client/index.d.ts +52 -52
- package/dist/client/index.js +1620 -1537
- package/dist/client/index.js.map +1 -1
- package/dist/conformance/cli.cjs +2367 -2106
- package/dist/conformance/cli.cjs.map +1 -1
- package/dist/conformance/cli.js +2367 -2106
- package/dist/conformance/cli.js.map +1 -1
- package/dist/identity/index.cjs +219 -104
- package/dist/identity/index.cjs.map +1 -1
- package/dist/identity/index.d.cts +1 -1
- package/dist/identity/index.d.ts +1 -1
- package/dist/identity/index.js +219 -104
- package/dist/identity/index.js.map +1 -1
- package/dist/ids/index.cjs.map +1 -1
- package/dist/ids/index.js.map +1 -1
- package/dist/index.cjs +2808 -2530
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2805 -2527
- package/dist/index.js.map +1 -1
- package/dist/merkle/index.cjs +1 -1
- package/dist/merkle/index.cjs.map +1 -1
- package/dist/merkle/index.js +1 -1
- package/dist/merkle/index.js.map +1 -1
- package/dist/{types-BQMtbRCb.d.cts → types-DGsZTMuZ.d.cts} +6 -6
- package/dist/{types-BQMtbRCb.d.ts → types-DGsZTMuZ.d.ts} +6 -6
- package/dist/verifier/index.cjs +2368 -2107
- package/dist/verifier/index.cjs.map +1 -1
- package/dist/verifier/index.d.cts +3 -3
- package/dist/verifier/index.d.ts +3 -3
- package/dist/verifier/index.js +2369 -2108
- package/dist/verifier/index.js.map +1 -1
- package/package.json +8 -8
package/dist/ids/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ids/crockford-base32.ts","../../src/ids/prefixed-id.ts","../../src/ids/zod-schemas.ts"],"names":["z"],"mappings":"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","file":"index.cjs","sourcesContent":["// Crockford Base32 codec for 16-byte UUID payloads (yielding 26-char strings).\n//\n// Alphabet per https://www.crockford.com/base32.html — `0123456789ABCDEFGHJKMNPQRSTVWXYZ`\n// (32 symbols; the letters I, L, O, U are intentionally excluded for visual\n// disambiguation against digits and to avoid accidental profanity in\n// generated identifiers).\n//\n// Encoding: 16 raw bytes (128 bits) packs into exactly 26 base32 symbols\n// (130 bits with 2 trailing zero-padding bits we drop on encode and\n// reconstruct on decode). No `=` padding character is emitted — UUID payloads\n// are fixed-width.\n//\n// Decoding: case-insensitive (per Crockford spec); we also tolerate the\n// disambiguation map I/L → 1, O → 0. The encoded length MUST be 26 chars;\n// rejection is explicit (callers downstream feed the bytes back into a UUIDv7\n// validator anyway, so we surface the length problem at the codec boundary).\n\nconst ALPHABET = '0123456789abcdefghjkmnpqrstvwxyz';\n\n// 256-entry decode table indexed by lowercased ASCII char code. -1 = invalid.\n// We populate it once at module load.\nconst DECODE_TABLE: Int8Array = (() => {\n const table = new Int8Array(128).fill(-1);\n for (let i = 0; i < ALPHABET.length; i++) {\n const ch = ALPHABET.charCodeAt(i);\n table[ch] = i;\n // Uppercase variant (Crockford accepts case-insensitive input).\n const upper = String.fromCharCode(ch).toUpperCase().charCodeAt(0);\n table[upper] = i;\n }\n // Crockford disambiguation: I, L → 1; O → 0; U is reserved (always invalid).\n table['I'.charCodeAt(0)] = 1;\n table['i'.charCodeAt(0)] = 1;\n table['L'.charCodeAt(0)] = 1;\n table['l'.charCodeAt(0)] = 1;\n table['O'.charCodeAt(0)] = 0;\n table['o'.charCodeAt(0)] = 0;\n return table;\n})();\n\nexport const CROCKFORD_ENCODED_LENGTH_FOR_UUID = 26;\n\n/**\n * Encode `bytes.length` raw bytes as a lowercase Crockford base32 string.\n * Output length is `ceil(bytes.length * 8 / 5)` — no `=` padding character.\n * For 16-byte UUIDs this produces 26 chars; for 32-byte API-key secrets it\n * produces 52 chars (256 bits of entropy, matching the Stripe / OpenAI /\n * Anthropic secret-key entropy class).\n */\nexport function encodeBytesVariableLength(bytes: Uint8Array): string {\n let bits = 0;\n let bitCount = 0;\n let out = '';\n for (let i = 0; i < bytes.length; i++) {\n bits = (bits << 8) | bytes[i]!;\n bitCount += 8;\n while (bitCount >= 5) {\n bitCount -= 5;\n const idx = (bits >>> bitCount) & 0x1f;\n out += ALPHABET[idx];\n }\n }\n if (bitCount > 0) {\n const idx = (bits << (5 - bitCount)) & 0x1f;\n out += ALPHABET[idx];\n }\n return out;\n}\n\n/**\n * Encode 16 raw bytes (a UUID payload) as a 26-char lowercase Crockford\n * base32 string. Throws if the input is not exactly 16 bytes.\n */\nexport function encodeBytes(bytes: Uint8Array): string {\n if (bytes.length !== 16) {\n throw new Error(`crockford-base32: expected 16 bytes, got ${bytes.length}`);\n }\n // 16 bytes × 8 = 128 bits → 26 × 5 = 130 bits; we pad the input with 2 zero\n // bits on the right, which simply means we treat byte[15] as occupying the\n // top 8 bits of a 10-bit window for the final two symbols.\n return encodeBytesVariableLength(bytes);\n}\n\n/**\n * Decode a 26-char Crockford base32 string back to 16 raw bytes.\n * Case-insensitive; accepts the I/L → 1, O → 0 disambiguation mappings.\n * Throws on wrong length, invalid characters, or non-zero pad bits.\n */\nexport function decodeBytes(encoded: string): Uint8Array {\n if (encoded.length !== CROCKFORD_ENCODED_LENGTH_FOR_UUID) {\n throw new Error(\n `crockford-base32: expected ${CROCKFORD_ENCODED_LENGTH_FOR_UUID}-char input, got ${encoded.length}`,\n );\n }\n const out = new Uint8Array(16);\n let bits = 0;\n let bitCount = 0;\n let outIdx = 0;\n for (let i = 0; i < encoded.length; i++) {\n const code = encoded.charCodeAt(i);\n const value = code < 128 ? DECODE_TABLE[code]! : -1;\n if (value < 0) {\n throw new Error(\n `crockford-base32: invalid character ${JSON.stringify(encoded[i])} at index ${i}`,\n );\n }\n bits = (bits << 5) | value;\n bitCount += 5;\n if (bitCount >= 8) {\n bitCount -= 8;\n out[outIdx++] = (bits >>> bitCount) & 0xff;\n }\n }\n // After 26 symbols × 5 = 130 bits consumed and 16 bytes × 8 = 128 bits\n // emitted, there should be exactly 2 trailing zero pad bits. Anything else\n // means the input wasn't produced by our encoder (or was tampered with).\n if (bitCount !== 2 || (bits & 0x3) !== 0) {\n throw new Error('crockford-base32: non-zero pad bits at end of input');\n }\n return out;\n}\n","// Stripe-style prefixed resource IDs. The Postgres column stays UUIDv7; the\n// wire form is `<prefix>_<26-char-crockford-base32>`. This module is the\n// only place that knows the byte-level encoding — everything else (Zod\n// schemas, route handlers, SDK types) consumes the helpers below.\n//\n// We intentionally do NOT bind the helpers to a closed prefix enum here: the\n// SDK is published as a versioned dependency and adding a new resource type\n// (e.g. `topup_*`) must not require an SDK bump just to validate the wire.\n// The helpers therefore take the prefix as a generic string parameter; the\n// per-resource Zod schemas in `./zod-schemas.ts` are the place to enumerate\n// the known prefixes for validation purposes.\n\nimport { decodeBytes, encodeBytes } from './crockford-base32';\n\n/**\n * Branded string type — `${prefix}_<26-base32-chars>`. The phantom `__brand`\n * field gives TypeScript a way to refuse a bare string at API boundaries\n * (`function fn(id: PrefixedId<'poe'>)`) while staying ABI-compatible with\n * `string` on the wire and in JSON serialisation.\n */\nexport type PrefixedId<P extends string> = `${P}_${string}` & { readonly __brand: P };\n\n// 32-char hex UUID without separators is what the encoder converts to bytes.\nconst UUID_RE_BYTES = /^[0-9a-f]{32}$/;\n\nfunction uuidStringToBytes(uuid: string): Uint8Array {\n // Accept canonical 8-4-4-4-12 hyphenated form (case-insensitive) only —\n // this is what every UUIDv4/v7 library produces and what Postgres returns\n // for the UUIDv7 columns. Anything else (no hyphens, wrong width, non-hex)\n // is rejected.\n const hex = uuid.replace(/-/g, '').toLowerCase();\n if (!UUID_RE_BYTES.test(hex) || uuid.replace(/[^-]/g, '').length !== 4) {\n throw new Error(`prefixed-id: not a canonical hyphenated UUID: ${JSON.stringify(uuid)}`);\n }\n const out = new Uint8Array(16);\n for (let i = 0; i < 16; i++) {\n out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);\n }\n return out;\n}\n\nfunction bytesToUuidString(bytes: Uint8Array): string {\n if (bytes.length !== 16) {\n throw new Error(`prefixed-id: expected 16 decoded bytes, got ${bytes.length}`);\n }\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\n/**\n * Encode a bare canonical UUID string (8-4-4-4-12 hyphenated) into the\n * Stripe-style wire form `${prefix}_<crockford>`.\n */\nexport function encodePrefixedId<P extends string>(prefix: P, uuid: string): PrefixedId<P> {\n const bytes = uuidStringToBytes(uuid);\n const encoded = encodeBytes(bytes);\n return `${prefix}_${encoded}` as PrefixedId<P>;\n}\n\n/**\n * Decode a wire-format prefixed id back to the bare canonical UUID string.\n * Throws when the prefix does not match, the body is not 26 base32 chars,\n * or the encoded payload is malformed.\n */\nexport function decodePrefixedId<P extends string>(prefix: P, encoded: string): string {\n if (typeof encoded !== 'string') {\n throw new Error(`prefixed-id: expected string, got ${typeof encoded}`);\n }\n const sep = encoded.indexOf('_');\n if (sep < 0) {\n throw new Error(`prefixed-id: missing prefix separator in ${JSON.stringify(encoded)}`);\n }\n const actualPrefix = encoded.slice(0, sep);\n if (actualPrefix !== prefix) {\n throw new Error(\n `prefixed-id: expected prefix ${JSON.stringify(prefix)}, got ${JSON.stringify(actualPrefix)}`,\n );\n }\n const body = encoded.slice(sep + 1);\n const bytes = decodeBytes(body);\n return bytesToUuidString(bytes);\n}\n\n/**\n * Type guard. Cheap-check: matches the prefix and the lowercase Crockford\n * length, but does NOT validate the payload bytes round-trip. Use\n * `decodePrefixedId` when a full validation is required.\n */\nexport function isPrefixedId<P extends string>(\n prefix: P,\n candidate: unknown,\n): candidate is PrefixedId<P> {\n if (typeof candidate !== 'string') return false;\n if (!candidate.startsWith(`${prefix}_`)) return false;\n const body = candidate.slice(prefix.length + 1);\n if (body.length !== 26) return false;\n // Strict Crockford alphabet — no I, L, O, U; lowercase only on the wire.\n return /^[0-9a-hjkmnp-tv-z]{26}$/.test(body);\n}\n","// Zod schema gating the CIP-309 record id at every parse boundary (HTTP route\n// handlers, SDK input validation, OpenAPI registration).\n//\n// The regex is the strict Crockford-32 alphabet (lowercase only on the wire,\n// no I/L/O/U). This is stricter than `[0-9a-z]{26}` because it catches the\n// most common typo classes (`poe_…ol1u…`) at the parser rather than letting\n// them through to the decoder for a confusing `non-zero pad bits` error.\n\nimport { z } from 'zod';\n\nconst CROCKFORD_LOWER = '[0-9a-hjkmnp-tv-z]{26}';\n\nexport const POE_ID_PREFIX = 'poe' as const;\n\nexport const PoeIdSchema = z\n .string()\n .regex(new RegExp(`^${POE_ID_PREFIX}_${CROCKFORD_LOWER}$`), 'invalid poe id');\n\nexport const POE_ID_PATTERN = `^${POE_ID_PREFIX}_${CROCKFORD_LOWER}$`;\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/ids/crockford-base32.ts","../../src/ids/prefixed-id.ts","../../src/ids/zod-schemas.ts"],"names":["z"],"mappings":"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","file":"index.cjs","sourcesContent":["// Crockford Base32 codec for 16-byte UUID payloads (yielding 26-char strings).\n//\n// Alphabet per https://www.crockford.com/base32.html — `0123456789ABCDEFGHJKMNPQRSTVWXYZ`\n// (32 symbols; the letters I, L, O, U are intentionally excluded for visual\n// disambiguation against digits and to avoid accidental profanity in\n// generated identifiers).\n//\n// Encoding: 16 raw bytes (128 bits) packs into exactly 26 base32 symbols\n// (130 bits with 2 trailing zero-padding bits we drop on encode and\n// reconstruct on decode). No `=` padding character is emitted — UUID payloads\n// are fixed-width.\n//\n// Decoding: case-insensitive (per Crockford spec); we also tolerate the\n// disambiguation map I/L → 1, O → 0. The encoded length MUST be 26 chars;\n// rejection is explicit (callers downstream feed the bytes back into a UUIDv7\n// validator anyway, so we surface the length problem at the codec boundary).\n\nconst ALPHABET = '0123456789abcdefghjkmnpqrstvwxyz';\n\n// 256-entry decode table indexed by lowercased ASCII char code. -1 = invalid.\n// We populate it once at module load.\nconst DECODE_TABLE: Int8Array = (() => {\n const table = new Int8Array(128).fill(-1);\n for (let i = 0; i < ALPHABET.length; i++) {\n const ch = ALPHABET.charCodeAt(i);\n table[ch] = i;\n // Uppercase variant (Crockford accepts case-insensitive input).\n const upper = String.fromCharCode(ch).toUpperCase().charCodeAt(0);\n table[upper] = i;\n }\n // Crockford disambiguation: I, L → 1; O → 0; U is reserved (always invalid).\n table['I'.charCodeAt(0)] = 1;\n table['i'.charCodeAt(0)] = 1;\n table['L'.charCodeAt(0)] = 1;\n table['l'.charCodeAt(0)] = 1;\n table['O'.charCodeAt(0)] = 0;\n table['o'.charCodeAt(0)] = 0;\n return table;\n})();\n\nexport const CROCKFORD_ENCODED_LENGTH_FOR_UUID = 26;\n\n/**\n * Encode `bytes.length` raw bytes as a lowercase Crockford base32 string.\n * Output length is `ceil(bytes.length * 8 / 5)` — no `=` padding character.\n * For 16-byte UUIDs this produces 26 chars; for 32-byte API-key secrets it\n * produces 52 chars (256 bits of entropy, matching the Stripe / OpenAI /\n * Anthropic secret-key entropy class).\n */\nexport function encodeBytesVariableLength(bytes: Uint8Array): string {\n let bits = 0;\n let bitCount = 0;\n let out = '';\n for (let i = 0; i < bytes.length; i++) {\n bits = (bits << 8) | bytes[i]!;\n bitCount += 8;\n while (bitCount >= 5) {\n bitCount -= 5;\n const idx = (bits >>> bitCount) & 0x1f;\n out += ALPHABET[idx];\n }\n }\n if (bitCount > 0) {\n const idx = (bits << (5 - bitCount)) & 0x1f;\n out += ALPHABET[idx];\n }\n return out;\n}\n\n/**\n * Encode 16 raw bytes (a UUID payload) as a 26-char lowercase Crockford\n * base32 string. Throws if the input is not exactly 16 bytes.\n */\nexport function encodeBytes(bytes: Uint8Array): string {\n if (bytes.length !== 16) {\n throw new Error(`crockford-base32: expected 16 bytes, got ${bytes.length}`);\n }\n // 16 bytes × 8 = 128 bits → 26 × 5 = 130 bits; we pad the input with 2 zero\n // bits on the right, which simply means we treat byte[15] as occupying the\n // top 8 bits of a 10-bit window for the final two symbols.\n return encodeBytesVariableLength(bytes);\n}\n\n/**\n * Decode a 26-char Crockford base32 string back to 16 raw bytes.\n * Case-insensitive; accepts the I/L → 1, O → 0 disambiguation mappings.\n * Throws on wrong length, invalid characters, or non-zero pad bits.\n */\nexport function decodeBytes(encoded: string): Uint8Array {\n if (encoded.length !== CROCKFORD_ENCODED_LENGTH_FOR_UUID) {\n throw new Error(\n `crockford-base32: expected ${CROCKFORD_ENCODED_LENGTH_FOR_UUID}-char input, got ${encoded.length}`,\n );\n }\n const out = new Uint8Array(16);\n let bits = 0;\n let bitCount = 0;\n let outIdx = 0;\n for (let i = 0; i < encoded.length; i++) {\n const code = encoded.charCodeAt(i);\n const value = code < 128 ? DECODE_TABLE[code]! : -1;\n if (value < 0) {\n throw new Error(\n `crockford-base32: invalid character ${JSON.stringify(encoded[i])} at index ${i}`,\n );\n }\n bits = (bits << 5) | value;\n bitCount += 5;\n if (bitCount >= 8) {\n bitCount -= 8;\n out[outIdx++] = (bits >>> bitCount) & 0xff;\n }\n }\n // After 26 symbols × 5 = 130 bits consumed and 16 bytes × 8 = 128 bits\n // emitted, there should be exactly 2 trailing zero pad bits. Anything else\n // means the input wasn't produced by our encoder (or was tampered with).\n if (bitCount !== 2 || (bits & 0x3) !== 0) {\n throw new Error('crockford-base32: non-zero pad bits at end of input');\n }\n return out;\n}\n","// Stripe-style prefixed resource IDs. The Postgres column stays UUIDv7; the\n// wire form is `<prefix>_<26-char-crockford-base32>`. This module is the\n// only place that knows the byte-level encoding — everything else (Zod\n// schemas, route handlers, SDK types) consumes the helpers below.\n//\n// We intentionally do NOT bind the helpers to a closed prefix enum here: the\n// SDK is published as a versioned dependency and adding a new resource type\n// (e.g. `topup_*`) must not require an SDK bump just to validate the wire.\n// The helpers therefore take the prefix as a generic string parameter; the\n// per-resource Zod schemas in `./zod-schemas.ts` are the place to enumerate\n// the known prefixes for validation purposes.\n\nimport { decodeBytes, encodeBytes } from './crockford-base32';\n\n/**\n * Branded string type — `${prefix}_<26-base32-chars>`. The phantom `__brand`\n * field gives TypeScript a way to refuse a bare string at API boundaries\n * (`function fn(id: PrefixedId<'poe'>)`) while staying ABI-compatible with\n * `string` on the wire and in JSON serialisation.\n */\nexport type PrefixedId<P extends string> = `${P}_${string}` & { readonly __brand: P };\n\n// 32-char hex UUID without separators is what the encoder converts to bytes.\nconst UUID_RE_BYTES = /^[0-9a-f]{32}$/;\n\nfunction uuidStringToBytes(uuid: string): Uint8Array {\n // Accept canonical 8-4-4-4-12 hyphenated form (case-insensitive) only —\n // this is what every UUIDv4/v7 library produces and what Postgres returns\n // for the UUIDv7 columns. Anything else (no hyphens, wrong width, non-hex)\n // is rejected.\n const hex = uuid.replace(/-/g, '').toLowerCase();\n if (!UUID_RE_BYTES.test(hex) || uuid.replace(/[^-]/g, '').length !== 4) {\n throw new Error(`prefixed-id: not a canonical hyphenated UUID: ${JSON.stringify(uuid)}`);\n }\n const out = new Uint8Array(16);\n for (let i = 0; i < 16; i++) {\n out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);\n }\n return out;\n}\n\nfunction bytesToUuidString(bytes: Uint8Array): string {\n if (bytes.length !== 16) {\n throw new Error(`prefixed-id: expected 16 decoded bytes, got ${bytes.length}`);\n }\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\n/**\n * Encode a bare canonical UUID string (8-4-4-4-12 hyphenated) into the\n * Stripe-style wire form `${prefix}_<crockford>`.\n */\nexport function encodePrefixedId<P extends string>(prefix: P, uuid: string): PrefixedId<P> {\n const bytes = uuidStringToBytes(uuid);\n const encoded = encodeBytes(bytes);\n return `${prefix}_${encoded}` as PrefixedId<P>;\n}\n\n/**\n * Decode a wire-format prefixed id back to the bare canonical UUID string.\n * Throws when the prefix does not match, the body is not 26 base32 chars,\n * or the encoded payload is malformed.\n */\nexport function decodePrefixedId<P extends string>(prefix: P, encoded: string): string {\n if (typeof encoded !== 'string') {\n throw new Error(`prefixed-id: expected string, got ${typeof encoded}`);\n }\n const sep = encoded.indexOf('_');\n if (sep < 0) {\n throw new Error(`prefixed-id: missing prefix separator in ${JSON.stringify(encoded)}`);\n }\n const actualPrefix = encoded.slice(0, sep);\n if (actualPrefix !== prefix) {\n throw new Error(\n `prefixed-id: expected prefix ${JSON.stringify(prefix)}, got ${JSON.stringify(actualPrefix)}`,\n );\n }\n const body = encoded.slice(sep + 1);\n const bytes = decodeBytes(body);\n return bytesToUuidString(bytes);\n}\n\n/**\n * Type guard. Cheap-check: matches the prefix and the lowercase Crockford\n * length, but does NOT validate the payload bytes round-trip. Use\n * `decodePrefixedId` when a full validation is required.\n */\nexport function isPrefixedId<P extends string>(\n prefix: P,\n candidate: unknown,\n): candidate is PrefixedId<P> {\n if (typeof candidate !== 'string') return false;\n if (!candidate.startsWith(`${prefix}_`)) return false;\n const body = candidate.slice(prefix.length + 1);\n if (body.length !== 26) return false;\n // Strict Crockford alphabet — no I, L, O, U; lowercase only on the wire.\n return /^[0-9a-hjkmnp-tv-z]{26}$/.test(body);\n}\n","// Zod schema gating the Label 309 record id at every parse boundary (HTTP route\n// handlers, SDK input validation, OpenAPI registration).\n//\n// The regex is the strict Crockford-32 alphabet (lowercase only on the wire,\n// no I/L/O/U). This is stricter than `[0-9a-z]{26}` because it catches the\n// most common typo classes (`poe_…ol1u…`) at the parser rather than letting\n// them through to the decoder for a confusing `non-zero pad bits` error.\n\nimport { z } from 'zod';\n\nconst CROCKFORD_LOWER = '[0-9a-hjkmnp-tv-z]{26}';\n\nexport const POE_ID_PREFIX = 'poe' as const;\n\nexport const PoeIdSchema = z\n .string()\n .regex(new RegExp(`^${POE_ID_PREFIX}_${CROCKFORD_LOWER}$`), 'invalid poe id');\n\nexport const POE_ID_PATTERN = `^${POE_ID_PREFIX}_${CROCKFORD_LOWER}$`;\n"]}
|
package/dist/ids/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ids/crockford-base32.ts","../../src/ids/prefixed-id.ts","../../src/ids/zod-schemas.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// Crockford Base32 codec for 16-byte UUID payloads (yielding 26-char strings).\n//\n// Alphabet per https://www.crockford.com/base32.html — `0123456789ABCDEFGHJKMNPQRSTVWXYZ`\n// (32 symbols; the letters I, L, O, U are intentionally excluded for visual\n// disambiguation against digits and to avoid accidental profanity in\n// generated identifiers).\n//\n// Encoding: 16 raw bytes (128 bits) packs into exactly 26 base32 symbols\n// (130 bits with 2 trailing zero-padding bits we drop on encode and\n// reconstruct on decode). No `=` padding character is emitted — UUID payloads\n// are fixed-width.\n//\n// Decoding: case-insensitive (per Crockford spec); we also tolerate the\n// disambiguation map I/L → 1, O → 0. The encoded length MUST be 26 chars;\n// rejection is explicit (callers downstream feed the bytes back into a UUIDv7\n// validator anyway, so we surface the length problem at the codec boundary).\n\nconst ALPHABET = '0123456789abcdefghjkmnpqrstvwxyz';\n\n// 256-entry decode table indexed by lowercased ASCII char code. -1 = invalid.\n// We populate it once at module load.\nconst DECODE_TABLE: Int8Array = (() => {\n const table = new Int8Array(128).fill(-1);\n for (let i = 0; i < ALPHABET.length; i++) {\n const ch = ALPHABET.charCodeAt(i);\n table[ch] = i;\n // Uppercase variant (Crockford accepts case-insensitive input).\n const upper = String.fromCharCode(ch).toUpperCase().charCodeAt(0);\n table[upper] = i;\n }\n // Crockford disambiguation: I, L → 1; O → 0; U is reserved (always invalid).\n table['I'.charCodeAt(0)] = 1;\n table['i'.charCodeAt(0)] = 1;\n table['L'.charCodeAt(0)] = 1;\n table['l'.charCodeAt(0)] = 1;\n table['O'.charCodeAt(0)] = 0;\n table['o'.charCodeAt(0)] = 0;\n return table;\n})();\n\nexport const CROCKFORD_ENCODED_LENGTH_FOR_UUID = 26;\n\n/**\n * Encode `bytes.length` raw bytes as a lowercase Crockford base32 string.\n * Output length is `ceil(bytes.length * 8 / 5)` — no `=` padding character.\n * For 16-byte UUIDs this produces 26 chars; for 32-byte API-key secrets it\n * produces 52 chars (256 bits of entropy, matching the Stripe / OpenAI /\n * Anthropic secret-key entropy class).\n */\nexport function encodeBytesVariableLength(bytes: Uint8Array): string {\n let bits = 0;\n let bitCount = 0;\n let out = '';\n for (let i = 0; i < bytes.length; i++) {\n bits = (bits << 8) | bytes[i]!;\n bitCount += 8;\n while (bitCount >= 5) {\n bitCount -= 5;\n const idx = (bits >>> bitCount) & 0x1f;\n out += ALPHABET[idx];\n }\n }\n if (bitCount > 0) {\n const idx = (bits << (5 - bitCount)) & 0x1f;\n out += ALPHABET[idx];\n }\n return out;\n}\n\n/**\n * Encode 16 raw bytes (a UUID payload) as a 26-char lowercase Crockford\n * base32 string. Throws if the input is not exactly 16 bytes.\n */\nexport function encodeBytes(bytes: Uint8Array): string {\n if (bytes.length !== 16) {\n throw new Error(`crockford-base32: expected 16 bytes, got ${bytes.length}`);\n }\n // 16 bytes × 8 = 128 bits → 26 × 5 = 130 bits; we pad the input with 2 zero\n // bits on the right, which simply means we treat byte[15] as occupying the\n // top 8 bits of a 10-bit window for the final two symbols.\n return encodeBytesVariableLength(bytes);\n}\n\n/**\n * Decode a 26-char Crockford base32 string back to 16 raw bytes.\n * Case-insensitive; accepts the I/L → 1, O → 0 disambiguation mappings.\n * Throws on wrong length, invalid characters, or non-zero pad bits.\n */\nexport function decodeBytes(encoded: string): Uint8Array {\n if (encoded.length !== CROCKFORD_ENCODED_LENGTH_FOR_UUID) {\n throw new Error(\n `crockford-base32: expected ${CROCKFORD_ENCODED_LENGTH_FOR_UUID}-char input, got ${encoded.length}`,\n );\n }\n const out = new Uint8Array(16);\n let bits = 0;\n let bitCount = 0;\n let outIdx = 0;\n for (let i = 0; i < encoded.length; i++) {\n const code = encoded.charCodeAt(i);\n const value = code < 128 ? DECODE_TABLE[code]! : -1;\n if (value < 0) {\n throw new Error(\n `crockford-base32: invalid character ${JSON.stringify(encoded[i])} at index ${i}`,\n );\n }\n bits = (bits << 5) | value;\n bitCount += 5;\n if (bitCount >= 8) {\n bitCount -= 8;\n out[outIdx++] = (bits >>> bitCount) & 0xff;\n }\n }\n // After 26 symbols × 5 = 130 bits consumed and 16 bytes × 8 = 128 bits\n // emitted, there should be exactly 2 trailing zero pad bits. Anything else\n // means the input wasn't produced by our encoder (or was tampered with).\n if (bitCount !== 2 || (bits & 0x3) !== 0) {\n throw new Error('crockford-base32: non-zero pad bits at end of input');\n }\n return out;\n}\n","// Stripe-style prefixed resource IDs. The Postgres column stays UUIDv7; the\n// wire form is `<prefix>_<26-char-crockford-base32>`. This module is the\n// only place that knows the byte-level encoding — everything else (Zod\n// schemas, route handlers, SDK types) consumes the helpers below.\n//\n// We intentionally do NOT bind the helpers to a closed prefix enum here: the\n// SDK is published as a versioned dependency and adding a new resource type\n// (e.g. `topup_*`) must not require an SDK bump just to validate the wire.\n// The helpers therefore take the prefix as a generic string parameter; the\n// per-resource Zod schemas in `./zod-schemas.ts` are the place to enumerate\n// the known prefixes for validation purposes.\n\nimport { decodeBytes, encodeBytes } from './crockford-base32';\n\n/**\n * Branded string type — `${prefix}_<26-base32-chars>`. The phantom `__brand`\n * field gives TypeScript a way to refuse a bare string at API boundaries\n * (`function fn(id: PrefixedId<'poe'>)`) while staying ABI-compatible with\n * `string` on the wire and in JSON serialisation.\n */\nexport type PrefixedId<P extends string> = `${P}_${string}` & { readonly __brand: P };\n\n// 32-char hex UUID without separators is what the encoder converts to bytes.\nconst UUID_RE_BYTES = /^[0-9a-f]{32}$/;\n\nfunction uuidStringToBytes(uuid: string): Uint8Array {\n // Accept canonical 8-4-4-4-12 hyphenated form (case-insensitive) only —\n // this is what every UUIDv4/v7 library produces and what Postgres returns\n // for the UUIDv7 columns. Anything else (no hyphens, wrong width, non-hex)\n // is rejected.\n const hex = uuid.replace(/-/g, '').toLowerCase();\n if (!UUID_RE_BYTES.test(hex) || uuid.replace(/[^-]/g, '').length !== 4) {\n throw new Error(`prefixed-id: not a canonical hyphenated UUID: ${JSON.stringify(uuid)}`);\n }\n const out = new Uint8Array(16);\n for (let i = 0; i < 16; i++) {\n out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);\n }\n return out;\n}\n\nfunction bytesToUuidString(bytes: Uint8Array): string {\n if (bytes.length !== 16) {\n throw new Error(`prefixed-id: expected 16 decoded bytes, got ${bytes.length}`);\n }\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\n/**\n * Encode a bare canonical UUID string (8-4-4-4-12 hyphenated) into the\n * Stripe-style wire form `${prefix}_<crockford>`.\n */\nexport function encodePrefixedId<P extends string>(prefix: P, uuid: string): PrefixedId<P> {\n const bytes = uuidStringToBytes(uuid);\n const encoded = encodeBytes(bytes);\n return `${prefix}_${encoded}` as PrefixedId<P>;\n}\n\n/**\n * Decode a wire-format prefixed id back to the bare canonical UUID string.\n * Throws when the prefix does not match, the body is not 26 base32 chars,\n * or the encoded payload is malformed.\n */\nexport function decodePrefixedId<P extends string>(prefix: P, encoded: string): string {\n if (typeof encoded !== 'string') {\n throw new Error(`prefixed-id: expected string, got ${typeof encoded}`);\n }\n const sep = encoded.indexOf('_');\n if (sep < 0) {\n throw new Error(`prefixed-id: missing prefix separator in ${JSON.stringify(encoded)}`);\n }\n const actualPrefix = encoded.slice(0, sep);\n if (actualPrefix !== prefix) {\n throw new Error(\n `prefixed-id: expected prefix ${JSON.stringify(prefix)}, got ${JSON.stringify(actualPrefix)}`,\n );\n }\n const body = encoded.slice(sep + 1);\n const bytes = decodeBytes(body);\n return bytesToUuidString(bytes);\n}\n\n/**\n * Type guard. Cheap-check: matches the prefix and the lowercase Crockford\n * length, but does NOT validate the payload bytes round-trip. Use\n * `decodePrefixedId` when a full validation is required.\n */\nexport function isPrefixedId<P extends string>(\n prefix: P,\n candidate: unknown,\n): candidate is PrefixedId<P> {\n if (typeof candidate !== 'string') return false;\n if (!candidate.startsWith(`${prefix}_`)) return false;\n const body = candidate.slice(prefix.length + 1);\n if (body.length !== 26) return false;\n // Strict Crockford alphabet — no I, L, O, U; lowercase only on the wire.\n return /^[0-9a-hjkmnp-tv-z]{26}$/.test(body);\n}\n","// Zod schema gating the CIP-309 record id at every parse boundary (HTTP route\n// handlers, SDK input validation, OpenAPI registration).\n//\n// The regex is the strict Crockford-32 alphabet (lowercase only on the wire,\n// no I/L/O/U). This is stricter than `[0-9a-z]{26}` because it catches the\n// most common typo classes (`poe_…ol1u…`) at the parser rather than letting\n// them through to the decoder for a confusing `non-zero pad bits` error.\n\nimport { z } from 'zod';\n\nconst CROCKFORD_LOWER = '[0-9a-hjkmnp-tv-z]{26}';\n\nexport const POE_ID_PREFIX = 'poe' as const;\n\nexport const PoeIdSchema = z\n .string()\n .regex(new RegExp(`^${POE_ID_PREFIX}_${CROCKFORD_LOWER}$`), 'invalid poe id');\n\nexport const POE_ID_PATTERN = `^${POE_ID_PREFIX}_${CROCKFORD_LOWER}$`;\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/ids/crockford-base32.ts","../../src/ids/prefixed-id.ts","../../src/ids/zod-schemas.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// Crockford Base32 codec for 16-byte UUID payloads (yielding 26-char strings).\n//\n// Alphabet per https://www.crockford.com/base32.html — `0123456789ABCDEFGHJKMNPQRSTVWXYZ`\n// (32 symbols; the letters I, L, O, U are intentionally excluded for visual\n// disambiguation against digits and to avoid accidental profanity in\n// generated identifiers).\n//\n// Encoding: 16 raw bytes (128 bits) packs into exactly 26 base32 symbols\n// (130 bits with 2 trailing zero-padding bits we drop on encode and\n// reconstruct on decode). No `=` padding character is emitted — UUID payloads\n// are fixed-width.\n//\n// Decoding: case-insensitive (per Crockford spec); we also tolerate the\n// disambiguation map I/L → 1, O → 0. The encoded length MUST be 26 chars;\n// rejection is explicit (callers downstream feed the bytes back into a UUIDv7\n// validator anyway, so we surface the length problem at the codec boundary).\n\nconst ALPHABET = '0123456789abcdefghjkmnpqrstvwxyz';\n\n// 256-entry decode table indexed by lowercased ASCII char code. -1 = invalid.\n// We populate it once at module load.\nconst DECODE_TABLE: Int8Array = (() => {\n const table = new Int8Array(128).fill(-1);\n for (let i = 0; i < ALPHABET.length; i++) {\n const ch = ALPHABET.charCodeAt(i);\n table[ch] = i;\n // Uppercase variant (Crockford accepts case-insensitive input).\n const upper = String.fromCharCode(ch).toUpperCase().charCodeAt(0);\n table[upper] = i;\n }\n // Crockford disambiguation: I, L → 1; O → 0; U is reserved (always invalid).\n table['I'.charCodeAt(0)] = 1;\n table['i'.charCodeAt(0)] = 1;\n table['L'.charCodeAt(0)] = 1;\n table['l'.charCodeAt(0)] = 1;\n table['O'.charCodeAt(0)] = 0;\n table['o'.charCodeAt(0)] = 0;\n return table;\n})();\n\nexport const CROCKFORD_ENCODED_LENGTH_FOR_UUID = 26;\n\n/**\n * Encode `bytes.length` raw bytes as a lowercase Crockford base32 string.\n * Output length is `ceil(bytes.length * 8 / 5)` — no `=` padding character.\n * For 16-byte UUIDs this produces 26 chars; for 32-byte API-key secrets it\n * produces 52 chars (256 bits of entropy, matching the Stripe / OpenAI /\n * Anthropic secret-key entropy class).\n */\nexport function encodeBytesVariableLength(bytes: Uint8Array): string {\n let bits = 0;\n let bitCount = 0;\n let out = '';\n for (let i = 0; i < bytes.length; i++) {\n bits = (bits << 8) | bytes[i]!;\n bitCount += 8;\n while (bitCount >= 5) {\n bitCount -= 5;\n const idx = (bits >>> bitCount) & 0x1f;\n out += ALPHABET[idx];\n }\n }\n if (bitCount > 0) {\n const idx = (bits << (5 - bitCount)) & 0x1f;\n out += ALPHABET[idx];\n }\n return out;\n}\n\n/**\n * Encode 16 raw bytes (a UUID payload) as a 26-char lowercase Crockford\n * base32 string. Throws if the input is not exactly 16 bytes.\n */\nexport function encodeBytes(bytes: Uint8Array): string {\n if (bytes.length !== 16) {\n throw new Error(`crockford-base32: expected 16 bytes, got ${bytes.length}`);\n }\n // 16 bytes × 8 = 128 bits → 26 × 5 = 130 bits; we pad the input with 2 zero\n // bits on the right, which simply means we treat byte[15] as occupying the\n // top 8 bits of a 10-bit window for the final two symbols.\n return encodeBytesVariableLength(bytes);\n}\n\n/**\n * Decode a 26-char Crockford base32 string back to 16 raw bytes.\n * Case-insensitive; accepts the I/L → 1, O → 0 disambiguation mappings.\n * Throws on wrong length, invalid characters, or non-zero pad bits.\n */\nexport function decodeBytes(encoded: string): Uint8Array {\n if (encoded.length !== CROCKFORD_ENCODED_LENGTH_FOR_UUID) {\n throw new Error(\n `crockford-base32: expected ${CROCKFORD_ENCODED_LENGTH_FOR_UUID}-char input, got ${encoded.length}`,\n );\n }\n const out = new Uint8Array(16);\n let bits = 0;\n let bitCount = 0;\n let outIdx = 0;\n for (let i = 0; i < encoded.length; i++) {\n const code = encoded.charCodeAt(i);\n const value = code < 128 ? DECODE_TABLE[code]! : -1;\n if (value < 0) {\n throw new Error(\n `crockford-base32: invalid character ${JSON.stringify(encoded[i])} at index ${i}`,\n );\n }\n bits = (bits << 5) | value;\n bitCount += 5;\n if (bitCount >= 8) {\n bitCount -= 8;\n out[outIdx++] = (bits >>> bitCount) & 0xff;\n }\n }\n // After 26 symbols × 5 = 130 bits consumed and 16 bytes × 8 = 128 bits\n // emitted, there should be exactly 2 trailing zero pad bits. Anything else\n // means the input wasn't produced by our encoder (or was tampered with).\n if (bitCount !== 2 || (bits & 0x3) !== 0) {\n throw new Error('crockford-base32: non-zero pad bits at end of input');\n }\n return out;\n}\n","// Stripe-style prefixed resource IDs. The Postgres column stays UUIDv7; the\n// wire form is `<prefix>_<26-char-crockford-base32>`. This module is the\n// only place that knows the byte-level encoding — everything else (Zod\n// schemas, route handlers, SDK types) consumes the helpers below.\n//\n// We intentionally do NOT bind the helpers to a closed prefix enum here: the\n// SDK is published as a versioned dependency and adding a new resource type\n// (e.g. `topup_*`) must not require an SDK bump just to validate the wire.\n// The helpers therefore take the prefix as a generic string parameter; the\n// per-resource Zod schemas in `./zod-schemas.ts` are the place to enumerate\n// the known prefixes for validation purposes.\n\nimport { decodeBytes, encodeBytes } from './crockford-base32';\n\n/**\n * Branded string type — `${prefix}_<26-base32-chars>`. The phantom `__brand`\n * field gives TypeScript a way to refuse a bare string at API boundaries\n * (`function fn(id: PrefixedId<'poe'>)`) while staying ABI-compatible with\n * `string` on the wire and in JSON serialisation.\n */\nexport type PrefixedId<P extends string> = `${P}_${string}` & { readonly __brand: P };\n\n// 32-char hex UUID without separators is what the encoder converts to bytes.\nconst UUID_RE_BYTES = /^[0-9a-f]{32}$/;\n\nfunction uuidStringToBytes(uuid: string): Uint8Array {\n // Accept canonical 8-4-4-4-12 hyphenated form (case-insensitive) only —\n // this is what every UUIDv4/v7 library produces and what Postgres returns\n // for the UUIDv7 columns. Anything else (no hyphens, wrong width, non-hex)\n // is rejected.\n const hex = uuid.replace(/-/g, '').toLowerCase();\n if (!UUID_RE_BYTES.test(hex) || uuid.replace(/[^-]/g, '').length !== 4) {\n throw new Error(`prefixed-id: not a canonical hyphenated UUID: ${JSON.stringify(uuid)}`);\n }\n const out = new Uint8Array(16);\n for (let i = 0; i < 16; i++) {\n out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);\n }\n return out;\n}\n\nfunction bytesToUuidString(bytes: Uint8Array): string {\n if (bytes.length !== 16) {\n throw new Error(`prefixed-id: expected 16 decoded bytes, got ${bytes.length}`);\n }\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\n/**\n * Encode a bare canonical UUID string (8-4-4-4-12 hyphenated) into the\n * Stripe-style wire form `${prefix}_<crockford>`.\n */\nexport function encodePrefixedId<P extends string>(prefix: P, uuid: string): PrefixedId<P> {\n const bytes = uuidStringToBytes(uuid);\n const encoded = encodeBytes(bytes);\n return `${prefix}_${encoded}` as PrefixedId<P>;\n}\n\n/**\n * Decode a wire-format prefixed id back to the bare canonical UUID string.\n * Throws when the prefix does not match, the body is not 26 base32 chars,\n * or the encoded payload is malformed.\n */\nexport function decodePrefixedId<P extends string>(prefix: P, encoded: string): string {\n if (typeof encoded !== 'string') {\n throw new Error(`prefixed-id: expected string, got ${typeof encoded}`);\n }\n const sep = encoded.indexOf('_');\n if (sep < 0) {\n throw new Error(`prefixed-id: missing prefix separator in ${JSON.stringify(encoded)}`);\n }\n const actualPrefix = encoded.slice(0, sep);\n if (actualPrefix !== prefix) {\n throw new Error(\n `prefixed-id: expected prefix ${JSON.stringify(prefix)}, got ${JSON.stringify(actualPrefix)}`,\n );\n }\n const body = encoded.slice(sep + 1);\n const bytes = decodeBytes(body);\n return bytesToUuidString(bytes);\n}\n\n/**\n * Type guard. Cheap-check: matches the prefix and the lowercase Crockford\n * length, but does NOT validate the payload bytes round-trip. Use\n * `decodePrefixedId` when a full validation is required.\n */\nexport function isPrefixedId<P extends string>(\n prefix: P,\n candidate: unknown,\n): candidate is PrefixedId<P> {\n if (typeof candidate !== 'string') return false;\n if (!candidate.startsWith(`${prefix}_`)) return false;\n const body = candidate.slice(prefix.length + 1);\n if (body.length !== 26) return false;\n // Strict Crockford alphabet — no I, L, O, U; lowercase only on the wire.\n return /^[0-9a-hjkmnp-tv-z]{26}$/.test(body);\n}\n","// Zod schema gating the Label 309 record id at every parse boundary (HTTP route\n// handlers, SDK input validation, OpenAPI registration).\n//\n// The regex is the strict Crockford-32 alphabet (lowercase only on the wire,\n// no I/L/O/U). This is stricter than `[0-9a-z]{26}` because it catches the\n// most common typo classes (`poe_…ol1u…`) at the parser rather than letting\n// them through to the decoder for a confusing `non-zero pad bits` error.\n\nimport { z } from 'zod';\n\nconst CROCKFORD_LOWER = '[0-9a-hjkmnp-tv-z]{26}';\n\nexport const POE_ID_PREFIX = 'poe' as const;\n\nexport const PoeIdSchema = z\n .string()\n .regex(new RegExp(`^${POE_ID_PREFIX}_${CROCKFORD_LOWER}$`), 'invalid poe id');\n\nexport const POE_ID_PATTERN = `^${POE_ID_PREFIX}_${CROCKFORD_LOWER}$`;\n"]}
|