@relai-fi/x402 0.6.4 → 0.6.6

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.
Files changed (66) hide show
  1. package/README.md +116 -0
  2. package/dist/bridge.cjs +109 -0
  3. package/dist/bridge.cjs.map +1 -0
  4. package/dist/bridge.d.cts +78 -0
  5. package/dist/bridge.d.ts +78 -0
  6. package/dist/bridge.js +80 -0
  7. package/dist/bridge.js.map +1 -0
  8. package/dist/client.cjs +209 -1
  9. package/dist/client.cjs.map +1 -1
  10. package/dist/client.d.cts +12 -0
  11. package/dist/client.d.ts +12 -0
  12. package/dist/client.js +209 -1
  13. package/dist/client.js.map +1 -1
  14. package/dist/index.cjs +327 -74
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.js +327 -74
  17. package/dist/index.js.map +1 -1
  18. package/dist/mpp/bridge-client.cjs +23922 -0
  19. package/dist/mpp/bridge-client.cjs.map +1 -0
  20. package/dist/mpp/bridge-client.d.cts +58 -0
  21. package/dist/mpp/bridge-client.d.ts +58 -0
  22. package/dist/mpp/bridge-client.js +23892 -0
  23. package/dist/mpp/bridge-client.js.map +1 -0
  24. package/dist/mpp/bridge-method.cjs +13202 -0
  25. package/dist/mpp/bridge-method.cjs.map +1 -0
  26. package/dist/mpp/bridge-method.d.cts +69 -0
  27. package/dist/mpp/bridge-method.d.ts +69 -0
  28. package/dist/mpp/bridge-method.js +13181 -0
  29. package/dist/mpp/bridge-method.js.map +1 -0
  30. package/dist/mpp/bridge-server.cjs +13887 -0
  31. package/dist/mpp/bridge-server.cjs.map +1 -0
  32. package/dist/mpp/bridge-server.d.cts +62 -0
  33. package/dist/mpp/bridge-server.d.ts +62 -0
  34. package/dist/mpp/bridge-server.js +13866 -0
  35. package/dist/mpp/bridge-server.js.map +1 -0
  36. package/dist/mpp/evm-server.cjs +49 -33
  37. package/dist/mpp/evm-server.cjs.map +1 -1
  38. package/dist/mpp/evm-server.js +49 -33
  39. package/dist/mpp/evm-server.js.map +1 -1
  40. package/dist/mpp/verify-erc20.cjs +71 -0
  41. package/dist/mpp/verify-erc20.cjs.map +1 -0
  42. package/dist/mpp/verify-erc20.d.cts +27 -0
  43. package/dist/mpp/verify-erc20.d.ts +27 -0
  44. package/dist/mpp/verify-erc20.js +46 -0
  45. package/dist/mpp/verify-erc20.js.map +1 -0
  46. package/dist/mpp/verify-spl.cjs +96 -0
  47. package/dist/mpp/verify-spl.cjs.map +1 -0
  48. package/dist/mpp/verify-spl.d.cts +30 -0
  49. package/dist/mpp/verify-spl.d.ts +30 -0
  50. package/dist/mpp/verify-spl.js +71 -0
  51. package/dist/mpp/verify-spl.js.map +1 -0
  52. package/dist/mpp/with-bridge.cjs +23956 -0
  53. package/dist/mpp/with-bridge.cjs.map +1 -0
  54. package/dist/mpp/with-bridge.d.cts +53 -0
  55. package/dist/mpp/with-bridge.d.ts +53 -0
  56. package/dist/mpp/with-bridge.js +23926 -0
  57. package/dist/mpp/with-bridge.js.map +1 -0
  58. package/dist/react/index.cjs +209 -1
  59. package/dist/react/index.cjs.map +1 -1
  60. package/dist/react/index.js +209 -1
  61. package/dist/react/index.js.map +1 -1
  62. package/dist/server.cjs +8 -40
  63. package/dist/server.cjs.map +1 -1
  64. package/dist/server.js +8 -40
  65. package/dist/server.js.map +1 -1
  66. package/package.json +32 -1
package/dist/server.cjs CHANGED
@@ -440,7 +440,8 @@ var Relai = class {
440
440
  }
441
441
  const isRelAI = this.facilitatorUrl.includes("facilitator.x402.fi") || this.facilitatorUrl.includes("relai");
442
442
  if (isRelAI) {
443
- const relaiFeePayer = "0x1892f72fdB3A966b2AD8595aA5f7741Ef72d6085";
443
+ const isSolanaNetwork = caip2.startsWith("solana:");
444
+ const relaiFeePayer = isSolanaNetwork ? "4x4ZhcqiT1FnirM8Ne97iVupkN4NcQgc2YYbE2jDZbZn" : "0x1892f72fdB3A966b2AD8595aA5f7741Ef72d6085";
444
445
  this.feePayerCache.set(caip2, relaiFeePayer);
445
446
  return relaiFeePayer;
446
447
  }
@@ -524,7 +525,6 @@ var Relai = class {
524
525
  const integritasMode = integritasFlow === "single" ? "single_signature_fee_included" : integritasFlow === "dual" ? "dual_signature_split" : void 0;
525
526
  const paymentHeader = req.headers["x-payment"] || req.headers["payment-signature"] || req.headers["x-payment-signature"];
526
527
  const authHeader = req.headers["authorization"] || "";
527
- console.log(`[Relai] MPP check: paymentHeader=${!!paymentHeader}, hasMpp=${!!self.mpp}, authHeader=${authHeader?.slice(0, 30)}`);
528
528
  if (!paymentHeader && self.mpp && /^Payment\s+/i.test(authHeader)) {
529
529
  try {
530
530
  const mppAmount = resolvedPrice.toFixed(6);
@@ -536,10 +536,7 @@ var Relai = class {
536
536
  const mppRequest = new Request(mppUrl, { method: req.method, headers: mppHeaders });
537
537
  const chargeHandler = self.mpp.charge({ amount: mppAmount });
538
538
  const mppResult = await chargeHandler(mppRequest);
539
- console.log(`[Relai] MPP charge result: status=${mppResult.status}, keys=${Object.keys(mppResult)}, hasChallenge=${!!mppResult.challenge}, hasWithReceipt=${!!mppResult.withReceipt}`);
540
539
  if (mppResult.status === 402 && mppResult.challenge instanceof Response) {
541
- const retryAuth = mppResult.challenge.headers.get("www-authenticate");
542
- console.log(`[Relai] MPP re-challenged (credential not accepted). New WWW-Auth: ${retryAuth?.slice(0, 60)}`);
543
540
  }
544
541
  if (mppResult.status !== 200 && !mppResult.withReceipt && mppResult.status !== 402) {
545
542
  if (self.plugins.length > 0) {
@@ -582,7 +579,10 @@ var Relai = class {
582
579
  const dummyResponse = new Response(null);
583
580
  const receiptResponse = mppResult.withReceipt(dummyResponse);
584
581
  const receiptHeader = receiptResponse.headers.get("payment-receipt");
585
- if (receiptHeader) res.setHeader("Payment-Receipt", receiptHeader);
582
+ if (receiptHeader) {
583
+ res.setHeader?.("Payment-Receipt", receiptHeader);
584
+ res.setHeader?.("Cache-Control", "private");
585
+ }
586
586
  }
587
587
  options.onPaymentSettled?.(req, {
588
588
  success: true,
@@ -799,12 +799,13 @@ var Relai = class {
799
799
  if (mppResult?.challenge instanceof Response) {
800
800
  const wwwAuth = mppResult.challenge.headers.get("www-authenticate");
801
801
  if (wwwAuth) {
802
- res.setHeader("WWW-Authenticate", wwwAuth);
802
+ res.setHeader?.("WWW-Authenticate", wwwAuth);
803
803
  }
804
804
  }
805
805
  } catch {
806
806
  }
807
807
  }
808
+ res.setHeader?.("Cache-Control", "no-store");
808
809
  return res.status(402).json(paymentRequiredResponse);
809
810
  }
810
811
  let paymentProof;
@@ -821,39 +822,6 @@ var Relai = class {
821
822
  });
822
823
  }
823
824
  }
824
- if (paymentProof.bridged === true && paymentProof.targetTxId) {
825
- console.log(`[Relai] Bridged payment accepted: source=${paymentProof.sourceTxId}, target=${paymentProof.targetTxId}`);
826
- const paymentInfo2 = {
827
- verified: true,
828
- transactionId: paymentProof.targetTxId,
829
- payer: paymentProof.sourceTxId || "bridge",
830
- network,
831
- amount: resolvedPrice
832
- };
833
- req.payment = paymentInfo2;
834
- req.x402Payer = paymentProof.sourceTxId || "bridge";
835
- req.x402Paid = true;
836
- req.x402Transaction = paymentProof.targetTxId;
837
- req.x402Network = network;
838
- req.x402Bridged = true;
839
- req.x402SourceChain = paymentProof.sourceChain;
840
- const paymentResponse2 = {
841
- x402Version: 2,
842
- scheme: "exact",
843
- network: caip2,
844
- transaction: paymentProof.targetTxId,
845
- payer: paymentProof.sourceTxId,
846
- amount,
847
- asset,
848
- bridged: true
849
- };
850
- res.setHeader(
851
- "PAYMENT-RESPONSE",
852
- Buffer.from(JSON.stringify(paymentResponse2)).toString("base64")
853
- );
854
- options.onPaymentSettled?.(req, { success: true, transaction: paymentProof.targetTxId, payer: paymentProof.sourceTxId });
855
- return next();
856
- }
857
825
  let settlePayTo;
858
826
  if (stripeConfig) {
859
827
  settlePayTo = paymentProof.payload?.authorization?.to || paymentProof.accepted?.payTo || "";
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.ts","../src/types.ts"],"sourcesContent":["// src/server.ts\nimport {\n NETWORK_CAIP2,\n USDC_ADDRESSES,\n RELAI_FACILITATOR_URL,\n resolveToken,\n type NetworkToken,\n type RelaiNetwork,\n} from './types';\nimport type { RelaiPlugin, PluginContext, PluginResult } from './plugins';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Server-side MPP verifier. When provided, protect() will accept\n * Authorization: Payment credentials and verify them via this handler.\n *\n * Compatible with mppx Mppx.create() server instances.\n *\n * @example\n * ```typescript\n * import { Mppx, tempo } from 'mppx/server';\n *\n * const mppx = Mppx.create({\n * secretKey: process.env.MPP_SECRET_KEY,\n * methods: [tempo.charge({ recipient: '0x...', currency: USDC, decimals: 6 })],\n * });\n *\n * const relai = new Relai({\n * network: 'base',\n * mpp: mppx,\n * });\n * ```\n */\n/**\n * MPP server handler — compatible with `Mppx.create()` from `mppx/server`.\n *\n * The `charge()` method returns a handler function that:\n * - On a request WITHOUT a Payment credential → returns `{ status: 402, challenge: Response }`\n * - On a request WITH a valid credential → returns `{ status: 200, withReceipt: fn }`\n */\nexport interface MppServerHandler {\n charge(params: Record<string, unknown>): (request: Request) => Promise<MppChargeResult>;\n}\n\nexport type MppChargeResult = {\n status: number;\n challenge?: Response;\n withReceipt?: (response: Response) => Response;\n receipt?: { method?: string; reference?: string; status?: string };\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 /** Plugins to extend protect() behavior (e.g. freeTier, rateLimit) */\n plugins?: RelaiPlugin[];\n /**\n * Optional MPP (Machine Payment Protocol) server handler.\n * When set, protect() accepts Authorization: Payment credentials\n * (Tempo, Stripe MPP) alongside standard x402 payments.\n */\n mpp?: MppServerHandler;\n}\n\nexport type DynamicPrice = number | ((req: any) => number | Promise<number>);\n\nexport type RelaiIntegritasFlow = 'single' | 'dual';\n\nexport interface RelaiIntegritasOptions {\n /** Enable Integritas by default for this endpoint */\n enabled?: boolean;\n /** Default flow when Integritas is enabled */\n flow?: RelaiIntegritasFlow;\n}\n\nexport interface ProtectOptions {\n /** Price in USD (e.g., 0.01 for 1 cent) */\n price: DynamicPrice;\n /** Optional token asset address for networks supporting multiple tokens */\n asset?: string;\n /** Wallet address to receive payments, or stripePayTo() for Stripe settlement */\n payTo: string | StripePayTo;\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 /** Integritas options (or simple boolean enable flag) */\n integritas?: boolean | RelaiIntegritasOptions;\n /** Override network for this endpoint */\n network?: RelaiNetwork;\n /** Override feePayer address (Solana only) — bypasses facilitator /supported fetch */\n feePayer?: string;\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 splitTransfers?: Record<string, unknown>;\n integritasFeePaid?: boolean;\n provenance?: Record<string, unknown>;\n integritas?: Record<string, unknown>;\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// Stripe Pay-To Helper\n// ============================================================================\n\n/** Config returned by stripePayTo() - used by protect() to create Stripe deposit addresses */\nexport interface StripePayTo {\n readonly __brand: 'stripePayTo';\n readonly secretKey: string;\n /** Stripe crypto deposits network (default: 'base') */\n readonly stripeNetwork: string;\n}\n\n/**\n * Create a Stripe pay-to configuration for x402 payments.\n * Payments settle as USD in your Stripe Dashboard - no crypto knowledge required.\n *\n * Stripe creates a fresh PaymentIntent + deposit address per request.\n * Network is auto-set to Base (Stripe settles USDC on Base).\n *\n * @example\n * ```typescript\n * import Relai, { stripePayTo } from '@relai-fi/x402/server';\n *\n * const relai = new Relai({ network: 'base' });\n *\n * app.get('/api/data', relai.protect({\n * price: 0.01,\n * payTo: stripePayTo(process.env.STRIPE_SECRET_KEY!),\n * }), (req, res) => {\n * res.json({ data: 'paid content' });\n * });\n * ```\n */\nexport function stripePayTo(\n stripeSecretKey: string,\n options?: { network?: string },\n): StripePayTo {\n if (!stripeSecretKey) {\n throw new Error('stripePayTo requires a Stripe secret key');\n }\n return {\n __brand: 'stripePayTo' as const,\n secretKey: stripeSecretKey,\n stripeNetwork: options?.network || 'base',\n };\n}\n\nconst USD_PRICE_CACHE_TTL_MS = 60 * 1000;\nconst usdPriceCache = new Map<string, { usd: number; expiresAt: number }>();\n\nconst GECKOTERMINAL_NETWORK_BY_RELAI: Partial<Record<RelaiNetwork, string>> = {\n polygon: 'polygon_pos',\n};\n\nconst COINGECKO_ID_BY_SYMBOL: Record<string, string> = {\n WETH: 'ethereum',\n WBTC: 'bitcoin',\n USDT: 'tether',\n EURC: 'euro-coin',\n DAI: 'dai',\n cbETH: 'coinbase-wrapped-staked-eth',\n cbBTC: 'coinbase-wrapped-btc',\n};\n\nfunction isStableUsdToken(token: NetworkToken): boolean {\n if (token.isStableUsd === true) return true;\n const symbol = String(token.symbol || '').toUpperCase();\n return symbol === 'USDC' || symbol === 'USDT';\n}\n\nasync function fetchUsdPriceFromCoinGecko(coinId: string): Promise<number> {\n const now = Date.now();\n const cached = usdPriceCache.get(coinId);\n if (cached && cached.expiresAt > now) {\n return cached.usd;\n }\n\n const url = `https://api.coingecko.com/api/v3/simple/price?ids=${encodeURIComponent(coinId)}&vs_currencies=usd`;\n const res = await fetch(url, {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n },\n });\n\n if (!res.ok) {\n throw new Error(`CoinGecko price request failed: HTTP ${res.status}`);\n }\n\n const payload = await res.json() as Record<string, { usd?: number }>;\n const usd = Number(payload?.[coinId]?.usd);\n if (!Number.isFinite(usd) || usd <= 0) {\n throw new Error(`CoinGecko returned invalid usd price for ${coinId}`);\n }\n\n usdPriceCache.set(coinId, {\n usd,\n expiresAt: now + USD_PRICE_CACHE_TTL_MS,\n });\n\n return usd;\n}\n\nasync function fetchUsdPriceFromGeckoTerminal(network: RelaiNetwork, tokenAddress: string): Promise<number> {\n const geckoNetwork = GECKOTERMINAL_NETWORK_BY_RELAI[network];\n if (!geckoNetwork) {\n throw new Error(`GeckoTerminal network not configured for ${network}`);\n }\n\n const normalizedAddress = String(tokenAddress || '').trim().toLowerCase();\n if (!normalizedAddress) {\n throw new Error('GeckoTerminal requires a token address');\n }\n\n const cacheKey = `gt:${geckoNetwork}:${normalizedAddress}`;\n const now = Date.now();\n const cached = usdPriceCache.get(cacheKey);\n if (cached && cached.expiresAt > now) {\n return cached.usd;\n }\n\n const url = `https://api.geckoterminal.com/api/v2/networks/${encodeURIComponent(geckoNetwork)}/tokens/${encodeURIComponent(normalizedAddress)}`;\n const res = await fetch(url, {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n },\n });\n\n if (!res.ok) {\n throw new Error(`GeckoTerminal price request failed: HTTP ${res.status}`);\n }\n\n const payload = await res.json() as { data?: { attributes?: { price_usd?: string | number } } };\n const usd = Number(payload?.data?.attributes?.price_usd);\n if (!Number.isFinite(usd) || usd <= 0) {\n throw new Error(`GeckoTerminal returned invalid usd price for ${normalizedAddress} on ${geckoNetwork}`);\n }\n\n usdPriceCache.set(cacheKey, {\n usd,\n expiresAt: now + USD_PRICE_CACHE_TTL_MS,\n });\n\n return usd;\n}\n\nasync function resolveAmountAtomicFromUsd({\n priceUsd,\n token,\n network,\n}: {\n priceUsd: number;\n token: NetworkToken;\n network: RelaiNetwork;\n}): Promise<string> {\n const decimals = Number(token.decimals);\n if (!Number.isFinite(decimals) || decimals < 0) {\n throw new Error(`Invalid token decimals for ${token.symbol || token.address}`);\n }\n\n if (isStableUsdToken(token)) {\n const units = Math.floor(priceUsd * Math.pow(10, decimals));\n return String(Math.max(1, units));\n }\n\n const symbol = String(token.symbol || '').toUpperCase();\n const coinGeckoId = COINGECKO_ID_BY_SYMBOL[symbol];\n if (!coinGeckoId) {\n throw new Error(`No USD quote source configured for token ${symbol || token.address} on ${network}`);\n }\n\n const overrideEnv = process.env[`EVM_TOKEN_PRICE_${symbol}_USD`];\n let usdPerToken: number;\n if (overrideEnv && Number(overrideEnv) > 0) {\n usdPerToken = Number(overrideEnv);\n } else {\n try {\n usdPerToken = await fetchUsdPriceFromCoinGecko(coinGeckoId);\n } catch (coinGeckoError) {\n try {\n usdPerToken = await fetchUsdPriceFromGeckoTerminal(network, token.address);\n } catch (geckoTerminalError) {\n throw new Error(\n `USD quote failed for ${symbol || token.address} on ${network}. CoinGecko: ${coinGeckoError instanceof Error ? coinGeckoError.message : String(coinGeckoError)}; GeckoTerminal: ${geckoTerminalError instanceof Error ? geckoTerminalError.message : String(geckoTerminalError)}`,\n );\n }\n }\n }\n\n const tokenAmount = priceUsd / usdPerToken;\n const rawUnits = tokenAmount * Math.pow(10, decimals);\n\n if (!Number.isFinite(rawUnits) || rawUnits <= 0) {\n throw new Error(\n `Invalid conversion result for token ${symbol || token.address}: priceUsd=${priceUsd}, usdPerToken=${usdPerToken}`,\n );\n }\n\n return String(Math.max(1, Math.floor(rawUnits)));\n}\n\n/** @internal Type guard for StripePayTo */\nfunction isStripePayTo(payTo: unknown): payTo is StripePayTo {\n return (\n typeof payTo === 'object' &&\n payTo !== null &&\n (payTo as any).__brand === 'stripePayTo'\n );\n}\n\nfunction parseBooleanHeader(value: unknown): boolean | null {\n if (value == null) return null;\n const normalized = String(value).trim().toLowerCase();\n if (normalized === 'true' || normalized === '1' || normalized === 'yes' || normalized === 'on') {\n return true;\n }\n if (normalized === 'false' || normalized === '0' || normalized === 'no' || normalized === 'off') {\n return false;\n }\n return null;\n}\n\nfunction normalizeIntegritasFlow(value: unknown): RelaiIntegritasFlow | undefined {\n const normalized = String(value || '').trim().toLowerCase();\n if (normalized === 'single') return 'single';\n if (normalized === 'dual') return 'dual';\n return undefined;\n}\n\nfunction normalizeIntegritasOptions(\n value: boolean | RelaiIntegritasOptions | undefined,\n): { enabled: boolean; flow?: RelaiIntegritasFlow } {\n if (value === true) return { enabled: true };\n if (value === false || value == null) return { enabled: false };\n\n const flow = normalizeIntegritasFlow(value.flow);\n const enabled =\n typeof value.enabled === 'boolean'\n ? value.enabled\n : true;\n\n return {\n enabled,\n ...(flow ? { flow } : {}),\n };\n}\n\n/**\n * @internal Create a Stripe PaymentIntent with crypto payment method\n * and extract the deposit address.\n */\nasync function createStripeDepositAddress(\n secretKey: string,\n amountUsdCents: number,\n network: string = 'base',\n): Promise<string> {\n const params = new URLSearchParams();\n params.append('amount', String(amountUsdCents));\n params.append('currency', 'usd');\n params.append('payment_method_types[]', 'crypto');\n params.append('payment_method_data[type]', 'crypto');\n params.append('confirm', 'true');\n\n const res = await fetch('https://api.stripe.com/v1/payment_intents', {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${secretKey}`,\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: params.toString(),\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({})) as any;\n const msg = err?.error?.message || res.statusText;\n\n // Provide actionable guidance for common issues\n if (msg.includes('unknown parameter') || msg.includes('crypto')) {\n throw new Error(\n `Stripe crypto payins not enabled on this account. ` +\n `Enable at: https://support.stripe.com/questions/get-started-with-pay-with-crypto ` +\n `(Original: ${msg})`,\n );\n }\n throw new Error(`Stripe PaymentIntent creation failed: ${msg}`);\n }\n\n const pi = await res.json() as any;\n const depositDetails = pi.next_action?.crypto_collect_deposit_details;\n if (!depositDetails) {\n throw new Error(\n 'Stripe PaymentIntent missing crypto deposit details. ' +\n 'Ensure crypto payins are enabled: https://support.stripe.com/questions/get-started-with-pay-with-crypto',\n );\n }\n\n const address = depositDetails.deposit_addresses?.[network]?.address;\n if (!address) {\n throw new Error(`No Stripe deposit address for network: ${network}`);\n }\n\n return address;\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, SKALE Base Sepolia, SKALE BITE, Polygon, and Ethereum.\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 private feePayerCache: Map<string, string> = new Map(); // Cache feePayer per network\n private plugins: RelaiPlugin[];\n private pluginInitPromise: Promise<void> | null = null;\n private mpp?: MppServerHandler;\n\n constructor(config: RelaiServerConfig) {\n this.network = config.network;\n this.facilitatorUrl = config.facilitatorUrl || RELAI_FACILITATOR_URL;\n this.plugins = config.plugins ?? [];\n this.mpp = config.mpp;\n }\n\n private async runPluginInit(): Promise<void> {\n for (const plugin of this.plugins) {\n if (plugin.onInit) {\n try {\n await plugin.onInit();\n } catch (err) {\n console.warn(`[Relai] Plugin '${plugin.name}' init failed:`, err);\n }\n }\n }\n }\n\n /**\n * Get feePayer address for a network (cached)\n */\n private async getFeePayer(caip2: string): Promise<string | undefined> {\n // Check cache first\n if (this.feePayerCache.has(caip2)) {\n return this.feePayerCache.get(caip2);\n }\n\n // If using RelAI facilitator, use hardcoded address (no fetch needed)\n const isRelAI = this.facilitatorUrl.includes('facilitator.x402.fi') || \n this.facilitatorUrl.includes('relai');\n \n if (isRelAI) {\n const relaiFeePayer = '0x1892f72fdB3A966b2AD8595aA5f7741Ef72d6085';\n this.feePayerCache.set(caip2, relaiFeePayer);\n return relaiFeePayer;\n }\n\n // For other facilitators, fetch from /supported\n try {\n const supportedUrl = `${this.facilitatorUrl}/supported`;\n const supportedRes = await fetch(supportedUrl);\n if (supportedRes.ok) {\n const supportedData = await supportedRes.json();\n // Cache all feePayers from supported kinds\n supportedData.kinds?.forEach((kind: any) => {\n if (kind.network && kind.extra?.feePayer) {\n this.feePayerCache.set(kind.network, kind.extra.feePayer);\n }\n });\n return this.feePayerCache.get(caip2);\n }\n } catch (err) {\n // feePayer MUST come from facilitator - cannot use env for security\n console.error(`[Relai] Failed to fetch feePayer from facilitator: ${err}`);\n }\n return undefined;\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 // -----------------------------------------------------------\n // Preflight probe: respond 200 immediately so the preflight\n // plugin (or external clients) can verify the endpoint is alive.\n // -----------------------------------------------------------\n if (req.headers['x-preflight'] === 'true' || req.headers['x-preflight'] === '1') {\n return res.status(200).json({ status: 'ok', preflight: true });\n }\n\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 // Resolve network (Stripe auto-sets to base)\n const stripeConfig = isStripePayTo(options.payTo) ? options.payTo : null;\n const network = stripeConfig\n ? (stripeConfig.stripeNetwork as RelaiNetwork) || 'base'\n : (options.network || self.network);\n const caip2 = NETWORK_CAIP2[network];\n const requestedAsset =\n typeof options.asset === 'string' && options.asset.trim() !== ''\n ? options.asset.trim()\n : undefined;\n const explicitToken = requestedAsset ? resolveToken(network, requestedAsset) : null;\n if (requestedAsset && !explicitToken) {\n return res.status(400).json({\n error: `Unsupported asset ${requestedAsset} for network ${network}`,\n });\n }\n\n const fallbackToken: NetworkToken = {\n address: USDC_ADDRESSES[network],\n symbol: 'USDC',\n name: network === 'skale-bite' ? 'USDC' : 'USD Coin',\n decimals: 6,\n domainVersion: network === 'skale-bite' ? '1' : '2',\n isStableUsd: true,\n };\n const token = explicitToken || resolveToken(network) || fallbackToken;\n const asset = token.address;\n const tokenName = token.name || 'USD Coin';\n const tokenVersion = token.domainVersion || (network === 'skale-bite' ? '1' : '2');\n const tokenDecimals = Number.isFinite(Number(token.decimals)) ? Number(token.decimals) : 6;\n\n let amount: string;\n try {\n amount = await resolveAmountAtomicFromUsd({\n priceUsd: resolvedPrice,\n token,\n network,\n });\n } catch (err) {\n console.error('[Relai] Failed to convert USD amount to token units:', err);\n return res.status(500).json({\n error: 'Failed to quote token amount for payment requirements',\n });\n }\n\n const configuredIntegritas = normalizeIntegritasOptions(options.integritas);\n const headerIntegritasEnabled = parseBooleanHeader(req.headers['x-integritas']);\n const headerIntegritasFlow = normalizeIntegritasFlow(req.headers['x-integritas-flow']);\n const integritasEnabled =\n headerIntegritasEnabled === null\n ? configuredIntegritas.enabled\n : headerIntegritasEnabled;\n const integritasFlow = headerIntegritasFlow || configuredIntegritas.flow;\n const integritasMode =\n integritasFlow === 'single'\n ? 'single_signature_fee_included'\n : (integritasFlow === 'dual' ? 'dual_signature_split' : undefined);\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 // MPP: check for Authorization: Payment credential\n // -----------------------------------------------------------\n const authHeader = req.headers['authorization'] || '';\n console.log(`[Relai] MPP check: paymentHeader=${!!paymentHeader}, hasMpp=${!!self.mpp}, authHeader=${authHeader?.slice(0, 30)}`);\n if (!paymentHeader && self.mpp && /^Payment\\s+/i.test(authHeader)) {\n try {\n // Use the same amount format as the challenge (USD with 6 decimals)\n const mppAmount = resolvedPrice.toFixed(6);\n\n // Build a web Request from the Express req for the mppx handler\n const mppUrl = `${req.protocol}://${req.get('host')}${req.originalUrl}`;\n const mppHeaders = new Headers();\n for (const [k, v] of Object.entries(req.headers)) {\n if (typeof v === 'string') mppHeaders.set(k, v);\n }\n const mppRequest = new Request(mppUrl, { method: req.method, headers: mppHeaders });\n\n // Call the charge handler — it detects the credential in Authorization header\n // and verifies it against the HMAC-signed challenge\n const chargeHandler = self.mpp.charge({ amount: mppAmount } as any);\n const mppResult = await chargeHandler(mppRequest);\n console.log(`[Relai] MPP charge result: status=${mppResult.status}, keys=${Object.keys(mppResult)}, hasChallenge=${!!mppResult.challenge}, hasWithReceipt=${!!mppResult.withReceipt}`);\n if (mppResult.status === 402 && mppResult.challenge instanceof Response) {\n const retryAuth = mppResult.challenge.headers.get('www-authenticate');\n console.log(`[Relai] MPP re-challenged (credential not accepted). New WWW-Auth: ${retryAuth?.slice(0, 60)}`);\n }\n\n // MPP charge genuinely failed (not a 402 re-challenge, which is normal handshake)\n // Only notify plugins for non-402 failures (e.g. 500, invalid credential, etc.)\n if (mppResult.status !== 200 && !mppResult.withReceipt && mppResult.status !== 402) {\n if (self.plugins.length > 0) {\n const mppFailCtx: PluginContext = {\n network,\n price: resolvedPrice,\n path: req.path || req.originalUrl || '/',\n method: (req.method || 'GET').toUpperCase(),\n };\n const mppFailResult: SettleResult = {\n success: false,\n payer: 'mpp',\n error: `MPP charge failed with status ${mppResult.status}`,\n };\n for (const plugin of self.plugins) {\n if (!plugin.afterSettled) continue;\n try {\n await plugin.afterSettled(req, mppFailResult, mppFailCtx);\n } catch (pluginErr) {\n console.warn(`[Relai] Plugin '${plugin.name}' afterSettled error (non-blocking):`, pluginErr);\n }\n }\n }\n }\n\n if (mppResult.status === 200 || mppResult.withReceipt) {\n // Payment verified by mppx\n const receipt = mppResult.receipt || {};\n const paymentInfo: PaymentInfo = {\n verified: true,\n transactionId: receipt.reference || '',\n payer: receipt.method || 'mpp',\n network,\n amount: resolvedPrice,\n };\n req.payment = paymentInfo;\n req.x402Payer = receipt.method ? `${receipt.method}-mpp` : 'mpp';\n req.x402Paid = true;\n req.x402Transaction = receipt.reference || '';\n req.x402Network = network;\n\n // Use withReceipt to attach Payment-Receipt header\n if (mppResult.withReceipt) {\n const dummyResponse = new Response(null);\n const receiptResponse = mppResult.withReceipt(dummyResponse);\n const receiptHeader = receiptResponse.headers.get('payment-receipt');\n if (receiptHeader) res.setHeader('Payment-Receipt', receiptHeader);\n }\n\n options.onPaymentSettled?.(req, {\n success: true,\n transaction: receipt.reference,\n payer: req.x402Payer,\n } as SettleResult);\n\n // Plugin hooks: afterSettled\n if (self.plugins.length > 0) {\n const settleCtx: PluginContext = {\n network,\n price: resolvedPrice,\n path: req.path || req.originalUrl || '/',\n method: (req.method || 'GET').toUpperCase(),\n };\n for (const plugin of self.plugins) {\n if (!plugin.afterSettled) continue;\n try {\n await plugin.afterSettled(req, {\n success: true,\n transaction: receipt.reference,\n payer: req.x402Payer,\n } as SettleResult, settleCtx);\n } catch (pluginErr) {\n console.warn(`[Relai] Plugin '${plugin.name}' afterSettled error (non-blocking):`, pluginErr);\n }\n }\n }\n\n return next();\n }\n } catch (mppErr) {\n console.warn(`[Relai] MPP verification failed (${mppErr instanceof Error ? mppErr.message : mppErr}), falling through to x402`);\n\n // Notify plugins of MPP failure\n if (self.plugins.length > 0) {\n const mppErrCtx: PluginContext = {\n network,\n price: resolvedPrice,\n path: req.path || req.originalUrl || '/',\n method: (req.method || 'GET').toUpperCase(),\n };\n const mppErrResult: SettleResult = {\n success: false,\n payer: 'mpp',\n error: mppErr instanceof Error ? mppErr.message : String(mppErr),\n };\n for (const plugin of self.plugins) {\n if (!plugin.afterSettled) continue;\n try {\n await plugin.afterSettled(req, mppErrResult, mppErrCtx);\n } catch (pluginErr) {\n console.warn(`[Relai] Plugin '${plugin.name}' afterSettled error (non-blocking):`, pluginErr);\n }\n }\n }\n }\n }\n\n // -----------------------------------------------------------\n // Plugin hooks: beforePaymentCheck\n // If any plugin returns { skip: true }, bypass payment entirely.\n // Ensure plugins are initialized (config synced) before checking.\n // -----------------------------------------------------------\n if (!paymentHeader && self.plugins.length > 0) {\n if (!self.pluginInitPromise) {\n self.pluginInitPromise = self.runPluginInit();\n }\n await self.pluginInitPromise;\n const pluginCtx: PluginContext = {\n network,\n price: resolvedPrice,\n path: req.path || req.originalUrl || '/',\n method: (req.method || 'GET').toUpperCase(),\n };\n\n for (const plugin of self.plugins) {\n if (!plugin.beforePaymentCheck) continue;\n try {\n const pluginResult = await plugin.beforePaymentCheck(req, pluginCtx);\n\n // Reject: plugin blocks the request entirely (e.g. service unhealthy)\n if (pluginResult?.reject) {\n const rejectStatus = pluginResult.rejectStatus || 503;\n if (pluginResult.headers) {\n for (const [k, v] of Object.entries(pluginResult.headers)) {\n res.setHeader(k, v);\n }\n }\n return res.status(rejectStatus).json({\n error: pluginResult.rejectMessage || 'Service unavailable',\n plugin: plugin.name,\n });\n }\n\n // Skip: bypass payment and serve content for free\n if (pluginResult?.skip) {\n // Set plugin-provided headers\n if (pluginResult.headers) {\n for (const [k, v] of Object.entries(pluginResult.headers)) {\n res.setHeader(k, v);\n }\n }\n // Attach plugin metadata to request\n req.pluginMeta = { ...(req.pluginMeta || {}), ...(pluginResult.meta || {}) };\n req.x402Paid = false;\n req.x402Free = true;\n req.x402Plugin = plugin.name;\n // Still set up afterSettled interceptor so plugins (e.g. refund) can\n // re-issue a credit if the endpoint fails on this free call too.\n const skipPluginsWithHook = self.plugins.filter((p) => !!p.afterSettled);\n if (skipPluginsWithHook.length > 0) {\n const skipCtx: PluginContext = {\n network,\n price: resolvedPrice,\n path: req.path || req.originalUrl || '/',\n method: (req.method || 'GET').toUpperCase(),\n };\n const skipResult: SettleResult = {\n success: true,\n payer: req.headers?.['x-wallet-address'] || req.headers?.['x-buyer-address'] || req.ip || req.socket?.remoteAddress || 'unknown',\n transaction: '',\n } as any;\n const originalJsonSkip = (res as any).json?.bind(res);\n const originalSendSkip = (res as any).send?.bind(res);\n let skipFired = false;\n const fireSkipAfterSettled = (statusCode: number) => {\n if (skipFired) return;\n skipFired = true;\n const resultWithStatus = { ...skipResult, statusCode };\n for (const p of skipPluginsWithHook) {\n p.afterSettled!(req, resultWithStatus, skipCtx).catch((e: unknown) => {\n console.warn(`[Relai] Plugin '${p.name}' afterSettled (skip) error:`, e);\n });\n }\n };\n if (typeof originalJsonSkip === 'function') {\n (res as any).json = function (body: unknown) {\n fireSkipAfterSettled(res.statusCode ?? 200);\n (res as any).json = originalJsonSkip;\n return originalJsonSkip(body);\n };\n }\n if (typeof originalSendSkip === 'function') {\n (res as any).send = function (body: unknown) {\n fireSkipAfterSettled(res.statusCode ?? 200);\n (res as any).send = originalSendSkip;\n return originalSendSkip(body);\n };\n }\n }\n return next();\n }\n } catch (pluginErr) {\n console.warn(`[Relai] Plugin '${plugin.name}' beforePaymentCheck error (non-blocking):`, pluginErr);\n }\n }\n }\n\n // -----------------------------------------------------------\n // No payment → return 402 Payment Required\n // -----------------------------------------------------------\n if (!paymentHeader) {\n options.onPaymentRequired?.(req, { price: resolvedPrice, network });\n\n // Resolve payTo address (Stripe creates a fresh deposit address per request)\n let resolvedPayTo: string;\n if (stripeConfig) {\n const amountInCents = Math.max(1, Math.round(resolvedPrice * 100));\n resolvedPayTo = await createStripeDepositAddress(\n stripeConfig.secretKey,\n amountInCents,\n stripeConfig.stripeNetwork,\n );\n } else {\n resolvedPayTo = options.payTo as string;\n }\n\n // Get facilitator feePayer address — use explicit override if provided, otherwise fetch\n const feePayer = (options.feePayer as string | undefined) || await self.getFeePayer(caip2);\n\n let paymentRequiredResponse: any = {\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: resolvedPayTo,\n maxTimeoutSeconds: options.maxTimeoutSeconds || 60,\n extra: {\n name: tokenName,\n version: tokenVersion,\n decimals: tokenDecimals,\n symbol: token.symbol,\n ...(feePayer && { feePayer }), // Add feePayer if available\n ...(integritasEnabled ? { integritasEnabled: true } : {}),\n ...(integritasFlow ? { integritasFlow } : {}),\n ...(integritasMode ? { integritasMode } : {}),\n ...(integritasFlow === 'single' ? { integritasSingleSignature: true } : {}),\n },\n }],\n ...((configuredIntegritas.enabled || integritasEnabled || !!integritasFlow)\n ? {\n extensions: {\n integritas: {\n available: true,\n selectedFlow: integritasFlow || null,\n availableFlows: ['single', 'dual'],\n enabled: integritasEnabled,\n },\n },\n }\n : {}),\n };\n\n // Plugin hooks: enrich402Response (e.g. bridge adds extensions.bridge)\n if (self.plugins.length > 0) {\n const enrichCtx: PluginContext = {\n network,\n price: resolvedPrice,\n path: req.path || req.originalUrl || '/',\n method: (req.method || 'GET').toUpperCase(),\n };\n for (const plugin of self.plugins) {\n if (!plugin.enrich402Response) continue;\n try {\n paymentRequiredResponse = plugin.enrich402Response(paymentRequiredResponse, enrichCtx) || paymentRequiredResponse;\n } catch (pluginErr) {\n console.warn(`[Relai] Plugin '${plugin.name}' enrich402Response error (non-blocking):`, pluginErr);\n }\n }\n }\n\n // Add MPP challenge header if mpp is configured\n if (self.mpp?.charge) {\n try {\n const mppAmount = resolvedPrice.toFixed(6);\n const chargeHandler = self.mpp.charge({ amount: mppAmount } as any);\n const mockReq = new Request(`${req.protocol}://${req.get('host')}${req.originalUrl}`);\n const mppResult = await chargeHandler(mockReq);\n if (mppResult?.challenge instanceof Response) {\n const wwwAuth = mppResult.challenge.headers.get('www-authenticate');\n if (wwwAuth) {\n res.setHeader('WWW-Authenticate', wwwAuth);\n }\n }\n } catch {\n // Non-fatal — x402 response is still valid without MPP headers\n }\n }\n\n return res.status(402).json(paymentRequiredResponse);\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 // -----------------------------------------------------------\n // Bridged payment: trust the bridge proof (already settled)\n // -----------------------------------------------------------\n if (paymentProof.bridged === true && paymentProof.targetTxId) {\n console.log(`[Relai] Bridged payment accepted: source=${paymentProof.sourceTxId}, target=${paymentProof.targetTxId}`);\n\n const paymentInfo: PaymentInfo = {\n verified: true,\n transactionId: paymentProof.targetTxId,\n payer: paymentProof.sourceTxId || 'bridge',\n network,\n amount: resolvedPrice,\n };\n req.payment = paymentInfo;\n req.x402Payer = paymentProof.sourceTxId || 'bridge';\n req.x402Paid = true;\n req.x402Transaction = paymentProof.targetTxId;\n req.x402Network = network;\n req.x402Bridged = true;\n req.x402SourceChain = paymentProof.sourceChain;\n\n const paymentResponse = {\n x402Version: 2,\n scheme: 'exact',\n network: caip2,\n transaction: paymentProof.targetTxId,\n payer: paymentProof.sourceTxId,\n amount,\n asset,\n bridged: true,\n };\n res.setHeader(\n 'PAYMENT-RESPONSE',\n Buffer.from(JSON.stringify(paymentResponse)).toString('base64'),\n );\n\n options.onPaymentSettled?.(req, { success: true, transaction: paymentProof.targetTxId, payer: paymentProof.sourceTxId } as SettleResult);\n\n return next();\n }\n\n // -----------------------------------------------------------\n // Standard payment: settle via facilitator\n // -----------------------------------------------------------\n\n // Resolve payTo for settle (extract from signed proof when using Stripe)\n let settlePayTo: string;\n if (stripeConfig) {\n settlePayTo =\n paymentProof.payload?.authorization?.to ||\n paymentProof.accepted?.payTo ||\n '';\n if (!settlePayTo) {\n return res.status(400).json({\n x402Version: 2,\n error: 'Cannot extract destination address from payment proof',\n });\n }\n } else {\n settlePayTo = options.payTo as string;\n }\n\n // Build payment requirements for facilitator\n const paymentRequirements = {\n scheme: 'exact',\n network: caip2,\n amount,\n asset,\n payTo: settlePayTo,\n maxTimeoutSeconds: options.maxTimeoutSeconds || 60,\n extra: {\n name: tokenName,\n version: tokenVersion,\n decimals: tokenDecimals,\n symbol: token.symbol,\n ...(integritasEnabled ? { integritasEnabled: true } : {}),\n ...(integritasFlow ? { integritasFlow } : {}),\n ...(integritasMode ? { integritasMode } : {}),\n ...(integritasFlow === 'single' ? { integritasSingleSignature: true } : {}),\n },\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 // Notify plugins of settlement failure (circuit breaker, refund, etc.)\n if (self.plugins.length > 0) {\n const failCtx: PluginContext = {\n network,\n price: resolvedPrice,\n path: req.path || req.originalUrl || '/',\n method: (req.method || 'GET').toUpperCase(),\n };\n for (const plugin of self.plugins) {\n if (!plugin.afterSettled) continue;\n try {\n await plugin.afterSettled(req, result, failCtx);\n } catch (pluginErr) {\n console.warn(`[Relai] Plugin '${plugin.name}' afterSettled error (non-blocking):`, pluginErr);\n }\n }\n }\n\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 // Plugin hooks: afterSettled — called AFTER the handler responds so plugins\n // can see the actual HTTP status code (e.g. circuit breaker, refund).\n if (self.plugins.length > 0) {\n const settleCtx: PluginContext = {\n network,\n price: resolvedPrice,\n path: req.path || req.originalUrl || '/',\n method: (req.method || 'GET').toUpperCase(),\n };\n const pluginsWithHook = self.plugins.filter((p) => !!p.afterSettled);\n if (pluginsWithHook.length > 0) {\n // Wrap res.json / res.send to fire afterSettled with actual statusCode\n const originalJson = (res as any).json?.bind(res);\n const originalSend = (res as any).send?.bind(res);\n let afterSettledFired = false;\n const fireAfterSettled = (statusCode: number) => {\n if (afterSettledFired) return;\n afterSettledFired = true;\n const resultWithStatus = { ...result, statusCode };\n for (const plugin of pluginsWithHook) {\n plugin.afterSettled!(req, resultWithStatus, settleCtx).catch((e: unknown) => {\n console.warn(`[Relai] Plugin '${plugin.name}' afterSettled error (non-blocking):`, e);\n });\n }\n };\n if (typeof originalJson === 'function') {\n (res as any).json = function (body: unknown) {\n fireAfterSettled(res.statusCode ?? 200);\n (res as any).json = originalJson; // restore\n return originalJson(body);\n };\n }\n if (typeof originalSend === 'function') {\n (res as any).send = function (body: unknown) {\n fireAfterSettled(res.statusCode ?? 200);\n (res as any).send = originalSend; // restore\n return originalSend(body);\n };\n }\n }\n }\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","// 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 =\n | 'solana'\n | 'solana-devnet'\n | 'base'\n | 'avalanche'\n | 'skale-base'\n | 'skale-base-sepolia'\n | 'skale-bite'\n | 'polygon'\n | 'ethereum'\n | 'telos';\n\n/** CAIP-2 network identifiers */\nexport const NETWORK_CAIP2: Record<RelaiNetwork, string> = {\n 'solana': 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',\n 'solana-devnet': 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1',\n 'base': 'eip155:8453',\n 'avalanche': 'eip155:43114',\n 'skale-base': 'eip155:1187947933',\n 'skale-base-sepolia': 'eip155:324705682',\n 'skale-bite': 'eip155:103698795',\n 'polygon': 'eip155:137',\n 'ethereum': 'eip155:1',\n 'telos': 'eip155:40',\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-base-sepolia': 324705682,\n 'skale-bite': 103698795,\n 'polygon': 137,\n 'ethereum': 1,\n 'telos': 40,\n};\n\nexport interface NetworkToken {\n address: string;\n symbol: string;\n name: string;\n decimals: number;\n domainVersion?: string;\n isStableUsd?: boolean;\n standards?: string[];\n}\n\n/** Token metadata per network (default token is always the first entry) */\nexport const NETWORK_TOKENS: Partial<Record<RelaiNetwork, NetworkToken[]>> = {\n 'solana': [\n {\n address: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',\n symbol: 'USDC',\n name: 'USD Coin',\n decimals: 6,\n },\n ],\n 'solana-devnet': [\n {\n address: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',\n symbol: 'USDC',\n name: 'USD Coin (Devnet)',\n decimals: 6,\n },\n ],\n 'base': [\n { address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', symbol: 'USDC', name: 'USD Coin', decimals: 6, domainVersion: '2', isStableUsd: true },\n ],\n 'avalanche': [\n {\n address: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',\n symbol: 'USDC',\n name: 'USD Coin',\n decimals: 6,\n domainVersion: '2',\n isStableUsd: true,\n },\n ],\n 'telos': [\n {\n address: '0x818ec0a7fe18ff94269904fced6ae3dae6d6dc0b',\n symbol: 'USDC',\n name: 'USD Coin',\n decimals: 6,\n isStableUsd: true,\n standards: ['eip2612'],\n },\n ],\n 'skale-base': [\n {\n address: '0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20',\n symbol: 'USDC',\n name: 'Bridged USDC (SKALE Bridge)',\n decimals: 6,\n domainVersion: '2',\n isStableUsd: true,\n },\n {\n address: '0x2bF5bF154b515EaA82C31a65ec11554fF5aF7fCA',\n symbol: 'USDT',\n name: 'Bridged USDT (SKALE Bridge)',\n decimals: 6,\n domainVersion: '1',\n isStableUsd: true,\n },\n {\n address: '0x1aeeCFE5454c83B42D8A316246CAc9739E7f690e',\n symbol: 'WBTC',\n name: 'Wrapped Bitcoin',\n decimals: 8,\n domainVersion: '1',\n isStableUsd: false,\n },\n {\n address: '0x7bD39ABBd0Dd13103542cAe3276C7fA332bCA486',\n symbol: 'WETH',\n name: 'Wrapped Ether',\n decimals: 18,\n domainVersion: '1',\n isStableUsd: false,\n },\n ],\n 'skale-base-sepolia': [\n {\n address: '0x2e08028E3C4c2356572E096d8EF835cD5C6030bD',\n symbol: 'USDC',\n name: 'Bridged USDC (SKALE Bridge)',\n decimals: 6,\n domainVersion: '2',\n isStableUsd: true,\n },\n {\n address: '0x3ca0a49f511c2c89c4dcbbf1731120d8919050bf',\n symbol: 'USDT',\n name: 'Bridged USDT (SKALE Bridge)',\n decimals: 6,\n domainVersion: '1',\n isStableUsd: true,\n },\n {\n address: '0x4512eacd4186b025186e1cf6cc0d89497c530e87',\n symbol: 'WBTC',\n name: 'Wrapped Bitcoin',\n decimals: 8,\n domainVersion: '1',\n isStableUsd: false,\n },\n {\n address: '0xf94056bd7f6965db3757e1b145f200b7346b4fc0',\n symbol: 'WETH',\n name: 'Wrapped Ether',\n decimals: 18,\n domainVersion: '1',\n isStableUsd: false,\n },\n ],\n 'skale-bite': [\n {\n address: '0xc4083B1E81ceb461Ccef3FDa8A9F24F0d764B6D8',\n symbol: 'USDC',\n name: 'USDC',\n decimals: 6,\n domainVersion: '1',\n isStableUsd: true,\n },\n ],\n 'polygon': [\n {\n address: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n symbol: 'USDC',\n name: 'USD Coin',\n decimals: 6,\n domainVersion: '2',\n isStableUsd: true,\n },\n ],\n 'ethereum': [\n {\n address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n symbol: 'USDC',\n name: 'USD Coin',\n decimals: 6,\n domainVersion: '2',\n isStableUsd: true,\n },\n ],\n};\n\nexport function resolveToken(network: RelaiNetwork, asset?: string): NetworkToken | null {\n const tokens = NETWORK_TOKENS[network];\n if (!tokens || tokens.length === 0) return null;\n if (!asset) return tokens[0];\n\n const normalized = String(asset).toLowerCase();\n return tokens.find((token) => token.address.toLowerCase() === normalized) || null;\n}\n\n/** USDC contract addresses per network */\nexport const USDC_ADDRESSES: Record<RelaiNetwork, string> = {\n 'solana': 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',\n 'solana-devnet': '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',\n 'base': '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n 'avalanche': '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',\n 'skale-base': '0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20',\n 'skale-base-sepolia': '0x2e08028E3C4c2356572E096d8EF835cD5C6030bD',\n 'skale-bite': '0xc4083B1E81ceb461Ccef3FDa8A9F24F0d764B6D8',\n 'polygon': '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n 'ethereum': '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n 'telos': '0x818ec0a7fe18ff94269904fced6ae3dae6d6dc0b',\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 'solana-devnet': (tx) => `https://solscan.io/tx/${tx}?cluster=devnet`,\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-base-sepolia': (tx) => `https://base-sepolia-testnet-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 'telos': (tx) => `https://teloscan.io/tx/${tx}`,\n};\n\n/** Human-readable network labels */\nexport const NETWORK_LABELS: Record<RelaiNetwork, string> = {\n 'solana': 'Solana',\n 'solana-devnet': 'Solana Devnet',\n 'base': 'Base',\n 'avalanche': 'Avalanche',\n 'skale-base': 'SKALE Base',\n 'skale-base-sepolia': 'SKALE Base Sepolia',\n 'skale-bite': 'SKALE BITE V2',\n 'polygon': 'Polygon',\n 'ethereum': 'Ethereum',\n 'telos': 'Telos EVM',\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[] = [\n 'solana',\n 'solana-devnet',\n 'base',\n 'avalanche',\n 'skale-base',\n 'skale-base-sepolia',\n 'skale-bite',\n 'polygon',\n 'ethereum',\n 'telos',\n];\n\n/** Check if a network is Solana-based */\nexport function isSolana(network: string): boolean {\n return network === 'solana' || network === 'solana-devnet' || 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-base-sepolia', 'skale-bite', 'polygon', 'ethereum', 'telos'].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"],"mappings":"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","names":["paymentInfo","paymentResponse"]}
1
+ {"version":3,"sources":["../src/server.ts","../src/types.ts"],"sourcesContent":["// src/server.ts\nimport {\n NETWORK_CAIP2,\n USDC_ADDRESSES,\n RELAI_FACILITATOR_URL,\n resolveToken,\n type NetworkToken,\n type RelaiNetwork,\n} from './types';\nimport type { RelaiPlugin, PluginContext, PluginResult } from './plugins';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Server-side MPP verifier. When provided, protect() will accept\n * Authorization: Payment credentials and verify them via this handler.\n *\n * Compatible with mppx Mppx.create() server instances.\n *\n * @example\n * ```typescript\n * import { Mppx, tempo } from 'mppx/server';\n *\n * const mppx = Mppx.create({\n * secretKey: process.env.MPP_SECRET_KEY,\n * methods: [tempo.charge({ recipient: '0x...', currency: USDC, decimals: 6 })],\n * });\n *\n * const relai = new Relai({\n * network: 'base',\n * mpp: mppx,\n * });\n * ```\n */\n/**\n * MPP server handler — compatible with `Mppx.create()` from `mppx/server`.\n *\n * The `charge()` method returns a handler function that:\n * - On a request WITHOUT a Payment credential → returns `{ status: 402, challenge: Response }`\n * - On a request WITH a valid credential → returns `{ status: 200, withReceipt: fn }`\n */\nexport interface MppServerHandler {\n charge(params: Record<string, unknown>): (request: Request) => Promise<MppChargeResult>;\n}\n\nexport type MppChargeResult = {\n status: number;\n challenge?: Response;\n withReceipt?: (response: Response) => Response;\n receipt?: { method?: string; reference?: string; status?: string };\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 /** Plugins to extend protect() behavior (e.g. freeTier, rateLimit) */\n plugins?: RelaiPlugin[];\n /**\n * Optional MPP (Machine Payment Protocol) server handler.\n * When set, protect() accepts Authorization: Payment credentials\n * (Tempo, Stripe MPP) alongside standard x402 payments.\n */\n mpp?: MppServerHandler;\n}\n\nexport type DynamicPrice = number | ((req: any) => number | Promise<number>);\n\nexport type RelaiIntegritasFlow = 'single' | 'dual';\n\nexport interface RelaiIntegritasOptions {\n /** Enable Integritas by default for this endpoint */\n enabled?: boolean;\n /** Default flow when Integritas is enabled */\n flow?: RelaiIntegritasFlow;\n}\n\nexport interface ProtectOptions {\n /** Price in USD (e.g., 0.01 for 1 cent) */\n price: DynamicPrice;\n /** Optional token asset address for networks supporting multiple tokens */\n asset?: string;\n /** Wallet address to receive payments, or stripePayTo() for Stripe settlement */\n payTo: string | StripePayTo;\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 /** Integritas options (or simple boolean enable flag) */\n integritas?: boolean | RelaiIntegritasOptions;\n /** Override network for this endpoint */\n network?: RelaiNetwork;\n /** Override feePayer address (Solana only) — bypasses facilitator /supported fetch */\n feePayer?: string;\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 splitTransfers?: Record<string, unknown>;\n integritasFeePaid?: boolean;\n provenance?: Record<string, unknown>;\n integritas?: Record<string, unknown>;\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// Stripe Pay-To Helper\n// ============================================================================\n\n/** Config returned by stripePayTo() - used by protect() to create Stripe deposit addresses */\nexport interface StripePayTo {\n readonly __brand: 'stripePayTo';\n readonly secretKey: string;\n /** Stripe crypto deposits network (default: 'base') */\n readonly stripeNetwork: string;\n}\n\n/**\n * Create a Stripe pay-to configuration for x402 payments.\n * Payments settle as USD in your Stripe Dashboard - no crypto knowledge required.\n *\n * Stripe creates a fresh PaymentIntent + deposit address per request.\n * Network is auto-set to Base (Stripe settles USDC on Base).\n *\n * @example\n * ```typescript\n * import Relai, { stripePayTo } from '@relai-fi/x402/server';\n *\n * const relai = new Relai({ network: 'base' });\n *\n * app.get('/api/data', relai.protect({\n * price: 0.01,\n * payTo: stripePayTo(process.env.STRIPE_SECRET_KEY!),\n * }), (req, res) => {\n * res.json({ data: 'paid content' });\n * });\n * ```\n */\nexport function stripePayTo(\n stripeSecretKey: string,\n options?: { network?: string },\n): StripePayTo {\n if (!stripeSecretKey) {\n throw new Error('stripePayTo requires a Stripe secret key');\n }\n return {\n __brand: 'stripePayTo' as const,\n secretKey: stripeSecretKey,\n stripeNetwork: options?.network || 'base',\n };\n}\n\nconst USD_PRICE_CACHE_TTL_MS = 60 * 1000;\nconst usdPriceCache = new Map<string, { usd: number; expiresAt: number }>();\n\nconst GECKOTERMINAL_NETWORK_BY_RELAI: Partial<Record<RelaiNetwork, string>> = {\n polygon: 'polygon_pos',\n};\n\nconst COINGECKO_ID_BY_SYMBOL: Record<string, string> = {\n WETH: 'ethereum',\n WBTC: 'bitcoin',\n USDT: 'tether',\n EURC: 'euro-coin',\n DAI: 'dai',\n cbETH: 'coinbase-wrapped-staked-eth',\n cbBTC: 'coinbase-wrapped-btc',\n};\n\nfunction isStableUsdToken(token: NetworkToken): boolean {\n if (token.isStableUsd === true) return true;\n const symbol = String(token.symbol || '').toUpperCase();\n return symbol === 'USDC' || symbol === 'USDT';\n}\n\nasync function fetchUsdPriceFromCoinGecko(coinId: string): Promise<number> {\n const now = Date.now();\n const cached = usdPriceCache.get(coinId);\n if (cached && cached.expiresAt > now) {\n return cached.usd;\n }\n\n const url = `https://api.coingecko.com/api/v3/simple/price?ids=${encodeURIComponent(coinId)}&vs_currencies=usd`;\n const res = await fetch(url, {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n },\n });\n\n if (!res.ok) {\n throw new Error(`CoinGecko price request failed: HTTP ${res.status}`);\n }\n\n const payload = await res.json() as Record<string, { usd?: number }>;\n const usd = Number(payload?.[coinId]?.usd);\n if (!Number.isFinite(usd) || usd <= 0) {\n throw new Error(`CoinGecko returned invalid usd price for ${coinId}`);\n }\n\n usdPriceCache.set(coinId, {\n usd,\n expiresAt: now + USD_PRICE_CACHE_TTL_MS,\n });\n\n return usd;\n}\n\nasync function fetchUsdPriceFromGeckoTerminal(network: RelaiNetwork, tokenAddress: string): Promise<number> {\n const geckoNetwork = GECKOTERMINAL_NETWORK_BY_RELAI[network];\n if (!geckoNetwork) {\n throw new Error(`GeckoTerminal network not configured for ${network}`);\n }\n\n const normalizedAddress = String(tokenAddress || '').trim().toLowerCase();\n if (!normalizedAddress) {\n throw new Error('GeckoTerminal requires a token address');\n }\n\n const cacheKey = `gt:${geckoNetwork}:${normalizedAddress}`;\n const now = Date.now();\n const cached = usdPriceCache.get(cacheKey);\n if (cached && cached.expiresAt > now) {\n return cached.usd;\n }\n\n const url = `https://api.geckoterminal.com/api/v2/networks/${encodeURIComponent(geckoNetwork)}/tokens/${encodeURIComponent(normalizedAddress)}`;\n const res = await fetch(url, {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n },\n });\n\n if (!res.ok) {\n throw new Error(`GeckoTerminal price request failed: HTTP ${res.status}`);\n }\n\n const payload = await res.json() as { data?: { attributes?: { price_usd?: string | number } } };\n const usd = Number(payload?.data?.attributes?.price_usd);\n if (!Number.isFinite(usd) || usd <= 0) {\n throw new Error(`GeckoTerminal returned invalid usd price for ${normalizedAddress} on ${geckoNetwork}`);\n }\n\n usdPriceCache.set(cacheKey, {\n usd,\n expiresAt: now + USD_PRICE_CACHE_TTL_MS,\n });\n\n return usd;\n}\n\nasync function resolveAmountAtomicFromUsd({\n priceUsd,\n token,\n network,\n}: {\n priceUsd: number;\n token: NetworkToken;\n network: RelaiNetwork;\n}): Promise<string> {\n const decimals = Number(token.decimals);\n if (!Number.isFinite(decimals) || decimals < 0) {\n throw new Error(`Invalid token decimals for ${token.symbol || token.address}`);\n }\n\n if (isStableUsdToken(token)) {\n const units = Math.floor(priceUsd * Math.pow(10, decimals));\n return String(Math.max(1, units));\n }\n\n const symbol = String(token.symbol || '').toUpperCase();\n const coinGeckoId = COINGECKO_ID_BY_SYMBOL[symbol];\n if (!coinGeckoId) {\n throw new Error(`No USD quote source configured for token ${symbol || token.address} on ${network}`);\n }\n\n const overrideEnv = process.env[`EVM_TOKEN_PRICE_${symbol}_USD`];\n let usdPerToken: number;\n if (overrideEnv && Number(overrideEnv) > 0) {\n usdPerToken = Number(overrideEnv);\n } else {\n try {\n usdPerToken = await fetchUsdPriceFromCoinGecko(coinGeckoId);\n } catch (coinGeckoError) {\n try {\n usdPerToken = await fetchUsdPriceFromGeckoTerminal(network, token.address);\n } catch (geckoTerminalError) {\n throw new Error(\n `USD quote failed for ${symbol || token.address} on ${network}. CoinGecko: ${coinGeckoError instanceof Error ? coinGeckoError.message : String(coinGeckoError)}; GeckoTerminal: ${geckoTerminalError instanceof Error ? geckoTerminalError.message : String(geckoTerminalError)}`,\n );\n }\n }\n }\n\n const tokenAmount = priceUsd / usdPerToken;\n const rawUnits = tokenAmount * Math.pow(10, decimals);\n\n if (!Number.isFinite(rawUnits) || rawUnits <= 0) {\n throw new Error(\n `Invalid conversion result for token ${symbol || token.address}: priceUsd=${priceUsd}, usdPerToken=${usdPerToken}`,\n );\n }\n\n return String(Math.max(1, Math.floor(rawUnits)));\n}\n\n/** @internal Type guard for StripePayTo */\nfunction isStripePayTo(payTo: unknown): payTo is StripePayTo {\n return (\n typeof payTo === 'object' &&\n payTo !== null &&\n (payTo as any).__brand === 'stripePayTo'\n );\n}\n\nfunction parseBooleanHeader(value: unknown): boolean | null {\n if (value == null) return null;\n const normalized = String(value).trim().toLowerCase();\n if (normalized === 'true' || normalized === '1' || normalized === 'yes' || normalized === 'on') {\n return true;\n }\n if (normalized === 'false' || normalized === '0' || normalized === 'no' || normalized === 'off') {\n return false;\n }\n return null;\n}\n\nfunction normalizeIntegritasFlow(value: unknown): RelaiIntegritasFlow | undefined {\n const normalized = String(value || '').trim().toLowerCase();\n if (normalized === 'single') return 'single';\n if (normalized === 'dual') return 'dual';\n return undefined;\n}\n\nfunction normalizeIntegritasOptions(\n value: boolean | RelaiIntegritasOptions | undefined,\n): { enabled: boolean; flow?: RelaiIntegritasFlow } {\n if (value === true) return { enabled: true };\n if (value === false || value == null) return { enabled: false };\n\n const flow = normalizeIntegritasFlow(value.flow);\n const enabled =\n typeof value.enabled === 'boolean'\n ? value.enabled\n : true;\n\n return {\n enabled,\n ...(flow ? { flow } : {}),\n };\n}\n\n/**\n * @internal Create a Stripe PaymentIntent with crypto payment method\n * and extract the deposit address.\n */\nasync function createStripeDepositAddress(\n secretKey: string,\n amountUsdCents: number,\n network: string = 'base',\n): Promise<string> {\n const params = new URLSearchParams();\n params.append('amount', String(amountUsdCents));\n params.append('currency', 'usd');\n params.append('payment_method_types[]', 'crypto');\n params.append('payment_method_data[type]', 'crypto');\n params.append('confirm', 'true');\n\n const res = await fetch('https://api.stripe.com/v1/payment_intents', {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${secretKey}`,\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: params.toString(),\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({})) as any;\n const msg = err?.error?.message || res.statusText;\n\n // Provide actionable guidance for common issues\n if (msg.includes('unknown parameter') || msg.includes('crypto')) {\n throw new Error(\n `Stripe crypto payins not enabled on this account. ` +\n `Enable at: https://support.stripe.com/questions/get-started-with-pay-with-crypto ` +\n `(Original: ${msg})`,\n );\n }\n throw new Error(`Stripe PaymentIntent creation failed: ${msg}`);\n }\n\n const pi = await res.json() as any;\n const depositDetails = pi.next_action?.crypto_collect_deposit_details;\n if (!depositDetails) {\n throw new Error(\n 'Stripe PaymentIntent missing crypto deposit details. ' +\n 'Ensure crypto payins are enabled: https://support.stripe.com/questions/get-started-with-pay-with-crypto',\n );\n }\n\n const address = depositDetails.deposit_addresses?.[network]?.address;\n if (!address) {\n throw new Error(`No Stripe deposit address for network: ${network}`);\n }\n\n return address;\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, SKALE Base Sepolia, SKALE BITE, Polygon, and Ethereum.\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 private feePayerCache: Map<string, string> = new Map(); // Cache feePayer per network\n private plugins: RelaiPlugin[];\n private pluginInitPromise: Promise<void> | null = null;\n private mpp?: MppServerHandler;\n\n constructor(config: RelaiServerConfig) {\n this.network = config.network;\n this.facilitatorUrl = config.facilitatorUrl || RELAI_FACILITATOR_URL;\n this.plugins = config.plugins ?? [];\n this.mpp = config.mpp;\n }\n\n private async runPluginInit(): Promise<void> {\n for (const plugin of this.plugins) {\n if (plugin.onInit) {\n try {\n await plugin.onInit();\n } catch (err) {\n console.warn(`[Relai] Plugin '${plugin.name}' init failed:`, err);\n }\n }\n }\n }\n\n /**\n * Get feePayer address for a network (cached)\n */\n private async getFeePayer(caip2: string): Promise<string | undefined> {\n // Check cache first\n if (this.feePayerCache.has(caip2)) {\n return this.feePayerCache.get(caip2);\n }\n\n // If using RelAI facilitator, use hardcoded address (no fetch needed)\n const isRelAI = this.facilitatorUrl.includes('facilitator.x402.fi') || \n this.facilitatorUrl.includes('relai');\n \n if (isRelAI) {\n const isSolanaNetwork = caip2.startsWith('solana:');\n const relaiFeePayer = isSolanaNetwork\n ? '4x4ZhcqiT1FnirM8Ne97iVupkN4NcQgc2YYbE2jDZbZn'\n : '0x1892f72fdB3A966b2AD8595aA5f7741Ef72d6085';\n this.feePayerCache.set(caip2, relaiFeePayer);\n return relaiFeePayer;\n }\n\n // For other facilitators, fetch from /supported\n try {\n const supportedUrl = `${this.facilitatorUrl}/supported`;\n const supportedRes = await fetch(supportedUrl);\n if (supportedRes.ok) {\n const supportedData = await supportedRes.json();\n // Cache all feePayers from supported kinds\n supportedData.kinds?.forEach((kind: any) => {\n if (kind.network && kind.extra?.feePayer) {\n this.feePayerCache.set(kind.network, kind.extra.feePayer);\n }\n });\n return this.feePayerCache.get(caip2);\n }\n } catch (err) {\n // feePayer MUST come from facilitator - cannot use env for security\n console.error(`[Relai] Failed to fetch feePayer from facilitator: ${err}`);\n }\n return undefined;\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 // -----------------------------------------------------------\n // Preflight probe: respond 200 immediately so the preflight\n // plugin (or external clients) can verify the endpoint is alive.\n // -----------------------------------------------------------\n if (req.headers['x-preflight'] === 'true' || req.headers['x-preflight'] === '1') {\n return res.status(200).json({ status: 'ok', preflight: true });\n }\n\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 // Resolve network (Stripe auto-sets to base)\n const stripeConfig = isStripePayTo(options.payTo) ? options.payTo : null;\n const network = stripeConfig\n ? (stripeConfig.stripeNetwork as RelaiNetwork) || 'base'\n : (options.network || self.network);\n const caip2 = NETWORK_CAIP2[network];\n const requestedAsset =\n typeof options.asset === 'string' && options.asset.trim() !== ''\n ? options.asset.trim()\n : undefined;\n const explicitToken = requestedAsset ? resolveToken(network, requestedAsset) : null;\n if (requestedAsset && !explicitToken) {\n return res.status(400).json({\n error: `Unsupported asset ${requestedAsset} for network ${network}`,\n });\n }\n\n const fallbackToken: NetworkToken = {\n address: USDC_ADDRESSES[network],\n symbol: 'USDC',\n name: network === 'skale-bite' ? 'USDC' : 'USD Coin',\n decimals: 6,\n domainVersion: network === 'skale-bite' ? '1' : '2',\n isStableUsd: true,\n };\n const token = explicitToken || resolveToken(network) || fallbackToken;\n const asset = token.address;\n const tokenName = token.name || 'USD Coin';\n const tokenVersion = token.domainVersion || (network === 'skale-bite' ? '1' : '2');\n const tokenDecimals = Number.isFinite(Number(token.decimals)) ? Number(token.decimals) : 6;\n\n let amount: string;\n try {\n amount = await resolveAmountAtomicFromUsd({\n priceUsd: resolvedPrice,\n token,\n network,\n });\n } catch (err) {\n console.error('[Relai] Failed to convert USD amount to token units:', err);\n return res.status(500).json({\n error: 'Failed to quote token amount for payment requirements',\n });\n }\n\n const configuredIntegritas = normalizeIntegritasOptions(options.integritas);\n const headerIntegritasEnabled = parseBooleanHeader(req.headers['x-integritas']);\n const headerIntegritasFlow = normalizeIntegritasFlow(req.headers['x-integritas-flow']);\n const integritasEnabled =\n headerIntegritasEnabled === null\n ? configuredIntegritas.enabled\n : headerIntegritasEnabled;\n const integritasFlow = headerIntegritasFlow || configuredIntegritas.flow;\n const integritasMode =\n integritasFlow === 'single'\n ? 'single_signature_fee_included'\n : (integritasFlow === 'dual' ? 'dual_signature_split' : undefined);\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 // MPP: check for Authorization: Payment credential\n // -----------------------------------------------------------\n const authHeader = req.headers['authorization'] || '';\n if (!paymentHeader && self.mpp && /^Payment\\s+/i.test(authHeader)) {\n try {\n // Use the same amount format as the challenge (USD with 6 decimals)\n const mppAmount = resolvedPrice.toFixed(6);\n\n // Build a web Request from the Express req for the mppx handler\n const mppUrl = `${req.protocol}://${req.get('host')}${req.originalUrl}`;\n const mppHeaders = new Headers();\n for (const [k, v] of Object.entries(req.headers)) {\n if (typeof v === 'string') mppHeaders.set(k, v);\n }\n const mppRequest = new Request(mppUrl, { method: req.method, headers: mppHeaders });\n\n // Call the charge handler — it detects the credential in Authorization header\n // and verifies it against the HMAC-signed challenge\n const chargeHandler = self.mpp.charge({ amount: mppAmount } as any);\n const mppResult = await chargeHandler(mppRequest);\n if (mppResult.status === 402 && mppResult.challenge instanceof Response) {\n // Credential not accepted — mppx re-challenges (normal handshake)\n }\n\n // MPP charge genuinely failed (not a 402 re-challenge, which is normal handshake)\n // Only notify plugins for non-402 failures (e.g. 500, invalid credential, etc.)\n if (mppResult.status !== 200 && !mppResult.withReceipt && mppResult.status !== 402) {\n if (self.plugins.length > 0) {\n const mppFailCtx: PluginContext = {\n network,\n price: resolvedPrice,\n path: req.path || req.originalUrl || '/',\n method: (req.method || 'GET').toUpperCase(),\n };\n const mppFailResult: SettleResult = {\n success: false,\n payer: 'mpp',\n error: `MPP charge failed with status ${mppResult.status}`,\n };\n for (const plugin of self.plugins) {\n if (!plugin.afterSettled) continue;\n try {\n await plugin.afterSettled(req, mppFailResult, mppFailCtx);\n } catch (pluginErr) {\n console.warn(`[Relai] Plugin '${plugin.name}' afterSettled error (non-blocking):`, pluginErr);\n }\n }\n }\n }\n\n if (mppResult.status === 200 || mppResult.withReceipt) {\n // Payment verified by mppx\n const receipt = mppResult.receipt || {};\n const paymentInfo: PaymentInfo = {\n verified: true,\n transactionId: receipt.reference || '',\n payer: receipt.method || 'mpp',\n network,\n amount: resolvedPrice,\n };\n req.payment = paymentInfo;\n req.x402Payer = receipt.method ? `${receipt.method}-mpp` : 'mpp';\n req.x402Paid = true;\n req.x402Transaction = receipt.reference || '';\n req.x402Network = network;\n\n // Use withReceipt to attach Payment-Receipt header\n if (mppResult.withReceipt) {\n const dummyResponse = new Response(null);\n const receiptResponse = mppResult.withReceipt(dummyResponse);\n const receiptHeader = receiptResponse.headers.get('payment-receipt');\n if (receiptHeader) {\n res.setHeader?.('Payment-Receipt', receiptHeader);\n res.setHeader?.('Cache-Control', 'private');\n }\n }\n\n options.onPaymentSettled?.(req, {\n success: true,\n transaction: receipt.reference,\n payer: req.x402Payer,\n } as SettleResult);\n\n // Plugin hooks: afterSettled\n if (self.plugins.length > 0) {\n const settleCtx: PluginContext = {\n network,\n price: resolvedPrice,\n path: req.path || req.originalUrl || '/',\n method: (req.method || 'GET').toUpperCase(),\n };\n for (const plugin of self.plugins) {\n if (!plugin.afterSettled) continue;\n try {\n await plugin.afterSettled(req, {\n success: true,\n transaction: receipt.reference,\n payer: req.x402Payer,\n } as SettleResult, settleCtx);\n } catch (pluginErr) {\n console.warn(`[Relai] Plugin '${plugin.name}' afterSettled error (non-blocking):`, pluginErr);\n }\n }\n }\n\n return next();\n }\n } catch (mppErr) {\n console.warn(`[Relai] MPP verification failed (${mppErr instanceof Error ? mppErr.message : mppErr}), falling through to x402`);\n\n // Notify plugins of MPP failure\n if (self.plugins.length > 0) {\n const mppErrCtx: PluginContext = {\n network,\n price: resolvedPrice,\n path: req.path || req.originalUrl || '/',\n method: (req.method || 'GET').toUpperCase(),\n };\n const mppErrResult: SettleResult = {\n success: false,\n payer: 'mpp',\n error: mppErr instanceof Error ? mppErr.message : String(mppErr),\n };\n for (const plugin of self.plugins) {\n if (!plugin.afterSettled) continue;\n try {\n await plugin.afterSettled(req, mppErrResult, mppErrCtx);\n } catch (pluginErr) {\n console.warn(`[Relai] Plugin '${plugin.name}' afterSettled error (non-blocking):`, pluginErr);\n }\n }\n }\n }\n }\n\n // -----------------------------------------------------------\n // Plugin hooks: beforePaymentCheck\n // If any plugin returns { skip: true }, bypass payment entirely.\n // Ensure plugins are initialized (config synced) before checking.\n // -----------------------------------------------------------\n if (!paymentHeader && self.plugins.length > 0) {\n if (!self.pluginInitPromise) {\n self.pluginInitPromise = self.runPluginInit();\n }\n await self.pluginInitPromise;\n const pluginCtx: PluginContext = {\n network,\n price: resolvedPrice,\n path: req.path || req.originalUrl || '/',\n method: (req.method || 'GET').toUpperCase(),\n };\n\n for (const plugin of self.plugins) {\n if (!plugin.beforePaymentCheck) continue;\n try {\n const pluginResult = await plugin.beforePaymentCheck(req, pluginCtx);\n\n // Reject: plugin blocks the request entirely (e.g. service unhealthy)\n if (pluginResult?.reject) {\n const rejectStatus = pluginResult.rejectStatus || 503;\n if (pluginResult.headers) {\n for (const [k, v] of Object.entries(pluginResult.headers)) {\n res.setHeader(k, v);\n }\n }\n return res.status(rejectStatus).json({\n error: pluginResult.rejectMessage || 'Service unavailable',\n plugin: plugin.name,\n });\n }\n\n // Skip: bypass payment and serve content for free\n if (pluginResult?.skip) {\n // Set plugin-provided headers\n if (pluginResult.headers) {\n for (const [k, v] of Object.entries(pluginResult.headers)) {\n res.setHeader(k, v);\n }\n }\n // Attach plugin metadata to request\n req.pluginMeta = { ...(req.pluginMeta || {}), ...(pluginResult.meta || {}) };\n req.x402Paid = false;\n req.x402Free = true;\n req.x402Plugin = plugin.name;\n // Still set up afterSettled interceptor so plugins (e.g. refund) can\n // re-issue a credit if the endpoint fails on this free call too.\n const skipPluginsWithHook = self.plugins.filter((p) => !!p.afterSettled);\n if (skipPluginsWithHook.length > 0) {\n const skipCtx: PluginContext = {\n network,\n price: resolvedPrice,\n path: req.path || req.originalUrl || '/',\n method: (req.method || 'GET').toUpperCase(),\n };\n const skipResult: SettleResult = {\n success: true,\n payer: req.headers?.['x-wallet-address'] || req.headers?.['x-buyer-address'] || req.ip || req.socket?.remoteAddress || 'unknown',\n transaction: '',\n } as any;\n const originalJsonSkip = (res as any).json?.bind(res);\n const originalSendSkip = (res as any).send?.bind(res);\n let skipFired = false;\n const fireSkipAfterSettled = (statusCode: number) => {\n if (skipFired) return;\n skipFired = true;\n const resultWithStatus = { ...skipResult, statusCode };\n for (const p of skipPluginsWithHook) {\n p.afterSettled!(req, resultWithStatus, skipCtx).catch((e: unknown) => {\n console.warn(`[Relai] Plugin '${p.name}' afterSettled (skip) error:`, e);\n });\n }\n };\n if (typeof originalJsonSkip === 'function') {\n (res as any).json = function (body: unknown) {\n fireSkipAfterSettled(res.statusCode ?? 200);\n (res as any).json = originalJsonSkip;\n return originalJsonSkip(body);\n };\n }\n if (typeof originalSendSkip === 'function') {\n (res as any).send = function (body: unknown) {\n fireSkipAfterSettled(res.statusCode ?? 200);\n (res as any).send = originalSendSkip;\n return originalSendSkip(body);\n };\n }\n }\n return next();\n }\n } catch (pluginErr) {\n console.warn(`[Relai] Plugin '${plugin.name}' beforePaymentCheck error (non-blocking):`, pluginErr);\n }\n }\n }\n\n // -----------------------------------------------------------\n // No payment → return 402 Payment Required\n // -----------------------------------------------------------\n if (!paymentHeader) {\n options.onPaymentRequired?.(req, { price: resolvedPrice, network });\n\n // Resolve payTo address (Stripe creates a fresh deposit address per request)\n let resolvedPayTo: string;\n if (stripeConfig) {\n const amountInCents = Math.max(1, Math.round(resolvedPrice * 100));\n resolvedPayTo = await createStripeDepositAddress(\n stripeConfig.secretKey,\n amountInCents,\n stripeConfig.stripeNetwork,\n );\n } else {\n resolvedPayTo = options.payTo as string;\n }\n\n // Get facilitator feePayer address — use explicit override if provided, otherwise fetch\n const feePayer = (options.feePayer as string | undefined) || await self.getFeePayer(caip2);\n\n let paymentRequiredResponse: any = {\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: resolvedPayTo,\n maxTimeoutSeconds: options.maxTimeoutSeconds || 60,\n extra: {\n name: tokenName,\n version: tokenVersion,\n decimals: tokenDecimals,\n symbol: token.symbol,\n ...(feePayer && { feePayer }), // Add feePayer if available\n ...(integritasEnabled ? { integritasEnabled: true } : {}),\n ...(integritasFlow ? { integritasFlow } : {}),\n ...(integritasMode ? { integritasMode } : {}),\n ...(integritasFlow === 'single' ? { integritasSingleSignature: true } : {}),\n },\n }],\n ...((configuredIntegritas.enabled || integritasEnabled || !!integritasFlow)\n ? {\n extensions: {\n integritas: {\n available: true,\n selectedFlow: integritasFlow || null,\n availableFlows: ['single', 'dual'],\n enabled: integritasEnabled,\n },\n },\n }\n : {}),\n };\n\n // Plugin hooks: enrich402Response (e.g. bridge adds extensions.bridge)\n if (self.plugins.length > 0) {\n const enrichCtx: PluginContext = {\n network,\n price: resolvedPrice,\n path: req.path || req.originalUrl || '/',\n method: (req.method || 'GET').toUpperCase(),\n };\n for (const plugin of self.plugins) {\n if (!plugin.enrich402Response) continue;\n try {\n paymentRequiredResponse = plugin.enrich402Response(paymentRequiredResponse, enrichCtx) || paymentRequiredResponse;\n } catch (pluginErr) {\n console.warn(`[Relai] Plugin '${plugin.name}' enrich402Response error (non-blocking):`, pluginErr);\n }\n }\n }\n\n // Add MPP challenge header if mpp is configured\n if (self.mpp?.charge) {\n try {\n const mppAmount = resolvedPrice.toFixed(6);\n const chargeHandler = self.mpp.charge({ amount: mppAmount } as any);\n const mockReq = new Request(`${req.protocol}://${req.get('host')}${req.originalUrl}`);\n const mppResult = await chargeHandler(mockReq);\n if (mppResult?.challenge instanceof Response) {\n const wwwAuth = mppResult.challenge.headers.get('www-authenticate');\n if (wwwAuth) {\n res.setHeader?.('WWW-Authenticate', wwwAuth);\n }\n }\n } catch {\n // Non-fatal — x402 response is still valid without MPP headers\n }\n }\n\n res.setHeader?.('Cache-Control', 'no-store');\n return res.status(402).json(paymentRequiredResponse);\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 // -----------------------------------------------------------\n // Standard payment: settle via facilitator\n // (Bridged payments go through the same facilitator /settle path.\n // The bridge settle returns a valid xPayment that the facilitator\n // can verify — no special-casing needed server-side.)\n // -----------------------------------------------------------\n\n // Resolve payTo for settle (extract from signed proof when using Stripe)\n let settlePayTo: string;\n if (stripeConfig) {\n settlePayTo =\n paymentProof.payload?.authorization?.to ||\n paymentProof.accepted?.payTo ||\n '';\n if (!settlePayTo) {\n return res.status(400).json({\n x402Version: 2,\n error: 'Cannot extract destination address from payment proof',\n });\n }\n } else {\n settlePayTo = options.payTo as string;\n }\n\n // Build payment requirements for facilitator\n const paymentRequirements = {\n scheme: 'exact',\n network: caip2,\n amount,\n asset,\n payTo: settlePayTo,\n maxTimeoutSeconds: options.maxTimeoutSeconds || 60,\n extra: {\n name: tokenName,\n version: tokenVersion,\n decimals: tokenDecimals,\n symbol: token.symbol,\n ...(integritasEnabled ? { integritasEnabled: true } : {}),\n ...(integritasFlow ? { integritasFlow } : {}),\n ...(integritasMode ? { integritasMode } : {}),\n ...(integritasFlow === 'single' ? { integritasSingleSignature: true } : {}),\n },\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 // Notify plugins of settlement failure (circuit breaker, refund, etc.)\n if (self.plugins.length > 0) {\n const failCtx: PluginContext = {\n network,\n price: resolvedPrice,\n path: req.path || req.originalUrl || '/',\n method: (req.method || 'GET').toUpperCase(),\n };\n for (const plugin of self.plugins) {\n if (!plugin.afterSettled) continue;\n try {\n await plugin.afterSettled(req, result, failCtx);\n } catch (pluginErr) {\n console.warn(`[Relai] Plugin '${plugin.name}' afterSettled error (non-blocking):`, pluginErr);\n }\n }\n }\n\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 // Plugin hooks: afterSettled — called AFTER the handler responds so plugins\n // can see the actual HTTP status code (e.g. circuit breaker, refund).\n if (self.plugins.length > 0) {\n const settleCtx: PluginContext = {\n network,\n price: resolvedPrice,\n path: req.path || req.originalUrl || '/',\n method: (req.method || 'GET').toUpperCase(),\n };\n const pluginsWithHook = self.plugins.filter((p) => !!p.afterSettled);\n if (pluginsWithHook.length > 0) {\n // Wrap res.json / res.send to fire afterSettled with actual statusCode\n const originalJson = (res as any).json?.bind(res);\n const originalSend = (res as any).send?.bind(res);\n let afterSettledFired = false;\n const fireAfterSettled = (statusCode: number) => {\n if (afterSettledFired) return;\n afterSettledFired = true;\n const resultWithStatus = { ...result, statusCode };\n for (const plugin of pluginsWithHook) {\n plugin.afterSettled!(req, resultWithStatus, settleCtx).catch((e: unknown) => {\n console.warn(`[Relai] Plugin '${plugin.name}' afterSettled error (non-blocking):`, e);\n });\n }\n };\n if (typeof originalJson === 'function') {\n (res as any).json = function (body: unknown) {\n fireAfterSettled(res.statusCode ?? 200);\n (res as any).json = originalJson; // restore\n return originalJson(body);\n };\n }\n if (typeof originalSend === 'function') {\n (res as any).send = function (body: unknown) {\n fireAfterSettled(res.statusCode ?? 200);\n (res as any).send = originalSend; // restore\n return originalSend(body);\n };\n }\n }\n }\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","// 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 =\n | 'solana'\n | 'solana-devnet'\n | 'base'\n | 'avalanche'\n | 'skale-base'\n | 'skale-base-sepolia'\n | 'skale-bite'\n | 'polygon'\n | 'ethereum'\n | 'telos';\n\n/** CAIP-2 network identifiers */\nexport const NETWORK_CAIP2: Record<RelaiNetwork, string> = {\n 'solana': 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',\n 'solana-devnet': 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1',\n 'base': 'eip155:8453',\n 'avalanche': 'eip155:43114',\n 'skale-base': 'eip155:1187947933',\n 'skale-base-sepolia': 'eip155:324705682',\n 'skale-bite': 'eip155:103698795',\n 'polygon': 'eip155:137',\n 'ethereum': 'eip155:1',\n 'telos': 'eip155:40',\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-base-sepolia': 324705682,\n 'skale-bite': 103698795,\n 'polygon': 137,\n 'ethereum': 1,\n 'telos': 40,\n};\n\nexport interface NetworkToken {\n address: string;\n symbol: string;\n name: string;\n decimals: number;\n domainVersion?: string;\n isStableUsd?: boolean;\n standards?: string[];\n}\n\n/** Token metadata per network (default token is always the first entry) */\nexport const NETWORK_TOKENS: Partial<Record<RelaiNetwork, NetworkToken[]>> = {\n 'solana': [\n {\n address: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',\n symbol: 'USDC',\n name: 'USD Coin',\n decimals: 6,\n },\n ],\n 'solana-devnet': [\n {\n address: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',\n symbol: 'USDC',\n name: 'USD Coin (Devnet)',\n decimals: 6,\n },\n ],\n 'base': [\n { address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', symbol: 'USDC', name: 'USD Coin', decimals: 6, domainVersion: '2', isStableUsd: true },\n ],\n 'avalanche': [\n {\n address: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',\n symbol: 'USDC',\n name: 'USD Coin',\n decimals: 6,\n domainVersion: '2',\n isStableUsd: true,\n },\n ],\n 'telos': [\n {\n address: '0x818ec0a7fe18ff94269904fced6ae3dae6d6dc0b',\n symbol: 'USDC',\n name: 'USD Coin',\n decimals: 6,\n isStableUsd: true,\n standards: ['eip2612'],\n },\n ],\n 'skale-base': [\n {\n address: '0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20',\n symbol: 'USDC',\n name: 'Bridged USDC (SKALE Bridge)',\n decimals: 6,\n domainVersion: '2',\n isStableUsd: true,\n },\n {\n address: '0x2bF5bF154b515EaA82C31a65ec11554fF5aF7fCA',\n symbol: 'USDT',\n name: 'Bridged USDT (SKALE Bridge)',\n decimals: 6,\n domainVersion: '1',\n isStableUsd: true,\n },\n {\n address: '0x1aeeCFE5454c83B42D8A316246CAc9739E7f690e',\n symbol: 'WBTC',\n name: 'Wrapped Bitcoin',\n decimals: 8,\n domainVersion: '1',\n isStableUsd: false,\n },\n {\n address: '0x7bD39ABBd0Dd13103542cAe3276C7fA332bCA486',\n symbol: 'WETH',\n name: 'Wrapped Ether',\n decimals: 18,\n domainVersion: '1',\n isStableUsd: false,\n },\n ],\n 'skale-base-sepolia': [\n {\n address: '0x2e08028E3C4c2356572E096d8EF835cD5C6030bD',\n symbol: 'USDC',\n name: 'Bridged USDC (SKALE Bridge)',\n decimals: 6,\n domainVersion: '2',\n isStableUsd: true,\n },\n {\n address: '0x3ca0a49f511c2c89c4dcbbf1731120d8919050bf',\n symbol: 'USDT',\n name: 'Bridged USDT (SKALE Bridge)',\n decimals: 6,\n domainVersion: '1',\n isStableUsd: true,\n },\n {\n address: '0x4512eacd4186b025186e1cf6cc0d89497c530e87',\n symbol: 'WBTC',\n name: 'Wrapped Bitcoin',\n decimals: 8,\n domainVersion: '1',\n isStableUsd: false,\n },\n {\n address: '0xf94056bd7f6965db3757e1b145f200b7346b4fc0',\n symbol: 'WETH',\n name: 'Wrapped Ether',\n decimals: 18,\n domainVersion: '1',\n isStableUsd: false,\n },\n ],\n 'skale-bite': [\n {\n address: '0xc4083B1E81ceb461Ccef3FDa8A9F24F0d764B6D8',\n symbol: 'USDC',\n name: 'USDC',\n decimals: 6,\n domainVersion: '1',\n isStableUsd: true,\n },\n ],\n 'polygon': [\n {\n address: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n symbol: 'USDC',\n name: 'USD Coin',\n decimals: 6,\n domainVersion: '2',\n isStableUsd: true,\n },\n ],\n 'ethereum': [\n {\n address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n symbol: 'USDC',\n name: 'USD Coin',\n decimals: 6,\n domainVersion: '2',\n isStableUsd: true,\n },\n ],\n};\n\nexport function resolveToken(network: RelaiNetwork, asset?: string): NetworkToken | null {\n const tokens = NETWORK_TOKENS[network];\n if (!tokens || tokens.length === 0) return null;\n if (!asset) return tokens[0];\n\n const normalized = String(asset).toLowerCase();\n return tokens.find((token) => token.address.toLowerCase() === normalized) || null;\n}\n\n/** USDC contract addresses per network */\nexport const USDC_ADDRESSES: Record<RelaiNetwork, string> = {\n 'solana': 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',\n 'solana-devnet': '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',\n 'base': '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n 'avalanche': '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',\n 'skale-base': '0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20',\n 'skale-base-sepolia': '0x2e08028E3C4c2356572E096d8EF835cD5C6030bD',\n 'skale-bite': '0xc4083B1E81ceb461Ccef3FDa8A9F24F0d764B6D8',\n 'polygon': '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n 'ethereum': '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n 'telos': '0x818ec0a7fe18ff94269904fced6ae3dae6d6dc0b',\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 'solana-devnet': (tx) => `https://solscan.io/tx/${tx}?cluster=devnet`,\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-base-sepolia': (tx) => `https://base-sepolia-testnet-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 'telos': (tx) => `https://teloscan.io/tx/${tx}`,\n};\n\n/** Human-readable network labels */\nexport const NETWORK_LABELS: Record<RelaiNetwork, string> = {\n 'solana': 'Solana',\n 'solana-devnet': 'Solana Devnet',\n 'base': 'Base',\n 'avalanche': 'Avalanche',\n 'skale-base': 'SKALE Base',\n 'skale-base-sepolia': 'SKALE Base Sepolia',\n 'skale-bite': 'SKALE BITE V2',\n 'polygon': 'Polygon',\n 'ethereum': 'Ethereum',\n 'telos': 'Telos EVM',\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[] = [\n 'solana',\n 'solana-devnet',\n 'base',\n 'avalanche',\n 'skale-base',\n 'skale-base-sepolia',\n 'skale-bite',\n 'polygon',\n 'ethereum',\n 'telos',\n];\n\n/** Check if a network is Solana-based */\nexport function isSolana(network: string): boolean {\n return network === 'solana' || network === 'solana-devnet' || 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-base-sepolia', 'skale-bite', 'polygon', 'ethereum', 'telos'].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"],"mappings":"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","names":["paymentInfo"]}
package/dist/server.js CHANGED
@@ -412,7 +412,8 @@ var Relai = class {
412
412
  }
413
413
  const isRelAI = this.facilitatorUrl.includes("facilitator.x402.fi") || this.facilitatorUrl.includes("relai");
414
414
  if (isRelAI) {
415
- const relaiFeePayer = "0x1892f72fdB3A966b2AD8595aA5f7741Ef72d6085";
415
+ const isSolanaNetwork = caip2.startsWith("solana:");
416
+ const relaiFeePayer = isSolanaNetwork ? "4x4ZhcqiT1FnirM8Ne97iVupkN4NcQgc2YYbE2jDZbZn" : "0x1892f72fdB3A966b2AD8595aA5f7741Ef72d6085";
416
417
  this.feePayerCache.set(caip2, relaiFeePayer);
417
418
  return relaiFeePayer;
418
419
  }
@@ -496,7 +497,6 @@ var Relai = class {
496
497
  const integritasMode = integritasFlow === "single" ? "single_signature_fee_included" : integritasFlow === "dual" ? "dual_signature_split" : void 0;
497
498
  const paymentHeader = req.headers["x-payment"] || req.headers["payment-signature"] || req.headers["x-payment-signature"];
498
499
  const authHeader = req.headers["authorization"] || "";
499
- console.log(`[Relai] MPP check: paymentHeader=${!!paymentHeader}, hasMpp=${!!self.mpp}, authHeader=${authHeader?.slice(0, 30)}`);
500
500
  if (!paymentHeader && self.mpp && /^Payment\s+/i.test(authHeader)) {
501
501
  try {
502
502
  const mppAmount = resolvedPrice.toFixed(6);
@@ -508,10 +508,7 @@ var Relai = class {
508
508
  const mppRequest = new Request(mppUrl, { method: req.method, headers: mppHeaders });
509
509
  const chargeHandler = self.mpp.charge({ amount: mppAmount });
510
510
  const mppResult = await chargeHandler(mppRequest);
511
- console.log(`[Relai] MPP charge result: status=${mppResult.status}, keys=${Object.keys(mppResult)}, hasChallenge=${!!mppResult.challenge}, hasWithReceipt=${!!mppResult.withReceipt}`);
512
511
  if (mppResult.status === 402 && mppResult.challenge instanceof Response) {
513
- const retryAuth = mppResult.challenge.headers.get("www-authenticate");
514
- console.log(`[Relai] MPP re-challenged (credential not accepted). New WWW-Auth: ${retryAuth?.slice(0, 60)}`);
515
512
  }
516
513
  if (mppResult.status !== 200 && !mppResult.withReceipt && mppResult.status !== 402) {
517
514
  if (self.plugins.length > 0) {
@@ -554,7 +551,10 @@ var Relai = class {
554
551
  const dummyResponse = new Response(null);
555
552
  const receiptResponse = mppResult.withReceipt(dummyResponse);
556
553
  const receiptHeader = receiptResponse.headers.get("payment-receipt");
557
- if (receiptHeader) res.setHeader("Payment-Receipt", receiptHeader);
554
+ if (receiptHeader) {
555
+ res.setHeader?.("Payment-Receipt", receiptHeader);
556
+ res.setHeader?.("Cache-Control", "private");
557
+ }
558
558
  }
559
559
  options.onPaymentSettled?.(req, {
560
560
  success: true,
@@ -771,12 +771,13 @@ var Relai = class {
771
771
  if (mppResult?.challenge instanceof Response) {
772
772
  const wwwAuth = mppResult.challenge.headers.get("www-authenticate");
773
773
  if (wwwAuth) {
774
- res.setHeader("WWW-Authenticate", wwwAuth);
774
+ res.setHeader?.("WWW-Authenticate", wwwAuth);
775
775
  }
776
776
  }
777
777
  } catch {
778
778
  }
779
779
  }
780
+ res.setHeader?.("Cache-Control", "no-store");
780
781
  return res.status(402).json(paymentRequiredResponse);
781
782
  }
782
783
  let paymentProof;
@@ -793,39 +794,6 @@ var Relai = class {
793
794
  });
794
795
  }
795
796
  }
796
- if (paymentProof.bridged === true && paymentProof.targetTxId) {
797
- console.log(`[Relai] Bridged payment accepted: source=${paymentProof.sourceTxId}, target=${paymentProof.targetTxId}`);
798
- const paymentInfo2 = {
799
- verified: true,
800
- transactionId: paymentProof.targetTxId,
801
- payer: paymentProof.sourceTxId || "bridge",
802
- network,
803
- amount: resolvedPrice
804
- };
805
- req.payment = paymentInfo2;
806
- req.x402Payer = paymentProof.sourceTxId || "bridge";
807
- req.x402Paid = true;
808
- req.x402Transaction = paymentProof.targetTxId;
809
- req.x402Network = network;
810
- req.x402Bridged = true;
811
- req.x402SourceChain = paymentProof.sourceChain;
812
- const paymentResponse2 = {
813
- x402Version: 2,
814
- scheme: "exact",
815
- network: caip2,
816
- transaction: paymentProof.targetTxId,
817
- payer: paymentProof.sourceTxId,
818
- amount,
819
- asset,
820
- bridged: true
821
- };
822
- res.setHeader(
823
- "PAYMENT-RESPONSE",
824
- Buffer.from(JSON.stringify(paymentResponse2)).toString("base64")
825
- );
826
- options.onPaymentSettled?.(req, { success: true, transaction: paymentProof.targetTxId, payer: paymentProof.sourceTxId });
827
- return next();
828
- }
829
797
  let settlePayTo;
830
798
  if (stripeConfig) {
831
799
  settlePayTo = paymentProof.payload?.authorization?.to || paymentProof.accepted?.payTo || "";