@alleyboss/micropay-solana-x402-paywall 3.5.1 → 3.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/dist/agent/index.cjs +19 -0
- package/dist/agent/index.js +19 -0
- package/dist/fetch/index.cjs +19 -0
- package/dist/fetch/index.js +19 -0
- package/dist/index.cjs +19 -0
- package/dist/index.js +19 -0
- package/dist/next/index.cjs +29 -45
- package/dist/next/index.d.cts +1 -1
- package/dist/next/index.d.ts +1 -1
- package/dist/next/index.js +29 -45
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -117,6 +117,12 @@ const x402Fetch = createX402Fetch({
|
|
|
117
117
|
windowMs: 60_000, // Per minute
|
|
118
118
|
},
|
|
119
119
|
});
|
|
120
|
+
|
|
121
|
+
// 💡 Header Compatibility:
|
|
122
|
+
// Automatically detects requirements from:
|
|
123
|
+
// - WWW-Authenticate: X402 ... (Standard)
|
|
124
|
+
// - X-Payment-Requirements: json (Simple)
|
|
125
|
+
// - payment-required: base64 (Upstream Middleware)
|
|
120
126
|
```
|
|
121
127
|
|
|
122
128
|
**Security Error Codes:**
|
|
@@ -229,6 +235,19 @@ const withMicropay = createX402Middleware({
|
|
|
229
235
|
| **Setup** | Zero-config | Requires RPC URL |
|
|
230
236
|
| **Best For** | Quick startups, MVPs | Production, High-Volume, Agents |
|
|
231
237
|
|
|
238
|
+
## 🔧 What's New in v3.5.2
|
|
239
|
+
|
|
240
|
+
**Middleware Fix**: The `createX402Middleware` now generates 402 responses directly, fixing a bug where the upstream library multiplied payment amounts by 1M. Your configured `price` in lamports is now used exactly as specified.
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
// price: '1000000' → 0.001 SOL (correct!)
|
|
244
|
+
const withPayment = createX402Middleware({
|
|
245
|
+
walletAddress: 'YOUR_WALLET',
|
|
246
|
+
price: '1000000', // This is now used correctly
|
|
247
|
+
network: 'devnet'
|
|
248
|
+
});
|
|
249
|
+
```
|
|
250
|
+
|
|
232
251
|
## 🌐 PayAI Format Support (New in v3.3.13)
|
|
233
252
|
|
|
234
253
|
Native support for the **PayAI payment format** - a universal payment protocol that works across Solana, Ethereum, Base, and other chains.
|
package/dist/agent/index.cjs
CHANGED
|
@@ -542,6 +542,25 @@ function parse402Response(response) {
|
|
|
542
542
|
throw invalid402ResponseError("Invalid WWW-Authenticate header");
|
|
543
543
|
}
|
|
544
544
|
}
|
|
545
|
+
const paymentRequired = response.headers.get("payment-required");
|
|
546
|
+
if (paymentRequired) {
|
|
547
|
+
try {
|
|
548
|
+
const jsonStr = atob(paymentRequired.trim());
|
|
549
|
+
const parsed = JSON.parse(jsonStr);
|
|
550
|
+
const option = Array.isArray(parsed.accepts) && parsed.accepts.length > 0 ? parsed.accepts[0] : parsed;
|
|
551
|
+
return {
|
|
552
|
+
payTo: option.payTo ?? option.recipient,
|
|
553
|
+
amount: String(option.amount),
|
|
554
|
+
asset: option.asset ?? "SOL",
|
|
555
|
+
network: option.network ?? "solana-mainnet",
|
|
556
|
+
description: parsed.description ?? option.description,
|
|
557
|
+
resource: parsed.resource ?? option.resource,
|
|
558
|
+
maxAge: parsed.maxAge ?? option.maxAge
|
|
559
|
+
};
|
|
560
|
+
} catch {
|
|
561
|
+
throw invalid402ResponseError("Invalid payment-required header");
|
|
562
|
+
}
|
|
563
|
+
}
|
|
545
564
|
throw invalid402ResponseError("No payment requirements found in 402 response");
|
|
546
565
|
}
|
|
547
566
|
function buildPaymentHeader(signature) {
|
package/dist/agent/index.js
CHANGED
|
@@ -536,6 +536,25 @@ function parse402Response(response) {
|
|
|
536
536
|
throw invalid402ResponseError("Invalid WWW-Authenticate header");
|
|
537
537
|
}
|
|
538
538
|
}
|
|
539
|
+
const paymentRequired = response.headers.get("payment-required");
|
|
540
|
+
if (paymentRequired) {
|
|
541
|
+
try {
|
|
542
|
+
const jsonStr = atob(paymentRequired.trim());
|
|
543
|
+
const parsed = JSON.parse(jsonStr);
|
|
544
|
+
const option = Array.isArray(parsed.accepts) && parsed.accepts.length > 0 ? parsed.accepts[0] : parsed;
|
|
545
|
+
return {
|
|
546
|
+
payTo: option.payTo ?? option.recipient,
|
|
547
|
+
amount: String(option.amount),
|
|
548
|
+
asset: option.asset ?? "SOL",
|
|
549
|
+
network: option.network ?? "solana-mainnet",
|
|
550
|
+
description: parsed.description ?? option.description,
|
|
551
|
+
resource: parsed.resource ?? option.resource,
|
|
552
|
+
maxAge: parsed.maxAge ?? option.maxAge
|
|
553
|
+
};
|
|
554
|
+
} catch {
|
|
555
|
+
throw invalid402ResponseError("Invalid payment-required header");
|
|
556
|
+
}
|
|
557
|
+
}
|
|
539
558
|
throw invalid402ResponseError("No payment requirements found in 402 response");
|
|
540
559
|
}
|
|
541
560
|
function buildPaymentHeader(signature) {
|
package/dist/fetch/index.cjs
CHANGED
|
@@ -210,6 +210,25 @@ function parse402Response(response) {
|
|
|
210
210
|
throw invalid402ResponseError("Invalid WWW-Authenticate header");
|
|
211
211
|
}
|
|
212
212
|
}
|
|
213
|
+
const paymentRequired = response.headers.get("payment-required");
|
|
214
|
+
if (paymentRequired) {
|
|
215
|
+
try {
|
|
216
|
+
const jsonStr = atob(paymentRequired.trim());
|
|
217
|
+
const parsed = JSON.parse(jsonStr);
|
|
218
|
+
const option = Array.isArray(parsed.accepts) && parsed.accepts.length > 0 ? parsed.accepts[0] : parsed;
|
|
219
|
+
return {
|
|
220
|
+
payTo: option.payTo ?? option.recipient,
|
|
221
|
+
amount: String(option.amount),
|
|
222
|
+
asset: option.asset ?? "SOL",
|
|
223
|
+
network: option.network ?? "solana-mainnet",
|
|
224
|
+
description: parsed.description ?? option.description,
|
|
225
|
+
resource: parsed.resource ?? option.resource,
|
|
226
|
+
maxAge: parsed.maxAge ?? option.maxAge
|
|
227
|
+
};
|
|
228
|
+
} catch {
|
|
229
|
+
throw invalid402ResponseError("Invalid payment-required header");
|
|
230
|
+
}
|
|
231
|
+
}
|
|
213
232
|
throw invalid402ResponseError("No payment requirements found in 402 response");
|
|
214
233
|
}
|
|
215
234
|
function buildPaymentHeader(signature) {
|
package/dist/fetch/index.js
CHANGED
|
@@ -208,6 +208,25 @@ function parse402Response(response) {
|
|
|
208
208
|
throw invalid402ResponseError("Invalid WWW-Authenticate header");
|
|
209
209
|
}
|
|
210
210
|
}
|
|
211
|
+
const paymentRequired = response.headers.get("payment-required");
|
|
212
|
+
if (paymentRequired) {
|
|
213
|
+
try {
|
|
214
|
+
const jsonStr = atob(paymentRequired.trim());
|
|
215
|
+
const parsed = JSON.parse(jsonStr);
|
|
216
|
+
const option = Array.isArray(parsed.accepts) && parsed.accepts.length > 0 ? parsed.accepts[0] : parsed;
|
|
217
|
+
return {
|
|
218
|
+
payTo: option.payTo ?? option.recipient,
|
|
219
|
+
amount: String(option.amount),
|
|
220
|
+
asset: option.asset ?? "SOL",
|
|
221
|
+
network: option.network ?? "solana-mainnet",
|
|
222
|
+
description: parsed.description ?? option.description,
|
|
223
|
+
resource: parsed.resource ?? option.resource,
|
|
224
|
+
maxAge: parsed.maxAge ?? option.maxAge
|
|
225
|
+
};
|
|
226
|
+
} catch {
|
|
227
|
+
throw invalid402ResponseError("Invalid payment-required header");
|
|
228
|
+
}
|
|
229
|
+
}
|
|
211
230
|
throw invalid402ResponseError("No payment requirements found in 402 response");
|
|
212
231
|
}
|
|
213
232
|
function buildPaymentHeader(signature) {
|
package/dist/index.cjs
CHANGED
|
@@ -822,6 +822,25 @@ function parse402Response(response) {
|
|
|
822
822
|
throw invalid402ResponseError("Invalid WWW-Authenticate header");
|
|
823
823
|
}
|
|
824
824
|
}
|
|
825
|
+
const paymentRequired = response.headers.get("payment-required");
|
|
826
|
+
if (paymentRequired) {
|
|
827
|
+
try {
|
|
828
|
+
const jsonStr = atob(paymentRequired.trim());
|
|
829
|
+
const parsed = JSON.parse(jsonStr);
|
|
830
|
+
const option = Array.isArray(parsed.accepts) && parsed.accepts.length > 0 ? parsed.accepts[0] : parsed;
|
|
831
|
+
return {
|
|
832
|
+
payTo: option.payTo ?? option.recipient,
|
|
833
|
+
amount: String(option.amount),
|
|
834
|
+
asset: option.asset ?? "SOL",
|
|
835
|
+
network: option.network ?? "solana-mainnet",
|
|
836
|
+
description: parsed.description ?? option.description,
|
|
837
|
+
resource: parsed.resource ?? option.resource,
|
|
838
|
+
maxAge: parsed.maxAge ?? option.maxAge
|
|
839
|
+
};
|
|
840
|
+
} catch {
|
|
841
|
+
throw invalid402ResponseError("Invalid payment-required header");
|
|
842
|
+
}
|
|
843
|
+
}
|
|
825
844
|
throw invalid402ResponseError("No payment requirements found in 402 response");
|
|
826
845
|
}
|
|
827
846
|
function buildPaymentHeader(signature) {
|
package/dist/index.js
CHANGED
|
@@ -817,6 +817,25 @@ function parse402Response(response) {
|
|
|
817
817
|
throw invalid402ResponseError("Invalid WWW-Authenticate header");
|
|
818
818
|
}
|
|
819
819
|
}
|
|
820
|
+
const paymentRequired = response.headers.get("payment-required");
|
|
821
|
+
if (paymentRequired) {
|
|
822
|
+
try {
|
|
823
|
+
const jsonStr = atob(paymentRequired.trim());
|
|
824
|
+
const parsed = JSON.parse(jsonStr);
|
|
825
|
+
const option = Array.isArray(parsed.accepts) && parsed.accepts.length > 0 ? parsed.accepts[0] : parsed;
|
|
826
|
+
return {
|
|
827
|
+
payTo: option.payTo ?? option.recipient,
|
|
828
|
+
amount: String(option.amount),
|
|
829
|
+
asset: option.asset ?? "SOL",
|
|
830
|
+
network: option.network ?? "solana-mainnet",
|
|
831
|
+
description: parsed.description ?? option.description,
|
|
832
|
+
resource: parsed.resource ?? option.resource,
|
|
833
|
+
maxAge: parsed.maxAge ?? option.maxAge
|
|
834
|
+
};
|
|
835
|
+
} catch {
|
|
836
|
+
throw invalid402ResponseError("Invalid payment-required header");
|
|
837
|
+
}
|
|
838
|
+
}
|
|
820
839
|
throw invalid402ResponseError("No payment requirements found in 402 response");
|
|
821
840
|
}
|
|
822
841
|
function buildPaymentHeader(signature) {
|
package/dist/next/index.cjs
CHANGED
|
@@ -233,31 +233,14 @@ function createX402Middleware(config) {
|
|
|
233
233
|
const server$2 = new server.x402ResourceServer(facilitatorClient);
|
|
234
234
|
server$1.registerExactSvmScheme(server$2);
|
|
235
235
|
const networkId = config.network === "mainnet-beta" ? "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp" : "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1";
|
|
236
|
-
return function withMicropay(handler,
|
|
236
|
+
return function withMicropay(handler, _routeConfig) {
|
|
237
237
|
const priceValue = config.price?.toString() || "0";
|
|
238
|
-
const amountValue = (BigInt(priceValue) * BigInt(1e6)).toString();
|
|
239
|
-
const paymentSpec = {
|
|
240
|
-
scheme: "exact",
|
|
241
|
-
payTo: config.walletAddress,
|
|
242
|
-
amount: amountValue,
|
|
243
|
-
network: networkId,
|
|
244
|
-
asset: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU"
|
|
245
|
-
// Native SOL asset
|
|
246
|
-
};
|
|
247
|
-
const finalConfig = routeConfig || {
|
|
248
|
-
accepts: {
|
|
249
|
-
...paymentSpec,
|
|
250
|
-
price: priceValue
|
|
251
|
-
// Include for x402 SDK 402 generation
|
|
252
|
-
}
|
|
253
|
-
};
|
|
254
|
-
const wrappedHandler = next.withX402(handler, finalConfig, server$2);
|
|
255
238
|
return async (req, ctx) => {
|
|
256
239
|
const authHeader = req.headers?.get?.("authorization") || req.headers?.authorization;
|
|
257
240
|
if (authHeader && authHeader.toLowerCase().startsWith("x402 ")) {
|
|
258
241
|
try {
|
|
259
|
-
const
|
|
260
|
-
const payloadJson = Buffer.from(
|
|
242
|
+
const base64Payload2 = authHeader.slice(5);
|
|
243
|
+
const payloadJson = Buffer.from(base64Payload2, "base64").toString("utf8");
|
|
261
244
|
let payload = JSON.parse(payloadJson);
|
|
262
245
|
if (payload.scheme === "exact-svm" || payload.scheme === "exact-evm") {
|
|
263
246
|
payload = transformPayAIToX402(payload, networkId);
|
|
@@ -267,7 +250,7 @@ function createX402Middleware(config) {
|
|
|
267
250
|
const verifyPaymentSpec = {
|
|
268
251
|
scheme: payload.scheme || "exact",
|
|
269
252
|
network: payload.network || networkId,
|
|
270
|
-
amount:
|
|
253
|
+
amount: priceValue,
|
|
271
254
|
payTo: config.walletAddress
|
|
272
255
|
};
|
|
273
256
|
let verifyResult;
|
|
@@ -290,32 +273,33 @@ function createX402Middleware(config) {
|
|
|
290
273
|
} catch (parseError) {
|
|
291
274
|
}
|
|
292
275
|
}
|
|
293
|
-
const
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
276
|
+
const paymentPayload = {
|
|
277
|
+
x402Version: 2,
|
|
278
|
+
error: "Payment required",
|
|
279
|
+
resource: {
|
|
280
|
+
url: req.nextUrl?.pathname || req.url,
|
|
281
|
+
description: "",
|
|
282
|
+
mimeType: ""
|
|
283
|
+
},
|
|
284
|
+
accepts: [{
|
|
285
|
+
scheme: "exact",
|
|
286
|
+
network: networkId,
|
|
287
|
+
amount: priceValue,
|
|
288
|
+
// Use raw lamports, no multiplier
|
|
289
|
+
asset: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU",
|
|
290
|
+
payTo: config.walletAddress,
|
|
291
|
+
maxTimeoutSeconds: 300,
|
|
292
|
+
extra: { feePayer: "11111111111111111111111111111111" }
|
|
293
|
+
}]
|
|
294
|
+
};
|
|
295
|
+
const base64Payload = Buffer.from(JSON.stringify(paymentPayload)).toString("base64");
|
|
296
|
+
return new Response(JSON.stringify({}), {
|
|
297
|
+
status: 402,
|
|
298
|
+
headers: {
|
|
299
|
+
"Content-Type": "application/json",
|
|
300
|
+
"payment-required": base64Payload
|
|
316
301
|
}
|
|
317
302
|
});
|
|
318
|
-
return await wrappedHandler(compatibleReq, ctx);
|
|
319
303
|
};
|
|
320
304
|
};
|
|
321
305
|
}
|
package/dist/next/index.d.cts
CHANGED
|
@@ -19,7 +19,7 @@ interface X402Config {
|
|
|
19
19
|
/**
|
|
20
20
|
* Create a specialized Next.js middleware with Solana support pre-configured
|
|
21
21
|
*/
|
|
22
|
-
declare function createX402Middleware(config: X402Config): (handler: any,
|
|
22
|
+
declare function createX402Middleware(config: X402Config): (handler: any, _routeConfig?: any) => (req: any, ctx: any) => Promise<any>;
|
|
23
23
|
declare const withX402: typeof withX402$1;
|
|
24
24
|
|
|
25
25
|
export { type X402Config, createX402Middleware, withX402 };
|
package/dist/next/index.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ interface X402Config {
|
|
|
19
19
|
/**
|
|
20
20
|
* Create a specialized Next.js middleware with Solana support pre-configured
|
|
21
21
|
*/
|
|
22
|
-
declare function createX402Middleware(config: X402Config): (handler: any,
|
|
22
|
+
declare function createX402Middleware(config: X402Config): (handler: any, _routeConfig?: any) => (req: any, ctx: any) => Promise<any>;
|
|
23
23
|
declare const withX402: typeof withX402$1;
|
|
24
24
|
|
|
25
25
|
export { type X402Config, createX402Middleware, withX402 };
|
package/dist/next/index.js
CHANGED
|
@@ -232,31 +232,14 @@ function createX402Middleware(config) {
|
|
|
232
232
|
const server = new x402ResourceServer(facilitatorClient);
|
|
233
233
|
registerExactSvmScheme(server);
|
|
234
234
|
const networkId = config.network === "mainnet-beta" ? "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp" : "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1";
|
|
235
|
-
return function withMicropay(handler,
|
|
235
|
+
return function withMicropay(handler, _routeConfig) {
|
|
236
236
|
const priceValue = config.price?.toString() || "0";
|
|
237
|
-
const amountValue = (BigInt(priceValue) * BigInt(1e6)).toString();
|
|
238
|
-
const paymentSpec = {
|
|
239
|
-
scheme: "exact",
|
|
240
|
-
payTo: config.walletAddress,
|
|
241
|
-
amount: amountValue,
|
|
242
|
-
network: networkId,
|
|
243
|
-
asset: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU"
|
|
244
|
-
// Native SOL asset
|
|
245
|
-
};
|
|
246
|
-
const finalConfig = routeConfig || {
|
|
247
|
-
accepts: {
|
|
248
|
-
...paymentSpec,
|
|
249
|
-
price: priceValue
|
|
250
|
-
// Include for x402 SDK 402 generation
|
|
251
|
-
}
|
|
252
|
-
};
|
|
253
|
-
const wrappedHandler = withX402$1(handler, finalConfig, server);
|
|
254
237
|
return async (req, ctx) => {
|
|
255
238
|
const authHeader = req.headers?.get?.("authorization") || req.headers?.authorization;
|
|
256
239
|
if (authHeader && authHeader.toLowerCase().startsWith("x402 ")) {
|
|
257
240
|
try {
|
|
258
|
-
const
|
|
259
|
-
const payloadJson = Buffer.from(
|
|
241
|
+
const base64Payload2 = authHeader.slice(5);
|
|
242
|
+
const payloadJson = Buffer.from(base64Payload2, "base64").toString("utf8");
|
|
260
243
|
let payload = JSON.parse(payloadJson);
|
|
261
244
|
if (payload.scheme === "exact-svm" || payload.scheme === "exact-evm") {
|
|
262
245
|
payload = transformPayAIToX402(payload, networkId);
|
|
@@ -266,7 +249,7 @@ function createX402Middleware(config) {
|
|
|
266
249
|
const verifyPaymentSpec = {
|
|
267
250
|
scheme: payload.scheme || "exact",
|
|
268
251
|
network: payload.network || networkId,
|
|
269
|
-
amount:
|
|
252
|
+
amount: priceValue,
|
|
270
253
|
payTo: config.walletAddress
|
|
271
254
|
};
|
|
272
255
|
let verifyResult;
|
|
@@ -289,32 +272,33 @@ function createX402Middleware(config) {
|
|
|
289
272
|
} catch (parseError) {
|
|
290
273
|
}
|
|
291
274
|
}
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
275
|
+
const paymentPayload = {
|
|
276
|
+
x402Version: 2,
|
|
277
|
+
error: "Payment required",
|
|
278
|
+
resource: {
|
|
279
|
+
url: req.nextUrl?.pathname || req.url,
|
|
280
|
+
description: "",
|
|
281
|
+
mimeType: ""
|
|
282
|
+
},
|
|
283
|
+
accepts: [{
|
|
284
|
+
scheme: "exact",
|
|
285
|
+
network: networkId,
|
|
286
|
+
amount: priceValue,
|
|
287
|
+
// Use raw lamports, no multiplier
|
|
288
|
+
asset: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU",
|
|
289
|
+
payTo: config.walletAddress,
|
|
290
|
+
maxTimeoutSeconds: 300,
|
|
291
|
+
extra: { feePayer: "11111111111111111111111111111111" }
|
|
292
|
+
}]
|
|
293
|
+
};
|
|
294
|
+
const base64Payload = Buffer.from(JSON.stringify(paymentPayload)).toString("base64");
|
|
295
|
+
return new Response(JSON.stringify({}), {
|
|
296
|
+
status: 402,
|
|
297
|
+
headers: {
|
|
298
|
+
"Content-Type": "application/json",
|
|
299
|
+
"payment-required": base64Payload
|
|
315
300
|
}
|
|
316
301
|
});
|
|
317
|
-
return await wrappedHandler(compatibleReq, ctx);
|
|
318
302
|
};
|
|
319
303
|
};
|
|
320
304
|
}
|
package/package.json
CHANGED