@parallel-protocol/x402 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +11 -1
|
@@ -1,29 +1,53 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkJPMK5YBU_cjs = require('./chunk-JPMK5YBU.cjs');
|
|
4
4
|
var chains = require('@parallel-protocol/chains');
|
|
5
|
+
var zod = require('zod');
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
7
|
+
var PARALLEL_TOKENS = {
|
|
8
|
+
ethereum: {
|
|
9
|
+
usdp: "0x9B3a8f7CEC208e247d97dEE13313690977e24459",
|
|
10
|
+
susdp: "0xd3a452B305C8285c0Dd7b8537665c734d3D279eF",
|
|
11
|
+
usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
12
|
+
frxUSD: "0xCAcd6fd266aF91b8AeD52aCCc382b4e165586E29",
|
|
13
|
+
sfrxUSD: "0xcf62F905562626CfcDD2261162a51fd02Fc9c5b6",
|
|
14
|
+
USDe: "0x4c9EDD5852cd905f086C759E8383e09bff1E68B3",
|
|
15
|
+
sUSDe: "0x9D39A5DE30e57443BfF2A8307A4256c8797A3497"
|
|
16
|
+
},
|
|
17
|
+
base: {
|
|
18
|
+
usdp: "0x76A9A0062ec6712b99B4f63bD2b4270185759dd5",
|
|
19
|
+
susdp: "0x472eD57b376fE400259FB28e5C46eB53f0E3e7E7",
|
|
20
|
+
usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
21
|
+
USDS: "0x820C137fa70C8691f0e44Dc420a5e53c168921Dc",
|
|
22
|
+
sUSDS: "0x5875eEE11Cf8398102FdAd704C9E96607675467a"
|
|
23
|
+
},
|
|
24
|
+
avalanche: {
|
|
25
|
+
usdp: "0x9eE1963f05553eF838604Dd39403be21ceF26AA4",
|
|
26
|
+
susdp: "0x9d92c21205383651610f90722131655a5b8ed3e0",
|
|
27
|
+
usdc: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
|
|
28
|
+
ygamiUSDC: "0x9fD32FD5e32C6B95483d36C5E724C5C5250Ce010"
|
|
29
|
+
},
|
|
30
|
+
hyperevm: {
|
|
31
|
+
usdp: "0xBE65F0F410A72BeC163dC65d46c83699e957D588",
|
|
32
|
+
susdp: "0x9B3a8f7CEC208e247d97dEE13313690977e24459",
|
|
33
|
+
usdc: "0xb88339cb7199b77e23db6e890353e22632ba630f",
|
|
34
|
+
USDe: "0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34",
|
|
35
|
+
sUSDe: "0x211Cc4DD073734dA055fbF44a2b4667d5E5fE5d2"
|
|
24
36
|
}
|
|
25
|
-
code;
|
|
26
37
|
};
|
|
38
|
+
function getDefaultAcceptedTokens(network) {
|
|
39
|
+
const entry = PARALLEL_TOKENS[network];
|
|
40
|
+
if (!entry) return void 0;
|
|
41
|
+
return [entry.usdp, entry.usdc, entry.susdp];
|
|
42
|
+
}
|
|
43
|
+
function getMeteredAcceptedTokens(network) {
|
|
44
|
+
const entry = PARALLEL_TOKENS[network];
|
|
45
|
+
if (!entry) return void 0;
|
|
46
|
+
return [entry.usdp];
|
|
47
|
+
}
|
|
48
|
+
function getTokenDecimals(network, address) {
|
|
49
|
+
return chains.getTokenDecimals(network, address);
|
|
50
|
+
}
|
|
27
51
|
|
|
28
52
|
// src/utils.ts
|
|
29
53
|
var EIP155_NETWORKS = {
|
|
@@ -47,6 +71,28 @@ function parsePrice(price, decimals = 18) {
|
|
|
47
71
|
`Invalid price format: "${price}". Expected "0.01" or a bigint.`
|
|
48
72
|
);
|
|
49
73
|
}
|
|
74
|
+
function isJsonContentType(contentType) {
|
|
75
|
+
return /^application\/(?:[\w.-]+\+)?json(?:\s*;.*)?$/i.test(
|
|
76
|
+
contentType?.trim() ?? ""
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
function parseJsonBody(contentType, text) {
|
|
80
|
+
if (text === void 0 || !isJsonContentType(contentType)) return void 0;
|
|
81
|
+
try {
|
|
82
|
+
return JSON.parse(text);
|
|
83
|
+
} catch {
|
|
84
|
+
return void 0;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async function jsonFromResponse(res) {
|
|
88
|
+
const contentType = res.headers.get("content-type") ?? void 0;
|
|
89
|
+
if (!isJsonContentType(contentType)) return void 0;
|
|
90
|
+
try {
|
|
91
|
+
return parseJsonBody(contentType, await res.clone().text());
|
|
92
|
+
} catch {
|
|
93
|
+
return void 0;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
50
96
|
function validateAddress(address) {
|
|
51
97
|
return /^0x[0-9a-fA-F]{40}$/.test(address);
|
|
52
98
|
}
|
|
@@ -76,7 +122,12 @@ var ethereumAddressSchema = zod.z.string().regex(/^0x[0-9a-fA-F]{40}$/, "Invalid
|
|
|
76
122
|
var txHashSchema = zod.z.string().regex(/^0x[0-9a-fA-F]{64}$/);
|
|
77
123
|
var priceSchema = zod.z.union([
|
|
78
124
|
zod.z.bigint().positive("Price must be greater than 0"),
|
|
79
|
-
zod.z.string().regex(/^\d+(?:\.\d+)?$/, 'Price must be in format "0.01"').refine((price) => Number(price) > 0, "Price must be greater than 0")
|
|
125
|
+
zod.z.string().regex(/^\d+(?:\.\d+)?$/, 'Price must be in format "0.01"').refine((price) => Number(price) > 0, "Price must be greater than 0"),
|
|
126
|
+
// A per-request price function; its return value is checked per request.
|
|
127
|
+
zod.z.custom(
|
|
128
|
+
(value) => typeof value === "function",
|
|
129
|
+
"Price must be a string, a bigint or a function of the request"
|
|
130
|
+
)
|
|
80
131
|
]);
|
|
81
132
|
var facilitatorConfigSchema = zod.z.object({
|
|
82
133
|
url: zod.z.string().refine((v) => URL.canParse(v), "Invalid facilitator URL"),
|
|
@@ -90,11 +141,25 @@ var routeConfigSchema = zod.z.object({
|
|
|
90
141
|
acceptedTokens: zod.z.array(ethereumAddressSchema).optional(),
|
|
91
142
|
description: zod.z.string().optional(),
|
|
92
143
|
scheme: zod.z.enum(["exact", "upto"]).optional(),
|
|
93
|
-
maxTimeoutSeconds: zod.z.number().int().positive().optional()
|
|
144
|
+
maxTimeoutSeconds: zod.z.number().int().positive().optional(),
|
|
145
|
+
meter: zod.z.custom(
|
|
146
|
+
(value) => typeof value === "function",
|
|
147
|
+
"meter must be a function of the response"
|
|
148
|
+
).optional()
|
|
94
149
|
}).refine(
|
|
150
|
+
(route) => route.meter === void 0 || route.scheme === "upto",
|
|
151
|
+
"meter only applies to upto routes"
|
|
152
|
+
).refine(
|
|
95
153
|
(route) => route.scheme !== "upto" || (route.maxTimeoutSeconds ?? 300) <= UPTO_MAX_TIMEOUT_SECONDS,
|
|
96
154
|
`maxTimeoutSeconds must be at most ${UPTO_MAX_TIMEOUT_SECONDS} on an upto route`
|
|
97
|
-
)
|
|
155
|
+
).refine((route) => {
|
|
156
|
+
if (route.scheme !== "upto" || !route.acceptedTokens?.length) return true;
|
|
157
|
+
const usdp = PARALLEL_TOKENS[route.network]?.usdp;
|
|
158
|
+
if (!usdp) return true;
|
|
159
|
+
return route.acceptedTokens.every(
|
|
160
|
+
(token) => token.toLowerCase() === usdp.toLowerCase()
|
|
161
|
+
);
|
|
162
|
+
}, "acceptedTokens on an upto route may only list the network's USDp");
|
|
98
163
|
var paymentMiddlewareConfigSchema = zod.z.object({
|
|
99
164
|
facilitator: facilitatorConfigSchema,
|
|
100
165
|
routes: zod.z.record(zod.z.string(), routeConfigSchema).refine((r) => Object.keys(r).length > 0, "At least one route is required")
|
|
@@ -144,7 +209,7 @@ function decodePaymentHeader(paymentHeader) {
|
|
|
144
209
|
try {
|
|
145
210
|
return decodeBase64(paymentHeader);
|
|
146
211
|
} catch {
|
|
147
|
-
throw new X402RuntimeError(X402_ERROR_CODES.INVALID_PAYMENT);
|
|
212
|
+
throw new chunkJPMK5YBU_cjs.X402RuntimeError(chunkJPMK5YBU_cjs.X402_ERROR_CODES.INVALID_PAYMENT);
|
|
148
213
|
}
|
|
149
214
|
}
|
|
150
215
|
var FacilitatorClient = class {
|
|
@@ -164,18 +229,18 @@ var FacilitatorClient = class {
|
|
|
164
229
|
});
|
|
165
230
|
if (!response.ok) {
|
|
166
231
|
const errorBody = await response.json().catch(() => null);
|
|
167
|
-
const code = errorBody?.error ?? X402_ERROR_CODES.FACILITATOR_UNAVAILABLE;
|
|
168
|
-
throw new X402RuntimeError(code);
|
|
232
|
+
const code = errorBody?.error ?? chunkJPMK5YBU_cjs.X402_ERROR_CODES.FACILITATOR_UNAVAILABLE;
|
|
233
|
+
throw new chunkJPMK5YBU_cjs.X402RuntimeError(code);
|
|
169
234
|
}
|
|
170
235
|
json = await response.json();
|
|
171
236
|
} catch (e) {
|
|
172
|
-
if (e instanceof X402RuntimeError) throw e;
|
|
173
|
-
throw new X402RuntimeError(X402_ERROR_CODES.FACILITATOR_UNAVAILABLE);
|
|
237
|
+
if (e instanceof chunkJPMK5YBU_cjs.X402RuntimeError) throw e;
|
|
238
|
+
throw new chunkJPMK5YBU_cjs.X402RuntimeError(chunkJPMK5YBU_cjs.X402_ERROR_CODES.FACILITATOR_UNAVAILABLE);
|
|
174
239
|
}
|
|
175
240
|
try {
|
|
176
241
|
verifyResponseSchema.parse(json);
|
|
177
242
|
} catch {
|
|
178
|
-
throw new X402RuntimeError(X402_ERROR_CODES.FACILITATOR_INVALID_RESPONSE);
|
|
243
|
+
throw new chunkJPMK5YBU_cjs.X402RuntimeError(chunkJPMK5YBU_cjs.X402_ERROR_CODES.FACILITATOR_INVALID_RESPONSE);
|
|
179
244
|
}
|
|
180
245
|
}
|
|
181
246
|
async settle(paymentHeader, paymentRequirements, options) {
|
|
@@ -203,8 +268,8 @@ var FacilitatorClient = class {
|
|
|
203
268
|
}
|
|
204
269
|
json = await response.json();
|
|
205
270
|
} catch (e) {
|
|
206
|
-
if (e instanceof X402RuntimeError) throw e;
|
|
207
|
-
throw new X402RuntimeError(X402_ERROR_CODES.FACILITATOR_UNAVAILABLE);
|
|
271
|
+
if (e instanceof chunkJPMK5YBU_cjs.X402RuntimeError) throw e;
|
|
272
|
+
throw new chunkJPMK5YBU_cjs.X402RuntimeError(chunkJPMK5YBU_cjs.X402_ERROR_CODES.FACILITATOR_UNAVAILABLE);
|
|
208
273
|
}
|
|
209
274
|
try {
|
|
210
275
|
const parsed = settleResponseSchema.parse(json);
|
|
@@ -226,7 +291,7 @@ var FacilitatorClient = class {
|
|
|
226
291
|
error: { code: parsed.error, message: parsed.message }
|
|
227
292
|
};
|
|
228
293
|
} catch {
|
|
229
|
-
throw new X402RuntimeError(X402_ERROR_CODES.FACILITATOR_INVALID_RESPONSE);
|
|
294
|
+
throw new chunkJPMK5YBU_cjs.X402RuntimeError(chunkJPMK5YBU_cjs.X402_ERROR_CODES.FACILITATOR_INVALID_RESPONSE);
|
|
230
295
|
}
|
|
231
296
|
}
|
|
232
297
|
async pay(paymentHeader) {
|
|
@@ -240,17 +305,17 @@ var FacilitatorClient = class {
|
|
|
240
305
|
signal: AbortSignal.timeout(FACILITATOR_TIMEOUT_MS)
|
|
241
306
|
});
|
|
242
307
|
if (!response.ok) {
|
|
243
|
-
throw new X402RuntimeError(X402_ERROR_CODES.FACILITATOR_UNAVAILABLE);
|
|
308
|
+
throw new chunkJPMK5YBU_cjs.X402RuntimeError(chunkJPMK5YBU_cjs.X402_ERROR_CODES.FACILITATOR_UNAVAILABLE);
|
|
244
309
|
}
|
|
245
310
|
json = await response.json();
|
|
246
311
|
} catch (e) {
|
|
247
|
-
if (e instanceof X402RuntimeError) throw e;
|
|
248
|
-
throw new X402RuntimeError(X402_ERROR_CODES.FACILITATOR_UNAVAILABLE);
|
|
312
|
+
if (e instanceof chunkJPMK5YBU_cjs.X402RuntimeError) throw e;
|
|
313
|
+
throw new chunkJPMK5YBU_cjs.X402RuntimeError(chunkJPMK5YBU_cjs.X402_ERROR_CODES.FACILITATOR_UNAVAILABLE);
|
|
249
314
|
}
|
|
250
315
|
try {
|
|
251
316
|
return facilitatorResponseSchema.parse(json);
|
|
252
317
|
} catch {
|
|
253
|
-
throw new X402RuntimeError(X402_ERROR_CODES.FACILITATOR_INVALID_RESPONSE);
|
|
318
|
+
throw new chunkJPMK5YBU_cjs.X402RuntimeError(chunkJPMK5YBU_cjs.X402_ERROR_CODES.FACILITATOR_INVALID_RESPONSE);
|
|
254
319
|
}
|
|
255
320
|
}
|
|
256
321
|
buildHeaders() {
|
|
@@ -279,47 +344,41 @@ async function raceTimeout(promise, ms = HANDLER_TIMEOUT_MS) {
|
|
|
279
344
|
clearTimeout(timer);
|
|
280
345
|
}
|
|
281
346
|
}
|
|
282
|
-
var PARALLEL_TOKENS = {
|
|
283
|
-
ethereum: {
|
|
284
|
-
usdp: "0x9B3a8f7CEC208e247d97dEE13313690977e24459",
|
|
285
|
-
susdp: "0xd3a452B305C8285c0Dd7b8537665c734d3D279eF",
|
|
286
|
-
usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
287
|
-
frxUSD: "0xCAcd6fd266aF91b8AeD52aCCc382b4e165586E29",
|
|
288
|
-
sfrxUSD: "0xcf62F905562626CfcDD2261162a51fd02Fc9c5b6",
|
|
289
|
-
USDe: "0x4c9EDD5852cd905f086C759E8383e09bff1E68B3",
|
|
290
|
-
sUSDe: "0x9D39A5DE30e57443BfF2A8307A4256c8797A3497"
|
|
291
|
-
},
|
|
292
|
-
base: {
|
|
293
|
-
usdp: "0x76A9A0062ec6712b99B4f63bD2b4270185759dd5",
|
|
294
|
-
susdp: "0x472eD57b376fE400259FB28e5C46eB53f0E3e7E7",
|
|
295
|
-
usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
296
|
-
USDS: "0x820C137fa70C8691f0e44Dc420a5e53c168921Dc",
|
|
297
|
-
sUSDS: "0x5875eEE11Cf8398102FdAd704C9E96607675467a"
|
|
298
|
-
},
|
|
299
|
-
avalanche: {
|
|
300
|
-
usdp: "0x9eE1963f05553eF838604Dd39403be21ceF26AA4",
|
|
301
|
-
susdp: "0x9d92c21205383651610f90722131655a5b8ed3e0",
|
|
302
|
-
usdc: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
|
|
303
|
-
ygamiUSDC: "0x9fD32FD5e32C6B95483d36C5E724C5C5250Ce010"
|
|
304
|
-
},
|
|
305
|
-
hyperevm: {
|
|
306
|
-
usdp: "0xBE65F0F410A72BeC163dC65d46c83699e957D588",
|
|
307
|
-
susdp: "0x9B3a8f7CEC208e247d97dEE13313690977e24459",
|
|
308
|
-
usdc: "0xb88339cb7199b77e23db6e890353e22632ba630f",
|
|
309
|
-
USDe: "0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34",
|
|
310
|
-
sUSDe: "0x211Cc4DD073734dA055fbF44a2b4667d5E5fE5d2"
|
|
311
|
-
}
|
|
312
|
-
};
|
|
313
|
-
function getDefaultAcceptedTokens(network) {
|
|
314
|
-
const entry = PARALLEL_TOKENS[network];
|
|
315
|
-
if (!entry) return void 0;
|
|
316
|
-
return [entry.usdp, entry.usdc, entry.susdp];
|
|
317
|
-
}
|
|
318
|
-
function getTokenDecimals(network, address) {
|
|
319
|
-
return chains.getTokenDecimals(network, address);
|
|
320
|
-
}
|
|
321
347
|
|
|
322
348
|
// src/middleware.ts
|
|
349
|
+
var PRICE_FORMAT = /^\d+(?:\.\d+)?$/;
|
|
350
|
+
async function requestContext(adapter) {
|
|
351
|
+
return {
|
|
352
|
+
method: adapter.getMethod(),
|
|
353
|
+
path: adapter.getPath(),
|
|
354
|
+
url: adapter.getUrl(),
|
|
355
|
+
header: (name) => adapter.getHeader(name),
|
|
356
|
+
body: adapter.getBody ? await adapter.getBody() : void 0
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
async function resolvePrice(config, ctx) {
|
|
360
|
+
if (typeof config.price !== "function") return config.price;
|
|
361
|
+
if (!ctx) throw new chunkJPMK5YBU_cjs.X402ConfigError("A price function needs the request");
|
|
362
|
+
let price;
|
|
363
|
+
try {
|
|
364
|
+
price = await config.price(ctx);
|
|
365
|
+
} catch (cause) {
|
|
366
|
+
if (chunkJPMK5YBU_cjs.isPriceRejection(cause)) throw cause;
|
|
367
|
+
throw new chunkJPMK5YBU_cjs.X402ConfigError(
|
|
368
|
+
`The price function of route "${config.network}${ctx.path}" threw`,
|
|
369
|
+
cause
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
const valid = typeof price === "bigint" ? price > 0n : typeof price === "string" && PRICE_FORMAT.test(price) && Number(price) > 0;
|
|
373
|
+
if (!valid) {
|
|
374
|
+
throw new chunkJPMK5YBU_cjs.X402ConfigError(
|
|
375
|
+
`The price function of route "${config.network}${ctx.path}" returned ${JSON.stringify(
|
|
376
|
+
typeof price === "bigint" ? price.toString() : price
|
|
377
|
+
)} \u2014 expected a positive amount like "0.01" or a bigint`
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
return price;
|
|
381
|
+
}
|
|
323
382
|
var SETTLE_AMOUNT_HEADER = "payment-settle-amount";
|
|
324
383
|
var DEFAULT_MAX_TIMEOUT_SECONDS = 300;
|
|
325
384
|
function handlerTimeoutFor(config) {
|
|
@@ -348,26 +407,91 @@ var INVALID_SETTLE_AMOUNT_RESPONSE = {
|
|
|
348
407
|
error: "INVALID_SETTLE_AMOUNT",
|
|
349
408
|
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.`
|
|
350
409
|
};
|
|
410
|
+
var INVALID_METER_RESPONSE = {
|
|
411
|
+
error: "INVALID_SETTLE_AMOUNT",
|
|
412
|
+
message: "The route's meter function failed or returned something that is not an amount; the response was discarded and nothing was charged."
|
|
413
|
+
};
|
|
414
|
+
function invalidSettleAmountResponse(reason) {
|
|
415
|
+
return reason === "meter" ? INVALID_METER_RESPONSE : INVALID_SETTLE_AMOUNT_RESPONSE;
|
|
416
|
+
}
|
|
417
|
+
var AMOUNT_FORMAT = /^\d+(?:\.\d+)?$/;
|
|
418
|
+
async function resolveCharge(verified, settleHeader, response) {
|
|
419
|
+
if (verified.meter) {
|
|
420
|
+
if (!verified.request) {
|
|
421
|
+
throw new chunkJPMK5YBU_cjs.X402ConfigError(
|
|
422
|
+
"A metered payment carries a meter but no request context"
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
let result;
|
|
426
|
+
try {
|
|
427
|
+
const body = await raceTimeout(
|
|
428
|
+
response.body(),
|
|
429
|
+
verified.handlerTimeoutMs
|
|
430
|
+
);
|
|
431
|
+
if (body === HANDLER_TIMEOUT) return { kind: "invalid", reason: "meter" };
|
|
432
|
+
result = await verified.meter({
|
|
433
|
+
status: response.status,
|
|
434
|
+
header: response.header,
|
|
435
|
+
body,
|
|
436
|
+
request: verified.request
|
|
437
|
+
});
|
|
438
|
+
} catch {
|
|
439
|
+
return { kind: "invalid", reason: "meter" };
|
|
440
|
+
}
|
|
441
|
+
if (result != null) {
|
|
442
|
+
let amount;
|
|
443
|
+
if (typeof result === "bigint") {
|
|
444
|
+
if (result < 0n) return { kind: "invalid", reason: "meter" };
|
|
445
|
+
amount = result;
|
|
446
|
+
} else if (typeof result === "string" && AMOUNT_FORMAT.test(result)) {
|
|
447
|
+
const fraction = result.split(".")[1] ?? "";
|
|
448
|
+
if (fraction.length > verified.decimals) {
|
|
449
|
+
return { kind: "invalid", reason: "meter" };
|
|
450
|
+
}
|
|
451
|
+
amount = parsePrice(result, verified.decimals);
|
|
452
|
+
} else {
|
|
453
|
+
return { kind: "invalid", reason: "meter" };
|
|
454
|
+
}
|
|
455
|
+
if (amount === 0n) return { kind: "skip" };
|
|
456
|
+
if (amount > verified.maxAmount) amount = verified.maxAmount;
|
|
457
|
+
return { kind: "settle", amount: amount.toString() };
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return resolveSettleAmount(
|
|
461
|
+
settleHeader,
|
|
462
|
+
verified.maxAmount,
|
|
463
|
+
verified.decimals
|
|
464
|
+
);
|
|
465
|
+
}
|
|
351
466
|
function resolveAcceptedTokens(config) {
|
|
352
467
|
if (config.acceptedTokens?.length) {
|
|
353
468
|
return config.acceptedTokens;
|
|
354
469
|
}
|
|
355
|
-
const defaults = getDefaultAcceptedTokens(config.network);
|
|
470
|
+
const defaults = config.scheme === "upto" ? getMeteredAcceptedTokens(config.network) : getDefaultAcceptedTokens(config.network);
|
|
356
471
|
if (defaults) return defaults;
|
|
357
|
-
throw new X402ConfigError(
|
|
472
|
+
throw new chunkJPMK5YBU_cjs.X402ConfigError(
|
|
358
473
|
`acceptedTokens is required for network "${config.network}" \u2014 no defaults available for this chain`
|
|
359
474
|
);
|
|
360
475
|
}
|
|
361
476
|
function resolveDecimals(config, asset) {
|
|
362
477
|
const decimals = config.decimals ?? getTokenDecimals(config.network, asset);
|
|
363
478
|
if (decimals === void 0) {
|
|
364
|
-
throw new X402ConfigError(
|
|
479
|
+
throw new chunkJPMK5YBU_cjs.X402ConfigError(
|
|
365
480
|
`Unknown decimals for token ${asset} on "${config.network}" \u2014 add it to the @parallel-protocol/chains catalog or set the route's \`decimals\` explicitly`
|
|
366
481
|
);
|
|
367
482
|
}
|
|
368
483
|
return decimals;
|
|
369
484
|
}
|
|
370
|
-
function
|
|
485
|
+
function priceInUnits(price, decimals, asset) {
|
|
486
|
+
const units = parsePrice(price, decimals);
|
|
487
|
+
if (units === 0n) {
|
|
488
|
+
throw new chunkJPMK5YBU_cjs.X402ConfigError(
|
|
489
|
+
`Price ${typeof price === "bigint" ? price.toString() : `"${price}"`} is below the precision of token ${asset} (${decimals} decimals)`
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
return units.toString();
|
|
493
|
+
}
|
|
494
|
+
function buildPaymentRequired(url, config, resolvedTokens, price) {
|
|
371
495
|
const network = toEip155Network(config.network);
|
|
372
496
|
const accepts = resolvedTokens.map((asset) => {
|
|
373
497
|
const decimals = resolveDecimals(config, asset);
|
|
@@ -375,7 +499,7 @@ function buildPaymentRequired(url, config, resolvedTokens) {
|
|
|
375
499
|
scheme: config.scheme ?? "exact",
|
|
376
500
|
network,
|
|
377
501
|
asset,
|
|
378
|
-
amount:
|
|
502
|
+
amount: priceInUnits(price, decimals, asset),
|
|
379
503
|
payTo: config.payTo,
|
|
380
504
|
maxTimeoutSeconds: config.maxTimeoutSeconds ?? DEFAULT_MAX_TIMEOUT_SECONDS,
|
|
381
505
|
extra: { decimals }
|
|
@@ -421,11 +545,11 @@ function resolveDeliveredAsset(header, config, resolvedTokens) {
|
|
|
421
545
|
const lower = target?.toLowerCase();
|
|
422
546
|
return resolvedTokens.find((token) => token.toLowerCase() === lower) ?? resolvedTokens[0];
|
|
423
547
|
}
|
|
424
|
-
function buildFacilitatorRequirements(config, asset) {
|
|
548
|
+
function buildFacilitatorRequirements(config, asset, price) {
|
|
425
549
|
const decimals = resolveDecimals(config, asset);
|
|
426
550
|
const scheme = config.scheme ?? "exact";
|
|
427
551
|
return {
|
|
428
|
-
maxAmountRequired:
|
|
552
|
+
maxAmountRequired: priceInUnits(price, decimals, asset),
|
|
429
553
|
asset,
|
|
430
554
|
payTo: config.payTo,
|
|
431
555
|
network: config.network,
|
|
@@ -436,8 +560,13 @@ function buildFacilitatorRequirements(config, asset) {
|
|
|
436
560
|
}
|
|
437
561
|
};
|
|
438
562
|
}
|
|
439
|
-
function paymentRequiredResponse(url, config, resolvedTokens, error) {
|
|
440
|
-
const paymentRequired = buildPaymentRequired(
|
|
563
|
+
function paymentRequiredResponse(url, config, resolvedTokens, price, error) {
|
|
564
|
+
const paymentRequired = buildPaymentRequired(
|
|
565
|
+
url,
|
|
566
|
+
config,
|
|
567
|
+
resolvedTokens,
|
|
568
|
+
price
|
|
569
|
+
);
|
|
441
570
|
if (error) paymentRequired.error = error;
|
|
442
571
|
return {
|
|
443
572
|
status: 402,
|
|
@@ -453,7 +582,7 @@ function createPaymentGate(config) {
|
|
|
453
582
|
try {
|
|
454
583
|
paymentMiddlewareConfigSchema.parse(config);
|
|
455
584
|
} catch (cause) {
|
|
456
|
-
throw new X402ConfigError(
|
|
585
|
+
throw new chunkJPMK5YBU_cjs.X402ConfigError(
|
|
457
586
|
"Invalid paymentMiddleware config \u2014 check your routes, facilitator URL and payTo addresses",
|
|
458
587
|
cause
|
|
459
588
|
);
|
|
@@ -465,6 +594,22 @@ function createPaymentGate(config) {
|
|
|
465
594
|
const routeConfig = matchRoute(adapter.getPath(), config.routes);
|
|
466
595
|
if (!routeConfig) return { type: "pass" };
|
|
467
596
|
const resolvedTokens = resolveAcceptedTokens(routeConfig);
|
|
597
|
+
let request = typeof routeConfig.price === "function" ? await requestContext(adapter) : void 0;
|
|
598
|
+
let price;
|
|
599
|
+
try {
|
|
600
|
+
price = await resolvePrice(routeConfig, request);
|
|
601
|
+
} catch (err) {
|
|
602
|
+
if (!chunkJPMK5YBU_cjs.isPriceRejection(err)) throw err;
|
|
603
|
+
const status = Number.isInteger(err.status) && err.status >= 400 && err.status <= 599 ? err.status : 400;
|
|
604
|
+
return {
|
|
605
|
+
type: "error",
|
|
606
|
+
result: {
|
|
607
|
+
status,
|
|
608
|
+
headers: { "Content-Type": "application/json" },
|
|
609
|
+
body: { error: err.code, message: err.message }
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
}
|
|
468
613
|
const paymentHeader = adapter.getHeader("payment-signature") ?? adapter.getHeader("x-payment");
|
|
469
614
|
if (!paymentHeader) {
|
|
470
615
|
return {
|
|
@@ -472,7 +617,8 @@ function createPaymentGate(config) {
|
|
|
472
617
|
result: paymentRequiredResponse(
|
|
473
618
|
adapter.getUrl(),
|
|
474
619
|
routeConfig,
|
|
475
|
-
resolvedTokens
|
|
620
|
+
resolvedTokens,
|
|
621
|
+
price
|
|
476
622
|
)
|
|
477
623
|
};
|
|
478
624
|
}
|
|
@@ -481,21 +627,27 @@ function createPaymentGate(config) {
|
|
|
481
627
|
routeConfig,
|
|
482
628
|
resolvedTokens
|
|
483
629
|
);
|
|
484
|
-
const requirements = buildFacilitatorRequirements(
|
|
630
|
+
const requirements = buildFacilitatorRequirements(
|
|
631
|
+
routeConfig,
|
|
632
|
+
asset,
|
|
633
|
+
price
|
|
634
|
+
);
|
|
485
635
|
try {
|
|
486
636
|
await client.verify(paymentHeader, requirements);
|
|
487
637
|
} catch (e) {
|
|
488
|
-
const code = e instanceof X402RuntimeError ? e.code : X402_ERROR_CODES.FACILITATOR_UNAVAILABLE;
|
|
638
|
+
const code = e instanceof chunkJPMK5YBU_cjs.X402RuntimeError ? e.code : chunkJPMK5YBU_cjs.X402_ERROR_CODES.FACILITATOR_UNAVAILABLE;
|
|
489
639
|
return {
|
|
490
640
|
type: "error",
|
|
491
641
|
result: paymentRequiredResponse(
|
|
492
642
|
adapter.getUrl(),
|
|
493
643
|
routeConfig,
|
|
494
644
|
resolvedTokens,
|
|
645
|
+
price,
|
|
495
646
|
code
|
|
496
647
|
)
|
|
497
648
|
};
|
|
498
649
|
}
|
|
650
|
+
if (routeConfig.meter && !request) request = await requestContext(adapter);
|
|
499
651
|
return {
|
|
500
652
|
type: "verified",
|
|
501
653
|
scheme: routeConfig.scheme ?? "exact",
|
|
@@ -503,7 +655,8 @@ function createPaymentGate(config) {
|
|
|
503
655
|
decimals: resolveDecimals(routeConfig, asset),
|
|
504
656
|
handlerTimeoutMs: handlerTimeoutFor(routeConfig),
|
|
505
657
|
// Exact routes keep the historical two-argument client call.
|
|
506
|
-
settle: (options) => options ? client.settle(paymentHeader, requirements, options) : client.settle(paymentHeader, requirements)
|
|
658
|
+
settle: (options) => options ? client.settle(paymentHeader, requirements, options) : client.settle(paymentHeader, requirements),
|
|
659
|
+
...routeConfig.meter && { meter: routeConfig.meter, request }
|
|
507
660
|
};
|
|
508
661
|
};
|
|
509
662
|
}
|
|
@@ -529,17 +682,17 @@ function createPaymentMiddleware(config) {
|
|
|
529
682
|
if (handlerResult.status >= 200 && handlerResult.status < 300) {
|
|
530
683
|
let settleOptions;
|
|
531
684
|
if (gateResult.scheme === "upto") {
|
|
532
|
-
const resolved =
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
);
|
|
685
|
+
const resolved = await resolveCharge(gateResult, raw, {
|
|
686
|
+
status: handlerResult.status,
|
|
687
|
+
header: (name) => handlerResult.getResponseHeader?.(name),
|
|
688
|
+
body: async () => handlerResult.getResponseBody?.()
|
|
689
|
+
});
|
|
537
690
|
if (resolved.kind === "invalid") {
|
|
538
691
|
handlerResult.discardResponse();
|
|
539
692
|
return {
|
|
540
693
|
status: 402,
|
|
541
694
|
headers: { "Content-Type": "application/json" },
|
|
542
|
-
body:
|
|
695
|
+
body: invalidSettleAmountResponse(resolved.reason)
|
|
543
696
|
};
|
|
544
697
|
}
|
|
545
698
|
if (resolved.kind === "skip") {
|
|
@@ -583,18 +736,20 @@ function createPaymentMiddleware(config) {
|
|
|
583
736
|
|
|
584
737
|
exports.FacilitatorClient = FacilitatorClient;
|
|
585
738
|
exports.HANDLER_TIMEOUT = HANDLER_TIMEOUT;
|
|
586
|
-
exports.INVALID_SETTLE_AMOUNT_RESPONSE = INVALID_SETTLE_AMOUNT_RESPONSE;
|
|
587
739
|
exports.PARALLEL_TOKENS = PARALLEL_TOKENS;
|
|
588
740
|
exports.SETTLE_AMOUNT_HEADER = SETTLE_AMOUNT_HEADER;
|
|
589
|
-
exports.X402ConfigError = X402ConfigError;
|
|
590
|
-
exports.X402RuntimeError = X402RuntimeError;
|
|
591
|
-
exports.X402_ERROR_CODES = X402_ERROR_CODES;
|
|
592
741
|
exports.createPaymentGate = createPaymentGate;
|
|
593
742
|
exports.createPaymentMiddleware = createPaymentMiddleware;
|
|
594
743
|
exports.encodeBase64 = encodeBase64;
|
|
595
744
|
exports.getDefaultAcceptedTokens = getDefaultAcceptedTokens;
|
|
745
|
+
exports.invalidSettleAmountResponse = invalidSettleAmountResponse;
|
|
746
|
+
exports.isJsonContentType = isJsonContentType;
|
|
747
|
+
exports.jsonFromResponse = jsonFromResponse;
|
|
748
|
+
exports.matchRoute = matchRoute;
|
|
749
|
+
exports.parseJsonBody = parseJsonBody;
|
|
596
750
|
exports.parsePrice = parsePrice;
|
|
597
751
|
exports.raceTimeout = raceTimeout;
|
|
752
|
+
exports.resolveCharge = resolveCharge;
|
|
598
753
|
exports.resolveSettleAmount = resolveSettleAmount;
|
|
599
754
|
exports.toEip155Network = toEip155Network;
|
|
600
755
|
exports.validateAddress = validateAddress;
|
package/dist/express.cjs
CHANGED
|
@@ -1,12 +1,38 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkPOU7EH3E_cjs = require('./chunk-POU7EH3E.cjs');
|
|
4
|
+
require('./chunk-JPMK5YBU.cjs');
|
|
4
5
|
|
|
5
6
|
// src/express/adapter.ts
|
|
7
|
+
function chunkBytes(args) {
|
|
8
|
+
const [chunk, encoding] = args;
|
|
9
|
+
if (typeof chunk === "string") {
|
|
10
|
+
return Buffer.from(
|
|
11
|
+
chunk,
|
|
12
|
+
typeof encoding === "string" ? encoding : "utf8"
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
if (chunk instanceof Uint8Array) return Buffer.from(chunk);
|
|
16
|
+
return void 0;
|
|
17
|
+
}
|
|
6
18
|
function headerValue(value) {
|
|
7
19
|
if (value === void 0) return void 0;
|
|
8
20
|
return Array.isArray(value) ? value[0] : String(value);
|
|
9
21
|
}
|
|
22
|
+
function writeHeadContentType(args) {
|
|
23
|
+
const headers = args.find((arg) => typeof arg === "object" && arg !== null);
|
|
24
|
+
if (!headers) return void 0;
|
|
25
|
+
if (Array.isArray(headers)) {
|
|
26
|
+
const index = headers.findIndex(
|
|
27
|
+
(entry, i) => i % 2 === 0 && typeof entry === "string" && entry.toLowerCase() === "content-type"
|
|
28
|
+
);
|
|
29
|
+
return index === -1 ? void 0 : headerValue(headers[index + 1]);
|
|
30
|
+
}
|
|
31
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
32
|
+
if (name.toLowerCase() === "content-type") return headerValue(value);
|
|
33
|
+
}
|
|
34
|
+
return void 0;
|
|
35
|
+
}
|
|
10
36
|
var TIMEOUT_BODY = JSON.stringify({
|
|
11
37
|
error: "HANDLER_TIMEOUT",
|
|
12
38
|
message: "The resource handler did not respond in time."
|
|
@@ -33,6 +59,11 @@ var ExpressAdapter = class {
|
|
|
33
59
|
getUrl() {
|
|
34
60
|
return `${this.req.protocol}://${this.req.headers.host}${this.req.originalUrl}`;
|
|
35
61
|
}
|
|
62
|
+
// Whatever a body parser mounted before this middleware left on `req.body`
|
|
63
|
+
// (`express.json()` for JSON); `undefined` when none ran.
|
|
64
|
+
async getBody() {
|
|
65
|
+
return this.req.body;
|
|
66
|
+
}
|
|
36
67
|
async runHandler(options) {
|
|
37
68
|
const res = this.res;
|
|
38
69
|
const next = this.next;
|
|
@@ -77,8 +108,8 @@ var ExpressAdapter = class {
|
|
|
77
108
|
return originalEnd(...args);
|
|
78
109
|
});
|
|
79
110
|
next();
|
|
80
|
-
const outcome = await
|
|
81
|
-
if (outcome ===
|
|
111
|
+
const outcome = await chunkPOU7EH3E_cjs.raceTimeout(endPromise, options?.timeoutMs);
|
|
112
|
+
if (outcome === chunkPOU7EH3E_cjs.HANDLER_TIMEOUT) {
|
|
82
113
|
discarded = true;
|
|
83
114
|
return {
|
|
84
115
|
status: 504,
|
|
@@ -102,6 +133,24 @@ var ExpressAdapter = class {
|
|
|
102
133
|
setResponseHeader: (name, value) => res.setHeader(name, value),
|
|
103
134
|
getResponseHeader: (name) => headerValue(res.getHeader(name)),
|
|
104
135
|
removeResponseHeader: (name) => res.removeHeader(name),
|
|
136
|
+
// The buffered chunks are the whole response: parse them when the
|
|
137
|
+
// handler declared JSON.
|
|
138
|
+
getResponseBody: async () => {
|
|
139
|
+
const bytes = [];
|
|
140
|
+
let contentType = headerValue(res.getHeader("content-type"));
|
|
141
|
+
for (const [method, args] of buffered) {
|
|
142
|
+
if (method === "writeHead") {
|
|
143
|
+
contentType ??= writeHeadContentType(args);
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
const chunk = chunkBytes(args);
|
|
147
|
+
if (chunk) bytes.push(chunk);
|
|
148
|
+
}
|
|
149
|
+
return chunkPOU7EH3E_cjs.parseJsonBody(
|
|
150
|
+
contentType,
|
|
151
|
+
Buffer.concat(bytes).toString("utf8")
|
|
152
|
+
);
|
|
153
|
+
},
|
|
105
154
|
sendResponse: () => {
|
|
106
155
|
settled = true;
|
|
107
156
|
restore();
|
|
@@ -121,7 +170,7 @@ var ExpressAdapter = class {
|
|
|
121
170
|
|
|
122
171
|
// src/express/index.ts
|
|
123
172
|
function paymentMiddleware(config) {
|
|
124
|
-
const middleware =
|
|
173
|
+
const middleware = chunkPOU7EH3E_cjs.createPaymentMiddleware(config);
|
|
125
174
|
return async (req, res, next) => {
|
|
126
175
|
const result = await middleware(new ExpressAdapter(req, res, next));
|
|
127
176
|
if ("pass" in result) {
|
package/dist/express.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Request, Response, NextFunction } from 'express';
|
|
2
|
-
import { H as HTTPAdapter, R as RunHandlerOptions, a as RunHandlerResult, P as PaymentMiddlewareConfig } from './types-
|
|
2
|
+
import { H as HTTPAdapter, R as RunHandlerOptions, a as RunHandlerResult, P as PaymentMiddlewareConfig } from './types-q_gu5wjz.cjs';
|
|
3
3
|
import 'viem';
|
|
4
4
|
|
|
5
5
|
declare class ExpressAdapter implements HTTPAdapter {
|
|
@@ -11,6 +11,7 @@ declare class ExpressAdapter implements HTTPAdapter {
|
|
|
11
11
|
getMethod(): string;
|
|
12
12
|
getPath(): string;
|
|
13
13
|
getUrl(): string;
|
|
14
|
+
getBody(): Promise<unknown>;
|
|
14
15
|
runHandler(options?: RunHandlerOptions): Promise<RunHandlerResult>;
|
|
15
16
|
}
|
|
16
17
|
|
package/dist/express.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Request, Response, NextFunction } from 'express';
|
|
2
|
-
import { H as HTTPAdapter, R as RunHandlerOptions, a as RunHandlerResult, P as PaymentMiddlewareConfig } from './types-
|
|
2
|
+
import { H as HTTPAdapter, R as RunHandlerOptions, a as RunHandlerResult, P as PaymentMiddlewareConfig } from './types-q_gu5wjz.js';
|
|
3
3
|
import 'viem';
|
|
4
4
|
|
|
5
5
|
declare class ExpressAdapter implements HTTPAdapter {
|
|
@@ -11,6 +11,7 @@ declare class ExpressAdapter implements HTTPAdapter {
|
|
|
11
11
|
getMethod(): string;
|
|
12
12
|
getPath(): string;
|
|
13
13
|
getUrl(): string;
|
|
14
|
+
getBody(): Promise<unknown>;
|
|
14
15
|
runHandler(options?: RunHandlerOptions): Promise<RunHandlerResult>;
|
|
15
16
|
}
|
|
16
17
|
|