@alleyboss/micropay-solana-x402-paywall 2.3.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -116
- package/dist/agent/index.cjs +358 -0
- package/dist/agent/index.cjs.map +1 -0
- package/dist/agent/index.d.cts +221 -0
- package/dist/agent/index.d.ts +221 -0
- package/dist/agent/index.js +347 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/client/index.cjs +1 -1
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +10 -1
- package/dist/client/index.d.ts +10 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/express/index.cjs +79 -0
- package/dist/express/index.cjs.map +1 -0
- package/dist/express/index.d.cts +40 -0
- package/dist/express/index.d.ts +40 -0
- package/dist/express/index.js +76 -0
- package/dist/express/index.js.map +1 -0
- package/dist/index.cjs +315 -1116
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -10
- package/dist/index.d.ts +6 -10
- package/dist/index.js +283 -1074
- package/dist/index.js.map +1 -1
- package/dist/session/index.cjs.map +1 -1
- package/dist/session/index.d.cts +1 -1
- package/dist/session/index.d.ts +1 -1
- package/dist/session/index.js.map +1 -1
- package/dist/{session-D2IoWAWV.d.cts → types-BWYQMw03.d.cts} +1 -16
- package/dist/{session-D2IoWAWV.d.ts → types-BWYQMw03.d.ts} +1 -16
- package/package.json +29 -59
- package/dist/client-D-dteoJw.d.cts +0 -63
- package/dist/client-DfCIRrNG.d.ts +0 -63
- package/dist/memory-Daxkczti.d.cts +0 -29
- package/dist/memory-Daxkczti.d.ts +0 -29
- package/dist/middleware/index.cjs +0 -273
- package/dist/middleware/index.cjs.map +0 -1
- package/dist/middleware/index.d.cts +0 -91
- package/dist/middleware/index.d.ts +0 -91
- package/dist/middleware/index.js +0 -267
- package/dist/middleware/index.js.map +0 -1
- package/dist/nextjs-BDyOqGAq.d.cts +0 -81
- package/dist/nextjs-CbX8_9yK.d.ts +0 -81
- package/dist/payment-BGp7eMQl.d.cts +0 -103
- package/dist/payment-BGp7eMQl.d.ts +0 -103
- package/dist/solana/index.cjs +0 -589
- package/dist/solana/index.cjs.map +0 -1
- package/dist/solana/index.d.cts +0 -240
- package/dist/solana/index.d.ts +0 -240
- package/dist/solana/index.js +0 -567
- package/dist/solana/index.js.map +0 -1
- package/dist/store/index.cjs +0 -99
- package/dist/store/index.cjs.map +0 -1
- package/dist/store/index.d.cts +0 -38
- package/dist/store/index.d.ts +0 -38
- package/dist/store/index.js +0 -96
- package/dist/store/index.js.map +0 -1
- package/dist/utils/index.cjs +0 -68
- package/dist/utils/index.cjs.map +0 -1
- package/dist/utils/index.d.cts +0 -30
- package/dist/utils/index.d.ts +0 -30
- package/dist/utils/index.js +0 -65
- package/dist/utils/index.js.map +0 -1
- package/dist/x402/index.cjs +0 -387
- package/dist/x402/index.cjs.map +0 -1
- package/dist/x402/index.d.cts +0 -96
- package/dist/x402/index.d.ts +0 -96
- package/dist/x402/index.js +0 -375
- package/dist/x402/index.js.map +0 -1
package/dist/solana/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/solana/client.ts","../../src/solana/verification.ts","../../src/types/payment.ts","../../src/solana/spl.ts","../../src/solana/priority-fees.ts","../../src/solana/versioned.ts"],"names":["SIGNATURE_REGEX","WALLET_REGEX","PublicKey"],"mappings":"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","file":"index.js","sourcesContent":["// Solana RPC client with multi-provider support and optional fallback\nimport { Connection, clusterApiUrl, type Cluster } from '@solana/web3.js';\nimport type { SolanaNetwork } from '../types';\n\n/** Configuration for Solana client */\nexport interface SolanaClientConfig {\n /** Network to connect to */\n network: SolanaNetwork;\n /** Custom RPC URL (optional) */\n rpcUrl?: string;\n /** Tatum.io API key for RPC (optional) */\n tatumApiKey?: string;\n /** Enable RPC fallback on errors (default: false) */\n enableFallback?: boolean;\n /** Fallback RPC URLs to try on primary failure (optional) */\n fallbackRpcUrls?: string[];\n}\n\n/** RPC connection with fallback support */\nexport interface RpcConnectionWithFallback {\n /** Primary connection */\n connection: Connection;\n /** Fallback connections (if configured) */\n fallbacks: Connection[];\n /** Whether fallback is enabled */\n fallbackEnabled: boolean;\n}\n\n// Singleton state\nlet cachedConnection: Connection | null = null;\nlet cachedNetwork: SolanaNetwork | null = null;\nlet cachedFallbacks: Connection[] = [];\nlet cachedFallbackEnabled = false;\n\n/**\n * Build RPC URL based on configuration priority:\n * 1. Custom RPC URL\n * 2. Tatum.io with API key\n * 3. Public RPC (rate limited)\n */\nfunction buildRpcUrl(config: SolanaClientConfig): string {\n const { network, rpcUrl, tatumApiKey } = config;\n\n if (rpcUrl) {\n // If Tatum URL without key, append key if available\n if (rpcUrl.includes('tatum.io') && tatumApiKey && !rpcUrl.includes(tatumApiKey)) {\n return rpcUrl.endsWith('/') ? `${rpcUrl}${tatumApiKey}` : `${rpcUrl}/${tatumApiKey}`;\n }\n return rpcUrl;\n }\n\n if (tatumApiKey) {\n const baseUrl = network === 'mainnet-beta'\n ? 'https://solana-mainnet.gateway.tatum.io'\n : 'https://solana-devnet.gateway.tatum.io';\n return `${baseUrl}/${tatumApiKey}`;\n }\n\n // Fallback to public RPC\n return clusterApiUrl(network as Cluster);\n}\n\n/**\n * Create a connection with specified options\n */\nfunction createConnection(rpcUrl: string): Connection {\n return new Connection(rpcUrl, {\n commitment: 'confirmed',\n confirmTransactionInitialTimeout: 60000,\n });\n}\n\n/**\n * Get or create a Solana connection\n * Uses singleton pattern with network-aware caching\n */\nexport function getConnection(config: SolanaClientConfig): Connection {\n const { network } = config;\n\n // Return cached if same network\n if (cachedConnection && cachedNetwork === network) {\n return cachedConnection;\n }\n\n const rpcUrl = buildRpcUrl(config);\n cachedConnection = createConnection(rpcUrl);\n cachedNetwork = network;\n\n // Setup fallbacks if enabled\n cachedFallbackEnabled = config.enableFallback ?? false;\n cachedFallbacks = [];\n\n if (cachedFallbackEnabled && config.fallbackRpcUrls?.length) {\n cachedFallbacks = config.fallbackRpcUrls.map(createConnection);\n }\n\n return cachedConnection;\n}\n\n/**\n * Get connection with fallback support\n * Returns both primary and fallback connections for manual failover\n */\nexport function getConnectionWithFallback(config: SolanaClientConfig): RpcConnectionWithFallback {\n const connection = getConnection(config);\n return {\n connection,\n fallbacks: cachedFallbacks,\n fallbackEnabled: cachedFallbackEnabled,\n };\n}\n\n/**\n * Execute an RPC call with automatic fallback on failure\n * Only used when fallback is enabled in config\n * \n * @example\n * ```typescript\n * const balance = await withFallback(\n * config,\n * (conn) => conn.getBalance(publicKey)\n * );\n * ```\n */\nexport async function withFallback<T>(\n config: SolanaClientConfig,\n operation: (connection: Connection) => Promise<T>\n): Promise<T> {\n const { connection, fallbacks, fallbackEnabled } = getConnectionWithFallback(config);\n\n try {\n return await operation(connection);\n } catch (error) {\n if (!fallbackEnabled || fallbacks.length === 0) {\n throw error;\n }\n\n // Check if error is retryable (network errors, rate limits)\n if (!isRetryableError(error)) {\n throw error;\n }\n\n // Try fallbacks in order\n for (let i = 0; i < fallbacks.length; i++) {\n try {\n return await operation(fallbacks[i]);\n } catch (fallbackError) {\n // If last fallback, throw the error\n if (i === fallbacks.length - 1) {\n throw fallbackError;\n }\n // Otherwise continue to next fallback\n }\n }\n\n // Should never reach here, but TypeScript needs this\n throw error;\n }\n}\n\n/**\n * Check if an error is retryable (network issues, rate limits)\n */\nfunction isRetryableError(error: unknown): boolean {\n if (error instanceof Error) {\n const message = error.message.toLowerCase();\n return (\n message.includes('429') ||\n message.includes('503') ||\n message.includes('502') ||\n message.includes('timeout') ||\n message.includes('econnrefused') ||\n message.includes('enotfound') ||\n message.includes('rate limit')\n );\n }\n return false;\n}\n\n/**\n * Reset the cached connection\n * Useful for testing or network switching\n */\nexport function resetConnection(): void {\n cachedConnection = null;\n cachedNetwork = null;\n}\n\n/**\n * Check if network is mainnet\n */\nexport function isMainnet(network: SolanaNetwork): boolean {\n return network === 'mainnet-beta';\n}\n\n/**\n * Convert Solana network to x402 network identifier\n */\nexport function toX402Network(network: SolanaNetwork): 'solana-devnet' | 'solana-mainnet' {\n return network === 'mainnet-beta' ? 'solana-mainnet' : 'solana-devnet';\n}\n","// Transaction verification for SOL payments\n// SECURITY: On-chain verification, signature validation, replay protection\nimport { PublicKey, LAMPORTS_PER_SOL, type ParsedTransactionWithMeta } from '@solana/web3.js';\nimport { getConnection, type SolanaClientConfig } from './client';\nimport type { SignatureStore } from '../store';\n\n/** Result of transaction verification */\nexport interface TransactionVerificationResult {\n /** Whether the transaction is valid for the payment */\n valid: boolean;\n /** Whether the transaction is confirmed on-chain */\n confirmed: boolean;\n /** Transaction signature */\n signature: string;\n /** Sender wallet address */\n from?: string;\n /** Recipient wallet address */\n to?: string;\n /** Amount transferred in lamports */\n amount?: bigint;\n /** Block time (Unix timestamp) */\n blockTime?: number;\n /** Slot number */\n slot?: number;\n /** Error message if verification failed */\n error?: string;\n}\n\n/** Parameters for verifying a payment */\nexport interface VerifyPaymentParams {\n /** Transaction signature to verify */\n signature: string;\n /** Expected recipient wallet address */\n expectedRecipient: string;\n /** Expected amount in lamports */\n expectedAmount: bigint;\n /** Maximum age of transaction in seconds (default: 300) */\n maxAgeSeconds?: number;\n /** Optional signature store for anti-replay protection */\n signatureStore?: SignatureStore;\n /** Solana client configuration */\n clientConfig: SolanaClientConfig;\n}\n\n// Signature validation regex (base58, 87-88 chars)\nconst SIGNATURE_REGEX = /^[1-9A-HJ-NP-Za-km-z]{87,88}$/;\n\n// Wallet address validation regex\nconst WALLET_REGEX = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;\n\n/**\n * Validate transaction signature format\n * SECURITY: Prevents malformed signatures from reaching RPC\n */\nfunction isValidSignature(signature: string): boolean {\n if (!signature || typeof signature !== 'string') return false;\n return SIGNATURE_REGEX.test(signature);\n}\n\n/**\n * Validate wallet address format\n * SECURITY: Ensures valid base58 address\n */\nfunction isValidWalletAddress(address: string): boolean {\n if (!address || typeof address !== 'string') return false;\n return WALLET_REGEX.test(address);\n}\n\n/**\n * Parse SOL transfer details from a transaction\n */\nfunction parseSOLTransfer(\n transaction: ParsedTransactionWithMeta,\n expectedRecipient: string\n): { from: string; to: string; amount: bigint } | null {\n const instructions = transaction.transaction.message.instructions;\n\n // Check main instructions\n for (const ix of instructions) {\n if ('parsed' in ix && ix.program === 'system') {\n const parsed = ix.parsed as {\n type: string;\n info: { source: string; destination: string; lamports: number }\n };\n\n if (parsed.type === 'transfer' && parsed.info.destination === expectedRecipient) {\n return {\n from: parsed.info.source,\n to: parsed.info.destination,\n amount: BigInt(parsed.info.lamports),\n };\n }\n }\n }\n\n // Check inner instructions\n if (transaction.meta?.innerInstructions) {\n for (const inner of transaction.meta.innerInstructions) {\n for (const ix of inner.instructions) {\n if ('parsed' in ix && ix.program === 'system') {\n const parsed = ix.parsed as {\n type: string;\n info: { source: string; destination: string; lamports: number }\n };\n\n if (parsed.type === 'transfer' && parsed.info.destination === expectedRecipient) {\n return {\n from: parsed.info.source,\n to: parsed.info.destination,\n amount: BigInt(parsed.info.lamports),\n };\n }\n }\n }\n }\n }\n\n return null;\n}\n\n/**\n * Verify a SOL transfer transaction\n * SECURITY: Full on-chain verification with amount/recipient/age checks\n */\nexport async function verifyPayment(\n params: VerifyPaymentParams\n): Promise<TransactionVerificationResult> {\n const {\n signature,\n expectedRecipient,\n expectedAmount,\n maxAgeSeconds = 300,\n clientConfig,\n signatureStore,\n } = params;\n\n // SECURITY: Validate signature format before RPC call\n if (!isValidSignature(signature)) {\n return { valid: false, confirmed: false, signature, error: 'Invalid signature format' };\n }\n\n // SECURITY: Validate recipient address format\n if (!isValidWalletAddress(expectedRecipient)) {\n return { valid: false, confirmed: false, signature, error: 'Invalid recipient address' };\n }\n\n // SECURITY: Validate expected amount is positive\n if (expectedAmount <= 0n) {\n return { valid: false, confirmed: false, signature, error: 'Invalid expected amount' };\n }\n\n // SECURITY: Enforce reasonable max age (prevent replay with very old transactions)\n // Check local signature store (if provided)\n if (signatureStore) {\n const isUsed = await signatureStore.hasBeenUsed(signature);\n if (isUsed) {\n return { valid: false, confirmed: true, signature, error: 'Signature already used' };\n }\n }\n\n const effectiveMaxAge = Math.min(Math.max(maxAgeSeconds, 60), 3600); // 1 min to 1 hour\n\n const connection = getConnection(clientConfig);\n\n try {\n const transaction = await connection.getParsedTransaction(signature, {\n commitment: 'confirmed',\n maxSupportedTransactionVersion: 0,\n });\n\n if (!transaction) {\n return { valid: false, confirmed: false, signature, error: 'Transaction not found' };\n }\n\n // Check for transaction errors\n if (transaction.meta?.err) {\n return {\n valid: false,\n confirmed: true,\n signature,\n error: 'Transaction failed on-chain',\n };\n }\n\n // SECURITY: Validate transaction age (replay protection)\n if (transaction.blockTime) {\n const now = Math.floor(Date.now() / 1000);\n if (now - transaction.blockTime > effectiveMaxAge) {\n return { valid: false, confirmed: true, signature, error: 'Transaction too old' };\n }\n // Also reject future-dated transactions (clock skew attack)\n if (transaction.blockTime > now + 60) {\n return { valid: false, confirmed: true, signature, error: 'Invalid transaction time' };\n }\n }\n\n // Parse transfer details\n const transferDetails = parseSOLTransfer(transaction, expectedRecipient);\n\n if (!transferDetails) {\n return {\n valid: false,\n confirmed: true,\n signature,\n error: 'No valid SOL transfer to recipient found',\n };\n }\n\n // SECURITY: Validate amount (must meet or exceed expected)\n if (transferDetails.amount < expectedAmount) {\n return {\n valid: false,\n confirmed: true,\n signature,\n from: transferDetails.from,\n to: transferDetails.to,\n amount: transferDetails.amount,\n error: 'Insufficient payment amount',\n };\n }\n\n return {\n valid: true,\n confirmed: true,\n signature,\n from: transferDetails.from,\n to: transferDetails.to,\n amount: transferDetails.amount,\n blockTime: transaction.blockTime ?? undefined,\n slot: transaction.slot,\n };\n } catch (error) {\n // SECURITY: Don't expose internal error details\n return {\n valid: false,\n confirmed: false,\n signature,\n error: 'Verification failed',\n };\n }\n}\n\n/**\n * Wait for transaction confirmation\n */\nexport async function waitForConfirmation(\n signature: string,\n clientConfig: SolanaClientConfig\n): Promise<{ confirmed: boolean; slot?: number; error?: string }> {\n if (!isValidSignature(signature)) {\n return { confirmed: false, error: 'Invalid signature format' };\n }\n\n const connection = getConnection(clientConfig);\n\n try {\n const confirmation = await connection.confirmTransaction(signature, 'confirmed');\n\n if (confirmation.value.err) {\n return { confirmed: false, error: 'Transaction failed' };\n }\n\n return { confirmed: true, slot: confirmation.context?.slot };\n } catch {\n return { confirmed: false, error: 'Confirmation timeout' };\n }\n}\n\n/**\n * Get recent transactions for a wallet\n */\nexport async function getWalletTransactions(\n walletAddress: string,\n clientConfig: SolanaClientConfig,\n limit: number = 20\n): Promise<Array<{ signature: string; blockTime?: number; slot: number }>> {\n if (!isValidWalletAddress(walletAddress)) {\n return [];\n }\n\n // SECURITY: Cap limit to prevent abuse\n const safeLimit = Math.min(Math.max(limit, 1), 100);\n\n const connection = getConnection(clientConfig);\n\n try {\n const pubkey = new PublicKey(walletAddress);\n const signatures = await connection.getSignaturesForAddress(pubkey, { limit: safeLimit });\n return signatures.map((sig) => ({\n signature: sig.signature,\n blockTime: sig.blockTime ?? undefined,\n slot: sig.slot,\n }));\n } catch {\n return [];\n }\n}\n\n/**\n * Convert lamports to SOL\n */\nexport function lamportsToSol(lamports: bigint | number): number {\n return Number(lamports) / LAMPORTS_PER_SOL;\n}\n\n/**\n * Convert SOL to lamports\n */\nexport function solToLamports(sol: number): bigint {\n if (!Number.isFinite(sol) || sol < 0) {\n throw new Error('Invalid SOL amount');\n }\n return BigInt(Math.floor(sol * LAMPORTS_PER_SOL));\n}\n","// Payment-related TypeScript types for x402 protocol\n\n/** x402 network identifiers for Solana */\nexport type X402Network = 'solana-devnet' | 'solana-mainnet';\n\n/** Solana network types */\nexport type SolanaNetwork = 'devnet' | 'mainnet-beta';\n\n/** SPL Token asset specification */\nexport interface SPLTokenAsset {\n /** Token mint address */\n mint: string;\n /** Token decimals (default: 6 for USDC/USDT) */\n decimals?: number;\n}\n\n/** Asset types for payments */\nexport type PaymentAsset = 'native' | 'usdc' | 'usdt' | SPLTokenAsset;\n\n/** Known SPL token mint addresses */\nexport const TOKEN_MINTS = {\n /** USDC on mainnet */\n USDC_MAINNET: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',\n /** USDC on devnet */\n USDC_DEVNET: '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU',\n /** USDT on mainnet */\n USDT_MAINNET: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',\n} as const;\n\n/** Payment requirement for x402 protocol */\nexport interface PaymentRequirement {\n /** Payment scheme - currently only 'exact' is supported */\n scheme: 'exact';\n /** Network identifier for x402 */\n network: X402Network;\n /** Amount in smallest unit as string (lamports for SOL, base units for tokens) */\n maxAmountRequired: string;\n /** URL of the protected resource */\n resource: string;\n /** Human-readable description */\n description: string;\n /** MIME type of the resource */\n mimeType?: string;\n /** Recipient wallet address */\n payTo: string;\n /** Maximum time in seconds to complete payment */\n maxTimeoutSeconds: number;\n /** Asset type - 'native' for SOL, 'usdc', 'usdt', or custom mint */\n asset: PaymentAsset;\n /** Additional metadata */\n extra?: {\n name?: string;\n articleId?: string;\n [key: string]: unknown;\n };\n}\n\n/** Payment payload sent by client after transaction */\nexport interface PaymentPayload {\n /** x402 protocol version */\n x402Version: number;\n /** Payment scheme */\n scheme: 'exact';\n /** Network identifier */\n network: X402Network;\n /** Transaction details */\n payload: {\n /** Transaction signature (base58) */\n signature: string;\n /** Base64 encoded transaction (optional) */\n transaction?: string;\n };\n}\n\n/** Request to verify a payment */\nexport interface VerificationRequest {\n paymentPayload: PaymentPayload;\n paymentRequirements: PaymentRequirement;\n}\n\n/** Response from payment verification */\nexport interface VerificationResponse {\n /** Whether the payment is valid */\n valid: boolean;\n /** Reason for invalid payment */\n invalidReason?: string;\n /** Whether the transaction is settled on-chain */\n settled?: boolean;\n /** Sender wallet address (payer) */\n from?: string;\n /** Transaction details */\n transaction?: {\n signature: string;\n blockTime?: number;\n slot?: number;\n };\n}\n\n/** Payment status for tracking */\nexport interface PaymentStatus {\n status: 'pending' | 'confirmed' | 'failed' | 'expired';\n signature?: string;\n confirmations?: number;\n error?: string;\n}\n\n/** x402 HTTP header constants */\nexport const X402_HEADERS = {\n PAYMENT_REQUIRED: 'x-payment-required',\n PAYMENT: 'x-payment',\n PAYMENT_RESPONSE: 'x-payment-response',\n} as const;\n\n/** Configuration for article pricing */\nexport interface ArticlePaymentConfig {\n articleId: string;\n priceInLamports: bigint;\n title: string;\n description?: string;\n}\n","// SPL Token payment verification\n// SECURITY: On-chain verification for SPL token transfers (USDC, USDT, custom)\nimport { type ParsedTransactionWithMeta, PublicKey } from '@solana/web3.js';\nimport { getConnection, type SolanaClientConfig } from './client';\nimport { TOKEN_MINTS, type PaymentAsset } from '../types';\nimport type { SignatureStore } from '../store';\n\n/** Result of SPL token transfer verification */\nexport interface SPLVerificationResult {\n /** Whether the transfer is valid */\n valid: boolean;\n /** Whether transaction is confirmed */\n confirmed: boolean;\n /** Transaction signature */\n signature: string;\n /** Sender wallet address */\n from?: string;\n /** Recipient wallet address */\n to?: string;\n /** Token mint address */\n mint?: string;\n /** Amount transferred (in token's smallest unit) */\n amount?: bigint;\n /** Block time */\n blockTime?: number;\n /** Slot number */\n slot?: number;\n /** Error message */\n error?: string;\n}\n\n/** Parameters for SPL payment verification */\nexport interface VerifySPLPaymentParams {\n /** Transaction signature */\n signature: string;\n /** Expected recipient wallet */\n expectedRecipient: string;\n /** Expected amount in token's smallest unit */\n expectedAmount: bigint;\n /** Asset specification */\n asset: PaymentAsset;\n /** Solana network config */\n clientConfig: SolanaClientConfig;\n /** Maximum transaction age in seconds */\n maxAgeSeconds?: number;\n /** Optional signature store for anti-replay protection */\n signatureStore?: SignatureStore;\n}\n\n// Signature validation regex\nconst SIGNATURE_REGEX = /^[1-9A-HJ-NP-Za-km-z]{87,88}$/;\nconst WALLET_REGEX = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;\n\n/**\n * Resolve asset to mint address\n */\nexport function resolveMintAddress(asset: PaymentAsset, network: 'devnet' | 'mainnet-beta'): string | null {\n if (asset === 'native') return null;\n\n if (asset === 'usdc') {\n return network === 'mainnet-beta' ? TOKEN_MINTS.USDC_MAINNET : TOKEN_MINTS.USDC_DEVNET;\n }\n\n if (asset === 'usdt') {\n return TOKEN_MINTS.USDT_MAINNET; // USDT only on mainnet\n }\n\n if (typeof asset === 'object' && 'mint' in asset) {\n return asset.mint;\n }\n\n return null;\n}\n\n/**\n * Get token decimals for an asset\n */\nexport function getTokenDecimals(asset: PaymentAsset): number {\n if (asset === 'native') return 9; // SOL\n if (asset === 'usdc' || asset === 'usdt') return 6;\n if (typeof asset === 'object' && 'decimals' in asset) {\n return asset.decimals ?? 6;\n }\n return 6; // Default for SPL tokens\n}\n\n/**\n * Parse SPL token transfer from transaction\n * Handles Token Program transfers to the expected recipient\n */\nfunction parseSPLTransfer(\n transaction: ParsedTransactionWithMeta,\n expectedRecipient: string,\n expectedMint: string\n): { from: string; to: string; amount: bigint; mint: string } | null {\n const instructions = transaction.transaction.message.instructions;\n\n // Check main instructions for Token Program transfers\n for (const ix of instructions) {\n if ('parsed' in ix && (ix.program === 'spl-token' || ix.program === 'spl-token-2022')) {\n const parsed = ix.parsed as {\n type: string;\n info: {\n source?: string;\n destination?: string;\n authority?: string;\n amount?: string;\n tokenAmount?: { amount: string; decimals: number };\n mint?: string;\n };\n };\n\n // Handle 'transfer' and 'transferChecked' instructions\n if (parsed.type === 'transfer' || parsed.type === 'transferChecked') {\n const amount = parsed.info.amount || parsed.info.tokenAmount?.amount;\n\n if (amount && parsed.info.destination) {\n // We need to resolve the token account to the owner wallet\n // For now, accept if destination matches expected recipient's token account\n return {\n from: parsed.info.authority || parsed.info.source || '',\n to: parsed.info.destination,\n amount: BigInt(amount),\n mint: parsed.info.mint || expectedMint,\n };\n }\n }\n }\n }\n\n // Check inner instructions\n if (transaction.meta?.innerInstructions) {\n for (const inner of transaction.meta.innerInstructions) {\n for (const ix of inner.instructions) {\n if ('parsed' in ix && (ix.program === 'spl-token' || ix.program === 'spl-token-2022')) {\n const parsed = ix.parsed as {\n type: string;\n info: {\n source?: string;\n destination?: string;\n authority?: string;\n amount?: string;\n tokenAmount?: { amount: string };\n mint?: string;\n };\n };\n\n if (parsed.type === 'transfer' || parsed.type === 'transferChecked') {\n const amount = parsed.info.amount || parsed.info.tokenAmount?.amount;\n if (amount) {\n return {\n from: parsed.info.authority || parsed.info.source || '',\n to: parsed.info.destination || '',\n amount: BigInt(amount),\n mint: parsed.info.mint || expectedMint,\n };\n }\n }\n }\n }\n }\n }\n\n // Check post token balances for transfers\n if (transaction.meta?.postTokenBalances && transaction.meta?.preTokenBalances) {\n const preBalances = transaction.meta.preTokenBalances;\n const postBalances = transaction.meta.postTokenBalances;\n\n for (const post of postBalances) {\n if (post.mint === expectedMint && post.owner === expectedRecipient) {\n const pre = preBalances.find(\n (p) => p.accountIndex === post.accountIndex\n );\n const preAmount = BigInt(pre?.uiTokenAmount?.amount || '0');\n const postAmount = BigInt(post.uiTokenAmount?.amount || '0');\n const transferred = postAmount - preAmount;\n\n if (transferred > 0n) {\n return {\n from: '', // Can't determine from balance changes\n to: expectedRecipient,\n amount: transferred,\n mint: expectedMint,\n };\n }\n }\n }\n }\n\n return null;\n}\n\n/**\n * Verify an SPL token transfer\n * SECURITY: Full on-chain verification with amount/recipient/mint checks\n */\nexport async function verifySPLPayment(\n params: VerifySPLPaymentParams\n): Promise<SPLVerificationResult> {\n const {\n signature,\n expectedRecipient,\n expectedAmount,\n asset,\n clientConfig,\n maxAgeSeconds = 300,\n signatureStore,\n } = params;\n\n // Check local signature store (if provided)\n if (signatureStore) {\n const isUsed = await signatureStore.hasBeenUsed(signature);\n if (isUsed) {\n return { valid: false, confirmed: true, signature, error: 'Signature already used' };\n }\n }\n\n // Validate signature format\n if (!SIGNATURE_REGEX.test(signature)) {\n return { valid: false, confirmed: false, signature, error: 'Invalid signature format' };\n }\n\n // Validate recipient\n if (!WALLET_REGEX.test(expectedRecipient)) {\n return { valid: false, confirmed: false, signature, error: 'Invalid recipient address' };\n }\n\n // Resolve mint address\n const mintAddress = resolveMintAddress(asset, clientConfig.network);\n if (!mintAddress) {\n return { valid: false, confirmed: false, signature, error: 'Invalid asset configuration' };\n }\n\n // Validate amount\n if (expectedAmount <= 0n) {\n return { valid: false, confirmed: false, signature, error: 'Invalid expected amount' };\n }\n\n const effectiveMaxAge = Math.min(Math.max(maxAgeSeconds, 60), 3600);\n const connection = getConnection(clientConfig);\n\n try {\n const transaction = await connection.getParsedTransaction(signature, {\n commitment: 'confirmed',\n maxSupportedTransactionVersion: 0,\n });\n\n if (!transaction) {\n return { valid: false, confirmed: false, signature, error: 'Transaction not found' };\n }\n\n if (transaction.meta?.err) {\n return { valid: false, confirmed: true, signature, error: 'Transaction failed on-chain' };\n }\n\n // Validate age\n if (transaction.blockTime) {\n const now = Math.floor(Date.now() / 1000);\n if (now - transaction.blockTime > effectiveMaxAge) {\n return { valid: false, confirmed: true, signature, error: 'Transaction too old' };\n }\n if (transaction.blockTime > now + 60) {\n return { valid: false, confirmed: true, signature, error: 'Invalid transaction time' };\n }\n }\n\n // Parse transfer\n const transfer = parseSPLTransfer(transaction, expectedRecipient, mintAddress);\n if (!transfer) {\n return {\n valid: false,\n confirmed: true,\n signature,\n error: 'No valid token transfer to recipient found',\n };\n }\n\n // SECURITY: Verify token account owner (Critical fix for spoofing)\n // Ensure tokens were sent to an account OWNED by expectedRecipient\n if (transfer.to) {\n try {\n // If we found the transfer via postTokenBalances, we might already know the owner\n // But parseSPLTransfer doesn't return that info explicitly, so we verify strictly via RPC\n // unless it was a direct transfer to wallet (rare for tokens)\n\n // Note: Only perform this check if we fell back to instruction parsing\n // or just always do it to be safe 100%. \n // Optimization: We could return 'verifiedOwner' from parseSPLTransfer if found in balances.\n\n const destinationInfo = await connection.getParsedAccountInfo(new PublicKey(transfer.to));\n const owner = (destinationInfo.value?.data as any)?.parsed?.info?.owner;\n\n if (owner && owner !== expectedRecipient) {\n return {\n valid: false,\n confirmed: true,\n signature,\n error: 'Recipient mismatch: Token account not owned by merchant'\n };\n }\n } catch (e) {\n // Fail secure if we can't verify ownership\n return {\n valid: false,\n confirmed: true,\n signature,\n error: 'Could not verify token account owner'\n };\n }\n }\n\n // Validate mint matches\n if (transfer.mint !== mintAddress) {\n return {\n valid: false,\n confirmed: true,\n signature,\n error: 'Token mint mismatch',\n };\n }\n\n // Validate amount\n if (transfer.amount < expectedAmount) {\n return {\n valid: false,\n confirmed: true,\n signature,\n from: transfer.from,\n to: transfer.to,\n mint: transfer.mint,\n amount: transfer.amount,\n error: 'Insufficient payment amount',\n };\n }\n\n return {\n valid: true,\n confirmed: true,\n signature,\n from: transfer.from,\n to: transfer.to,\n mint: transfer.mint,\n amount: transfer.amount,\n blockTime: transaction.blockTime ?? undefined,\n slot: transaction.slot,\n };\n } catch {\n return { valid: false, confirmed: false, signature, error: 'Verification failed' };\n }\n}\n\n/**\n * Check if asset is native SOL\n */\nexport function isNativeAsset(asset: PaymentAsset): asset is 'native' {\n return asset === 'native';\n}\n","// Priority Fee Utilities for Solana Transactions\n// Adds compute budget instructions for landing transactions faster\n\nimport {\n ComputeBudgetProgram,\n type Connection,\n type PublicKey,\n type TransactionInstruction,\n} from '@solana/web3.js';\n\n/** Configuration for priority fees */\nexport interface PriorityFeeConfig {\n /** Enable priority fees (default: false) */\n enabled?: boolean;\n /** Price per compute unit in micro-lamports (default: auto-estimate) */\n microLamports?: number;\n /** Maximum compute units for transaction (default: 200_000) */\n computeUnits?: number;\n}\n\n/** Default priority fee settings */\nconst DEFAULT_COMPUTE_UNITS = 200_000;\nconst DEFAULT_MICRO_LAMPORTS = 1_000; // 0.001 lamports per CU\n\n/**\n * Create compute budget instructions for priority fees\n * \n * @example\n * ```typescript\n * const priorityIxs = createPriorityFeeInstructions({\n * enabled: true,\n * microLamports: 5000,\n * computeUnits: 150_000,\n * });\n * \n * // Add to transaction\n * transaction.add(...priorityIxs, ...yourInstructions);\n * ```\n */\nexport function createPriorityFeeInstructions(\n config: PriorityFeeConfig = {}\n): TransactionInstruction[] {\n const { enabled = false, microLamports, computeUnits } = config;\n\n if (!enabled) {\n return [];\n }\n\n const instructions: TransactionInstruction[] = [];\n\n // Set compute unit limit\n const units = computeUnits ?? DEFAULT_COMPUTE_UNITS;\n instructions.push(ComputeBudgetProgram.setComputeUnitLimit({ units }));\n\n // Set compute unit price\n const price = microLamports ?? DEFAULT_MICRO_LAMPORTS;\n instructions.push(ComputeBudgetProgram.setComputeUnitPrice({ microLamports: price }));\n\n return instructions;\n}\n\n/**\n * Estimate priority fee based on recent network activity\n * Returns micro-lamports per compute unit\n * \n * @example\n * ```typescript\n * const fee = await estimatePriorityFee(connection, [recipientPubkey]);\n * console.log(`Recommended fee: ${fee} micro-lamports/CU`);\n * ```\n */\nexport async function estimatePriorityFee(\n connection: Connection,\n accounts: PublicKey[] = []\n): Promise<number> {\n try {\n const fees = await connection.getRecentPrioritizationFees({\n lockedWritableAccounts: accounts,\n });\n\n if (fees.length === 0) {\n return DEFAULT_MICRO_LAMPORTS;\n }\n\n // Get median of recent fees (more stable than mean)\n const sortedFees = fees\n .map((f) => f.prioritizationFee)\n .filter((f) => f > 0)\n .sort((a, b) => a - b);\n\n if (sortedFees.length === 0) {\n return DEFAULT_MICRO_LAMPORTS;\n }\n\n const medianIndex = Math.floor(sortedFees.length / 2);\n return sortedFees[medianIndex];\n } catch {\n // Fallback on RPC errors\n return DEFAULT_MICRO_LAMPORTS;\n }\n}\n\n/**\n * Calculate total priority fee cost in lamports\n * \n * @example\n * ```typescript\n * const cost = calculatePriorityFeeCost(5000, 200_000);\n * console.log(`Priority fee: ${cost} lamports`);\n * ```\n */\nexport function calculatePriorityFeeCost(\n microLamportsPerCU: number,\n computeUnits: number\n): number {\n return Math.ceil((microLamportsPerCU * computeUnits) / 1_000_000);\n}\n","// Versioned Transaction Support\n// Utilities for building and working with versioned transactions\n\nimport {\n TransactionMessage,\n VersionedTransaction,\n type AddressLookupTableAccount,\n type Connection,\n type PublicKey,\n type TransactionInstruction,\n} from '@solana/web3.js';\nimport { createPriorityFeeInstructions, type PriorityFeeConfig } from './priority-fees';\n\n/** Configuration for building versioned transactions */\nexport interface VersionedTransactionConfig {\n /** Solana connection */\n connection: Connection;\n /** Fee payer public key */\n payer: PublicKey;\n /** Transaction instructions */\n instructions: TransactionInstruction[];\n /** Address lookup tables for compression (optional) */\n lookupTables?: AddressLookupTableAccount[];\n /** Priority fee configuration (optional, default: disabled) */\n priorityFee?: PriorityFeeConfig;\n /** Recent blockhash (optional, will fetch if not provided) */\n recentBlockhash?: string;\n}\n\n/** Result of building a versioned transaction */\nexport interface VersionedTransactionResult {\n /** The built versioned transaction */\n transaction: VersionedTransaction;\n /** The blockhash used */\n blockhash: string;\n /** Last valid block height for the transaction */\n lastValidBlockHeight: number;\n}\n\n/**\n * Build a versioned transaction (v0) with optional priority fees and lookup tables\n * \n * @example\n * ```typescript\n * const { transaction, blockhash, lastValidBlockHeight } = await buildVersionedTransaction({\n * connection,\n * payer: wallet.publicKey,\n * instructions: [transferIx],\n * priorityFee: { enabled: true, microLamports: 5000 },\n * });\n * \n * // Sign and send\n * transaction.sign([wallet]);\n * const sig = await connection.sendTransaction(transaction);\n * ```\n */\nexport async function buildVersionedTransaction(\n config: VersionedTransactionConfig\n): Promise<VersionedTransactionResult> {\n const {\n connection,\n payer,\n instructions,\n lookupTables = [],\n priorityFee,\n recentBlockhash,\n } = config;\n\n // Prepend priority fee instructions if configured\n const priorityIxs = createPriorityFeeInstructions(priorityFee);\n const allInstructions = [...priorityIxs, ...instructions];\n\n // Get recent blockhash if not provided\n let blockhash: string;\n let lastValidBlockHeight: number;\n\n if (recentBlockhash) {\n blockhash = recentBlockhash;\n // Estimate last valid block height (typically ~150 blocks)\n const slot = await connection.getSlot();\n lastValidBlockHeight = slot + 150;\n } else {\n const latestBlockhash = await connection.getLatestBlockhash('confirmed');\n blockhash = latestBlockhash.blockhash;\n lastValidBlockHeight = latestBlockhash.lastValidBlockHeight;\n }\n\n // Build message\n const message = new TransactionMessage({\n payerKey: payer,\n recentBlockhash: blockhash,\n instructions: allInstructions,\n }).compileToV0Message(lookupTables);\n\n // Create versioned transaction\n const transaction = new VersionedTransaction(message);\n\n return {\n transaction,\n blockhash,\n lastValidBlockHeight,\n };\n}\n\n/**\n * Fetch address lookup table accounts\n * \n * @example\n * ```typescript\n * const tables = await fetchLookupTables(connection, [tableAddress1, tableAddress2]);\n * const { transaction } = await buildVersionedTransaction({\n * connection,\n * payer,\n * instructions,\n * lookupTables: tables,\n * });\n * ```\n */\nexport async function fetchLookupTables(\n connection: Connection,\n addresses: PublicKey[]\n): Promise<AddressLookupTableAccount[]> {\n const tables: AddressLookupTableAccount[] = [];\n\n for (const address of addresses) {\n const result = await connection.getAddressLookupTable(address);\n if (result.value) {\n tables.push(result.value);\n }\n }\n\n return tables;\n}\n\n/**\n * Check if a transaction version is supported\n */\nexport function isVersionedTransaction(\n tx: unknown\n): tx is VersionedTransaction {\n return tx instanceof VersionedTransaction;\n}\n"]}
|
package/dist/store/index.cjs
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// src/store/memory.ts
|
|
4
|
-
function createMemoryStore(options = {}) {
|
|
5
|
-
const { cleanupInterval = 6e4 } = options;
|
|
6
|
-
const store = /* @__PURE__ */ new Map();
|
|
7
|
-
const cleanupTimer = setInterval(() => {
|
|
8
|
-
const now = Date.now();
|
|
9
|
-
for (const [key, record] of store.entries()) {
|
|
10
|
-
if (record.expiresAt < now) {
|
|
11
|
-
store.delete(key);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
}, cleanupInterval);
|
|
15
|
-
return {
|
|
16
|
-
async hasBeenUsed(signature) {
|
|
17
|
-
const record = store.get(signature);
|
|
18
|
-
if (!record) return false;
|
|
19
|
-
if (record.expiresAt < Date.now()) {
|
|
20
|
-
store.delete(signature);
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
return true;
|
|
24
|
-
},
|
|
25
|
-
async markAsUsed(signature, resourceId, expiresAt) {
|
|
26
|
-
store.set(signature, {
|
|
27
|
-
resourceId,
|
|
28
|
-
usedAt: Date.now(),
|
|
29
|
-
expiresAt: expiresAt.getTime()
|
|
30
|
-
});
|
|
31
|
-
},
|
|
32
|
-
async getUsage(signature) {
|
|
33
|
-
const record = store.get(signature);
|
|
34
|
-
if (!record) return null;
|
|
35
|
-
if (record.expiresAt < Date.now()) {
|
|
36
|
-
store.delete(signature);
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
return {
|
|
40
|
-
signature,
|
|
41
|
-
resourceId: record.resourceId,
|
|
42
|
-
usedAt: new Date(record.usedAt),
|
|
43
|
-
expiresAt: new Date(record.expiresAt),
|
|
44
|
-
walletAddress: record.walletAddress
|
|
45
|
-
};
|
|
46
|
-
},
|
|
47
|
-
/** Stop cleanup timer (for graceful shutdown) */
|
|
48
|
-
close() {
|
|
49
|
-
clearInterval(cleanupTimer);
|
|
50
|
-
store.clear();
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// src/store/redis.ts
|
|
56
|
-
function createRedisStore(options) {
|
|
57
|
-
const { client, keyPrefix = "micropay:sig:" } = options;
|
|
58
|
-
const buildKey = (signature) => `${keyPrefix}${signature}`;
|
|
59
|
-
return {
|
|
60
|
-
async hasBeenUsed(signature) {
|
|
61
|
-
const exists = await client.exists(buildKey(signature));
|
|
62
|
-
return exists > 0;
|
|
63
|
-
},
|
|
64
|
-
async markAsUsed(signature, resourceId, expiresAt) {
|
|
65
|
-
const key = buildKey(signature);
|
|
66
|
-
const ttl = Math.max(1, Math.floor((expiresAt.getTime() - Date.now()) / 1e3));
|
|
67
|
-
const record = {
|
|
68
|
-
signature,
|
|
69
|
-
resourceId,
|
|
70
|
-
usedAt: /* @__PURE__ */ new Date(),
|
|
71
|
-
expiresAt
|
|
72
|
-
};
|
|
73
|
-
if (client.setex) {
|
|
74
|
-
await client.setex(key, ttl, JSON.stringify(record));
|
|
75
|
-
} else {
|
|
76
|
-
await client.set(key, JSON.stringify(record), { EX: ttl });
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
-
async getUsage(signature) {
|
|
80
|
-
const data = await client.get(buildKey(signature));
|
|
81
|
-
if (!data) return null;
|
|
82
|
-
try {
|
|
83
|
-
const record = JSON.parse(data);
|
|
84
|
-
return {
|
|
85
|
-
...record,
|
|
86
|
-
usedAt: new Date(record.usedAt),
|
|
87
|
-
expiresAt: new Date(record.expiresAt)
|
|
88
|
-
};
|
|
89
|
-
} catch {
|
|
90
|
-
return null;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
exports.createMemoryStore = createMemoryStore;
|
|
97
|
-
exports.createRedisStore = createRedisStore;
|
|
98
|
-
//# sourceMappingURL=index.cjs.map
|
|
99
|
-
//# sourceMappingURL=index.cjs.map
|
package/dist/store/index.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/store/memory.ts","../../src/store/redis.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["// In-Memory Signature Store\n// For development, testing, and single-instance deployments\n\n/** Signature usage record */\nexport interface SignatureUsage {\n signature: string;\n resourceId: string;\n usedAt: Date;\n expiresAt: Date;\n walletAddress?: string;\n}\n\n/** Interface for tracking payment signature usage */\nexport interface SignatureStore {\n hasBeenUsed(signature: string): Promise<boolean>;\n markAsUsed(signature: string, resourceId: string, expiresAt: Date): Promise<void>;\n getUsage?(signature: string): Promise<SignatureUsage | null>;\n}\n\nexport interface MemoryStoreOptions {\n /** Default TTL in seconds */\n defaultTTL?: number;\n /** Cleanup interval in ms (default: 60000) */\n cleanupInterval?: number;\n}\n\ninterface StoredRecord {\n resourceId: string;\n usedAt: number;\n expiresAt: number;\n walletAddress?: string;\n}\n\n/**\n * Create an in-memory signature store\n * ⚠️ Not suitable for multi-instance deployments (use Redis instead)\n */\nexport function createMemoryStore(options: MemoryStoreOptions = {}): SignatureStore & { close: () => void } {\n const { cleanupInterval = 60000 } = options;\n const store = new Map<string, StoredRecord>();\n\n // Periodic cleanup of expired entries\n const cleanupTimer = setInterval(() => {\n const now = Date.now();\n for (const [key, record] of store.entries()) {\n if (record.expiresAt < now) {\n store.delete(key);\n }\n }\n }, cleanupInterval);\n\n return {\n async hasBeenUsed(signature: string): Promise<boolean> {\n const record = store.get(signature);\n if (!record) return false;\n\n // Check if expired\n if (record.expiresAt < Date.now()) {\n store.delete(signature);\n return false;\n }\n\n return true;\n },\n\n async markAsUsed(signature: string, resourceId: string, expiresAt: Date): Promise<void> {\n store.set(signature, {\n resourceId,\n usedAt: Date.now(),\n expiresAt: expiresAt.getTime(),\n });\n },\n\n async getUsage(signature: string): Promise<SignatureUsage | null> {\n const record = store.get(signature);\n if (!record) return null;\n\n // Check expiration\n if (record.expiresAt < Date.now()) {\n store.delete(signature);\n return null;\n }\n\n return {\n signature,\n resourceId: record.resourceId,\n usedAt: new Date(record.usedAt),\n expiresAt: new Date(record.expiresAt),\n walletAddress: record.walletAddress,\n };\n },\n\n /** Stop cleanup timer (for graceful shutdown) */\n close(): void {\n clearInterval(cleanupTimer);\n store.clear();\n },\n };\n}\n","// Redis Signature Store Adapter\n// For production multi-instance deployments\n\nimport type { SignatureStore, SignatureUsage } from './memory';\n\n/**\n * Minimal Redis client interface\n * Compatible with ioredis, redis, and similar clients\n */\nexport interface RedisClient {\n get(key: string): Promise<string | null>;\n set(key: string, value: string, options?: { EX?: number }): Promise<string | null>;\n setex?(key: string, seconds: number, value: string): Promise<string>;\n exists(key: string): Promise<number>;\n del(key: string): Promise<number>;\n}\n\nexport interface RedisStoreOptions {\n /** Redis client instance */\n client: RedisClient;\n /** Key prefix */\n keyPrefix?: string;\n /** Default TTL in seconds */\n defaultTTL?: number;\n}\n\n/**\n * Create a Redis-backed signature store\n * Production-ready for distributed deployments\n */\nexport function createRedisStore(options: RedisStoreOptions): SignatureStore {\n const { client, keyPrefix = 'micropay:sig:' } = options;\n\n const buildKey = (signature: string) => `${keyPrefix}${signature}`;\n\n return {\n async hasBeenUsed(signature: string): Promise<boolean> {\n const exists = await client.exists(buildKey(signature));\n return exists > 0;\n },\n\n async markAsUsed(signature: string, resourceId: string, expiresAt: Date): Promise<void> {\n const key = buildKey(signature);\n const ttl = Math.max(1, Math.floor((expiresAt.getTime() - Date.now()) / 1000));\n\n const record: SignatureUsage = {\n signature,\n resourceId,\n usedAt: new Date(),\n expiresAt,\n };\n\n // Support both `setex` (ioredis) and `set` with EX (node-redis)\n if (client.setex) {\n await client.setex(key, ttl, JSON.stringify(record));\n } else {\n await client.set(key, JSON.stringify(record), { EX: ttl });\n }\n },\n\n async getUsage(signature: string): Promise<SignatureUsage | null> {\n const data = await client.get(buildKey(signature));\n if (!data) return null;\n\n try {\n const record = JSON.parse(data) as SignatureUsage;\n // Convert date strings back to Date objects\n return {\n ...record,\n usedAt: new Date(record.usedAt),\n expiresAt: new Date(record.expiresAt),\n };\n } catch {\n return null;\n }\n },\n };\n}\n"]}
|
package/dist/store/index.d.cts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { S as SignatureStore } from '../memory-Daxkczti.cjs';
|
|
2
|
-
export { M as MemoryStoreOptions, a as SignatureUsage, c as createMemoryStore } from '../memory-Daxkczti.cjs';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Minimal Redis client interface
|
|
6
|
-
* Compatible with ioredis, redis, and similar clients
|
|
7
|
-
*/
|
|
8
|
-
interface RedisClient {
|
|
9
|
-
get(key: string): Promise<string | null>;
|
|
10
|
-
set(key: string, value: string, options?: {
|
|
11
|
-
EX?: number;
|
|
12
|
-
}): Promise<string | null>;
|
|
13
|
-
setex?(key: string, seconds: number, value: string): Promise<string>;
|
|
14
|
-
exists(key: string): Promise<number>;
|
|
15
|
-
del(key: string): Promise<number>;
|
|
16
|
-
}
|
|
17
|
-
interface RedisStoreOptions {
|
|
18
|
-
/** Redis client instance */
|
|
19
|
-
client: RedisClient;
|
|
20
|
-
/** Key prefix */
|
|
21
|
-
keyPrefix?: string;
|
|
22
|
-
/** Default TTL in seconds */
|
|
23
|
-
defaultTTL?: number;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Create a Redis-backed signature store
|
|
27
|
-
* Production-ready for distributed deployments
|
|
28
|
-
*/
|
|
29
|
-
declare function createRedisStore(options: RedisStoreOptions): SignatureStore;
|
|
30
|
-
|
|
31
|
-
interface StoreConfig {
|
|
32
|
-
/** Default TTL in seconds for signature records */
|
|
33
|
-
defaultTTL?: number;
|
|
34
|
-
/** Prefix for keys (useful for Redis) */
|
|
35
|
-
keyPrefix?: string;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export { type RedisClient, type RedisStoreOptions, SignatureStore, type StoreConfig, createRedisStore };
|
package/dist/store/index.d.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { S as SignatureStore } from '../memory-Daxkczti.js';
|
|
2
|
-
export { M as MemoryStoreOptions, a as SignatureUsage, c as createMemoryStore } from '../memory-Daxkczti.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Minimal Redis client interface
|
|
6
|
-
* Compatible with ioredis, redis, and similar clients
|
|
7
|
-
*/
|
|
8
|
-
interface RedisClient {
|
|
9
|
-
get(key: string): Promise<string | null>;
|
|
10
|
-
set(key: string, value: string, options?: {
|
|
11
|
-
EX?: number;
|
|
12
|
-
}): Promise<string | null>;
|
|
13
|
-
setex?(key: string, seconds: number, value: string): Promise<string>;
|
|
14
|
-
exists(key: string): Promise<number>;
|
|
15
|
-
del(key: string): Promise<number>;
|
|
16
|
-
}
|
|
17
|
-
interface RedisStoreOptions {
|
|
18
|
-
/** Redis client instance */
|
|
19
|
-
client: RedisClient;
|
|
20
|
-
/** Key prefix */
|
|
21
|
-
keyPrefix?: string;
|
|
22
|
-
/** Default TTL in seconds */
|
|
23
|
-
defaultTTL?: number;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Create a Redis-backed signature store
|
|
27
|
-
* Production-ready for distributed deployments
|
|
28
|
-
*/
|
|
29
|
-
declare function createRedisStore(options: RedisStoreOptions): SignatureStore;
|
|
30
|
-
|
|
31
|
-
interface StoreConfig {
|
|
32
|
-
/** Default TTL in seconds for signature records */
|
|
33
|
-
defaultTTL?: number;
|
|
34
|
-
/** Prefix for keys (useful for Redis) */
|
|
35
|
-
keyPrefix?: string;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export { type RedisClient, type RedisStoreOptions, SignatureStore, type StoreConfig, createRedisStore };
|
package/dist/store/index.js
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
// src/store/memory.ts
|
|
2
|
-
function createMemoryStore(options = {}) {
|
|
3
|
-
const { cleanupInterval = 6e4 } = options;
|
|
4
|
-
const store = /* @__PURE__ */ new Map();
|
|
5
|
-
const cleanupTimer = setInterval(() => {
|
|
6
|
-
const now = Date.now();
|
|
7
|
-
for (const [key, record] of store.entries()) {
|
|
8
|
-
if (record.expiresAt < now) {
|
|
9
|
-
store.delete(key);
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
}, cleanupInterval);
|
|
13
|
-
return {
|
|
14
|
-
async hasBeenUsed(signature) {
|
|
15
|
-
const record = store.get(signature);
|
|
16
|
-
if (!record) return false;
|
|
17
|
-
if (record.expiresAt < Date.now()) {
|
|
18
|
-
store.delete(signature);
|
|
19
|
-
return false;
|
|
20
|
-
}
|
|
21
|
-
return true;
|
|
22
|
-
},
|
|
23
|
-
async markAsUsed(signature, resourceId, expiresAt) {
|
|
24
|
-
store.set(signature, {
|
|
25
|
-
resourceId,
|
|
26
|
-
usedAt: Date.now(),
|
|
27
|
-
expiresAt: expiresAt.getTime()
|
|
28
|
-
});
|
|
29
|
-
},
|
|
30
|
-
async getUsage(signature) {
|
|
31
|
-
const record = store.get(signature);
|
|
32
|
-
if (!record) return null;
|
|
33
|
-
if (record.expiresAt < Date.now()) {
|
|
34
|
-
store.delete(signature);
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
return {
|
|
38
|
-
signature,
|
|
39
|
-
resourceId: record.resourceId,
|
|
40
|
-
usedAt: new Date(record.usedAt),
|
|
41
|
-
expiresAt: new Date(record.expiresAt),
|
|
42
|
-
walletAddress: record.walletAddress
|
|
43
|
-
};
|
|
44
|
-
},
|
|
45
|
-
/** Stop cleanup timer (for graceful shutdown) */
|
|
46
|
-
close() {
|
|
47
|
-
clearInterval(cleanupTimer);
|
|
48
|
-
store.clear();
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// src/store/redis.ts
|
|
54
|
-
function createRedisStore(options) {
|
|
55
|
-
const { client, keyPrefix = "micropay:sig:" } = options;
|
|
56
|
-
const buildKey = (signature) => `${keyPrefix}${signature}`;
|
|
57
|
-
return {
|
|
58
|
-
async hasBeenUsed(signature) {
|
|
59
|
-
const exists = await client.exists(buildKey(signature));
|
|
60
|
-
return exists > 0;
|
|
61
|
-
},
|
|
62
|
-
async markAsUsed(signature, resourceId, expiresAt) {
|
|
63
|
-
const key = buildKey(signature);
|
|
64
|
-
const ttl = Math.max(1, Math.floor((expiresAt.getTime() - Date.now()) / 1e3));
|
|
65
|
-
const record = {
|
|
66
|
-
signature,
|
|
67
|
-
resourceId,
|
|
68
|
-
usedAt: /* @__PURE__ */ new Date(),
|
|
69
|
-
expiresAt
|
|
70
|
-
};
|
|
71
|
-
if (client.setex) {
|
|
72
|
-
await client.setex(key, ttl, JSON.stringify(record));
|
|
73
|
-
} else {
|
|
74
|
-
await client.set(key, JSON.stringify(record), { EX: ttl });
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
async getUsage(signature) {
|
|
78
|
-
const data = await client.get(buildKey(signature));
|
|
79
|
-
if (!data) return null;
|
|
80
|
-
try {
|
|
81
|
-
const record = JSON.parse(data);
|
|
82
|
-
return {
|
|
83
|
-
...record,
|
|
84
|
-
usedAt: new Date(record.usedAt),
|
|
85
|
-
expiresAt: new Date(record.expiresAt)
|
|
86
|
-
};
|
|
87
|
-
} catch {
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export { createMemoryStore, createRedisStore };
|
|
95
|
-
//# sourceMappingURL=index.js.map
|
|
96
|
-
//# sourceMappingURL=index.js.map
|
package/dist/store/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/store/memory.ts","../../src/store/redis.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// In-Memory Signature Store\n// For development, testing, and single-instance deployments\n\n/** Signature usage record */\nexport interface SignatureUsage {\n signature: string;\n resourceId: string;\n usedAt: Date;\n expiresAt: Date;\n walletAddress?: string;\n}\n\n/** Interface for tracking payment signature usage */\nexport interface SignatureStore {\n hasBeenUsed(signature: string): Promise<boolean>;\n markAsUsed(signature: string, resourceId: string, expiresAt: Date): Promise<void>;\n getUsage?(signature: string): Promise<SignatureUsage | null>;\n}\n\nexport interface MemoryStoreOptions {\n /** Default TTL in seconds */\n defaultTTL?: number;\n /** Cleanup interval in ms (default: 60000) */\n cleanupInterval?: number;\n}\n\ninterface StoredRecord {\n resourceId: string;\n usedAt: number;\n expiresAt: number;\n walletAddress?: string;\n}\n\n/**\n * Create an in-memory signature store\n * ⚠️ Not suitable for multi-instance deployments (use Redis instead)\n */\nexport function createMemoryStore(options: MemoryStoreOptions = {}): SignatureStore & { close: () => void } {\n const { cleanupInterval = 60000 } = options;\n const store = new Map<string, StoredRecord>();\n\n // Periodic cleanup of expired entries\n const cleanupTimer = setInterval(() => {\n const now = Date.now();\n for (const [key, record] of store.entries()) {\n if (record.expiresAt < now) {\n store.delete(key);\n }\n }\n }, cleanupInterval);\n\n return {\n async hasBeenUsed(signature: string): Promise<boolean> {\n const record = store.get(signature);\n if (!record) return false;\n\n // Check if expired\n if (record.expiresAt < Date.now()) {\n store.delete(signature);\n return false;\n }\n\n return true;\n },\n\n async markAsUsed(signature: string, resourceId: string, expiresAt: Date): Promise<void> {\n store.set(signature, {\n resourceId,\n usedAt: Date.now(),\n expiresAt: expiresAt.getTime(),\n });\n },\n\n async getUsage(signature: string): Promise<SignatureUsage | null> {\n const record = store.get(signature);\n if (!record) return null;\n\n // Check expiration\n if (record.expiresAt < Date.now()) {\n store.delete(signature);\n return null;\n }\n\n return {\n signature,\n resourceId: record.resourceId,\n usedAt: new Date(record.usedAt),\n expiresAt: new Date(record.expiresAt),\n walletAddress: record.walletAddress,\n };\n },\n\n /** Stop cleanup timer (for graceful shutdown) */\n close(): void {\n clearInterval(cleanupTimer);\n store.clear();\n },\n };\n}\n","// Redis Signature Store Adapter\n// For production multi-instance deployments\n\nimport type { SignatureStore, SignatureUsage } from './memory';\n\n/**\n * Minimal Redis client interface\n * Compatible with ioredis, redis, and similar clients\n */\nexport interface RedisClient {\n get(key: string): Promise<string | null>;\n set(key: string, value: string, options?: { EX?: number }): Promise<string | null>;\n setex?(key: string, seconds: number, value: string): Promise<string>;\n exists(key: string): Promise<number>;\n del(key: string): Promise<number>;\n}\n\nexport interface RedisStoreOptions {\n /** Redis client instance */\n client: RedisClient;\n /** Key prefix */\n keyPrefix?: string;\n /** Default TTL in seconds */\n defaultTTL?: number;\n}\n\n/**\n * Create a Redis-backed signature store\n * Production-ready for distributed deployments\n */\nexport function createRedisStore(options: RedisStoreOptions): SignatureStore {\n const { client, keyPrefix = 'micropay:sig:' } = options;\n\n const buildKey = (signature: string) => `${keyPrefix}${signature}`;\n\n return {\n async hasBeenUsed(signature: string): Promise<boolean> {\n const exists = await client.exists(buildKey(signature));\n return exists > 0;\n },\n\n async markAsUsed(signature: string, resourceId: string, expiresAt: Date): Promise<void> {\n const key = buildKey(signature);\n const ttl = Math.max(1, Math.floor((expiresAt.getTime() - Date.now()) / 1000));\n\n const record: SignatureUsage = {\n signature,\n resourceId,\n usedAt: new Date(),\n expiresAt,\n };\n\n // Support both `setex` (ioredis) and `set` with EX (node-redis)\n if (client.setex) {\n await client.setex(key, ttl, JSON.stringify(record));\n } else {\n await client.set(key, JSON.stringify(record), { EX: ttl });\n }\n },\n\n async getUsage(signature: string): Promise<SignatureUsage | null> {\n const data = await client.get(buildKey(signature));\n if (!data) return null;\n\n try {\n const record = JSON.parse(data) as SignatureUsage;\n // Convert date strings back to Date objects\n return {\n ...record,\n usedAt: new Date(record.usedAt),\n expiresAt: new Date(record.expiresAt),\n };\n } catch {\n return null;\n }\n },\n };\n}\n"]}
|
package/dist/utils/index.cjs
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// src/utils/retry.ts
|
|
4
|
-
function sleep(ms) {
|
|
5
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
6
|
-
}
|
|
7
|
-
function calculateDelay(attempt, options) {
|
|
8
|
-
const { baseDelay, maxDelay, jitter } = options;
|
|
9
|
-
let delay = baseDelay * Math.pow(2, attempt);
|
|
10
|
-
delay = Math.min(delay, maxDelay);
|
|
11
|
-
if (jitter) {
|
|
12
|
-
const jitterAmount = delay * 0.25;
|
|
13
|
-
delay += Math.random() * jitterAmount * 2 - jitterAmount;
|
|
14
|
-
}
|
|
15
|
-
return Math.floor(delay);
|
|
16
|
-
}
|
|
17
|
-
async function withRetry(fn, options = {}) {
|
|
18
|
-
const {
|
|
19
|
-
maxAttempts = 3,
|
|
20
|
-
baseDelay = 500,
|
|
21
|
-
maxDelay = 1e4,
|
|
22
|
-
jitter = true,
|
|
23
|
-
retryOn = () => true
|
|
24
|
-
} = options;
|
|
25
|
-
let lastError;
|
|
26
|
-
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
27
|
-
try {
|
|
28
|
-
return await fn();
|
|
29
|
-
} catch (error) {
|
|
30
|
-
lastError = error;
|
|
31
|
-
if (!retryOn(error)) {
|
|
32
|
-
throw error;
|
|
33
|
-
}
|
|
34
|
-
if (attempt < maxAttempts - 1) {
|
|
35
|
-
const delay = calculateDelay(attempt, {
|
|
36
|
-
baseDelay,
|
|
37
|
-
maxDelay,
|
|
38
|
-
jitter
|
|
39
|
-
});
|
|
40
|
-
await sleep(delay);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
throw lastError;
|
|
45
|
-
}
|
|
46
|
-
function isRetryableRPCError(error) {
|
|
47
|
-
if (error instanceof Error) {
|
|
48
|
-
const message = error.message.toLowerCase();
|
|
49
|
-
if (message.includes("429") || message.includes("rate limit")) {
|
|
50
|
-
return true;
|
|
51
|
-
}
|
|
52
|
-
if (message.includes("timeout") || message.includes("econnreset")) {
|
|
53
|
-
return true;
|
|
54
|
-
}
|
|
55
|
-
if (message.includes("503") || message.includes("502") || message.includes("500")) {
|
|
56
|
-
return true;
|
|
57
|
-
}
|
|
58
|
-
if (message.includes("blockhash not found") || message.includes("slot skipped")) {
|
|
59
|
-
return true;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
exports.isRetryableRPCError = isRetryableRPCError;
|
|
66
|
-
exports.withRetry = withRetry;
|
|
67
|
-
//# sourceMappingURL=index.cjs.map
|
|
68
|
-
//# sourceMappingURL=index.cjs.map
|
package/dist/utils/index.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/retry.ts"],"names":[],"mappings":";;;AAmBA,SAAS,MAAM,EAAA,EAA2B;AACtC,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAA,OAAA,KAAW,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AACzD;AAKA,SAAS,cAAA,CAAe,SAAiB,OAAA,EAA0D;AAC/F,EAAA,MAAM,EAAE,SAAA,EAAW,QAAA,EAAU,MAAA,EAAO,GAAI,OAAA;AAGxC,EAAA,IAAI,KAAA,GAAQ,SAAA,GAAY,IAAA,CAAK,GAAA,CAAI,GAAG,OAAO,CAAA;AAG3C,EAAA,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,KAAA,EAAO,QAAQ,CAAA;AAGhC,EAAA,IAAI,MAAA,EAAQ;AACR,IAAA,MAAM,eAAe,KAAA,GAAQ,IAAA;AAC7B,IAAA,KAAA,IAAU,IAAA,CAAK,MAAA,EAAO,GAAI,YAAA,GAAe,CAAA,GAAK,YAAA;AAAA,EAClD;AAEA,EAAA,OAAO,IAAA,CAAK,MAAM,KAAK,CAAA;AAC3B;AAaA,eAAsB,SAAA,CAClB,EAAA,EACA,OAAA,GAAwB,EAAC,EACf;AACV,EAAA,MAAM;AAAA,IACF,WAAA,GAAc,CAAA;AAAA,IACd,SAAA,GAAY,GAAA;AAAA,IACZ,QAAA,GAAW,GAAA;AAAA,IACX,MAAA,GAAS,IAAA;AAAA,IACT,UAAU,MAAM;AAAA,GACpB,GAAI,OAAA;AAEJ,EAAA,IAAI,SAAA;AAEJ,EAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,GAAU,WAAA,EAAa,OAAA,EAAA,EAAW;AACpD,IAAA,IAAI;AACA,MAAA,OAAO,MAAM,EAAA,EAAG;AAAA,IACpB,SAAS,KAAA,EAAO;AACZ,MAAA,SAAA,GAAY,KAAA;AAGZ,MAAA,IAAI,CAAC,OAAA,CAAQ,KAAK,CAAA,EAAG;AACjB,QAAA,MAAM,KAAA;AAAA,MACV;AAGA,MAAA,IAAI,OAAA,GAAU,cAAc,CAAA,EAAG;AAC3B,QAAA,MAAM,KAAA,GAAQ,eAAe,OAAA,EAAS;AAAA,UAElC,SAAA;AAAA,UACA,QAAA;AAAA,UACA;AAAA,SACH,CAAA;AACD,QAAA,MAAM,MAAM,KAAK,CAAA;AAAA,MACrB;AAAA,IACJ;AAAA,EACJ;AAEA,EAAA,MAAM,SAAA;AACV;AAKO,SAAS,oBAAoB,KAAA,EAAyB;AACzD,EAAA,IAAI,iBAAiB,KAAA,EAAO;AACxB,IAAA,MAAM,OAAA,GAAU,KAAA,CAAM,OAAA,CAAQ,WAAA,EAAY;AAG1C,IAAA,IAAI,QAAQ,QAAA,CAAS,KAAK,KAAK,OAAA,CAAQ,QAAA,CAAS,YAAY,CAAA,EAAG;AAC3D,MAAA,OAAO,IAAA;AAAA,IACX;AAGA,IAAA,IAAI,QAAQ,QAAA,CAAS,SAAS,KAAK,OAAA,CAAQ,QAAA,CAAS,YAAY,CAAA,EAAG;AAC/D,MAAA,OAAO,IAAA;AAAA,IACX;AAGA,IAAA,IAAI,OAAA,CAAQ,QAAA,CAAS,KAAK,CAAA,IAAK,OAAA,CAAQ,QAAA,CAAS,KAAK,CAAA,IAAK,OAAA,CAAQ,QAAA,CAAS,KAAK,CAAA,EAAG;AAC/E,MAAA,OAAO,IAAA;AAAA,IACX;AAGA,IAAA,IAAI,QAAQ,QAAA,CAAS,qBAAqB,KAAK,OAAA,CAAQ,QAAA,CAAS,cAAc,CAAA,EAAG;AAC7E,MAAA,OAAO,IAAA;AAAA,IACX;AAAA,EACJ;AAEA,EAAA,OAAO,KAAA;AACX","file":"index.cjs","sourcesContent":["// Utility functions\n// Retry logic with exponential backoff for RPC resilience\n\nexport interface RetryOptions {\n /** Maximum number of attempts */\n maxAttempts?: number;\n /** Base delay in milliseconds */\n baseDelay?: number;\n /** Maximum delay in milliseconds */\n maxDelay?: number;\n /** Whether to add jitter to delay */\n jitter?: boolean;\n /** Errors to retry on (default: all) */\n retryOn?: (error: unknown) => boolean;\n}\n\n/**\n * Sleep for a given duration\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n/**\n * Calculate delay with exponential backoff and optional jitter\n */\nfunction calculateDelay(attempt: number, options: Required<Omit<RetryOptions, 'retryOn'>>): number {\n const { baseDelay, maxDelay, jitter } = options;\n\n // Exponential backoff: baseDelay * 2^attempt\n let delay = baseDelay * Math.pow(2, attempt);\n\n // Cap at maxDelay\n delay = Math.min(delay, maxDelay);\n\n // Add jitter (±25%)\n if (jitter) {\n const jitterAmount = delay * 0.25;\n delay += (Math.random() * jitterAmount * 2) - jitterAmount;\n }\n\n return Math.floor(delay);\n}\n\n/**\n * Execute a function with retry logic and exponential backoff\n * \n * @example\n * ```typescript\n * const result = await withRetry(\n * () => connection.getBalance(publicKey),\n * { maxAttempts: 3, baseDelay: 500 }\n * );\n * ```\n */\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n options: RetryOptions = {}\n): Promise<T> {\n const {\n maxAttempts = 3,\n baseDelay = 500,\n maxDelay = 10000,\n jitter = true,\n retryOn = () => true,\n } = options;\n\n let lastError: unknown;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error;\n\n // Check if we should retry this error\n if (!retryOn(error)) {\n throw error;\n }\n\n // Don't sleep after the last attempt\n if (attempt < maxAttempts - 1) {\n const delay = calculateDelay(attempt, {\n maxAttempts,\n baseDelay,\n maxDelay,\n jitter\n });\n await sleep(delay);\n }\n }\n }\n\n throw lastError;\n}\n\n/**\n * Check if error is a transient RPC error that should be retried\n */\nexport function isRetryableRPCError(error: unknown): boolean {\n if (error instanceof Error) {\n const message = error.message.toLowerCase();\n\n // Rate limiting\n if (message.includes('429') || message.includes('rate limit')) {\n return true;\n }\n\n // Network errors\n if (message.includes('timeout') || message.includes('econnreset')) {\n return true;\n }\n\n // Server errors\n if (message.includes('503') || message.includes('502') || message.includes('500')) {\n return true;\n }\n\n // Solana-specific transient errors\n if (message.includes('blockhash not found') || message.includes('slot skipped')) {\n return true;\n }\n }\n\n return false;\n}\n"]}
|
package/dist/utils/index.d.cts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
interface RetryOptions {
|
|
2
|
-
/** Maximum number of attempts */
|
|
3
|
-
maxAttempts?: number;
|
|
4
|
-
/** Base delay in milliseconds */
|
|
5
|
-
baseDelay?: number;
|
|
6
|
-
/** Maximum delay in milliseconds */
|
|
7
|
-
maxDelay?: number;
|
|
8
|
-
/** Whether to add jitter to delay */
|
|
9
|
-
jitter?: boolean;
|
|
10
|
-
/** Errors to retry on (default: all) */
|
|
11
|
-
retryOn?: (error: unknown) => boolean;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Execute a function with retry logic and exponential backoff
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* ```typescript
|
|
18
|
-
* const result = await withRetry(
|
|
19
|
-
* () => connection.getBalance(publicKey),
|
|
20
|
-
* { maxAttempts: 3, baseDelay: 500 }
|
|
21
|
-
* );
|
|
22
|
-
* ```
|
|
23
|
-
*/
|
|
24
|
-
declare function withRetry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
|
|
25
|
-
/**
|
|
26
|
-
* Check if error is a transient RPC error that should be retried
|
|
27
|
-
*/
|
|
28
|
-
declare function isRetryableRPCError(error: unknown): boolean;
|
|
29
|
-
|
|
30
|
-
export { type RetryOptions, isRetryableRPCError, withRetry };
|
package/dist/utils/index.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
interface RetryOptions {
|
|
2
|
-
/** Maximum number of attempts */
|
|
3
|
-
maxAttempts?: number;
|
|
4
|
-
/** Base delay in milliseconds */
|
|
5
|
-
baseDelay?: number;
|
|
6
|
-
/** Maximum delay in milliseconds */
|
|
7
|
-
maxDelay?: number;
|
|
8
|
-
/** Whether to add jitter to delay */
|
|
9
|
-
jitter?: boolean;
|
|
10
|
-
/** Errors to retry on (default: all) */
|
|
11
|
-
retryOn?: (error: unknown) => boolean;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Execute a function with retry logic and exponential backoff
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* ```typescript
|
|
18
|
-
* const result = await withRetry(
|
|
19
|
-
* () => connection.getBalance(publicKey),
|
|
20
|
-
* { maxAttempts: 3, baseDelay: 500 }
|
|
21
|
-
* );
|
|
22
|
-
* ```
|
|
23
|
-
*/
|
|
24
|
-
declare function withRetry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
|
|
25
|
-
/**
|
|
26
|
-
* Check if error is a transient RPC error that should be retried
|
|
27
|
-
*/
|
|
28
|
-
declare function isRetryableRPCError(error: unknown): boolean;
|
|
29
|
-
|
|
30
|
-
export { type RetryOptions, isRetryableRPCError, withRetry };
|