@armory-sh/middleware-elysia 0.3.26 → 0.3.27

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.
@@ -1,5 +1,5 @@
1
- import { Elysia } from 'elysia';
2
1
  import { matchRoute, PAYMENT_SIGNATURE_HEADER, createPaymentRequiredHeaders, decodePayloadHeader, verifyPayment, settlePayment, createSettlementHeaders, validateRouteConfig } from '@armory-sh/base';
2
+ import { Elysia } from 'elysia';
3
3
 
4
4
  // src/routes.ts
5
5
  var resolveRouteConfig = (config) => {
@@ -37,18 +37,25 @@ var routeAwarePaymentMiddleware = (perRouteConfig) => {
37
37
  try {
38
38
  if (configError) {
39
39
  return errorResponse(
40
- { error: "Payment middleware configuration error", details: configError.message },
40
+ {
41
+ error: "Payment middleware configuration error",
42
+ details: configError.message
43
+ },
41
44
  500
42
45
  );
43
46
  }
44
47
  const path = new URL(context.request.url).pathname;
45
- const matchedRoute = resolvedRoutes.find((r) => matchRoute(r.pattern, path));
48
+ const matchedRoute = resolvedRoutes.find(
49
+ (r) => matchRoute(r.pattern, path)
50
+ );
46
51
  if (!matchedRoute) {
47
52
  return;
48
53
  }
49
54
  const routeConfig = matchedRoute.config;
50
55
  const { requirements, facilitatorUrl } = routeConfig;
51
- const paymentHeader = context.request.headers.get(PAYMENT_SIGNATURE_HEADER);
56
+ const paymentHeader = context.request.headers.get(
57
+ PAYMENT_SIGNATURE_HEADER
58
+ );
52
59
  if (!paymentHeader) {
53
60
  return errorResponse(
54
61
  { error: "Payment required", accepts: [requirements] },
@@ -62,16 +69,29 @@ var routeAwarePaymentMiddleware = (perRouteConfig) => {
62
69
  accepted: requirements
63
70
  });
64
71
  } catch (error) {
65
- return errorResponse({
66
- error: "Invalid payment payload",
67
- message: error instanceof Error ? error.message : "Unknown error"
68
- }, 400);
72
+ return errorResponse(
73
+ {
74
+ error: "Invalid payment payload",
75
+ message: error instanceof Error ? error.message : "Unknown error"
76
+ },
77
+ 400
78
+ );
69
79
  }
70
80
  if (!facilitatorUrl) {
71
- return errorResponse({ error: "Payment middleware configuration error", message: "Facilitator URL is required for verification" }, 500);
81
+ return errorResponse(
82
+ {
83
+ error: "Payment middleware configuration error",
84
+ message: "Facilitator URL is required for verification"
85
+ },
86
+ 500
87
+ );
72
88
  }
73
89
  const verifyConfig = { url: facilitatorUrl };
74
- const verifyResult = await verifyPayment(payload, requirements, verifyConfig);
90
+ const verifyResult = await verifyPayment(
91
+ payload,
92
+ requirements,
93
+ verifyConfig
94
+ );
75
95
  if (!verifyResult.isValid) {
76
96
  return errorResponse(
77
97
  { error: verifyResult.invalidReason },
@@ -80,12 +100,20 @@ var routeAwarePaymentMiddleware = (perRouteConfig) => {
80
100
  );
81
101
  }
82
102
  const payerAddress = verifyResult.payer ?? payload.payload.authorization.from;
83
- context.payment = { payload, payerAddress, verified: true, route: matchedRoute.pattern };
103
+ context.payment = {
104
+ payload,
105
+ payerAddress,
106
+ verified: true,
107
+ route: matchedRoute.pattern
108
+ };
84
109
  } catch (error) {
85
- return errorResponse({
86
- error: "Payment middleware error",
87
- message: error instanceof Error ? error.message : "Unknown error"
88
- }, 500);
110
+ return errorResponse(
111
+ {
112
+ error: "Payment middleware error",
113
+ message: error instanceof Error ? error.message : "Unknown error"
114
+ },
115
+ 500
116
+ );
89
117
  }
90
118
  }).onAfterHandle(async (context) => {
91
119
  const payment = context.payment;
@@ -102,12 +130,25 @@ var routeAwarePaymentMiddleware = (perRouteConfig) => {
102
130
  return;
103
131
  }
104
132
  if (!routeConfig.facilitatorUrl) {
105
- return errorResponse({ error: "Payment middleware configuration error", message: "Facilitator URL is required for settlement" }, 500);
133
+ return errorResponse(
134
+ {
135
+ error: "Payment middleware configuration error",
136
+ message: "Facilitator URL is required for settlement"
137
+ },
138
+ 500
139
+ );
106
140
  }
107
141
  const settleConfig = { url: routeConfig.facilitatorUrl };
108
- const settlementResult = await settlePayment(payment.payload, routeConfig.requirements, settleConfig);
142
+ const settlementResult = await settlePayment(
143
+ payment.payload,
144
+ routeConfig.requirements,
145
+ settleConfig
146
+ );
109
147
  if (!settlementResult.success) {
110
- return errorResponse({ error: "Settlement failed", details: settlementResult.errorReason }, 502);
148
+ return errorResponse(
149
+ { error: "Settlement failed", details: settlementResult.errorReason },
150
+ 502
151
+ );
111
152
  }
112
153
  return {
113
154
  headers: createSettlementHeaders(settlementResult)
package/dist/index.d.ts CHANGED
@@ -1,20 +1,32 @@
1
+ import { PaymentRequirementsV2, X402PaymentPayload, X402PaymentRequirements } from '@armory-sh/base';
1
2
  import { Elysia } from 'elysia';
2
- import { X402PaymentPayload, X402PaymentRequirements } from '@armory-sh/base';
3
3
  export { PaymentMiddlewareConfigEntry, RouteAwarePaymentInfo, RouteAwarePaymentMiddlewareConfig, routeAwarePaymentMiddleware } from './routes.js';
4
4
 
5
- interface PaymentMiddlewareConfig {
6
- requirements: X402PaymentRequirements;
7
- facilitatorUrl: string;
8
- }
9
- interface PaymentInfo {
10
- payload: X402PaymentPayload;
11
- payerAddress: string;
12
- verified: boolean;
5
+ type NetworkId = string | number;
6
+ type TokenId = string;
7
+ interface PaymentConfig {
8
+ payTo?: string;
9
+ requirements?: PaymentRequirementsV2 | PaymentRequirementsV2[];
10
+ chains?: NetworkId[];
11
+ chain?: NetworkId;
12
+ tokens?: TokenId[];
13
+ token?: TokenId;
14
+ amount?: string;
15
+ maxTimeoutSeconds?: number;
16
+ facilitatorUrl?: string;
17
+ facilitatorUrlByChain?: Record<string, string>;
18
+ facilitatorUrlByToken?: Record<string, Record<string, string>>;
13
19
  }
14
- interface PaymentContext {
15
- payment: PaymentInfo;
20
+ interface ResolvedRequirementsConfig {
21
+ requirements: PaymentRequirementsV2[];
22
+ error?: {
23
+ code: string;
24
+ message: string;
25
+ };
16
26
  }
17
- declare const paymentMiddleware: (config: PaymentMiddlewareConfig) => Elysia<"", {
27
+ declare function resolveFacilitatorUrlFromRequirement(config: PaymentConfig, requirement: PaymentRequirementsV2): string | undefined;
28
+ declare function createPaymentRequirements(config: PaymentConfig): ResolvedRequirementsConfig;
29
+ declare const paymentMiddleware: (config: PaymentConfig) => Elysia<"", {
18
30
  decorator: {};
19
31
  store: {};
20
32
  derive: {};
@@ -37,7 +49,12 @@ declare const paymentMiddleware: (config: PaymentMiddlewareConfig) => Elysia<"",
37
49
  response: {};
38
50
  }, {
39
51
  derive: {
40
- readonly payment: PaymentInfo | undefined;
52
+ readonly payment: {
53
+ payload: X402PaymentPayload;
54
+ payerAddress: string;
55
+ verified: boolean;
56
+ selectedRequirement: PaymentRequirementsV2;
57
+ } | undefined;
41
58
  };
42
59
  resolve: {};
43
60
  schema: {};
@@ -49,4 +66,17 @@ declare const paymentMiddleware: (config: PaymentMiddlewareConfig) => Elysia<"",
49
66
  };
50
67
  }>;
51
68
 
52
- export { type PaymentContext, type PaymentInfo, type PaymentMiddlewareConfig, paymentMiddleware };
69
+ interface PaymentMiddlewareConfig {
70
+ requirements: X402PaymentRequirements;
71
+ facilitatorUrl: string;
72
+ }
73
+ interface PaymentInfo {
74
+ payload: X402PaymentPayload;
75
+ payerAddress: string;
76
+ verified: boolean;
77
+ }
78
+ interface PaymentContext {
79
+ payment: PaymentInfo;
80
+ }
81
+
82
+ export { type PaymentConfig, type PaymentContext, type PaymentInfo, type PaymentMiddlewareConfig, type ResolvedRequirementsConfig, createPaymentRequirements, paymentMiddleware, resolveFacilitatorUrlFromRequirement };
package/dist/index.js CHANGED
@@ -1,56 +1,168 @@
1
- export { routeAwarePaymentMiddleware } from './chunk-XZ4WVA3M.js';
1
+ export { routeAwarePaymentMiddleware } from './chunk-L45RQOFN.js';
2
+ import { resolveNetwork, isValidationError, resolveToken, createPaymentRequirements as createPaymentRequirements$1, PAYMENT_SIGNATURE_HEADER, createPaymentRequiredHeaders, decodePayloadHeader, findRequirementByAccepted, verifyPayment, settlePayment, createSettlementHeaders, TOKENS, registerToken } from '@armory-sh/base';
2
3
  import { Elysia } from 'elysia';
3
- import { PAYMENT_SIGNATURE_HEADER, createPaymentRequiredHeaders, decodePayloadHeader, verifyPayment, settlePayment, createSettlementHeaders } from '@armory-sh/base';
4
4
 
5
+ function ensureTokensRegistered() {
6
+ for (const token of Object.values(TOKENS)) {
7
+ try {
8
+ registerToken(token);
9
+ } catch {
10
+ }
11
+ }
12
+ }
13
+ function resolveFacilitatorUrlFromRequirement(config, requirement) {
14
+ const chainId = parseInt(requirement.network.split(":")[1] || "0", 10);
15
+ const assetAddress = requirement.asset.toLowerCase();
16
+ if (config.facilitatorUrlByToken) {
17
+ for (const [chainKey, tokenMap] of Object.entries(
18
+ config.facilitatorUrlByToken
19
+ )) {
20
+ const resolvedChain = resolveNetwork(chainKey);
21
+ if (!isValidationError(resolvedChain) && resolvedChain.config.chainId === chainId) {
22
+ for (const [, url] of Object.entries(tokenMap)) {
23
+ const network = resolveNetwork(chainKey);
24
+ if (!isValidationError(network)) {
25
+ for (const tokenKey of Object.keys(tokenMap)) {
26
+ const resolvedToken = resolveToken(tokenKey, network);
27
+ if (!isValidationError(resolvedToken) && resolvedToken.config.contractAddress.toLowerCase() === assetAddress) {
28
+ return url;
29
+ }
30
+ }
31
+ }
32
+ }
33
+ }
34
+ }
35
+ }
36
+ if (config.facilitatorUrlByChain) {
37
+ for (const [chainKey, url] of Object.entries(
38
+ config.facilitatorUrlByChain
39
+ )) {
40
+ const resolvedChain = resolveNetwork(chainKey);
41
+ if (!isValidationError(resolvedChain) && resolvedChain.config.chainId === chainId) {
42
+ return url;
43
+ }
44
+ }
45
+ }
46
+ return config.facilitatorUrl;
47
+ }
48
+ function createPaymentRequirements(config) {
49
+ if (config.requirements) {
50
+ return {
51
+ requirements: Array.isArray(config.requirements) ? config.requirements : [config.requirements]
52
+ };
53
+ }
54
+ if (!config.payTo) {
55
+ return {
56
+ requirements: [],
57
+ error: {
58
+ code: "VALIDATION_FAILED",
59
+ message: "Missing payment configuration: provide payTo or explicit requirements"
60
+ }
61
+ };
62
+ }
63
+ ensureTokensRegistered();
64
+ return createPaymentRequirements$1(config);
65
+ }
5
66
  var errorResponse = (error, status, headers) => new Response(JSON.stringify(error), {
6
67
  status,
7
68
  headers: { "Content-Type": "application/json", ...headers }
8
69
  });
9
70
  var paymentMiddleware = (config) => {
10
- const { requirements, facilitatorUrl } = config;
71
+ const { requirements, error } = createPaymentRequirements(config);
11
72
  return new Elysia({ name: "armory-payment" }).derive(() => ({
12
73
  payment: void 0
13
74
  })).onBeforeHandle(async (context) => {
75
+ if (error) {
76
+ return errorResponse(
77
+ {
78
+ error: "Payment middleware configuration error",
79
+ details: error.message
80
+ },
81
+ 500
82
+ );
83
+ }
84
+ const primaryRequirement = requirements[0];
85
+ if (!primaryRequirement) {
86
+ return errorResponse(
87
+ {
88
+ error: "Payment middleware configuration error",
89
+ message: "No payment requirements configured"
90
+ },
91
+ 500
92
+ );
93
+ }
94
+ const paymentHeader = context.request.headers.get(
95
+ PAYMENT_SIGNATURE_HEADER
96
+ );
97
+ if (!paymentHeader) {
98
+ return errorResponse(
99
+ { error: "Payment required", accepts: requirements },
100
+ 402,
101
+ createPaymentRequiredHeaders(requirements)
102
+ );
103
+ }
104
+ let paymentPayload;
14
105
  try {
15
- const paymentHeader = context.request.headers.get(PAYMENT_SIGNATURE_HEADER);
16
- if (!paymentHeader) {
17
- return errorResponse(
18
- { error: "Payment required", accepts: [requirements] },
19
- 402,
20
- createPaymentRequiredHeaders(requirements)
21
- );
22
- }
23
- let paymentPayload;
24
- try {
25
- paymentPayload = decodePayloadHeader(paymentHeader, {
26
- accepted: requirements
27
- });
28
- } catch (error) {
29
- return errorResponse({
106
+ paymentPayload = decodePayloadHeader(paymentHeader, {
107
+ accepted: primaryRequirement
108
+ });
109
+ } catch (err) {
110
+ return errorResponse(
111
+ {
30
112
  error: "Invalid payment payload",
31
- message: error instanceof Error ? error.message : "Unknown error"
32
- }, 400);
33
- }
34
- if (!facilitatorUrl) {
35
- return errorResponse({ error: "Payment middleware configuration error", message: "Facilitator URL is required for verification" }, 500);
36
- }
37
- const verifyConfig = { url: facilitatorUrl };
38
- const verifyResult = await verifyPayment(paymentPayload, requirements, verifyConfig);
39
- if (!verifyResult.isValid) {
40
- return errorResponse(
41
- { error: verifyResult.invalidReason },
42
- 402,
43
- createPaymentRequiredHeaders(requirements)
44
- );
45
- }
46
- const payerAddress = verifyResult.payer ?? paymentPayload.payload.authorization.from;
47
- context.payment = { payload: paymentPayload, payerAddress, verified: true };
48
- } catch (error) {
49
- return errorResponse({
50
- error: "Payment middleware error",
51
- message: error instanceof Error ? error.message : "Unknown error"
52
- }, 500);
113
+ message: err instanceof Error ? err.message : "Unknown error"
114
+ },
115
+ 400
116
+ );
53
117
  }
118
+ const selectedRequirement = findRequirementByAccepted(
119
+ requirements,
120
+ paymentPayload.accepted
121
+ );
122
+ if (!selectedRequirement) {
123
+ return errorResponse(
124
+ {
125
+ error: "Invalid payment payload",
126
+ message: "Accepted requirement is not configured for this endpoint"
127
+ },
128
+ 400
129
+ );
130
+ }
131
+ const facilitatorUrl = resolveFacilitatorUrlFromRequirement(
132
+ config,
133
+ selectedRequirement
134
+ );
135
+ if (!facilitatorUrl) {
136
+ return errorResponse(
137
+ {
138
+ error: "Payment middleware configuration error",
139
+ message: "Facilitator URL is required for verification"
140
+ },
141
+ 500
142
+ );
143
+ }
144
+ const verifyResult = await verifyPayment(
145
+ paymentPayload,
146
+ selectedRequirement,
147
+ { url: facilitatorUrl }
148
+ );
149
+ if (!verifyResult.isValid) {
150
+ return errorResponse(
151
+ {
152
+ error: "Payment verification failed",
153
+ message: verifyResult.invalidReason
154
+ },
155
+ 402,
156
+ createPaymentRequiredHeaders(requirements)
157
+ );
158
+ }
159
+ const payerAddress = verifyResult.payer ?? paymentPayload.payload.authorization.from;
160
+ context.payment = {
161
+ payload: paymentPayload,
162
+ payerAddress,
163
+ verified: true,
164
+ selectedRequirement
165
+ };
54
166
  }).onAfterHandle(async (context) => {
55
167
  const payment = context.payment;
56
168
  if (!payment) {
@@ -60,18 +172,34 @@ var paymentMiddleware = (config) => {
60
172
  if (statusCode >= 400) {
61
173
  return;
62
174
  }
175
+ const facilitatorUrl = resolveFacilitatorUrlFromRequirement(
176
+ config,
177
+ payment.selectedRequirement
178
+ );
63
179
  if (!facilitatorUrl) {
64
- return errorResponse({ error: "Payment middleware configuration error", message: "Facilitator URL is required for settlement" }, 500);
180
+ return errorResponse(
181
+ {
182
+ error: "Payment middleware configuration error",
183
+ message: "Facilitator URL is required for settlement"
184
+ },
185
+ 500
186
+ );
65
187
  }
66
- const settleConfig = { url: facilitatorUrl };
67
- const settlementResult = await settlePayment(payment.payload, requirements, settleConfig);
68
- if (!settlementResult.success) {
69
- return errorResponse({ error: "Settlement failed", details: settlementResult.errorReason }, 502);
188
+ const settleResult = await settlePayment(
189
+ payment.payload,
190
+ payment.selectedRequirement,
191
+ { url: facilitatorUrl }
192
+ );
193
+ if (!settleResult.success) {
194
+ return errorResponse(
195
+ { error: "Settlement failed", details: settleResult.errorReason },
196
+ 502
197
+ );
70
198
  }
71
199
  return {
72
- headers: createSettlementHeaders(settlementResult)
200
+ headers: createSettlementHeaders(settleResult)
73
201
  };
74
202
  });
75
203
  };
76
204
 
77
- export { paymentMiddleware };
205
+ export { createPaymentRequirements, paymentMiddleware, resolveFacilitatorUrlFromRequirement };
package/dist/routes.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { Elysia } from 'elysia';
2
1
  import { X402PaymentRequirements, X402PaymentPayload } from '@armory-sh/base';
2
+ import { Elysia } from 'elysia';
3
3
 
4
4
  interface RouteAwarePaymentMiddlewareConfig {
5
5
  route?: string;
package/dist/routes.js CHANGED
@@ -1 +1 @@
1
- export { routeAwarePaymentMiddleware } from './chunk-XZ4WVA3M.js';
1
+ export { routeAwarePaymentMiddleware } from './chunk-L45RQOFN.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@armory-sh/middleware-elysia",
3
- "version": "0.3.26",
3
+ "version": "0.3.27",
4
4
  "license": "MIT",
5
5
  "author": "Sawyer Cutler <sawyer@dirtroad.dev>",
6
6
  "keywords": [
@@ -47,7 +47,7 @@
47
47
  "elysia": "^1"
48
48
  },
49
49
  "dependencies": {
50
- "@armory-sh/base": "0.2.28"
50
+ "@armory-sh/base": "0.2.29"
51
51
  },
52
52
  "devDependencies": {
53
53
  "bun-types": "latest",
@@ -57,6 +57,8 @@
57
57
  },
58
58
  "scripts": {
59
59
  "build": "rm -rf dist && tsup",
60
+ "lint": "bun run build",
61
+ "format": "bun run lint",
60
62
  "test": "bun test"
61
63
  }
62
64
  }