@mixrpay/merchant-sdk 0.5.0 → 0.5.1

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/index.js CHANGED
@@ -310,7 +310,7 @@ var MerchantClient = class {
310
310
  * ```
311
311
  */
312
312
  async listMCPTools() {
313
- return this.request("GET", "/api/seller/mcp-tools");
313
+ return this.request("GET", "/api/seller/gateway-tools");
314
314
  }
315
315
  /**
316
316
  * Enable an MCP tool.
@@ -325,7 +325,7 @@ var MerchantClient = class {
325
325
  * ```
326
326
  */
327
327
  async enableMCPTool(toolSlug) {
328
- return this.request("POST", "/api/seller/mcp-tools/toggle", {
328
+ return this.request("POST", "/api/seller/gateway-tools/toggle", {
329
329
  toolSlug,
330
330
  enable: true
331
331
  });
@@ -342,7 +342,7 @@ var MerchantClient = class {
342
342
  * ```
343
343
  */
344
344
  async disableMCPTool(toolSlug) {
345
- return this.request("POST", "/api/seller/mcp-tools/toggle", {
345
+ return this.request("POST", "/api/seller/gateway-tools/toggle", {
346
346
  toolSlug,
347
347
  enable: false
348
348
  });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/charges.ts","../src/utils.ts","../src/platform-types.ts","../src/platform.ts"],"sourcesContent":["/**\n * MixrPay Merchant SDK\n * \n * Accept payments from AI agents and web apps with one middleware.\n * \n * @example Express\n * ```typescript\n * import { mixrpay } from '@mixrpay/merchant-sdk/express';\n * \n * app.post('/api/query', mixrpay({ priceUsd: 0.05 }), (req, res) => {\n * console.log(`Paid by ${req.mixrPayment?.payer}`);\n * res.json({ result: 'success' });\n * });\n * ```\n * \n * @example Next.js\n * ```typescript\n * import { withMixrPay } from '@mixrpay/merchant-sdk/nextjs';\n * \n * export const POST = withMixrPay({ priceUsd: 0.05 }, async (req, payment) => {\n * return NextResponse.json({ result: 'success' });\n * });\n * ```\n * \n * @packageDocumentation\n */\n\n// Session webhook verification\nexport { verifySessionWebhook } from './charges';\n\n// Utility functions and constants\nexport {\n getWidgetUrl,\n WIDGET_SCRIPT_URL,\n MIXRPAY_API_URL,\n usdToMinor,\n minorToUsd,\n validateEnv,\n logEnvValidation,\n} from './utils';\n\nexport type { EnvValidationResult } from './utils';\n\n// Types for TypeScript users\nexport type {\n MixrPayOptions,\n MixrPayPaymentResult,\n PaymentMethod,\n PriceContext,\n} from './types';\n\nexport type {\n SessionGrant,\n} from './charges';\n\n// Widget element types (for TypeScript JSX support)\nexport type {} from './widget-elements';\n\n// Platform client for programmatic configuration\nexport { MerchantClient } from './platform';\n\n// Platform types\nexport type {\n MerchantClientOptions,\n MarkupInfo,\n SetMarkupParams,\n SetMarkupResponse,\n LLMModel,\n LLMModelsResponse,\n MCPTool,\n MCPToolsResponse,\n ToggleResult,\n Feature,\n FeaturesResponse,\n CreateFeatureParams,\n CreateFeatureResponse,\n SyncFeaturesParams,\n SyncResult,\n} from './platform-types';\n\nexport { MerchantAPIError } from './platform-types';\n","/**\n * MixrPay Charges Module\n * \n * Create and manage charges using session signers.\n * Session signers allow you to charge user wallets without\n * requiring approval for each transaction.\n */\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface CreateChargeParams {\n /** Session key ID granted by the user */\n sessionId: string;\n /** Amount to charge in USD (e.g., 0.05 for 5 cents) */\n amountUsd: number;\n /** Unique reference for idempotency (e.g., \"order_123\") */\n reference: string;\n /** Optional metadata */\n metadata?: Record<string, unknown>;\n}\n\nexport interface Charge {\n /** Unique charge ID */\n id: string;\n /** Current status (from database) */\n status: 'pending' | 'submitted' | 'confirmed' | 'failed';\n /** Real-time status (may differ from DB if not yet synced) */\n liveStatus?: 'pending' | 'submitted' | 'confirmed' | 'failed';\n /** Raw on-chain status */\n onChainStatus?: 'pending' | 'confirmed' | 'failed' | 'not_found' | null;\n /** Amount in USD */\n amountUsd: number;\n /** Formatted USDC amount */\n amountUsdc: string;\n /** Transaction hash (if submitted) */\n txHash?: string;\n /** Block explorer URL */\n explorerUrl?: string;\n /** From wallet address */\n fromAddress: string;\n /** To wallet address */\n toAddress: string;\n /** Your reference */\n reference: string;\n /** When the charge was created */\n createdAt: string;\n /** When the charge was confirmed */\n confirmedAt?: string;\n /** Session name */\n sessionName?: string;\n /** User wallet address */\n userWallet?: string;\n /** Error message if failed */\n error?: string;\n /** True if DB status differs from on-chain - call sync() to update */\n needsSync?: boolean;\n}\n\nexport interface CreateChargeResult {\n success: boolean;\n charge?: Charge;\n /** True if this is a replay of an existing charge */\n idempotentReplay?: boolean;\n error?: string;\n details?: string;\n}\n\nexport interface SessionGrant {\n /** Session key ID */\n sessionId: string;\n /** User's wallet address */\n userWallet: string;\n /** Your merchant wallet address */\n merchantWallet: string;\n /** Spending limits */\n limits: {\n maxTotalUsd?: number;\n maxPerTxUsd?: number;\n expiresAt: string;\n };\n /** When the session was granted */\n grantedAt: string;\n}\n\n// Internal types for API responses\ninterface CreateChargeApiResponse {\n success: boolean;\n charge_id?: string;\n status?: string;\n amount_usd?: number;\n amount_usdc?: string;\n tx_hash?: string;\n explorer_url?: string;\n idempotent_replay?: boolean;\n error?: string;\n details?: string;\n}\n\ninterface ChargeApiResponse {\n id: string;\n status: string;\n /** Real-time status (may differ from DB status if not yet synced) */\n live_status?: string;\n /** Raw on-chain status */\n on_chain_status?: 'pending' | 'confirmed' | 'failed' | 'not_found' | null;\n amount_usd: number;\n amount_usdc: string;\n tx_hash?: string;\n explorer_url?: string;\n from_address: string;\n to_address: string;\n reference: string;\n created_at: string;\n confirmed_at?: string;\n session_name?: string;\n user_wallet?: string;\n /** True if DB status differs from on-chain status */\n needs_sync?: boolean;\n}\n\ninterface SyncChargeApiResponse {\n success: boolean;\n charge?: {\n id: string;\n status: string;\n };\n error?: string;\n}\n\nexport interface ChargesClientOptions {\n /** Your API key */\n apiKey: string;\n /** MixrPay API base URL */\n baseUrl?: string;\n}\n\n// =============================================================================\n// Client\n// =============================================================================\n\nexport class ChargesClient {\n private apiKey: string;\n private baseUrl: string;\n\n constructor(options: ChargesClientOptions) {\n this.apiKey = options.apiKey;\n this.baseUrl = options.baseUrl || process.env.MIXRPAY_BASE_URL || 'https://www.mixrpay.com';\n }\n\n /**\n * Create a new charge.\n * \n * @example\n * ```typescript\n * const result = await charges.create({\n * sessionId: 'sk_xxx',\n * amountUsd: 0.05,\n * reference: 'image_gen_123',\n * metadata: { feature: 'image_generation' }\n * });\n * \n * if (result.success) {\n * console.log(`Charged ${result.charge.amountUsdc}`);\n * console.log(`TX: ${result.charge.explorerUrl}`);\n * }\n * ```\n */\n async create(params: CreateChargeParams): Promise<CreateChargeResult> {\n const response = await fetch(`${this.baseUrl}/api/v1/charges`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({\n session_id: params.sessionId,\n amount_usd: params.amountUsd,\n reference: params.reference,\n metadata: params.metadata,\n }),\n });\n\n const data = await response.json() as CreateChargeApiResponse;\n\n if (!response.ok) {\n return {\n success: false,\n error: data.error,\n details: data.details,\n };\n }\n\n return {\n success: data.success,\n charge: data.charge_id ? {\n id: data.charge_id,\n status: data.status as Charge['status'],\n amountUsd: data.amount_usd ?? 0,\n amountUsdc: data.amount_usdc ?? '0',\n txHash: data.tx_hash,\n explorerUrl: data.explorer_url,\n fromAddress: '',\n toAddress: '',\n reference: params.reference,\n createdAt: new Date().toISOString(),\n } : undefined,\n idempotentReplay: data.idempotent_replay,\n error: data.error,\n };\n }\n\n /**\n * Get a charge by ID.\n * \n * Note: The returned status is from the database. If `needsSync` is true,\n * the on-chain status differs and you should call `sync()` to update.\n * \n * @example\n * ```typescript\n * const charge = await charges.get('chg_xxx');\n * console.log(charge.status); // 'submitted'\n * console.log(charge.liveStatus); // 'confirmed' (real-time)\n * \n * if (charge.needsSync) {\n * await charges.sync(charge.id);\n * }\n * ```\n */\n async get(chargeId: string): Promise<Charge | null> {\n const response = await fetch(`${this.baseUrl}/api/v1/charges?id=${chargeId}`, {\n headers: {\n 'Authorization': `Bearer ${this.apiKey}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 404) {\n return null;\n }\n throw new Error(`Failed to get charge: ${response.statusText}`);\n }\n\n const data = await response.json() as ChargeApiResponse;\n\n return this.mapChargeResponse(data);\n }\n\n /**\n * Get a charge by transaction hash.\n */\n async getByTxHash(txHash: string): Promise<Charge | null> {\n const response = await fetch(`${this.baseUrl}/api/v1/charges?tx_hash=${txHash}`, {\n headers: {\n 'Authorization': `Bearer ${this.apiKey}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 404) {\n return null;\n }\n throw new Error(`Failed to get charge: ${response.statusText}`);\n }\n\n const data = await response.json() as ChargeApiResponse;\n\n return this.mapChargeResponse(data);\n }\n\n /**\n * Sync a charge's status from the blockchain.\n * \n * Call this when `get()` returns a charge with `needsSync: true`.\n * This will update the database with the on-chain status.\n * \n * @example\n * ```typescript\n * const charge = await charges.get('chg_xxx');\n * if (charge?.needsSync) {\n * const synced = await charges.sync(charge.id);\n * console.log(`Status updated to: ${synced.status}`);\n * }\n * ```\n */\n async sync(chargeId: string): Promise<{ id: string; status: string }> {\n const response = await fetch(`${this.baseUrl}/api/v1/charges/sync`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({ charge_id: chargeId }),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(`Failed to sync charge: ${(error as { error?: string }).error || response.statusText}`);\n }\n\n const data = await response.json() as SyncChargeApiResponse;\n\n if (!data.success || !data.charge) {\n throw new Error(`Sync failed: ${data.error || 'Unknown error'}`);\n }\n\n return data.charge;\n }\n\n /**\n * Poll for charge confirmation.\n * \n * Convenience method that polls until the charge is confirmed or failed,\n * automatically syncing when needed.\n * \n * @example\n * ```typescript\n * const charge = await charges.waitForConfirmation('chg_xxx', {\n * timeoutMs: 60000,\n * pollIntervalMs: 2000,\n * });\n * console.log(`Final status: ${charge.status}`);\n * ```\n */\n async waitForConfirmation(\n chargeId: string,\n options: { timeoutMs?: number; pollIntervalMs?: number } = {}\n ): Promise<Charge> {\n const { timeoutMs = 60000, pollIntervalMs = 2000 } = options;\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeoutMs) {\n const charge = await this.get(chargeId);\n \n if (!charge) {\n throw new Error('Charge not found');\n }\n\n // If needs sync, sync it first\n if (charge.needsSync) {\n await this.sync(chargeId);\n // Re-fetch to get updated status\n const synced = await this.get(chargeId);\n if (synced && (synced.status === 'confirmed' || synced.status === 'failed')) {\n return synced;\n }\n }\n\n // Check if we've reached a terminal state\n if (charge.status === 'confirmed' || charge.status === 'failed') {\n return charge;\n }\n\n // Also check live status for early return\n if (charge.liveStatus === 'confirmed' || charge.liveStatus === 'failed') {\n // Sync and return\n await this.sync(chargeId);\n const final = await this.get(chargeId);\n if (final) return final;\n }\n\n // Wait before next poll\n await new Promise(resolve => setTimeout(resolve, pollIntervalMs));\n }\n\n throw new Error(`Timeout waiting for charge confirmation after ${timeoutMs}ms`);\n }\n\n private mapChargeResponse(data: ChargeApiResponse): Charge {\n return {\n id: data.id,\n status: data.status as Charge['status'],\n liveStatus: data.live_status as Charge['status'] | undefined,\n onChainStatus: data.on_chain_status,\n amountUsd: data.amount_usd,\n amountUsdc: data.amount_usdc,\n txHash: data.tx_hash,\n explorerUrl: data.explorer_url,\n fromAddress: data.from_address,\n toAddress: data.to_address,\n reference: data.reference,\n createdAt: data.created_at,\n confirmedAt: data.confirmed_at,\n sessionName: data.session_name,\n userWallet: data.user_wallet,\n needsSync: data.needs_sync,\n };\n }\n}\n\n// =============================================================================\n// Webhook Verification\n// =============================================================================\n\nimport crypto from 'crypto';\n\n/**\n * Verify a session.granted webhook signature.\n * \n * @example\n * ```typescript\n * const payload = req.body;\n * const signature = req.headers['x-mixrpay-signature'];\n * \n * if (verifySessionWebhook(JSON.stringify(payload), signature, webhookSecret)) {\n * const grant = parseSessionGrant(payload);\n * console.log(`User ${grant.userWallet} granted access`);\n * }\n * ```\n */\nexport function verifySessionWebhook(\n payload: string,\n signature: string,\n secret: string\n): boolean {\n const expectedSignature = crypto\n .createHmac('sha256', secret)\n .update(payload)\n .digest('hex');\n \n return crypto.timingSafeEqual(\n Buffer.from(signature),\n Buffer.from(expectedSignature)\n );\n}\n\n/**\n * Parse a session.granted webhook payload.\n */\nexport function parseSessionGrant(payload: {\n event: string;\n session_id: string;\n user_wallet: string;\n merchant_wallet: string;\n limits: {\n max_total_usd?: number;\n max_per_tx_usd?: number;\n expires_at: string;\n };\n granted_at: string;\n}): SessionGrant {\n if (payload.event !== 'session.granted') {\n throw new Error(`Unexpected event type: ${payload.event}`);\n }\n\n return {\n sessionId: payload.session_id,\n userWallet: payload.user_wallet,\n merchantWallet: payload.merchant_wallet,\n limits: {\n maxTotalUsd: payload.limits.max_total_usd,\n maxPerTxUsd: payload.limits.max_per_tx_usd,\n expiresAt: payload.limits.expires_at,\n },\n grantedAt: payload.granted_at,\n };\n}\n\n","/**\n * MixrPay Merchant SDK - Utilities\n */\n\nimport type { EIP712Domain } from './types';\n\n// =============================================================================\n// Widget URLs\n// =============================================================================\n\n/**\n * Get the MixrPay widget script URL.\n * \n * @example\n * ```html\n * <script src=\"${getWidgetUrl()}\"\n * data-seller-public-key=\"pk_live_...\"\n * data-user-token=\"...\"></script>\n * ```\n */\nexport function getWidgetUrl(): string {\n return 'https://www.mixrpay.com/widget.js';\n}\n\n/**\n * MixrPay API base URL\n */\nexport const MIXRPAY_API_URL = 'https://www.mixrpay.com';\n\n/**\n * Widget script URL (for convenience)\n */\nexport const WIDGET_SCRIPT_URL = 'https://www.mixrpay.com/widget.js';\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// Environment Validation\n// =============================================================================\n\nexport interface EnvValidationResult {\n valid: boolean;\n errors: string[];\n warnings: string[];\n config: {\n publicKey: string | null;\n secretKey: string | null;\n hmacSecret: string | null;\n webhookSecret: string | null;\n merchantAddress: string | null;\n };\n}\n\n/**\n * Validate MixrPay environment variables and provide helpful feedback.\n * \n * @example\n * ```typescript\n * import { validateEnv } from '@mixrpay/merchant-sdk';\n * \n * const result = validateEnv();\n * if (!result.valid) {\n * console.error('MixrPay configuration errors:', result.errors);\n * }\n * ```\n */\nexport function validateEnv(env?: Record<string, string | undefined>): EnvValidationResult {\n const e = env || (typeof process !== 'undefined' ? process.env : {});\n \n const result: EnvValidationResult = {\n valid: true,\n errors: [],\n warnings: [],\n config: {\n publicKey: (e.MIXRPAY_PUBLIC_KEY as string) || null,\n secretKey: (e.MIXRPAY_SECRET_KEY as string) || null,\n hmacSecret: (e.MIXRPAY_HMAC_SECRET as string) || null,\n webhookSecret: (e.MIXRPAY_WEBHOOK_SECRET as string) || null,\n merchantAddress: (e.MIXRPAY_MERCHANT_ADDRESS as string) || null,\n },\n };\n \n // Check public key\n if (!result.config.publicKey) {\n result.errors.push('MIXRPAY_PUBLIC_KEY is required. Get it from https://www.mixrpay.com/seller/developers');\n result.valid = false;\n } else if (!result.config.publicKey.startsWith('pk_')) {\n result.errors.push(`MIXRPAY_PUBLIC_KEY must start with 'pk_'. Got: ${result.config.publicKey.slice(0, 10)}...`);\n result.valid = false;\n }\n \n // Check secret key\n if (!result.config.secretKey) {\n result.errors.push('MIXRPAY_SECRET_KEY is required. Get it from https://www.mixrpay.com/seller/developers');\n result.valid = false;\n } else if (!result.config.secretKey.startsWith('sk_')) {\n result.errors.push(`MIXRPAY_SECRET_KEY must start with 'sk_'. Got: ${result.config.secretKey.slice(0, 10)}...`);\n result.valid = false;\n }\n \n // Check webhook secret (required)\n if (!result.config.webhookSecret) {\n result.errors.push('MIXRPAY_WEBHOOK_SECRET is required. Get it from https://www.mixrpay.com/seller/developers');\n result.valid = false;\n }\n \n // Check HMAC secret (warning only - only needed for widget with user linking)\n if (!result.config.hmacSecret) {\n result.warnings.push('MIXRPAY_HMAC_SECRET not set. Only required if using Widget with user linking (data-user-token).');\n }\n \n // Check merchant address (warning only - needed for x402)\n if (!result.config.merchantAddress) {\n result.warnings.push('MIXRPAY_MERCHANT_ADDRESS not set. Required for x402 protocol support.');\n } else if (!isValidAddress(result.config.merchantAddress)) {\n result.errors.push(`MIXRPAY_MERCHANT_ADDRESS is not a valid Ethereum address: ${result.config.merchantAddress}`);\n result.valid = false;\n }\n \n return result;\n}\n\n/**\n * Log environment validation results to console with formatting.\n */\nexport function logEnvValidation(result?: EnvValidationResult): void {\n const r = result || validateEnv();\n \n console.log('\\nšŸ”§ MixrPay Environment Check\\n');\n \n if (r.valid) {\n console.log('āœ… Configuration valid\\n');\n } else {\n console.log('āŒ Configuration errors found\\n');\n }\n \n if (r.errors.length > 0) {\n console.log('Errors:');\n r.errors.forEach(e => console.log(` āŒ ${e}`));\n console.log('');\n }\n \n if (r.warnings.length > 0) {\n console.log('Warnings:');\n r.warnings.forEach(w => console.log(` āš ļø ${w}`));\n console.log('');\n }\n \n console.log('Required credentials:');\n console.log(` Public Key: ${r.config.publicKey ? 'āœ“ Set' : 'āœ— Missing'}`);\n console.log(` Secret Key: ${r.config.secretKey ? 'āœ“ Set' : 'āœ— Missing'}`);\n console.log(` Webhook Secret: ${r.config.webhookSecret ? 'āœ“ Set' : 'āœ— Missing'}`);\n console.log('');\n console.log('Optional credentials:');\n console.log(` HMAC Secret: ${r.config.hmacSecret ? 'āœ“ Set' : 'ā—‹ Not set (widget only)'}`);\n console.log(` Merchant Address: ${r.config.merchantAddress ? 'āœ“ Set' : 'ā—‹ Not set (x402 only)'}`);\n console.log('');\n}\n\n","/**\n * MixrPay Merchant SDK - Platform Types\n * \n * Type definitions for the MerchantClient class that enables\n * programmatic management of platform features.\n */\n\n// =============================================================================\n// Configuration\n// =============================================================================\n\nexport interface MerchantClientOptions {\n /** Your secret API key (sk_live_xxx or sk_test_xxx) */\n secretKey: string;\n /** API base URL (defaults to https://www.mixrpay.com) */\n baseUrl?: string;\n}\n\n// =============================================================================\n// Markup\n// =============================================================================\n\nexport interface MarkupInfo {\n /** Markup in basis points (e.g., 2000 = 20%) */\n markupBps: number;\n /** Markup as percentage (e.g., 20 = 20%) */\n markupPercent: number;\n /** Multiplier to apply to platform prices (e.g., 1.2 for 20% markup) */\n markupMultiplier: number;\n /** Example calculation */\n example?: {\n platformPrice: number;\n yourPrice: number;\n yourProfit: number;\n };\n}\n\nexport interface SetMarkupParams {\n /** Markup percentage (10-200). e.g., 20 = 20% markup. Minimum 10% required. */\n percent: number;\n}\n\nexport interface SetMarkupResponse extends MarkupInfo {\n success: boolean;\n message?: string;\n}\n\n// =============================================================================\n// LLM Models\n// =============================================================================\n\nexport interface LLMModel {\n /** Platform feature ID */\n id: string;\n /** Model identifier (e.g., \"gpt-4o-mini\", \"claude-3-5-haiku-latest\") */\n modelId: string;\n /** Human-readable name */\n displayName: string;\n /** Model description */\n description: string | null;\n /** Provider (e.g., \"openai\", \"anthropic\") */\n provider: string;\n /** Input token price per 1M tokens in USD */\n inputPricePer1M: number;\n /** Output token price per 1M tokens in USD */\n outputPricePer1M: number;\n /** Maximum context window size */\n contextWindow: number | null;\n /** Whether the merchant has enabled this model */\n enabled: boolean;\n}\n\nexport interface LLMModelsResponse {\n /** List of available LLM models */\n models: LLMModel[];\n /** Total number of models */\n count: number;\n /** Number of models enabled by merchant */\n enabledCount: number;\n}\n\nexport interface ToggleResult {\n success: boolean;\n enabled: boolean;\n modelId?: string;\n featureId?: string;\n toolSlug?: string;\n displayName?: string;\n}\n\n// =============================================================================\n// MCP Tools\n// =============================================================================\n\nexport interface MCPTool {\n /** Platform feature ID */\n id: string;\n /** Tool slug (e.g., \"firecrawl-scrape\", \"exa-search\") */\n slug: string;\n /** Human-readable name */\n displayName: string;\n /** Tool description */\n description: string | null;\n /** Tool provider */\n provider: string | null;\n /** Price per call in USD */\n priceUsd: number;\n /** Primary use case */\n primaryIntent: string | null;\n /** Agent workflow stage (acquire, parse, transform, reason, act) */\n agentStage: string | null;\n /** What the tool is best for */\n bestFor: string[];\n /** Latency class (low, medium, high) */\n latencyClass: string | null;\n /** Whether the merchant has enabled this tool */\n enabled: boolean;\n}\n\nexport interface MCPToolsResponse {\n /** List of available MCP tools */\n tools: MCPTool[];\n /** Total number of tools */\n count: number;\n /** Number of tools enabled by merchant */\n enabledCount: number;\n}\n\n// =============================================================================\n// Features (Merchant's Own)\n// =============================================================================\n\nexport interface Feature {\n /** Feature ID */\n id: string;\n /** URL-safe slug */\n slug: string;\n /** Human-readable name */\n displayName: string;\n /** Description */\n description: string | null;\n /** Price per call in USD */\n priceUsd: number;\n /** Icon identifier */\n icon: string | null;\n /** Webhook URL for notifications */\n webhookUrl: string | null;\n /** Target URL for proxy features */\n targetUrl: string | null;\n /** Whether the feature is active */\n isActive: boolean;\n /** Whether this is an MCP tool */\n isMcpTool: boolean;\n /** Creation timestamp */\n createdAt: string;\n /** Last update timestamp */\n updatedAt: string;\n}\n\nexport interface FeaturesResponse {\n /** List of merchant's features */\n features: Feature[];\n /** Total count */\n count: number;\n}\n\nexport interface CreateFeatureParams {\n /** URL-safe slug (letters, numbers, hyphens, underscores) */\n slug: string;\n /** Human-readable name */\n displayName: string;\n /** Price per call in USD */\n priceUsd: number;\n /** Description */\n description?: string;\n /** Icon identifier */\n icon?: string;\n /** Webhook URL for notifications */\n webhookUrl?: string;\n /** Target URL for proxy features */\n targetUrl?: string;\n /** Whether the feature is active (default: true) */\n isActive?: boolean;\n /** Whether this is an MCP tool */\n isMcpTool?: boolean;\n /** MCP tool name */\n mcpToolName?: string;\n /** JSON Schema for input validation */\n inputSchema?: Record<string, unknown>;\n /** JSON Schema for output validation */\n outputSchema?: Record<string, unknown>;\n /** Execution timeout in milliseconds */\n executionTimeoutMs?: number;\n /** Rate limit (requests per minute) */\n rateLimitRpm?: number;\n /** Primary intent description */\n primaryIntent?: string;\n /** Agent workflow stage */\n agentStage?: string;\n /** What the feature is best for */\n bestFor?: string[];\n /** What the feature is not ideal for */\n notIdealFor?: string[];\n /** Latency class */\n latencyClass?: 'low' | 'medium' | 'high';\n}\n\nexport interface CreateFeatureResponse {\n success: boolean;\n feature: Feature;\n}\n\nexport interface SyncFeaturesParams {\n /** Features to sync (upsert) */\n features: CreateFeatureParams[];\n /** If true, deactivate features not in the list */\n deleteUnlisted?: boolean;\n}\n\nexport interface SyncResult {\n success: boolean;\n results: {\n /** Slugs of newly created features */\n created: string[];\n /** Slugs of updated features */\n updated: string[];\n /** Slugs of deactivated features */\n deactivated: string[];\n };\n}\n\n// =============================================================================\n// Errors\n// =============================================================================\n\n/**\n * Error thrown when a MerchantClient API request fails.\n */\nexport class MerchantAPIError extends Error {\n constructor(\n message: string,\n /** HTTP status code */\n public status: number,\n /** Seconds to wait before retrying (for rate limits) */\n public retryAfterSeconds?: number\n ) {\n super(message);\n this.name = 'MerchantAPIError';\n }\n}\n\n","/**\n * MixrPay Merchant SDK - Platform Client\n * \n * Programmatic management of platform features including\n * LLM models, MCP tools, markup, and merchant features.\n * \n * @example\n * ```typescript\n * import { MerchantClient } from '@mixrpay/merchant-sdk';\n * \n * const client = new MerchantClient({ \n * secretKey: process.env.MIXRPAY_SECRET_KEY! \n * });\n * \n * // Set 15% markup on platform features\n * await client.setMarkup({ percent: 15 });\n * \n * // Enable LLM models\n * await client.enableLLMModel('gpt-4o-mini');\n * await client.enableLLMModel('claude-3-5-haiku-latest');\n * \n * // Enable MCP tools\n * await client.enableMCPTool('exa-search');\n * ```\n */\n\nimport {\n MerchantClientOptions,\n MarkupInfo,\n SetMarkupParams,\n SetMarkupResponse,\n LLMModelsResponse,\n MCPToolsResponse,\n ToggleResult,\n Feature,\n FeaturesResponse,\n CreateFeatureParams,\n CreateFeatureResponse,\n SyncFeaturesParams,\n SyncResult,\n MerchantAPIError,\n} from './platform-types';\n\nexport class MerchantClient {\n private secretKey: string;\n private baseUrl: string;\n\n /**\n * Create a new MerchantClient instance.\n * \n * @param options - Configuration options\n * @throws Error if secretKey is missing or invalid\n * \n * @example\n * ```typescript\n * const client = new MerchantClient({\n * secretKey: process.env.MIXRPAY_SECRET_KEY!,\n * baseUrl: 'https://www.mixrpay.com', // optional\n * });\n * ```\n */\n constructor(options: MerchantClientOptions) {\n if (!options.secretKey) {\n throw new Error('secretKey is required');\n }\n if (!options.secretKey.startsWith('sk_')) {\n throw new Error('secretKey must start with sk_');\n }\n this.secretKey = options.secretKey;\n this.baseUrl = options.baseUrl \n || process.env.MIXRPAY_BASE_URL \n || 'https://www.mixrpay.com';\n }\n\n // ==========================================================================\n // Internal Request Helper\n // ==========================================================================\n\n private async request<T>(\n method: string,\n path: string,\n body?: unknown\n ): Promise<T> {\n const res = await fetch(`${this.baseUrl}${path}`, {\n method,\n headers: {\n 'Authorization': `Bearer ${this.secretKey}`,\n 'Content-Type': 'application/json',\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n const data = await res.json();\n\n if (!res.ok) {\n throw new MerchantAPIError(\n data.error || 'Request failed',\n res.status,\n data.retry_after_seconds\n );\n }\n\n return data as T;\n }\n\n // ==========================================================================\n // Markup Management\n // ==========================================================================\n\n /**\n * Get current markup settings.\n * \n * @returns Current markup configuration\n * \n * @example\n * ```typescript\n * const markup = await client.getMarkup();\n * console.log(`Current markup: ${markup.markupPercent}%`);\n * ```\n */\n async getMarkup(): Promise<MarkupInfo> {\n return this.request<MarkupInfo>('GET', '/api/seller/platform-markup');\n }\n\n /**\n * Set markup percentage for platform features.\n * \n * @param params - Markup settings\n * @returns Updated markup configuration\n * \n * @example\n * ```typescript\n * // Set 15% markup (minimum is 10%)\n * const result = await client.setMarkup({ percent: 15 });\n * console.log(`New price multiplier: ${result.markupMultiplier}`);\n * ```\n */\n async setMarkup(params: SetMarkupParams): Promise<SetMarkupResponse> {\n return this.request<SetMarkupResponse>('PUT', '/api/seller/platform-markup', {\n markupPercent: params.percent,\n });\n }\n\n // ==========================================================================\n // LLM Models\n // ==========================================================================\n\n /**\n * List all available LLM models with enablement status.\n * \n * @returns List of LLM models\n * \n * @example\n * ```typescript\n * const { models, enabledCount } = await client.listLLMModels();\n * console.log(`${enabledCount} of ${models.length} models enabled`);\n * \n * // Get only enabled models\n * const enabled = models.filter(m => m.enabled);\n * ```\n */\n async listLLMModels(): Promise<LLMModelsResponse> {\n return this.request<LLMModelsResponse>('GET', '/api/seller/llm-gateway/models');\n }\n\n /**\n * Enable an LLM model.\n * \n * @param modelId - Model identifier (e.g., \"gpt-4o-mini\")\n * @returns Toggle result\n * \n * @example\n * ```typescript\n * await client.enableLLMModel('gpt-4o-mini');\n * await client.enableLLMModel('claude-3-5-haiku-latest');\n * ```\n */\n async enableLLMModel(modelId: string): Promise<ToggleResult> {\n return this.request<ToggleResult>('POST', '/api/seller/llm-gateway/toggle', {\n modelId,\n enabled: true,\n });\n }\n\n /**\n * Disable an LLM model.\n * \n * @param modelId - Model identifier (e.g., \"gpt-4o-mini\")\n * @returns Toggle result\n * \n * @example\n * ```typescript\n * await client.disableLLMModel('gpt-4o');\n * ```\n */\n async disableLLMModel(modelId: string): Promise<ToggleResult> {\n return this.request<ToggleResult>('POST', '/api/seller/llm-gateway/toggle', {\n modelId,\n enabled: false,\n });\n }\n\n // ==========================================================================\n // MCP Tools\n // ==========================================================================\n\n /**\n * List all available MCP tools with enablement status.\n * \n * @returns List of MCP tools\n * \n * @example\n * ```typescript\n * const { tools, enabledCount } = await client.listMCPTools();\n * console.log(`${enabledCount} of ${tools.length} tools enabled`);\n * \n * // Group by agent stage\n * const byStage = tools.reduce((acc, t) => {\n * const stage = t.agentStage || 'other';\n * (acc[stage] = acc[stage] || []).push(t);\n * return acc;\n * }, {});\n * ```\n */\n async listMCPTools(): Promise<MCPToolsResponse> {\n return this.request<MCPToolsResponse>('GET', '/api/seller/mcp-tools');\n }\n\n /**\n * Enable an MCP tool.\n * \n * @param toolSlug - Tool slug (e.g., \"firecrawl-scrape\")\n * @returns Toggle result\n * \n * @example\n * ```typescript\n * await client.enableMCPTool('exa-search');\n * await client.enableMCPTool('tavily-search');\n * ```\n */\n async enableMCPTool(toolSlug: string): Promise<ToggleResult> {\n return this.request<ToggleResult>('POST', '/api/seller/mcp-tools/toggle', {\n toolSlug,\n enable: true,\n });\n }\n\n /**\n * Disable an MCP tool.\n * \n * @param toolSlug - Tool slug (e.g., \"firecrawl-scrape\")\n * @returns Toggle result\n * \n * @example\n * ```typescript\n * await client.disableMCPTool('firecrawl-scrape');\n * ```\n */\n async disableMCPTool(toolSlug: string): Promise<ToggleResult> {\n return this.request<ToggleResult>('POST', '/api/seller/mcp-tools/toggle', {\n toolSlug,\n enable: false,\n });\n }\n\n // ==========================================================================\n // Features (Merchant's Own)\n // ==========================================================================\n\n /**\n * List all merchant features.\n * \n * @returns List of features\n * \n * @example\n * ```typescript\n * const { features, count } = await client.listFeatures();\n * console.log(`You have ${count} features`);\n * ```\n */\n async listFeatures(): Promise<FeaturesResponse> {\n return this.request<FeaturesResponse>('GET', '/api/seller/features');\n }\n\n /**\n * Create a new feature.\n * \n * @param params - Feature configuration\n * @returns Created feature\n * \n * @example\n * ```typescript\n * const { feature } = await client.createFeature({\n * slug: 'premium-search',\n * displayName: 'Premium Search',\n * priceUsd: 0.10,\n * description: 'Advanced search with AI ranking',\n * });\n * console.log(`Created feature: ${feature.id}`);\n * ```\n */\n async createFeature(params: CreateFeatureParams): Promise<CreateFeatureResponse> {\n return this.request<CreateFeatureResponse>('POST', '/api/seller/features', params);\n }\n\n /**\n * Sync multiple features (upsert).\n * \n * Creates new features and updates existing ones based on slug.\n * Optionally deactivates features not in the list.\n * \n * @param params - Sync configuration\n * @returns Sync results\n * \n * @example\n * ```typescript\n * const result = await client.syncFeatures({\n * features: [\n * { slug: 'search', displayName: 'Search', priceUsd: 0.05 },\n * { slug: 'analyze', displayName: 'Analyze', priceUsd: 0.10 },\n * ],\n * deleteUnlisted: false, // don't deactivate other features\n * });\n * \n * console.log(`Created: ${result.results.created.join(', ')}`);\n * console.log(`Updated: ${result.results.updated.join(', ')}`);\n * ```\n */\n async syncFeatures(params: SyncFeaturesParams): Promise<SyncResult> {\n return this.request<SyncResult>('POST', '/api/seller/features', {\n sync: true,\n features: params.features,\n deleteUnlisted: params.deleteUnlisted,\n });\n }\n}\n\n"],"mappings":"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","names":["crypto"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/charges.ts","../src/utils.ts","../src/platform-types.ts","../src/platform.ts"],"sourcesContent":["/**\n * MixrPay Merchant SDK\n * \n * Accept payments from AI agents and web apps with one middleware.\n * \n * @example Express\n * ```typescript\n * import { mixrpay } from '@mixrpay/merchant-sdk/express';\n * \n * app.post('/api/query', mixrpay({ priceUsd: 0.05 }), (req, res) => {\n * console.log(`Paid by ${req.mixrPayment?.payer}`);\n * res.json({ result: 'success' });\n * });\n * ```\n * \n * @example Next.js\n * ```typescript\n * import { withMixrPay } from '@mixrpay/merchant-sdk/nextjs';\n * \n * export const POST = withMixrPay({ priceUsd: 0.05 }, async (req, payment) => {\n * return NextResponse.json({ result: 'success' });\n * });\n * ```\n * \n * @packageDocumentation\n */\n\n// Session webhook verification\nexport { verifySessionWebhook } from './charges';\n\n// Utility functions and constants\nexport {\n getWidgetUrl,\n WIDGET_SCRIPT_URL,\n MIXRPAY_API_URL,\n usdToMinor,\n minorToUsd,\n validateEnv,\n logEnvValidation,\n} from './utils';\n\nexport type { EnvValidationResult } from './utils';\n\n// Types for TypeScript users\nexport type {\n MixrPayOptions,\n MixrPayPaymentResult,\n PaymentMethod,\n PriceContext,\n} from './types';\n\nexport type {\n SessionGrant,\n} from './charges';\n\n// Widget element types (for TypeScript JSX support)\nexport type {} from './widget-elements';\n\n// Platform client for programmatic configuration\nexport { MerchantClient } from './platform';\n\n// Platform types\nexport type {\n MerchantClientOptions,\n MarkupInfo,\n SetMarkupParams,\n SetMarkupResponse,\n LLMModel,\n LLMModelsResponse,\n MCPTool,\n MCPToolsResponse,\n ToggleResult,\n Feature,\n FeaturesResponse,\n CreateFeatureParams,\n CreateFeatureResponse,\n SyncFeaturesParams,\n SyncResult,\n} from './platform-types';\n\nexport { MerchantAPIError } from './platform-types';\n","/**\n * MixrPay Charges Module\n * \n * Create and manage charges using session signers.\n * Session signers allow you to charge user wallets without\n * requiring approval for each transaction.\n */\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface CreateChargeParams {\n /** Session key ID granted by the user */\n sessionId: string;\n /** Amount to charge in USD (e.g., 0.05 for 5 cents) */\n amountUsd: number;\n /** Unique reference for idempotency (e.g., \"order_123\") */\n reference: string;\n /** Optional metadata */\n metadata?: Record<string, unknown>;\n}\n\nexport interface Charge {\n /** Unique charge ID */\n id: string;\n /** Current status (from database) */\n status: 'pending' | 'submitted' | 'confirmed' | 'failed';\n /** Real-time status (may differ from DB if not yet synced) */\n liveStatus?: 'pending' | 'submitted' | 'confirmed' | 'failed';\n /** Raw on-chain status */\n onChainStatus?: 'pending' | 'confirmed' | 'failed' | 'not_found' | null;\n /** Amount in USD */\n amountUsd: number;\n /** Formatted USDC amount */\n amountUsdc: string;\n /** Transaction hash (if submitted) */\n txHash?: string;\n /** Block explorer URL */\n explorerUrl?: string;\n /** From wallet address */\n fromAddress: string;\n /** To wallet address */\n toAddress: string;\n /** Your reference */\n reference: string;\n /** When the charge was created */\n createdAt: string;\n /** When the charge was confirmed */\n confirmedAt?: string;\n /** Session name */\n sessionName?: string;\n /** User wallet address */\n userWallet?: string;\n /** Error message if failed */\n error?: string;\n /** True if DB status differs from on-chain - call sync() to update */\n needsSync?: boolean;\n}\n\nexport interface CreateChargeResult {\n success: boolean;\n charge?: Charge;\n /** True if this is a replay of an existing charge */\n idempotentReplay?: boolean;\n error?: string;\n details?: string;\n}\n\nexport interface SessionGrant {\n /** Session key ID */\n sessionId: string;\n /** User's wallet address */\n userWallet: string;\n /** Your merchant wallet address */\n merchantWallet: string;\n /** Spending limits */\n limits: {\n maxTotalUsd?: number;\n maxPerTxUsd?: number;\n expiresAt: string;\n };\n /** When the session was granted */\n grantedAt: string;\n}\n\n// Internal types for API responses\ninterface CreateChargeApiResponse {\n success: boolean;\n charge_id?: string;\n status?: string;\n amount_usd?: number;\n amount_usdc?: string;\n tx_hash?: string;\n explorer_url?: string;\n idempotent_replay?: boolean;\n error?: string;\n details?: string;\n}\n\ninterface ChargeApiResponse {\n id: string;\n status: string;\n /** Real-time status (may differ from DB status if not yet synced) */\n live_status?: string;\n /** Raw on-chain status */\n on_chain_status?: 'pending' | 'confirmed' | 'failed' | 'not_found' | null;\n amount_usd: number;\n amount_usdc: string;\n tx_hash?: string;\n explorer_url?: string;\n from_address: string;\n to_address: string;\n reference: string;\n created_at: string;\n confirmed_at?: string;\n session_name?: string;\n user_wallet?: string;\n /** True if DB status differs from on-chain status */\n needs_sync?: boolean;\n}\n\ninterface SyncChargeApiResponse {\n success: boolean;\n charge?: {\n id: string;\n status: string;\n };\n error?: string;\n}\n\nexport interface ChargesClientOptions {\n /** Your API key */\n apiKey: string;\n /** MixrPay API base URL */\n baseUrl?: string;\n}\n\n// =============================================================================\n// Client\n// =============================================================================\n\nexport class ChargesClient {\n private apiKey: string;\n private baseUrl: string;\n\n constructor(options: ChargesClientOptions) {\n this.apiKey = options.apiKey;\n this.baseUrl = options.baseUrl || process.env.MIXRPAY_BASE_URL || 'https://www.mixrpay.com';\n }\n\n /**\n * Create a new charge.\n * \n * @example\n * ```typescript\n * const result = await charges.create({\n * sessionId: 'sk_xxx',\n * amountUsd: 0.05,\n * reference: 'image_gen_123',\n * metadata: { feature: 'image_generation' }\n * });\n * \n * if (result.success) {\n * console.log(`Charged ${result.charge.amountUsdc}`);\n * console.log(`TX: ${result.charge.explorerUrl}`);\n * }\n * ```\n */\n async create(params: CreateChargeParams): Promise<CreateChargeResult> {\n const response = await fetch(`${this.baseUrl}/api/v1/charges`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({\n session_id: params.sessionId,\n amount_usd: params.amountUsd,\n reference: params.reference,\n metadata: params.metadata,\n }),\n });\n\n const data = await response.json() as CreateChargeApiResponse;\n\n if (!response.ok) {\n return {\n success: false,\n error: data.error,\n details: data.details,\n };\n }\n\n return {\n success: data.success,\n charge: data.charge_id ? {\n id: data.charge_id,\n status: data.status as Charge['status'],\n amountUsd: data.amount_usd ?? 0,\n amountUsdc: data.amount_usdc ?? '0',\n txHash: data.tx_hash,\n explorerUrl: data.explorer_url,\n fromAddress: '',\n toAddress: '',\n reference: params.reference,\n createdAt: new Date().toISOString(),\n } : undefined,\n idempotentReplay: data.idempotent_replay,\n error: data.error,\n };\n }\n\n /**\n * Get a charge by ID.\n * \n * Note: The returned status is from the database. If `needsSync` is true,\n * the on-chain status differs and you should call `sync()` to update.\n * \n * @example\n * ```typescript\n * const charge = await charges.get('chg_xxx');\n * console.log(charge.status); // 'submitted'\n * console.log(charge.liveStatus); // 'confirmed' (real-time)\n * \n * if (charge.needsSync) {\n * await charges.sync(charge.id);\n * }\n * ```\n */\n async get(chargeId: string): Promise<Charge | null> {\n const response = await fetch(`${this.baseUrl}/api/v1/charges?id=${chargeId}`, {\n headers: {\n 'Authorization': `Bearer ${this.apiKey}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 404) {\n return null;\n }\n throw new Error(`Failed to get charge: ${response.statusText}`);\n }\n\n const data = await response.json() as ChargeApiResponse;\n\n return this.mapChargeResponse(data);\n }\n\n /**\n * Get a charge by transaction hash.\n */\n async getByTxHash(txHash: string): Promise<Charge | null> {\n const response = await fetch(`${this.baseUrl}/api/v1/charges?tx_hash=${txHash}`, {\n headers: {\n 'Authorization': `Bearer ${this.apiKey}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 404) {\n return null;\n }\n throw new Error(`Failed to get charge: ${response.statusText}`);\n }\n\n const data = await response.json() as ChargeApiResponse;\n\n return this.mapChargeResponse(data);\n }\n\n /**\n * Sync a charge's status from the blockchain.\n * \n * Call this when `get()` returns a charge with `needsSync: true`.\n * This will update the database with the on-chain status.\n * \n * @example\n * ```typescript\n * const charge = await charges.get('chg_xxx');\n * if (charge?.needsSync) {\n * const synced = await charges.sync(charge.id);\n * console.log(`Status updated to: ${synced.status}`);\n * }\n * ```\n */\n async sync(chargeId: string): Promise<{ id: string; status: string }> {\n const response = await fetch(`${this.baseUrl}/api/v1/charges/sync`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({ charge_id: chargeId }),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(`Failed to sync charge: ${(error as { error?: string }).error || response.statusText}`);\n }\n\n const data = await response.json() as SyncChargeApiResponse;\n\n if (!data.success || !data.charge) {\n throw new Error(`Sync failed: ${data.error || 'Unknown error'}`);\n }\n\n return data.charge;\n }\n\n /**\n * Poll for charge confirmation.\n * \n * Convenience method that polls until the charge is confirmed or failed,\n * automatically syncing when needed.\n * \n * @example\n * ```typescript\n * const charge = await charges.waitForConfirmation('chg_xxx', {\n * timeoutMs: 60000,\n * pollIntervalMs: 2000,\n * });\n * console.log(`Final status: ${charge.status}`);\n * ```\n */\n async waitForConfirmation(\n chargeId: string,\n options: { timeoutMs?: number; pollIntervalMs?: number } = {}\n ): Promise<Charge> {\n const { timeoutMs = 60000, pollIntervalMs = 2000 } = options;\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeoutMs) {\n const charge = await this.get(chargeId);\n \n if (!charge) {\n throw new Error('Charge not found');\n }\n\n // If needs sync, sync it first\n if (charge.needsSync) {\n await this.sync(chargeId);\n // Re-fetch to get updated status\n const synced = await this.get(chargeId);\n if (synced && (synced.status === 'confirmed' || synced.status === 'failed')) {\n return synced;\n }\n }\n\n // Check if we've reached a terminal state\n if (charge.status === 'confirmed' || charge.status === 'failed') {\n return charge;\n }\n\n // Also check live status for early return\n if (charge.liveStatus === 'confirmed' || charge.liveStatus === 'failed') {\n // Sync and return\n await this.sync(chargeId);\n const final = await this.get(chargeId);\n if (final) return final;\n }\n\n // Wait before next poll\n await new Promise(resolve => setTimeout(resolve, pollIntervalMs));\n }\n\n throw new Error(`Timeout waiting for charge confirmation after ${timeoutMs}ms`);\n }\n\n private mapChargeResponse(data: ChargeApiResponse): Charge {\n return {\n id: data.id,\n status: data.status as Charge['status'],\n liveStatus: data.live_status as Charge['status'] | undefined,\n onChainStatus: data.on_chain_status,\n amountUsd: data.amount_usd,\n amountUsdc: data.amount_usdc,\n txHash: data.tx_hash,\n explorerUrl: data.explorer_url,\n fromAddress: data.from_address,\n toAddress: data.to_address,\n reference: data.reference,\n createdAt: data.created_at,\n confirmedAt: data.confirmed_at,\n sessionName: data.session_name,\n userWallet: data.user_wallet,\n needsSync: data.needs_sync,\n };\n }\n}\n\n// =============================================================================\n// Webhook Verification\n// =============================================================================\n\nimport crypto from 'crypto';\n\n/**\n * Verify a session.granted webhook signature.\n * \n * @example\n * ```typescript\n * const payload = req.body;\n * const signature = req.headers['x-mixrpay-signature'];\n * \n * if (verifySessionWebhook(JSON.stringify(payload), signature, webhookSecret)) {\n * const grant = parseSessionGrant(payload);\n * console.log(`User ${grant.userWallet} granted access`);\n * }\n * ```\n */\nexport function verifySessionWebhook(\n payload: string,\n signature: string,\n secret: string\n): boolean {\n const expectedSignature = crypto\n .createHmac('sha256', secret)\n .update(payload)\n .digest('hex');\n \n return crypto.timingSafeEqual(\n Buffer.from(signature),\n Buffer.from(expectedSignature)\n );\n}\n\n/**\n * Parse a session.granted webhook payload.\n */\nexport function parseSessionGrant(payload: {\n event: string;\n session_id: string;\n user_wallet: string;\n merchant_wallet: string;\n limits: {\n max_total_usd?: number;\n max_per_tx_usd?: number;\n expires_at: string;\n };\n granted_at: string;\n}): SessionGrant {\n if (payload.event !== 'session.granted') {\n throw new Error(`Unexpected event type: ${payload.event}`);\n }\n\n return {\n sessionId: payload.session_id,\n userWallet: payload.user_wallet,\n merchantWallet: payload.merchant_wallet,\n limits: {\n maxTotalUsd: payload.limits.max_total_usd,\n maxPerTxUsd: payload.limits.max_per_tx_usd,\n expiresAt: payload.limits.expires_at,\n },\n grantedAt: payload.granted_at,\n };\n}\n\n","/**\n * MixrPay Merchant SDK - Utilities\n */\n\nimport type { EIP712Domain } from './types';\n\n// =============================================================================\n// Widget URLs\n// =============================================================================\n\n/**\n * Get the MixrPay widget script URL.\n * \n * @example\n * ```html\n * <script src=\"${getWidgetUrl()}\"\n * data-seller-public-key=\"pk_live_...\"\n * data-user-token=\"...\"></script>\n * ```\n */\nexport function getWidgetUrl(): string {\n return 'https://www.mixrpay.com/widget.js';\n}\n\n/**\n * MixrPay API base URL\n */\nexport const MIXRPAY_API_URL = 'https://www.mixrpay.com';\n\n/**\n * Widget script URL (for convenience)\n */\nexport const WIDGET_SCRIPT_URL = 'https://www.mixrpay.com/widget.js';\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// Environment Validation\n// =============================================================================\n\nexport interface EnvValidationResult {\n valid: boolean;\n errors: string[];\n warnings: string[];\n config: {\n publicKey: string | null;\n secretKey: string | null;\n hmacSecret: string | null;\n webhookSecret: string | null;\n merchantAddress: string | null;\n };\n}\n\n/**\n * Validate MixrPay environment variables and provide helpful feedback.\n * \n * @example\n * ```typescript\n * import { validateEnv } from '@mixrpay/merchant-sdk';\n * \n * const result = validateEnv();\n * if (!result.valid) {\n * console.error('MixrPay configuration errors:', result.errors);\n * }\n * ```\n */\nexport function validateEnv(env?: Record<string, string | undefined>): EnvValidationResult {\n const e = env || (typeof process !== 'undefined' ? process.env : {});\n \n const result: EnvValidationResult = {\n valid: true,\n errors: [],\n warnings: [],\n config: {\n publicKey: (e.MIXRPAY_PUBLIC_KEY as string) || null,\n secretKey: (e.MIXRPAY_SECRET_KEY as string) || null,\n hmacSecret: (e.MIXRPAY_HMAC_SECRET as string) || null,\n webhookSecret: (e.MIXRPAY_WEBHOOK_SECRET as string) || null,\n merchantAddress: (e.MIXRPAY_MERCHANT_ADDRESS as string) || null,\n },\n };\n \n // Check public key\n if (!result.config.publicKey) {\n result.errors.push('MIXRPAY_PUBLIC_KEY is required. Get it from https://www.mixrpay.com/seller/developers');\n result.valid = false;\n } else if (!result.config.publicKey.startsWith('pk_')) {\n result.errors.push(`MIXRPAY_PUBLIC_KEY must start with 'pk_'. Got: ${result.config.publicKey.slice(0, 10)}...`);\n result.valid = false;\n }\n \n // Check secret key\n if (!result.config.secretKey) {\n result.errors.push('MIXRPAY_SECRET_KEY is required. Get it from https://www.mixrpay.com/seller/developers');\n result.valid = false;\n } else if (!result.config.secretKey.startsWith('sk_')) {\n result.errors.push(`MIXRPAY_SECRET_KEY must start with 'sk_'. Got: ${result.config.secretKey.slice(0, 10)}...`);\n result.valid = false;\n }\n \n // Check webhook secret (required)\n if (!result.config.webhookSecret) {\n result.errors.push('MIXRPAY_WEBHOOK_SECRET is required. Get it from https://www.mixrpay.com/seller/developers');\n result.valid = false;\n }\n \n // Check HMAC secret (warning only - only needed for widget with user linking)\n if (!result.config.hmacSecret) {\n result.warnings.push('MIXRPAY_HMAC_SECRET not set. Only required if using Widget with user linking (data-user-token).');\n }\n \n // Check merchant address (warning only - needed for x402)\n if (!result.config.merchantAddress) {\n result.warnings.push('MIXRPAY_MERCHANT_ADDRESS not set. Required for x402 protocol support.');\n } else if (!isValidAddress(result.config.merchantAddress)) {\n result.errors.push(`MIXRPAY_MERCHANT_ADDRESS is not a valid Ethereum address: ${result.config.merchantAddress}`);\n result.valid = false;\n }\n \n return result;\n}\n\n/**\n * Log environment validation results to console with formatting.\n */\nexport function logEnvValidation(result?: EnvValidationResult): void {\n const r = result || validateEnv();\n \n console.log('\\nšŸ”§ MixrPay Environment Check\\n');\n \n if (r.valid) {\n console.log('āœ… Configuration valid\\n');\n } else {\n console.log('āŒ Configuration errors found\\n');\n }\n \n if (r.errors.length > 0) {\n console.log('Errors:');\n r.errors.forEach(e => console.log(` āŒ ${e}`));\n console.log('');\n }\n \n if (r.warnings.length > 0) {\n console.log('Warnings:');\n r.warnings.forEach(w => console.log(` āš ļø ${w}`));\n console.log('');\n }\n \n console.log('Required credentials:');\n console.log(` Public Key: ${r.config.publicKey ? 'āœ“ Set' : 'āœ— Missing'}`);\n console.log(` Secret Key: ${r.config.secretKey ? 'āœ“ Set' : 'āœ— Missing'}`);\n console.log(` Webhook Secret: ${r.config.webhookSecret ? 'āœ“ Set' : 'āœ— Missing'}`);\n console.log('');\n console.log('Optional credentials:');\n console.log(` HMAC Secret: ${r.config.hmacSecret ? 'āœ“ Set' : 'ā—‹ Not set (widget only)'}`);\n console.log(` Merchant Address: ${r.config.merchantAddress ? 'āœ“ Set' : 'ā—‹ Not set (x402 only)'}`);\n console.log('');\n}\n\n","/**\n * MixrPay Merchant SDK - Platform Types\n * \n * Type definitions for the MerchantClient class that enables\n * programmatic management of platform features.\n */\n\n// =============================================================================\n// Configuration\n// =============================================================================\n\nexport interface MerchantClientOptions {\n /** Your secret API key (sk_live_xxx or sk_test_xxx) */\n secretKey: string;\n /** API base URL (defaults to https://www.mixrpay.com) */\n baseUrl?: string;\n}\n\n// =============================================================================\n// Markup\n// =============================================================================\n\nexport interface MarkupInfo {\n /** Markup in basis points (e.g., 2000 = 20%) */\n markupBps: number;\n /** Markup as percentage (e.g., 20 = 20%) */\n markupPercent: number;\n /** Multiplier to apply to platform prices (e.g., 1.2 for 20% markup) */\n markupMultiplier: number;\n /** Example calculation */\n example?: {\n platformPrice: number;\n yourPrice: number;\n yourProfit: number;\n };\n}\n\nexport interface SetMarkupParams {\n /** Markup percentage (10-200). e.g., 20 = 20% markup. Minimum 10% required. */\n percent: number;\n}\n\nexport interface SetMarkupResponse extends MarkupInfo {\n success: boolean;\n message?: string;\n}\n\n// =============================================================================\n// LLM Models\n// =============================================================================\n\nexport interface LLMModel {\n /** Platform feature ID */\n id: string;\n /** Model identifier (e.g., \"gpt-4o-mini\", \"claude-3-5-haiku-latest\") */\n modelId: string;\n /** Human-readable name */\n displayName: string;\n /** Model description */\n description: string | null;\n /** Provider (e.g., \"openai\", \"anthropic\") */\n provider: string;\n /** Input token price per 1M tokens in USD */\n inputPricePer1M: number;\n /** Output token price per 1M tokens in USD */\n outputPricePer1M: number;\n /** Maximum context window size */\n contextWindow: number | null;\n /** Whether the merchant has enabled this model */\n enabled: boolean;\n}\n\nexport interface LLMModelsResponse {\n /** List of available LLM models */\n models: LLMModel[];\n /** Total number of models */\n count: number;\n /** Number of models enabled by merchant */\n enabledCount: number;\n}\n\nexport interface ToggleResult {\n success: boolean;\n enabled: boolean;\n modelId?: string;\n featureId?: string;\n toolSlug?: string;\n displayName?: string;\n}\n\n// =============================================================================\n// MCP Tools\n// =============================================================================\n\nexport interface MCPTool {\n /** Platform feature ID */\n id: string;\n /** Tool slug (e.g., \"firecrawl-scrape\", \"exa-search\") */\n slug: string;\n /** Human-readable name */\n displayName: string;\n /** Tool description */\n description: string | null;\n /** Tool provider */\n provider: string | null;\n /** Price per call in USD */\n priceUsd: number;\n /** Primary use case */\n primaryIntent: string | null;\n /** Agent workflow stage (acquire, parse, transform, reason, act) */\n agentStage: string | null;\n /** What the tool is best for */\n bestFor: string[];\n /** Latency class (low, medium, high) */\n latencyClass: string | null;\n /** Whether the merchant has enabled this tool */\n enabled: boolean;\n}\n\nexport interface MCPToolsResponse {\n /** List of available MCP tools */\n tools: MCPTool[];\n /** Total number of tools */\n count: number;\n /** Number of tools enabled by merchant */\n enabledCount: number;\n}\n\n// =============================================================================\n// Features (Merchant's Own)\n// =============================================================================\n\nexport interface Feature {\n /** Feature ID */\n id: string;\n /** URL-safe slug */\n slug: string;\n /** Human-readable name */\n displayName: string;\n /** Description */\n description: string | null;\n /** Price per call in USD */\n priceUsd: number;\n /** Icon identifier */\n icon: string | null;\n /** Webhook URL for notifications */\n webhookUrl: string | null;\n /** Target URL for proxy features */\n targetUrl: string | null;\n /** Whether the feature is active */\n isActive: boolean;\n /** Whether this is an MCP tool */\n isMcpTool: boolean;\n /** Creation timestamp */\n createdAt: string;\n /** Last update timestamp */\n updatedAt: string;\n}\n\nexport interface FeaturesResponse {\n /** List of merchant's features */\n features: Feature[];\n /** Total count */\n count: number;\n}\n\nexport interface CreateFeatureParams {\n /** URL-safe slug (letters, numbers, hyphens, underscores) */\n slug: string;\n /** Human-readable name */\n displayName: string;\n /** Price per call in USD */\n priceUsd: number;\n /** Description */\n description?: string;\n /** Icon identifier */\n icon?: string;\n /** Webhook URL for notifications */\n webhookUrl?: string;\n /** Target URL for proxy features */\n targetUrl?: string;\n /** Whether the feature is active (default: true) */\n isActive?: boolean;\n /** Whether this is an MCP tool */\n isMcpTool?: boolean;\n /** MCP tool name */\n mcpToolName?: string;\n /** JSON Schema for input validation */\n inputSchema?: Record<string, unknown>;\n /** JSON Schema for output validation */\n outputSchema?: Record<string, unknown>;\n /** Execution timeout in milliseconds */\n executionTimeoutMs?: number;\n /** Rate limit (requests per minute) */\n rateLimitRpm?: number;\n /** Primary intent description */\n primaryIntent?: string;\n /** Agent workflow stage */\n agentStage?: string;\n /** What the feature is best for */\n bestFor?: string[];\n /** What the feature is not ideal for */\n notIdealFor?: string[];\n /** Latency class */\n latencyClass?: 'low' | 'medium' | 'high';\n}\n\nexport interface CreateFeatureResponse {\n success: boolean;\n feature: Feature;\n}\n\nexport interface SyncFeaturesParams {\n /** Features to sync (upsert) */\n features: CreateFeatureParams[];\n /** If true, deactivate features not in the list */\n deleteUnlisted?: boolean;\n}\n\nexport interface SyncResult {\n success: boolean;\n results: {\n /** Slugs of newly created features */\n created: string[];\n /** Slugs of updated features */\n updated: string[];\n /** Slugs of deactivated features */\n deactivated: string[];\n };\n}\n\n// =============================================================================\n// Errors\n// =============================================================================\n\n/**\n * Error thrown when a MerchantClient API request fails.\n */\nexport class MerchantAPIError extends Error {\n constructor(\n message: string,\n /** HTTP status code */\n public status: number,\n /** Seconds to wait before retrying (for rate limits) */\n public retryAfterSeconds?: number\n ) {\n super(message);\n this.name = 'MerchantAPIError';\n }\n}\n\n","/**\n * MixrPay Merchant SDK - Platform Client\n * \n * Programmatic management of platform features including\n * LLM models, MCP tools, markup, and merchant features.\n * \n * @example\n * ```typescript\n * import { MerchantClient } from '@mixrpay/merchant-sdk';\n * \n * const client = new MerchantClient({ \n * secretKey: process.env.MIXRPAY_SECRET_KEY! \n * });\n * \n * // Set 15% markup on platform features\n * await client.setMarkup({ percent: 15 });\n * \n * // Enable LLM models\n * await client.enableLLMModel('gpt-4o-mini');\n * await client.enableLLMModel('claude-3-5-haiku-latest');\n * \n * // Enable MCP tools\n * await client.enableMCPTool('exa-search');\n * ```\n */\n\nimport {\n MerchantClientOptions,\n MarkupInfo,\n SetMarkupParams,\n SetMarkupResponse,\n LLMModelsResponse,\n MCPToolsResponse,\n ToggleResult,\n Feature,\n FeaturesResponse,\n CreateFeatureParams,\n CreateFeatureResponse,\n SyncFeaturesParams,\n SyncResult,\n MerchantAPIError,\n} from './platform-types';\n\nexport class MerchantClient {\n private secretKey: string;\n private baseUrl: string;\n\n /**\n * Create a new MerchantClient instance.\n * \n * @param options - Configuration options\n * @throws Error if secretKey is missing or invalid\n * \n * @example\n * ```typescript\n * const client = new MerchantClient({\n * secretKey: process.env.MIXRPAY_SECRET_KEY!,\n * baseUrl: 'https://www.mixrpay.com', // optional\n * });\n * ```\n */\n constructor(options: MerchantClientOptions) {\n if (!options.secretKey) {\n throw new Error('secretKey is required');\n }\n if (!options.secretKey.startsWith('sk_')) {\n throw new Error('secretKey must start with sk_');\n }\n this.secretKey = options.secretKey;\n this.baseUrl = options.baseUrl \n || process.env.MIXRPAY_BASE_URL \n || 'https://www.mixrpay.com';\n }\n\n // ==========================================================================\n // Internal Request Helper\n // ==========================================================================\n\n private async request<T>(\n method: string,\n path: string,\n body?: unknown\n ): Promise<T> {\n const res = await fetch(`${this.baseUrl}${path}`, {\n method,\n headers: {\n 'Authorization': `Bearer ${this.secretKey}`,\n 'Content-Type': 'application/json',\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n const data = await res.json();\n\n if (!res.ok) {\n throw new MerchantAPIError(\n data.error || 'Request failed',\n res.status,\n data.retry_after_seconds\n );\n }\n\n return data as T;\n }\n\n // ==========================================================================\n // Markup Management\n // ==========================================================================\n\n /**\n * Get current markup settings.\n * \n * @returns Current markup configuration\n * \n * @example\n * ```typescript\n * const markup = await client.getMarkup();\n * console.log(`Current markup: ${markup.markupPercent}%`);\n * ```\n */\n async getMarkup(): Promise<MarkupInfo> {\n return this.request<MarkupInfo>('GET', '/api/seller/platform-markup');\n }\n\n /**\n * Set markup percentage for platform features.\n * \n * @param params - Markup settings\n * @returns Updated markup configuration\n * \n * @example\n * ```typescript\n * // Set 15% markup (minimum is 10%)\n * const result = await client.setMarkup({ percent: 15 });\n * console.log(`New price multiplier: ${result.markupMultiplier}`);\n * ```\n */\n async setMarkup(params: SetMarkupParams): Promise<SetMarkupResponse> {\n return this.request<SetMarkupResponse>('PUT', '/api/seller/platform-markup', {\n markupPercent: params.percent,\n });\n }\n\n // ==========================================================================\n // LLM Models\n // ==========================================================================\n\n /**\n * List all available LLM models with enablement status.\n * \n * @returns List of LLM models\n * \n * @example\n * ```typescript\n * const { models, enabledCount } = await client.listLLMModels();\n * console.log(`${enabledCount} of ${models.length} models enabled`);\n * \n * // Get only enabled models\n * const enabled = models.filter(m => m.enabled);\n * ```\n */\n async listLLMModels(): Promise<LLMModelsResponse> {\n return this.request<LLMModelsResponse>('GET', '/api/seller/llm-gateway/models');\n }\n\n /**\n * Enable an LLM model.\n * \n * @param modelId - Model identifier (e.g., \"gpt-4o-mini\")\n * @returns Toggle result\n * \n * @example\n * ```typescript\n * await client.enableLLMModel('gpt-4o-mini');\n * await client.enableLLMModel('claude-3-5-haiku-latest');\n * ```\n */\n async enableLLMModel(modelId: string): Promise<ToggleResult> {\n return this.request<ToggleResult>('POST', '/api/seller/llm-gateway/toggle', {\n modelId,\n enabled: true,\n });\n }\n\n /**\n * Disable an LLM model.\n * \n * @param modelId - Model identifier (e.g., \"gpt-4o-mini\")\n * @returns Toggle result\n * \n * @example\n * ```typescript\n * await client.disableLLMModel('gpt-4o');\n * ```\n */\n async disableLLMModel(modelId: string): Promise<ToggleResult> {\n return this.request<ToggleResult>('POST', '/api/seller/llm-gateway/toggle', {\n modelId,\n enabled: false,\n });\n }\n\n // ==========================================================================\n // MCP Tools\n // ==========================================================================\n\n /**\n * List all available MCP tools with enablement status.\n * \n * @returns List of MCP tools\n * \n * @example\n * ```typescript\n * const { tools, enabledCount } = await client.listMCPTools();\n * console.log(`${enabledCount} of ${tools.length} tools enabled`);\n * \n * // Group by agent stage\n * const byStage = tools.reduce((acc, t) => {\n * const stage = t.agentStage || 'other';\n * (acc[stage] = acc[stage] || []).push(t);\n * return acc;\n * }, {});\n * ```\n */\n async listMCPTools(): Promise<MCPToolsResponse> {\n return this.request<MCPToolsResponse>('GET', '/api/seller/gateway-tools');\n }\n\n /**\n * Enable an MCP tool.\n * \n * @param toolSlug - Tool slug (e.g., \"firecrawl-scrape\")\n * @returns Toggle result\n * \n * @example\n * ```typescript\n * await client.enableMCPTool('exa-search');\n * await client.enableMCPTool('tavily-search');\n * ```\n */\n async enableMCPTool(toolSlug: string): Promise<ToggleResult> {\n return this.request<ToggleResult>('POST', '/api/seller/gateway-tools/toggle', {\n toolSlug,\n enable: true,\n });\n }\n\n /**\n * Disable an MCP tool.\n * \n * @param toolSlug - Tool slug (e.g., \"firecrawl-scrape\")\n * @returns Toggle result\n * \n * @example\n * ```typescript\n * await client.disableMCPTool('firecrawl-scrape');\n * ```\n */\n async disableMCPTool(toolSlug: string): Promise<ToggleResult> {\n return this.request<ToggleResult>('POST', '/api/seller/gateway-tools/toggle', {\n toolSlug,\n enable: false,\n });\n }\n\n // ==========================================================================\n // Features (Merchant's Own)\n // ==========================================================================\n\n /**\n * List all merchant features.\n * \n * @returns List of features\n * \n * @example\n * ```typescript\n * const { features, count } = await client.listFeatures();\n * console.log(`You have ${count} features`);\n * ```\n */\n async listFeatures(): Promise<FeaturesResponse> {\n return this.request<FeaturesResponse>('GET', '/api/seller/features');\n }\n\n /**\n * Create a new feature.\n * \n * @param params - Feature configuration\n * @returns Created feature\n * \n * @example\n * ```typescript\n * const { feature } = await client.createFeature({\n * slug: 'premium-search',\n * displayName: 'Premium Search',\n * priceUsd: 0.10,\n * description: 'Advanced search with AI ranking',\n * });\n * console.log(`Created feature: ${feature.id}`);\n * ```\n */\n async createFeature(params: CreateFeatureParams): Promise<CreateFeatureResponse> {\n return this.request<CreateFeatureResponse>('POST', '/api/seller/features', params);\n }\n\n /**\n * Sync multiple features (upsert).\n * \n * Creates new features and updates existing ones based on slug.\n * Optionally deactivates features not in the list.\n * \n * @param params - Sync configuration\n * @returns Sync results\n * \n * @example\n * ```typescript\n * const result = await client.syncFeatures({\n * features: [\n * { slug: 'search', displayName: 'Search', priceUsd: 0.05 },\n * { slug: 'analyze', displayName: 'Analyze', priceUsd: 0.10 },\n * ],\n * deleteUnlisted: false, // don't deactivate other features\n * });\n * \n * console.log(`Created: ${result.results.created.join(', ')}`);\n * console.log(`Updated: ${result.results.updated.join(', ')}`);\n * ```\n */\n async syncFeatures(params: SyncFeaturesParams): Promise<SyncResult> {\n return this.request<SyncResult>('POST', '/api/seller/features', {\n sync: true,\n features: params.features,\n deleteUnlisted: params.deleteUnlisted,\n });\n }\n}\n\n"],"mappings":"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","names":["crypto"]}
package/dist/index.mjs CHANGED
@@ -265,7 +265,7 @@ var MerchantClient = class {
265
265
  * ```
266
266
  */
267
267
  async listMCPTools() {
268
- return this.request("GET", "/api/seller/mcp-tools");
268
+ return this.request("GET", "/api/seller/gateway-tools");
269
269
  }
270
270
  /**
271
271
  * Enable an MCP tool.
@@ -280,7 +280,7 @@ var MerchantClient = class {
280
280
  * ```
281
281
  */
282
282
  async enableMCPTool(toolSlug) {
283
- return this.request("POST", "/api/seller/mcp-tools/toggle", {
283
+ return this.request("POST", "/api/seller/gateway-tools/toggle", {
284
284
  toolSlug,
285
285
  enable: true
286
286
  });
@@ -297,7 +297,7 @@ var MerchantClient = class {
297
297
  * ```
298
298
  */
299
299
  async disableMCPTool(toolSlug) {
300
- return this.request("POST", "/api/seller/mcp-tools/toggle", {
300
+ return this.request("POST", "/api/seller/gateway-tools/toggle", {
301
301
  toolSlug,
302
302
  enable: false
303
303
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/charges.ts","../src/utils.ts","../src/platform-types.ts","../src/platform.ts"],"sourcesContent":["/**\n * MixrPay Charges Module\n * \n * Create and manage charges using session signers.\n * Session signers allow you to charge user wallets without\n * requiring approval for each transaction.\n */\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface CreateChargeParams {\n /** Session key ID granted by the user */\n sessionId: string;\n /** Amount to charge in USD (e.g., 0.05 for 5 cents) */\n amountUsd: number;\n /** Unique reference for idempotency (e.g., \"order_123\") */\n reference: string;\n /** Optional metadata */\n metadata?: Record<string, unknown>;\n}\n\nexport interface Charge {\n /** Unique charge ID */\n id: string;\n /** Current status (from database) */\n status: 'pending' | 'submitted' | 'confirmed' | 'failed';\n /** Real-time status (may differ from DB if not yet synced) */\n liveStatus?: 'pending' | 'submitted' | 'confirmed' | 'failed';\n /** Raw on-chain status */\n onChainStatus?: 'pending' | 'confirmed' | 'failed' | 'not_found' | null;\n /** Amount in USD */\n amountUsd: number;\n /** Formatted USDC amount */\n amountUsdc: string;\n /** Transaction hash (if submitted) */\n txHash?: string;\n /** Block explorer URL */\n explorerUrl?: string;\n /** From wallet address */\n fromAddress: string;\n /** To wallet address */\n toAddress: string;\n /** Your reference */\n reference: string;\n /** When the charge was created */\n createdAt: string;\n /** When the charge was confirmed */\n confirmedAt?: string;\n /** Session name */\n sessionName?: string;\n /** User wallet address */\n userWallet?: string;\n /** Error message if failed */\n error?: string;\n /** True if DB status differs from on-chain - call sync() to update */\n needsSync?: boolean;\n}\n\nexport interface CreateChargeResult {\n success: boolean;\n charge?: Charge;\n /** True if this is a replay of an existing charge */\n idempotentReplay?: boolean;\n error?: string;\n details?: string;\n}\n\nexport interface SessionGrant {\n /** Session key ID */\n sessionId: string;\n /** User's wallet address */\n userWallet: string;\n /** Your merchant wallet address */\n merchantWallet: string;\n /** Spending limits */\n limits: {\n maxTotalUsd?: number;\n maxPerTxUsd?: number;\n expiresAt: string;\n };\n /** When the session was granted */\n grantedAt: string;\n}\n\n// Internal types for API responses\ninterface CreateChargeApiResponse {\n success: boolean;\n charge_id?: string;\n status?: string;\n amount_usd?: number;\n amount_usdc?: string;\n tx_hash?: string;\n explorer_url?: string;\n idempotent_replay?: boolean;\n error?: string;\n details?: string;\n}\n\ninterface ChargeApiResponse {\n id: string;\n status: string;\n /** Real-time status (may differ from DB status if not yet synced) */\n live_status?: string;\n /** Raw on-chain status */\n on_chain_status?: 'pending' | 'confirmed' | 'failed' | 'not_found' | null;\n amount_usd: number;\n amount_usdc: string;\n tx_hash?: string;\n explorer_url?: string;\n from_address: string;\n to_address: string;\n reference: string;\n created_at: string;\n confirmed_at?: string;\n session_name?: string;\n user_wallet?: string;\n /** True if DB status differs from on-chain status */\n needs_sync?: boolean;\n}\n\ninterface SyncChargeApiResponse {\n success: boolean;\n charge?: {\n id: string;\n status: string;\n };\n error?: string;\n}\n\nexport interface ChargesClientOptions {\n /** Your API key */\n apiKey: string;\n /** MixrPay API base URL */\n baseUrl?: string;\n}\n\n// =============================================================================\n// Client\n// =============================================================================\n\nexport class ChargesClient {\n private apiKey: string;\n private baseUrl: string;\n\n constructor(options: ChargesClientOptions) {\n this.apiKey = options.apiKey;\n this.baseUrl = options.baseUrl || process.env.MIXRPAY_BASE_URL || 'https://www.mixrpay.com';\n }\n\n /**\n * Create a new charge.\n * \n * @example\n * ```typescript\n * const result = await charges.create({\n * sessionId: 'sk_xxx',\n * amountUsd: 0.05,\n * reference: 'image_gen_123',\n * metadata: { feature: 'image_generation' }\n * });\n * \n * if (result.success) {\n * console.log(`Charged ${result.charge.amountUsdc}`);\n * console.log(`TX: ${result.charge.explorerUrl}`);\n * }\n * ```\n */\n async create(params: CreateChargeParams): Promise<CreateChargeResult> {\n const response = await fetch(`${this.baseUrl}/api/v1/charges`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({\n session_id: params.sessionId,\n amount_usd: params.amountUsd,\n reference: params.reference,\n metadata: params.metadata,\n }),\n });\n\n const data = await response.json() as CreateChargeApiResponse;\n\n if (!response.ok) {\n return {\n success: false,\n error: data.error,\n details: data.details,\n };\n }\n\n return {\n success: data.success,\n charge: data.charge_id ? {\n id: data.charge_id,\n status: data.status as Charge['status'],\n amountUsd: data.amount_usd ?? 0,\n amountUsdc: data.amount_usdc ?? '0',\n txHash: data.tx_hash,\n explorerUrl: data.explorer_url,\n fromAddress: '',\n toAddress: '',\n reference: params.reference,\n createdAt: new Date().toISOString(),\n } : undefined,\n idempotentReplay: data.idempotent_replay,\n error: data.error,\n };\n }\n\n /**\n * Get a charge by ID.\n * \n * Note: The returned status is from the database. If `needsSync` is true,\n * the on-chain status differs and you should call `sync()` to update.\n * \n * @example\n * ```typescript\n * const charge = await charges.get('chg_xxx');\n * console.log(charge.status); // 'submitted'\n * console.log(charge.liveStatus); // 'confirmed' (real-time)\n * \n * if (charge.needsSync) {\n * await charges.sync(charge.id);\n * }\n * ```\n */\n async get(chargeId: string): Promise<Charge | null> {\n const response = await fetch(`${this.baseUrl}/api/v1/charges?id=${chargeId}`, {\n headers: {\n 'Authorization': `Bearer ${this.apiKey}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 404) {\n return null;\n }\n throw new Error(`Failed to get charge: ${response.statusText}`);\n }\n\n const data = await response.json() as ChargeApiResponse;\n\n return this.mapChargeResponse(data);\n }\n\n /**\n * Get a charge by transaction hash.\n */\n async getByTxHash(txHash: string): Promise<Charge | null> {\n const response = await fetch(`${this.baseUrl}/api/v1/charges?tx_hash=${txHash}`, {\n headers: {\n 'Authorization': `Bearer ${this.apiKey}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 404) {\n return null;\n }\n throw new Error(`Failed to get charge: ${response.statusText}`);\n }\n\n const data = await response.json() as ChargeApiResponse;\n\n return this.mapChargeResponse(data);\n }\n\n /**\n * Sync a charge's status from the blockchain.\n * \n * Call this when `get()` returns a charge with `needsSync: true`.\n * This will update the database with the on-chain status.\n * \n * @example\n * ```typescript\n * const charge = await charges.get('chg_xxx');\n * if (charge?.needsSync) {\n * const synced = await charges.sync(charge.id);\n * console.log(`Status updated to: ${synced.status}`);\n * }\n * ```\n */\n async sync(chargeId: string): Promise<{ id: string; status: string }> {\n const response = await fetch(`${this.baseUrl}/api/v1/charges/sync`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({ charge_id: chargeId }),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(`Failed to sync charge: ${(error as { error?: string }).error || response.statusText}`);\n }\n\n const data = await response.json() as SyncChargeApiResponse;\n\n if (!data.success || !data.charge) {\n throw new Error(`Sync failed: ${data.error || 'Unknown error'}`);\n }\n\n return data.charge;\n }\n\n /**\n * Poll for charge confirmation.\n * \n * Convenience method that polls until the charge is confirmed or failed,\n * automatically syncing when needed.\n * \n * @example\n * ```typescript\n * const charge = await charges.waitForConfirmation('chg_xxx', {\n * timeoutMs: 60000,\n * pollIntervalMs: 2000,\n * });\n * console.log(`Final status: ${charge.status}`);\n * ```\n */\n async waitForConfirmation(\n chargeId: string,\n options: { timeoutMs?: number; pollIntervalMs?: number } = {}\n ): Promise<Charge> {\n const { timeoutMs = 60000, pollIntervalMs = 2000 } = options;\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeoutMs) {\n const charge = await this.get(chargeId);\n \n if (!charge) {\n throw new Error('Charge not found');\n }\n\n // If needs sync, sync it first\n if (charge.needsSync) {\n await this.sync(chargeId);\n // Re-fetch to get updated status\n const synced = await this.get(chargeId);\n if (synced && (synced.status === 'confirmed' || synced.status === 'failed')) {\n return synced;\n }\n }\n\n // Check if we've reached a terminal state\n if (charge.status === 'confirmed' || charge.status === 'failed') {\n return charge;\n }\n\n // Also check live status for early return\n if (charge.liveStatus === 'confirmed' || charge.liveStatus === 'failed') {\n // Sync and return\n await this.sync(chargeId);\n const final = await this.get(chargeId);\n if (final) return final;\n }\n\n // Wait before next poll\n await new Promise(resolve => setTimeout(resolve, pollIntervalMs));\n }\n\n throw new Error(`Timeout waiting for charge confirmation after ${timeoutMs}ms`);\n }\n\n private mapChargeResponse(data: ChargeApiResponse): Charge {\n return {\n id: data.id,\n status: data.status as Charge['status'],\n liveStatus: data.live_status as Charge['status'] | undefined,\n onChainStatus: data.on_chain_status,\n amountUsd: data.amount_usd,\n amountUsdc: data.amount_usdc,\n txHash: data.tx_hash,\n explorerUrl: data.explorer_url,\n fromAddress: data.from_address,\n toAddress: data.to_address,\n reference: data.reference,\n createdAt: data.created_at,\n confirmedAt: data.confirmed_at,\n sessionName: data.session_name,\n userWallet: data.user_wallet,\n needsSync: data.needs_sync,\n };\n }\n}\n\n// =============================================================================\n// Webhook Verification\n// =============================================================================\n\nimport crypto from 'crypto';\n\n/**\n * Verify a session.granted webhook signature.\n * \n * @example\n * ```typescript\n * const payload = req.body;\n * const signature = req.headers['x-mixrpay-signature'];\n * \n * if (verifySessionWebhook(JSON.stringify(payload), signature, webhookSecret)) {\n * const grant = parseSessionGrant(payload);\n * console.log(`User ${grant.userWallet} granted access`);\n * }\n * ```\n */\nexport function verifySessionWebhook(\n payload: string,\n signature: string,\n secret: string\n): boolean {\n const expectedSignature = crypto\n .createHmac('sha256', secret)\n .update(payload)\n .digest('hex');\n \n return crypto.timingSafeEqual(\n Buffer.from(signature),\n Buffer.from(expectedSignature)\n );\n}\n\n/**\n * Parse a session.granted webhook payload.\n */\nexport function parseSessionGrant(payload: {\n event: string;\n session_id: string;\n user_wallet: string;\n merchant_wallet: string;\n limits: {\n max_total_usd?: number;\n max_per_tx_usd?: number;\n expires_at: string;\n };\n granted_at: string;\n}): SessionGrant {\n if (payload.event !== 'session.granted') {\n throw new Error(`Unexpected event type: ${payload.event}`);\n }\n\n return {\n sessionId: payload.session_id,\n userWallet: payload.user_wallet,\n merchantWallet: payload.merchant_wallet,\n limits: {\n maxTotalUsd: payload.limits.max_total_usd,\n maxPerTxUsd: payload.limits.max_per_tx_usd,\n expiresAt: payload.limits.expires_at,\n },\n grantedAt: payload.granted_at,\n };\n}\n\n","/**\n * MixrPay Merchant SDK - Utilities\n */\n\nimport type { EIP712Domain } from './types';\n\n// =============================================================================\n// Widget URLs\n// =============================================================================\n\n/**\n * Get the MixrPay widget script URL.\n * \n * @example\n * ```html\n * <script src=\"${getWidgetUrl()}\"\n * data-seller-public-key=\"pk_live_...\"\n * data-user-token=\"...\"></script>\n * ```\n */\nexport function getWidgetUrl(): string {\n return 'https://www.mixrpay.com/widget.js';\n}\n\n/**\n * MixrPay API base URL\n */\nexport const MIXRPAY_API_URL = 'https://www.mixrpay.com';\n\n/**\n * Widget script URL (for convenience)\n */\nexport const WIDGET_SCRIPT_URL = 'https://www.mixrpay.com/widget.js';\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// Environment Validation\n// =============================================================================\n\nexport interface EnvValidationResult {\n valid: boolean;\n errors: string[];\n warnings: string[];\n config: {\n publicKey: string | null;\n secretKey: string | null;\n hmacSecret: string | null;\n webhookSecret: string | null;\n merchantAddress: string | null;\n };\n}\n\n/**\n * Validate MixrPay environment variables and provide helpful feedback.\n * \n * @example\n * ```typescript\n * import { validateEnv } from '@mixrpay/merchant-sdk';\n * \n * const result = validateEnv();\n * if (!result.valid) {\n * console.error('MixrPay configuration errors:', result.errors);\n * }\n * ```\n */\nexport function validateEnv(env?: Record<string, string | undefined>): EnvValidationResult {\n const e = env || (typeof process !== 'undefined' ? process.env : {});\n \n const result: EnvValidationResult = {\n valid: true,\n errors: [],\n warnings: [],\n config: {\n publicKey: (e.MIXRPAY_PUBLIC_KEY as string) || null,\n secretKey: (e.MIXRPAY_SECRET_KEY as string) || null,\n hmacSecret: (e.MIXRPAY_HMAC_SECRET as string) || null,\n webhookSecret: (e.MIXRPAY_WEBHOOK_SECRET as string) || null,\n merchantAddress: (e.MIXRPAY_MERCHANT_ADDRESS as string) || null,\n },\n };\n \n // Check public key\n if (!result.config.publicKey) {\n result.errors.push('MIXRPAY_PUBLIC_KEY is required. Get it from https://www.mixrpay.com/seller/developers');\n result.valid = false;\n } else if (!result.config.publicKey.startsWith('pk_')) {\n result.errors.push(`MIXRPAY_PUBLIC_KEY must start with 'pk_'. Got: ${result.config.publicKey.slice(0, 10)}...`);\n result.valid = false;\n }\n \n // Check secret key\n if (!result.config.secretKey) {\n result.errors.push('MIXRPAY_SECRET_KEY is required. Get it from https://www.mixrpay.com/seller/developers');\n result.valid = false;\n } else if (!result.config.secretKey.startsWith('sk_')) {\n result.errors.push(`MIXRPAY_SECRET_KEY must start with 'sk_'. Got: ${result.config.secretKey.slice(0, 10)}...`);\n result.valid = false;\n }\n \n // Check webhook secret (required)\n if (!result.config.webhookSecret) {\n result.errors.push('MIXRPAY_WEBHOOK_SECRET is required. Get it from https://www.mixrpay.com/seller/developers');\n result.valid = false;\n }\n \n // Check HMAC secret (warning only - only needed for widget with user linking)\n if (!result.config.hmacSecret) {\n result.warnings.push('MIXRPAY_HMAC_SECRET not set. Only required if using Widget with user linking (data-user-token).');\n }\n \n // Check merchant address (warning only - needed for x402)\n if (!result.config.merchantAddress) {\n result.warnings.push('MIXRPAY_MERCHANT_ADDRESS not set. Required for x402 protocol support.');\n } else if (!isValidAddress(result.config.merchantAddress)) {\n result.errors.push(`MIXRPAY_MERCHANT_ADDRESS is not a valid Ethereum address: ${result.config.merchantAddress}`);\n result.valid = false;\n }\n \n return result;\n}\n\n/**\n * Log environment validation results to console with formatting.\n */\nexport function logEnvValidation(result?: EnvValidationResult): void {\n const r = result || validateEnv();\n \n console.log('\\nšŸ”§ MixrPay Environment Check\\n');\n \n if (r.valid) {\n console.log('āœ… Configuration valid\\n');\n } else {\n console.log('āŒ Configuration errors found\\n');\n }\n \n if (r.errors.length > 0) {\n console.log('Errors:');\n r.errors.forEach(e => console.log(` āŒ ${e}`));\n console.log('');\n }\n \n if (r.warnings.length > 0) {\n console.log('Warnings:');\n r.warnings.forEach(w => console.log(` āš ļø ${w}`));\n console.log('');\n }\n \n console.log('Required credentials:');\n console.log(` Public Key: ${r.config.publicKey ? 'āœ“ Set' : 'āœ— Missing'}`);\n console.log(` Secret Key: ${r.config.secretKey ? 'āœ“ Set' : 'āœ— Missing'}`);\n console.log(` Webhook Secret: ${r.config.webhookSecret ? 'āœ“ Set' : 'āœ— Missing'}`);\n console.log('');\n console.log('Optional credentials:');\n console.log(` HMAC Secret: ${r.config.hmacSecret ? 'āœ“ Set' : 'ā—‹ Not set (widget only)'}`);\n console.log(` Merchant Address: ${r.config.merchantAddress ? 'āœ“ Set' : 'ā—‹ Not set (x402 only)'}`);\n console.log('');\n}\n\n","/**\n * MixrPay Merchant SDK - Platform Types\n * \n * Type definitions for the MerchantClient class that enables\n * programmatic management of platform features.\n */\n\n// =============================================================================\n// Configuration\n// =============================================================================\n\nexport interface MerchantClientOptions {\n /** Your secret API key (sk_live_xxx or sk_test_xxx) */\n secretKey: string;\n /** API base URL (defaults to https://www.mixrpay.com) */\n baseUrl?: string;\n}\n\n// =============================================================================\n// Markup\n// =============================================================================\n\nexport interface MarkupInfo {\n /** Markup in basis points (e.g., 2000 = 20%) */\n markupBps: number;\n /** Markup as percentage (e.g., 20 = 20%) */\n markupPercent: number;\n /** Multiplier to apply to platform prices (e.g., 1.2 for 20% markup) */\n markupMultiplier: number;\n /** Example calculation */\n example?: {\n platformPrice: number;\n yourPrice: number;\n yourProfit: number;\n };\n}\n\nexport interface SetMarkupParams {\n /** Markup percentage (10-200). e.g., 20 = 20% markup. Minimum 10% required. */\n percent: number;\n}\n\nexport interface SetMarkupResponse extends MarkupInfo {\n success: boolean;\n message?: string;\n}\n\n// =============================================================================\n// LLM Models\n// =============================================================================\n\nexport interface LLMModel {\n /** Platform feature ID */\n id: string;\n /** Model identifier (e.g., \"gpt-4o-mini\", \"claude-3-5-haiku-latest\") */\n modelId: string;\n /** Human-readable name */\n displayName: string;\n /** Model description */\n description: string | null;\n /** Provider (e.g., \"openai\", \"anthropic\") */\n provider: string;\n /** Input token price per 1M tokens in USD */\n inputPricePer1M: number;\n /** Output token price per 1M tokens in USD */\n outputPricePer1M: number;\n /** Maximum context window size */\n contextWindow: number | null;\n /** Whether the merchant has enabled this model */\n enabled: boolean;\n}\n\nexport interface LLMModelsResponse {\n /** List of available LLM models */\n models: LLMModel[];\n /** Total number of models */\n count: number;\n /** Number of models enabled by merchant */\n enabledCount: number;\n}\n\nexport interface ToggleResult {\n success: boolean;\n enabled: boolean;\n modelId?: string;\n featureId?: string;\n toolSlug?: string;\n displayName?: string;\n}\n\n// =============================================================================\n// MCP Tools\n// =============================================================================\n\nexport interface MCPTool {\n /** Platform feature ID */\n id: string;\n /** Tool slug (e.g., \"firecrawl-scrape\", \"exa-search\") */\n slug: string;\n /** Human-readable name */\n displayName: string;\n /** Tool description */\n description: string | null;\n /** Tool provider */\n provider: string | null;\n /** Price per call in USD */\n priceUsd: number;\n /** Primary use case */\n primaryIntent: string | null;\n /** Agent workflow stage (acquire, parse, transform, reason, act) */\n agentStage: string | null;\n /** What the tool is best for */\n bestFor: string[];\n /** Latency class (low, medium, high) */\n latencyClass: string | null;\n /** Whether the merchant has enabled this tool */\n enabled: boolean;\n}\n\nexport interface MCPToolsResponse {\n /** List of available MCP tools */\n tools: MCPTool[];\n /** Total number of tools */\n count: number;\n /** Number of tools enabled by merchant */\n enabledCount: number;\n}\n\n// =============================================================================\n// Features (Merchant's Own)\n// =============================================================================\n\nexport interface Feature {\n /** Feature ID */\n id: string;\n /** URL-safe slug */\n slug: string;\n /** Human-readable name */\n displayName: string;\n /** Description */\n description: string | null;\n /** Price per call in USD */\n priceUsd: number;\n /** Icon identifier */\n icon: string | null;\n /** Webhook URL for notifications */\n webhookUrl: string | null;\n /** Target URL for proxy features */\n targetUrl: string | null;\n /** Whether the feature is active */\n isActive: boolean;\n /** Whether this is an MCP tool */\n isMcpTool: boolean;\n /** Creation timestamp */\n createdAt: string;\n /** Last update timestamp */\n updatedAt: string;\n}\n\nexport interface FeaturesResponse {\n /** List of merchant's features */\n features: Feature[];\n /** Total count */\n count: number;\n}\n\nexport interface CreateFeatureParams {\n /** URL-safe slug (letters, numbers, hyphens, underscores) */\n slug: string;\n /** Human-readable name */\n displayName: string;\n /** Price per call in USD */\n priceUsd: number;\n /** Description */\n description?: string;\n /** Icon identifier */\n icon?: string;\n /** Webhook URL for notifications */\n webhookUrl?: string;\n /** Target URL for proxy features */\n targetUrl?: string;\n /** Whether the feature is active (default: true) */\n isActive?: boolean;\n /** Whether this is an MCP tool */\n isMcpTool?: boolean;\n /** MCP tool name */\n mcpToolName?: string;\n /** JSON Schema for input validation */\n inputSchema?: Record<string, unknown>;\n /** JSON Schema for output validation */\n outputSchema?: Record<string, unknown>;\n /** Execution timeout in milliseconds */\n executionTimeoutMs?: number;\n /** Rate limit (requests per minute) */\n rateLimitRpm?: number;\n /** Primary intent description */\n primaryIntent?: string;\n /** Agent workflow stage */\n agentStage?: string;\n /** What the feature is best for */\n bestFor?: string[];\n /** What the feature is not ideal for */\n notIdealFor?: string[];\n /** Latency class */\n latencyClass?: 'low' | 'medium' | 'high';\n}\n\nexport interface CreateFeatureResponse {\n success: boolean;\n feature: Feature;\n}\n\nexport interface SyncFeaturesParams {\n /** Features to sync (upsert) */\n features: CreateFeatureParams[];\n /** If true, deactivate features not in the list */\n deleteUnlisted?: boolean;\n}\n\nexport interface SyncResult {\n success: boolean;\n results: {\n /** Slugs of newly created features */\n created: string[];\n /** Slugs of updated features */\n updated: string[];\n /** Slugs of deactivated features */\n deactivated: string[];\n };\n}\n\n// =============================================================================\n// Errors\n// =============================================================================\n\n/**\n * Error thrown when a MerchantClient API request fails.\n */\nexport class MerchantAPIError extends Error {\n constructor(\n message: string,\n /** HTTP status code */\n public status: number,\n /** Seconds to wait before retrying (for rate limits) */\n public retryAfterSeconds?: number\n ) {\n super(message);\n this.name = 'MerchantAPIError';\n }\n}\n\n","/**\n * MixrPay Merchant SDK - Platform Client\n * \n * Programmatic management of platform features including\n * LLM models, MCP tools, markup, and merchant features.\n * \n * @example\n * ```typescript\n * import { MerchantClient } from '@mixrpay/merchant-sdk';\n * \n * const client = new MerchantClient({ \n * secretKey: process.env.MIXRPAY_SECRET_KEY! \n * });\n * \n * // Set 15% markup on platform features\n * await client.setMarkup({ percent: 15 });\n * \n * // Enable LLM models\n * await client.enableLLMModel('gpt-4o-mini');\n * await client.enableLLMModel('claude-3-5-haiku-latest');\n * \n * // Enable MCP tools\n * await client.enableMCPTool('exa-search');\n * ```\n */\n\nimport {\n MerchantClientOptions,\n MarkupInfo,\n SetMarkupParams,\n SetMarkupResponse,\n LLMModelsResponse,\n MCPToolsResponse,\n ToggleResult,\n Feature,\n FeaturesResponse,\n CreateFeatureParams,\n CreateFeatureResponse,\n SyncFeaturesParams,\n SyncResult,\n MerchantAPIError,\n} from './platform-types';\n\nexport class MerchantClient {\n private secretKey: string;\n private baseUrl: string;\n\n /**\n * Create a new MerchantClient instance.\n * \n * @param options - Configuration options\n * @throws Error if secretKey is missing or invalid\n * \n * @example\n * ```typescript\n * const client = new MerchantClient({\n * secretKey: process.env.MIXRPAY_SECRET_KEY!,\n * baseUrl: 'https://www.mixrpay.com', // optional\n * });\n * ```\n */\n constructor(options: MerchantClientOptions) {\n if (!options.secretKey) {\n throw new Error('secretKey is required');\n }\n if (!options.secretKey.startsWith('sk_')) {\n throw new Error('secretKey must start with sk_');\n }\n this.secretKey = options.secretKey;\n this.baseUrl = options.baseUrl \n || process.env.MIXRPAY_BASE_URL \n || 'https://www.mixrpay.com';\n }\n\n // ==========================================================================\n // Internal Request Helper\n // ==========================================================================\n\n private async request<T>(\n method: string,\n path: string,\n body?: unknown\n ): Promise<T> {\n const res = await fetch(`${this.baseUrl}${path}`, {\n method,\n headers: {\n 'Authorization': `Bearer ${this.secretKey}`,\n 'Content-Type': 'application/json',\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n const data = await res.json();\n\n if (!res.ok) {\n throw new MerchantAPIError(\n data.error || 'Request failed',\n res.status,\n data.retry_after_seconds\n );\n }\n\n return data as T;\n }\n\n // ==========================================================================\n // Markup Management\n // ==========================================================================\n\n /**\n * Get current markup settings.\n * \n * @returns Current markup configuration\n * \n * @example\n * ```typescript\n * const markup = await client.getMarkup();\n * console.log(`Current markup: ${markup.markupPercent}%`);\n * ```\n */\n async getMarkup(): Promise<MarkupInfo> {\n return this.request<MarkupInfo>('GET', '/api/seller/platform-markup');\n }\n\n /**\n * Set markup percentage for platform features.\n * \n * @param params - Markup settings\n * @returns Updated markup configuration\n * \n * @example\n * ```typescript\n * // Set 15% markup (minimum is 10%)\n * const result = await client.setMarkup({ percent: 15 });\n * console.log(`New price multiplier: ${result.markupMultiplier}`);\n * ```\n */\n async setMarkup(params: SetMarkupParams): Promise<SetMarkupResponse> {\n return this.request<SetMarkupResponse>('PUT', '/api/seller/platform-markup', {\n markupPercent: params.percent,\n });\n }\n\n // ==========================================================================\n // LLM Models\n // ==========================================================================\n\n /**\n * List all available LLM models with enablement status.\n * \n * @returns List of LLM models\n * \n * @example\n * ```typescript\n * const { models, enabledCount } = await client.listLLMModels();\n * console.log(`${enabledCount} of ${models.length} models enabled`);\n * \n * // Get only enabled models\n * const enabled = models.filter(m => m.enabled);\n * ```\n */\n async listLLMModels(): Promise<LLMModelsResponse> {\n return this.request<LLMModelsResponse>('GET', '/api/seller/llm-gateway/models');\n }\n\n /**\n * Enable an LLM model.\n * \n * @param modelId - Model identifier (e.g., \"gpt-4o-mini\")\n * @returns Toggle result\n * \n * @example\n * ```typescript\n * await client.enableLLMModel('gpt-4o-mini');\n * await client.enableLLMModel('claude-3-5-haiku-latest');\n * ```\n */\n async enableLLMModel(modelId: string): Promise<ToggleResult> {\n return this.request<ToggleResult>('POST', '/api/seller/llm-gateway/toggle', {\n modelId,\n enabled: true,\n });\n }\n\n /**\n * Disable an LLM model.\n * \n * @param modelId - Model identifier (e.g., \"gpt-4o-mini\")\n * @returns Toggle result\n * \n * @example\n * ```typescript\n * await client.disableLLMModel('gpt-4o');\n * ```\n */\n async disableLLMModel(modelId: string): Promise<ToggleResult> {\n return this.request<ToggleResult>('POST', '/api/seller/llm-gateway/toggle', {\n modelId,\n enabled: false,\n });\n }\n\n // ==========================================================================\n // MCP Tools\n // ==========================================================================\n\n /**\n * List all available MCP tools with enablement status.\n * \n * @returns List of MCP tools\n * \n * @example\n * ```typescript\n * const { tools, enabledCount } = await client.listMCPTools();\n * console.log(`${enabledCount} of ${tools.length} tools enabled`);\n * \n * // Group by agent stage\n * const byStage = tools.reduce((acc, t) => {\n * const stage = t.agentStage || 'other';\n * (acc[stage] = acc[stage] || []).push(t);\n * return acc;\n * }, {});\n * ```\n */\n async listMCPTools(): Promise<MCPToolsResponse> {\n return this.request<MCPToolsResponse>('GET', '/api/seller/mcp-tools');\n }\n\n /**\n * Enable an MCP tool.\n * \n * @param toolSlug - Tool slug (e.g., \"firecrawl-scrape\")\n * @returns Toggle result\n * \n * @example\n * ```typescript\n * await client.enableMCPTool('exa-search');\n * await client.enableMCPTool('tavily-search');\n * ```\n */\n async enableMCPTool(toolSlug: string): Promise<ToggleResult> {\n return this.request<ToggleResult>('POST', '/api/seller/mcp-tools/toggle', {\n toolSlug,\n enable: true,\n });\n }\n\n /**\n * Disable an MCP tool.\n * \n * @param toolSlug - Tool slug (e.g., \"firecrawl-scrape\")\n * @returns Toggle result\n * \n * @example\n * ```typescript\n * await client.disableMCPTool('firecrawl-scrape');\n * ```\n */\n async disableMCPTool(toolSlug: string): Promise<ToggleResult> {\n return this.request<ToggleResult>('POST', '/api/seller/mcp-tools/toggle', {\n toolSlug,\n enable: false,\n });\n }\n\n // ==========================================================================\n // Features (Merchant's Own)\n // ==========================================================================\n\n /**\n * List all merchant features.\n * \n * @returns List of features\n * \n * @example\n * ```typescript\n * const { features, count } = await client.listFeatures();\n * console.log(`You have ${count} features`);\n * ```\n */\n async listFeatures(): Promise<FeaturesResponse> {\n return this.request<FeaturesResponse>('GET', '/api/seller/features');\n }\n\n /**\n * Create a new feature.\n * \n * @param params - Feature configuration\n * @returns Created feature\n * \n * @example\n * ```typescript\n * const { feature } = await client.createFeature({\n * slug: 'premium-search',\n * displayName: 'Premium Search',\n * priceUsd: 0.10,\n * description: 'Advanced search with AI ranking',\n * });\n * console.log(`Created feature: ${feature.id}`);\n * ```\n */\n async createFeature(params: CreateFeatureParams): Promise<CreateFeatureResponse> {\n return this.request<CreateFeatureResponse>('POST', '/api/seller/features', params);\n }\n\n /**\n * Sync multiple features (upsert).\n * \n * Creates new features and updates existing ones based on slug.\n * Optionally deactivates features not in the list.\n * \n * @param params - Sync configuration\n * @returns Sync results\n * \n * @example\n * ```typescript\n * const result = await client.syncFeatures({\n * features: [\n * { slug: 'search', displayName: 'Search', priceUsd: 0.05 },\n * { slug: 'analyze', displayName: 'Analyze', priceUsd: 0.10 },\n * ],\n * deleteUnlisted: false, // don't deactivate other features\n * });\n * \n * console.log(`Created: ${result.results.created.join(', ')}`);\n * console.log(`Updated: ${result.results.updated.join(', ')}`);\n * ```\n */\n async syncFeatures(params: SyncFeaturesParams): Promise<SyncResult> {\n return this.request<SyncResult>('POST', '/api/seller/features', {\n sync: true,\n features: params.features,\n deleteUnlisted: params.deleteUnlisted,\n });\n }\n}\n\n"],"mappings":"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","names":["crypto","crypto"]}
1
+ {"version":3,"sources":["../src/charges.ts","../src/utils.ts","../src/platform-types.ts","../src/platform.ts"],"sourcesContent":["/**\n * MixrPay Charges Module\n * \n * Create and manage charges using session signers.\n * Session signers allow you to charge user wallets without\n * requiring approval for each transaction.\n */\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface CreateChargeParams {\n /** Session key ID granted by the user */\n sessionId: string;\n /** Amount to charge in USD (e.g., 0.05 for 5 cents) */\n amountUsd: number;\n /** Unique reference for idempotency (e.g., \"order_123\") */\n reference: string;\n /** Optional metadata */\n metadata?: Record<string, unknown>;\n}\n\nexport interface Charge {\n /** Unique charge ID */\n id: string;\n /** Current status (from database) */\n status: 'pending' | 'submitted' | 'confirmed' | 'failed';\n /** Real-time status (may differ from DB if not yet synced) */\n liveStatus?: 'pending' | 'submitted' | 'confirmed' | 'failed';\n /** Raw on-chain status */\n onChainStatus?: 'pending' | 'confirmed' | 'failed' | 'not_found' | null;\n /** Amount in USD */\n amountUsd: number;\n /** Formatted USDC amount */\n amountUsdc: string;\n /** Transaction hash (if submitted) */\n txHash?: string;\n /** Block explorer URL */\n explorerUrl?: string;\n /** From wallet address */\n fromAddress: string;\n /** To wallet address */\n toAddress: string;\n /** Your reference */\n reference: string;\n /** When the charge was created */\n createdAt: string;\n /** When the charge was confirmed */\n confirmedAt?: string;\n /** Session name */\n sessionName?: string;\n /** User wallet address */\n userWallet?: string;\n /** Error message if failed */\n error?: string;\n /** True if DB status differs from on-chain - call sync() to update */\n needsSync?: boolean;\n}\n\nexport interface CreateChargeResult {\n success: boolean;\n charge?: Charge;\n /** True if this is a replay of an existing charge */\n idempotentReplay?: boolean;\n error?: string;\n details?: string;\n}\n\nexport interface SessionGrant {\n /** Session key ID */\n sessionId: string;\n /** User's wallet address */\n userWallet: string;\n /** Your merchant wallet address */\n merchantWallet: string;\n /** Spending limits */\n limits: {\n maxTotalUsd?: number;\n maxPerTxUsd?: number;\n expiresAt: string;\n };\n /** When the session was granted */\n grantedAt: string;\n}\n\n// Internal types for API responses\ninterface CreateChargeApiResponse {\n success: boolean;\n charge_id?: string;\n status?: string;\n amount_usd?: number;\n amount_usdc?: string;\n tx_hash?: string;\n explorer_url?: string;\n idempotent_replay?: boolean;\n error?: string;\n details?: string;\n}\n\ninterface ChargeApiResponse {\n id: string;\n status: string;\n /** Real-time status (may differ from DB status if not yet synced) */\n live_status?: string;\n /** Raw on-chain status */\n on_chain_status?: 'pending' | 'confirmed' | 'failed' | 'not_found' | null;\n amount_usd: number;\n amount_usdc: string;\n tx_hash?: string;\n explorer_url?: string;\n from_address: string;\n to_address: string;\n reference: string;\n created_at: string;\n confirmed_at?: string;\n session_name?: string;\n user_wallet?: string;\n /** True if DB status differs from on-chain status */\n needs_sync?: boolean;\n}\n\ninterface SyncChargeApiResponse {\n success: boolean;\n charge?: {\n id: string;\n status: string;\n };\n error?: string;\n}\n\nexport interface ChargesClientOptions {\n /** Your API key */\n apiKey: string;\n /** MixrPay API base URL */\n baseUrl?: string;\n}\n\n// =============================================================================\n// Client\n// =============================================================================\n\nexport class ChargesClient {\n private apiKey: string;\n private baseUrl: string;\n\n constructor(options: ChargesClientOptions) {\n this.apiKey = options.apiKey;\n this.baseUrl = options.baseUrl || process.env.MIXRPAY_BASE_URL || 'https://www.mixrpay.com';\n }\n\n /**\n * Create a new charge.\n * \n * @example\n * ```typescript\n * const result = await charges.create({\n * sessionId: 'sk_xxx',\n * amountUsd: 0.05,\n * reference: 'image_gen_123',\n * metadata: { feature: 'image_generation' }\n * });\n * \n * if (result.success) {\n * console.log(`Charged ${result.charge.amountUsdc}`);\n * console.log(`TX: ${result.charge.explorerUrl}`);\n * }\n * ```\n */\n async create(params: CreateChargeParams): Promise<CreateChargeResult> {\n const response = await fetch(`${this.baseUrl}/api/v1/charges`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({\n session_id: params.sessionId,\n amount_usd: params.amountUsd,\n reference: params.reference,\n metadata: params.metadata,\n }),\n });\n\n const data = await response.json() as CreateChargeApiResponse;\n\n if (!response.ok) {\n return {\n success: false,\n error: data.error,\n details: data.details,\n };\n }\n\n return {\n success: data.success,\n charge: data.charge_id ? {\n id: data.charge_id,\n status: data.status as Charge['status'],\n amountUsd: data.amount_usd ?? 0,\n amountUsdc: data.amount_usdc ?? '0',\n txHash: data.tx_hash,\n explorerUrl: data.explorer_url,\n fromAddress: '',\n toAddress: '',\n reference: params.reference,\n createdAt: new Date().toISOString(),\n } : undefined,\n idempotentReplay: data.idempotent_replay,\n error: data.error,\n };\n }\n\n /**\n * Get a charge by ID.\n * \n * Note: The returned status is from the database. If `needsSync` is true,\n * the on-chain status differs and you should call `sync()` to update.\n * \n * @example\n * ```typescript\n * const charge = await charges.get('chg_xxx');\n * console.log(charge.status); // 'submitted'\n * console.log(charge.liveStatus); // 'confirmed' (real-time)\n * \n * if (charge.needsSync) {\n * await charges.sync(charge.id);\n * }\n * ```\n */\n async get(chargeId: string): Promise<Charge | null> {\n const response = await fetch(`${this.baseUrl}/api/v1/charges?id=${chargeId}`, {\n headers: {\n 'Authorization': `Bearer ${this.apiKey}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 404) {\n return null;\n }\n throw new Error(`Failed to get charge: ${response.statusText}`);\n }\n\n const data = await response.json() as ChargeApiResponse;\n\n return this.mapChargeResponse(data);\n }\n\n /**\n * Get a charge by transaction hash.\n */\n async getByTxHash(txHash: string): Promise<Charge | null> {\n const response = await fetch(`${this.baseUrl}/api/v1/charges?tx_hash=${txHash}`, {\n headers: {\n 'Authorization': `Bearer ${this.apiKey}`,\n },\n });\n\n if (!response.ok) {\n if (response.status === 404) {\n return null;\n }\n throw new Error(`Failed to get charge: ${response.statusText}`);\n }\n\n const data = await response.json() as ChargeApiResponse;\n\n return this.mapChargeResponse(data);\n }\n\n /**\n * Sync a charge's status from the blockchain.\n * \n * Call this when `get()` returns a charge with `needsSync: true`.\n * This will update the database with the on-chain status.\n * \n * @example\n * ```typescript\n * const charge = await charges.get('chg_xxx');\n * if (charge?.needsSync) {\n * const synced = await charges.sync(charge.id);\n * console.log(`Status updated to: ${synced.status}`);\n * }\n * ```\n */\n async sync(chargeId: string): Promise<{ id: string; status: string }> {\n const response = await fetch(`${this.baseUrl}/api/v1/charges/sync`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({ charge_id: chargeId }),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({}));\n throw new Error(`Failed to sync charge: ${(error as { error?: string }).error || response.statusText}`);\n }\n\n const data = await response.json() as SyncChargeApiResponse;\n\n if (!data.success || !data.charge) {\n throw new Error(`Sync failed: ${data.error || 'Unknown error'}`);\n }\n\n return data.charge;\n }\n\n /**\n * Poll for charge confirmation.\n * \n * Convenience method that polls until the charge is confirmed or failed,\n * automatically syncing when needed.\n * \n * @example\n * ```typescript\n * const charge = await charges.waitForConfirmation('chg_xxx', {\n * timeoutMs: 60000,\n * pollIntervalMs: 2000,\n * });\n * console.log(`Final status: ${charge.status}`);\n * ```\n */\n async waitForConfirmation(\n chargeId: string,\n options: { timeoutMs?: number; pollIntervalMs?: number } = {}\n ): Promise<Charge> {\n const { timeoutMs = 60000, pollIntervalMs = 2000 } = options;\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeoutMs) {\n const charge = await this.get(chargeId);\n \n if (!charge) {\n throw new Error('Charge not found');\n }\n\n // If needs sync, sync it first\n if (charge.needsSync) {\n await this.sync(chargeId);\n // Re-fetch to get updated status\n const synced = await this.get(chargeId);\n if (synced && (synced.status === 'confirmed' || synced.status === 'failed')) {\n return synced;\n }\n }\n\n // Check if we've reached a terminal state\n if (charge.status === 'confirmed' || charge.status === 'failed') {\n return charge;\n }\n\n // Also check live status for early return\n if (charge.liveStatus === 'confirmed' || charge.liveStatus === 'failed') {\n // Sync and return\n await this.sync(chargeId);\n const final = await this.get(chargeId);\n if (final) return final;\n }\n\n // Wait before next poll\n await new Promise(resolve => setTimeout(resolve, pollIntervalMs));\n }\n\n throw new Error(`Timeout waiting for charge confirmation after ${timeoutMs}ms`);\n }\n\n private mapChargeResponse(data: ChargeApiResponse): Charge {\n return {\n id: data.id,\n status: data.status as Charge['status'],\n liveStatus: data.live_status as Charge['status'] | undefined,\n onChainStatus: data.on_chain_status,\n amountUsd: data.amount_usd,\n amountUsdc: data.amount_usdc,\n txHash: data.tx_hash,\n explorerUrl: data.explorer_url,\n fromAddress: data.from_address,\n toAddress: data.to_address,\n reference: data.reference,\n createdAt: data.created_at,\n confirmedAt: data.confirmed_at,\n sessionName: data.session_name,\n userWallet: data.user_wallet,\n needsSync: data.needs_sync,\n };\n }\n}\n\n// =============================================================================\n// Webhook Verification\n// =============================================================================\n\nimport crypto from 'crypto';\n\n/**\n * Verify a session.granted webhook signature.\n * \n * @example\n * ```typescript\n * const payload = req.body;\n * const signature = req.headers['x-mixrpay-signature'];\n * \n * if (verifySessionWebhook(JSON.stringify(payload), signature, webhookSecret)) {\n * const grant = parseSessionGrant(payload);\n * console.log(`User ${grant.userWallet} granted access`);\n * }\n * ```\n */\nexport function verifySessionWebhook(\n payload: string,\n signature: string,\n secret: string\n): boolean {\n const expectedSignature = crypto\n .createHmac('sha256', secret)\n .update(payload)\n .digest('hex');\n \n return crypto.timingSafeEqual(\n Buffer.from(signature),\n Buffer.from(expectedSignature)\n );\n}\n\n/**\n * Parse a session.granted webhook payload.\n */\nexport function parseSessionGrant(payload: {\n event: string;\n session_id: string;\n user_wallet: string;\n merchant_wallet: string;\n limits: {\n max_total_usd?: number;\n max_per_tx_usd?: number;\n expires_at: string;\n };\n granted_at: string;\n}): SessionGrant {\n if (payload.event !== 'session.granted') {\n throw new Error(`Unexpected event type: ${payload.event}`);\n }\n\n return {\n sessionId: payload.session_id,\n userWallet: payload.user_wallet,\n merchantWallet: payload.merchant_wallet,\n limits: {\n maxTotalUsd: payload.limits.max_total_usd,\n maxPerTxUsd: payload.limits.max_per_tx_usd,\n expiresAt: payload.limits.expires_at,\n },\n grantedAt: payload.granted_at,\n };\n}\n\n","/**\n * MixrPay Merchant SDK - Utilities\n */\n\nimport type { EIP712Domain } from './types';\n\n// =============================================================================\n// Widget URLs\n// =============================================================================\n\n/**\n * Get the MixrPay widget script URL.\n * \n * @example\n * ```html\n * <script src=\"${getWidgetUrl()}\"\n * data-seller-public-key=\"pk_live_...\"\n * data-user-token=\"...\"></script>\n * ```\n */\nexport function getWidgetUrl(): string {\n return 'https://www.mixrpay.com/widget.js';\n}\n\n/**\n * MixrPay API base URL\n */\nexport const MIXRPAY_API_URL = 'https://www.mixrpay.com';\n\n/**\n * Widget script URL (for convenience)\n */\nexport const WIDGET_SCRIPT_URL = 'https://www.mixrpay.com/widget.js';\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// Environment Validation\n// =============================================================================\n\nexport interface EnvValidationResult {\n valid: boolean;\n errors: string[];\n warnings: string[];\n config: {\n publicKey: string | null;\n secretKey: string | null;\n hmacSecret: string | null;\n webhookSecret: string | null;\n merchantAddress: string | null;\n };\n}\n\n/**\n * Validate MixrPay environment variables and provide helpful feedback.\n * \n * @example\n * ```typescript\n * import { validateEnv } from '@mixrpay/merchant-sdk';\n * \n * const result = validateEnv();\n * if (!result.valid) {\n * console.error('MixrPay configuration errors:', result.errors);\n * }\n * ```\n */\nexport function validateEnv(env?: Record<string, string | undefined>): EnvValidationResult {\n const e = env || (typeof process !== 'undefined' ? process.env : {});\n \n const result: EnvValidationResult = {\n valid: true,\n errors: [],\n warnings: [],\n config: {\n publicKey: (e.MIXRPAY_PUBLIC_KEY as string) || null,\n secretKey: (e.MIXRPAY_SECRET_KEY as string) || null,\n hmacSecret: (e.MIXRPAY_HMAC_SECRET as string) || null,\n webhookSecret: (e.MIXRPAY_WEBHOOK_SECRET as string) || null,\n merchantAddress: (e.MIXRPAY_MERCHANT_ADDRESS as string) || null,\n },\n };\n \n // Check public key\n if (!result.config.publicKey) {\n result.errors.push('MIXRPAY_PUBLIC_KEY is required. Get it from https://www.mixrpay.com/seller/developers');\n result.valid = false;\n } else if (!result.config.publicKey.startsWith('pk_')) {\n result.errors.push(`MIXRPAY_PUBLIC_KEY must start with 'pk_'. Got: ${result.config.publicKey.slice(0, 10)}...`);\n result.valid = false;\n }\n \n // Check secret key\n if (!result.config.secretKey) {\n result.errors.push('MIXRPAY_SECRET_KEY is required. Get it from https://www.mixrpay.com/seller/developers');\n result.valid = false;\n } else if (!result.config.secretKey.startsWith('sk_')) {\n result.errors.push(`MIXRPAY_SECRET_KEY must start with 'sk_'. Got: ${result.config.secretKey.slice(0, 10)}...`);\n result.valid = false;\n }\n \n // Check webhook secret (required)\n if (!result.config.webhookSecret) {\n result.errors.push('MIXRPAY_WEBHOOK_SECRET is required. Get it from https://www.mixrpay.com/seller/developers');\n result.valid = false;\n }\n \n // Check HMAC secret (warning only - only needed for widget with user linking)\n if (!result.config.hmacSecret) {\n result.warnings.push('MIXRPAY_HMAC_SECRET not set. Only required if using Widget with user linking (data-user-token).');\n }\n \n // Check merchant address (warning only - needed for x402)\n if (!result.config.merchantAddress) {\n result.warnings.push('MIXRPAY_MERCHANT_ADDRESS not set. Required for x402 protocol support.');\n } else if (!isValidAddress(result.config.merchantAddress)) {\n result.errors.push(`MIXRPAY_MERCHANT_ADDRESS is not a valid Ethereum address: ${result.config.merchantAddress}`);\n result.valid = false;\n }\n \n return result;\n}\n\n/**\n * Log environment validation results to console with formatting.\n */\nexport function logEnvValidation(result?: EnvValidationResult): void {\n const r = result || validateEnv();\n \n console.log('\\nšŸ”§ MixrPay Environment Check\\n');\n \n if (r.valid) {\n console.log('āœ… Configuration valid\\n');\n } else {\n console.log('āŒ Configuration errors found\\n');\n }\n \n if (r.errors.length > 0) {\n console.log('Errors:');\n r.errors.forEach(e => console.log(` āŒ ${e}`));\n console.log('');\n }\n \n if (r.warnings.length > 0) {\n console.log('Warnings:');\n r.warnings.forEach(w => console.log(` āš ļø ${w}`));\n console.log('');\n }\n \n console.log('Required credentials:');\n console.log(` Public Key: ${r.config.publicKey ? 'āœ“ Set' : 'āœ— Missing'}`);\n console.log(` Secret Key: ${r.config.secretKey ? 'āœ“ Set' : 'āœ— Missing'}`);\n console.log(` Webhook Secret: ${r.config.webhookSecret ? 'āœ“ Set' : 'āœ— Missing'}`);\n console.log('');\n console.log('Optional credentials:');\n console.log(` HMAC Secret: ${r.config.hmacSecret ? 'āœ“ Set' : 'ā—‹ Not set (widget only)'}`);\n console.log(` Merchant Address: ${r.config.merchantAddress ? 'āœ“ Set' : 'ā—‹ Not set (x402 only)'}`);\n console.log('');\n}\n\n","/**\n * MixrPay Merchant SDK - Platform Types\n * \n * Type definitions for the MerchantClient class that enables\n * programmatic management of platform features.\n */\n\n// =============================================================================\n// Configuration\n// =============================================================================\n\nexport interface MerchantClientOptions {\n /** Your secret API key (sk_live_xxx or sk_test_xxx) */\n secretKey: string;\n /** API base URL (defaults to https://www.mixrpay.com) */\n baseUrl?: string;\n}\n\n// =============================================================================\n// Markup\n// =============================================================================\n\nexport interface MarkupInfo {\n /** Markup in basis points (e.g., 2000 = 20%) */\n markupBps: number;\n /** Markup as percentage (e.g., 20 = 20%) */\n markupPercent: number;\n /** Multiplier to apply to platform prices (e.g., 1.2 for 20% markup) */\n markupMultiplier: number;\n /** Example calculation */\n example?: {\n platformPrice: number;\n yourPrice: number;\n yourProfit: number;\n };\n}\n\nexport interface SetMarkupParams {\n /** Markup percentage (10-200). e.g., 20 = 20% markup. Minimum 10% required. */\n percent: number;\n}\n\nexport interface SetMarkupResponse extends MarkupInfo {\n success: boolean;\n message?: string;\n}\n\n// =============================================================================\n// LLM Models\n// =============================================================================\n\nexport interface LLMModel {\n /** Platform feature ID */\n id: string;\n /** Model identifier (e.g., \"gpt-4o-mini\", \"claude-3-5-haiku-latest\") */\n modelId: string;\n /** Human-readable name */\n displayName: string;\n /** Model description */\n description: string | null;\n /** Provider (e.g., \"openai\", \"anthropic\") */\n provider: string;\n /** Input token price per 1M tokens in USD */\n inputPricePer1M: number;\n /** Output token price per 1M tokens in USD */\n outputPricePer1M: number;\n /** Maximum context window size */\n contextWindow: number | null;\n /** Whether the merchant has enabled this model */\n enabled: boolean;\n}\n\nexport interface LLMModelsResponse {\n /** List of available LLM models */\n models: LLMModel[];\n /** Total number of models */\n count: number;\n /** Number of models enabled by merchant */\n enabledCount: number;\n}\n\nexport interface ToggleResult {\n success: boolean;\n enabled: boolean;\n modelId?: string;\n featureId?: string;\n toolSlug?: string;\n displayName?: string;\n}\n\n// =============================================================================\n// MCP Tools\n// =============================================================================\n\nexport interface MCPTool {\n /** Platform feature ID */\n id: string;\n /** Tool slug (e.g., \"firecrawl-scrape\", \"exa-search\") */\n slug: string;\n /** Human-readable name */\n displayName: string;\n /** Tool description */\n description: string | null;\n /** Tool provider */\n provider: string | null;\n /** Price per call in USD */\n priceUsd: number;\n /** Primary use case */\n primaryIntent: string | null;\n /** Agent workflow stage (acquire, parse, transform, reason, act) */\n agentStage: string | null;\n /** What the tool is best for */\n bestFor: string[];\n /** Latency class (low, medium, high) */\n latencyClass: string | null;\n /** Whether the merchant has enabled this tool */\n enabled: boolean;\n}\n\nexport interface MCPToolsResponse {\n /** List of available MCP tools */\n tools: MCPTool[];\n /** Total number of tools */\n count: number;\n /** Number of tools enabled by merchant */\n enabledCount: number;\n}\n\n// =============================================================================\n// Features (Merchant's Own)\n// =============================================================================\n\nexport interface Feature {\n /** Feature ID */\n id: string;\n /** URL-safe slug */\n slug: string;\n /** Human-readable name */\n displayName: string;\n /** Description */\n description: string | null;\n /** Price per call in USD */\n priceUsd: number;\n /** Icon identifier */\n icon: string | null;\n /** Webhook URL for notifications */\n webhookUrl: string | null;\n /** Target URL for proxy features */\n targetUrl: string | null;\n /** Whether the feature is active */\n isActive: boolean;\n /** Whether this is an MCP tool */\n isMcpTool: boolean;\n /** Creation timestamp */\n createdAt: string;\n /** Last update timestamp */\n updatedAt: string;\n}\n\nexport interface FeaturesResponse {\n /** List of merchant's features */\n features: Feature[];\n /** Total count */\n count: number;\n}\n\nexport interface CreateFeatureParams {\n /** URL-safe slug (letters, numbers, hyphens, underscores) */\n slug: string;\n /** Human-readable name */\n displayName: string;\n /** Price per call in USD */\n priceUsd: number;\n /** Description */\n description?: string;\n /** Icon identifier */\n icon?: string;\n /** Webhook URL for notifications */\n webhookUrl?: string;\n /** Target URL for proxy features */\n targetUrl?: string;\n /** Whether the feature is active (default: true) */\n isActive?: boolean;\n /** Whether this is an MCP tool */\n isMcpTool?: boolean;\n /** MCP tool name */\n mcpToolName?: string;\n /** JSON Schema for input validation */\n inputSchema?: Record<string, unknown>;\n /** JSON Schema for output validation */\n outputSchema?: Record<string, unknown>;\n /** Execution timeout in milliseconds */\n executionTimeoutMs?: number;\n /** Rate limit (requests per minute) */\n rateLimitRpm?: number;\n /** Primary intent description */\n primaryIntent?: string;\n /** Agent workflow stage */\n agentStage?: string;\n /** What the feature is best for */\n bestFor?: string[];\n /** What the feature is not ideal for */\n notIdealFor?: string[];\n /** Latency class */\n latencyClass?: 'low' | 'medium' | 'high';\n}\n\nexport interface CreateFeatureResponse {\n success: boolean;\n feature: Feature;\n}\n\nexport interface SyncFeaturesParams {\n /** Features to sync (upsert) */\n features: CreateFeatureParams[];\n /** If true, deactivate features not in the list */\n deleteUnlisted?: boolean;\n}\n\nexport interface SyncResult {\n success: boolean;\n results: {\n /** Slugs of newly created features */\n created: string[];\n /** Slugs of updated features */\n updated: string[];\n /** Slugs of deactivated features */\n deactivated: string[];\n };\n}\n\n// =============================================================================\n// Errors\n// =============================================================================\n\n/**\n * Error thrown when a MerchantClient API request fails.\n */\nexport class MerchantAPIError extends Error {\n constructor(\n message: string,\n /** HTTP status code */\n public status: number,\n /** Seconds to wait before retrying (for rate limits) */\n public retryAfterSeconds?: number\n ) {\n super(message);\n this.name = 'MerchantAPIError';\n }\n}\n\n","/**\n * MixrPay Merchant SDK - Platform Client\n * \n * Programmatic management of platform features including\n * LLM models, MCP tools, markup, and merchant features.\n * \n * @example\n * ```typescript\n * import { MerchantClient } from '@mixrpay/merchant-sdk';\n * \n * const client = new MerchantClient({ \n * secretKey: process.env.MIXRPAY_SECRET_KEY! \n * });\n * \n * // Set 15% markup on platform features\n * await client.setMarkup({ percent: 15 });\n * \n * // Enable LLM models\n * await client.enableLLMModel('gpt-4o-mini');\n * await client.enableLLMModel('claude-3-5-haiku-latest');\n * \n * // Enable MCP tools\n * await client.enableMCPTool('exa-search');\n * ```\n */\n\nimport {\n MerchantClientOptions,\n MarkupInfo,\n SetMarkupParams,\n SetMarkupResponse,\n LLMModelsResponse,\n MCPToolsResponse,\n ToggleResult,\n Feature,\n FeaturesResponse,\n CreateFeatureParams,\n CreateFeatureResponse,\n SyncFeaturesParams,\n SyncResult,\n MerchantAPIError,\n} from './platform-types';\n\nexport class MerchantClient {\n private secretKey: string;\n private baseUrl: string;\n\n /**\n * Create a new MerchantClient instance.\n * \n * @param options - Configuration options\n * @throws Error if secretKey is missing or invalid\n * \n * @example\n * ```typescript\n * const client = new MerchantClient({\n * secretKey: process.env.MIXRPAY_SECRET_KEY!,\n * baseUrl: 'https://www.mixrpay.com', // optional\n * });\n * ```\n */\n constructor(options: MerchantClientOptions) {\n if (!options.secretKey) {\n throw new Error('secretKey is required');\n }\n if (!options.secretKey.startsWith('sk_')) {\n throw new Error('secretKey must start with sk_');\n }\n this.secretKey = options.secretKey;\n this.baseUrl = options.baseUrl \n || process.env.MIXRPAY_BASE_URL \n || 'https://www.mixrpay.com';\n }\n\n // ==========================================================================\n // Internal Request Helper\n // ==========================================================================\n\n private async request<T>(\n method: string,\n path: string,\n body?: unknown\n ): Promise<T> {\n const res = await fetch(`${this.baseUrl}${path}`, {\n method,\n headers: {\n 'Authorization': `Bearer ${this.secretKey}`,\n 'Content-Type': 'application/json',\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n const data = await res.json();\n\n if (!res.ok) {\n throw new MerchantAPIError(\n data.error || 'Request failed',\n res.status,\n data.retry_after_seconds\n );\n }\n\n return data as T;\n }\n\n // ==========================================================================\n // Markup Management\n // ==========================================================================\n\n /**\n * Get current markup settings.\n * \n * @returns Current markup configuration\n * \n * @example\n * ```typescript\n * const markup = await client.getMarkup();\n * console.log(`Current markup: ${markup.markupPercent}%`);\n * ```\n */\n async getMarkup(): Promise<MarkupInfo> {\n return this.request<MarkupInfo>('GET', '/api/seller/platform-markup');\n }\n\n /**\n * Set markup percentage for platform features.\n * \n * @param params - Markup settings\n * @returns Updated markup configuration\n * \n * @example\n * ```typescript\n * // Set 15% markup (minimum is 10%)\n * const result = await client.setMarkup({ percent: 15 });\n * console.log(`New price multiplier: ${result.markupMultiplier}`);\n * ```\n */\n async setMarkup(params: SetMarkupParams): Promise<SetMarkupResponse> {\n return this.request<SetMarkupResponse>('PUT', '/api/seller/platform-markup', {\n markupPercent: params.percent,\n });\n }\n\n // ==========================================================================\n // LLM Models\n // ==========================================================================\n\n /**\n * List all available LLM models with enablement status.\n * \n * @returns List of LLM models\n * \n * @example\n * ```typescript\n * const { models, enabledCount } = await client.listLLMModels();\n * console.log(`${enabledCount} of ${models.length} models enabled`);\n * \n * // Get only enabled models\n * const enabled = models.filter(m => m.enabled);\n * ```\n */\n async listLLMModels(): Promise<LLMModelsResponse> {\n return this.request<LLMModelsResponse>('GET', '/api/seller/llm-gateway/models');\n }\n\n /**\n * Enable an LLM model.\n * \n * @param modelId - Model identifier (e.g., \"gpt-4o-mini\")\n * @returns Toggle result\n * \n * @example\n * ```typescript\n * await client.enableLLMModel('gpt-4o-mini');\n * await client.enableLLMModel('claude-3-5-haiku-latest');\n * ```\n */\n async enableLLMModel(modelId: string): Promise<ToggleResult> {\n return this.request<ToggleResult>('POST', '/api/seller/llm-gateway/toggle', {\n modelId,\n enabled: true,\n });\n }\n\n /**\n * Disable an LLM model.\n * \n * @param modelId - Model identifier (e.g., \"gpt-4o-mini\")\n * @returns Toggle result\n * \n * @example\n * ```typescript\n * await client.disableLLMModel('gpt-4o');\n * ```\n */\n async disableLLMModel(modelId: string): Promise<ToggleResult> {\n return this.request<ToggleResult>('POST', '/api/seller/llm-gateway/toggle', {\n modelId,\n enabled: false,\n });\n }\n\n // ==========================================================================\n // MCP Tools\n // ==========================================================================\n\n /**\n * List all available MCP tools with enablement status.\n * \n * @returns List of MCP tools\n * \n * @example\n * ```typescript\n * const { tools, enabledCount } = await client.listMCPTools();\n * console.log(`${enabledCount} of ${tools.length} tools enabled`);\n * \n * // Group by agent stage\n * const byStage = tools.reduce((acc, t) => {\n * const stage = t.agentStage || 'other';\n * (acc[stage] = acc[stage] || []).push(t);\n * return acc;\n * }, {});\n * ```\n */\n async listMCPTools(): Promise<MCPToolsResponse> {\n return this.request<MCPToolsResponse>('GET', '/api/seller/gateway-tools');\n }\n\n /**\n * Enable an MCP tool.\n * \n * @param toolSlug - Tool slug (e.g., \"firecrawl-scrape\")\n * @returns Toggle result\n * \n * @example\n * ```typescript\n * await client.enableMCPTool('exa-search');\n * await client.enableMCPTool('tavily-search');\n * ```\n */\n async enableMCPTool(toolSlug: string): Promise<ToggleResult> {\n return this.request<ToggleResult>('POST', '/api/seller/gateway-tools/toggle', {\n toolSlug,\n enable: true,\n });\n }\n\n /**\n * Disable an MCP tool.\n * \n * @param toolSlug - Tool slug (e.g., \"firecrawl-scrape\")\n * @returns Toggle result\n * \n * @example\n * ```typescript\n * await client.disableMCPTool('firecrawl-scrape');\n * ```\n */\n async disableMCPTool(toolSlug: string): Promise<ToggleResult> {\n return this.request<ToggleResult>('POST', '/api/seller/gateway-tools/toggle', {\n toolSlug,\n enable: false,\n });\n }\n\n // ==========================================================================\n // Features (Merchant's Own)\n // ==========================================================================\n\n /**\n * List all merchant features.\n * \n * @returns List of features\n * \n * @example\n * ```typescript\n * const { features, count } = await client.listFeatures();\n * console.log(`You have ${count} features`);\n * ```\n */\n async listFeatures(): Promise<FeaturesResponse> {\n return this.request<FeaturesResponse>('GET', '/api/seller/features');\n }\n\n /**\n * Create a new feature.\n * \n * @param params - Feature configuration\n * @returns Created feature\n * \n * @example\n * ```typescript\n * const { feature } = await client.createFeature({\n * slug: 'premium-search',\n * displayName: 'Premium Search',\n * priceUsd: 0.10,\n * description: 'Advanced search with AI ranking',\n * });\n * console.log(`Created feature: ${feature.id}`);\n * ```\n */\n async createFeature(params: CreateFeatureParams): Promise<CreateFeatureResponse> {\n return this.request<CreateFeatureResponse>('POST', '/api/seller/features', params);\n }\n\n /**\n * Sync multiple features (upsert).\n * \n * Creates new features and updates existing ones based on slug.\n * Optionally deactivates features not in the list.\n * \n * @param params - Sync configuration\n * @returns Sync results\n * \n * @example\n * ```typescript\n * const result = await client.syncFeatures({\n * features: [\n * { slug: 'search', displayName: 'Search', priceUsd: 0.05 },\n * { slug: 'analyze', displayName: 'Analyze', priceUsd: 0.10 },\n * ],\n * deleteUnlisted: false, // don't deactivate other features\n * });\n * \n * console.log(`Created: ${result.results.created.join(', ')}`);\n * console.log(`Updated: ${result.results.updated.join(', ')}`);\n * ```\n */\n async syncFeatures(params: SyncFeaturesParams): Promise<SyncResult> {\n return this.request<SyncResult>('POST', '/api/seller/features', {\n sync: true,\n features: params.features,\n deleteUnlisted: params.deleteUnlisted,\n });\n }\n}\n\n"],"mappings":"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","names":["crypto","crypto"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mixrpay/merchant-sdk",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Add x402 payments to your API in minutes - middleware for Express, Next.js, and Fastify",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",