@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
@@ -0,0 +1,630 @@
1
+ // src/payment/networks.ts
2
+ var networks = {
3
+ base: {
4
+ mainnet: { caip2: "eip155:8453", chainId: 8453 },
5
+ sepolia: { caip2: "eip155:84532", chainId: 84532 }
6
+ },
7
+ solana: {
8
+ mainnet: { caip2: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp" },
9
+ devnet: { caip2: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1" }
10
+ },
11
+ tempo: {
12
+ mainnet: { caip2: "eip155:4217", chainId: 4217 },
13
+ testnet: { caip2: "eip155:42431", chainId: 42431 }
14
+ }
15
+ };
16
+
17
+ // src/payment/usdc.ts
18
+ var USDC = {
19
+ base: {
20
+ mainnet: { address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", decimals: 6 },
21
+ sepolia: { address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", decimals: 6 }
22
+ },
23
+ solana: {
24
+ mainnet: { mint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", decimals: 6 },
25
+ devnet: { mint: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", decimals: 6 }
26
+ },
27
+ tempo: {
28
+ mainnet: { address: "0x20C000000000000000000000b9537d11c60E8b50", decimals: 6 },
29
+ testnet: { address: "0x20c0000000000000000000000000000000000000", decimals: 6 }
30
+ }
31
+ };
32
+
33
+ // src/payment/rails.ts
34
+ var rails = {
35
+ "tempo-mainnet": {
36
+ method: "tempo",
37
+ network: networks.tempo.mainnet.caip2,
38
+ chainId: networks.tempo.mainnet.chainId,
39
+ currency: USDC.tempo.mainnet.address,
40
+ decimals: USDC.tempo.mainnet.decimals,
41
+ asset: USDC.tempo.mainnet.address
42
+ },
43
+ "tempo-testnet": {
44
+ method: "tempo",
45
+ network: networks.tempo.testnet.caip2,
46
+ chainId: networks.tempo.testnet.chainId,
47
+ currency: USDC.tempo.testnet.address,
48
+ decimals: USDC.tempo.testnet.decimals,
49
+ asset: USDC.tempo.testnet.address
50
+ },
51
+ "x402-base-mainnet": {
52
+ method: "x402",
53
+ network: networks.base.mainnet.caip2,
54
+ chainId: networks.base.mainnet.chainId,
55
+ currency: USDC.base.mainnet.address,
56
+ decimals: USDC.base.mainnet.decimals,
57
+ asset: USDC.base.mainnet.address
58
+ },
59
+ "x402-base-sepolia": {
60
+ method: "x402",
61
+ network: networks.base.sepolia.caip2,
62
+ chainId: networks.base.sepolia.chainId,
63
+ currency: USDC.base.sepolia.address,
64
+ decimals: USDC.base.sepolia.decimals,
65
+ asset: USDC.base.sepolia.address
66
+ },
67
+ // Upto rails — pay UP TO a max amount (Permit2-based, vs EIP-3009 for exact). Use for
68
+ // variable-cost APIs where the actual cost depends on output (LLM tokens, bandwidth, etc.).
69
+ // Only available on EVM networks; Solana svm doesn't ship an upto scheme yet.
70
+ "x402-base-mainnet-upto": {
71
+ method: "x402-upto",
72
+ network: networks.base.mainnet.caip2,
73
+ chainId: networks.base.mainnet.chainId,
74
+ currency: USDC.base.mainnet.address,
75
+ decimals: USDC.base.mainnet.decimals,
76
+ asset: USDC.base.mainnet.address
77
+ },
78
+ "x402-base-sepolia-upto": {
79
+ method: "x402-upto",
80
+ network: networks.base.sepolia.caip2,
81
+ chainId: networks.base.sepolia.chainId,
82
+ currency: USDC.base.sepolia.address,
83
+ decimals: USDC.base.sepolia.decimals,
84
+ asset: USDC.base.sepolia.address
85
+ },
86
+ "x402-solana-mainnet": {
87
+ method: "x402",
88
+ network: networks.solana.mainnet.caip2,
89
+ currency: USDC.solana.mainnet.mint,
90
+ decimals: USDC.solana.mainnet.decimals,
91
+ asset: USDC.solana.mainnet.mint
92
+ },
93
+ "x402-solana-devnet": {
94
+ method: "x402",
95
+ network: networks.solana.devnet.caip2,
96
+ currency: USDC.solana.devnet.mint,
97
+ decimals: USDC.solana.devnet.decimals,
98
+ asset: USDC.solana.devnet.mint
99
+ },
100
+ "stripe-spt": {
101
+ method: "stripe",
102
+ currency: "usd",
103
+ decimals: 2
104
+ }
105
+ };
106
+ function lookupRail(name) {
107
+ return rails[name];
108
+ }
109
+
110
+ // src/payment/directive.ts
111
+ function buildPaymentRequestBlob(input) {
112
+ const railDef = input.rail ? lookupRail(input.rail) : void 0;
113
+ const decimals = input.decimals ?? railDef?.decimals ?? 6;
114
+ const currency = input.currency ?? railDef?.currency ?? "usd";
115
+ const chainId = input.chainId ?? railDef?.chainId;
116
+ const amountNum = typeof input.amountUsd === "string" ? Number(input.amountUsd) : input.amountUsd;
117
+ const amountRaw = BigInt(Math.round(amountNum * 10 ** decimals)).toString();
118
+ const blob = { amount: amountRaw, currency, decimals };
119
+ if (input.recipient) blob.recipient = input.recipient;
120
+ const methodDetails = {};
121
+ if (chainId !== void 0) methodDetails.chainId = chainId;
122
+ if (input.networkId) methodDetails.networkId = input.networkId;
123
+ if (Object.keys(methodDetails).length > 0) blob.methodDetails = methodDetails;
124
+ return Buffer.from(JSON.stringify(blob)).toString("base64url");
125
+ }
126
+ function paymentDirective(input) {
127
+ const railDef = input.rail ? lookupRail(input.rail) : void 0;
128
+ const method = input.method ?? railDef?.method ?? "unknown";
129
+ const intent = input.intent ?? "charge";
130
+ const expires = input.expires ?? new Date(Date.now() + 5 * 60 * 1e3).toISOString();
131
+ return `Payment id="${input.id}", realm="${input.realm}", method="${method}", intent="${intent}", expires="${expires}", request="${input.request}"`;
132
+ }
133
+
134
+ // src/payment/wwwauthenticate.ts
135
+ function paymentRequiredHeader(input) {
136
+ return Buffer.from(JSON.stringify(input)).toString("base64");
137
+ }
138
+
139
+ // src/discovery/probe.ts
140
+ var ZERO_EVM_PAYTO = "0x0000000000000000000000000000000000000000";
141
+ var ZERO_SOLANA_PAYTO = "11111111111111111111111111111111";
142
+ function sampleX402AcceptForNetwork(caip2, amountAtomic = "1000000") {
143
+ if (caip2 === networks.base.mainnet.caip2) {
144
+ return {
145
+ scheme: "exact",
146
+ network: caip2,
147
+ amount: amountAtomic,
148
+ asset: USDC.base.mainnet.address,
149
+ payTo: ZERO_EVM_PAYTO,
150
+ maxTimeoutSeconds: 300,
151
+ extra: { name: "USDC", version: "2" }
152
+ };
153
+ }
154
+ if (caip2 === networks.base.sepolia.caip2) {
155
+ return {
156
+ scheme: "exact",
157
+ network: caip2,
158
+ amount: amountAtomic,
159
+ asset: USDC.base.sepolia.address,
160
+ payTo: ZERO_EVM_PAYTO,
161
+ maxTimeoutSeconds: 300,
162
+ extra: { name: "USDC", version: "2" }
163
+ };
164
+ }
165
+ if (caip2 === networks.solana.mainnet.caip2) {
166
+ return {
167
+ scheme: "exact",
168
+ network: caip2,
169
+ amount: amountAtomic,
170
+ asset: USDC.solana.mainnet.mint,
171
+ payTo: ZERO_SOLANA_PAYTO,
172
+ maxTimeoutSeconds: 300
173
+ };
174
+ }
175
+ if (caip2 === networks.solana.devnet.caip2) {
176
+ return {
177
+ scheme: "exact",
178
+ network: caip2,
179
+ amount: amountAtomic,
180
+ asset: USDC.solana.devnet.mint,
181
+ payTo: ZERO_SOLANA_PAYTO,
182
+ maxTimeoutSeconds: 300
183
+ };
184
+ }
185
+ return null;
186
+ }
187
+ function buildDiscoveryProbeResponse(opts) {
188
+ const probeId = `probe_${Date.now()}`;
189
+ const expires = new Date(Date.now() + (opts.ttlSeconds ?? 300) * 1e3).toISOString();
190
+ const request = buildPaymentRequestBlob({
191
+ rail: opts.sampleRail,
192
+ amountUsd: opts.sampleAmountUsd,
193
+ recipient: opts.sampleRecipient
194
+ });
195
+ const directive = paymentDirective({
196
+ rail: opts.sampleRail,
197
+ id: probeId,
198
+ realm: opts.realm,
199
+ intent: opts.intent,
200
+ expires,
201
+ request
202
+ });
203
+ const bodyObj = {
204
+ error: {
205
+ code: "payment_required",
206
+ message: opts.message ?? "This endpoint requires payment. Send a valid request body to receive a full challenge."
207
+ },
208
+ discovery: true,
209
+ ...opts.docsUrl ? { docs: opts.docsUrl } : {}
210
+ };
211
+ const headers = {
212
+ "content-type": "application/json",
213
+ "www-authenticate": directive
214
+ };
215
+ if (opts.x402Sample) {
216
+ const x402Version = opts.x402Sample.version ?? 2;
217
+ const sampleAccepts = opts.x402Sample.accepts ?? (opts.x402Sample.networks ?? []).map((n) => sampleX402AcceptForNetwork(n, opts.x402Sample.amountAtomic ?? "1000000")).filter((e) => e !== null);
218
+ headers["payment-required"] = paymentRequiredHeader({
219
+ x402Version,
220
+ accepts: sampleAccepts,
221
+ ...opts.x402Sample.resourceUrl ? { resource: { url: opts.x402Sample.resourceUrl, mimeType: "application/json" } } : {}
222
+ });
223
+ bodyObj.x402Version = x402Version;
224
+ const headerJson = JSON.parse(Buffer.from(headers["payment-required"], "base64").toString("utf-8"));
225
+ bodyObj.accepts = headerJson.accepts;
226
+ }
227
+ return {
228
+ status: 402,
229
+ headers,
230
+ body: JSON.stringify(bodyObj)
231
+ };
232
+ }
233
+ async function isDiscoveryProbeRequest(req) {
234
+ if (req.method !== "POST") return false;
235
+ const auth = req.headers.get("authorization");
236
+ if (auth?.startsWith("Payment ")) return false;
237
+ const body = await req.clone().text();
238
+ return !body || body === "{}";
239
+ }
240
+
241
+ // src/discovery/bazaar.ts
242
+ async function createBazaarDiscovery(config) {
243
+ const bazaar = await dynamicImport("@x402/extensions/bazaar");
244
+ if (!bazaar?.declareDiscoveryExtension) {
245
+ throw new Error(
246
+ "@x402/extensions not installed \u2014 `npm install @x402/extensions` for createBazaarDiscovery."
247
+ );
248
+ }
249
+ return bazaar.declareDiscoveryExtension(config);
250
+ }
251
+ async function dynamicImport(moduleName) {
252
+ try {
253
+ return await import(moduleName);
254
+ } catch {
255
+ return null;
256
+ }
257
+ }
258
+
259
+ // src/discovery/well_known_mpp.ts
260
+ function buildWellKnownMpp(input) {
261
+ return {
262
+ name: input.name,
263
+ ...input.description ? { description: input.description } : {},
264
+ url: input.url,
265
+ ...input.openapi ? { openapi: input.openapi } : {},
266
+ endpoints: input.endpoints,
267
+ ...input.catalog ? { catalog: input.catalog } : {},
268
+ purchase: {
269
+ ...input.purchase.required_fields ? { required_fields: input.purchase.required_fields } : {},
270
+ ...input.purchase.optional_fields ? { optional_fields: input.purchase.optional_fields } : {},
271
+ ...input.purchase.extra ?? {},
272
+ ...input.purchase.identity ? { identity: input.purchase.identity } : {},
273
+ ...input.purchase.identity_paths ? { identity_paths: input.purchase.identity_paths } : {},
274
+ payment_methods: input.purchase.methods,
275
+ ...input.purchase.x402 ? { x402: input.purchase.x402 } : {},
276
+ ...input.purchase.compliance ? { compliance: input.purchase.compliance } : {}
277
+ },
278
+ ...input.shipping ? { shipping: input.shipping } : {},
279
+ ...input.extra ?? {}
280
+ };
281
+ }
282
+
283
+ // src/discovery/llms_txt.ts
284
+ function llmsTxtIdentitySection(input = {}) {
285
+ if (!input.agentscore) {
286
+ return "";
287
+ }
288
+ const compliance = input.compliance;
289
+ const complianceNote = compliance ? `
290
+
291
+ Compliance: ${[
292
+ compliance.require_kyc ? "KYC required" : null,
293
+ compliance.min_age ? `age ${compliance.min_age}+` : null,
294
+ compliance.allowed_jurisdictions?.length ? `${compliance.allowed_jurisdictions.join("/")} only` : null,
295
+ compliance.require_sanctions_clear ? "sanctions clear" : null
296
+ ].filter(Boolean).join(", ")}.` : "";
297
+ return `## Choose your identity header
298
+
299
+ AgentScore provides cross-merchant identity \u2014 one KYC works for every AgentScore-gated endpoint, no re-verification per site. Pick the right header based on how you plan to pay:
300
+
301
+ - **Wallet-auth** (preferred for agents with a stable crypto wallet): send \`X-Wallet-Address: 0x...\`. Only works on rails that carry a wallet signature \u2014 Tempo MPP and x402 EIP-3009. The wallet you claim MUST sign the payment; we verify that the payment signer resolves to the same operator as the claimed wallet. No TTL, no rotation.
302
+ - **Operator-token** (works for every rail): send \`X-Operator-Token: opc_...\`. Required when paying with Stripe SPT or card (those rails have no wallet signer). Reusable across every AgentScore merchant until the token expires.
303
+ - **Neither**: you'll get 403 with \`verify_url\` + \`poll_secret\` \u2014 complete the session flow once, then reuse the credential (or any wallet that pays under it) forever.
304
+
305
+ If you reach another AgentScore-gated endpoint in the future, the same credential and/or any linked wallet already works \u2014 skip the session flow.
306
+
307
+ ## Memory contract
308
+
309
+ First-encounter 403 responses (and the POST /v1/sessions success body) include an \`agent_memory\` block describing how AgentScore identity works across merchants. LLM-hosted agents should persist its contents (the pattern, never secrets) so subsequent AgentScore-gated endpoints become returning-customer encounters.${complianceNote}`;
310
+ }
311
+ function llmsTxtPaymentSection(input) {
312
+ return input.verbose ? llmsTxtPaymentSectionVerbose(input) : llmsTxtPaymentSectionCompact(input);
313
+ }
314
+ function hasRailFamily(rails2, prefix) {
315
+ return rails2.some((r) => r.startsWith(prefix));
316
+ }
317
+ function isTestnetRail(rails2, prefix) {
318
+ return rails2.some((r) => r.startsWith(prefix) && /(sepolia|devnet|moderato|testnet)/.test(r));
319
+ }
320
+ function llmsTxtPaymentSectionCompact(input) {
321
+ const lines = ["## Payment", ""];
322
+ const rails2 = input.rails;
323
+ if (hasRailFamily(rails2, "tempo-")) {
324
+ lines.push(`- **Tempo USDC via MPP** \u2014 \`tempo request -X POST -H "X-Operator-Token: opc_..." --json '{...}' --max-spend N ` + input.appUrl + "`");
325
+ }
326
+ if (hasRailFamily(rails2, "x402-base-")) {
327
+ lines.push("- **x402 USDC on Base** (EIP-3009) \u2014 `agentscore-pay pay POST " + input.appUrl + ` --chain base -H "X-Operator-Token: opc_..." -d '{...}'\``);
328
+ }
329
+ if (hasRailFamily(rails2, "x402-solana-")) {
330
+ lines.push("- **x402 USDC on Solana** (SPL Token) \u2014 `agentscore-pay pay POST " + input.appUrl + ` --chain solana -H "X-Operator-Token: opc_..." -d '{...}'\``);
331
+ }
332
+ if (rails2.includes("stripe-spt")) {
333
+ lines.push("- **Stripe Shared Payment Token** \u2014 agent mints SPT (own Stripe account scoped to networkId, OR `link-cli spend-request create --credential-type shared_payment_token --network-id <profileId> ...`)");
334
+ }
335
+ lines.push("");
336
+ lines.push("IMPORTANT: Do NOT use raw on-chain transfers. Use the CLI commands above so the payment credential is signed and submitted via the protocol handshake.");
337
+ lines.push("");
338
+ return lines.join("\n");
339
+ }
340
+ function llmsTxtPaymentSectionVerbose(input) {
341
+ const rails2 = input.rails;
342
+ const tempoNetwork = input.tempoNetworkName ?? "tempo-mainnet";
343
+ const tempoChain = input.tempoChainId ?? 4217;
344
+ const hasTempo = hasRailFamily(rails2, "tempo-");
345
+ const hasBase = hasRailFamily(rails2, "x402-base-");
346
+ const hasSolana = hasRailFamily(rails2, "x402-solana-");
347
+ const hasStripe = rails2.includes("stripe-spt");
348
+ const baseNetworkName = isTestnetRail(rails2, "x402-base-") ? "Base Sepolia" : "Base";
349
+ const solanaNetworkName = isTestnetRail(rails2, "x402-solana-") ? "Solana devnet" : "Solana";
350
+ const lines = ["## Payment", ""];
351
+ lines.push("This is an agent-first API. All payments are initiated and completed by agents. The 402 challenge advertises:");
352
+ lines.push("");
353
+ if (hasTempo) lines.push("- **Tempo USDC via MPP** (on-chain stablecoin)");
354
+ if (hasBase || hasSolana) {
355
+ const chains = [hasBase && `${baseNetworkName} (EIP-3009)`, hasSolana && `${solanaNetworkName} (SPL Token)`].filter(Boolean).join(" and ");
356
+ lines.push(`- **x402 USDC** on ${chains}, via the Coinbase facilitator`);
357
+ }
358
+ if (hasStripe) lines.push("- **Stripe Shared Payment Token** (agent mints SPT on their Stripe account scoped to our networkId in the challenge, submits it in the credential)");
359
+ lines.push("");
360
+ if (hasTempo) {
361
+ lines.push("### How to pay with Tempo");
362
+ lines.push("");
363
+ lines.push("1. Install the Tempo CLI: curl -fsSL https://tempo.xyz/install | bash");
364
+ lines.push("2. Log in to your Tempo Wallet: tempo wallet login (passkey auth in browser)");
365
+ lines.push(`3. Confirm your balance: tempo wallet whoami (need USDC.e on ${tempoNetwork}, chain ${tempoChain})`);
366
+ lines.push("4. If balance is zero, fund it: tempo wallet fund");
367
+ lines.push("");
368
+ lines.push("Then use `tempo request` to make the paid purchase:");
369
+ lines.push("");
370
+ lines.push("tempo request -X POST \\");
371
+ lines.push(' -H "X-Operator-Token: opc_your_credential" \\');
372
+ lines.push(' -H "Content-Type: application/json" \\');
373
+ lines.push(" --json '{...}' \\");
374
+ lines.push(" --max-spend N \\");
375
+ lines.push(` ${input.appUrl}`);
376
+ lines.push("");
377
+ lines.push(`\`tempo request\` handles the full MPP handshake: sends the POST, receives the 402 challenge, signs the payment on ${tempoNetwork}, submits the credential, and returns the completed order.`);
378
+ lines.push("");
379
+ }
380
+ if (hasBase || hasSolana) {
381
+ const chainsLabel = [hasBase && baseNetworkName, hasSolana && solanaNetworkName].filter(Boolean).join(" or ");
382
+ const flags = [hasBase && "`--chain base`", hasSolana && "`--chain solana`"].filter(Boolean).join(" or ");
383
+ lines.push(`### How to pay with x402 (${chainsLabel})`);
384
+ lines.push("");
385
+ lines.push("1. Install the agentscore-pay CLI: npm install -g @agent-score/pay (or: brew install agentscore/tap/agentscore-pay)");
386
+ lines.push(`2. Create a wallet on your chain of choice: agentscore-pay wallet create ${flags}`);
387
+ lines.push(`3. Fund the printed address with USDC on ${chainsLabel}`);
388
+ lines.push(`4. Confirm balance: agentscore-pay balance ${flags}`);
389
+ lines.push("");
390
+ lines.push("Then submit the paid purchase:");
391
+ lines.push("");
392
+ lines.push(`agentscore-pay pay POST ${input.appUrl} \\`);
393
+ lines.push(` ${hasBase ? "--chain base" : "--chain solana"} \\`);
394
+ lines.push(' -H "X-Operator-Token: opc_your_credential" \\');
395
+ lines.push(' -H "Content-Type: application/json" \\');
396
+ lines.push(" -d '{...}' \\");
397
+ lines.push(" --max-spend N");
398
+ lines.push("");
399
+ const handshakeChains = [hasBase && "EIP-3009 (Base)", hasSolana && "SPL Token (Solana)"].filter(Boolean).join(" or ");
400
+ lines.push(`The CLI handles the full x402 handshake: hits the URL, parses the 402 challenge, signs the ${handshakeChains} transaction, submits via X-Payment header, and returns the completed order.`);
401
+ lines.push("");
402
+ }
403
+ if (hasStripe) {
404
+ lines.push("### How to pay with Stripe SPT");
405
+ lines.push("");
406
+ lines.push("Mint a SharedPaymentToken scoped to the profile_id advertised in `accepted_methods.stripe.profile_id`, then submit via `Authorization: Payment` MPP header with `method=stripe/charge`. Either bring your own Stripe account or use `link-cli spend-request create --credential-type shared_payment_token --network-id <profileId> ...` for users with Stripe Link wallets.");
407
+ lines.push("");
408
+ }
409
+ lines.push("IMPORTANT: Do NOT use `tempo wallet transfer` or send USDC manually to the x402 deposit addresses \u2014 those bypass the payment handshake and your order will stay in pending_identity.");
410
+ if (hasBase || hasSolana) {
411
+ lines.push("IMPORTANT: x402 payments must be the exact amount specified in the 402 challenge. Overpayments and underpayments cannot be matched and funds may be unrecoverable.");
412
+ }
413
+ lines.push("");
414
+ return lines.join("\n");
415
+ }
416
+ function buildLlmsTxt(input) {
417
+ const parts = [`# ${input.merchantName}`];
418
+ if (input.tagline) {
419
+ parts.push(`> ${input.tagline}`);
420
+ }
421
+ parts.push("");
422
+ for (const s of input.sections) {
423
+ parts.push(`## ${s.heading}`);
424
+ parts.push("");
425
+ parts.push(s.content);
426
+ parts.push("");
427
+ }
428
+ if (input.agentscoreIdentity) {
429
+ parts.push(llmsTxtIdentitySection(input.agentscoreIdentity));
430
+ parts.push("");
431
+ }
432
+ if (input.payment) {
433
+ parts.push(llmsTxtPaymentSection(input.payment));
434
+ }
435
+ return parts.join("\n");
436
+ }
437
+
438
+ // src/discovery/openapi.ts
439
+ function agentscoreSecuritySchemes() {
440
+ return {
441
+ OperatorToken: {
442
+ type: "apiKey",
443
+ in: "header",
444
+ name: "X-Operator-Token",
445
+ description: "Operator-token-path identity (opc_...). Works on every payment rail; reusable across AgentScore merchants. If both X-Operator-Token and X-Wallet-Address are sent, this one wins."
446
+ },
447
+ WalletAddress: {
448
+ type: "apiKey",
449
+ in: "header",
450
+ name: "X-Wallet-Address",
451
+ description: "Wallet-path identity (0x... or base58). Only works on rails that carry a wallet signature (Tempo MPP, x402 EIP-3009, x402 SPL Token). The wallet you claim MUST sign the payment."
452
+ }
453
+ };
454
+ }
455
+ function agentscoreDenialSchemas() {
456
+ return {
457
+ AgentScoreDenialReason: {
458
+ type: "string",
459
+ enum: [
460
+ "missing_identity",
461
+ "identity_verification_required",
462
+ "token_expired",
463
+ "invalid_credential",
464
+ "wallet_signer_mismatch",
465
+ "wallet_auth_requires_wallet_signing",
466
+ "wallet_not_trusted",
467
+ "api_error",
468
+ "payment_required"
469
+ ],
470
+ description: "Denial code emitted by AgentScore's gate middleware in 403 responses. Each comes with a structured agent_instructions block describing recovery actions."
471
+ },
472
+ AgentScoreDenialBody: {
473
+ type: "object",
474
+ properties: {
475
+ error: { $ref: "#/components/schemas/AgentScoreDenialReason" },
476
+ agent_instructions: {
477
+ type: "string",
478
+ description: "JSON-encoded { action, steps, user_message } block. Agents parse this to learn how to recover (e.g., poll a verify_url, switch headers, re-sign)."
479
+ },
480
+ verify_url: { type: "string", format: "uri", description: "Present for missing_identity / token_expired denials." },
481
+ session_id: { type: "string" },
482
+ poll_url: { type: "string", format: "uri" },
483
+ poll_secret: { type: "string" },
484
+ agent_memory: { type: "object", description: "Cross-merchant pattern hint emitted on first-encounter denials." }
485
+ },
486
+ required: ["error", "agent_instructions"]
487
+ }
488
+ };
489
+ }
490
+ function agentscorePaymentRequiredSchema() {
491
+ return {
492
+ AgentScorePaymentRequired: {
493
+ type: "object",
494
+ properties: {
495
+ payment_required: { type: "boolean", enum: [true] },
496
+ x402Version: { type: "integer", enum: [1, 2] },
497
+ accepts: { type: "array", items: { type: "object" }, description: "x402 PaymentRequired.accepts entries." },
498
+ accepted_methods: {
499
+ type: "array",
500
+ items: { type: "object" },
501
+ description: "MPP method entries (tempo/charge, x402/exact, stripe/charge, ...)."
502
+ },
503
+ amount_usd: { type: "string" },
504
+ currency: { type: "string" },
505
+ pricing: {
506
+ type: "object",
507
+ properties: {
508
+ subtotal: { type: "string" },
509
+ tax: { type: "string" },
510
+ tax_rate: { type: "number" },
511
+ tax_state: { type: "string" },
512
+ total: { type: "string" }
513
+ }
514
+ },
515
+ identity_mode: { type: "string", enum: ["wallet", "operator_token"] },
516
+ required_signer: { type: "string" },
517
+ linked_wallets: { type: "array", items: { type: "string" } },
518
+ signer_constraint: { type: "string" },
519
+ agent_instructions: { type: "object" },
520
+ agent_memory: { type: "object" }
521
+ }
522
+ }
523
+ };
524
+ }
525
+ function agentscoreOpenApiSnippets(opts = {}) {
526
+ const out = {};
527
+ if (opts.security !== false) {
528
+ out.securitySchemes = agentscoreSecuritySchemes();
529
+ }
530
+ if (opts.denials !== false || opts.paymentRequired !== false) {
531
+ out.schemas = {
532
+ ...opts.denials !== false ? agentscoreDenialSchemas() : {},
533
+ ...opts.paymentRequired !== false ? agentscorePaymentRequiredSchema() : {}
534
+ };
535
+ }
536
+ return out;
537
+ }
538
+
539
+ // src/discovery/robots_tag.ts
540
+ var defaultDiscoveryPaths = /* @__PURE__ */ new Set([
541
+ "/openapi.json",
542
+ "/llms.txt",
543
+ "/.well-known/mpp.json",
544
+ "/.well-known/agent-card.json",
545
+ "/.well-known/ucp",
546
+ "/favicon.png",
547
+ "/favicon.ico"
548
+ ]);
549
+ function isDiscoveryPath(path, options) {
550
+ if (options?.replace) {
551
+ return new Set(options.customPaths ?? []).has(path);
552
+ }
553
+ if (defaultDiscoveryPaths.has(path)) return true;
554
+ if (options?.customPaths) {
555
+ for (const p of options.customPaths) if (p === path) return true;
556
+ }
557
+ return false;
558
+ }
559
+ var DEFAULT_ROBOTS_TAG = "noindex, nofollow, noarchive, nosnippet";
560
+ function shouldNoindex(path, customSet, replacePaths) {
561
+ const isDiscovery = replacePaths ? customSet?.has(path) ?? false : defaultDiscoveryPaths.has(path) || (customSet?.has(path) ?? false);
562
+ return !isDiscovery;
563
+ }
564
+ function noindexNonDiscoveryPaths(options) {
565
+ const customSet = options?.customPaths ? new Set(options.customPaths) : void 0;
566
+ const robotsTag = options?.robotsTag ?? DEFAULT_ROBOTS_TAG;
567
+ return async (c, next) => {
568
+ await next();
569
+ if (shouldNoindex(c.req.path, customSet, options?.replacePaths)) {
570
+ c.header("X-Robots-Tag", robotsTag);
571
+ }
572
+ };
573
+ }
574
+ function noindexNonDiscoveryPathsExpress(options) {
575
+ const customSet = options?.customPaths ? new Set(options.customPaths) : void 0;
576
+ const robotsTag = options?.robotsTag ?? DEFAULT_ROBOTS_TAG;
577
+ return (req, res, next) => {
578
+ if (shouldNoindex(req.path, customSet, options?.replacePaths)) {
579
+ res.setHeader("X-Robots-Tag", robotsTag);
580
+ }
581
+ next();
582
+ };
583
+ }
584
+ function noindexNonDiscoveryPathsFastify(app, options, done) {
585
+ const customSet = options?.customPaths ? new Set(options.customPaths) : void 0;
586
+ const robotsTag = options?.robotsTag ?? DEFAULT_ROBOTS_TAG;
587
+ app.addHook("onRequest", (req, reply, hookDone) => {
588
+ const path = (req.url ?? req.routerPath ?? "").split("?")[0];
589
+ if (shouldNoindex(path, customSet, options?.replacePaths)) {
590
+ reply.header("X-Robots-Tag", robotsTag);
591
+ }
592
+ hookDone();
593
+ });
594
+ done();
595
+ }
596
+ function wrapNoindexResponse(path, response, options) {
597
+ const customSet = options?.customPaths ? new Set(options.customPaths) : void 0;
598
+ const robotsTag = options?.robotsTag ?? DEFAULT_ROBOTS_TAG;
599
+ if (!shouldNoindex(path, customSet, options?.replacePaths)) return response;
600
+ const headers = new Headers(response.headers);
601
+ headers.set("X-Robots-Tag", robotsTag);
602
+ return new Response(response.body, {
603
+ status: response.status,
604
+ statusText: response.statusText,
605
+ headers
606
+ });
607
+ }
608
+ var applyNoindexHeader = wrapNoindexResponse;
609
+ export {
610
+ agentscoreDenialSchemas,
611
+ agentscoreOpenApiSnippets,
612
+ agentscorePaymentRequiredSchema,
613
+ agentscoreSecuritySchemes,
614
+ applyNoindexHeader,
615
+ buildDiscoveryProbeResponse,
616
+ buildLlmsTxt,
617
+ buildWellKnownMpp,
618
+ createBazaarDiscovery,
619
+ defaultDiscoveryPaths,
620
+ isDiscoveryPath,
621
+ isDiscoveryProbeRequest,
622
+ llmsTxtIdentitySection,
623
+ llmsTxtPaymentSection,
624
+ noindexNonDiscoveryPaths,
625
+ noindexNonDiscoveryPathsExpress,
626
+ noindexNonDiscoveryPathsFastify,
627
+ sampleX402AcceptForNetwork,
628
+ wrapNoindexResponse
629
+ };
630
+ //# sourceMappingURL=index.mjs.map