@relai-fi/x402 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.d.cts CHANGED
@@ -1,18 +1,85 @@
1
- import { m as RelaiConfig, o as ProtectOptions } from './types-DGRfrYd3.cjs';
1
+ import { a as RelaiNetwork } from './types-C9LlAJj8.cjs';
2
2
 
3
+ interface RelaiServerConfig {
4
+ /** Network to accept payments on */
5
+ network: RelaiNetwork;
6
+ /** RelAI facilitator URL (default: https://facilitator.x402.fi) */
7
+ facilitatorUrl?: string;
8
+ }
9
+ type DynamicPrice = number | ((req: any) => number | Promise<number>);
10
+ interface ProtectOptions {
11
+ /** Price in USD (e.g., 0.01 for 1 cent) */
12
+ price: DynamicPrice;
13
+ /** Wallet address to receive payments */
14
+ payTo: string;
15
+ /** Description shown to payer */
16
+ description?: string;
17
+ /** MIME type of the response (default: application/json) */
18
+ mimeType?: string;
19
+ /** Maximum timeout in seconds (default: 60) */
20
+ maxTimeoutSeconds?: number;
21
+ /** Override network for this endpoint */
22
+ network?: RelaiNetwork;
23
+ /** Custom validation after payment is settled */
24
+ customRules?: (req: any) => boolean | Promise<boolean>;
25
+ /** Callback when 402 is returned (no payment provided) */
26
+ onPaymentRequired?: (req: any, info: {
27
+ price: number;
28
+ network: RelaiNetwork;
29
+ }) => void;
30
+ /** Callback when payment is settled successfully */
31
+ onPaymentSettled?: (req: any, result: SettleResult) => void;
32
+ /** Callback on error */
33
+ onError?: (req: any, error: unknown) => void;
34
+ }
35
+ interface SettleResult {
36
+ success: boolean;
37
+ transaction?: string;
38
+ payer?: string;
39
+ network?: string;
40
+ error?: string;
41
+ errorReason?: string;
42
+ }
43
+ interface PaymentInfo {
44
+ verified: boolean;
45
+ transactionId?: string;
46
+ payer?: string;
47
+ network: RelaiNetwork;
48
+ amount: number;
49
+ }
50
+ /**
51
+ * Server-side SDK for protecting Express endpoints with x402 micropayments.
52
+ * Settles payments through the RelAI facilitator (zero gas fees for users).
53
+ *
54
+ * Supports: Solana, Base, Avalanche, SKALE Base.
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * import Relai from '@relai-fi/x402/server';
59
+ *
60
+ * const relai = new Relai({ network: 'base' });
61
+ *
62
+ * app.get('/api/data', relai.protect({
63
+ * payTo: '0xYourWallet',
64
+ * price: 0.01, // $0.01 USDC
65
+ * }), (req, res) => {
66
+ * res.json({ data: 'Protected content', payment: req.payment });
67
+ * });
68
+ * ```
69
+ */
3
70
  declare class Relai {
4
- private config;
5
- private client;
6
- constructor(config: RelaiConfig);
71
+ private network;
72
+ private facilitatorUrl;
73
+ constructor(config: RelaiServerConfig);
7
74
  /**
8
75
  * Express middleware to protect an endpoint with x402 micropayments.
9
- * Returns a 402 with `accepts` for the configured network.
10
- * Supports: Solana, Base, Avalanche, SKALE Base.
76
+ *
77
+ * Flow:
78
+ * 1. No payment header → returns 402 with payment requirements
79
+ * 2. Payment header present → calls RelAI facilitator `/settle`
80
+ * 3. Settlement success → sets `PAYMENT-RESPONSE` header, attaches `req.payment`, calls `next()`
11
81
  */
12
82
  protect(options: ProtectOptions): (req: any, res: any, next: any) => Promise<any>;
13
- private verifyPayment;
14
- getStats(apiId?: string): Promise<any>;
15
- createProtectedEndpoint(options: ProtectOptions): (req: any, res: any, next: any) => Promise<any>;
16
83
  }
17
84
 
18
- export { Relai, Relai as default };
85
+ export { type DynamicPrice, type PaymentInfo, type ProtectOptions, Relai, type RelaiServerConfig, type SettleResult, Relai as default };
package/dist/server.d.ts CHANGED
@@ -1,18 +1,85 @@
1
- import { m as RelaiConfig, o as ProtectOptions } from './types-DGRfrYd3.js';
1
+ import { a as RelaiNetwork } from './types-C9LlAJj8.js';
2
2
 
3
+ interface RelaiServerConfig {
4
+ /** Network to accept payments on */
5
+ network: RelaiNetwork;
6
+ /** RelAI facilitator URL (default: https://facilitator.x402.fi) */
7
+ facilitatorUrl?: string;
8
+ }
9
+ type DynamicPrice = number | ((req: any) => number | Promise<number>);
10
+ interface ProtectOptions {
11
+ /** Price in USD (e.g., 0.01 for 1 cent) */
12
+ price: DynamicPrice;
13
+ /** Wallet address to receive payments */
14
+ payTo: string;
15
+ /** Description shown to payer */
16
+ description?: string;
17
+ /** MIME type of the response (default: application/json) */
18
+ mimeType?: string;
19
+ /** Maximum timeout in seconds (default: 60) */
20
+ maxTimeoutSeconds?: number;
21
+ /** Override network for this endpoint */
22
+ network?: RelaiNetwork;
23
+ /** Custom validation after payment is settled */
24
+ customRules?: (req: any) => boolean | Promise<boolean>;
25
+ /** Callback when 402 is returned (no payment provided) */
26
+ onPaymentRequired?: (req: any, info: {
27
+ price: number;
28
+ network: RelaiNetwork;
29
+ }) => void;
30
+ /** Callback when payment is settled successfully */
31
+ onPaymentSettled?: (req: any, result: SettleResult) => void;
32
+ /** Callback on error */
33
+ onError?: (req: any, error: unknown) => void;
34
+ }
35
+ interface SettleResult {
36
+ success: boolean;
37
+ transaction?: string;
38
+ payer?: string;
39
+ network?: string;
40
+ error?: string;
41
+ errorReason?: string;
42
+ }
43
+ interface PaymentInfo {
44
+ verified: boolean;
45
+ transactionId?: string;
46
+ payer?: string;
47
+ network: RelaiNetwork;
48
+ amount: number;
49
+ }
50
+ /**
51
+ * Server-side SDK for protecting Express endpoints with x402 micropayments.
52
+ * Settles payments through the RelAI facilitator (zero gas fees for users).
53
+ *
54
+ * Supports: Solana, Base, Avalanche, SKALE Base.
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * import Relai from '@relai-fi/x402/server';
59
+ *
60
+ * const relai = new Relai({ network: 'base' });
61
+ *
62
+ * app.get('/api/data', relai.protect({
63
+ * payTo: '0xYourWallet',
64
+ * price: 0.01, // $0.01 USDC
65
+ * }), (req, res) => {
66
+ * res.json({ data: 'Protected content', payment: req.payment });
67
+ * });
68
+ * ```
69
+ */
3
70
  declare class Relai {
4
- private config;
5
- private client;
6
- constructor(config: RelaiConfig);
71
+ private network;
72
+ private facilitatorUrl;
73
+ constructor(config: RelaiServerConfig);
7
74
  /**
8
75
  * Express middleware to protect an endpoint with x402 micropayments.
9
- * Returns a 402 with `accepts` for the configured network.
10
- * Supports: Solana, Base, Avalanche, SKALE Base.
76
+ *
77
+ * Flow:
78
+ * 1. No payment header → returns 402 with payment requirements
79
+ * 2. Payment header present → calls RelAI facilitator `/settle`
80
+ * 3. Settlement success → sets `PAYMENT-RESPONSE` header, attaches `req.payment`, calls `next()`
11
81
  */
12
82
  protect(options: ProtectOptions): (req: any, res: any, next: any) => Promise<any>;
13
- private verifyPayment;
14
- getStats(apiId?: string): Promise<any>;
15
- createProtectedEndpoint(options: ProtectOptions): (req: any, res: any, next: any) => Promise<any>;
16
83
  }
17
84
 
18
- export { Relai, Relai as default };
85
+ export { type DynamicPrice, type PaymentInfo, type ProtectOptions, Relai, type RelaiServerConfig, type SettleResult, Relai as default };
package/dist/server.js CHANGED
@@ -1,13 +1,13 @@
1
- // src/server.ts
2
- import axios from "axios";
3
-
4
1
  // src/types.ts
5
2
  var RELAI_FACILITATOR_URL = "https://facilitator.x402.fi";
6
3
  var NETWORK_CAIP2 = {
7
4
  "solana": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
8
5
  "base": "eip155:8453",
9
6
  "avalanche": "eip155:43114",
10
- "skale-base": "eip155:1187947933"
7
+ "skale-base": "eip155:1187947933",
8
+ "skale-bite": "eip155:103698795",
9
+ "polygon": "eip155:137",
10
+ "ethereum": "eip155:1"
11
11
  };
12
12
  var CAIP2_TO_NETWORK = Object.fromEntries(
13
13
  Object.entries(NETWORK_CAIP2).map(([k, v]) => [v, k])
@@ -16,7 +16,10 @@ var USDC_ADDRESSES = {
16
16
  "solana": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
17
17
  "base": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
18
18
  "avalanche": "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
19
- "skale-base": "0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20"
19
+ "skale-base": "0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",
20
+ "skale-bite": "0xc4083B1E81ceb461Ccef3FDa8A9F24F0d764B6D8",
21
+ "polygon": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
22
+ "ethereum": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
20
23
  };
21
24
  var SOLANA_MAINNET_NETWORK = NETWORK_CAIP2["solana"];
22
25
  var BASE_MAINNET_NETWORK = NETWORK_CAIP2["base"];
@@ -26,107 +29,133 @@ var USDC_BASE = USDC_ADDRESSES["base"];
26
29
  // src/server.ts
27
30
  var Relai = class {
28
31
  constructor(config) {
29
- this.config = {
30
- network: "solana",
31
- apiBaseUrl: "https://relai.fi/api",
32
- facilitatorUrl: RELAI_FACILITATOR_URL,
33
- ...config
34
- };
35
- if (!this.config.apiKey || typeof this.config.apiKey !== "string") {
36
- throw new Error("[Relai] Missing required apiKey in configuration");
37
- }
38
- this.client = axios.create({
39
- baseURL: this.config.apiBaseUrl,
40
- timeout: 1e4,
41
- headers: {
42
- "Authorization": `Bearer ${this.config.apiKey}`,
43
- "Content-Type": "application/json"
44
- }
45
- });
32
+ this.network = config.network;
33
+ this.facilitatorUrl = config.facilitatorUrl || RELAI_FACILITATOR_URL;
46
34
  }
47
35
  /**
48
36
  * Express middleware to protect an endpoint with x402 micropayments.
49
- * Returns a 402 with `accepts` for the configured network.
50
- * Supports: Solana, Base, Avalanche, SKALE Base.
37
+ *
38
+ * Flow:
39
+ * 1. No payment header → returns 402 with payment requirements
40
+ * 2. Payment header present → calls RelAI facilitator `/settle`
41
+ * 3. Settlement success → sets `PAYMENT-RESPONSE` header, attaches `req.payment`, calls `next()`
51
42
  */
52
43
  protect(options) {
44
+ const self = this;
53
45
  return async (req, res, next) => {
54
46
  try {
55
47
  const resolvedPrice = typeof options.price === "function" ? await options.price(req) : options.price;
56
48
  if (typeof resolvedPrice !== "number" || !isFinite(resolvedPrice) || resolvedPrice <= 0) {
57
- return res.status(400).json({ error: "Invalid price configuration", code: "INVALID_PRICE" });
49
+ return res.status(400).json({ error: "Invalid price configuration" });
58
50
  }
59
- const paymentSignature = req.headers["x-payment-signature"] || req.headers["x-relai-payment"];
60
- if (!paymentSignature) {
61
- const network = this.config.network;
62
- const caip2 = NETWORK_CAIP2[network] || NETWORK_CAIP2["solana"];
63
- const asset = USDC_ADDRESSES[network] || USDC_ADDRESSES["solana"];
51
+ const network = options.network || self.network;
52
+ const caip2 = NETWORK_CAIP2[network];
53
+ const asset = USDC_ADDRESSES[network];
54
+ const amount = String(Math.floor(resolvedPrice * 1e6));
55
+ const paymentHeader = req.headers["x-payment"] || req.headers["payment-signature"] || req.headers["x-payment-signature"];
56
+ if (!paymentHeader) {
57
+ options.onPaymentRequired?.(req, { price: resolvedPrice, network });
64
58
  return res.status(402).json({
65
59
  x402Version: 2,
66
60
  error: "Payment required",
67
61
  resource: {
68
62
  url: `${req.protocol}://${req.get("host")}${req.originalUrl}`,
69
63
  description: options.description || "API access",
70
- mimeType: "application/json"
64
+ mimeType: options.mimeType || "application/json"
71
65
  },
72
66
  accepts: [{
73
67
  scheme: "exact",
74
68
  network: caip2,
75
- maxAmountRequired: String(Math.floor(resolvedPrice * 1e6)),
69
+ amount,
76
70
  asset,
77
71
  payTo: options.payTo,
78
- maxTimeoutSeconds: 60,
72
+ maxTimeoutSeconds: options.maxTimeoutSeconds || 60,
79
73
  extra: {
80
74
  name: "USD Coin",
81
75
  version: "2",
82
- decimals: 6,
83
- facilitatorUrl: this.config.facilitatorUrl
76
+ decimals: 6
84
77
  }
85
78
  }]
86
79
  });
87
80
  }
88
- const verification = await this.verifyPayment(paymentSignature, resolvedPrice, options.maxTimeout);
89
- if (!verification.verified) {
81
+ let paymentProof;
82
+ try {
83
+ const decoded = Buffer.from(paymentHeader, "base64").toString("utf-8");
84
+ paymentProof = JSON.parse(decoded);
85
+ } catch {
86
+ try {
87
+ paymentProof = JSON.parse(paymentHeader);
88
+ } catch {
89
+ return res.status(400).json({
90
+ x402Version: 2,
91
+ error: "Invalid payment header \u2014 expected base64-encoded JSON"
92
+ });
93
+ }
94
+ }
95
+ const paymentRequirements = {
96
+ scheme: "exact",
97
+ network,
98
+ amount,
99
+ asset,
100
+ payTo: options.payTo,
101
+ maxTimeoutSeconds: options.maxTimeoutSeconds || 60
102
+ };
103
+ const settleUrl = `${self.facilitatorUrl}/settle`;
104
+ const settleRes = await fetch(settleUrl, {
105
+ method: "POST",
106
+ headers: { "Content-Type": "application/json" },
107
+ body: JSON.stringify({
108
+ paymentPayload: paymentProof,
109
+ paymentRequirements
110
+ })
111
+ });
112
+ const result = await settleRes.json();
113
+ if (!result.success) {
90
114
  return res.status(402).json({
91
- error: "Payment verification failed",
92
- code: "PAYMENT_INVALID",
93
- details: verification.error
115
+ x402Version: 2,
116
+ error: result.errorReason || result.error || "Payment settlement failed"
94
117
  });
95
118
  }
96
- req.payment = verification;
119
+ const paymentInfo = {
120
+ verified: true,
121
+ transactionId: result.transaction,
122
+ payer: result.payer,
123
+ network,
124
+ amount: resolvedPrice
125
+ };
126
+ req.payment = paymentInfo;
127
+ req.x402Payer = result.payer;
128
+ req.x402Paid = true;
129
+ req.x402Transaction = result.transaction;
130
+ req.x402Network = network;
131
+ const paymentResponse = {
132
+ x402Version: 2,
133
+ scheme: "exact",
134
+ network: caip2,
135
+ transaction: result.transaction,
136
+ payer: result.payer,
137
+ amount,
138
+ asset
139
+ };
140
+ res.setHeader(
141
+ "PAYMENT-RESPONSE",
142
+ Buffer.from(JSON.stringify(paymentResponse)).toString("base64")
143
+ );
144
+ options.onPaymentSettled?.(req, result);
97
145
  if (options.customRules) {
98
- const customValid = await options.customRules(req);
99
- if (!customValid) {
100
- return res.status(403).json({ error: "Custom validation failed", code: "VALIDATION_FAILED" });
146
+ const valid = await options.customRules(req);
147
+ if (!valid) {
148
+ return res.status(403).json({ error: "Custom validation failed" });
101
149
  }
102
150
  }
103
151
  next();
104
152
  } catch (error) {
105
- console.error("Relai protection error:", error);
106
- res.status(500).json({ error: "Internal server error", code: "SERVER_ERROR" });
153
+ options.onError?.(req, error);
154
+ console.error("[Relai] Protection error:", error);
155
+ res.status(500).json({ error: "Internal server error" });
107
156
  }
108
157
  };
109
158
  }
110
- async verifyPayment(signature, expectedPrice, timeoutMs) {
111
- try {
112
- const response = await this.client.post(
113
- "/verify-payment",
114
- { signature, expectedPrice, network: this.config.network },
115
- { timeout: typeof timeoutMs === "number" ? Math.max(1, timeoutMs) : void 0 }
116
- );
117
- return response.data;
118
- } catch (error) {
119
- return { verified: false, error: error.response?.data?.error || "Verification failed" };
120
- }
121
- }
122
- async getStats(apiId) {
123
- const params = apiId ? { apiId } : {};
124
- const response = await this.client.get("/stats", { params });
125
- return response.data;
126
- }
127
- createProtectedEndpoint(options) {
128
- return this.protect(options);
129
- }
130
159
  };
131
160
  var server_default = Relai;
132
161
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.ts","../src/types.ts"],"sourcesContent":["// src/server.ts\nimport axios, { AxiosInstance } from 'axios';\nimport {\n RelaiConfig,\n ProtectOptions,\n PaymentResult,\n NETWORK_CAIP2,\n USDC_ADDRESSES,\n RELAI_FACILITATOR_URL,\n type RelaiNetwork,\n} from './types';\n\nexport class Relai {\n private config: Required<Pick<RelaiConfig, 'network' | 'facilitatorUrl' | 'apiBaseUrl'>> & RelaiConfig;\n private client: AxiosInstance;\n\n constructor(config: RelaiConfig) {\n this.config = {\n network: 'solana',\n apiBaseUrl: 'https://relai.fi/api',\n facilitatorUrl: RELAI_FACILITATOR_URL,\n ...config,\n };\n\n if (!this.config.apiKey || typeof this.config.apiKey !== 'string') {\n throw new Error('[Relai] Missing required apiKey in configuration');\n }\n\n this.client = axios.create({\n baseURL: this.config.apiBaseUrl,\n timeout: 10000,\n headers: {\n 'Authorization': `Bearer ${this.config.apiKey}`,\n 'Content-Type': 'application/json',\n },\n });\n }\n\n /**\n * Express middleware to protect an endpoint with x402 micropayments.\n * Returns a 402 with `accepts` for the configured network.\n * Supports: Solana, Base, Avalanche, SKALE Base.\n */\n protect(options: ProtectOptions) {\n return async (req: any, res: any, next: any) => {\n try {\n const resolvedPrice = typeof options.price === 'function'\n ? await options.price(req)\n : options.price;\n\n if (typeof resolvedPrice !== 'number' || !isFinite(resolvedPrice) || resolvedPrice <= 0) {\n return res.status(400).json({ error: 'Invalid price configuration', code: 'INVALID_PRICE' });\n }\n\n // Check for payment header\n const paymentSignature = req.headers['x-payment-signature'] || req.headers['x-relai-payment'];\n\n if (!paymentSignature) {\n const network = this.config.network as RelaiNetwork;\n const caip2 = NETWORK_CAIP2[network] || NETWORK_CAIP2['solana'];\n const asset = USDC_ADDRESSES[network] || USDC_ADDRESSES['solana'];\n\n return res.status(402).json({\n x402Version: 2,\n error: 'Payment required',\n resource: {\n url: `${req.protocol}://${req.get('host')}${req.originalUrl}`,\n description: options.description || 'API access',\n mimeType: 'application/json',\n },\n accepts: [{\n scheme: 'exact',\n network: caip2,\n maxAmountRequired: String(Math.floor(resolvedPrice * 1_000_000)),\n asset,\n payTo: options.payTo,\n maxTimeoutSeconds: 60,\n extra: {\n name: 'USD Coin',\n version: '2',\n decimals: 6,\n facilitatorUrl: this.config.facilitatorUrl,\n },\n }],\n });\n }\n\n // Verify payment\n const verification = await this.verifyPayment(paymentSignature, resolvedPrice, options.maxTimeout);\n\n if (!verification.verified) {\n return res.status(402).json({\n error: 'Payment verification failed',\n code: 'PAYMENT_INVALID',\n details: verification.error,\n });\n }\n\n req.payment = verification;\n\n if (options.customRules) {\n const customValid = await options.customRules(req);\n if (!customValid) {\n return res.status(403).json({ error: 'Custom validation failed', code: 'VALIDATION_FAILED' });\n }\n }\n\n next();\n } catch (error) {\n console.error('Relai protection error:', error);\n res.status(500).json({ error: 'Internal server error', code: 'SERVER_ERROR' });\n }\n };\n }\n\n private async verifyPayment(signature: string, expectedPrice: number, timeoutMs?: number): Promise<PaymentResult> {\n try {\n const response = await this.client.post(\n '/verify-payment',\n { signature, expectedPrice, network: this.config.network },\n { timeout: typeof timeoutMs === 'number' ? Math.max(1, timeoutMs) : undefined },\n );\n return response.data;\n } catch (error: any) {\n return { verified: false, error: error.response?.data?.error || 'Verification failed' };\n }\n }\n\n async getStats(apiId?: string) {\n const params = apiId ? { apiId } : {};\n const response = await this.client.get('/stats', { params });\n return response.data;\n }\n\n createProtectedEndpoint(options: ProtectOptions) {\n return this.protect(options);\n }\n}\n\nexport default Relai;\n","// src/types.ts\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** RelAI Facilitator URL */\nexport const RELAI_FACILITATOR_URL = 'https://facilitator.x402.fi';\n\n// ============================================================================\n// Supported Networks\n// ============================================================================\n\n/** All networks supported by RelAI facilitator */\nexport type RelaiNetwork = 'solana' | 'base' | 'avalanche' | 'skale-base';\n\n/** CAIP-2 network identifiers */\nexport const NETWORK_CAIP2: Record<RelaiNetwork, string> = {\n 'solana': 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',\n 'base': 'eip155:8453',\n 'avalanche': 'eip155:43114',\n 'skale-base': 'eip155:1187947933',\n};\n\n/** Reverse lookup: CAIP-2 → simple network name */\nexport const CAIP2_TO_NETWORK: Record<string, RelaiNetwork> = Object.fromEntries(\n Object.entries(NETWORK_CAIP2).map(([k, v]) => [v, k as RelaiNetwork])\n) as Record<string, RelaiNetwork>;\n\n/** Chain IDs for EVM networks */\nexport const CHAIN_IDS: Record<string, number> = {\n 'base': 8453,\n 'avalanche': 43114,\n 'skale-base': 1187947933,\n};\n\n/** USDC contract addresses per network */\nexport const USDC_ADDRESSES: Record<RelaiNetwork, string> = {\n 'solana': 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',\n 'base': '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n 'avalanche': '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',\n 'skale-base': '0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20',\n};\n\n/** Explorer URLs per network */\nexport const EXPLORER_TX_URL: Record<RelaiNetwork, (tx: string) => string> = {\n 'solana': (tx) => `https://solscan.io/tx/${tx}`,\n 'base': (tx) => `https://basescan.org/tx/${tx}`,\n 'avalanche': (tx) => `https://snowtrace.io/tx/${tx}`,\n 'skale-base': (tx) => `https://skale-base-explorer.skalenodes.com/tx/${tx}`,\n};\n\n/** Human-readable network labels */\nexport const NETWORK_LABELS: Record<RelaiNetwork, string> = {\n 'solana': 'Solana',\n 'base': 'Base',\n 'avalanche': 'Avalanche',\n 'skale-base': 'SKALE Base',\n};\n\n/** Legacy CAIP-2 exports for backward compatibility */\nexport const SOLANA_MAINNET_NETWORK = NETWORK_CAIP2['solana'];\nexport const BASE_MAINNET_NETWORK = NETWORK_CAIP2['base'];\n\n/** Legacy USDC exports for backward compatibility */\nexport const USDC_SOLANA = USDC_ADDRESSES['solana'];\nexport const USDC_BASE = USDC_ADDRESSES['base'];\n\n/** All supported RelAI networks list */\nexport const RELAI_NETWORKS: RelaiNetwork[] = ['solana', 'base', 'avalanche', 'skale-base'];\n\n/** Check if a network is Solana-based */\nexport function isSolana(network: string): boolean {\n return network === 'solana' || network.startsWith('solana:');\n}\n\n/** Check if a network is EVM-based */\nexport function isEvm(network: string): boolean {\n return ['base', 'avalanche', 'skale-base'].includes(network) || network.startsWith('eip155:');\n}\n\n/** Normalize CAIP-2 or simple name to RelaiNetwork */\nexport function normalizeNetwork(network: string): RelaiNetwork | null {\n if (RELAI_NETWORKS.includes(network as RelaiNetwork)) return network as RelaiNetwork;\n const fromCaip2 = CAIP2_TO_NETWORK[network];\n if (fromCaip2) return fromCaip2;\n // Partial match\n if (network.startsWith('solana:')) return 'solana';\n if (network.startsWith('eip155:')) {\n const chainId = parseInt(network.split(':')[1]);\n const entry = Object.entries(CHAIN_IDS).find(([, id]) => id === chainId);\n if (entry) return entry[0] as RelaiNetwork;\n }\n return null;\n}\n\n// ============================================================================\n// Wallet Types\n// ============================================================================\n\n/** Solana wallet interface */\nexport interface SolanaWallet {\n publicKey: { toString(): string } | null;\n signTransaction: ((tx: unknown) => Promise<unknown>) | null;\n signAllTransactions?: ((txs: unknown[]) => Promise<unknown[]>) | null;\n}\n\n/** EVM wallet interface (viem-compatible) */\nexport interface EvmWallet {\n address: string;\n signTypedData: (params: unknown) => Promise<string>;\n chain?: { id: number };\n}\n\n/** Wallet set for multi-chain support */\nexport interface WalletSet {\n solana?: SolanaWallet;\n evm?: EvmWallet;\n}\n\n// ============================================================================\n// Payment Types\n// ============================================================================\n\n/** Extra fields in payment requirements */\nexport interface AcceptsExtra {\n feePayer?: string;\n decimals?: number;\n name?: string;\n version?: string;\n [key: string]: unknown;\n}\n\n/** A single payment option */\nexport interface PaymentAccept {\n x402Version?: 1 | 2;\n scheme: string;\n network: string;\n maxAmountRequired?: string;\n amount?: string;\n asset: string;\n payTo: string;\n maxTimeoutSeconds?: number;\n extra?: AcceptsExtra;\n resource?: string;\n description?: string;\n mimeType?: string;\n outputSchema?: unknown;\n}\n\n/** Resource info for v2 */\nexport interface ResourceInfo {\n url: string;\n description?: string;\n mimeType?: string;\n}\n\n/** Payment requirements (402 response) */\nexport interface PaymentRequired {\n x402Version: 1 | 2;\n error?: string;\n accepts: PaymentAccept[];\n resource?: ResourceInfo;\n extensions?: Record<string, unknown>;\n}\n\n// ============================================================================\n// Config Types\n// ============================================================================\n\nexport interface RelaiConfig {\n apiKey?: string;\n network?: RelaiNetwork;\n facilitatorUrl?: string;\n apiBaseUrl?: string;\n}\n\nexport type DynamicPrice = number | ((req: unknown) => number | Promise<number>);\n\nexport interface ProtectOptions {\n /** Price in USD (e.g., 0.01 for 1 cent) */\n price: DynamicPrice;\n /** Wallet address to receive payments */\n payTo: string;\n /** Description shown to payer */\n description?: string;\n /** Maximum timeout in seconds */\n maxTimeout?: number;\n /** Custom validation rules */\n customRules?: (req: unknown) => boolean | Promise<boolean>;\n onPaymentRequired?: (\n req: unknown,\n info: { price: number; description?: string; facilitatorUrl?: string }\n ) => void;\n onPaymentVerified?: (req: unknown, result: PaymentResult) => void;\n onError?: (req: unknown, error: unknown) => void;\n}\n\nexport interface PaymentResult {\n verified: boolean;\n transactionId?: string;\n amount?: number;\n currency?: string;\n error?: string;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/types.ts","../src/server.ts"],"sourcesContent":["// src/types.ts\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** RelAI Facilitator URL */\nexport const RELAI_FACILITATOR_URL = 'https://facilitator.x402.fi';\n\n// ============================================================================\n// Supported Networks\n// ============================================================================\n\n/** All networks supported by RelAI facilitator */\nexport type RelaiNetwork = 'solana' | 'base' | 'avalanche' | 'skale-base' | 'skale-bite' | 'polygon' | 'ethereum';\n\n/** CAIP-2 network identifiers */\nexport const NETWORK_CAIP2: Record<RelaiNetwork, string> = {\n 'solana': 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',\n 'base': 'eip155:8453',\n 'avalanche': 'eip155:43114',\n 'skale-base': 'eip155:1187947933',\n 'skale-bite': 'eip155:103698795',\n 'polygon': 'eip155:137',\n 'ethereum': 'eip155:1',\n};\n\n/** Reverse lookup: CAIP-2 → simple network name */\nexport const CAIP2_TO_NETWORK: Record<string, RelaiNetwork> = Object.fromEntries(\n Object.entries(NETWORK_CAIP2).map(([k, v]) => [v, k as RelaiNetwork])\n) as Record<string, RelaiNetwork>;\n\n/** Chain IDs for EVM networks */\nexport const CHAIN_IDS: Record<string, number> = {\n 'base': 8453,\n 'avalanche': 43114,\n 'skale-base': 1187947933,\n 'skale-bite': 103698795,\n 'polygon': 137,\n 'ethereum': 1,\n};\n\n/** USDC contract addresses per network */\nexport const USDC_ADDRESSES: Record<RelaiNetwork, string> = {\n 'solana': 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',\n 'base': '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n 'avalanche': '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',\n 'skale-base': '0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20',\n 'skale-bite': '0xc4083B1E81ceb461Ccef3FDa8A9F24F0d764B6D8',\n 'polygon': '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n 'ethereum': '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n};\n\n/** Explorer URLs per network */\nexport const EXPLORER_TX_URL: Record<RelaiNetwork, (tx: string) => string> = {\n 'solana': (tx) => `https://solscan.io/tx/${tx}`,\n 'base': (tx) => `https://basescan.org/tx/${tx}`,\n 'avalanche': (tx) => `https://snowtrace.io/tx/${tx}`,\n 'skale-base': (tx) => `https://skale-base-explorer.skalenodes.com/tx/${tx}`,\n 'skale-bite': (tx) => `https://base-sepolia-testnet.explorer.skalenodes.com/tx/${tx}`,\n 'polygon': (tx) => `https://polygonscan.com/tx/${tx}`,\n 'ethereum': (tx) => `https://etherscan.io/tx/${tx}`,\n};\n\n/** Human-readable network labels */\nexport const NETWORK_LABELS: Record<RelaiNetwork, string> = {\n 'solana': 'Solana',\n 'base': 'Base',\n 'avalanche': 'Avalanche',\n 'skale-base': 'SKALE Base',\n 'skale-bite': 'SKALE BITE V2',\n 'polygon': 'Polygon',\n 'ethereum': 'Ethereum',\n};\n\n/** Legacy CAIP-2 exports for backward compatibility */\nexport const SOLANA_MAINNET_NETWORK = NETWORK_CAIP2['solana'];\nexport const BASE_MAINNET_NETWORK = NETWORK_CAIP2['base'];\n\n/** Legacy USDC exports for backward compatibility */\nexport const USDC_SOLANA = USDC_ADDRESSES['solana'];\nexport const USDC_BASE = USDC_ADDRESSES['base'];\n\n/** All supported RelAI networks list */\nexport const RELAI_NETWORKS: RelaiNetwork[] = ['solana', 'base', 'avalanche', 'skale-base', 'skale-bite', 'polygon', 'ethereum'];\n\n/** Check if a network is Solana-based */\nexport function isSolana(network: string): boolean {\n return network === 'solana' || network.startsWith('solana:');\n}\n\n/** Check if a network is EVM-based */\nexport function isEvm(network: string): boolean {\n return ['base', 'avalanche', 'skale-base', 'skale-bite', 'polygon', 'ethereum'].includes(network) || network.startsWith('eip155:');\n}\n\n/** Normalize CAIP-2 or simple name to RelaiNetwork */\nexport function normalizeNetwork(network: string): RelaiNetwork | null {\n if (RELAI_NETWORKS.includes(network as RelaiNetwork)) return network as RelaiNetwork;\n const fromCaip2 = CAIP2_TO_NETWORK[network];\n if (fromCaip2) return fromCaip2;\n // Partial match\n if (network.startsWith('solana:')) return 'solana';\n if (network.startsWith('eip155:')) {\n const chainId = parseInt(network.split(':')[1]);\n const entry = Object.entries(CHAIN_IDS).find(([, id]) => id === chainId);\n if (entry) return entry[0] as RelaiNetwork;\n }\n return null;\n}\n\n// ============================================================================\n// Wallet Types\n// ============================================================================\n\n/** Solana wallet interface */\nexport interface SolanaWallet {\n publicKey: { toString(): string } | null;\n signTransaction: ((tx: unknown) => Promise<unknown>) | null;\n signAllTransactions?: ((txs: unknown[]) => Promise<unknown[]>) | null;\n}\n\n/** EVM wallet interface (viem-compatible) */\nexport interface EvmWallet {\n address: string;\n signTypedData: (params: unknown) => Promise<string>;\n chain?: { id: number };\n}\n\n/** Wallet set for multi-chain support */\nexport interface WalletSet {\n solana?: SolanaWallet;\n evm?: EvmWallet;\n}\n\n// ============================================================================\n// Payment Types\n// ============================================================================\n\n/** Extra fields in payment requirements */\nexport interface AcceptsExtra {\n feePayer?: string;\n decimals?: number;\n name?: string;\n version?: string;\n [key: string]: unknown;\n}\n\n/** A single payment option */\nexport interface PaymentAccept {\n x402Version?: 1 | 2;\n scheme: string;\n network: string;\n maxAmountRequired?: string;\n amount?: string;\n asset: string;\n payTo: string;\n maxTimeoutSeconds?: number;\n extra?: AcceptsExtra;\n resource?: string;\n description?: string;\n mimeType?: string;\n outputSchema?: unknown;\n}\n\n/** Resource info for v2 */\nexport interface ResourceInfo {\n url: string;\n description?: string;\n mimeType?: string;\n}\n\n/** Payment requirements (402 response) */\nexport interface PaymentRequired {\n x402Version: 1 | 2;\n error?: string;\n accepts: PaymentAccept[];\n resource?: ResourceInfo;\n extensions?: Record<string, unknown>;\n}\n\n// ============================================================================\n// Config Types (server-specific types are in server.ts)\n// ============================================================================\n","// src/server.ts\nimport {\n NETWORK_CAIP2,\n USDC_ADDRESSES,\n RELAI_FACILITATOR_URL,\n type RelaiNetwork,\n} from './types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface RelaiServerConfig {\n /** Network to accept payments on */\n network: RelaiNetwork;\n /** RelAI facilitator URL (default: https://facilitator.x402.fi) */\n facilitatorUrl?: string;\n}\n\nexport type DynamicPrice = number | ((req: any) => number | Promise<number>);\n\nexport interface ProtectOptions {\n /** Price in USD (e.g., 0.01 for 1 cent) */\n price: DynamicPrice;\n /** Wallet address to receive payments */\n payTo: string;\n /** Description shown to payer */\n description?: string;\n /** MIME type of the response (default: application/json) */\n mimeType?: string;\n /** Maximum timeout in seconds (default: 60) */\n maxTimeoutSeconds?: number;\n /** Override network for this endpoint */\n network?: RelaiNetwork;\n /** Custom validation after payment is settled */\n customRules?: (req: any) => boolean | Promise<boolean>;\n /** Callback when 402 is returned (no payment provided) */\n onPaymentRequired?: (req: any, info: { price: number; network: RelaiNetwork }) => void;\n /** Callback when payment is settled successfully */\n onPaymentSettled?: (req: any, result: SettleResult) => void;\n /** Callback on error */\n onError?: (req: any, error: unknown) => void;\n}\n\nexport interface SettleResult {\n success: boolean;\n transaction?: string;\n payer?: string;\n network?: string;\n error?: string;\n errorReason?: string;\n}\n\nexport interface PaymentInfo {\n verified: boolean;\n transactionId?: string;\n payer?: string;\n network: RelaiNetwork;\n amount: number;\n}\n\n// ============================================================================\n// Relai Server SDK\n// ============================================================================\n\n/**\n * Server-side SDK for protecting Express endpoints with x402 micropayments.\n * Settles payments through the RelAI facilitator (zero gas fees for users).\n *\n * Supports: Solana, Base, Avalanche, SKALE Base.\n *\n * @example\n * ```typescript\n * import Relai from '@relai-fi/x402/server';\n *\n * const relai = new Relai({ network: 'base' });\n *\n * app.get('/api/data', relai.protect({\n * payTo: '0xYourWallet',\n * price: 0.01, // $0.01 USDC\n * }), (req, res) => {\n * res.json({ data: 'Protected content', payment: req.payment });\n * });\n * ```\n */\nexport class Relai {\n private network: RelaiNetwork;\n private facilitatorUrl: string;\n\n constructor(config: RelaiServerConfig) {\n this.network = config.network;\n this.facilitatorUrl = config.facilitatorUrl || RELAI_FACILITATOR_URL;\n }\n\n /**\n * Express middleware to protect an endpoint with x402 micropayments.\n *\n * Flow:\n * 1. No payment header → returns 402 with payment requirements\n * 2. Payment header present → calls RelAI facilitator `/settle`\n * 3. Settlement success → sets `PAYMENT-RESPONSE` header, attaches `req.payment`, calls `next()`\n */\n protect(options: ProtectOptions) {\n const self = this;\n\n return async (req: any, res: any, next: any) => {\n try {\n // Resolve dynamic price\n const resolvedPrice = typeof options.price === 'function'\n ? await options.price(req)\n : options.price;\n\n if (typeof resolvedPrice !== 'number' || !isFinite(resolvedPrice) || resolvedPrice <= 0) {\n return res.status(400).json({ error: 'Invalid price configuration' });\n }\n\n const network = options.network || self.network;\n const caip2 = NETWORK_CAIP2[network];\n const asset = USDC_ADDRESSES[network];\n const amount = String(Math.floor(resolvedPrice * 1_000_000)); // USD → USDC atomic units (6 decimals)\n\n // Check for payment header (base64-encoded JSON)\n const paymentHeader =\n req.headers['x-payment'] ||\n req.headers['payment-signature'] ||\n req.headers['x-payment-signature'];\n\n // -----------------------------------------------------------\n // No payment → return 402 Payment Required\n // -----------------------------------------------------------\n if (!paymentHeader) {\n options.onPaymentRequired?.(req, { price: resolvedPrice, network });\n\n return res.status(402).json({\n x402Version: 2,\n error: 'Payment required',\n resource: {\n url: `${req.protocol}://${req.get('host')}${req.originalUrl}`,\n description: options.description || 'API access',\n mimeType: options.mimeType || 'application/json',\n },\n accepts: [{\n scheme: 'exact',\n network: caip2,\n amount,\n asset,\n payTo: options.payTo,\n maxTimeoutSeconds: options.maxTimeoutSeconds || 60,\n extra: {\n name: 'USD Coin',\n version: '2',\n decimals: 6,\n },\n }],\n });\n }\n\n // -----------------------------------------------------------\n // Payment header present → parse and settle via facilitator\n // -----------------------------------------------------------\n let paymentProof: any;\n try {\n // Try base64 first (standard x402 format)\n const decoded = Buffer.from(paymentHeader, 'base64').toString('utf-8');\n paymentProof = JSON.parse(decoded);\n } catch {\n try {\n // Fallback: raw JSON string\n paymentProof = JSON.parse(paymentHeader);\n } catch {\n return res.status(400).json({\n x402Version: 2,\n error: 'Invalid payment header — expected base64-encoded JSON',\n });\n }\n }\n\n // Build payment requirements for facilitator\n const paymentRequirements = {\n scheme: 'exact',\n network,\n amount,\n asset,\n payTo: options.payTo,\n maxTimeoutSeconds: options.maxTimeoutSeconds || 60,\n };\n\n // Call facilitator /settle\n const settleUrl = `${self.facilitatorUrl}/settle`;\n const settleRes = await fetch(settleUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n paymentPayload: paymentProof,\n paymentRequirements,\n }),\n });\n\n const result: SettleResult = await settleRes.json() as SettleResult;\n\n if (!result.success) {\n return res.status(402).json({\n x402Version: 2,\n error: result.errorReason || result.error || 'Payment settlement failed',\n });\n }\n\n // Attach payment info to request\n const paymentInfo: PaymentInfo = {\n verified: true,\n transactionId: result.transaction,\n payer: result.payer,\n network,\n amount: resolvedPrice,\n };\n req.payment = paymentInfo;\n req.x402Payer = result.payer;\n req.x402Paid = true;\n req.x402Transaction = result.transaction;\n req.x402Network = network;\n\n // Set x402 v2 PAYMENT-RESPONSE header (base64 JSON)\n const paymentResponse = {\n x402Version: 2,\n scheme: 'exact',\n network: caip2,\n transaction: result.transaction,\n payer: result.payer,\n amount,\n asset,\n };\n res.setHeader(\n 'PAYMENT-RESPONSE',\n Buffer.from(JSON.stringify(paymentResponse)).toString('base64'),\n );\n\n options.onPaymentSettled?.(req, result);\n\n // Custom validation after payment\n if (options.customRules) {\n const valid = await options.customRules(req);\n if (!valid) {\n return res.status(403).json({ error: 'Custom validation failed' });\n }\n }\n\n next();\n } catch (error) {\n options.onError?.(req, error);\n console.error('[Relai] Protection error:', error);\n res.status(500).json({ error: 'Internal server error' });\n }\n };\n }\n}\n\nexport default Relai;\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  /** RelAI Facilitator URL */
2
2
  declare const RELAI_FACILITATOR_URL = "https://facilitator.x402.fi";
3
3
  /** All networks supported by RelAI facilitator */
4
- type RelaiNetwork = 'solana' | 'base' | 'avalanche' | 'skale-base';
4
+ type RelaiNetwork = 'solana' | 'base' | 'avalanche' | 'skale-base' | 'skale-bite' | 'polygon' | 'ethereum';
5
5
  /** CAIP-2 network identifiers */
6
6
  declare const NETWORK_CAIP2: Record<RelaiNetwork, string>;
7
7
  /** Reverse lookup: CAIP-2 → simple network name */
@@ -87,38 +87,5 @@ interface PaymentRequired {
87
87
  resource?: ResourceInfo;
88
88
  extensions?: Record<string, unknown>;
89
89
  }
90
- interface RelaiConfig {
91
- apiKey?: string;
92
- network?: RelaiNetwork;
93
- facilitatorUrl?: string;
94
- apiBaseUrl?: string;
95
- }
96
- type DynamicPrice = number | ((req: unknown) => number | Promise<number>);
97
- interface ProtectOptions {
98
- /** Price in USD (e.g., 0.01 for 1 cent) */
99
- price: DynamicPrice;
100
- /** Wallet address to receive payments */
101
- payTo: string;
102
- /** Description shown to payer */
103
- description?: string;
104
- /** Maximum timeout in seconds */
105
- maxTimeout?: number;
106
- /** Custom validation rules */
107
- customRules?: (req: unknown) => boolean | Promise<boolean>;
108
- onPaymentRequired?: (req: unknown, info: {
109
- price: number;
110
- description?: string;
111
- facilitatorUrl?: string;
112
- }) => void;
113
- onPaymentVerified?: (req: unknown, result: PaymentResult) => void;
114
- onError?: (req: unknown, error: unknown) => void;
115
- }
116
- interface PaymentResult {
117
- verified: boolean;
118
- transactionId?: string;
119
- amount?: number;
120
- currency?: string;
121
- error?: string;
122
- }
123
90
 
124
- export { type AcceptsExtra as A, BASE_MAINNET_NETWORK as B, CAIP2_TO_NETWORK as C, type DynamicPrice as D, EXPLORER_TX_URL as E, NETWORK_CAIP2 as N, type PaymentAccept as P, RELAI_FACILITATOR_URL as R, SOLANA_MAINNET_NETWORK as S, USDC_ADDRESSES as U, type WalletSet as W, type RelaiNetwork as a, CHAIN_IDS as b, NETWORK_LABELS as c, USDC_SOLANA as d, USDC_BASE as e, RELAI_NETWORKS as f, isEvm as g, type SolanaWallet as h, isSolana as i, type EvmWallet as j, type ResourceInfo as k, type PaymentRequired as l, type RelaiConfig as m, normalizeNetwork as n, type ProtectOptions as o, type PaymentResult as p };
91
+ export { type AcceptsExtra as A, BASE_MAINNET_NETWORK as B, CAIP2_TO_NETWORK as C, EXPLORER_TX_URL as E, NETWORK_CAIP2 as N, type PaymentAccept as P, RELAI_FACILITATOR_URL as R, SOLANA_MAINNET_NETWORK as S, USDC_ADDRESSES as U, type WalletSet as W, type RelaiNetwork as a, CHAIN_IDS as b, NETWORK_LABELS as c, USDC_SOLANA as d, USDC_BASE as e, RELAI_NETWORKS as f, isEvm as g, type SolanaWallet as h, isSolana as i, type EvmWallet as j, type ResourceInfo as k, type PaymentRequired as l, normalizeNetwork as n };
@@ -1,7 +1,7 @@
1
1
  /** RelAI Facilitator URL */
2
2
  declare const RELAI_FACILITATOR_URL = "https://facilitator.x402.fi";
3
3
  /** All networks supported by RelAI facilitator */
4
- type RelaiNetwork = 'solana' | 'base' | 'avalanche' | 'skale-base';
4
+ type RelaiNetwork = 'solana' | 'base' | 'avalanche' | 'skale-base' | 'skale-bite' | 'polygon' | 'ethereum';
5
5
  /** CAIP-2 network identifiers */
6
6
  declare const NETWORK_CAIP2: Record<RelaiNetwork, string>;
7
7
  /** Reverse lookup: CAIP-2 → simple network name */
@@ -87,38 +87,5 @@ interface PaymentRequired {
87
87
  resource?: ResourceInfo;
88
88
  extensions?: Record<string, unknown>;
89
89
  }
90
- interface RelaiConfig {
91
- apiKey?: string;
92
- network?: RelaiNetwork;
93
- facilitatorUrl?: string;
94
- apiBaseUrl?: string;
95
- }
96
- type DynamicPrice = number | ((req: unknown) => number | Promise<number>);
97
- interface ProtectOptions {
98
- /** Price in USD (e.g., 0.01 for 1 cent) */
99
- price: DynamicPrice;
100
- /** Wallet address to receive payments */
101
- payTo: string;
102
- /** Description shown to payer */
103
- description?: string;
104
- /** Maximum timeout in seconds */
105
- maxTimeout?: number;
106
- /** Custom validation rules */
107
- customRules?: (req: unknown) => boolean | Promise<boolean>;
108
- onPaymentRequired?: (req: unknown, info: {
109
- price: number;
110
- description?: string;
111
- facilitatorUrl?: string;
112
- }) => void;
113
- onPaymentVerified?: (req: unknown, result: PaymentResult) => void;
114
- onError?: (req: unknown, error: unknown) => void;
115
- }
116
- interface PaymentResult {
117
- verified: boolean;
118
- transactionId?: string;
119
- amount?: number;
120
- currency?: string;
121
- error?: string;
122
- }
123
90
 
124
- export { type AcceptsExtra as A, BASE_MAINNET_NETWORK as B, CAIP2_TO_NETWORK as C, type DynamicPrice as D, EXPLORER_TX_URL as E, NETWORK_CAIP2 as N, type PaymentAccept as P, RELAI_FACILITATOR_URL as R, SOLANA_MAINNET_NETWORK as S, USDC_ADDRESSES as U, type WalletSet as W, type RelaiNetwork as a, CHAIN_IDS as b, NETWORK_LABELS as c, USDC_SOLANA as d, USDC_BASE as e, RELAI_NETWORKS as f, isEvm as g, type SolanaWallet as h, isSolana as i, type EvmWallet as j, type ResourceInfo as k, type PaymentRequired as l, type RelaiConfig as m, normalizeNetwork as n, type ProtectOptions as o, type PaymentResult as p };
91
+ export { type AcceptsExtra as A, BASE_MAINNET_NETWORK as B, CAIP2_TO_NETWORK as C, EXPLORER_TX_URL as E, NETWORK_CAIP2 as N, type PaymentAccept as P, RELAI_FACILITATOR_URL as R, SOLANA_MAINNET_NETWORK as S, USDC_ADDRESSES as U, type WalletSet as W, type RelaiNetwork as a, CHAIN_IDS as b, NETWORK_LABELS as c, USDC_SOLANA as d, USDC_BASE as e, RELAI_NETWORKS as f, isEvm as g, type SolanaWallet as h, isSolana as i, type EvmWallet as j, type ResourceInfo as k, type PaymentRequired as l, normalizeNetwork as n };
@@ -158,7 +158,7 @@ function isSolanaNetwork(network) {
158
158
  return network === "solana" || network === "solana-devnet" || network.startsWith("solana:");
159
159
  }
160
160
  function isEvmNetwork(network) {
161
- const evmNetworks = ["base", "base-sepolia", "ethereum", "polygon", "avalanche", "skale-base", "peaq", "sei"];
161
+ const evmNetworks = ["base", "base-sepolia", "ethereum", "polygon", "avalanche", "skale-base", "skale-bite", "peaq", "sei"];
162
162
  return evmNetworks.includes(network) || network.startsWith("eip155:");
163
163
  }
164
164
  function toAtomicUnits(usd, decimals = 6) {