@alleyboss/micropay-solana-x402-paywall 1.0.0 → 2.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.
Files changed (66) hide show
  1. package/README.md +100 -167
  2. package/dist/client/index.cjs +99 -0
  3. package/dist/client/index.cjs.map +1 -0
  4. package/dist/client/index.d.cts +112 -0
  5. package/dist/client/index.d.ts +112 -0
  6. package/dist/client/index.js +95 -0
  7. package/dist/client/index.js.map +1 -0
  8. package/dist/client-CSZHI8o8.d.ts +32 -0
  9. package/dist/client-vRr48m2x.d.cts +32 -0
  10. package/dist/index.cjs +803 -41
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +11 -3
  13. package/dist/index.d.ts +11 -3
  14. package/dist/index.js +783 -42
  15. package/dist/index.js.map +1 -1
  16. package/dist/memory-Daxkczti.d.cts +29 -0
  17. package/dist/memory-Daxkczti.d.ts +29 -0
  18. package/dist/middleware/index.cjs +261 -0
  19. package/dist/middleware/index.cjs.map +1 -0
  20. package/dist/middleware/index.d.cts +90 -0
  21. package/dist/middleware/index.d.ts +90 -0
  22. package/dist/middleware/index.js +255 -0
  23. package/dist/middleware/index.js.map +1 -0
  24. package/dist/nextjs-BK0pVb9Y.d.ts +78 -0
  25. package/dist/nextjs-Bm272Jkj.d.cts +78 -0
  26. package/dist/{client-kfCr7G-P.d.cts → payment-CTxdtqmc.d.cts} +23 -34
  27. package/dist/{client-kfCr7G-P.d.ts → payment-CTxdtqmc.d.ts} +23 -34
  28. package/dist/pricing/index.cjs +79 -0
  29. package/dist/pricing/index.cjs.map +1 -0
  30. package/dist/pricing/index.d.cts +67 -0
  31. package/dist/pricing/index.d.ts +67 -0
  32. package/dist/pricing/index.js +72 -0
  33. package/dist/pricing/index.js.map +1 -0
  34. package/dist/session/index.cjs +51 -11
  35. package/dist/session/index.cjs.map +1 -1
  36. package/dist/session/index.d.cts +29 -1
  37. package/dist/session/index.d.ts +29 -1
  38. package/dist/session/index.js +51 -11
  39. package/dist/session/index.js.map +1 -1
  40. package/dist/{index-DptevtnU.d.cts → session-D2IoWAWV.d.cts} +1 -24
  41. package/dist/{index-DptevtnU.d.ts → session-D2IoWAWV.d.ts} +1 -24
  42. package/dist/solana/index.cjs +235 -15
  43. package/dist/solana/index.cjs.map +1 -1
  44. package/dist/solana/index.d.cts +61 -3
  45. package/dist/solana/index.d.ts +61 -3
  46. package/dist/solana/index.js +232 -16
  47. package/dist/solana/index.js.map +1 -1
  48. package/dist/store/index.cjs +99 -0
  49. package/dist/store/index.cjs.map +1 -0
  50. package/dist/store/index.d.cts +38 -0
  51. package/dist/store/index.d.ts +38 -0
  52. package/dist/store/index.js +96 -0
  53. package/dist/store/index.js.map +1 -0
  54. package/dist/utils/index.cjs +68 -0
  55. package/dist/utils/index.cjs.map +1 -0
  56. package/dist/utils/index.d.cts +30 -0
  57. package/dist/utils/index.d.ts +30 -0
  58. package/dist/utils/index.js +65 -0
  59. package/dist/utils/index.js.map +1 -0
  60. package/dist/x402/index.cjs +119 -18
  61. package/dist/x402/index.cjs.map +1 -1
  62. package/dist/x402/index.d.cts +6 -1
  63. package/dist/x402/index.d.ts +6 -1
  64. package/dist/x402/index.js +119 -18
  65. package/dist/x402/index.js.map +1 -1
  66. package/package.json +56 -3
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/solana/client.ts","../../src/solana/verification.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// Solana RPC client with multi-provider support\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}\n\n// Singleton state\nlet cachedConnection: Connection | null = null;\nlet cachedNetwork: SolanaNetwork | null = null;\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 * 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\n cachedConnection = new Connection(rpcUrl, {\n commitment: 'confirmed',\n confirmTransactionInitialTimeout: 60000,\n });\n cachedNetwork = network;\n\n return cachedConnection;\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\nimport { PublicKey, LAMPORTS_PER_SOL, type ParsedTransactionWithMeta } from '@solana/web3.js';\nimport { getConnection, type SolanaClientConfig } from './client';\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 /** Solana client configuration */\n clientConfig: SolanaClientConfig;\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 */\nexport async function verifyPayment(\n params: VerifyPaymentParams\n): Promise<TransactionVerificationResult> {\n const {\n signature,\n expectedRecipient,\n expectedAmount,\n maxAgeSeconds = 300,\n clientConfig\n } = params;\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: ${JSON.stringify(transaction.meta.err)}`,\n };\n }\n\n // Validate transaction age\n if (transaction.blockTime) {\n const now = Math.floor(Date.now() / 1000);\n if (now - transaction.blockTime > maxAgeSeconds) {\n return { valid: false, confirmed: true, signature, error: 'Transaction too old' };\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 // Validate amount\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 amount: expected ${expectedAmount}, got ${transferDetails.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 return {\n valid: false,\n confirmed: false,\n signature,\n error: error instanceof Error ? error.message : 'Unknown verification error',\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 const connection = getConnection(clientConfig);\n\n try {\n const confirmation = await connection.confirmTransaction(signature, 'confirmed');\n\n if (confirmation.value.err) {\n return {\n confirmed: false,\n error: `Transaction failed: ${JSON.stringify(confirmation.value.err)}`,\n };\n }\n\n return { confirmed: true, slot: confirmation.context?.slot };\n } catch (error) {\n return {\n confirmed: false,\n error: error instanceof Error ? error.message : 'Confirmation timeout',\n };\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 const connection = getConnection(clientConfig);\n const pubkey = new PublicKey(walletAddress);\n\n try {\n const signatures = await connection.getSignaturesForAddress(pubkey, { limit });\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 return BigInt(Math.floor(sol * LAMPORTS_PER_SOL));\n}\n"]}
1
+ {"version":3,"sources":["../../src/solana/client.ts","../../src/solana/verification.ts","../../src/types/payment.ts","../../src/solana/spl.ts"],"names":["SIGNATURE_REGEX","WALLET_REGEX"],"mappings":"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","file":"index.js","sourcesContent":["// Solana RPC client with multi-provider support\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}\n\n// Singleton state\nlet cachedConnection: Connection | null = null;\nlet cachedNetwork: SolanaNetwork | null = null;\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 * 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\n cachedConnection = new Connection(rpcUrl, {\n commitment: 'confirmed',\n confirmTransactionInitialTimeout: 60000,\n });\n cachedNetwork = network;\n\n return cachedConnection;\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';\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 /** 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 } = 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 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 /** 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 } from '@solana/web3.js';\nimport { getConnection, type SolanaClientConfig } from './client';\nimport { TOKEN_MINTS, type PaymentAsset } from '../types';\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}\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 } = params;\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 // 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"]}
@@ -0,0 +1,99 @@
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
@@ -0,0 +1 @@
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"]}
@@ -0,0 +1,38 @@
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 };
@@ -0,0 +1,38 @@
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 };
@@ -0,0 +1,96 @@
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
@@ -0,0 +1 @@
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"]}
@@ -0,0 +1,68 @@
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
@@ -0,0 +1 @@
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"]}
@@ -0,0 +1,30 @@
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 };
@@ -0,0 +1,30 @@
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 };