@peac/protocol 0.9.18 → 0.10.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/dist/issue.d.ts CHANGED
@@ -2,7 +2,8 @@
2
2
  * Receipt issuance
3
3
  * Validates input, generates UUIDv7 rid, and signs with Ed25519
4
4
  */
5
- import { PEACReceiptClaims, SubjectProfileSnapshot } from '@peac/schema';
5
+ import type { JsonValue } from '@peac/kernel';
6
+ import { PEACReceiptClaims, SubjectProfileSnapshot, type PEACError, type PurposeToken, type CanonicalPurpose, type PurposeReason } from '@peac/schema';
6
7
  /**
7
8
  * Options for issuing a receipt
8
9
  */
@@ -27,8 +28,8 @@ export interface IssueOptions {
27
28
  network?: string;
28
29
  /** Facilitator reference (optional) */
29
30
  facilitator_ref?: string;
30
- /** Rail-specific evidence (opaque) - defaults to empty object if not provided */
31
- evidence?: unknown;
31
+ /** Rail-specific evidence (JSON-safe) - defaults to empty object if not provided */
32
+ evidence?: JsonValue;
32
33
  /** Idempotency key (optional) */
33
34
  idempotency_key?: string;
34
35
  /** Rail-specific metadata (optional) */
@@ -41,6 +42,26 @@ export interface IssueOptions {
41
42
  exp?: number;
42
43
  /** Subject profile snapshot for envelope (v0.9.17+, optional) */
43
44
  subject_snapshot?: SubjectProfileSnapshot;
45
+ /**
46
+ * Purposes declared by the requesting agent (v0.9.24+, optional)
47
+ *
48
+ * From PEAC-Purpose request header. Accepts single token or array.
49
+ * Unknown tokens are preserved for forward compatibility.
50
+ */
51
+ purpose?: PurposeToken | PurposeToken[];
52
+ /**
53
+ * Single purpose enforced by policy (v0.9.24+, optional)
54
+ *
55
+ * MUST be one of declared purposes OR a more restrictive downgrade.
56
+ * Only canonical purposes have enforcement semantics.
57
+ */
58
+ purpose_enforced?: CanonicalPurpose;
59
+ /**
60
+ * Reason for enforcement decision (v0.9.24+, optional)
61
+ *
62
+ * The audit spine - explains WHY purpose was enforced as it was.
63
+ */
64
+ purpose_reason?: PurposeReason;
44
65
  /** Ed25519 private key (32 bytes) */
45
66
  privateKey: Uint8Array;
46
67
  /** Key ID (ISO 8601 timestamp) */
@@ -55,11 +76,22 @@ export interface IssueResult {
55
76
  /** Validated subject snapshot (if provided) */
56
77
  subject_snapshot?: SubjectProfileSnapshot;
57
78
  }
79
+ /**
80
+ * Error thrown during receipt issuance
81
+ *
82
+ * Wraps a structured PEACError for programmatic handling.
83
+ */
84
+ export declare class IssueError extends Error {
85
+ /** Structured error details */
86
+ readonly peacError: PEACError;
87
+ constructor(peacError: PEACError);
88
+ }
58
89
  /**
59
90
  * Issue a PEAC receipt
60
91
  *
61
92
  * @param options - Receipt options
62
93
  * @returns Issue result with JWS and optional subject_snapshot
94
+ * @throws IssueError if evidence contains non-JSON-safe values
63
95
  */
64
96
  export declare function issue(options: IssueOptions): Promise<IssueResult>;
65
97
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"issue.d.ts","sourceRoot":"","sources":["../src/issue.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EACL,iBAAiB,EAEjB,sBAAsB,EAEvB,MAAM,cAAc,CAAC;AAEtB;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,4BAA4B;IAC5B,GAAG,EAAE,MAAM,CAAC;IAEZ,yCAAyC;IACzC,GAAG,EAAE,MAAM,CAAC;IAEZ,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAC;IAEZ,yCAAyC;IACzC,GAAG,EAAE,MAAM,CAAC;IAEZ,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;IAEb,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAElB,4FAA4F;IAC5F,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,0DAA0D;IAC1D,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAEtB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,uCAAuC;IACvC,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,iCAAiC;IACjC,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEnC,6BAA6B;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,4BAA4B;IAC5B,GAAG,CAAC,EAAE,iBAAiB,CAAC,KAAK,CAAC,CAAC;IAE/B,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,iEAAiE;IACjE,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;IAE1C,qCAAqC;IACrC,UAAU,EAAE,UAAU,CAAC;IAEvB,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,gCAAgC;IAChC,GAAG,EAAE,MAAM,CAAC;IAEZ,+CAA+C;IAC/C,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;CAC3C;AAED;;;;;GAKG;AACH,wBAAsB,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CA2EvE;AAED;;;;;;;;GAQG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAGrE"}
1
+ {"version":3,"file":"issue.d.ts","sourceRoot":"","sources":["../src/issue.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,EACL,iBAAiB,EAEjB,sBAAsB,EAGtB,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAInB,MAAM,cAAc,CAAC;AAItB;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,4BAA4B;IAC5B,GAAG,EAAE,MAAM,CAAC;IAEZ,yCAAyC;IACzC,GAAG,EAAE,MAAM,CAAC;IAEZ,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAC;IAEZ,yCAAyC;IACzC,GAAG,EAAE,MAAM,CAAC;IAEZ,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;IAEb,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAElB,4FAA4F;IAC5F,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,0DAA0D;IAC1D,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAEtB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,uCAAuC;IACvC,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,oFAAoF;IACpF,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB,iCAAiC;IACjC,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEnC,6BAA6B;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,4BAA4B;IAC5B,GAAG,CAAC,EAAE,iBAAiB,CAAC,KAAK,CAAC,CAAC;IAE/B,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,iEAAiE;IACjE,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;IAE1C;;;;;OAKG;IACH,OAAO,CAAC,EAAE,YAAY,GAAG,YAAY,EAAE,CAAC;IAExC;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAEpC;;;;OAIG;IACH,cAAc,CAAC,EAAE,aAAa,CAAC;IAE/B,qCAAqC;IACrC,UAAU,EAAE,UAAU,CAAC;IAEvB,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,gCAAgC;IAChC,GAAG,EAAE,MAAM,CAAC;IAEZ,+CAA+C;IAC/C,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;CAC3C;AAED;;;;GAIG;AACH,qBAAa,UAAW,SAAQ,KAAK;IACnC,+BAA+B;IAC/B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;gBAElB,SAAS,EAAE,SAAS;CAMjC;AAED;;;;;;GAMG;AACH,wBAAsB,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CA0JvE;AAED;;;;;;;;GAQG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAGrE"}
package/dist/issue.js CHANGED
@@ -4,16 +4,37 @@
4
4
  * Validates input, generates UUIDv7 rid, and signs with Ed25519
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.IssueError = void 0;
7
8
  exports.issue = issue;
8
9
  exports.issueJws = issueJws;
9
10
  const uuidv7_1 = require("uuidv7");
10
11
  const crypto_1 = require("@peac/crypto");
12
+ const zod_1 = require("zod");
11
13
  const schema_1 = require("@peac/schema");
14
+ const telemetry_1 = require("@peac/telemetry");
15
+ const telemetry_js_1 = require("./telemetry.js");
16
+ /**
17
+ * Error thrown during receipt issuance
18
+ *
19
+ * Wraps a structured PEACError for programmatic handling.
20
+ */
21
+ class IssueError extends Error {
22
+ /** Structured error details */
23
+ peacError;
24
+ constructor(peacError) {
25
+ const details = peacError.details;
26
+ super(details?.message ?? peacError.code);
27
+ this.name = 'IssueError';
28
+ this.peacError = peacError;
29
+ }
30
+ }
31
+ exports.IssueError = IssueError;
12
32
  /**
13
33
  * Issue a PEAC receipt
14
34
  *
15
35
  * @param options - Receipt options
16
36
  * @returns Issue result with JWS and optional subject_snapshot
37
+ * @throws IssueError if evidence contains non-JSON-safe values
17
38
  */
18
39
  async function issue(options) {
19
40
  // Validate URLs
@@ -40,6 +61,39 @@ async function issue(options) {
40
61
  throw new Error('Expiry must be a non-negative integer');
41
62
  }
42
63
  }
64
+ // Normalize and validate purpose (v0.9.24+)
65
+ let purposeDeclared;
66
+ if (options.purpose !== undefined) {
67
+ // Normalize to array
68
+ const rawPurposes = Array.isArray(options.purpose) ? options.purpose : [options.purpose];
69
+ // Validate each token
70
+ const invalidTokens = [];
71
+ for (const token of rawPurposes) {
72
+ if (!(0, schema_1.isValidPurposeToken)(token)) {
73
+ invalidTokens.push(token);
74
+ }
75
+ }
76
+ if (invalidTokens.length > 0) {
77
+ throw new Error(`Invalid purpose tokens: ${invalidTokens.join(', ')}`);
78
+ }
79
+ // Check for explicit 'undeclared' which is invalid on wire
80
+ if (rawPurposes.includes('undeclared')) {
81
+ throw new Error("Explicit 'undeclared' is not a valid purpose token (internal-only)");
82
+ }
83
+ purposeDeclared = rawPurposes;
84
+ }
85
+ // Validate purpose_enforced (must be canonical)
86
+ if (options.purpose_enforced !== undefined) {
87
+ if (!(0, schema_1.isCanonicalPurpose)(options.purpose_enforced)) {
88
+ throw new Error(`purpose_enforced must be a canonical purpose, got: ${options.purpose_enforced}`);
89
+ }
90
+ }
91
+ // Validate purpose_reason
92
+ if (options.purpose_reason !== undefined) {
93
+ if (!(0, schema_1.isValidPurposeReason)(options.purpose_reason)) {
94
+ throw new Error(`Invalid purpose_reason: ${options.purpose_reason}`);
95
+ }
96
+ }
43
97
  // Generate UUIDv7 for receipt ID
44
98
  const rid = (0, uuidv7_1.uuidv7)();
45
99
  // Get current timestamp
@@ -68,14 +122,49 @@ async function issue(options) {
68
122
  ...(options.exp && { exp: options.exp }),
69
123
  ...(options.subject && { subject: { uri: options.subject } }),
70
124
  ...(options.ext && { ext: options.ext }),
125
+ // Purpose claims (v0.9.24+)
126
+ ...(purposeDeclared && { purpose_declared: purposeDeclared }),
127
+ ...(options.purpose_enforced && { purpose_enforced: options.purpose_enforced }),
128
+ ...(options.purpose_reason && { purpose_reason: options.purpose_reason }),
71
129
  };
72
- // Validate claims with Zod
73
- schema_1.ReceiptClaims.parse(claims);
130
+ // Validate claims with Zod - map evidence errors to typed error
131
+ try {
132
+ schema_1.ReceiptClaims.parse(claims);
133
+ }
134
+ catch (err) {
135
+ if (err instanceof zod_1.ZodError) {
136
+ // Check if any error path touches evidence
137
+ const evidenceIssue = err.issues.find((issue) => issue.path.some((p) => p === 'evidence' || p === 'payment'));
138
+ if (evidenceIssue && evidenceIssue.path.includes('evidence')) {
139
+ const peacError = (0, schema_1.createEvidenceNotJsonError)(evidenceIssue.message, evidenceIssue.path);
140
+ throw new IssueError(peacError);
141
+ }
142
+ }
143
+ throw err;
144
+ }
74
145
  // Validate subject_snapshot if provided (v0.9.17+)
75
146
  // This validates schema and logs advisory PII warning if applicable
76
147
  const validatedSnapshot = (0, schema_1.validateSubjectSnapshot)(options.subject_snapshot);
148
+ // Track start time for telemetry
149
+ const startTime = performance.now();
77
150
  // Sign with Ed25519
78
151
  const jws = await (0, crypto_1.sign)(claims, options.privateKey, options.kid);
152
+ // Emit telemetry (no-throw guard)
153
+ const p = telemetry_1.providerRef.current;
154
+ if (p) {
155
+ try {
156
+ const durationMs = performance.now() - startTime;
157
+ p.onReceiptIssued({
158
+ receiptHash: (0, telemetry_js_1.hashReceipt)(jws),
159
+ issuer: options.iss,
160
+ kid: options.kid,
161
+ durationMs,
162
+ });
163
+ }
164
+ catch {
165
+ // Telemetry MUST NOT break core flow
166
+ }
167
+ }
79
168
  return {
80
169
  jws,
81
170
  ...(validatedSnapshot && { subject_snapshot: validatedSnapshot }),
package/dist/issue.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"issue.js","sourceRoot":"","sources":["../src/issue.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"issue.js","sourceRoot":"","sources":["../src/issue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Telemetry utilities for protocol package
3
+ */
4
+ /**
5
+ * Compute a SHA-256 hash of a receipt JWS
6
+ *
7
+ * Returns format: sha256:{hex prefix}
8
+ * Uses first 16 chars of hex for brevity in logs/spans.
9
+ */
10
+ export declare function hashReceipt(jws: string): string;
11
+ //# sourceMappingURL=telemetry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG/C"}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ /**
3
+ * Telemetry utilities for protocol package
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.hashReceipt = hashReceipt;
7
+ const node_crypto_1 = require("node:crypto");
8
+ /**
9
+ * Compute a SHA-256 hash of a receipt JWS
10
+ *
11
+ * Returns format: sha256:{hex prefix}
12
+ * Uses first 16 chars of hex for brevity in logs/spans.
13
+ */
14
+ function hashReceipt(jws) {
15
+ const hash = (0, node_crypto_1.createHash)('sha256').update(jws).digest('hex');
16
+ return `sha256:${hash.slice(0, 16)}`;
17
+ }
18
+ //# sourceMappingURL=telemetry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAUH,kCAGC;AAXD,6CAAyC;AAEzC;;;;;GAKG;AACH,SAAgB,WAAW,CAAC,GAAW;IACrC,MAAM,IAAI,GAAG,IAAA,wBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5D,OAAO,UAAU,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;AACvC,CAAC"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Local receipt verification with schema validation
3
+ *
4
+ * Use this for verifying receipts when you have the public key locally,
5
+ * without JWKS discovery.
6
+ */
7
+ import { type ReceiptClaimsType } from '@peac/schema';
8
+ /**
9
+ * Canonical error codes for local verification
10
+ *
11
+ * These map to E_* codes in specs/kernel/errors.json
12
+ */
13
+ export type VerifyLocalErrorCode = 'E_INVALID_SIGNATURE' | 'E_INVALID_FORMAT' | 'E_EXPIRED' | 'E_NOT_YET_VALID' | 'E_INVALID_ISSUER' | 'E_INVALID_AUDIENCE' | 'E_INVALID_SUBJECT' | 'E_INVALID_RECEIPT_ID' | 'E_MISSING_EXP' | 'E_INTERNAL';
14
+ /**
15
+ * Options for local verification
16
+ */
17
+ export interface VerifyLocalOptions {
18
+ /**
19
+ * Expected issuer URL
20
+ *
21
+ * If provided, verification fails if receipt.iss does not match.
22
+ */
23
+ issuer?: string;
24
+ /**
25
+ * Expected audience URL
26
+ *
27
+ * If provided, verification fails if receipt.aud does not match.
28
+ */
29
+ audience?: string;
30
+ /**
31
+ * Expected subject URI
32
+ *
33
+ * If provided, verification fails if receipt.subject.uri does not match.
34
+ * Binds the receipt to a specific resource/interaction target.
35
+ */
36
+ subjectUri?: string;
37
+ /**
38
+ * Expected receipt ID (rid)
39
+ *
40
+ * If provided, verification fails if receipt.rid does not match.
41
+ * Useful for idempotency checks or correlating with prior receipts.
42
+ */
43
+ rid?: string;
44
+ /**
45
+ * Require expiration claim
46
+ *
47
+ * If true, receipts without exp claim are rejected.
48
+ * Defaults to false.
49
+ */
50
+ requireExp?: boolean;
51
+ /**
52
+ * Current timestamp (Unix seconds)
53
+ *
54
+ * Defaults to Date.now() / 1000. Override for testing.
55
+ */
56
+ now?: number;
57
+ /**
58
+ * Maximum clock skew tolerance (seconds)
59
+ *
60
+ * Allows for clock drift between issuer and verifier.
61
+ * Defaults to 300 (5 minutes).
62
+ */
63
+ maxClockSkew?: number;
64
+ }
65
+ /**
66
+ * Result of successful local verification
67
+ */
68
+ export interface VerifyLocalSuccess {
69
+ /** Verification succeeded */
70
+ valid: true;
71
+ /** Validated receipt claims (schema-derived type) */
72
+ claims: ReceiptClaimsType;
73
+ /** Key ID from JWS header (for logging/indexing) */
74
+ kid: string;
75
+ }
76
+ /**
77
+ * Result of failed local verification
78
+ */
79
+ export interface VerifyLocalFailure {
80
+ /** Verification failed */
81
+ valid: false;
82
+ /** Canonical error code (maps to specs/kernel/errors.json) */
83
+ code: VerifyLocalErrorCode;
84
+ /** Human-readable error message */
85
+ message: string;
86
+ }
87
+ /**
88
+ * Union type for local verification result
89
+ */
90
+ export type VerifyLocalResult = VerifyLocalSuccess | VerifyLocalFailure;
91
+ /**
92
+ * Verify a PEAC receipt locally with a known public key
93
+ *
94
+ * This function:
95
+ * 1. Verifies the Ed25519 signature and header (typ, alg)
96
+ * 2. Validates the receipt schema with Zod
97
+ * 3. Checks issuer/audience/subject binding (if options provided)
98
+ * 4. Checks time validity (exp/iat with clock skew tolerance)
99
+ *
100
+ * Use this when you have the issuer's public key and don't need JWKS discovery.
101
+ * For JWKS-based verification, use `verifyReceipt()` instead.
102
+ *
103
+ * @param jws - JWS compact serialization
104
+ * @param publicKey - Ed25519 public key (32 bytes)
105
+ * @param options - Optional verification options (issuer, audience, subject, clock skew)
106
+ * @returns Typed verification result
107
+ *
108
+ * @example
109
+ * ```typescript
110
+ * const result = await verifyLocal(jws, publicKey, {
111
+ * issuer: 'https://api.example.com',
112
+ * audience: 'https://client.example.com',
113
+ * subjectUri: 'https://api.example.com/inference/v1',
114
+ * });
115
+ * if (result.valid) {
116
+ * console.log('Issuer:', result.claims.iss);
117
+ * console.log('Amount:', result.claims.amt, result.claims.cur);
118
+ * console.log('Key ID:', result.kid);
119
+ * } else {
120
+ * console.error('Verification failed:', result.code, result.message);
121
+ * }
122
+ * ```
123
+ */
124
+ export declare function verifyLocal(jws: string, publicKey: Uint8Array, options?: VerifyLocalOptions): Promise<VerifyLocalResult>;
125
+ //# sourceMappingURL=verify-local.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-local.d.ts","sourceRoot":"","sources":["../src/verify-local.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAuB,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AA8B3E;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAC5B,qBAAqB,GACrB,kBAAkB,GAClB,WAAW,GACX,iBAAiB,GACjB,kBAAkB,GAClB,oBAAoB,GACpB,mBAAmB,GACnB,sBAAsB,GACtB,eAAe,GACf,YAAY,CAAC;AAEjB;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;OAKG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,6BAA6B;IAC7B,KAAK,EAAE,IAAI,CAAC;IAEZ,qDAAqD;IACrD,MAAM,EAAE,iBAAiB,CAAC;IAE1B,oDAAoD;IACpD,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,0BAA0B;IAC1B,KAAK,EAAE,KAAK,CAAC;IAEb,8DAA8D;IAC9D,IAAI,EAAE,oBAAoB,CAAC;IAE3B,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,kBAAkB,GAAG,kBAAkB,CAAC;AAaxE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,UAAU,EACrB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,CAAC,CAmI5B"}
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+ /**
3
+ * Local receipt verification with schema validation
4
+ *
5
+ * Use this for verifying receipts when you have the public key locally,
6
+ * without JWKS discovery.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.verifyLocal = verifyLocal;
10
+ const crypto_1 = require("@peac/crypto");
11
+ const schema_1 = require("@peac/schema");
12
+ /**
13
+ * Structural check for CryptoError
14
+ * More robust than instanceof across module boundaries (ESM/CJS, duplicate packages)
15
+ */
16
+ function isCryptoError(err) {
17
+ return (err !== null &&
18
+ typeof err === 'object' &&
19
+ 'name' in err &&
20
+ err.name === 'CryptoError' &&
21
+ 'code' in err &&
22
+ typeof err.code === 'string' &&
23
+ err.code.startsWith('CRYPTO_') &&
24
+ 'message' in err &&
25
+ typeof err.message === 'string');
26
+ }
27
+ /**
28
+ * Crypto error codes that indicate format/validation issues
29
+ * These are CRYPTO_* internal codes from @peac/crypto, mapped to canonical E_* codes
30
+ */
31
+ const FORMAT_ERROR_CODES = new Set([
32
+ 'CRYPTO_INVALID_JWS_FORMAT',
33
+ 'CRYPTO_INVALID_TYP',
34
+ 'CRYPTO_INVALID_ALG',
35
+ 'CRYPTO_INVALID_KEY_LENGTH',
36
+ ]);
37
+ /**
38
+ * Verify a PEAC receipt locally with a known public key
39
+ *
40
+ * This function:
41
+ * 1. Verifies the Ed25519 signature and header (typ, alg)
42
+ * 2. Validates the receipt schema with Zod
43
+ * 3. Checks issuer/audience/subject binding (if options provided)
44
+ * 4. Checks time validity (exp/iat with clock skew tolerance)
45
+ *
46
+ * Use this when you have the issuer's public key and don't need JWKS discovery.
47
+ * For JWKS-based verification, use `verifyReceipt()` instead.
48
+ *
49
+ * @param jws - JWS compact serialization
50
+ * @param publicKey - Ed25519 public key (32 bytes)
51
+ * @param options - Optional verification options (issuer, audience, subject, clock skew)
52
+ * @returns Typed verification result
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * const result = await verifyLocal(jws, publicKey, {
57
+ * issuer: 'https://api.example.com',
58
+ * audience: 'https://client.example.com',
59
+ * subjectUri: 'https://api.example.com/inference/v1',
60
+ * });
61
+ * if (result.valid) {
62
+ * console.log('Issuer:', result.claims.iss);
63
+ * console.log('Amount:', result.claims.amt, result.claims.cur);
64
+ * console.log('Key ID:', result.kid);
65
+ * } else {
66
+ * console.error('Verification failed:', result.code, result.message);
67
+ * }
68
+ * ```
69
+ */
70
+ async function verifyLocal(jws, publicKey, options = {}) {
71
+ const { issuer, audience, subjectUri, rid, requireExp = false, maxClockSkew = 300 } = options;
72
+ const now = options.now ?? Math.floor(Date.now() / 1000);
73
+ try {
74
+ // 1. Verify signature and header (typ, alg validated by @peac/crypto)
75
+ const result = await (0, crypto_1.verify)(jws, publicKey);
76
+ if (!result.valid) {
77
+ return {
78
+ valid: false,
79
+ code: 'E_INVALID_SIGNATURE',
80
+ message: 'Ed25519 signature verification failed',
81
+ };
82
+ }
83
+ // 2. Validate schema
84
+ const parseResult = schema_1.ReceiptClaimsSchema.safeParse(result.payload);
85
+ if (!parseResult.success) {
86
+ const firstIssue = parseResult.error.issues[0];
87
+ return {
88
+ valid: false,
89
+ code: 'E_INVALID_FORMAT',
90
+ message: `Receipt schema validation failed: ${firstIssue?.message ?? 'unknown error'}`,
91
+ };
92
+ }
93
+ const claims = parseResult.data;
94
+ // 3. Check issuer binding
95
+ if (issuer !== undefined && claims.iss !== issuer) {
96
+ return {
97
+ valid: false,
98
+ code: 'E_INVALID_ISSUER',
99
+ message: `Issuer mismatch: expected "${issuer}", got "${claims.iss}"`,
100
+ };
101
+ }
102
+ // 4. Check audience binding
103
+ if (audience !== undefined && claims.aud !== audience) {
104
+ return {
105
+ valid: false,
106
+ code: 'E_INVALID_AUDIENCE',
107
+ message: `Audience mismatch: expected "${audience}", got "${claims.aud}"`,
108
+ };
109
+ }
110
+ // 5. Check subject binding
111
+ if (subjectUri !== undefined) {
112
+ const actualSubjectUri = claims.subject?.uri;
113
+ if (actualSubjectUri !== subjectUri) {
114
+ return {
115
+ valid: false,
116
+ code: 'E_INVALID_SUBJECT',
117
+ message: `Subject mismatch: expected "${subjectUri}", got "${actualSubjectUri ?? 'undefined'}"`,
118
+ };
119
+ }
120
+ }
121
+ // 6. Check receipt ID binding
122
+ if (rid !== undefined && claims.rid !== rid) {
123
+ return {
124
+ valid: false,
125
+ code: 'E_INVALID_RECEIPT_ID',
126
+ message: `Receipt ID mismatch: expected "${rid}", got "${claims.rid}"`,
127
+ };
128
+ }
129
+ // 7. Check requireExp
130
+ if (requireExp && claims.exp === undefined) {
131
+ return {
132
+ valid: false,
133
+ code: 'E_MISSING_EXP',
134
+ message: 'Receipt missing required exp claim',
135
+ };
136
+ }
137
+ // 8. Check not-yet-valid (iat with clock skew)
138
+ if (claims.iat > now + maxClockSkew) {
139
+ return {
140
+ valid: false,
141
+ code: 'E_NOT_YET_VALID',
142
+ message: `Receipt not yet valid: issued at ${new Date(claims.iat * 1000).toISOString()}, now is ${new Date(now * 1000).toISOString()}`,
143
+ };
144
+ }
145
+ // 9. Check expiry (with clock skew tolerance)
146
+ if (claims.exp !== undefined && claims.exp < now - maxClockSkew) {
147
+ return {
148
+ valid: false,
149
+ code: 'E_EXPIRED',
150
+ message: `Receipt expired at ${new Date(claims.exp * 1000).toISOString()}`,
151
+ };
152
+ }
153
+ return {
154
+ valid: true,
155
+ claims,
156
+ kid: result.header.kid,
157
+ };
158
+ }
159
+ catch (err) {
160
+ // Handle typed CryptoError from @peac/crypto
161
+ // Use structural check instead of instanceof for robustness across ESM/CJS boundaries
162
+ // Map internal CRYPTO_* codes to canonical E_* codes
163
+ if (isCryptoError(err)) {
164
+ if (FORMAT_ERROR_CODES.has(err.code)) {
165
+ return {
166
+ valid: false,
167
+ code: 'E_INVALID_FORMAT',
168
+ message: err.message,
169
+ };
170
+ }
171
+ if (err.code === 'CRYPTO_INVALID_SIGNATURE') {
172
+ return {
173
+ valid: false,
174
+ code: 'E_INVALID_SIGNATURE',
175
+ message: err.message,
176
+ };
177
+ }
178
+ }
179
+ // All other errors (JSON parse, unexpected) -> E_INTERNAL
180
+ // No message parsing - code-based mapping only
181
+ const message = err instanceof Error ? err.message : String(err);
182
+ return {
183
+ valid: false,
184
+ code: 'E_INTERNAL',
185
+ message: `Unexpected verification error: ${message}`,
186
+ };
187
+ }
188
+ }
189
+ //# sourceMappingURL=verify-local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-local.js","sourceRoot":"","sources":["../src/verify-local.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EACL,iBAAiB,EAEjB,sBAAsB,EAEvB,MAAM,cAAc,CAAC;AA8BtB;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,6BAA6B;IAC7B,EAAE,EAAE,IAAI,CAAC;IAET,qBAAqB;IACrB,MAAM,EAAE,iBAAiB,CAAC;IAE1B,uDAAuD;IACvD,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;IAE1C,0BAA0B;IAC1B,IAAI,CAAC,EAAE;QACL,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,0BAA0B;IAC1B,EAAE,EAAE,KAAK,CAAC;IAEV,mBAAmB;IACnB,MAAM,EAAE,MAAM,CAAC;IAEf,oBAAoB;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAmGD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,gCAAgC;IAChC,UAAU,EAAE,MAAM,CAAC;IAEnB,sEAAsE;IACtE,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;CAC3C;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,YAAY,EAAE,MAAM,GAAG,aAAa,GACnC,OAAO,CAAC,YAAY,GAAG,aAAa,CAAC,CA6EvC"}
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EACL,iBAAiB,EAEjB,sBAAsB,EAEvB,MAAM,cAAc,CAAC;AAgCtB;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,6BAA6B;IAC7B,EAAE,EAAE,IAAI,CAAC;IAET,qBAAqB;IACrB,MAAM,EAAE,iBAAiB,CAAC;IAE1B,uDAAuD;IACvD,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;IAE1C,0BAA0B;IAC1B,IAAI,CAAC,EAAE;QACL,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,0BAA0B;IAC1B,EAAE,EAAE,KAAK,CAAC;IAEV,mBAAmB;IACnB,MAAM,EAAE,MAAM,CAAC;IAEf,oBAAoB;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAmGD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,gCAAgC;IAChC,UAAU,EAAE,MAAM,CAAC;IAEnB,sEAAsE;IACtE,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;CAC3C;AA8BD;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,YAAY,EAAE,MAAM,GAAG,aAAa,GACnC,OAAO,CAAC,YAAY,GAAG,aAAa,CAAC,CA+FvC"}