@peac/protocol 0.12.0-preview.1 → 0.12.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 CHANGED
@@ -22,11 +22,16 @@ const { publicKey, privateKey } = await generateKeypair();
22
22
 
23
23
  const { jws } = await issue({
24
24
  iss: 'https://api.example.com',
25
- aud: 'https://client.example.com',
26
- amt: 100,
27
- cur: 'USD',
28
- rail: 'stripe',
29
- reference: 'pi_abc123',
25
+ kind: 'evidence',
26
+ type: 'org.peacprotocol/payment',
27
+ pillars: ['commerce'],
28
+ extensions: {
29
+ 'org.peacprotocol/commerce': {
30
+ payment_rail: 'stripe',
31
+ amount_minor: '10000',
32
+ currency: 'USD',
33
+ },
34
+ },
30
35
  privateKey,
31
36
  kid: 'key-2026-02',
32
37
  });
@@ -39,10 +44,10 @@ import { verifyLocal } from '@peac/protocol';
39
44
 
40
45
  const result = await verifyLocal(jws, publicKey);
41
46
 
42
- if (result.valid && result.variant === 'commerce') {
47
+ if (result.valid && result.wireVersion === '0.2') {
43
48
  console.log(result.claims.iss); // issuer
44
- console.log(result.claims.amt); // amount
45
- console.log(result.claims.cur); // currency
49
+ console.log(result.claims.kind); // evidence
50
+ console.log(result.claims.type); // org.peacprotocol/payment
46
51
  } else if (!result.valid) {
47
52
  console.log(result.code, result.message);
48
53
  }
@@ -50,16 +55,23 @@ if (result.valid && result.variant === 'commerce') {
50
55
 
51
56
  ## How Do I Verify with JWKS Discovery?
52
57
 
58
+ > **Note:** `verifyReceipt()` is deprecated (Wire 0.1 only). For Wire 0.2 receipts,
59
+ > resolve the issuer's JWKS manually and pass the public key to `verifyLocal()`.
60
+ > Automated JWKS discovery for Wire 0.2 is planned for a future release.
61
+
53
62
  ```typescript
54
- import { verifyReceipt } from '@peac/protocol';
63
+ import { verifyLocal } from '@peac/protocol';
55
64
 
56
- // Resolves issuer's /.well-known/peac-issuer.json -> jwks_uri -> public key
57
- const result = await verifyReceipt(jws);
65
+ // 1. Resolve issuer's /.well-known/peac-issuer.json -> jwks_uri -> public key
66
+ // 2. Pass the resolved key to verifyLocal()
67
+ const result = await verifyLocal(jws, resolvedPublicKey, {
68
+ issuer: 'https://api.example.com',
69
+ });
58
70
 
59
- if (result.ok) {
71
+ if (result.valid) {
60
72
  console.log('Issuer:', result.claims.iss);
61
73
  } else {
62
- console.log(result.reason, result.details);
74
+ console.log(result.code, result.message);
63
75
  }
64
76
  ```
65
77
 
package/dist/index.cjs CHANGED
@@ -35,7 +35,7 @@ var IssueError = class extends Error {
35
35
  this.peacError = peacError;
36
36
  }
37
37
  };
38
- async function issue(options) {
38
+ async function issueWire01(options) {
39
39
  if (!options.iss.startsWith("https://")) {
40
40
  throw new Error("Issuer URL must start with https://");
41
41
  }
@@ -176,9 +176,12 @@ async function issue(options) {
176
176
  };
177
177
  }
178
178
  async function issueJws(options) {
179
- const result = await issue(options);
179
+ const result = await issueWire01(options);
180
180
  return result.jws;
181
181
  }
182
+ async function issue(options) {
183
+ return issueWire02(options);
184
+ }
182
185
  async function issueWire02(options) {
183
186
  if (!schema.isCanonicalIss(options.iss)) {
184
187
  throw new IssueError({
@@ -188,7 +191,7 @@ async function issueWire02(options) {
188
191
  retryable: false,
189
192
  http_status: 400,
190
193
  details: {
191
- message: `iss is not in canonical form: "${options.iss}". Use https:// origin or did: identifier.`
194
+ message: `iss is not in canonical form: "${options.iss}". Use an https://<origin> or did:<method> identifier.`
192
195
  }
193
196
  });
194
197
  }
@@ -1415,16 +1418,7 @@ function sanitizeParseIssues(issues) {
1415
1418
  }));
1416
1419
  }
1417
1420
  async function verifyLocal(jws, publicKey, options = {}) {
1418
- const {
1419
- issuer,
1420
- audience,
1421
- subjectUri,
1422
- rid,
1423
- requireExp = false,
1424
- maxClockSkew = 300,
1425
- strictness = "strict",
1426
- policyDigest
1427
- } = options;
1421
+ const { issuer, subjectUri, maxClockSkew = 300, strictness = "strict", policyDigest } = options;
1428
1422
  const now = options.now ?? Math.floor(Date.now() / 1e3);
1429
1423
  try {
1430
1424
  const result = await crypto.verify(jws, publicKey);
@@ -1556,86 +1550,11 @@ async function verifyLocal(jws, publicKey, options = {}) {
1556
1550
  policy_binding: bindingStatus
1557
1551
  };
1558
1552
  }
1559
- const w01 = pr.claims;
1560
- if (issuer !== void 0 && w01.iss !== issuer) {
1561
- return {
1562
- valid: false,
1563
- code: "E_INVALID_ISSUER",
1564
- message: `Issuer mismatch: expected "${issuer}", got "${w01.iss}"`
1565
- };
1566
- }
1567
- if (audience !== void 0 && w01.aud !== audience) {
1568
- return {
1569
- valid: false,
1570
- code: "E_INVALID_AUDIENCE",
1571
- message: `Audience mismatch: expected "${audience}", got "${w01.aud}"`
1572
- };
1573
- }
1574
- if (rid !== void 0 && w01.rid !== rid) {
1575
- return {
1576
- valid: false,
1577
- code: "E_INVALID_RECEIPT_ID",
1578
- message: `Receipt ID mismatch: expected "${rid}", got "${w01.rid}"`
1579
- };
1580
- }
1581
- if (requireExp && w01.exp === void 0) {
1582
- return {
1583
- valid: false,
1584
- code: "E_MISSING_EXP",
1585
- message: "Receipt missing required exp claim"
1586
- };
1587
- }
1588
- if (w01.iat > now + maxClockSkew) {
1589
- return {
1590
- valid: false,
1591
- code: "E_NOT_YET_VALID",
1592
- message: `Receipt not yet valid: issued at ${new Date(w01.iat * 1e3).toISOString()}, now is ${new Date(now * 1e3).toISOString()}`
1593
- };
1594
- }
1595
- if (w01.exp !== void 0 && w01.exp < now - maxClockSkew) {
1596
- return {
1597
- valid: false,
1598
- code: "E_EXPIRED",
1599
- message: `Receipt expired at ${new Date(w01.exp * 1e3).toISOString()}`
1600
- };
1601
- }
1602
- if (pr.variant === "commerce") {
1603
- const claims = pr.claims;
1604
- if (subjectUri !== void 0 && claims.subject?.uri !== subjectUri) {
1605
- return {
1606
- valid: false,
1607
- code: "E_INVALID_SUBJECT",
1608
- message: `Subject mismatch: expected "${subjectUri}", got "${claims.subject?.uri ?? "undefined"}"`
1609
- };
1610
- }
1611
- return {
1612
- valid: true,
1613
- variant: "commerce",
1614
- claims,
1615
- kid: result.header.kid,
1616
- wireVersion: "0.1",
1617
- warnings: [],
1618
- policy_binding: "unavailable"
1619
- };
1620
- } else {
1621
- const claims = pr.claims;
1622
- if (subjectUri !== void 0 && claims.sub !== subjectUri) {
1623
- return {
1624
- valid: false,
1625
- code: "E_INVALID_SUBJECT",
1626
- message: `Subject mismatch: expected "${subjectUri}", got "${claims.sub ?? "undefined"}"`
1627
- };
1628
- }
1629
- return {
1630
- valid: true,
1631
- variant: "attestation",
1632
- claims,
1633
- kid: result.header.kid,
1634
- wireVersion: "0.1",
1635
- warnings: [],
1636
- policy_binding: "unavailable"
1637
- };
1638
- }
1553
+ return {
1554
+ valid: false,
1555
+ code: "E_UNSUPPORTED_WIRE_VERSION",
1556
+ message: "Wire 0.1 receipts are not supported. Re-issue as Wire 0.2 using issue()."
1557
+ };
1639
1558
  } catch (err) {
1640
1559
  if (isCryptoError(err)) {
1641
1560
  if (Object.prototype.hasOwnProperty.call(JOSE_CODE_MAP, err.code)) {
@@ -1684,10 +1603,10 @@ async function verifyLocal(jws, publicKey, options = {}) {
1684
1603
  }
1685
1604
  }
1686
1605
  function isCommerceResult(r) {
1687
- return r.valid === true && r.variant === "commerce";
1606
+ return false;
1688
1607
  }
1689
1608
  function isAttestationResult(r) {
1690
- return r.valid === true && r.variant === "attestation";
1609
+ return false;
1691
1610
  }
1692
1611
  function isWire02Result(r) {
1693
1612
  return r.valid === true && r.variant === "wire-02";
@@ -3084,6 +3003,7 @@ exports.isCommerceResult = isCommerceResult;
3084
3003
  exports.isWire02Result = isWire02Result;
3085
3004
  exports.issue = issue;
3086
3005
  exports.issueJws = issueJws;
3006
+ exports.issueWire01 = issueWire01;
3087
3007
  exports.issueWire02 = issueWire02;
3088
3008
  exports.parseBodyProfile = parseBodyProfile;
3089
3009
  exports.parseDiscovery = parseDiscovery;