@parallel-protocol/x402 0.10.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 +20 -10
- package/dist/{chunk-KZZY5LS6.cjs → chunk-4CEMNRCZ.cjs} +2 -0
- package/dist/{chunk-MYCUOJ3H.cjs → chunk-AYMDIX7A.cjs} +223 -53
- package/dist/{chunk-VSNDEQGS.js → chunk-CNASNROQ.js} +181 -16
- 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-BWL9h1eY.d.cts → types-CRBMTQaq.d.cts} +12 -0
- package/dist/{types-BWL9h1eY.d.ts → types-CRBMTQaq.d.ts} +12 -0
- package/package.json +2 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { X402_ERROR_CODES, X402ConfigError, X402RuntimeError, isPriceRejection } from './chunk-
|
|
1
|
+
import { X402_ERROR_CODES, X402ConfigError, X402RuntimeError, isPriceRejection } from './chunk-MZCHBBUN.js';
|
|
2
2
|
import { isKnownChain, isActiveParallelizerChain, ACTIVE_PARALLELIZER_CHAINS, getUptoEscrowAddress, getTokenDecimals as getTokenDecimals$1 } from '@parallel-protocol/chains';
|
|
3
3
|
import { permit2NonceToBytes32 } from '@parallel-protocol/payment-core';
|
|
4
4
|
import { z } from 'zod';
|
|
@@ -114,18 +114,144 @@ function encodeBase64(obj) {
|
|
|
114
114
|
function decodeBase64(str) {
|
|
115
115
|
return JSON.parse(Buffer.from(str, "base64").toString("utf8"));
|
|
116
116
|
}
|
|
117
|
-
|
|
118
|
-
if
|
|
117
|
+
var CONDITIONAL_HEADERS = [
|
|
118
|
+
"if-match",
|
|
119
|
+
"if-none-match",
|
|
120
|
+
"if-modified-since",
|
|
121
|
+
"if-unmodified-since"
|
|
122
|
+
];
|
|
123
|
+
function dropConditionalHeaders(headers) {
|
|
124
|
+
for (const name of CONDITIONAL_HEADERS) delete headers[name];
|
|
125
|
+
}
|
|
126
|
+
var UTF8 = new TextDecoder();
|
|
127
|
+
var DECODE_ROUNDS = 8;
|
|
128
|
+
function decodePercent(path) {
|
|
129
|
+
try {
|
|
130
|
+
return decodeURIComponent(path);
|
|
131
|
+
} catch {
|
|
132
|
+
return path.replace(
|
|
133
|
+
/(?:%[\da-f]{2})+/gi,
|
|
134
|
+
(run) => UTF8.decode(
|
|
135
|
+
Uint8Array.from(
|
|
136
|
+
run.slice(1).split("%"),
|
|
137
|
+
(hex) => Number.parseInt(hex, 16)
|
|
138
|
+
)
|
|
139
|
+
)
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function hasLongMarkRun(segment) {
|
|
144
|
+
for (const [run] of segment.matchAll(/\p{M}+/gu))
|
|
145
|
+
if (run.length > 8) return true;
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
function foldCase(segment) {
|
|
149
|
+
const composed = hasLongMarkRun(segment) ? segment : segment.normalize("NFC");
|
|
150
|
+
return composed.toLowerCase().toUpperCase().toLowerCase();
|
|
151
|
+
}
|
|
152
|
+
function pathSegments(path) {
|
|
153
|
+
let decoded = path;
|
|
154
|
+
for (let round = 0; round < DECODE_ROUNDS && decoded.includes("%"); round++) {
|
|
155
|
+
const next = decodePercent(decoded);
|
|
156
|
+
if (next === decoded) break;
|
|
157
|
+
decoded = next;
|
|
158
|
+
}
|
|
159
|
+
const target = decoded.replaceAll("\\", "/").replace(/^[a-z][\d+.a-z-]*:\/\/[^/]*/i, "").split(/[?#]/, 1)[0] ?? "";
|
|
160
|
+
return target.split("/").map((segment) => foldCase(segment).split(";", 1)[0] ?? "").filter((segment) => segment !== "");
|
|
161
|
+
}
|
|
162
|
+
function resolveDots(segments) {
|
|
163
|
+
const resolved = [];
|
|
164
|
+
for (const segment of segments) {
|
|
165
|
+
if (segment === "..") resolved.pop();
|
|
166
|
+
else if (segment !== ".") resolved.push(segment);
|
|
167
|
+
}
|
|
168
|
+
return resolved;
|
|
169
|
+
}
|
|
170
|
+
function normalizeRoutePath(path) {
|
|
171
|
+
return `/${resolveDots(pathSegments(path)).join("/")}`;
|
|
172
|
+
}
|
|
173
|
+
function routeTable(routes) {
|
|
174
|
+
return Object.entries(routes).map(([key, route]) => [
|
|
175
|
+
normalizeRoutePath(key),
|
|
176
|
+
route
|
|
177
|
+
]);
|
|
178
|
+
}
|
|
179
|
+
function longestMatch(target, table) {
|
|
119
180
|
let bestMatch;
|
|
120
181
|
let bestLength = 0;
|
|
121
|
-
for (const [
|
|
122
|
-
if (
|
|
123
|
-
|
|
124
|
-
|
|
182
|
+
for (const [key, route] of table) {
|
|
183
|
+
if (key === target) return route;
|
|
184
|
+
if (target.startsWith(`${key}/`) && key.length > bestLength) {
|
|
185
|
+
bestMatch = route;
|
|
186
|
+
bestLength = key.length;
|
|
125
187
|
}
|
|
126
188
|
}
|
|
127
189
|
return bestMatch;
|
|
128
190
|
}
|
|
191
|
+
function findRoute(path, table) {
|
|
192
|
+
const segments = pathSegments(path);
|
|
193
|
+
const dotSegments = segments.some(
|
|
194
|
+
(segment) => segment === "." || segment === ".."
|
|
195
|
+
);
|
|
196
|
+
const routePath = `/${resolveDots(segments).join("/")}`;
|
|
197
|
+
const route = longestMatch(routePath, table) ?? (dotSegments ? longestMatch(`/${segments.join("/")}`, table) : void 0);
|
|
198
|
+
return { route, dotSegments, routePath };
|
|
199
|
+
}
|
|
200
|
+
function isPreflightHeader(name) {
|
|
201
|
+
return /^(?:access-control-|vary$|allow$)/i.test(String(name));
|
|
202
|
+
}
|
|
203
|
+
function preflightHeaders(headers) {
|
|
204
|
+
if (Array.isArray(headers)) {
|
|
205
|
+
if (Array.isArray(headers[0]))
|
|
206
|
+
return headers.filter((pair) => isPreflightHeader(pair[0]));
|
|
207
|
+
return headers.flatMap(
|
|
208
|
+
(item, i) => i % 2 === 0 && isPreflightHeader(item) ? [item, headers[i + 1]] : []
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
if (headers !== null && typeof headers === "object")
|
|
212
|
+
return Object.fromEntries(
|
|
213
|
+
Object.entries(headers).filter(([name]) => isPreflightHeader(name))
|
|
214
|
+
);
|
|
215
|
+
return headers;
|
|
216
|
+
}
|
|
217
|
+
function answerAsPreflight(res) {
|
|
218
|
+
const writeHead = res.writeHead.bind(res);
|
|
219
|
+
const end = res.end.bind(res);
|
|
220
|
+
const callbackOf = (args) => args.find((arg) => typeof arg === "function");
|
|
221
|
+
const dropOtherHeaders = () => {
|
|
222
|
+
for (const name of res.getHeaderNames())
|
|
223
|
+
if (!isPreflightHeader(name)) res.removeHeader(name);
|
|
224
|
+
};
|
|
225
|
+
res.writeHead = ((statusCode, ...rest) => {
|
|
226
|
+
dropOtherHeaders();
|
|
227
|
+
res.statusMessage = "";
|
|
228
|
+
const headers = rest.find((arg) => typeof arg !== "string");
|
|
229
|
+
return headers === void 0 ? writeHead(statusCode) : writeHead(statusCode, preflightHeaders(headers));
|
|
230
|
+
});
|
|
231
|
+
res.write = ((...args) => {
|
|
232
|
+
const done = callbackOf(args);
|
|
233
|
+
if (done) queueMicrotask(done);
|
|
234
|
+
return true;
|
|
235
|
+
});
|
|
236
|
+
res.end = ((...args) => {
|
|
237
|
+
if (!res.headersSent) dropOtherHeaders();
|
|
238
|
+
const done = callbackOf(args);
|
|
239
|
+
return done ? end(done) : end();
|
|
240
|
+
});
|
|
241
|
+
res.addTrailers = () => {
|
|
242
|
+
};
|
|
243
|
+
res.writeEarlyHints = ((_hints, done) => {
|
|
244
|
+
if (done) queueMicrotask(done);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
function preflightInit(res) {
|
|
248
|
+
res.body?.cancel().catch(() => {
|
|
249
|
+
});
|
|
250
|
+
const headers = new Headers();
|
|
251
|
+
for (const [name, value] of res.headers)
|
|
252
|
+
if (isPreflightHeader(name)) headers.append(name, value);
|
|
253
|
+
return { status: res.status, headers };
|
|
254
|
+
}
|
|
129
255
|
function permit2Extra(network, asset) {
|
|
130
256
|
const domain = USDC_EIP712_DOMAIN[network];
|
|
131
257
|
const escrow = getUptoEscrowAddress(network);
|
|
@@ -296,9 +422,31 @@ var routeConfigSchema = z.object({
|
|
|
296
422
|
(route) => route.scheme !== "upto" || !hasMixedDecimals(route.network, route.acceptedTokens) || typeof route.price !== "bigint" && route.decimals === void 0,
|
|
297
423
|
'An upto route that accepts tokens with different decimals needs a price like "0.01", not a bigint or an explicit decimals'
|
|
298
424
|
);
|
|
425
|
+
function sameValue(a, b) {
|
|
426
|
+
if (Object.is(a, b)) return true;
|
|
427
|
+
if (typeof a !== "object" || typeof b !== "object" || !a || !b) return false;
|
|
428
|
+
const entries = Object.entries(a);
|
|
429
|
+
return Array.isArray(a) === Array.isArray(b) && entries.length === Object.keys(b).length && entries.every(
|
|
430
|
+
([key, value]) => sameValue(value, b[key])
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
function consistentRoutePaths(routes, ctx) {
|
|
434
|
+
const keyByPath = /* @__PURE__ */ new Map();
|
|
435
|
+
for (const [key, route] of Object.entries(routes)) {
|
|
436
|
+
const path = normalizeRoutePath(key);
|
|
437
|
+
const other = keyByPath.get(path);
|
|
438
|
+
if (other === void 0) keyByPath.set(path, key);
|
|
439
|
+
else if (!sameValue(routes[other], route))
|
|
440
|
+
ctx.addIssue({
|
|
441
|
+
code: "custom",
|
|
442
|
+
path: [key],
|
|
443
|
+
message: `Same path as "${other}" once normalized, with another config: keep one of the two routes`
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
}
|
|
299
447
|
var paymentMiddlewareConfigSchema = z.object({
|
|
300
448
|
facilitator: facilitatorConfigSchema,
|
|
301
|
-
routes: z.record(z.string(), routeConfigSchema).refine((r) => Object.keys(r).length > 0, "At least one route is required")
|
|
449
|
+
routes: z.record(z.string(), routeConfigSchema).refine((r) => Object.keys(r).length > 0, "At least one route is required").superRefine(consistentRoutePaths)
|
|
302
450
|
});
|
|
303
451
|
var facilitatorResponseSchema = z.discriminatedUnion("success", [
|
|
304
452
|
z.object({
|
|
@@ -583,10 +731,11 @@ async function raceTimeout(promise, ms = HANDLER_TIMEOUT_MS) {
|
|
|
583
731
|
|
|
584
732
|
// src/middleware.ts
|
|
585
733
|
var PRICE_FORMAT = /^\d+(?:\.\d+)?$/;
|
|
586
|
-
async function requestContext(adapter) {
|
|
734
|
+
async function requestContext(adapter, routePath) {
|
|
587
735
|
return {
|
|
588
736
|
method: adapter.getMethod(),
|
|
589
737
|
path: adapter.getPath(),
|
|
738
|
+
routePath,
|
|
590
739
|
url: adapter.getUrl(),
|
|
591
740
|
header: (name) => adapter.getHeader(name),
|
|
592
741
|
body: adapter.getBody ? await adapter.getBody() : void 0
|
|
@@ -882,13 +1031,28 @@ function createPaymentGate(config) {
|
|
|
882
1031
|
);
|
|
883
1032
|
}
|
|
884
1033
|
const client = new FacilitatorClient(config.facilitator);
|
|
1034
|
+
const routes = routeTable(config.routes);
|
|
885
1035
|
return async (adapter) => {
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
1036
|
+
const path = adapter.getPath();
|
|
1037
|
+
const fullPath = adapter.getFullPath?.();
|
|
1038
|
+
let match = findRoute(path, routes);
|
|
1039
|
+
if (!match.route && fullPath !== void 0 && fullPath !== path)
|
|
1040
|
+
match = findRoute(fullPath, routes);
|
|
1041
|
+
const { route: routeConfig, dotSegments, routePath } = match;
|
|
889
1042
|
if (!routeConfig) return { type: "pass" };
|
|
1043
|
+
if (dotSegments) {
|
|
1044
|
+
return {
|
|
1045
|
+
type: "error",
|
|
1046
|
+
result: jsonResult(400, {
|
|
1047
|
+
error: X402_ERROR_CODES.INVALID_PATH,
|
|
1048
|
+
message: "A paid route is not served on a path with . or .. segments: send the path resolved"
|
|
1049
|
+
})
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
1052
|
+
if (adapter.getMethod().toUpperCase() === "OPTIONS")
|
|
1053
|
+
return { type: "pass", preflight: true };
|
|
890
1054
|
const resolvedTokens = resolveAcceptedTokens(routeConfig);
|
|
891
|
-
let request = typeof routeConfig.price === "function" ? await requestContext(adapter) : void 0;
|
|
1055
|
+
let request = typeof routeConfig.price === "function" ? await requestContext(adapter, routePath) : void 0;
|
|
892
1056
|
let price;
|
|
893
1057
|
try {
|
|
894
1058
|
price = await resolvePrice(routeConfig, request, resolvedTokens);
|
|
@@ -943,7 +1107,7 @@ function createPaymentGate(config) {
|
|
|
943
1107
|
};
|
|
944
1108
|
}
|
|
945
1109
|
const meter = routeConfig.meter && hasMixedDecimals(routeConfig.network, resolvedTokens) ? refusingBigints(routeConfig.meter) : routeConfig.meter;
|
|
946
|
-
if (meter && !request) request = await requestContext(adapter);
|
|
1110
|
+
if (meter && !request) request = await requestContext(adapter, routePath);
|
|
947
1111
|
return {
|
|
948
1112
|
type: "verified",
|
|
949
1113
|
scheme: routeConfig.scheme ?? "exact",
|
|
@@ -1025,7 +1189,8 @@ function createPaymentMiddleware(config) {
|
|
|
1025
1189
|
const gate = createPaymentGate(config);
|
|
1026
1190
|
return async (adapter) => {
|
|
1027
1191
|
const gateResult = await gate(adapter);
|
|
1028
|
-
if (gateResult.type === "pass")
|
|
1192
|
+
if (gateResult.type === "pass")
|
|
1193
|
+
return gateResult.preflight ? { pass: true, preflight: true } : { pass: true };
|
|
1029
1194
|
if (gateResult.type === "error") return gateResult.result;
|
|
1030
1195
|
let handlerResult;
|
|
1031
1196
|
try {
|
|
@@ -1077,4 +1242,4 @@ function createPaymentMiddleware(config) {
|
|
|
1077
1242
|
};
|
|
1078
1243
|
}
|
|
1079
1244
|
|
|
1080
|
-
export { FacilitatorClient, HANDLER_TIMEOUT, PARALLEL_TOKENS, SETTLE_AMOUNT_HEADER, createPaymentGate, createPaymentMiddleware, encodeBase64, getDefaultAcceptedTokens, invalidSettleAmountResponse, isJsonContentType, jsonFromResponse,
|
|
1245
|
+
export { FacilitatorClient, HANDLER_TIMEOUT, PARALLEL_TOKENS, SETTLE_AMOUNT_HEADER, answerAsPreflight, createPaymentGate, createPaymentMiddleware, dropConditionalHeaders, encodeBase64, findRoute, getDefaultAcceptedTokens, invalidSettleAmountResponse, isJsonContentType, jsonFromResponse, normalizeRoutePath, parseJsonBody, parsePrice, preflightInit, raceTimeout, resolveCharge, resolveSettleAmount, routeTable, settleVerified, settlementFailureResponse, toEip155Network, validateAddress };
|
|
@@ -3,6 +3,8 @@ var X402_ERROR_CODES = {
|
|
|
3
3
|
FACILITATOR_UNAVAILABLE: "FACILITATOR_UNAVAILABLE",
|
|
4
4
|
FACILITATOR_INVALID_RESPONSE: "FACILITATOR_INVALID_RESPONSE",
|
|
5
5
|
INVALID_PAYMENT: "INVALID_PAYMENT",
|
|
6
|
+
/** A path with `.` or `..` segments on a paid route, refused with 400. */
|
|
7
|
+
INVALID_PATH: "INVALID_PATH",
|
|
6
8
|
/** The facilitator did not answer a settle within the client's timeout: the payment may still settle. */
|
|
7
9
|
SETTLE_TIMEOUT: "SETTLE_TIMEOUT"
|
|
8
10
|
};
|
package/dist/express.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('./chunk-
|
|
3
|
+
var chunkAYMDIX7A_cjs = require('./chunk-AYMDIX7A.cjs');
|
|
4
|
+
require('./chunk-4CEMNRCZ.cjs');
|
|
5
5
|
|
|
6
6
|
// src/express/adapter.ts
|
|
7
7
|
function chunkBytes(args) {
|
|
@@ -56,6 +56,9 @@ var ExpressAdapter = class {
|
|
|
56
56
|
getPath() {
|
|
57
57
|
return this.req.path;
|
|
58
58
|
}
|
|
59
|
+
getFullPath() {
|
|
60
|
+
return this.req.baseUrl + this.req.path;
|
|
61
|
+
}
|
|
59
62
|
getUrl() {
|
|
60
63
|
return `${this.req.protocol}://${this.req.headers.host}${this.req.originalUrl}`;
|
|
61
64
|
}
|
|
@@ -67,9 +70,19 @@ var ExpressAdapter = class {
|
|
|
67
70
|
async runHandler(options) {
|
|
68
71
|
const res = this.res;
|
|
69
72
|
const next = this.next;
|
|
73
|
+
chunkAYMDIX7A_cjs.dropConditionalHeaders(this.req.headers);
|
|
70
74
|
const originalWriteHead = res.writeHead.bind(res);
|
|
71
75
|
const originalWrite = res.write.bind(res);
|
|
72
76
|
const originalEnd = res.end.bind(res);
|
|
77
|
+
const headersBefore = structuredClone(res.getHeaders());
|
|
78
|
+
const dropHandlerHeaders = () => {
|
|
79
|
+
for (const name of res.getHeaderNames())
|
|
80
|
+
if (!Object.hasOwn(headersBefore, name)) res.removeHeader(name);
|
|
81
|
+
for (const [name, value] of Object.entries(headersBefore))
|
|
82
|
+
if (value !== void 0) res.setHeader(name, value);
|
|
83
|
+
res.statusMessage = "";
|
|
84
|
+
};
|
|
85
|
+
const nodeWriters = Object.getPrototypeOf(res);
|
|
73
86
|
const buffered = [];
|
|
74
87
|
let settled = false;
|
|
75
88
|
let discarded = false;
|
|
@@ -108,8 +121,8 @@ var ExpressAdapter = class {
|
|
|
108
121
|
return originalEnd(...args);
|
|
109
122
|
});
|
|
110
123
|
next();
|
|
111
|
-
const outcome = await
|
|
112
|
-
if (outcome ===
|
|
124
|
+
const outcome = await chunkAYMDIX7A_cjs.raceTimeout(endPromise, options?.timeoutMs);
|
|
125
|
+
if (outcome === chunkAYMDIX7A_cjs.HANDLER_TIMEOUT) {
|
|
113
126
|
discarded = true;
|
|
114
127
|
return {
|
|
115
128
|
status: 504,
|
|
@@ -121,8 +134,17 @@ var ExpressAdapter = class {
|
|
|
121
134
|
},
|
|
122
135
|
sendResponse: () => {
|
|
123
136
|
if (res.headersSent) return;
|
|
124
|
-
|
|
125
|
-
|
|
137
|
+
dropHandlerHeaders();
|
|
138
|
+
nodeWriters.writeHead.call(res, 504, {
|
|
139
|
+
"Content-Type": "application/json",
|
|
140
|
+
"Content-Length": Buffer.byteLength(TIMEOUT_BODY)
|
|
141
|
+
});
|
|
142
|
+
nodeWriters.end.call(res, TIMEOUT_BODY, "utf8");
|
|
143
|
+
res.setHeader = (() => res);
|
|
144
|
+
res.setHeaders = (() => res);
|
|
145
|
+
res.appendHeader = (() => res);
|
|
146
|
+
res.removeHeader = () => {
|
|
147
|
+
};
|
|
126
148
|
},
|
|
127
149
|
discardResponse: () => {
|
|
128
150
|
}
|
|
@@ -146,7 +168,7 @@ var ExpressAdapter = class {
|
|
|
146
168
|
const chunk = chunkBytes(args);
|
|
147
169
|
if (chunk) bytes.push(chunk);
|
|
148
170
|
}
|
|
149
|
-
return
|
|
171
|
+
return chunkAYMDIX7A_cjs.parseJsonBody(
|
|
150
172
|
contentType,
|
|
151
173
|
Buffer.concat(bytes).toString("utf8")
|
|
152
174
|
);
|
|
@@ -162,7 +184,9 @@ var ExpressAdapter = class {
|
|
|
162
184
|
},
|
|
163
185
|
discardResponse: () => {
|
|
164
186
|
settled = true;
|
|
165
|
-
|
|
187
|
+
dropHandlerHeaders();
|
|
188
|
+
for (const name of ["writeHead", "write", "end"])
|
|
189
|
+
Reflect.deleteProperty(res, name);
|
|
166
190
|
}
|
|
167
191
|
};
|
|
168
192
|
}
|
|
@@ -170,11 +194,12 @@ var ExpressAdapter = class {
|
|
|
170
194
|
|
|
171
195
|
// src/express/index.ts
|
|
172
196
|
function paymentMiddleware(config) {
|
|
173
|
-
const middleware =
|
|
197
|
+
const middleware = chunkAYMDIX7A_cjs.createPaymentMiddleware(config);
|
|
174
198
|
return async (req, res, next) => {
|
|
175
199
|
const result = await middleware(new ExpressAdapter(req, res, next));
|
|
176
200
|
if ("pass" in result) {
|
|
177
201
|
if (result.handlerRan) return;
|
|
202
|
+
if (result.preflight) chunkAYMDIX7A_cjs.answerAsPreflight(res);
|
|
178
203
|
return next();
|
|
179
204
|
}
|
|
180
205
|
for (const [key, value] of Object.entries(result.headers)) {
|
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-CRBMTQaq.cjs';
|
|
3
3
|
import 'viem';
|
|
4
4
|
|
|
5
5
|
declare class ExpressAdapter implements HTTPAdapter {
|
|
@@ -10,6 +10,7 @@ declare class ExpressAdapter implements HTTPAdapter {
|
|
|
10
10
|
getHeader(name: string): string | undefined;
|
|
11
11
|
getMethod(): string;
|
|
12
12
|
getPath(): string;
|
|
13
|
+
getFullPath(): string;
|
|
13
14
|
getUrl(): string;
|
|
14
15
|
getBody(): Promise<unknown>;
|
|
15
16
|
runHandler(options?: RunHandlerOptions): Promise<RunHandlerResult>;
|
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-CRBMTQaq.js';
|
|
3
3
|
import 'viem';
|
|
4
4
|
|
|
5
5
|
declare class ExpressAdapter implements HTTPAdapter {
|
|
@@ -10,6 +10,7 @@ declare class ExpressAdapter implements HTTPAdapter {
|
|
|
10
10
|
getHeader(name: string): string | undefined;
|
|
11
11
|
getMethod(): string;
|
|
12
12
|
getPath(): string;
|
|
13
|
+
getFullPath(): string;
|
|
13
14
|
getUrl(): string;
|
|
14
15
|
getBody(): Promise<unknown>;
|
|
15
16
|
runHandler(options?: RunHandlerOptions): Promise<RunHandlerResult>;
|
package/dist/express.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { raceTimeout, HANDLER_TIMEOUT, parseJsonBody, createPaymentMiddleware } from './chunk-
|
|
2
|
-
import './chunk-
|
|
1
|
+
import { dropConditionalHeaders, raceTimeout, HANDLER_TIMEOUT, parseJsonBody, createPaymentMiddleware, answerAsPreflight } from './chunk-CNASNROQ.js';
|
|
2
|
+
import './chunk-MZCHBBUN.js';
|
|
3
3
|
|
|
4
4
|
// src/express/adapter.ts
|
|
5
5
|
function chunkBytes(args) {
|
|
@@ -54,6 +54,9 @@ var ExpressAdapter = class {
|
|
|
54
54
|
getPath() {
|
|
55
55
|
return this.req.path;
|
|
56
56
|
}
|
|
57
|
+
getFullPath() {
|
|
58
|
+
return this.req.baseUrl + this.req.path;
|
|
59
|
+
}
|
|
57
60
|
getUrl() {
|
|
58
61
|
return `${this.req.protocol}://${this.req.headers.host}${this.req.originalUrl}`;
|
|
59
62
|
}
|
|
@@ -65,9 +68,19 @@ var ExpressAdapter = class {
|
|
|
65
68
|
async runHandler(options) {
|
|
66
69
|
const res = this.res;
|
|
67
70
|
const next = this.next;
|
|
71
|
+
dropConditionalHeaders(this.req.headers);
|
|
68
72
|
const originalWriteHead = res.writeHead.bind(res);
|
|
69
73
|
const originalWrite = res.write.bind(res);
|
|
70
74
|
const originalEnd = res.end.bind(res);
|
|
75
|
+
const headersBefore = structuredClone(res.getHeaders());
|
|
76
|
+
const dropHandlerHeaders = () => {
|
|
77
|
+
for (const name of res.getHeaderNames())
|
|
78
|
+
if (!Object.hasOwn(headersBefore, name)) res.removeHeader(name);
|
|
79
|
+
for (const [name, value] of Object.entries(headersBefore))
|
|
80
|
+
if (value !== void 0) res.setHeader(name, value);
|
|
81
|
+
res.statusMessage = "";
|
|
82
|
+
};
|
|
83
|
+
const nodeWriters = Object.getPrototypeOf(res);
|
|
71
84
|
const buffered = [];
|
|
72
85
|
let settled = false;
|
|
73
86
|
let discarded = false;
|
|
@@ -119,8 +132,17 @@ var ExpressAdapter = class {
|
|
|
119
132
|
},
|
|
120
133
|
sendResponse: () => {
|
|
121
134
|
if (res.headersSent) return;
|
|
122
|
-
|
|
123
|
-
|
|
135
|
+
dropHandlerHeaders();
|
|
136
|
+
nodeWriters.writeHead.call(res, 504, {
|
|
137
|
+
"Content-Type": "application/json",
|
|
138
|
+
"Content-Length": Buffer.byteLength(TIMEOUT_BODY)
|
|
139
|
+
});
|
|
140
|
+
nodeWriters.end.call(res, TIMEOUT_BODY, "utf8");
|
|
141
|
+
res.setHeader = (() => res);
|
|
142
|
+
res.setHeaders = (() => res);
|
|
143
|
+
res.appendHeader = (() => res);
|
|
144
|
+
res.removeHeader = () => {
|
|
145
|
+
};
|
|
124
146
|
},
|
|
125
147
|
discardResponse: () => {
|
|
126
148
|
}
|
|
@@ -160,7 +182,9 @@ var ExpressAdapter = class {
|
|
|
160
182
|
},
|
|
161
183
|
discardResponse: () => {
|
|
162
184
|
settled = true;
|
|
163
|
-
|
|
185
|
+
dropHandlerHeaders();
|
|
186
|
+
for (const name of ["writeHead", "write", "end"])
|
|
187
|
+
Reflect.deleteProperty(res, name);
|
|
164
188
|
}
|
|
165
189
|
};
|
|
166
190
|
}
|
|
@@ -173,6 +197,7 @@ function paymentMiddleware(config) {
|
|
|
173
197
|
const result = await middleware(new ExpressAdapter(req, res, next));
|
|
174
198
|
if ("pass" in result) {
|
|
175
199
|
if (result.handlerRan) return;
|
|
200
|
+
if (result.preflight) answerAsPreflight(res);
|
|
176
201
|
return next();
|
|
177
202
|
}
|
|
178
203
|
for (const [key, value] of Object.entries(result.headers)) {
|
package/dist/fastify.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('./chunk-
|
|
3
|
+
var chunkAYMDIX7A_cjs = require('./chunk-AYMDIX7A.cjs');
|
|
4
|
+
require('./chunk-4CEMNRCZ.cjs');
|
|
5
5
|
var fp = require('fastify-plugin');
|
|
6
6
|
|
|
7
7
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -37,9 +37,39 @@ var FastifyAdapter = class {
|
|
|
37
37
|
// src/fastify/index.ts
|
|
38
38
|
function payloadJson(contentType, payload) {
|
|
39
39
|
const text = typeof payload === "string" ? payload : payload instanceof Uint8Array ? Buffer.from(payload).toString("utf8") : void 0;
|
|
40
|
-
return
|
|
40
|
+
return chunkAYMDIX7A_cjs.parseJsonBody(contentType, text);
|
|
41
41
|
}
|
|
42
|
-
function
|
|
42
|
+
function keepCookiesBefore(reply, cookies) {
|
|
43
|
+
const raw = reply.raw;
|
|
44
|
+
const writeHead = raw.writeHead;
|
|
45
|
+
raw.writeHead = ((...args) => {
|
|
46
|
+
for (const arg of args)
|
|
47
|
+
if (typeof arg === "object" && arg !== null && !Array.isArray(arg))
|
|
48
|
+
delete arg["set-cookie"];
|
|
49
|
+
raw.removeHeader("set-cookie");
|
|
50
|
+
if (cookies !== void 0) raw.setHeader("set-cookie", cookies);
|
|
51
|
+
return writeHead.apply(raw, args);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function release(payload) {
|
|
55
|
+
if (payload instanceof ReadableStream) payload.cancel().catch(() => {
|
|
56
|
+
});
|
|
57
|
+
else if (typeof payload?.destroy === "function")
|
|
58
|
+
payload.destroy();
|
|
59
|
+
}
|
|
60
|
+
function refuse(reply, result, before, payload) {
|
|
61
|
+
release(payload);
|
|
62
|
+
if (before) {
|
|
63
|
+
for (const name of Object.keys(reply.getHeaders()))
|
|
64
|
+
reply.removeHeader(name);
|
|
65
|
+
for (const [name, value] of Object.entries(before.headers))
|
|
66
|
+
if (value !== void 0) reply.header(name, value);
|
|
67
|
+
for (const name of before.trailers) reply.removeTrailer(name);
|
|
68
|
+
for (const name of ["writeHead", "write", "end"])
|
|
69
|
+
Reflect.deleteProperty(reply.raw, name);
|
|
70
|
+
keepCookiesBefore(reply, before.headers["set-cookie"]);
|
|
71
|
+
}
|
|
72
|
+
reply.raw.statusMessage = "";
|
|
43
73
|
const json = JSON.stringify(result.body);
|
|
44
74
|
reply.status(result.status);
|
|
45
75
|
for (const [name, value] of Object.entries(result.headers)) {
|
|
@@ -54,35 +84,51 @@ function headerValue(value) {
|
|
|
54
84
|
}
|
|
55
85
|
function paymentMiddleware(config) {
|
|
56
86
|
return fp__default.default(async (fastify) => {
|
|
57
|
-
const gate =
|
|
87
|
+
const gate = chunkAYMDIX7A_cjs.createPaymentGate(config);
|
|
58
88
|
const verifiedMap = /* @__PURE__ */ new WeakMap();
|
|
59
89
|
const rawWriters = /* @__PURE__ */ new WeakMap();
|
|
90
|
+
const replyBefore = /* @__PURE__ */ new WeakMap();
|
|
91
|
+
const routes = chunkAYMDIX7A_cjs.routeTable(config.routes);
|
|
92
|
+
const needsBodyByRequest = /* @__PURE__ */ new WeakMap();
|
|
60
93
|
const needsBody = (req) => {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
94
|
+
let needs = needsBodyByRequest.get(req);
|
|
95
|
+
if (needs === void 0) {
|
|
96
|
+
const { route } = chunkAYMDIX7A_cjs.findRoute(new FastifyAdapter(req).getPath(), routes);
|
|
97
|
+
needs = typeof route?.price === "function" || route?.meter !== void 0;
|
|
98
|
+
needsBodyByRequest.set(req, needs);
|
|
99
|
+
}
|
|
100
|
+
return needs;
|
|
66
101
|
};
|
|
67
102
|
fastify.addHook("onRequest", async (req, reply) => {
|
|
68
103
|
if (needsBody(req)) return;
|
|
69
|
-
|
|
104
|
+
return runGate(req, reply);
|
|
70
105
|
});
|
|
71
106
|
fastify.addHook("preHandler", async (req, reply) => {
|
|
72
107
|
if (!needsBody(req)) return;
|
|
73
|
-
|
|
108
|
+
return runGate(req, reply);
|
|
74
109
|
});
|
|
75
110
|
async function runGate(req, reply) {
|
|
76
111
|
const gateResult = await gate(new FastifyAdapter(req));
|
|
77
|
-
if (gateResult.type === "pass")
|
|
112
|
+
if (gateResult.type === "pass") {
|
|
113
|
+
if (gateResult.preflight) chunkAYMDIX7A_cjs.answerAsPreflight(reply.raw);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
78
116
|
if (gateResult.type === "error") {
|
|
79
117
|
for (const [key, value] of Object.entries(gateResult.result.headers)) {
|
|
80
118
|
reply.header(key, value);
|
|
81
119
|
}
|
|
82
|
-
reply.status(gateResult.result.status).send(gateResult.result.body);
|
|
83
|
-
return;
|
|
120
|
+
return reply.status(gateResult.result.status).send(gateResult.result.body);
|
|
84
121
|
}
|
|
85
122
|
verifiedMap.set(req, gateResult);
|
|
123
|
+
chunkAYMDIX7A_cjs.dropConditionalHeaders(req.headers);
|
|
124
|
+
const trailers = /* @__PURE__ */ new Set();
|
|
125
|
+
const headers = structuredClone(reply.getHeaders());
|
|
126
|
+
replyBefore.set(req, { headers, trailers });
|
|
127
|
+
const trailer = reply.trailer.bind(reply);
|
|
128
|
+
reply.trailer = ((name, fn) => {
|
|
129
|
+
trailers.add(name.toLowerCase());
|
|
130
|
+
return trailer(name, fn);
|
|
131
|
+
});
|
|
86
132
|
const raw = reply.raw;
|
|
87
133
|
rawWriters.set(req, {
|
|
88
134
|
write: raw.write,
|
|
@@ -111,29 +157,39 @@ function paymentMiddleware(config) {
|
|
|
111
157
|
if (!verified) return payload;
|
|
112
158
|
let raw;
|
|
113
159
|
if (verified.scheme === "upto") {
|
|
114
|
-
raw = headerValue(reply.getHeader(
|
|
115
|
-
reply.removeHeader(
|
|
160
|
+
raw = headerValue(reply.getHeader(chunkAYMDIX7A_cjs.SETTLE_AMOUNT_HEADER));
|
|
161
|
+
reply.removeHeader(chunkAYMDIX7A_cjs.SETTLE_AMOUNT_HEADER);
|
|
116
162
|
}
|
|
117
163
|
if (reply.statusCode < 200 || reply.statusCode >= 300) {
|
|
118
164
|
return payload;
|
|
119
165
|
}
|
|
120
166
|
let settleOptions;
|
|
121
167
|
if (verified.scheme === "upto") {
|
|
122
|
-
const resolved = await
|
|
168
|
+
const resolved = await chunkAYMDIX7A_cjs.resolveCharge(verified, raw, {
|
|
123
169
|
status: reply.statusCode,
|
|
124
170
|
header: (name) => headerValue(reply.getHeader(name)),
|
|
125
171
|
body: async () => payloadJson(headerValue(reply.getHeader("content-type")), payload)
|
|
126
172
|
});
|
|
127
173
|
if (resolved.kind === "invalid") {
|
|
128
|
-
return refuse(
|
|
174
|
+
return refuse(
|
|
175
|
+
reply,
|
|
176
|
+
chunkAYMDIX7A_cjs.invalidSettleAmountResponse(resolved.reason),
|
|
177
|
+
replyBefore.get(req),
|
|
178
|
+
payload
|
|
179
|
+
);
|
|
129
180
|
}
|
|
130
181
|
if (resolved.kind === "skip") return payload;
|
|
131
182
|
settleOptions = { amount: resolved.amount };
|
|
132
183
|
}
|
|
133
|
-
const outcome = await
|
|
184
|
+
const outcome = await chunkAYMDIX7A_cjs.settleVerified(verified, settleOptions);
|
|
134
185
|
if (!outcome.settled)
|
|
135
|
-
return refuse(
|
|
136
|
-
|
|
186
|
+
return refuse(
|
|
187
|
+
reply,
|
|
188
|
+
chunkAYMDIX7A_cjs.settlementFailureResponse(outcome),
|
|
189
|
+
replyBefore.get(req),
|
|
190
|
+
payload
|
|
191
|
+
);
|
|
192
|
+
reply.header("payment-response", chunkAYMDIX7A_cjs.encodeBase64(outcome.confirmation));
|
|
137
193
|
reply.header("access-control-expose-headers", "payment-response");
|
|
138
194
|
return payload;
|
|
139
195
|
});
|
package/dist/fastify.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FastifyRequest, FastifyPluginAsync } from 'fastify';
|
|
2
|
-
import { H as HTTPAdapter, P as PaymentMiddlewareConfig } from './types-
|
|
2
|
+
import { H as HTTPAdapter, P as PaymentMiddlewareConfig } from './types-CRBMTQaq.cjs';
|
|
3
3
|
import 'viem';
|
|
4
4
|
|
|
5
5
|
declare class FastifyAdapter implements HTTPAdapter {
|
package/dist/fastify.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FastifyRequest, FastifyPluginAsync } from 'fastify';
|
|
2
|
-
import { H as HTTPAdapter, P as PaymentMiddlewareConfig } from './types-
|
|
2
|
+
import { H as HTTPAdapter, P as PaymentMiddlewareConfig } from './types-CRBMTQaq.js';
|
|
3
3
|
import 'viem';
|
|
4
4
|
|
|
5
5
|
declare class FastifyAdapter implements HTTPAdapter {
|