@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/LICENSE +190 -0
- package/dist/discovery.d.ts +48 -8
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +331 -46
- package/dist/discovery.js.map +1 -1
- package/dist/headers.d.ts +38 -1
- package/dist/headers.d.ts.map +1 -1
- package/dist/headers.js +65 -1
- package/dist/headers.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/issue.d.ts +35 -3
- package/dist/issue.d.ts.map +1 -1
- package/dist/issue.js +91 -2
- package/dist/issue.js.map +1 -1
- package/dist/telemetry.d.ts +11 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +18 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/verify-local.d.ts +125 -0
- package/dist/verify-local.d.ts.map +1 -0
- package/dist/verify-local.js +189 -0
- package/dist/verify-local.js.map +1 -0
- package/dist/verify.d.ts.map +1 -1
- package/dist/verify.js +33 -0
- package/dist/verify.js.map +1 -1
- package/package.json +14 -11
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 {
|
|
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 (
|
|
31
|
-
evidence?:
|
|
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
|
/**
|
package/dist/issue.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue.d.ts","sourceRoot":"","sources":["../src/issue.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EACL,iBAAiB,EAEjB,sBAAsB,
|
|
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
|
-
|
|
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":";AAAA;;;GAGG
|
|
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":";AAAA;;;;;GAKG;;AAyLH,kCAuIC;AA9TD,yCAAmD;AACnD,yCAA2E;AAY3E;;;GAGG;AACH,SAAS,aAAa,CAAC,GAAY;IACjC,OAAO,CACL,GAAG,KAAK,IAAI;QACZ,OAAO,GAAG,KAAK,QAAQ;QACvB,MAAM,IAAI,GAAG;QACb,GAAG,CAAC,IAAI,KAAK,aAAa;QAC1B,MAAM,IAAI,GAAG;QACb,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ;QAC5B,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAC9B,SAAS,IAAI,GAAG;QAChB,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAChC,CAAC;AACJ,CAAC;AA8GD;;;GAGG;AACH,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC;IACjC,2BAA2B;IAC3B,oBAAoB;IACpB,oBAAoB;IACpB,2BAA2B;CAC5B,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACI,KAAK,UAAU,WAAW,CAC/B,GAAW,EACX,SAAqB,EACrB,UAA8B,EAAE;IAEhC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,GAAG,KAAK,EAAE,YAAY,GAAG,GAAG,EAAE,GAAG,OAAO,CAAC;IAC9F,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAEzD,IAAI,CAAC;QACH,sEAAsE;QACtE,MAAM,MAAM,GAAG,MAAM,IAAA,eAAS,EAAU,GAAG,EAAE,SAAS,CAAC,CAAC;QAExD,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,IAAI,EAAE,qBAAqB;gBAC3B,OAAO,EAAE,uCAAuC;aACjD,CAAC;QACJ,CAAC;QAED,qBAAqB;QACrB,MAAM,WAAW,GAAG,4BAAmB,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAElE,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;YACzB,MAAM,UAAU,GAAG,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAC/C,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,IAAI,EAAE,kBAAkB;gBACxB,OAAO,EAAE,qCAAqC,UAAU,EAAE,OAAO,IAAI,eAAe,EAAE;aACvF,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC;QAEhC,0BAA0B;QAC1B,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,GAAG,KAAK,MAAM,EAAE,CAAC;YAClD,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,IAAI,EAAE,kBAAkB;gBACxB,OAAO,EAAE,8BAA8B,MAAM,WAAW,MAAM,CAAC,GAAG,GAAG;aACtE,CAAC;QACJ,CAAC;QAED,4BAA4B;QAC5B,IAAI,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;YACtD,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,IAAI,EAAE,oBAAoB;gBAC1B,OAAO,EAAE,gCAAgC,QAAQ,WAAW,MAAM,CAAC,GAAG,GAAG;aAC1E,CAAC;QACJ,CAAC;QAED,2BAA2B;QAC3B,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC7B,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC;YAC7C,IAAI,gBAAgB,KAAK,UAAU,EAAE,CAAC;gBACpC,OAAO;oBACL,KAAK,EAAE,KAAK;oBACZ,IAAI,EAAE,mBAAmB;oBACzB,OAAO,EAAE,+BAA+B,UAAU,WAAW,gBAAgB,IAAI,WAAW,GAAG;iBAChG,CAAC;YACJ,CAAC;QACH,CAAC;QAED,8BAA8B;QAC9B,IAAI,GAAG,KAAK,SAAS,IAAI,MAAM,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;YAC5C,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,IAAI,EAAE,sBAAsB;gBAC5B,OAAO,EAAE,kCAAkC,GAAG,WAAW,MAAM,CAAC,GAAG,GAAG;aACvE,CAAC;QACJ,CAAC;QAED,sBAAsB;QACtB,IAAI,UAAU,IAAI,MAAM,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;YAC3C,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,IAAI,EAAE,eAAe;gBACrB,OAAO,EAAE,oCAAoC;aAC9C,CAAC;QACJ,CAAC;QAED,+CAA+C;QAC/C,IAAI,MAAM,CAAC,GAAG,GAAG,GAAG,GAAG,YAAY,EAAE,CAAC;YACpC,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,IAAI,EAAE,iBAAiB;gBACvB,OAAO,EAAE,oCAAoC,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,YAAY,IAAI,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE;aACvI,CAAC;QACJ,CAAC;QAED,8CAA8C;QAC9C,IAAI,MAAM,CAAC,GAAG,KAAK,SAAS,IAAI,MAAM,CAAC,GAAG,GAAG,GAAG,GAAG,YAAY,EAAE,CAAC;YAChE,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,sBAAsB,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE;aAC3E,CAAC;QACJ,CAAC;QAED,OAAO;YACL,KAAK,EAAE,IAAI;YACX,MAAM;YACN,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG;SACvB,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,6CAA6C;QAC7C,sFAAsF;QACtF,qDAAqD;QACrD,IAAI,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,IAAI,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrC,OAAO;oBACL,KAAK,EAAE,KAAK;oBACZ,IAAI,EAAE,kBAAkB;oBACxB,OAAO,EAAE,GAAG,CAAC,OAAO;iBACrB,CAAC;YACJ,CAAC;YACD,IAAI,GAAG,CAAC,IAAI,KAAK,0BAA0B,EAAE,CAAC;gBAC5C,OAAO;oBACL,KAAK,EAAE,KAAK;oBACZ,IAAI,EAAE,qBAAqB;oBAC3B,OAAO,EAAE,GAAG,CAAC,OAAO;iBACrB,CAAC;YACJ,CAAC;QACH,CAAC;QAED,0DAA0D;QAC1D,+CAA+C;QAC/C,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,IAAI,EAAE,YAAY;YAClB,OAAO,EAAE,kCAAkC,OAAO,EAAE;SACrD,CAAC;IACJ,CAAC;AACH,CAAC"}
|
package/dist/verify.d.ts.map
CHANGED
|
@@ -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;
|
|
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"}
|