@armory-sh/middleware-hono 0.3.29 → 0.3.31

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
@@ -14,24 +14,47 @@ bun add @armory-sh/middleware-hono
14
14
 
15
15
  Armory enables HTTP API payments via EIP-3009 `transferWithAuthorization`. Accept payments from any x402-compatible client—Coinbase SDK, Armory SDK, or your own implementation.
16
16
 
17
- ## Key Exports
17
+ ## API Reference
18
+
19
+ ### Middleware
18
20
 
19
21
  ```typescript
20
22
  import {
21
- // Middleware
22
23
  paymentMiddleware,
23
24
  routeAwarePaymentMiddleware,
24
25
 
25
- // Requirements
26
- createPaymentRequirements,
27
-
28
26
  // Types
29
27
  type PaymentConfig,
30
28
  type RouteAwarePaymentConfig,
31
- type HonoPaymentContext,
29
+ type AugmentedContext,
32
30
  } from '@armory-sh/middleware-hono';
33
31
  ```
34
32
 
33
+ ### Payment Requirements
34
+
35
+ ```typescript
36
+ import {
37
+ createPaymentRequirements,
38
+
39
+ // Types
40
+ type ResolvedRequirementsConfig,
41
+ } from '@armory-sh/middleware-hono';
42
+ ```
43
+
44
+ ### Extensions
45
+
46
+ ```typescript
47
+ import {
48
+ buildExtensions,
49
+ extractExtension,
50
+
51
+ // Types
52
+ type ExtensionConfig,
53
+ } from '@armory-sh/middleware-hono';
54
+ ```
55
+
56
+ ---
57
+
35
58
  ## Quick Start
36
59
 
37
60
  ### Basic Middleware
@@ -168,6 +191,7 @@ interface RouteAwarePaymentConfig extends PaymentConfig {
168
191
  | Base Sepolia | 84532 |
169
192
  | SKALE Base | 1187947933 |
170
193
  | SKALE Base Sepolia | 324705682 |
194
+ | Ethereum Sepolia | 11155111 |
171
195
 
172
196
  ## License
173
197
 
package/dist/index.d.ts CHANGED
@@ -23,6 +23,7 @@ interface PaymentConfig {
23
23
  facilitatorUrl?: string;
24
24
  facilitatorUrlByChain?: Record<string, string>;
25
25
  facilitatorUrlByToken?: Record<string, Record<string, string>>;
26
+ extensions?: Record<string, unknown>;
26
27
  }
27
28
  interface ResolvedRequirementsConfig {
28
29
  requirements: PaymentRequirementsV2[];
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export { buildExtensions, extractExtension } from './chunk-XYM6YXAQ.js';
2
- import { matchRoute, V2_HEADERS, safeBase64Encode, decodePayloadHeader, findRequirementByAccepted, verifyPayment, createPaymentRequiredHeaders, settlePayment, createSettlementHeaders, resolveNetwork, isValidationError, resolveToken, createPaymentRequirements as createPaymentRequirements$1, PAYMENT_SIGNATURE_HEADER, PAYMENT_REQUIRED_HEADER, validateRouteConfig, TOKENS, registerToken } from '@armory-sh/base';
2
+ import { matchRoute, V2_HEADERS, safeBase64Encode, decodePayloadHeader, findRequirementByAccepted, verifyPayment, createPaymentRequiredHeaders, settlePayment, createSettlementHeaders, resolveNetwork, isValidationError, resolveToken, enrichPaymentRequirements, createPaymentRequirements as createPaymentRequirements$1, PAYMENT_SIGNATURE_HEADER, PAYMENT_REQUIRED_HEADER, validateRouteConfig, TOKENS, registerToken, getSupported } from '@armory-sh/base';
3
3
 
4
4
  var resolveRouteConfig = (config) => {
5
5
  const validationError = validateRouteConfig(config);
@@ -155,6 +155,8 @@ var routeAwarePaymentMiddleware = (config) => {
155
155
  };
156
156
 
157
157
  // src/index.ts
158
+ var extensionCapabilityCache = /* @__PURE__ */ new Map();
159
+ var EXTENSION_CAPABILITY_TTL_MS = 5 * 60 * 1e3;
158
160
  function ensureTokensRegistered() {
159
161
  for (const token of Object.values(TOKENS)) {
160
162
  try {
@@ -171,17 +173,13 @@ function resolveFacilitatorUrlFromRequirement(config, requirement) {
171
173
  config.facilitatorUrlByToken
172
174
  )) {
173
175
  const resolvedChain = resolveNetwork(chainKey);
174
- if (!isValidationError(resolvedChain) && resolvedChain.config.chainId === chainId) {
175
- for (const [, url] of Object.entries(tokenMap)) {
176
- const network = resolveNetwork(chainKey);
177
- if (!isValidationError(network)) {
178
- for (const tokenKey of Object.keys(tokenMap)) {
179
- const resolvedToken = resolveToken(tokenKey, network);
180
- if (!isValidationError(resolvedToken) && resolvedToken.config.contractAddress.toLowerCase() === assetAddress) {
181
- return url;
182
- }
183
- }
184
- }
176
+ if (isValidationError(resolvedChain) || resolvedChain.config.chainId !== chainId) {
177
+ continue;
178
+ }
179
+ for (const [tokenKey, url] of Object.entries(tokenMap)) {
180
+ const resolvedToken = resolveToken(tokenKey, resolvedChain);
181
+ if (!isValidationError(resolvedToken) && resolvedToken.config.contractAddress.toLowerCase() === assetAddress) {
182
+ return url;
185
183
  }
186
184
  }
187
185
  }
@@ -200,8 +198,9 @@ function resolveFacilitatorUrlFromRequirement(config, requirement) {
200
198
  }
201
199
  function createPaymentRequirements(config) {
202
200
  if (config.requirements) {
201
+ const requirements = Array.isArray(config.requirements) ? config.requirements : [config.requirements];
203
202
  return {
204
- requirements: Array.isArray(config.requirements) ? config.requirements : [config.requirements]
203
+ requirements: enrichPaymentRequirements(requirements)
205
204
  };
206
205
  }
207
206
  if (!config.payTo) {
@@ -216,8 +215,56 @@ function createPaymentRequirements(config) {
216
215
  ensureTokensRegistered();
217
216
  return createPaymentRequirements$1(config);
218
217
  }
218
+ async function resolvePaymentRequiredExtensions(config, requirements) {
219
+ if (!config.extensions) {
220
+ return {};
221
+ }
222
+ let filtered = { ...config.extensions };
223
+ for (const requirement of requirements) {
224
+ const facilitatorUrl = resolveFacilitatorUrlFromRequirement(config, requirement);
225
+ if (!facilitatorUrl) {
226
+ continue;
227
+ }
228
+ const cacheKey = `${facilitatorUrl}|${requirement.network.toLowerCase()}`;
229
+ const now = Date.now();
230
+ let keys = extensionCapabilityCache.get(cacheKey);
231
+ if (!keys || keys.expiresAt <= now) {
232
+ try {
233
+ const supported = await getSupported({ url: facilitatorUrl });
234
+ const nextKeys = /* @__PURE__ */ new Set();
235
+ for (const kind of supported.kinds) {
236
+ if (kind.network.toLowerCase() !== requirement.network.toLowerCase()) {
237
+ continue;
238
+ }
239
+ if (kind.extra && typeof kind.extra === "object") {
240
+ for (const key of Object.keys(kind.extra)) {
241
+ nextKeys.add(key);
242
+ }
243
+ }
244
+ }
245
+ keys = { expiresAt: now + EXTENSION_CAPABILITY_TTL_MS, keys: nextKeys };
246
+ } catch {
247
+ keys = { expiresAt: now + EXTENSION_CAPABILITY_TTL_MS, keys: /* @__PURE__ */ new Set() };
248
+ }
249
+ extensionCapabilityCache.set(cacheKey, keys);
250
+ }
251
+ filtered = Object.fromEntries(
252
+ Object.entries(filtered).filter(([key]) => keys.keys.has(key))
253
+ );
254
+ if (Object.keys(filtered).length === 0) {
255
+ return {};
256
+ }
257
+ }
258
+ return filtered;
259
+ }
219
260
  function paymentMiddleware(config) {
220
261
  const { requirements, error } = createPaymentRequirements(config);
262
+ const resolvePaymentRequiredHeader = async () => createPaymentRequiredHeaders(requirements, {
263
+ extensions: await resolvePaymentRequiredExtensions(
264
+ config,
265
+ requirements
266
+ )
267
+ })[PAYMENT_REQUIRED_HEADER];
221
268
  return async (c, next) => {
222
269
  if (error) {
223
270
  c.status(500);
@@ -250,7 +297,7 @@ function paymentMiddleware(config) {
250
297
  c.status(402);
251
298
  c.header(
252
299
  PAYMENT_REQUIRED_HEADER,
253
- safeBase64Encode(JSON.stringify(paymentRequired))
300
+ await resolvePaymentRequiredHeader() ?? safeBase64Encode(JSON.stringify(paymentRequired))
254
301
  );
255
302
  return c.json({
256
303
  error: "Payment required",
@@ -297,7 +344,7 @@ function paymentMiddleware(config) {
297
344
  c.status(402);
298
345
  c.header(
299
346
  PAYMENT_REQUIRED_HEADER,
300
- createPaymentRequiredHeaders(requirements)[PAYMENT_REQUIRED_HEADER]
347
+ await resolvePaymentRequiredHeader()
301
348
  );
302
349
  return c.json({
303
350
  error: "Payment verification failed",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@armory-sh/middleware-hono",
3
- "version": "0.3.29",
3
+ "version": "0.3.31",
4
4
  "license": "MIT",
5
5
  "author": "Sawyer Cutler <sawyer@dirtroad.dev>",
6
6
  "keywords": [
@@ -52,8 +52,8 @@
52
52
  "hono": "^4"
53
53
  },
54
54
  "dependencies": {
55
- "@armory-sh/base": "0.2.29",
56
- "@armory-sh/extensions": "0.1.10"
55
+ "@armory-sh/base": "0.2.31",
56
+ "@armory-sh/extensions": "0.1.12"
57
57
  },
58
58
  "devDependencies": {
59
59
  "bun-types": "latest",