@armory-sh/middleware-hono 0.3.19 → 0.3.20

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 ADDED
@@ -0,0 +1,220 @@
1
+ # @armory-sh/middleware-hono
2
+
3
+ x402 payment middleware for Hono applications.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ bun add @armory-sh/middleware-hono
9
+ ```
10
+
11
+ ## Features
12
+
13
+ - Simple payment middleware for Hono
14
+ - Route-aware payment configuration
15
+ - Multi-network, multi-token support
16
+ - Per-route facilitator configuration
17
+ - Full TypeScript support
18
+
19
+ ## Basic Usage
20
+
21
+ ```typescript
22
+ import { Hono } from "hono";
23
+ import { paymentMiddleware } from "@armory-sh/middleware-hono";
24
+
25
+ const app = new Hono();
26
+
27
+ app.use("/*", paymentMiddleware({
28
+ payTo: "0xYourAddress...",
29
+ chain: "base",
30
+ token: "usdc",
31
+ amount: "1.0",
32
+ }));
33
+
34
+ app.get("/api/data", (c) => {
35
+ const payment = c.get("payment");
36
+ return c.json({
37
+ data: "protected data",
38
+ payerAddress: payment?.payload?.authorization?.from,
39
+ });
40
+ });
41
+ ```
42
+
43
+ ## Route-Aware Middleware
44
+
45
+ Configure different payment requirements for different routes:
46
+
47
+ ```typescript
48
+ import { routeAwarePaymentMiddleware } from "@armory-sh/middleware-hono";
49
+
50
+ const app = new Hono();
51
+
52
+ // Single route with wildcard
53
+ app.use("/api/premium/*", routeAwarePaymentMiddleware({
54
+ routes: ["/api/premium/*"],
55
+ payTo: "0xYourAddress...",
56
+ amount: "$5.00",
57
+ network: "base"
58
+ }));
59
+
60
+ // Multiple routes with per-route configuration
61
+ app.use("/api/*", routeAwarePaymentMiddleware({
62
+ routes: ["/api/basic", "/api/premium/*"],
63
+ payTo: "0xYourAddress...",
64
+ amount: "$1.00", // Default amount
65
+ network: "base",
66
+ perRoute: {
67
+ "/api/premium/*": {
68
+ amount: "$5.00", // Override for premium routes
69
+ network: "ethereum",
70
+ }
71
+ }
72
+ }));
73
+ ```
74
+
75
+ ## Configuration Options
76
+
77
+ ### PaymentConfig
78
+
79
+ ```typescript
80
+ interface PaymentConfig {
81
+ payTo: string; // Payment recipient address
82
+ chain?: string | number; // Network (name or chain ID)
83
+ chains?: Array<string | number>; // Multiple networks
84
+ token?: string; // Token symbol
85
+ tokens?: string[]; // Multiple tokens
86
+ amount?: string; // Amount (default: "1.0")
87
+ maxTimeoutSeconds?: number; // Payment timeout (default: 300)
88
+
89
+ // Per-chain configuration
90
+ payToByChain?: Record<string, string>;
91
+ facilitatorUrlByChain?: Record<string, string>;
92
+
93
+ // Per-token-per-chain configuration
94
+ payToByToken?: Record<string, Record<string, string>>;
95
+ facilitatorUrlByToken?: Record<string, Record<string, string>>;
96
+ }
97
+ ```
98
+
99
+ ### RouteAwarePaymentConfig
100
+
101
+ ```typescript
102
+ interface RouteAwarePaymentConfig extends PaymentConfig {
103
+ route?: string; // Single exact route (no wildcards)
104
+ routes?: string[]; // Multiple routes (allows wildcards)
105
+ perRoute?: Record<string, Partial<PaymentConfig>>;
106
+ }
107
+ ```
108
+
109
+ ## Payment Context
110
+
111
+ The middleware adds payment information to the Hono context:
112
+
113
+ ```typescript
114
+ app.get("/api/data", (c) => {
115
+ const payment = c.get("payment");
116
+ // payment.payload: PaymentPayloadV2
117
+ // payment.verified: boolean
118
+ // payment.route: string (only for route-aware middleware)
119
+ });
120
+ ```
121
+
122
+ ## Input Formats
123
+
124
+ **Networks** - Use any format:
125
+ ```typescript
126
+ 'base' // name
127
+ 8453 // chain ID
128
+ 'eip155:8453' // CAIP-2
129
+ ```
130
+
131
+ **Tokens** - Use any format:
132
+ ```typescript
133
+ 'usdc' // symbol (case-insensitive)
134
+ '0x8335...' // EVM address
135
+ 'eip155:8453/erc20:0x8335...' // CAIP Asset ID
136
+ ```
137
+
138
+ ## Route Pattern Matching
139
+
140
+ - **Exact**: `/api/users` - matches only `/api/users`
141
+ - **Wildcard**: `/api/*` - matches `/api/users`, `/api/posts/123`
142
+ - **Parameterized**: `/api/users/:id` - matches `/api/users/123`
143
+
144
+ Priority order: Exact matches > Parameterized routes > Wildcard routes
145
+
146
+ ## Examples
147
+
148
+ ### Multi-Network Support
149
+
150
+ ```typescript
151
+ app.use("/*", paymentMiddleware({
152
+ payTo: "0xYourAddress...",
153
+ chains: ["base", "ethereum", "skale-base"],
154
+ tokens: ["usdc", "eurc"],
155
+ amount: "1.0"
156
+ }));
157
+ ```
158
+
159
+ ### Per-Chain Configuration
160
+
161
+ ```typescript
162
+ app.use("/*", paymentMiddleware({
163
+ payTo: "0xDefaultAddress...",
164
+ payToByChain: {
165
+ base: "0xBaseAddress...",
166
+ ethereum: "0xEthAddress...",
167
+ },
168
+ chain: "base",
169
+ token: "usdc"
170
+ }));
171
+ ```
172
+
173
+ ### Route-Specific Pricing
174
+
175
+ ```typescript
176
+ app.use("/api/*", routeAwarePaymentMiddleware({
177
+ routes: ["/api/basic", "/api/pro", "/api/enterprise"],
178
+ payTo: "0xYourAddress...",
179
+ amount: "$1.00",
180
+ network: "base",
181
+ perRoute: {
182
+ "/api/pro": {
183
+ amount: "$5.00",
184
+ },
185
+ "/api/enterprise": {
186
+ amount: "$50.00",
187
+ network: "ethereum",
188
+ }
189
+ }
190
+ }));
191
+ ```
192
+
193
+ ## API
194
+
195
+ ### `paymentMiddleware(config)`
196
+
197
+ Creates a basic payment middleware for Hono.
198
+
199
+ **Parameters:**
200
+ - `config`: Payment configuration
201
+
202
+ **Returns:** Hono middleware function
203
+
204
+ ### `createPaymentRequirements(config)`
205
+
206
+ Creates payment requirements from configuration (for advanced use).
207
+
208
+ **Parameters:**
209
+ - `config`: Payment configuration
210
+
211
+ **Returns:** Object with `requirements` array and optional `error`
212
+
213
+ ### `routeAwarePaymentMiddleware(config)`
214
+
215
+ Creates a route-aware payment middleware for Hono.
216
+
217
+ **Parameters:**
218
+ - `config`: Route-aware payment configuration
219
+
220
+ **Returns:** Hono middleware function
@@ -0,0 +1,39 @@
1
+ import { Extensions } from '@armory-sh/base';
2
+
3
+ /**
4
+ * Extension handling for Hono middleware
5
+ * Integrates with @armory-sh/extensions package
6
+ */
7
+
8
+ type BazaarDiscoveryConfig = {
9
+ input?: unknown;
10
+ inputSchema?: Record<string, unknown>;
11
+ bodyType?: "json" | "form-data" | "text";
12
+ output?: {
13
+ example?: unknown;
14
+ schema?: Record<string, unknown>;
15
+ };
16
+ };
17
+ type SIWxExtensionConfig = {
18
+ domain?: string;
19
+ resourceUri?: string;
20
+ network?: string | string[];
21
+ statement?: string;
22
+ version?: string;
23
+ expirationSeconds?: number;
24
+ };
25
+ type Extension<T = unknown> = {
26
+ info: T;
27
+ schema: Record<string, unknown>;
28
+ };
29
+ interface ExtensionConfig {
30
+ bazaar?: BazaarDiscoveryConfig;
31
+ signInWithX?: SIWxExtensionConfig;
32
+ }
33
+ interface PaymentConfigWithExtensions {
34
+ extensions?: ExtensionConfig;
35
+ }
36
+ declare function buildExtensions(config: ExtensionConfig): Extensions;
37
+ declare function extractExtension<T>(extensions: Extensions | undefined, key: string): Extension<T> | null;
38
+
39
+ export { type ExtensionConfig, type PaymentConfigWithExtensions, buildExtensions, extractExtension };
@@ -0,0 +1,60 @@
1
+ // src/extensions.ts
2
+ var declareDiscoveryExtension = (config = {}) => {
3
+ const info = {};
4
+ if (config.input !== void 0) {
5
+ info.input = config.input;
6
+ }
7
+ if (config.inputSchema !== void 0) {
8
+ info.inputSchema = config.inputSchema;
9
+ }
10
+ if (config.output !== void 0) {
11
+ info.output = config.output;
12
+ }
13
+ return { info, schema: { type: "object" } };
14
+ };
15
+ var declareSIWxExtension = (config = {}) => {
16
+ const info = {};
17
+ if (config.domain !== void 0) {
18
+ info.domain = config.domain;
19
+ }
20
+ if (config.resourceUri !== void 0) {
21
+ info.resourceUri = config.resourceUri;
22
+ }
23
+ if (config.network !== void 0) {
24
+ info.network = config.network;
25
+ }
26
+ if (config.statement !== void 0) {
27
+ info.statement = config.statement;
28
+ }
29
+ if (config.version !== void 0) {
30
+ info.version = config.version;
31
+ }
32
+ if (config.expirationSeconds !== void 0) {
33
+ info.expirationSeconds = config.expirationSeconds;
34
+ }
35
+ return { info, schema: { type: "object" } };
36
+ };
37
+ function buildExtensions(config) {
38
+ const extensions = {};
39
+ if (config.bazaar) {
40
+ extensions.bazaar = declareDiscoveryExtension(config.bazaar);
41
+ }
42
+ if (config.signInWithX) {
43
+ extensions["sign-in-with-x"] = declareSIWxExtension(config.signInWithX);
44
+ }
45
+ return extensions;
46
+ }
47
+ function extractExtension(extensions, key) {
48
+ if (!extensions || typeof extensions !== "object") {
49
+ return null;
50
+ }
51
+ const extension = extensions[key];
52
+ if (!extension || typeof extension !== "object") {
53
+ return null;
54
+ }
55
+ return extension;
56
+ }
57
+ export {
58
+ buildExtensions,
59
+ extractExtension
60
+ };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import { Context, Next } from 'hono';
2
2
  import { PaymentRequirementsV2, ValidationError, PaymentRequirements, PaymentPayloadV2 } from '@armory-sh/base';
3
+ import { ExtensionConfig } from './extensions.js';
4
+ export { buildExtensions, extractExtension } from './extensions.js';
3
5
 
4
6
  /**
5
7
  * Simplified middleware API for easy x402 payment integration
@@ -16,6 +18,12 @@ interface PaymentConfig {
16
18
  token?: TokenId;
17
19
  amount?: string;
18
20
  maxTimeoutSeconds?: number;
21
+ payToByChain?: Record<NetworkId, string>;
22
+ payToByToken?: Record<NetworkId, Record<TokenId, string>>;
23
+ facilitatorUrl?: string;
24
+ facilitatorUrlByChain?: Record<NetworkId, string>;
25
+ facilitatorUrlByToken?: Record<NetworkId, Record<TokenId, string>>;
26
+ extensions?: ExtensionConfig;
19
27
  }
20
28
  interface ResolvedSimpleConfig {
21
29
  requirements: PaymentRequirementsV2[];
@@ -24,10 +32,16 @@ interface ResolvedSimpleConfig {
24
32
  declare function createPaymentRequirements(config: PaymentConfig): ResolvedSimpleConfig;
25
33
  declare function paymentMiddleware(config: PaymentConfig): (c: Context, next: Next) => Promise<Response | void>;
26
34
 
35
+ interface RouteAwarePaymentConfig extends PaymentConfig {
36
+ route?: string;
37
+ routes?: string[];
38
+ perRoute?: Record<string, Partial<PaymentConfig>>;
39
+ }
40
+ declare const routeAwarePaymentMiddleware: (config: RouteAwarePaymentConfig) => (c: Context, next: Next) => Promise<Response | void>;
41
+
27
42
  interface AdvancedPaymentConfig {
28
43
  requirements: PaymentRequirements;
29
44
  facilitatorUrl?: string;
30
- skipVerification?: boolean;
31
45
  network?: string;
32
46
  }
33
47
  interface AugmentedRequest extends Request {
@@ -39,4 +53,4 @@ interface AugmentedRequest extends Request {
39
53
  }
40
54
  declare const advancedPaymentMiddleware: (config: AdvancedPaymentConfig) => (c: Context, next: Next) => Promise<Response | void>;
41
55
 
42
- export { type AdvancedPaymentConfig, type AugmentedRequest, type PaymentConfig, advancedPaymentMiddleware, createPaymentRequirements, paymentMiddleware };
56
+ export { type AdvancedPaymentConfig, type AugmentedRequest, ExtensionConfig, type PaymentConfig, type RouteAwarePaymentConfig, advancedPaymentMiddleware, createPaymentRequirements, paymentMiddleware, routeAwarePaymentMiddleware };
package/dist/index.js CHANGED
@@ -16,6 +16,65 @@ import {
16
16
  import {
17
17
  TOKENS
18
18
  } from "@armory-sh/base";
19
+
20
+ // src/extensions.ts
21
+ var declareDiscoveryExtension = (config = {}) => {
22
+ const info = {};
23
+ if (config.input !== void 0) {
24
+ info.input = config.input;
25
+ }
26
+ if (config.inputSchema !== void 0) {
27
+ info.inputSchema = config.inputSchema;
28
+ }
29
+ if (config.output !== void 0) {
30
+ info.output = config.output;
31
+ }
32
+ return { info, schema: { type: "object" } };
33
+ };
34
+ var declareSIWxExtension = (config = {}) => {
35
+ const info = {};
36
+ if (config.domain !== void 0) {
37
+ info.domain = config.domain;
38
+ }
39
+ if (config.resourceUri !== void 0) {
40
+ info.resourceUri = config.resourceUri;
41
+ }
42
+ if (config.network !== void 0) {
43
+ info.network = config.network;
44
+ }
45
+ if (config.statement !== void 0) {
46
+ info.statement = config.statement;
47
+ }
48
+ if (config.version !== void 0) {
49
+ info.version = config.version;
50
+ }
51
+ if (config.expirationSeconds !== void 0) {
52
+ info.expirationSeconds = config.expirationSeconds;
53
+ }
54
+ return { info, schema: { type: "object" } };
55
+ };
56
+ function buildExtensions(config) {
57
+ const extensions = {};
58
+ if (config.bazaar) {
59
+ extensions.bazaar = declareDiscoveryExtension(config.bazaar);
60
+ }
61
+ if (config.signInWithX) {
62
+ extensions["sign-in-with-x"] = declareSIWxExtension(config.signInWithX);
63
+ }
64
+ return extensions;
65
+ }
66
+ function extractExtension(extensions, key) {
67
+ if (!extensions || typeof extensions !== "object") {
68
+ return null;
69
+ }
70
+ const extension = extensions[key];
71
+ if (!extension || typeof extension !== "object") {
72
+ return null;
73
+ }
74
+ return extension;
75
+ }
76
+
77
+ // src/simple.ts
19
78
  var isValidationError = (value) => {
20
79
  return typeof value === "object" && value !== null && "code" in value;
21
80
  };
@@ -83,6 +142,56 @@ function toAtomicUnits(amount) {
83
142
  }
84
143
  return `${amount}000000`;
85
144
  }
145
+ function resolvePayTo(config, network, token) {
146
+ const chainId = network.config.chainId;
147
+ if (config.payToByToken) {
148
+ for (const [chainKey, tokenMap] of Object.entries(config.payToByToken)) {
149
+ const resolvedChain = resolveNetwork(chainKey);
150
+ if (!isValidationError(resolvedChain) && resolvedChain.config.chainId === chainId) {
151
+ for (const [tokenKey, address] of Object.entries(tokenMap)) {
152
+ const resolvedToken = resolveToken(tokenKey, network);
153
+ if (!isValidationError(resolvedToken) && resolvedToken.config.contractAddress.toLowerCase() === token.config.contractAddress.toLowerCase()) {
154
+ return address;
155
+ }
156
+ }
157
+ }
158
+ }
159
+ }
160
+ if (config.payToByChain) {
161
+ for (const [chainKey, address] of Object.entries(config.payToByChain)) {
162
+ const resolvedChain = resolveNetwork(chainKey);
163
+ if (!isValidationError(resolvedChain) && resolvedChain.config.chainId === chainId) {
164
+ return address;
165
+ }
166
+ }
167
+ }
168
+ return config.payTo;
169
+ }
170
+ function resolveFacilitatorUrl(config, network, token) {
171
+ const chainId = network.config.chainId;
172
+ if (config.facilitatorUrlByToken) {
173
+ for (const [chainKey, tokenMap] of Object.entries(config.facilitatorUrlByToken)) {
174
+ const resolvedChain = resolveNetwork(chainKey);
175
+ if (!isValidationError(resolvedChain) && resolvedChain.config.chainId === chainId) {
176
+ for (const [tokenKey, url] of Object.entries(tokenMap)) {
177
+ const resolvedToken = resolveToken(tokenKey, network);
178
+ if (!isValidationError(resolvedToken) && resolvedToken.config.contractAddress.toLowerCase() === token.config.contractAddress.toLowerCase()) {
179
+ return url;
180
+ }
181
+ }
182
+ }
183
+ }
184
+ }
185
+ if (config.facilitatorUrlByChain) {
186
+ for (const [chainKey, url] of Object.entries(config.facilitatorUrlByChain)) {
187
+ const resolvedChain = resolveNetwork(chainKey);
188
+ if (!isValidationError(resolvedChain) && resolvedChain.config.chainId === chainId) {
189
+ return url;
190
+ }
191
+ }
192
+ }
193
+ return config.facilitatorUrl;
194
+ }
86
195
  function createPaymentRequirements(config) {
87
196
  ensureTokensRegistered();
88
197
  const {
@@ -111,16 +220,19 @@ function createPaymentRequirements(config) {
111
220
  }
112
221
  const atomicAmount = toAtomicUnits(amount);
113
222
  const tokenConfig = resolvedToken.config;
223
+ const resolvedPayTo = resolvePayTo(config, network, resolvedToken);
224
+ const resolvedFacilitatorUrl = resolveFacilitatorUrl(config, network, resolvedToken);
114
225
  requirements.push({
115
226
  scheme: "exact",
116
227
  network: network.caip2,
117
228
  amount: atomicAmount,
118
229
  asset: tokenConfig.contractAddress,
119
- payTo,
230
+ payTo: resolvedPayTo,
120
231
  maxTimeoutSeconds,
121
232
  extra: {
122
233
  name: tokenConfig.name,
123
- version: tokenConfig.version
234
+ version: tokenConfig.version,
235
+ ...resolvedFacilitatorUrl && { facilitatorUrl: resolvedFacilitatorUrl }
124
236
  }
125
237
  });
126
238
  }
@@ -148,7 +260,8 @@ function paymentMiddleware(config) {
148
260
  x402Version: 2,
149
261
  error: "Payment required",
150
262
  resource,
151
- accepts: requirements
263
+ accepts: requirements,
264
+ extensions: config.extensions ? buildExtensions(config.extensions) : void 0
152
265
  };
153
266
  c.status(402);
154
267
  c.header(V2_HEADERS.PAYMENT_REQUIRED, safeBase64Encode(JSON.stringify(paymentRequired)));
@@ -178,9 +291,104 @@ function paymentMiddleware(config) {
178
291
  };
179
292
  }
180
293
 
294
+ // src/routes.ts
295
+ import {
296
+ safeBase64Encode as safeBase64Encode2,
297
+ V2_HEADERS as V2_HEADERS2,
298
+ matchRoute,
299
+ validateRouteConfig
300
+ } from "@armory-sh/base";
301
+ var resolveRouteConfig = (config) => {
302
+ const validationError = validateRouteConfig(config);
303
+ if (validationError) {
304
+ return { routes: [], error: validationError };
305
+ }
306
+ const { route, routes, perRoute, ...baseConfig } = config;
307
+ const routePatterns = route ? [route] : routes || [];
308
+ const resolvedRoutes = [];
309
+ for (const pattern of routePatterns) {
310
+ const perRouteOverride = perRoute?.[pattern];
311
+ const mergedConfig = {
312
+ ...baseConfig,
313
+ ...perRouteOverride
314
+ };
315
+ resolvedRoutes.push({
316
+ pattern,
317
+ config: mergedConfig
318
+ });
319
+ }
320
+ return { routes: resolvedRoutes };
321
+ };
322
+ var routeAwarePaymentMiddleware = (config) => {
323
+ const { routes, error } = resolveRouteConfig(config);
324
+ return async (c, next) => {
325
+ if (error) {
326
+ c.status(500);
327
+ return c.json({
328
+ error: "Payment middleware configuration error",
329
+ details: error.message
330
+ });
331
+ }
332
+ const path = new URL(c.req.url).pathname;
333
+ const matchedRoute = routes.find((r) => matchRoute(r.pattern, path));
334
+ if (!matchedRoute) {
335
+ return next();
336
+ }
337
+ const { requirements, error: requirementsError } = createPaymentRequirements(matchedRoute.config);
338
+ if (requirementsError) {
339
+ c.status(500);
340
+ return c.json({
341
+ error: "Payment middleware configuration error",
342
+ details: requirementsError.message
343
+ });
344
+ }
345
+ const paymentHeader = c.req.header(V2_HEADERS2.PAYMENT_SIGNATURE);
346
+ if (!paymentHeader) {
347
+ const resource = {
348
+ url: c.req.url,
349
+ description: "API Access",
350
+ mimeType: "application/json"
351
+ };
352
+ const paymentRequired = {
353
+ x402Version: 2,
354
+ error: "Payment required",
355
+ resource,
356
+ accepts: requirements
357
+ };
358
+ c.status(402);
359
+ c.header(
360
+ V2_HEADERS2.PAYMENT_REQUIRED,
361
+ safeBase64Encode2(JSON.stringify(paymentRequired))
362
+ );
363
+ return c.json({
364
+ error: "Payment required",
365
+ accepts: requirements
366
+ });
367
+ }
368
+ let parsedPayload;
369
+ try {
370
+ const decoded = atob(paymentHeader);
371
+ parsedPayload = JSON.parse(decoded);
372
+ } catch {
373
+ try {
374
+ parsedPayload = JSON.parse(paymentHeader);
375
+ } catch {
376
+ c.status(400);
377
+ return c.json({ error: "Invalid payment payload" });
378
+ }
379
+ }
380
+ c.set("payment", {
381
+ payload: parsedPayload,
382
+ verified: false,
383
+ route: matchedRoute.pattern
384
+ });
385
+ return next();
386
+ };
387
+ };
388
+
181
389
  // src/index.ts
182
390
  var advancedPaymentMiddleware = (config) => {
183
- const { requirements, facilitatorUrl, skipVerification = false, network = "base" } = config;
391
+ const { requirements, facilitatorUrl, network = "base" } = config;
184
392
  return async (c, next) => {
185
393
  const paymentHeader = c.req.header(PAYMENT_SIGNATURE_HEADER);
186
394
  if (!paymentHeader) {
@@ -209,13 +417,16 @@ var advancedPaymentMiddleware = (config) => {
209
417
  c.set("payment", {
210
418
  payload: paymentPayload,
211
419
  payerAddress,
212
- verified: !skipVerification
420
+ verified: true
213
421
  });
214
422
  return next();
215
423
  };
216
424
  };
217
425
  export {
218
426
  advancedPaymentMiddleware,
427
+ buildExtensions,
219
428
  createPaymentRequirements,
220
- paymentMiddleware
429
+ extractExtension,
430
+ paymentMiddleware,
431
+ routeAwarePaymentMiddleware
221
432
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@armory-sh/middleware-hono",
3
- "version": "0.3.19",
3
+ "version": "0.3.20",
4
4
  "license": "MIT",
5
5
  "author": "Sawyer Cutler <sawyer@dirtroad.dev>",
6
6
  "type": "module",
@@ -11,6 +11,11 @@
11
11
  "types": "./dist/index.d.ts",
12
12
  "bun": "./src/index.ts",
13
13
  "default": "./dist/index.js"
14
+ },
15
+ "./extensions": {
16
+ "types": "./dist/extensions.d.ts",
17
+ "bun": "./src/extensions.ts",
18
+ "default": "./dist/extensions.js"
14
19
  }
15
20
  },
16
21
  "files": [
@@ -28,10 +33,12 @@
28
33
  "hono": "^4"
29
34
  },
30
35
  "dependencies": {
31
- "@armory-sh/base": "0.2.19"
36
+ "@armory-sh/base": "0.2.20",
37
+ "@armory-sh/extensions": "0.1.1"
32
38
  },
33
39
  "devDependencies": {
34
40
  "bun-types": "latest",
41
+ "tsup": "^8.5.1",
35
42
  "typescript": "5.9.3",
36
43
  "hono": "^4"
37
44
  },