| #!/usr/bin/env node | ||
| /** | ||
| * paygate CLI. | ||
| * | ||
| * npx paygate init [flags] scaffold a working x402 seller | ||
| * | ||
| * Zero runtime deps — see init.ts for the implementation. | ||
| */ | ||
| export {}; | ||
| //# sourceMappingURL=cli.d.ts.map |
| {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;GAMG"} |
+26
| #!/usr/bin/env node | ||
| /** | ||
| * paygate CLI. | ||
| * | ||
| * npx paygate init [flags] scaffold a working x402 seller | ||
| * | ||
| * Zero runtime deps — see init.ts for the implementation. | ||
| */ | ||
| import { HELP_TEXT, runInit } from "./init.js"; | ||
| async function main() { | ||
| const [command, ...rest] = process.argv.slice(2); | ||
| if (command === "init") { | ||
| return runInit(rest); | ||
| } | ||
| if (command === undefined || command === "--help" || command === "-h" || command === "help") { | ||
| process.stdout.write(`paygate — make your API payable in one command.\n\nCommands:\n init scaffold a working x402 seller\n\n${HELP_TEXT}`); | ||
| return command === undefined ? 1 : 0; | ||
| } | ||
| process.stderr.write(`Unknown command: ${command}. Run \`paygate --help\` for usage.\n`); | ||
| return 1; | ||
| } | ||
| main().then((code) => process.exit(code), (err) => { | ||
| process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`); | ||
| process.exit(1); | ||
| }); | ||
| //# sourceMappingURL=cli.js.map |
| {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE/C,KAAK,UAAU,IAAI;IACjB,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEjD,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACvB,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;IAED,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QAC5F,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,6GAA6G,SAAS,EAAE,CACzH,CAAC;QACF,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC;IAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oBAAoB,OAAO,uCAAuC,CAAC,CAAC;IACzF,OAAO,CAAC,CAAC;AACX,CAAC;AAED,IAAI,EAAE,CAAC,IAAI,CACT,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAC5B,CAAC,GAAG,EAAE,EAAE;IACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CACF,CAAC"} |
| /** | ||
| * `paygate init` — template generation. | ||
| * | ||
| * Pure functions only: every generator returns `{ path, content }[]` and | ||
| * never touches the filesystem, so the whole surface is unit-testable. | ||
| * | ||
| * Two families of template: | ||
| * | ||
| * 1. Account-free x402 seller (default). Uses the upstream `@x402/*` | ||
| * packages (`@x402/express`, `@x402/fastify`, `@x402/hono`, | ||
| * `@x402/next`, or the `x402` pip package) pointed at a facilitator. | ||
| * No ArisPay account, no API key — just a wallet address that | ||
| * receives the funds. Modeled on `examples/x402-demo/server.js`, | ||
| * which is proven live against facilitator.arispay.app. | ||
| * | ||
| * 2. Hosted PayGate mode (`--merchant-id`, express/fastify only). | ||
| * Uses this package's own SDK (`paygate({ merchantId })`); payout | ||
| * wallet / network / facilitator come from the merchant's capability | ||
| * manifest. Requires a merchant account at paygate.arispay.app. | ||
| * | ||
| * Network truthfulness: the public ArisPay facilitator settles Base | ||
| * MAINNET only. Testnet (`base-sepolia`, the default) templates point | ||
| * FACILITATOR_URL at Coinbase's public testnet facilitator | ||
| * (https://x402.org/facilitator) and say so; production templates | ||
| * (`--network base`) default to https://facilitator.arispay.app. | ||
| */ | ||
| export type InitFramework = "express" | "fastify" | "next" | "hono" | "workers" | "fastapi"; | ||
| export type InitNetwork = "base" | "base-sepolia"; | ||
| export type InitCurrency = "USD" | "EUR"; | ||
| export type InitMethod = "GET" | "POST" | "PUT" | "DELETE"; | ||
| export declare const INIT_FRAMEWORKS: readonly InitFramework[]; | ||
| export declare const MAINNET_FACILITATOR = "https://facilitator.arispay.app"; | ||
| /** Coinbase's public testnet facilitator — used by the upstream x402 examples. */ | ||
| export declare const TESTNET_FACILITATOR = "https://x402.org/facilitator"; | ||
| export declare const CAIP2: Record<InitNetwork, string>; | ||
| /** | ||
| * Circle EURC on Base mainnet — address + EIP-712 domain verified on-chain | ||
| * (see packages/paygate/src/core.ts EURC_ADDRESSES). EUR templates are | ||
| * restricted to `base` because the testnet default facilitator does not | ||
| * settle EURC. | ||
| */ | ||
| export declare const EURC_BASE_MAINNET = "0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"; | ||
| export interface TemplateOptions { | ||
| framework: InitFramework; | ||
| /** 0x-prefixed 40-hex EVM address. Public — safe to write to .env.example. May be absent in --dry-run. */ | ||
| wallet?: string; | ||
| /** Paid route path, starts with "/". */ | ||
| route: string; | ||
| method: InitMethod; | ||
| /** Integer cents (USD or EUR). */ | ||
| priceCents: number; | ||
| currency: InitCurrency; | ||
| network: InitNetwork; | ||
| /** Hosted PayGate mode (express/fastify only). */ | ||
| merchantId?: string; | ||
| /** Directory-name-ish project name, used in package.json / wrangler.toml. */ | ||
| projectName: string; | ||
| } | ||
| export interface GeneratedFile { | ||
| path: string; | ||
| content: string; | ||
| } | ||
| export declare function defaultFacilitatorFor(network: InitNetwork): string; | ||
| /** "$0.01"-style money string from integer cents. */ | ||
| export declare function centsToMoneyString(cents: number): string; | ||
| /** cents → 6-decimal atomic units (USDC/EURC): cents * 10^4. */ | ||
| export declare function centsToAtomic(cents: number): string; | ||
| export declare function generateFiles(opts: TemplateOptions): GeneratedFile[]; | ||
| //# sourceMappingURL=init-templates.d.ts.map |
| {"version":3,"file":"init-templates.d.ts","sourceRoot":"","sources":["../src/init-templates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;AAC5F,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,cAAc,CAAC;AAClD,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,KAAK,CAAC;AACzC,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;AAE3D,eAAO,MAAM,eAAe,EAAE,SAAS,aAAa,EAOnD,CAAC;AAEF,eAAO,MAAM,mBAAmB,oCAAoC,CAAC;AACrE,kFAAkF;AAClF,eAAO,MAAM,mBAAmB,iCAAiC,CAAC;AAElE,eAAO,MAAM,KAAK,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAG7C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,+CAA+C,CAAC;AAE9E,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,aAAa,CAAC;IACzB,0GAA0G;IAC1G,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;IACnB,kCAAkC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,YAAY,CAAC;IACvB,OAAO,EAAE,WAAW,CAAC;IACrB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAID,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAElE;AAED,qDAAqD;AACrD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIxD;AAED,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnD;AAguBD,wBAAgB,aAAa,CAAC,IAAI,EAAE,eAAe,GAAG,aAAa,EAAE,CAoIpE"} |
| /** | ||
| * `paygate init` — template generation. | ||
| * | ||
| * Pure functions only: every generator returns `{ path, content }[]` and | ||
| * never touches the filesystem, so the whole surface is unit-testable. | ||
| * | ||
| * Two families of template: | ||
| * | ||
| * 1. Account-free x402 seller (default). Uses the upstream `@x402/*` | ||
| * packages (`@x402/express`, `@x402/fastify`, `@x402/hono`, | ||
| * `@x402/next`, or the `x402` pip package) pointed at a facilitator. | ||
| * No ArisPay account, no API key — just a wallet address that | ||
| * receives the funds. Modeled on `examples/x402-demo/server.js`, | ||
| * which is proven live against facilitator.arispay.app. | ||
| * | ||
| * 2. Hosted PayGate mode (`--merchant-id`, express/fastify only). | ||
| * Uses this package's own SDK (`paygate({ merchantId })`); payout | ||
| * wallet / network / facilitator come from the merchant's capability | ||
| * manifest. Requires a merchant account at paygate.arispay.app. | ||
| * | ||
| * Network truthfulness: the public ArisPay facilitator settles Base | ||
| * MAINNET only. Testnet (`base-sepolia`, the default) templates point | ||
| * FACILITATOR_URL at Coinbase's public testnet facilitator | ||
| * (https://x402.org/facilitator) and say so; production templates | ||
| * (`--network base`) default to https://facilitator.arispay.app. | ||
| */ | ||
| export const INIT_FRAMEWORKS = [ | ||
| "express", | ||
| "fastify", | ||
| "next", | ||
| "hono", | ||
| "workers", | ||
| "fastapi", | ||
| ]; | ||
| export const MAINNET_FACILITATOR = "https://facilitator.arispay.app"; | ||
| /** Coinbase's public testnet facilitator — used by the upstream x402 examples. */ | ||
| export const TESTNET_FACILITATOR = "https://x402.org/facilitator"; | ||
| export const CAIP2 = { | ||
| base: "eip155:8453", | ||
| "base-sepolia": "eip155:84532", | ||
| }; | ||
| /** | ||
| * Circle EURC on Base mainnet — address + EIP-712 domain verified on-chain | ||
| * (see packages/paygate/src/core.ts EURC_ADDRESSES). EUR templates are | ||
| * restricted to `base` because the testnet default facilitator does not | ||
| * settle EURC. | ||
| */ | ||
| export const EURC_BASE_MAINNET = "0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"; | ||
| // ── Helpers ──────────────────────────────────────────────────────────── | ||
| export function defaultFacilitatorFor(network) { | ||
| return network === "base" ? MAINNET_FACILITATOR : TESTNET_FACILITATOR; | ||
| } | ||
| /** "$0.01"-style money string from integer cents. */ | ||
| export function centsToMoneyString(cents) { | ||
| const dollars = Math.floor(cents / 100); | ||
| const rem = cents % 100; | ||
| return `$${dollars}.${String(rem).padStart(2, "0")}`; | ||
| } | ||
| /** cents → 6-decimal atomic units (USDC/EURC): cents * 10^4. */ | ||
| export function centsToAtomic(cents) { | ||
| return (BigInt(cents) * BigInt(10_000)).toString(); | ||
| } | ||
| function humanPrice(opts) { | ||
| const base = centsToMoneyString(opts.priceCents); | ||
| return opts.currency === "EUR" ? `${base.replace("$", "€")} (EURC)` : base; | ||
| } | ||
| /** | ||
| * The x402 `price` value as a JS expression string. | ||
| * USD → money string ("$0.01"); the upstream server resolves it to USDC. | ||
| * EUR → explicit AssetAmount pinning Circle EURC on Base mainnet. | ||
| */ | ||
| function priceExprJs(opts) { | ||
| if (opts.currency === "EUR") { | ||
| return [ | ||
| `{`, | ||
| ` // Circle EURC on Base mainnet — ${opts.priceCents} EUR cents as 6-decimal atomic units (cents * 10^4).`, | ||
| ` asset: '${EURC_BASE_MAINNET}',`, | ||
| ` amount: '${centsToAtomic(opts.priceCents)}',`, | ||
| ` extra: { name: 'EURC', version: '2' },`, | ||
| ` }`, | ||
| ].join("\n"); | ||
| } | ||
| return `'${centsToMoneyString(opts.priceCents)}'`; | ||
| } | ||
| function priceExprPy(opts) { | ||
| if (opts.currency === "EUR") { | ||
| return (`{\n` + | ||
| ` # Circle EURC on Base mainnet — ${opts.priceCents} EUR cents as 6-decimal atomic units (cents * 10^4).\n` + | ||
| ` "asset": "${EURC_BASE_MAINNET}",\n` + | ||
| ` "amount": "${centsToAtomic(opts.priceCents)}",\n` + | ||
| ` "extra": {"name": "EURC", "version": "2"},\n` + | ||
| ` }`); | ||
| } | ||
| return `"${centsToMoneyString(opts.priceCents)}"`; | ||
| } | ||
| function networkBanner(opts) { | ||
| if (opts.network === "base") { | ||
| return (`// Production: Base mainnet (eip155:8453), settled by the ArisPay facilitator\n` + | ||
| `// (${MAINNET_FACILITATOR}) — no facilitator fee; the seller pays chain gas.`); | ||
| } | ||
| return (`// Testnet: Base Sepolia (eip155:84532). The public ArisPay facilitator\n` + | ||
| `// (${MAINNET_FACILITATOR}) settles Base MAINNET ONLY, so this template\n` + | ||
| `// defaults FACILITATOR_URL to Coinbase's public testnet facilitator\n` + | ||
| `// (${TESTNET_FACILITATOR}). For production, switch NETWORK to 'base' and\n` + | ||
| `// FACILITATOR_URL to ${MAINNET_FACILITATOR}.`); | ||
| } | ||
| function envExample(opts) { | ||
| const lines = [ | ||
| `# Wallet (EVM address) that receives settled funds.`, | ||
| `# A wallet ADDRESS is public information — safe to commit. Never put a`, | ||
| `# private key or API key in this file.`, | ||
| `PAY_TO_ADDRESS=${opts.wallet ?? ""}`, | ||
| ``, | ||
| `# x402 facilitator used for verify + settle.`, | ||
| ]; | ||
| if (opts.network === "base") { | ||
| lines.push(`# Production default: the ArisPay facilitator (Base mainnet, USDC + EURC).`, `FACILITATOR_URL=${MAINNET_FACILITATOR}`); | ||
| } | ||
| else { | ||
| lines.push(`# Testnet default: Coinbase's public testnet facilitator. The ArisPay`, `# facilitator (${MAINNET_FACILITATOR}) settles Base MAINNET ONLY —`, `# switch to it (and NETWORK=base) when you go to production.`, `FACILITATOR_URL=${TESTNET_FACILITATOR}`); | ||
| } | ||
| lines.push(``, `# Port for the local server.`, `PORT=3000`, ``); | ||
| return lines.join("\n"); | ||
| } | ||
| const GITIGNORE = `node_modules/ | ||
| dist/ | ||
| .env | ||
| .dev.vars | ||
| __pycache__/ | ||
| .venv/ | ||
| `; | ||
| function curlExample(opts, port) { | ||
| const methodFlag = opts.method === "GET" ? "" : ` -X ${opts.method}`; | ||
| return `curl -i${methodFlag} http://localhost:${port}${opts.route}`; | ||
| } | ||
| function readmeCommon(opts, runCmd, port) { | ||
| const testnet = opts.network === "base-sepolia"; | ||
| return `## Test the 402 | ||
| \`\`\`bash | ||
| ${curlExample(opts, port)} | ||
| \`\`\` | ||
| You should see \`HTTP/1.1 402 Payment Required\` with a JSON body listing the | ||
| payment requirements (asset, amount, payTo, network). That 402 body is the | ||
| whole protocol surface — any x402-capable client can take it from there. | ||
| ## Pay it end-to-end without risking real funds | ||
| ${testnet | ||
| ? `This template targets **Base Sepolia** (testnet), so full payment loops move | ||
| testnet USDC only. Fund a testnet wallet from a Base Sepolia faucet, then use | ||
| any x402 client (for example \`npx payagent pay <url>\`, or the upstream | ||
| \`@x402/fetch\` client) against your route.` | ||
| : `This template targets **Base mainnet** — payments move real USDC${opts.currency === "EUR" ? "/EURC" : ""}. | ||
| To rehearse without moving real funds first, re-run \`npx paygate init\` with | ||
| \`--network base-sepolia\` and test the same code path on testnet, or just | ||
| inspect the 402 challenge with the curl above (issuing the challenge never | ||
| moves funds — money only moves when a payer signs and the facilitator | ||
| settles).`} | ||
| ## Discovery (Bazaar) | ||
| The paid route declares an x402 Bazaar discovery extension. Once your endpoint | ||
| is live and the first payment verifies through a Bazaar-participating | ||
| facilitator, the resource becomes eligible for the public x402 catalog — no | ||
| extra registration step. | ||
| ## Learn more | ||
| - Machine-readable facilitator docs: https://facilitator.arispay.app/llms.txt | ||
| - Live facilitator policy (networks/assets/fees): https://facilitator.arispay.app/supported | ||
| ## Run | ||
| \`\`\`bash | ||
| ${runCmd} | ||
| \`\`\` | ||
| `; | ||
| } | ||
| // ── Direct-mode templates (upstream @x402/*) ─────────────────────────── | ||
| function jsRouteConfig(opts, resourceIndent = "") { | ||
| // Route config for @x402 paymentMiddleware-style APIs (RouteConfig from | ||
| // @x402/core 2.8: accepts, description, mimeType, extensions). | ||
| const i = resourceIndent; | ||
| return `{ | ||
| ${i} accepts: { | ||
| ${i} scheme: 'exact', | ||
| ${i} price: ${priceExprJs(opts)}, | ||
| ${i} network: NETWORK_CAIP2, | ||
| ${i} payTo: PAY_TO_ADDRESS, | ||
| ${i} maxTimeoutSeconds: 60, | ||
| ${i} }, | ||
| ${i} description: 'Paid ${opts.method} ${opts.route} (${humanPrice(opts)})', | ||
| ${i} mimeType: 'application/json', | ||
| ${i} // Bazaar discovery declaration — makes the route eligible for the | ||
| ${i} // public x402 catalog after its first successful verify. | ||
| ${i} extensions: declareDiscoveryExtension({ | ||
| ${i} output: { example: { ok: true, data: 'paid content' } }, | ||
| ${i} }), | ||
| ${i} }`; | ||
| } | ||
| function jsHeader(opts, framework) { | ||
| return `/** | ||
| * x402 seller (${framework}) — generated by \`npx paygate init\`. | ||
| * | ||
| * Routes: | ||
| * GET /health unpaid health check | ||
| * ${opts.method.padEnd(4)}${opts.route.padEnd(18)}${humanPrice(opts)} per request, gated by x402 | ||
| * | ||
| ${networkBanner(opts) | ||
| .split("\n") | ||
| .map((l) => ` ${l.replace(/^\/\//, "*")}`) | ||
| .join("\n")} | ||
| */`; | ||
| } | ||
| function commonJsConsts(opts) { | ||
| return `const PAY_TO_ADDRESS = process.env.PAY_TO_ADDRESS; | ||
| const FACILITATOR_URL = process.env.FACILITATOR_URL || '${defaultFacilitatorFor(opts.network)}'; | ||
| const NETWORK = process.env.NETWORK || '${opts.network}'; | ||
| const PORT = parseInt(process.env.PORT || '3000', 10); | ||
| if (!PAY_TO_ADDRESS || !/^0x[0-9a-fA-F]{40}$/.test(PAY_TO_ADDRESS)) { | ||
| console.error('PAY_TO_ADDRESS env var is required and must be a 0x-prefixed EVM address'); | ||
| process.exit(1); | ||
| } | ||
| const NETWORK_TO_CAIP2 = { | ||
| 'base-sepolia': '${CAIP2["base-sepolia"]}', | ||
| 'base': '${CAIP2.base}', | ||
| }; | ||
| const NETWORK_CAIP2 = NETWORK_TO_CAIP2[NETWORK] || NETWORK;`; | ||
| } | ||
| function expressServerJs(opts) { | ||
| return `${jsHeader(opts, "Express")} | ||
| import express from 'express'; | ||
| import { paymentMiddleware, x402ResourceServer } from '@x402/express'; | ||
| import { HTTPFacilitatorClient } from '@x402/core/server'; | ||
| import { ExactEvmScheme } from '@x402/evm/exact/server'; | ||
| import { declareDiscoveryExtension } from '@x402/extensions/bazaar'; | ||
| ${commonJsConsts(opts)} | ||
| const facilitatorClient = new HTTPFacilitatorClient({ url: FACILITATOR_URL }); | ||
| const resourceServer = new x402ResourceServer(facilitatorClient).register( | ||
| NETWORK_CAIP2, | ||
| new ExactEvmScheme(), | ||
| ); | ||
| const app = express(); | ||
| // Health check — unprotected. | ||
| app.get('/health', (_req, res) => { | ||
| res.json({ ok: true, network: NETWORK, facilitator: FACILITATOR_URL }); | ||
| }); | ||
| // Paywall — every matching request must carry a valid X-PAYMENT header. | ||
| app.use( | ||
| paymentMiddleware( | ||
| { | ||
| '${opts.method} ${opts.route}': ${jsRouteConfig(opts)}, | ||
| }, | ||
| resourceServer, | ||
| ), | ||
| ); | ||
| // Protected resource. Only reached after payment settles. | ||
| app.${opts.method.toLowerCase()}('${opts.route}', (_req, res) => { | ||
| res.json({ ok: true, data: 'paid content', servedAt: new Date().toISOString() }); | ||
| }); | ||
| app.listen(PORT, () => { | ||
| console.log(\`x402 seller listening on :\${PORT}\`); | ||
| console.log(\`network=\${NETWORK} price=${humanPrice(opts).replace(/'/g, "")} payTo=\${PAY_TO_ADDRESS}\`); | ||
| console.log(\`facilitator=\${FACILITATOR_URL}\`); | ||
| }); | ||
| `; | ||
| } | ||
| function fastifyServerJs(opts) { | ||
| return `${jsHeader(opts, "Fastify")} | ||
| import Fastify from 'fastify'; | ||
| import { paymentMiddleware, x402ResourceServer } from '@x402/fastify'; | ||
| import { HTTPFacilitatorClient } from '@x402/core/server'; | ||
| import { ExactEvmScheme } from '@x402/evm/exact/server'; | ||
| import { declareDiscoveryExtension } from '@x402/extensions/bazaar'; | ||
| ${commonJsConsts(opts)} | ||
| const facilitatorClient = new HTTPFacilitatorClient({ url: FACILITATOR_URL }); | ||
| const resourceServer = new x402ResourceServer(facilitatorClient).register( | ||
| NETWORK_CAIP2, | ||
| new ExactEvmScheme(), | ||
| ); | ||
| const app = Fastify({ logger: true }); | ||
| // Health check — unprotected. | ||
| app.get('/health', async () => ({ ok: true, network: NETWORK, facilitator: FACILITATOR_URL })); | ||
| // Paywall — every matching request must carry a valid X-PAYMENT header. | ||
| paymentMiddleware( | ||
| app, | ||
| { | ||
| '${opts.method} ${opts.route}': ${jsRouteConfig(opts)}, | ||
| }, | ||
| resourceServer, | ||
| ); | ||
| // Protected resource. Only reached after payment settles. | ||
| app.${opts.method.toLowerCase()}('${opts.route}', async () => ({ | ||
| ok: true, | ||
| data: 'paid content', | ||
| servedAt: new Date().toISOString(), | ||
| })); | ||
| app.listen({ port: PORT, host: '0.0.0.0' }).then(() => { | ||
| console.log(\`x402 seller listening on :\${PORT} network=\${NETWORK} facilitator=\${FACILITATOR_URL}\`); | ||
| }); | ||
| `; | ||
| } | ||
| function honoServerJs(opts) { | ||
| return `${jsHeader(opts, "Hono")} | ||
| import { Hono } from 'hono'; | ||
| import { serve } from '@hono/node-server'; | ||
| import { paymentMiddleware, x402ResourceServer } from '@x402/hono'; | ||
| import { HTTPFacilitatorClient } from '@x402/core/server'; | ||
| import { ExactEvmScheme } from '@x402/evm/exact/server'; | ||
| import { declareDiscoveryExtension } from '@x402/extensions/bazaar'; | ||
| ${commonJsConsts(opts)} | ||
| const facilitatorClient = new HTTPFacilitatorClient({ url: FACILITATOR_URL }); | ||
| const resourceServer = new x402ResourceServer(facilitatorClient).register( | ||
| NETWORK_CAIP2, | ||
| new ExactEvmScheme(), | ||
| ); | ||
| const app = new Hono(); | ||
| // Health check — unprotected. | ||
| app.get('/health', (c) => c.json({ ok: true, network: NETWORK, facilitator: FACILITATOR_URL })); | ||
| // Paywall — every matching request must carry a valid X-PAYMENT header. | ||
| app.use( | ||
| paymentMiddleware( | ||
| { | ||
| '${opts.method} ${opts.route}': ${jsRouteConfig(opts)}, | ||
| }, | ||
| resourceServer, | ||
| ), | ||
| ); | ||
| // Protected resource. Only reached after payment settles. | ||
| app.${opts.method.toLowerCase()}('${opts.route}', (c) => | ||
| c.json({ ok: true, data: 'paid content', servedAt: new Date().toISOString() }), | ||
| ); | ||
| serve({ fetch: app.fetch, port: PORT }, () => { | ||
| console.log(\`x402 seller listening on :\${PORT} network=\${NETWORK} facilitator=\${FACILITATOR_URL}\`); | ||
| }); | ||
| `; | ||
| } | ||
| function workersIndexJs(opts) { | ||
| return `${jsHeader(opts, "Cloudflare Workers + Hono")} | ||
| import { Hono } from 'hono'; | ||
| import { paymentMiddleware, x402ResourceServer } from '@x402/hono'; | ||
| import { HTTPFacilitatorClient } from '@x402/core/server'; | ||
| import { ExactEvmScheme } from '@x402/evm/exact/server'; | ||
| import { declareDiscoveryExtension } from '@x402/extensions/bazaar'; | ||
| const NETWORK_TO_CAIP2 = { | ||
| 'base-sepolia': '${CAIP2["base-sepolia"]}', | ||
| 'base': '${CAIP2.base}', | ||
| }; | ||
| const app = new Hono(); | ||
| // Health check — unprotected. | ||
| app.get('/health', (c) => | ||
| c.json({ ok: true, network: c.env.NETWORK, facilitator: c.env.FACILITATOR_URL }), | ||
| ); | ||
| // Workers expose env bindings per-request (c.env), not at module scope, so | ||
| // the x402 middleware is built lazily on first request and reused after. | ||
| let x402; | ||
| app.use('*', async (c, next) => { | ||
| if (!x402) { | ||
| const PAY_TO_ADDRESS = c.env.PAY_TO_ADDRESS; | ||
| if (!PAY_TO_ADDRESS || !/^0x[0-9a-fA-F]{40}$/.test(PAY_TO_ADDRESS)) { | ||
| return c.json({ error: 'PAY_TO_ADDRESS var is required (see wrangler.toml [vars])' }, 500); | ||
| } | ||
| const FACILITATOR_URL = c.env.FACILITATOR_URL || '${defaultFacilitatorFor(opts.network)}'; | ||
| const NETWORK = c.env.NETWORK || '${opts.network}'; | ||
| const NETWORK_CAIP2 = NETWORK_TO_CAIP2[NETWORK] || NETWORK; | ||
| const facilitatorClient = new HTTPFacilitatorClient({ url: FACILITATOR_URL }); | ||
| const resourceServer = new x402ResourceServer(facilitatorClient).register( | ||
| NETWORK_CAIP2, | ||
| new ExactEvmScheme(), | ||
| ); | ||
| x402 = paymentMiddleware( | ||
| { | ||
| '${opts.method} ${opts.route}': { | ||
| accepts: { | ||
| scheme: 'exact', | ||
| price: ${priceExprJs(opts)}, | ||
| network: NETWORK_CAIP2, | ||
| payTo: PAY_TO_ADDRESS, | ||
| maxTimeoutSeconds: 60, | ||
| }, | ||
| description: 'Paid ${opts.method} ${opts.route} (${humanPrice(opts)})', | ||
| mimeType: 'application/json', | ||
| // Bazaar discovery declaration — makes the route eligible for the | ||
| // public x402 catalog after its first successful verify. | ||
| extensions: declareDiscoveryExtension({ | ||
| output: { example: { ok: true, data: 'paid content' } }, | ||
| }), | ||
| }, | ||
| }, | ||
| resourceServer, | ||
| ); | ||
| } | ||
| return x402(c, next); | ||
| }); | ||
| // Protected resource. Only reached after payment settles. | ||
| app.${opts.method.toLowerCase()}('${opts.route}', (c) => | ||
| c.json({ ok: true, data: 'paid content', servedAt: new Date().toISOString() }), | ||
| ); | ||
| export default app; | ||
| `; | ||
| } | ||
| function wranglerToml(opts) { | ||
| return `name = "${opts.projectName}" | ||
| main = "src/index.js" | ||
| compatibility_date = "2026-07-01" | ||
| compatibility_flags = ["nodejs_compat"] | ||
| [vars] | ||
| # Wallet (EVM address) that receives settled funds. A wallet ADDRESS is | ||
| # public information — safe to commit. Never put a private key here. | ||
| PAY_TO_ADDRESS = "${opts.wallet ?? ""}" | ||
| ${opts.network === "base" | ||
| ? `# Production: the ArisPay facilitator (Base mainnet, USDC + EURC). | ||
| FACILITATOR_URL = "${MAINNET_FACILITATOR}"` | ||
| : `# Testnet default: Coinbase's public testnet facilitator. The ArisPay | ||
| # facilitator (${MAINNET_FACILITATOR}) settles Base MAINNET ONLY — | ||
| # switch to it (and NETWORK = "base") when you go to production. | ||
| FACILITATOR_URL = "${TESTNET_FACILITATOR}"`} | ||
| NETWORK = "${opts.network}" | ||
| `; | ||
| } | ||
| function nextRouteFileDir(route) { | ||
| // "/api/paid" → "app/api/paid" (App Router route handler directory). | ||
| return `app${route.replace(/\/+$/, "")}`; | ||
| } | ||
| function nextLibX402Js(opts) { | ||
| return `${jsHeader(opts, "Next.js (App Router)")} | ||
| import { x402ResourceServer } from '@x402/next'; | ||
| import { HTTPFacilitatorClient } from '@x402/core/server'; | ||
| import { ExactEvmScheme } from '@x402/evm/exact/server'; | ||
| export const FACILITATOR_URL = process.env.FACILITATOR_URL || '${defaultFacilitatorFor(opts.network)}'; | ||
| export const NETWORK = process.env.NETWORK || '${opts.network}'; | ||
| export const PAY_TO_ADDRESS = process.env.PAY_TO_ADDRESS; | ||
| const NETWORK_TO_CAIP2 = { | ||
| 'base-sepolia': '${CAIP2["base-sepolia"]}', | ||
| 'base': '${CAIP2.base}', | ||
| }; | ||
| export const NETWORK_CAIP2 = NETWORK_TO_CAIP2[NETWORK] || NETWORK; | ||
| const facilitatorClient = new HTTPFacilitatorClient({ url: FACILITATOR_URL }); | ||
| export const resourceServer = new x402ResourceServer(facilitatorClient).register( | ||
| NETWORK_CAIP2, | ||
| new ExactEvmScheme(), | ||
| ); | ||
| `; | ||
| } | ||
| function nextPaidRouteJs(opts) { | ||
| // withX402(handler, routeConfig, server) — verified against @x402/next | ||
| // 2.20.0 (README + dist exports). It settles only after the handler | ||
| // succeeds, so failed responses are never charged. | ||
| // Route file lives at app/<route>/route.js; lib/x402.js is at the project | ||
| // root, so hop up one level per route segment plus one for app/. | ||
| const up = "../".repeat(opts.route.split("/").filter(Boolean).length + 1); | ||
| return `import { NextResponse } from 'next/server'; | ||
| import { withX402 } from '@x402/next'; | ||
| import { declareDiscoveryExtension } from '@x402/extensions/bazaar'; | ||
| import { resourceServer, NETWORK_CAIP2, PAY_TO_ADDRESS } from '${up}lib/x402.js'; | ||
| const handler = async (_req) => { | ||
| return NextResponse.json({ ok: true, data: 'paid content', servedAt: new Date().toISOString() }); | ||
| }; | ||
| export const ${opts.method} = withX402( | ||
| handler, | ||
| { | ||
| accepts: { | ||
| scheme: 'exact', | ||
| price: ${priceExprJs(opts)}, | ||
| network: NETWORK_CAIP2, | ||
| payTo: PAY_TO_ADDRESS, | ||
| maxTimeoutSeconds: 60, | ||
| }, | ||
| description: 'Paid ${opts.method} ${opts.route} (${humanPrice(opts)})', | ||
| mimeType: 'application/json', | ||
| // Bazaar discovery declaration — makes the route eligible for the | ||
| // public x402 catalog after its first successful verify. | ||
| extensions: declareDiscoveryExtension({ | ||
| output: { example: { ok: true, data: 'paid content' } }, | ||
| }), | ||
| }, | ||
| resourceServer, | ||
| ); | ||
| `; | ||
| } | ||
| function nextHealthRouteJs(_opts) { | ||
| return `import { NextResponse } from 'next/server'; | ||
| import { FACILITATOR_URL, NETWORK } from '../../../lib/x402.js'; | ||
| export const GET = async () => { | ||
| return NextResponse.json({ ok: true, network: NETWORK, facilitator: FACILITATOR_URL }); | ||
| }; | ||
| `; | ||
| } | ||
| function fastapiMainPy(opts) { | ||
| return `"""x402 seller (FastAPI) — generated standalone template by \`npx paygate init\`. | ||
| Uses the \`x402\` pip package (FastAPI middleware, verified against x402 | ||
| 2.17.0). Routes: | ||
| GET /health unpaid health check | ||
| ${opts.method} ${opts.route} ${humanPrice(opts)} per request, gated by x402 | ||
| ${opts.network === "base" | ||
| ? `Production: Base mainnet (eip155:8453), settled by the ArisPay facilitator | ||
| (${MAINNET_FACILITATOR}) — no facilitator fee; the seller pays chain gas.` | ||
| : `Testnet: Base Sepolia (eip155:84532). The public ArisPay facilitator | ||
| (${MAINNET_FACILITATOR}) settles Base MAINNET ONLY, so this template | ||
| defaults FACILITATOR_URL to Coinbase's public testnet facilitator | ||
| (${TESTNET_FACILITATOR}). For production, switch NETWORK to "base" and | ||
| FACILITATOR_URL to ${MAINNET_FACILITATOR}.`} | ||
| """ | ||
| import os | ||
| import re | ||
| from fastapi import FastAPI | ||
| from x402 import x402ResourceServer | ||
| from x402.extensions.bazaar import declare_discovery_extension | ||
| from x402.http import HTTPFacilitatorClient | ||
| from x402.http.middleware.fastapi import payment_middleware | ||
| from x402.mechanisms.evm.exact import ExactEvmServerScheme | ||
| PAY_TO_ADDRESS = os.environ.get("PAY_TO_ADDRESS", "") | ||
| FACILITATOR_URL = os.environ.get("FACILITATOR_URL", "${defaultFacilitatorFor(opts.network)}") | ||
| NETWORK = os.environ.get("NETWORK", "${opts.network}") | ||
| if not re.fullmatch(r"0x[0-9a-fA-F]{40}", PAY_TO_ADDRESS): | ||
| raise SystemExit("PAY_TO_ADDRESS env var is required and must be a 0x-prefixed EVM address") | ||
| NETWORK_TO_CAIP2 = { | ||
| "base-sepolia": "${CAIP2["base-sepolia"]}", | ||
| "base": "${CAIP2.base}", | ||
| } | ||
| NETWORK_CAIP2 = NETWORK_TO_CAIP2.get(NETWORK, NETWORK) | ||
| facilitator = HTTPFacilitatorClient(url=FACILITATOR_URL) | ||
| server = x402ResourceServer(facilitator) | ||
| server.register(NETWORK_CAIP2, ExactEvmServerScheme()) | ||
| server.initialize() | ||
| app = FastAPI() | ||
| routes = { | ||
| "${opts.method} ${opts.route}": { | ||
| "accepts": { | ||
| "scheme": "exact", | ||
| "price": ${priceExprPy(opts)}, | ||
| "network": NETWORK_CAIP2, | ||
| "payTo": PAY_TO_ADDRESS, | ||
| "maxTimeoutSeconds": 60, | ||
| }, | ||
| "description": "Paid ${opts.method} ${opts.route} (${humanPrice(opts)})", | ||
| "mime_type": "application/json", | ||
| # Bazaar discovery declaration — makes the route eligible for the | ||
| # public x402 catalog after its first successful verify. | ||
| "extensions": declare_discovery_extension( | ||
| output={"example": {"ok": True, "data": "paid content"}}, | ||
| ), | ||
| }, | ||
| } | ||
| _x402 = payment_middleware(routes, server) | ||
| @app.middleware("http") | ||
| async def x402_middleware(request, call_next): | ||
| return await _x402(request, call_next) | ||
| @app.get("/health") | ||
| async def health(): | ||
| """Unpaid health check.""" | ||
| return {"ok": True, "network": NETWORK, "facilitator": FACILITATOR_URL} | ||
| @app.${opts.method.toLowerCase()}("${opts.route}") | ||
| async def paid_route(): | ||
| """Protected resource. Only reached after payment settles.""" | ||
| return {"ok": True, "data": "paid content"} | ||
| `; | ||
| } | ||
| // ── Hosted PayGate mode (merchantId) ─────────────────────────────────── | ||
| function merchantEnvExample(opts) { | ||
| return `# Hosted PayGate merchant id (from https://paygate.arispay.app). | ||
| # Not a secret, but keeping it in env makes per-environment setups easier. | ||
| PAYGATE_MERCHANT_ID=${opts.merchantId ?? ""} | ||
| # Port for the local server. | ||
| PORT=3000 | ||
| # NOTE: in merchantId mode the payout wallet, network, and facilitator all | ||
| # come from your merchant capability manifest (configured in the PayGate | ||
| # dashboard) — there is nothing else to configure here. The default | ||
| # facilitator behind hosted PayGate is ${MAINNET_FACILITATOR}. | ||
| `; | ||
| } | ||
| function merchantExpressServerJs(opts) { | ||
| const currencyLine = opts.currency === "EUR" ? `\n currency: 'EUR',` : ""; | ||
| return `/** | ||
| * Hosted PayGate seller (Express) — generated by \`npx paygate init\`. | ||
| * | ||
| * This template uses the hosted PayGate product: the \`paygate\` SDK fetches | ||
| * your payout wallet, network, and facilitator from your merchant capability | ||
| * manifest. It requires a merchant account at https://paygate.arispay.app. | ||
| * (For the account-free path, re-run \`npx paygate init\` without | ||
| * \`--merchant-id\`.) | ||
| */ | ||
| import express from 'express'; | ||
| import { paygate } from 'paygate/express'; | ||
| const PORT = parseInt(process.env.PORT || '3000', 10); | ||
| const MERCHANT_ID = process.env.PAYGATE_MERCHANT_ID; | ||
| if (!MERCHANT_ID) { | ||
| console.error('PAYGATE_MERCHANT_ID env var is required (see .env.example)'); | ||
| process.exit(1); | ||
| } | ||
| const pw = paygate({ | ||
| merchantId: MERCHANT_ID,${currencyLine} | ||
| }); | ||
| const app = express(); | ||
| // Health check — unprotected. | ||
| app.get('/health', (_req, res) => { | ||
| res.json({ ok: true, merchantId: MERCHANT_ID }); | ||
| }); | ||
| // ${humanPrice(opts)} per request. | ||
| app.${opts.method.toLowerCase()}('${opts.route}', pw({ priceCents: ${opts.priceCents} }), (_req, res) => { | ||
| res.json({ ok: true, data: 'paid content', servedAt: new Date().toISOString() }); | ||
| }); | ||
| app.listen(PORT, () => { | ||
| console.log(\`hosted-paygate seller listening on :\${PORT} merchantId=\${MERCHANT_ID}\`); | ||
| }); | ||
| `; | ||
| } | ||
| function merchantFastifyServerJs(opts) { | ||
| const currencyLine = opts.currency === "EUR" ? `\n currency: 'EUR',` : ""; | ||
| return `/** | ||
| * Hosted PayGate seller (Fastify) — generated by \`npx paygate init\`. | ||
| * | ||
| * This template uses the hosted PayGate product: the \`paygate\` SDK fetches | ||
| * your payout wallet, network, and facilitator from your merchant capability | ||
| * manifest. It requires a merchant account at https://paygate.arispay.app. | ||
| * (For the account-free path, re-run \`npx paygate init\` without | ||
| * \`--merchant-id\`.) | ||
| */ | ||
| import Fastify from 'fastify'; | ||
| import { paygatePlugin } from 'paygate/fastify'; | ||
| const PORT = parseInt(process.env.PORT || '3000', 10); | ||
| const MERCHANT_ID = process.env.PAYGATE_MERCHANT_ID; | ||
| if (!MERCHANT_ID) { | ||
| console.error('PAYGATE_MERCHANT_ID env var is required (see .env.example)'); | ||
| process.exit(1); | ||
| } | ||
| const app = Fastify({ logger: true }); | ||
| await app.register(paygatePlugin, { | ||
| merchantId: MERCHANT_ID,${currencyLine} | ||
| }); | ||
| // Health check — unprotected. | ||
| app.get('/health', async () => ({ ok: true, merchantId: MERCHANT_ID })); | ||
| // ${humanPrice(opts)} per request. | ||
| app.${opts.method.toLowerCase()}('${opts.route}', { | ||
| config: { paygate: { priceCents: ${opts.priceCents} } }, | ||
| }, async () => ({ ok: true, data: 'paid content', servedAt: new Date().toISOString() })); | ||
| await app.listen({ port: PORT, host: '0.0.0.0' }); | ||
| console.log(\`hosted-paygate seller listening on :\${PORT} merchantId=\${MERCHANT_ID}\`); | ||
| `; | ||
| } | ||
| // ── package.json builders ────────────────────────────────────────────── | ||
| function pkgJson(opts, deps, extra) { | ||
| return `${JSON.stringify({ | ||
| name: opts.projectName, | ||
| version: "0.1.0", | ||
| private: true, | ||
| type: "module", | ||
| description: `x402 seller (${opts.framework}) generated by paygate init`, | ||
| scripts: opts.framework === "workers" | ||
| ? { dev: "wrangler dev", deploy: "wrangler deploy" } | ||
| : opts.framework === "next" | ||
| ? { dev: "next dev", build: "next build", start: "next start" } | ||
| : { | ||
| // --env-file makes `cp .env.example .env && npm start` work | ||
| // without a dotenv dependency (Node >= 20.6). | ||
| start: "node --env-file=.env server.js", | ||
| dev: "node --env-file=.env --watch server.js", | ||
| }, | ||
| engines: { node: ">=20.6" }, | ||
| dependencies: deps, | ||
| ...(extra ?? {}), | ||
| }, null, 2)}\n`; | ||
| } | ||
| // Upstream versions: @x402/express verified in-repo at 2.8.0 (the proven | ||
| // live demo); @x402/fastify, @x402/hono, @x402/next verified from the | ||
| // published 2.20.0 tarballs. | ||
| const X402_EXPRESS_RANGE = "^2.8.0"; | ||
| const X402_OTHER_RANGE = "^2.20.0"; | ||
| // ── Entry point ──────────────────────────────────────────────────────── | ||
| export function generateFiles(opts) { | ||
| if (opts.merchantId && (opts.framework === "express" || opts.framework === "fastify")) { | ||
| return generateMerchantFiles(opts); | ||
| } | ||
| switch (opts.framework) { | ||
| case "express": | ||
| return [ | ||
| { | ||
| path: "package.json", | ||
| content: pkgJson(opts, { | ||
| "@x402/core": X402_EXPRESS_RANGE, | ||
| "@x402/evm": X402_EXPRESS_RANGE, | ||
| "@x402/express": X402_EXPRESS_RANGE, | ||
| "@x402/extensions": X402_EXPRESS_RANGE, | ||
| express: "^4.21.2", | ||
| }), | ||
| }, | ||
| { path: "server.js", content: expressServerJs(opts) }, | ||
| { path: ".env.example", content: envExample(opts) }, | ||
| { path: ".gitignore", content: GITIGNORE }, | ||
| { | ||
| path: "README.md", | ||
| content: `# ${opts.projectName}\n\nAccount-free x402 seller (Express) generated by \`npx paygate init\`. No\nArisPay account or API key — the wallet in \`PAY_TO_ADDRESS\` receives funds\ndirectly.\n\n\`\`\`bash\nnpm install\ncp .env.example .env # set PAY_TO_ADDRESS\nnpm start\n\`\`\`\n\n${readmeCommon(opts, "npm start", 3000)}`, | ||
| }, | ||
| ]; | ||
| case "fastify": | ||
| return [ | ||
| { | ||
| path: "package.json", | ||
| content: pkgJson(opts, { | ||
| "@x402/core": X402_OTHER_RANGE, | ||
| "@x402/evm": X402_OTHER_RANGE, | ||
| "@x402/fastify": X402_OTHER_RANGE, | ||
| "@x402/extensions": X402_OTHER_RANGE, | ||
| fastify: "^5.0.0", | ||
| }), | ||
| }, | ||
| { path: "server.js", content: fastifyServerJs(opts) }, | ||
| { path: ".env.example", content: envExample(opts) }, | ||
| { path: ".gitignore", content: GITIGNORE }, | ||
| { | ||
| path: "README.md", | ||
| content: `# ${opts.projectName}\n\nAccount-free x402 seller (Fastify) generated by \`npx paygate init\`. No\nArisPay account or API key — the wallet in \`PAY_TO_ADDRESS\` receives funds\ndirectly.\n\n\`\`\`bash\nnpm install\ncp .env.example .env # set PAY_TO_ADDRESS\nnpm start\n\`\`\`\n\n${readmeCommon(opts, "npm start", 3000)}`, | ||
| }, | ||
| ]; | ||
| case "hono": | ||
| return [ | ||
| { | ||
| path: "package.json", | ||
| content: pkgJson(opts, { | ||
| "@hono/node-server": "^1.13.0", | ||
| "@x402/core": X402_OTHER_RANGE, | ||
| "@x402/evm": X402_OTHER_RANGE, | ||
| "@x402/extensions": X402_OTHER_RANGE, | ||
| "@x402/hono": X402_OTHER_RANGE, | ||
| hono: "^4.6.0", | ||
| }), | ||
| }, | ||
| { path: "server.js", content: honoServerJs(opts) }, | ||
| { path: ".env.example", content: envExample(opts) }, | ||
| { path: ".gitignore", content: GITIGNORE }, | ||
| { | ||
| path: "README.md", | ||
| content: `# ${opts.projectName}\n\nAccount-free x402 seller (Hono, Node.js) generated by \`npx paygate init\`.\nNo ArisPay account or API key — the wallet in \`PAY_TO_ADDRESS\` receives\nfunds directly.\n\n\`\`\`bash\nnpm install\ncp .env.example .env # set PAY_TO_ADDRESS\nnpm start\n\`\`\`\n\n${readmeCommon(opts, "npm start", 3000)}`, | ||
| }, | ||
| ]; | ||
| case "workers": | ||
| return [ | ||
| { | ||
| path: "package.json", | ||
| content: pkgJson(opts, { | ||
| "@x402/core": X402_OTHER_RANGE, | ||
| "@x402/evm": X402_OTHER_RANGE, | ||
| "@x402/extensions": X402_OTHER_RANGE, | ||
| "@x402/hono": X402_OTHER_RANGE, | ||
| hono: "^4.6.0", | ||
| }, { devDependencies: { wrangler: "^4.0.0" } }), | ||
| }, | ||
| { path: "src/index.js", content: workersIndexJs(opts) }, | ||
| { path: "wrangler.toml", content: wranglerToml(opts) }, | ||
| { path: ".gitignore", content: GITIGNORE }, | ||
| { | ||
| path: "README.md", | ||
| content: `# ${opts.projectName}\n\nAccount-free x402 seller on Cloudflare Workers (Hono) generated by\n\`npx paygate init\`. No ArisPay account or API key — the wallet in the\n\`PAY_TO_ADDRESS\` var (see \`wrangler.toml\` \`[vars]\`) receives funds directly.\n\n\`\`\`bash\nnpm install\n# set PAY_TO_ADDRESS in wrangler.toml [vars]\nnpx wrangler dev\n\`\`\`\n\nDeploy with \`npx wrangler deploy\`. Local dev serves on port 8787.\n\n${readmeCommon(opts, "npx wrangler dev", 8787)}`, | ||
| }, | ||
| ]; | ||
| case "next": { | ||
| const routeDir = nextRouteFileDir(opts.route); | ||
| return [ | ||
| { | ||
| path: "package.json", | ||
| content: pkgJson(opts, { | ||
| "@x402/core": X402_OTHER_RANGE, | ||
| "@x402/evm": X402_OTHER_RANGE, | ||
| "@x402/extensions": X402_OTHER_RANGE, | ||
| "@x402/next": X402_OTHER_RANGE, | ||
| next: "^16.2.6", | ||
| react: "^19.0.0", | ||
| "react-dom": "^19.0.0", | ||
| }), | ||
| }, | ||
| { path: "lib/x402.js", content: nextLibX402Js(opts) }, | ||
| { path: `${routeDir}/route.js`, content: nextPaidRouteJs(opts) }, | ||
| { path: "app/api/health/route.js", content: nextHealthRouteJs(opts) }, | ||
| { path: ".env.example", content: envExample(opts) }, | ||
| { path: ".gitignore", content: GITIGNORE }, | ||
| { | ||
| path: "README.md", | ||
| content: `# ${opts.projectName}\n\nAccount-free x402 seller (Next.js App Router) generated by\n\`npx paygate init\`. No ArisPay account or API key — the wallet in\n\`PAY_TO_ADDRESS\` receives funds directly. The paid route handler is wrapped\nwith \`withX402\` from \`@x402/next\` (verified against @x402/next 2.20.0),\nwhich settles only after your handler succeeds — failed responses are never\ncharged.\n\nNote: this scaffold contains only the API route handlers (no pages). Drop\nthe \`app/\` + \`lib/\` folders into an existing Next.js project, or add a\nminimal \`app/layout.js\` + \`app/page.js\` to run it standalone.\n\n\`\`\`bash\nnpm install\ncp .env.example .env.local # set PAY_TO_ADDRESS\nnpm run dev\n\`\`\`\n\n${readmeCommon(opts, "npm run dev", 3000)}`, | ||
| }, | ||
| ]; | ||
| } | ||
| case "fastapi": | ||
| return [ | ||
| { path: "main.py", content: fastapiMainPy(opts) }, | ||
| { | ||
| path: "requirements.txt", | ||
| content: `# x402 pip package (FastAPI middleware + EVM mechanism), verified against 2.17.0\nx402[fastapi,evm]>=2.17.0\nfastapi>=0.115.0\nuvicorn>=0.30.0\n`, | ||
| }, | ||
| { path: ".env.example", content: envExample(opts) }, | ||
| { path: ".gitignore", content: GITIGNORE }, | ||
| { | ||
| path: "README.md", | ||
| content: `# ${opts.projectName}\n\nAccount-free x402 seller (FastAPI) — a generated standalone Python template\nfrom \`npx paygate init\` (it does not use the \`paygate\` npm package at\nruntime). No ArisPay account or API key — the wallet in \`PAY_TO_ADDRESS\`\nreceives funds directly.\n\n\`\`\`bash\npython -m venv .venv && source .venv/bin/activate\npip install -r requirements.txt\ncp .env.example .env # set PAY_TO_ADDRESS, then export the vars\nexport $(grep -v '^#' .env | xargs)\nuvicorn main:app --port 3000\n\`\`\`\n\n${readmeCommon(opts, "uvicorn main:app --port 3000", 3000)}`, | ||
| }, | ||
| ]; | ||
| } | ||
| } | ||
| function generateMerchantFiles(opts) { | ||
| const isExpress = opts.framework === "express"; | ||
| const frameworkDep = isExpress | ||
| ? { express: "^4.21.2" } | ||
| : { fastify: "^5.0.0" }; | ||
| return [ | ||
| { | ||
| path: "package.json", | ||
| content: pkgJson(opts, { paygate: "^5.3.0", ...frameworkDep }), | ||
| }, | ||
| { | ||
| path: "server.js", | ||
| content: isExpress ? merchantExpressServerJs(opts) : merchantFastifyServerJs(opts), | ||
| }, | ||
| { path: ".env.example", content: merchantEnvExample(opts) }, | ||
| { path: ".gitignore", content: GITIGNORE }, | ||
| { | ||
| path: "README.md", | ||
| content: `# ${opts.projectName} | ||
| Hosted PayGate seller (${isExpress ? "Express" : "Fastify"}) generated by \`npx paygate init --merchant-id\`. | ||
| **This is the hosted PayGate product path** — it needs a merchant account at | ||
| https://paygate.arispay.app. The \`paygate\` SDK fetches your payout wallet, | ||
| network, asset, trust policy, and facilitator from your merchant capability | ||
| manifest, so those are configured in the dashboard rather than in this repo. | ||
| Settlement runs through the facilitator named by your manifest (default: | ||
| ${MAINNET_FACILITATOR}, Base mainnet). | ||
| **Prefer the account-free path?** Re-run \`npx paygate init\` without | ||
| \`--merchant-id\` to scaffold a standalone x402 seller that pays a wallet | ||
| address directly with no account at all. | ||
| \`\`\`bash | ||
| npm install | ||
| cp .env.example .env # set PAYGATE_MERCHANT_ID | ||
| npm start | ||
| \`\`\` | ||
| ## Test the 402 | ||
| \`\`\`bash | ||
| ${curlExample(opts, 3000)} | ||
| \`\`\` | ||
| You should see \`HTTP/1.1 402 Payment Required\` with a JSON body listing the | ||
| payment requirements. Issuing the challenge never moves funds — money only | ||
| moves when a payer signs and the facilitator settles. | ||
| ## Learn more | ||
| - Machine-readable facilitator docs: https://facilitator.arispay.app/llms.txt | ||
| - Live facilitator policy (networks/assets/fees): https://facilitator.arispay.app/supported | ||
| `, | ||
| }, | ||
| ]; | ||
| } | ||
| //# sourceMappingURL=init-templates.js.map |
| {"version":3,"file":"init-templates.js","sourceRoot":"","sources":["../src/init-templates.ts"],"names":[],"mappings":"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"} |
| /** | ||
| * `paygate init` — orchestration: parse argv → validate → plan → write. | ||
| * | ||
| * Zero runtime deps by design (paygate ships with `dependencies: {}`): | ||
| * hand-rolled argv parser, node:readline for the interactive prompts, | ||
| * node:fs / node:path for writes. All pure logic (parsing, validation, | ||
| * planning, conflict detection) is exported for unit tests; only | ||
| * `runInit` touches process/stdin. | ||
| */ | ||
| import { type GeneratedFile, type InitFramework, type TemplateOptions } from "./init-templates.js"; | ||
| export declare const WALLET_RE: RegExp; | ||
| export interface RawArgs { | ||
| framework?: string; | ||
| wallet?: string; | ||
| route?: string; | ||
| method?: string; | ||
| price?: string; | ||
| currency?: string; | ||
| network?: string; | ||
| directory?: string; | ||
| merchantId?: string; | ||
| yes: boolean; | ||
| dryRun: boolean; | ||
| help: boolean; | ||
| } | ||
| export type ParseResult = { | ||
| ok: true; | ||
| args: RawArgs; | ||
| } | { | ||
| ok: false; | ||
| error: string; | ||
| }; | ||
| export declare function parseArgv(argv: string[]): ParseResult; | ||
| export interface ValidatedOptions extends TemplateOptions { | ||
| directory: string; | ||
| dryRun: boolean; | ||
| } | ||
| export type ValidateResult = { | ||
| ok: true; | ||
| options: ValidatedOptions; | ||
| } | { | ||
| ok: false; | ||
| errors: string[]; | ||
| }; | ||
| export declare function validateArgs(args: RawArgs): ValidateResult; | ||
| export declare function deriveProjectName(framework: InitFramework, merchantMode: boolean): string; | ||
| export declare function planFiles(options: ValidatedOptions): GeneratedFile[]; | ||
| export interface WritePlan { | ||
| /** Files that will be created. */ | ||
| create: GeneratedFile[]; | ||
| /** Files that already exist byte-identical (idempotent re-run — skipped). */ | ||
| identical: string[]; | ||
| /** Files that exist with DIFFERENT content — the plan must be refused. */ | ||
| conflicts: string[]; | ||
| } | ||
| /** | ||
| * Directory safety: writing is allowed iff every planned file either does | ||
| * not exist yet or exists byte-identical (idempotent re-run). Unrelated | ||
| * files in the directory are left alone and do not block. | ||
| */ | ||
| export declare function checkWritePlan(directory: string, files: GeneratedFile[]): WritePlan; | ||
| export declare function writeFiles(directory: string, files: GeneratedFile[]): void; | ||
| export declare function dryRunOutput(options: ValidatedOptions, files: GeneratedFile[]): string; | ||
| export declare const HELP_TEXT = "paygate init \u2014 make your API payable in one command.\n\nScaffolds a working x402 seller with the ArisPay facilitator as the\nproduction default. Fully non-interactive with flags (for agents/CI).\n\nUsage:\n npx paygate init --framework express --wallet 0xYourAddress [options]\n\nOptions:\n --framework <fw> express | fastify | next | hono | workers | fastapi\n --wallet <0x...> EVM address that receives funds (public info, not a secret)\n --route <path> Paid route path (default: /api/paid)\n --method <verb> GET | POST | PUT | DELETE (default: GET)\n --price <cents> Price in INTEGER cents (default: 1 = $0.01)\n --currency <cur> USD | EUR (default: USD; EUR requires --network base)\n --network <net> base | base-sepolia (default: base-sepolia \u2014 testnet.\n Base mainnet is used ONLY when you pass --network base.)\n --directory <dir> Target directory (default: ./<derived-name>)\n --merchant-id <id> Hosted PayGate mode (express/fastify): use the paygate\n SDK + your merchant account instead of the account-free\n upstream template.\n --yes, -y Accept defaults, never prompt.\n --dry-run Print the file plan (JSON lines + summary), write nothing.\n --help, -h Show this help.\n\nNetworks & facilitators:\n base-sepolia (default) testnet \u2014 FACILITATOR_URL defaults to\n https://x402.org/facilitator (Coinbase's public\n testnet facilitator). The ArisPay facilitator does\n NOT settle testnets.\n base production \u2014 FACILITATOR_URL defaults to\n https://facilitator.arispay.app (Base mainnet,\n USDC + EURC, no facilitator fee).\n"; | ||
| export interface InitIO { | ||
| stdout: (s: string) => void; | ||
| stderr: (s: string) => void; | ||
| /** Whether stdin is a TTY (prompting allowed). */ | ||
| isTTY: boolean; | ||
| /** Ask one question; resolve with the raw answer. Only called when isTTY. */ | ||
| ask: (question: string) => Promise<string>; | ||
| } | ||
| export declare function defaultIO(): InitIO; | ||
| /** Which required inputs are missing for a non-interactive run? */ | ||
| export declare function missingRequired(args: RawArgs): string[]; | ||
| /** Run `paygate init`. Returns a process exit code. */ | ||
| export declare function runInit(argv: string[], io?: InitIO): Promise<number>; | ||
| //# sourceMappingURL=init.d.ts.map |
| {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"} |
+361
| /** | ||
| * `paygate init` — orchestration: parse argv → validate → plan → write. | ||
| * | ||
| * Zero runtime deps by design (paygate ships with `dependencies: {}`): | ||
| * hand-rolled argv parser, node:readline for the interactive prompts, | ||
| * node:fs / node:path for writes. All pure logic (parsing, validation, | ||
| * planning, conflict detection) is exported for unit tests; only | ||
| * `runInit` touches process/stdin. | ||
| */ | ||
| import * as fs from "node:fs"; | ||
| import * as path from "node:path"; | ||
| import * as readline from "node:readline"; | ||
| import { CAIP2, INIT_FRAMEWORKS, MAINNET_FACILITATOR, TESTNET_FACILITATOR, generateFiles, } from "./init-templates.js"; | ||
| export const WALLET_RE = /^0x[0-9a-fA-F]{40}$/; | ||
| const METHODS = ["GET", "POST", "PUT", "DELETE"]; | ||
| const NETWORKS = ["base", "base-sepolia"]; | ||
| const CURRENCIES = ["USD", "EUR"]; | ||
| const VALUE_FLAGS = { | ||
| "--framework": "framework", | ||
| "--wallet": "wallet", | ||
| "--route": "route", | ||
| "--method": "method", | ||
| "--price": "price", | ||
| "--currency": "currency", | ||
| "--network": "network", | ||
| "--directory": "directory", | ||
| "--merchant-id": "merchantId", | ||
| }; | ||
| const BOOL_FLAGS = { | ||
| "--yes": "yes", | ||
| "-y": "yes", | ||
| "--dry-run": "dryRun", | ||
| "--help": "help", | ||
| "-h": "help", | ||
| }; | ||
| export function parseArgv(argv) { | ||
| const args = { yes: false, dryRun: false, help: false }; | ||
| for (let i = 0; i < argv.length; i++) { | ||
| const token = argv[i]; | ||
| const eq = token.indexOf("="); | ||
| const flag = eq > 0 ? token.slice(0, eq) : token; | ||
| if (BOOL_FLAGS[flag]) { | ||
| if (eq > 0) | ||
| return { ok: false, error: `${flag} does not take a value` }; | ||
| args[BOOL_FLAGS[flag]] = true; | ||
| continue; | ||
| } | ||
| const key = VALUE_FLAGS[flag]; | ||
| if (!key) { | ||
| return { ok: false, error: `Unknown flag: ${flag}. Run \`paygate init --help\` for usage.` }; | ||
| } | ||
| let value; | ||
| if (eq > 0) { | ||
| value = token.slice(eq + 1); | ||
| } | ||
| else { | ||
| value = argv[i + 1]; | ||
| if (value === undefined || value.startsWith("--")) { | ||
| return { ok: false, error: `${flag} requires a value` }; | ||
| } | ||
| i++; | ||
| } | ||
| args[key] = value; | ||
| } | ||
| return { ok: true, args }; | ||
| } | ||
| export function validateArgs(args) { | ||
| const errors = []; | ||
| // framework | ||
| const framework = args.framework; | ||
| if (!framework) { | ||
| errors.push(`--framework is required. One of: ${INIT_FRAMEWORKS.join(", ")}.`); | ||
| } | ||
| else if (!INIT_FRAMEWORKS.includes(framework)) { | ||
| errors.push(`Unknown framework "${framework}". One of: ${INIT_FRAMEWORKS.join(", ")}.`); | ||
| } | ||
| // merchant mode is express/fastify only | ||
| const merchantMode = Boolean(args.merchantId); | ||
| // merchantId is interpolated into generated source/.env.example — same | ||
| // strict-charset rule as --route (no quotes, spaces, or newlines). | ||
| if (args.merchantId && !/^[A-Za-z0-9._-]+$/.test(args.merchantId)) { | ||
| errors.push(`--merchant-id may contain only letters, digits, and "._-" (got "${args.merchantId}").`); | ||
| } | ||
| if (merchantMode && framework && framework !== "express" && framework !== "fastify") { | ||
| errors.push(`--merchant-id (hosted PayGate mode) is only supported for express and fastify templates.`); | ||
| } | ||
| // wallet — required for the account-free templates (it's where the money | ||
| // goes). Not needed in merchantId mode (the manifest carries the payout | ||
| // wallet) and waived for --dry-run. | ||
| if (args.wallet !== undefined && !WALLET_RE.test(args.wallet)) { | ||
| errors.push(`--wallet must be a 0x-prefixed 40-hex EVM address (got "${args.wallet}").`); | ||
| } | ||
| else if (args.wallet === undefined && !merchantMode && !args.dryRun) { | ||
| errors.push(`--wallet is required (the EVM address that receives funds). Use --dry-run to preview without one.`); | ||
| } | ||
| // route — strict charset: the value is interpolated into generated source | ||
| // files and (for next/workers) into filesystem paths, so anything outside | ||
| // URL-path characters is rejected outright (no quotes, no spaces, no | ||
| // template syntax) and ".." segments are refused to keep every generated | ||
| // file inside --directory. | ||
| const route = args.route ?? "/api/paid"; | ||
| if (!/^\/[A-Za-z0-9._~/:-]*$/.test(route)) { | ||
| errors.push(`--route must start with "/" and contain only letters, digits, and ` + | ||
| `"._~/:-" (got "${route}").`); | ||
| } | ||
| else if (route.split("/").some((seg) => seg === "..")) { | ||
| errors.push(`--route must not contain ".." path segments (got "${route}").`); | ||
| } | ||
| // method | ||
| const method = (args.method ?? "GET").toUpperCase(); | ||
| if (!METHODS.includes(method)) { | ||
| errors.push(`--method must be one of ${METHODS.join(", ")} (got "${args.method}").`); | ||
| } | ||
| // price — integer cents, >= 1 | ||
| const rawPrice = args.price ?? "1"; | ||
| let priceCents = Number.NaN; | ||
| if (!/^\d+$/.test(rawPrice.trim())) { | ||
| errors.push(`--price must be an INTEGER number of cents (got "${rawPrice}"). ` + | ||
| `Prices are integer cents, never floats or dollar strings: for $0.10 pass --price 10, for $2.50 pass --price 250.`); | ||
| } | ||
| else { | ||
| priceCents = Number.parseInt(rawPrice.trim(), 10); | ||
| if (!Number.isInteger(priceCents) || priceCents < 1) { | ||
| errors.push(`--price must be an integer >= 1 (cents). Got "${rawPrice}".`); | ||
| } | ||
| } | ||
| // currency | ||
| const currency = (args.currency ?? "USD").toUpperCase(); | ||
| if (!CURRENCIES.includes(currency)) { | ||
| errors.push(`--currency must be USD or EUR (got "${args.currency}").`); | ||
| } | ||
| // network — default is TESTNET; mainnet only when explicitly chosen. | ||
| const network = (args.network ?? "base-sepolia"); | ||
| if (!NETWORKS.includes(network)) { | ||
| errors.push(`--network must be "base" or "base-sepolia" (got "${args.network}").`); | ||
| } | ||
| // EUR requires base mainnet: EUR settles in Circle EURC, and the testnet | ||
| // default facilitator (x402.org) does not settle EURC — there is no | ||
| // EURC testnet path in these templates. | ||
| if (currency === "EUR" && network !== "base" && NETWORKS.includes(network)) { | ||
| errors.push(`--currency EUR requires --network base. EUR settles in Circle EURC and the ` + | ||
| `testnet default facilitator does not settle EURC, so there is no EUR testnet template.`); | ||
| } | ||
| if (errors.length > 0) | ||
| return { ok: false, errors }; | ||
| const projectName = deriveProjectName(framework, merchantMode); | ||
| const directory = args.directory ?? `./${projectName}`; | ||
| return { | ||
| ok: true, | ||
| options: { | ||
| framework: framework, | ||
| wallet: args.wallet, | ||
| route, | ||
| method, | ||
| priceCents, | ||
| currency, | ||
| network, | ||
| merchantId: args.merchantId, | ||
| projectName, | ||
| directory, | ||
| dryRun: args.dryRun, | ||
| }, | ||
| }; | ||
| } | ||
| export function deriveProjectName(framework, merchantMode) { | ||
| return merchantMode ? `paygate-${framework}-seller` : `x402-${framework}-seller`; | ||
| } | ||
| // ── Planning + directory safety ──────────────────────────────────────── | ||
| export function planFiles(options) { | ||
| return generateFiles(options); | ||
| } | ||
| /** | ||
| * Directory safety: writing is allowed iff every planned file either does | ||
| * not exist yet or exists byte-identical (idempotent re-run). Unrelated | ||
| * files in the directory are left alone and do not block. | ||
| */ | ||
| export function checkWritePlan(directory, files) { | ||
| const create = []; | ||
| const identical = []; | ||
| const conflicts = []; | ||
| for (const file of files) { | ||
| const target = path.join(directory, file.path); | ||
| if (!fs.existsSync(target)) { | ||
| create.push(file); | ||
| continue; | ||
| } | ||
| const existing = fs.readFileSync(target); | ||
| if (existing.equals(Buffer.from(file.content, "utf8"))) { | ||
| identical.push(file.path); | ||
| } | ||
| else { | ||
| conflicts.push(file.path); | ||
| } | ||
| } | ||
| return { create, identical, conflicts }; | ||
| } | ||
| export function writeFiles(directory, files) { | ||
| for (const file of files) { | ||
| const target = path.join(directory, file.path); | ||
| fs.mkdirSync(path.dirname(target), { recursive: true }); | ||
| fs.writeFileSync(target, file.content, "utf8"); | ||
| } | ||
| } | ||
| // ── Output helpers ───────────────────────────────────────────────────── | ||
| export function dryRunOutput(options, files) { | ||
| const lines = files.map((f) => JSON.stringify({ path: f.path, bytes: Buffer.byteLength(f.content, "utf8") })); | ||
| const summary = [ | ||
| ``, | ||
| `Dry run — nothing written.`, | ||
| `Framework: ${options.framework}${options.merchantId ? " (hosted PayGate mode)" : ""}`, | ||
| `Route: ${options.method} ${options.route} @ ${options.priceCents}¢ ${options.currency}`, | ||
| `Network: ${options.network} (${CAIP2[options.network]})`, | ||
| `Facilitator: ${options.network === "base" | ||
| ? `${MAINNET_FACILITATOR} (Base mainnet)` | ||
| : `${TESTNET_FACILITATOR} (testnet default — the ArisPay facilitator settles Base mainnet only)`}`, | ||
| `Directory: ${options.directory}`, | ||
| `${files.length} file(s) would be written.`, | ||
| ]; | ||
| return `${lines.join("\n")}\n${summary.join("\n")}\n`; | ||
| } | ||
| export const HELP_TEXT = `paygate init — make your API payable in one command. | ||
| Scaffolds a working x402 seller with the ArisPay facilitator as the | ||
| production default. Fully non-interactive with flags (for agents/CI). | ||
| Usage: | ||
| npx paygate init --framework express --wallet 0xYourAddress [options] | ||
| Options: | ||
| --framework <fw> express | fastify | next | hono | workers | fastapi | ||
| --wallet <0x...> EVM address that receives funds (public info, not a secret) | ||
| --route <path> Paid route path (default: /api/paid) | ||
| --method <verb> GET | POST | PUT | DELETE (default: GET) | ||
| --price <cents> Price in INTEGER cents (default: 1 = $0.01) | ||
| --currency <cur> USD | EUR (default: USD; EUR requires --network base) | ||
| --network <net> base | base-sepolia (default: base-sepolia — testnet. | ||
| Base mainnet is used ONLY when you pass --network base.) | ||
| --directory <dir> Target directory (default: ./<derived-name>) | ||
| --merchant-id <id> Hosted PayGate mode (express/fastify): use the paygate | ||
| SDK + your merchant account instead of the account-free | ||
| upstream template. | ||
| --yes, -y Accept defaults, never prompt. | ||
| --dry-run Print the file plan (JSON lines + summary), write nothing. | ||
| --help, -h Show this help. | ||
| Networks & facilitators: | ||
| base-sepolia (default) testnet — FACILITATOR_URL defaults to | ||
| ${TESTNET_FACILITATOR} (Coinbase's public | ||
| testnet facilitator). The ArisPay facilitator does | ||
| NOT settle testnets. | ||
| base production — FACILITATOR_URL defaults to | ||
| ${MAINNET_FACILITATOR} (Base mainnet, | ||
| USDC + EURC, no facilitator fee). | ||
| `; | ||
| export function defaultIO() { | ||
| return { | ||
| stdout: (s) => process.stdout.write(s), | ||
| stderr: (s) => process.stderr.write(s), | ||
| isTTY: Boolean(process.stdin.isTTY && process.stdout.isTTY), | ||
| ask: (question) => { | ||
| const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); | ||
| return new Promise((resolve) => rl.question(question, (answer) => { | ||
| rl.close(); | ||
| resolve(answer.trim()); | ||
| })); | ||
| }, | ||
| }; | ||
| } | ||
| /** Which required inputs are missing for a non-interactive run? */ | ||
| export function missingRequired(args) { | ||
| const missing = []; | ||
| if (!args.framework) | ||
| missing.push("--framework"); | ||
| if (!args.wallet && !args.merchantId && !args.dryRun) | ||
| missing.push("--wallet"); | ||
| return missing; | ||
| } | ||
| async function promptMissing(args, io) { | ||
| const out = { ...args }; | ||
| if (!out.framework) { | ||
| const answer = await io.ask(`Framework (${INIT_FRAMEWORKS.join(" | ")}) [express]: `); | ||
| out.framework = answer || "express"; | ||
| } | ||
| if (!out.wallet && !out.merchantId && !out.dryRun) { | ||
| out.wallet = await io.ask(`Wallet address that receives funds (0x..., public info): `); | ||
| } | ||
| if (!out.network) { | ||
| const answer = await io.ask(`Network — 1) base-sepolia (testnet, default) 2) base (production, Base mainnet via ${MAINNET_FACILITATOR}) [1]: `); | ||
| out.network = | ||
| answer === "2" || answer === "base" || answer === "production" ? "base" : "base-sepolia"; | ||
| } | ||
| return out; | ||
| } | ||
| // ── Entry point ──────────────────────────────────────────────────────── | ||
| /** Run `paygate init`. Returns a process exit code. */ | ||
| export async function runInit(argv, io = defaultIO()) { | ||
| const parsed = parseArgv(argv); | ||
| if (!parsed.ok) { | ||
| io.stderr(`${parsed.error}\n`); | ||
| return 1; | ||
| } | ||
| let args = parsed.args; | ||
| if (args.help) { | ||
| io.stdout(HELP_TEXT); | ||
| return 0; | ||
| } | ||
| // Non-interactive detection: --yes, or everything required already given, | ||
| // or stdin is not a TTY (never prompt in that case — fail with the list | ||
| // of missing flags instead). | ||
| const missing = missingRequired(args); | ||
| if (missing.length > 0 && !args.yes) { | ||
| if (io.isTTY) { | ||
| args = await promptMissing(args, io); | ||
| } | ||
| else { | ||
| io.stderr(`Missing required flags: ${missing.join(", ")} (stdin is not a TTY, so paygate init cannot prompt).\n` + | ||
| `Pass them explicitly, e.g.:\n npx paygate init --framework express --wallet 0xYourAddress --yes\n`); | ||
| return 1; | ||
| } | ||
| } | ||
| else if (missing.length > 0 && args.yes) { | ||
| // --yes accepts defaults but cannot invent required inputs. | ||
| io.stderr(`Missing required flags: ${missing.join(", ")}. --yes cannot supply these.\n`); | ||
| return 1; | ||
| } | ||
| const validated = validateArgs(args); | ||
| if (!validated.ok) { | ||
| io.stderr(`${validated.errors.map((e) => `error: ${e}`).join("\n")}\n`); | ||
| return 1; | ||
| } | ||
| const options = validated.options; | ||
| const files = planFiles(options); | ||
| if (options.dryRun) { | ||
| io.stdout(dryRunOutput(options, files)); | ||
| return 0; | ||
| } | ||
| const plan = checkWritePlan(options.directory, files); | ||
| if (plan.conflicts.length > 0) { | ||
| io.stderr(`Refusing to overwrite existing files in ${options.directory} that differ from the template:\n` + | ||
| `${plan.conflicts.map((p) => ` - ${p}`).join("\n")}\n` + | ||
| `Move them aside or pick another --directory. (Re-running over an identical scaffold is fine.)\n`); | ||
| return 1; | ||
| } | ||
| writeFiles(options.directory, plan.create); | ||
| const skipped = plan.identical.length > 0 ? ` (${plan.identical.length} already up to date)` : ""; | ||
| io.stdout(`\nCreated ${plan.create.length} file(s) in ${options.directory}${skipped}:\n` + | ||
| `${files.map((f) => ` ${f.path}`).join("\n")}\n\n` + | ||
| `Next steps:\n` + | ||
| ` cd ${options.directory}\n` + | ||
| (options.framework === "fastapi" | ||
| ? ` pip install -r requirements.txt && cp .env.example .env && uvicorn main:app --port 3000\n` | ||
| : options.framework === "workers" | ||
| ? ` npm install && npx wrangler dev\n` | ||
| : ` npm install && cp .env.example .env && npm ${options.framework === "next" ? "run dev" : "start"}\n`) + | ||
| ` curl -i localhost:${options.framework === "workers" ? 8787 : 3000}${options.route} # expect HTTP 402\n\n` + | ||
| (options.network === "base" | ||
| ? `Production network: Base mainnet via ${MAINNET_FACILITATOR}.\n` | ||
| : `Testnet network: base-sepolia via ${TESTNET_FACILITATOR} — the ArisPay facilitator settles Base mainnet only; re-run with --network base for production.\n`)); | ||
| return 0; | ||
| } | ||
| //# sourceMappingURL=init.js.map |
| {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"} |
+21
| MIT License | ||
| Copyright (c) 2026 Polar Industries Ltd | ||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| of this software and associated documentation files (the "Software"), to deal | ||
| in the Software without restriction, including without limitation the rights | ||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the Software is | ||
| furnished to do so, subject to the following conditions: | ||
| The above copyright notice and this permission notice shall be included in all | ||
| copies or substantial portions of the Software. | ||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| SOFTWARE. |
+15
-10
| { | ||
| "name": "paygate", | ||
| "version": "5.3.3", | ||
| "version": "5.4.0", | ||
| "description": "Accept payment from AI agents in two lines of code. Gate any Express or Fastify route with an x402 paywall — USD (USDC) or EUR (EURC) pricing, settled on Base mainnet via ArisPay's facilitator.", | ||
@@ -8,2 +8,5 @@ "type": "module", | ||
| "types": "./dist/index.d.ts", | ||
| "bin": { | ||
| "paygate": "./dist/cli.js" | ||
| }, | ||
| "exports": { | ||
@@ -23,2 +26,9 @@ ".": { | ||
| }, | ||
| "scripts": { | ||
| "build": "tsc && chmod +x dist/cli.js", | ||
| "dev": "tsc --watch", | ||
| "type-check": "tsc --noEmit", | ||
| "test": "vitest run --root ../.. packages/paygate/src/", | ||
| "prepublishOnly": "pnpm build" | ||
| }, | ||
| "dependencies": {}, | ||
@@ -84,11 +94,6 @@ "peerDependencies": { | ||
| "type": "git", | ||
| "url": "https://github.com/arispay-inc/ArisPay" | ||
| "url": "git+https://github.com/arispay-inc/ArisPay.git", | ||
| "directory": "packages/paygate" | ||
| }, | ||
| "private": false, | ||
| "scripts": { | ||
| "build": "tsc", | ||
| "dev": "tsc --watch", | ||
| "type-check": "tsc --noEmit", | ||
| "test": "vitest run --root ../.. packages/paygate/src/ghost-partner.test.ts" | ||
| } | ||
| } | ||
| "private": false | ||
| } |
+99
-17
| # paygate | ||
| Create agent-payable offers with HTTP 402 and USDC settlement. PayGate handles the x402 challenge, calls the [ArisPay facilitator](https://facilitator.arispay.app), and lets your handler run only after payment settles. | ||
| Make your API payable in one command. | ||
| API endpoint offers are live today. Use the hosted proxy for zero-code acceptance, or install this package when you want the 402 flow on your own domain. | ||
| ```bash | ||
| npx paygate init | ||
| ``` | ||
| ## Install | ||
| `paygate init` scaffolds a **working x402 seller** — an HTTP API where a paid | ||
| route answers `402 Payment Required` until an AI agent (or any x402 client) | ||
| pays it in stablecoins. Pick a framework, give it the wallet address that | ||
| should receive the money, and you have a payable endpoint in under five | ||
| minutes. No account, no API key: funds settle on-chain straight to your | ||
| wallet through the [ArisPay facilitator](https://facilitator.arispay.app). | ||
| ```bash | ||
| # Non-interactive (agents / CI): everything via flags | ||
| npx paygate init \ | ||
| --framework express \ | ||
| --wallet 0xYourAddress \ | ||
| --route /api/data --price 10 \ | ||
| --yes | ||
| cd x402-express-seller && npm install && cp .env.example .env && npm start | ||
| curl -i localhost:3000/api/data # → HTTP 402 with the payment requirements | ||
| ``` | ||
| Supported templates: `express`, `fastify`, `next` (App Router), `hono`, | ||
| `workers` (Cloudflare Workers + Hono), `fastapi` (standalone Python). | ||
| Every template ships a `/health` route, a paid route with Bazaar discovery | ||
| metadata (so the endpoint can enter the public x402 catalog), a `.env.example`, | ||
| and a README with a copy-paste 402 test. | ||
| Useful flags: `--price <integer cents>` (never floats), `--method`, | ||
| `--currency USD|EUR` (EUR settles in Circle EURC and requires | ||
| `--network base`), `--network base|base-sepolia`, `--merchant-id` (hosted | ||
| PayGate mode, see below), `--dry-run` (print the file plan, write nothing), | ||
| `--yes` (accept defaults, never prompt). Run `npx paygate init --help` for | ||
| the full list. | ||
| **Networks:** the default is `base-sepolia` (testnet) so you can rehearse | ||
| without moving real funds — testnet templates point at Coinbase's public | ||
| testnet facilitator (`https://x402.org/facilitator`) because the ArisPay | ||
| facilitator settles **Base mainnet only**. Pass `--network base` for | ||
| production; that flips `FACILITATOR_URL` to `https://facilitator.arispay.app`. | ||
| See also the full quickstart: `docs/quickstart-accept-x402.md` in the | ||
| [ArisPay repo](https://github.com/arispay-inc/ArisPay). | ||
| --- | ||
| ## The SDK | ||
| If you'd rather wire the paywall into an existing app yourself, install the | ||
| middleware: | ||
| ```bash | ||
| npm install paygate | ||
| ``` | ||
| PayGate handles the x402 challenge, verifies/settles through a facilitator, | ||
| and lets your handler run only after payment settles. | ||
| There are **two ways to configure it**: | ||
| - **Direct (wallet) mode** — pass `wallet` + `network`. No ArisPay account: | ||
| the 402 challenge points straight at your wallet and the SDK settles | ||
| through `facilitatorUrl` (default `https://facilitator.arispay.app`). | ||
| - **Hosted PayGate mode** — pass `merchantId` (from | ||
| [paygate.arispay.app](https://paygate.arispay.app)). The SDK fetches your | ||
| payout wallet, network, asset, trust policy, **and facilitator** from your | ||
| merchant capability manifest. | ||
| `merchantId` is optional — direct mode is fully supported. (Direct mode is | ||
| configured via the fields the v3 docs label "v2 compat"; they keep working | ||
| and are what `paygate init` account-free templates rely on conceptually.) | ||
| ## Express | ||
@@ -33,3 +98,2 @@ | ||
| priceCents: (req) => req.body.depth === 'deep' ? 50 : 10, | ||
| description: 'AI analysis', | ||
| }), (req, res) => { | ||
@@ -63,6 +127,3 @@ res.json({ result: '...' }); | ||
| app.get('/api/research', async (req, reply) => { | ||
| const { paid } = await req.paygatePay({ | ||
| priceCents: 5, | ||
| description: 'Research query', | ||
| }); | ||
| const { paid } = await req.paygatePay({ priceCents: 5 }); | ||
| if (!paid) return; // 402 challenge already sent | ||
@@ -129,5 +190,9 @@ reply.send({ results: '...' }); | ||
| |---|---|---|---| | ||
| | `merchantId` | Yes | — | PayGate merchant ID from the dashboard. The SDK fetches payout rail, wallet, asset, facilitator, and trust policy from ArisPay. | | ||
| | `apiUrl` | No | `https://api.arispay.app` | Override ArisPay API URL for staging/self-hosting. | | ||
| | `facilitatorUrl` | No | Manifest value | Compatibility override. In v3, merchant capabilities are authoritative. | | ||
| | `merchantId` | No¹ | — | Hosted PayGate merchant ID from the dashboard. When set, the SDK fetches payout rail, wallet, asset, facilitator, and trust policy from ArisPay — the manifest is authoritative. | | ||
| | `wallet` | No¹ | — | Direct mode: the EVM address that receives funds. Pair with `network`. | | ||
| | `network` | No¹ | — | Direct mode: CAIP-2 id or short name (`base`, `base-sepolia`, `ethereum`, `polygon`). | | ||
| | `currency` | No | `"USD"` | `"USD"` (USDC) or `"EUR"` (Circle EURC). `priceCents` is then integer cents of that currency — the cents → 6-decimal conversion factor is 10⁴ for both assets. In direct mode EURC addresses are known for Base mainnet + Base Sepolia (other networks need an explicit `asset`); in merchantId mode the SDK selects the merchant's EURC rail and errors clearly if there is none. | | ||
| | `asset` | No | derived | Direct mode only: settlement token contract, auto-derived from `network` + `currency`. Ignored in merchantId mode. | | ||
| | `facilitatorUrl` | No | `https://facilitator.arispay.app` | **Direct mode only.** In merchantId mode this option is ignored — the facilitator comes from the merchant capability manifest, which is authoritative. | | ||
| | `apiUrl` | No | `https://api.arispay.app` | Override ArisPay API URL for staging/self-hosting (merchantId mode). | | ||
| | `timeout` | No | `30000` | ArisPay/facilitator call timeout in ms. | | ||
@@ -137,2 +202,20 @@ | `cacheTtlMs` | No | `300000` | Merchant capability cache TTL. | | ||
| ¹ Pass either `merchantId` (hosted mode) **or** `wallet` + `network` (direct | ||
| mode). Direct mode currently emits a deprecation warning pointing at | ||
| `merchantId`; it remains supported. | ||
| Per-route config (`pw({ ... })`): `priceCents` (integer cents, or a function | ||
| of the request for dynamic pricing). A `description` field is accepted for | ||
| forward compatibility but is **reserved/currently unused** — it does not | ||
| appear in the 402 challenge today. | ||
| ### EUR pricing | ||
| ```ts | ||
| const pw = paygate({ | ||
| merchantId: "m_123", | ||
| currency: "EUR", // settles in Circle EURC; priceCents = EUR cents | ||
| }); | ||
| ``` | ||
| ### Self-settle | ||
@@ -157,13 +240,12 @@ | ||
| ### Compatibility mode | ||
| Older code that passes `wallet` and `network` still works through a v2 shim, but new integrations should use `merchantId` and configure payout wallets in the dashboard. The shim will be removed in a future major version. | ||
| ## Networks | ||
| PayGate currently settles USDC on EVM networks advertised by your merchant capability manifest. Base mainnet (`eip155:8453`) is the recommended production network. | ||
| PayGate settles **USDC and EURC** on EVM networks — in merchantId mode the | ||
| networks advertised by your merchant capability manifest, in direct mode the | ||
| network you pass. Base mainnet (`eip155:8453`) is the recommended production | ||
| network. | ||
| ## Facilitator | ||
| PayGate settles through [**facilitator.arispay.app**](https://facilitator.arispay.app) by default — a non-custodial x402 facilitator, live on Base mainnet, settling USDC and EURC. It verifies signed payment authorizations and submits settlement on-chain; funds move directly from buyer to seller (no held funds, no balances, no payouts to release). No facilitator fee: the seller pays chain gas (self-settle with your own key, or the default relayer path, where the facilitator fronts limited launch-period gas with ≥30 days' notice before any change). The live policy is machine-readable at [`/supported`](https://facilitator.arispay.app/supported); the discovery document is at [`/facilitator`](https://facilitator.arispay.app/facilitator). Point `facilitatorUrl` elsewhere if you run your own. | ||
| PayGate settles through [**facilitator.arispay.app**](https://facilitator.arispay.app) by default (direct mode) — a non-custodial x402 facilitator, live on Base mainnet, settling USDC and EURC. It verifies signed payment authorizations and submits settlement on-chain; funds move directly from buyer to seller (no held funds, no balances, no payouts to release). No facilitator fee: the seller pays chain gas (self-settle with your own key, or the default relayer path, where the facilitator fronts limited launch-period gas with ≥30 days' notice before any change). The live policy is machine-readable at [`/supported`](https://facilitator.arispay.app/supported); the discovery document is at [`/facilitator`](https://facilitator.arispay.app/facilitator). Point `facilitatorUrl` elsewhere if you run your own (direct mode; in merchantId mode the manifest names the facilitator). | ||
@@ -170,0 +252,0 @@ ## License |
| export {}; | ||
| //# sourceMappingURL=core.test.d.ts.map |
| {"version":3,"file":"core.test.d.ts","sourceRoot":"","sources":["../src/core.test.ts"],"names":[],"mappings":""} |
| import { describe, expect, it } from "vitest"; | ||
| import { buildChallengeHeaders } from "./core.js"; | ||
| const baseAccept = { | ||
| scheme: "exact", | ||
| network: "eip155:8453", | ||
| amount: "10000", | ||
| resource: "https://example.com/api/protected", | ||
| asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", | ||
| payTo: "0xabcdef1234567890abcdef1234567890abcdef12", | ||
| extra: { name: "USD Coin", version: "2" }, | ||
| }; | ||
| const baseBody = { | ||
| error: "Payment Required", | ||
| x402Version: 2, | ||
| accepts: [baseAccept], | ||
| facilitator: "https://facilitator.arispay.app", | ||
| gasSponsored: true, | ||
| }; | ||
| describe("buildChallengeHeaders", () => { | ||
| it("emits payment-required as base64-encoded JSON of the body", () => { | ||
| const headers = buildChallengeHeaders(baseBody, [baseAccept]); | ||
| const decoded = Buffer.from(headers["payment-required"], "base64").toString("utf8"); | ||
| expect(JSON.parse(decoded)).toEqual(baseBody); | ||
| }); | ||
| it("keeps X-Payment-Requirements as raw JSON of {x402Version, accepts} only", () => { | ||
| const headers = buildChallengeHeaders(baseBody, [baseAccept]); | ||
| expect(JSON.parse(headers["X-Payment-Requirements"])).toEqual({ | ||
| x402Version: 2, | ||
| accepts: [baseAccept], | ||
| }); | ||
| }); | ||
| it("declares x402 in WWW-Authenticate", () => { | ||
| const headers = buildChallengeHeaders(baseBody, [baseAccept]); | ||
| expect(headers["WWW-Authenticate"]).toBe("x402"); | ||
| }); | ||
| it("exposes the canonical headers via CORS", () => { | ||
| const headers = buildChallengeHeaders(baseBody, [baseAccept]); | ||
| const expose = headers["Access-Control-Expose-Headers"]; | ||
| expect(expose).toContain("payment-required"); | ||
| expect(expose).toContain("x-payment-response"); | ||
| }); | ||
| it("strips non-printable-ASCII from the legacy header (Latin1 safety)", () => { | ||
| const acceptsWithEmDash = [ | ||
| { | ||
| ...baseAccept, | ||
| extra: { ...baseAccept.extra, name: "USD — Coin" }, | ||
| }, | ||
| ]; | ||
| const bodyWithEmDash = { ...baseBody, accepts: acceptsWithEmDash }; | ||
| const headers = buildChallengeHeaders(bodyWithEmDash, acceptsWithEmDash); | ||
| // Legacy header should have ? replacements — em dash (U+2014) is char 8212. | ||
| expect(headers["X-Payment-Requirements"]).not.toMatch(/—/); | ||
| expect(/[^\x20-\x7E]/.test(headers["X-Payment-Requirements"])).toBe(false); | ||
| // Canonical header preserves the em dash via base64 round-trip. | ||
| const decoded = Buffer.from(headers["payment-required"], "base64").toString("utf8"); | ||
| expect(decoded).toContain("—"); | ||
| }); | ||
| it("canonical header is valid base64 (alphabet only, padding optional)", () => { | ||
| const headers = buildChallengeHeaders(baseBody, [baseAccept]); | ||
| expect(headers["payment-required"]).toMatch(/^[A-Za-z0-9+/]+=*$/); | ||
| }); | ||
| }); | ||
| // ── EUR (EURC) currency support ────────────────────── | ||
| // | ||
| // `currency: "EUR"` switches the settlement asset to Circle EURC. These | ||
| // tests drive handlePaywall through the v2-shim challenge path (no network | ||
| // I/O) and pin the on-chain-verified EURC constants — a wrong address or | ||
| // EIP-712 name silently breaks every EUR payment. | ||
| import { handlePaywall } from "./core.js"; | ||
| const WALLET = "0xabcdef1234567890abcdef1234567890abcdef12"; | ||
| const RESOURCE = "https://merchant.example.com/api/data"; | ||
| async function challengeFor(config, priceCents = 100) { | ||
| const result = await handlePaywall(config, { priceCents }, RESOURCE, undefined); | ||
| if (result.error) | ||
| throw new Error(`expected challenge, got error: ${result.error.body.error}`); | ||
| return result.challenge; | ||
| } | ||
| describe("currency: EUR (v2-shim path)", () => { | ||
| it("emits the on-chain-verified EURC asset + domain on Base mainnet", async () => { | ||
| const challenge = await challengeFor({ wallet: WALLET, network: "base", currency: "EUR" }); | ||
| const accept = challenge.body.accepts[0]; | ||
| expect(accept.asset).toBe("0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42"); | ||
| expect(accept.extra).toEqual({ name: "EURC", version: "2" }); | ||
| expect(accept.network).toBe("eip155:8453"); | ||
| }); | ||
| it("emits the Base Sepolia EURC asset for testnet", async () => { | ||
| const challenge = await challengeFor({ | ||
| wallet: WALLET, | ||
| network: "base-sepolia", | ||
| currency: "EUR", | ||
| }); | ||
| const accept = challenge.body.accepts[0]; | ||
| expect(accept.asset).toBe("0x808456652fdb597867f38412077A9182bf77359F"); | ||
| expect(accept.extra).toEqual({ name: "EURC", version: "2" }); | ||
| }); | ||
| it("converts EUR cents with the same 10^4 factor (EURC has 6 decimals)", async () => { | ||
| const challenge = await challengeFor({ wallet: WALLET, network: "base", currency: "EUR" }, 250); | ||
| expect(challenge.body.accepts[0].amount).toBe("2500000"); | ||
| }); | ||
| it("errors clearly on networks with no verified EURC address", async () => { | ||
| const result = await handlePaywall({ wallet: WALLET, network: "polygon", currency: "EUR" }, { priceCents: 100 }, RESOURCE, undefined); | ||
| expect(result.paid).toBe(false); | ||
| expect(result.error?.body.error).toContain("no known EURC address"); | ||
| }); | ||
| it("honours an explicit asset override under EUR", async () => { | ||
| const challenge = await challengeFor({ | ||
| wallet: WALLET, | ||
| network: "polygon", | ||
| currency: "EUR", | ||
| asset: "0x1111111111111111111111111111111111111111", | ||
| }); | ||
| expect(challenge.body.accepts[0].asset).toBe("0x1111111111111111111111111111111111111111"); | ||
| }); | ||
| it("defaults to USDC when currency is omitted (no behavior change)", async () => { | ||
| const challenge = await challengeFor({ wallet: WALLET, network: "base" }); | ||
| const accept = challenge.body.accepts[0]; | ||
| expect(accept.asset).toBe("0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"); | ||
| expect(accept.extra).toEqual({ name: "USD Coin", version: "2" }); | ||
| }); | ||
| }); | ||
| // ── v3 manifest path: EUR rail selection ───────────── | ||
| // | ||
| // Locks the manifest-rail selection contract the changeset documents: | ||
| // currency EUR picks the rail whose assetName is "EURC"; absence of a EUR | ||
| // rail is a clear configuration error, not a silent USDC fallback. | ||
| import { afterEach, vi } from "vitest"; | ||
| function manifestResponse(rails) { | ||
| return { | ||
| ok: true, | ||
| status: 200, | ||
| json: async () => ({ | ||
| version: "1", | ||
| merchant: { slug: "test-merchant", name: "Test" }, | ||
| trust: { minTier: "any" }, | ||
| rails, | ||
| updated: new Date().toISOString(), | ||
| }), | ||
| }; | ||
| } | ||
| const USDC_RAIL = { | ||
| scheme: "x402", | ||
| network: "eip155:8453", | ||
| asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", | ||
| assetName: "USDC", | ||
| payTo: WALLET, | ||
| facilitator: "https://facilitator.arispay.app", | ||
| }; | ||
| const EURC_RAIL = { | ||
| ...USDC_RAIL, | ||
| asset: "0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42", | ||
| assetName: "EURC", | ||
| }; | ||
| describe("currency: EUR (v3 manifest path)", () => { | ||
| afterEach(() => { | ||
| vi.unstubAllGlobals(); | ||
| }); | ||
| it("selects the EURC rail when currency is EUR", async () => { | ||
| vi.stubGlobal("fetch", vi.fn().mockResolvedValue(manifestResponse([USDC_RAIL, EURC_RAIL]))); | ||
| const challenge = await challengeFor({ merchantId: "m_eur_pick", currency: "EUR" }); | ||
| const accept = challenge.body.accepts[0]; | ||
| expect(accept.asset).toBe(EURC_RAIL.asset); | ||
| expect(accept.extra).toEqual({ name: "EURC", version: "2" }); | ||
| }); | ||
| it("errors clearly (no silent USDC fallback) when the merchant has no EUR rail", async () => { | ||
| vi.stubGlobal("fetch", vi.fn().mockResolvedValue(manifestResponse([USDC_RAIL]))); | ||
| const result = await handlePaywall({ merchantId: "m_eur_missing", currency: "EUR" }, { priceCents: 100 }, RESOURCE, undefined); | ||
| expect(result.paid).toBe(false); | ||
| expect(result.error?.body.error).toContain("no EUR (EURC) payout rail"); | ||
| }); | ||
| it("keeps the rails[0] fallback for USD callers (pre-EUR manifests unchanged)", async () => { | ||
| vi.stubGlobal("fetch", vi.fn().mockResolvedValue(manifestResponse([USDC_RAIL]))); | ||
| const challenge = await challengeFor({ merchantId: "m_usd_fallback" }); | ||
| expect(challenge.body.accepts[0].asset).toBe(USDC_RAIL.asset); | ||
| }); | ||
| }); | ||
| // ── Settlement validation (L7) ─────────────────────── | ||
| const PAYER = "0x1111111111111111111111111111111111111111"; | ||
| const PAYEE = "0x2222222222222222222222222222222222222222"; | ||
| function makePaymentHeader(payer = PAYER) { | ||
| const payload = { | ||
| x402Version: 2, | ||
| scheme: "exact", | ||
| network: "eip155:8453", | ||
| payload: { | ||
| signature: "0xsig", | ||
| authorization: { | ||
| from: payer, | ||
| to: PAYEE, | ||
| value: "10000", | ||
| validAfter: "0", | ||
| validBefore: "9999999999", | ||
| nonce: "0xabcd", | ||
| }, | ||
| }, | ||
| }; | ||
| return Buffer.from(JSON.stringify(payload), "utf8").toString("base64"); | ||
| } | ||
| function settleResponse(overrides = {}) { | ||
| return { | ||
| ok: true, | ||
| status: 200, | ||
| json: async () => ({ | ||
| success: true, | ||
| transaction: "0xtxhash", | ||
| payer: PAYER, | ||
| ...overrides, | ||
| }), | ||
| }; | ||
| } | ||
| describe("handlePaywall settlement", () => { | ||
| afterEach(() => { | ||
| vi.unstubAllGlobals(); | ||
| }); | ||
| it("rejects a v3 manifest rail with a missing or non-HTTPS facilitator", async () => { | ||
| vi.stubGlobal("fetch", vi.fn().mockResolvedValue(manifestResponse([{ ...USDC_RAIL, facilitator: "http://insecure.example.com" }]))); | ||
| const result = await handlePaywall({ merchantId: "m_bad_facilitator" }, { priceCents: 100 }, RESOURCE, makePaymentHeader()); | ||
| expect(result.paid).toBe(false); | ||
| expect(result.error?.body.error).toContain("invalid facilitator URL"); | ||
| }); | ||
| function mockSettleFetch(settleOverrides = {}) { | ||
| return vi.fn().mockImplementation((url) => { | ||
| if (url.includes("/capabilities")) { | ||
| return manifestResponse([USDC_RAIL]); | ||
| } | ||
| return settleResponse(settleOverrides); | ||
| }); | ||
| } | ||
| it("accepts a valid facilitator settlement", async () => { | ||
| vi.stubGlobal("fetch", mockSettleFetch()); | ||
| const result = await handlePaywall({ merchantId: "m_ok" }, { priceCents: 100 }, RESOURCE, makePaymentHeader()); | ||
| expect(result.paid).toBe(true); | ||
| expect(result.receipt?.txHash).toBe("0xtxhash"); | ||
| }); | ||
| it("rejects a success response without a transaction hash", async () => { | ||
| vi.stubGlobal("fetch", mockSettleFetch({ transaction: "" })); | ||
| const result = await handlePaywall({ merchantId: "m_ok" }, { priceCents: 100 }, RESOURCE, makePaymentHeader()); | ||
| expect(result.paid).toBe(false); | ||
| expect(result.error?.body.code).toBe("INVALID_SETTLEMENT"); | ||
| }); | ||
| it("rejects a success response with a mismatched payer", async () => { | ||
| vi.stubGlobal("fetch", mockSettleFetch({ payer: "0x9999999999999999999999999999999999999999" })); | ||
| const result = await handlePaywall({ merchantId: "m_ok" }, { priceCents: 100 }, RESOURCE, makePaymentHeader()); | ||
| expect(result.paid).toBe(false); | ||
| expect(result.error?.body.code).toBe("INVALID_SETTLEMENT"); | ||
| }); | ||
| }); | ||
| // ── Self-settle (seller-submitted settlement) ──────── | ||
| // | ||
| // Never-sponsor / never-charge: with `selfSettle` configured the SDK | ||
| // verifies via the facilitator (free) and submits the EIP-3009 | ||
| // transferWithAuthorization from the seller's own key — the facilitator's | ||
| // /settle is never called. | ||
| const ethersMocks = vi.hoisted(() => { | ||
| const wait = vi.fn().mockResolvedValue({ status: 1, hash: "0xselftx" }); | ||
| const transferWithAuthorization = vi.fn().mockResolvedValue({ wait, hash: "0xselftx" }); | ||
| return { | ||
| wait, | ||
| transferWithAuthorization, | ||
| JsonRpcProvider: vi.fn(), | ||
| Wallet: vi.fn(), | ||
| Contract: vi.fn().mockImplementation(() => ({ transferWithAuthorization })), | ||
| Signature: { from: vi.fn().mockReturnValue({ v: 27, r: "0xr", s: "0xs" }) }, | ||
| }; | ||
| }); | ||
| vi.mock("ethers", () => ({ | ||
| JsonRpcProvider: ethersMocks.JsonRpcProvider, | ||
| Wallet: ethersMocks.Wallet, | ||
| Contract: ethersMocks.Contract, | ||
| Signature: ethersMocks.Signature, | ||
| })); | ||
| const SELF_SETTLE = { privateKey: `0x${"11".repeat(32)}` }; | ||
| function mockVerifyFetch(verdict) { | ||
| return vi.fn().mockImplementation((url) => { | ||
| if (url.includes("/capabilities")) | ||
| return manifestResponse([USDC_RAIL]); | ||
| if (url.includes("/verify")) { | ||
| return { ok: true, status: 200, json: async () => verdict }; | ||
| } | ||
| throw new Error(`unexpected fetch in self-settle mode: ${url}`); | ||
| }); | ||
| } | ||
| describe("handlePaywall self-settle", () => { | ||
| afterEach(() => { | ||
| vi.unstubAllGlobals(); | ||
| vi.clearAllMocks(); | ||
| }); | ||
| it("verifies via facilitator, submits from the seller's key, never calls /settle", async () => { | ||
| const fetchMock = mockVerifyFetch({ isValid: true }); | ||
| vi.stubGlobal("fetch", fetchMock); | ||
| const result = await handlePaywall({ merchantId: "m_self", selfSettle: SELF_SETTLE }, { priceCents: 100 }, RESOURCE, makePaymentHeader()); | ||
| expect(result.paid).toBe(true); | ||
| expect(result.receipt?.txHash).toBe("0xselftx"); | ||
| expect(result.settlement?.payer).toBe(PAYER); | ||
| expect(ethersMocks.transferWithAuthorization).toHaveBeenCalledWith(PAYER, PAYEE, "10000", "0", "9999999999", "0xabcd", 27, "0xr", "0xs"); | ||
| const urls = fetchMock.mock.calls.map((c) => String(c[0])); | ||
| expect(urls.some((u) => u.includes("/settle"))).toBe(false); | ||
| }); | ||
| it("returns 402 without submitting when facilitator verification fails", async () => { | ||
| vi.stubGlobal("fetch", mockVerifyFetch({ isValid: false, invalidReason: "invalid_signature" })); | ||
| const result = await handlePaywall({ merchantId: "m_self", selfSettle: SELF_SETTLE }, { priceCents: 100 }, RESOURCE, makePaymentHeader()); | ||
| expect(result.paid).toBe(false); | ||
| expect(result.error?.statusCode).toBe(402); | ||
| expect(result.error?.body.code).toBe("invalid_signature"); | ||
| expect(ethersMocks.transferWithAuthorization).not.toHaveBeenCalled(); | ||
| }); | ||
| it("fails clearly on an unknown network with no rpcUrl override", async () => { | ||
| vi.stubGlobal("fetch", vi.fn().mockImplementation((url) => { | ||
| if (url.includes("/capabilities")) | ||
| return manifestResponse([{ ...USDC_RAIL, network: "eip155:1" }]); | ||
| if (url.includes("/verify")) | ||
| return { ok: true, status: 200, json: async () => ({ isValid: true }) }; | ||
| throw new Error(`unexpected fetch: ${url}`); | ||
| })); | ||
| const result = await handlePaywall({ merchantId: "m_self_unknown_net", selfSettle: SELF_SETTLE }, { priceCents: 100 }, RESOURCE, makePaymentHeader()); | ||
| expect(result.paid).toBe(false); | ||
| expect(result.error?.body.code).toBe("SELF_SETTLE_CONFIG"); | ||
| expect(result.error?.body.error).toContain("set selfSettle.rpcUrl"); | ||
| }); | ||
| }); | ||
| //# sourceMappingURL=core.test.js.map |
| {"version":3,"file":"core.test.js","sourceRoot":"","sources":["../src/core.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAelD,MAAM,UAAU,GAAsB;IACpC,MAAM,EAAE,OAAO;IACf,OAAO,EAAE,aAAa;IACtB,MAAM,EAAE,OAAO;IACf,QAAQ,EAAE,mCAAmC;IAC7C,KAAK,EAAE,4CAA4C;IACnD,KAAK,EAAE,4CAA4C;IACnD,KAAK,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE;CAC1C,CAAC;AAEF,MAAM,QAAQ,GAAG;IACf,KAAK,EAAE,kBAAkB;IACzB,WAAW,EAAE,CAAC;IACd,OAAO,EAAE,CAAC,UAAU,CAAC;IACrB,WAAW,EAAE,iCAAiC;IAC9C,YAAY,EAAE,IAAI;CACnB,CAAC;AAEF,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,OAAO,GAAG,qBAAqB,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;QAC9D,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACpF,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yEAAyE,EAAE,GAAG,EAAE;QACjF,MAAM,OAAO,GAAG,qBAAqB,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;QAC9D,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YAC5D,WAAW,EAAE,CAAC;YACd,OAAO,EAAE,CAAC,UAAU,CAAC;SACtB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,OAAO,GAAG,qBAAqB,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;QAC9D,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,OAAO,GAAG,qBAAqB,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;QAC9D,MAAM,MAAM,GAAG,OAAO,CAAC,+BAA+B,CAAC,CAAC;QACxD,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC;QAC7C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,iBAAiB,GAAwB;YAC7C;gBACE,GAAG,UAAU;gBACb,KAAK,EAAE,EAAE,GAAG,UAAU,CAAC,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE;aACnD;SACF,CAAC;QACF,MAAM,cAAc,GAAG,EAAE,GAAG,QAAQ,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC;QACnE,MAAM,OAAO,GAAG,qBAAqB,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAC;QAEzE,4EAA4E;QAC5E,MAAM,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC3D,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAE3E,gEAAgE;QAChE,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACpF,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,OAAO,GAAG,qBAAqB,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;QAC9D,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,wDAAwD;AACxD,EAAE;AACF,wEAAwE;AACxE,2EAA2E;AAC3E,yEAAyE;AACzE,kDAAkD;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,MAAM,GAAG,4CAA4C,CAAC;AAC5D,MAAM,QAAQ,GAAG,uCAAuC,CAAC;AAEzD,KAAK,UAAU,YAAY,CAAC,MAA+B,EAAE,UAAU,GAAG,GAAG;IAC3E,MAAM,MAAM,GAAG,MAAM,aAAa,CAChC,MAA6C,EAC7C,EAAE,UAAU,EAAE,EACd,QAAQ,EACR,SAAS,CACV,CAAC;IACF,IAAI,MAAM,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IAC/F,OAAO,MAAM,CAAC,SAAU,CAAC;AAC3B,CAAC;AAED,QAAQ,CAAC,8BAA8B,EAAE,GAAG,EAAE;IAC5C,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;QAC/E,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QAC3F,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC;QAC1C,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;QACxE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;QAC7D,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC;YACnC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,cAAc;YACvB,QAAQ,EAAE,KAAK;SAChB,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC;QAC1C,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;QACxE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,KAAK,IAAI,EAAE;QAClF,MAAM,SAAS,GAAG,MAAM,YAAY,CAClC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,EACpD,GAAG,CACJ,CAAC;QACF,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;QACxE,MAAM,MAAM,GAAG,MAAM,aAAa,CAChC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,EACvD,EAAE,UAAU,EAAE,GAAG,EAAE,EACnB,QAAQ,EACR,SAAS,CACV,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC;YACnC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,SAAS;YAClB,QAAQ,EAAE,KAAK;YACf,KAAK,EAAE,4CAA4C;SACpD,CAAC,CAAC;QACH,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;IAC9F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;QAC9E,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QAC1E,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC;QAC1C,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;QACxE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,wDAAwD;AACxD,EAAE;AACF,sEAAsE;AACtE,0EAA0E;AAC1E,mEAAmE;AACnE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAEvC,SAAS,gBAAgB,CAAC,KAAqC;IAC7D,OAAO;QACL,EAAE,EAAE,IAAI;QACR,MAAM,EAAE,GAAG;QACX,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;YACjB,OAAO,EAAE,GAAG;YACZ,QAAQ,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE;YACjD,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;YACzB,KAAK;YACL,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SAClC,CAAC;KACS,CAAC;AAChB,CAAC;AAED,MAAM,SAAS,GAAG;IAChB,MAAM,EAAE,MAAM;IACd,OAAO,EAAE,aAAa;IACtB,KAAK,EAAE,4CAA4C;IACnD,SAAS,EAAE,MAAM;IACjB,KAAK,EAAE,MAAM;IACb,WAAW,EAAE,iCAAiC;CAC/C,CAAC;AACF,MAAM,SAAS,GAAG;IAChB,GAAG,SAAS;IACZ,KAAK,EAAE,4CAA4C;IACnD,SAAS,EAAE,MAAM;CAClB,CAAC;AAEF,QAAQ,CAAC,kCAAkC,EAAE,GAAG,EAAE;IAChD,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,gBAAgB,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,EAAE,CAAC,UAAU,CACX,OAAO,EACP,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,CACpE,CAAC;QACF,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QACpF,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC;QAC1C,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC3C,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,KAAK,IAAI,EAAE;QAC1F,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;QACjF,MAAM,MAAM,GAAG,MAAM,aAAa,CAChC,EAAE,UAAU,EAAE,eAAe,EAAE,QAAQ,EAAE,KAAK,EAAE,EAChD,EAAE,UAAU,EAAE,GAAG,EAAE,EACnB,QAAQ,EACR,SAAS,CACV,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,2BAA2B,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2EAA2E,EAAE,KAAK,IAAI,EAAE;QACzF,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;QACjF,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,EAAE,UAAU,EAAE,gBAAgB,EAAE,CAAC,CAAC;QACvE,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,wDAAwD;AAExD,MAAM,KAAK,GAAG,4CAA4C,CAAC;AAC3D,MAAM,KAAK,GAAG,4CAA4C,CAAC;AAE3D,SAAS,iBAAiB,CAAC,QAAgB,KAAK;IAC9C,MAAM,OAAO,GAAG;QACd,WAAW,EAAE,CAAC;QACd,MAAM,EAAE,OAAO;QACf,OAAO,EAAE,aAAa;QACtB,OAAO,EAAE;YACP,SAAS,EAAE,OAAO;YAClB,aAAa,EAAE;gBACb,IAAI,EAAE,KAAK;gBACX,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE,OAAO;gBACd,UAAU,EAAE,GAAG;gBACf,WAAW,EAAE,YAAY;gBACzB,KAAK,EAAE,QAAQ;aAChB;SACF;KACF,CAAC;IACF,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACzE,CAAC;AAED,SAAS,cAAc,CAAC,YAAqC,EAAE;IAC7D,OAAO;QACL,EAAE,EAAE,IAAI;QACR,MAAM,EAAE,GAAG;QACX,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;YACjB,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,UAAU;YACvB,KAAK,EAAE,KAAK;YACZ,GAAG,SAAS;SACb,CAAC;KACS,CAAC;AAChB,CAAC;AAED,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,gBAAgB,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,KAAK,IAAI,EAAE;QAClF,EAAE,CAAC,UAAU,CACX,OAAO,EACP,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CACvB,gBAAgB,CAAC,CAAC,EAAE,GAAG,SAAS,EAAE,WAAW,EAAE,6BAA6B,EAAE,CAAC,CAAC,CACjF,CACF,CAAC;QACF,MAAM,MAAM,GAAG,MAAM,aAAa,CAChC,EAAE,UAAU,EAAE,mBAAmB,EAAE,EACnC,EAAE,UAAU,EAAE,GAAG,EAAE,EACnB,QAAQ,EACR,iBAAiB,EAAE,CACpB,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,SAAS,eAAe,CAAC,kBAA2C,EAAE;QACpE,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC,GAAW,EAAE,EAAE;YAChD,IAAI,GAAG,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;gBAClC,OAAO,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;YACvC,CAAC;YACD,OAAO,cAAc,CAAC,eAAe,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC;IAED,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACtD,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,eAAe,EAAE,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,MAAM,aAAa,CAChC,EAAE,UAAU,EAAE,MAAM,EAAE,EACtB,EAAE,UAAU,EAAE,GAAG,EAAE,EACnB,QAAQ,EACR,iBAAiB,EAAE,CACpB,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,eAAe,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;QAC7D,MAAM,MAAM,GAAG,MAAM,aAAa,CAChC,EAAE,UAAU,EAAE,MAAM,EAAE,EACtB,EAAE,UAAU,EAAE,GAAG,EAAE,EACnB,QAAQ,EACR,iBAAiB,EAAE,CACpB,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAClE,EAAE,CAAC,UAAU,CACX,OAAO,EACP,eAAe,CAAC,EAAE,KAAK,EAAE,4CAA4C,EAAE,CAAC,CACzE,CAAC;QACF,MAAM,MAAM,GAAG,MAAM,aAAa,CAChC,EAAE,UAAU,EAAE,MAAM,EAAE,EACtB,EAAE,UAAU,EAAE,GAAG,EAAE,EACnB,QAAQ,EACR,iBAAiB,EAAE,CACpB,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,wDAAwD;AACxD,EAAE;AACF,qEAAqE;AACrE,+DAA+D;AAC/D,0EAA0E;AAC1E,2BAA2B;AAE3B,MAAM,WAAW,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;IAClC,MAAM,IAAI,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;IACxE,MAAM,yBAAyB,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;IACxF,OAAO;QACL,IAAI;QACJ,yBAAyB;QACzB,eAAe,EAAE,EAAE,CAAC,EAAE,EAAE;QACxB,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE;QACf,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,yBAAyB,EAAE,CAAC,CAAC;QAC3E,SAAS,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;KAC5E,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;IACvB,eAAe,EAAE,WAAW,CAAC,eAAe;IAC5C,MAAM,EAAE,WAAW,CAAC,MAAM;IAC1B,QAAQ,EAAE,WAAW,CAAC,QAAQ;IAC9B,SAAS,EAAE,WAAW,CAAC,SAAS;CACjC,CAAC,CAAC,CAAC;AAEJ,MAAM,WAAW,GAAG,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;AAE3D,SAAS,eAAe,CAAC,OAAqD;IAC5E,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC,GAAW,EAAE,EAAE;QAChD,IAAI,GAAG,CAAC,QAAQ,CAAC,eAAe,CAAC;YAAE,OAAO,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;QACxE,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YAC5B,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,OAAO,EAAc,CAAC;QAC1E,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,yCAAyC,GAAG,EAAE,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IACzC,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,gBAAgB,EAAE,CAAC;QACtB,EAAE,CAAC,aAAa,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8EAA8E,EAAE,KAAK,IAAI,EAAE;QAC5F,MAAM,SAAS,GAAG,eAAe,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QAClC,MAAM,MAAM,GAAG,MAAM,aAAa,CAChC,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,EACjD,EAAE,UAAU,EAAE,GAAG,EAAE,EACnB,QAAQ,EACR,iBAAiB,EAAE,CACpB,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7C,MAAM,CAAC,WAAW,CAAC,yBAAyB,CAAC,CAAC,oBAAoB,CAChE,KAAK,EACL,KAAK,EACL,OAAO,EACP,GAAG,EACH,YAAY,EACZ,QAAQ,EACR,EAAE,EACF,KAAK,EACL,KAAK,CACN,CAAC;QACF,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAY,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACtE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,KAAK,IAAI,EAAE;QAClF,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,eAAe,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,CAAC,CAAC,CAAC;QAChG,MAAM,MAAM,GAAG,MAAM,aAAa,CAChC,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,EACjD,EAAE,UAAU,EAAE,GAAG,EAAE,EACnB,QAAQ,EACR,iBAAiB,EAAE,CACpB,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3C,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAC1D,MAAM,CAAC,WAAW,CAAC,yBAAyB,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC3E,EAAE,CAAC,UAAU,CACX,OAAO,EACP,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC,GAAW,EAAE,EAAE;YACzC,IAAI,GAAG,CAAC,QAAQ,CAAC,eAAe,CAAC;gBAC/B,OAAO,gBAAgB,CAAC,CAAC,EAAE,GAAG,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC;YACnE,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC;gBACzB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAc,CAAC;YACtF,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;QAC9C,CAAC,CAAC,CACH,CAAC;QACF,MAAM,MAAM,GAAG,MAAM,aAAa,CAChC,EAAE,UAAU,EAAE,oBAAoB,EAAE,UAAU,EAAE,WAAW,EAAE,EAC7D,EAAE,UAAU,EAAE,GAAG,EAAE,EACnB,QAAQ,EACR,iBAAiB,EAAE,CACpB,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAC3D,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} |
| export {}; | ||
| //# sourceMappingURL=ghost-partner.test.d.ts.map |
| {"version":3,"file":"ghost-partner.test.d.ts","sourceRoot":"","sources":["../src/ghost-partner.test.ts"],"names":[],"mappings":""} |
| /** | ||
| * Unit tests for the GhostPayPartner SDK helper. | ||
| */ | ||
| import { createHmac } from "node:crypto"; | ||
| import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; | ||
| import { GhostPayPartner } from "./ghost-partner.js"; | ||
| describe("GhostPayPartner", () => { | ||
| let fetchMock; | ||
| beforeEach(() => { | ||
| fetchMock = vi.fn(); | ||
| vi.stubGlobal("fetch", fetchMock); | ||
| }); | ||
| afterEach(() => { | ||
| vi.unstubAllGlobals(); | ||
| }); | ||
| describe("createPaymentLink", () => { | ||
| it("POSTs to the merchant payment-link endpoint", async () => { | ||
| fetchMock.mockResolvedValue({ | ||
| ok: true, | ||
| json: async () => ({ | ||
| linkId: "link_1", | ||
| token: "tok", | ||
| amountCents: 1000, | ||
| currency: "USD", | ||
| memo: null, | ||
| reference: "ref", | ||
| status: "open", | ||
| expiresAt: null, | ||
| url: "https://arispay.app/ghost/pay/tok", | ||
| }), | ||
| }); | ||
| const partner = new GhostPayPartner({ apiKey: "mp_live_test" }); | ||
| const link = await partner.createPaymentLink({ | ||
| amountCents: 1000, | ||
| reference: "ref", | ||
| }); | ||
| expect(link.url).toBe("https://arispay.app/ghost/pay/tok"); | ||
| expect(fetchMock).toHaveBeenCalledWith("https://api.arispay.app/v1/merchants/me/ghost/payment-links", expect.objectContaining({ | ||
| method: "POST", | ||
| headers: expect.objectContaining({ | ||
| Authorization: "Bearer mp_live_test", | ||
| "Content-Type": "application/json", | ||
| }), | ||
| })); | ||
| }); | ||
| it("throws on API error", async () => { | ||
| fetchMock.mockResolvedValue({ | ||
| ok: false, | ||
| status: 400, | ||
| json: async () => ({ error: { code: "INVALID_REQUEST", message: "bad" } }), | ||
| }); | ||
| const partner = new GhostPayPartner({ apiKey: "mp_live_test" }); | ||
| await expect(partner.createPaymentLink({ amountCents: -1 })).rejects.toThrow("INVALID_REQUEST: bad"); | ||
| }); | ||
| }); | ||
| describe("verifyWebhook", () => { | ||
| it("returns the payload when the signature is valid", () => { | ||
| const secret = "super-secret-webhook-key"; | ||
| const partner = new GhostPayPartner({ apiKey: "mp_live_test", webhookSecret: secret }); | ||
| const payload = { | ||
| type: "ghost.payment.succeeded", | ||
| data: { | ||
| paymentId: "gp_1", | ||
| merchantReference: "ref-1", | ||
| amountCents: 1000, | ||
| currency: "USD", | ||
| feeCents: 15, | ||
| settlementProvider: "usdc", | ||
| settlementTxRef: "0xabc", | ||
| reference: "order-123", | ||
| settledAt: "2026-06-17T00:00:00.000Z", | ||
| }, | ||
| }; | ||
| const body = JSON.stringify(payload); | ||
| const timestamp = Math.floor(Date.now() / 1000); | ||
| const signature = createHmac("sha256", secret) | ||
| .update(`${timestamp}.${body}`) | ||
| .digest("hex"); | ||
| const result = partner.verifyWebhook(signature, String(timestamp), body); | ||
| expect(result.type).toBe("ghost.payment.succeeded"); | ||
| expect(result.data.paymentId).toBe("gp_1"); | ||
| }); | ||
| it("throws when the signature is invalid", () => { | ||
| const partner = new GhostPayPartner({ | ||
| apiKey: "mp_live_test", | ||
| webhookSecret: "secret", | ||
| }); | ||
| const ts = String(Math.floor(Date.now() / 1000)); | ||
| expect(() => partner.verifyWebhook("bad", ts, "{}")).toThrow("Invalid Ghost webhook signature"); | ||
| }); | ||
| it("throws when the timestamp is too old", () => { | ||
| const partner = new GhostPayPartner({ | ||
| apiKey: "mp_live_test", | ||
| webhookSecret: "secret", | ||
| }); | ||
| const oldTs = String(Math.floor(Date.now() / 1000) - 400); | ||
| expect(() => partner.verifyWebhook("a".repeat(64), oldTs, "{}")).toThrow("too old"); | ||
| }); | ||
| }); | ||
| }); | ||
| //# sourceMappingURL=ghost-partner.test.js.map |
| {"version":3,"file":"ghost-partner.test.js","sourceRoot":"","sources":["../src/ghost-partner.test.ts"],"names":[],"mappings":"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"} |
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
178057
51.85%35
16.67%2451
64.83%250
48.81%4
300%