@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 +21 -21
- package/README.md +259 -233
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/middleware/nextjs.d.ts +31 -0
- package/dist/middleware/nextjs.d.ts.map +1 -0
- package/dist/middleware/nextjs.js +182 -0
- package/dist/middleware/nextjs.js.map +1 -0
- package/package.json +8 -35
- package/dist/middleware/express.d.ts +0 -18
- package/dist/middleware/express.d.ts.map +0 -1
- package/dist/middleware/express.js +0 -62
- package/dist/middleware/express.js.map +0 -1
- package/dist/middleware/hono.d.ts +0 -18
- package/dist/middleware/hono.d.ts.map +0 -1
- package/dist/middleware/hono.js +0 -62
- package/dist/middleware/hono.js.map +0 -1
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
|
-
[](https://www.npmjs.com/package/@pincerpay/merchant)
|
|
4
|
-
[](https://www.npmjs.com/package/@pincerpay/merchant)
|
|
5
|
-
[](https://github.com/ds1/pincerpay/blob/master/LICENSE)
|
|
6
|
-
[](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
|
-
##
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
```typescript
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
1
|
+
# @pincerpay/merchant
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@pincerpay/merchant)
|
|
4
|
+
[](https://www.npmjs.com/package/@pincerpay/merchant)
|
|
5
|
+
[](https://github.com/ds1/pincerpay/blob/master/LICENSE)
|
|
6
|
+
[](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 {
|
|
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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
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 {
|
|
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,
|
|
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":"AACA,OAAO,EACL,YAAY,EACZ,uBAAuB,EACvB,cAAc,EACd,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AAGzB;;GAEG;AACH,SAAS,WAAW,CAAC,MAAc;IACjC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;IAC9B,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACzD,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAChE,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;AAC3B,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,yBAAyB,CAAC,MAAuB;IAC/D,mGAAmG;IACnG,MAAM,MAAM,GAAG,MAAM,CAAC,cAAc,IAAI,uBAAuB,CAAC;IAChE,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAEtD,0EAA0E;IAC1E,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CACT,2CAA2C,EAC3C,uBAAuB,CACxB,CAAC;IACJ,CAAC;IAED,kFAAkF;IAClF,6EAA6E;IAC7E,MAAM,uBAAuB,GAC3B,KAAK,CAAC,GAAG,cAAc,GAAG,kBAAkB,CAAC,SAAS,EAAE,CAAC;SACtD,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;SACzB,IAAI,CAAC,CAAC,IAA4E,EAAE,EAAE;QACrF,MAAM,GAAG,GAAG,IAAI,GAAG,EAAmC,CAAC;QACvD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,IAAI,IAAI,CAAC,KAAK;gBAAE,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC,CAAC;SACD,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,GAAG,EAAmC,CAAC,CAAC;IAa7D,MAAM,cAAc,GAAG,IAAI,GAAG,EAM3B,CAAC;IAEJ,mFAAmF;IACnF,SAAS,YAAY,CAAC,SAAiB;QACrC,OAAO,SAAS,KAAK,QAAQ;YAC3B,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,eAAe,EAAE;YACtC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;IACzC,CAAC;IAED,KAAK,MAAM,CAAC,OAAO,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QACnE,MAAM,MAAM,GACV,WAAW,CAAC,MAAM;YAClB,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QAEzD,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,OAAO;gBACtB,MAAM,EAAE,WAAW,CAAC,WAAW,CAAC,KAAK,CAAC;gBACtC,KAAK,EAAE,KAAK,CAAC,WAAW;gBACxB,KAAK,EAAE,MAAM,CAAC,eAAe;gBAC7B,iBAAiB,EAAE,GAAG;gBACtB,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC;aACrC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,cAAc,CAAC,GAAG,CAAC,OAAO,EAAE;YAC1B,WAAW,EAAE,WAAW,CAAC,WAAW,IAAI,OAAO;YAC/C,OAAO;SACR,CAAC,CAAC;IACL,CAAC;IAED,yEAAyE;IACzE,IAAI,wBAAwB,GAAG,KAAK,CAAC;IACrC,uBAAuB,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE;QACxC,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO;QAChC,KAAK,MAAM,KAAK,IAAI,cAAc,CAAC,MAAM,EAAE,EAAE,CAAC;YAC5C,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;gBACnC,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBAC3C,IAAI,KAAK;oBAAE,MAAM,CAAC,KAAK,GAAG,EAAE,GAAG,MAAM,CAAC,KAAK,EAAE,GAAG,KAAK,EAAE,CAAC;YAC1D,CAAC;QACH,CAAC;QACD,wBAAwB,GAAG,IAAI,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,8DAA8D;IAC9D,OAAO,CAAC,KAAK,EAAE,CAAU,EAAE,IAAU,EAAE,EAAE;QACvC,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;QAC5B,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;QACxB,MAAM,QAAQ,GAAG,GAAG,MAAM,IAAI,IAAI,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAE3C,uCAAuC;QACvC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,EAAE,CAAC;QAE1B,oEAAoE;QACpE,IAAI,CAAC,wBAAwB;YAAE,MAAM,uBAAuB,CAAC;QAE7D,6CAA6C;QAC7C,MAAM,aAAa,GACjB,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAEjE,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,8BAA8B;YAC9B,MAAM,eAAe,GAAG;gBACtB,WAAW,EAAE,CAAC;gBACd,KAAK,EAAE,kBAAkB;gBACzB,QAAQ,EAAE;oBACR,QAAQ,EAAE,IAAI;oBACd,WAAW,EAAE,KAAK,CAAC,WAAW;oBAC9B,QAAQ,EAAE,kBAAkB;iBAC7B;gBACD,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,UAAU,EAAE,EAAE;aACf,CAAC;YAEF,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAChF,CAAC,CAAC,MAAM,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC;YACtC,OAAO,CAAC,CAAC,IAAI,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC;QACtC,CAAC;QAED,kDAAkD;QAClD,IAAI,CAAC;YACH,mDAAmD;YACnD,IAAI,OAAgC,CAAC;YACrC,IAAI,CAAC;gBACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;YACtC,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,GAAG,IAAI,CAAC,KAAK,CAClB,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CACvD,CAAC;YACJ,CAAC;YAED,MAAM,mBAAmB,GACvB,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,mBAAmB,CAAC;YAElD,MAAM,SAAS,GAAG,MAAM,KAAK,CAC3B,GAAG,cAAc,GAAG,kBAAkB,CAAC,MAAM,EAAE,EAC/C;gBACE,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM;iBAChC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,cAAc,EAAE,OAAO;oBACvB,mBAAmB;iBACpB,CAAC;aACH,CACF,CAAC;YAEF,MAAM,MAAM,GAAG,CAAC,MAAM,SAAS,CAAC,IAAI,EAAE,CAMrC,CAAC;YAEF,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,OAAO,CAAC,CAAC,IAAI,CACX;oBACE,KAAK,EAAE,2BAA2B;oBAClC,MAAM,EAAE,MAAM,CAAC,WAAW;oBAC1B,OAAO,EAAE,MAAM,CAAC,YAAY;iBAC7B,EACD,GAAG,CACJ,CAAC;YACJ,CAAC;YAED,2EAA2E;YAC3E,MAAM,cAAc,GAAG;gBACrB,WAAW,EAAE,CAAC;gBACd,OAAO,EAAE,IAAI;gBACb,WAAW,EAAE,MAAM,CAAC,WAAW;gBAC/B,OAAO,EAAE,MAAM,CAAC,OAAO;aACxB,CAAC;YACF,CAAC,CAAC,MAAM,CAAC,kBAAkB,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;YAE7F,OAAO,IAAI,EAAE,CAAC;QAChB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,GAAG,CAAC,CAAC;YACpD,OAAO,CAAC,CAAC,IAAI,CACX,EAAE,KAAK,EAAE,2BAA2B,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,EAC3D,GAAG,CACJ,CAAC;QACJ,CAAC;QACD,8DAA8D;IAChE,CAAC,CAAQ,CAAC;AACZ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pincerpay/merchant",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "Merchant SDK for PincerPay.
|
|
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
|
-
"
|
|
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
|
-
"./
|
|
52
|
-
"types": "./dist/middleware/
|
|
53
|
-
"import": "./dist/middleware/
|
|
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.
|
|
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/
|
|
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"}
|
package/dist/middleware/hono.js
DELETED
|
@@ -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"}
|