@parallel-protocol/x402 0.5.3 → 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 +226 -6
- package/dist/{chunk-75GLDK7L.js → chunk-AENXD4OC.js} +338 -81
- package/dist/chunk-AFRDHGDT.js +36 -0
- package/dist/chunk-JPMK5YBU.cjs +42 -0
- package/dist/chunk-POU7EH3E.cjs +755 -0
- package/dist/express.cjs +63 -6
- package/dist/express.d.cts +3 -2
- package/dist/express.d.ts +3 -2
- package/dist/express.js +61 -4
- package/dist/fastify.cjs +88 -14
- package/dist/fastify.d.cts +2 -1
- package/dist/fastify.d.ts +2 -1
- package/dist/fastify.js +86 -12
- package/dist/hono.cjs +27 -6
- package/dist/hono.d.cts +3 -2
- package/dist/hono.d.ts +3 -2
- package/dist/hono.js +25 -4
- package/dist/index.cjs +41 -20
- package/dist/index.d.cts +64 -5
- package/dist/index.d.ts +64 -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 +57 -7
- package/dist/next.d.cts +2 -1
- package/dist/next.d.ts +2 -1
- package/dist/next.js +54 -4
- package/dist/types-q_gu5wjz.d.cts +185 -0
- package/dist/types-q_gu5wjz.d.ts +185 -0
- package/package.json +12 -2
- package/dist/chunk-2UEAVMCH.js +0 -17
- package/dist/chunk-KQPIZ6SZ.cjs +0 -491
- package/dist/chunk-XUNNMCO5.cjs +0 -20
- package/dist/types-CUi55YSx.d.cts +0 -95
- package/dist/types-CUi55YSx.d.ts +0 -95
package/dist/express.cjs
CHANGED
|
@@ -1,9 +1,38 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
|
|
3
|
+
var chunkPOU7EH3E_cjs = require('./chunk-POU7EH3E.cjs');
|
|
4
|
+
require('./chunk-JPMK5YBU.cjs');
|
|
5
5
|
|
|
6
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
|
+
}
|
|
18
|
+
function headerValue(value) {
|
|
19
|
+
if (value === void 0) return void 0;
|
|
20
|
+
return Array.isArray(value) ? value[0] : String(value);
|
|
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
|
+
}
|
|
7
36
|
var TIMEOUT_BODY = JSON.stringify({
|
|
8
37
|
error: "HANDLER_TIMEOUT",
|
|
9
38
|
message: "The resource handler did not respond in time."
|
|
@@ -30,7 +59,12 @@ var ExpressAdapter = class {
|
|
|
30
59
|
getUrl() {
|
|
31
60
|
return `${this.req.protocol}://${this.req.headers.host}${this.req.originalUrl}`;
|
|
32
61
|
}
|
|
33
|
-
|
|
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
|
+
}
|
|
67
|
+
async runHandler(options) {
|
|
34
68
|
const res = this.res;
|
|
35
69
|
const next = this.next;
|
|
36
70
|
const originalWriteHead = res.writeHead.bind(res);
|
|
@@ -74,14 +108,17 @@ var ExpressAdapter = class {
|
|
|
74
108
|
return originalEnd(...args);
|
|
75
109
|
});
|
|
76
110
|
next();
|
|
77
|
-
const outcome = await
|
|
78
|
-
if (outcome ===
|
|
111
|
+
const outcome = await chunkPOU7EH3E_cjs.raceTimeout(endPromise, options?.timeoutMs);
|
|
112
|
+
if (outcome === chunkPOU7EH3E_cjs.HANDLER_TIMEOUT) {
|
|
79
113
|
discarded = true;
|
|
80
114
|
return {
|
|
81
115
|
status: 504,
|
|
82
116
|
setResponseHeader: (name, value) => {
|
|
83
117
|
if (!res.headersSent) res.setHeader(name, value);
|
|
84
118
|
},
|
|
119
|
+
getResponseHeader: () => void 0,
|
|
120
|
+
removeResponseHeader: () => {
|
|
121
|
+
},
|
|
85
122
|
sendResponse: () => {
|
|
86
123
|
if (res.headersSent) return;
|
|
87
124
|
originalWriteHead(504, { "Content-Type": "application/json" });
|
|
@@ -94,6 +131,26 @@ var ExpressAdapter = class {
|
|
|
94
131
|
return {
|
|
95
132
|
status: res.statusCode,
|
|
96
133
|
setResponseHeader: (name, value) => res.setHeader(name, value),
|
|
134
|
+
getResponseHeader: (name) => headerValue(res.getHeader(name)),
|
|
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
|
+
},
|
|
97
154
|
sendResponse: () => {
|
|
98
155
|
settled = true;
|
|
99
156
|
restore();
|
|
@@ -113,7 +170,7 @@ var ExpressAdapter = class {
|
|
|
113
170
|
|
|
114
171
|
// src/express/index.ts
|
|
115
172
|
function paymentMiddleware(config) {
|
|
116
|
-
const middleware =
|
|
173
|
+
const middleware = chunkPOU7EH3E_cjs.createPaymentMiddleware(config);
|
|
117
174
|
return async (req, res, next) => {
|
|
118
175
|
const result = await middleware(new ExpressAdapter(req, res, next));
|
|
119
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 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,7 +11,8 @@ declare class ExpressAdapter implements HTTPAdapter {
|
|
|
11
11
|
getMethod(): string;
|
|
12
12
|
getPath(): string;
|
|
13
13
|
getUrl(): string;
|
|
14
|
-
|
|
14
|
+
getBody(): Promise<unknown>;
|
|
15
|
+
runHandler(options?: RunHandlerOptions): Promise<RunHandlerResult>;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
declare function paymentMiddleware(config: PaymentMiddlewareConfig): (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
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 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,7 +11,8 @@ declare class ExpressAdapter implements HTTPAdapter {
|
|
|
11
11
|
getMethod(): string;
|
|
12
12
|
getPath(): string;
|
|
13
13
|
getUrl(): string;
|
|
14
|
-
|
|
14
|
+
getBody(): Promise<unknown>;
|
|
15
|
+
runHandler(options?: RunHandlerOptions): Promise<RunHandlerResult>;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
declare function paymentMiddleware(config: PaymentMiddlewareConfig): (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
package/dist/express.js
CHANGED
|
@@ -1,7 +1,36 @@
|
|
|
1
|
-
import { raceTimeout, HANDLER_TIMEOUT } from './chunk-
|
|
2
|
-
import
|
|
1
|
+
import { raceTimeout, HANDLER_TIMEOUT, parseJsonBody, createPaymentMiddleware } from './chunk-AENXD4OC.js';
|
|
2
|
+
import './chunk-AFRDHGDT.js';
|
|
3
3
|
|
|
4
4
|
// src/express/adapter.ts
|
|
5
|
+
function chunkBytes(args) {
|
|
6
|
+
const [chunk, encoding] = args;
|
|
7
|
+
if (typeof chunk === "string") {
|
|
8
|
+
return Buffer.from(
|
|
9
|
+
chunk,
|
|
10
|
+
typeof encoding === "string" ? encoding : "utf8"
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
if (chunk instanceof Uint8Array) return Buffer.from(chunk);
|
|
14
|
+
return void 0;
|
|
15
|
+
}
|
|
16
|
+
function headerValue(value) {
|
|
17
|
+
if (value === void 0) return void 0;
|
|
18
|
+
return Array.isArray(value) ? value[0] : String(value);
|
|
19
|
+
}
|
|
20
|
+
function writeHeadContentType(args) {
|
|
21
|
+
const headers = args.find((arg) => typeof arg === "object" && arg !== null);
|
|
22
|
+
if (!headers) return void 0;
|
|
23
|
+
if (Array.isArray(headers)) {
|
|
24
|
+
const index = headers.findIndex(
|
|
25
|
+
(entry, i) => i % 2 === 0 && typeof entry === "string" && entry.toLowerCase() === "content-type"
|
|
26
|
+
);
|
|
27
|
+
return index === -1 ? void 0 : headerValue(headers[index + 1]);
|
|
28
|
+
}
|
|
29
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
30
|
+
if (name.toLowerCase() === "content-type") return headerValue(value);
|
|
31
|
+
}
|
|
32
|
+
return void 0;
|
|
33
|
+
}
|
|
5
34
|
var TIMEOUT_BODY = JSON.stringify({
|
|
6
35
|
error: "HANDLER_TIMEOUT",
|
|
7
36
|
message: "The resource handler did not respond in time."
|
|
@@ -28,7 +57,12 @@ var ExpressAdapter = class {
|
|
|
28
57
|
getUrl() {
|
|
29
58
|
return `${this.req.protocol}://${this.req.headers.host}${this.req.originalUrl}`;
|
|
30
59
|
}
|
|
31
|
-
|
|
60
|
+
// Whatever a body parser mounted before this middleware left on `req.body`
|
|
61
|
+
// (`express.json()` for JSON); `undefined` when none ran.
|
|
62
|
+
async getBody() {
|
|
63
|
+
return this.req.body;
|
|
64
|
+
}
|
|
65
|
+
async runHandler(options) {
|
|
32
66
|
const res = this.res;
|
|
33
67
|
const next = this.next;
|
|
34
68
|
const originalWriteHead = res.writeHead.bind(res);
|
|
@@ -72,7 +106,7 @@ var ExpressAdapter = class {
|
|
|
72
106
|
return originalEnd(...args);
|
|
73
107
|
});
|
|
74
108
|
next();
|
|
75
|
-
const outcome = await raceTimeout(endPromise);
|
|
109
|
+
const outcome = await raceTimeout(endPromise, options?.timeoutMs);
|
|
76
110
|
if (outcome === HANDLER_TIMEOUT) {
|
|
77
111
|
discarded = true;
|
|
78
112
|
return {
|
|
@@ -80,6 +114,9 @@ var ExpressAdapter = class {
|
|
|
80
114
|
setResponseHeader: (name, value) => {
|
|
81
115
|
if (!res.headersSent) res.setHeader(name, value);
|
|
82
116
|
},
|
|
117
|
+
getResponseHeader: () => void 0,
|
|
118
|
+
removeResponseHeader: () => {
|
|
119
|
+
},
|
|
83
120
|
sendResponse: () => {
|
|
84
121
|
if (res.headersSent) return;
|
|
85
122
|
originalWriteHead(504, { "Content-Type": "application/json" });
|
|
@@ -92,6 +129,26 @@ var ExpressAdapter = class {
|
|
|
92
129
|
return {
|
|
93
130
|
status: res.statusCode,
|
|
94
131
|
setResponseHeader: (name, value) => res.setHeader(name, value),
|
|
132
|
+
getResponseHeader: (name) => headerValue(res.getHeader(name)),
|
|
133
|
+
removeResponseHeader: (name) => res.removeHeader(name),
|
|
134
|
+
// The buffered chunks are the whole response: parse them when the
|
|
135
|
+
// handler declared JSON.
|
|
136
|
+
getResponseBody: async () => {
|
|
137
|
+
const bytes = [];
|
|
138
|
+
let contentType = headerValue(res.getHeader("content-type"));
|
|
139
|
+
for (const [method, args] of buffered) {
|
|
140
|
+
if (method === "writeHead") {
|
|
141
|
+
contentType ??= writeHeadContentType(args);
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const chunk = chunkBytes(args);
|
|
145
|
+
if (chunk) bytes.push(chunk);
|
|
146
|
+
}
|
|
147
|
+
return parseJsonBody(
|
|
148
|
+
contentType,
|
|
149
|
+
Buffer.concat(bytes).toString("utf8")
|
|
150
|
+
);
|
|
151
|
+
},
|
|
95
152
|
sendResponse: () => {
|
|
96
153
|
settled = true;
|
|
97
154
|
restore();
|
package/dist/fastify.cjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkPOU7EH3E_cjs = require('./chunk-POU7EH3E.cjs');
|
|
4
|
+
require('./chunk-JPMK5YBU.cjs');
|
|
4
5
|
var fp = require('fastify-plugin');
|
|
5
6
|
|
|
6
7
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -26,14 +27,50 @@ var FastifyAdapter = class {
|
|
|
26
27
|
getUrl() {
|
|
27
28
|
return `${this.req.protocol}://${this.req.host || this.req.hostname}${this.req.url}`;
|
|
28
29
|
}
|
|
30
|
+
// Fastify has parsed the body by the time the preHandler stage runs, which
|
|
31
|
+
// is where routes priced per request are gated.
|
|
32
|
+
async getBody() {
|
|
33
|
+
return this.req.body;
|
|
34
|
+
}
|
|
29
35
|
};
|
|
30
36
|
|
|
31
37
|
// src/fastify/index.ts
|
|
38
|
+
function payloadJson(contentType, payload) {
|
|
39
|
+
const text = typeof payload === "string" ? payload : payload instanceof Uint8Array ? Buffer.from(payload).toString("utf8") : void 0;
|
|
40
|
+
return chunkPOU7EH3E_cjs.parseJsonBody(contentType, text);
|
|
41
|
+
}
|
|
42
|
+
function refuse(reply, body) {
|
|
43
|
+
const json = JSON.stringify(body);
|
|
44
|
+
reply.status(402);
|
|
45
|
+
reply.header("Content-Type", "application/json");
|
|
46
|
+
reply.header("Content-Length", Buffer.byteLength(json));
|
|
47
|
+
return json;
|
|
48
|
+
}
|
|
49
|
+
function headerValue(value) {
|
|
50
|
+
if (value === void 0) return void 0;
|
|
51
|
+
return Array.isArray(value) ? value[0] : String(value);
|
|
52
|
+
}
|
|
32
53
|
function paymentMiddleware(config) {
|
|
33
54
|
return fp__default.default(async (fastify) => {
|
|
34
|
-
const gate =
|
|
35
|
-
const
|
|
55
|
+
const gate = chunkPOU7EH3E_cjs.createPaymentGate(config);
|
|
56
|
+
const verifiedMap = /* @__PURE__ */ new WeakMap();
|
|
57
|
+
const rawWriters = /* @__PURE__ */ new WeakMap();
|
|
58
|
+
const needsBody = (req) => {
|
|
59
|
+
const route = chunkPOU7EH3E_cjs.matchRoute(
|
|
60
|
+
new FastifyAdapter(req).getPath(),
|
|
61
|
+
config.routes
|
|
62
|
+
);
|
|
63
|
+
return typeof route?.price === "function" || route?.meter !== void 0;
|
|
64
|
+
};
|
|
36
65
|
fastify.addHook("onRequest", async (req, reply) => {
|
|
66
|
+
if (needsBody(req)) return;
|
|
67
|
+
await runGate(req, reply);
|
|
68
|
+
});
|
|
69
|
+
fastify.addHook("preHandler", async (req, reply) => {
|
|
70
|
+
if (!needsBody(req)) return;
|
|
71
|
+
await runGate(req, reply);
|
|
72
|
+
});
|
|
73
|
+
async function runGate(req, reply) {
|
|
37
74
|
const gateResult = await gate(new FastifyAdapter(req));
|
|
38
75
|
if (gateResult.type === "pass") return;
|
|
39
76
|
if (gateResult.type === "error") {
|
|
@@ -43,32 +80,69 @@ function paymentMiddleware(config) {
|
|
|
43
80
|
reply.status(gateResult.result.status).send(gateResult.result.body);
|
|
44
81
|
return;
|
|
45
82
|
}
|
|
46
|
-
|
|
47
|
-
|
|
83
|
+
verifiedMap.set(req, gateResult);
|
|
84
|
+
const raw = reply.raw;
|
|
85
|
+
rawWriters.set(req, {
|
|
86
|
+
write: raw.write,
|
|
87
|
+
end: raw.end,
|
|
88
|
+
writeHead: raw.writeHead
|
|
89
|
+
});
|
|
90
|
+
const refuse2 = () => {
|
|
91
|
+
throw new Error(
|
|
92
|
+
"x402: raw responses are not supported on paid routes \u2014 return the body from the handler so the payment can settle"
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
raw.write = refuse2;
|
|
96
|
+
raw.end = refuse2;
|
|
97
|
+
raw.writeHead = refuse2;
|
|
98
|
+
}
|
|
48
99
|
fastify.addHook("onSend", async (req, reply, payload) => {
|
|
49
|
-
const
|
|
50
|
-
if (
|
|
100
|
+
const writers = rawWriters.get(req);
|
|
101
|
+
if (writers) {
|
|
102
|
+
const raw2 = reply.raw;
|
|
103
|
+
raw2.write = writers.write;
|
|
104
|
+
raw2.end = writers.end;
|
|
105
|
+
raw2.writeHead = writers.writeHead;
|
|
106
|
+
rawWriters.delete(req);
|
|
107
|
+
}
|
|
108
|
+
const verified = verifiedMap.get(req);
|
|
109
|
+
if (!verified) return payload;
|
|
110
|
+
let raw;
|
|
111
|
+
if (verified.scheme === "upto") {
|
|
112
|
+
raw = headerValue(reply.getHeader(chunkPOU7EH3E_cjs.SETTLE_AMOUNT_HEADER));
|
|
113
|
+
reply.removeHeader(chunkPOU7EH3E_cjs.SETTLE_AMOUNT_HEADER);
|
|
114
|
+
}
|
|
115
|
+
if (reply.statusCode < 200 || reply.statusCode >= 300) {
|
|
51
116
|
return payload;
|
|
52
117
|
}
|
|
118
|
+
let settleOptions;
|
|
119
|
+
if (verified.scheme === "upto") {
|
|
120
|
+
const resolved = await chunkPOU7EH3E_cjs.resolveCharge(verified, raw, {
|
|
121
|
+
status: reply.statusCode,
|
|
122
|
+
header: (name) => headerValue(reply.getHeader(name)),
|
|
123
|
+
body: async () => payloadJson(headerValue(reply.getHeader("content-type")), payload)
|
|
124
|
+
});
|
|
125
|
+
if (resolved.kind === "invalid") {
|
|
126
|
+
return refuse(reply, chunkPOU7EH3E_cjs.invalidSettleAmountResponse(resolved.reason));
|
|
127
|
+
}
|
|
128
|
+
if (resolved.kind === "skip") return payload;
|
|
129
|
+
settleOptions = { amount: resolved.amount };
|
|
130
|
+
}
|
|
53
131
|
let settled = false;
|
|
54
132
|
try {
|
|
55
|
-
const settleResponse = await settle();
|
|
133
|
+
const settleResponse = settleOptions ? await verified.settle(settleOptions) : await verified.settle();
|
|
56
134
|
if (settleResponse.success) {
|
|
57
|
-
reply.header("payment-response",
|
|
135
|
+
reply.header("payment-response", chunkPOU7EH3E_cjs.encodeBase64(settleResponse));
|
|
58
136
|
reply.header("access-control-expose-headers", "payment-response");
|
|
59
137
|
settled = true;
|
|
60
138
|
}
|
|
61
139
|
} catch {
|
|
62
140
|
}
|
|
63
141
|
if (!settled) {
|
|
64
|
-
|
|
142
|
+
return refuse(reply, {
|
|
65
143
|
error: "PAYMENT_SETTLEMENT_FAILED",
|
|
66
144
|
message: "Payment could not be confirmed after multiple attempts. Please retry."
|
|
67
145
|
});
|
|
68
|
-
reply.status(402);
|
|
69
|
-
reply.header("Content-Type", "application/json");
|
|
70
|
-
reply.header("Content-Length", Buffer.byteLength(body));
|
|
71
|
-
return body;
|
|
72
146
|
}
|
|
73
147
|
return payload;
|
|
74
148
|
});
|
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-q_gu5wjz.cjs';
|
|
3
3
|
import 'viem';
|
|
4
4
|
|
|
5
5
|
declare class FastifyAdapter implements HTTPAdapter {
|
|
@@ -9,6 +9,7 @@ declare class FastifyAdapter implements HTTPAdapter {
|
|
|
9
9
|
getMethod(): string;
|
|
10
10
|
getPath(): string;
|
|
11
11
|
getUrl(): string;
|
|
12
|
+
getBody(): Promise<unknown>;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
declare function paymentMiddleware(config: PaymentMiddlewareConfig): FastifyPluginAsync;
|
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-q_gu5wjz.js';
|
|
3
3
|
import 'viem';
|
|
4
4
|
|
|
5
5
|
declare class FastifyAdapter implements HTTPAdapter {
|
|
@@ -9,6 +9,7 @@ declare class FastifyAdapter implements HTTPAdapter {
|
|
|
9
9
|
getMethod(): string;
|
|
10
10
|
getPath(): string;
|
|
11
11
|
getUrl(): string;
|
|
12
|
+
getBody(): Promise<unknown>;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
declare function paymentMiddleware(config: PaymentMiddlewareConfig): FastifyPluginAsync;
|
package/dist/fastify.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { createPaymentGate, encodeBase64 } from './chunk-
|
|
1
|
+
import { createPaymentGate, SETTLE_AMOUNT_HEADER, resolveCharge, invalidSettleAmountResponse, encodeBase64, matchRoute, parseJsonBody } from './chunk-AENXD4OC.js';
|
|
2
|
+
import './chunk-AFRDHGDT.js';
|
|
2
3
|
import fp from 'fastify-plugin';
|
|
3
4
|
|
|
4
5
|
// src/fastify/adapter.ts
|
|
@@ -20,14 +21,50 @@ var FastifyAdapter = class {
|
|
|
20
21
|
getUrl() {
|
|
21
22
|
return `${this.req.protocol}://${this.req.host || this.req.hostname}${this.req.url}`;
|
|
22
23
|
}
|
|
24
|
+
// Fastify has parsed the body by the time the preHandler stage runs, which
|
|
25
|
+
// is where routes priced per request are gated.
|
|
26
|
+
async getBody() {
|
|
27
|
+
return this.req.body;
|
|
28
|
+
}
|
|
23
29
|
};
|
|
24
30
|
|
|
25
31
|
// src/fastify/index.ts
|
|
32
|
+
function payloadJson(contentType, payload) {
|
|
33
|
+
const text = typeof payload === "string" ? payload : payload instanceof Uint8Array ? Buffer.from(payload).toString("utf8") : void 0;
|
|
34
|
+
return parseJsonBody(contentType, text);
|
|
35
|
+
}
|
|
36
|
+
function refuse(reply, body) {
|
|
37
|
+
const json = JSON.stringify(body);
|
|
38
|
+
reply.status(402);
|
|
39
|
+
reply.header("Content-Type", "application/json");
|
|
40
|
+
reply.header("Content-Length", Buffer.byteLength(json));
|
|
41
|
+
return json;
|
|
42
|
+
}
|
|
43
|
+
function headerValue(value) {
|
|
44
|
+
if (value === void 0) return void 0;
|
|
45
|
+
return Array.isArray(value) ? value[0] : String(value);
|
|
46
|
+
}
|
|
26
47
|
function paymentMiddleware(config) {
|
|
27
48
|
return fp(async (fastify) => {
|
|
28
49
|
const gate = createPaymentGate(config);
|
|
29
|
-
const
|
|
50
|
+
const verifiedMap = /* @__PURE__ */ new WeakMap();
|
|
51
|
+
const rawWriters = /* @__PURE__ */ new WeakMap();
|
|
52
|
+
const needsBody = (req) => {
|
|
53
|
+
const route = matchRoute(
|
|
54
|
+
new FastifyAdapter(req).getPath(),
|
|
55
|
+
config.routes
|
|
56
|
+
);
|
|
57
|
+
return typeof route?.price === "function" || route?.meter !== void 0;
|
|
58
|
+
};
|
|
30
59
|
fastify.addHook("onRequest", async (req, reply) => {
|
|
60
|
+
if (needsBody(req)) return;
|
|
61
|
+
await runGate(req, reply);
|
|
62
|
+
});
|
|
63
|
+
fastify.addHook("preHandler", async (req, reply) => {
|
|
64
|
+
if (!needsBody(req)) return;
|
|
65
|
+
await runGate(req, reply);
|
|
66
|
+
});
|
|
67
|
+
async function runGate(req, reply) {
|
|
31
68
|
const gateResult = await gate(new FastifyAdapter(req));
|
|
32
69
|
if (gateResult.type === "pass") return;
|
|
33
70
|
if (gateResult.type === "error") {
|
|
@@ -37,16 +74,57 @@ function paymentMiddleware(config) {
|
|
|
37
74
|
reply.status(gateResult.result.status).send(gateResult.result.body);
|
|
38
75
|
return;
|
|
39
76
|
}
|
|
40
|
-
|
|
41
|
-
|
|
77
|
+
verifiedMap.set(req, gateResult);
|
|
78
|
+
const raw = reply.raw;
|
|
79
|
+
rawWriters.set(req, {
|
|
80
|
+
write: raw.write,
|
|
81
|
+
end: raw.end,
|
|
82
|
+
writeHead: raw.writeHead
|
|
83
|
+
});
|
|
84
|
+
const refuse2 = () => {
|
|
85
|
+
throw new Error(
|
|
86
|
+
"x402: raw responses are not supported on paid routes \u2014 return the body from the handler so the payment can settle"
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
raw.write = refuse2;
|
|
90
|
+
raw.end = refuse2;
|
|
91
|
+
raw.writeHead = refuse2;
|
|
92
|
+
}
|
|
42
93
|
fastify.addHook("onSend", async (req, reply, payload) => {
|
|
43
|
-
const
|
|
44
|
-
if (
|
|
94
|
+
const writers = rawWriters.get(req);
|
|
95
|
+
if (writers) {
|
|
96
|
+
const raw2 = reply.raw;
|
|
97
|
+
raw2.write = writers.write;
|
|
98
|
+
raw2.end = writers.end;
|
|
99
|
+
raw2.writeHead = writers.writeHead;
|
|
100
|
+
rawWriters.delete(req);
|
|
101
|
+
}
|
|
102
|
+
const verified = verifiedMap.get(req);
|
|
103
|
+
if (!verified) return payload;
|
|
104
|
+
let raw;
|
|
105
|
+
if (verified.scheme === "upto") {
|
|
106
|
+
raw = headerValue(reply.getHeader(SETTLE_AMOUNT_HEADER));
|
|
107
|
+
reply.removeHeader(SETTLE_AMOUNT_HEADER);
|
|
108
|
+
}
|
|
109
|
+
if (reply.statusCode < 200 || reply.statusCode >= 300) {
|
|
45
110
|
return payload;
|
|
46
111
|
}
|
|
112
|
+
let settleOptions;
|
|
113
|
+
if (verified.scheme === "upto") {
|
|
114
|
+
const resolved = await resolveCharge(verified, raw, {
|
|
115
|
+
status: reply.statusCode,
|
|
116
|
+
header: (name) => headerValue(reply.getHeader(name)),
|
|
117
|
+
body: async () => payloadJson(headerValue(reply.getHeader("content-type")), payload)
|
|
118
|
+
});
|
|
119
|
+
if (resolved.kind === "invalid") {
|
|
120
|
+
return refuse(reply, invalidSettleAmountResponse(resolved.reason));
|
|
121
|
+
}
|
|
122
|
+
if (resolved.kind === "skip") return payload;
|
|
123
|
+
settleOptions = { amount: resolved.amount };
|
|
124
|
+
}
|
|
47
125
|
let settled = false;
|
|
48
126
|
try {
|
|
49
|
-
const settleResponse = await settle();
|
|
127
|
+
const settleResponse = settleOptions ? await verified.settle(settleOptions) : await verified.settle();
|
|
50
128
|
if (settleResponse.success) {
|
|
51
129
|
reply.header("payment-response", encodeBase64(settleResponse));
|
|
52
130
|
reply.header("access-control-expose-headers", "payment-response");
|
|
@@ -55,14 +133,10 @@ function paymentMiddleware(config) {
|
|
|
55
133
|
} catch {
|
|
56
134
|
}
|
|
57
135
|
if (!settled) {
|
|
58
|
-
|
|
136
|
+
return refuse(reply, {
|
|
59
137
|
error: "PAYMENT_SETTLEMENT_FAILED",
|
|
60
138
|
message: "Payment could not be confirmed after multiple attempts. Please retry."
|
|
61
139
|
});
|
|
62
|
-
reply.status(402);
|
|
63
|
-
reply.header("Content-Type", "application/json");
|
|
64
|
-
reply.header("Content-Length", Buffer.byteLength(body));
|
|
65
|
-
return body;
|
|
66
140
|
}
|
|
67
141
|
return payload;
|
|
68
142
|
});
|
package/dist/hono.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
|
|
3
|
+
var chunkPOU7EH3E_cjs = require('./chunk-POU7EH3E.cjs');
|
|
4
|
+
require('./chunk-JPMK5YBU.cjs');
|
|
5
5
|
|
|
6
6
|
// src/hono/adapter.ts
|
|
7
7
|
var TIMEOUT_BODY = JSON.stringify({
|
|
@@ -27,13 +27,26 @@ var HonoAdapter = class {
|
|
|
27
27
|
getUrl() {
|
|
28
28
|
return this.c.req.url;
|
|
29
29
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
// Hono caches the parsed body on the request, so the handler can still read
|
|
31
|
+
// it after the price function did.
|
|
32
|
+
async getBody() {
|
|
33
|
+
if (!chunkPOU7EH3E_cjs.isJsonContentType(this.c.req.header("content-type"))) return void 0;
|
|
34
|
+
try {
|
|
35
|
+
return await this.c.req.json();
|
|
36
|
+
} catch {
|
|
37
|
+
return void 0;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async runHandler(options) {
|
|
41
|
+
const outcome = await chunkPOU7EH3E_cjs.raceTimeout(this.next(), options?.timeoutMs);
|
|
42
|
+
if (outcome === chunkPOU7EH3E_cjs.HANDLER_TIMEOUT) {
|
|
33
43
|
return {
|
|
34
44
|
status: 504,
|
|
35
45
|
setResponseHeader: () => {
|
|
36
46
|
},
|
|
47
|
+
getResponseHeader: () => void 0,
|
|
48
|
+
removeResponseHeader: () => {
|
|
49
|
+
},
|
|
37
50
|
sendResponse: () => {
|
|
38
51
|
this.c.res = new Response(TIMEOUT_BODY, {
|
|
39
52
|
status: 504,
|
|
@@ -48,9 +61,17 @@ var HonoAdapter = class {
|
|
|
48
61
|
return {
|
|
49
62
|
status: res.status,
|
|
50
63
|
setResponseHeader: (name, value) => res.headers.set(name, value),
|
|
64
|
+
getResponseHeader: (name) => res.headers.get(name) ?? void 0,
|
|
65
|
+
removeResponseHeader: (name) => res.headers.delete(name),
|
|
66
|
+
// Read from a clone: the response body streams once, to the client.
|
|
67
|
+
getResponseBody: () => chunkPOU7EH3E_cjs.jsonFromResponse(res),
|
|
51
68
|
sendResponse: () => {
|
|
52
69
|
},
|
|
70
|
+
// The response is replaced: release its body (and whatever upstream
|
|
71
|
+
// stream feeds it) instead of leaving it open until collected.
|
|
53
72
|
discardResponse: () => {
|
|
73
|
+
res.body?.cancel().catch(() => {
|
|
74
|
+
});
|
|
54
75
|
}
|
|
55
76
|
};
|
|
56
77
|
}
|
|
@@ -58,7 +79,7 @@ var HonoAdapter = class {
|
|
|
58
79
|
|
|
59
80
|
// src/hono/index.ts
|
|
60
81
|
function paymentMiddleware(config) {
|
|
61
|
-
const middleware =
|
|
82
|
+
const middleware = chunkPOU7EH3E_cjs.createPaymentMiddleware(config);
|
|
62
83
|
return async (c, next) => {
|
|
63
84
|
const result = await middleware(new HonoAdapter(c, next));
|
|
64
85
|
if ("pass" in result) {
|
package/dist/hono.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Context, Next, MiddlewareHandler } from 'hono';
|
|
2
|
-
import { H as HTTPAdapter, R 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 HonoAdapter implements HTTPAdapter {
|
|
@@ -10,7 +10,8 @@ declare class HonoAdapter implements HTTPAdapter {
|
|
|
10
10
|
getMethod(): string;
|
|
11
11
|
getPath(): string;
|
|
12
12
|
getUrl(): string;
|
|
13
|
-
|
|
13
|
+
getBody(): Promise<unknown>;
|
|
14
|
+
runHandler(options?: RunHandlerOptions): Promise<RunHandlerResult>;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
declare function paymentMiddleware(config: PaymentMiddlewareConfig): MiddlewareHandler;
|
package/dist/hono.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Context, Next, MiddlewareHandler } from 'hono';
|
|
2
|
-
import { H as HTTPAdapter, R 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 HonoAdapter implements HTTPAdapter {
|
|
@@ -10,7 +10,8 @@ declare class HonoAdapter implements HTTPAdapter {
|
|
|
10
10
|
getMethod(): string;
|
|
11
11
|
getPath(): string;
|
|
12
12
|
getUrl(): string;
|
|
13
|
-
|
|
13
|
+
getBody(): Promise<unknown>;
|
|
14
|
+
runHandler(options?: RunHandlerOptions): Promise<RunHandlerResult>;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
declare function paymentMiddleware(config: PaymentMiddlewareConfig): MiddlewareHandler;
|