yeetful 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/next.js ADDED
@@ -0,0 +1,192 @@
1
+ // src/facilitator.ts
2
+ var Facilitator = class {
3
+ url;
4
+ authHeader;
5
+ fetcher;
6
+ constructor(config) {
7
+ this.url = config.url.replace(/\/$/, "");
8
+ this.authHeader = config.authHeader;
9
+ this.fetcher = config.fetch ?? globalThis.fetch.bind(globalThis);
10
+ }
11
+ async verify(payment, requirement) {
12
+ return this.post("/verify", { paymentPayload: payment, paymentRequirements: requirement });
13
+ }
14
+ async settle(payment, requirement) {
15
+ return this.post("/settle", { paymentPayload: payment, paymentRequirements: requirement });
16
+ }
17
+ async post(path, body) {
18
+ const res = await this.fetcher(this.url + path, {
19
+ method: "POST",
20
+ headers: {
21
+ "content-type": "application/json",
22
+ ...this.authHeader ? { authorization: this.authHeader } : {}
23
+ },
24
+ body: JSON.stringify(body)
25
+ });
26
+ if (!res.ok) {
27
+ const text = await res.text().catch(() => "");
28
+ throw new Error(`Facilitator ${path} failed: ${res.status} ${text}`);
29
+ }
30
+ return await res.json();
31
+ }
32
+ };
33
+ var DEFAULT_FACILITATOR_URL = "https://facilitator.yeetful.com";
34
+
35
+ // src/utils.ts
36
+ var USDC_BY_NETWORK = {
37
+ base: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
38
+ "base-sepolia": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
39
+ ethereum: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
40
+ optimism: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
41
+ arbitrum: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
42
+ polygon: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359"
43
+ };
44
+ var USDC_DECIMALS = 6;
45
+ function usdcAddress(network) {
46
+ return USDC_BY_NETWORK[network];
47
+ }
48
+ function usdToAtomic(amount, decimals = USDC_DECIMALS) {
49
+ const str = typeof amount === "number" ? amount.toString() : amount;
50
+ if (!/^\d+(\.\d+)?$/.test(str)) {
51
+ throw new Error(`Invalid amount: ${str}`);
52
+ }
53
+ const [whole, frac = ""] = str.split(".");
54
+ const padded = frac.slice(0, decimals).padEnd(decimals, "0");
55
+ return (BigInt(whole ?? "0") * 10n ** BigInt(decimals) + BigInt(padded || "0")).toString();
56
+ }
57
+ var utf8Encoder = new TextEncoder();
58
+ var utf8Decoder = new TextDecoder();
59
+ function encodePayment(value) {
60
+ const bytes = utf8Encoder.encode(JSON.stringify(value));
61
+ if (typeof Buffer !== "undefined") {
62
+ return Buffer.from(bytes).toString("base64");
63
+ }
64
+ let binary = "";
65
+ for (const byte of bytes) binary += String.fromCharCode(byte);
66
+ return btoa(binary);
67
+ }
68
+ function decodePayment(b64) {
69
+ let bytes;
70
+ if (typeof Buffer !== "undefined") {
71
+ bytes = new Uint8Array(Buffer.from(b64, "base64"));
72
+ } else {
73
+ const binary = atob(b64);
74
+ bytes = new Uint8Array(binary.length);
75
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
76
+ }
77
+ return JSON.parse(utf8Decoder.decode(bytes));
78
+ }
79
+
80
+ // src/server.ts
81
+ async function gate(request, opts) {
82
+ const requirements = buildRequirements(request, opts);
83
+ const header = request.headers.get("x-payment") ?? request.headers.get("X-PAYMENT");
84
+ if (!header) {
85
+ return { type: "paymentRequired", response: paymentRequiredResponse(requirements) };
86
+ }
87
+ let payment;
88
+ try {
89
+ payment = decodePayment(header);
90
+ } catch {
91
+ return {
92
+ type: "paymentRequired",
93
+ response: paymentRequiredResponse(requirements, "Invalid X-PAYMENT header")
94
+ };
95
+ }
96
+ const matched = requirements.find(
97
+ (r) => r.network === payment.network && r.scheme === payment.scheme
98
+ );
99
+ if (!matched) {
100
+ return {
101
+ type: "paymentRequired",
102
+ response: paymentRequiredResponse(requirements, "Payment does not match any accepted requirement")
103
+ };
104
+ }
105
+ if (opts.facilitator === false) {
106
+ const payer2 = payment.payload.authorization.from;
107
+ return {
108
+ type: "ok",
109
+ payer: payer2,
110
+ settle: async () => ({
111
+ header: encodePayment({ success: true, network: matched.network }),
112
+ result: { success: true }
113
+ })
114
+ };
115
+ }
116
+ const facilitator = new Facilitator(opts.facilitator ?? { url: DEFAULT_FACILITATOR_URL });
117
+ const verified = await facilitator.verify(payment, matched);
118
+ if (!verified.isValid) {
119
+ return {
120
+ type: "paymentRequired",
121
+ response: paymentRequiredResponse(
122
+ requirements,
123
+ verified.invalidReason ?? "Payment verification failed"
124
+ )
125
+ };
126
+ }
127
+ const payer = verified.payer ?? payment.payload.authorization.from;
128
+ return {
129
+ type: "ok",
130
+ payer,
131
+ settle: async () => {
132
+ const result = await facilitator.settle(payment, matched);
133
+ return {
134
+ header: encodePayment({
135
+ success: result.success,
136
+ transaction: result.transaction,
137
+ network: result.network ?? matched.network,
138
+ errorReason: result.errorReason,
139
+ payer
140
+ }),
141
+ result
142
+ };
143
+ }
144
+ };
145
+ }
146
+ function buildRequirements(request, opts) {
147
+ const networks = Array.isArray(opts.network) ? opts.network : [opts.network ?? "base"];
148
+ const atomic = usdToAtomic(opts.price);
149
+ const resource = opts.resource ?? request.url;
150
+ return networks.map((network) => ({
151
+ scheme: "exact",
152
+ network,
153
+ asset: opts.asset ?? usdcAddress(network),
154
+ maxAmountRequired: atomic,
155
+ payTo: opts.recipient,
156
+ description: opts.description,
157
+ resource,
158
+ maxTimeoutSeconds: opts.maxTimeoutSeconds ?? 600,
159
+ extra: { name: "USD Coin", version: "2" }
160
+ }));
161
+ }
162
+ function paymentRequiredResponse(accepts, error) {
163
+ const body = { x402Version: 1, accepts, ...error ? { error } : {} };
164
+ return new Response(JSON.stringify(body), {
165
+ status: 402,
166
+ headers: { "content-type": "application/json" }
167
+ });
168
+ }
169
+
170
+ // src/next.ts
171
+ function withPayment(options, handler) {
172
+ return async function paywalled(request, context) {
173
+ const result = await gate(request, options);
174
+ if (result.type === "paymentRequired") return result.response;
175
+ const response = await handler(request, context);
176
+ try {
177
+ const { header } = await result.settle();
178
+ const merged = new Response(response.body, response);
179
+ merged.headers.set("X-PAYMENT-RESPONSE", header);
180
+ return merged;
181
+ } catch (err) {
182
+ return new Response(
183
+ JSON.stringify({ error: "Payment settlement failed", detail: String(err) }),
184
+ { status: 502, headers: { "content-type": "application/json" } }
185
+ );
186
+ }
187
+ };
188
+ }
189
+
190
+ export { gate, withPayment };
191
+ //# sourceMappingURL=next.js.map
192
+ //# sourceMappingURL=next.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/facilitator.ts","../src/utils.ts","../src/server.ts","../src/next.ts"],"names":["payer"],"mappings":"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","file":"next.js","sourcesContent":["import type {\n FacilitatorConfig,\n PaymentPayload,\n PaymentRequirement,\n SettleResult,\n VerifyResult,\n} from './types.js'\n\n/**\n * Thin wrapper around an x402 facilitator HTTP service.\n * The facilitator verifies signed payment authorizations and settles them on-chain.\n */\nexport class Facilitator {\n private readonly url: string\n private readonly authHeader?: string\n private readonly fetcher: typeof fetch\n\n constructor(config: FacilitatorConfig) {\n this.url = config.url.replace(/\\/$/, '')\n this.authHeader = config.authHeader\n this.fetcher = config.fetch ?? globalThis.fetch.bind(globalThis)\n }\n\n async verify(\n payment: PaymentPayload,\n requirement: PaymentRequirement,\n ): Promise<VerifyResult> {\n return this.post<VerifyResult>('/verify', { paymentPayload: payment, paymentRequirements: requirement })\n }\n\n async settle(\n payment: PaymentPayload,\n requirement: PaymentRequirement,\n ): Promise<SettleResult> {\n return this.post<SettleResult>('/settle', { paymentPayload: payment, paymentRequirements: requirement })\n }\n\n private async post<T>(path: string, body: unknown): Promise<T> {\n const res = await this.fetcher(this.url + path, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...(this.authHeader ? { authorization: this.authHeader } : {}),\n },\n body: JSON.stringify(body),\n })\n if (!res.ok) {\n const text = await res.text().catch(() => '')\n throw new Error(`Facilitator ${path} failed: ${res.status} ${text}`)\n }\n return (await res.json()) as T\n }\n}\n\n/** Default hosted facilitator. Override for self-hosted deployments. */\nexport const DEFAULT_FACILITATOR_URL = 'https://facilitator.yeetful.com'\n","import type { X402Network } from './types.js'\n\nconst USDC_BY_NETWORK: Record<X402Network, `0x${string}`> = {\n base: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n 'base-sepolia': '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n ethereum: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n optimism: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85',\n arbitrum: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',\n polygon: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n}\n\nexport const USDC_DECIMALS = 6\n\n/** Returns the canonical USDC contract address for a supported network. */\nexport function usdcAddress(network: X402Network): `0x${string}` {\n return USDC_BY_NETWORK[network]\n}\n\n/**\n * Convert a human-friendly USD amount (e.g. \"0.01\") into atomic USDC units.\n * Fixed-point to avoid float drift — safer than Number math for payments.\n */\nexport function usdToAtomic(amount: string | number, decimals = USDC_DECIMALS): string {\n const str = typeof amount === 'number' ? amount.toString() : amount\n if (!/^\\d+(\\.\\d+)?$/.test(str)) {\n throw new Error(`Invalid amount: ${str}`)\n }\n const [whole, frac = ''] = str.split('.')\n const padded = frac.slice(0, decimals).padEnd(decimals, '0')\n return (BigInt(whole ?? '0') * 10n ** BigInt(decimals) + BigInt(padded || '0')).toString()\n}\n\nconst utf8Encoder = new TextEncoder()\nconst utf8Decoder = new TextDecoder()\n\n/** Base64 encode a JSON value — works in Node 18+ and browsers. */\nexport function encodePayment(value: unknown): string {\n const bytes = utf8Encoder.encode(JSON.stringify(value))\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(bytes).toString('base64')\n }\n let binary = ''\n for (const byte of bytes) binary += String.fromCharCode(byte)\n return btoa(binary)\n}\n\n/** Base64 decode a payment header value back into JSON. */\nexport function decodePayment<T = unknown>(b64: string): T {\n let bytes: Uint8Array\n if (typeof Buffer !== 'undefined') {\n bytes = new Uint8Array(Buffer.from(b64, 'base64'))\n } else {\n const binary = atob(b64)\n bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i)\n }\n return JSON.parse(utf8Decoder.decode(bytes)) as T\n}\n\n/** Generate a random 32-byte nonce as a 0x-prefixed hex string. */\nexport function randomNonce(): `0x${string}` {\n const bytes = new Uint8Array(32)\n globalThis.crypto.getRandomValues(bytes)\n return ('0x' + Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('')) as `0x${string}`\n}\n","import type { Address } from 'viem'\nimport { Facilitator, DEFAULT_FACILITATOR_URL } from './facilitator.js'\nimport type {\n FacilitatorConfig,\n PaymentPayload,\n PaymentRequirement,\n PaymentRequiredResponse,\n SettleResult,\n X402Network,\n} from './types.js'\nimport { decodePayment, encodePayment, usdcAddress, usdToAtomic } from './utils.js'\n\nexport interface RouteGateOptions {\n /** Price in USD, e.g. \"0.01\". Converted to USDC atomic units. */\n price: string | number\n /** Recipient address that receives the funds. */\n recipient: Address\n /** Network(s) to accept. Defaults to `['base']`. Pass an array for multi-chain. */\n network?: X402Network | X402Network[]\n /** Override the payment asset (defaults to USDC for the given network). */\n asset?: Address\n /** Human-readable description of the resource. */\n description?: string\n /** Seconds the signed authorization is valid. Default: 600. */\n maxTimeoutSeconds?: number\n /** Facilitator config, or `false` to skip verification/settlement (trust-mode). */\n facilitator?: FacilitatorConfig | false\n /**\n * Optional resource identifier (defaults to the request URL). Useful for\n * logging / receipts.\n */\n resource?: string\n}\n\n/**\n * Runtime-agnostic gate: given a Fetch-API `Request`, either returns a 402\n * `Response` or a `{ settle }` handle. After your handler runs, call `settle()`\n * to finalize the payment and get a `X-PAYMENT-RESPONSE` header to attach.\n *\n * This is the building block used by the framework adapters (`./next`, `./express`).\n */\nexport async function gate(\n request: Request,\n opts: RouteGateOptions,\n): Promise<\n | { type: 'paymentRequired'; response: Response }\n | { type: 'ok'; payer: Address; settle: () => Promise<{ header: string; result: SettleResult }> }\n> {\n const requirements = buildRequirements(request, opts)\n\n const header = request.headers.get('x-payment') ?? request.headers.get('X-PAYMENT')\n if (!header) {\n return { type: 'paymentRequired', response: paymentRequiredResponse(requirements) }\n }\n\n let payment: PaymentPayload\n try {\n payment = decodePayment<PaymentPayload>(header)\n } catch {\n return {\n type: 'paymentRequired',\n response: paymentRequiredResponse(requirements, 'Invalid X-PAYMENT header'),\n }\n }\n\n const matched = requirements.find(\n (r) => r.network === payment.network && r.scheme === payment.scheme,\n )\n if (!matched) {\n return {\n type: 'paymentRequired',\n response: paymentRequiredResponse(requirements, 'Payment does not match any accepted requirement'),\n }\n }\n\n if (opts.facilitator === false) {\n const payer = payment.payload.authorization.from as Address\n return {\n type: 'ok',\n payer,\n settle: async () => ({\n header: encodePayment({ success: true, network: matched.network }),\n result: { success: true },\n }),\n }\n }\n\n const facilitator = new Facilitator(opts.facilitator ?? { url: DEFAULT_FACILITATOR_URL })\n const verified = await facilitator.verify(payment, matched)\n if (!verified.isValid) {\n return {\n type: 'paymentRequired',\n response: paymentRequiredResponse(\n requirements,\n verified.invalidReason ?? 'Payment verification failed',\n ),\n }\n }\n\n const payer = (verified.payer ?? payment.payload.authorization.from) as Address\n\n return {\n type: 'ok',\n payer,\n settle: async () => {\n const result = await facilitator.settle(payment, matched)\n return {\n header: encodePayment({\n success: result.success,\n transaction: result.transaction,\n network: result.network ?? matched.network,\n errorReason: result.errorReason,\n payer,\n }),\n result,\n }\n },\n }\n}\n\nfunction buildRequirements(request: Request, opts: RouteGateOptions): PaymentRequirement[] {\n const networks = Array.isArray(opts.network) ? opts.network : [opts.network ?? 'base']\n const atomic = usdToAtomic(opts.price)\n const resource = opts.resource ?? request.url\n\n return networks.map((network) => ({\n scheme: 'exact',\n network,\n asset: opts.asset ?? usdcAddress(network),\n maxAmountRequired: atomic,\n payTo: opts.recipient,\n description: opts.description,\n resource,\n maxTimeoutSeconds: opts.maxTimeoutSeconds ?? 600,\n extra: { name: 'USD Coin', version: '2' },\n }))\n}\n\nfunction paymentRequiredResponse(\n accepts: PaymentRequirement[],\n error?: string,\n): Response {\n const body: PaymentRequiredResponse = { x402Version: 1, accepts, ...(error ? { error } : {}) }\n return new Response(JSON.stringify(body), {\n status: 402,\n headers: { 'content-type': 'application/json' },\n })\n}\n\nexport { Facilitator, DEFAULT_FACILITATOR_URL } from './facilitator.js'\n","import { gate, type RouteGateOptions } from './server.js'\n\nexport type NextRouteHandler = (\n request: Request,\n context?: unknown,\n) => Promise<Response> | Response\n\n/**\n * Wrap a Next.js App Router route handler with an x402 paywall.\n *\n * @example\n * ```ts\n * // app/api/premium/route.ts\n * import { withPayment } from 'yeetful/next'\n *\n * export const GET = withPayment(\n * { price: '0.01', recipient: '0xYourAddress', network: 'base' },\n * async () => Response.json({ secret: 'gm' })\n * )\n * ```\n */\nexport function withPayment(\n options: RouteGateOptions,\n handler: NextRouteHandler,\n): NextRouteHandler {\n return async function paywalled(request, context) {\n const result = await gate(request, options)\n if (result.type === 'paymentRequired') return result.response\n\n const response = await handler(request, context)\n\n try {\n const { header } = await result.settle()\n const merged = new Response(response.body, response)\n merged.headers.set('X-PAYMENT-RESPONSE', header)\n return merged\n } catch (err) {\n return new Response(\n JSON.stringify({ error: 'Payment settlement failed', detail: String(err) }),\n { status: 502, headers: { 'content-type': 'application/json' } },\n )\n }\n }\n}\n\nexport { gate } from './server.js'\nexport type { RouteGateOptions } from './server.js'\n"]}
@@ -0,0 +1,176 @@
1
+ 'use strict';
2
+
3
+ // src/facilitator.ts
4
+ var Facilitator = class {
5
+ url;
6
+ authHeader;
7
+ fetcher;
8
+ constructor(config) {
9
+ this.url = config.url.replace(/\/$/, "");
10
+ this.authHeader = config.authHeader;
11
+ this.fetcher = config.fetch ?? globalThis.fetch.bind(globalThis);
12
+ }
13
+ async verify(payment, requirement) {
14
+ return this.post("/verify", { paymentPayload: payment, paymentRequirements: requirement });
15
+ }
16
+ async settle(payment, requirement) {
17
+ return this.post("/settle", { paymentPayload: payment, paymentRequirements: requirement });
18
+ }
19
+ async post(path, body) {
20
+ const res = await this.fetcher(this.url + path, {
21
+ method: "POST",
22
+ headers: {
23
+ "content-type": "application/json",
24
+ ...this.authHeader ? { authorization: this.authHeader } : {}
25
+ },
26
+ body: JSON.stringify(body)
27
+ });
28
+ if (!res.ok) {
29
+ const text = await res.text().catch(() => "");
30
+ throw new Error(`Facilitator ${path} failed: ${res.status} ${text}`);
31
+ }
32
+ return await res.json();
33
+ }
34
+ };
35
+ var DEFAULT_FACILITATOR_URL = "https://facilitator.yeetful.com";
36
+
37
+ // src/utils.ts
38
+ var USDC_BY_NETWORK = {
39
+ base: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
40
+ "base-sepolia": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
41
+ ethereum: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
42
+ optimism: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
43
+ arbitrum: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
44
+ polygon: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359"
45
+ };
46
+ var USDC_DECIMALS = 6;
47
+ function usdcAddress(network) {
48
+ return USDC_BY_NETWORK[network];
49
+ }
50
+ function usdToAtomic(amount, decimals = USDC_DECIMALS) {
51
+ const str = typeof amount === "number" ? amount.toString() : amount;
52
+ if (!/^\d+(\.\d+)?$/.test(str)) {
53
+ throw new Error(`Invalid amount: ${str}`);
54
+ }
55
+ const [whole, frac = ""] = str.split(".");
56
+ const padded = frac.slice(0, decimals).padEnd(decimals, "0");
57
+ return (BigInt(whole ?? "0") * 10n ** BigInt(decimals) + BigInt(padded || "0")).toString();
58
+ }
59
+ var utf8Encoder = new TextEncoder();
60
+ var utf8Decoder = new TextDecoder();
61
+ function encodePayment(value) {
62
+ const bytes = utf8Encoder.encode(JSON.stringify(value));
63
+ if (typeof Buffer !== "undefined") {
64
+ return Buffer.from(bytes).toString("base64");
65
+ }
66
+ let binary = "";
67
+ for (const byte of bytes) binary += String.fromCharCode(byte);
68
+ return btoa(binary);
69
+ }
70
+ function decodePayment(b64) {
71
+ let bytes;
72
+ if (typeof Buffer !== "undefined") {
73
+ bytes = new Uint8Array(Buffer.from(b64, "base64"));
74
+ } else {
75
+ const binary = atob(b64);
76
+ bytes = new Uint8Array(binary.length);
77
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
78
+ }
79
+ return JSON.parse(utf8Decoder.decode(bytes));
80
+ }
81
+
82
+ // src/server.ts
83
+ async function gate(request, opts) {
84
+ const requirements = buildRequirements(request, opts);
85
+ const header = request.headers.get("x-payment") ?? request.headers.get("X-PAYMENT");
86
+ if (!header) {
87
+ return { type: "paymentRequired", response: paymentRequiredResponse(requirements) };
88
+ }
89
+ let payment;
90
+ try {
91
+ payment = decodePayment(header);
92
+ } catch {
93
+ return {
94
+ type: "paymentRequired",
95
+ response: paymentRequiredResponse(requirements, "Invalid X-PAYMENT header")
96
+ };
97
+ }
98
+ const matched = requirements.find(
99
+ (r) => r.network === payment.network && r.scheme === payment.scheme
100
+ );
101
+ if (!matched) {
102
+ return {
103
+ type: "paymentRequired",
104
+ response: paymentRequiredResponse(requirements, "Payment does not match any accepted requirement")
105
+ };
106
+ }
107
+ if (opts.facilitator === false) {
108
+ const payer2 = payment.payload.authorization.from;
109
+ return {
110
+ type: "ok",
111
+ payer: payer2,
112
+ settle: async () => ({
113
+ header: encodePayment({ success: true, network: matched.network }),
114
+ result: { success: true }
115
+ })
116
+ };
117
+ }
118
+ const facilitator = new Facilitator(opts.facilitator ?? { url: DEFAULT_FACILITATOR_URL });
119
+ const verified = await facilitator.verify(payment, matched);
120
+ if (!verified.isValid) {
121
+ return {
122
+ type: "paymentRequired",
123
+ response: paymentRequiredResponse(
124
+ requirements,
125
+ verified.invalidReason ?? "Payment verification failed"
126
+ )
127
+ };
128
+ }
129
+ const payer = verified.payer ?? payment.payload.authorization.from;
130
+ return {
131
+ type: "ok",
132
+ payer,
133
+ settle: async () => {
134
+ const result = await facilitator.settle(payment, matched);
135
+ return {
136
+ header: encodePayment({
137
+ success: result.success,
138
+ transaction: result.transaction,
139
+ network: result.network ?? matched.network,
140
+ errorReason: result.errorReason,
141
+ payer
142
+ }),
143
+ result
144
+ };
145
+ }
146
+ };
147
+ }
148
+ function buildRequirements(request, opts) {
149
+ const networks = Array.isArray(opts.network) ? opts.network : [opts.network ?? "base"];
150
+ const atomic = usdToAtomic(opts.price);
151
+ const resource = opts.resource ?? request.url;
152
+ return networks.map((network) => ({
153
+ scheme: "exact",
154
+ network,
155
+ asset: opts.asset ?? usdcAddress(network),
156
+ maxAmountRequired: atomic,
157
+ payTo: opts.recipient,
158
+ description: opts.description,
159
+ resource,
160
+ maxTimeoutSeconds: opts.maxTimeoutSeconds ?? 600,
161
+ extra: { name: "USD Coin", version: "2" }
162
+ }));
163
+ }
164
+ function paymentRequiredResponse(accepts, error) {
165
+ const body = { x402Version: 1, accepts, ...error ? { error } : {} };
166
+ return new Response(JSON.stringify(body), {
167
+ status: 402,
168
+ headers: { "content-type": "application/json" }
169
+ });
170
+ }
171
+
172
+ exports.DEFAULT_FACILITATOR_URL = DEFAULT_FACILITATOR_URL;
173
+ exports.Facilitator = Facilitator;
174
+ exports.gate = gate;
175
+ //# sourceMappingURL=server.cjs.map
176
+ //# sourceMappingURL=server.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/facilitator.ts","../src/utils.ts","../src/server.ts"],"names":["payer"],"mappings":"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","file":"server.cjs","sourcesContent":["import type {\n FacilitatorConfig,\n PaymentPayload,\n PaymentRequirement,\n SettleResult,\n VerifyResult,\n} from './types.js'\n\n/**\n * Thin wrapper around an x402 facilitator HTTP service.\n * The facilitator verifies signed payment authorizations and settles them on-chain.\n */\nexport class Facilitator {\n private readonly url: string\n private readonly authHeader?: string\n private readonly fetcher: typeof fetch\n\n constructor(config: FacilitatorConfig) {\n this.url = config.url.replace(/\\/$/, '')\n this.authHeader = config.authHeader\n this.fetcher = config.fetch ?? globalThis.fetch.bind(globalThis)\n }\n\n async verify(\n payment: PaymentPayload,\n requirement: PaymentRequirement,\n ): Promise<VerifyResult> {\n return this.post<VerifyResult>('/verify', { paymentPayload: payment, paymentRequirements: requirement })\n }\n\n async settle(\n payment: PaymentPayload,\n requirement: PaymentRequirement,\n ): Promise<SettleResult> {\n return this.post<SettleResult>('/settle', { paymentPayload: payment, paymentRequirements: requirement })\n }\n\n private async post<T>(path: string, body: unknown): Promise<T> {\n const res = await this.fetcher(this.url + path, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...(this.authHeader ? { authorization: this.authHeader } : {}),\n },\n body: JSON.stringify(body),\n })\n if (!res.ok) {\n const text = await res.text().catch(() => '')\n throw new Error(`Facilitator ${path} failed: ${res.status} ${text}`)\n }\n return (await res.json()) as T\n }\n}\n\n/** Default hosted facilitator. Override for self-hosted deployments. */\nexport const DEFAULT_FACILITATOR_URL = 'https://facilitator.yeetful.com'\n","import type { X402Network } from './types.js'\n\nconst USDC_BY_NETWORK: Record<X402Network, `0x${string}`> = {\n base: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n 'base-sepolia': '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n ethereum: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n optimism: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85',\n arbitrum: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',\n polygon: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n}\n\nexport const USDC_DECIMALS = 6\n\n/** Returns the canonical USDC contract address for a supported network. */\nexport function usdcAddress(network: X402Network): `0x${string}` {\n return USDC_BY_NETWORK[network]\n}\n\n/**\n * Convert a human-friendly USD amount (e.g. \"0.01\") into atomic USDC units.\n * Fixed-point to avoid float drift — safer than Number math for payments.\n */\nexport function usdToAtomic(amount: string | number, decimals = USDC_DECIMALS): string {\n const str = typeof amount === 'number' ? amount.toString() : amount\n if (!/^\\d+(\\.\\d+)?$/.test(str)) {\n throw new Error(`Invalid amount: ${str}`)\n }\n const [whole, frac = ''] = str.split('.')\n const padded = frac.slice(0, decimals).padEnd(decimals, '0')\n return (BigInt(whole ?? '0') * 10n ** BigInt(decimals) + BigInt(padded || '0')).toString()\n}\n\nconst utf8Encoder = new TextEncoder()\nconst utf8Decoder = new TextDecoder()\n\n/** Base64 encode a JSON value — works in Node 18+ and browsers. */\nexport function encodePayment(value: unknown): string {\n const bytes = utf8Encoder.encode(JSON.stringify(value))\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(bytes).toString('base64')\n }\n let binary = ''\n for (const byte of bytes) binary += String.fromCharCode(byte)\n return btoa(binary)\n}\n\n/** Base64 decode a payment header value back into JSON. */\nexport function decodePayment<T = unknown>(b64: string): T {\n let bytes: Uint8Array\n if (typeof Buffer !== 'undefined') {\n bytes = new Uint8Array(Buffer.from(b64, 'base64'))\n } else {\n const binary = atob(b64)\n bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i)\n }\n return JSON.parse(utf8Decoder.decode(bytes)) as T\n}\n\n/** Generate a random 32-byte nonce as a 0x-prefixed hex string. */\nexport function randomNonce(): `0x${string}` {\n const bytes = new Uint8Array(32)\n globalThis.crypto.getRandomValues(bytes)\n return ('0x' + Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('')) as `0x${string}`\n}\n","import type { Address } from 'viem'\nimport { Facilitator, DEFAULT_FACILITATOR_URL } from './facilitator.js'\nimport type {\n FacilitatorConfig,\n PaymentPayload,\n PaymentRequirement,\n PaymentRequiredResponse,\n SettleResult,\n X402Network,\n} from './types.js'\nimport { decodePayment, encodePayment, usdcAddress, usdToAtomic } from './utils.js'\n\nexport interface RouteGateOptions {\n /** Price in USD, e.g. \"0.01\". Converted to USDC atomic units. */\n price: string | number\n /** Recipient address that receives the funds. */\n recipient: Address\n /** Network(s) to accept. Defaults to `['base']`. Pass an array for multi-chain. */\n network?: X402Network | X402Network[]\n /** Override the payment asset (defaults to USDC for the given network). */\n asset?: Address\n /** Human-readable description of the resource. */\n description?: string\n /** Seconds the signed authorization is valid. Default: 600. */\n maxTimeoutSeconds?: number\n /** Facilitator config, or `false` to skip verification/settlement (trust-mode). */\n facilitator?: FacilitatorConfig | false\n /**\n * Optional resource identifier (defaults to the request URL). Useful for\n * logging / receipts.\n */\n resource?: string\n}\n\n/**\n * Runtime-agnostic gate: given a Fetch-API `Request`, either returns a 402\n * `Response` or a `{ settle }` handle. After your handler runs, call `settle()`\n * to finalize the payment and get a `X-PAYMENT-RESPONSE` header to attach.\n *\n * This is the building block used by the framework adapters (`./next`, `./express`).\n */\nexport async function gate(\n request: Request,\n opts: RouteGateOptions,\n): Promise<\n | { type: 'paymentRequired'; response: Response }\n | { type: 'ok'; payer: Address; settle: () => Promise<{ header: string; result: SettleResult }> }\n> {\n const requirements = buildRequirements(request, opts)\n\n const header = request.headers.get('x-payment') ?? request.headers.get('X-PAYMENT')\n if (!header) {\n return { type: 'paymentRequired', response: paymentRequiredResponse(requirements) }\n }\n\n let payment: PaymentPayload\n try {\n payment = decodePayment<PaymentPayload>(header)\n } catch {\n return {\n type: 'paymentRequired',\n response: paymentRequiredResponse(requirements, 'Invalid X-PAYMENT header'),\n }\n }\n\n const matched = requirements.find(\n (r) => r.network === payment.network && r.scheme === payment.scheme,\n )\n if (!matched) {\n return {\n type: 'paymentRequired',\n response: paymentRequiredResponse(requirements, 'Payment does not match any accepted requirement'),\n }\n }\n\n if (opts.facilitator === false) {\n const payer = payment.payload.authorization.from as Address\n return {\n type: 'ok',\n payer,\n settle: async () => ({\n header: encodePayment({ success: true, network: matched.network }),\n result: { success: true },\n }),\n }\n }\n\n const facilitator = new Facilitator(opts.facilitator ?? { url: DEFAULT_FACILITATOR_URL })\n const verified = await facilitator.verify(payment, matched)\n if (!verified.isValid) {\n return {\n type: 'paymentRequired',\n response: paymentRequiredResponse(\n requirements,\n verified.invalidReason ?? 'Payment verification failed',\n ),\n }\n }\n\n const payer = (verified.payer ?? payment.payload.authorization.from) as Address\n\n return {\n type: 'ok',\n payer,\n settle: async () => {\n const result = await facilitator.settle(payment, matched)\n return {\n header: encodePayment({\n success: result.success,\n transaction: result.transaction,\n network: result.network ?? matched.network,\n errorReason: result.errorReason,\n payer,\n }),\n result,\n }\n },\n }\n}\n\nfunction buildRequirements(request: Request, opts: RouteGateOptions): PaymentRequirement[] {\n const networks = Array.isArray(opts.network) ? opts.network : [opts.network ?? 'base']\n const atomic = usdToAtomic(opts.price)\n const resource = opts.resource ?? request.url\n\n return networks.map((network) => ({\n scheme: 'exact',\n network,\n asset: opts.asset ?? usdcAddress(network),\n maxAmountRequired: atomic,\n payTo: opts.recipient,\n description: opts.description,\n resource,\n maxTimeoutSeconds: opts.maxTimeoutSeconds ?? 600,\n extra: { name: 'USD Coin', version: '2' },\n }))\n}\n\nfunction paymentRequiredResponse(\n accepts: PaymentRequirement[],\n error?: string,\n): Response {\n const body: PaymentRequiredResponse = { x402Version: 1, accepts, ...(error ? { error } : {}) }\n return new Response(JSON.stringify(body), {\n status: 402,\n headers: { 'content-type': 'application/json' },\n })\n}\n\nexport { Facilitator, DEFAULT_FACILITATOR_URL } from './facilitator.js'\n"]}
@@ -0,0 +1,60 @@
1
+ import { Address } from 'viem';
2
+ import { F as FacilitatorConfig, P as PaymentPayload, b as PaymentRequirement, V as VerifyResult, S as SettleResult, X as X402Network } from './types-DzGpKiV3.cjs';
3
+
4
+ /**
5
+ * Thin wrapper around an x402 facilitator HTTP service.
6
+ * The facilitator verifies signed payment authorizations and settles them on-chain.
7
+ */
8
+ declare class Facilitator {
9
+ private readonly url;
10
+ private readonly authHeader?;
11
+ private readonly fetcher;
12
+ constructor(config: FacilitatorConfig);
13
+ verify(payment: PaymentPayload, requirement: PaymentRequirement): Promise<VerifyResult>;
14
+ settle(payment: PaymentPayload, requirement: PaymentRequirement): Promise<SettleResult>;
15
+ private post;
16
+ }
17
+ /** Default hosted facilitator. Override for self-hosted deployments. */
18
+ declare const DEFAULT_FACILITATOR_URL = "https://facilitator.yeetful.com";
19
+
20
+ interface RouteGateOptions {
21
+ /** Price in USD, e.g. "0.01". Converted to USDC atomic units. */
22
+ price: string | number;
23
+ /** Recipient address that receives the funds. */
24
+ recipient: Address;
25
+ /** Network(s) to accept. Defaults to `['base']`. Pass an array for multi-chain. */
26
+ network?: X402Network | X402Network[];
27
+ /** Override the payment asset (defaults to USDC for the given network). */
28
+ asset?: Address;
29
+ /** Human-readable description of the resource. */
30
+ description?: string;
31
+ /** Seconds the signed authorization is valid. Default: 600. */
32
+ maxTimeoutSeconds?: number;
33
+ /** Facilitator config, or `false` to skip verification/settlement (trust-mode). */
34
+ facilitator?: FacilitatorConfig | false;
35
+ /**
36
+ * Optional resource identifier (defaults to the request URL). Useful for
37
+ * logging / receipts.
38
+ */
39
+ resource?: string;
40
+ }
41
+ /**
42
+ * Runtime-agnostic gate: given a Fetch-API `Request`, either returns a 402
43
+ * `Response` or a `{ settle }` handle. After your handler runs, call `settle()`
44
+ * to finalize the payment and get a `X-PAYMENT-RESPONSE` header to attach.
45
+ *
46
+ * This is the building block used by the framework adapters (`./next`, `./express`).
47
+ */
48
+ declare function gate(request: Request, opts: RouteGateOptions): Promise<{
49
+ type: 'paymentRequired';
50
+ response: Response;
51
+ } | {
52
+ type: 'ok';
53
+ payer: Address;
54
+ settle: () => Promise<{
55
+ header: string;
56
+ result: SettleResult;
57
+ }>;
58
+ }>;
59
+
60
+ export { DEFAULT_FACILITATOR_URL, Facilitator, type RouteGateOptions, gate };
@@ -0,0 +1,60 @@
1
+ import { Address } from 'viem';
2
+ import { F as FacilitatorConfig, P as PaymentPayload, b as PaymentRequirement, V as VerifyResult, S as SettleResult, X as X402Network } from './types-DzGpKiV3.js';
3
+
4
+ /**
5
+ * Thin wrapper around an x402 facilitator HTTP service.
6
+ * The facilitator verifies signed payment authorizations and settles them on-chain.
7
+ */
8
+ declare class Facilitator {
9
+ private readonly url;
10
+ private readonly authHeader?;
11
+ private readonly fetcher;
12
+ constructor(config: FacilitatorConfig);
13
+ verify(payment: PaymentPayload, requirement: PaymentRequirement): Promise<VerifyResult>;
14
+ settle(payment: PaymentPayload, requirement: PaymentRequirement): Promise<SettleResult>;
15
+ private post;
16
+ }
17
+ /** Default hosted facilitator. Override for self-hosted deployments. */
18
+ declare const DEFAULT_FACILITATOR_URL = "https://facilitator.yeetful.com";
19
+
20
+ interface RouteGateOptions {
21
+ /** Price in USD, e.g. "0.01". Converted to USDC atomic units. */
22
+ price: string | number;
23
+ /** Recipient address that receives the funds. */
24
+ recipient: Address;
25
+ /** Network(s) to accept. Defaults to `['base']`. Pass an array for multi-chain. */
26
+ network?: X402Network | X402Network[];
27
+ /** Override the payment asset (defaults to USDC for the given network). */
28
+ asset?: Address;
29
+ /** Human-readable description of the resource. */
30
+ description?: string;
31
+ /** Seconds the signed authorization is valid. Default: 600. */
32
+ maxTimeoutSeconds?: number;
33
+ /** Facilitator config, or `false` to skip verification/settlement (trust-mode). */
34
+ facilitator?: FacilitatorConfig | false;
35
+ /**
36
+ * Optional resource identifier (defaults to the request URL). Useful for
37
+ * logging / receipts.
38
+ */
39
+ resource?: string;
40
+ }
41
+ /**
42
+ * Runtime-agnostic gate: given a Fetch-API `Request`, either returns a 402
43
+ * `Response` or a `{ settle }` handle. After your handler runs, call `settle()`
44
+ * to finalize the payment and get a `X-PAYMENT-RESPONSE` header to attach.
45
+ *
46
+ * This is the building block used by the framework adapters (`./next`, `./express`).
47
+ */
48
+ declare function gate(request: Request, opts: RouteGateOptions): Promise<{
49
+ type: 'paymentRequired';
50
+ response: Response;
51
+ } | {
52
+ type: 'ok';
53
+ payer: Address;
54
+ settle: () => Promise<{
55
+ header: string;
56
+ result: SettleResult;
57
+ }>;
58
+ }>;
59
+
60
+ export { DEFAULT_FACILITATOR_URL, Facilitator, type RouteGateOptions, gate };