@mixrpay/merchant-sdk 0.3.2 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/middleware/express.js +33 -3
- package/dist/middleware/express.js.map +1 -1
- package/dist/middleware/express.mjs +33 -3
- package/dist/middleware/express.mjs.map +1 -1
- package/dist/middleware/nextjs.js +33 -3
- package/dist/middleware/nextjs.js.map +1 -1
- package/dist/middleware/nextjs.mjs +33 -3
- package/dist/middleware/nextjs.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -457,8 +457,18 @@ async function validatePreChargedSessionNext(sessionId, expectedPriceUsd, charge
|
|
|
457
457
|
"Content-Type": "application/json",
|
|
458
458
|
"Authorization": `Bearer ${secretKey}`
|
|
459
459
|
},
|
|
460
|
-
body: JSON.stringify({ session_id: sessionId })
|
|
460
|
+
body: JSON.stringify({ session_id: sessionId }),
|
|
461
|
+
redirect: "manual"
|
|
461
462
|
});
|
|
463
|
+
if (response.status >= 300 && response.status < 400) {
|
|
464
|
+
const location = response.headers.get("location");
|
|
465
|
+
return {
|
|
466
|
+
valid: false,
|
|
467
|
+
method: "session",
|
|
468
|
+
error: `API URL caused redirect (${response.status}). Update MIXRPAY_API_URL to: ${location || baseUrl}. Redirects strip Authorization headers.`,
|
|
469
|
+
sessionId
|
|
470
|
+
};
|
|
471
|
+
}
|
|
462
472
|
if (!response.ok) {
|
|
463
473
|
const errorData = await response.json().catch(() => ({}));
|
|
464
474
|
return {
|
|
@@ -500,8 +510,19 @@ async function chargeSessionNext(sessionId, priceUsd, baseUrl, secretKey, config
|
|
|
500
510
|
price_usd: priceUsd,
|
|
501
511
|
feature: config.feature || req.headers.get("x-mixr-feature"),
|
|
502
512
|
idempotency_key: req.headers.get("x-idempotency-key")
|
|
503
|
-
})
|
|
513
|
+
}),
|
|
514
|
+
redirect: "manual"
|
|
515
|
+
// Prevent redirect from stripping Authorization header
|
|
504
516
|
});
|
|
517
|
+
if (response.status >= 300 && response.status < 400) {
|
|
518
|
+
const location = response.headers.get("location");
|
|
519
|
+
return {
|
|
520
|
+
valid: false,
|
|
521
|
+
method: "session",
|
|
522
|
+
error: `API URL caused redirect (${response.status}). Update MIXRPAY_API_URL to: ${location || baseUrl}. Redirects strip Authorization headers.`,
|
|
523
|
+
sessionId
|
|
524
|
+
};
|
|
525
|
+
}
|
|
505
526
|
if (!response.ok) {
|
|
506
527
|
const errorData = await response.json().catch(() => ({}));
|
|
507
528
|
return {
|
|
@@ -541,8 +562,17 @@ async function verifyWidgetPaymentNext(paymentJwt, priceUsd, config, req) {
|
|
|
541
562
|
paymentJwt,
|
|
542
563
|
expectedAmountUsd: priceUsd,
|
|
543
564
|
feature: config.feature || req.headers.get("x-mixr-feature")
|
|
544
|
-
})
|
|
565
|
+
}),
|
|
566
|
+
redirect: "manual"
|
|
545
567
|
});
|
|
568
|
+
if (response.status >= 300 && response.status < 400) {
|
|
569
|
+
const location = response.headers.get("location");
|
|
570
|
+
return {
|
|
571
|
+
valid: false,
|
|
572
|
+
method: "widget",
|
|
573
|
+
error: `API URL caused redirect (${response.status}). Update MIXRPAY_API_URL to: ${location || baseUrl}. Redirects strip Authorization headers.`
|
|
574
|
+
};
|
|
575
|
+
}
|
|
546
576
|
if (!response.ok) {
|
|
547
577
|
const errorData = await response.json().catch(() => ({}));
|
|
548
578
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/middleware/nextjs.ts","../../src/verify.ts","../../src/utils.ts","../../src/receipt-fetcher.ts"],"sourcesContent":["/**\n * MixrPay Merchant SDK - Next.js Integration\n * \n * Add x402 payment requirement to Next.js API routes.\n * \n * @example\n * ```typescript\n * // app/api/query/route.ts\n * import { withX402 } from '@mixrpay/merchant-sdk/nextjs';\n * \n * async function handler(req: NextRequest, payment: X402PaymentResult) {\n * // This handler only runs after payment is verified\n * return NextResponse.json({ \n * result: 'success', \n * payer: payment.payer,\n * amount: payment.amount,\n * });\n * }\n * \n * export const POST = withX402({ price: 0.05 }, handler);\n * \n * // With JWT receipts\n * export const POST = withX402({ price: 0.10, receiptMode: 'jwt' }, handler);\n * ```\n */\n\nimport type { NextRequest } from 'next/server';\nimport { NextResponse } from 'next/server';\nimport { verifyX402Payment } from '../verify';\nimport { usdToMinor, generateNonce, DEFAULT_FACILITATOR } from '../utils';\nimport { fetchPaymentReceipt } from '../receipt-fetcher';\nimport type { X402Options, X402PaymentResult, X402PaymentRequired, PriceContext, ReceiptMode, MixrPayOptions, MixrPayPaymentResult, PaymentMethod } from '../types';\n\nexport interface X402Config {\n /** Price in USD (e.g., 0.05 for 5 cents) */\n price: number;\n /** Your merchant wallet address to receive payments */\n recipient?: string;\n /** Chain ID (default: 8453 for Base) */\n chainId?: number;\n /** Facilitator URL */\n facilitator?: string;\n /** Description of what the payment is for */\n description?: string;\n /** Skip payment verification (for testing) */\n testMode?: boolean;\n /** Custom function to determine price dynamically */\n getPrice?: (req: NextRequest) => number | Promise<number>;\n /** Called after successful payment */\n onPayment?: (payment: X402PaymentResult, req: NextRequest) => void | Promise<void>;\n /**\n * Receipt mode for payment verification responses.\n * - 'jwt': Set X-Payment-Receipt header with JWT (no webhook)\n * - 'webhook': Send webhook only (default, backwards compatible)\n * - 'both': Set JWT header AND send webhook\n */\n receiptMode?: ReceiptMode;\n /** MixrPay API URL for fetching JWT receipts (default: production) */\n mixrpayApiUrl?: string;\n}\n\ntype X402Handler = (req: NextRequest, payment: X402PaymentResult) => Promise<NextResponse> | NextResponse;\n\n/**\n * Wrap a Next.js API route handler with x402 payment requirement.\n * \n * @param config - x402 configuration\n * @param handler - The handler to wrap (receives req and payment result)\n * @returns Wrapped handler function\n */\nexport function withX402(config: X402Config, handler: X402Handler) {\n return async (req: NextRequest): Promise<NextResponse> => {\n try {\n // Get recipient address\n const recipient = config.recipient || process.env.MIXRPAY_MERCHANT_ADDRESS;\n if (!recipient) {\n console.error('[x402] No recipient address configured');\n return NextResponse.json(\n { error: 'Payment configuration error' },\n { status: 500 }\n );\n }\n\n // Determine price\n const price = config.getPrice \n ? await config.getPrice(req)\n : config.price;\n \n const priceMinor = usdToMinor(price);\n const chainId = config.chainId || 8453;\n const facilitator = config.facilitator || DEFAULT_FACILITATOR;\n\n // Check for X-PAYMENT header\n const paymentHeader = req.headers.get('x-payment');\n\n if (!paymentHeader) {\n // Return 402 with payment requirements\n const nonce = generateNonce();\n const expiresAt = Math.floor(Date.now() / 1000) + 300;\n\n const paymentRequired: X402PaymentRequired = {\n recipient,\n amount: priceMinor.toString(),\n currency: 'USDC',\n chainId,\n facilitator,\n nonce,\n expiresAt,\n description: config.description,\n };\n\n return NextResponse.json(\n { error: 'Payment required', payment: paymentRequired },\n { \n status: 402,\n headers: {\n 'X-Payment-Required': JSON.stringify(paymentRequired),\n 'WWW-Authenticate': `X-402 ${Buffer.from(JSON.stringify(paymentRequired)).toString('base64')}`,\n },\n }\n );\n }\n\n // Verify the payment\n const result = await verifyX402Payment(paymentHeader, {\n expectedAmount: priceMinor,\n expectedRecipient: recipient,\n chainId,\n facilitator,\n skipSettlement: config.testMode,\n });\n\n if (!result.valid) {\n return NextResponse.json(\n { error: 'Invalid payment', reason: result.error },\n { status: 402 }\n );\n }\n\n // Handle receipt mode\n const receiptMode = config.receiptMode || 'webhook';\n \n if ((receiptMode === 'jwt' || receiptMode === 'both') && result.txHash && result.payer) {\n try {\n const receipt = await fetchPaymentReceipt({\n txHash: result.txHash,\n payer: result.payer,\n recipient,\n amount: priceMinor,\n chainId,\n apiUrl: config.mixrpayApiUrl,\n });\n \n if (receipt) {\n result.receipt = receipt;\n }\n } catch (receiptError) {\n console.warn('[x402] Failed to fetch JWT receipt:', receiptError);\n // Continue without receipt - payment was still successful\n }\n }\n\n // Call onPayment callback\n if (config.onPayment) {\n await config.onPayment(result, req);\n }\n\n // Call the handler with payment result\n const response = await handler(req, result);\n\n // Add tx hash to response headers\n if (result.txHash) {\n response.headers.set('X-Payment-TxHash', result.txHash);\n }\n\n // Add receipt to response headers\n if (result.receipt) {\n response.headers.set('X-Payment-Receipt', result.receipt);\n }\n\n return response;\n } catch (error) {\n console.error('[x402] Handler error:', error);\n return NextResponse.json(\n { error: 'Payment processing error' },\n { status: 500 }\n );\n }\n };\n}\n\n/**\n * Create a x402 payment requirements response.\n * Useful for building custom payment flows.\n */\nexport function createPaymentRequired(options: {\n recipient: string;\n amount: number;\n chainId?: number;\n facilitator?: string;\n description?: string;\n}): NextResponse {\n const priceMinor = usdToMinor(options.amount);\n const nonce = generateNonce();\n const expiresAt = Math.floor(Date.now() / 1000) + 300;\n\n const paymentRequired: X402PaymentRequired = {\n recipient: options.recipient,\n amount: priceMinor.toString(),\n currency: 'USDC',\n chainId: options.chainId || 8453,\n facilitator: options.facilitator || DEFAULT_FACILITATOR,\n nonce,\n expiresAt,\n description: options.description,\n };\n\n return NextResponse.json(\n { error: 'Payment required', payment: paymentRequired },\n { \n status: 402,\n headers: {\n 'X-Payment-Required': JSON.stringify(paymentRequired),\n },\n }\n );\n}\n\nexport type { X402PaymentResult };\n\n// =============================================================================\n// Unified MixrPay Wrapper (withMixrPay)\n// =============================================================================\n\nexport interface MixrPayConfig {\n /** \n * Price in USD (e.g., 0.05 for 5 cents).\n * If not provided and `feature` is set, price will be looked up from dashboard.\n */\n priceUsd?: number;\n\n /** Custom function to determine price dynamically */\n getPrice?: (req: NextRequest) => number | Promise<number>;\n\n /** \n * Feature slug for pricing and tracking.\n * If provided without priceUsd, price will be fetched from MixrPay dashboard.\n * This is the recommended approach - configure prices in dashboard, not code.\n */\n feature?: string;\n\n /** Description of what the payment is for */\n description?: string;\n\n /** Skip payment for testing */\n testMode?: boolean;\n\n /** Called after successful payment */\n onPayment?: (payment: MixrPayPaymentResult, req: NextRequest) => void | Promise<void>;\n\n // x402-specific options\n recipient?: string;\n chainId?: number;\n facilitator?: string;\n receiptMode?: ReceiptMode;\n mixrpayApiUrl?: string;\n}\n\ntype MixrPayHandler = (req: NextRequest, payment: MixrPayPaymentResult) => Promise<NextResponse> | NextResponse;\n\n/**\n * Wrap a Next.js API route handler with unified MixrPay payment requirement.\n * Accepts payments from Session Authorizations, Widget, and x402 Protocol.\n * \n * @example\n * ```typescript\n * // app/api/query/route.ts\n * import { withMixrPay } from '@mixrpay/merchant-sdk/nextjs';\n * \n * async function handler(req: NextRequest, payment: MixrPayPaymentResult) {\n * console.log(`Paid $${payment.amountUsd} via ${payment.method}`);\n * return NextResponse.json({ result: 'success' });\n * }\n * \n * export const POST = withMixrPay({ priceUsd: 0.05 }, handler);\n * ```\n */\n// Cache for feature prices (in-memory, refreshes every 5 minutes)\nconst featurePriceCache = new Map<string, { price: number; expiresAt: number }>();\nconst FEATURE_CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes\n\nasync function getFeaturePrice(feature: string, merchantPublicKey: string | undefined, baseUrl: string): Promise<number | null> {\n const cacheKey = `${merchantPublicKey}:${feature}`;\n const cached = featurePriceCache.get(cacheKey);\n \n if (cached && cached.expiresAt > Date.now()) {\n return cached.price;\n }\n \n try {\n const url = new URL('/api/v1/features/price', baseUrl);\n url.searchParams.set('feature', feature);\n if (merchantPublicKey) {\n url.searchParams.set('public_key', merchantPublicKey);\n }\n \n const response = await fetch(url.toString(), {\n headers: {\n 'Authorization': `Bearer ${process.env.MIXRPAY_SECRET_KEY || ''}`,\n },\n });\n \n if (!response.ok) {\n console.warn(`[withMixrPay] Failed to fetch feature price for \"${feature}\": ${response.status}`);\n return null;\n }\n \n const data = await response.json() as Record<string, unknown>;\n const price = data.price_usd;\n \n if (typeof price === 'number') {\n featurePriceCache.set(cacheKey, { price, expiresAt: Date.now() + FEATURE_CACHE_TTL_MS });\n return price;\n }\n \n return null;\n } catch (err) {\n console.error(`[withMixrPay] Error fetching feature price:`, err);\n return null;\n }\n}\n\nexport function withMixrPay(config: MixrPayConfig, handler: MixrPayHandler) {\n return async (req: NextRequest): Promise<NextResponse> => {\n try {\n const baseUrl = config.mixrpayApiUrl || process.env.MIXRPAY_API_URL || 'https://www.mixrpay.com';\n const publicKey = process.env.MIXRPAY_PUBLIC_KEY;\n \n // Determine price - priority: getPrice() > priceUsd > feature lookup\n let priceUsd: number | undefined;\n \n if (config.getPrice) {\n priceUsd = await config.getPrice(req);\n } else if (config.priceUsd !== undefined) {\n priceUsd = config.priceUsd;\n } else if (config.feature) {\n // Feature-based pricing: lookup from dashboard\n const featurePrice = await getFeaturePrice(config.feature, publicKey, baseUrl);\n if (featurePrice !== null) {\n priceUsd = featurePrice;\n } else {\n console.error(`[withMixrPay] Could not determine price for feature \"${config.feature}\". Configure price in dashboard or provide priceUsd.`);\n return NextResponse.json(\n { error: 'Price configuration error', feature: config.feature },\n { status: 500 }\n );\n }\n } else {\n console.error('[withMixrPay] No price configured. Provide priceUsd, getPrice, or feature.');\n return NextResponse.json(\n { error: 'Price not configured' },\n { status: 500 }\n );\n }\n\n // Check headers in priority order\n const sessionHeader = req.headers.get('x-mixr-session');\n const widgetHeader = req.headers.get('x-mixr-payment');\n const x402Header = req.headers.get('x-payment');\n\n let result: MixrPayPaymentResult;\n\n // 1. Session Authorization\n if (sessionHeader) {\n result = await verifySessionPaymentNext(sessionHeader, priceUsd, config, req);\n }\n // 2. Widget Payment\n else if (widgetHeader) {\n result = await verifyWidgetPaymentNext(widgetHeader, priceUsd, config, req);\n }\n // 3. x402 Protocol\n else if (x402Header) {\n result = await verifyX402PaymentNext(x402Header, priceUsd, config);\n }\n // No payment header - return 402\n else {\n return returnPaymentRequiredNext(priceUsd, config);\n }\n\n if (!result.valid) {\n return NextResponse.json(\n { error: 'Invalid payment', reason: result.error, method: result.method },\n { status: 402 }\n );\n }\n\n // Call onPayment callback\n if (config.onPayment) {\n await config.onPayment(result, req);\n }\n\n // Call the handler with payment result\n const response = await handler(req, result);\n\n // Add headers to response\n if (result.txHash) {\n response.headers.set('X-Payment-TxHash', result.txHash);\n }\n if (result.chargeId) {\n response.headers.set('X-Mixr-Charge-Id', result.chargeId);\n }\n if (result.amountUsd !== undefined) {\n response.headers.set('X-Mixr-Charged', result.amountUsd.toString());\n }\n\n return response;\n } catch (error) {\n console.error('[withMixrPay] Handler error:', error);\n return NextResponse.json(\n { error: 'Payment processing error' },\n { status: 500 }\n );\n }\n };\n}\n\n/**\n * Verify a session authorization payment (Next.js).\n * \n * Supports two flows:\n * 1. Pre-charged: Agent already charged before calling merchant API (X-Mixr-Charged header)\n * - Validates session only, no charge\n * 2. Merchant-initiated: Middleware charges the session\n * - Charges the session via /api/v2/charge\n */\nasync function verifySessionPaymentNext(\n sessionId: string,\n priceUsd: number,\n config: MixrPayConfig,\n req: NextRequest\n): Promise<MixrPayPaymentResult> {\n const baseUrl = config.mixrpayApiUrl || process.env.MIXRPAY_API_URL || 'https://www.mixrpay.com';\n const secretKey = process.env.MIXRPAY_SECRET_KEY;\n\n if (!secretKey) {\n return { valid: false, method: 'session', error: 'MIXRPAY_SECRET_KEY not configured' };\n }\n\n // Check if agent pre-charged (X-Mixr-Charged header indicates amount already charged)\n const preChargedHeader = req.headers.get('x-mixr-charged');\n const isPreCharged = preChargedHeader && preChargedHeader !== '0' && preChargedHeader.toLowerCase() !== 'false';\n\n try {\n if (isPreCharged) {\n // Pre-charged flow: Validate session only (agent already charged)\n return await validatePreChargedSessionNext(sessionId, priceUsd, preChargedHeader!, baseUrl, secretKey, config);\n } else {\n // Merchant-initiated flow: Charge the session\n return await chargeSessionNext(sessionId, priceUsd, baseUrl, secretKey, config, req);\n }\n } catch (error) {\n return {\n valid: false,\n method: 'session',\n error: `Session verification failed: ${(error as Error).message}`,\n sessionId,\n };\n }\n}\n\n/**\n * Validate a pre-charged session without charging (Next.js).\n */\nasync function validatePreChargedSessionNext(\n sessionId: string,\n expectedPriceUsd: number,\n chargedAmount: string,\n baseUrl: string,\n secretKey: string,\n config: MixrPayConfig\n): Promise<MixrPayPaymentResult> {\n // Verify the charged amount matches expected price\n const chargedUsd = parseFloat(chargedAmount);\n if (isNaN(chargedUsd) || chargedUsd < expectedPriceUsd) {\n return {\n valid: false,\n method: 'session',\n error: `Insufficient payment: charged $${chargedUsd}, required $${expectedPriceUsd}`,\n sessionId,\n };\n }\n\n // Validate the session is still active\n const response = await fetch(`${baseUrl}/api/v2/session/validate`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${secretKey}`,\n },\n body: JSON.stringify({ session_id: sessionId }),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({})) as Record<string, unknown>;\n return {\n valid: false,\n method: 'session',\n error: (errorData.error || `Validation failed: ${response.status}`) as string,\n sessionId,\n };\n }\n\n const data = await response.json() as Record<string, unknown>;\n\n if (!data.valid) {\n return {\n valid: false,\n method: 'session',\n error: (data.error || data.code || 'Session invalid') as string,\n sessionId,\n };\n }\n\n return {\n valid: true,\n method: 'session',\n payer: data.wallet_address as string,\n amountUsd: chargedUsd,\n sessionId,\n feature: config.feature,\n settledAt: new Date(),\n preCharged: true,\n };\n}\n\n/**\n * Charge a session via /api/v2/charge (Next.js).\n */\nasync function chargeSessionNext(\n sessionId: string,\n priceUsd: number,\n baseUrl: string,\n secretKey: string,\n config: MixrPayConfig,\n req: NextRequest\n): Promise<MixrPayPaymentResult> {\n const response = await fetch(`${baseUrl}/api/v2/charge`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${secretKey}`,\n },\n body: JSON.stringify({\n session_id: sessionId,\n price_usd: priceUsd,\n feature: config.feature || req.headers.get('x-mixr-feature'),\n idempotency_key: req.headers.get('x-idempotency-key'),\n }),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({})) as Record<string, unknown>;\n return {\n valid: false,\n method: 'session',\n error: (errorData.message || errorData.error || `Charge failed: ${response.status}`) as string,\n sessionId,\n };\n }\n\n const data = await response.json() as Record<string, unknown>;\n return {\n valid: true,\n method: 'session',\n payer: (data.payer || data.walletAddress) as string,\n amountUsd: (data.charged_usd as number) || priceUsd,\n txHash: data.tx_hash as string | undefined,\n chargeId: data.idempotency_key as string | undefined,\n sessionId,\n feature: config.feature,\n settledAt: data.settledAt ? new Date(data.settledAt as string) : new Date(),\n };\n}\n\nasync function verifyWidgetPaymentNext(\n paymentJwt: string,\n priceUsd: number,\n config: MixrPayConfig,\n req: NextRequest\n): Promise<MixrPayPaymentResult> {\n const baseUrl = config.mixrpayApiUrl || process.env.MIXRPAY_API_URL || 'https://www.mixrpay.com';\n const secretKey = process.env.MIXRPAY_SECRET_KEY;\n\n if (!secretKey) {\n return { valid: false, method: 'widget', error: 'MIXRPAY_SECRET_KEY not configured' };\n }\n\n try {\n const response = await fetch(`${baseUrl}/api/widget/verify`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${secretKey}`,\n },\n body: JSON.stringify({\n paymentJwt,\n expectedAmountUsd: priceUsd,\n feature: config.feature || req.headers.get('x-mixr-feature'),\n }),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({})) as Record<string, unknown>;\n return {\n valid: false,\n method: 'widget',\n error: (errorData.message || errorData.error || `Widget verification failed: ${response.status}`) as string,\n };\n }\n\n const data = await response.json() as Record<string, unknown>;\n return {\n valid: true,\n method: 'widget',\n payer: (data.payer || data.walletAddress) as string,\n amountUsd: (data.amountUsd as number) || priceUsd,\n txHash: data.txHash as string | undefined,\n chargeId: data.chargeId as string | undefined,\n feature: config.feature,\n settledAt: data.settledAt ? new Date(data.settledAt as string) : new Date(),\n };\n } catch (error) {\n return {\n valid: false,\n method: 'widget',\n error: `Widget verification failed: ${(error as Error).message}`,\n };\n }\n}\n\nasync function verifyX402PaymentNext(\n paymentHeader: string,\n priceUsd: number,\n config: MixrPayConfig\n): Promise<MixrPayPaymentResult> {\n const recipient = config.recipient || process.env.MIXRPAY_MERCHANT_ADDRESS;\n\n if (!recipient) {\n return {\n valid: false,\n method: 'x402',\n error: 'MIXRPAY_MERCHANT_ADDRESS not configured for x402 payments',\n };\n }\n\n const priceMinor = usdToMinor(priceUsd);\n const chainId = config.chainId || 8453;\n const facilitator = config.facilitator || DEFAULT_FACILITATOR;\n\n const x402Result = await verifyX402Payment(paymentHeader, {\n expectedAmount: priceMinor,\n expectedRecipient: recipient,\n chainId,\n facilitator,\n skipSettlement: config.testMode,\n });\n\n if (!x402Result.valid) {\n return {\n valid: false,\n method: 'x402',\n error: x402Result.error,\n x402Result,\n };\n }\n\n // Fetch JWT receipt if needed\n const receiptMode = config.receiptMode || 'webhook';\n if ((receiptMode === 'jwt' || receiptMode === 'both') && x402Result.txHash && x402Result.payer) {\n try {\n const receipt = await fetchPaymentReceipt({\n txHash: x402Result.txHash,\n payer: x402Result.payer,\n recipient,\n amount: priceMinor,\n chainId,\n apiUrl: config.mixrpayApiUrl,\n });\n if (receipt) {\n x402Result.receipt = receipt;\n }\n } catch (receiptError) {\n console.warn('[withMixrPay] Failed to fetch JWT receipt:', receiptError);\n }\n }\n\n return {\n valid: true,\n method: 'x402',\n payer: x402Result.payer,\n amountUsd: x402Result.amount,\n txHash: x402Result.txHash,\n receipt: x402Result.receipt,\n settledAt: x402Result.settledAt,\n x402Result,\n };\n}\n\nfunction returnPaymentRequiredNext(priceUsd: number, config: MixrPayConfig): NextResponse {\n const priceMinor = usdToMinor(priceUsd);\n const recipient = config.recipient || process.env.MIXRPAY_MERCHANT_ADDRESS;\n const chainId = config.chainId || 8453;\n const facilitator = config.facilitator || DEFAULT_FACILITATOR;\n const nonce = generateNonce();\n const expiresAt = Math.floor(Date.now() / 1000) + 300;\n\n const x402PaymentRequired: X402PaymentRequired | null = recipient ? {\n recipient,\n amount: priceMinor.toString(),\n currency: 'USDC',\n chainId,\n facilitator,\n nonce,\n expiresAt,\n description: config.description,\n } : null;\n\n const headers: Record<string, string> = {};\n if (x402PaymentRequired) {\n headers['X-Payment-Required'] = JSON.stringify(x402PaymentRequired);\n headers['WWW-Authenticate'] = `X-402 ${Buffer.from(JSON.stringify(x402PaymentRequired)).toString('base64')}`;\n }\n\n return NextResponse.json(\n {\n error: 'Payment required',\n priceUsd,\n acceptedMethods: [\n { method: 'session', header: 'X-Mixr-Session', description: 'Session authorization ID' },\n { method: 'widget', header: 'X-Mixr-Payment', description: 'Widget payment JWT' },\n ...(recipient ? [{ method: 'x402', header: 'X-PAYMENT', description: 'x402 protocol payment' }] : []),\n ],\n x402: x402PaymentRequired,\n description: config.description,\n },\n { status: 402, headers }\n );\n}\n\n// Types are already exported via interface declarations above\n\n","/**\n * MixrPay Merchant SDK - Payment Verification\n */\n\nimport { recoverTypedDataAddress } from 'viem';\nimport type { \n X402PaymentResult, \n X402PaymentPayload, \n VerifyOptions,\n TransferWithAuthorizationMessage,\n} from './types';\nimport { \n getUSDCDomain, \n TRANSFER_WITH_AUTHORIZATION_TYPES, \n base64Decode,\n minorToUsd,\n DEFAULT_FACILITATOR,\n} from './utils';\n\n// =============================================================================\n// Payment Verification\n// =============================================================================\n\n/**\n * Verify an X-PAYMENT header and optionally settle the payment.\n * \n * @param paymentHeader - The X-PAYMENT header value (base64 encoded JSON)\n * @param options - Verification options\n * @returns Payment verification result\n * \n * @example\n * ```typescript\n * const result = await verifyX402Payment(req.headers['x-payment'], {\n * expectedAmount: 50000n, // 0.05 USDC\n * expectedRecipient: '0x...',\n * });\n * \n * if (result.valid) {\n * console.log(`Payment from ${result.payer}: $${result.amount}`);\n * }\n * ```\n */\nexport async function verifyX402Payment(\n paymentHeader: string,\n options: VerifyOptions\n): Promise<X402PaymentResult> {\n try {\n // 1. Decode the X-PAYMENT header\n let decoded: X402PaymentPayload;\n try {\n const jsonStr = base64Decode(paymentHeader);\n decoded = JSON.parse(jsonStr);\n } catch (e) {\n return { valid: false, error: 'Invalid payment header encoding' };\n }\n\n // 2. Validate payload structure\n if (!decoded.payload?.authorization || !decoded.payload?.signature) {\n return { valid: false, error: 'Missing authorization or signature in payment' };\n }\n\n const { authorization, signature } = decoded.payload;\n const chainId = options.chainId || 8453;\n\n // 3. Build EIP-712 message for verification\n const message: TransferWithAuthorizationMessage = {\n from: authorization.from as `0x${string}`,\n to: authorization.to as `0x${string}`,\n value: BigInt(authorization.value),\n validAfter: BigInt(authorization.validAfter),\n validBefore: BigInt(authorization.validBefore),\n nonce: authorization.nonce as `0x${string}`,\n };\n\n // 4. Recover signer address\n const domain = getUSDCDomain(chainId);\n let signerAddress: string;\n \n try {\n signerAddress = await recoverTypedDataAddress({\n domain,\n types: TRANSFER_WITH_AUTHORIZATION_TYPES,\n primaryType: 'TransferWithAuthorization',\n message,\n signature: signature as `0x${string}`,\n });\n } catch (e) {\n return { valid: false, error: 'Failed to recover signer from signature' };\n }\n\n // 5. Verify signer matches the 'from' address\n if (signerAddress.toLowerCase() !== authorization.from.toLowerCase()) {\n return { \n valid: false, \n error: `Signature mismatch: expected ${authorization.from}, got ${signerAddress}` \n };\n }\n\n // 6. Verify payment amount\n const paymentAmount = BigInt(authorization.value);\n if (paymentAmount < options.expectedAmount) {\n return { \n valid: false, \n error: `Insufficient payment: expected ${options.expectedAmount}, got ${paymentAmount}` \n };\n }\n\n // 7. Verify recipient\n if (authorization.to.toLowerCase() !== options.expectedRecipient.toLowerCase()) {\n return { \n valid: false, \n error: `Wrong recipient: expected ${options.expectedRecipient}, got ${authorization.to}` \n };\n }\n\n // 8. Check expiration\n const now = Math.floor(Date.now() / 1000);\n if (Number(authorization.validBefore) < now) {\n return { valid: false, error: 'Payment authorization has expired' };\n }\n\n // 9. Check validAfter\n if (Number(authorization.validAfter) > now) {\n return { valid: false, error: 'Payment authorization is not yet valid' };\n }\n\n // 10. Submit to facilitator for settlement (unless skipped)\n let txHash: string | undefined;\n let settledAt: Date | undefined;\n\n if (!options.skipSettlement) {\n const facilitatorUrl = options.facilitator || DEFAULT_FACILITATOR;\n \n try {\n const settlementResponse = await fetch(`${facilitatorUrl}/settle`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n authorization, \n signature,\n chainId,\n }),\n });\n\n if (!settlementResponse.ok) {\n const errorBody = await settlementResponse.text();\n let errorMessage = 'Settlement failed';\n try {\n const errorJson = JSON.parse(errorBody);\n errorMessage = errorJson.message || errorJson.error || errorMessage;\n } catch {\n errorMessage = errorBody || errorMessage;\n }\n return { valid: false, error: `Settlement failed: ${errorMessage}` };\n }\n\n const settlement = await settlementResponse.json() as { txHash?: string; tx_hash?: string };\n txHash = settlement.txHash || settlement.tx_hash;\n settledAt = new Date();\n } catch (e) {\n return { \n valid: false, \n error: `Settlement request failed: ${(e as Error).message}` \n };\n }\n }\n\n // Success!\n return {\n valid: true,\n payer: authorization.from,\n amount: minorToUsd(paymentAmount),\n amountMinor: paymentAmount,\n txHash,\n settledAt: settledAt || new Date(),\n nonce: authorization.nonce,\n };\n\n } catch (error) {\n return { \n valid: false, \n error: `Verification error: ${(error as Error).message}` \n };\n }\n}\n\n/**\n * Parse and validate an X-PAYMENT header without settlement.\n * Useful for checking if a payment is structurally valid before processing.\n */\nexport async function parseX402Payment(\n paymentHeader: string,\n chainId: number = 8453\n): Promise<{\n valid: boolean;\n error?: string;\n payer?: string;\n recipient?: string;\n amount?: number;\n amountMinor?: bigint;\n expiresAt?: Date;\n}> {\n try {\n const jsonStr = base64Decode(paymentHeader);\n const decoded: X402PaymentPayload = JSON.parse(jsonStr);\n\n if (!decoded.payload?.authorization) {\n return { valid: false, error: 'Missing authorization in payment' };\n }\n\n const { authorization, signature } = decoded.payload;\n\n // Verify signature\n const domain = getUSDCDomain(chainId);\n const message: TransferWithAuthorizationMessage = {\n from: authorization.from as `0x${string}`,\n to: authorization.to as `0x${string}`,\n value: BigInt(authorization.value),\n validAfter: BigInt(authorization.validAfter),\n validBefore: BigInt(authorization.validBefore),\n nonce: authorization.nonce as `0x${string}`,\n };\n\n const signerAddress = await recoverTypedDataAddress({\n domain,\n types: TRANSFER_WITH_AUTHORIZATION_TYPES,\n primaryType: 'TransferWithAuthorization',\n message,\n signature: signature as `0x${string}`,\n });\n\n if (signerAddress.toLowerCase() !== authorization.from.toLowerCase()) {\n return { valid: false, error: 'Signature mismatch' };\n }\n\n const amountMinor = BigInt(authorization.value);\n \n return {\n valid: true,\n payer: authorization.from,\n recipient: authorization.to,\n amount: minorToUsd(amountMinor),\n amountMinor,\n expiresAt: new Date(Number(authorization.validBefore) * 1000),\n };\n } catch (error) {\n return { valid: false, error: `Parse error: ${(error as Error).message}` };\n }\n}\n\n","/**\n * MixrPay Merchant SDK - Utilities\n */\n\nimport type { EIP712Domain } from './types';\n\n// =============================================================================\n// USDC Constants by Chain\n// =============================================================================\n\nexport const USDC_CONTRACTS: Record<number, `0x${string}`> = {\n 8453: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // Base Mainnet\n 84532: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', // Base Sepolia\n};\n\nexport const DEFAULT_FACILITATOR = 'https://x402.org/facilitator';\n\n// =============================================================================\n// EIP-712 Domain\n// =============================================================================\n\nexport function getUSDCDomain(chainId: number): EIP712Domain {\n const verifyingContract = USDC_CONTRACTS[chainId];\n if (!verifyingContract) {\n throw new Error(`Unsupported chain ID: ${chainId}. Supported: ${Object.keys(USDC_CONTRACTS).join(', ')}`);\n }\n\n return {\n name: 'USD Coin',\n version: '2',\n chainId,\n verifyingContract,\n };\n}\n\n// EIP-712 types for TransferWithAuthorization\nexport const TRANSFER_WITH_AUTHORIZATION_TYPES = {\n TransferWithAuthorization: [\n { name: 'from', type: 'address' },\n { name: 'to', type: 'address' },\n { name: 'value', type: 'uint256' },\n { name: 'validAfter', type: 'uint256' },\n { name: 'validBefore', type: 'uint256' },\n { name: 'nonce', type: 'bytes32' },\n ],\n} as const;\n\n// =============================================================================\n// Utility Functions\n// =============================================================================\n\n/**\n * Convert USD dollars to USDC minor units (6 decimals)\n */\nexport function usdToMinor(usd: number): bigint {\n return BigInt(Math.round(usd * 1_000_000));\n}\n\n/**\n * Convert USDC minor units to USD dollars\n */\nexport function minorToUsd(minor: bigint): number {\n return Number(minor) / 1_000_000;\n}\n\n/**\n * Generate a random nonce for x402 payments\n */\nexport function generateNonce(): `0x${string}` {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return `0x${Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('')}` as `0x${string}`;\n}\n\n/**\n * Check if an address is valid\n */\nexport function isValidAddress(address: string): address is `0x${string}` {\n return /^0x[a-fA-F0-9]{40}$/.test(address);\n}\n\n/**\n * Normalize an address to lowercase checksum format\n */\nexport function normalizeAddress(address: string): `0x${string}` {\n if (!isValidAddress(address)) {\n throw new Error(`Invalid address: ${address}`);\n }\n return address.toLowerCase() as `0x${string}`;\n}\n\n/**\n * Safe base64 decode that works in both Node.js and browsers\n */\nexport function base64Decode(str: string): string {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(str, 'base64').toString('utf-8');\n }\n return atob(str);\n}\n\n/**\n * Safe base64 encode that works in both Node.js and browsers\n */\nexport function base64Encode(str: string): string {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(str, 'utf-8').toString('base64');\n }\n return btoa(str);\n}\n\n","/**\n * MixrPay Merchant SDK - Receipt Fetcher\n * \n * Internal utility to fetch JWT receipts from MixrPay API after settlement.\n * Used by x402 middleware to get receipts for the X-Payment-Receipt header.\n */\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nconst DEFAULT_MIXRPAY_API_URL = process.env.MIXRPAY_BASE_URL || 'https://www.mixrpay.com';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface FetchReceiptParams {\n /** Settlement transaction hash */\n txHash: string;\n /** Payer address */\n payer: string;\n /** Recipient address */\n recipient: string;\n /** Amount in USDC minor units */\n amount: bigint;\n /** Chain ID */\n chainId: number;\n /** Custom MixrPay API URL (optional) */\n apiUrl?: string;\n}\n\ninterface ReceiptResponse {\n receipt: string;\n expiresAt: string;\n}\n\n// =============================================================================\n// Receipt Fetching\n// =============================================================================\n\n/**\n * Fetch a JWT payment receipt from MixrPay API.\n * \n * This is called by the x402 middleware after successful payment verification\n * when receiptMode is 'jwt' or 'both'.\n * \n * @param params - Receipt request parameters\n * @returns JWT receipt string, or null if not available\n */\nexport async function fetchPaymentReceipt(params: FetchReceiptParams): Promise<string | null> {\n const apiUrl = params.apiUrl || DEFAULT_MIXRPAY_API_URL;\n const endpoint = `${apiUrl}/api/v1/receipts`;\n\n try {\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n tx_hash: params.txHash,\n payer: params.payer,\n recipient: params.recipient,\n amount: params.amount.toString(),\n chain_id: params.chainId,\n }),\n });\n\n if (!response.ok) {\n // Log but don't throw - receipt is optional\n console.warn(`[x402] Receipt fetch failed: ${response.status} ${response.statusText}`);\n return null;\n }\n\n const data = await response.json() as ReceiptResponse;\n return data.receipt || null;\n } catch (error) {\n // Log but don't throw - payment was successful, receipt is optional\n console.warn('[x402] Receipt fetch error:', (error as Error).message);\n return null;\n }\n}\n\n/**\n * Generate a local receipt for testing purposes.\n * \n * WARNING: This generates an unsigned receipt that will NOT verify.\n * Use only for local development and testing.\n * \n * @param params - Receipt parameters\n * @returns Mock JWT-like string (not cryptographically signed)\n */\nexport function generateMockReceipt(params: FetchReceiptParams): string {\n const header = {\n alg: 'none',\n typ: 'JWT',\n };\n\n const payload = {\n paymentId: `mock_${Date.now()}`,\n amount: params.amount.toString(),\n amountUsd: Number(params.amount) / 1_000_000,\n payer: params.payer,\n recipient: params.recipient,\n chainId: params.chainId,\n txHash: params.txHash,\n settledAt: new Date().toISOString(),\n iat: Math.floor(Date.now() / 1000),\n exp: Math.floor(Date.now() / 1000) + 3600,\n _mock: true,\n };\n\n const base64Header = Buffer.from(JSON.stringify(header)).toString('base64url');\n const base64Payload = Buffer.from(JSON.stringify(payload)).toString('base64url');\n\n // Mock signature (not cryptographically valid)\n return `${base64Header}.${base64Payload}.mock_signature_for_testing_only`;\n}\n\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/middleware/nextjs.ts","../../src/verify.ts","../../src/utils.ts","../../src/receipt-fetcher.ts"],"sourcesContent":["/**\n * MixrPay Merchant SDK - Next.js Integration\n * \n * Add x402 payment requirement to Next.js API routes.\n * \n * @example\n * ```typescript\n * // app/api/query/route.ts\n * import { withX402 } from '@mixrpay/merchant-sdk/nextjs';\n * \n * async function handler(req: NextRequest, payment: X402PaymentResult) {\n * // This handler only runs after payment is verified\n * return NextResponse.json({ \n * result: 'success', \n * payer: payment.payer,\n * amount: payment.amount,\n * });\n * }\n * \n * export const POST = withX402({ price: 0.05 }, handler);\n * \n * // With JWT receipts\n * export const POST = withX402({ price: 0.10, receiptMode: 'jwt' }, handler);\n * ```\n */\n\nimport type { NextRequest } from 'next/server';\nimport { NextResponse } from 'next/server';\nimport { verifyX402Payment } from '../verify';\nimport { usdToMinor, generateNonce, DEFAULT_FACILITATOR } from '../utils';\nimport { fetchPaymentReceipt } from '../receipt-fetcher';\nimport type { X402Options, X402PaymentResult, X402PaymentRequired, PriceContext, ReceiptMode, MixrPayOptions, MixrPayPaymentResult, PaymentMethod } from '../types';\n\nexport interface X402Config {\n /** Price in USD (e.g., 0.05 for 5 cents) */\n price: number;\n /** Your merchant wallet address to receive payments */\n recipient?: string;\n /** Chain ID (default: 8453 for Base) */\n chainId?: number;\n /** Facilitator URL */\n facilitator?: string;\n /** Description of what the payment is for */\n description?: string;\n /** Skip payment verification (for testing) */\n testMode?: boolean;\n /** Custom function to determine price dynamically */\n getPrice?: (req: NextRequest) => number | Promise<number>;\n /** Called after successful payment */\n onPayment?: (payment: X402PaymentResult, req: NextRequest) => void | Promise<void>;\n /**\n * Receipt mode for payment verification responses.\n * - 'jwt': Set X-Payment-Receipt header with JWT (no webhook)\n * - 'webhook': Send webhook only (default, backwards compatible)\n * - 'both': Set JWT header AND send webhook\n */\n receiptMode?: ReceiptMode;\n /** MixrPay API URL for fetching JWT receipts (default: production) */\n mixrpayApiUrl?: string;\n}\n\ntype X402Handler = (req: NextRequest, payment: X402PaymentResult) => Promise<NextResponse> | NextResponse;\n\n/**\n * Wrap a Next.js API route handler with x402 payment requirement.\n * \n * @param config - x402 configuration\n * @param handler - The handler to wrap (receives req and payment result)\n * @returns Wrapped handler function\n */\nexport function withX402(config: X402Config, handler: X402Handler) {\n return async (req: NextRequest): Promise<NextResponse> => {\n try {\n // Get recipient address\n const recipient = config.recipient || process.env.MIXRPAY_MERCHANT_ADDRESS;\n if (!recipient) {\n console.error('[x402] No recipient address configured');\n return NextResponse.json(\n { error: 'Payment configuration error' },\n { status: 500 }\n );\n }\n\n // Determine price\n const price = config.getPrice \n ? await config.getPrice(req)\n : config.price;\n \n const priceMinor = usdToMinor(price);\n const chainId = config.chainId || 8453;\n const facilitator = config.facilitator || DEFAULT_FACILITATOR;\n\n // Check for X-PAYMENT header\n const paymentHeader = req.headers.get('x-payment');\n\n if (!paymentHeader) {\n // Return 402 with payment requirements\n const nonce = generateNonce();\n const expiresAt = Math.floor(Date.now() / 1000) + 300;\n\n const paymentRequired: X402PaymentRequired = {\n recipient,\n amount: priceMinor.toString(),\n currency: 'USDC',\n chainId,\n facilitator,\n nonce,\n expiresAt,\n description: config.description,\n };\n\n return NextResponse.json(\n { error: 'Payment required', payment: paymentRequired },\n { \n status: 402,\n headers: {\n 'X-Payment-Required': JSON.stringify(paymentRequired),\n 'WWW-Authenticate': `X-402 ${Buffer.from(JSON.stringify(paymentRequired)).toString('base64')}`,\n },\n }\n );\n }\n\n // Verify the payment\n const result = await verifyX402Payment(paymentHeader, {\n expectedAmount: priceMinor,\n expectedRecipient: recipient,\n chainId,\n facilitator,\n skipSettlement: config.testMode,\n });\n\n if (!result.valid) {\n return NextResponse.json(\n { error: 'Invalid payment', reason: result.error },\n { status: 402 }\n );\n }\n\n // Handle receipt mode\n const receiptMode = config.receiptMode || 'webhook';\n \n if ((receiptMode === 'jwt' || receiptMode === 'both') && result.txHash && result.payer) {\n try {\n const receipt = await fetchPaymentReceipt({\n txHash: result.txHash,\n payer: result.payer,\n recipient,\n amount: priceMinor,\n chainId,\n apiUrl: config.mixrpayApiUrl,\n });\n \n if (receipt) {\n result.receipt = receipt;\n }\n } catch (receiptError) {\n console.warn('[x402] Failed to fetch JWT receipt:', receiptError);\n // Continue without receipt - payment was still successful\n }\n }\n\n // Call onPayment callback\n if (config.onPayment) {\n await config.onPayment(result, req);\n }\n\n // Call the handler with payment result\n const response = await handler(req, result);\n\n // Add tx hash to response headers\n if (result.txHash) {\n response.headers.set('X-Payment-TxHash', result.txHash);\n }\n\n // Add receipt to response headers\n if (result.receipt) {\n response.headers.set('X-Payment-Receipt', result.receipt);\n }\n\n return response;\n } catch (error) {\n console.error('[x402] Handler error:', error);\n return NextResponse.json(\n { error: 'Payment processing error' },\n { status: 500 }\n );\n }\n };\n}\n\n/**\n * Create a x402 payment requirements response.\n * Useful for building custom payment flows.\n */\nexport function createPaymentRequired(options: {\n recipient: string;\n amount: number;\n chainId?: number;\n facilitator?: string;\n description?: string;\n}): NextResponse {\n const priceMinor = usdToMinor(options.amount);\n const nonce = generateNonce();\n const expiresAt = Math.floor(Date.now() / 1000) + 300;\n\n const paymentRequired: X402PaymentRequired = {\n recipient: options.recipient,\n amount: priceMinor.toString(),\n currency: 'USDC',\n chainId: options.chainId || 8453,\n facilitator: options.facilitator || DEFAULT_FACILITATOR,\n nonce,\n expiresAt,\n description: options.description,\n };\n\n return NextResponse.json(\n { error: 'Payment required', payment: paymentRequired },\n { \n status: 402,\n headers: {\n 'X-Payment-Required': JSON.stringify(paymentRequired),\n },\n }\n );\n}\n\nexport type { X402PaymentResult };\n\n// =============================================================================\n// Unified MixrPay Wrapper (withMixrPay)\n// =============================================================================\n\nexport interface MixrPayConfig {\n /** \n * Price in USD (e.g., 0.05 for 5 cents).\n * If not provided and `feature` is set, price will be looked up from dashboard.\n */\n priceUsd?: number;\n\n /** Custom function to determine price dynamically */\n getPrice?: (req: NextRequest) => number | Promise<number>;\n\n /** \n * Feature slug for pricing and tracking.\n * If provided without priceUsd, price will be fetched from MixrPay dashboard.\n * This is the recommended approach - configure prices in dashboard, not code.\n */\n feature?: string;\n\n /** Description of what the payment is for */\n description?: string;\n\n /** Skip payment for testing */\n testMode?: boolean;\n\n /** Called after successful payment */\n onPayment?: (payment: MixrPayPaymentResult, req: NextRequest) => void | Promise<void>;\n\n // x402-specific options\n recipient?: string;\n chainId?: number;\n facilitator?: string;\n receiptMode?: ReceiptMode;\n mixrpayApiUrl?: string;\n}\n\ntype MixrPayHandler = (req: NextRequest, payment: MixrPayPaymentResult) => Promise<NextResponse> | NextResponse;\n\n/**\n * Wrap a Next.js API route handler with unified MixrPay payment requirement.\n * Accepts payments from Session Authorizations, Widget, and x402 Protocol.\n * \n * @example\n * ```typescript\n * // app/api/query/route.ts\n * import { withMixrPay } from '@mixrpay/merchant-sdk/nextjs';\n * \n * async function handler(req: NextRequest, payment: MixrPayPaymentResult) {\n * console.log(`Paid $${payment.amountUsd} via ${payment.method}`);\n * return NextResponse.json({ result: 'success' });\n * }\n * \n * export const POST = withMixrPay({ priceUsd: 0.05 }, handler);\n * ```\n */\n// Cache for feature prices (in-memory, refreshes every 5 minutes)\nconst featurePriceCache = new Map<string, { price: number; expiresAt: number }>();\nconst FEATURE_CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes\n\nasync function getFeaturePrice(feature: string, merchantPublicKey: string | undefined, baseUrl: string): Promise<number | null> {\n const cacheKey = `${merchantPublicKey}:${feature}`;\n const cached = featurePriceCache.get(cacheKey);\n \n if (cached && cached.expiresAt > Date.now()) {\n return cached.price;\n }\n \n try {\n const url = new URL('/api/v1/features/price', baseUrl);\n url.searchParams.set('feature', feature);\n if (merchantPublicKey) {\n url.searchParams.set('public_key', merchantPublicKey);\n }\n \n const response = await fetch(url.toString(), {\n headers: {\n 'Authorization': `Bearer ${process.env.MIXRPAY_SECRET_KEY || ''}`,\n },\n });\n \n if (!response.ok) {\n console.warn(`[withMixrPay] Failed to fetch feature price for \"${feature}\": ${response.status}`);\n return null;\n }\n \n const data = await response.json() as Record<string, unknown>;\n const price = data.price_usd;\n \n if (typeof price === 'number') {\n featurePriceCache.set(cacheKey, { price, expiresAt: Date.now() + FEATURE_CACHE_TTL_MS });\n return price;\n }\n \n return null;\n } catch (err) {\n console.error(`[withMixrPay] Error fetching feature price:`, err);\n return null;\n }\n}\n\nexport function withMixrPay(config: MixrPayConfig, handler: MixrPayHandler) {\n return async (req: NextRequest): Promise<NextResponse> => {\n try {\n const baseUrl = config.mixrpayApiUrl || process.env.MIXRPAY_API_URL || 'https://www.mixrpay.com';\n const publicKey = process.env.MIXRPAY_PUBLIC_KEY;\n \n // Determine price - priority: getPrice() > priceUsd > feature lookup\n let priceUsd: number | undefined;\n \n if (config.getPrice) {\n priceUsd = await config.getPrice(req);\n } else if (config.priceUsd !== undefined) {\n priceUsd = config.priceUsd;\n } else if (config.feature) {\n // Feature-based pricing: lookup from dashboard\n const featurePrice = await getFeaturePrice(config.feature, publicKey, baseUrl);\n if (featurePrice !== null) {\n priceUsd = featurePrice;\n } else {\n console.error(`[withMixrPay] Could not determine price for feature \"${config.feature}\". Configure price in dashboard or provide priceUsd.`);\n return NextResponse.json(\n { error: 'Price configuration error', feature: config.feature },\n { status: 500 }\n );\n }\n } else {\n console.error('[withMixrPay] No price configured. Provide priceUsd, getPrice, or feature.');\n return NextResponse.json(\n { error: 'Price not configured' },\n { status: 500 }\n );\n }\n\n // Check headers in priority order\n const sessionHeader = req.headers.get('x-mixr-session');\n const widgetHeader = req.headers.get('x-mixr-payment');\n const x402Header = req.headers.get('x-payment');\n\n let result: MixrPayPaymentResult;\n\n // 1. Session Authorization\n if (sessionHeader) {\n result = await verifySessionPaymentNext(sessionHeader, priceUsd, config, req);\n }\n // 2. Widget Payment\n else if (widgetHeader) {\n result = await verifyWidgetPaymentNext(widgetHeader, priceUsd, config, req);\n }\n // 3. x402 Protocol\n else if (x402Header) {\n result = await verifyX402PaymentNext(x402Header, priceUsd, config);\n }\n // No payment header - return 402\n else {\n return returnPaymentRequiredNext(priceUsd, config);\n }\n\n if (!result.valid) {\n return NextResponse.json(\n { error: 'Invalid payment', reason: result.error, method: result.method },\n { status: 402 }\n );\n }\n\n // Call onPayment callback\n if (config.onPayment) {\n await config.onPayment(result, req);\n }\n\n // Call the handler with payment result\n const response = await handler(req, result);\n\n // Add headers to response\n if (result.txHash) {\n response.headers.set('X-Payment-TxHash', result.txHash);\n }\n if (result.chargeId) {\n response.headers.set('X-Mixr-Charge-Id', result.chargeId);\n }\n if (result.amountUsd !== undefined) {\n response.headers.set('X-Mixr-Charged', result.amountUsd.toString());\n }\n\n return response;\n } catch (error) {\n console.error('[withMixrPay] Handler error:', error);\n return NextResponse.json(\n { error: 'Payment processing error' },\n { status: 500 }\n );\n }\n };\n}\n\n/**\n * Verify a session authorization payment (Next.js).\n * \n * Supports two flows:\n * 1. Pre-charged: Agent already charged before calling merchant API (X-Mixr-Charged header)\n * - Validates session only, no charge\n * 2. Merchant-initiated: Middleware charges the session\n * - Charges the session via /api/v2/charge\n */\nasync function verifySessionPaymentNext(\n sessionId: string,\n priceUsd: number,\n config: MixrPayConfig,\n req: NextRequest\n): Promise<MixrPayPaymentResult> {\n const baseUrl = config.mixrpayApiUrl || process.env.MIXRPAY_API_URL || 'https://www.mixrpay.com';\n const secretKey = process.env.MIXRPAY_SECRET_KEY;\n\n if (!secretKey) {\n return { valid: false, method: 'session', error: 'MIXRPAY_SECRET_KEY not configured' };\n }\n\n // Check if agent pre-charged (X-Mixr-Charged header indicates amount already charged)\n const preChargedHeader = req.headers.get('x-mixr-charged');\n const isPreCharged = preChargedHeader && preChargedHeader !== '0' && preChargedHeader.toLowerCase() !== 'false';\n\n try {\n if (isPreCharged) {\n // Pre-charged flow: Validate session only (agent already charged)\n return await validatePreChargedSessionNext(sessionId, priceUsd, preChargedHeader!, baseUrl, secretKey, config);\n } else {\n // Merchant-initiated flow: Charge the session\n return await chargeSessionNext(sessionId, priceUsd, baseUrl, secretKey, config, req);\n }\n } catch (error) {\n return {\n valid: false,\n method: 'session',\n error: `Session verification failed: ${(error as Error).message}`,\n sessionId,\n };\n }\n}\n\n/**\n * Validate a pre-charged session without charging (Next.js).\n */\nasync function validatePreChargedSessionNext(\n sessionId: string,\n expectedPriceUsd: number,\n chargedAmount: string,\n baseUrl: string,\n secretKey: string,\n config: MixrPayConfig\n): Promise<MixrPayPaymentResult> {\n // Verify the charged amount matches expected price\n const chargedUsd = parseFloat(chargedAmount);\n if (isNaN(chargedUsd) || chargedUsd < expectedPriceUsd) {\n return {\n valid: false,\n method: 'session',\n error: `Insufficient payment: charged $${chargedUsd}, required $${expectedPriceUsd}`,\n sessionId,\n };\n }\n\n // Validate the session is still active\n // Use redirect: 'manual' to prevent Authorization header from being stripped\n const response = await fetch(`${baseUrl}/api/v2/session/validate`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${secretKey}`,\n },\n body: JSON.stringify({ session_id: sessionId }),\n redirect: 'manual',\n });\n\n // Check for redirects - these will strip the Authorization header\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get('location');\n return {\n valid: false,\n method: 'session',\n error: `API URL caused redirect (${response.status}). Update MIXRPAY_API_URL to: ${location || baseUrl}. Redirects strip Authorization headers.`,\n sessionId,\n };\n }\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({})) as Record<string, unknown>;\n return {\n valid: false,\n method: 'session',\n error: (errorData.error || `Validation failed: ${response.status}`) as string,\n sessionId,\n };\n }\n\n const data = await response.json() as Record<string, unknown>;\n\n if (!data.valid) {\n return {\n valid: false,\n method: 'session',\n error: (data.error || data.code || 'Session invalid') as string,\n sessionId,\n };\n }\n\n return {\n valid: true,\n method: 'session',\n payer: data.wallet_address as string,\n amountUsd: chargedUsd,\n sessionId,\n feature: config.feature,\n settledAt: new Date(),\n preCharged: true,\n };\n}\n\n/**\n * Charge a session via /api/v2/charge (Next.js).\n */\nasync function chargeSessionNext(\n sessionId: string,\n priceUsd: number,\n baseUrl: string,\n secretKey: string,\n config: MixrPayConfig,\n req: NextRequest\n): Promise<MixrPayPaymentResult> {\n // IMPORTANT: Use redirect: 'manual' to prevent Authorization header from being stripped\n // during redirects (e.g., http→https, www→non-www). This is a common security measure\n // that can silently break API calls.\n const response = await fetch(`${baseUrl}/api/v2/charge`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${secretKey}`,\n },\n body: JSON.stringify({\n session_id: sessionId,\n price_usd: priceUsd,\n feature: config.feature || req.headers.get('x-mixr-feature'),\n idempotency_key: req.headers.get('x-idempotency-key'),\n }),\n redirect: 'manual', // Prevent redirect from stripping Authorization header\n });\n\n // Check for redirects - these will strip the Authorization header\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get('location');\n return {\n valid: false,\n method: 'session',\n error: `API URL caused redirect (${response.status}). Update MIXRPAY_API_URL to: ${location || baseUrl}. Redirects strip Authorization headers.`,\n sessionId,\n };\n }\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({})) as Record<string, unknown>;\n return {\n valid: false,\n method: 'session',\n error: (errorData.message || errorData.error || `Charge failed: ${response.status}`) as string,\n sessionId,\n };\n }\n\n const data = await response.json() as Record<string, unknown>;\n return {\n valid: true,\n method: 'session',\n payer: (data.payer || data.walletAddress) as string,\n amountUsd: (data.charged_usd as number) || priceUsd,\n txHash: data.tx_hash as string | undefined,\n chargeId: data.idempotency_key as string | undefined,\n sessionId,\n feature: config.feature,\n settledAt: data.settledAt ? new Date(data.settledAt as string) : new Date(),\n };\n}\n\nasync function verifyWidgetPaymentNext(\n paymentJwt: string,\n priceUsd: number,\n config: MixrPayConfig,\n req: NextRequest\n): Promise<MixrPayPaymentResult> {\n const baseUrl = config.mixrpayApiUrl || process.env.MIXRPAY_API_URL || 'https://www.mixrpay.com';\n const secretKey = process.env.MIXRPAY_SECRET_KEY;\n\n if (!secretKey) {\n return { valid: false, method: 'widget', error: 'MIXRPAY_SECRET_KEY not configured' };\n }\n\n try {\n // Use redirect: 'manual' to prevent Authorization header from being stripped\n const response = await fetch(`${baseUrl}/api/widget/verify`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${secretKey}`,\n },\n body: JSON.stringify({\n paymentJwt,\n expectedAmountUsd: priceUsd,\n feature: config.feature || req.headers.get('x-mixr-feature'),\n }),\n redirect: 'manual',\n });\n\n // Check for redirects - these will strip the Authorization header\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get('location');\n return {\n valid: false,\n method: 'widget',\n error: `API URL caused redirect (${response.status}). Update MIXRPAY_API_URL to: ${location || baseUrl}. Redirects strip Authorization headers.`,\n };\n }\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({})) as Record<string, unknown>;\n return {\n valid: false,\n method: 'widget',\n error: (errorData.message || errorData.error || `Widget verification failed: ${response.status}`) as string,\n };\n }\n\n const data = await response.json() as Record<string, unknown>;\n return {\n valid: true,\n method: 'widget',\n payer: (data.payer || data.walletAddress) as string,\n amountUsd: (data.amountUsd as number) || priceUsd,\n txHash: data.txHash as string | undefined,\n chargeId: data.chargeId as string | undefined,\n feature: config.feature,\n settledAt: data.settledAt ? new Date(data.settledAt as string) : new Date(),\n };\n } catch (error) {\n return {\n valid: false,\n method: 'widget',\n error: `Widget verification failed: ${(error as Error).message}`,\n };\n }\n}\n\nasync function verifyX402PaymentNext(\n paymentHeader: string,\n priceUsd: number,\n config: MixrPayConfig\n): Promise<MixrPayPaymentResult> {\n const recipient = config.recipient || process.env.MIXRPAY_MERCHANT_ADDRESS;\n\n if (!recipient) {\n return {\n valid: false,\n method: 'x402',\n error: 'MIXRPAY_MERCHANT_ADDRESS not configured for x402 payments',\n };\n }\n\n const priceMinor = usdToMinor(priceUsd);\n const chainId = config.chainId || 8453;\n const facilitator = config.facilitator || DEFAULT_FACILITATOR;\n\n const x402Result = await verifyX402Payment(paymentHeader, {\n expectedAmount: priceMinor,\n expectedRecipient: recipient,\n chainId,\n facilitator,\n skipSettlement: config.testMode,\n });\n\n if (!x402Result.valid) {\n return {\n valid: false,\n method: 'x402',\n error: x402Result.error,\n x402Result,\n };\n }\n\n // Fetch JWT receipt if needed\n const receiptMode = config.receiptMode || 'webhook';\n if ((receiptMode === 'jwt' || receiptMode === 'both') && x402Result.txHash && x402Result.payer) {\n try {\n const receipt = await fetchPaymentReceipt({\n txHash: x402Result.txHash,\n payer: x402Result.payer,\n recipient,\n amount: priceMinor,\n chainId,\n apiUrl: config.mixrpayApiUrl,\n });\n if (receipt) {\n x402Result.receipt = receipt;\n }\n } catch (receiptError) {\n console.warn('[withMixrPay] Failed to fetch JWT receipt:', receiptError);\n }\n }\n\n return {\n valid: true,\n method: 'x402',\n payer: x402Result.payer,\n amountUsd: x402Result.amount,\n txHash: x402Result.txHash,\n receipt: x402Result.receipt,\n settledAt: x402Result.settledAt,\n x402Result,\n };\n}\n\nfunction returnPaymentRequiredNext(priceUsd: number, config: MixrPayConfig): NextResponse {\n const priceMinor = usdToMinor(priceUsd);\n const recipient = config.recipient || process.env.MIXRPAY_MERCHANT_ADDRESS;\n const chainId = config.chainId || 8453;\n const facilitator = config.facilitator || DEFAULT_FACILITATOR;\n const nonce = generateNonce();\n const expiresAt = Math.floor(Date.now() / 1000) + 300;\n\n const x402PaymentRequired: X402PaymentRequired | null = recipient ? {\n recipient,\n amount: priceMinor.toString(),\n currency: 'USDC',\n chainId,\n facilitator,\n nonce,\n expiresAt,\n description: config.description,\n } : null;\n\n const headers: Record<string, string> = {};\n if (x402PaymentRequired) {\n headers['X-Payment-Required'] = JSON.stringify(x402PaymentRequired);\n headers['WWW-Authenticate'] = `X-402 ${Buffer.from(JSON.stringify(x402PaymentRequired)).toString('base64')}`;\n }\n\n return NextResponse.json(\n {\n error: 'Payment required',\n priceUsd,\n acceptedMethods: [\n { method: 'session', header: 'X-Mixr-Session', description: 'Session authorization ID' },\n { method: 'widget', header: 'X-Mixr-Payment', description: 'Widget payment JWT' },\n ...(recipient ? [{ method: 'x402', header: 'X-PAYMENT', description: 'x402 protocol payment' }] : []),\n ],\n x402: x402PaymentRequired,\n description: config.description,\n },\n { status: 402, headers }\n );\n}\n\n// Types are already exported via interface declarations above\n\n","/**\n * MixrPay Merchant SDK - Payment Verification\n */\n\nimport { recoverTypedDataAddress } from 'viem';\nimport type { \n X402PaymentResult, \n X402PaymentPayload, \n VerifyOptions,\n TransferWithAuthorizationMessage,\n} from './types';\nimport { \n getUSDCDomain, \n TRANSFER_WITH_AUTHORIZATION_TYPES, \n base64Decode,\n minorToUsd,\n DEFAULT_FACILITATOR,\n} from './utils';\n\n// =============================================================================\n// Payment Verification\n// =============================================================================\n\n/**\n * Verify an X-PAYMENT header and optionally settle the payment.\n * \n * @param paymentHeader - The X-PAYMENT header value (base64 encoded JSON)\n * @param options - Verification options\n * @returns Payment verification result\n * \n * @example\n * ```typescript\n * const result = await verifyX402Payment(req.headers['x-payment'], {\n * expectedAmount: 50000n, // 0.05 USDC\n * expectedRecipient: '0x...',\n * });\n * \n * if (result.valid) {\n * console.log(`Payment from ${result.payer}: $${result.amount}`);\n * }\n * ```\n */\nexport async function verifyX402Payment(\n paymentHeader: string,\n options: VerifyOptions\n): Promise<X402PaymentResult> {\n try {\n // 1. Decode the X-PAYMENT header\n let decoded: X402PaymentPayload;\n try {\n const jsonStr = base64Decode(paymentHeader);\n decoded = JSON.parse(jsonStr);\n } catch (e) {\n return { valid: false, error: 'Invalid payment header encoding' };\n }\n\n // 2. Validate payload structure\n if (!decoded.payload?.authorization || !decoded.payload?.signature) {\n return { valid: false, error: 'Missing authorization or signature in payment' };\n }\n\n const { authorization, signature } = decoded.payload;\n const chainId = options.chainId || 8453;\n\n // 3. Build EIP-712 message for verification\n const message: TransferWithAuthorizationMessage = {\n from: authorization.from as `0x${string}`,\n to: authorization.to as `0x${string}`,\n value: BigInt(authorization.value),\n validAfter: BigInt(authorization.validAfter),\n validBefore: BigInt(authorization.validBefore),\n nonce: authorization.nonce as `0x${string}`,\n };\n\n // 4. Recover signer address\n const domain = getUSDCDomain(chainId);\n let signerAddress: string;\n \n try {\n signerAddress = await recoverTypedDataAddress({\n domain,\n types: TRANSFER_WITH_AUTHORIZATION_TYPES,\n primaryType: 'TransferWithAuthorization',\n message,\n signature: signature as `0x${string}`,\n });\n } catch (e) {\n return { valid: false, error: 'Failed to recover signer from signature' };\n }\n\n // 5. Verify signer matches the 'from' address\n if (signerAddress.toLowerCase() !== authorization.from.toLowerCase()) {\n return { \n valid: false, \n error: `Signature mismatch: expected ${authorization.from}, got ${signerAddress}` \n };\n }\n\n // 6. Verify payment amount\n const paymentAmount = BigInt(authorization.value);\n if (paymentAmount < options.expectedAmount) {\n return { \n valid: false, \n error: `Insufficient payment: expected ${options.expectedAmount}, got ${paymentAmount}` \n };\n }\n\n // 7. Verify recipient\n if (authorization.to.toLowerCase() !== options.expectedRecipient.toLowerCase()) {\n return { \n valid: false, \n error: `Wrong recipient: expected ${options.expectedRecipient}, got ${authorization.to}` \n };\n }\n\n // 8. Check expiration\n const now = Math.floor(Date.now() / 1000);\n if (Number(authorization.validBefore) < now) {\n return { valid: false, error: 'Payment authorization has expired' };\n }\n\n // 9. Check validAfter\n if (Number(authorization.validAfter) > now) {\n return { valid: false, error: 'Payment authorization is not yet valid' };\n }\n\n // 10. Submit to facilitator for settlement (unless skipped)\n let txHash: string | undefined;\n let settledAt: Date | undefined;\n\n if (!options.skipSettlement) {\n const facilitatorUrl = options.facilitator || DEFAULT_FACILITATOR;\n \n try {\n const settlementResponse = await fetch(`${facilitatorUrl}/settle`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n authorization, \n signature,\n chainId,\n }),\n });\n\n if (!settlementResponse.ok) {\n const errorBody = await settlementResponse.text();\n let errorMessage = 'Settlement failed';\n try {\n const errorJson = JSON.parse(errorBody);\n errorMessage = errorJson.message || errorJson.error || errorMessage;\n } catch {\n errorMessage = errorBody || errorMessage;\n }\n return { valid: false, error: `Settlement failed: ${errorMessage}` };\n }\n\n const settlement = await settlementResponse.json() as { txHash?: string; tx_hash?: string };\n txHash = settlement.txHash || settlement.tx_hash;\n settledAt = new Date();\n } catch (e) {\n return { \n valid: false, \n error: `Settlement request failed: ${(e as Error).message}` \n };\n }\n }\n\n // Success!\n return {\n valid: true,\n payer: authorization.from,\n amount: minorToUsd(paymentAmount),\n amountMinor: paymentAmount,\n txHash,\n settledAt: settledAt || new Date(),\n nonce: authorization.nonce,\n };\n\n } catch (error) {\n return { \n valid: false, \n error: `Verification error: ${(error as Error).message}` \n };\n }\n}\n\n/**\n * Parse and validate an X-PAYMENT header without settlement.\n * Useful for checking if a payment is structurally valid before processing.\n */\nexport async function parseX402Payment(\n paymentHeader: string,\n chainId: number = 8453\n): Promise<{\n valid: boolean;\n error?: string;\n payer?: string;\n recipient?: string;\n amount?: number;\n amountMinor?: bigint;\n expiresAt?: Date;\n}> {\n try {\n const jsonStr = base64Decode(paymentHeader);\n const decoded: X402PaymentPayload = JSON.parse(jsonStr);\n\n if (!decoded.payload?.authorization) {\n return { valid: false, error: 'Missing authorization in payment' };\n }\n\n const { authorization, signature } = decoded.payload;\n\n // Verify signature\n const domain = getUSDCDomain(chainId);\n const message: TransferWithAuthorizationMessage = {\n from: authorization.from as `0x${string}`,\n to: authorization.to as `0x${string}`,\n value: BigInt(authorization.value),\n validAfter: BigInt(authorization.validAfter),\n validBefore: BigInt(authorization.validBefore),\n nonce: authorization.nonce as `0x${string}`,\n };\n\n const signerAddress = await recoverTypedDataAddress({\n domain,\n types: TRANSFER_WITH_AUTHORIZATION_TYPES,\n primaryType: 'TransferWithAuthorization',\n message,\n signature: signature as `0x${string}`,\n });\n\n if (signerAddress.toLowerCase() !== authorization.from.toLowerCase()) {\n return { valid: false, error: 'Signature mismatch' };\n }\n\n const amountMinor = BigInt(authorization.value);\n \n return {\n valid: true,\n payer: authorization.from,\n recipient: authorization.to,\n amount: minorToUsd(amountMinor),\n amountMinor,\n expiresAt: new Date(Number(authorization.validBefore) * 1000),\n };\n } catch (error) {\n return { valid: false, error: `Parse error: ${(error as Error).message}` };\n }\n}\n\n","/**\n * MixrPay Merchant SDK - Utilities\n */\n\nimport type { EIP712Domain } from './types';\n\n// =============================================================================\n// USDC Constants by Chain\n// =============================================================================\n\nexport const USDC_CONTRACTS: Record<number, `0x${string}`> = {\n 8453: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // Base Mainnet\n 84532: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', // Base Sepolia\n};\n\nexport const DEFAULT_FACILITATOR = 'https://x402.org/facilitator';\n\n// =============================================================================\n// EIP-712 Domain\n// =============================================================================\n\nexport function getUSDCDomain(chainId: number): EIP712Domain {\n const verifyingContract = USDC_CONTRACTS[chainId];\n if (!verifyingContract) {\n throw new Error(`Unsupported chain ID: ${chainId}. Supported: ${Object.keys(USDC_CONTRACTS).join(', ')}`);\n }\n\n return {\n name: 'USD Coin',\n version: '2',\n chainId,\n verifyingContract,\n };\n}\n\n// EIP-712 types for TransferWithAuthorization\nexport const TRANSFER_WITH_AUTHORIZATION_TYPES = {\n TransferWithAuthorization: [\n { name: 'from', type: 'address' },\n { name: 'to', type: 'address' },\n { name: 'value', type: 'uint256' },\n { name: 'validAfter', type: 'uint256' },\n { name: 'validBefore', type: 'uint256' },\n { name: 'nonce', type: 'bytes32' },\n ],\n} as const;\n\n// =============================================================================\n// Utility Functions\n// =============================================================================\n\n/**\n * Convert USD dollars to USDC minor units (6 decimals)\n */\nexport function usdToMinor(usd: number): bigint {\n return BigInt(Math.round(usd * 1_000_000));\n}\n\n/**\n * Convert USDC minor units to USD dollars\n */\nexport function minorToUsd(minor: bigint): number {\n return Number(minor) / 1_000_000;\n}\n\n/**\n * Generate a random nonce for x402 payments\n */\nexport function generateNonce(): `0x${string}` {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return `0x${Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('')}` as `0x${string}`;\n}\n\n/**\n * Check if an address is valid\n */\nexport function isValidAddress(address: string): address is `0x${string}` {\n return /^0x[a-fA-F0-9]{40}$/.test(address);\n}\n\n/**\n * Normalize an address to lowercase checksum format\n */\nexport function normalizeAddress(address: string): `0x${string}` {\n if (!isValidAddress(address)) {\n throw new Error(`Invalid address: ${address}`);\n }\n return address.toLowerCase() as `0x${string}`;\n}\n\n/**\n * Safe base64 decode that works in both Node.js and browsers\n */\nexport function base64Decode(str: string): string {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(str, 'base64').toString('utf-8');\n }\n return atob(str);\n}\n\n/**\n * Safe base64 encode that works in both Node.js and browsers\n */\nexport function base64Encode(str: string): string {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(str, 'utf-8').toString('base64');\n }\n return btoa(str);\n}\n\n","/**\n * MixrPay Merchant SDK - Receipt Fetcher\n * \n * Internal utility to fetch JWT receipts from MixrPay API after settlement.\n * Used by x402 middleware to get receipts for the X-Payment-Receipt header.\n */\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nconst DEFAULT_MIXRPAY_API_URL = process.env.MIXRPAY_BASE_URL || 'https://www.mixrpay.com';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface FetchReceiptParams {\n /** Settlement transaction hash */\n txHash: string;\n /** Payer address */\n payer: string;\n /** Recipient address */\n recipient: string;\n /** Amount in USDC minor units */\n amount: bigint;\n /** Chain ID */\n chainId: number;\n /** Custom MixrPay API URL (optional) */\n apiUrl?: string;\n}\n\ninterface ReceiptResponse {\n receipt: string;\n expiresAt: string;\n}\n\n// =============================================================================\n// Receipt Fetching\n// =============================================================================\n\n/**\n * Fetch a JWT payment receipt from MixrPay API.\n * \n * This is called by the x402 middleware after successful payment verification\n * when receiptMode is 'jwt' or 'both'.\n * \n * @param params - Receipt request parameters\n * @returns JWT receipt string, or null if not available\n */\nexport async function fetchPaymentReceipt(params: FetchReceiptParams): Promise<string | null> {\n const apiUrl = params.apiUrl || DEFAULT_MIXRPAY_API_URL;\n const endpoint = `${apiUrl}/api/v1/receipts`;\n\n try {\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n tx_hash: params.txHash,\n payer: params.payer,\n recipient: params.recipient,\n amount: params.amount.toString(),\n chain_id: params.chainId,\n }),\n });\n\n if (!response.ok) {\n // Log but don't throw - receipt is optional\n console.warn(`[x402] Receipt fetch failed: ${response.status} ${response.statusText}`);\n return null;\n }\n\n const data = await response.json() as ReceiptResponse;\n return data.receipt || null;\n } catch (error) {\n // Log but don't throw - payment was successful, receipt is optional\n console.warn('[x402] Receipt fetch error:', (error as Error).message);\n return null;\n }\n}\n\n/**\n * Generate a local receipt for testing purposes.\n * \n * WARNING: This generates an unsigned receipt that will NOT verify.\n * Use only for local development and testing.\n * \n * @param params - Receipt parameters\n * @returns Mock JWT-like string (not cryptographically signed)\n */\nexport function generateMockReceipt(params: FetchReceiptParams): string {\n const header = {\n alg: 'none',\n typ: 'JWT',\n };\n\n const payload = {\n paymentId: `mock_${Date.now()}`,\n amount: params.amount.toString(),\n amountUsd: Number(params.amount) / 1_000_000,\n payer: params.payer,\n recipient: params.recipient,\n chainId: params.chainId,\n txHash: params.txHash,\n settledAt: new Date().toISOString(),\n iat: Math.floor(Date.now() / 1000),\n exp: Math.floor(Date.now() / 1000) + 3600,\n _mock: true,\n };\n\n const base64Header = Buffer.from(JSON.stringify(header)).toString('base64url');\n const base64Payload = Buffer.from(JSON.stringify(payload)).toString('base64url');\n\n // Mock signature (not cryptographically valid)\n return `${base64Header}.${base64Payload}.mock_signature_for_testing_only`;\n}\n\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED