@agenticprimitives/payments 0.0.0-alpha.4 → 0.0.0-alpha.40

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.
Files changed (66) hide show
  1. package/README.md +2 -0
  2. package/dist/entitlement/index.d.ts +125 -0
  3. package/dist/entitlement/index.d.ts.map +1 -0
  4. package/dist/entitlement/index.js +128 -0
  5. package/dist/entitlement/index.js.map +1 -0
  6. package/dist/entitlement/voucher.d.ts +85 -0
  7. package/dist/entitlement/voucher.d.ts.map +1 -0
  8. package/dist/entitlement/voucher.js +109 -0
  9. package/dist/entitlement/voucher.js.map +1 -0
  10. package/dist/external-checkout.d.ts +40 -0
  11. package/dist/external-checkout.d.ts.map +1 -0
  12. package/dist/external-checkout.js +70 -0
  13. package/dist/external-checkout.js.map +1 -0
  14. package/dist/index.d.ts +24 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +21 -0
  17. package/dist/index.js.map +1 -1
  18. package/dist/mandate-sign.d.ts +190 -0
  19. package/dist/mandate-sign.d.ts.map +1 -0
  20. package/dist/mandate-sign.js +202 -0
  21. package/dist/mandate-sign.js.map +1 -0
  22. package/dist/mandate.d.ts +34 -0
  23. package/dist/mandate.d.ts.map +1 -0
  24. package/dist/mandate.js +40 -0
  25. package/dist/mandate.js.map +1 -0
  26. package/dist/ops.d.ts +55 -0
  27. package/dist/ops.d.ts.map +1 -0
  28. package/dist/ops.js +66 -0
  29. package/dist/ops.js.map +1 -0
  30. package/dist/rails/escrow.d.ts +156 -0
  31. package/dist/rails/escrow.d.ts.map +1 -0
  32. package/dist/rails/escrow.js +88 -0
  33. package/dist/rails/escrow.js.map +1 -0
  34. package/dist/rails/invoice.d.ts +65 -0
  35. package/dist/rails/invoice.d.ts.map +1 -0
  36. package/dist/rails/invoice.js +57 -0
  37. package/dist/rails/invoice.js.map +1 -0
  38. package/dist/rails/recurring.d.ts +56 -0
  39. package/dist/rails/recurring.d.ts.map +1 -0
  40. package/dist/rails/recurring.js +58 -0
  41. package/dist/rails/recurring.js.map +1 -0
  42. package/dist/rails/wallet.d.ts +16 -0
  43. package/dist/rails/wallet.d.ts.map +1 -0
  44. package/dist/rails/wallet.js +20 -0
  45. package/dist/rails/wallet.js.map +1 -0
  46. package/dist/rails/x402/executor.d.ts +26 -1
  47. package/dist/rails/x402/executor.d.ts.map +1 -1
  48. package/dist/rails/x402/executor.js +45 -2
  49. package/dist/rails/x402/executor.js.map +1 -1
  50. package/dist/receipt.d.ts +36 -0
  51. package/dist/receipt.d.ts.map +1 -0
  52. package/dist/receipt.js +50 -0
  53. package/dist/receipt.js.map +1 -0
  54. package/dist/refund.d.ts +29 -0
  55. package/dist/refund.d.ts.map +1 -0
  56. package/dist/refund.js +19 -0
  57. package/dist/refund.js.map +1 -0
  58. package/dist/split.d.ts +27 -0
  59. package/dist/split.d.ts.map +1 -0
  60. package/dist/split.js +33 -0
  61. package/dist/split.js.map +1 -0
  62. package/dist/transfer.d.ts +51 -0
  63. package/dist/transfer.d.ts.map +1 -0
  64. package/dist/transfer.js +54 -0
  65. package/dist/transfer.js.map +1 -0
  66. package/package.json +21 -11
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # @agenticprimitives/payments
2
2
 
3
+ > Part of **[Agentic Primitives](https://agenticprimitives.dev)** — the open-source trust substrate for agentic applications: identity that can sign, authority checked at act time, evidence the owner carries. [Developer kit](https://github.com/agentictrustlabs/agentic-primitives) · [All packages](https://agenticprimitives.dev/developers)
4
+
3
5
  > **Status: STUB** (Wave 0.5 of the W1 implementation wave). Typed primitives and invariant guards ship today; the EIP-712 mandate signer and the three W1 rails land in Wave 6 per the [w1 implementation wave plan](../../docs/architecture/w1-implementation-wave-plan.md). A recent self-audit flagged this package's docs for overclaiming ([NEW-PMT-1](../../docs/audits/findings.yaml)); this README is written to the actual surface.
4
6
 
5
7
  Machine payments arrived. x402 made HTTP-native pay-per-request real; Google's AP2 defined mandates for agent-initiated spend. What neither ships — what nobody ships — is machine payments scoped by the *same* delegation, custody, and audit substrate that governs everything else the agent does. "This agent may spend up to this amount, for this task, on this rail, until Friday — signed by a smart account, bound to the work it pays for, receipted into an attestation registry" is the combination the agent economy actually needs, and it only exists when payments are a layer of one system rather than a bolted-on rail.
@@ -0,0 +1,125 @@
1
+ /**
2
+ * spec 272 §10 — entitlements: pay-once-then-access.
3
+ *
4
+ * A successful settlement mints an `EntitlementRecord`. Later access reads CONSUME
5
+ * the entitlement (decrement `usesLeft`) with NO new settlement — one access lane
6
+ * (X402-D8): a request is served against {a fresh charge} OR {a live entitlement},
7
+ * never both. **Prepaid credits = an entitlement with `maxUses: N`** — same machinery.
8
+ *
9
+ * Two bindings:
10
+ * - `'sa'` — held by a specific SA; the presenter MUST be that SA.
11
+ * - `'bearer'`— held by whoever presents the matching voucher (tier A3, unlinkable);
12
+ * this module gates on `voucherId`, the voucher crypto lives in `./voucher`.
13
+ *
14
+ * Fail-closed: an unknown binding, scope mismatch, expiry, or exhausted uses all DENY.
15
+ * Pure (no store): `consumeEntitlement` returns the decremented record; the app persists — single-writer
16
+ * only. For a shared/persisted entitlement use `EntitlementStore.claimUse` (atomic conditional decrement,
17
+ * the ARCH-H3 sibling) so two concurrent redemptions can't double-spend a prepaid credit.
18
+ */
19
+ import { type Address } from 'viem';
20
+ import type { Hex32 } from '../index.js';
21
+ export * as voucher from './voucher.js';
22
+ export type EntitlementBinding = 'sa' | 'bearer';
23
+ export interface EntitlementRecord {
24
+ entitlementId: Hex32;
25
+ binding: EntitlementBinding;
26
+ /** what this grants access to (e.g. keccak of the resource/skill scope) */
27
+ scopeHash: Hex32;
28
+ /** for `'sa'` binding — the SA that may present it */
29
+ subject?: Address;
30
+ /** for `'bearer'` binding — the voucher this entitlement is tied to */
31
+ voucherId?: Hex32;
32
+ /** expiry (unix seconds) */
33
+ ttl: number;
34
+ maxUses: number;
35
+ usesLeft: number;
36
+ provenance: {
37
+ mandateId: Hex32;
38
+ settlementHash: Hex32;
39
+ };
40
+ }
41
+ export interface MintEntitlementInput {
42
+ binding: EntitlementBinding;
43
+ scopeHash: Hex32;
44
+ ttl: number;
45
+ maxUses: number;
46
+ mandateId: Hex32;
47
+ settlementHash: Hex32;
48
+ /** required for `'sa'` binding */
49
+ subject?: Address;
50
+ /** required for `'bearer'` binding */
51
+ voucherId?: Hex32;
52
+ }
53
+ /** Mint an entitlement from a settled payment. Throws if the binding's required handle is missing. */
54
+ export declare function mintEntitlementOnPayment(input: MintEntitlementInput): EntitlementRecord;
55
+ /** Prepaid credit pack = an SA-bound entitlement with `maxUses = count`. */
56
+ export declare function mintCredits(input: Omit<MintEntitlementInput, 'binding' | 'maxUses'> & {
57
+ subject: Address;
58
+ count: number;
59
+ }): EntitlementRecord;
60
+ export interface EntitlementContext {
61
+ scopeHash: Hex32;
62
+ now: number;
63
+ /** the SA presenting (required to match an `'sa'` binding) */
64
+ presenter?: Address;
65
+ /** the voucher id presented (required to match a `'bearer'` binding) */
66
+ voucherId?: Hex32;
67
+ }
68
+ export type EntitlementCheck = {
69
+ ok: true;
70
+ } | {
71
+ ok: false;
72
+ reason: string;
73
+ };
74
+ /** Fail-closed validity check (does NOT consume). */
75
+ export declare function checkEntitlement(record: EntitlementRecord, ctx: EntitlementContext): EntitlementCheck;
76
+ export interface ConsumptionReceipt {
77
+ entitlementId: Hex32;
78
+ scopeHash: Hex32;
79
+ usesLeftAfter: number;
80
+ at: number;
81
+ }
82
+ export type ConsumeResult = {
83
+ ok: true;
84
+ record: EntitlementRecord;
85
+ consumption: ConsumptionReceipt;
86
+ } | {
87
+ ok: false;
88
+ reason: string;
89
+ };
90
+ /**
91
+ * Validate + decrement (PURE — returns the updated record; does NOT persist).
92
+ *
93
+ * entitlement-consume-toctou-no-atomic-claim (2026-07-04 self-audit): on its own this is a TOCTOU seam.
94
+ * A caller that does `checkEntitlement()` (or `consumeEntitlement()`) and THEN persists `record.usesLeft`
95
+ * has a read→decrement→write window: two concurrent redemptions of a prepaid `usesLeft:1` credit can both
96
+ * read 1 and both write 0, double-spending a money-equivalent pack. Use this only in-process/single-writer.
97
+ * For a shared/persisted entitlement, go through {@link EntitlementStore.claimUse}, whose atomic conditional
98
+ * decrement is the ARCH-H3 sibling of `SpentSet.claim`.
99
+ */
100
+ export declare function consumeEntitlement(record: EntitlementRecord, ctx: EntitlementContext): ConsumeResult;
101
+ export interface EntitlementStore {
102
+ /**
103
+ * entitlement-consume-toctou / ARCH-H3 sibling: ATOMIC validate + single-use decrement of a STORED
104
+ * entitlement. Returns ok ONLY if this call claimed a use — the record exists, matches `ctx` (scope +
105
+ * binding + presenter/voucher), is unexpired, and had `usesLeft > 0` at the instant of decrement. Two
106
+ * concurrent redemptions of a `usesLeft:1` credit: exactly one gets ok, the other `entitlement exhausted`.
107
+ * A distributed backend MUST implement the decrement as a conditional write so atomicity lives in the
108
+ * interface, not each caller: D1 `UPDATE … SET usesLeft = usesLeft - 1 WHERE entitlementId = ? AND
109
+ * usesLeft > 0 RETURNING usesLeft` (rows-affected == 1 is the claim), a Durable Object transaction, or a
110
+ * conditional put. Mirrors `SpentSet.claim` / x402 `NonceReservationStore.reserve`.
111
+ */
112
+ claimUse(entitlementId: Hex32, ctx: EntitlementContext): ConsumeResult | Promise<ConsumeResult>;
113
+ }
114
+ /**
115
+ * Reference in-memory {@link EntitlementStore}. In-process JS is single-threaded, so the validate +
116
+ * decrement below is naturally atomic — the interface demands the same guarantee of every (distributed)
117
+ * implementer. Seed it with the minted records; `claimUse` mutates `usesLeft` in place under the claim.
118
+ */
119
+ export declare function createMemoryEntitlementStore(records?: Iterable<EntitlementRecord>): EntitlementStore & {
120
+ put(record: EntitlementRecord): void;
121
+ get(id: Hex32): EntitlementRecord | undefined;
122
+ };
123
+ /** Convenience: keccak of a resource/skill scope string → `scopeHash`. */
124
+ export declare function scopeHashOf(scope: string): Hex32;
125
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/entitlement/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * spec 272 §10 — entitlements: pay-once-then-access.
3
+ *
4
+ * A successful settlement mints an `EntitlementRecord`. Later access reads CONSUME
5
+ * the entitlement (decrement `usesLeft`) with NO new settlement — one access lane
6
+ * (X402-D8): a request is served against {a fresh charge} OR {a live entitlement},
7
+ * never both. **Prepaid credits = an entitlement with `maxUses: N`** — same machinery.
8
+ *
9
+ * Two bindings:
10
+ * - `'sa'` — held by a specific SA; the presenter MUST be that SA.
11
+ * - `'bearer'`— held by whoever presents the matching voucher (tier A3, unlinkable);
12
+ * this module gates on `voucherId`, the voucher crypto lives in `./voucher`.
13
+ *
14
+ * Fail-closed: an unknown binding, scope mismatch, expiry, or exhausted uses all DENY.
15
+ * Pure (no store): `consumeEntitlement` returns the decremented record; the app persists — single-writer
16
+ * only. For a shared/persisted entitlement use `EntitlementStore.claimUse` (atomic conditional decrement,
17
+ * the ARCH-H3 sibling) so two concurrent redemptions can't double-spend a prepaid credit.
18
+ */
19
+ import { keccak256, encodeAbiParameters, toBytes } from 'viem';
20
+ // tier A3 — blind bearer vouchers (Privacy Pass / VOPRF).
21
+ export * as voucher from './voucher.js';
22
+ const ZERO32 = ('0x' + '00'.repeat(32));
23
+ function entitlementId(args) {
24
+ return keccak256(encodeAbiParameters([{ type: 'string' }, { type: 'bytes32' }, { type: 'bytes32' }, { type: 'bytes32' }], [
25
+ args.binding,
26
+ args.scopeHash,
27
+ args.binding === 'sa'
28
+ ? keccak256(toBytes(args.subject ?? '0x'))
29
+ : (args.voucherId ?? ZERO32),
30
+ args.mandateId,
31
+ ]));
32
+ }
33
+ /** Mint an entitlement from a settled payment. Throws if the binding's required handle is missing. */
34
+ export function mintEntitlementOnPayment(input) {
35
+ if (input.binding === 'sa' && !input.subject)
36
+ throw new Error("[entitlement] 'sa' binding requires subject");
37
+ if (input.binding === 'bearer' && !input.voucherId)
38
+ throw new Error("[entitlement] 'bearer' binding requires voucherId");
39
+ if (input.maxUses < 1)
40
+ throw new Error('[entitlement] maxUses must be >= 1');
41
+ return {
42
+ entitlementId: entitlementId(input),
43
+ binding: input.binding,
44
+ scopeHash: input.scopeHash,
45
+ subject: input.subject,
46
+ voucherId: input.voucherId,
47
+ ttl: input.ttl,
48
+ maxUses: input.maxUses,
49
+ usesLeft: input.maxUses,
50
+ provenance: { mandateId: input.mandateId, settlementHash: input.settlementHash },
51
+ };
52
+ }
53
+ /** Prepaid credit pack = an SA-bound entitlement with `maxUses = count`. */
54
+ export function mintCredits(input) {
55
+ return mintEntitlementOnPayment({ ...input, binding: 'sa', maxUses: input.count });
56
+ }
57
+ /** Fail-closed validity check (does NOT consume). */
58
+ export function checkEntitlement(record, ctx) {
59
+ if (record.binding !== 'sa' && record.binding !== 'bearer')
60
+ return { ok: false, reason: 'unknown entitlement binding' };
61
+ if (record.scopeHash.toLowerCase() !== ctx.scopeHash.toLowerCase())
62
+ return { ok: false, reason: 'scope mismatch' };
63
+ if (ctx.now >= record.ttl)
64
+ return { ok: false, reason: 'entitlement expired' };
65
+ if (record.usesLeft <= 0)
66
+ return { ok: false, reason: 'entitlement exhausted' };
67
+ if (record.binding === 'sa') {
68
+ if (!ctx.presenter || !record.subject || ctx.presenter.toLowerCase() !== record.subject.toLowerCase()) {
69
+ return { ok: false, reason: 'presenter is not the entitlement subject' };
70
+ }
71
+ }
72
+ else {
73
+ if (!ctx.voucherId || !record.voucherId || ctx.voucherId.toLowerCase() !== record.voucherId.toLowerCase()) {
74
+ return { ok: false, reason: 'voucher mismatch' };
75
+ }
76
+ }
77
+ return { ok: true };
78
+ }
79
+ /**
80
+ * Validate + decrement (PURE — returns the updated record; does NOT persist).
81
+ *
82
+ * entitlement-consume-toctou-no-atomic-claim (2026-07-04 self-audit): on its own this is a TOCTOU seam.
83
+ * A caller that does `checkEntitlement()` (or `consumeEntitlement()`) and THEN persists `record.usesLeft`
84
+ * has a read→decrement→write window: two concurrent redemptions of a prepaid `usesLeft:1` credit can both
85
+ * read 1 and both write 0, double-spending a money-equivalent pack. Use this only in-process/single-writer.
86
+ * For a shared/persisted entitlement, go through {@link EntitlementStore.claimUse}, whose atomic conditional
87
+ * decrement is the ARCH-H3 sibling of `SpentSet.claim`.
88
+ */
89
+ export function consumeEntitlement(record, ctx) {
90
+ const v = checkEntitlement(record, ctx);
91
+ if (!v.ok)
92
+ return v;
93
+ const updated = { ...record, usesLeft: record.usesLeft - 1 };
94
+ return {
95
+ ok: true,
96
+ record: updated,
97
+ consumption: { entitlementId: record.entitlementId, scopeHash: record.scopeHash, usesLeftAfter: updated.usesLeft, at: ctx.now },
98
+ };
99
+ }
100
+ /**
101
+ * Reference in-memory {@link EntitlementStore}. In-process JS is single-threaded, so the validate +
102
+ * decrement below is naturally atomic — the interface demands the same guarantee of every (distributed)
103
+ * implementer. Seed it with the minted records; `claimUse` mutates `usesLeft` in place under the claim.
104
+ */
105
+ export function createMemoryEntitlementStore(records = []) {
106
+ const byId = new Map();
107
+ for (const r of records)
108
+ byId.set(r.entitlementId.toLowerCase(), { ...r });
109
+ return {
110
+ put: (r) => byId.set(r.entitlementId.toLowerCase(), { ...r }),
111
+ get: (id) => byId.get(id.toLowerCase()),
112
+ claimUse: (id, ctx) => {
113
+ const record = byId.get(id.toLowerCase());
114
+ if (!record)
115
+ return { ok: false, reason: 'entitlement not found' };
116
+ const result = consumeEntitlement(record, ctx);
117
+ if (!result.ok)
118
+ return result;
119
+ byId.set(id.toLowerCase(), result.record); // commit the decrement under the same synchronous claim
120
+ return result;
121
+ },
122
+ };
123
+ }
124
+ /** Convenience: keccak of a resource/skill scope string → `scopeHash`. */
125
+ export function scopeHashOf(scope) {
126
+ return keccak256(toBytes(`entitlement-scope:${scope}`));
127
+ }
128
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/entitlement/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * spec 272 §10 tier A3 — blind bearer vouchers (Privacy Pass / RFC 9497 VOPRF).
3
+ *
4
+ * Pay once → receive a pack of UNLINKABLE one-use vouchers → redeem each from a
5
+ * separate context with no link back to the purchase. Built on ristretto255 VOPRF
6
+ * (`@noble/curves`) — the issuer never sees the unblinded token at issuance, so the
7
+ * blinded request it signs and the token presented at redemption cannot be linked.
8
+ *
9
+ * Flow:
10
+ * client blindVoucherRequest() → { request(blinded), secret(tokenId,blind,blinded) }
11
+ * issuer issueVoucher(key, request) → { evaluated, proof } (VOPRF blind-evaluate)
12
+ * client unblindVoucher(secret, issued, pubKey) → Voucher (verifies the issuer proof)
13
+ * issuer redeemVoucher(key, voucher, spentSet) → ok | reason (VOPRF verify + double-spend)
14
+ *
15
+ * One-use is enforced by the spent-set keyed on `voucherId = keccak(tokenId)`.
16
+ */
17
+ import type { Hex } from '@agenticprimitives/types';
18
+ import type { Hex32 } from '../index.js';
19
+ export interface VoucherIssuerKey {
20
+ secretKey: Hex;
21
+ publicKey: Hex;
22
+ }
23
+ export interface BlindedVoucherRequest {
24
+ blinded: Hex;
25
+ }
26
+ /** The client's unblinding state — kept private until `unblindVoucher`. */
27
+ export interface VoucherSecret {
28
+ tokenId: Hex;
29
+ blind: Hex;
30
+ blinded: Hex;
31
+ }
32
+ export interface IssuedVoucher {
33
+ evaluated: Hex;
34
+ proof: Hex;
35
+ }
36
+ /** A redeemable one-use bearer token. */
37
+ export interface Voucher {
38
+ voucherId: Hex32;
39
+ tokenId: Hex;
40
+ output: Hex;
41
+ }
42
+ export declare function generateVoucherIssuerKey(): VoucherIssuerKey;
43
+ /** Deterministic issuer key from a 32-byte seed (stable across processes). */
44
+ export declare function deriveVoucherIssuerKey(seed: Hex, info?: string): VoucherIssuerKey;
45
+ /** `voucherId` — the public, spent-set key derived from the token (no link to the blinded request). */
46
+ export declare function voucherIdOf(tokenId: Hex): Hex32;
47
+ /** Client: blind a fresh random token (or a supplied one) for issuance. */
48
+ export declare function blindVoucherRequest(tokenId?: Hex): {
49
+ request: BlindedVoucherRequest;
50
+ secret: VoucherSecret;
51
+ };
52
+ /** Issuer: blind-evaluate one request (VOPRF — issuer learns nothing about the token). */
53
+ export declare function issueVoucher(key: VoucherIssuerKey, request: BlindedVoucherRequest): IssuedVoucher;
54
+ /** Issuer: issue a whole pack. */
55
+ export declare function issueVouchers(key: VoucherIssuerKey, requests: BlindedVoucherRequest[]): IssuedVoucher[];
56
+ /**
57
+ * Client: unblind into a finished voucher. Throws if the issuer's VOPRF proof fails
58
+ * (a malicious issuer using the wrong key is detected here — verifiability).
59
+ */
60
+ export declare function unblindVoucher(secret: VoucherSecret, issued: IssuedVoucher, issuerPublicKey: Hex): Voucher;
61
+ /** Issuer: VOPRF validity of a presented voucher (does NOT check double-spend). Fail-closed. */
62
+ export declare function verifyVoucher(key: VoucherIssuerKey, voucher: Voucher): {
63
+ ok: boolean;
64
+ reason?: string;
65
+ };
66
+ export interface SpentSet {
67
+ /**
68
+ * ARCH-H3 (seam audit): ATOMIC claim of a one-use id. Returns `true` if THIS call claimed the id
69
+ * (it was fresh), `false` if it was already spent. Replaces the former TOCTOU `has()` + `add()` pair —
70
+ * a check-then-add across an `await` let two concurrent redemptions of a money-equivalent one-use
71
+ * voucher BOTH succeed. A distributed backend MUST implement this as an insert-if-absent (D1 `INSERT
72
+ * ... ON CONFLICT DO NOTHING` + rows-affected, a Durable Object transaction, or a conditional put) so
73
+ * the atomicity lives in the interface, not in each caller. Mirrors x402 `NonceReservationStore.reserve`.
74
+ */
75
+ claim(id: Hex32): boolean | Promise<boolean>;
76
+ }
77
+ export declare function createMemorySpentSet(): SpentSet & {
78
+ size(): number;
79
+ };
80
+ /** Issuer: verify + one-shot redeem. Rejects an invalid voucher and a replayed one. */
81
+ export declare function redeemVoucher(key: VoucherIssuerKey, voucher: Voucher, spent: SpentSet): Promise<{
82
+ ok: boolean;
83
+ reason?: string;
84
+ }>;
85
+ //# sourceMappingURL=voucher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voucher.d.ts","sourceRoot":"","sources":["../../src/entitlement/voucher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAezC,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,GAAG,CAAC;IACf,SAAS,EAAE,GAAG,CAAC;CAChB;AACD,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,GAAG,CAAC;CACd;AACD,2EAA2E;AAC3E,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,GAAG,CAAC;IACb,KAAK,EAAE,GAAG,CAAC;IACX,OAAO,EAAE,GAAG,CAAC;CACd;AACD,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,GAAG,CAAC;IACf,KAAK,EAAE,GAAG,CAAC;CACZ;AACD,yCAAyC;AACzC,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,KAAK,CAAC;IACjB,OAAO,EAAE,GAAG,CAAC;IACb,MAAM,EAAE,GAAG,CAAC;CACb;AAED,wBAAgB,wBAAwB,IAAI,gBAAgB,CAG3D;AAED,8EAA8E;AAC9E,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,SAA2B,GAAG,gBAAgB,CAGnG;AAED,uGAAuG;AACvG,wBAAgB,WAAW,CAAC,OAAO,EAAE,GAAG,GAAG,KAAK,CAE/C;AAED,2EAA2E;AAC3E,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE,GAAG,GAAG;IAAE,OAAO,EAAE,qBAAqB,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,CAO5G;AAED,0FAA0F;AAC1F,wBAAgB,YAAY,CAAC,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,qBAAqB,GAAG,aAAa,CAGjG;AAED,kCAAkC;AAClC,wBAAgB,aAAa,CAAC,GAAG,EAAE,gBAAgB,EAAE,QAAQ,EAAE,qBAAqB,EAAE,GAAG,aAAa,EAAE,CAEvG;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,EAAE,eAAe,EAAE,GAAG,GAAG,OAAO,CAU1G;AASD,gGAAgG;AAChG,wBAAgB,aAAa,CAAC,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,OAAO,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAUvG;AAED,MAAM,WAAW,QAAQ;IACvB;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,EAAE,KAAK,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9C;AAED,wBAAgB,oBAAoB,IAAI,QAAQ,GAAG;IAAE,IAAI,IAAI,MAAM,CAAA;CAAE,CAapE;AAED,uFAAuF;AACvF,wBAAsB,aAAa,CAAC,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAMvI"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * spec 272 §10 tier A3 — blind bearer vouchers (Privacy Pass / RFC 9497 VOPRF).
3
+ *
4
+ * Pay once → receive a pack of UNLINKABLE one-use vouchers → redeem each from a
5
+ * separate context with no link back to the purchase. Built on ristretto255 VOPRF
6
+ * (`@noble/curves`) — the issuer never sees the unblinded token at issuance, so the
7
+ * blinded request it signs and the token presented at redemption cannot be linked.
8
+ *
9
+ * Flow:
10
+ * client blindVoucherRequest() → { request(blinded), secret(tokenId,blind,blinded) }
11
+ * issuer issueVoucher(key, request) → { evaluated, proof } (VOPRF blind-evaluate)
12
+ * client unblindVoucher(secret, issued, pubKey) → Voucher (verifies the issuer proof)
13
+ * issuer redeemVoucher(key, voucher, spentSet) → ok | reason (VOPRF verify + double-spend)
14
+ *
15
+ * One-use is enforced by the spent-set keyed on `voucherId = keccak(tokenId)`.
16
+ */
17
+ import { ristretto255_oprf } from '@noble/curves/ed25519.js';
18
+ import { bytesToHex, hexToBytes } from '@noble/hashes/utils.js';
19
+ import { keccak256 } from 'viem';
20
+ const voprf = ristretto255_oprf.voprf;
21
+ const enc = new TextEncoder();
22
+ // @noble bytesToHex returns NO `0x` prefix; add it so values are real `Hex` and `.slice(2)` strips it.
23
+ const hx = (b) => ('0x' + bytesToHex(b));
24
+ export function generateVoucherIssuerKey() {
25
+ const kp = voprf.generateKeyPair();
26
+ return { secretKey: hx(kp.secretKey), publicKey: hx(kp.publicKey) };
27
+ }
28
+ /** Deterministic issuer key from a 32-byte seed (stable across processes). */
29
+ export function deriveVoucherIssuerKey(seed, info = 'agentic-voucher-issuer') {
30
+ const kp = voprf.deriveKeyPair(hexToBytes(seed.slice(2)), enc.encode(info));
31
+ return { secretKey: hx(kp.secretKey), publicKey: hx(kp.publicKey) };
32
+ }
33
+ /** `voucherId` — the public, spent-set key derived from the token (no link to the blinded request). */
34
+ export function voucherIdOf(tokenId) {
35
+ return keccak256(tokenId);
36
+ }
37
+ /** Client: blind a fresh random token (or a supplied one) for issuance. */
38
+ export function blindVoucherRequest(tokenId) {
39
+ const tok = tokenId ? hexToBytes(tokenId.slice(2)) : globalThis.crypto.getRandomValues(new Uint8Array(32));
40
+ const { blind, blinded } = voprf.blind(tok);
41
+ return {
42
+ request: { blinded: hx(blinded) },
43
+ secret: { tokenId: hx(tok), blind: hx(blind), blinded: hx(blinded) },
44
+ };
45
+ }
46
+ /** Issuer: blind-evaluate one request (VOPRF — issuer learns nothing about the token). */
47
+ export function issueVoucher(key, request) {
48
+ const be = voprf.blindEvaluate(hexToBytes(key.secretKey.slice(2)), hexToBytes(key.publicKey.slice(2)), hexToBytes(request.blinded.slice(2)));
49
+ return { evaluated: hx(be.evaluated), proof: hx(be.proof) };
50
+ }
51
+ /** Issuer: issue a whole pack. */
52
+ export function issueVouchers(key, requests) {
53
+ return requests.map((r) => issueVoucher(key, r));
54
+ }
55
+ /**
56
+ * Client: unblind into a finished voucher. Throws if the issuer's VOPRF proof fails
57
+ * (a malicious issuer using the wrong key is detected here — verifiability).
58
+ */
59
+ export function unblindVoucher(secret, issued, issuerPublicKey) {
60
+ const output = voprf.finalize(hexToBytes(secret.tokenId.slice(2)), hexToBytes(secret.blind.slice(2)), hexToBytes(issued.evaluated.slice(2)), hexToBytes(secret.blinded.slice(2)), hexToBytes(issuerPublicKey.slice(2)), hexToBytes(issued.proof.slice(2)));
61
+ return { voucherId: voucherIdOf(secret.tokenId), tokenId: secret.tokenId, output: hx(output) };
62
+ }
63
+ function ctEqual(a, b) {
64
+ if (a.length !== b.length)
65
+ return false;
66
+ let d = 0;
67
+ for (let i = 0; i < a.length; i++)
68
+ d |= a[i] ^ b[i];
69
+ return d === 0;
70
+ }
71
+ /** Issuer: VOPRF validity of a presented voucher (does NOT check double-spend). Fail-closed. */
72
+ export function verifyVoucher(key, voucher) {
73
+ try {
74
+ if (voucher.voucherId.toLowerCase() !== voucherIdOf(voucher.tokenId).toLowerCase()) {
75
+ return { ok: false, reason: 'voucherId does not match tokenId' };
76
+ }
77
+ const expected = voprf.evaluate(hexToBytes(key.secretKey.slice(2)), hexToBytes(voucher.tokenId.slice(2)));
78
+ return ctEqual(expected, hexToBytes(voucher.output.slice(2))) ? { ok: true } : { ok: false, reason: 'invalid voucher' };
79
+ }
80
+ catch {
81
+ return { ok: false, reason: 'malformed voucher' };
82
+ }
83
+ }
84
+ export function createMemorySpentSet() {
85
+ const set = new Set();
86
+ return {
87
+ // In-process JS is single-threaded, so test-and-set here is naturally atomic; the interface demands
88
+ // the same guarantee of every (distributed) implementer.
89
+ claim: (id) => {
90
+ const k = id.toLowerCase();
91
+ if (set.has(k))
92
+ return false;
93
+ set.add(k);
94
+ return true;
95
+ },
96
+ size: () => set.size,
97
+ };
98
+ }
99
+ /** Issuer: verify + one-shot redeem. Rejects an invalid voucher and a replayed one. */
100
+ export async function redeemVoucher(key, voucher, spent) {
101
+ const v = verifyVoucher(key, voucher);
102
+ if (!v.ok)
103
+ return v;
104
+ // ARCH-H3: atomic claim — no check-then-add window. Two concurrent redemptions can't both win.
105
+ if (!(await spent.claim(voucher.voucherId)))
106
+ return { ok: false, reason: 'voucher already spent' };
107
+ return { ok: true };
108
+ }
109
+ //# sourceMappingURL=voucher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voucher.js","sourceRoot":"","sources":["../../src/entitlement/voucher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import type { Hex32 } from './index.js';
2
+ /** A payment credential a company or PSP issued for ONE operation — held by REFERENCE, bound by digest, expiring. */
3
+ export interface ExternalPaymentCredentialRefV1 {
4
+ type: 'ap.external-payment-credential.v1';
5
+ /** Who issued it: the PSP / credential provider, as an https origin. */
6
+ provider: string;
7
+ /** An opaque reference to the credential sealed in the vault or held by the provider — never the token itself. */
8
+ credentialRef: string;
9
+ /** The external operation this credential may settle (`externalOperationIntentDigest`); any other is refused. */
10
+ boundToIntentDigest: Hex32;
11
+ /** Unix seconds; short by design. */
12
+ expiresAt: number;
13
+ singleUse: true;
14
+ }
15
+ export type Ap2MandateKind = 'intent' | 'cart' | 'payment';
16
+ /** OUR mandate in THEIR envelope: a VC-JWS the Smart Agent signed, carrying the spec 336 mandate by digest. */
17
+ export interface Ap2MandateEnvelopeRefV1 {
18
+ type: 'ap.ap2-mandate-envelope.v1';
19
+ kind: Ap2MandateKind;
20
+ /** The spec 336 mandate (delegation + intent-digest caveat) this envelope carries, by digest. The authority is there, not here. */
21
+ mandateDigest: Hex32;
22
+ /** The Smart Agent that signed the VC-JWS (CAIP-10); verified through ERC-1271, never a bare key. */
23
+ subject: string;
24
+ envelope: 'vc-jws';
25
+ /** The compact JWS, when rendered. Absent in a record that only names the mandate. */
26
+ jws?: string;
27
+ expiresAt: number;
28
+ }
29
+ /** A JWT, a PAN or a long bare token where a REFERENCE belongs. */
30
+ export declare function looksLikeRawPaymentCredential(s: string): boolean;
31
+ export declare function validateExternalPaymentCredentialRef(c: unknown): string[];
32
+ export declare function validateAp2MandateEnvelopeRef(e: unknown): string[];
33
+ /** May this credential settle THIS operation now? Bound by digest, expiring, single-use — nothing else is asked here. */
34
+ export declare function paymentCredentialCovers(c: ExternalPaymentCredentialRefV1, intentDigest: Hex32, now: number): {
35
+ ok: true;
36
+ } | {
37
+ ok: false;
38
+ reason: 'CREDENTIAL_MALFORMED' | 'CREDENTIAL_NOT_BOUND_TO_OPERATION' | 'CREDENTIAL_EXPIRED';
39
+ };
40
+ //# sourceMappingURL=external-checkout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"external-checkout.d.ts","sourceRoot":"","sources":["../src/external-checkout.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,qHAAqH;AACrH,MAAM,WAAW,8BAA8B;IAC7C,IAAI,EAAE,mCAAmC,CAAC;IAC1C,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,kHAAkH;IAClH,aAAa,EAAE,MAAM,CAAC;IACtB,iHAAiH;IACjH,mBAAmB,EAAE,KAAK,CAAC;IAC3B,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAE3D,+GAA+G;AAC/G,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,4BAA4B,CAAC;IACnC,IAAI,EAAE,cAAc,CAAC;IACrB,mIAAmI;IACnI,aAAa,EAAE,KAAK,CAAC;IACrB,qGAAqG;IACrG,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,QAAQ,CAAC;IACnB,sFAAsF;IACtF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD,mEAAmE;AACnE,wBAAgB,6BAA6B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAEhE;AAED,wBAAgB,oCAAoC,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,EAAE,CAYzE;AAED,wBAAgB,6BAA6B,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,EAAE,CAYlE;AAED,yHAAyH;AACzH,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,8BAA8B,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,sBAAsB,GAAG,mCAAmC,GAAG,oBAAoB,CAAA;CAAE,CAKtO"}
@@ -0,0 +1,70 @@
1
+ // PAYMENTS AT THE COMPANY'S DOOR — types only (spec 442 §10; spec 337 §4.3).
2
+ //
3
+ // ACP's Shared Payment Token and UCP's payment-token-exchange output are the `apeng:ExecutionCredential` discipline:
4
+ // the agent never sees raw credentials; the credential is short-lived and bound to ONE checkout. AP2's three
5
+ // mandates (intent · cart · payment) are W3C VCs; ours is the spec 336 mandate, and when a UCP checkout wants
6
+ // "AP2 mandate JWTs in the body" it carries OUR mandate in THEIR envelope — a VC-JWS the Smart Agent signs
7
+ // (ERC-1271 through `verifiable-credentials`). Fiat rails (cards, PAR, PSP exchange) stay Ring 1 (442 §14).
8
+ //
9
+ // Nothing here moves value or signs; these are the reference shapes the ap-federation projections render, and the
10
+ // validators refuse the one thing that must never be in a record: a raw credential.
11
+ const HEX32 = /^0x[0-9a-f]{64}$/;
12
+ const HTTPS_ORIGIN = /^https:\/\/[^\s/?#]+$/;
13
+ const CAIP10_EVM = /^eip155:\d+:0x[0-9a-fA-F]{40}$/;
14
+ /** A JWT, a PAN or a long bare token where a REFERENCE belongs. */
15
+ export function looksLikeRawPaymentCredential(s) {
16
+ return /^ey[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\./.test(s) || /^\d{13,19}$/.test(s) || /^(tok|pm|spt)_[A-Za-z0-9]{16,}$/.test(s);
17
+ }
18
+ export function validateExternalPaymentCredentialRef(c) {
19
+ const issues = [];
20
+ if (typeof c !== 'object' || c === null || Array.isArray(c))
21
+ return ['credential: must be an object'];
22
+ const x = c;
23
+ if (x.type !== 'ap.external-payment-credential.v1')
24
+ issues.push('credential.type: must be ap.external-payment-credential.v1');
25
+ if (typeof x.provider !== 'string' || !HTTPS_ORIGIN.test(x.provider))
26
+ issues.push('credential.provider: must be an https origin');
27
+ if (typeof x.credentialRef !== 'string' || !x.credentialRef)
28
+ issues.push('credential.credentialRef: required');
29
+ else if (looksLikeRawPaymentCredential(x.credentialRef))
30
+ issues.push('credential.credentialRef: looks like a raw payment credential — the agent never holds one; a reference only');
31
+ if (typeof x.boundToIntentDigest !== 'string' || !HEX32.test(x.boundToIntentDigest))
32
+ issues.push('credential.boundToIntentDigest: must be 0x + 64 lowercase hex');
33
+ if (!Number.isInteger(x.expiresAt) || x.expiresAt <= 0)
34
+ issues.push('credential.expiresAt: must be a positive integer');
35
+ if (x.singleUse !== true)
36
+ issues.push('credential.singleUse: must be true — a reusable payment credential is a card on file, which is Ring 1');
37
+ return issues;
38
+ }
39
+ export function validateAp2MandateEnvelopeRef(e) {
40
+ const issues = [];
41
+ if (typeof e !== 'object' || e === null || Array.isArray(e))
42
+ return ['envelope: must be an object'];
43
+ const x = e;
44
+ if (x.type !== 'ap.ap2-mandate-envelope.v1')
45
+ issues.push('envelope.type: must be ap.ap2-mandate-envelope.v1');
46
+ if (x.kind !== 'intent' && x.kind !== 'cart' && x.kind !== 'payment')
47
+ issues.push('envelope.kind: must be intent | cart | payment');
48
+ if (typeof x.mandateDigest !== 'string' || !HEX32.test(x.mandateDigest))
49
+ issues.push('envelope.mandateDigest: must be 0x + 64 lowercase hex');
50
+ if (typeof x.subject !== 'string' || !CAIP10_EVM.test(x.subject))
51
+ issues.push('envelope.subject: must be a CAIP-10 Smart Agent');
52
+ if (x.envelope !== 'vc-jws')
53
+ issues.push('envelope.envelope: must be vc-jws');
54
+ if (x.jws !== undefined && (typeof x.jws !== 'string' || x.jws.split('.').length !== 3))
55
+ issues.push('envelope.jws: must be a compact JWS');
56
+ if (!Number.isInteger(x.expiresAt) || x.expiresAt <= 0)
57
+ issues.push('envelope.expiresAt: must be a positive integer');
58
+ return issues;
59
+ }
60
+ /** May this credential settle THIS operation now? Bound by digest, expiring, single-use — nothing else is asked here. */
61
+ export function paymentCredentialCovers(c, intentDigest, now) {
62
+ if (validateExternalPaymentCredentialRef(c).length)
63
+ return { ok: false, reason: 'CREDENTIAL_MALFORMED' };
64
+ if (c.boundToIntentDigest.toLowerCase() !== intentDigest.toLowerCase())
65
+ return { ok: false, reason: 'CREDENTIAL_NOT_BOUND_TO_OPERATION' };
66
+ if (c.expiresAt <= now)
67
+ return { ok: false, reason: 'CREDENTIAL_EXPIRED' };
68
+ return { ok: true };
69
+ }
70
+ //# sourceMappingURL=external-checkout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"external-checkout.js","sourceRoot":"","sources":["../src/external-checkout.ts"],"names":[],"mappings":"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"}