@armory-sh/middleware 0.3.0 → 0.3.3

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 CHANGED
@@ -1,6 +1,12 @@
1
1
  # @armory-sh/middleware
2
2
 
3
- Payment verification middleware for Express, Hono, Bun, Elysia.
3
+ > **DEPRECATED**: Use framework-specific packages directly for smaller bundles and better type inference:
4
+ > - `@armory-sh/middleware-bun`
5
+ > - `@armory-sh/middleware-express`
6
+ > - `@armory-sh/middleware-hono`
7
+ > - `@armory-sh/middleware-elysia`
8
+
9
+ Barrel package for Armory middleware. Re-exports all framework-specific packages:
4
10
 
5
11
  ## Install
6
12
 
@@ -11,21 +17,21 @@ bun add @armory-sh/middleware
11
17
  ## Use
12
18
 
13
19
  ```typescript
14
- // Express
15
- import { paymentMiddleware } from '@armory-sh/middleware'
16
-
17
- app.use(paymentMiddleware({
18
- requirements: {
19
- to: '0x...',
20
- amount: 1000000n,
21
- expiry: Date.now() + 3600,
22
- chainId: 'eip155:8453',
23
- assetId: 'eip155:8453/erc20:0x...'
24
- },
25
- facilitatorUrl: 'https://facilitator.example.com'
26
- }))
20
+ // All exports from framework packages are available
21
+ import {
22
+ createBunMiddleware,
23
+ paymentMiddleware, // Express
24
+ acceptPaymentsViaArmory, // Hono
25
+ paymentMiddleware, // Elysia
26
+ } from '@armory-sh/middleware'
27
27
  ```
28
28
 
29
+ For framework-specific usage, see individual packages:
30
+ - Bun: `@armory-sh/middleware-bun`
31
+ - Express: `@armory-sh/middleware-express`
32
+ - Hono: `@armory-sh/middleware-hono`
33
+ - Elysia: `@armory-sh/middleware-elysia`
34
+
29
35
  ---
30
36
 
31
37
  MIT License | Sawyer Cutler 2026 | Provided "AS IS" without warranty
package/package.json CHANGED
@@ -1,38 +1,19 @@
1
1
  {
2
2
  "name": "@armory-sh/middleware",
3
- "version": "0.3.0",
3
+ "version": "0.3.3",
4
4
  "license": "MIT",
5
5
  "author": "Sawyer Cutler <sawyer@dirtroad.dev>",
6
6
  "type": "module",
7
- "main": "./dist/index.js",
8
- "types": "./dist/index.d.ts",
7
+ "main": "./src/index.ts",
8
+ "types": "./src/index.ts",
9
9
  "exports": {
10
10
  ".": {
11
- "types": "./dist/index.d.ts",
12
- "bun": "./src/index.ts",
13
- "default": "./dist/index.js"
14
- },
15
- "./integrations/hono": {
16
- "types": "./integrations/hono.ts",
17
- "default": "./integrations/hono.ts"
18
- },
19
- "./integrations/hono-simple": {
20
- "types": "./integrations/hono-simple.ts",
21
- "default": "./integrations/hono-simple.ts"
22
- },
23
- "./integrations/express": {
24
- "types": "./integrations/express.ts",
25
- "default": "./integrations/express.ts"
26
- },
27
- "./integrations/elysia": {
28
- "types": "./integrations/elysia.ts",
29
- "default": "./integrations/elysia.ts"
30
- },
31
- "./dist/*": "./dist/*.js"
11
+ "types": "./src/index.ts",
12
+ "default": "./src/index.ts"
13
+ }
32
14
  },
33
15
  "files": [
34
- "dist",
35
- "README.md"
16
+ "src"
36
17
  ],
37
18
  "publishConfig": {
38
19
  "access": "public"
@@ -43,15 +24,9 @@
43
24
  "directory": "packages/middleware"
44
25
  },
45
26
  "dependencies": {
46
- "@armory-sh/base": "0.2.2",
47
- "@armory-sh/facilitator": "0.2.2"
48
- },
49
- "devDependencies": {
50
- "typescript": "5.9.3",
51
- "bun-types": "latest"
52
- },
53
- "scripts": {
54
- "build": "tsup",
55
- "test": "bun test"
27
+ "@armory-sh/middleware-bun": "0.3.7",
28
+ "@armory-sh/middleware-express": "0.3.7",
29
+ "@armory-sh/middleware-hono": "0.3.7",
30
+ "@armory-sh/middleware-elysia": "0.3.7"
56
31
  }
57
32
  }
package/src/index.ts ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @deprecated Use framework-specific packages directly for smaller bundles and better type inference.
3
+ * This barrel package re-exports all framework middleware packages.
4
+ */
5
+
6
+ // Bun
7
+ export * from "@armory-sh/middleware-bun";
8
+
9
+ // Express
10
+ export { paymentMiddleware as expressPaymentMiddleware } from "@armory-sh/middleware-express";
11
+ export type { PaymentMiddlewareConfig as ExpressPaymentMiddlewareConfig } from "@armory-sh/middleware-express";
12
+
13
+ // Hono
14
+ export * from "@armory-sh/middleware-hono";
15
+
16
+ // Elysia
17
+ export { paymentMiddleware as elysiaPaymentMiddleware } from "@armory-sh/middleware-elysia";
18
+ export type { PaymentMiddlewareConfig as ElysiaPaymentMiddlewareConfig } from "@armory-sh/middleware-elysia";
package/dist/index.d.ts DELETED
@@ -1,203 +0,0 @@
1
- import * as _armory_sh_base from '@armory-sh/base';
2
- import { Address, CAIP2ChainId, CAIPAssetId, PaymentRequirements as PaymentRequirements$1, X402SettlementResponse, SettlementResponseV1, SettlementResponseV2, X402PaymentPayload, X402PaymentRequirements, ResolvedPaymentConfig, PricingConfig, AcceptPaymentOptions, NetworkId, TokenId, ValidationError } from '@armory-sh/base';
3
- export { AcceptPaymentOptions, NetworkId, PaymentRequirementsV1, PaymentRequirementsV2, SettlementResponseV1, SettlementResponseV2, FacilitatorConfig as SimpleFacilitatorConfig, TokenId } from '@armory-sh/base';
4
- import { X402VerifyOptions } from '@armory-sh/facilitator';
5
-
6
- interface FacilitatorConfig {
7
- url: string;
8
- createHeaders?: () => Record<string, string>;
9
- }
10
- type SettlementMode = "verify" | "settle" | "async";
11
- type PayToAddress = Address | CAIP2ChainId | CAIPAssetId;
12
- interface MiddlewareConfig {
13
- payTo: PayToAddress;
14
- network: string | number;
15
- amount: string;
16
- facilitator?: FacilitatorConfig;
17
- settlementMode?: SettlementMode;
18
- }
19
- interface HttpRequest {
20
- headers: Record<string, string | string[] | undefined>;
21
- body?: unknown;
22
- method?: string;
23
- url?: string;
24
- }
25
- interface HttpResponse {
26
- status: number;
27
- headers: Record<string, string>;
28
- body?: unknown;
29
- }
30
- interface FacilitatorVerifyResult {
31
- success: boolean;
32
- payerAddress?: string;
33
- balance?: string;
34
- requiredAmount?: string;
35
- error?: string;
36
- }
37
- interface FacilitatorSettleResult {
38
- success: boolean;
39
- txHash?: string;
40
- error?: string;
41
- }
42
-
43
- declare const createPaymentRequirements: (config: MiddlewareConfig, version?: 1 | 2) => PaymentRequirements$1;
44
- declare const verifyWithFacilitator: (request: HttpRequest, facilitator: FacilitatorConfig) => Promise<FacilitatorVerifyResult>;
45
- declare const settleWithFacilitator: (request: HttpRequest, facilitator: FacilitatorConfig) => Promise<FacilitatorSettleResult>;
46
- declare const createPaymentRequiredHeaders: (requirements: PaymentRequirements$1, version: 1 | 2) => Record<string, string>;
47
- /**
48
- * Accepts both X402SettlementResponse and legacy SettlementResponseV1/V2
49
- * For V1, manually constructs the header. For V2/x402, uses the x402 encoder.
50
- */
51
- declare const createSettlementHeaders: (response: X402SettlementResponse | SettlementResponseV1 | SettlementResponseV2, version: 1 | 2) => Record<string, string>;
52
-
53
- interface LegacyPaymentPayloadV1 {
54
- amount: string;
55
- network: string;
56
- contractAddress: string;
57
- payTo: string;
58
- from: string;
59
- expiry: number;
60
- signature: string;
61
- }
62
- interface LegacyPaymentPayloadV2 {
63
- to: string;
64
- from: string;
65
- amount: string;
66
- chainId: string;
67
- assetId: string;
68
- nonce: string;
69
- expiry: number;
70
- signature: string;
71
- }
72
- type AnyPaymentPayload = X402PaymentPayload | LegacyPaymentPayloadV1 | LegacyPaymentPayloadV2;
73
- type PaymentVersion = 1 | 2;
74
- interface PaymentVerificationResult {
75
- success: boolean;
76
- payload?: AnyPaymentPayload;
77
- version?: PaymentVersion;
78
- payerAddress?: string;
79
- error?: string;
80
- }
81
- interface PaymentHeaders {
82
- payment: string;
83
- required: string;
84
- response: string;
85
- }
86
- declare const getHeadersForVersion: (version: PaymentVersion) => PaymentHeaders;
87
- declare const getRequirementsVersion: (requirements: X402PaymentRequirements) => PaymentVersion;
88
- declare const encodeRequirements: (requirements: X402PaymentRequirements) => string;
89
- declare const decodePayload: (headerValue: string) => {
90
- payload: AnyPaymentPayload;
91
- version: PaymentVersion;
92
- };
93
- declare const verifyPaymentWithRetry: (payload: AnyPaymentPayload, requirements: X402PaymentRequirements, facilitatorUrl?: string, verifyOptions?: X402VerifyOptions) => Promise<PaymentVerificationResult>;
94
- /**
95
- * Extract payer address from various payload formats
96
- */
97
- declare const extractPayerAddress: (payload: AnyPaymentPayload) => string;
98
- declare const createResponseHeaders: (payerAddress: string, version: PaymentVersion) => Record<string, string>;
99
-
100
- /**
101
- * Simple one-line middleware API for Armory merchants
102
- * Focus on DX/UX - "everything just magically works"
103
- */
104
-
105
- /**
106
- * Simple configuration for acceptPaymentsViaArmory middleware
107
- */
108
- interface SimpleMiddlewareConfig {
109
- /** Address to receive payments */
110
- payTo: Address;
111
- /** Default amount to charge (default: "1.0") */
112
- amount?: string;
113
- /** Payment acceptance options */
114
- accept?: AcceptPaymentOptions;
115
- /** Fallback facilitator URL (if not using accept.facilitators) */
116
- facilitatorUrl?: string;
117
- /** Per-network/token/facilitator pricing overrides */
118
- pricing?: PricingConfig[];
119
- }
120
- /**
121
- * Resolved middleware configuration with all options validated
122
- */
123
- interface ResolvedMiddlewareConfig {
124
- /** All valid payment configurations (network/token combinations) */
125
- configs: ResolvedPaymentConfigWithPricing[];
126
- /** Protocol version */
127
- version: 1 | 2 | "auto";
128
- /** Facilitator configs */
129
- facilitators: FacilitatorConfig[];
130
- }
131
- /** Extended config with pricing info */
132
- interface ResolvedPaymentConfigWithPricing extends ResolvedPaymentConfig {
133
- /** Facilitator URL (for per-facilitator pricing) */
134
- facilitatorUrl?: string;
135
- /** Pricing config entry (if any) */
136
- pricing?: PricingConfig;
137
- }
138
- /**
139
- * Resolve simple middleware config to full config
140
- */
141
- declare const resolveMiddlewareConfig: (config: SimpleMiddlewareConfig) => ResolvedMiddlewareConfig | ValidationError;
142
- /**
143
- * Get payment requirements for a specific network/token combination
144
- */
145
- declare const getRequirements: (config: ResolvedMiddlewareConfig, network: NetworkId, token: TokenId) => PaymentRequirements$1 | ValidationError;
146
- /**
147
- * Get primary/default middleware config for legacy middlewares
148
- */
149
- declare const getPrimaryConfig: (resolved: ResolvedMiddlewareConfig) => MiddlewareConfig;
150
- /**
151
- * Get all supported networks from config
152
- */
153
- declare const getSupportedNetworks: (config: ResolvedMiddlewareConfig) => string[];
154
- /**
155
- * Get all supported tokens from config
156
- */
157
- declare const getSupportedTokens: (config: ResolvedMiddlewareConfig) => string[];
158
- /**
159
- * Check if a network/token combination is supported
160
- */
161
- declare const isSupported: (config: ResolvedMiddlewareConfig, network: NetworkId, token: TokenId) => boolean;
162
-
163
- type BunMiddleware = (request: Request) => Promise<Response | null>;
164
- interface BunMiddlewareConfig extends MiddlewareConfig {
165
- defaultVersion?: 1 | 2;
166
- waitForSettlement?: boolean;
167
- }
168
- declare const createBunMiddleware: (config: BunMiddlewareConfig) => BunMiddleware;
169
- /**
170
- * One-line middleware setup for accepting Armory payments
171
- *
172
- * @example
173
- * ```ts
174
- * // Simple usage - default USDC on Base
175
- * app.use(acceptPaymentsViaArmory({
176
- * payTo: "0xMerchantAddress...",
177
- * amount: "1.0"
178
- * }));
179
- *
180
- * // Multi-network, multi-token support
181
- * app.use(acceptPaymentsViaArmory({
182
- * payTo: "0xMerchantAddress...",
183
- * amount: "1.0",
184
- * accept: {
185
- * networks: ["base", "skale-base", "ethereum"],
186
- * tokens: ["usdc", "eurc"],
187
- * facilitators: [
188
- * { url: "https://facilitator1.com" },
189
- * { url: "https://facilitator2.com" }
190
- * ]
191
- * }
192
- * }));
193
- * ```
194
- */
195
- declare const acceptPaymentsViaArmory: (config: SimpleMiddlewareConfig & {
196
- defaultVersion?: 1 | 2;
197
- waitForSettlement?: boolean;
198
- }) => BunMiddleware;
199
-
200
- type PaymentRequirements = _armory_sh_base.PaymentRequirementsV1 | _armory_sh_base.PaymentRequirementsV2;
201
- type SettlementResponse = _armory_sh_base.SettlementResponseV1 | _armory_sh_base.SettlementResponseV2;
202
-
203
- export { type AnyPaymentPayload, type BunMiddleware, type BunMiddlewareConfig, type FacilitatorConfig, type FacilitatorSettleResult, type FacilitatorVerifyResult, type HttpRequest, type HttpResponse, type LegacyPaymentPayloadV1, type LegacyPaymentPayloadV2, type MiddlewareConfig, type PayToAddress, type AnyPaymentPayload as PaymentPayload, type PaymentRequirements, type PaymentVerificationResult, type PaymentVersion, type ResolvedMiddlewareConfig, type ResolvedPaymentConfigWithPricing, type SettlementMode, type SettlementResponse, type SimpleMiddlewareConfig, acceptPaymentsViaArmory, createBunMiddleware, createPaymentRequiredHeaders, createPaymentRequirements, createResponseHeaders, createSettlementHeaders, decodePayload, encodeRequirements, extractPayerAddress, getHeadersForVersion, getPrimaryConfig, getRequirements, getRequirementsVersion, getSupportedNetworks, getSupportedTokens, isSupported, resolveMiddlewareConfig, settleWithFacilitator, verifyPaymentWithRetry, verifyWithFacilitator };
package/dist/index.js DELETED
@@ -1,508 +0,0 @@
1
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
- }) : x)(function(x) {
4
- if (typeof require !== "undefined") return require.apply(this, arguments);
5
- throw Error('Dynamic require of "' + x + '" is not supported');
6
- });
7
-
8
- // src/core.ts
9
- import {
10
- getNetworkConfig,
11
- getNetworkByChainId
12
- } from "@armory-sh/base";
13
- var getNetworkName = (network) => {
14
- if (typeof network === "string") return network;
15
- const net = getNetworkByChainId(network);
16
- if (!net) throw new Error(`No network found for chainId: ${network}`);
17
- return net.name.toLowerCase().replace(" mainnet", "").replace(" sepolia", "-sepolia");
18
- };
19
- var createV1Requirements = (config, expiry) => {
20
- const networkName = getNetworkName(config.network);
21
- const network = getNetworkConfig(networkName);
22
- if (!network) throw new Error(`Unsupported network: ${networkName}`);
23
- return {
24
- amount: config.amount,
25
- network: networkName,
26
- contractAddress: network.usdcAddress,
27
- payTo: config.payTo,
28
- expiry
29
- };
30
- };
31
- var createV2Requirements = (config, expiry) => {
32
- const networkName = getNetworkName(config.network);
33
- const network = getNetworkConfig(networkName);
34
- if (!network) throw new Error(`Unsupported network: ${networkName}`);
35
- return {
36
- amount: config.amount,
37
- to: config.payTo,
38
- chainId: network.caip2Id,
39
- assetId: network.caipAssetId,
40
- nonce: `${Date.now()}-${crypto.randomUUID()}`,
41
- expiry
42
- };
43
- };
44
- var createPaymentRequirements = (config, version = 1) => {
45
- const networkName = getNetworkName(config.network);
46
- const network = getNetworkConfig(networkName);
47
- if (!network) throw new Error(`Unsupported network: ${networkName}`);
48
- const expiry = Math.floor(Date.now() / 1e3) + 3600;
49
- return version === 1 ? createV1Requirements(config, expiry) : createV2Requirements(config, expiry);
50
- };
51
- var findHeaderValue = (headers, name) => {
52
- const value = headers[name];
53
- if (typeof value === "string") return value;
54
- if (Array.isArray(value) && value.length > 0) return value[0];
55
- const lowerName = name.toLowerCase();
56
- for (const [key, val] of Object.entries(headers)) {
57
- if (key.toLowerCase() === lowerName) {
58
- if (typeof val === "string") return val;
59
- if (Array.isArray(val) && val.length > 0) return val[0];
60
- }
61
- }
62
- return void 0;
63
- };
64
- var parseHeader = (header) => {
65
- try {
66
- if (header.startsWith("{")) return JSON.parse(header);
67
- return JSON.parse(atob(header));
68
- } catch {
69
- return null;
70
- }
71
- };
72
- var extractPaymentPayload = (request) => {
73
- const v1Header = findHeaderValue(request.headers, "X-PAYMENT");
74
- if (v1Header) return parseHeader(v1Header);
75
- const v2Header = findHeaderValue(request.headers, "PAYMENT-SIGNATURE");
76
- if (v2Header) return parseHeader(v2Header);
77
- return null;
78
- };
79
- var postFacilitator = async (url, headers, body) => {
80
- const response = await fetch(url, {
81
- method: "POST",
82
- headers: { "Content-Type": "application/json", ...headers },
83
- body: JSON.stringify(body)
84
- });
85
- if (!response.ok) {
86
- const error = await response.text();
87
- throw new Error(error || `Request failed: ${response.status}`);
88
- }
89
- return response.json();
90
- };
91
- var verifyWithFacilitator = async (request, facilitator) => {
92
- const payload = extractPaymentPayload(request);
93
- if (!payload) {
94
- return { success: false, error: "No payment payload found in request headers" };
95
- }
96
- try {
97
- const url = new URL("/verify", facilitator.url);
98
- const headers = facilitator.createHeaders?.() ?? {};
99
- const data = await postFacilitator(url.toString(), headers, { payload, headers: request.headers });
100
- return {
101
- success: true,
102
- payerAddress: data.payerAddress,
103
- balance: data.balance,
104
- requiredAmount: data.requiredAmount
105
- };
106
- } catch (error) {
107
- return {
108
- success: false,
109
- error: error instanceof Error ? error.message : "Unknown verification error"
110
- };
111
- }
112
- };
113
- var settleWithFacilitator = async (request, facilitator) => {
114
- const payload = extractPaymentPayload(request);
115
- if (!payload) {
116
- return { success: false, error: "No payment payload found in request headers" };
117
- }
118
- try {
119
- const url = new URL("/settle", facilitator.url);
120
- const headers = facilitator.createHeaders?.() ?? {};
121
- const data = await postFacilitator(url.toString(), headers, { payload, headers: request.headers });
122
- return {
123
- success: true,
124
- txHash: data.txHash
125
- };
126
- } catch (error) {
127
- return {
128
- success: false,
129
- error: error instanceof Error ? error.message : "Unknown settlement error"
130
- };
131
- }
132
- };
133
- var createPaymentRequiredHeaders = (requirements, version) => {
134
- if (version === 1) {
135
- const { encodePaymentPayload: encodeV1Payload } = __require("@armory-sh/base");
136
- return { "X-PAYMENT-REQUIRED": encodeV1Payload(requirements) };
137
- }
138
- return { "PAYMENT-REQUIRED": Buffer.from(JSON.stringify(requirements)).toString("base64") };
139
- };
140
- var createSettlementHeaders = (response, version) => {
141
- if (version === 1) {
142
- const isSuccess2 = "success" in response ? response.success : response.status === "success";
143
- const txHash2 = "transaction" in response ? response.transaction : response.txHash || "";
144
- const settlementJson2 = JSON.stringify({
145
- status: isSuccess2 ? "success" : "failed",
146
- txHash: txHash2 ?? ""
147
- });
148
- return { "X-PAYMENT-RESPONSE": Buffer.from(settlementJson2).toString("base64") };
149
- }
150
- const txHash = "transaction" in response ? response.transaction : response.txHash || "";
151
- const isSuccess = "success" in response ? response.success : response.status === "success";
152
- const settlementJson = JSON.stringify({
153
- status: isSuccess ? "success" : "failed",
154
- txHash: txHash || ""
155
- });
156
- return { "PAYMENT-RESPONSE": Buffer.from(settlementJson).toString("base64") };
157
- };
158
-
159
- // src/payment-utils.ts
160
- import { extractPaymentFromHeaders, X402_HEADERS } from "@armory-sh/base";
161
- import { verifyX402Payment as verifyPayment } from "@armory-sh/facilitator";
162
- var getHeadersForVersion = (version) => version === 1 ? { payment: "X-PAYMENT", required: "X-PAYMENT-REQUIRED", response: "X-PAYMENT-RESPONSE" } : { payment: "PAYMENT-SIGNATURE", required: "PAYMENT-REQUIRED", response: "PAYMENT-RESPONSE" };
163
- var getRequirementsVersion = (requirements) => "contractAddress" in requirements && "network" in requirements ? 1 : 2;
164
- var encodeRequirements = (requirements) => JSON.stringify(requirements);
165
- function isLegacyV1(payload) {
166
- return typeof payload === "object" && payload !== null && "contractAddress" in payload && "network" in payload && "signature" in payload && typeof payload.signature === "string";
167
- }
168
- function isLegacyV2(payload) {
169
- return typeof payload === "object" && payload !== null && "chainId" in payload && "assetId" in payload && "signature" in payload && typeof payload.signature === "string";
170
- }
171
- var decodePayload = (headerValue) => {
172
- let parsed;
173
- try {
174
- if (headerValue.startsWith("{")) {
175
- parsed = JSON.parse(headerValue);
176
- } else {
177
- parsed = JSON.parse(atob(headerValue));
178
- }
179
- } catch {
180
- throw new Error("Invalid payment payload");
181
- }
182
- const headers = new Headers();
183
- headers.set(X402_HEADERS.PAYMENT, headerValue);
184
- const x402Payload = extractPaymentFromHeaders(headers);
185
- if (x402Payload) {
186
- return { payload: x402Payload, version: 2 };
187
- }
188
- if (isLegacyV1(parsed)) {
189
- return { payload: parsed, version: 1 };
190
- }
191
- if (isLegacyV2(parsed)) {
192
- return { payload: parsed, version: 2 };
193
- }
194
- throw new Error("Unrecognized payment payload format");
195
- };
196
- var verifyWithFacilitator2 = async (facilitatorUrl, payload, requirements, verifyOptions) => {
197
- try {
198
- const response = await fetch(`${facilitatorUrl}/verify`, {
199
- method: "POST",
200
- headers: { "Content-Type": "application/json" },
201
- body: JSON.stringify({ payload, requirements, options: verifyOptions })
202
- });
203
- if (!response.ok) {
204
- const error = await response.json();
205
- return { success: false, error: JSON.stringify(error) };
206
- }
207
- const result = await response.json();
208
- if (!result.success) {
209
- return { success: false, error: result.error ?? "Verification failed" };
210
- }
211
- return { success: true, payerAddress: result.payerAddress ?? "" };
212
- } catch (error) {
213
- return {
214
- success: false,
215
- error: error instanceof Error ? error.message : "Unknown facilitator error"
216
- };
217
- }
218
- };
219
- var verifyLocally = async (payload, requirements, verifyOptions) => {
220
- if (isLegacyV1(payload) || isLegacyV2(payload)) {
221
- return {
222
- success: false,
223
- error: "Local verification not supported for legacy payload formats. Use a facilitator."
224
- };
225
- }
226
- const result = await verifyPayment(payload, requirements, verifyOptions);
227
- if (!result.success) {
228
- return {
229
- success: false,
230
- error: JSON.stringify({
231
- error: "Payment verification failed",
232
- reason: result.error.name,
233
- message: result.error.message
234
- })
235
- };
236
- }
237
- return { success: true, payerAddress: result.payerAddress };
238
- };
239
- var verifyPaymentWithRetry = async (payload, requirements, facilitatorUrl, verifyOptions) => facilitatorUrl ? verifyWithFacilitator2(facilitatorUrl, payload, requirements, verifyOptions) : verifyLocally(payload, requirements, verifyOptions);
240
- var extractPayerAddress = (payload) => {
241
- if ("payload" in payload) {
242
- const x402Payload = payload;
243
- if ("authorization" in x402Payload.payload) {
244
- return x402Payload.payload.authorization.from;
245
- }
246
- }
247
- if ("from" in payload && typeof payload.from === "string") {
248
- return payload.from;
249
- }
250
- throw new Error("Unable to extract payer address from payload");
251
- };
252
- var createResponseHeaders = (payerAddress, version) => ({
253
- [getHeadersForVersion(version).response]: JSON.stringify({
254
- status: "verified",
255
- payerAddress,
256
- version
257
- })
258
- });
259
-
260
- // src/bun.ts
261
- import { decodePayment, isExactEvmPayload, X402_HEADERS as X402_HEADERS2 } from "@armory-sh/base";
262
-
263
- // src/simple.ts
264
- import {
265
- resolveNetwork,
266
- resolveToken,
267
- validateAcceptConfig,
268
- isValidationError
269
- } from "@armory-sh/base";
270
- var findPricingConfig = (pricing, network, token, facilitatorUrl) => {
271
- if (!pricing) return void 0;
272
- const withFacilitator = pricing.find(
273
- (p) => p.network === network && p.token === token && p.facilitator === facilitatorUrl
274
- );
275
- if (withFacilitator) return withFacilitator;
276
- const withNetworkToken = pricing.find(
277
- (p) => p.network === network && p.token === token && !p.facilitator
278
- );
279
- if (withNetworkToken) return withNetworkToken;
280
- const networkOnly = pricing.find(
281
- (p) => p.network === network && !p.token && !p.facilitator
282
- );
283
- if (networkOnly) return networkOnly;
284
- return void 0;
285
- };
286
- var resolveMiddlewareConfig = (config) => {
287
- const { payTo, amount = "1.0", accept = {}, facilitatorUrl, pricing } = config;
288
- const acceptOptions = facilitatorUrl ? {
289
- ...accept,
290
- facilitators: accept.facilitators ? [...Array.isArray(accept.facilitators) ? accept.facilitators : [accept.facilitators], { url: facilitatorUrl }] : { url: facilitatorUrl }
291
- } : accept;
292
- const result = validateAcceptConfig(acceptOptions, payTo, amount);
293
- if (!result.success) {
294
- return result.error;
295
- }
296
- const facilitatorConfigs = result.config[0]?.facilitators.map((f) => ({
297
- url: f.url,
298
- createHeaders: f.input.headers
299
- })) ?? [];
300
- const enrichedConfigs = result.config.map((c) => {
301
- const networkName = c.network.config.name;
302
- const tokenSymbol = c.token.config.symbol;
303
- const facilitatorPricing = c.facilitators.map((f) => {
304
- const pricingConfig = findPricingConfig(pricing, networkName, tokenSymbol, f.url);
305
- return { url: f.url, pricing: pricingConfig };
306
- });
307
- const defaultPricing = findPricingConfig(pricing, networkName, tokenSymbol, "");
308
- return {
309
- ...c,
310
- amount: defaultPricing?.amount ?? c.amount,
311
- facilitatorUrl: facilitatorPricing[0]?.url,
312
- pricing: defaultPricing
313
- };
314
- });
315
- return {
316
- configs: enrichedConfigs,
317
- version: acceptOptions.version ?? "auto",
318
- facilitators: facilitatorConfigs
319
- };
320
- };
321
- var getRequirements = (config, network, token) => {
322
- const resolvedNetwork = resolveNetwork(network);
323
- if (isValidationError(resolvedNetwork)) {
324
- return resolvedNetwork;
325
- }
326
- const resolvedToken = resolveToken(token, resolvedNetwork);
327
- if (isValidationError(resolvedToken)) {
328
- return resolvedToken;
329
- }
330
- const matchingConfig = config.configs.find(
331
- (c) => c.network.config.chainId === resolvedNetwork.config.chainId && c.token.config.contractAddress.toLowerCase() === resolvedToken.config.contractAddress.toLowerCase()
332
- );
333
- if (!matchingConfig) {
334
- return {
335
- code: "TOKEN_NOT_ON_NETWORK",
336
- message: `No configuration found for network "${network}" with token "${token}"`
337
- };
338
- }
339
- const version = config.version === "auto" ? 2 : config.version;
340
- return createPaymentRequirements(
341
- {
342
- payTo: matchingConfig.payTo,
343
- network: matchingConfig.network.config.name,
344
- amount: matchingConfig.amount,
345
- facilitator: config.facilitators[0]
346
- },
347
- version
348
- );
349
- };
350
- var getPrimaryConfig = (resolved) => {
351
- const primary = resolved.configs[0];
352
- if (!primary) {
353
- throw new Error("No valid payment configurations found");
354
- }
355
- return {
356
- payTo: primary.payTo,
357
- network: primary.network.config.name,
358
- amount: primary.amount,
359
- facilitator: resolved.facilitators[0],
360
- settlementMode: "verify"
361
- };
362
- };
363
- var getSupportedNetworks = (config) => {
364
- const networks = new Set(config.configs.map((c) => c.network.config.name));
365
- return Array.from(networks);
366
- };
367
- var getSupportedTokens = (config) => {
368
- const tokens = new Set(config.configs.map((c) => c.token.config.symbol));
369
- return Array.from(tokens);
370
- };
371
- var isSupported = (config, network, token) => {
372
- const resolvedNetwork = resolveNetwork(network);
373
- if (isValidationError(resolvedNetwork)) {
374
- return false;
375
- }
376
- const resolvedToken = resolveToken(token, resolvedNetwork);
377
- if (isValidationError(resolvedToken)) {
378
- return false;
379
- }
380
- return config.configs.some(
381
- (c) => c.network.config.chainId === resolvedNetwork.config.chainId && c.token.config.contractAddress.toLowerCase() === resolvedToken.config.contractAddress.toLowerCase()
382
- );
383
- };
384
-
385
- // src/bun.ts
386
- var parsePaymentHeader = async (request) => {
387
- const x402Sig = request.headers.get(X402_HEADERS2.PAYMENT);
388
- if (x402Sig) {
389
- try {
390
- const payload = decodePayment(x402Sig);
391
- if (isExactEvmPayload(payload)) {
392
- return { payload, version: 2, payerAddress: payload.payload.authorization.from };
393
- }
394
- } catch {
395
- }
396
- }
397
- const v1 = request.headers.get("X-PAYMENT");
398
- if (v1) {
399
- try {
400
- const payload = decodePayment(v1);
401
- if (isExactEvmPayload(payload)) {
402
- return { payload, version: 2, payerAddress: payload.payload.authorization.from };
403
- }
404
- } catch {
405
- }
406
- }
407
- return null;
408
- };
409
- var toHttpRequest = (request) => {
410
- const headers = {};
411
- request.headers.forEach((v, k) => {
412
- headers[k] = v;
413
- });
414
- return { headers, method: request.method, url: request.url };
415
- };
416
- var errorResponse = (error, status, headers) => new Response(JSON.stringify({ error }), {
417
- status,
418
- headers: { "Content-Type": "application/json", ...headers }
419
- });
420
- var createSettlementResponse = (success, txHash) => ({
421
- success,
422
- transaction: txHash ?? "",
423
- errorReason: success ? void 0 : "Settlement failed",
424
- network: "base"
425
- });
426
- var successResponse = (payerAddress, version, settlement) => {
427
- const isSuccess = settlement?.success;
428
- const txHash = settlement?.transaction;
429
- return new Response(
430
- JSON.stringify({
431
- verified: true,
432
- payerAddress,
433
- version,
434
- settlement: settlement ? { success: isSuccess, txHash } : void 0
435
- }),
436
- {
437
- status: 200,
438
- headers: {
439
- "Content-Type": "application/json",
440
- "X-Payment-Verified": "true",
441
- "X-Payer-Address": payerAddress,
442
- ...settlement ? createSettlementHeaders(settlement, version) : {}
443
- }
444
- }
445
- );
446
- };
447
- var createBunMiddleware = (config) => {
448
- const { facilitator, settlementMode = "verify", defaultVersion = 2, waitForSettlement = false } = config;
449
- const requirementsV1 = createPaymentRequirements(config, 1);
450
- const requirementsV2 = createPaymentRequirements(config, 2);
451
- return async (request) => {
452
- const paymentResult = await parsePaymentHeader(request);
453
- if (!paymentResult) {
454
- const requirements = defaultVersion === 1 ? requirementsV1 : requirementsV2;
455
- return errorResponse("Payment required", 402, createPaymentRequiredHeaders(requirements, defaultVersion));
456
- }
457
- const { version, payerAddress } = paymentResult;
458
- if (facilitator) {
459
- const verifyResult = await verifyWithFacilitator(toHttpRequest(request), facilitator);
460
- if (!verifyResult.success) {
461
- const requirements = version === 1 ? requirementsV1 : requirementsV2;
462
- return errorResponse(`Payment verification failed: ${verifyResult.error}`, 402, createPaymentRequiredHeaders(requirements, version));
463
- }
464
- }
465
- if (settlementMode === "settle" && facilitator) {
466
- const settle = async () => {
467
- const result = await settleWithFacilitator(toHttpRequest(request), facilitator);
468
- return result.success ? successResponse(payerAddress, version, createSettlementResponse(true, result.txHash)) : errorResponse(result.error ?? "Settlement failed", 400);
469
- };
470
- return waitForSettlement ? await settle() : (settle().catch(console.error), successResponse(payerAddress, version));
471
- }
472
- return successResponse(payerAddress, version);
473
- };
474
- };
475
- var acceptPaymentsViaArmory = (config) => {
476
- const resolved = resolveMiddlewareConfig(config);
477
- if ("code" in resolved) {
478
- throw new Error(`Invalid payment configuration: ${resolved.message}`);
479
- }
480
- const primaryConfig = getPrimaryConfig(resolved);
481
- return createBunMiddleware({
482
- ...primaryConfig,
483
- defaultVersion: config.defaultVersion ?? 2,
484
- waitForSettlement: config.waitForSettlement ?? false
485
- });
486
- };
487
- export {
488
- acceptPaymentsViaArmory,
489
- createBunMiddleware,
490
- createPaymentRequiredHeaders,
491
- createPaymentRequirements,
492
- createResponseHeaders,
493
- createSettlementHeaders,
494
- decodePayload,
495
- encodeRequirements,
496
- extractPayerAddress,
497
- getHeadersForVersion,
498
- getPrimaryConfig,
499
- getRequirements,
500
- getRequirementsVersion,
501
- getSupportedNetworks,
502
- getSupportedTokens,
503
- isSupported,
504
- resolveMiddlewareConfig,
505
- settleWithFacilitator,
506
- verifyPaymentWithRetry,
507
- verifyWithFacilitator
508
- };