@parallel-protocol/x402 0.9.0 → 0.10.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 +76 -19
- package/dist/{chunk-KZZY5LS6.cjs → chunk-4CEMNRCZ.cjs} +2 -0
- package/dist/{chunk-TH77IB3T.cjs → chunk-AYMDIX7A.cjs} +416 -71
- package/dist/{chunk-G7HSURPM.js → chunk-CNASNROQ.js} +377 -37
- package/dist/{chunk-QAECRSWF.js → chunk-MZCHBBUN.js} +2 -0
- package/dist/express.cjs +34 -9
- package/dist/express.d.cts +2 -1
- package/dist/express.d.ts +2 -1
- package/dist/express.js +30 -5
- package/dist/fastify.cjs +78 -22
- package/dist/fastify.d.cts +1 -1
- package/dist/fastify.d.ts +1 -1
- package/dist/fastify.js +71 -15
- package/dist/hono.cjs +22 -14
- package/dist/hono.d.cts +1 -1
- package/dist/hono.d.ts +1 -1
- package/dist/hono.js +17 -9
- package/dist/index.cjs +25 -21
- package/dist/index.d.cts +8 -4
- package/dist/index.d.ts +8 -4
- package/dist/index.js +2 -2
- package/dist/llm.cjs +13 -13
- package/dist/llm.d.cts +1 -1
- package/dist/llm.d.ts +1 -1
- package/dist/llm.js +1 -1
- package/dist/next.cjs +16 -15
- package/dist/next.d.cts +1 -1
- package/dist/next.d.ts +1 -1
- package/dist/next.js +4 -3
- package/dist/{types-BkGQ2lPA.d.cts → types-CRBMTQaq.d.cts} +23 -0
- package/dist/{types-BkGQ2lPA.d.ts → types-CRBMTQaq.d.ts} +23 -0
- package/package.json +4 -2
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunk4CEMNRCZ_cjs = require('./chunk-4CEMNRCZ.cjs');
|
|
4
4
|
var chains = require('@parallel-protocol/chains');
|
|
5
|
+
var paymentCore = require('@parallel-protocol/payment-core');
|
|
5
6
|
var zod = require('zod');
|
|
6
7
|
|
|
7
8
|
var PARALLEL_TOKENS = {
|
|
@@ -35,6 +36,9 @@ var PARALLEL_TOKENS = {
|
|
|
35
36
|
sUSDe: "0x211Cc4DD073734dA055fbF44a2b4667d5E5fE5d2"
|
|
36
37
|
}
|
|
37
38
|
};
|
|
39
|
+
var USDC_EIP712_DOMAIN = {
|
|
40
|
+
base: { name: "USD Coin", version: "2" }
|
|
41
|
+
};
|
|
38
42
|
function getDefaultAcceptedTokens(network) {
|
|
39
43
|
const entry = PARALLEL_TOKENS[network];
|
|
40
44
|
if (!entry) return void 0;
|
|
@@ -48,6 +52,12 @@ function getMeteredAcceptedTokens(network) {
|
|
|
48
52
|
function getTokenDecimals(network, address) {
|
|
49
53
|
return chains.getTokenDecimals(network, address);
|
|
50
54
|
}
|
|
55
|
+
function hasMixedDecimals(network, tokens) {
|
|
56
|
+
const decimals = new Set(
|
|
57
|
+
tokens?.map((token) => chains.getTokenDecimals(network, token))
|
|
58
|
+
);
|
|
59
|
+
return decimals.size > 1;
|
|
60
|
+
}
|
|
51
61
|
|
|
52
62
|
// src/utils.ts
|
|
53
63
|
var EIP155_NETWORKS = {
|
|
@@ -106,18 +116,252 @@ function encodeBase64(obj) {
|
|
|
106
116
|
function decodeBase64(str) {
|
|
107
117
|
return JSON.parse(Buffer.from(str, "base64").toString("utf8"));
|
|
108
118
|
}
|
|
109
|
-
|
|
110
|
-
if
|
|
119
|
+
var CONDITIONAL_HEADERS = [
|
|
120
|
+
"if-match",
|
|
121
|
+
"if-none-match",
|
|
122
|
+
"if-modified-since",
|
|
123
|
+
"if-unmodified-since"
|
|
124
|
+
];
|
|
125
|
+
function dropConditionalHeaders(headers) {
|
|
126
|
+
for (const name of CONDITIONAL_HEADERS) delete headers[name];
|
|
127
|
+
}
|
|
128
|
+
var UTF8 = new TextDecoder();
|
|
129
|
+
var DECODE_ROUNDS = 8;
|
|
130
|
+
function decodePercent(path) {
|
|
131
|
+
try {
|
|
132
|
+
return decodeURIComponent(path);
|
|
133
|
+
} catch {
|
|
134
|
+
return path.replace(
|
|
135
|
+
/(?:%[\da-f]{2})+/gi,
|
|
136
|
+
(run) => UTF8.decode(
|
|
137
|
+
Uint8Array.from(
|
|
138
|
+
run.slice(1).split("%"),
|
|
139
|
+
(hex) => Number.parseInt(hex, 16)
|
|
140
|
+
)
|
|
141
|
+
)
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function hasLongMarkRun(segment) {
|
|
146
|
+
for (const [run] of segment.matchAll(/\p{M}+/gu))
|
|
147
|
+
if (run.length > 8) return true;
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
function foldCase(segment) {
|
|
151
|
+
const composed = hasLongMarkRun(segment) ? segment : segment.normalize("NFC");
|
|
152
|
+
return composed.toLowerCase().toUpperCase().toLowerCase();
|
|
153
|
+
}
|
|
154
|
+
function pathSegments(path) {
|
|
155
|
+
let decoded = path;
|
|
156
|
+
for (let round = 0; round < DECODE_ROUNDS && decoded.includes("%"); round++) {
|
|
157
|
+
const next = decodePercent(decoded);
|
|
158
|
+
if (next === decoded) break;
|
|
159
|
+
decoded = next;
|
|
160
|
+
}
|
|
161
|
+
const target = decoded.replaceAll("\\", "/").replace(/^[a-z][\d+.a-z-]*:\/\/[^/]*/i, "").split(/[?#]/, 1)[0] ?? "";
|
|
162
|
+
return target.split("/").map((segment) => foldCase(segment).split(";", 1)[0] ?? "").filter((segment) => segment !== "");
|
|
163
|
+
}
|
|
164
|
+
function resolveDots(segments) {
|
|
165
|
+
const resolved = [];
|
|
166
|
+
for (const segment of segments) {
|
|
167
|
+
if (segment === "..") resolved.pop();
|
|
168
|
+
else if (segment !== ".") resolved.push(segment);
|
|
169
|
+
}
|
|
170
|
+
return resolved;
|
|
171
|
+
}
|
|
172
|
+
function normalizeRoutePath(path) {
|
|
173
|
+
return `/${resolveDots(pathSegments(path)).join("/")}`;
|
|
174
|
+
}
|
|
175
|
+
function routeTable(routes) {
|
|
176
|
+
return Object.entries(routes).map(([key, route]) => [
|
|
177
|
+
normalizeRoutePath(key),
|
|
178
|
+
route
|
|
179
|
+
]);
|
|
180
|
+
}
|
|
181
|
+
function longestMatch(target, table) {
|
|
111
182
|
let bestMatch;
|
|
112
183
|
let bestLength = 0;
|
|
113
|
-
for (const [
|
|
114
|
-
if (
|
|
115
|
-
|
|
116
|
-
|
|
184
|
+
for (const [key, route] of table) {
|
|
185
|
+
if (key === target) return route;
|
|
186
|
+
if (target.startsWith(`${key}/`) && key.length > bestLength) {
|
|
187
|
+
bestMatch = route;
|
|
188
|
+
bestLength = key.length;
|
|
117
189
|
}
|
|
118
190
|
}
|
|
119
191
|
return bestMatch;
|
|
120
192
|
}
|
|
193
|
+
function findRoute(path, table) {
|
|
194
|
+
const segments = pathSegments(path);
|
|
195
|
+
const dotSegments = segments.some(
|
|
196
|
+
(segment) => segment === "." || segment === ".."
|
|
197
|
+
);
|
|
198
|
+
const routePath = `/${resolveDots(segments).join("/")}`;
|
|
199
|
+
const route = longestMatch(routePath, table) ?? (dotSegments ? longestMatch(`/${segments.join("/")}`, table) : void 0);
|
|
200
|
+
return { route, dotSegments, routePath };
|
|
201
|
+
}
|
|
202
|
+
function isPreflightHeader(name) {
|
|
203
|
+
return /^(?:access-control-|vary$|allow$)/i.test(String(name));
|
|
204
|
+
}
|
|
205
|
+
function preflightHeaders(headers) {
|
|
206
|
+
if (Array.isArray(headers)) {
|
|
207
|
+
if (Array.isArray(headers[0]))
|
|
208
|
+
return headers.filter((pair) => isPreflightHeader(pair[0]));
|
|
209
|
+
return headers.flatMap(
|
|
210
|
+
(item, i) => i % 2 === 0 && isPreflightHeader(item) ? [item, headers[i + 1]] : []
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
if (headers !== null && typeof headers === "object")
|
|
214
|
+
return Object.fromEntries(
|
|
215
|
+
Object.entries(headers).filter(([name]) => isPreflightHeader(name))
|
|
216
|
+
);
|
|
217
|
+
return headers;
|
|
218
|
+
}
|
|
219
|
+
function answerAsPreflight(res) {
|
|
220
|
+
const writeHead = res.writeHead.bind(res);
|
|
221
|
+
const end = res.end.bind(res);
|
|
222
|
+
const callbackOf = (args) => args.find((arg) => typeof arg === "function");
|
|
223
|
+
const dropOtherHeaders = () => {
|
|
224
|
+
for (const name of res.getHeaderNames())
|
|
225
|
+
if (!isPreflightHeader(name)) res.removeHeader(name);
|
|
226
|
+
};
|
|
227
|
+
res.writeHead = ((statusCode, ...rest) => {
|
|
228
|
+
dropOtherHeaders();
|
|
229
|
+
res.statusMessage = "";
|
|
230
|
+
const headers = rest.find((arg) => typeof arg !== "string");
|
|
231
|
+
return headers === void 0 ? writeHead(statusCode) : writeHead(statusCode, preflightHeaders(headers));
|
|
232
|
+
});
|
|
233
|
+
res.write = ((...args) => {
|
|
234
|
+
const done = callbackOf(args);
|
|
235
|
+
if (done) queueMicrotask(done);
|
|
236
|
+
return true;
|
|
237
|
+
});
|
|
238
|
+
res.end = ((...args) => {
|
|
239
|
+
if (!res.headersSent) dropOtherHeaders();
|
|
240
|
+
const done = callbackOf(args);
|
|
241
|
+
return done ? end(done) : end();
|
|
242
|
+
});
|
|
243
|
+
res.addTrailers = () => {
|
|
244
|
+
};
|
|
245
|
+
res.writeEarlyHints = ((_hints, done) => {
|
|
246
|
+
if (done) queueMicrotask(done);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
function preflightInit(res) {
|
|
250
|
+
res.body?.cancel().catch(() => {
|
|
251
|
+
});
|
|
252
|
+
const headers = new Headers();
|
|
253
|
+
for (const [name, value] of res.headers)
|
|
254
|
+
if (isPreflightHeader(name)) headers.append(name, value);
|
|
255
|
+
return { status: res.status, headers };
|
|
256
|
+
}
|
|
257
|
+
function permit2Extra(network, asset) {
|
|
258
|
+
const domain = USDC_EIP712_DOMAIN[network];
|
|
259
|
+
const escrow = chains.getUptoEscrowAddress(network);
|
|
260
|
+
if (!domain || !escrow) return void 0;
|
|
261
|
+
const usdc = PARALLEL_TOKENS[network].usdc;
|
|
262
|
+
if (usdc.toLowerCase() !== asset.toLowerCase()) return void 0;
|
|
263
|
+
return { ...domain, facilitatorAddress: escrow };
|
|
264
|
+
}
|
|
265
|
+
var EIP2612_GAS_SPONSORING_EXTENSION = {
|
|
266
|
+
eip2612GasSponsoring: {
|
|
267
|
+
info: {
|
|
268
|
+
description: "The facilitator accepts EIP-2612 gasless Permit to `Permit2` canonical contract.",
|
|
269
|
+
version: "1"
|
|
270
|
+
},
|
|
271
|
+
schema: {
|
|
272
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
273
|
+
type: "object",
|
|
274
|
+
properties: {
|
|
275
|
+
from: {
|
|
276
|
+
type: "string",
|
|
277
|
+
pattern: "^0x[a-fA-F0-9]{40}$",
|
|
278
|
+
description: "The address of the sender."
|
|
279
|
+
},
|
|
280
|
+
asset: {
|
|
281
|
+
type: "string",
|
|
282
|
+
pattern: "^0x[a-fA-F0-9]{40}$",
|
|
283
|
+
description: "The address of the ERC-20 token contract."
|
|
284
|
+
},
|
|
285
|
+
spender: {
|
|
286
|
+
type: "string",
|
|
287
|
+
pattern: "^0x[a-fA-F0-9]{40}$",
|
|
288
|
+
description: "The address of the spender (Canonical Permit2)."
|
|
289
|
+
},
|
|
290
|
+
amount: {
|
|
291
|
+
type: "string",
|
|
292
|
+
pattern: "^[0-9]+$",
|
|
293
|
+
description: "The amount to approve (uint256). Typically MaxUint."
|
|
294
|
+
},
|
|
295
|
+
nonce: {
|
|
296
|
+
type: "string",
|
|
297
|
+
pattern: "^[0-9]+$",
|
|
298
|
+
description: "The current nonce of the sender."
|
|
299
|
+
},
|
|
300
|
+
deadline: {
|
|
301
|
+
type: "string",
|
|
302
|
+
pattern: "^[0-9]+$",
|
|
303
|
+
description: "The timestamp at which the signature expires."
|
|
304
|
+
},
|
|
305
|
+
signature: {
|
|
306
|
+
type: "string",
|
|
307
|
+
pattern: "^0x[a-fA-F0-9]+$",
|
|
308
|
+
description: "The 65-byte concatenated signature (r, s, v) as a hex string."
|
|
309
|
+
},
|
|
310
|
+
version: {
|
|
311
|
+
type: "string",
|
|
312
|
+
pattern: "^[0-9]+(\\.[0-9]+)*$",
|
|
313
|
+
description: "Schema version identifier."
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
required: [
|
|
317
|
+
"from",
|
|
318
|
+
"asset",
|
|
319
|
+
"spender",
|
|
320
|
+
"amount",
|
|
321
|
+
"nonce",
|
|
322
|
+
"deadline",
|
|
323
|
+
"signature",
|
|
324
|
+
"version"
|
|
325
|
+
]
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
function signedPermit(info = {}) {
|
|
330
|
+
const { amount, deadline, signature } = info;
|
|
331
|
+
return typeof amount === "string" && typeof deadline === "string" && typeof signature === "string" ? { value: amount, deadline, signature } : void 0;
|
|
332
|
+
}
|
|
333
|
+
function isStandardPermit2Payment(decoded) {
|
|
334
|
+
const payment = decoded;
|
|
335
|
+
return typeof payment?.payload?.permit2Authorization === "object" && payment.payload.permit2Authorization !== null && payment.accepted?.scheme === "upto";
|
|
336
|
+
}
|
|
337
|
+
function toFacilitatorPayload(decoded, network) {
|
|
338
|
+
if (!isStandardPermit2Payment(decoded)) return decoded;
|
|
339
|
+
const { signature, permit2Authorization: auth } = decoded.payload;
|
|
340
|
+
const permit = signedPermit(decoded.extensions?.eip2612GasSponsoring?.info);
|
|
341
|
+
return {
|
|
342
|
+
scheme: "upto",
|
|
343
|
+
network,
|
|
344
|
+
method: "uptoPermit2",
|
|
345
|
+
tokenIn: auth.permitted.token,
|
|
346
|
+
payload: {
|
|
347
|
+
signature,
|
|
348
|
+
authorization: {
|
|
349
|
+
from: auth.from,
|
|
350
|
+
to: auth.witness.to,
|
|
351
|
+
value: auth.permitted.amount,
|
|
352
|
+
validAfter: auth.witness.validAfter,
|
|
353
|
+
validBefore: auth.deadline,
|
|
354
|
+
nonce: paymentCore.permit2NonceToBytes32(auth.nonce)
|
|
355
|
+
},
|
|
356
|
+
...permit && { permit2612: permit }
|
|
357
|
+
},
|
|
358
|
+
uptoParams: { payTo: auth.witness.to },
|
|
359
|
+
permit2Params: {
|
|
360
|
+
spender: auth.spender,
|
|
361
|
+
facilitator: auth.witness.facilitator
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
}
|
|
121
365
|
var ethereumAddressSchema = zod.z.string().regex(/^0x[0-9a-fA-F]{40}$/, "Invalid Ethereum address");
|
|
122
366
|
var txHashSchema = zod.z.string().regex(/^0x[0-9a-fA-F]{64}$/);
|
|
123
367
|
var priceSchema = zod.z.union([
|
|
@@ -152,6 +396,7 @@ var routeConfigSchema = zod.z.object({
|
|
|
152
396
|
description: zod.z.string().optional(),
|
|
153
397
|
scheme: zod.z.enum(["exact", "upto"]).optional(),
|
|
154
398
|
maxTimeoutSeconds: zod.z.number().int().positive().optional(),
|
|
399
|
+
decimals: zod.z.number().int().nonnegative().optional(),
|
|
155
400
|
meter: zod.z.custom(
|
|
156
401
|
(value) => typeof value === "function",
|
|
157
402
|
"meter must be a function of the response"
|
|
@@ -173,12 +418,37 @@ var routeConfigSchema = zod.z.object({
|
|
|
173
418
|
const usdp = PARALLEL_TOKENS[route.network]?.usdp;
|
|
174
419
|
if (!usdp) return true;
|
|
175
420
|
return route.acceptedTokens.every(
|
|
176
|
-
(token) => token.toLowerCase() === usdp.toLowerCase()
|
|
421
|
+
(token) => token.toLowerCase() === usdp.toLowerCase() || permit2Extra(route.network, token) !== void 0
|
|
177
422
|
);
|
|
178
|
-
}, "acceptedTokens on an upto route may only list the network's USDp")
|
|
423
|
+
}, "acceptedTokens on an upto route may only list the network's USDp, and its USDC where the escrow takes Permit2 payments").refine(
|
|
424
|
+
(route) => route.scheme !== "upto" || !hasMixedDecimals(route.network, route.acceptedTokens) || typeof route.price !== "bigint" && route.decimals === void 0,
|
|
425
|
+
'An upto route that accepts tokens with different decimals needs a price like "0.01", not a bigint or an explicit decimals'
|
|
426
|
+
);
|
|
427
|
+
function sameValue(a, b) {
|
|
428
|
+
if (Object.is(a, b)) return true;
|
|
429
|
+
if (typeof a !== "object" || typeof b !== "object" || !a || !b) return false;
|
|
430
|
+
const entries = Object.entries(a);
|
|
431
|
+
return Array.isArray(a) === Array.isArray(b) && entries.length === Object.keys(b).length && entries.every(
|
|
432
|
+
([key, value]) => sameValue(value, b[key])
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
function consistentRoutePaths(routes, ctx) {
|
|
436
|
+
const keyByPath = /* @__PURE__ */ new Map();
|
|
437
|
+
for (const [key, route] of Object.entries(routes)) {
|
|
438
|
+
const path = normalizeRoutePath(key);
|
|
439
|
+
const other = keyByPath.get(path);
|
|
440
|
+
if (other === void 0) keyByPath.set(path, key);
|
|
441
|
+
else if (!sameValue(routes[other], route))
|
|
442
|
+
ctx.addIssue({
|
|
443
|
+
code: "custom",
|
|
444
|
+
path: [key],
|
|
445
|
+
message: `Same path as "${other}" once normalized, with another config: keep one of the two routes`
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
}
|
|
179
449
|
var paymentMiddlewareConfigSchema = zod.z.object({
|
|
180
450
|
facilitator: facilitatorConfigSchema,
|
|
181
|
-
routes: zod.z.record(zod.z.string(), routeConfigSchema).refine((r) => Object.keys(r).length > 0, "At least one route is required")
|
|
451
|
+
routes: zod.z.record(zod.z.string(), routeConfigSchema).refine((r) => Object.keys(r).length > 0, "At least one route is required").superRefine(consistentRoutePaths)
|
|
182
452
|
});
|
|
183
453
|
var facilitatorResponseSchema = zod.z.discriminatedUnion("success", [
|
|
184
454
|
zod.z.object({
|
|
@@ -212,6 +482,9 @@ var settleSuccessSchema = zod.z.object({
|
|
|
212
482
|
gasSponsored: zod.z.boolean(),
|
|
213
483
|
// Metered routes: the amount actually charged (smallest unit).
|
|
214
484
|
amountSettled: zod.z.string().optional(),
|
|
485
|
+
// A standard x402 Permit2 payment: the USDp the merchant received for
|
|
486
|
+
// amountSettled (smallest unit), when the facilitator read it.
|
|
487
|
+
amountDelivered: zod.z.string().optional(),
|
|
215
488
|
// The facilitator answered from a recorded outcome, nothing was broadcast.
|
|
216
489
|
alreadySettled: zod.z.boolean().optional()
|
|
217
490
|
});
|
|
@@ -246,17 +519,21 @@ function throwIfRedirect(response) {
|
|
|
246
519
|
if (!redirected) return;
|
|
247
520
|
response.body?.cancel().catch(() => {
|
|
248
521
|
});
|
|
249
|
-
throw new
|
|
522
|
+
throw new chunk4CEMNRCZ_cjs.X402RuntimeError(chunk4CEMNRCZ_cjs.X402_ERROR_CODES.FACILITATOR_UNAVAILABLE, {
|
|
250
523
|
status: response.status
|
|
251
524
|
});
|
|
252
525
|
}
|
|
253
|
-
function decodePaymentHeader(paymentHeader) {
|
|
526
|
+
function decodePaymentHeader(paymentHeader, network) {
|
|
254
527
|
try {
|
|
255
|
-
return decodeBase64(paymentHeader);
|
|
528
|
+
return toFacilitatorPayload(decodeBase64(paymentHeader), network);
|
|
256
529
|
} catch {
|
|
257
|
-
throw new
|
|
530
|
+
throw new chunk4CEMNRCZ_cjs.X402RuntimeError(chunk4CEMNRCZ_cjs.X402_ERROR_CODES.INVALID_PAYMENT);
|
|
258
531
|
}
|
|
259
532
|
}
|
|
533
|
+
function payerOf(paymentPayload) {
|
|
534
|
+
const from = paymentPayload?.payload?.authorization?.from;
|
|
535
|
+
return typeof from === "string" ? from : void 0;
|
|
536
|
+
}
|
|
260
537
|
var FacilitatorClient = class {
|
|
261
538
|
// Checked and kept when the client is built: a config changed afterwards
|
|
262
539
|
// does not move the calls elsewhere.
|
|
@@ -265,7 +542,7 @@ var FacilitatorClient = class {
|
|
|
265
542
|
constructor(config) {
|
|
266
543
|
const url = facilitatorUrlSchema.safeParse(config.url);
|
|
267
544
|
if (!url.success) {
|
|
268
|
-
throw new
|
|
545
|
+
throw new chunk4CEMNRCZ_cjs.X402ConfigError(
|
|
269
546
|
url.error.issues[0]?.message ?? "Invalid facilitator URL",
|
|
270
547
|
url.error
|
|
271
548
|
);
|
|
@@ -274,7 +551,10 @@ var FacilitatorClient = class {
|
|
|
274
551
|
this.apiKey = config.apiKey;
|
|
275
552
|
}
|
|
276
553
|
async verify(paymentHeader, paymentRequirements) {
|
|
277
|
-
const paymentPayload = decodePaymentHeader(
|
|
554
|
+
const paymentPayload = decodePaymentHeader(
|
|
555
|
+
paymentHeader,
|
|
556
|
+
paymentRequirements.network
|
|
557
|
+
);
|
|
278
558
|
let json;
|
|
279
559
|
try {
|
|
280
560
|
const response = await fetch(`${this.url}/x402/verify`, {
|
|
@@ -287,8 +567,8 @@ var FacilitatorClient = class {
|
|
|
287
567
|
throwIfRedirect(response);
|
|
288
568
|
if (!response.ok) {
|
|
289
569
|
const body = await readErrorBody(response);
|
|
290
|
-
throw new
|
|
291
|
-
body.error ??
|
|
570
|
+
throw new chunk4CEMNRCZ_cjs.X402RuntimeError(
|
|
571
|
+
body.error ?? chunk4CEMNRCZ_cjs.X402_ERROR_CODES.FACILITATOR_UNAVAILABLE,
|
|
292
572
|
{
|
|
293
573
|
detail: body.message,
|
|
294
574
|
status: response.status,
|
|
@@ -298,18 +578,21 @@ var FacilitatorClient = class {
|
|
|
298
578
|
}
|
|
299
579
|
json = await response.json();
|
|
300
580
|
} catch (e) {
|
|
301
|
-
if (e instanceof
|
|
302
|
-
throw new
|
|
581
|
+
if (e instanceof chunk4CEMNRCZ_cjs.X402RuntimeError) throw e;
|
|
582
|
+
throw new chunk4CEMNRCZ_cjs.X402RuntimeError(chunk4CEMNRCZ_cjs.X402_ERROR_CODES.FACILITATOR_UNAVAILABLE);
|
|
303
583
|
}
|
|
304
584
|
try {
|
|
305
585
|
const { settleToken } = verifyResponseSchema.parse(json);
|
|
306
586
|
return { settleToken };
|
|
307
587
|
} catch {
|
|
308
|
-
throw new
|
|
588
|
+
throw new chunk4CEMNRCZ_cjs.X402RuntimeError(chunk4CEMNRCZ_cjs.X402_ERROR_CODES.FACILITATOR_INVALID_RESPONSE);
|
|
309
589
|
}
|
|
310
590
|
}
|
|
311
591
|
async settle(paymentHeader, paymentRequirements, options) {
|
|
312
|
-
const paymentPayload = decodePaymentHeader(
|
|
592
|
+
const paymentPayload = decodePaymentHeader(
|
|
593
|
+
paymentHeader,
|
|
594
|
+
paymentRequirements.network
|
|
595
|
+
);
|
|
313
596
|
let json;
|
|
314
597
|
try {
|
|
315
598
|
const response = await fetch(`${this.url}/x402/settle`, {
|
|
@@ -334,7 +617,7 @@ var FacilitatorClient = class {
|
|
|
334
617
|
if (!response.ok) {
|
|
335
618
|
const body = await readErrorBody(response);
|
|
336
619
|
if (body.error === void 0) {
|
|
337
|
-
throw new
|
|
620
|
+
throw new chunk4CEMNRCZ_cjs.X402RuntimeError(chunk4CEMNRCZ_cjs.X402_ERROR_CODES.FACILITATOR_UNAVAILABLE, {
|
|
338
621
|
status: response.status
|
|
339
622
|
});
|
|
340
623
|
}
|
|
@@ -351,26 +634,36 @@ var FacilitatorClient = class {
|
|
|
351
634
|
}
|
|
352
635
|
json = await response.json();
|
|
353
636
|
} catch (e) {
|
|
354
|
-
if (e instanceof
|
|
637
|
+
if (e instanceof chunk4CEMNRCZ_cjs.X402RuntimeError) throw e;
|
|
355
638
|
if (e instanceof Error && e.name === "TimeoutError") {
|
|
356
|
-
throw new
|
|
639
|
+
throw new chunk4CEMNRCZ_cjs.X402RuntimeError(chunk4CEMNRCZ_cjs.X402_ERROR_CODES.SETTLE_TIMEOUT);
|
|
357
640
|
}
|
|
358
|
-
throw new
|
|
641
|
+
throw new chunk4CEMNRCZ_cjs.X402RuntimeError(chunk4CEMNRCZ_cjs.X402_ERROR_CODES.FACILITATOR_UNAVAILABLE);
|
|
359
642
|
}
|
|
360
643
|
try {
|
|
361
644
|
const parsed = settleResponseSchema.parse(json);
|
|
362
645
|
if ("txHash" in parsed) {
|
|
646
|
+
const txHash = parsed.txHash;
|
|
647
|
+
const networkId = toEip155Network(paymentRequirements.network);
|
|
648
|
+
const payer = payerOf(paymentPayload);
|
|
363
649
|
return {
|
|
364
650
|
success: true,
|
|
365
|
-
txHash
|
|
651
|
+
txHash,
|
|
366
652
|
route: parsed.route,
|
|
367
653
|
chain: paymentRequirements.network,
|
|
368
654
|
gasSponsored: parsed.gasSponsored,
|
|
369
|
-
networkId
|
|
655
|
+
networkId,
|
|
370
656
|
...parsed.amountSettled !== void 0 && {
|
|
371
657
|
amountSettled: parsed.amountSettled
|
|
372
658
|
},
|
|
373
|
-
...parsed.
|
|
659
|
+
...parsed.amountDelivered !== void 0 && {
|
|
660
|
+
amountDelivered: parsed.amountDelivered
|
|
661
|
+
},
|
|
662
|
+
...parsed.alreadySettled && { alreadySettled: true },
|
|
663
|
+
transaction: txHash,
|
|
664
|
+
network: networkId,
|
|
665
|
+
amount: parsed.amountSettled ?? paymentRequirements.maxAmountRequired,
|
|
666
|
+
...payer && { payer }
|
|
374
667
|
};
|
|
375
668
|
}
|
|
376
669
|
return {
|
|
@@ -378,7 +671,7 @@ var FacilitatorClient = class {
|
|
|
378
671
|
error: { code: parsed.error, message: parsed.message }
|
|
379
672
|
};
|
|
380
673
|
} catch {
|
|
381
|
-
throw new
|
|
674
|
+
throw new chunk4CEMNRCZ_cjs.X402RuntimeError(chunk4CEMNRCZ_cjs.X402_ERROR_CODES.FACILITATOR_INVALID_RESPONSE);
|
|
382
675
|
}
|
|
383
676
|
}
|
|
384
677
|
/**
|
|
@@ -398,17 +691,17 @@ var FacilitatorClient = class {
|
|
|
398
691
|
});
|
|
399
692
|
throwIfRedirect(response);
|
|
400
693
|
if (!response.ok) {
|
|
401
|
-
throw new
|
|
694
|
+
throw new chunk4CEMNRCZ_cjs.X402RuntimeError(chunk4CEMNRCZ_cjs.X402_ERROR_CODES.FACILITATOR_UNAVAILABLE);
|
|
402
695
|
}
|
|
403
696
|
json = await response.json();
|
|
404
697
|
} catch (e) {
|
|
405
|
-
if (e instanceof
|
|
406
|
-
throw new
|
|
698
|
+
if (e instanceof chunk4CEMNRCZ_cjs.X402RuntimeError) throw e;
|
|
699
|
+
throw new chunk4CEMNRCZ_cjs.X402RuntimeError(chunk4CEMNRCZ_cjs.X402_ERROR_CODES.FACILITATOR_UNAVAILABLE);
|
|
407
700
|
}
|
|
408
701
|
try {
|
|
409
702
|
return facilitatorResponseSchema.parse(json);
|
|
410
703
|
} catch {
|
|
411
|
-
throw new
|
|
704
|
+
throw new chunk4CEMNRCZ_cjs.X402RuntimeError(chunk4CEMNRCZ_cjs.X402_ERROR_CODES.FACILITATOR_INVALID_RESPONSE);
|
|
412
705
|
}
|
|
413
706
|
}
|
|
414
707
|
buildHeaders() {
|
|
@@ -440,36 +733,42 @@ async function raceTimeout(promise, ms = HANDLER_TIMEOUT_MS) {
|
|
|
440
733
|
|
|
441
734
|
// src/middleware.ts
|
|
442
735
|
var PRICE_FORMAT = /^\d+(?:\.\d+)?$/;
|
|
443
|
-
async function requestContext(adapter) {
|
|
736
|
+
async function requestContext(adapter, routePath) {
|
|
444
737
|
return {
|
|
445
738
|
method: adapter.getMethod(),
|
|
446
739
|
path: adapter.getPath(),
|
|
740
|
+
routePath,
|
|
447
741
|
url: adapter.getUrl(),
|
|
448
742
|
header: (name) => adapter.getHeader(name),
|
|
449
743
|
body: adapter.getBody ? await adapter.getBody() : void 0
|
|
450
744
|
};
|
|
451
745
|
}
|
|
452
|
-
async function resolvePrice(config, ctx) {
|
|
746
|
+
async function resolvePrice(config, ctx, tokens) {
|
|
453
747
|
if (typeof config.price !== "function") return config.price;
|
|
454
|
-
if (!ctx) throw new
|
|
748
|
+
if (!ctx) throw new chunk4CEMNRCZ_cjs.X402ConfigError("A price function needs the request");
|
|
455
749
|
let price;
|
|
456
750
|
try {
|
|
457
751
|
price = await config.price(ctx);
|
|
458
752
|
} catch (cause) {
|
|
459
|
-
if (
|
|
460
|
-
throw new
|
|
753
|
+
if (chunk4CEMNRCZ_cjs.isPriceRejection(cause)) throw cause;
|
|
754
|
+
throw new chunk4CEMNRCZ_cjs.X402ConfigError(
|
|
461
755
|
`The price function of route "${config.network}${ctx.path}" threw`,
|
|
462
756
|
cause
|
|
463
757
|
);
|
|
464
758
|
}
|
|
465
759
|
const valid = typeof price === "bigint" ? price > 0n : typeof price === "string" && PRICE_FORMAT.test(price) && Number(price) > 0;
|
|
466
760
|
if (!valid) {
|
|
467
|
-
throw new
|
|
761
|
+
throw new chunk4CEMNRCZ_cjs.X402ConfigError(
|
|
468
762
|
`The price function of route "${config.network}${ctx.path}" returned ${JSON.stringify(
|
|
469
763
|
typeof price === "bigint" ? price.toString() : price
|
|
470
764
|
)} \u2014 expected a positive amount like "0.01" or a bigint`
|
|
471
765
|
);
|
|
472
766
|
}
|
|
767
|
+
if (typeof price === "bigint" && config.scheme === "upto" && hasMixedDecimals(config.network, tokens)) {
|
|
768
|
+
throw new chunk4CEMNRCZ_cjs.X402ConfigError(
|
|
769
|
+
`The price function of route "${config.network}${ctx.path}" returned a bigint, but the route accepts tokens with different decimals: return a price like "0.01"`
|
|
770
|
+
);
|
|
771
|
+
}
|
|
473
772
|
return price;
|
|
474
773
|
}
|
|
475
774
|
var SETTLE_AMOUNT_HEADER = "payment-settle-amount";
|
|
@@ -521,11 +820,22 @@ function invalidSettleAmountResponse(reason) {
|
|
|
521
820
|
reason === "meter" ? INVALID_METER_RESPONSE : INVALID_SETTLE_AMOUNT_RESPONSE
|
|
522
821
|
);
|
|
523
822
|
}
|
|
823
|
+
function refusingBigints(meter) {
|
|
824
|
+
return async (ctx) => {
|
|
825
|
+
const amount = await meter(ctx);
|
|
826
|
+
if (typeof amount === "bigint") {
|
|
827
|
+
throw new chunk4CEMNRCZ_cjs.X402ConfigError(
|
|
828
|
+
'The meter returned a bigint, but the route accepts tokens with different decimals: return an amount like "0.75"'
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
return amount;
|
|
832
|
+
};
|
|
833
|
+
}
|
|
524
834
|
var AMOUNT_FORMAT = /^\d+(?:\.\d+)?$/;
|
|
525
835
|
async function resolveCharge(verified, settleHeader, response) {
|
|
526
836
|
if (verified.meter) {
|
|
527
837
|
if (!verified.request) {
|
|
528
|
-
throw new
|
|
838
|
+
throw new chunk4CEMNRCZ_cjs.X402ConfigError(
|
|
529
839
|
"A metered payment carries a meter but no request context"
|
|
530
840
|
);
|
|
531
841
|
}
|
|
@@ -576,14 +886,14 @@ function resolveAcceptedTokens(config) {
|
|
|
576
886
|
}
|
|
577
887
|
const defaults = config.scheme === "upto" ? getMeteredAcceptedTokens(config.network) : getDefaultAcceptedTokens(config.network);
|
|
578
888
|
if (defaults) return defaults;
|
|
579
|
-
throw new
|
|
889
|
+
throw new chunk4CEMNRCZ_cjs.X402ConfigError(
|
|
580
890
|
`acceptedTokens is required for network "${config.network}" \u2014 no defaults available for this chain`
|
|
581
891
|
);
|
|
582
892
|
}
|
|
583
893
|
function resolveDecimals(config, asset) {
|
|
584
894
|
const decimals = config.decimals ?? getTokenDecimals(config.network, asset);
|
|
585
895
|
if (decimals === void 0) {
|
|
586
|
-
throw new
|
|
896
|
+
throw new chunk4CEMNRCZ_cjs.X402ConfigError(
|
|
587
897
|
`Unknown decimals for token ${asset} on "${config.network}" \u2014 add it to the @parallel-protocol/chains catalog or set the route's \`decimals\` explicitly`
|
|
588
898
|
);
|
|
589
899
|
}
|
|
@@ -592,7 +902,7 @@ function resolveDecimals(config, asset) {
|
|
|
592
902
|
function priceInUnits(price, decimals, asset) {
|
|
593
903
|
const units = parsePrice(price, decimals);
|
|
594
904
|
if (units === 0n) {
|
|
595
|
-
throw new
|
|
905
|
+
throw new chunk4CEMNRCZ_cjs.X402ConfigError(
|
|
596
906
|
`Price ${typeof price === "bigint" ? price.toString() : `"${price}"`} is below the precision of token ${asset} (${decimals} decimals)`
|
|
597
907
|
);
|
|
598
908
|
}
|
|
@@ -600,18 +910,27 @@ function priceInUnits(price, decimals, asset) {
|
|
|
600
910
|
}
|
|
601
911
|
function buildPaymentRequired(url, config, resolvedTokens, price) {
|
|
602
912
|
const network = toEip155Network(config.network);
|
|
603
|
-
const
|
|
913
|
+
const scheme = config.scheme ?? "exact";
|
|
914
|
+
const entries = resolvedTokens.map((asset) => {
|
|
604
915
|
const decimals = resolveDecimals(config, asset);
|
|
605
916
|
return {
|
|
606
|
-
scheme
|
|
917
|
+
scheme,
|
|
607
918
|
network,
|
|
608
919
|
asset,
|
|
609
920
|
amount: priceInUnits(price, decimals, asset),
|
|
610
921
|
payTo: config.payTo,
|
|
611
922
|
maxTimeoutSeconds: config.maxTimeoutSeconds ?? DEFAULT_MAX_TIMEOUT_SECONDS,
|
|
612
|
-
extra: {
|
|
923
|
+
extra: {
|
|
924
|
+
decimals,
|
|
925
|
+
...scheme === "upto" && permit2Extra(config.network, asset)
|
|
926
|
+
}
|
|
613
927
|
};
|
|
614
928
|
});
|
|
929
|
+
const viaPermit2 = (entry) => "facilitatorAddress" in entry.extra;
|
|
930
|
+
const accepts = [
|
|
931
|
+
...entries.filter(viaPermit2),
|
|
932
|
+
...entries.filter((entry) => !viaPermit2(entry))
|
|
933
|
+
];
|
|
615
934
|
return {
|
|
616
935
|
x402Version: 2,
|
|
617
936
|
resource: {
|
|
@@ -619,13 +938,17 @@ function buildPaymentRequired(url, config, resolvedTokens, price) {
|
|
|
619
938
|
description: config.description,
|
|
620
939
|
mimeType: "application/json"
|
|
621
940
|
},
|
|
622
|
-
accepts
|
|
941
|
+
accepts,
|
|
942
|
+
...accepts.some(viaPermit2) && {
|
|
943
|
+
extensions: EIP2612_GAS_SPONSORING_EXTENSION
|
|
944
|
+
}
|
|
623
945
|
};
|
|
624
946
|
}
|
|
625
|
-
function decodePaymentPayload(header) {
|
|
947
|
+
function decodePaymentPayload(header, network) {
|
|
626
948
|
try {
|
|
627
|
-
const parsed =
|
|
628
|
-
Buffer.from(header, "base64").toString("utf8")
|
|
949
|
+
const parsed = toFacilitatorPayload(
|
|
950
|
+
JSON.parse(Buffer.from(header, "base64").toString("utf8")),
|
|
951
|
+
network
|
|
629
952
|
);
|
|
630
953
|
return typeof parsed === "object" && parsed !== null ? parsed : void 0;
|
|
631
954
|
} catch {
|
|
@@ -644,7 +967,7 @@ function deliveredToken(payload, chainTokens) {
|
|
|
644
967
|
return payload.tokenIn ?? chainTokens?.usdp;
|
|
645
968
|
}
|
|
646
969
|
function resolveDeliveredAsset(header, config, resolvedTokens) {
|
|
647
|
-
const payload = decodePaymentPayload(header);
|
|
970
|
+
const payload = decodePaymentPayload(header, config.network);
|
|
648
971
|
const target = payload ? deliveredToken(
|
|
649
972
|
payload,
|
|
650
973
|
PARALLEL_TOKENS[config.network]
|
|
@@ -687,7 +1010,7 @@ function paymentRequiredResponse(url, config, resolvedTokens, price, refusal) {
|
|
|
687
1010
|
price
|
|
688
1011
|
);
|
|
689
1012
|
if (refusal) {
|
|
690
|
-
paymentRequired.error = shapedCode(refusal.code) ??
|
|
1013
|
+
paymentRequired.error = shapedCode(refusal.code) ?? chunk4CEMNRCZ_cjs.X402_ERROR_CODES.FACILITATOR_INVALID_RESPONSE;
|
|
691
1014
|
const message = boundedMessage(refusal.detail);
|
|
692
1015
|
if (message) paymentRequired.message = message;
|
|
693
1016
|
}
|
|
@@ -704,24 +1027,39 @@ function createPaymentGate(config) {
|
|
|
704
1027
|
if (!checked.success) {
|
|
705
1028
|
const issue = checked.error.issues[0];
|
|
706
1029
|
const where = issue?.path.length ? ` at ${issue.path.join(".")}` : "";
|
|
707
|
-
throw new
|
|
1030
|
+
throw new chunk4CEMNRCZ_cjs.X402ConfigError(
|
|
708
1031
|
`Invalid paymentMiddleware config${where}: ${issue?.message ?? "check your routes, facilitator URL and payTo addresses"}`,
|
|
709
1032
|
checked.error
|
|
710
1033
|
);
|
|
711
1034
|
}
|
|
712
1035
|
const client = new FacilitatorClient(config.facilitator);
|
|
1036
|
+
const routes = routeTable(config.routes);
|
|
713
1037
|
return async (adapter) => {
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
1038
|
+
const path = adapter.getPath();
|
|
1039
|
+
const fullPath = adapter.getFullPath?.();
|
|
1040
|
+
let match = findRoute(path, routes);
|
|
1041
|
+
if (!match.route && fullPath !== void 0 && fullPath !== path)
|
|
1042
|
+
match = findRoute(fullPath, routes);
|
|
1043
|
+
const { route: routeConfig, dotSegments, routePath } = match;
|
|
717
1044
|
if (!routeConfig) return { type: "pass" };
|
|
1045
|
+
if (dotSegments) {
|
|
1046
|
+
return {
|
|
1047
|
+
type: "error",
|
|
1048
|
+
result: jsonResult(400, {
|
|
1049
|
+
error: chunk4CEMNRCZ_cjs.X402_ERROR_CODES.INVALID_PATH,
|
|
1050
|
+
message: "A paid route is not served on a path with . or .. segments: send the path resolved"
|
|
1051
|
+
})
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
if (adapter.getMethod().toUpperCase() === "OPTIONS")
|
|
1055
|
+
return { type: "pass", preflight: true };
|
|
718
1056
|
const resolvedTokens = resolveAcceptedTokens(routeConfig);
|
|
719
|
-
let request = typeof routeConfig.price === "function" ? await requestContext(adapter) : void 0;
|
|
1057
|
+
let request = typeof routeConfig.price === "function" ? await requestContext(adapter, routePath) : void 0;
|
|
720
1058
|
let price;
|
|
721
1059
|
try {
|
|
722
|
-
price = await resolvePrice(routeConfig, request);
|
|
1060
|
+
price = await resolvePrice(routeConfig, request, resolvedTokens);
|
|
723
1061
|
} catch (err) {
|
|
724
|
-
if (!
|
|
1062
|
+
if (!chunk4CEMNRCZ_cjs.isPriceRejection(err)) throw err;
|
|
725
1063
|
const status = Number.isInteger(err.status) && err.status >= 400 && err.status <= 599 ? err.status : 400;
|
|
726
1064
|
return {
|
|
727
1065
|
type: "error",
|
|
@@ -758,7 +1096,7 @@ function createPaymentGate(config) {
|
|
|
758
1096
|
try {
|
|
759
1097
|
({ settleToken } = await client.verify(paymentHeader, requirements));
|
|
760
1098
|
} catch (e) {
|
|
761
|
-
const refusal = e instanceof
|
|
1099
|
+
const refusal = e instanceof chunk4CEMNRCZ_cjs.X402RuntimeError ? { code: e.code, detail: e.detail, retryAfter: e.retryAfter } : { code: chunk4CEMNRCZ_cjs.X402_ERROR_CODES.FACILITATOR_UNAVAILABLE };
|
|
762
1100
|
return {
|
|
763
1101
|
type: "error",
|
|
764
1102
|
result: paymentRequiredResponse(
|
|
@@ -770,7 +1108,8 @@ function createPaymentGate(config) {
|
|
|
770
1108
|
)
|
|
771
1109
|
};
|
|
772
1110
|
}
|
|
773
|
-
|
|
1111
|
+
const meter = routeConfig.meter && hasMixedDecimals(routeConfig.network, resolvedTokens) ? refusingBigints(routeConfig.meter) : routeConfig.meter;
|
|
1112
|
+
if (meter && !request) request = await requestContext(adapter, routePath);
|
|
774
1113
|
return {
|
|
775
1114
|
type: "verified",
|
|
776
1115
|
scheme: routeConfig.scheme ?? "exact",
|
|
@@ -778,7 +1117,7 @@ function createPaymentGate(config) {
|
|
|
778
1117
|
decimals: resolveDecimals(routeConfig, asset),
|
|
779
1118
|
handlerTimeoutMs: handlerTimeoutFor(routeConfig),
|
|
780
1119
|
settle: (options) => client.settle(paymentHeader, requirements, { ...options, settleToken }),
|
|
781
|
-
...
|
|
1120
|
+
...meter && { meter, request }
|
|
782
1121
|
};
|
|
783
1122
|
};
|
|
784
1123
|
}
|
|
@@ -786,9 +1125,9 @@ var DEFAULT_SETTLEMENT_MESSAGE = "The payment could not be settled.";
|
|
|
786
1125
|
var MERCHANT_SETTLEMENT_MESSAGE = "The merchant could not complete the settlement of this payment. The payment was not taken: do not sign another payment for this request before checking with the merchant.";
|
|
787
1126
|
var UNAVAILABLE_SETTLEMENT_MESSAGE = "The facilitator could not settle the payment for now. It may still settle until its authorization expires, or an earlier attempt may already have settled it: do not sign another payment for this request before checking with the merchant.";
|
|
788
1127
|
var AGENT_MESSAGES = {
|
|
789
|
-
[
|
|
790
|
-
[
|
|
791
|
-
[
|
|
1128
|
+
[chunk4CEMNRCZ_cjs.X402_ERROR_CODES.SETTLE_TIMEOUT]: "The facilitator did not confirm the settlement in time. The payment may still settle: do not sign another payment for this request before checking with the merchant.",
|
|
1129
|
+
[chunk4CEMNRCZ_cjs.X402_ERROR_CODES.FACILITATOR_UNAVAILABLE]: "The facilitator could not be reached to settle the payment. It may still have settled: do not sign another payment for this request before checking with the merchant.",
|
|
1130
|
+
[chunk4CEMNRCZ_cjs.X402_ERROR_CODES.FACILITATOR_INVALID_RESPONSE]: "The facilitator answered the settlement with an unexpected response. The payment may have settled: do not sign another payment for this request before checking with the merchant.",
|
|
792
1131
|
SETTLE_IN_PROGRESS: "The facilitator is still settling this payment. Do not sign another payment for this request before checking with the merchant.",
|
|
793
1132
|
RECEIPT_UNAVAILABLE: "The facilitator sent the transaction but could not read its confirmation. The payment may have settled: do not sign another payment for this request before checking with the merchant.",
|
|
794
1133
|
SETTLE_TOKEN_INVALID: MERCHANT_SETTLEMENT_MESSAGE,
|
|
@@ -813,8 +1152,8 @@ function settlementFailure(code, failure) {
|
|
|
813
1152
|
};
|
|
814
1153
|
}
|
|
815
1154
|
var RETRY_ONCE_CODES = /* @__PURE__ */ new Set([
|
|
816
|
-
|
|
817
|
-
|
|
1155
|
+
chunk4CEMNRCZ_cjs.X402_ERROR_CODES.SETTLE_TIMEOUT,
|
|
1156
|
+
chunk4CEMNRCZ_cjs.X402_ERROR_CODES.FACILITATOR_UNAVAILABLE
|
|
818
1157
|
]);
|
|
819
1158
|
async function settleVerified(verified, options) {
|
|
820
1159
|
let response;
|
|
@@ -822,7 +1161,7 @@ async function settleVerified(verified, options) {
|
|
|
822
1161
|
try {
|
|
823
1162
|
response = await verified.settle(options);
|
|
824
1163
|
} catch (e) {
|
|
825
|
-
const code = e instanceof
|
|
1164
|
+
const code = e instanceof chunk4CEMNRCZ_cjs.X402RuntimeError ? e.code : "UNKNOWN";
|
|
826
1165
|
if (attempt > 0 || !RETRY_ONCE_CODES.has(code)) {
|
|
827
1166
|
return settlementFailure(code);
|
|
828
1167
|
}
|
|
@@ -852,7 +1191,8 @@ function createPaymentMiddleware(config) {
|
|
|
852
1191
|
const gate = createPaymentGate(config);
|
|
853
1192
|
return async (adapter) => {
|
|
854
1193
|
const gateResult = await gate(adapter);
|
|
855
|
-
if (gateResult.type === "pass")
|
|
1194
|
+
if (gateResult.type === "pass")
|
|
1195
|
+
return gateResult.preflight ? { pass: true, preflight: true } : { pass: true };
|
|
856
1196
|
if (gateResult.type === "error") return gateResult.result;
|
|
857
1197
|
let handlerResult;
|
|
858
1198
|
try {
|
|
@@ -908,19 +1248,24 @@ exports.FacilitatorClient = FacilitatorClient;
|
|
|
908
1248
|
exports.HANDLER_TIMEOUT = HANDLER_TIMEOUT;
|
|
909
1249
|
exports.PARALLEL_TOKENS = PARALLEL_TOKENS;
|
|
910
1250
|
exports.SETTLE_AMOUNT_HEADER = SETTLE_AMOUNT_HEADER;
|
|
1251
|
+
exports.answerAsPreflight = answerAsPreflight;
|
|
911
1252
|
exports.createPaymentGate = createPaymentGate;
|
|
912
1253
|
exports.createPaymentMiddleware = createPaymentMiddleware;
|
|
1254
|
+
exports.dropConditionalHeaders = dropConditionalHeaders;
|
|
913
1255
|
exports.encodeBase64 = encodeBase64;
|
|
1256
|
+
exports.findRoute = findRoute;
|
|
914
1257
|
exports.getDefaultAcceptedTokens = getDefaultAcceptedTokens;
|
|
915
1258
|
exports.invalidSettleAmountResponse = invalidSettleAmountResponse;
|
|
916
1259
|
exports.isJsonContentType = isJsonContentType;
|
|
917
1260
|
exports.jsonFromResponse = jsonFromResponse;
|
|
918
|
-
exports.
|
|
1261
|
+
exports.normalizeRoutePath = normalizeRoutePath;
|
|
919
1262
|
exports.parseJsonBody = parseJsonBody;
|
|
920
1263
|
exports.parsePrice = parsePrice;
|
|
1264
|
+
exports.preflightInit = preflightInit;
|
|
921
1265
|
exports.raceTimeout = raceTimeout;
|
|
922
1266
|
exports.resolveCharge = resolveCharge;
|
|
923
1267
|
exports.resolveSettleAmount = resolveSettleAmount;
|
|
1268
|
+
exports.routeTable = routeTable;
|
|
924
1269
|
exports.settleVerified = settleVerified;
|
|
925
1270
|
exports.settlementFailureResponse = settlementFailureResponse;
|
|
926
1271
|
exports.toEip155Network = toEip155Network;
|