@agent-score/commerce 1.0.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.
Files changed (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +306 -0
  3. package/dist/_response-DmziuJz6.d.mts +137 -0
  4. package/dist/_response-rbK0zM7y.d.ts +137 -0
  5. package/dist/api/index.d.mts +1 -0
  6. package/dist/api/index.d.ts +1 -0
  7. package/dist/api/index.js +37 -0
  8. package/dist/api/index.js.map +1 -0
  9. package/dist/api/index.mjs +14 -0
  10. package/dist/api/index.mjs.map +1 -0
  11. package/dist/challenge/index.d.mts +523 -0
  12. package/dist/challenge/index.d.ts +523 -0
  13. package/dist/challenge/index.js +354 -0
  14. package/dist/challenge/index.js.map +1 -0
  15. package/dist/challenge/index.mjs +318 -0
  16. package/dist/challenge/index.mjs.map +1 -0
  17. package/dist/core.d.mts +252 -0
  18. package/dist/core.d.ts +252 -0
  19. package/dist/core.js +500 -0
  20. package/dist/core.js.map +1 -0
  21. package/dist/core.mjs +472 -0
  22. package/dist/core.mjs.map +1 -0
  23. package/dist/discovery/index.d.mts +382 -0
  24. package/dist/discovery/index.d.ts +382 -0
  25. package/dist/discovery/index.js +675 -0
  26. package/dist/discovery/index.js.map +1 -0
  27. package/dist/discovery/index.mjs +630 -0
  28. package/dist/discovery/index.mjs.map +1 -0
  29. package/dist/identity/express.d.mts +44 -0
  30. package/dist/identity/express.d.ts +44 -0
  31. package/dist/identity/express.js +777 -0
  32. package/dist/identity/express.js.map +1 -0
  33. package/dist/identity/express.mjs +738 -0
  34. package/dist/identity/express.mjs.map +1 -0
  35. package/dist/identity/fastify.d.mts +63 -0
  36. package/dist/identity/fastify.d.ts +63 -0
  37. package/dist/identity/fastify.js +780 -0
  38. package/dist/identity/fastify.js.map +1 -0
  39. package/dist/identity/fastify.mjs +741 -0
  40. package/dist/identity/fastify.mjs.map +1 -0
  41. package/dist/identity/hono.d.mts +83 -0
  42. package/dist/identity/hono.d.ts +83 -0
  43. package/dist/identity/hono.js +779 -0
  44. package/dist/identity/hono.js.map +1 -0
  45. package/dist/identity/hono.mjs +740 -0
  46. package/dist/identity/hono.mjs.map +1 -0
  47. package/dist/identity/nextjs.d.mts +62 -0
  48. package/dist/identity/nextjs.d.ts +62 -0
  49. package/dist/identity/nextjs.js +784 -0
  50. package/dist/identity/nextjs.js.map +1 -0
  51. package/dist/identity/nextjs.mjs +747 -0
  52. package/dist/identity/nextjs.mjs.map +1 -0
  53. package/dist/identity/policy.d.mts +115 -0
  54. package/dist/identity/policy.d.ts +115 -0
  55. package/dist/identity/policy.js +81 -0
  56. package/dist/identity/policy.js.map +1 -0
  57. package/dist/identity/policy.mjs +53 -0
  58. package/dist/identity/policy.mjs.map +1 -0
  59. package/dist/identity/web.d.mts +82 -0
  60. package/dist/identity/web.d.ts +82 -0
  61. package/dist/identity/web.js +775 -0
  62. package/dist/identity/web.js.map +1 -0
  63. package/dist/identity/web.mjs +738 -0
  64. package/dist/identity/web.mjs.map +1 -0
  65. package/dist/index.d.mts +252 -0
  66. package/dist/index.d.ts +252 -0
  67. package/dist/index.js +432 -0
  68. package/dist/index.js.map +1 -0
  69. package/dist/index.mjs +388 -0
  70. package/dist/index.mjs.map +1 -0
  71. package/dist/payment/index.d.mts +716 -0
  72. package/dist/payment/index.d.ts +716 -0
  73. package/dist/payment/index.js +691 -0
  74. package/dist/payment/index.js.map +1 -0
  75. package/dist/payment/index.mjs +639 -0
  76. package/dist/payment/index.mjs.map +1 -0
  77. package/dist/signer-Cvdwn6Cs.d.mts +48 -0
  78. package/dist/signer-Cvdwn6Cs.d.ts +48 -0
  79. package/dist/stripe-multichain/index.d.mts +221 -0
  80. package/dist/stripe-multichain/index.d.ts +221 -0
  81. package/dist/stripe-multichain/index.js +243 -0
  82. package/dist/stripe-multichain/index.js.map +1 -0
  83. package/dist/stripe-multichain/index.mjs +199 -0
  84. package/dist/stripe-multichain/index.mjs.map +1 -0
  85. package/dist/wwwauthenticate-CU1eNvMQ.d.mts +37 -0
  86. package/dist/wwwauthenticate-CU1eNvMQ.d.ts +37 -0
  87. package/package.json +172 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AgentScore
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,306 @@
1
+ # @agent-score/commerce
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@agent-score/commerce.svg)](https://www.npmjs.com/package/@agent-score/commerce)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
5
+
6
+ The full merchant-side SDK for [AgentScore](https://agentscore.sh) — agent commerce in one install. Ships identity gating, payment rail helpers, 402 challenge builders, MPP discovery, and Stripe multichain support. Built and maintained by AgentScore; works with any 402/MPP merchant in the ecosystem, AgentScore-gated or not.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm install @agent-score/commerce
12
+ # or
13
+ bun add @agent-score/commerce
14
+ ```
15
+
16
+ Framework + protocol packages are optional peer deps — install only what you use:
17
+
18
+ ```bash
19
+ npm install hono mppx @x402/core @x402/evm @x402/svm stripe # whatever your stack needs
20
+ ```
21
+
22
+ ## What's in the package
23
+
24
+ | Subpath | What it provides |
25
+ |---|---|
26
+ | `/identity/{hono,express,fastify,nextjs,web}` | Trust gate middleware: KYC, sanctions, age, jurisdiction. `agentscoreGate(...)`, `getAgentScoreData(c)`, `captureWallet(...)`, `verifyWalletSignerMatch(...)`. Plus shared denial helpers: `denialReasonStatus`, `denialReasonToBody`, `buildSignerMismatchBody`, `buildContactSupportNextSteps`, `verificationAgentInstructions`, `isFixableDenial`, `FIXABLE_DENIAL_REASONS`. |
27
+ | `/payment` | `networks`, `USDC`, `rails` registries; `paymentDirective`, `buildPaymentDirective`, `wwwAuthenticateHeader`, `paymentRequiredHeader`, `aliasAmountFields` (v1↔v2 amount field shim — emits both `amount` and `maxAmountRequired` so v1-only x402 parsers like Coinbase awal can read v2 bodies), `settlementOverrideHeader`, `dispatchSettlementByNetwork`, `extractPaymentSigner` (returns `{address, network}`); `createX402Server`, `createMppxServer`; drop-in x402 helpers: `validateX402NetworkConfig` (boot-time guard), `verifyX402Request` (parse + validate inbound X-Payment), `processX402Settle` (verify-then-settle with one call). |
28
+ | `/discovery` | `isDiscoveryProbeRequest`, `buildDiscoveryProbeResponse` (with optional `x402Sample` for x402-aware crawlers — `awal x402 details` etc.), `sampleX402AcceptForNetwork` (USDC sample-accept builder for known CAIP-2 networks), `buildWellKnownMpp`, `buildLlmsTxt` + `llmsTxtIdentitySection` + `llmsTxtPaymentSection` (compact + verbose modes), `agentscoreOpenApiSnippets`, `createBazaarDiscovery`, `noindexNonDiscoveryPaths` (Hono middleware that emits `X-Robots-Tag: noindex` on every path except the agent-discovery surfaces — defaults cover `/openapi.json`, `/llms.txt`, `/.well-known/{mpp.json,agent-card.json,ucp}`, `/favicon.{png,ico}`; pure helpers `isDiscoveryPath` + `defaultDiscoveryPaths` for non-Hono frameworks). |
29
+ | `/challenge` | `build402Body`, `buildAcceptedMethods`, `buildIdentityMetadata`, `buildHowToPay`, `buildAgentInstructions`, `buildPricingBlock`, `firstEncounterAgentMemory`, `OrderReceipt`; `respond402` — drop-in 402 emit that preserves mppx's `WWW-Authenticate` and layers x402's `PAYMENT-REQUIRED`. `buildValidationError` — structured 4xx body builder (`{error: {code, message}, required_fields?, example_body?, next_steps?, ...extra}`) so vendors compose body shapes by name instead of inlining at every validation site. |
30
+ | `/stripe-multichain` | `createMultichainPaymentIntent`, `getDepositAddress`, `simulateCryptoDeposit`, `createMppxStripe`; `createPiCache` (TTL'd PI / deposit-address cache, Redis-backed when `redisUrl` set, in-memory otherwise), `simulateDepositIfTestMode` (gates on `sk_test_` and looks up the PI for you), `STRIPE_TEST_TX_HASH_SUCCESS` / `STRIPE_TEST_TX_HASH_FAILED` constants. Peer dep on `stripe`. |
31
+ | `/api` | Everything from `@agent-score/sdk` re-exported in one place: `AgentScore` + `AgentScoreError`, `AGENTSCORE_TEST_ADDRESSES` + `isAgentScoreTestAddress`. **Don't add `@agent-score/sdk` as a separate dep** — the two can drift versions and cause subtle type mismatches. |
32
+
33
+ ## Quick start
34
+
35
+ ### Identity gate (Hono)
36
+
37
+ ```typescript
38
+ import { Hono } from "hono";
39
+ import {
40
+ agentscoreGate,
41
+ captureWallet,
42
+ getAgentScoreData,
43
+ verifyWalletSignerMatch,
44
+ } from "@agent-score/commerce/identity/hono";
45
+
46
+ const app = new Hono();
47
+
48
+ const _gate = agentscoreGate({
49
+ apiKey: process.env.AGENTSCORE_API_KEY!,
50
+ requireKyc: true,
51
+ minAge: 21,
52
+ allowedJurisdictions: ["US"],
53
+ createSessionOnMissing: { apiKey: process.env.AGENTSCORE_API_KEY!, context: "wine-purchase" },
54
+ });
55
+
56
+ // Run the gate CONDITIONALLY — only when a payment credential is already attached.
57
+ // Anonymous discovery (no payment header) flows through to the handler so any spec-
58
+ // compliant x402 wallet can read the 402 challenge with rails + pricing without first
59
+ // proving identity. Identity is verified at settle time on the retry leg.
60
+ app.use("/purchase", async (c, next) => {
61
+ const hasPaymentHeader = Boolean(
62
+ c.req.header("payment-signature") ||
63
+ c.req.header("x-payment") ||
64
+ c.req.header("authorization")?.startsWith("Payment "),
65
+ );
66
+ if (!hasPaymentHeader) { await next(); return; }
67
+ return _gate(c, next);
68
+ });
69
+
70
+ app.post("/purchase", async (c) => {
71
+ const data = getAgentScoreData(c);
72
+ // ... settle payment ...
73
+ // After payment, capture the signer wallet for cross-merchant attribution
74
+ await captureWallet(c, { walletAddress: signer, network: "evm", idempotencyKey: paymentIntentId });
75
+ return c.json({ ok: true });
76
+ });
77
+ ```
78
+
79
+ ### Payment helpers
80
+
81
+ ```typescript
82
+ import {
83
+ buildPaymentDirective,
84
+ extractPaymentSigner,
85
+ networks,
86
+ paymentRequiredHeader,
87
+ wwwAuthenticateHeader,
88
+ } from "@agent-score/commerce/payment";
89
+
90
+ // Build paymentauth.org directives by symbolic rail name (decimals + currency from registry)
91
+ const directives = [
92
+ buildPaymentDirective({ rail: "tempo-mainnet", id: "chg_t", realm: "ex.com", recipient: TEMPO_ADDR, amountUsd: 0.01 }),
93
+ buildPaymentDirective({ rail: "x402-base-mainnet", id: "chg_b", realm: "ex.com", recipient: BASE_ADDR, amountUsd: 0.01 }),
94
+ buildPaymentDirective({ rail: "x402-solana-mainnet", id: "chg_s", realm: "ex.com", recipient: SOL_ADDR, amountUsd: 0.01 }),
95
+ ];
96
+ const wwwAuth = wwwAuthenticateHeader(directives);
97
+
98
+ // Recover the on-chain signer from the inbound credential — returns {address, network}
99
+ const signer = await extractPaymentSigner(req, req.headers.get("x-payment") ?? undefined);
100
+ ```
101
+
102
+ ### x402 + MPP server setup
103
+
104
+ ```typescript
105
+ import { createX402Server, createMppxServer } from "@agent-score/commerce/payment";
106
+
107
+ const x402 = await createX402Server({
108
+ facilitator: "coinbase", // or "http", or pass a custom facilitator instance
109
+ rails: ["x402-base-mainnet", "x402-solana-mainnet", "x402-base-mainnet-upto"],
110
+ });
111
+
112
+ const mppx = await createMppxServer({
113
+ rails: {
114
+ tempo: { recipient: process.env.TEMPO_RECIPIENT! },
115
+ stripe: { profileId: process.env.STRIPE_PROFILE_ID!, secretKey: process.env.STRIPE_SECRET_KEY! },
116
+ },
117
+ secretKey: process.env.MPP_SECRET_KEY!,
118
+ });
119
+ ```
120
+
121
+ ### 402 builders
122
+
123
+ ```typescript
124
+ import {
125
+ build402Body,
126
+ buildAcceptedMethods,
127
+ buildAgentInstructions,
128
+ buildHowToPay,
129
+ buildIdentityMetadata,
130
+ } from "@agent-score/commerce/challenge";
131
+
132
+ const acceptedMethods = buildAcceptedMethods({
133
+ tempo: { recipient: TEMPO_ADDR },
134
+ x402_base: { recipient: BASE_ADDR },
135
+ x402_solana: { recipient: SOL_ADDR },
136
+ stripe: { profileId: STRIPE_PROFILE_ID },
137
+ });
138
+
139
+ const howToPay = buildHowToPay({
140
+ url: req.url,
141
+ retryBodyJson: JSON.stringify(body),
142
+ totalUsd: "10.00",
143
+ rails: { tempo: { recipient: TEMPO_ADDR }, x402_base: { recipient: BASE_ADDR } },
144
+ });
145
+
146
+ const responseBody = build402Body({
147
+ acceptedMethods,
148
+ agentInstructions: buildAgentInstructions({ howToPay }),
149
+ identityMetadata: buildIdentityMetadata({ mode: "wallet", wallet: claimedAddress }),
150
+ pricing: buildPricingBlock({ subtotalCents: 1000, taxCents: 80, shippingCents: 999, taxRate: 0.08, taxState: "CA" }),
151
+ amountUsd: "10.80",
152
+ retryBody: body,
153
+ // First-encounter merchants attach the cross-merchant agent_memory hint so agents persist the AgentScore pattern.
154
+ agentMemory: firstEncounterAgentMemory({ firstEncounter: !merchant.hasSeenOperator(opToken) }),
155
+ });
156
+ ```
157
+
158
+ `buildPricingBlock` handles cents → dollar-string conversion (with optional shipping). `firstEncounterAgentMemory` returns the canonical hint or `undefined` based on a per-merchant first-seen flag. `OrderReceipt` is a TS interface for the post-settlement 200 response shape.
159
+
160
+ ### Idempotency-key + multi-rail header bundle
161
+
162
+ ```typescript
163
+ import { buildIdempotencyKey, buildPaymentHeaders } from "@agent-score/commerce/payment";
164
+
165
+ // Stable per-payment key — Stripe PI id wins, falls back to pi-{orderId}-{amountCents}.
166
+ const idempotencyKey = buildIdempotencyKey({ paymentIntentId, orderId, amountCents });
167
+
168
+ // One-call WWW-Authenticate + PAYMENT-REQUIRED bundle from a single rails declaration.
169
+ const headers = buildPaymentHeaders({
170
+ orderId,
171
+ realm: "agents.merchant.example",
172
+ rails: [
173
+ { rail: "tempo-mainnet", amountUsd: "10.00", recipient: TEMPO_ADDR },
174
+ { rail: "x402-base-mainnet", amountUsd: "10.00", recipient: BASE_ADDR },
175
+ { rail: "stripe", amountUsd: "10.00", networkId: STRIPE_PROFILE_ID },
176
+ ],
177
+ x402: { accepts: x402Accepts, version: 2 },
178
+ });
179
+ return new Response(JSON.stringify(responseBody), { status: 402, headers });
180
+ ```
181
+
182
+ ### Identity publishing (cross-vendor standards)
183
+
184
+ ```typescript
185
+ import { buildA2AAgentCard, buildUCPProfile } from "@agent-score/commerce";
186
+
187
+ // Google A2A v1.0 Signed Agent Card — publish at /.well-known/agent-card.json
188
+ const card = buildA2AAgentCard({ name, url, capabilities, data: assess });
189
+
190
+ // Google Universal Commerce Protocol — publish at /.well-known/ucp
191
+ const profile = buildUCPProfile({ name, services, payment_handlers, signing_keys, data: assess });
192
+ ```
193
+
194
+ ACP (Stripe + OpenAI Agentic Commerce Protocol) is a transactional checkout protocol with no identity-publishing surface — ACP merchants integrate via the existing `build402Body` + `buildPaymentHeaders` + Stripe SPT rail.
195
+
196
+ ### Stripe multichain (peer dep on `stripe`)
197
+
198
+ ```typescript
199
+ import {
200
+ createMultichainPaymentIntent,
201
+ createPiCache,
202
+ getDepositAddress,
203
+ simulateCryptoDeposit,
204
+ simulateDepositIfTestMode,
205
+ } from "@agent-score/commerce/stripe-multichain";
206
+
207
+ const result = await createMultichainPaymentIntent({
208
+ stripe: stripeClient,
209
+ amount: 1000,
210
+ networks: ["tempo", "base", "solana"],
211
+ metadata: { order_id: orderId },
212
+ idempotencyKey: orderId,
213
+ });
214
+ const baseAddress = getDepositAddress(result, "base");
215
+ const solanaAddress = getDepositAddress(result, "solana");
216
+
217
+ // PI / deposit-address cache. Redis-backed when REDIS_URL is set, in-memory otherwise —
218
+ // multi-task deployments need Redis so a deposit lands on whichever task settles it.
219
+ const piCache = createPiCache({ redisUrl: process.env.REDIS_URL });
220
+ for (const addr of Object.values(result.depositAddresses)) {
221
+ await piCache.cacheAddress(addr);
222
+ piCache.cachePaymentIntent(addr, result.paymentIntentId);
223
+ }
224
+ piCache.cacheNetworkAddresses(result.paymentIntentId, result.depositAddresses);
225
+
226
+ // Testnet helper — gates on sk_test_ and looks up the PI for you. No-op on live keys.
227
+ await simulateDepositIfTestMode({
228
+ getPaymentIntentId: piCache.getPaymentIntentId,
229
+ depositAddress: baseAddress!,
230
+ network: "base",
231
+ stripeSecretKey: process.env.STRIPE_SECRET_KEY!,
232
+ });
233
+ ```
234
+
235
+ ### Drop-in 402 + settle (x402)
236
+
237
+ ```typescript
238
+ import {
239
+ processX402Settle,
240
+ validateX402NetworkConfig,
241
+ verifyX402Request,
242
+ } from "@agent-score/commerce/payment";
243
+ import { respond402 } from "@agent-score/commerce/challenge";
244
+
245
+ // Boot-time guard — raises if a configured network isn't supported.
246
+ validateX402NetworkConfig({ baseNetwork: X402_BASE, svmNetwork: X402_SVM });
247
+
248
+ app.post("/purchase", async (c) => {
249
+ // Path A — agent presented an x402 X-Payment header
250
+ if (c.req.header("payment-signature") || c.req.header("x-payment")) {
251
+ const verified = await verifyX402Request({
252
+ request: c.req.raw,
253
+ isCachedAddress: piCache.hasAddress,
254
+ acceptedNetworks: { base: X402_BASE, svm: X402_SVM },
255
+ });
256
+ if (!verified.ok) return c.json(verified.body, verified.status);
257
+
258
+ const settle = await processX402Settle({
259
+ x402Server,
260
+ payload: verified.payload,
261
+ resourceConfig: { scheme: "exact", network: verified.signedNetwork, price: `$${total}`, payTo: verified.signedPayTo, maxTimeoutSeconds: 300 },
262
+ resourceMeta: { url: c.req.url, mimeType: "application/json" },
263
+ });
264
+ if (!settle.success) return c.json({ error: { code: "payment_proof_invalid", phase: settle.phase } }, 400);
265
+
266
+ const headers: Record<string, string> = {};
267
+ if (settle.paymentResponseHeader) headers["payment-response"] = settle.paymentResponseHeader;
268
+ return c.json({ ok: true }, { headers });
269
+ }
270
+
271
+ // Path B — cold call (or Authorization: Payment for mppx). After mppx.compose() returns 402,
272
+ // respond402 PRESERVES mppx's WWW-Authenticate and ADDS x402's PAYMENT-REQUIRED.
273
+ return respond402({
274
+ mppxChallenge: mppxResult.challenge as Response,
275
+ body: { acceptedMethods, agentInstructions, pricing, amountUsd: total, retryBody: body },
276
+ x402: { x402Version: 2, accepts: x402Accepts, resource: { url: c.req.url, mimeType: "application/json" } },
277
+ });
278
+ });
279
+ ```
280
+
281
+ ## Examples
282
+
283
+ The [examples/](./examples) directory has 6 runnable single-file Hono apps covering common merchant scenarios — copy-paste templates, not frameworks. See [examples/README.md](./examples/README.md) for the full table.
284
+
285
+ ## Vendor profile examples
286
+
287
+ | Vendor type | Subpaths used | Example install line |
288
+ |---|---|---|
289
+ | Wine merchant (full compliance + multi-rail) | `/identity/*`, `/payment`, `/discovery`, `/challenge`, `/stripe-multichain` | `npm install @agent-score/commerce stripe` |
290
+ | API provider (per-call billing, no compliance) | `/payment`, `/discovery` | `npm install @agent-score/commerce` |
291
+ | Tempo-only merchant | `/payment` | `npm install @agent-score/commerce mppx` |
292
+ | Crypto-native, no Stripe | `/identity/*`, `/payment`, `/challenge` | `npm install @agent-score/commerce @x402/core` |
293
+
294
+ The SDK is genuinely a toolkit — vendors compose only what they need. Helpers don't bundle assumptions about which rails or protocols you support, and don't recommend one rail over another.
295
+
296
+ ## Stability
297
+
298
+ `@agent-score/commerce@1.0.0` ships with the full merchant SDK surface stable. Helpers are protocol translations + configurable opinions — most evolution is additive (new optional params, new helpers, new networks/rails). Major bumps are reserved for genuine protocol-mapping bugs.
299
+
300
+ ## Documentation
301
+
302
+ Full integration docs at [docs.agentscore.sh/integrations/node-commerce](https://docs.agentscore.sh/integrations/node-commerce).
303
+
304
+ ## License
305
+
306
+ [MIT](LICENSE)
@@ -0,0 +1,137 @@
1
+ import { VerifyWalletSignerResult, DenialReason } from './core.mjs';
2
+
3
+ /**
4
+ * Universal denial helpers shared across every adapter.
5
+ *
6
+ * What lives here:
7
+ * - `FIXABLE_DENIAL_REASONS` / `isFixableDenial` — classifier for compliance reasons that can
8
+ * be resolved by re-completing KYC (vs sanctions / age failures which are permanent).
9
+ * - `denialReasonStatus` — picks the right HTTP status code per denial code (401 for credential
10
+ * problems, 503 for transient API errors, 403 for everything else).
11
+ * - `buildSignerMismatchBody` — produces the standard 403 body for a `verifyWalletSignerMatch`
12
+ * non-pass result.
13
+ * - `buildContactSupportNextSteps` — standard `next_steps.action: "contact_support"` shape for
14
+ * unfixable compliance denials.
15
+ * - `verificationAgentInstructions` — the canned `agent_instructions` block for
16
+ * identity-verification 403s. Vendors can override individual fields.
17
+ *
18
+ * Adapters use `denialReasonStatus` inside their default `onDenied` so vendors get the right
19
+ * status code for free. The body builders are exported from each adapter so vendors who write
20
+ * a custom `onDenied` can compose them without copy-paste.
21
+ */
22
+
23
+ /**
24
+ * Compliance denial reasons that can be resolved by re-completing KYC. Sanctions hits and
25
+ * age-not-verified are NOT in this set — they're permanent policy failures on an
26
+ * otherwise-verified identity and require contact-support, not retry.
27
+ */
28
+ declare const FIXABLE_DENIAL_REASONS: ReadonlySet<string>;
29
+ /**
30
+ * Returns true when a `wallet_not_trusted` denial's reasons are all "fixable" (the user can
31
+ * re-verify and retry). False when any reason is permanent (sanctions, age).
32
+ *
33
+ * Empty reasons array is treated as fixable on the assumption that an empty-reason denial
34
+ * means a generic policy fail that's worth retrying — vendors can override by checking the
35
+ * specific reasons themselves.
36
+ */
37
+ declare function isFixableDenial(reasons: readonly string[] | undefined): boolean;
38
+ /**
39
+ * The right HTTP status code for a denial. `defaultOnDenied` in every adapter uses this so
40
+ * vendors get correct status codes without writing per-code branches.
41
+ *
42
+ * - 401 for credential problems the agent can recover from (`token_expired`, `invalid_credential`)
43
+ * - 503 for transient `api_error`
44
+ * - 403 for everything else (identity required, compliance fail, signer mismatch, etc.)
45
+ */
46
+ declare function denialReasonStatus(reason: DenialReason): 401 | 403 | 503;
47
+ interface SignerMismatchBodyInput {
48
+ /** Result from `verifyWalletSignerMatch`. The function only emits a body for non-pass results. */
49
+ result: VerifyWalletSignerResult;
50
+ /** Optional override for the human-facing `next_steps.user_message`. */
51
+ userMessage?: string;
52
+ /** Optional override for `next_steps.learn_more_url`. Default: AgentScore agent-identity guide. */
53
+ learnMoreUrl?: string;
54
+ }
55
+ /**
56
+ * Standard 403 body for a non-pass `verifyWalletSignerMatch` result. Returns null for `pass` /
57
+ * `api_error` so vendors can call it unconditionally:
58
+ *
59
+ * const result = await verifyWalletSignerMatch(c);
60
+ * const mismatchBody = buildSignerMismatchBody({ result });
61
+ * if (mismatchBody) return c.json(mismatchBody, 403);
62
+ *
63
+ * Body shape mirrors the gate's denial bodies: top-level error.code, all signer-match fields
64
+ * (`claimed_operator`, `actual_signer_operator`, `expected_signer`, `actual_signer`,
65
+ * `linked_wallets`), plus a `next_steps` action describing the recovery path.
66
+ */
67
+ declare function buildSignerMismatchBody(input: SignerMismatchBodyInput): Record<string, unknown> | null;
68
+ /**
69
+ * Standard `next_steps` block for unfixable compliance denials (sanctions, age, etc.). Vendors
70
+ * spread this into a 403 body alongside the usual `error`/`reasons` fields.
71
+ *
72
+ * return c.json({
73
+ * error: { code: 'compliance_denied', message: '...' },
74
+ * reasons,
75
+ * next_steps: buildContactSupportNextSteps('support@martinestate.com'),
76
+ * }, 403);
77
+ */
78
+ declare function buildContactSupportNextSteps(supportEmail: string, message?: string): {
79
+ action: 'contact_support';
80
+ support_email: string;
81
+ user_message: string;
82
+ };
83
+ interface VerificationAgentInstructionsInput {
84
+ /** Override the user-facing message. */
85
+ userAction?: string;
86
+ /** Replace the generic "Retry the original merchant request..." step with a merchant-specific
87
+ * one (e.g. "Retry POST /purchase with X-Operator-Token AND include order_id..."). When set,
88
+ * this REPLACES baseSteps[4] rather than appending — use it instead of `extraSteps[0]` when
89
+ * your retry instruction is a refinement of the canonical retry, not an additional step. */
90
+ retryStep?: string;
91
+ /** Append additional steps after the retry step. Use this for genuinely additional steps
92
+ * (e.g. "After payment the same call returns 200 with the order"), not for re-stating the
93
+ * retry — use `retryStep` for that. */
94
+ extraSteps?: string[];
95
+ /** Override the poll cadence. Default 5 seconds. */
96
+ pollIntervalSeconds?: number;
97
+ /** Override how long the agent should keep polling. Default 3600 seconds (1 hour). */
98
+ timeoutSeconds?: number;
99
+ /** Optional `order_ttl` note describing how long pending orders survive. */
100
+ orderTtl?: string;
101
+ /** Arbitrary additional fields merged into the instructions object. */
102
+ extra?: Record<string, unknown>;
103
+ }
104
+ /**
105
+ * The canonical `agent_instructions` block for identity-verification 403s. Tells the agent how to
106
+ * present the verify_url, poll for the operator_token, and retry the original request. Universal
107
+ * across every AgentScore-gated merchant — overrides let vendors add merchant-specific steps
108
+ * (e.g. "include order_id when retrying").
109
+ */
110
+ declare function verificationAgentInstructions(input?: VerificationAgentInstructionsInput): {
111
+ action: 'poll_for_credential';
112
+ user_action: string;
113
+ steps: string[];
114
+ poll_interval_seconds: number;
115
+ poll_secret_header: 'X-Poll-Secret';
116
+ retry_token_header: 'X-Operator-Token';
117
+ timeout_seconds: number;
118
+ order_ttl?: string;
119
+ [key: string]: unknown;
120
+ };
121
+
122
+ /**
123
+ * Shared DenialReason → response body serialization for all adapters.
124
+ *
125
+ * Keeps Hono / Express / Fastify / Web / Next.js defaults aligned — a field added
126
+ * here shows up in every adapter's 403 body automatically, and there's one place
127
+ * to test the marshaling.
128
+ *
129
+ * Body shape: `{ error: { code, message }, ... }` — matches the canonical AgentScore
130
+ * core API response shape (`core/api/src/lib/auth.ts`, `lib/rate-limit.ts`, etc.) and
131
+ * martin-estate's pre-commerce shape, so downstream agents see one consistent
132
+ * `error.code` + `error.message` pair regardless of which layer produced the denial.
133
+ */
134
+
135
+ declare function denialReasonToBody(reason: DenialReason): Record<string, unknown>;
136
+
137
+ export { FIXABLE_DENIAL_REASONS as F, buildSignerMismatchBody as a, buildContactSupportNextSteps as b, denialReasonToBody as c, denialReasonStatus as d, isFixableDenial as i, verificationAgentInstructions as v };
@@ -0,0 +1,137 @@
1
+ import { VerifyWalletSignerResult, DenialReason } from './core.js';
2
+
3
+ /**
4
+ * Universal denial helpers shared across every adapter.
5
+ *
6
+ * What lives here:
7
+ * - `FIXABLE_DENIAL_REASONS` / `isFixableDenial` — classifier for compliance reasons that can
8
+ * be resolved by re-completing KYC (vs sanctions / age failures which are permanent).
9
+ * - `denialReasonStatus` — picks the right HTTP status code per denial code (401 for credential
10
+ * problems, 503 for transient API errors, 403 for everything else).
11
+ * - `buildSignerMismatchBody` — produces the standard 403 body for a `verifyWalletSignerMatch`
12
+ * non-pass result.
13
+ * - `buildContactSupportNextSteps` — standard `next_steps.action: "contact_support"` shape for
14
+ * unfixable compliance denials.
15
+ * - `verificationAgentInstructions` — the canned `agent_instructions` block for
16
+ * identity-verification 403s. Vendors can override individual fields.
17
+ *
18
+ * Adapters use `denialReasonStatus` inside their default `onDenied` so vendors get the right
19
+ * status code for free. The body builders are exported from each adapter so vendors who write
20
+ * a custom `onDenied` can compose them without copy-paste.
21
+ */
22
+
23
+ /**
24
+ * Compliance denial reasons that can be resolved by re-completing KYC. Sanctions hits and
25
+ * age-not-verified are NOT in this set — they're permanent policy failures on an
26
+ * otherwise-verified identity and require contact-support, not retry.
27
+ */
28
+ declare const FIXABLE_DENIAL_REASONS: ReadonlySet<string>;
29
+ /**
30
+ * Returns true when a `wallet_not_trusted` denial's reasons are all "fixable" (the user can
31
+ * re-verify and retry). False when any reason is permanent (sanctions, age).
32
+ *
33
+ * Empty reasons array is treated as fixable on the assumption that an empty-reason denial
34
+ * means a generic policy fail that's worth retrying — vendors can override by checking the
35
+ * specific reasons themselves.
36
+ */
37
+ declare function isFixableDenial(reasons: readonly string[] | undefined): boolean;
38
+ /**
39
+ * The right HTTP status code for a denial. `defaultOnDenied` in every adapter uses this so
40
+ * vendors get correct status codes without writing per-code branches.
41
+ *
42
+ * - 401 for credential problems the agent can recover from (`token_expired`, `invalid_credential`)
43
+ * - 503 for transient `api_error`
44
+ * - 403 for everything else (identity required, compliance fail, signer mismatch, etc.)
45
+ */
46
+ declare function denialReasonStatus(reason: DenialReason): 401 | 403 | 503;
47
+ interface SignerMismatchBodyInput {
48
+ /** Result from `verifyWalletSignerMatch`. The function only emits a body for non-pass results. */
49
+ result: VerifyWalletSignerResult;
50
+ /** Optional override for the human-facing `next_steps.user_message`. */
51
+ userMessage?: string;
52
+ /** Optional override for `next_steps.learn_more_url`. Default: AgentScore agent-identity guide. */
53
+ learnMoreUrl?: string;
54
+ }
55
+ /**
56
+ * Standard 403 body for a non-pass `verifyWalletSignerMatch` result. Returns null for `pass` /
57
+ * `api_error` so vendors can call it unconditionally:
58
+ *
59
+ * const result = await verifyWalletSignerMatch(c);
60
+ * const mismatchBody = buildSignerMismatchBody({ result });
61
+ * if (mismatchBody) return c.json(mismatchBody, 403);
62
+ *
63
+ * Body shape mirrors the gate's denial bodies: top-level error.code, all signer-match fields
64
+ * (`claimed_operator`, `actual_signer_operator`, `expected_signer`, `actual_signer`,
65
+ * `linked_wallets`), plus a `next_steps` action describing the recovery path.
66
+ */
67
+ declare function buildSignerMismatchBody(input: SignerMismatchBodyInput): Record<string, unknown> | null;
68
+ /**
69
+ * Standard `next_steps` block for unfixable compliance denials (sanctions, age, etc.). Vendors
70
+ * spread this into a 403 body alongside the usual `error`/`reasons` fields.
71
+ *
72
+ * return c.json({
73
+ * error: { code: 'compliance_denied', message: '...' },
74
+ * reasons,
75
+ * next_steps: buildContactSupportNextSteps('support@martinestate.com'),
76
+ * }, 403);
77
+ */
78
+ declare function buildContactSupportNextSteps(supportEmail: string, message?: string): {
79
+ action: 'contact_support';
80
+ support_email: string;
81
+ user_message: string;
82
+ };
83
+ interface VerificationAgentInstructionsInput {
84
+ /** Override the user-facing message. */
85
+ userAction?: string;
86
+ /** Replace the generic "Retry the original merchant request..." step with a merchant-specific
87
+ * one (e.g. "Retry POST /purchase with X-Operator-Token AND include order_id..."). When set,
88
+ * this REPLACES baseSteps[4] rather than appending — use it instead of `extraSteps[0]` when
89
+ * your retry instruction is a refinement of the canonical retry, not an additional step. */
90
+ retryStep?: string;
91
+ /** Append additional steps after the retry step. Use this for genuinely additional steps
92
+ * (e.g. "After payment the same call returns 200 with the order"), not for re-stating the
93
+ * retry — use `retryStep` for that. */
94
+ extraSteps?: string[];
95
+ /** Override the poll cadence. Default 5 seconds. */
96
+ pollIntervalSeconds?: number;
97
+ /** Override how long the agent should keep polling. Default 3600 seconds (1 hour). */
98
+ timeoutSeconds?: number;
99
+ /** Optional `order_ttl` note describing how long pending orders survive. */
100
+ orderTtl?: string;
101
+ /** Arbitrary additional fields merged into the instructions object. */
102
+ extra?: Record<string, unknown>;
103
+ }
104
+ /**
105
+ * The canonical `agent_instructions` block for identity-verification 403s. Tells the agent how to
106
+ * present the verify_url, poll for the operator_token, and retry the original request. Universal
107
+ * across every AgentScore-gated merchant — overrides let vendors add merchant-specific steps
108
+ * (e.g. "include order_id when retrying").
109
+ */
110
+ declare function verificationAgentInstructions(input?: VerificationAgentInstructionsInput): {
111
+ action: 'poll_for_credential';
112
+ user_action: string;
113
+ steps: string[];
114
+ poll_interval_seconds: number;
115
+ poll_secret_header: 'X-Poll-Secret';
116
+ retry_token_header: 'X-Operator-Token';
117
+ timeout_seconds: number;
118
+ order_ttl?: string;
119
+ [key: string]: unknown;
120
+ };
121
+
122
+ /**
123
+ * Shared DenialReason → response body serialization for all adapters.
124
+ *
125
+ * Keeps Hono / Express / Fastify / Web / Next.js defaults aligned — a field added
126
+ * here shows up in every adapter's 403 body automatically, and there's one place
127
+ * to test the marshaling.
128
+ *
129
+ * Body shape: `{ error: { code, message }, ... }` — matches the canonical AgentScore
130
+ * core API response shape (`core/api/src/lib/auth.ts`, `lib/rate-limit.ts`, etc.) and
131
+ * martin-estate's pre-commerce shape, so downstream agents see one consistent
132
+ * `error.code` + `error.message` pair regardless of which layer produced the denial.
133
+ */
134
+
135
+ declare function denialReasonToBody(reason: DenialReason): Record<string, unknown>;
136
+
137
+ export { FIXABLE_DENIAL_REASONS as F, buildSignerMismatchBody as a, buildContactSupportNextSteps as b, denialReasonToBody as c, denialReasonStatus as d, isFixableDenial as i, verificationAgentInstructions as v };
@@ -0,0 +1 @@
1
+ export { AGENTSCORE_TEST_ADDRESSES, AgentScore, AgentScoreError, isAgentScoreTestAddress } from '@agent-score/sdk';
@@ -0,0 +1 @@
1
+ export { AGENTSCORE_TEST_ADDRESSES, AgentScore, AgentScoreError, isAgentScoreTestAddress } from '@agent-score/sdk';
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/api/index.ts
21
+ var api_exports = {};
22
+ __export(api_exports, {
23
+ AGENTSCORE_TEST_ADDRESSES: () => import_sdk.AGENTSCORE_TEST_ADDRESSES,
24
+ AgentScore: () => import_sdk.AgentScore,
25
+ AgentScoreError: () => import_sdk.AgentScoreError,
26
+ isAgentScoreTestAddress: () => import_sdk.isAgentScoreTestAddress
27
+ });
28
+ module.exports = __toCommonJS(api_exports);
29
+ var import_sdk = require("@agent-score/sdk");
30
+ // Annotate the CommonJS export names for ESM import in node:
31
+ 0 && (module.exports = {
32
+ AGENTSCORE_TEST_ADDRESSES,
33
+ AgentScore,
34
+ AgentScoreError,
35
+ isAgentScoreTestAddress
36
+ });
37
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/api/index.ts"],"sourcesContent":["/**\n * AgentScore SDK re-export — vendors install only `@agent-score/commerce` and reach\n * everything from the underlying `@agent-score/sdk` here. Don't add `@agent-score/sdk`\n * as a separate dep; the two can drift versions and cause subtle type mismatches.\n *\n * Use this for: programmatic API calls (sessions, credentials, reputation) and the\n * test-mode address fixtures for integration tests.\n */\nexport {\n AGENTSCORE_TEST_ADDRESSES,\n AgentScore,\n AgentScoreError,\n isAgentScoreTestAddress,\n} from '@agent-score/sdk';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,iBAKO;","names":[]}
@@ -0,0 +1,14 @@
1
+ // src/api/index.ts
2
+ import {
3
+ AGENTSCORE_TEST_ADDRESSES,
4
+ AgentScore,
5
+ AgentScoreError,
6
+ isAgentScoreTestAddress
7
+ } from "@agent-score/sdk";
8
+ export {
9
+ AGENTSCORE_TEST_ADDRESSES,
10
+ AgentScore,
11
+ AgentScoreError,
12
+ isAgentScoreTestAddress
13
+ };
14
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/api/index.ts"],"sourcesContent":["/**\n * AgentScore SDK re-export — vendors install only `@agent-score/commerce` and reach\n * everything from the underlying `@agent-score/sdk` here. Don't add `@agent-score/sdk`\n * as a separate dep; the two can drift versions and cause subtle type mismatches.\n *\n * Use this for: programmatic API calls (sessions, credentials, reputation) and the\n * test-mode address fixtures for integration tests.\n */\nexport {\n AGENTSCORE_TEST_ADDRESSES,\n AgentScore,\n AgentScoreError,\n isAgentScoreTestAddress,\n} from '@agent-score/sdk';\n"],"mappings":";AAQA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;","names":[]}