@pincerpay/merchant 0.2.0 → 0.5.0

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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 PincerPay
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 PincerPay
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,233 +1,259 @@
1
- # @pincerpay/merchant
2
-
3
- [![npm](https://img.shields.io/npm/v/@pincerpay/merchant?style=flat-square)](https://www.npmjs.com/package/@pincerpay/merchant)
4
- [![downloads](https://img.shields.io/npm/dm/@pincerpay/merchant?style=flat-square)](https://www.npmjs.com/package/@pincerpay/merchant)
5
- [![license](https://img.shields.io/npm/l/@pincerpay/merchant?style=flat-square)](https://github.com/ds1/pincerpay/blob/master/LICENSE)
6
- [![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
7
-
8
- Merchant SDK for accepting on-chain USDC payments from AI agents via the [x402 protocol](https://x402.org). Supports Express, Hono, and Next.js.
9
-
10
- > **ESM Required:** Your project must have `"type": "module"` in package.json. This package is ESM-only.
11
-
12
- ## Install
13
-
14
- ```bash
15
- npm install @pincerpay/merchant
16
- ```
17
-
18
- ## Quick Start
19
-
20
- ### Express
21
-
22
- ```typescript
23
- import express from "express";
24
- import { pincerpay } from "@pincerpay/merchant/express";
25
-
26
- const app = express();
27
-
28
- app.use(
29
- pincerpay({
30
- apiKey: process.env.PINCERPAY_API_KEY!,
31
- merchantAddress: "YOUR_SOLANA_ADDRESS",
32
- routes: {
33
- "GET /api/weather": {
34
- price: "0.01",
35
- chain: "solana",
36
- description: "Current weather data",
37
- },
38
- "POST /api/analyze": {
39
- price: "0.10",
40
- chains: ["solana", "base"],
41
- description: "AI text analysis",
42
- },
43
- },
44
- })
45
- );
46
-
47
- app.get("/api/weather", (req, res) => {
48
- res.json({ temp: 72, unit: "F" });
49
- });
50
-
51
- app.listen(3000);
52
- ```
53
-
54
- ### Hono
55
-
56
- ```typescript
57
- import { Hono } from "hono";
58
- import { pincerpayHono } from "@pincerpay/merchant/hono";
59
-
60
- const app = new Hono();
61
-
62
- app.use(
63
- "*",
64
- pincerpayHono({
65
- apiKey: process.env.PINCERPAY_API_KEY!,
66
- merchantAddress: "YOUR_SOLANA_ADDRESS",
67
- routes: {
68
- "GET /api/weather": {
69
- price: "0.01",
70
- chain: "solana",
71
- description: "Current weather data",
72
- },
73
- },
74
- })
75
- );
76
-
77
- app.get("/api/weather", (c) => c.json({ temp: 72 }));
78
-
79
- export default app;
80
- ```
81
-
82
- ### Next.js (Hono Adapter)
83
-
84
- Next.js doesn't have native x402 middleware support. Use Hono as a lightweight handler inside a catch-all App Router route:
85
-
86
- ```typescript
87
- // app/api/[...route]/route.ts
88
- import { Hono } from "hono";
89
- import { handle } from "hono/vercel";
90
- import { pincerpayHono } from "@pincerpay/merchant/hono";
91
-
92
- const app = new Hono().basePath("/api");
93
-
94
- app.use(
95
- "*",
96
- pincerpayHono({
97
- apiKey: process.env.PINCERPAY_API_KEY!,
98
- merchantAddress: "YOUR_SOLANA_ADDRESS",
99
- syncFacilitatorOnStart: false, // Avoids build-time network call during prerendering
100
- routes: {
101
- "GET /api/weather": {
102
- price: "0.01",
103
- chain: "solana",
104
- description: "Current weather data",
105
- },
106
- },
107
- })
108
- );
109
-
110
- app.get("/weather", (c) => c.json({ temp: 72 }));
111
-
112
- export const GET = handle(app);
113
- export const POST = handle(app);
114
- ```
115
-
116
- Install: `npm install @pincerpay/merchant hono`
117
-
118
- > **Note:** `basePath("/api")` must match the catch-all route location. Route handlers use paths relative to basePath (`/weather` serves `/api/weather`).
119
-
120
- ## API Reference
121
-
122
- ### `pincerpay(config): Express.RequestHandler`
123
-
124
- Express middleware that intercepts requests matching configured routes and returns HTTP 402 with x402 payment requirements.
125
-
126
- ### `pincerpayHono(config): HonoMiddleware`
127
-
128
- Hono middleware with identical behavior. Also used for Next.js via the Hono adapter pattern (see Next.js example above).
129
-
130
- ### `PincerPayClient`
131
-
132
- Low-level client for direct facilitator API access.
133
-
134
- ```typescript
135
- import { PincerPayClient } from "@pincerpay/merchant";
136
-
137
- const client = new PincerPayClient({
138
- apiKey: process.env.PINCERPAY_API_KEY!,
139
- merchantAddress: "YOUR_ADDRESS",
140
- facilitatorUrl: "https://facilitator.pincerpay.com", // default
141
- routes: {},
142
- });
143
-
144
- const result = await client.settle(paymentPayload, paymentRequirements);
145
- const status = await client.getStatus(txHash);
146
- const supported = await client.getSupported();
147
- ```
148
-
149
- ### Config
150
-
151
- ```typescript
152
- interface PincerPayConfig {
153
- apiKey: string;
154
- merchantAddress: string;
155
- facilitatorUrl?: string; // defaults to https://facilitator.pincerpay.com
156
- routes: Record<string, RoutePaywallConfig>;
157
- syncFacilitatorOnStart?: boolean; // defer facilitator sync to first request (default: false)
158
- }
159
-
160
- interface RoutePaywallConfig {
161
- price: string; // USDC amount (e.g., "0.01")
162
- chain?: string; // Chain shorthand (e.g., "solana", "base")
163
- chains?: string[]; // Multiple chains
164
- description?: string; // Human-readable description
165
- }
166
- ```
167
-
168
- ### Utility Functions
169
-
170
- ```typescript
171
- import { toBaseUnits, resolveRouteChains, getUsdcAsset } from "@pincerpay/merchant";
172
-
173
- toBaseUnits("0.01"); // "10000" (USDC has 6 decimals)
174
- toBaseUnits("1.00"); // "1000000"
175
-
176
- resolveRouteChains(routeConfig); // ["solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"]
177
-
178
- getUsdcAsset("solana-devnet"); // USDC mint address for Solana devnet
179
- getUsdcAsset("base"); // USDC contract address for Base
180
- ```
181
-
182
- ## Common Patterns
183
-
184
- ### Multi-chain pricing
185
-
186
- ```typescript
187
- pincerpay({
188
- apiKey: process.env.PINCERPAY_API_KEY!,
189
- merchantAddress: "YOUR_ADDRESS",
190
- routes: {
191
- "GET /api/data": {
192
- price: "0.05",
193
- chains: ["solana", "base", "polygon"],
194
- description: "Accept USDC on any supported chain",
195
- },
196
- },
197
- });
198
- ```
199
-
200
- ### Free routes alongside paid routes
201
-
202
- Routes not listed in `routes` pass through without payment. Only matching `METHOD /path` patterns trigger the 402 paywall.
203
-
204
- ```typescript
205
- pincerpay({
206
- apiKey: process.env.PINCERPAY_API_KEY!,
207
- merchantAddress: "YOUR_ADDRESS",
208
- routes: {
209
- "GET /api/premium": { price: "1.00", chain: "solana" },
210
- // GET /api/free is not listed -- no paywall
211
- },
212
- });
213
- ```
214
-
215
- ## Anti-Patterns
216
-
217
- ### Don't hardcode API keys
218
-
219
- ```typescript
220
- // Bad
221
- pincerpay({ apiKey: "pp_live_abc123...", ... });
222
-
223
- // Good
224
- pincerpay({ apiKey: process.env.PINCERPAY_API_KEY!, ... });
225
- ```
226
-
227
- ### Don't use the merchant SDK on the agent side
228
-
229
- The merchant SDK is for servers accepting payments. Agents should use `@pincerpay/agent` to make payments.
230
-
231
- ### Don't set price to "0"
232
-
233
- A price of "0" will still trigger the 402 flow. If a route should be free, omit it from the `routes` config.
1
+ # @pincerpay/merchant
2
+
3
+ [![npm](https://img.shields.io/npm/v/@pincerpay/merchant?style=flat-square)](https://www.npmjs.com/package/@pincerpay/merchant)
4
+ [![downloads](https://img.shields.io/npm/dm/@pincerpay/merchant?style=flat-square)](https://www.npmjs.com/package/@pincerpay/merchant)
5
+ [![license](https://img.shields.io/npm/l/@pincerpay/merchant?style=flat-square)](https://github.com/ds1/pincerpay/blob/master/LICENSE)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
7
+
8
+ Merchant SDK for accepting on-chain USDC payments from AI agents via the [x402 protocol](https://x402.org). Supports Express, Hono, and Next.js.
9
+
10
+ > **ESM Required:** Your project must have `"type": "module"` in package.json. This package is ESM-only.
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ npm install @pincerpay/merchant
16
+ ```
17
+
18
+ ## Quick Start
19
+
20
+ ### Express
21
+
22
+ ```typescript
23
+ import express from "express";
24
+ import { pincerpay } from "@pincerpay/merchant/express";
25
+
26
+ const app = express();
27
+
28
+ app.use(
29
+ pincerpay({
30
+ apiKey: process.env.PINCERPAY_API_KEY!,
31
+ merchantAddress: "YOUR_SOLANA_ADDRESS",
32
+ routes: {
33
+ "GET /api/weather": {
34
+ price: "0.01",
35
+ chain: "solana",
36
+ description: "Current weather data",
37
+ },
38
+ "POST /api/analyze": {
39
+ price: "0.10",
40
+ chains: ["solana", "base"],
41
+ description: "AI text analysis",
42
+ },
43
+ },
44
+ })
45
+ );
46
+
47
+ app.get("/api/weather", (req, res) => {
48
+ res.json({ temp: 72, unit: "F" });
49
+ });
50
+
51
+ app.listen(3000);
52
+ ```
53
+
54
+ ### Hono
55
+
56
+ ```typescript
57
+ import { Hono } from "hono";
58
+ import { pincerpayHono } from "@pincerpay/merchant/hono";
59
+
60
+ const app = new Hono();
61
+
62
+ app.use(
63
+ "*",
64
+ pincerpayHono({
65
+ apiKey: process.env.PINCERPAY_API_KEY!,
66
+ merchantAddress: "YOUR_SOLANA_ADDRESS",
67
+ routes: {
68
+ "GET /api/weather": {
69
+ price: "0.01",
70
+ chain: "solana",
71
+ description: "Current weather data",
72
+ },
73
+ },
74
+ })
75
+ );
76
+
77
+ app.get("/api/weather", (c) => c.json({ temp: 72 }));
78
+
79
+ export default app;
80
+ ```
81
+
82
+ ### Next.js (Hono Adapter)
83
+
84
+ Next.js doesn't have native x402 middleware support. Use Hono as a lightweight handler inside a catch-all App Router route:
85
+
86
+ ```typescript
87
+ // app/api/[...route]/route.ts
88
+ import { Hono } from "hono";
89
+ import { handle } from "hono/vercel";
90
+ import { pincerpayHono } from "@pincerpay/merchant/hono";
91
+
92
+ const app = new Hono().basePath("/api");
93
+
94
+ app.use(
95
+ "*",
96
+ pincerpayHono({
97
+ apiKey: process.env.PINCERPAY_API_KEY!,
98
+ merchantAddress: "YOUR_SOLANA_ADDRESS",
99
+ syncFacilitatorOnStart: false, // Avoids build-time network call during prerendering
100
+ routes: {
101
+ "GET /api/weather": {
102
+ price: "0.01",
103
+ chain: "solana",
104
+ description: "Current weather data",
105
+ },
106
+ },
107
+ })
108
+ );
109
+
110
+ app.get("/weather", (c) => c.json({ temp: 72 }));
111
+
112
+ export const GET = handle(app);
113
+ export const POST = handle(app);
114
+ ```
115
+
116
+ Install: `npm install @pincerpay/merchant hono`
117
+
118
+ > **Note:** `basePath("/api")` must match the catch-all route location. Route handlers use paths relative to basePath (`/weather` serves `/api/weather`).
119
+
120
+ ## API Reference
121
+
122
+ ### `pincerpay(config): Express.RequestHandler`
123
+
124
+ Express middleware that intercepts requests matching configured routes and returns HTTP 402 with x402 payment requirements.
125
+
126
+ ### `pincerpayHono(config): HonoMiddleware`
127
+
128
+ Hono middleware with identical behavior. Also used for Next.js via the Hono adapter pattern (see Next.js example above).
129
+
130
+ ### `PincerPayClient`
131
+
132
+ Low-level client for direct facilitator API access.
133
+
134
+ ```typescript
135
+ import { PincerPayClient } from "@pincerpay/merchant";
136
+
137
+ const client = new PincerPayClient({
138
+ apiKey: process.env.PINCERPAY_API_KEY!,
139
+ merchantAddress: "YOUR_ADDRESS",
140
+ facilitatorUrl: "https://facilitator.pincerpay.com", // default
141
+ routes: {},
142
+ });
143
+
144
+ const result = await client.settle(paymentPayload, paymentRequirements);
145
+ const status = await client.getStatus(txHash);
146
+ const supported = await client.getSupported();
147
+ ```
148
+
149
+ ### Config
150
+
151
+ ```typescript
152
+ interface PincerPayConfig {
153
+ apiKey: string;
154
+ merchantAddress: string;
155
+ facilitatorUrl?: string; // defaults to https://facilitator.pincerpay.com
156
+ routes: Record<string, RoutePaywallConfig>;
157
+ syncFacilitatorOnStart?: boolean; // defer facilitator sync to first request (default: false)
158
+ }
159
+
160
+ interface RoutePaywallConfig {
161
+ price: string; // USDC amount (e.g., "0.01")
162
+ chain?: string; // Chain shorthand (e.g., "solana", "base")
163
+ chains?: string[]; // Multiple chains
164
+ description?: string; // Human-readable description
165
+ }
166
+ ```
167
+
168
+ ### Utility Functions
169
+
170
+ ```typescript
171
+ import { toBaseUnits, resolveRouteChains, getUsdcAsset } from "@pincerpay/merchant";
172
+
173
+ toBaseUnits("0.01"); // "10000" (USDC has 6 decimals)
174
+ toBaseUnits("1.00"); // "1000000"
175
+
176
+ resolveRouteChains(routeConfig); // ["solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"]
177
+
178
+ getUsdcAsset("solana-devnet"); // USDC mint address for Solana devnet
179
+ getUsdcAsset("base"); // USDC contract address for Base
180
+ ```
181
+
182
+ ## Common Patterns
183
+
184
+ ### Multi-chain pricing
185
+
186
+ ```typescript
187
+ pincerpay({
188
+ apiKey: process.env.PINCERPAY_API_KEY!,
189
+ merchantAddress: "YOUR_ADDRESS",
190
+ routes: {
191
+ "GET /api/data": {
192
+ price: "0.05",
193
+ chains: ["solana", "base", "polygon"],
194
+ description: "Accept USDC on any supported chain",
195
+ },
196
+ },
197
+ });
198
+ ```
199
+
200
+ ### Free routes alongside paid routes
201
+
202
+ Routes not listed in `routes` pass through without payment. Only matching `METHOD /path` patterns trigger the 402 paywall.
203
+
204
+ ```typescript
205
+ pincerpay({
206
+ apiKey: process.env.PINCERPAY_API_KEY!,
207
+ merchantAddress: "YOUR_ADDRESS",
208
+ routes: {
209
+ "GET /api/premium": { price: "1.00", chain: "solana" },
210
+ // GET /api/free is not listed -- no paywall
211
+ },
212
+ });
213
+ ```
214
+
215
+ ## Webhook Verification
216
+
217
+ PincerPay signs every webhook delivery with your webhook secret (HMAC-SHA256). Verify the `X-PincerPay-Signature` header to ensure requests are authentic:
218
+
219
+ ```typescript
220
+ import crypto from "node:crypto";
221
+
222
+ function verifyWebhook(payload: string, header: string, secret: string): boolean {
223
+ const parts = Object.fromEntries(
224
+ header.split(",").map((p) => p.split("=") as [string, string])
225
+ );
226
+ const age = Math.floor(Date.now() / 1000) - Number(parts.t);
227
+ if (age > 300) return false; // Reject replays > 5 min
228
+
229
+ const expected = crypto
230
+ .createHmac("sha256", secret)
231
+ .update(`${parts.t}.${payload}`)
232
+ .digest("hex");
233
+ return crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
234
+ }
235
+ ```
236
+
237
+ Header format: `t=<unix-timestamp>,v1=<hmac-sha256-hex>`
238
+
239
+ Your webhook secret is in the [dashboard settings](https://www.pincerpay.com/dashboard/settings). See [full docs](https://www.pincerpay.com/docs/testing) for Python examples and Express integration patterns.
240
+
241
+ ## Anti-Patterns
242
+
243
+ ### Don't hardcode API keys
244
+
245
+ ```typescript
246
+ // Bad
247
+ pincerpay({ apiKey: "pp_live_abc123...", ... });
248
+
249
+ // Good
250
+ pincerpay({ apiKey: process.env.PINCERPAY_API_KEY!, ... });
251
+ ```
252
+
253
+ ### Don't use the merchant SDK on the agent side
254
+
255
+ The merchant SDK is for servers accepting payments. Agents should use `@pincerpay/agent` to make payments.
256
+
257
+ ### Don't set price to "0"
258
+
259
+ A price of "0" will still trigger the 402 flow. If a route should be free, omit it from the `routes` config.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- export { pincerpay } from "./middleware/express.js";
2
- export { pincerpayHono } from "./middleware/hono.js";
1
+ export { createPincerPayMiddleware } from "./middleware/nextjs.js";
3
2
  export { PincerPayClient, toBaseUnits, resolveRouteChains, getUsdcAsset } from "./client.js";
4
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,3 @@
1
- export { pincerpay } from "./middleware/express.js";
2
- export { pincerpayHono } from "./middleware/hono.js";
1
+ export { createPincerPayMiddleware } from "./middleware/nextjs.js";
3
2
  export { PincerPayClient, toBaseUnits, resolveRouteChains, getUsdcAsset } from "./client.js";
4
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,31 @@
1
+ import type { PincerPayConfig } from "@pincerpay/core";
2
+ /**
3
+ * Lightweight Next.js / Hono middleware for PincerPay x402 paywalls.
4
+ *
5
+ * Zero @x402/*, viem, @solana/kit imports — settlement is delegated
6
+ * entirely to the PincerPay facilitator via fetch().
7
+ *
8
+ * ```ts
9
+ * // app/api/[...route]/route.ts
10
+ * import { Hono } from "hono";
11
+ * import { handle } from "hono/vercel";
12
+ * import { createPincerPayMiddleware } from "@pincerpay/merchant/nextjs";
13
+ *
14
+ * const app = new Hono().basePath("/api");
15
+ *
16
+ * app.use("*", createPincerPayMiddleware({
17
+ * apiKey: process.env.PINCERPAY_API_KEY!,
18
+ * merchantAddress: "YOUR_WALLET_ADDRESS",
19
+ * routes: {
20
+ * "GET /api/weather": { price: "0.01", chain: "solana", description: "Weather data" },
21
+ * },
22
+ * }));
23
+ *
24
+ * app.get("/weather", (c) => c.json({ temp: 72 }));
25
+ *
26
+ * export const GET = handle(app);
27
+ * export const POST = handle(app);
28
+ * ```
29
+ */
30
+ export declare function createPincerPayMiddleware(config: PincerPayConfig): any;
31
+ //# sourceMappingURL=nextjs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nextjs.d.ts","sourceRoot":"","sources":["../../src/middleware/nextjs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAoBvD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,eAAe,GAmMzD,GAAG,CACV"}
@@ -0,0 +1,182 @@
1
+ import { resolveChain, DEFAULT_FACILITATOR_URL, API_KEY_HEADER, FACILITATOR_ROUTES, } from "@pincerpay/core";
2
+ /**
3
+ * Convert human-readable USDC price (e.g., "0.01") to base units (e.g., "10000").
4
+ */
5
+ function toBaseUnits(amount) {
6
+ const parts = amount.split(".");
7
+ const whole = parts[0] ?? "0";
8
+ const frac = (parts[1] ?? "").padEnd(6, "0").slice(0, 6);
9
+ const result = BigInt(whole) * BigInt(1_000_000) + BigInt(frac);
10
+ return result.toString();
11
+ }
12
+ /**
13
+ * Lightweight Next.js / Hono middleware for PincerPay x402 paywalls.
14
+ *
15
+ * Zero @x402/*, viem, @solana/kit imports — settlement is delegated
16
+ * entirely to the PincerPay facilitator via fetch().
17
+ *
18
+ * ```ts
19
+ * // app/api/[...route]/route.ts
20
+ * import { Hono } from "hono";
21
+ * import { handle } from "hono/vercel";
22
+ * import { createPincerPayMiddleware } from "@pincerpay/merchant/nextjs";
23
+ *
24
+ * const app = new Hono().basePath("/api");
25
+ *
26
+ * app.use("*", createPincerPayMiddleware({
27
+ * apiKey: process.env.PINCERPAY_API_KEY!,
28
+ * merchantAddress: "YOUR_WALLET_ADDRESS",
29
+ * routes: {
30
+ * "GET /api/weather": { price: "0.01", chain: "solana", description: "Weather data" },
31
+ * },
32
+ * }));
33
+ *
34
+ * app.get("/weather", (c) => c.json({ temp: 72 }));
35
+ *
36
+ * export const GET = handle(app);
37
+ * export const POST = handle(app);
38
+ * ```
39
+ */
40
+ export function createPincerPayMiddleware(config) {
41
+ // Normalize: strip trailing /v1 if present — FACILITATOR_ROUTES already include the version prefix
42
+ const rawUrl = config.facilitatorUrl ?? DEFAULT_FACILITATOR_URL;
43
+ const facilitatorUrl = rawUrl.replace(/\/v1\/?$/, "");
44
+ // Warn if using devnet facilitator or default URL without explicit config
45
+ if (!config.facilitatorUrl) {
46
+ console.log("[pincerpay] Using production facilitator:", DEFAULT_FACILITATOR_URL);
47
+ }
48
+ // Fetch facilitator's supported schemes eagerly — provides correct `extra` fields
49
+ // (e.g., Solana feePayer = facilitator's address, EVM EIP-712 domain params)
50
+ const facilitatorExtraPromise = fetch(`${facilitatorUrl}${FACILITATOR_ROUTES.supported}`)
51
+ .then((res) => res.json())
52
+ .then((data) => {
53
+ const map = new Map();
54
+ for (const kind of data.kinds) {
55
+ if (kind.extra)
56
+ map.set(kind.network, kind.extra);
57
+ }
58
+ return map;
59
+ })
60
+ .catch(() => new Map());
61
+ const resolvedRoutes = new Map();
62
+ // Default extra fields per namespace (used as fallback if facilitator fetch fails)
63
+ function defaultExtra(namespace) {
64
+ return namespace === "solana"
65
+ ? { feePayer: config.merchantAddress }
66
+ : { name: "USD Coin", version: "2" };
67
+ }
68
+ for (const [pattern, routeConfig] of Object.entries(config.routes)) {
69
+ const chains = routeConfig.chains ??
70
+ (routeConfig.chain ? [routeConfig.chain] : ["solana"]);
71
+ const accepts = chains.map((chainShorthand) => {
72
+ const chain = resolveChain(chainShorthand);
73
+ if (!chain)
74
+ throw new Error(`Unknown chain: ${chainShorthand}`);
75
+ return {
76
+ scheme: "exact",
77
+ network: chain.caip2Id,
78
+ amount: toBaseUnits(routeConfig.price),
79
+ asset: chain.usdcAddress,
80
+ payTo: config.merchantAddress,
81
+ maxTimeoutSeconds: 300,
82
+ extra: defaultExtra(chain.namespace),
83
+ };
84
+ });
85
+ resolvedRoutes.set(pattern, {
86
+ description: routeConfig.description ?? pattern,
87
+ accepts,
88
+ });
89
+ }
90
+ // Once facilitator responds, merge its extra fields into resolved routes
91
+ let facilitatorExtraResolved = false;
92
+ facilitatorExtraPromise.then((extraMap) => {
93
+ if (extraMap.size === 0)
94
+ return;
95
+ for (const route of resolvedRoutes.values()) {
96
+ for (const accept of route.accepts) {
97
+ const extra = extraMap.get(accept.network);
98
+ if (extra)
99
+ accept.extra = { ...accept.extra, ...extra };
100
+ }
101
+ }
102
+ facilitatorExtraResolved = true;
103
+ });
104
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
105
+ return (async (c, next) => {
106
+ const method = c.req.method;
107
+ const path = c.req.path;
108
+ const routeKey = `${method} ${path}`;
109
+ const route = resolvedRoutes.get(routeKey);
110
+ // Not a paywalled route — pass through
111
+ if (!route)
112
+ return next();
113
+ // Ensure facilitator extra fields are resolved before returning 402
114
+ if (!facilitatorExtraResolved)
115
+ await facilitatorExtraPromise;
116
+ // Check for x402 v2 payment signature header
117
+ const paymentHeader = c.req.header("payment-signature") ?? c.req.header("x-payment");
118
+ if (!paymentHeader) {
119
+ // Return 402 Payment Required
120
+ const paymentRequired = {
121
+ x402Version: 2,
122
+ error: "Payment required",
123
+ resource: {
124
+ resource: path,
125
+ description: route.description,
126
+ mimeType: "application/json",
127
+ },
128
+ accepts: route.accepts,
129
+ extensions: {},
130
+ };
131
+ const encoded = Buffer.from(JSON.stringify(paymentRequired)).toString("base64");
132
+ c.header("payment-required", encoded);
133
+ return c.json(paymentRequired, 402);
134
+ }
135
+ // Payment header present — settle via facilitator
136
+ try {
137
+ // x402 may send as raw JSON or base64-encoded JSON
138
+ let decoded;
139
+ try {
140
+ decoded = JSON.parse(paymentHeader);
141
+ }
142
+ catch {
143
+ decoded = JSON.parse(Buffer.from(paymentHeader, "base64").toString("utf-8"));
144
+ }
145
+ const paymentRequirements = decoded.accepted ?? decoded.paymentRequirements;
146
+ const settleRes = await fetch(`${facilitatorUrl}${FACILITATOR_ROUTES.settle}`, {
147
+ method: "POST",
148
+ headers: {
149
+ "content-type": "application/json",
150
+ [API_KEY_HEADER]: config.apiKey,
151
+ },
152
+ body: JSON.stringify({
153
+ paymentPayload: decoded,
154
+ paymentRequirements,
155
+ }),
156
+ });
157
+ const settle = (await settleRes.json());
158
+ if (!settle.success) {
159
+ return c.json({
160
+ error: "Payment settlement failed",
161
+ reason: settle.errorReason,
162
+ message: settle.errorMessage,
163
+ }, 402);
164
+ }
165
+ // Payment succeeded — attach settlement response header and serve resource
166
+ const settleResponse = {
167
+ x402Version: 2,
168
+ success: true,
169
+ transaction: settle.transaction,
170
+ network: settle.network,
171
+ };
172
+ c.header("payment-response", Buffer.from(JSON.stringify(settleResponse)).toString("base64"));
173
+ return next();
174
+ }
175
+ catch (err) {
176
+ console.error("[pincerpay] settlement error:", err);
177
+ return c.json({ error: "Payment processing failed", detail: String(err) }, 500);
178
+ }
179
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
180
+ });
181
+ }
182
+ //# sourceMappingURL=nextjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nextjs.js","sourceRoot":"","sources":["../../src/middleware/nextjs.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@pincerpay/merchant",
3
- "version": "0.2.0",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
- "description": "Merchant SDK for PincerPay. Express and Hono middleware for accepting USDC payments from AI agents.",
5
+ "description": "Merchant SDK for PincerPay. Lightweight Next.js middleware for accepting USDC payments from AI agents via x402.",
6
6
  "license": "MIT",
7
7
  "publishConfig": {
8
8
  "access": "public"
@@ -25,7 +25,7 @@
25
25
  "solana",
26
26
  "merchant-sdk",
27
27
  "middleware",
28
- "express",
28
+ "nextjs",
29
29
  "hono",
30
30
  "typescript",
31
31
  "web3",
@@ -48,47 +48,20 @@
48
48
  "types": "./dist/index.d.ts",
49
49
  "import": "./dist/index.js"
50
50
  },
51
- "./express": {
52
- "types": "./dist/middleware/express.d.ts",
53
- "import": "./dist/middleware/express.js"
54
- },
55
- "./hono": {
56
- "types": "./dist/middleware/hono.d.ts",
57
- "import": "./dist/middleware/hono.js"
51
+ "./nextjs": {
52
+ "types": "./dist/middleware/nextjs.d.ts",
53
+ "import": "./dist/middleware/nextjs.js"
58
54
  }
59
55
  },
60
56
  "dependencies": {
61
- "@x402/core": "^2.3",
62
- "@x402/evm": "^2.3",
63
- "@x402/svm": "^2.3",
64
57
  "zod": "^3.24",
65
- "@pincerpay/core": "0.2.0"
58
+ "@pincerpay/core": "0.5.0"
66
59
  },
67
60
  "peerDependencies": {
68
- "@x402/express": "^2.3",
69
- "@x402/hono": "^2.3",
70
- "express": "^4 || ^5",
71
61
  "hono": "^4"
72
62
  },
73
- "peerDependenciesMeta": {
74
- "@x402/express": {
75
- "optional": true
76
- },
77
- "@x402/hono": {
78
- "optional": true
79
- },
80
- "express": {
81
- "optional": true
82
- },
83
- "hono": {
84
- "optional": true
85
- }
86
- },
87
63
  "devDependencies": {
88
- "@types/express": "^5",
89
- "@x402/express": "^2.3",
90
- "@x402/hono": "^2.3",
91
- "express": "^5",
64
+ "@types/node": "^22",
92
65
  "hono": "^4.12.0",
93
66
  "typescript": "^5.7"
94
67
  },
@@ -1,18 +0,0 @@
1
- import type { PincerPayConfig } from "@pincerpay/core";
2
- import { type PaywallConfig } from "@x402/express";
3
- /**
4
- * Express middleware factory — the dead-simple API from the plan:
5
- *
6
- * ```ts
7
- * app.use(pincerpay({
8
- * apiKey: process.env.PINCERPAY_API_KEY!,
9
- * merchantAddress: "0xYourAddress",
10
- * routes: {
11
- * "GET /api/weather": { price: "0.01", chain: "base", description: "Weather data" },
12
- * },
13
- * }));
14
- * ```
15
- */
16
- export declare function pincerpay(config: PincerPayConfig, paywallConfig?: PaywallConfig): (req: import("express").Request, res: import("express").Response, next: import("express").NextFunction) => Promise<void>;
17
- export { PincerPayClient } from "../client.js";
18
- //# sourceMappingURL=express.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/middleware/express.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,eAAe,CAAC;AAMvB;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,eAAe,EAAE,aAAa,CAAC,EAAE,aAAa,4HA+D/E;AAED,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC"}
@@ -1,62 +0,0 @@
1
- import { resolveChain, DEFAULT_FACILITATOR_URL } from "@pincerpay/core";
2
- import { paymentMiddlewareFromConfig, } from "@x402/express";
3
- import { HTTPFacilitatorClient } from "@x402/core/server";
4
- import { ExactEvmScheme } from "@x402/evm/exact/server";
5
- import { ExactSvmScheme } from "@x402/svm/exact/server";
6
- /**
7
- * Express middleware factory — the dead-simple API from the plan:
8
- *
9
- * ```ts
10
- * app.use(pincerpay({
11
- * apiKey: process.env.PINCERPAY_API_KEY!,
12
- * merchantAddress: "0xYourAddress",
13
- * routes: {
14
- * "GET /api/weather": { price: "0.01", chain: "base", description: "Weather data" },
15
- * },
16
- * }));
17
- * ```
18
- */
19
- export function pincerpay(config, paywallConfig) {
20
- const facilitatorUrl = config.facilitatorUrl ?? DEFAULT_FACILITATOR_URL;
21
- // Build x402-compatible routes config
22
- // Pass price as Money (string) so the EVM server scheme handles conversion
23
- // and automatically includes EIP-712 domain parameters (name, version)
24
- const x402Routes = {};
25
- for (const [pattern, routeConfig] of Object.entries(config.routes)) {
26
- const chains = routeConfig.chains ?? (routeConfig.chain ? [routeConfig.chain] : ["solana"]);
27
- const accepts = chains.map((chainShorthand) => {
28
- const chain = resolveChain(chainShorthand);
29
- if (!chain)
30
- throw new Error(`Unknown chain: ${chainShorthand}`);
31
- return {
32
- scheme: "exact",
33
- network: chain.caip2Id,
34
- payTo: config.merchantAddress,
35
- price: routeConfig.price,
36
- maxTimeoutSeconds: 300,
37
- };
38
- });
39
- x402Routes[pattern] = {
40
- accepts,
41
- description: routeConfig.description ?? pattern,
42
- };
43
- }
44
- // Create facilitator client pointing to PincerPay
45
- const facilitatorClient = new HTTPFacilitatorClient({
46
- url: facilitatorUrl,
47
- createAuthHeaders: async () => ({
48
- verify: { "x-pincerpay-api-key": config.apiKey },
49
- settle: { "x-pincerpay-api-key": config.apiKey },
50
- supported: { "x-pincerpay-api-key": config.apiKey },
51
- }),
52
- });
53
- // Register server schemes so the resource server can build payment requirements
54
- const schemes = [
55
- { network: "eip155:*", server: new ExactEvmScheme() },
56
- { network: "solana:*", server: new ExactSvmScheme() },
57
- ];
58
- return paymentMiddlewareFromConfig(x402Routes, facilitatorClient, schemes, paywallConfig, undefined, // paywall provider
59
- config.syncFacilitatorOnStart ?? true);
60
- }
61
- export { PincerPayClient } from "../client.js";
62
- //# sourceMappingURL=express.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"express.js","sourceRoot":"","sources":["../../src/middleware/express.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EACL,2BAA2B,GAE5B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,SAAS,CAAC,MAAuB,EAAE,aAA6B;IAC9E,MAAM,cAAc,GAAG,MAAM,CAAC,cAAc,IAAI,uBAAuB,CAAC;IAExE,sCAAsC;IACtC,2EAA2E;IAC3E,uEAAuE;IACvE,MAAM,UAAU,GASX,EAAE,CAAC;IAER,KAAK,MAAM,CAAC,OAAO,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QACnE,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QAE5F,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,cAAc,EAAE,EAAE;YAC5C,MAAM,KAAK,GAAG,YAAY,CAAC,cAAc,CAAC,CAAC;YAC3C,IAAI,CAAC,KAAK;gBAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,cAAc,EAAE,CAAC,CAAC;YAEhE,OAAO;gBACL,MAAM,EAAE,OAAgB;gBACxB,OAAO,EAAE,KAAK,CAAC,OAAkB;gBACjC,KAAK,EAAE,MAAM,CAAC,eAAe;gBAC7B,KAAK,EAAE,WAAW,CAAC,KAAK;gBACxB,iBAAiB,EAAE,GAAG;aACvB,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,UAAU,CAAC,OAAO,CAAC,GAAG;YACpB,OAAO;YACP,WAAW,EAAE,WAAW,CAAC,WAAW,IAAI,OAAO;SAChD,CAAC;IACJ,CAAC;IAED,kDAAkD;IAClD,MAAM,iBAAiB,GAAG,IAAI,qBAAqB,CAAC;QAClD,GAAG,EAAE,cAAc;QACnB,iBAAiB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;YAC9B,MAAM,EAAE,EAAE,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE;YAChD,MAAM,EAAE,EAAE,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE;YAChD,SAAS,EAAE,EAAE,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE;SACpD,CAAC;KACH,CAAC,CAAC;IAEH,gFAAgF;IAChF,MAAM,OAAO,GAAG;QACd,EAAE,OAAO,EAAE,UAAqB,EAAE,MAAM,EAAE,IAAI,cAAc,EAAE,EAAE;QAChE,EAAE,OAAO,EAAE,UAAqB,EAAE,MAAM,EAAE,IAAI,cAAc,EAAE,EAAE;KACjE,CAAC;IAEF,OAAO,2BAA2B,CAChC,UAAU,EACV,iBAAiB,EACjB,OAAO,EACP,aAAa,EACb,SAAS,EAAE,mBAAmB;IAC9B,MAAM,CAAC,sBAAsB,IAAI,IAAI,CACtC,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC"}
@@ -1,18 +0,0 @@
1
- import type { PincerPayConfig } from "@pincerpay/core";
2
- import { type PaywallConfig } from "@x402/hono";
3
- /**
4
- * Hono middleware factory for PincerPay merchants.
5
- *
6
- * ```ts
7
- * app.use("*", pincerpayHono({
8
- * apiKey: process.env.PINCERPAY_API_KEY!,
9
- * merchantAddress: "0xYourAddress",
10
- * routes: {
11
- * "GET /api/weather": { price: "0.01", chain: "base", description: "Weather data" },
12
- * },
13
- * }));
14
- * ```
15
- */
16
- export declare function pincerpayHono(config: PincerPayConfig, paywallConfig?: PaywallConfig): import("hono").MiddlewareHandler;
17
- export { PincerPayClient } from "../client.js";
18
- //# sourceMappingURL=hono.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"hono.d.ts","sourceRoot":"","sources":["../../src/middleware/hono.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,YAAY,CAAC;AAMpB;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,eAAe,EAAE,aAAa,CAAC,EAAE,aAAa,oCA+DnF;AAED,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC"}
@@ -1,62 +0,0 @@
1
- import { resolveChain, DEFAULT_FACILITATOR_URL } from "@pincerpay/core";
2
- import { paymentMiddlewareFromConfig, } from "@x402/hono";
3
- import { HTTPFacilitatorClient } from "@x402/core/server";
4
- import { ExactEvmScheme } from "@x402/evm/exact/server";
5
- import { ExactSvmScheme } from "@x402/svm/exact/server";
6
- /**
7
- * Hono middleware factory for PincerPay merchants.
8
- *
9
- * ```ts
10
- * app.use("*", pincerpayHono({
11
- * apiKey: process.env.PINCERPAY_API_KEY!,
12
- * merchantAddress: "0xYourAddress",
13
- * routes: {
14
- * "GET /api/weather": { price: "0.01", chain: "base", description: "Weather data" },
15
- * },
16
- * }));
17
- * ```
18
- */
19
- export function pincerpayHono(config, paywallConfig) {
20
- const facilitatorUrl = config.facilitatorUrl ?? DEFAULT_FACILITATOR_URL;
21
- // Build x402-compatible routes config
22
- // Pass price as Money (string) so the EVM server scheme handles conversion
23
- // and automatically includes EIP-712 domain parameters (name, version)
24
- const x402Routes = {};
25
- for (const [pattern, routeConfig] of Object.entries(config.routes)) {
26
- const chains = routeConfig.chains ?? (routeConfig.chain ? [routeConfig.chain] : ["solana"]);
27
- const accepts = chains.map((chainShorthand) => {
28
- const chain = resolveChain(chainShorthand);
29
- if (!chain)
30
- throw new Error(`Unknown chain: ${chainShorthand}`);
31
- return {
32
- scheme: "exact",
33
- network: chain.caip2Id,
34
- payTo: config.merchantAddress,
35
- price: routeConfig.price,
36
- maxTimeoutSeconds: 300,
37
- };
38
- });
39
- x402Routes[pattern] = {
40
- accepts,
41
- description: routeConfig.description ?? pattern,
42
- };
43
- }
44
- // Create facilitator client pointing to PincerPay
45
- const facilitatorClient = new HTTPFacilitatorClient({
46
- url: facilitatorUrl,
47
- createAuthHeaders: async () => ({
48
- verify: { "x-pincerpay-api-key": config.apiKey },
49
- settle: { "x-pincerpay-api-key": config.apiKey },
50
- supported: { "x-pincerpay-api-key": config.apiKey },
51
- }),
52
- });
53
- // Register server schemes so the resource server can build payment requirements
54
- const schemes = [
55
- { network: "eip155:*", server: new ExactEvmScheme() },
56
- { network: "solana:*", server: new ExactSvmScheme() },
57
- ];
58
- return paymentMiddlewareFromConfig(x402Routes, facilitatorClient, schemes, paywallConfig, undefined, // paywall provider
59
- config.syncFacilitatorOnStart ?? true);
60
- }
61
- export { PincerPayClient } from "../client.js";
62
- //# sourceMappingURL=hono.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"hono.js","sourceRoot":"","sources":["../../src/middleware/hono.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EACL,2BAA2B,GAE5B,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,aAAa,CAAC,MAAuB,EAAE,aAA6B;IAClF,MAAM,cAAc,GAAG,MAAM,CAAC,cAAc,IAAI,uBAAuB,CAAC;IAExE,sCAAsC;IACtC,2EAA2E;IAC3E,uEAAuE;IACvE,MAAM,UAAU,GASX,EAAE,CAAC;IAER,KAAK,MAAM,CAAC,OAAO,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QACnE,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QAE5F,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,cAAc,EAAE,EAAE;YAC5C,MAAM,KAAK,GAAG,YAAY,CAAC,cAAc,CAAC,CAAC;YAC3C,IAAI,CAAC,KAAK;gBAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,cAAc,EAAE,CAAC,CAAC;YAEhE,OAAO;gBACL,MAAM,EAAE,OAAgB;gBACxB,OAAO,EAAE,KAAK,CAAC,OAAkB;gBACjC,KAAK,EAAE,MAAM,CAAC,eAAe;gBAC7B,KAAK,EAAE,WAAW,CAAC,KAAK;gBACxB,iBAAiB,EAAE,GAAG;aACvB,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,UAAU,CAAC,OAAO,CAAC,GAAG;YACpB,OAAO;YACP,WAAW,EAAE,WAAW,CAAC,WAAW,IAAI,OAAO;SAChD,CAAC;IACJ,CAAC;IAED,kDAAkD;IAClD,MAAM,iBAAiB,GAAG,IAAI,qBAAqB,CAAC;QAClD,GAAG,EAAE,cAAc;QACnB,iBAAiB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;YAC9B,MAAM,EAAE,EAAE,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE;YAChD,MAAM,EAAE,EAAE,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE;YAChD,SAAS,EAAE,EAAE,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE;SACpD,CAAC;KACH,CAAC,CAAC;IAEH,gFAAgF;IAChF,MAAM,OAAO,GAAG;QACd,EAAE,OAAO,EAAE,UAAqB,EAAE,MAAM,EAAE,IAAI,cAAc,EAAE,EAAE;QAChE,EAAE,OAAO,EAAE,UAAqB,EAAE,MAAM,EAAE,IAAI,cAAc,EAAE,EAAE;KACjE,CAAC;IAEF,OAAO,2BAA2B,CAChC,UAAU,EACV,iBAAiB,EACjB,OAAO,EACP,aAAa,EACb,SAAS,EAAE,mBAAmB;IAC9B,MAAM,CAAC,sBAAsB,IAAI,IAAI,CACtC,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC"}