@agent-score/commerce 1.8.1 → 2.0.1
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 +73 -9
- package/dist/{_response-9yp6Fit2.d.mts → _response-BFYN3b6i.d.mts} +17 -19
- package/dist/{_response-CC6jNb8q.d.ts → _response-_iPD5AIj.d.ts} +17 -19
- package/dist/challenge/index.d.mts +106 -198
- package/dist/challenge/index.d.ts +106 -198
- package/dist/challenge/index.js +238 -111
- package/dist/challenge/index.js.map +1 -1
- package/dist/challenge/index.mjs +238 -111
- package/dist/challenge/index.mjs.map +1 -1
- package/dist/checkout-B1JuEcbx.d.ts +939 -0
- package/dist/checkout-BN5i1Fi7.d.mts +939 -0
- package/dist/core.d.mts +2 -2
- package/dist/core.d.ts +2 -2
- package/dist/core.js +1 -1
- package/dist/core.js.map +1 -1
- package/dist/core.mjs +1 -1
- package/dist/core.mjs.map +1 -1
- package/dist/discovery/index.d.mts +453 -51
- package/dist/discovery/index.d.ts +453 -51
- package/dist/discovery/index.js +1092 -58
- package/dist/discovery/index.js.map +1 -1
- package/dist/discovery/index.mjs +1060 -57
- package/dist/discovery/index.mjs.map +1 -1
- package/dist/identity/express.d.mts +3 -3
- package/dist/identity/express.d.ts +3 -3
- package/dist/identity/express.js +30 -19
- package/dist/identity/express.js.map +1 -1
- package/dist/identity/express.mjs +30 -19
- package/dist/identity/express.mjs.map +1 -1
- package/dist/identity/fastify.d.mts +4 -4
- package/dist/identity/fastify.d.ts +4 -4
- package/dist/identity/fastify.js +30 -19
- package/dist/identity/fastify.js.map +1 -1
- package/dist/identity/fastify.mjs +30 -19
- package/dist/identity/fastify.mjs.map +1 -1
- package/dist/identity/hono.d.mts +3 -3
- package/dist/identity/hono.d.ts +3 -3
- package/dist/identity/hono.js +30 -19
- package/dist/identity/hono.js.map +1 -1
- package/dist/identity/hono.mjs +30 -19
- package/dist/identity/hono.mjs.map +1 -1
- package/dist/identity/nextjs.d.mts +6 -7
- package/dist/identity/nextjs.d.ts +6 -7
- package/dist/identity/nextjs.js +30 -19
- package/dist/identity/nextjs.js.map +1 -1
- package/dist/identity/nextjs.mjs +30 -19
- package/dist/identity/nextjs.mjs.map +1 -1
- package/dist/identity/policy.d.mts +41 -4
- package/dist/identity/policy.d.ts +41 -4
- package/dist/identity/policy.js +23307 -18
- package/dist/identity/policy.js.map +1 -1
- package/dist/identity/policy.mjs +23313 -3
- package/dist/identity/policy.mjs.map +1 -1
- package/dist/identity/web.d.mts +3 -3
- package/dist/identity/web.d.ts +3 -3
- package/dist/identity/web.js +30 -19
- package/dist/identity/web.js.map +1 -1
- package/dist/identity/web.mjs +30 -19
- package/dist/identity/web.mjs.map +1 -1
- package/dist/index.d.mts +72 -329
- package/dist/index.d.ts +72 -329
- package/dist/index.js +23301 -378
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +23294 -362
- package/dist/index.mjs.map +1 -1
- package/dist/payment/index.d.mts +297 -265
- package/dist/payment/index.d.ts +297 -265
- package/dist/payment/index.js +605 -149
- package/dist/payment/index.js.map +1 -1
- package/dist/payment/index.mjs +590 -148
- package/dist/payment/index.mjs.map +1 -1
- package/dist/{agent_instructions-DiMSGkdm.d.mts → pricing-CQ9DIFaw.d.ts} +109 -56
- package/dist/{agent_instructions-DiMSGkdm.d.ts → pricing-CxzwyiO6.d.mts} +109 -56
- package/dist/rail_spec-XP0wKgJV.d.mts +132 -0
- package/dist/rail_spec-XP0wKgJV.d.ts +132 -0
- package/dist/{signer-CFVQsWjL.d.mts → signer-3FAit11j.d.mts} +27 -1
- package/dist/{signer-CFVQsWjL.d.ts → signer-3FAit11j.d.ts} +27 -1
- package/dist/solana-Cds87OTu.d.mts +67 -0
- package/dist/solana-Cds87OTu.d.ts +67 -0
- package/dist/stripe-multichain/index.d.mts +55 -66
- package/dist/stripe-multichain/index.d.ts +55 -66
- package/dist/stripe-multichain/index.js +68 -42
- package/dist/stripe-multichain/index.js.map +1 -1
- package/dist/stripe-multichain/index.mjs +68 -41
- package/dist/stripe-multichain/index.mjs.map +1 -1
- package/dist/{wwwauthenticate-CU1eNvMQ.d.mts → wwwauthenticate-D_FMnPgU.d.mts} +9 -10
- package/dist/{wwwauthenticate-CU1eNvMQ.d.ts → wwwauthenticate-D_FMnPgU.d.ts} +9 -10
- package/dist/x402_server-hgQzWQwB.d.mts +81 -0
- package/dist/x402_server-hgQzWQwB.d.ts +81 -0
- package/package.json +9 -7
package/dist/payment/index.js
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/payment/index.ts
|
|
21
21
|
var payment_exports = {};
|
|
22
22
|
__export(payment_exports, {
|
|
23
|
+
RAIL_SPEC_DEFAULTS: () => RAIL_SPEC_DEFAULTS,
|
|
23
24
|
SETTLEMENT_OVERRIDES_HEADER: () => SETTLEMENT_OVERRIDES_HEADER,
|
|
24
25
|
USDC: () => USDC,
|
|
25
26
|
X402_SUPPORTED_BASE_NETWORKS: () => X402_SUPPORTED_BASE_NETWORKS,
|
|
@@ -29,12 +30,22 @@ __export(payment_exports, {
|
|
|
29
30
|
buildPaymentHeaders: () => buildPaymentHeaders,
|
|
30
31
|
buildPaymentRequestBlob: () => buildPaymentRequestBlob,
|
|
31
32
|
buildX402AcceptsFor402: () => buildX402AcceptsFor402,
|
|
33
|
+
classifyOrchestrationError: () => classifyOrchestrationError,
|
|
32
34
|
classifyX402SettleResult: () => classifyX402SettleResult,
|
|
35
|
+
composeMppxRequest: () => composeMppxRequest,
|
|
33
36
|
createMppxServer: () => createMppxServer,
|
|
34
37
|
createX402Server: () => createX402Server,
|
|
38
|
+
detectRailFromHeaders: () => detectRailFromHeaders,
|
|
35
39
|
dispatchSettlementByNetwork: () => dispatchSettlementByNetwork,
|
|
36
40
|
extractPaymentSigner: () => extractPaymentSigner,
|
|
41
|
+
extractPaymentSignerFromAuth: () => extractPaymentSignerFromAuth,
|
|
42
|
+
extractSignerForPrecheck: () => extractSignerForPrecheck,
|
|
43
|
+
formatUsdCents: () => formatUsdCents,
|
|
44
|
+
lazyMppxServer: () => lazyMppxServer,
|
|
45
|
+
lazyX402Server: () => lazyX402Server,
|
|
46
|
+
loadSolanaFeePayer: () => loadSolanaFeePayer,
|
|
37
47
|
lookupRail: () => lookupRail,
|
|
48
|
+
mppxChallengeHeaders: () => mppxChallengeHeaders,
|
|
38
49
|
networkFamily: () => networkFamily,
|
|
39
50
|
networks: () => networks,
|
|
40
51
|
paymentDirective: () => paymentDirective,
|
|
@@ -43,11 +54,14 @@ __export(payment_exports, {
|
|
|
43
54
|
rails: () => rails,
|
|
44
55
|
readX402PaymentHeader: () => readX402PaymentHeader,
|
|
45
56
|
registerX402SchemesV1V2: () => registerX402SchemesV1V2,
|
|
57
|
+
resolveRecipient: () => resolveRecipient,
|
|
46
58
|
settlementOverrideHeader: () => settlementOverrideHeader,
|
|
59
|
+
usdToAtomic: () => usdToAtomic,
|
|
47
60
|
validateX402NetworkConfig: () => validateX402NetworkConfig,
|
|
48
61
|
verifyX402Request: () => verifyX402Request,
|
|
49
62
|
wrapSolanaChargeWithFinalizedBlockhash: () => wrapSolanaChargeWithFinalizedBlockhash,
|
|
50
|
-
wwwAuthenticateHeader: () => wwwAuthenticateHeader
|
|
63
|
+
wwwAuthenticateHeader: () => wwwAuthenticateHeader,
|
|
64
|
+
zeroAmountCarveOut: () => zeroAmountCarveOut
|
|
51
65
|
});
|
|
52
66
|
module.exports = __toCommonJS(payment_exports);
|
|
53
67
|
|
|
@@ -168,49 +182,116 @@ function lookupRail(name) {
|
|
|
168
182
|
}
|
|
169
183
|
|
|
170
184
|
// src/payment/directive.ts
|
|
171
|
-
function buildPaymentRequestBlob(
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
185
|
+
function buildPaymentRequestBlob({
|
|
186
|
+
rail,
|
|
187
|
+
amountUsd,
|
|
188
|
+
currency,
|
|
189
|
+
decimals,
|
|
190
|
+
recipient,
|
|
191
|
+
chainId,
|
|
192
|
+
networkId
|
|
193
|
+
}) {
|
|
194
|
+
const railDef = rail ? lookupRail(rail) : void 0;
|
|
195
|
+
const decimalsResolved = decimals ?? railDef?.decimals ?? 6;
|
|
196
|
+
const currencyResolved = currency ?? railDef?.currency ?? "usd";
|
|
197
|
+
const chainIdResolved = chainId ?? railDef?.chainId;
|
|
198
|
+
const amountNum = typeof amountUsd === "string" ? Number(amountUsd) : amountUsd;
|
|
199
|
+
const amountRaw = BigInt(Math.round(amountNum * 10 ** decimalsResolved)).toString();
|
|
200
|
+
const blob = { amount: amountRaw, currency: currencyResolved, decimals: decimalsResolved };
|
|
201
|
+
if (recipient) blob.recipient = recipient;
|
|
180
202
|
const methodDetails = {};
|
|
181
|
-
if (
|
|
182
|
-
if (
|
|
203
|
+
if (chainIdResolved !== void 0) methodDetails.chainId = chainIdResolved;
|
|
204
|
+
if (networkId) methodDetails.networkId = networkId;
|
|
183
205
|
if (Object.keys(methodDetails).length > 0) blob.methodDetails = methodDetails;
|
|
184
206
|
return Buffer.from(JSON.stringify(blob)).toString("base64url");
|
|
185
207
|
}
|
|
186
|
-
function paymentDirective(
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
208
|
+
function paymentDirective({
|
|
209
|
+
rail,
|
|
210
|
+
id,
|
|
211
|
+
realm,
|
|
212
|
+
method,
|
|
213
|
+
intent,
|
|
214
|
+
expires,
|
|
215
|
+
request
|
|
216
|
+
}) {
|
|
217
|
+
const railDef = rail ? lookupRail(rail) : void 0;
|
|
218
|
+
const methodResolved = method ?? railDef?.method ?? "unknown";
|
|
219
|
+
const intentResolved = intent ?? "charge";
|
|
220
|
+
const expiresResolved = expires ?? new Date(Date.now() + 5 * 60 * 1e3).toISOString();
|
|
221
|
+
return `Payment id="${id}", realm="${realm}", method="${methodResolved}", intent="${intentResolved}", expires="${expiresResolved}", request="${request}"`;
|
|
192
222
|
}
|
|
193
|
-
function buildPaymentDirective(
|
|
223
|
+
function buildPaymentDirective({
|
|
224
|
+
rail,
|
|
225
|
+
id,
|
|
226
|
+
realm,
|
|
227
|
+
amountUsd,
|
|
228
|
+
currency,
|
|
229
|
+
decimals,
|
|
230
|
+
recipient,
|
|
231
|
+
chainId,
|
|
232
|
+
networkId,
|
|
233
|
+
method,
|
|
234
|
+
intent,
|
|
235
|
+
expires
|
|
236
|
+
}) {
|
|
194
237
|
const request = buildPaymentRequestBlob({
|
|
195
|
-
rail
|
|
196
|
-
amountUsd
|
|
197
|
-
currency
|
|
198
|
-
decimals
|
|
199
|
-
recipient
|
|
200
|
-
chainId
|
|
201
|
-
networkId
|
|
238
|
+
rail,
|
|
239
|
+
amountUsd,
|
|
240
|
+
currency,
|
|
241
|
+
decimals,
|
|
242
|
+
recipient,
|
|
243
|
+
chainId,
|
|
244
|
+
networkId
|
|
202
245
|
});
|
|
203
246
|
return paymentDirective({
|
|
204
|
-
rail
|
|
205
|
-
id
|
|
206
|
-
realm
|
|
207
|
-
method
|
|
208
|
-
intent
|
|
209
|
-
expires
|
|
247
|
+
rail,
|
|
248
|
+
id,
|
|
249
|
+
realm,
|
|
250
|
+
method,
|
|
251
|
+
intent,
|
|
252
|
+
expires,
|
|
210
253
|
request
|
|
211
254
|
});
|
|
212
255
|
}
|
|
213
256
|
|
|
257
|
+
// src/payment/rail_spec.ts
|
|
258
|
+
async function resolveRecipient(r) {
|
|
259
|
+
if (typeof r === "string") return r;
|
|
260
|
+
return Promise.resolve(r());
|
|
261
|
+
}
|
|
262
|
+
var RAIL_SPEC_DEFAULTS = {
|
|
263
|
+
tempo: {
|
|
264
|
+
network: "tempo-mainnet",
|
|
265
|
+
chainId: 4217,
|
|
266
|
+
token: USDC.tempo.mainnet.address,
|
|
267
|
+
symbol: "USDC.e",
|
|
268
|
+
decimals: 6,
|
|
269
|
+
testnet: false,
|
|
270
|
+
recommend: "both"
|
|
271
|
+
},
|
|
272
|
+
x402Base: {
|
|
273
|
+
network: "eip155:8453",
|
|
274
|
+
chainId: 8453,
|
|
275
|
+
token: USDC.base.mainnet.address,
|
|
276
|
+
symbol: "USDC",
|
|
277
|
+
decimals: 6,
|
|
278
|
+
mode: "exact"
|
|
279
|
+
},
|
|
280
|
+
solanaMpp: {
|
|
281
|
+
network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
|
|
282
|
+
token: USDC.solana.mainnet.mint,
|
|
283
|
+
symbol: "USDC",
|
|
284
|
+
decimals: 6
|
|
285
|
+
},
|
|
286
|
+
stripe: {
|
|
287
|
+
rails: ["card", "link", "shared_payment_token"]
|
|
288
|
+
},
|
|
289
|
+
tempoSession: {
|
|
290
|
+
currency: USDC.tempo.mainnet.address,
|
|
291
|
+
testnet: false
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
|
|
214
295
|
// src/payment/x402.ts
|
|
215
296
|
function registerX402SchemesV1V2(server, network, scheme) {
|
|
216
297
|
server.register(network, scheme);
|
|
@@ -228,7 +309,8 @@ async function createX402Server(opts = {}) {
|
|
|
228
309
|
);
|
|
229
310
|
}
|
|
230
311
|
let facilitator;
|
|
231
|
-
|
|
312
|
+
const facilitatorChoice = opts.facilitator ?? (process.env.CDP_API_KEY_ID && process.env.CDP_API_KEY_SECRET ? "coinbase" : "http");
|
|
313
|
+
if (facilitatorChoice === "coinbase") {
|
|
232
314
|
const cb = await dynamicImport("@coinbase/x402");
|
|
233
315
|
if (!cb?.facilitator) {
|
|
234
316
|
throw new Error(
|
|
@@ -236,10 +318,10 @@ async function createX402Server(opts = {}) {
|
|
|
236
318
|
);
|
|
237
319
|
}
|
|
238
320
|
facilitator = new x402Core.HTTPFacilitatorClient(cb.facilitator);
|
|
239
|
-
} else if (
|
|
321
|
+
} else if (facilitatorChoice === "http") {
|
|
240
322
|
facilitator = new x402Core.HTTPFacilitatorClient();
|
|
241
323
|
} else {
|
|
242
|
-
facilitator =
|
|
324
|
+
facilitator = facilitatorChoice;
|
|
243
325
|
}
|
|
244
326
|
const server = new x402Core.x402ResourceServer(facilitator);
|
|
245
327
|
let evmExactModule = null;
|
|
@@ -349,44 +431,95 @@ function classifyX402SettleResult(result) {
|
|
|
349
431
|
};
|
|
350
432
|
}
|
|
351
433
|
}
|
|
352
|
-
|
|
353
|
-
|
|
434
|
+
function classifyOrchestrationError(err) {
|
|
435
|
+
let msg;
|
|
436
|
+
if (err instanceof Error) {
|
|
437
|
+
msg = err.message;
|
|
438
|
+
} else if (typeof err === "string") {
|
|
439
|
+
msg = err;
|
|
440
|
+
} else {
|
|
441
|
+
return null;
|
|
442
|
+
}
|
|
443
|
+
const msgLower = msg.toLowerCase();
|
|
444
|
+
if (msgLower.includes("x402version") || msgLower.includes("invalid payment") || msgLower.includes("unsupported x402")) {
|
|
445
|
+
return {
|
|
446
|
+
status: 400,
|
|
447
|
+
code: "payment_proof_invalid",
|
|
448
|
+
message: "Payment credential is malformed or uses an unsupported version",
|
|
449
|
+
nextSteps: {
|
|
450
|
+
action: "regenerate_payment_credential",
|
|
451
|
+
user_message: "The payment credential is malformed or uses an unsupported version. Regenerate from a fresh 402 challenge and re-sign."
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
if (msgLower.includes("stripe") || msgLower.includes("facilitator") || msgLower.includes("cdp")) {
|
|
456
|
+
return {
|
|
457
|
+
status: 503,
|
|
458
|
+
code: "payment_provider_unavailable",
|
|
459
|
+
message: "Payment provider returned an error",
|
|
460
|
+
nextSteps: {
|
|
461
|
+
action: "retry_or_swap_method",
|
|
462
|
+
retry_after_seconds: 10,
|
|
463
|
+
user_message: "Transient payment-provider error. Retry in a few seconds, or pick a different rail from the 402 challenge."
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
469
|
+
async function processX402Settle({
|
|
470
|
+
x402Server,
|
|
471
|
+
payload,
|
|
472
|
+
resourceConfig,
|
|
473
|
+
resourceMeta,
|
|
474
|
+
extension,
|
|
475
|
+
transportContext
|
|
476
|
+
}) {
|
|
477
|
+
const server = x402Server;
|
|
354
478
|
let builtRequirements;
|
|
355
479
|
try {
|
|
356
|
-
builtRequirements = await server.buildPaymentRequirements(
|
|
480
|
+
builtRequirements = await server.buildPaymentRequirements(resourceConfig);
|
|
357
481
|
} catch (err) {
|
|
482
|
+
console.warn("[x402_settle] build_requirements failed:", err instanceof Error ? err.message : err);
|
|
358
483
|
return { success: false, phase: "facilitator_error", step: "build_requirements", error: err };
|
|
359
484
|
}
|
|
360
485
|
const matchedRequirement = builtRequirements[0];
|
|
361
486
|
if (!matchedRequirement) {
|
|
362
487
|
return { success: false, phase: "no_requirements", reason: "x402Server.buildPaymentRequirements returned empty" };
|
|
363
488
|
}
|
|
364
|
-
const
|
|
365
|
-
const path = new URL(
|
|
489
|
+
const resolvedTransportContext = transportContext ?? (() => {
|
|
490
|
+
const path = new URL(resourceMeta.url).pathname;
|
|
366
491
|
return { method: "POST", adapter: { getPath: () => path }, routePattern: path };
|
|
367
492
|
})();
|
|
368
493
|
let enrichedExt;
|
|
369
494
|
try {
|
|
370
|
-
enrichedExt =
|
|
495
|
+
enrichedExt = extension !== void 0 ? server.enrichExtensions(extension, resolvedTransportContext) : void 0;
|
|
371
496
|
} catch (err) {
|
|
497
|
+
console.warn("[x402_settle] enrich_extensions failed:", err instanceof Error ? err.message : err);
|
|
372
498
|
return { success: false, phase: "facilitator_error", step: "enrich_extensions", error: err };
|
|
373
499
|
}
|
|
374
500
|
let verifyResult;
|
|
375
501
|
try {
|
|
376
|
-
verifyResult = await server.
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
502
|
+
verifyResult = await server.verifyPayment(
|
|
503
|
+
payload,
|
|
504
|
+
matchedRequirement,
|
|
505
|
+
enrichedExt,
|
|
506
|
+
resolvedTransportContext
|
|
381
507
|
);
|
|
382
508
|
} catch (err) {
|
|
383
|
-
|
|
509
|
+
console.warn("[x402_settle] verify_payment failed:", err instanceof Error ? err.message : err);
|
|
510
|
+
return { success: false, phase: "facilitator_error", step: "verify_payment", error: err };
|
|
384
511
|
}
|
|
385
|
-
|
|
512
|
+
const verifyOk = verifyResult.isValid === true || verifyResult.success === true;
|
|
513
|
+
if (!verifyOk) {
|
|
386
514
|
return { success: false, phase: "verify_failed", verifyResult };
|
|
387
515
|
}
|
|
388
516
|
try {
|
|
389
|
-
const settleResult = await server.settlePayment(
|
|
517
|
+
const settleResult = await server.settlePayment(
|
|
518
|
+
payload,
|
|
519
|
+
matchedRequirement,
|
|
520
|
+
enrichedExt,
|
|
521
|
+
resolvedTransportContext
|
|
522
|
+
);
|
|
390
523
|
const paymentResponseHeader = settleResult ? Buffer.from(JSON.stringify(settleResult)).toString("base64") : void 0;
|
|
391
524
|
return {
|
|
392
525
|
success: true,
|
|
@@ -405,10 +538,10 @@ var X402_SUPPORTED_BASE_NETWORKS = /* @__PURE__ */ new Set([
|
|
|
405
538
|
networks.base.mainnet.caip2,
|
|
406
539
|
networks.base.sepolia.caip2
|
|
407
540
|
]);
|
|
408
|
-
function validateX402NetworkConfig(
|
|
409
|
-
if (!X402_SUPPORTED_BASE_NETWORKS.has(
|
|
541
|
+
function validateX402NetworkConfig({ baseNetwork }) {
|
|
542
|
+
if (!X402_SUPPORTED_BASE_NETWORKS.has(baseNetwork)) {
|
|
410
543
|
throw new Error(
|
|
411
|
-
`X402_BASE_NETWORK=${
|
|
544
|
+
`X402_BASE_NETWORK=${baseNetwork} is not supported. Use one of: ${[...X402_SUPPORTED_BASE_NETWORKS].join(", ")}`
|
|
412
545
|
);
|
|
413
546
|
}
|
|
414
547
|
}
|
|
@@ -424,8 +557,12 @@ function regenerateBody(message, userMessage) {
|
|
|
424
557
|
}
|
|
425
558
|
};
|
|
426
559
|
}
|
|
427
|
-
async function verifyX402Request(
|
|
428
|
-
|
|
560
|
+
async function verifyX402Request({
|
|
561
|
+
request,
|
|
562
|
+
isCachedAddress,
|
|
563
|
+
acceptedNetwork
|
|
564
|
+
}) {
|
|
565
|
+
const headerValue = request.headers.get("payment-signature") ?? request.headers.get("x-payment");
|
|
429
566
|
if (!headerValue) {
|
|
430
567
|
return {
|
|
431
568
|
ok: false,
|
|
@@ -451,13 +588,13 @@ async function verifyX402Request(input) {
|
|
|
451
588
|
}
|
|
452
589
|
const signedNetwork = payload.accepted?.network;
|
|
453
590
|
const signedPayTo = payload.accepted?.payTo;
|
|
454
|
-
if (!signedNetwork || signedNetwork !==
|
|
591
|
+
if (!signedNetwork || signedNetwork !== acceptedNetwork) {
|
|
455
592
|
if (signedNetwork && signedNetwork.toLowerCase().startsWith("solana:")) {
|
|
456
593
|
return {
|
|
457
594
|
ok: false,
|
|
458
595
|
status: 400,
|
|
459
596
|
body: regenerateBody(
|
|
460
|
-
`x402 on ${signedNetwork} is not accepted; Solana payments must use the \`solana/charge\` rail advertised in the 402 challenge. This server accepts x402 on ${
|
|
597
|
+
`x402 on ${signedNetwork} is not accepted; Solana payments must use the \`solana/charge\` rail advertised in the 402 challenge. This server accepts x402 on ${acceptedNetwork} only.`,
|
|
461
598
|
"Solana payments are not accepted over x402 at this merchant. Pick the `solana/charge` rail from the 402 challenge and re-sign."
|
|
462
599
|
)
|
|
463
600
|
};
|
|
@@ -466,7 +603,7 @@ async function verifyX402Request(input) {
|
|
|
466
603
|
ok: false,
|
|
467
604
|
status: 400,
|
|
468
605
|
body: regenerateBody(
|
|
469
|
-
`Unsupported x402 network ${signedNetwork ?? "<missing>"}; this server accepts ${
|
|
606
|
+
`Unsupported x402 network ${signedNetwork ?? "<missing>"}; this server accepts ${acceptedNetwork}.`,
|
|
470
607
|
"The credential signed for an unsupported network. Pick the accepted network from the 402 challenge and re-sign."
|
|
471
608
|
)
|
|
472
609
|
};
|
|
@@ -482,7 +619,7 @@ async function verifyX402Request(input) {
|
|
|
482
619
|
)
|
|
483
620
|
};
|
|
484
621
|
}
|
|
485
|
-
if (!await
|
|
622
|
+
if (!await isCachedAddress(signedPayTo)) {
|
|
486
623
|
return {
|
|
487
624
|
ok: false,
|
|
488
625
|
status: 400,
|
|
@@ -496,7 +633,11 @@ async function verifyX402Request(input) {
|
|
|
496
633
|
}
|
|
497
634
|
|
|
498
635
|
// src/stripe-multichain/mppx_stripe.ts
|
|
499
|
-
async function createMppxStripe(
|
|
636
|
+
async function createMppxStripe({
|
|
637
|
+
profileId,
|
|
638
|
+
secretKey,
|
|
639
|
+
paymentMethodTypes
|
|
640
|
+
}) {
|
|
500
641
|
const moduleName = "mppx/server";
|
|
501
642
|
const mppx = await import(moduleName).catch(() => null);
|
|
502
643
|
if (!mppx?.stripe?.charge) {
|
|
@@ -505,80 +646,130 @@ async function createMppxStripe(input) {
|
|
|
505
646
|
);
|
|
506
647
|
}
|
|
507
648
|
return mppx.stripe.charge({
|
|
508
|
-
networkId:
|
|
509
|
-
paymentMethodTypes:
|
|
510
|
-
secretKey
|
|
649
|
+
networkId: profileId,
|
|
650
|
+
paymentMethodTypes: paymentMethodTypes ?? ["card", "link"],
|
|
651
|
+
secretKey
|
|
511
652
|
});
|
|
512
653
|
}
|
|
513
654
|
|
|
514
655
|
// src/payment/mppx_server.ts
|
|
515
|
-
|
|
656
|
+
function isStripeRailSpec(s) {
|
|
657
|
+
return !("recipient" in s);
|
|
658
|
+
}
|
|
659
|
+
function isTempoSessionRailSpec(s) {
|
|
660
|
+
return "escrowContract" in s && "store" in s;
|
|
661
|
+
}
|
|
662
|
+
function isSolanaMppRailSpec(s) {
|
|
663
|
+
if (!("recipient" in s)) return false;
|
|
664
|
+
if ("escrowContract" in s) return false;
|
|
665
|
+
if ("rpcUrl" in s || "tokenProgram" in s) return true;
|
|
666
|
+
return s.network?.startsWith("solana:") ?? false;
|
|
667
|
+
}
|
|
668
|
+
function solanaNetworkFromCAIP2(caip2) {
|
|
669
|
+
if (caip2 === networks.solana.devnet.caip2) return "devnet";
|
|
670
|
+
return "mainnet-beta";
|
|
671
|
+
}
|
|
672
|
+
function solanaDefaultRpcUrl(network) {
|
|
673
|
+
if (network === "mainnet-beta") return "https://api.mainnet-beta.solana.com";
|
|
674
|
+
if (network === "devnet") return "https://api.devnet.solana.com";
|
|
675
|
+
return "http://localhost:8899";
|
|
676
|
+
}
|
|
677
|
+
async function createMppxServer({
|
|
678
|
+
rails: rails2,
|
|
679
|
+
methods: extraMethods,
|
|
680
|
+
secretKey
|
|
681
|
+
}) {
|
|
516
682
|
const mppx = await dynamicImport2("mppx/server");
|
|
517
683
|
if (!mppx?.Mppx?.create) {
|
|
518
684
|
throw new Error("mppx not installed \u2014 `npm install mppx` to use createMppxServer.");
|
|
519
685
|
}
|
|
520
|
-
const methods = [...
|
|
521
|
-
|
|
522
|
-
if (
|
|
523
|
-
|
|
686
|
+
const methods = [...extraMethods ?? []];
|
|
687
|
+
for (const [name, spec] of Object.entries(rails2 ?? {})) {
|
|
688
|
+
if (isStripeRailSpec(spec)) {
|
|
689
|
+
methods.push(await registerStripe(spec));
|
|
690
|
+
continue;
|
|
524
691
|
}
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
692
|
+
if (isTempoSessionRailSpec(spec)) {
|
|
693
|
+
methods.push(await registerTempoSession(mppx, spec));
|
|
694
|
+
continue;
|
|
695
|
+
}
|
|
696
|
+
if (isSolanaMppRailSpec(spec)) {
|
|
697
|
+
methods.push(await registerSolana(spec));
|
|
698
|
+
continue;
|
|
699
|
+
}
|
|
700
|
+
methods.push(registerTempo(mppx, spec, name));
|
|
701
|
+
}
|
|
702
|
+
return mppx.Mppx.create({ methods, secretKey });
|
|
703
|
+
}
|
|
704
|
+
function registerTempo(mppx, spec, _name) {
|
|
705
|
+
if (!mppx.tempo?.charge) {
|
|
706
|
+
throw new Error("mppx.tempo.charge not available \u2014 check installed mppx version.");
|
|
707
|
+
}
|
|
708
|
+
const defaultCurrency = spec.testnet ? USDC.tempo.testnet.address : USDC.tempo.mainnet.address;
|
|
709
|
+
if (typeof spec.recipient !== "string") {
|
|
710
|
+
throw new TypeError(
|
|
711
|
+
"createMppxServer: TempoRailSpec requires a string recipient (per-order factories not supported here)."
|
|
533
712
|
);
|
|
534
713
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
mppx.tempo.session
|
|
545
|
-
currency: s.currency ?? defaultCurrency,
|
|
546
|
-
recipient: s.recipient,
|
|
547
|
-
escrowContract: s.escrowContract,
|
|
548
|
-
store: s.store,
|
|
549
|
-
testnet: s.testnet ?? false,
|
|
550
|
-
...s.chains ? { chains: s.chains } : {}
|
|
551
|
-
})
|
|
714
|
+
return mppx.tempo.charge({
|
|
715
|
+
currency: spec.token ?? defaultCurrency,
|
|
716
|
+
recipient: spec.recipient,
|
|
717
|
+
testnet: spec.testnet ?? false
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
async function registerTempoSession(mppx, spec) {
|
|
721
|
+
if (!mppx.tempo?.session) {
|
|
722
|
+
throw new Error(
|
|
723
|
+
"mppx.tempo.session not available \u2014 your mppx version may not support sessions yet. Upgrade with `npm install mppx@latest`."
|
|
552
724
|
);
|
|
553
725
|
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
...s.rpcUrl ? { rpcUrl: s.rpcUrl } : {},
|
|
571
|
-
...s.signer ? { signer: s.signer } : {},
|
|
572
|
-
...s.tokenProgram ? { tokenProgram: s.tokenProgram } : {}
|
|
573
|
-
});
|
|
574
|
-
const rpcUrl = s.rpcUrl ?? (network === "mainnet-beta" ? "https://api.mainnet-beta.solana.com" : network === "devnet" ? "https://api.devnet.solana.com" : "http://localhost:8899");
|
|
575
|
-
methods.push(wrapSolanaChargeWithFinalizedBlockhash(baseMethod, rpcUrl));
|
|
726
|
+
const defaultCurrency = spec.testnet ? USDC.tempo.testnet.address : USDC.tempo.mainnet.address;
|
|
727
|
+
return mppx.tempo.session({
|
|
728
|
+
currency: spec.currency ?? defaultCurrency,
|
|
729
|
+
recipient: await resolveRecipient(spec.recipient),
|
|
730
|
+
escrowContract: spec.escrowContract,
|
|
731
|
+
store: spec.store,
|
|
732
|
+
testnet: spec.testnet ?? false,
|
|
733
|
+
...spec.chains ? { chains: spec.chains } : {}
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
async function registerSolana(spec) {
|
|
737
|
+
const solanaMpp = await dynamicImport2("@solana/mpp/server");
|
|
738
|
+
if (!solanaMpp?.charge) {
|
|
739
|
+
throw new Error(
|
|
740
|
+
"@solana/mpp not installed \u2014 `npm install @solana/mpp @solana/kit` to use the solana rail."
|
|
741
|
+
);
|
|
576
742
|
}
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
743
|
+
const network = solanaNetworkFromCAIP2(spec.network);
|
|
744
|
+
const defaultMint = network === "mainnet-beta" ? USDC.solana.mainnet.mint : USDC.solana.devnet.mint;
|
|
745
|
+
const defaultDecimals = network === "mainnet-beta" ? USDC.solana.mainnet.decimals : USDC.solana.devnet.decimals;
|
|
746
|
+
if (typeof spec.recipient !== "string") {
|
|
747
|
+
throw new TypeError(
|
|
748
|
+
"createMppxServer: SolanaMppRailSpec requires a string recipient (per-order factories not supported here)."
|
|
749
|
+
);
|
|
580
750
|
}
|
|
581
|
-
|
|
751
|
+
const baseMethod = solanaMpp.charge({
|
|
752
|
+
recipient: spec.recipient,
|
|
753
|
+
currency: spec.token ?? defaultMint,
|
|
754
|
+
decimals: spec.decimals ?? defaultDecimals,
|
|
755
|
+
network,
|
|
756
|
+
...spec.rpcUrl ? { rpcUrl: spec.rpcUrl } : {},
|
|
757
|
+
...spec.signer ? { signer: spec.signer } : {},
|
|
758
|
+
...spec.tokenProgram ? { tokenProgram: spec.tokenProgram } : {}
|
|
759
|
+
});
|
|
760
|
+
return wrapSolanaChargeWithFinalizedBlockhash(baseMethod, spec.rpcUrl ?? solanaDefaultRpcUrl(network));
|
|
761
|
+
}
|
|
762
|
+
async function registerStripe(spec) {
|
|
763
|
+
if (!spec.profileId || !spec.secretKey) {
|
|
764
|
+
throw new Error(
|
|
765
|
+
"createMppxServer: StripeRailSpec requires both profileId and secretKey."
|
|
766
|
+
);
|
|
767
|
+
}
|
|
768
|
+
return createMppxStripe({
|
|
769
|
+
profileId: spec.profileId,
|
|
770
|
+
secretKey: spec.secretKey,
|
|
771
|
+
paymentMethodTypes: spec.paymentMethodTypes
|
|
772
|
+
});
|
|
582
773
|
}
|
|
583
774
|
async function dynamicImport2(moduleName) {
|
|
584
775
|
try {
|
|
@@ -618,8 +809,46 @@ function wrapSolanaChargeWithFinalizedBlockhash(baseMethod, rpcUrl) {
|
|
|
618
809
|
}
|
|
619
810
|
};
|
|
620
811
|
}
|
|
812
|
+
async function composeMppxRequest(mppx, intents, request) {
|
|
813
|
+
if (!mppx || typeof mppx !== "object" || !("compose" in mppx)) {
|
|
814
|
+
throw new Error("composeMppxRequest: argument is not an mppx server instance");
|
|
815
|
+
}
|
|
816
|
+
const compose = mppx.compose;
|
|
817
|
+
if (typeof compose !== "function") {
|
|
818
|
+
throw new Error("composeMppxRequest: mppx.compose is not a function");
|
|
819
|
+
}
|
|
820
|
+
const typedCompose = compose;
|
|
821
|
+
const handler = typedCompose.apply(mppx, [...intents]);
|
|
822
|
+
return handler(request);
|
|
823
|
+
}
|
|
824
|
+
function mppxChallengeHeaders(result) {
|
|
825
|
+
return Object.fromEntries(result.challenge.headers);
|
|
826
|
+
}
|
|
621
827
|
|
|
622
828
|
// src/payment/dispatch.ts
|
|
829
|
+
function detectRailFromHeaders(headers) {
|
|
830
|
+
const get = (name) => {
|
|
831
|
+
if (headers instanceof Headers) {
|
|
832
|
+
return headers.get(name) ?? "";
|
|
833
|
+
}
|
|
834
|
+
const lower = name.toLowerCase();
|
|
835
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
836
|
+
if (k.toLowerCase() === lower) {
|
|
837
|
+
if (v === void 0 || v === null) return "";
|
|
838
|
+
return Array.isArray(v) ? v[0] ?? "" : v;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
return "";
|
|
842
|
+
};
|
|
843
|
+
const auth = get("authorization");
|
|
844
|
+
if (auth.toLowerCase().startsWith("payment ")) {
|
|
845
|
+
return "mpp";
|
|
846
|
+
}
|
|
847
|
+
if (get("payment-signature") || get("x-payment")) {
|
|
848
|
+
return "x402";
|
|
849
|
+
}
|
|
850
|
+
return null;
|
|
851
|
+
}
|
|
623
852
|
async function dispatchSettlementByNetwork(payload, handlers) {
|
|
624
853
|
const network = payload.accepted.network;
|
|
625
854
|
if (network.startsWith("eip155:")) {
|
|
@@ -652,37 +881,45 @@ function aliasAmountFields(accepts) {
|
|
|
652
881
|
return e;
|
|
653
882
|
});
|
|
654
883
|
}
|
|
655
|
-
function paymentRequiredHeader(
|
|
656
|
-
|
|
884
|
+
function paymentRequiredHeader({
|
|
885
|
+
x402Version,
|
|
886
|
+
accepts,
|
|
887
|
+
resource
|
|
888
|
+
}) {
|
|
889
|
+
return Buffer.from(JSON.stringify({ x402Version, accepts, ...resource ? { resource } : {} })).toString("base64");
|
|
657
890
|
}
|
|
658
891
|
|
|
659
892
|
// src/payment/headers.ts
|
|
660
|
-
function buildPaymentHeaders(
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
893
|
+
function buildPaymentHeaders({
|
|
894
|
+
rails: rails2,
|
|
895
|
+
orderId,
|
|
896
|
+
realm,
|
|
897
|
+
x402
|
|
898
|
+
}) {
|
|
899
|
+
const directives = rails2.map(
|
|
900
|
+
(rail) => buildPaymentDirective({
|
|
901
|
+
id: `${orderId}-${rail.rail}`,
|
|
902
|
+
realm,
|
|
665
903
|
rail: rail.rail,
|
|
666
|
-
amountUsd: rail.amountUsd
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
});
|
|
904
|
+
amountUsd: rail.amountUsd,
|
|
905
|
+
...rail.recipient !== void 0 ? { recipient: rail.recipient } : {},
|
|
906
|
+
...rail.networkId !== void 0 ? { networkId: rail.networkId } : {},
|
|
907
|
+
...rail.chainId !== void 0 ? { chainId: rail.chainId } : {},
|
|
908
|
+
...rail.currency !== void 0 ? { currency: rail.currency } : {},
|
|
909
|
+
...rail.decimals !== void 0 ? { decimals: rail.decimals } : {},
|
|
910
|
+
...rail.method !== void 0 ? { method: rail.method } : {},
|
|
911
|
+
...rail.intent !== void 0 ? { intent: rail.intent } : {},
|
|
912
|
+
...rail.expires !== void 0 ? { expires: rail.expires } : {}
|
|
913
|
+
})
|
|
914
|
+
);
|
|
678
915
|
const result = {
|
|
679
916
|
"www-authenticate": wwwAuthenticateHeader(directives)
|
|
680
917
|
};
|
|
681
|
-
if (
|
|
918
|
+
if (x402) {
|
|
682
919
|
result["PAYMENT-REQUIRED"] = paymentRequiredHeader({
|
|
683
|
-
x402Version:
|
|
684
|
-
accepts:
|
|
685
|
-
...
|
|
920
|
+
x402Version: x402.version ?? 2,
|
|
921
|
+
accepts: x402.accepts,
|
|
922
|
+
...x402.resource ? { resource: x402.resource } : {}
|
|
686
923
|
});
|
|
687
924
|
}
|
|
688
925
|
return result;
|
|
@@ -690,15 +927,20 @@ function buildPaymentHeaders(input) {
|
|
|
690
927
|
|
|
691
928
|
// src/payment/idempotency.ts
|
|
692
929
|
var SERVER_IDEMPOTENCY_KEY_MAX = 200;
|
|
693
|
-
function buildIdempotencyKey(
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
930
|
+
function buildIdempotencyKey({
|
|
931
|
+
paymentIntentId,
|
|
932
|
+
orderId,
|
|
933
|
+
amountCents,
|
|
934
|
+
prefix
|
|
935
|
+
}) {
|
|
936
|
+
const prefixPart = prefix ? `${prefix}-` : "";
|
|
937
|
+
if (paymentIntentId) {
|
|
938
|
+
const key = `${prefixPart}${paymentIntentId}`;
|
|
697
939
|
return clampKey(key);
|
|
698
940
|
}
|
|
699
|
-
if (
|
|
700
|
-
const amountSuffix =
|
|
701
|
-
const key = `${
|
|
941
|
+
if (orderId) {
|
|
942
|
+
const amountSuffix = amountCents !== void 0 ? `-${amountCents}` : "";
|
|
943
|
+
const key = `${prefixPart}pi-${orderId}${amountSuffix}`;
|
|
702
944
|
return clampKey(key);
|
|
703
945
|
}
|
|
704
946
|
return void 0;
|
|
@@ -784,17 +1026,218 @@ async function extractPaymentSigner(request, x402PaymentHeader) {
|
|
|
784
1026
|
}
|
|
785
1027
|
return null;
|
|
786
1028
|
}
|
|
1029
|
+
async function extractPaymentSignerFromAuth(authHeader, x402PaymentHeader) {
|
|
1030
|
+
const request = new Request("http://internal.gate/", {
|
|
1031
|
+
headers: authHeader ? { authorization: authHeader } : {}
|
|
1032
|
+
});
|
|
1033
|
+
return extractPaymentSigner(request, x402PaymentHeader);
|
|
1034
|
+
}
|
|
787
1035
|
function readX402PaymentHeader(request) {
|
|
788
1036
|
return request.headers.get("payment-signature") ?? request.headers.get("x-payment") ?? void 0;
|
|
789
1037
|
}
|
|
1038
|
+
function lowerHeaders(headers) {
|
|
1039
|
+
const out = {};
|
|
1040
|
+
for (const [k, v] of Object.entries(headers)) out[k.toLowerCase()] = v;
|
|
1041
|
+
return out;
|
|
1042
|
+
}
|
|
1043
|
+
async function extractSignerForPrecheck(headers) {
|
|
1044
|
+
const lower = lowerHeaders(headers);
|
|
1045
|
+
const x402 = lower["payment-signature"] ?? lower["x-payment"];
|
|
1046
|
+
if (x402) {
|
|
1047
|
+
const signer = await extractPaymentSignerFromAuth(void 0, x402);
|
|
1048
|
+
if (signer !== null) return signer;
|
|
1049
|
+
}
|
|
1050
|
+
const authorization = lower["authorization"];
|
|
1051
|
+
if (authorization && authorization.toLowerCase().startsWith("payment ")) {
|
|
1052
|
+
return await extractPaymentSignerFromAuth(authorization);
|
|
1053
|
+
}
|
|
1054
|
+
return null;
|
|
1055
|
+
}
|
|
790
1056
|
|
|
791
1057
|
// src/payment/settlement_override.ts
|
|
792
1058
|
var SETTLEMENT_OVERRIDES_HEADER = "Settlement-Overrides";
|
|
793
1059
|
function settlementOverrideHeader(overrides) {
|
|
794
1060
|
return { name: SETTLEMENT_OVERRIDES_HEADER, value: JSON.stringify(overrides) };
|
|
795
1061
|
}
|
|
1062
|
+
|
|
1063
|
+
// src/payment/amounts.ts
|
|
1064
|
+
function usdToAtomic(usd, opts) {
|
|
1065
|
+
const { decimals } = opts;
|
|
1066
|
+
if (!Number.isInteger(decimals) || decimals < 0) {
|
|
1067
|
+
throw new RangeError(`decimals must be a non-negative integer, got ${decimals}`);
|
|
1068
|
+
}
|
|
1069
|
+
if (typeof usd === "number") {
|
|
1070
|
+
if (!Number.isFinite(usd)) {
|
|
1071
|
+
throw new RangeError(`usd must be finite, got ${usd}`);
|
|
1072
|
+
}
|
|
1073
|
+
if (usd < 0) {
|
|
1074
|
+
throw new RangeError(`usd must be non-negative, got ${usd}`);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
const s = (typeof usd === "number" ? usd.toString() : usd).trim();
|
|
1078
|
+
if (s.startsWith("-")) {
|
|
1079
|
+
throw new RangeError(`usd must be non-negative, got ${s}`);
|
|
1080
|
+
}
|
|
1081
|
+
if (s === "NaN" || s === "Infinity") {
|
|
1082
|
+
throw new RangeError(`usd must be finite, got ${s}`);
|
|
1083
|
+
}
|
|
1084
|
+
const match = /^(\d*)(?:\.(\d*))?$/.exec(s);
|
|
1085
|
+
if (!match || match[1] === "" && (match[2] === void 0 || match[2] === "")) {
|
|
1086
|
+
throw new SyntaxError(`invalid usd value: ${JSON.stringify(usd)}`);
|
|
1087
|
+
}
|
|
1088
|
+
const intPart = match[1] || "0";
|
|
1089
|
+
const fracPart = match[2] ?? "";
|
|
1090
|
+
if (fracPart.length <= decimals) {
|
|
1091
|
+
return BigInt(intPart + fracPart.padEnd(decimals, "0"));
|
|
1092
|
+
}
|
|
1093
|
+
const kept = fracPart.slice(0, decimals);
|
|
1094
|
+
const roundDigit = fracPart[decimals];
|
|
1095
|
+
let result = BigInt(intPart + kept);
|
|
1096
|
+
if (roundDigit >= "5") {
|
|
1097
|
+
result += 1n;
|
|
1098
|
+
}
|
|
1099
|
+
return result;
|
|
1100
|
+
}
|
|
1101
|
+
function formatUsdCents(cents) {
|
|
1102
|
+
return (cents / 100).toFixed(2);
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
// src/payment/zero-settle.ts
|
|
1106
|
+
var EVM_RE = /^0x[0-9a-fA-F]{40}$/;
|
|
1107
|
+
var SOLANA_BASE58_RE = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
|
|
1108
|
+
var NULL_RESULT = {
|
|
1109
|
+
signerAddress: null,
|
|
1110
|
+
signerNetwork: null,
|
|
1111
|
+
txHash: null
|
|
1112
|
+
};
|
|
1113
|
+
function zeroAmountCarveOut({
|
|
1114
|
+
rail,
|
|
1115
|
+
payload,
|
|
1116
|
+
authorizationHeader
|
|
1117
|
+
}) {
|
|
1118
|
+
if (rail === "x402-base") {
|
|
1119
|
+
return x402SignerFromPayload(payload);
|
|
1120
|
+
}
|
|
1121
|
+
if (rail === "tempo" || rail === "solana") {
|
|
1122
|
+
return mppSignerFromAuth(authorizationHeader);
|
|
1123
|
+
}
|
|
1124
|
+
return NULL_RESULT;
|
|
1125
|
+
}
|
|
1126
|
+
function x402SignerFromPayload(payload) {
|
|
1127
|
+
if (!payload || typeof payload !== "object") return NULL_RESULT;
|
|
1128
|
+
const inner = payload.payload;
|
|
1129
|
+
if (!inner || typeof inner !== "object") return NULL_RESULT;
|
|
1130
|
+
const authorization = inner.authorization;
|
|
1131
|
+
if (!authorization || typeof authorization !== "object") return NULL_RESULT;
|
|
1132
|
+
const fromAddr = authorization.from;
|
|
1133
|
+
if (typeof fromAddr !== "string" || !EVM_RE.test(fromAddr)) return NULL_RESULT;
|
|
1134
|
+
return {
|
|
1135
|
+
signerAddress: fromAddr.toLowerCase(),
|
|
1136
|
+
signerNetwork: "evm",
|
|
1137
|
+
txHash: null
|
|
1138
|
+
};
|
|
1139
|
+
}
|
|
1140
|
+
function mppSignerFromAuth(authorizationHeader) {
|
|
1141
|
+
if (typeof authorizationHeader !== "string") return NULL_RESULT;
|
|
1142
|
+
if (!authorizationHeader.toLowerCase().startsWith("payment ")) return NULL_RESULT;
|
|
1143
|
+
const token = authorizationHeader.slice("payment ".length).trim();
|
|
1144
|
+
if (!token) return NULL_RESULT;
|
|
1145
|
+
let credential;
|
|
1146
|
+
try {
|
|
1147
|
+
credential = JSON.parse(atob(token));
|
|
1148
|
+
} catch {
|
|
1149
|
+
return NULL_RESULT;
|
|
1150
|
+
}
|
|
1151
|
+
if (!credential || typeof credential !== "object") return NULL_RESULT;
|
|
1152
|
+
let source = credential.source;
|
|
1153
|
+
if (typeof source !== "string") {
|
|
1154
|
+
const challenge = credential.challenge;
|
|
1155
|
+
if (challenge && typeof challenge === "object") {
|
|
1156
|
+
source = challenge.source;
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
if (typeof source !== "string") return NULL_RESULT;
|
|
1160
|
+
const parts = source.split(":");
|
|
1161
|
+
if (parts.length < 4 || parts[0] !== "did" || parts[1] !== "pkh") return NULL_RESULT;
|
|
1162
|
+
const family = parts[2];
|
|
1163
|
+
const addr = parts[parts.length - 1] ?? "";
|
|
1164
|
+
if (family === "eip155" && EVM_RE.test(addr)) {
|
|
1165
|
+
return { signerAddress: addr.toLowerCase(), signerNetwork: "evm", txHash: null };
|
|
1166
|
+
}
|
|
1167
|
+
if (family === "solana" && SOLANA_BASE58_RE.test(addr)) {
|
|
1168
|
+
return { signerAddress: addr, signerNetwork: "solana", txHash: null };
|
|
1169
|
+
}
|
|
1170
|
+
return NULL_RESULT;
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
// src/payment/lazy.ts
|
|
1174
|
+
function x402RailName(spec) {
|
|
1175
|
+
const network = spec.network ?? "eip155:8453";
|
|
1176
|
+
if (network === "eip155:8453") return "x402-base-mainnet";
|
|
1177
|
+
if (network === "eip155:84532") return "x402-base-sepolia";
|
|
1178
|
+
throw new Error(
|
|
1179
|
+
`lazyX402Server: unsupported X402BaseRailSpec.network=${JSON.stringify(network)}`
|
|
1180
|
+
);
|
|
1181
|
+
}
|
|
1182
|
+
function lazyX402Server(opts) {
|
|
1183
|
+
const { spec, cdpApiKeyId, cdpApiKeySecret } = opts;
|
|
1184
|
+
const railName = x402RailName(spec);
|
|
1185
|
+
const useCdp = Boolean(cdpApiKeyId && cdpApiKeySecret);
|
|
1186
|
+
const facilitator = useCdp ? "coinbase" : "http";
|
|
1187
|
+
let cached;
|
|
1188
|
+
let pending;
|
|
1189
|
+
return async () => {
|
|
1190
|
+
if (cached !== void 0) return cached;
|
|
1191
|
+
if (pending !== void 0) return pending;
|
|
1192
|
+
pending = (async () => {
|
|
1193
|
+
const server = await createX402Server({ facilitator, rails: [railName] });
|
|
1194
|
+
cached = server;
|
|
1195
|
+
pending = void 0;
|
|
1196
|
+
return server;
|
|
1197
|
+
})();
|
|
1198
|
+
return pending;
|
|
1199
|
+
};
|
|
1200
|
+
}
|
|
1201
|
+
function lazyMppxServer(opts) {
|
|
1202
|
+
const { rails: rails2, secretKey } = opts;
|
|
1203
|
+
let cached;
|
|
1204
|
+
let pending;
|
|
1205
|
+
return async () => {
|
|
1206
|
+
if (cached !== void 0) return cached;
|
|
1207
|
+
if (pending !== void 0) return pending;
|
|
1208
|
+
pending = (async () => {
|
|
1209
|
+
const server = await createMppxServer({ secretKey, rails: rails2 });
|
|
1210
|
+
cached = server;
|
|
1211
|
+
pending = void 0;
|
|
1212
|
+
return server;
|
|
1213
|
+
})();
|
|
1214
|
+
return pending;
|
|
1215
|
+
};
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
// src/payment/solana.ts
|
|
1219
|
+
async function loadSolanaFeePayer(opts) {
|
|
1220
|
+
const raw = opts.privateKey;
|
|
1221
|
+
if (!raw) return void 0;
|
|
1222
|
+
const moduleName = "@solana/kit";
|
|
1223
|
+
const kit = await import(moduleName).catch(() => null);
|
|
1224
|
+
if (!kit?.createKeyPairSignerFromPrivateKeyBytes || !kit.getBase58Codec) {
|
|
1225
|
+
throw new Error(
|
|
1226
|
+
"@solana/kit not installed \u2014 `npm install @solana/kit` for loadSolanaFeePayer."
|
|
1227
|
+
);
|
|
1228
|
+
}
|
|
1229
|
+
let bytes;
|
|
1230
|
+
if (/^[0-9a-fA-F]{128}$/.test(raw)) {
|
|
1231
|
+
bytes = new Uint8Array(raw.match(/.{2}/g).map((h) => parseInt(h, 16))).slice(0, 32);
|
|
1232
|
+
} else {
|
|
1233
|
+
const decoded = new Uint8Array(kit.getBase58Codec().encode(raw));
|
|
1234
|
+
bytes = decoded.length === 64 ? decoded.slice(0, 32) : decoded;
|
|
1235
|
+
}
|
|
1236
|
+
return kit.createKeyPairSignerFromPrivateKeyBytes(bytes);
|
|
1237
|
+
}
|
|
796
1238
|
// Annotate the CommonJS export names for ESM import in node:
|
|
797
1239
|
0 && (module.exports = {
|
|
1240
|
+
RAIL_SPEC_DEFAULTS,
|
|
798
1241
|
SETTLEMENT_OVERRIDES_HEADER,
|
|
799
1242
|
USDC,
|
|
800
1243
|
X402_SUPPORTED_BASE_NETWORKS,
|
|
@@ -804,12 +1247,22 @@ function settlementOverrideHeader(overrides) {
|
|
|
804
1247
|
buildPaymentHeaders,
|
|
805
1248
|
buildPaymentRequestBlob,
|
|
806
1249
|
buildX402AcceptsFor402,
|
|
1250
|
+
classifyOrchestrationError,
|
|
807
1251
|
classifyX402SettleResult,
|
|
1252
|
+
composeMppxRequest,
|
|
808
1253
|
createMppxServer,
|
|
809
1254
|
createX402Server,
|
|
1255
|
+
detectRailFromHeaders,
|
|
810
1256
|
dispatchSettlementByNetwork,
|
|
811
1257
|
extractPaymentSigner,
|
|
1258
|
+
extractPaymentSignerFromAuth,
|
|
1259
|
+
extractSignerForPrecheck,
|
|
1260
|
+
formatUsdCents,
|
|
1261
|
+
lazyMppxServer,
|
|
1262
|
+
lazyX402Server,
|
|
1263
|
+
loadSolanaFeePayer,
|
|
812
1264
|
lookupRail,
|
|
1265
|
+
mppxChallengeHeaders,
|
|
813
1266
|
networkFamily,
|
|
814
1267
|
networks,
|
|
815
1268
|
paymentDirective,
|
|
@@ -818,10 +1271,13 @@ function settlementOverrideHeader(overrides) {
|
|
|
818
1271
|
rails,
|
|
819
1272
|
readX402PaymentHeader,
|
|
820
1273
|
registerX402SchemesV1V2,
|
|
1274
|
+
resolveRecipient,
|
|
821
1275
|
settlementOverrideHeader,
|
|
1276
|
+
usdToAtomic,
|
|
822
1277
|
validateX402NetworkConfig,
|
|
823
1278
|
verifyX402Request,
|
|
824
1279
|
wrapSolanaChargeWithFinalizedBlockhash,
|
|
825
|
-
wwwAuthenticateHeader
|
|
1280
|
+
wwwAuthenticateHeader,
|
|
1281
|
+
zeroAmountCarveOut
|
|
826
1282
|
});
|
|
827
1283
|
//# sourceMappingURL=index.js.map
|