@parallel-protocol/x402 0.6.0 → 0.7.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 +177 -4
- package/dist/{chunk-TLCEPWQI.js → chunk-AENXD4OC.js} +232 -79
- package/dist/chunk-AFRDHGDT.js +36 -0
- package/dist/chunk-JPMK5YBU.cjs +42 -0
- package/dist/{chunk-K6QETMQA.cjs → chunk-POU7EH3E.cjs} +254 -99
- package/dist/express.cjs +53 -4
- package/dist/express.d.cts +2 -1
- package/dist/express.d.ts +2 -1
- package/dist/express.js +50 -1
- package/dist/fastify.cjs +37 -12
- package/dist/fastify.d.cts +2 -1
- package/dist/fastify.d.ts +2 -1
- package/dist/fastify.js +33 -8
- package/dist/hono.cjs +21 -4
- package/dist/hono.d.cts +2 -1
- package/dist/hono.d.ts +2 -1
- package/dist/hono.js +18 -1
- package/dist/index.cjs +37 -24
- package/dist/index.d.cts +39 -5
- package/dist/index.d.ts +39 -5
- package/dist/index.js +2 -1
- package/dist/llm.cjs +486 -0
- package/dist/llm.d.cts +203 -0
- package/dist/llm.d.ts +203 -0
- package/dist/llm.js +473 -0
- package/dist/next.cjs +35 -14
- package/dist/next.d.cts +2 -1
- package/dist/next.d.ts +2 -1
- package/dist/next.js +29 -8
- package/dist/{types-CBzm5CtM.d.cts → types-q_gu5wjz.d.cts} +56 -2
- package/dist/{types-CBzm5CtM.d.ts → types-q_gu5wjz.d.ts} +56 -2
- package/package.json +12 -2
|
@@ -1,27 +1,51 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { X402_ERROR_CODES, X402RuntimeError, X402ConfigError, isPriceRejection } from './chunk-AFRDHGDT.js';
|
|
2
2
|
import { getTokenDecimals as getTokenDecimals$1 } from '@parallel-protocol/chains';
|
|
3
|
+
import { z } from 'zod';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
5
|
+
var PARALLEL_TOKENS = {
|
|
6
|
+
ethereum: {
|
|
7
|
+
usdp: "0x9B3a8f7CEC208e247d97dEE13313690977e24459",
|
|
8
|
+
susdp: "0xd3a452B305C8285c0Dd7b8537665c734d3D279eF",
|
|
9
|
+
usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
10
|
+
frxUSD: "0xCAcd6fd266aF91b8AeD52aCCc382b4e165586E29",
|
|
11
|
+
sfrxUSD: "0xcf62F905562626CfcDD2261162a51fd02Fc9c5b6",
|
|
12
|
+
USDe: "0x4c9EDD5852cd905f086C759E8383e09bff1E68B3",
|
|
13
|
+
sUSDe: "0x9D39A5DE30e57443BfF2A8307A4256c8797A3497"
|
|
14
|
+
},
|
|
15
|
+
base: {
|
|
16
|
+
usdp: "0x76A9A0062ec6712b99B4f63bD2b4270185759dd5",
|
|
17
|
+
susdp: "0x472eD57b376fE400259FB28e5C46eB53f0E3e7E7",
|
|
18
|
+
usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
19
|
+
USDS: "0x820C137fa70C8691f0e44Dc420a5e53c168921Dc",
|
|
20
|
+
sUSDS: "0x5875eEE11Cf8398102FdAd704C9E96607675467a"
|
|
21
|
+
},
|
|
22
|
+
avalanche: {
|
|
23
|
+
usdp: "0x9eE1963f05553eF838604Dd39403be21ceF26AA4",
|
|
24
|
+
susdp: "0x9d92c21205383651610f90722131655a5b8ed3e0",
|
|
25
|
+
usdc: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
|
|
26
|
+
ygamiUSDC: "0x9fD32FD5e32C6B95483d36C5E724C5C5250Ce010"
|
|
27
|
+
},
|
|
28
|
+
hyperevm: {
|
|
29
|
+
usdp: "0xBE65F0F410A72BeC163dC65d46c83699e957D588",
|
|
30
|
+
susdp: "0x9B3a8f7CEC208e247d97dEE13313690977e24459",
|
|
31
|
+
usdc: "0xb88339cb7199b77e23db6e890353e22632ba630f",
|
|
32
|
+
USDe: "0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34",
|
|
33
|
+
sUSDe: "0x211Cc4DD073734dA055fbF44a2b4667d5E5fE5d2"
|
|
22
34
|
}
|
|
23
|
-
code;
|
|
24
35
|
};
|
|
36
|
+
function getDefaultAcceptedTokens(network) {
|
|
37
|
+
const entry = PARALLEL_TOKENS[network];
|
|
38
|
+
if (!entry) return void 0;
|
|
39
|
+
return [entry.usdp, entry.usdc, entry.susdp];
|
|
40
|
+
}
|
|
41
|
+
function getMeteredAcceptedTokens(network) {
|
|
42
|
+
const entry = PARALLEL_TOKENS[network];
|
|
43
|
+
if (!entry) return void 0;
|
|
44
|
+
return [entry.usdp];
|
|
45
|
+
}
|
|
46
|
+
function getTokenDecimals(network, address) {
|
|
47
|
+
return getTokenDecimals$1(network, address);
|
|
48
|
+
}
|
|
25
49
|
|
|
26
50
|
// src/utils.ts
|
|
27
51
|
var EIP155_NETWORKS = {
|
|
@@ -45,6 +69,28 @@ function parsePrice(price, decimals = 18) {
|
|
|
45
69
|
`Invalid price format: "${price}". Expected "0.01" or a bigint.`
|
|
46
70
|
);
|
|
47
71
|
}
|
|
72
|
+
function isJsonContentType(contentType) {
|
|
73
|
+
return /^application\/(?:[\w.-]+\+)?json(?:\s*;.*)?$/i.test(
|
|
74
|
+
contentType?.trim() ?? ""
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
function parseJsonBody(contentType, text) {
|
|
78
|
+
if (text === void 0 || !isJsonContentType(contentType)) return void 0;
|
|
79
|
+
try {
|
|
80
|
+
return JSON.parse(text);
|
|
81
|
+
} catch {
|
|
82
|
+
return void 0;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async function jsonFromResponse(res) {
|
|
86
|
+
const contentType = res.headers.get("content-type") ?? void 0;
|
|
87
|
+
if (!isJsonContentType(contentType)) return void 0;
|
|
88
|
+
try {
|
|
89
|
+
return parseJsonBody(contentType, await res.clone().text());
|
|
90
|
+
} catch {
|
|
91
|
+
return void 0;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
48
94
|
function validateAddress(address) {
|
|
49
95
|
return /^0x[0-9a-fA-F]{40}$/.test(address);
|
|
50
96
|
}
|
|
@@ -74,7 +120,12 @@ var ethereumAddressSchema = z.string().regex(/^0x[0-9a-fA-F]{40}$/, "Invalid Eth
|
|
|
74
120
|
var txHashSchema = z.string().regex(/^0x[0-9a-fA-F]{64}$/);
|
|
75
121
|
var priceSchema = z.union([
|
|
76
122
|
z.bigint().positive("Price must be greater than 0"),
|
|
77
|
-
z.string().regex(/^\d+(?:\.\d+)?$/, 'Price must be in format "0.01"').refine((price) => Number(price) > 0, "Price must be greater than 0")
|
|
123
|
+
z.string().regex(/^\d+(?:\.\d+)?$/, 'Price must be in format "0.01"').refine((price) => Number(price) > 0, "Price must be greater than 0"),
|
|
124
|
+
// A per-request price function; its return value is checked per request.
|
|
125
|
+
z.custom(
|
|
126
|
+
(value) => typeof value === "function",
|
|
127
|
+
"Price must be a string, a bigint or a function of the request"
|
|
128
|
+
)
|
|
78
129
|
]);
|
|
79
130
|
var facilitatorConfigSchema = z.object({
|
|
80
131
|
url: z.string().refine((v) => URL.canParse(v), "Invalid facilitator URL"),
|
|
@@ -88,11 +139,25 @@ var routeConfigSchema = z.object({
|
|
|
88
139
|
acceptedTokens: z.array(ethereumAddressSchema).optional(),
|
|
89
140
|
description: z.string().optional(),
|
|
90
141
|
scheme: z.enum(["exact", "upto"]).optional(),
|
|
91
|
-
maxTimeoutSeconds: z.number().int().positive().optional()
|
|
142
|
+
maxTimeoutSeconds: z.number().int().positive().optional(),
|
|
143
|
+
meter: z.custom(
|
|
144
|
+
(value) => typeof value === "function",
|
|
145
|
+
"meter must be a function of the response"
|
|
146
|
+
).optional()
|
|
92
147
|
}).refine(
|
|
148
|
+
(route) => route.meter === void 0 || route.scheme === "upto",
|
|
149
|
+
"meter only applies to upto routes"
|
|
150
|
+
).refine(
|
|
93
151
|
(route) => route.scheme !== "upto" || (route.maxTimeoutSeconds ?? 300) <= UPTO_MAX_TIMEOUT_SECONDS,
|
|
94
152
|
`maxTimeoutSeconds must be at most ${UPTO_MAX_TIMEOUT_SECONDS} on an upto route`
|
|
95
|
-
)
|
|
153
|
+
).refine((route) => {
|
|
154
|
+
if (route.scheme !== "upto" || !route.acceptedTokens?.length) return true;
|
|
155
|
+
const usdp = PARALLEL_TOKENS[route.network]?.usdp;
|
|
156
|
+
if (!usdp) return true;
|
|
157
|
+
return route.acceptedTokens.every(
|
|
158
|
+
(token) => token.toLowerCase() === usdp.toLowerCase()
|
|
159
|
+
);
|
|
160
|
+
}, "acceptedTokens on an upto route may only list the network's USDp");
|
|
96
161
|
var paymentMiddlewareConfigSchema = z.object({
|
|
97
162
|
facilitator: facilitatorConfigSchema,
|
|
98
163
|
routes: z.record(z.string(), routeConfigSchema).refine((r) => Object.keys(r).length > 0, "At least one route is required")
|
|
@@ -277,47 +342,41 @@ async function raceTimeout(promise, ms = HANDLER_TIMEOUT_MS) {
|
|
|
277
342
|
clearTimeout(timer);
|
|
278
343
|
}
|
|
279
344
|
}
|
|
280
|
-
var PARALLEL_TOKENS = {
|
|
281
|
-
ethereum: {
|
|
282
|
-
usdp: "0x9B3a8f7CEC208e247d97dEE13313690977e24459",
|
|
283
|
-
susdp: "0xd3a452B305C8285c0Dd7b8537665c734d3D279eF",
|
|
284
|
-
usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
285
|
-
frxUSD: "0xCAcd6fd266aF91b8AeD52aCCc382b4e165586E29",
|
|
286
|
-
sfrxUSD: "0xcf62F905562626CfcDD2261162a51fd02Fc9c5b6",
|
|
287
|
-
USDe: "0x4c9EDD5852cd905f086C759E8383e09bff1E68B3",
|
|
288
|
-
sUSDe: "0x9D39A5DE30e57443BfF2A8307A4256c8797A3497"
|
|
289
|
-
},
|
|
290
|
-
base: {
|
|
291
|
-
usdp: "0x76A9A0062ec6712b99B4f63bD2b4270185759dd5",
|
|
292
|
-
susdp: "0x472eD57b376fE400259FB28e5C46eB53f0E3e7E7",
|
|
293
|
-
usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
294
|
-
USDS: "0x820C137fa70C8691f0e44Dc420a5e53c168921Dc",
|
|
295
|
-
sUSDS: "0x5875eEE11Cf8398102FdAd704C9E96607675467a"
|
|
296
|
-
},
|
|
297
|
-
avalanche: {
|
|
298
|
-
usdp: "0x9eE1963f05553eF838604Dd39403be21ceF26AA4",
|
|
299
|
-
susdp: "0x9d92c21205383651610f90722131655a5b8ed3e0",
|
|
300
|
-
usdc: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
|
|
301
|
-
ygamiUSDC: "0x9fD32FD5e32C6B95483d36C5E724C5C5250Ce010"
|
|
302
|
-
},
|
|
303
|
-
hyperevm: {
|
|
304
|
-
usdp: "0xBE65F0F410A72BeC163dC65d46c83699e957D588",
|
|
305
|
-
susdp: "0x9B3a8f7CEC208e247d97dEE13313690977e24459",
|
|
306
|
-
usdc: "0xb88339cb7199b77e23db6e890353e22632ba630f",
|
|
307
|
-
USDe: "0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34",
|
|
308
|
-
sUSDe: "0x211Cc4DD073734dA055fbF44a2b4667d5E5fE5d2"
|
|
309
|
-
}
|
|
310
|
-
};
|
|
311
|
-
function getDefaultAcceptedTokens(network) {
|
|
312
|
-
const entry = PARALLEL_TOKENS[network];
|
|
313
|
-
if (!entry) return void 0;
|
|
314
|
-
return [entry.usdp, entry.usdc, entry.susdp];
|
|
315
|
-
}
|
|
316
|
-
function getTokenDecimals(network, address) {
|
|
317
|
-
return getTokenDecimals$1(network, address);
|
|
318
|
-
}
|
|
319
345
|
|
|
320
346
|
// src/middleware.ts
|
|
347
|
+
var PRICE_FORMAT = /^\d+(?:\.\d+)?$/;
|
|
348
|
+
async function requestContext(adapter) {
|
|
349
|
+
return {
|
|
350
|
+
method: adapter.getMethod(),
|
|
351
|
+
path: adapter.getPath(),
|
|
352
|
+
url: adapter.getUrl(),
|
|
353
|
+
header: (name) => adapter.getHeader(name),
|
|
354
|
+
body: adapter.getBody ? await adapter.getBody() : void 0
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
async function resolvePrice(config, ctx) {
|
|
358
|
+
if (typeof config.price !== "function") return config.price;
|
|
359
|
+
if (!ctx) throw new X402ConfigError("A price function needs the request");
|
|
360
|
+
let price;
|
|
361
|
+
try {
|
|
362
|
+
price = await config.price(ctx);
|
|
363
|
+
} catch (cause) {
|
|
364
|
+
if (isPriceRejection(cause)) throw cause;
|
|
365
|
+
throw new X402ConfigError(
|
|
366
|
+
`The price function of route "${config.network}${ctx.path}" threw`,
|
|
367
|
+
cause
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
const valid = typeof price === "bigint" ? price > 0n : typeof price === "string" && PRICE_FORMAT.test(price) && Number(price) > 0;
|
|
371
|
+
if (!valid) {
|
|
372
|
+
throw new X402ConfigError(
|
|
373
|
+
`The price function of route "${config.network}${ctx.path}" returned ${JSON.stringify(
|
|
374
|
+
typeof price === "bigint" ? price.toString() : price
|
|
375
|
+
)} \u2014 expected a positive amount like "0.01" or a bigint`
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
return price;
|
|
379
|
+
}
|
|
321
380
|
var SETTLE_AMOUNT_HEADER = "payment-settle-amount";
|
|
322
381
|
var DEFAULT_MAX_TIMEOUT_SECONDS = 300;
|
|
323
382
|
function handlerTimeoutFor(config) {
|
|
@@ -346,11 +405,67 @@ var INVALID_SETTLE_AMOUNT_RESPONSE = {
|
|
|
346
405
|
error: "INVALID_SETTLE_AMOUNT",
|
|
347
406
|
message: `The handler set an invalid ${SETTLE_AMOUNT_HEADER} header \u2014 expected a decimal amount in token units, formatted like the route price and within the token's precision, at most the route price.`
|
|
348
407
|
};
|
|
408
|
+
var INVALID_METER_RESPONSE = {
|
|
409
|
+
error: "INVALID_SETTLE_AMOUNT",
|
|
410
|
+
message: "The route's meter function failed or returned something that is not an amount; the response was discarded and nothing was charged."
|
|
411
|
+
};
|
|
412
|
+
function invalidSettleAmountResponse(reason) {
|
|
413
|
+
return reason === "meter" ? INVALID_METER_RESPONSE : INVALID_SETTLE_AMOUNT_RESPONSE;
|
|
414
|
+
}
|
|
415
|
+
var AMOUNT_FORMAT = /^\d+(?:\.\d+)?$/;
|
|
416
|
+
async function resolveCharge(verified, settleHeader, response) {
|
|
417
|
+
if (verified.meter) {
|
|
418
|
+
if (!verified.request) {
|
|
419
|
+
throw new X402ConfigError(
|
|
420
|
+
"A metered payment carries a meter but no request context"
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
let result;
|
|
424
|
+
try {
|
|
425
|
+
const body = await raceTimeout(
|
|
426
|
+
response.body(),
|
|
427
|
+
verified.handlerTimeoutMs
|
|
428
|
+
);
|
|
429
|
+
if (body === HANDLER_TIMEOUT) return { kind: "invalid", reason: "meter" };
|
|
430
|
+
result = await verified.meter({
|
|
431
|
+
status: response.status,
|
|
432
|
+
header: response.header,
|
|
433
|
+
body,
|
|
434
|
+
request: verified.request
|
|
435
|
+
});
|
|
436
|
+
} catch {
|
|
437
|
+
return { kind: "invalid", reason: "meter" };
|
|
438
|
+
}
|
|
439
|
+
if (result != null) {
|
|
440
|
+
let amount;
|
|
441
|
+
if (typeof result === "bigint") {
|
|
442
|
+
if (result < 0n) return { kind: "invalid", reason: "meter" };
|
|
443
|
+
amount = result;
|
|
444
|
+
} else if (typeof result === "string" && AMOUNT_FORMAT.test(result)) {
|
|
445
|
+
const fraction = result.split(".")[1] ?? "";
|
|
446
|
+
if (fraction.length > verified.decimals) {
|
|
447
|
+
return { kind: "invalid", reason: "meter" };
|
|
448
|
+
}
|
|
449
|
+
amount = parsePrice(result, verified.decimals);
|
|
450
|
+
} else {
|
|
451
|
+
return { kind: "invalid", reason: "meter" };
|
|
452
|
+
}
|
|
453
|
+
if (amount === 0n) return { kind: "skip" };
|
|
454
|
+
if (amount > verified.maxAmount) amount = verified.maxAmount;
|
|
455
|
+
return { kind: "settle", amount: amount.toString() };
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return resolveSettleAmount(
|
|
459
|
+
settleHeader,
|
|
460
|
+
verified.maxAmount,
|
|
461
|
+
verified.decimals
|
|
462
|
+
);
|
|
463
|
+
}
|
|
349
464
|
function resolveAcceptedTokens(config) {
|
|
350
465
|
if (config.acceptedTokens?.length) {
|
|
351
466
|
return config.acceptedTokens;
|
|
352
467
|
}
|
|
353
|
-
const defaults = getDefaultAcceptedTokens(config.network);
|
|
468
|
+
const defaults = config.scheme === "upto" ? getMeteredAcceptedTokens(config.network) : getDefaultAcceptedTokens(config.network);
|
|
354
469
|
if (defaults) return defaults;
|
|
355
470
|
throw new X402ConfigError(
|
|
356
471
|
`acceptedTokens is required for network "${config.network}" \u2014 no defaults available for this chain`
|
|
@@ -365,7 +480,16 @@ function resolveDecimals(config, asset) {
|
|
|
365
480
|
}
|
|
366
481
|
return decimals;
|
|
367
482
|
}
|
|
368
|
-
function
|
|
483
|
+
function priceInUnits(price, decimals, asset) {
|
|
484
|
+
const units = parsePrice(price, decimals);
|
|
485
|
+
if (units === 0n) {
|
|
486
|
+
throw new X402ConfigError(
|
|
487
|
+
`Price ${typeof price === "bigint" ? price.toString() : `"${price}"`} is below the precision of token ${asset} (${decimals} decimals)`
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
return units.toString();
|
|
491
|
+
}
|
|
492
|
+
function buildPaymentRequired(url, config, resolvedTokens, price) {
|
|
369
493
|
const network = toEip155Network(config.network);
|
|
370
494
|
const accepts = resolvedTokens.map((asset) => {
|
|
371
495
|
const decimals = resolveDecimals(config, asset);
|
|
@@ -373,7 +497,7 @@ function buildPaymentRequired(url, config, resolvedTokens) {
|
|
|
373
497
|
scheme: config.scheme ?? "exact",
|
|
374
498
|
network,
|
|
375
499
|
asset,
|
|
376
|
-
amount:
|
|
500
|
+
amount: priceInUnits(price, decimals, asset),
|
|
377
501
|
payTo: config.payTo,
|
|
378
502
|
maxTimeoutSeconds: config.maxTimeoutSeconds ?? DEFAULT_MAX_TIMEOUT_SECONDS,
|
|
379
503
|
extra: { decimals }
|
|
@@ -419,11 +543,11 @@ function resolveDeliveredAsset(header, config, resolvedTokens) {
|
|
|
419
543
|
const lower = target?.toLowerCase();
|
|
420
544
|
return resolvedTokens.find((token) => token.toLowerCase() === lower) ?? resolvedTokens[0];
|
|
421
545
|
}
|
|
422
|
-
function buildFacilitatorRequirements(config, asset) {
|
|
546
|
+
function buildFacilitatorRequirements(config, asset, price) {
|
|
423
547
|
const decimals = resolveDecimals(config, asset);
|
|
424
548
|
const scheme = config.scheme ?? "exact";
|
|
425
549
|
return {
|
|
426
|
-
maxAmountRequired:
|
|
550
|
+
maxAmountRequired: priceInUnits(price, decimals, asset),
|
|
427
551
|
asset,
|
|
428
552
|
payTo: config.payTo,
|
|
429
553
|
network: config.network,
|
|
@@ -434,8 +558,13 @@ function buildFacilitatorRequirements(config, asset) {
|
|
|
434
558
|
}
|
|
435
559
|
};
|
|
436
560
|
}
|
|
437
|
-
function paymentRequiredResponse(url, config, resolvedTokens, error) {
|
|
438
|
-
const paymentRequired = buildPaymentRequired(
|
|
561
|
+
function paymentRequiredResponse(url, config, resolvedTokens, price, error) {
|
|
562
|
+
const paymentRequired = buildPaymentRequired(
|
|
563
|
+
url,
|
|
564
|
+
config,
|
|
565
|
+
resolvedTokens,
|
|
566
|
+
price
|
|
567
|
+
);
|
|
439
568
|
if (error) paymentRequired.error = error;
|
|
440
569
|
return {
|
|
441
570
|
status: 402,
|
|
@@ -463,6 +592,22 @@ function createPaymentGate(config) {
|
|
|
463
592
|
const routeConfig = matchRoute(adapter.getPath(), config.routes);
|
|
464
593
|
if (!routeConfig) return { type: "pass" };
|
|
465
594
|
const resolvedTokens = resolveAcceptedTokens(routeConfig);
|
|
595
|
+
let request = typeof routeConfig.price === "function" ? await requestContext(adapter) : void 0;
|
|
596
|
+
let price;
|
|
597
|
+
try {
|
|
598
|
+
price = await resolvePrice(routeConfig, request);
|
|
599
|
+
} catch (err) {
|
|
600
|
+
if (!isPriceRejection(err)) throw err;
|
|
601
|
+
const status = Number.isInteger(err.status) && err.status >= 400 && err.status <= 599 ? err.status : 400;
|
|
602
|
+
return {
|
|
603
|
+
type: "error",
|
|
604
|
+
result: {
|
|
605
|
+
status,
|
|
606
|
+
headers: { "Content-Type": "application/json" },
|
|
607
|
+
body: { error: err.code, message: err.message }
|
|
608
|
+
}
|
|
609
|
+
};
|
|
610
|
+
}
|
|
466
611
|
const paymentHeader = adapter.getHeader("payment-signature") ?? adapter.getHeader("x-payment");
|
|
467
612
|
if (!paymentHeader) {
|
|
468
613
|
return {
|
|
@@ -470,7 +615,8 @@ function createPaymentGate(config) {
|
|
|
470
615
|
result: paymentRequiredResponse(
|
|
471
616
|
adapter.getUrl(),
|
|
472
617
|
routeConfig,
|
|
473
|
-
resolvedTokens
|
|
618
|
+
resolvedTokens,
|
|
619
|
+
price
|
|
474
620
|
)
|
|
475
621
|
};
|
|
476
622
|
}
|
|
@@ -479,7 +625,11 @@ function createPaymentGate(config) {
|
|
|
479
625
|
routeConfig,
|
|
480
626
|
resolvedTokens
|
|
481
627
|
);
|
|
482
|
-
const requirements = buildFacilitatorRequirements(
|
|
628
|
+
const requirements = buildFacilitatorRequirements(
|
|
629
|
+
routeConfig,
|
|
630
|
+
asset,
|
|
631
|
+
price
|
|
632
|
+
);
|
|
483
633
|
try {
|
|
484
634
|
await client.verify(paymentHeader, requirements);
|
|
485
635
|
} catch (e) {
|
|
@@ -490,10 +640,12 @@ function createPaymentGate(config) {
|
|
|
490
640
|
adapter.getUrl(),
|
|
491
641
|
routeConfig,
|
|
492
642
|
resolvedTokens,
|
|
643
|
+
price,
|
|
493
644
|
code
|
|
494
645
|
)
|
|
495
646
|
};
|
|
496
647
|
}
|
|
648
|
+
if (routeConfig.meter && !request) request = await requestContext(adapter);
|
|
497
649
|
return {
|
|
498
650
|
type: "verified",
|
|
499
651
|
scheme: routeConfig.scheme ?? "exact",
|
|
@@ -501,7 +653,8 @@ function createPaymentGate(config) {
|
|
|
501
653
|
decimals: resolveDecimals(routeConfig, asset),
|
|
502
654
|
handlerTimeoutMs: handlerTimeoutFor(routeConfig),
|
|
503
655
|
// Exact routes keep the historical two-argument client call.
|
|
504
|
-
settle: (options) => options ? client.settle(paymentHeader, requirements, options) : client.settle(paymentHeader, requirements)
|
|
656
|
+
settle: (options) => options ? client.settle(paymentHeader, requirements, options) : client.settle(paymentHeader, requirements),
|
|
657
|
+
...routeConfig.meter && { meter: routeConfig.meter, request }
|
|
505
658
|
};
|
|
506
659
|
};
|
|
507
660
|
}
|
|
@@ -527,17 +680,17 @@ function createPaymentMiddleware(config) {
|
|
|
527
680
|
if (handlerResult.status >= 200 && handlerResult.status < 300) {
|
|
528
681
|
let settleOptions;
|
|
529
682
|
if (gateResult.scheme === "upto") {
|
|
530
|
-
const resolved =
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
);
|
|
683
|
+
const resolved = await resolveCharge(gateResult, raw, {
|
|
684
|
+
status: handlerResult.status,
|
|
685
|
+
header: (name) => handlerResult.getResponseHeader?.(name),
|
|
686
|
+
body: async () => handlerResult.getResponseBody?.()
|
|
687
|
+
});
|
|
535
688
|
if (resolved.kind === "invalid") {
|
|
536
689
|
handlerResult.discardResponse();
|
|
537
690
|
return {
|
|
538
691
|
status: 402,
|
|
539
692
|
headers: { "Content-Type": "application/json" },
|
|
540
|
-
body:
|
|
693
|
+
body: invalidSettleAmountResponse(resolved.reason)
|
|
541
694
|
};
|
|
542
695
|
}
|
|
543
696
|
if (resolved.kind === "skip") {
|
|
@@ -579,4 +732,4 @@ function createPaymentMiddleware(config) {
|
|
|
579
732
|
};
|
|
580
733
|
}
|
|
581
734
|
|
|
582
|
-
export { FacilitatorClient, HANDLER_TIMEOUT,
|
|
735
|
+
export { FacilitatorClient, HANDLER_TIMEOUT, PARALLEL_TOKENS, SETTLE_AMOUNT_HEADER, createPaymentGate, createPaymentMiddleware, encodeBase64, getDefaultAcceptedTokens, invalidSettleAmountResponse, isJsonContentType, jsonFromResponse, matchRoute, parseJsonBody, parsePrice, raceTimeout, resolveCharge, resolveSettleAmount, toEip155Network, validateAddress };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var X402_ERROR_CODES = {
|
|
3
|
+
FACILITATOR_UNAVAILABLE: "FACILITATOR_UNAVAILABLE",
|
|
4
|
+
FACILITATOR_INVALID_RESPONSE: "FACILITATOR_INVALID_RESPONSE",
|
|
5
|
+
INVALID_PAYMENT: "INVALID_PAYMENT"
|
|
6
|
+
};
|
|
7
|
+
var X402ConfigError = class extends Error {
|
|
8
|
+
constructor(message, cause) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "X402ConfigError";
|
|
11
|
+
this.cause = cause;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
var X402RuntimeError = class extends Error {
|
|
15
|
+
constructor(code) {
|
|
16
|
+
super(code);
|
|
17
|
+
this.code = code;
|
|
18
|
+
this.name = "X402RuntimeError";
|
|
19
|
+
}
|
|
20
|
+
code;
|
|
21
|
+
};
|
|
22
|
+
var X402PriceRejectedError = class extends Error {
|
|
23
|
+
constructor(code, message, status = 400) {
|
|
24
|
+
super(message);
|
|
25
|
+
this.code = code;
|
|
26
|
+
this.status = status;
|
|
27
|
+
this.name = "X402PriceRejectedError";
|
|
28
|
+
}
|
|
29
|
+
code;
|
|
30
|
+
status;
|
|
31
|
+
};
|
|
32
|
+
function isPriceRejection(error) {
|
|
33
|
+
return error instanceof Error && error.name === "X402PriceRejectedError" && typeof error.code === "string";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export { X402ConfigError, X402PriceRejectedError, X402RuntimeError, X402_ERROR_CODES, isPriceRejection };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/errors.ts
|
|
4
|
+
var X402_ERROR_CODES = {
|
|
5
|
+
FACILITATOR_UNAVAILABLE: "FACILITATOR_UNAVAILABLE",
|
|
6
|
+
FACILITATOR_INVALID_RESPONSE: "FACILITATOR_INVALID_RESPONSE",
|
|
7
|
+
INVALID_PAYMENT: "INVALID_PAYMENT"
|
|
8
|
+
};
|
|
9
|
+
var X402ConfigError = class extends Error {
|
|
10
|
+
constructor(message, cause) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = "X402ConfigError";
|
|
13
|
+
this.cause = cause;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
var X402RuntimeError = class extends Error {
|
|
17
|
+
constructor(code) {
|
|
18
|
+
super(code);
|
|
19
|
+
this.code = code;
|
|
20
|
+
this.name = "X402RuntimeError";
|
|
21
|
+
}
|
|
22
|
+
code;
|
|
23
|
+
};
|
|
24
|
+
var X402PriceRejectedError = class extends Error {
|
|
25
|
+
constructor(code, message, status = 400) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.code = code;
|
|
28
|
+
this.status = status;
|
|
29
|
+
this.name = "X402PriceRejectedError";
|
|
30
|
+
}
|
|
31
|
+
code;
|
|
32
|
+
status;
|
|
33
|
+
};
|
|
34
|
+
function isPriceRejection(error) {
|
|
35
|
+
return error instanceof Error && error.name === "X402PriceRejectedError" && typeof error.code === "string";
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
exports.X402ConfigError = X402ConfigError;
|
|
39
|
+
exports.X402PriceRejectedError = X402PriceRejectedError;
|
|
40
|
+
exports.X402RuntimeError = X402RuntimeError;
|
|
41
|
+
exports.X402_ERROR_CODES = X402_ERROR_CODES;
|
|
42
|
+
exports.isPriceRejection = isPriceRejection;
|