@dexterai/x402 1.5.5 → 1.6.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/dist/server/index.cjs +98 -0
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +68 -1
- package/dist/server/index.d.ts +68 -1
- package/dist/server/index.js +97 -0
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
package/dist/server/index.cjs
CHANGED
|
@@ -59,6 +59,7 @@ __export(server_exports, {
|
|
|
59
59
|
isValidModel: () => isValidModel,
|
|
60
60
|
isValidModelId: () => isValidModelId,
|
|
61
61
|
x402AccessPass: () => x402AccessPass,
|
|
62
|
+
x402BrowserSupport: () => x402BrowserSupport,
|
|
62
63
|
x402Middleware: () => x402Middleware
|
|
63
64
|
});
|
|
64
65
|
module.exports = __toCommonJS(server_exports);
|
|
@@ -422,6 +423,102 @@ function x402Middleware(config) {
|
|
|
422
423
|
};
|
|
423
424
|
}
|
|
424
425
|
|
|
426
|
+
// src/server/browser-support.ts
|
|
427
|
+
function generatePaywallHtml(paymentRequiredHeader, requestUrl, method, config) {
|
|
428
|
+
let price = "?";
|
|
429
|
+
let description = "This resource requires payment";
|
|
430
|
+
let network = "";
|
|
431
|
+
try {
|
|
432
|
+
const decoded = JSON.parse(Buffer.from(paymentRequiredHeader, "base64").toString());
|
|
433
|
+
const accept = decoded.accepts?.[0];
|
|
434
|
+
if (accept) {
|
|
435
|
+
const amount = accept.amount || accept.maxAmountRequired || "0";
|
|
436
|
+
const decimals = accept.extra?.decimals || 6;
|
|
437
|
+
price = (Number(amount) / Math.pow(10, decimals)).toFixed(decimals > 4 ? 4 : 2);
|
|
438
|
+
network = accept.network || "";
|
|
439
|
+
}
|
|
440
|
+
if (decoded.resource?.description) {
|
|
441
|
+
description = decoded.resource.description;
|
|
442
|
+
}
|
|
443
|
+
} catch {
|
|
444
|
+
}
|
|
445
|
+
const chainName = network.includes("solana") ? "Solana" : network.includes("eip155") ? "Base" : "Unknown";
|
|
446
|
+
const endpointSection = config.showEndpoint ? `<div class="endpoint"><code>${method} ${requestUrl}</code></div>` : "";
|
|
447
|
+
return `<!DOCTYPE html>
|
|
448
|
+
<html lang="en">
|
|
449
|
+
<head>
|
|
450
|
+
<meta charset="utf-8">
|
|
451
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
452
|
+
<title>${config.title} \u2014 $${price} USDC</title>
|
|
453
|
+
<style>
|
|
454
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
455
|
+
body{font-family:system-ui,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#0a0a0a;color:#e2e8f0;min-height:100vh;display:flex;align-items:center;justify-content:center;padding:1rem}
|
|
456
|
+
.paywall{max-width:460px;width:100%;background:#141414;border:1px solid #2a2a2a;border-radius:16px;padding:2.5rem;text-align:center}
|
|
457
|
+
.paywall h1{font-size:1.35rem;margin-bottom:.35rem;color:#f1f5f9;font-weight:600}
|
|
458
|
+
.desc{color:#94a3b8;font-size:.95rem;margin-bottom:1.5rem;line-height:1.5}
|
|
459
|
+
.price-badge{display:inline-block;background:linear-gradient(135deg,#22c55e,#16a34a);color:#fff;padding:.6rem 2rem;border-radius:999px;font-size:1.75rem;font-weight:700;margin:1rem 0;letter-spacing:-.02em}
|
|
460
|
+
.chain{color:#64748b;font-size:.8rem;margin-bottom:1.5rem}
|
|
461
|
+
.endpoint{background:#1e1e1e;border:1px solid #333;border-radius:8px;padding:.6rem 1rem;margin-bottom:1.5rem}
|
|
462
|
+
.endpoint code{font-family:'SF Mono',Monaco,Consolas,monospace;font-size:.85rem;color:#60a5fa}
|
|
463
|
+
.info{background:#1a1a2e;border:1px solid #2d2d5e;border-radius:10px;padding:1rem 1.25rem;font-size:.85rem;color:#a0aec0;line-height:1.6;text-align:left}
|
|
464
|
+
.info strong{color:#e2e8f0}
|
|
465
|
+
.info code{background:#2a2a3e;padding:2px 6px;border-radius:4px;font-size:.8rem;color:#818cf8;font-family:'SF Mono',Monaco,Consolas,monospace}
|
|
466
|
+
.info a{color:#60a5fa;text-decoration:none;font-weight:600}
|
|
467
|
+
.info a:hover{text-decoration:underline}
|
|
468
|
+
.powered{margin-top:1.5rem;font-size:.75rem;color:#475569}
|
|
469
|
+
.powered a{color:#64748b;text-decoration:none}
|
|
470
|
+
.powered a:hover{color:#94a3b8}
|
|
471
|
+
.x402-badge{display:inline-flex;align-items:center;gap:.35rem;background:#1a1a2e;border:1px solid #2d2d5e;padding:.25rem .75rem;border-radius:999px;font-size:.7rem;color:#818cf8;margin-top:.75rem;font-weight:500}
|
|
472
|
+
</style>
|
|
473
|
+
</head>
|
|
474
|
+
<body>
|
|
475
|
+
<div class="paywall">
|
|
476
|
+
<h1>${config.title}</h1>
|
|
477
|
+
<p class="desc">${description}</p>
|
|
478
|
+
<div class="price-badge">$${price} USDC</div>
|
|
479
|
+
<div class="chain">${chainName} network</div>
|
|
480
|
+
${endpointSection}
|
|
481
|
+
<div class="info">
|
|
482
|
+
<strong>How to access this endpoint:</strong><br><br>
|
|
483
|
+
Use any x402-compatible client or SDK. The client handles wallet connection and payment automatically.<br><br>
|
|
484
|
+
<code>npm install @dexterai/x402</code><br><br>
|
|
485
|
+
<a href="${config.sdkUrl}">Learn more about x402 →</a>
|
|
486
|
+
</div>
|
|
487
|
+
<div class="powered">${config.branding}</div>
|
|
488
|
+
<div class="x402-badge">x402 protocol</div>
|
|
489
|
+
</div>
|
|
490
|
+
</body>
|
|
491
|
+
</html>`;
|
|
492
|
+
}
|
|
493
|
+
function x402BrowserSupport(config = {}) {
|
|
494
|
+
const resolvedConfig = {
|
|
495
|
+
title: config.title ?? "Payment Required",
|
|
496
|
+
branding: config.branding ?? 'Powered by <a href="https://x402.org">x402</a>',
|
|
497
|
+
sdkUrl: config.sdkUrl ?? "https://x402.org",
|
|
498
|
+
showEndpoint: config.showEndpoint ?? true
|
|
499
|
+
};
|
|
500
|
+
return (req, res, next) => {
|
|
501
|
+
const originalJson = res.json.bind(res);
|
|
502
|
+
res.json = function(body) {
|
|
503
|
+
if (res.statusCode === 402 && req.accepts("html") && !req.headers["payment-signature"]) {
|
|
504
|
+
const paymentRequired = res.getHeader("PAYMENT-REQUIRED") || res.getHeader("payment-required");
|
|
505
|
+
if (paymentRequired && typeof paymentRequired === "string") {
|
|
506
|
+
const html = generatePaywallHtml(
|
|
507
|
+
paymentRequired,
|
|
508
|
+
req.originalUrl,
|
|
509
|
+
req.method,
|
|
510
|
+
resolvedConfig
|
|
511
|
+
);
|
|
512
|
+
res.status(402).type("html").send(html);
|
|
513
|
+
return res;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
return originalJson(body);
|
|
517
|
+
};
|
|
518
|
+
next();
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
|
|
425
522
|
// src/server/access-pass.ts
|
|
426
523
|
var import_crypto = __toESM(require("crypto"), 1);
|
|
427
524
|
var DURATION_REGEX = /^(\d+)(m|h|d|w)$/;
|
|
@@ -1462,6 +1559,7 @@ function formatTokenPricing(model = DEFAULT_MODEL) {
|
|
|
1462
1559
|
isValidModel,
|
|
1463
1560
|
isValidModelId,
|
|
1464
1561
|
x402AccessPass,
|
|
1562
|
+
x402BrowserSupport,
|
|
1465
1563
|
x402Middleware
|
|
1466
1564
|
});
|
|
1467
1565
|
//# sourceMappingURL=index.cjs.map
|