agent-passport-system 1.5.1 → 1.7.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
@@ -2,12 +2,12 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/agent-passport-system)](https://www.npmjs.com/package/agent-passport-system)
4
4
  [![license](https://img.shields.io/npm/l/agent-passport-system)](https://github.com/aeoess/agent-passport-system/blob/main/LICENSE)
5
- [![tests](https://img.shields.io/badge/tests-165%20passing-brightgreen)](https://github.com/aeoess/agent-passport-system)
5
+ [![tests](https://img.shields.io/badge/tests-182%20passing-brightgreen)](https://github.com/aeoess/agent-passport-system)
6
6
  [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.18749779.svg)](https://doi.org/10.5281/zenodo.18749779)
7
7
 
8
- Cryptographic identity, ethical governance, economic attribution, protocol-native communication, intent architecture, cascade revocation, and coordination primitives for autonomous AI agents.
8
+ Cryptographic identity, ethical governance, economic attribution, protocol-native communication, intent architecture, cascade revocation, coordination primitives, and agentic commerce for autonomous AI agents.
9
9
 
10
- **7 layers. 165 tests. Zero heavy dependencies. Running code. MCP server included.**
10
+ **8 layers. 182 tests. Zero heavy dependencies. Running code. MCP server included.**
11
11
 
12
12
  > *As AI agents from different creators, running different models, serving different humans begin to collaborate — who is responsible, under what authority, according to what values, and who benefits?*
13
13
 
@@ -231,10 +231,76 @@ const completion = completeTask(brief.id, {
231
231
  }, operatorKeys)
232
232
  ```
233
233
 
234
+ ### Layer 8 — Agentic Commerce (ACP by OpenAI + Stripe)
235
+
236
+ ```typescript
237
+ import {
238
+ commercePreflight, createCheckout, completeCheckout,
239
+ createCommerceDelegation, getSpendSummary,
240
+ requestHumanApproval, verifyCommerceReceipt
241
+ } from 'agent-passport-system'
242
+
243
+ // Create a commerce-scoped delegation with spend limit
244
+ const delegation = createCommerceDelegation({
245
+ delegatorKeys: humanKeys,
246
+ agentPublicKey: agent.publicKey,
247
+ spendLimit: 500,
248
+ allowedMerchants: ['merchant.example.com'],
249
+ currency: 'usd',
250
+ expiresAt: '2026-04-01T00:00:00Z'
251
+ })
252
+
253
+ // 4-gate preflight check before any merchant interaction
254
+ const preflight = commercePreflight(agent.passport, delegation, {
255
+ amount: { amount: 4999, currency: 'usd' }, // $49.99
256
+ merchant: 'merchant.example.com'
257
+ })
258
+ // → { approved: true, gates: { passport: ✓, scope: ✓, spend: ✓, merchant: ✓ } }
259
+
260
+ // Create ACP checkout session with merchant
261
+ const session = await createCheckout('https://merchant.example.com', {
262
+ lineItems: [{ name: 'Cloud API Credits', quantity: 1, price: { amount: 4999, currency: 'usd' } }],
263
+ agentPassport: agent.passport,
264
+ delegation
265
+ })
266
+
267
+ // Check if human approval needed (configurable threshold)
268
+ if (session.total.amount > config.humanApprovalThreshold) {
269
+ const approval = requestHumanApproval(session, agent, delegation)
270
+ // → { requestId, amount, merchant, beneficiary, expiresAt }
271
+ // Wait for human confirmation before proceeding
272
+ }
273
+
274
+ // Complete purchase → signed receipt with beneficiary attribution
275
+ const receipt = await completeCheckout(session.id, {
276
+ paymentToken: sharedPaymentToken,
277
+ agentKeys: agent.keys,
278
+ delegation
279
+ })
280
+
281
+ // Verify any commerce receipt (tamper-proof)
282
+ const valid = verifyCommerceReceipt(receipt)
283
+ // → true (Ed25519 signature over canonical JSON)
284
+
285
+ // Track spending against delegation limits
286
+ const summary = getSpendSummary(delegation, allReceipts)
287
+ // → { limit: 500, spent: 49.99, remaining: 450.01, utilization: '10.0%', nearLimit: false }
288
+ ```
289
+
290
+ **4-gate enforcement pipeline:** Every purchase passes through passport verification (Ed25519 signature), delegation scope check (must have `commerce:checkout`), spend limit enforcement (amount ≤ remaining budget), and optional merchant allowlist. Agents cannot bypass gates — the cryptography prevents it.
291
+
292
+ **Human approval thresholds:** Purchases above a configurable amount require explicit human confirmation. The agent generates an approval request; the human signs it. No unsigned approvals accepted.
293
+
294
+ **Beneficiary attribution:** Every purchase receipt traces back to a human principal through the delegation chain. Who authorized the spend, under what limits, and who benefits — cryptographically provable.
295
+
234
296
  ## Architecture
235
297
 
236
298
  ```
237
299
  ┌─────────────────────────────────────────────────┐
300
+ │ Layer 8: Agentic Commerce (ACP) │
301
+ │ 4-gate preflight · Spend tracking · Human │
302
+ │ approval · Signed receipts · Beneficiary trace │
303
+ ├─────────────────────────────────────────────────┤
238
304
  │ Layer 7: Coordination Primitives │
239
305
  │ Task briefs · Role assignment · Evidence · │
240
306
  │ Review gates · Handoffs · Deliverables · Metrics│
@@ -279,6 +345,8 @@ const completion = completeTask(brief.id, {
279
345
 
280
346
  **Layer 7 — Coordination Primitives.** Protocol-native multi-agent task orchestration. Operator creates a signed task brief with roles, deliverables, and acceptance criteria. Agents are assigned to roles and sign acceptance. Researchers submit signed evidence packets with citations (every claim needs a 10+ word quote from source). Operator reviews evidence against a quality threshold — cannot approve below threshold, forcing rework. Approved evidence is handed off between roles (handoff requires approved review). Analysts submit deliverables citing evidence packets. Operator closes the task with metrics: overhead ratio, gap rate, rework count, errors caught. Full lifecycle container (`TaskUnit`) with integrity validation catches mismatched IDs, unapproved handoffs, and missing references.
281
347
 
348
+ **Layer 8 — Agentic Commerce (ACP by OpenAI + Stripe).** Implements the [Agentic Commerce Protocol](https://openai.com/index/agentic-commerce-protocol/) identity and governance layer. 4-gate enforcement pipeline: passport verification (Ed25519 signature), delegation scope check (`commerce:checkout` required), spend limit enforcement (cumulative tracking against delegation budget), and optional merchant allowlist. Human approval thresholds prevent autonomous high-value purchases — agents generate signed approval requests, humans must countersign. Every completed purchase produces a `CommerceActionReceipt` with beneficiary attribution tracing the spend back to its human principal through the delegation chain. Spend analytics with utilization warnings at 80%. 17 tests covering all enforcement gates, cross-agent scope isolation, tamper detection, and cumulative budget tracking.
349
+
282
350
  ## Human Values Floor — v0.1
283
351
 
284
352
  | ID | Principle | Enforcement |
@@ -327,7 +395,7 @@ npm: [agent-passport-system-mcp](https://www.npmjs.com/package/agent-passport-sy
327
395
 
328
396
  ```bash
329
397
  npm test
330
- # 165 tests across 12 files, 40 suites, 0 failures
398
+ # 182 tests across 13 files, 40+ suites, 0 failures
331
399
  ```
332
400
 
333
401
  Includes 23 adversarial tests: Merkle tree tampering, attribution gaming resistance, compliance violations, floor negotiation attacks, wrong-key attestations.
@@ -336,6 +404,8 @@ Includes 23 adversarial tests: Merkle tree tampering, attribution gaming resista
336
404
 
337
405
  17 coordination tests: task brief creation/verification, role assignment, evidence submission, review gates (score vs threshold), handoff enforcement (requires approved review), deliverable submission, full lifecycle, task unit validation.
338
406
 
407
+ 17 commerce tests: delegation creation with commerce scopes, 4-gate preflight (passport, scope, spend, merchant), spend analytics, human approval request generation, receipt signing/verification, tamper detection, cross-agent scope enforcement, cumulative spend tracking.
408
+
339
409
  ## Paper
340
410
 
341
411
  **"The Agent Social Contract: Cryptographic Identity, Ethical Governance, and Beneficiary Economics for Autonomous AI Agents"**
@@ -356,13 +426,14 @@ By Tymofii Pidlisnyi — Published on Zenodo
356
426
  | Attribution | Merkle proofs | — | — | — | — |
357
427
  | Communication | Signed Agora | — | — | — | — |
358
428
  | Coordination | Task units + MCP server | — | — | — | — |
359
- | Tests | 165 (23 adversarial) | None | Limited | None | None |
429
+ | Commerce | ACP + 4-gate enforcement | | | | |
430
+ | Tests | 182 (23 adversarial) | None | Limited | None | None |
360
431
  | Dependencies | Node.js crypto + uuid | — | Multi-LLM | — | Consensus network |
361
432
 
362
433
  ## Structure
363
434
 
364
435
  ```
365
- src/ 21 source files
436
+ src/ 22 source files
366
437
  contract.ts — High-level API (6 functions)
367
438
  core/
368
439
  passport.ts — Ed25519 identity
@@ -373,6 +444,7 @@ src/ 21 source files
373
444
  intent.ts — Intent architecture, deliberation, roles
374
445
  policy.ts — 3-signature chain, policy validation
375
446
  coordination.ts — Task briefs, evidence, review, handoff, deliverables
447
+ commerce.ts — ACP checkout, 4-gate enforcement, spend tracking
376
448
  cli/
377
449
  index.ts — CLI (14 commands)
378
450
  crypto/
@@ -383,7 +455,8 @@ src/ 21 source files
383
455
  intent.ts — Layer 5 types
384
456
  policy.ts — Layer 6 types
385
457
  coordination.ts — Layer 7 types
386
- tests/ 12 test files, 165 tests (40 suites)
458
+ commerce.ts — Layer 8 types
459
+ tests/ 13 test files, 182 tests (40+ suites)
387
460
  adversarial.ts — 23 adversarial cases
388
461
  agora.test.ts — 15 Agora tests
389
462
  contract.test.ts — High-level API tests
@@ -396,6 +469,7 @@ tests/ 12 test files, 165 tests (40 suites)
396
469
  policy.test.ts — Intent, policy decision, 3-sig chain
397
470
  cascade.test.ts — Chain registry, cascade revocation, batch
398
471
  coordination.test.ts — Task briefs, evidence, review, handoff, lifecycle
472
+ commerce.test.ts — ACP checkout, 4-gate preflight, spend tracking
399
473
  values/
400
474
  floor.yaml — Human Values Floor manifest
401
475
  papers/
@@ -0,0 +1,100 @@
1
+ import type { SignedPassport } from '../types/passport.js';
2
+ import type { ACPCheckoutSession, ACPLineItem, ACPMoney, ACPAddress, CommerceConfig, CommerceDelegation, CommercePreflightResult, CommerceActionReceipt, HumanApprovalRequest } from '../types/commerce.js';
3
+ export declare function commercePreflight(opts: {
4
+ signedPassport: SignedPassport;
5
+ delegation: CommerceDelegation;
6
+ merchantName: string;
7
+ estimatedTotal: ACPMoney;
8
+ config?: CommerceConfig;
9
+ }): CommercePreflightResult;
10
+ export declare function createCheckout(opts: {
11
+ signedPassport: SignedPassport;
12
+ delegation: CommerceDelegation;
13
+ config: CommerceConfig;
14
+ items: {
15
+ skuId: string;
16
+ quantity: number;
17
+ }[];
18
+ customer?: {
19
+ name?: string;
20
+ email?: string;
21
+ };
22
+ fulfillmentAddress?: ACPAddress;
23
+ privateKey: string;
24
+ }): Promise<{
25
+ session: ACPCheckoutSession;
26
+ receipt: CommerceActionReceipt;
27
+ }>;
28
+ export declare function updateCheckout(opts: {
29
+ signedPassport: SignedPassport;
30
+ delegation: CommerceDelegation;
31
+ config: CommerceConfig;
32
+ sessionId: string;
33
+ updates: {
34
+ items?: {
35
+ id: string;
36
+ quantity: number;
37
+ }[];
38
+ fulfillmentAddress?: ACPAddress;
39
+ fulfillmentOptionId?: string;
40
+ };
41
+ privateKey: string;
42
+ }): Promise<{
43
+ session: ACPCheckoutSession;
44
+ receipt: CommerceActionReceipt;
45
+ }>;
46
+ export declare function completeCheckout(opts: {
47
+ signedPassport: SignedPassport;
48
+ delegation: CommerceDelegation;
49
+ config: CommerceConfig;
50
+ sessionId: string;
51
+ paymentToken: string;
52
+ paymentMethod?: string;
53
+ privateKey: string;
54
+ }): Promise<{
55
+ session: ACPCheckoutSession;
56
+ receipt: CommerceActionReceipt;
57
+ spendUpdated: CommerceDelegation;
58
+ }>;
59
+ export declare function cancelCheckout(opts: {
60
+ signedPassport: SignedPassport;
61
+ delegation: CommerceDelegation;
62
+ config: CommerceConfig;
63
+ sessionId: string;
64
+ privateKey: string;
65
+ }): Promise<{
66
+ session: ACPCheckoutSession;
67
+ receipt: CommerceActionReceipt;
68
+ }>;
69
+ export declare function requestHumanApproval(opts: {
70
+ agentId: string;
71
+ delegationId: string;
72
+ merchantName: string;
73
+ items: ACPLineItem[];
74
+ totalAmount: ACPMoney;
75
+ reason: string;
76
+ expiresInMinutes?: number;
77
+ }): HumanApprovalRequest;
78
+ export declare function createCommerceDelegation(opts: {
79
+ agentId: string;
80
+ delegationId: string;
81
+ spendLimit: number;
82
+ currency?: string;
83
+ approvedMerchants?: string[];
84
+ requireHumanApproval?: boolean;
85
+ humanApprovalThreshold?: number;
86
+ additionalScopes?: string[];
87
+ }): CommerceDelegation;
88
+ export declare function getSpendSummary(delegation: CommerceDelegation): {
89
+ limit: number;
90
+ spent: number;
91
+ remaining: number;
92
+ currency: string;
93
+ utilizationPercent: number;
94
+ nearLimit: boolean;
95
+ };
96
+ export declare function verifyCommerceReceipt(receipt: CommerceActionReceipt, publicKey: string): {
97
+ valid: boolean;
98
+ errors: string[];
99
+ };
100
+ //# sourceMappingURL=commerce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commerce.d.ts","sourceRoot":"","sources":["../../../src/core/commerce.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,389 @@
1
+ // ══════════════════════════════════════════════════════════════════
2
+ // Layer 7 — Agentic Commerce: Implementation
3
+ // ══════════════════════════════════════════════════════════════════
4
+ // Integration with the Agentic Commerce Protocol (ACP) by OpenAI + Stripe.
5
+ //
6
+ // Every commerce action flows through a 4-gate pipeline:
7
+ // 1. Passport verification — is this agent who it claims to be?
8
+ // 2. Delegation scope check — does this agent have commerce:checkout?
9
+ // 3. Spend limit check — would this purchase exceed the cap?
10
+ // 4. Values Floor check (F-003 Scoped Authority) — is this within policy?
11
+ //
12
+ // Only after all 4 gates pass does the agent interact with the merchant.
13
+ // Every completed action produces a signed CommerceActionReceipt.
14
+ // ══════════════════════════════════════════════════════════════════
15
+ import { randomBytes } from 'node:crypto';
16
+ import { sign, verify as ed25519Verify } from '../crypto/keys.js';
17
+ import { canonicalize } from './canonical.js';
18
+ import { verifyPassport } from '../verification/verify.js';
19
+ // ── Commerce Scopes ──
20
+ const COMMERCE_SCOPES = [
21
+ 'commerce:checkout',
22
+ 'commerce:browse',
23
+ 'commerce:purchase',
24
+ 'commerce:cancel',
25
+ ];
26
+ function hasScope(delegation, required) {
27
+ return delegation.scope.includes(required) || delegation.scope.includes('commerce:*');
28
+ }
29
+ // ── Preflight Check: 4-Gate Pipeline ──
30
+ export function commercePreflight(opts) {
31
+ const checks = [];
32
+ const warnings = [];
33
+ // Gate 1: Passport verification
34
+ const passportResult = verifyPassport(opts.signedPassport);
35
+ checks.push({
36
+ check: 'passport_valid',
37
+ passed: passportResult.valid,
38
+ detail: passportResult.valid
39
+ ? `Passport verified for ${opts.signedPassport.passport.agentId}`
40
+ : `Passport failed: ${passportResult.errors.join(', ')}`,
41
+ });
42
+ // Gate 2: Delegation scope
43
+ const hasCheckoutScope = hasScope(opts.delegation, 'commerce:checkout');
44
+ checks.push({
45
+ check: 'delegation_scope',
46
+ passed: hasCheckoutScope,
47
+ detail: hasCheckoutScope
48
+ ? `Agent has commerce:checkout scope via delegation ${opts.delegation.delegationId}`
49
+ : `Agent lacks commerce:checkout scope. Has: [${opts.delegation.scope.join(', ')}]`,
50
+ });
51
+ // Gate 3: Spend limit
52
+ const amountInBase = opts.estimatedTotal.amount;
53
+ const remainingBudget = opts.delegation.spendLimit - opts.delegation.spentAmount;
54
+ const withinBudget = amountInBase <= remainingBudget;
55
+ checks.push({
56
+ check: 'spend_limit',
57
+ passed: withinBudget,
58
+ detail: withinBudget
59
+ ? `Purchase ${amountInBase} within budget (${remainingBudget} remaining of ${opts.delegation.spendLimit})`
60
+ : `Purchase ${amountInBase} exceeds remaining budget of ${remainingBudget} (limit: ${opts.delegation.spendLimit}, spent: ${opts.delegation.spentAmount})`,
61
+ });
62
+ // Gate 3b: Human approval threshold
63
+ if (opts.delegation.requireHumanApproval && opts.delegation.humanApprovalThreshold) {
64
+ if (amountInBase > opts.delegation.humanApprovalThreshold) {
65
+ warnings.push(`Purchase of ${amountInBase} exceeds human approval threshold of ${opts.delegation.humanApprovalThreshold}. Human confirmation required.`);
66
+ }
67
+ }
68
+ // Gate 4: Merchant allowlist (if configured)
69
+ if (opts.delegation.approvedMerchants && opts.delegation.approvedMerchants.length > 0) {
70
+ const merchantApproved = opts.delegation.approvedMerchants.includes(opts.merchantName);
71
+ checks.push({
72
+ check: 'merchant_approved',
73
+ passed: merchantApproved,
74
+ detail: merchantApproved
75
+ ? `Merchant "${opts.merchantName}" is on approved list`
76
+ : `Merchant "${opts.merchantName}" is NOT on approved list: [${opts.delegation.approvedMerchants.join(', ')}]`,
77
+ });
78
+ }
79
+ const permitted = checks.every(c => c.passed);
80
+ return {
81
+ permitted,
82
+ checks,
83
+ delegation: opts.delegation,
84
+ warnings,
85
+ blockedReason: permitted ? undefined : checks.find(c => !c.passed)?.detail,
86
+ };
87
+ }
88
+ // ── ACP Client: Create Checkout Session ──
89
+ export async function createCheckout(opts) {
90
+ // Run preflight — estimate total as 0 for creation (real total comes from merchant)
91
+ const preflight = commercePreflight({
92
+ signedPassport: opts.signedPassport,
93
+ delegation: opts.delegation,
94
+ merchantName: opts.config.merchantName,
95
+ estimatedTotal: { amount: 0, currency: opts.delegation.currency },
96
+ });
97
+ if (!preflight.permitted) {
98
+ throw new Error(`Commerce preflight DENIED: ${preflight.blockedReason}`);
99
+ }
100
+ // Build ACP CreateCheckoutRequest
101
+ const requestBody = {
102
+ items: opts.items.map(i => ({ sku_id: i.skuId, quantity: i.quantity })),
103
+ ...(opts.customer && { customer: opts.customer }),
104
+ ...(opts.fulfillmentAddress && { fulfillment_address: opts.fulfillmentAddress }),
105
+ };
106
+ // Call merchant endpoint
107
+ const url = `${opts.config.merchantBaseUrl}/checkout_sessions`;
108
+ const response = await fetch(url, {
109
+ method: 'POST',
110
+ headers: {
111
+ 'Content-Type': 'application/json',
112
+ ...(opts.config.bearerToken && { 'Authorization': `Bearer ${opts.config.bearerToken}` }),
113
+ },
114
+ body: JSON.stringify(requestBody),
115
+ });
116
+ if (!response.ok) {
117
+ throw new Error(`ACP CreateCheckout failed: ${response.status} ${response.statusText}`);
118
+ }
119
+ const session = await response.json();
120
+ // Generate signed receipt
121
+ const receipt = signCommerceReceipt({
122
+ agentId: opts.signedPassport.passport.agentId,
123
+ delegationId: opts.delegation.delegationId,
124
+ actionType: 'commerce:create_checkout',
125
+ target: url,
126
+ method: 'POST',
127
+ session,
128
+ merchantName: opts.config.merchantName,
129
+ delegationChain: extractDelegationChain(opts.signedPassport),
130
+ beneficiary: opts.signedPassport.passport.metadata?.beneficiaryPrincipalId || 'unknown',
131
+ privateKey: opts.privateKey,
132
+ });
133
+ return { session, receipt };
134
+ }
135
+ // ── ACP Client: Update Checkout Session ──
136
+ export async function updateCheckout(opts) {
137
+ const url = `${opts.config.merchantBaseUrl}/checkout_sessions/${opts.sessionId}`;
138
+ const response = await fetch(url, {
139
+ method: 'PUT',
140
+ headers: {
141
+ 'Content-Type': 'application/json',
142
+ ...(opts.config.bearerToken && { 'Authorization': `Bearer ${opts.config.bearerToken}` }),
143
+ },
144
+ body: JSON.stringify({
145
+ ...(opts.updates.items && { items: opts.updates.items }),
146
+ ...(opts.updates.fulfillmentAddress && { fulfillment_address: opts.updates.fulfillmentAddress }),
147
+ ...(opts.updates.fulfillmentOptionId && { fulfillment_option_id: opts.updates.fulfillmentOptionId }),
148
+ }),
149
+ });
150
+ if (!response.ok) {
151
+ throw new Error(`ACP UpdateCheckout failed: ${response.status} ${response.statusText}`);
152
+ }
153
+ const session = await response.json();
154
+ const receipt = signCommerceReceipt({
155
+ agentId: opts.signedPassport.passport.agentId,
156
+ delegationId: opts.delegation.delegationId,
157
+ actionType: 'commerce:update_checkout',
158
+ target: url,
159
+ method: 'PUT',
160
+ session,
161
+ merchantName: opts.config.merchantName,
162
+ delegationChain: extractDelegationChain(opts.signedPassport),
163
+ beneficiary: opts.signedPassport.passport.metadata?.beneficiaryPrincipalId || 'unknown',
164
+ privateKey: opts.privateKey,
165
+ });
166
+ return { session, receipt };
167
+ }
168
+ // ── ACP Client: Complete Checkout (Payment) ──
169
+ export async function completeCheckout(opts) {
170
+ // Re-run preflight with actual total — fetch current session first
171
+ const getUrl = `${opts.config.merchantBaseUrl}/checkout_sessions/${opts.sessionId}`;
172
+ const getResponse = await fetch(getUrl, {
173
+ headers: opts.config.bearerToken ? { 'Authorization': `Bearer ${opts.config.bearerToken}` } : {},
174
+ });
175
+ if (!getResponse.ok) {
176
+ throw new Error(`ACP GetCheckout failed: ${getResponse.status}`);
177
+ }
178
+ const currentSession = await getResponse.json();
179
+ const total = currentSession.totals.total;
180
+ // Final preflight with real amount
181
+ const preflight = commercePreflight({
182
+ signedPassport: opts.signedPassport,
183
+ delegation: opts.delegation,
184
+ merchantName: opts.config.merchantName,
185
+ estimatedTotal: total,
186
+ });
187
+ if (!preflight.permitted) {
188
+ throw new Error(`Commerce preflight DENIED at payment: ${preflight.blockedReason}`);
189
+ }
190
+ // Check human approval threshold
191
+ if (opts.delegation.requireHumanApproval && opts.delegation.humanApprovalThreshold) {
192
+ if (total.amount > opts.delegation.humanApprovalThreshold) {
193
+ throw new Error(`HUMAN_APPROVAL_REQUIRED: Purchase of ${total.amount} ${total.currency} exceeds threshold of ${opts.delegation.humanApprovalThreshold}. ` +
194
+ `Use requestHumanApproval() to get confirmation before completing.`);
195
+ }
196
+ }
197
+ // Complete checkout via ACP
198
+ const url = `${opts.config.merchantBaseUrl}/checkout_sessions/${opts.sessionId}/complete`;
199
+ const response = await fetch(url, {
200
+ method: 'POST',
201
+ headers: {
202
+ 'Content-Type': 'application/json',
203
+ ...(opts.config.bearerToken && { 'Authorization': `Bearer ${opts.config.bearerToken}` }),
204
+ },
205
+ body: JSON.stringify({
206
+ payment_token: opts.paymentToken,
207
+ ...(opts.paymentMethod && { payment_method: opts.paymentMethod }),
208
+ }),
209
+ });
210
+ if (!response.ok) {
211
+ throw new Error(`ACP CompleteCheckout failed: ${response.status} ${response.statusText}`);
212
+ }
213
+ const session = await response.json();
214
+ // Update spend tracking on the delegation
215
+ const spendUpdated = {
216
+ ...opts.delegation,
217
+ spentAmount: opts.delegation.spentAmount + total.amount,
218
+ };
219
+ // Generate signed receipt with full purchase details
220
+ const receipt = signCommerceReceipt({
221
+ agentId: opts.signedPassport.passport.agentId,
222
+ delegationId: opts.delegation.delegationId,
223
+ actionType: 'commerce:complete_checkout',
224
+ target: url,
225
+ method: 'POST',
226
+ session,
227
+ merchantName: opts.config.merchantName,
228
+ delegationChain: extractDelegationChain(opts.signedPassport),
229
+ beneficiary: opts.signedPassport.passport.metadata?.beneficiaryPrincipalId || 'unknown',
230
+ privateKey: opts.privateKey,
231
+ });
232
+ return { session, receipt, spendUpdated };
233
+ }
234
+ // ── ACP Client: Cancel Checkout ──
235
+ export async function cancelCheckout(opts) {
236
+ const url = `${opts.config.merchantBaseUrl}/checkout_sessions/${opts.sessionId}/cancel`;
237
+ const response = await fetch(url, {
238
+ method: 'POST',
239
+ headers: {
240
+ 'Content-Type': 'application/json',
241
+ ...(opts.config.bearerToken && { 'Authorization': `Bearer ${opts.config.bearerToken}` }),
242
+ },
243
+ });
244
+ if (!response.ok) {
245
+ throw new Error(`ACP CancelCheckout failed: ${response.status} ${response.statusText}`);
246
+ }
247
+ const session = await response.json();
248
+ const receipt = signCommerceReceipt({
249
+ agentId: opts.signedPassport.passport.agentId,
250
+ delegationId: opts.delegation.delegationId,
251
+ actionType: 'commerce:cancel_checkout',
252
+ target: url,
253
+ method: 'POST',
254
+ session,
255
+ merchantName: opts.config.merchantName,
256
+ delegationChain: extractDelegationChain(opts.signedPassport),
257
+ beneficiary: opts.signedPassport.passport.metadata?.beneficiaryPrincipalId || 'unknown',
258
+ privateKey: opts.privateKey,
259
+ });
260
+ return { session, receipt };
261
+ }
262
+ // ── Human Approval Request ──
263
+ export function requestHumanApproval(opts) {
264
+ const now = new Date();
265
+ const expiresAt = new Date(now.getTime() + (opts.expiresInMinutes || 30) * 60 * 1000);
266
+ return {
267
+ requestId: `approval-${randomBytes(8).toString('hex')}`,
268
+ agentId: opts.agentId,
269
+ merchantName: opts.merchantName,
270
+ items: opts.items,
271
+ totalAmount: opts.totalAmount,
272
+ delegationId: opts.delegationId,
273
+ reason: opts.reason,
274
+ createdAt: now.toISOString(),
275
+ expiresAt: expiresAt.toISOString(),
276
+ status: 'pending',
277
+ };
278
+ }
279
+ // ── Commerce Receipt Signing ──
280
+ function signCommerceReceipt(opts) {
281
+ const receipt = {
282
+ receiptId: `rcpt-commerce-${randomBytes(8).toString('hex')}`,
283
+ version: '1.0',
284
+ timestamp: new Date().toISOString(),
285
+ agentId: opts.agentId,
286
+ delegationId: opts.delegationId,
287
+ action: {
288
+ type: opts.actionType,
289
+ target: opts.target,
290
+ method: opts.method,
291
+ scopeUsed: 'commerce:checkout',
292
+ spend: {
293
+ amount: opts.session.totals.total.amount,
294
+ currency: opts.session.totals.total.currency,
295
+ },
296
+ },
297
+ checkout: {
298
+ sessionId: opts.session.id,
299
+ merchantName: opts.merchantName,
300
+ items: opts.session.items.map(i => ({
301
+ skuId: i.skuId,
302
+ name: i.name,
303
+ quantity: i.quantity,
304
+ unitPrice: i.unitPrice.amount,
305
+ })),
306
+ totalAmount: opts.session.totals.total.amount,
307
+ totalCurrency: opts.session.totals.total.currency,
308
+ status: opts.session.status,
309
+ },
310
+ delegationChain: opts.delegationChain,
311
+ beneficiary: opts.beneficiary,
312
+ };
313
+ const payload = canonicalize(receipt);
314
+ const signature = sign(payload, opts.privateKey);
315
+ return { ...receipt, signature };
316
+ }
317
+ // ── Helpers ──
318
+ function extractDelegationChain(sp) {
319
+ const chain = [sp.passport.publicKey];
320
+ if (sp.passport.delegations) {
321
+ for (const d of sp.passport.delegations) {
322
+ if (!chain.includes(d.delegatedBy))
323
+ chain.push(d.delegatedBy);
324
+ }
325
+ }
326
+ return chain;
327
+ }
328
+ // ── Commerce Delegation Factory ──
329
+ export function createCommerceDelegation(opts) {
330
+ return {
331
+ agentId: opts.agentId,
332
+ delegationId: opts.delegationId,
333
+ scope: ['commerce:checkout', 'commerce:browse', ...(opts.additionalScopes || [])],
334
+ spendLimit: opts.spendLimit,
335
+ spentAmount: 0,
336
+ currency: opts.currency || 'usd',
337
+ approvedMerchants: opts.approvedMerchants,
338
+ requireHumanApproval: opts.requireHumanApproval ?? true,
339
+ humanApprovalThreshold: opts.humanApprovalThreshold,
340
+ };
341
+ }
342
+ // ── Spend Analytics ──
343
+ export function getSpendSummary(delegation) {
344
+ const remaining = delegation.spendLimit - delegation.spentAmount;
345
+ const utilization = delegation.spendLimit > 0
346
+ ? (delegation.spentAmount / delegation.spendLimit) * 100
347
+ : 0;
348
+ return {
349
+ limit: delegation.spendLimit,
350
+ spent: delegation.spentAmount,
351
+ remaining,
352
+ currency: delegation.currency,
353
+ utilizationPercent: Math.round(utilization * 100) / 100,
354
+ nearLimit: utilization >= 80,
355
+ };
356
+ }
357
+ // ── Verify Commerce Receipt ──
358
+ export function verifyCommerceReceipt(receipt, publicKey) {
359
+ const errors = [];
360
+ // Verify signature
361
+ const { signature, ...payload } = receipt;
362
+ const canonical = canonicalize(payload);
363
+ try {
364
+ const signatureValid = ed25519Verify(canonical, signature, publicKey);
365
+ if (!signatureValid) {
366
+ errors.push('Commerce receipt signature is invalid');
367
+ }
368
+ }
369
+ catch {
370
+ errors.push('Failed to verify commerce receipt signature');
371
+ }
372
+ // Verify required fields
373
+ if (!receipt.receiptId)
374
+ errors.push('Missing receiptId');
375
+ if (!receipt.agentId)
376
+ errors.push('Missing agentId');
377
+ if (!receipt.delegationId)
378
+ errors.push('Missing delegationId');
379
+ if (!receipt.action?.type)
380
+ errors.push('Missing action type');
381
+ if (!receipt.action?.scopeUsed)
382
+ errors.push('Missing scopeUsed');
383
+ if (!receipt.beneficiary)
384
+ errors.push('Missing beneficiary');
385
+ if (!receipt.checkout?.sessionId)
386
+ errors.push('Missing checkout sessionId');
387
+ return { valid: errors.length === 0, errors };
388
+ }
389
+ //# sourceMappingURL=commerce.js.map