@hlos-ai/schemas 0.4.2 → 0.6.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/receipt-hash.ts","../src/encoding.ts"],"sourcesContent":["/**\n * @hlos-ai/schemas - Receipt Hash Computation\n *\n * Canonical hash computation for HLOS receipts.\n *\n * receipt_hash = base64url(SHA-256(JCS(receipt)))\n *\n * This is the hash that:\n * - BazaarReceiptEnvelope references (hash-first, per BRIDGE_SPEC.md §1.1)\n * - Notary Attestation (NA) binds to (per BRIDGE_SPEC.md §4.3)\n * - Surfaces use to reference kernel receipts unambiguously\n *\n * IMPORTANT: receipt_hash is computed over the ENTIRE SignedReceiptV0 envelope\n * (including content, content_hash, signature, key_id, etc.), NOT just content.\n * This binds the hash to a specific signed receipt version.\n *\n * Requires @noble/hashes as peer dependency.\n *\n * @see BRIDGE_SPEC.md §1.3 for canonical hashing requirements\n */\n\nimport { z } from 'zod';\nimport { bytesToBase64url, Base64urlSha256Schema } from './encoding';\nimport type { SignedReceiptV0 } from './receipt-v0';\n\nlet cachedSha256: ((data: Uint8Array) => Uint8Array) | null = null;\n\n// =============================================================================\n// JCS Canonicalization (RFC 8785)\n// =============================================================================\n\n/**\n * Recursively sort object keys lexicographically (RFC 8785 requirement).\n * @internal\n */\nfunction sortKeysDeep(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(sortKeysDeep);\n if (value !== null && typeof value === 'object') {\n const obj = value as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const key of Object.keys(obj).sort()) {\n out[key] = sortKeysDeep(obj[key]);\n }\n return out;\n }\n return value;\n}\n\n/**\n * Detect lone surrogates (U+D800–U+DFFF) that are NOT part of a valid pair.\n * A high surrogate (D800–DBFF) must be followed by a low surrogate (DC00–DFFF).\n * Lone surrogates are invalid in well-formed UTF-8 / RFC 8259 JSON and can\n * cause parser differentials between JCS implementations.\n */\nfunction hasLoneSurrogate(s: string): boolean {\n for (let i = 0; i < s.length; i++) {\n const code = s.charCodeAt(i);\n if (code >= 0xD800 && code <= 0xDBFF) {\n const next = s.charCodeAt(i + 1);\n if (isNaN(next) || next < 0xDC00 || next > 0xDFFF) return true;\n i++;\n } else if (code >= 0xDC00 && code <= 0xDFFF) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * JCS (RFC 8785) canonical JSON serialization.\n *\n * Per RFC 8785:\n * - Object keys are lexicographically sorted\n * - Numbers use ES6 serialization\n * - Rejects: undefined, functions, symbols, bigint, non-finite numbers\n * - Rejects: strings containing lone surrogates (U+D800–U+DFFF)\n *\n * @throws Error if value contains non-canonicalizable types\n */\nexport function jcsCanonicalize(value: unknown): string {\n return JSON.stringify(sortKeysDeep(value), (_key, v) => {\n if (v === undefined) throw new Error('JCS: undefined is not allowed');\n if (typeof v === 'function') throw new Error('JCS: function is not allowed');\n if (typeof v === 'symbol') throw new Error('JCS: symbol is not allowed');\n if (typeof v === 'bigint') throw new Error('JCS: bigint is not allowed');\n if (typeof v === 'number' && !Number.isFinite(v))\n throw new Error('JCS: non-finite number is not allowed');\n if (typeof v === 'string' && hasLoneSurrogate(v))\n throw new Error('JCS: lone surrogate (U+D800–U+DFFF) is not allowed');\n return v;\n });\n}\n\n// =============================================================================\n// Hash Computation\n// =============================================================================\n\n/**\n * Compute receipt_hash for a SignedReceiptV0.\n *\n * receipt_hash = base64url(SHA-256(JCS(receipt)))\n *\n * The hash is over the ENTIRE receipt envelope (content, content_hash,\n * signature, key_id, @type, version, receipt_id, issued_at).\n *\n * This is the canonical hash format per BRIDGE_SPEC.md §1.3:\n * 1. Canonicalize the receipt using RFC 8785 JCS\n * 2. Hash canonical bytes using SHA-256\n * 3. Encode as base64url (no padding)\n *\n * @param receipt - A fully-formed SignedReceiptV0 (must already be signed)\n * @returns 43-char base64url string (32-byte SHA-256 digest)\n *\n * @example\n * ```typescript\n * const receipt = issueReceiptV0(content);\n * const hash = computeReceiptHash(receipt);\n * // hash is e.g. \"z8A2kCNck4rPL4ugNe-Fbxputdi3PkjkVpSrIBhojU0\"\n * ```\n */\nexport function computeReceiptHash(receipt: SignedReceiptV0): string {\n // Lazy-load to keep this module usable without @noble/hashes installed\n // (only fails at call time if peer dep is missing)\n const sha256 = loadSha256();\n const canonical = jcsCanonicalize(receipt);\n const digest = sha256(new TextEncoder().encode(canonical));\n return bytesToBase64url(digest);\n}\n\n/**\n * Compute content_hash for arbitrary content.\n *\n * content_hash = base64url(SHA-256(JCS(content)))\n *\n * This is the hash stored in SignedReceiptV0.content_hash.\n * It hashes only the content field, NOT the entire receipt.\n *\n * @param content - The content to hash (will be JCS-canonicalized)\n * @returns 43-char base64url string (32-byte SHA-256 digest)\n */\nexport function computeContentHash(content: unknown): string {\n const sha256 = loadSha256();\n const canonical = jcsCanonicalize(content);\n const digest = sha256(new TextEncoder().encode(canonical));\n return bytesToBase64url(digest);\n}\n\n/**\n * Lazy-load SHA-256 from @noble/hashes (optional peer dependency).\n * @internal\n */\nfunction loadSha256(): (data: Uint8Array) => Uint8Array {\n if (cachedSha256) return cachedSha256;\n\n // Resolve require for both ESM and CJS contexts without import.meta so\n // CommonJS test runners can parse this file directly.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const moduleApi = typeof process.getBuiltinModule === 'function'\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ? (process.getBuiltinModule('module') as any)\n : // eslint-disable-next-line @typescript-eslint/no-require-imports\n require('node:module');\n const createRequire = moduleApi.createRequire as (filename: string) => NodeRequire;\n const requireBase = typeof __filename === 'string'\n ? __filename\n : `${process.cwd()}/package.json`;\n const _require = createRequire(requireBase);\n\n let sha256: (data: Uint8Array) => Uint8Array;\n try {\n // @noble/hashes v2.x exports from sha2.js\n sha256 = _require('@noble/hashes/sha2.js').sha256;\n } catch {\n try {\n // Fallback for bundlers that resolve without .js extension\n sha256 = _require('@noble/hashes/sha2').sha256;\n } catch {\n throw new Error(\n 'computeReceiptHash/computeContentHash requires @noble/hashes as a peer dependency. ' +\n 'Install it: npm install @noble/hashes'\n );\n }\n }\n cachedSha256 = sha256;\n return sha256;\n}\n\n// =============================================================================\n// Schemas\n// =============================================================================\n\n/**\n * Zod schema for receipt_hash field.\n * base64url(SHA-256(JCS(receipt))) — always 43 chars.\n */\nexport const ReceiptHashSchema = Base64urlSha256Schema.describe(\n 'receipt_hash: base64url(SHA-256(JCS(receipt)))'\n);\n\n// =============================================================================\n// Golden Fixtures\n// =============================================================================\n\n/**\n * Golden receipt fixture for hash conformance testing.\n *\n * This is a deterministic SignedReceiptV0 with fixed field values.\n * The receipt_hash computed over this fixture is FROZEN.\n *\n * If your computeReceiptHash() produces a different result for this input,\n * your implementation is non-conformant. DO NOT CHANGE these values.\n */\nexport const RECEIPT_HASH_GOLDEN_FIXTURE = {\n receipt: {\n '@type': 'https://hlos.ai/schema/SignedReceiptV0' as const,\n version: 0 as const,\n receipt_id: 'rcpt_01HZGOLDENTEST000000000000',\n content: {\n type: 'CrossingSettled' as const,\n crossingId: 'cross_test123abc456def789ghi',\n settlement_authority: 'hlos.ai',\n },\n // Placeholder bytes (NOT a valid cryptographic signature)\n content_hash: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',\n signature:\n 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',\n key_id: 'hlos-v2-1',\n issued_at: '2026-01-27T00:00:00.000Z',\n } satisfies SignedReceiptV0,\n\n /**\n * Expected JCS canonical form of the receipt.\n * Keys are lexicographically sorted at all levels.\n */\n expectedJcs: '{\"@type\":\"https://hlos.ai/schema/SignedReceiptV0\",\"content\":{\"crossingId\":\"cross_test123abc456def789ghi\",\"settlement_authority\":\"hlos.ai\",\"type\":\"CrossingSettled\"},\"content_hash\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\",\"issued_at\":\"2026-01-27T00:00:00.000Z\",\"key_id\":\"hlos-v2-1\",\"receipt_id\":\"rcpt_01HZGOLDENTEST000000000000\",\"signature\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\",\"version\":0}',\n\n /**\n * Expected receipt_hash (FROZEN).\n * Compute: JCS canonicalize receipt → SHA-256 → base64url (no padding)\n *\n * DO NOT CHANGE unless the receipt fixture above changes.\n */\n expectedReceiptHash: 'uLiQVUeVKcE35Rdje2fArZQfTcECDgwK6UbmQB_36Pg',\n} as const;\n","/**\n * @hlos-ai/schemas - Base64url Encoding Utilities\n *\n * RFC 4648 §5 compliant base64url encoding/decoding.\n * Zero external dependencies.\n *\n * Used for:\n * - receipt_hash: base64url(SHA-256(JCS(receipt)))\n * - content_hash: base64url(SHA-256(JCS(content)))\n * - crossing_hash: base64url(SHA-256(JCS(CrossingHashInputV0)))\n * - Ed25519 signatures and public keys\n */\n\nimport { z } from 'zod';\n\n// =============================================================================\n// Encoding\n// =============================================================================\n\n/**\n * Encode Uint8Array to base64url (RFC 4648 §5, no padding).\n */\nexport function bytesToBase64url(bytes: Uint8Array): string {\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n const base64 = btoa(binary);\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\n/**\n * Decode base64url string to Uint8Array.\n */\nexport function base64urlToBytes(str: string): Uint8Array {\n const base64 = str.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64 + '='.repeat((4 - (base64.length % 4)) % 4);\n const binary = atob(padded);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n\n// =============================================================================\n// Schemas\n// =============================================================================\n\n/**\n * Regex for base64url-encoded SHA-256 hash (32 bytes = 43 chars, no padding).\n */\nexport const BASE64URL_SHA256_REGEX = /^[A-Za-z0-9_-]{43}$/;\n\n/**\n * Zod schema for a base64url-encoded SHA-256 hash.\n * 32 bytes = 43 chars base64url (no padding).\n */\nexport const Base64urlSha256Schema = z.string().regex(\n BASE64URL_SHA256_REGEX,\n 'Must be 43-char base64url (32-byte SHA-256 digest)'\n);\n\n/**\n * Zod schema for a base64url-encoded Ed25519 signature.\n * 64 bytes = 86 chars base64url (no padding).\n */\nexport const Base64urlEd25519SigSchema = z.string().regex(\n /^[A-Za-z0-9_-]{86}$/,\n 'Must be 86-char base64url (64-byte Ed25519 signature)'\n);\n"],"mappings":"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","names":[]}
@@ -0,0 +1,3 @@
1
+ import 'zod';
2
+ export { h as RECEIPT_HASH_GOLDEN_FIXTURE, g as ReceiptHashSchema, f as computeContentHash, e as computeReceiptHash, j as jcsCanonicalize } from './receipt-hash-Ci5oN12T.cjs';
3
+ import './ids.cjs';
@@ -0,0 +1,3 @@
1
+ import 'zod';
2
+ export { h as RECEIPT_HASH_GOLDEN_FIXTURE, g as ReceiptHashSchema, f as computeContentHash, e as computeReceiptHash, j as jcsCanonicalize } from './receipt-hash-B3OwdB1v.js';
3
+ import './ids.js';
@@ -0,0 +1,16 @@
1
+ import {
2
+ RECEIPT_HASH_GOLDEN_FIXTURE,
3
+ ReceiptHashSchema,
4
+ computeContentHash,
5
+ computeReceiptHash,
6
+ jcsCanonicalize
7
+ } from "./chunk-I4QGTJTP.js";
8
+ import "./chunk-DGUM43GV.js";
9
+ export {
10
+ RECEIPT_HASH_GOLDEN_FIXTURE,
11
+ ReceiptHashSchema,
12
+ computeContentHash,
13
+ computeReceiptHash,
14
+ jcsCanonicalize
15
+ };
16
+ //# sourceMappingURL=receipt-hash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hlos-ai/schemas",
3
- "version": "0.4.2",
3
+ "version": "0.6.0",
4
4
  "description": "HLOS Kernel v2 API contract types: responses, errors, receipts, IDs",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -16,6 +16,11 @@
16
16
  "types": "./dist/ids.d.ts",
17
17
  "import": "./dist/ids.js",
18
18
  "require": "./dist/ids.cjs"
19
+ },
20
+ "./receipt-hash": {
21
+ "types": "./dist/receipt-hash.d.ts",
22
+ "import": "./dist/receipt-hash.js",
23
+ "require": "./dist/receipt-hash.cjs"
19
24
  }
20
25
  },
21
26
  "scripts": {
@@ -29,6 +34,7 @@
29
34
  "zod": "^3.24.1"
30
35
  },
31
36
  "devDependencies": {
37
+ "@noble/ed25519": "^3.0.0",
32
38
  "@noble/hashes": "^2.0.1",
33
39
  "@types/node": "^20.0.0",
34
40
  "tsup": "^8.0.0",
@@ -50,14 +56,13 @@
50
56
  "files": [
51
57
  "dist"
52
58
  ],
59
+ "homepage": "https://hlos.ai",
60
+ "bugs": {
61
+ "url": "https://hlos.ai/support"
62
+ },
53
63
  "publishConfig": {
54
64
  "access": "public"
55
65
  },
56
- "repository": {
57
- "type": "git",
58
- "url": "git+https://github.com/hlos-ai/hlos.git",
59
- "directory": "packages/hlos-schemas"
60
- },
61
66
  "license": "Apache-2.0",
62
67
  "private": false
63
68
  }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/ids.ts"],"sourcesContent":["/**\n * @hlos-ai/schemas - Branded ID Types\n *\n * Strongly-typed ID strings to prevent cross-surface mistakes.\n * Use Zod for runtime validation.\n */\n\nimport { z } from 'zod';\n\n// =============================================================================\n// ID Patterns\n// =============================================================================\n\n/**\n * ULID pattern (26 chars, Crockford base32).\n */\nconst ULID_PATTERN = /^[0-9A-HJKMNP-TV-Z]{26}$/i;\n\n/**\n * CUID pattern (starts with 'c', 25+ chars).\n */\nconst CUID_PATTERN = /^c[a-z0-9]{24,}$/;\n\n/**\n * UUID v4 pattern.\n */\nconst UUID_V4_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\n// =============================================================================\n// Branded Types (TypeScript compile-time safety)\n// =============================================================================\n\ndeclare const WalletIdBrand: unique symbol;\ndeclare const PassportIdBrand: unique symbol;\ndeclare const ReceiptIdBrand: unique symbol;\ndeclare const CorrelationIdBrand: unique symbol;\ndeclare const IdempotencyKeyBrand: unique symbol;\ndeclare const CrossingIdBrand: unique symbol;\n\nexport type WalletId = string & { readonly [WalletIdBrand]: true };\nexport type PassportId = string & { readonly [PassportIdBrand]: true };\nexport type ReceiptId = string & { readonly [ReceiptIdBrand]: true };\nexport type CorrelationId = string & { readonly [CorrelationIdBrand]: true };\nexport type IdempotencyKey = string & { readonly [IdempotencyKeyBrand]: true };\nexport type CrossingId = string & { readonly [CrossingIdBrand]: true };\n\n// =============================================================================\n// Zod Schemas (runtime validation)\n// =============================================================================\n\n/**\n * WalletId: prefixed CUID or ULID.\n */\nexport const WalletIdSchema = z.string()\n .regex(/^wallet_[a-z0-9]{20,}$/i, 'Invalid WalletId format')\n .transform((s) => s as WalletId);\n\n/**\n * PassportId: prefixed CUID or ULID.\n */\nexport const PassportIdSchema = z.string()\n .regex(/^passport_[a-z0-9]{20,}$/i, 'Invalid PassportId format')\n .transform((s) => s as PassportId);\n\n/**\n * ReceiptId: prefixed ULID.\n */\nexport const ReceiptIdSchema = z.string()\n .regex(/^rcpt_[0-9A-HJKMNP-TV-Z]{26}$/i, 'Invalid ReceiptId format')\n .transform((s) => s as ReceiptId);\n\n/**\n * CorrelationId: UUID v4 or custom format.\n */\nexport const CorrelationIdSchema = z.string()\n .min(8)\n .max(128)\n .transform((s) => s as CorrelationId);\n\n/**\n * IdempotencyKey: client-provided, opaque.\n * Max 256 chars, printable ASCII.\n */\nexport const IdempotencyKeySchema = z.string()\n .min(1)\n .max(256)\n .regex(/^[\\x20-\\x7E]+$/, 'IdempotencyKey must be printable ASCII')\n .transform((s) => s as IdempotencyKey);\n\n/**\n * CrossingId: prefixed CUID.\n */\nexport const CrossingIdSchema = z.string()\n .regex(/^cross_[a-z0-9]{20,}$/i, 'Invalid CrossingId format')\n .transform((s) => s as CrossingId);\n\n// =============================================================================\n// ID Generation Helpers\n// =============================================================================\n\n/**\n * Generate a prefixed CUID-style ID.\n * Uses crypto.randomUUID() stripped of dashes + timestamp prefix.\n */\nexport function generateId(prefix: string): string {\n const timestamp = Date.now().toString(36);\n const random = crypto.randomUUID().replace(/-/g, '').slice(0, 16);\n return `${prefix}_${timestamp}${random}`;\n}\n\nexport const generateWalletId = (): WalletId => generateId('wallet') as WalletId;\nexport const generatePassportId = (): PassportId => generateId('passport') as PassportId;\nexport const generateReceiptId = (): ReceiptId => generateId('rcpt') as ReceiptId;\nexport const generateCrossingId = (): CrossingId => generateId('cross') as CrossingId;\n"],"mappings":";;;;;;;;AAOA,SAAS,SAAS;AA8CX,IAAM,iBAAiB,EAAE,OAAO,EAClC,MAAM,2BAA2B,yBAAyB,EAC1D,UAAU,CAAC,MAAM,CAAa;AAK5B,IAAM,mBAAmB,EAAE,OAAO,EACpC,MAAM,6BAA6B,2BAA2B,EAC9D,UAAU,CAAC,MAAM,CAAe;AAK9B,IAAM,kBAAkB,EAAE,OAAO,EACnC,MAAM,kCAAkC,0BAA0B,EAClE,UAAU,CAAC,MAAM,CAAc;AAK7B,IAAM,sBAAsB,EAAE,OAAO,EACvC,IAAI,CAAC,EACL,IAAI,GAAG,EACP,UAAU,CAAC,MAAM,CAAkB;AAMjC,IAAM,uBAAuB,EAAE,OAAO,EACxC,IAAI,CAAC,EACL,IAAI,GAAG,EACP,MAAM,kBAAkB,wCAAwC,EAChE,UAAU,CAAC,MAAM,CAAmB;AAKlC,IAAM,mBAAmB,EAAE,OAAO,EACpC,MAAM,0BAA0B,2BAA2B,EAC3D,UAAU,CAAC,MAAM,CAAe;AAU9B,SAAS,WAAW,QAAwB;AAC/C,QAAM,YAAY,KAAK,IAAI,EAAE,SAAS,EAAE;AACxC,QAAM,SAAS,OAAO,WAAW,EAAE,QAAQ,MAAM,EAAE,EAAE,MAAM,GAAG,EAAE;AAChE,SAAO,GAAG,MAAM,IAAI,SAAS,GAAG,MAAM;AAC1C;AAEO,IAAM,mBAAmB,MAAgB,WAAW,QAAQ;AAC5D,IAAM,qBAAqB,MAAkB,WAAW,UAAU;AAClE,IAAM,oBAAoB,MAAiB,WAAW,MAAM;AAC5D,IAAM,qBAAqB,MAAkB,WAAW,OAAO;","names":[]}