solana-pay-qr-code-x402-express
Version:
An Express middleware that combines x402 payment requests with a Solana Pay QR code paywall.
80 lines (79 loc) • 3.67 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.solanaPayQRMiddleware = solanaPayQRMiddleware;
const x402_express_1 = require("x402-express");
const pay_1 = require("@solana/pay");
const web3_js_1 = require("@solana/web3.js");
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const qrcode_1 = __importDefault(require("qrcode"));
function solanaPayQRMiddleware(payTo, routes, facilitator, paywall) {
const configsWithPaywall = JSON.parse(JSON.stringify(routes));
const recipient = new web3_js_1.PublicKey(payTo);
const qrCodeCache = {};
for (const route in configsWithPaywall) {
const config = configsWithPaywall[route];
if (config.network === "solana") {
const amount = new bignumber_js_1.default(config.price.replace("$", ""));
const reference = new web3_js_1.Keypair().publicKey;
const label = "API Access";
const message = `Payment for ${route}`;
const paymentUrl = (0, pay_1.encodeURL)({
recipient,
amount,
reference,
label,
message,
});
const generateQRCode = async () => {
if (!qrCodeCache[route]) {
qrCodeCache[route] = await qrcode_1.default.toString(paymentUrl.toString(), {
type: "svg",
margin: 2,
width: 250,
color: {
dark: "#000000",
light: "#FFFFFF",
},
});
}
return qrCodeCache[route];
};
const originalCustomPaywallHtml = config.customPaywallHtml;
config.customPaywallHtml = async () => {
const qrCodeSvg = await generateQRCode();
return `
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>402 Payment Required</title>
<style>
body { display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100vh; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; background-color: #f4f4f7; color: #333; margin: 0; }
.container { text-align: center; background: white; padding: 40px; border-radius: 12px; box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1); }
h1 { font-size: 24px; margin-bottom: 10px; }
p { margin: 0; color: #666; }
.qr-code { margin-top: 25px; }
.payment-link { margin-top: 25px; font-size: 16px; }
a { color: #007bff; text-decoration: none; }
a:hover { text-decoration: underline; }
</style>
</head>
<body>
<div class="container">
<h1>Payment Required</h1>
<p>Scan with a Solana wallet to pay ${amount.toString()} SOL</p>
<div class="qr-code">${qrCodeSvg}</div>
<p class="payment-link">
<a href="${paymentUrl.toString()}">Click here to open in your wallet</a>
</p>
</div>
</body>
</html>
`;
};
}
}
return (0, x402_express_1.paymentMiddleware)(payTo, configsWithPaywall, facilitator, paywall);
}