@armory-sh/middleware-bun 0.3.18 → 0.3.19-alpha.3.13

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.
@@ -0,0 +1,312 @@
1
+ import { getNetworkConfig, encodePaymentPayload, matchRoute, validateRouteConfig, decodePayment, isExactEvmPayload, getNetworkByChainId, normalizeNetworkName } from '@armory-sh/base';
2
+
3
+ // src/routes.ts
4
+ var toSlug = (network) => {
5
+ if (typeof network === "number") {
6
+ const net = getNetworkByChainId(network);
7
+ if (!net) throw new Error(`No network found for chainId: ${network}`);
8
+ return normalizeNetworkName(net.name);
9
+ }
10
+ if (network.startsWith("eip155:")) {
11
+ const chainId = parseInt(network.split(":")[1], 10);
12
+ const net = getNetworkByChainId(chainId);
13
+ if (!net) throw new Error(`No network found for chainId: ${chainId}`);
14
+ return normalizeNetworkName(net.name);
15
+ }
16
+ return normalizeNetworkName(network);
17
+ };
18
+ var toEip155 = (network) => {
19
+ if (typeof network === "number") {
20
+ const net2 = getNetworkByChainId(network);
21
+ if (!net2) throw new Error(`No network found for chainId: ${network}`);
22
+ return net2.caip2Id;
23
+ }
24
+ if (network.startsWith("eip155:")) {
25
+ const net2 = getNetworkConfig(network);
26
+ if (!net2) throw new Error(`No network found for: ${network}`);
27
+ return net2.caip2Id;
28
+ }
29
+ const slug = normalizeNetworkName(network);
30
+ const net = getNetworkConfig(slug);
31
+ if (!net) throw new Error(`No network found for: ${slug}`);
32
+ return net.caip2Id;
33
+ };
34
+ var getNetworkName = (network) => toSlug(network);
35
+ var getChainId = (network) => toEip155(network);
36
+ var createV1Requirements = (config, expiry) => {
37
+ const networkName = getNetworkName(config.network);
38
+ const network = getNetworkConfig(networkName);
39
+ if (!network) throw new Error(`Unsupported network: ${networkName}`);
40
+ return {
41
+ amount: config.amount,
42
+ network: networkName,
43
+ contractAddress: network.usdcAddress,
44
+ payTo: config.payTo,
45
+ expiry
46
+ };
47
+ };
48
+ var createV2Requirements = (config, expiry) => {
49
+ const networkName = getNetworkName(config.network);
50
+ const network = getNetworkConfig(networkName);
51
+ if (!network) throw new Error(`Unsupported network: ${networkName}`);
52
+ return {
53
+ amount: config.amount,
54
+ to: config.payTo,
55
+ chainId: getChainId(config.network),
56
+ assetId: network.caipAssetId,
57
+ nonce: `${Date.now()}-${crypto.randomUUID()}`,
58
+ expiry
59
+ };
60
+ };
61
+ var createPaymentRequirements = (config, version = 1) => {
62
+ const networkName = getNetworkName(config.network);
63
+ const network = getNetworkConfig(networkName);
64
+ if (!network) throw new Error(`Unsupported network: ${networkName}`);
65
+ const expiry = Math.floor(Date.now() / 1e3) + 3600;
66
+ return version === 1 ? createV1Requirements(config, expiry) : createV2Requirements(config, expiry);
67
+ };
68
+ var findHeaderValue = (headers, name) => {
69
+ const value = headers[name];
70
+ if (typeof value === "string") return value;
71
+ if (Array.isArray(value) && value.length > 0) return value[0];
72
+ const lowerName = name.toLowerCase();
73
+ for (const [key, val] of Object.entries(headers)) {
74
+ if (key.toLowerCase() === lowerName) {
75
+ if (typeof val === "string") return val;
76
+ if (Array.isArray(val) && val.length > 0) return val[0];
77
+ }
78
+ }
79
+ return void 0;
80
+ };
81
+ var parseHeader = (header) => {
82
+ try {
83
+ if (header.startsWith("{")) return JSON.parse(header);
84
+ return JSON.parse(atob(header));
85
+ } catch {
86
+ return null;
87
+ }
88
+ };
89
+ var extractPaymentPayload = (request) => {
90
+ const v1Header = findHeaderValue(request.headers, "X-PAYMENT");
91
+ if (v1Header) return parseHeader(v1Header);
92
+ const v2Header = findHeaderValue(request.headers, "PAYMENT-SIGNATURE");
93
+ if (v2Header) return parseHeader(v2Header);
94
+ return null;
95
+ };
96
+ var postFacilitator = async (url, headers, body) => {
97
+ const response = await fetch(url, {
98
+ method: "POST",
99
+ headers: { "Content-Type": "application/json", ...headers },
100
+ body: JSON.stringify(body)
101
+ });
102
+ if (!response.ok) {
103
+ const error = await response.text();
104
+ throw new Error(error || `Request failed: ${response.status}`);
105
+ }
106
+ return response.json();
107
+ };
108
+ var verifyWithFacilitator = async (request, facilitator) => {
109
+ const payload = extractPaymentPayload(request);
110
+ if (!payload) {
111
+ return { success: false, error: "No payment payload found in request headers" };
112
+ }
113
+ try {
114
+ const url = new URL("/verify", facilitator.url);
115
+ const headers = facilitator.createHeaders?.() ?? {};
116
+ const data = await postFacilitator(url.toString(), headers, { payload, headers: request.headers });
117
+ return {
118
+ success: true,
119
+ payerAddress: data.payerAddress,
120
+ balance: data.balance,
121
+ requiredAmount: data.requiredAmount
122
+ };
123
+ } catch (error) {
124
+ return {
125
+ success: false,
126
+ error: error instanceof Error ? error.message : "Unknown verification error"
127
+ };
128
+ }
129
+ };
130
+ var settleWithFacilitator = async (request, facilitator) => {
131
+ const payload = extractPaymentPayload(request);
132
+ if (!payload) {
133
+ return { success: false, error: "No payment payload found in request headers" };
134
+ }
135
+ try {
136
+ const url = new URL("/settle", facilitator.url);
137
+ const headers = facilitator.createHeaders?.() ?? {};
138
+ const data = await postFacilitator(url.toString(), headers, { payload, headers: request.headers });
139
+ return {
140
+ success: true,
141
+ txHash: data.txHash
142
+ };
143
+ } catch (error) {
144
+ return {
145
+ success: false,
146
+ error: error instanceof Error ? error.message : "Unknown settlement error"
147
+ };
148
+ }
149
+ };
150
+ var createPaymentRequiredHeaders = (requirements, version) => {
151
+ if (version === 1) {
152
+ return { "X-PAYMENT-REQUIRED": encodePaymentPayload(requirements) };
153
+ }
154
+ const paymentRequired = {
155
+ x402Version: 2,
156
+ resource: {
157
+ url: "https://api.example.com",
158
+ description: "API Access"
159
+ },
160
+ accepts: [requirements]
161
+ };
162
+ return { "PAYMENT-REQUIRED": Buffer.from(JSON.stringify(paymentRequired)).toString("base64") };
163
+ };
164
+ var createSettlementHeaders = (response, version) => {
165
+ if (version === 1) {
166
+ const isSuccess2 = "success" in response ? response.success : response.status === "success";
167
+ const txHash2 = "transaction" in response ? response.transaction : response.txHash || "";
168
+ const settlementJson2 = JSON.stringify({
169
+ status: isSuccess2 ? "success" : "failed",
170
+ txHash: txHash2 ?? ""
171
+ });
172
+ return { "X-PAYMENT-RESPONSE": Buffer.from(settlementJson2).toString("base64") };
173
+ }
174
+ const txHash = "transaction" in response ? response.transaction : response.txHash || "";
175
+ const isSuccess = "success" in response ? response.success : response.status === "success";
176
+ const settlementJson = JSON.stringify({
177
+ status: isSuccess ? "success" : "failed",
178
+ txHash: txHash || ""
179
+ });
180
+ return { "PAYMENT-RESPONSE": Buffer.from(settlementJson).toString("base64") };
181
+ };
182
+
183
+ // src/routes.ts
184
+ var resolveRouteConfig = (config) => {
185
+ const validationError = validateRouteConfig(config);
186
+ if (validationError) {
187
+ return { routes: [], error: validationError };
188
+ }
189
+ const { route, routes, perRoute, ...baseConfig } = config;
190
+ const routePatterns = route ? [route] : routes || [];
191
+ const resolvedRoutes = [];
192
+ for (const pattern of routePatterns) {
193
+ const perRouteOverride = perRoute?.[pattern];
194
+ const mergedConfig = {
195
+ ...baseConfig,
196
+ ...perRouteOverride
197
+ };
198
+ resolvedRoutes.push({
199
+ pattern,
200
+ config: mergedConfig
201
+ });
202
+ }
203
+ return { routes: resolvedRoutes };
204
+ };
205
+ var parsePaymentHeader = async (request) => {
206
+ const paymentSig = request.headers.get("PAYMENT-SIGNATURE");
207
+ if (paymentSig) {
208
+ try {
209
+ const payload = decodePayment(paymentSig);
210
+ if (isExactEvmPayload(payload)) {
211
+ return { payload, version: 2, payerAddress: payload.authorization.from };
212
+ }
213
+ } catch {
214
+ }
215
+ }
216
+ const xPayment = request.headers.get("X-PAYMENT");
217
+ if (xPayment) {
218
+ try {
219
+ const payload = decodePayment(xPayment);
220
+ if (isExactEvmPayload(payload)) {
221
+ return { payload, version: 2, payerAddress: payload.authorization.from };
222
+ }
223
+ if (payload && typeof payload === "object" && "from" in payload && typeof payload.from === "string") {
224
+ return { payload, version: 1, payerAddress: payload.from };
225
+ }
226
+ } catch {
227
+ }
228
+ }
229
+ return null;
230
+ };
231
+ var toHttpRequest = (request) => {
232
+ const headers = {};
233
+ request.headers.forEach((v, k) => {
234
+ headers[k] = v;
235
+ });
236
+ return { headers, method: request.method, url: request.url };
237
+ };
238
+ var errorResponse = (error, status, headers, accepts) => new Response(JSON.stringify({ error, accepts }), {
239
+ status,
240
+ headers: { "Content-Type": "application/json", ...headers }
241
+ });
242
+ var createSettlementResponse = (success, txHash) => ({
243
+ success,
244
+ transaction: txHash ?? "",
245
+ errorReason: void 0 ,
246
+ network: "base"
247
+ });
248
+ var successResponse = (payerAddress, version, settlement) => {
249
+ const isSuccess = settlement?.success;
250
+ const txHash = settlement?.transaction;
251
+ return new Response(
252
+ JSON.stringify({
253
+ verified: true,
254
+ payerAddress,
255
+ version,
256
+ settlement: settlement ? { success: isSuccess, txHash } : void 0
257
+ }),
258
+ {
259
+ status: 200,
260
+ headers: {
261
+ "Content-Type": "application/json",
262
+ "X-Payment-Verified": "true",
263
+ "X-Payer-Address": payerAddress,
264
+ ...settlement ? createSettlementHeaders(settlement, version) : {}
265
+ }
266
+ }
267
+ );
268
+ };
269
+ var createRouteAwareBunMiddleware = (config) => {
270
+ const { routes: resolvedRoutes, error: configError } = resolveRouteConfig(config);
271
+ return async (request) => {
272
+ if (configError) {
273
+ return errorResponse(`Payment middleware configuration error: ${configError.message}`, 500);
274
+ }
275
+ const path = new URL(request.url).pathname;
276
+ const matchedRoute = resolvedRoutes.find((r) => matchRoute(r.pattern, path));
277
+ if (!matchedRoute) {
278
+ return null;
279
+ }
280
+ const routeConfig = matchedRoute.config;
281
+ const { facilitator, settlementMode = "verify", defaultVersion = 2, waitForSettlement = false } = routeConfig;
282
+ const requirementsV1 = createPaymentRequirements(routeConfig, 1);
283
+ const requirementsV2 = createPaymentRequirements(routeConfig, 2);
284
+ const paymentResult = await parsePaymentHeader(request);
285
+ if (!paymentResult) {
286
+ const requirements = defaultVersion === 1 ? requirementsV1 : requirementsV2;
287
+ return errorResponse("Payment required", 402, createPaymentRequiredHeaders(requirements, defaultVersion), [requirements]);
288
+ }
289
+ const { version, payerAddress } = paymentResult;
290
+ if (facilitator) {
291
+ const verifyResult = await verifyWithFacilitator(toHttpRequest(request), facilitator);
292
+ if (!verifyResult.success) {
293
+ const requirements = version === 1 ? requirementsV1 : requirementsV2;
294
+ return errorResponse(`Payment verification failed: ${verifyResult.error}`, 402, createPaymentRequiredHeaders(requirements, version), [requirements]);
295
+ }
296
+ }
297
+ if (settlementMode === "settle" && facilitator) {
298
+ const settle = async () => {
299
+ const result = await settleWithFacilitator(toHttpRequest(request), facilitator);
300
+ return result.success ? successResponse(payerAddress, version, createSettlementResponse(true, result.txHash)) : errorResponse(result.error ?? "Settlement failed", 400);
301
+ };
302
+ if (waitForSettlement) {
303
+ return await settle();
304
+ }
305
+ settle().catch(console.error);
306
+ return successResponse(payerAddress, version);
307
+ }
308
+ return successResponse(payerAddress, version);
309
+ };
310
+ };
311
+
312
+ export { createPaymentRequiredHeaders, createPaymentRequirements, createRouteAwareBunMiddleware, createSettlementHeaders, settleWithFacilitator, verifyWithFacilitator };
package/dist/index.js CHANGED
@@ -1,224 +1,8 @@
1
- // src/index.ts
2
- import { decodePayment as decodePayment2, isExactEvmPayload as isExactEvmPayload2 } from "@armory-sh/base";
1
+ import { createPaymentRequirements, createPaymentRequiredHeaders, verifyWithFacilitator, settleWithFacilitator, createSettlementHeaders } from './chunk-IP3DZBNP.js';
2
+ export { createRouteAwareBunMiddleware } from './chunk-IP3DZBNP.js';
3
+ import { decodePayment, isExactEvmPayload } from '@armory-sh/base';
3
4
 
4
- // src/core.ts
5
- import {
6
- getNetworkConfig,
7
- getNetworkByChainId,
8
- encodePaymentPayload,
9
- normalizeNetworkName
10
- } from "@armory-sh/base";
11
- var toSlug = (network) => {
12
- if (typeof network === "number") {
13
- const net = getNetworkByChainId(network);
14
- if (!net) throw new Error(`No network found for chainId: ${network}`);
15
- return normalizeNetworkName(net.name);
16
- }
17
- if (network.startsWith("eip155:")) {
18
- const chainId = parseInt(network.split(":")[1], 10);
19
- const net = getNetworkByChainId(chainId);
20
- if (!net) throw new Error(`No network found for chainId: ${chainId}`);
21
- return normalizeNetworkName(net.name);
22
- }
23
- return normalizeNetworkName(network);
24
- };
25
- var toEip155 = (network) => {
26
- if (typeof network === "number") {
27
- const net2 = getNetworkByChainId(network);
28
- if (!net2) throw new Error(`No network found for chainId: ${network}`);
29
- return net2.caip2Id;
30
- }
31
- if (network.startsWith("eip155:")) {
32
- const net2 = getNetworkConfig(network);
33
- if (!net2) throw new Error(`No network found for: ${network}`);
34
- return net2.caip2Id;
35
- }
36
- const slug = normalizeNetworkName(network);
37
- const net = getNetworkConfig(slug);
38
- if (!net) throw new Error(`No network found for: ${slug}`);
39
- return net.caip2Id;
40
- };
41
- var getNetworkName = (network) => toSlug(network);
42
- var getChainId = (network) => toEip155(network);
43
- var createV1Requirements = (config, expiry) => {
44
- const networkName = getNetworkName(config.network);
45
- const network = getNetworkConfig(networkName);
46
- if (!network) throw new Error(`Unsupported network: ${networkName}`);
47
- return {
48
- amount: config.amount,
49
- network: networkName,
50
- contractAddress: network.usdcAddress,
51
- payTo: config.payTo,
52
- expiry
53
- };
54
- };
55
- var createV2Requirements = (config, expiry) => {
56
- const networkName = getNetworkName(config.network);
57
- const network = getNetworkConfig(networkName);
58
- if (!network) throw new Error(`Unsupported network: ${networkName}`);
59
- return {
60
- amount: config.amount,
61
- to: config.payTo,
62
- chainId: getChainId(config.network),
63
- assetId: network.caipAssetId,
64
- nonce: `${Date.now()}-${crypto.randomUUID()}`,
65
- expiry
66
- };
67
- };
68
- var createPaymentRequirements = (config, version = 1) => {
69
- const networkName = getNetworkName(config.network);
70
- const network = getNetworkConfig(networkName);
71
- if (!network) throw new Error(`Unsupported network: ${networkName}`);
72
- const expiry = Math.floor(Date.now() / 1e3) + 3600;
73
- return version === 1 ? createV1Requirements(config, expiry) : createV2Requirements(config, expiry);
74
- };
75
- var findHeaderValue = (headers, name) => {
76
- const value = headers[name];
77
- if (typeof value === "string") return value;
78
- if (Array.isArray(value) && value.length > 0) return value[0];
79
- const lowerName = name.toLowerCase();
80
- for (const [key, val] of Object.entries(headers)) {
81
- if (key.toLowerCase() === lowerName) {
82
- if (typeof val === "string") return val;
83
- if (Array.isArray(val) && val.length > 0) return val[0];
84
- }
85
- }
86
- return void 0;
87
- };
88
- var parseHeader = (header) => {
89
- try {
90
- if (header.startsWith("{")) return JSON.parse(header);
91
- return JSON.parse(atob(header));
92
- } catch {
93
- return null;
94
- }
95
- };
96
- var extractPaymentPayload = (request) => {
97
- const v1Header = findHeaderValue(request.headers, "X-PAYMENT");
98
- if (v1Header) return parseHeader(v1Header);
99
- const v2Header = findHeaderValue(request.headers, "PAYMENT-SIGNATURE");
100
- if (v2Header) return parseHeader(v2Header);
101
- return null;
102
- };
103
- var postFacilitator = async (url, headers, body) => {
104
- const response = await fetch(url, {
105
- method: "POST",
106
- headers: { "Content-Type": "application/json", ...headers },
107
- body: JSON.stringify(body)
108
- });
109
- if (!response.ok) {
110
- const error = await response.text();
111
- throw new Error(error || `Request failed: ${response.status}`);
112
- }
113
- return response.json();
114
- };
115
- var verifyWithFacilitator = async (request, facilitator) => {
116
- const payload = extractPaymentPayload(request);
117
- if (!payload) {
118
- return { success: false, error: "No payment payload found in request headers" };
119
- }
120
- try {
121
- const url = new URL("/verify", facilitator.url);
122
- const headers = facilitator.createHeaders?.() ?? {};
123
- const data = await postFacilitator(url.toString(), headers, { payload, headers: request.headers });
124
- return {
125
- success: true,
126
- payerAddress: data.payerAddress,
127
- balance: data.balance,
128
- requiredAmount: data.requiredAmount
129
- };
130
- } catch (error) {
131
- return {
132
- success: false,
133
- error: error instanceof Error ? error.message : "Unknown verification error"
134
- };
135
- }
136
- };
137
- var settleWithFacilitator = async (request, facilitator) => {
138
- const payload = extractPaymentPayload(request);
139
- if (!payload) {
140
- return { success: false, error: "No payment payload found in request headers" };
141
- }
142
- try {
143
- const url = new URL("/settle", facilitator.url);
144
- const headers = facilitator.createHeaders?.() ?? {};
145
- const data = await postFacilitator(url.toString(), headers, { payload, headers: request.headers });
146
- return {
147
- success: true,
148
- txHash: data.txHash
149
- };
150
- } catch (error) {
151
- return {
152
- success: false,
153
- error: error instanceof Error ? error.message : "Unknown settlement error"
154
- };
155
- }
156
- };
157
- var createPaymentRequiredHeaders = (requirements, version) => {
158
- if (version === 1) {
159
- return { "X-PAYMENT-REQUIRED": encodePaymentPayload(requirements) };
160
- }
161
- const paymentRequired = {
162
- x402Version: 2,
163
- resource: {
164
- url: "https://api.example.com",
165
- description: "API Access"
166
- },
167
- accepts: [requirements]
168
- };
169
- return { "PAYMENT-REQUIRED": Buffer.from(JSON.stringify(paymentRequired)).toString("base64") };
170
- };
171
- var createSettlementHeaders = (response, version) => {
172
- if (version === 1) {
173
- const isSuccess2 = "success" in response ? response.success : response.status === "success";
174
- const txHash2 = "transaction" in response ? response.transaction : response.txHash || "";
175
- const settlementJson2 = JSON.stringify({
176
- status: isSuccess2 ? "success" : "failed",
177
- txHash: txHash2 ?? ""
178
- });
179
- return { "X-PAYMENT-RESPONSE": Buffer.from(settlementJson2).toString("base64") };
180
- }
181
- const txHash = "transaction" in response ? response.transaction : response.txHash || "";
182
- const isSuccess = "success" in response ? response.success : response.status === "success";
183
- const settlementJson = JSON.stringify({
184
- status: isSuccess ? "success" : "failed",
185
- txHash: txHash || ""
186
- });
187
- return { "PAYMENT-RESPONSE": Buffer.from(settlementJson).toString("base64") };
188
- };
189
-
190
- // src/middleware-config.ts
191
- import {
192
- resolveNetwork,
193
- resolveToken,
194
- validateAcceptConfig,
195
- isValidationError,
196
- normalizeNetworkName as normalizeNetworkName2
197
- } from "@armory-sh/base";
198
-
199
- // src/routes.ts
200
- import { decodePayment, isExactEvmPayload, matchRoute, validateRouteConfig } from "@armory-sh/base";
201
- var resolveRouteConfig = (config) => {
202
- const validationError = validateRouteConfig(config);
203
- if (validationError) {
204
- return { routes: [], error: validationError };
205
- }
206
- const { route, routes, perRoute, ...baseConfig } = config;
207
- const routePatterns = route ? [route] : routes || [];
208
- const resolvedRoutes = [];
209
- for (const pattern of routePatterns) {
210
- const perRouteOverride = perRoute?.[pattern];
211
- const mergedConfig = {
212
- ...baseConfig,
213
- ...perRouteOverride
214
- };
215
- resolvedRoutes.push({
216
- pattern,
217
- config: mergedConfig
218
- });
219
- }
220
- return { routes: resolvedRoutes };
221
- };
5
+ // src/index.ts
222
6
  var parsePaymentHeader = async (request) => {
223
7
  const paymentSig = request.headers.get("PAYMENT-SIGNATURE");
224
8
  if (paymentSig) {
@@ -259,7 +43,7 @@ var errorResponse = (error, status, headers, accepts) => new Response(JSON.strin
259
43
  var createSettlementResponse = (success, txHash) => ({
260
44
  success,
261
45
  transaction: txHash ?? "",
262
- errorReason: success ? void 0 : "Settlement failed",
46
+ errorReason: void 0 ,
263
47
  network: "base"
264
48
  });
265
49
  var successResponse = (payerAddress, version, settlement) => {
@@ -283,21 +67,11 @@ var successResponse = (payerAddress, version, settlement) => {
283
67
  }
284
68
  );
285
69
  };
286
- var createRouteAwareBunMiddleware = (config) => {
287
- const { routes: resolvedRoutes, error: configError } = resolveRouteConfig(config);
70
+ var createBunMiddleware = (config) => {
71
+ const { facilitator, settlementMode = "verify", defaultVersion = 2, waitForSettlement = false } = config;
72
+ const requirementsV1 = createPaymentRequirements(config, 1);
73
+ const requirementsV2 = createPaymentRequirements(config, 2);
288
74
  return async (request) => {
289
- if (configError) {
290
- return errorResponse(`Payment middleware configuration error: ${configError.message}`, 500);
291
- }
292
- const path = new URL(request.url).pathname;
293
- const matchedRoute = resolvedRoutes.find((r) => matchRoute(r.pattern, path));
294
- if (!matchedRoute) {
295
- return null;
296
- }
297
- const routeConfig = matchedRoute.config;
298
- const { facilitator, settlementMode = "verify", defaultVersion = 2, waitForSettlement = false } = routeConfig;
299
- const requirementsV1 = createPaymentRequirements(routeConfig, 1);
300
- const requirementsV2 = createPaymentRequirements(routeConfig, 2);
301
75
  const paymentResult = await parsePaymentHeader(request);
302
76
  if (!paymentResult) {
303
77
  const requirements = defaultVersion === 1 ? requirementsV1 : requirementsV2;
@@ -326,104 +100,4 @@ var createRouteAwareBunMiddleware = (config) => {
326
100
  };
327
101
  };
328
102
 
329
- // src/index.ts
330
- var parsePaymentHeader2 = async (request) => {
331
- const paymentSig = request.headers.get("PAYMENT-SIGNATURE");
332
- if (paymentSig) {
333
- try {
334
- const payload = decodePayment2(paymentSig);
335
- if (isExactEvmPayload2(payload)) {
336
- return { payload, version: 2, payerAddress: payload.authorization.from };
337
- }
338
- } catch {
339
- }
340
- }
341
- const xPayment = request.headers.get("X-PAYMENT");
342
- if (xPayment) {
343
- try {
344
- const payload = decodePayment2(xPayment);
345
- if (isExactEvmPayload2(payload)) {
346
- return { payload, version: 2, payerAddress: payload.authorization.from };
347
- }
348
- if (payload && typeof payload === "object" && "from" in payload && typeof payload.from === "string") {
349
- return { payload, version: 1, payerAddress: payload.from };
350
- }
351
- } catch {
352
- }
353
- }
354
- return null;
355
- };
356
- var toHttpRequest2 = (request) => {
357
- const headers = {};
358
- request.headers.forEach((v, k) => {
359
- headers[k] = v;
360
- });
361
- return { headers, method: request.method, url: request.url };
362
- };
363
- var errorResponse2 = (error, status, headers, accepts) => new Response(JSON.stringify({ error, accepts }), {
364
- status,
365
- headers: { "Content-Type": "application/json", ...headers }
366
- });
367
- var createSettlementResponse2 = (success, txHash) => ({
368
- success,
369
- transaction: txHash ?? "",
370
- errorReason: success ? void 0 : "Settlement failed",
371
- network: "base"
372
- });
373
- var successResponse2 = (payerAddress, version, settlement) => {
374
- const isSuccess = settlement?.success;
375
- const txHash = settlement?.transaction;
376
- return new Response(
377
- JSON.stringify({
378
- verified: true,
379
- payerAddress,
380
- version,
381
- settlement: settlement ? { success: isSuccess, txHash } : void 0
382
- }),
383
- {
384
- status: 200,
385
- headers: {
386
- "Content-Type": "application/json",
387
- "X-Payment-Verified": "true",
388
- "X-Payer-Address": payerAddress,
389
- ...settlement ? createSettlementHeaders(settlement, version) : {}
390
- }
391
- }
392
- );
393
- };
394
- var createBunMiddleware = (config) => {
395
- const { facilitator, settlementMode = "verify", defaultVersion = 2, waitForSettlement = false } = config;
396
- const requirementsV1 = createPaymentRequirements(config, 1);
397
- const requirementsV2 = createPaymentRequirements(config, 2);
398
- return async (request) => {
399
- const paymentResult = await parsePaymentHeader2(request);
400
- if (!paymentResult) {
401
- const requirements = defaultVersion === 1 ? requirementsV1 : requirementsV2;
402
- return errorResponse2("Payment required", 402, createPaymentRequiredHeaders(requirements, defaultVersion), [requirements]);
403
- }
404
- const { version, payerAddress } = paymentResult;
405
- if (facilitator) {
406
- const verifyResult = await verifyWithFacilitator(toHttpRequest2(request), facilitator);
407
- if (!verifyResult.success) {
408
- const requirements = version === 1 ? requirementsV1 : requirementsV2;
409
- return errorResponse2(`Payment verification failed: ${verifyResult.error}`, 402, createPaymentRequiredHeaders(requirements, version), [requirements]);
410
- }
411
- }
412
- if (settlementMode === "settle" && facilitator) {
413
- const settle = async () => {
414
- const result = await settleWithFacilitator(toHttpRequest2(request), facilitator);
415
- return result.success ? successResponse2(payerAddress, version, createSettlementResponse2(true, result.txHash)) : errorResponse2(result.error ?? "Settlement failed", 400);
416
- };
417
- if (waitForSettlement) {
418
- return await settle();
419
- }
420
- settle().catch(console.error);
421
- return successResponse2(payerAddress, version);
422
- }
423
- return successResponse2(payerAddress, version);
424
- };
425
- };
426
- export {
427
- createBunMiddleware,
428
- createRouteAwareBunMiddleware
429
- };
103
+ export { createBunMiddleware };
package/dist/routes.js CHANGED
@@ -1,320 +1 @@
1
- // src/routes.ts
2
- import { decodePayment, isExactEvmPayload, matchRoute, validateRouteConfig } from "@armory-sh/base";
3
-
4
- // src/core.ts
5
- import {
6
- getNetworkConfig,
7
- getNetworkByChainId,
8
- encodePaymentPayload,
9
- normalizeNetworkName
10
- } from "@armory-sh/base";
11
- var toSlug = (network) => {
12
- if (typeof network === "number") {
13
- const net = getNetworkByChainId(network);
14
- if (!net) throw new Error(`No network found for chainId: ${network}`);
15
- return normalizeNetworkName(net.name);
16
- }
17
- if (network.startsWith("eip155:")) {
18
- const chainId = parseInt(network.split(":")[1], 10);
19
- const net = getNetworkByChainId(chainId);
20
- if (!net) throw new Error(`No network found for chainId: ${chainId}`);
21
- return normalizeNetworkName(net.name);
22
- }
23
- return normalizeNetworkName(network);
24
- };
25
- var toEip155 = (network) => {
26
- if (typeof network === "number") {
27
- const net2 = getNetworkByChainId(network);
28
- if (!net2) throw new Error(`No network found for chainId: ${network}`);
29
- return net2.caip2Id;
30
- }
31
- if (network.startsWith("eip155:")) {
32
- const net2 = getNetworkConfig(network);
33
- if (!net2) throw new Error(`No network found for: ${network}`);
34
- return net2.caip2Id;
35
- }
36
- const slug = normalizeNetworkName(network);
37
- const net = getNetworkConfig(slug);
38
- if (!net) throw new Error(`No network found for: ${slug}`);
39
- return net.caip2Id;
40
- };
41
- var getNetworkName = (network) => toSlug(network);
42
- var getChainId = (network) => toEip155(network);
43
- var createV1Requirements = (config, expiry) => {
44
- const networkName = getNetworkName(config.network);
45
- const network = getNetworkConfig(networkName);
46
- if (!network) throw new Error(`Unsupported network: ${networkName}`);
47
- return {
48
- amount: config.amount,
49
- network: networkName,
50
- contractAddress: network.usdcAddress,
51
- payTo: config.payTo,
52
- expiry
53
- };
54
- };
55
- var createV2Requirements = (config, expiry) => {
56
- const networkName = getNetworkName(config.network);
57
- const network = getNetworkConfig(networkName);
58
- if (!network) throw new Error(`Unsupported network: ${networkName}`);
59
- return {
60
- amount: config.amount,
61
- to: config.payTo,
62
- chainId: getChainId(config.network),
63
- assetId: network.caipAssetId,
64
- nonce: `${Date.now()}-${crypto.randomUUID()}`,
65
- expiry
66
- };
67
- };
68
- var createPaymentRequirements = (config, version = 1) => {
69
- const networkName = getNetworkName(config.network);
70
- const network = getNetworkConfig(networkName);
71
- if (!network) throw new Error(`Unsupported network: ${networkName}`);
72
- const expiry = Math.floor(Date.now() / 1e3) + 3600;
73
- return version === 1 ? createV1Requirements(config, expiry) : createV2Requirements(config, expiry);
74
- };
75
- var findHeaderValue = (headers, name) => {
76
- const value = headers[name];
77
- if (typeof value === "string") return value;
78
- if (Array.isArray(value) && value.length > 0) return value[0];
79
- const lowerName = name.toLowerCase();
80
- for (const [key, val] of Object.entries(headers)) {
81
- if (key.toLowerCase() === lowerName) {
82
- if (typeof val === "string") return val;
83
- if (Array.isArray(val) && val.length > 0) return val[0];
84
- }
85
- }
86
- return void 0;
87
- };
88
- var parseHeader = (header) => {
89
- try {
90
- if (header.startsWith("{")) return JSON.parse(header);
91
- return JSON.parse(atob(header));
92
- } catch {
93
- return null;
94
- }
95
- };
96
- var extractPaymentPayload = (request) => {
97
- const v1Header = findHeaderValue(request.headers, "X-PAYMENT");
98
- if (v1Header) return parseHeader(v1Header);
99
- const v2Header = findHeaderValue(request.headers, "PAYMENT-SIGNATURE");
100
- if (v2Header) return parseHeader(v2Header);
101
- return null;
102
- };
103
- var postFacilitator = async (url, headers, body) => {
104
- const response = await fetch(url, {
105
- method: "POST",
106
- headers: { "Content-Type": "application/json", ...headers },
107
- body: JSON.stringify(body)
108
- });
109
- if (!response.ok) {
110
- const error = await response.text();
111
- throw new Error(error || `Request failed: ${response.status}`);
112
- }
113
- return response.json();
114
- };
115
- var verifyWithFacilitator = async (request, facilitator) => {
116
- const payload = extractPaymentPayload(request);
117
- if (!payload) {
118
- return { success: false, error: "No payment payload found in request headers" };
119
- }
120
- try {
121
- const url = new URL("/verify", facilitator.url);
122
- const headers = facilitator.createHeaders?.() ?? {};
123
- const data = await postFacilitator(url.toString(), headers, { payload, headers: request.headers });
124
- return {
125
- success: true,
126
- payerAddress: data.payerAddress,
127
- balance: data.balance,
128
- requiredAmount: data.requiredAmount
129
- };
130
- } catch (error) {
131
- return {
132
- success: false,
133
- error: error instanceof Error ? error.message : "Unknown verification error"
134
- };
135
- }
136
- };
137
- var settleWithFacilitator = async (request, facilitator) => {
138
- const payload = extractPaymentPayload(request);
139
- if (!payload) {
140
- return { success: false, error: "No payment payload found in request headers" };
141
- }
142
- try {
143
- const url = new URL("/settle", facilitator.url);
144
- const headers = facilitator.createHeaders?.() ?? {};
145
- const data = await postFacilitator(url.toString(), headers, { payload, headers: request.headers });
146
- return {
147
- success: true,
148
- txHash: data.txHash
149
- };
150
- } catch (error) {
151
- return {
152
- success: false,
153
- error: error instanceof Error ? error.message : "Unknown settlement error"
154
- };
155
- }
156
- };
157
- var createPaymentRequiredHeaders = (requirements, version) => {
158
- if (version === 1) {
159
- return { "X-PAYMENT-REQUIRED": encodePaymentPayload(requirements) };
160
- }
161
- const paymentRequired = {
162
- x402Version: 2,
163
- resource: {
164
- url: "https://api.example.com",
165
- description: "API Access"
166
- },
167
- accepts: [requirements]
168
- };
169
- return { "PAYMENT-REQUIRED": Buffer.from(JSON.stringify(paymentRequired)).toString("base64") };
170
- };
171
- var createSettlementHeaders = (response, version) => {
172
- if (version === 1) {
173
- const isSuccess2 = "success" in response ? response.success : response.status === "success";
174
- const txHash2 = "transaction" in response ? response.transaction : response.txHash || "";
175
- const settlementJson2 = JSON.stringify({
176
- status: isSuccess2 ? "success" : "failed",
177
- txHash: txHash2 ?? ""
178
- });
179
- return { "X-PAYMENT-RESPONSE": Buffer.from(settlementJson2).toString("base64") };
180
- }
181
- const txHash = "transaction" in response ? response.transaction : response.txHash || "";
182
- const isSuccess = "success" in response ? response.success : response.status === "success";
183
- const settlementJson = JSON.stringify({
184
- status: isSuccess ? "success" : "failed",
185
- txHash: txHash || ""
186
- });
187
- return { "PAYMENT-RESPONSE": Buffer.from(settlementJson).toString("base64") };
188
- };
189
-
190
- // src/routes.ts
191
- var resolveRouteConfig = (config) => {
192
- const validationError = validateRouteConfig(config);
193
- if (validationError) {
194
- return { routes: [], error: validationError };
195
- }
196
- const { route, routes, perRoute, ...baseConfig } = config;
197
- const routePatterns = route ? [route] : routes || [];
198
- const resolvedRoutes = [];
199
- for (const pattern of routePatterns) {
200
- const perRouteOverride = perRoute?.[pattern];
201
- const mergedConfig = {
202
- ...baseConfig,
203
- ...perRouteOverride
204
- };
205
- resolvedRoutes.push({
206
- pattern,
207
- config: mergedConfig
208
- });
209
- }
210
- return { routes: resolvedRoutes };
211
- };
212
- var parsePaymentHeader = async (request) => {
213
- const paymentSig = request.headers.get("PAYMENT-SIGNATURE");
214
- if (paymentSig) {
215
- try {
216
- const payload = decodePayment(paymentSig);
217
- if (isExactEvmPayload(payload)) {
218
- return { payload, version: 2, payerAddress: payload.authorization.from };
219
- }
220
- } catch {
221
- }
222
- }
223
- const xPayment = request.headers.get("X-PAYMENT");
224
- if (xPayment) {
225
- try {
226
- const payload = decodePayment(xPayment);
227
- if (isExactEvmPayload(payload)) {
228
- return { payload, version: 2, payerAddress: payload.authorization.from };
229
- }
230
- if (payload && typeof payload === "object" && "from" in payload && typeof payload.from === "string") {
231
- return { payload, version: 1, payerAddress: payload.from };
232
- }
233
- } catch {
234
- }
235
- }
236
- return null;
237
- };
238
- var toHttpRequest = (request) => {
239
- const headers = {};
240
- request.headers.forEach((v, k) => {
241
- headers[k] = v;
242
- });
243
- return { headers, method: request.method, url: request.url };
244
- };
245
- var errorResponse = (error, status, headers, accepts) => new Response(JSON.stringify({ error, accepts }), {
246
- status,
247
- headers: { "Content-Type": "application/json", ...headers }
248
- });
249
- var createSettlementResponse = (success, txHash) => ({
250
- success,
251
- transaction: txHash ?? "",
252
- errorReason: success ? void 0 : "Settlement failed",
253
- network: "base"
254
- });
255
- var successResponse = (payerAddress, version, settlement) => {
256
- const isSuccess = settlement?.success;
257
- const txHash = settlement?.transaction;
258
- return new Response(
259
- JSON.stringify({
260
- verified: true,
261
- payerAddress,
262
- version,
263
- settlement: settlement ? { success: isSuccess, txHash } : void 0
264
- }),
265
- {
266
- status: 200,
267
- headers: {
268
- "Content-Type": "application/json",
269
- "X-Payment-Verified": "true",
270
- "X-Payer-Address": payerAddress,
271
- ...settlement ? createSettlementHeaders(settlement, version) : {}
272
- }
273
- }
274
- );
275
- };
276
- var createRouteAwareBunMiddleware = (config) => {
277
- const { routes: resolvedRoutes, error: configError } = resolveRouteConfig(config);
278
- return async (request) => {
279
- if (configError) {
280
- return errorResponse(`Payment middleware configuration error: ${configError.message}`, 500);
281
- }
282
- const path = new URL(request.url).pathname;
283
- const matchedRoute = resolvedRoutes.find((r) => matchRoute(r.pattern, path));
284
- if (!matchedRoute) {
285
- return null;
286
- }
287
- const routeConfig = matchedRoute.config;
288
- const { facilitator, settlementMode = "verify", defaultVersion = 2, waitForSettlement = false } = routeConfig;
289
- const requirementsV1 = createPaymentRequirements(routeConfig, 1);
290
- const requirementsV2 = createPaymentRequirements(routeConfig, 2);
291
- const paymentResult = await parsePaymentHeader(request);
292
- if (!paymentResult) {
293
- const requirements = defaultVersion === 1 ? requirementsV1 : requirementsV2;
294
- return errorResponse("Payment required", 402, createPaymentRequiredHeaders(requirements, defaultVersion), [requirements]);
295
- }
296
- const { version, payerAddress } = paymentResult;
297
- if (facilitator) {
298
- const verifyResult = await verifyWithFacilitator(toHttpRequest(request), facilitator);
299
- if (!verifyResult.success) {
300
- const requirements = version === 1 ? requirementsV1 : requirementsV2;
301
- return errorResponse(`Payment verification failed: ${verifyResult.error}`, 402, createPaymentRequiredHeaders(requirements, version), [requirements]);
302
- }
303
- }
304
- if (settlementMode === "settle" && facilitator) {
305
- const settle = async () => {
306
- const result = await settleWithFacilitator(toHttpRequest(request), facilitator);
307
- return result.success ? successResponse(payerAddress, version, createSettlementResponse(true, result.txHash)) : errorResponse(result.error ?? "Settlement failed", 400);
308
- };
309
- if (waitForSettlement) {
310
- return await settle();
311
- }
312
- settle().catch(console.error);
313
- return successResponse(payerAddress, version);
314
- }
315
- return successResponse(payerAddress, version);
316
- };
317
- };
318
- export {
319
- createRouteAwareBunMiddleware
320
- };
1
+ export { createRouteAwareBunMiddleware } from './chunk-IP3DZBNP.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@armory-sh/middleware-bun",
3
- "version": "0.3.18",
3
+ "version": "0.3.19-alpha.3.13",
4
4
  "license": "MIT",
5
5
  "author": "Sawyer Cutler <sawyer@dirtroad.dev>",
6
6
  "type": "module",
@@ -20,11 +20,11 @@
20
20
  },
21
21
  "repository": {
22
22
  "type": "git",
23
- "url": "git+https://github.com/thegreataxios/armory.git",
23
+ "url": "git+https://github.com/TheGreatAxios/armory.git",
24
24
  "directory": "packages/middleware-bun"
25
25
  },
26
26
  "dependencies": {
27
- "@armory-sh/base": "0.2.20"
27
+ "@armory-sh/base": "workspace:*"
28
28
  },
29
29
  "devDependencies": {
30
30
  "bun-types": "latest",