@three-ws/x402-payment-modal 1.1.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.
@@ -0,0 +1,44 @@
1
+ // Express adapter for the Solana checkout endpoints.
2
+ //
3
+ // import express from 'express';
4
+ // import { x402CheckoutRouter } from '@three-ws/x402-payment-modal/server/express';
5
+ //
6
+ // const app = express();
7
+ // app.use(express.json());
8
+ // app.use('/api/x402-checkout', x402CheckoutRouter({ rpcUrl: process.env.SOLANA_RPC_URL }));
9
+ //
10
+ // The modal POSTs to `/api/x402-checkout?action=prepare` and `?action=encode`.
11
+ // CORS is permissive (the drop-in modal runs on any origin); tighten `origin`
12
+ // via the option if you only serve your own pages.
13
+
14
+ import { handleCheckout } from './checkout.js';
15
+
16
+ /**
17
+ * @param {object} [options]
18
+ * @param {string} [options.rpcUrl] Solana mainnet RPC URL
19
+ * @param {string} [options.devnetRpcUrl] Solana devnet RPC URL
20
+ * @param {string} [options.origin] Access-Control-Allow-Origin (default '*')
21
+ * @returns {import('express').RequestHandler}
22
+ */
23
+ export function x402CheckoutRouter(options = {}) {
24
+ const allowOrigin = options.origin || '*';
25
+ return async function x402CheckoutHandler(req, res) {
26
+ res.setHeader('Access-Control-Allow-Origin', allowOrigin);
27
+ res.setHeader('Access-Control-Allow-Methods', 'POST,OPTIONS');
28
+ res.setHeader('Access-Control-Allow-Headers', 'content-type');
29
+ if (req.method === 'OPTIONS') {
30
+ res.status(204).end();
31
+ return;
32
+ }
33
+ if (req.method !== 'POST') {
34
+ res.status(405).json({ error: 'method_not_allowed', error_description: 'use POST' });
35
+ return;
36
+ }
37
+ const action = req.query?.action;
38
+ const body = req.body && typeof req.body === 'object' ? req.body : {};
39
+ const { status, body: out } = await handleCheckout({ action, body, options });
40
+ res.status(status).json(out);
41
+ };
42
+ }
43
+
44
+ export default x402CheckoutRouter;
@@ -0,0 +1,54 @@
1
+ // Vercel / Next.js (pages API) adapter for the Solana checkout endpoints.
2
+ //
3
+ // Save as `api/x402-checkout.js`:
4
+ //
5
+ // export { default } from '@three-ws/x402-payment-modal/server/vercel';
6
+ //
7
+ // or with options:
8
+ //
9
+ // import { createVercelCheckoutHandler } from '@three-ws/x402-payment-modal/server/vercel';
10
+ // export default createVercelCheckoutHandler({ rpcUrl: process.env.SOLANA_RPC_URL });
11
+ //
12
+ // The modal POSTs to this route with `?action=prepare` and `?action=encode`.
13
+
14
+ import { handleCheckout } from './checkout.js';
15
+
16
+ async function readJsonBody(req) {
17
+ // Next.js pages API and Vercel Node functions usually pre-parse JSON into
18
+ // req.body. When they don't (raw runtime), read the stream ourselves.
19
+ if (req.body && typeof req.body === 'object') return req.body;
20
+ if (typeof req.body === 'string' && req.body) {
21
+ try { return JSON.parse(req.body); } catch { return {}; }
22
+ }
23
+ const chunks = [];
24
+ for await (const chunk of req) chunks.push(chunk);
25
+ if (!chunks.length) return {};
26
+ try { return JSON.parse(Buffer.concat(chunks).toString('utf8')); } catch { return {}; }
27
+ }
28
+
29
+ /**
30
+ * @param {object} [options] { rpcUrl, devnetRpcUrl, origin }
31
+ * @returns {(req: any, res: any) => Promise<void>}
32
+ */
33
+ export function createVercelCheckoutHandler(options = {}) {
34
+ const allowOrigin = options.origin || '*';
35
+ return async function handler(req, res) {
36
+ res.setHeader('Access-Control-Allow-Origin', allowOrigin);
37
+ res.setHeader('Access-Control-Allow-Methods', 'POST,OPTIONS');
38
+ res.setHeader('Access-Control-Allow-Headers', 'content-type');
39
+ if (req.method === 'OPTIONS') {
40
+ res.status(204).end();
41
+ return;
42
+ }
43
+ if (req.method !== 'POST') {
44
+ res.status(405).json({ error: 'method_not_allowed', error_description: 'use POST' });
45
+ return;
46
+ }
47
+ const action = req.query?.action;
48
+ const body = await readJsonBody(req);
49
+ const { status, body: out } = await handleCheckout({ action, body, options });
50
+ res.status(status).json(out);
51
+ };
52
+ }
53
+
54
+ export default createVercelCheckoutHandler();