UNPKG

@ghostspeak/sdk

Version:

TypeScript SDK for GhostSpeak AI Agent Commerce Protocol - Production Ready Beta

1,456 lines (1,446 loc) 73.7 kB
export { batchGetAccounts, batchGetAccountsWithRetry, batchGetAndMap, batchGetExistingAccounts, createBatchFetcher } from './chunk-SKMJJ3Q6.js'; export { BaseReputationAdapter, GHOSTSPEAK_PROGRAM_ID, ReputationSource } from './chunk-TTB4OS2D.js'; export { AuthorizationModule, DidModule, GhostSpeakClient, PrivacyModule, UnifiedCredentialService, calculateVisibleScore, canViewerAccess, GhostSpeakClient_default as default, filterMetricsByVisibility, getDefaultMetricVisibility, getRangeDisplayString, getReputationTier, getScoreRange, getTierDisplayName, lamportsToSol, sol, validatePrivacySettings } from './chunk-5SS3OL4B.js'; import { init_MultiSourceAggregator, BaseModule } from './chunk-63A7F2YP.js'; export { ATTESTATION_SEED, AgentModule, BaseModule, CREDENTIAL_SEED, CacheManager, CredentialKind, CredentialModule, CredentialStatus, DEFAULT_IPFS_CONFIG, DidError, DidErrorClass, GhostModule, GovernanceModule, IPFSUtils, InstructionBuilder, MultiSourceAggregator, MultisigModule, ReputationModule, RpcClient, SASAttestationHelper, SAS_PROGRAM_ID, SCHEMA_SEED, ServiceEndpointType, StakingModule, VerificationMethodType, VerificationRelationship, canPerformAction, createEd25519VerificationMethod, createIPFSUtils, createMetadataUri, createServiceEndpoint, deriveDidDocumentPda, determineStorageMethod, didDocumentToJson, exportAsW3CDidDocument, generateDidString, getIdentifierFromDid, getMethodsForRelationship, getNetworkFromDid, isDidActive, parseDidString, validateDidString } from './chunk-63A7F2YP.js'; export { AccountNotFoundError, ErrorFactory, ErrorHandler, GhostSpeakError, InsufficientBalanceError, InvalidInputError, NetworkError, SimulationFailedError, TimeoutError, TransactionFailedError, ValidationError } from './chunk-5DMB3UAV.js'; export { decrypt, elgamal_exports as elgamal, encrypt, generateKeypair, generateTransferProof, generateWithdrawProof, isWasmAvailable, loadWasmModule, wasm_bridge_exports as wasmBridge } from './chunk-VQZQCHUT.js'; import { getFeatureFlags, ClientEncryptionService } from './chunk-EU6PHSM5.js'; export { ClientEncryptionService, FeatureFlagManager, TokenExtension, TokenProgram, createDiscriminatorErrorMessage, createMigrationPlan, createMigrationReport, deriveAssociatedTokenAddress, deriveMultisigPda, deriveProposalPda, deriveSplTokenAssociatedTokenAddress, deriveToken2022AssociatedTokenAddress, detectTokenProgram, diagnoseAccountFromChain, diagnoseBatchFromChain, exportDiagnosticReport, extractLegacyData, formatTokenAmount, generateLocalPrivacyProof, getAllAssociatedTokenAddresses, getAssociatedTokenAccount, getConfidentialTransferConfig, getFeatureFlags, getInterestBearingConfig, getMigrationInstructions, getTokenProgramAddress, getTokenProgramFromAddress, getTokenProgramType, getTransferFeeConfig, hasConfidentialTransferExtension, hasInterestBearingExtension, hasTransferFeeExtension, inspectAccountData, isFeatureEnabled, isToken2022Mint, parseTokenAmount, runAccountDiagnostics, runBatchDiagnostics, safeDecodeAgent, simulateMigration, validateAccountDiscriminator, validateAssociatedTokenAddress, verifyLocalPrivacyProof } from './chunk-EU6PHSM5.js'; export { deriveAgentPda, deriveAgentVerificationPda, deriveUserRegistryPda, findProgramDerivedAddress } from './chunk-BF3IQ35I.js'; export { createAuthorizationMessage, createSignedAuthorization, deserializeAuthorization, generateNonce, getAuthorizationId, isAuthorizationExhausted, isAuthorizationExpired, serializeAuthorization, signAuthorizationMessage, validateAuthorizationNetwork, verifyAuthorizationSignature } from './chunk-QWQTPTZ4.js'; import { init_reputation_tag_engine, init_reputation_tags, ExternalIdNotFoundError, GhostSpeakError, GhostNotFoundError } from './chunk-HIDBANFS.js'; export { ASSOCIATED_TOKEN_PROGRAM_ADDRESS, BadgeType, BehaviorTag, ComplianceTag, DEFAULT_TAG_DECAY, GhostSpeakSDKError, INSTRUCTION_MAPPINGS, IPFSClient, InstructionValidationError, NATIVE_MINT_ADDRESS, PRIVACY_CONSTANTS, PrivacyMode, PrivacyPresets, REPUTATION_CONSTANTS, ReputationTagEngine, ReputationTier, ScoreRange, SkillTag, TAG_CONSTANTS, TOKEN_2022_PROGRAM_ADDRESS, TOKEN_PROGRAM_ADDRESS, TagCategory, TagConfidenceLevel, VisibilityLevel, createAccountMismatchError, createErrorContext, debugInstructionCall, enhanceErrorMessage, enhanceTransactionError, extractInstructionName, generateAccountValidationError, getAccountRequirements, getInstructionMapping, getPDAAccounts, getRequiredSigners, getWritableAccounts, isKnownInstruction, logEnhancedError, validateInstructionAccounts, validatePreconditions, withEnhancedErrors, withEnhancedErrorsSync } from './chunk-HIDBANFS.js'; import { getCreateEscrowInstructionAsync, getSubmitDeliveryInstruction, getApproveDeliveryInstruction, getFileDisputeInstruction, getArbitrateDisputeInstruction } from './chunk-IQM5RASO.js'; export { getApproveDeliveryInstruction, getArbitrateDisputeInstruction, getClaimGhostInstruction, getCreateDidDocumentInstructionAsync, getCreateEscrowInstructionAsync, getDeactivateDidDocumentInstructionAsync, getFileDisputeInstruction, getGhostProtectEscrowDecoder, getInitializeStakingConfigInstructionAsync, getRegisterAgentInstructionAsync, getResolveDidDocumentInstructionAsync, getSlashStakeInstructionAsync, getStakeGhostInstructionAsync, getStakingAccountDecoder, getStakingConfigDecoder, getSubmitDeliveryInstruction, getUnstakeGhostInstructionAsync, getUpdateDidDocumentInstructionAsync, getUpdateReputationTagsInstructionAsync } from './chunk-IQM5RASO.js'; export { ProposalStatus, decodeAgent, fetchAgent, fetchMaybeAgent, getAgentDecoder } from './chunk-5QZVFUXB.js'; import './chunk-46QWY3MG.js'; import './chunk-A7ALCVUI.js'; import './chunk-QLRWUHN2.js'; export { GHOSTSPEAK_MARKETPLACE_PROGRAM_ADDRESS } from './chunk-AWMGX3OX.js'; export { AgentType, ChannelType, ErrorCode, EscrowStatus, MessageType, ParticipantType, isError, isSuccess, unwrap } from './chunk-SRS2SKFS.js'; export { CrossmintVCClient, GHOSTSPEAK_CREDENTIAL_TYPES } from './chunk-RIZZPLLB.js'; import { __require } from './chunk-UP2VWCW5.js'; import { createSolanaRpc, lamports, pipe, createTransactionMessage, setTransactionMessageFeePayer, setTransactionMessageLifetimeUsingBlockhash, appendTransactionMessageInstructions, signTransactionMessageWithSigners, getBase64EncodedWireTransaction, createKeyPairSignerFromBytes, generateKeyPairSigner } from '@solana/kit'; export { address, createKeyPairSignerFromBytes, createSolanaRpc, generateKeyPairSigner } from '@solana/kit'; import { address } from '@solana/addresses'; import { getTransferSolInstruction } from '@solana-program/system'; import { promises } from 'fs'; import process2 from 'process'; import os from 'os'; import tty from 'tty'; import bs58 from 'bs58'; import { sha256 } from '@noble/hashes/sha256'; import { bytesToHex, hexToBytes } from '@noble/curves/abstract/utils'; var DEFAULT_API_URL = "https://api.ghostspeak.ai"; var DEVNET_API_URL = "https://api-devnet.ghostspeak.ai"; var LOCALNET_API_URL = "http://localhost:3001"; var ExternalIdResolver = class { apiUrl; constructor(config) { if (config?.apiUrl) { this.apiUrl = config.apiUrl; } else { const cluster = config?.cluster || "devnet"; this.apiUrl = cluster === "mainnet-beta" ? DEFAULT_API_URL : cluster === "localnet" ? LOCALNET_API_URL : DEVNET_API_URL; } } /** * Resolve external ID to Ghost address * * @example * const address = await resolver.resolve('payai', 'agent-123'); */ async resolve(platform, externalId) { const result = await this.lookup(platform, externalId); return address(result.mapping.ghostAddress); } /** * Lookup external ID with full Ghost data * * @example * const { mapping, ghost } = await resolver.lookup('payai', 'agent-123'); */ async lookup(platform, externalId) { try { const response = await fetch( `${this.apiUrl}/ghosts/external/${encodeURIComponent(platform)}/${encodeURIComponent(externalId)}` ); if (response.status === 404) { throw new ExternalIdNotFoundError(platform, externalId); } if (!response.ok) { const error = await response.json().catch(() => ({})); throw new GhostSpeakError( error.message || "Failed to lookup external ID", error.code || "LOOKUP_FAILED" ); } const data = await response.json(); return data; } catch (error) { if (error instanceof GhostSpeakError || error instanceof ExternalIdNotFoundError) throw error; throw new GhostSpeakError( "Failed to lookup external ID", "LOOKUP_FAILED" ); } } /** * Get Ghost by Solana address via API * * Faster than on-chain lookup for read operations */ async getGhost(ghostAddress) { try { const addrString = typeof ghostAddress === "string" ? ghostAddress : ghostAddress; const response = await fetch( `${this.apiUrl}/ghosts/${encodeURIComponent(addrString)}` ); if (response.status === 404) { throw new GhostNotFoundError(addrString); } if (!response.ok) { const error = await response.json().catch(() => ({})); throw new GhostSpeakError( error.message || "Failed to fetch Ghost", error.code || "FETCH_FAILED" ); } const ghost = await response.json(); return ghost; } catch (error) { if (error instanceof GhostSpeakError || error instanceof GhostNotFoundError) throw error; throw new GhostSpeakError( "Failed to fetch Ghost", "FETCH_FAILED" ); } } /** * Get Ghost Score via API */ async getGhostScore(ghostAddress) { try { const addrString = typeof ghostAddress === "string" ? ghostAddress : ghostAddress; const response = await fetch( `${this.apiUrl}/ghosts/${encodeURIComponent(addrString)}/score` ); if (response.status === 404) { throw new GhostNotFoundError(addrString); } if (!response.ok) { const error = await response.json().catch(() => ({})); throw new GhostSpeakError( error.message || "Failed to fetch Ghost Score", error.code || "FETCH_FAILED" ); } const score = await response.json(); return score; } catch (error) { if (error instanceof GhostSpeakError || error instanceof GhostNotFoundError) throw error; throw new GhostSpeakError( "Failed to fetch Ghost Score", "FETCH_FAILED" ); } } /** * Get detailed reputation breakdown via API */ async getGhostReputation(ghostAddress) { try { const addrString = typeof ghostAddress === "string" ? ghostAddress : ghostAddress; const response = await fetch( `${this.apiUrl}/ghosts/${encodeURIComponent(addrString)}/reputation` ); if (response.status === 404) { throw new GhostNotFoundError(addrString); } if (!response.ok) { const error = await response.json().catch(() => ({})); throw new GhostSpeakError( error.message || "Failed to fetch reputation", error.code || "FETCH_FAILED" ); } return await response.json(); } catch (error) { if (error instanceof GhostSpeakError || error instanceof GhostNotFoundError) throw error; throw new GhostSpeakError( "Failed to fetch reputation", "FETCH_FAILED" ); } } /** * Batch resolve multiple external IDs */ async resolveBatch(identifiers) { const promises = identifiers.map( ({ platform, externalId }) => this.resolve(platform, externalId).catch(() => null) ); return Promise.all(promises); } /** * Check if external ID exists */ async exists(platform, externalId) { try { await this.resolve(platform, externalId); return true; } catch (error) { if (error instanceof ExternalIdNotFoundError) return false; throw error; } } /** * Get all external IDs for a Ghost * * Fetches Ghost data and returns external identifiers */ async getExternalIds(ghostAddress) { const ghost = await this.getGhost(ghostAddress); return ghost.externalIdentifiers; } /** * Search for Ghost by partial platform ID * * Note: This is a client-side filter, not server-side search * For production, implement server-side search endpoint */ async searchByExternalId(platform, partialId) { throw new GhostSpeakError( "Search not yet implemented", "NOT_IMPLEMENTED" ); } /** * Set custom API URL */ setApiUrl(apiUrl) { this.apiUrl = apiUrl; } /** * Get current API URL */ getApiUrl() { return this.apiUrl; } /** * Check API health */ async checkHealth() { try { const response = await fetch(`${this.apiUrl}/health`); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } return await response.json(); } catch (error) { throw new GhostSpeakError( "Failed to check API health", "HEALTH_CHECK_FAILED" ); } } }; // src/modules/escrow/EscrowModule.ts var EscrowModule = class extends BaseModule { /** * Create a new escrow for a service agreement * * @param params - Escrow creation parameters * @returns Transaction signature */ async createEscrow(params) { const instruction = await getCreateEscrowInstructionAsync({ agent: params.agent, clientTokenAccount: params.clientTokenAccount, escrowVault: params.escrowVault, tokenMint: params.tokenMint, client: params.client, escrowId: params.escrowId, amount: params.amount, jobDescription: params.jobDescription, deadline: params.deadline }, { programAddress: this.programId }); return this.execute("createEscrow", () => instruction, [params.client]); } /** * Submit proof of delivery for an escrow * * @param params - Delivery submission parameters * @returns Transaction signature */ async submitDelivery(params) { const instruction = getSubmitDeliveryInstruction({ escrow: params.escrow, agent: params.agent, agentOwner: params.agentOwner, deliveryProof: params.deliveryProof }, { programAddress: this.programId }); return this.execute("submitDelivery", () => instruction, [params.agentOwner]); } /** * Approve delivery and release funds to agent * * @param params - Approval parameters * @returns Transaction signature */ async approveDelivery(params) { const instruction = getApproveDeliveryInstruction({ escrow: params.escrow, escrowVault: params.escrowVault, agentTokenAccount: params.agentTokenAccount, client: params.client }, { programAddress: this.programId }); return this.execute("approveDelivery", () => instruction, [params.client]); } /** * File a dispute for an escrow * * @param params - Dispute filing parameters * @returns Transaction signature */ async fileDispute(params) { const instruction = getFileDisputeInstruction({ escrow: params.escrow, client: params.client, reason: params.reason }, { programAddress: this.programId }); return this.execute("fileDispute", () => instruction, [params.client]); } /** * Arbitrate a disputed escrow * * @param params - Arbitration parameters * @returns Transaction signature */ async arbitrateDispute(params) { const instruction = getArbitrateDisputeInstruction({ escrow: params.escrow, escrowVault: params.escrowVault, agentTokenAccount: params.agentTokenAccount, clientTokenAccount: params.clientTokenAccount, agentStaking: params.agentStaking, arbitrator: params.arbitrator, decision: params.decision }, { programAddress: this.programId }); return this.execute("arbitrateDispute", () => instruction, [params.arbitrator]); } /** * Get escrow account data * * @param escrowAddress - The escrow account address * @returns Escrow data or null if not found */ async getEscrow(escrowAddress) { try { return await this.getAccount(escrowAddress, "getGhostProtectEscrowDecoder"); } catch (error) { console.error("Error fetching escrow:", error); return null; } } }; // src/index.ts init_reputation_tag_engine(); // src/modules/indexer/X402TransactionIndexer.ts var X402TransactionIndexer = class { rpc; facilitatorAddress; network; batchSize; constructor(config) { this.rpc = config.rpc; this.facilitatorAddress = config.facilitatorAddress; this.network = config.network || "solana"; this.batchSize = config.batchSize || 100; } // ===================================================== // PUBLIC METHODS // ===================================================== /** * Poll for new x402 transactions since last sync * * @param lastSignature - Last processed signature (for pagination) * @param limit - Maximum transactions to fetch * @returns Array of parsed x402 payment data */ async pollTransactions(lastSignature, limit) { try { const signatures = await this.getSignatures(lastSignature, limit); if (signatures.length === 0) { return []; } console.log(`[X402 Indexer] Found ${signatures.length} new transactions`); const payments = []; for (const sig of signatures) { try { const payment = await this.parseTransaction(sig.signature); if (payment) { payments.push(payment); } } catch (error) { console.error(`[X402 Indexer] Failed to parse transaction ${sig.signature}:`, error); } } console.log(`[X402 Indexer] Parsed ${payments.length} x402 payments`); return payments; } catch (error) { console.error("[X402 Indexer] Failed to poll transactions:", error); throw error; } } /** * Parse a specific transaction signature * * @param signature - Transaction signature to parse * @returns Parsed x402 payment data or null if not an x402 payment */ async parseTransaction(sig) { try { const txSignature = typeof sig === "string" ? sig : sig; const response = await this.rpc.getTransaction(txSignature, { maxSupportedTransactionVersion: 0, encoding: "jsonParsed" }).send(); if (!response || !response.transaction) { return null; } const isX402 = this.isX402Payment(response); if (!isX402) { return null; } return this.extractPaymentData(response, typeof sig === "string" ? sig : String(sig)); } catch (error) { console.error(`[X402 Indexer] Failed to fetch transaction ${sig}:`, error); return null; } } // ===================================================== // PRIVATE METHODS // ===================================================== /** * Fetch transaction signatures for the facilitator address */ async getSignatures(before, limit) { try { const config = { limit: limit || this.batchSize }; if (before) { config.before = before; } const response = await this.rpc.getSignaturesForAddress(this.facilitatorAddress, config).send(); return response.map((sig) => ({ signature: sig.signature, slot: sig.slot, blockTime: sig.blockTime, err: sig.err ?? null })); } catch (error) { console.error("[X402 Indexer] Failed to fetch signatures:", error); throw error; } } /** * Check if transaction is an x402 payment * * x402 payments are characterized by: * - SPL token transfer (TokenProgram or Token2022Program) for USDC * - Native SOL transfer (System Program) * - Transfer TO the facilitator address * - Optional memo instruction with payment metadata * * Supports both devnet and mainnet for all payment types */ isX402Payment(transaction) { try { const instructions = transaction.transaction?.message?.instructions || []; const hasPaymentTransfer = instructions.some((ix) => { const programId = ix.programId?.toString(); const isTokenProgram = programId === "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" || // SPL Token programId === "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"; if (isTokenProgram) { const parsed = ix.parsed; if (parsed?.type === "transfer" || parsed?.type === "transferChecked") { const destination = parsed.info?.destination; return destination === this.facilitatorAddress.toString(); } } if (programId === "11111111111111111111111111111111") { const parsed = ix.parsed; if (parsed?.type === "transfer") { const destination = parsed.info?.destination; return destination === this.facilitatorAddress.toString(); } } return false; }); return hasPaymentTransfer; } catch (error) { console.error("[X402 Indexer] Error checking if x402 payment:", error); return false; } } /** * Extract payment data from transaction */ extractPaymentData(transaction, signature) { try { const instructions = transaction.transaction?.message?.instructions || []; const transferIx = instructions.find((ix) => { const parsed = ix.parsed; const programId = ix.programId?.toString(); if (parsed?.type === "transfer" || parsed?.type === "transferChecked") { return true; } return false; }); if (!transferIx) { return null; } const transferInfo = transferIx.parsed.info; const merchant = transferInfo.destination; const payer = transferInfo.source; const amount = transferInfo.amount || transferInfo.tokenAmount?.amount || transferInfo.lamports || "0"; const success = transaction.meta?.err === null; const blockTime = transaction.blockTime; const timestamp = blockTime ? new Date(blockTime * 1e3) : /* @__PURE__ */ new Date(); const memoIx = instructions.find( (ix) => ix.programId?.toString()?.includes("Memo") ); let responseTimeMs; let metadata; if (memoIx) { try { let memoText; if (memoIx.parsed) { memoText = memoIx.parsed; } else if (memoIx.data) { memoText = Buffer.from(memoIx.data, "base64").toString("utf-8"); } else { memoText = ""; } if (memoText) { const memoData = JSON.parse(memoText); responseTimeMs = memoData.responseTimeMs; metadata = memoData; } } catch { } } return { signature, merchant, payer, amount, success, timestamp, network: this.network, responseTimeMs, metadata }; } catch (error) { console.error("[X402 Indexer] Failed to extract payment data:", error); return null; } } }; // src/index.ts init_reputation_tags(); init_MultiSourceAggregator(); // src/utils/test-ipfs-config.ts var TEST_IPFS_CONFIG = { provider: { name: "test", endpoint: "http://localhost:8080" // Fake endpoint for testing }, gateways: [ "http://localhost:8080", "https://test.ipfs.io" ], autoPinning: true, sizeThreshold: 400, // Lower threshold for testing (400 bytes) maxRetries: 2, retryDelay: 500, enableCache: true, cacheTTL: 6e4 // 1 minute for testing }; function createTestIPFSConfig(options) { return { ...TEST_IPFS_CONFIG, ...options, provider: { ...TEST_IPFS_CONFIG.provider, ...options?.provider ?? {} } }; } // src/utils/ipfs-error-handling.ts var IPFSOperationError = class extends Error { constructor(type, message, provider, retryCount, originalError) { super(message); this.type = type; this.provider = provider; this.retryCount = retryCount; this.originalError = originalError; this.name = "IPFSOperationError"; } }; var DEFAULT_RETRY_CONFIG = { maxRetries: 3, baseDelay: 1e3, maxDelay: 3e4, backoffFactor: 2, retryableErrors: [ "NETWORK_ERROR", "TIMEOUT_ERROR", "PROVIDER_ERROR" ] }; var CircuitBreaker = class { constructor(failureThreshold = 5, recoveryTime = 3e4) { this.failureThreshold = failureThreshold; this.recoveryTime = recoveryTime; } failures = 0; lastFailureTime = 0; state = "CLOSED"; async execute(operation) { if (this.state === "OPEN") { if (Date.now() - this.lastFailureTime > this.recoveryTime) { this.state = "HALF_OPEN"; } else { throw new Error("Circuit breaker is OPEN - too many failures"); } } try { const result = await operation(); this.onSuccess(); return result; } catch (error) { this.onFailure(); throw error; } } onSuccess() { this.failures = 0; this.state = "CLOSED"; } onFailure() { this.failures++; this.lastFailureTime = Date.now(); if (this.failures >= this.failureThreshold) { this.state = "OPEN"; } } getState() { return { state: this.state, failures: this.failures, lastFailureTime: this.lastFailureTime }; } reset() { this.failures = 0; this.lastFailureTime = 0; this.state = "CLOSED"; } }; var RetryHandler = class { constructor(config = DEFAULT_RETRY_CONFIG) { this.config = config; this.circuitBreaker = new CircuitBreaker(); } circuitBreaker; async execute(operation, context) { return this.circuitBreaker.execute(async () => { let lastError; for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) { try { const result = await operation(); if (attempt > 0) { console.log(`\u2705 Operation succeeded after ${attempt} retries${context ? ` (${context})` : ""}`); } return result; } catch (error) { lastError = error instanceof Error ? error : new Error(String(error)); if (attempt === this.config.maxRetries) { break; } const shouldRetry = this.shouldRetry(lastError, attempt); if (!shouldRetry) { console.log(`\u274C Error not retryable${context ? ` (${context})` : ""}:`, lastError.message); break; } const delay = this.calculateDelay(attempt); console.log(`\u23F3 Retrying in ${delay}ms... (attempt ${attempt + 1}/${this.config.maxRetries}${context ? `, ${context}` : ""})`); await new Promise((resolve) => setTimeout(resolve, delay)); } } throw new IPFSOperationError( this.categorizeError(lastError), `Operation failed after ${this.config.maxRetries + 1} attempts${context ? ` (${context})` : ""}: ${lastError.message}`, void 0, this.config.maxRetries ); }); } shouldRetry(error, attempt) { if (attempt >= this.config.maxRetries) { return false; } const errorType = this.categorizeError(error); return this.config.retryableErrors.includes(errorType); } calculateDelay(attempt) { const exponentialDelay = this.config.baseDelay * Math.pow(this.config.backoffFactor, attempt); const jitter = Math.random() * 0.1 * exponentialDelay; return Math.min(exponentialDelay + jitter, this.config.maxDelay); } categorizeError(error) { const message = error.message.toLowerCase(); if (message.includes("timeout")) { return "TIMEOUT_ERROR"; } if (message.includes("network")) { return "NETWORK_ERROR"; } if (message.includes("unauthorized")) { return "AUTHENTICATION_FAILED"; } if (message.includes("quota")) { return "QUOTA_EXCEEDED"; } if (message.includes("invalid") && message.includes("hash")) { return "INVALID_HASH"; } if (message.includes("too large")) { return "CONTENT_TOO_LARGE"; } return "PROVIDER_ERROR"; } getStats() { return { circuitBreakerState: this.circuitBreaker.getState(), config: this.config }; } reset() { this.circuitBreaker.reset(); } }; var FallbackHandler = class { fallbackStrategies = /* @__PURE__ */ new Map(); constructor() { this.setupDefaultFallbacks(); } setupDefaultFallbacks() { this.fallbackStrategies.set("UPLOAD_FAILED", async (error) => { console.log("\u{1F504} Upload failed, attempting inline storage fallback..."); throw error; }); this.fallbackStrategies.set("RETRIEVAL_FAILED", async (error) => { console.log("\u{1F504} Retrieval failed, trying alternative gateways..."); throw error; }); this.fallbackStrategies.set("QUOTA_EXCEEDED", async (error) => { console.warn("\u26A0\uFE0F IPFS quota exceeded - consider upgrading plan or cleaning up old content"); throw error; }); } async handleError(error, fallbackValue) { const strategy = this.fallbackStrategies.get(error.type); if (strategy) { try { const result = await strategy(error); return result; } catch (_fallbackError) { console.warn("Fallback strategy also failed:", _fallbackError instanceof Error ? _fallbackError.message : String(_fallbackError)); } } if (fallbackValue !== void 0) { console.log("Using provided fallback value"); return fallbackValue; } throw error; } registerFallback(errorType, strategy) { this.fallbackStrategies.set(errorType, strategy); } }; var IPFSErrorHandler = class { retryHandler; fallbackHandler; constructor(retryConfig) { this.retryHandler = new RetryHandler({ ...DEFAULT_RETRY_CONFIG, ...retryConfig }); this.fallbackHandler = new FallbackHandler(); } async executeWithErrorHandling(operation, context, fallbackValue) { try { const result = await this.retryHandler.execute(async () => { const opResult = await operation(); if (!opResult.success && opResult.error) { throw new IPFSOperationError( opResult.error, opResult.message ?? `IPFS operation failed: ${opResult.error}` ); } return opResult; }, context); return result; } catch (error) { const ipfsError = error instanceof IPFSOperationError ? error : new IPFSOperationError("PROVIDER_ERROR", error instanceof Error ? error.message : String(error)); try { const fallbackResult = await this.fallbackHandler.handleError(ipfsError, fallbackValue); return { success: true, data: fallbackResult, message: "Operation succeeded using fallback strategy" }; } catch { return { success: false, error: ipfsError.type, message: ipfsError.message, duration: 0 }; } } } /** * Register a custom fallback strategy */ registerFallback(errorType, strategy) { this.fallbackHandler.registerFallback(errorType, strategy); } /** * Get error handler statistics */ getStats() { return { retryStats: this.retryHandler.getStats(), registeredFallbacks: Array.from(this.fallbackHandler["fallbackStrategies"].keys()) }; } /** * Reset all error handling state */ reset() { this.retryHandler.reset(); } }; function createIPFSErrorHandler(config) { const handler = new IPFSErrorHandler(config?.retryConfig); if (config?.customFallbacks) { for (const { errorType, strategy } of config.customFallbacks) { handler.registerFallback(errorType, strategy); } } return handler; } function isIPFSError(error) { return error instanceof IPFSOperationError; } async function withIPFSErrorHandling(operation, context, errorHandler) { const handler = errorHandler ?? new IPFSErrorHandler(); return handler.executeWithErrorHandling( async () => { try { const result = await operation(); return { success: true, data: result }; } catch (error) { const ipfsError = error instanceof IPFSOperationError ? error.type : "PROVIDER_ERROR"; return { success: false, error: ipfsError, message: error instanceof Error ? error.message : String(error) }; } }, context ); } // ../../node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/vendor/ansi-styles/index.js var ANSI_BACKGROUND_OFFSET = 10; var wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`; var wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`; var wrapAnsi16m = (offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`; var styles = { modifier: { reset: [0, 0], // 21 isn't widely supported and 22 does the same thing bold: [1, 22], dim: [2, 22], italic: [3, 23], underline: [4, 24], overline: [53, 55], inverse: [7, 27], hidden: [8, 28], strikethrough: [9, 29] }, color: { black: [30, 39], red: [31, 39], green: [32, 39], yellow: [33, 39], blue: [34, 39], magenta: [35, 39], cyan: [36, 39], white: [37, 39], // Bright color blackBright: [90, 39], gray: [90, 39], // Alias of `blackBright` grey: [90, 39], // Alias of `blackBright` redBright: [91, 39], greenBright: [92, 39], yellowBright: [93, 39], blueBright: [94, 39], magentaBright: [95, 39], cyanBright: [96, 39], whiteBright: [97, 39] }, bgColor: { bgBlack: [40, 49], bgRed: [41, 49], bgGreen: [42, 49], bgYellow: [43, 49], bgBlue: [44, 49], bgMagenta: [45, 49], bgCyan: [46, 49], bgWhite: [47, 49], // Bright color bgBlackBright: [100, 49], bgGray: [100, 49], // Alias of `bgBlackBright` bgGrey: [100, 49], // Alias of `bgBlackBright` bgRedBright: [101, 49], bgGreenBright: [102, 49], bgYellowBright: [103, 49], bgBlueBright: [104, 49], bgMagentaBright: [105, 49], bgCyanBright: [106, 49], bgWhiteBright: [107, 49] } }; Object.keys(styles.modifier); var foregroundColorNames = Object.keys(styles.color); var backgroundColorNames = Object.keys(styles.bgColor); [...foregroundColorNames, ...backgroundColorNames]; function assembleStyles() { const codes = /* @__PURE__ */ new Map(); for (const [groupName, group] of Object.entries(styles)) { for (const [styleName, style] of Object.entries(group)) { styles[styleName] = { open: `\x1B[${style[0]}m`, close: `\x1B[${style[1]}m` }; group[styleName] = styles[styleName]; codes.set(style[0], style[1]); } Object.defineProperty(styles, groupName, { value: group, enumerable: false }); } Object.defineProperty(styles, "codes", { value: codes, enumerable: false }); styles.color.close = "\x1B[39m"; styles.bgColor.close = "\x1B[49m"; styles.color.ansi = wrapAnsi16(); styles.color.ansi256 = wrapAnsi256(); styles.color.ansi16m = wrapAnsi16m(); styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET); styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET); styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET); Object.defineProperties(styles, { rgbToAnsi256: { value(red, green, blue) { if (red === green && green === blue) { if (red < 8) { return 16; } if (red > 248) { return 231; } return Math.round((red - 8) / 247 * 24) + 232; } return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5); }, enumerable: false }, hexToRgb: { value(hex) { const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16)); if (!matches) { return [0, 0, 0]; } let [colorString] = matches; if (colorString.length === 3) { colorString = [...colorString].map((character) => character + character).join(""); } const integer = Number.parseInt(colorString, 16); return [ /* eslint-disable no-bitwise */ integer >> 16 & 255, integer >> 8 & 255, integer & 255 /* eslint-enable no-bitwise */ ]; }, enumerable: false }, hexToAnsi256: { value: (hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)), enumerable: false }, ansi256ToAnsi: { value(code) { if (code < 8) { return 30 + code; } if (code < 16) { return 90 + (code - 8); } let red; let green; let blue; if (code >= 232) { red = ((code - 232) * 10 + 8) / 255; green = red; blue = red; } else { code -= 16; const remainder = code % 36; red = Math.floor(code / 36) / 5; green = Math.floor(remainder / 6) / 5; blue = remainder % 6 / 5; } const value = Math.max(red, green, blue) * 2; if (value === 0) { return 30; } let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red)); if (value === 2) { result += 60; } return result; }, enumerable: false }, rgbToAnsi: { value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)), enumerable: false }, hexToAnsi: { value: (hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)), enumerable: false } }); return styles; } var ansiStyles = assembleStyles(); var ansi_styles_default = ansiStyles; function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process2.argv) { const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--"; const position = argv.indexOf(prefix + flag); const terminatorPosition = argv.indexOf("--"); return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition); } var { env } = process2; var flagForceColor; if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) { flagForceColor = 0; } else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) { flagForceColor = 1; } function envForceColor() { if ("FORCE_COLOR" in env) { if (env.FORCE_COLOR === "true") { return 1; } if (env.FORCE_COLOR === "false") { return 0; } return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3); } } function translateLevel(level) { if (level === 0) { return false; } return { level, hasBasic: true, has256: level >= 2, has16m: level >= 3 }; } function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) { const noFlagForceColor = envForceColor(); if (noFlagForceColor !== void 0) { flagForceColor = noFlagForceColor; } const forceColor = sniffFlags ? flagForceColor : noFlagForceColor; if (forceColor === 0) { return 0; } if (sniffFlags) { if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) { return 3; } if (hasFlag("color=256")) { return 2; } } if ("TF_BUILD" in env && "AGENT_NAME" in env) { return 1; } if (haveStream && !streamIsTTY && forceColor === void 0) { return 0; } const min = forceColor || 0; if (env.TERM === "dumb") { return min; } if (process2.platform === "win32") { const osRelease = os.release().split("."); if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) { return Number(osRelease[2]) >= 14931 ? 3 : 2; } return 1; } if ("CI" in env) { if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => key in env)) { return 3; } if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => sign in env) || env.CI_NAME === "codeship") { return 1; } return min; } if ("TEAMCITY_VERSION" in env) { return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0; } if (env.COLORTERM === "truecolor") { return 3; } if (env.TERM === "xterm-kitty") { return 3; } if (env.TERM === "xterm-ghostty") { return 3; } if (env.TERM === "wezterm") { return 3; } if ("TERM_PROGRAM" in env) { const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10); switch (env.TERM_PROGRAM) { case "iTerm.app": { return version >= 3 ? 3 : 2; } case "Apple_Terminal": { return 2; } } } if (/-256(color)?$/i.test(env.TERM)) { return 2; } if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) { return 1; } if ("COLORTERM" in env) { return 1; } return min; } function createSupportsColor(stream, options = {}) { const level = _supportsColor(stream, { streamIsTTY: stream && stream.isTTY, ...options }); return translateLevel(level); } var supportsColor = { stdout: createSupportsColor({ isTTY: tty.isatty(1) }), stderr: createSupportsColor({ isTTY: tty.isatty(2) }) }; var supports_color_default = supportsColor; // ../../node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/utilities.js function stringReplaceAll(string, substring, replacer) { let index = string.indexOf(substring); if (index === -1) { return string; } const substringLength = substring.length; let endIndex = 0; let returnValue = ""; do { returnValue += string.slice(endIndex, index) + substring + replacer; endIndex = index + substringLength; index = string.indexOf(substring, endIndex); } while (index !== -1); returnValue += string.slice(endIndex); return returnValue; } function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) { let endIndex = 0; let returnValue = ""; do { const gotCR = string[index - 1] === "\r"; returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix; endIndex = index + 1; index = string.indexOf("\n", endIndex); } while (index !== -1); returnValue += string.slice(endIndex); return returnValue; } // ../../node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/index.js var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default; var GENERATOR = /* @__PURE__ */ Symbol("GENERATOR"); var STYLER = /* @__PURE__ */ Symbol("STYLER"); var IS_EMPTY = /* @__PURE__ */ Symbol("IS_EMPTY"); var levelMapping = [ "ansi", "ansi", "ansi256", "ansi16m" ]; var styles2 = /* @__PURE__ */ Object.create(null); var applyOptions = (object, options = {}) => { if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) { throw new Error("The `level` option should be an integer from 0 to 3"); } const colorLevel = stdoutColor ? stdoutColor.level : 0; object.level = options.level === void 0 ? colorLevel : options.level; }; var chalkFactory = (options) => { const chalk2 = (...strings) => strings.join(" "); applyOptions(chalk2, options); Object.setPrototypeOf(chalk2, createChalk.prototype); return chalk2; }; function createChalk(options) { return chalkFactory(options); } Object.setPrototypeOf(createChalk.prototype, Function.prototype); for (const [styleName, style] of Object.entries(ansi_styles_default)) { styles2[styleName] = { get() { const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]); Object.defineProperty(this, styleName, { value: builder }); return builder; } }; } styles2.visible = { get() { const builder = createBuilder(this, this[STYLER], true); Object.defineProperty(this, "visible", { value: builder }); return builder; } }; var getModelAnsi = (model, level, type, ...arguments_) => { if (model === "rgb") { if (level === "ansi16m") { return ansi_styles_default[type].ansi16m(...arguments_); } if (level === "ansi256") { return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_)); } return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_)); } if (model === "hex") { return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_)); } return ansi_styles_default[type][model](...arguments_); }; var usedModels = ["rgb", "hex", "ansi256"]; for (const model of usedModels) { styles2[model] = { get() { const { level } = this; return function(...arguments_) { const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]); return createBuilder(this, styler, this[IS_EMPTY]); }; } }; const bgModel = "bg" + model[0].toUpperCase() + model.slice(1); styles2[bgModel] = { get() { const { level } = this; return function(...arguments_) { const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]); return createBuilder(this, styler, this[IS_EMPTY]); }; } }; } var proto = Object.defineProperties(() => { }, { ...styles2, level: { enumerable: true, get() { return this[GENERATOR].level; }, set(level) { this[GENERATOR].level = level; } } }); var createStyler = (open, close, parent) => { let openAll; let closeAll; if (parent === void 0) { openAll = open; closeAll = close; } else { openAll = parent.openAll + open; closeAll = close + parent.closeAll; } return { open, close, openAll, closeAll, parent }; }; var createBuilder = (self, _styler, _isEmpty) => { const builder = (...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" ")); Object.setPrototypeOf(builder, proto); builder[GENERATOR] = self; builder[STYLER] = _styler; builder[IS_EMPTY] = _isEmpty; return builder; }; var applyStyle = (self, string) => { if (self.level <= 0 || !string) { return self[IS_EMPTY] ? "" : string; } let styler = self[STYLER]; if (styler === void 0) { return string; } const { openAll, closeAll } = styler; if (string.includes("\x1B")) { while (styler !== void 0) { string = stringReplaceAll(string, styler.close, styler.open); styler = styler.parent; } } const lfIndex = string.indexOf("\n"); if (lfIndex !== -1) { string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex); } return openAll + string + closeAll; }; Object.defineProperties(createChalk.prototype, styles2); var chalk = createChalk(); createChalk({ level: stderrColor ? stderrColor.level : 0 }); var source_default = chalk; var WalletFundingService = class { rpc; commitment = "confirmed"; isDevnetUrl; constructor(rpcUrl, commitment = "confirmed") { this.isDevnetUrl = rpcUrl.includes("devnet"); this.rpc = createSolanaRpc(rpcUrl); this.commitment = commitment; } /** * Fund a wallet using multiple strategies */ async fundWallet(targetWallet, options) { const { amount, minAmount = amount, maxRetries = 3, retryDelay = 2e3, useTreasury = true, treasuryWallet, fundedWallets = [], verbose = false } = options; const log = (message) => { if (verbose) { console.log(source_default.gray(`[WalletFunding] ${message}`)); } }; let attempts = 0; try { const currentBalance = await this.getBalance(targetWallet); log(`Current balance: ${this.formatSol(currentBalance)} SOL`); if (currentBalance >= minAmount) { log(`Wallet already has sufficient balance`); return { success: true, balance: currentBalance, method: "existing", attempts: 0 }; } const needed = amount - currentBalance; log(`Need to fund: ${this.formatSol(needed)} SOL`); if (this.isDevnetUrl && "requestAirdrop" in this.rpc) { log(`Attempting devnet airdrop...`); const airdropResult = await this.tryAirdrop( targetWallet, needed, maxRetries, retryDelay, verbose ); if (airdropResult.success) { const finalBalance = await this.getBalance(targetWallet); return { success: true, balance: finalBalance, method: "airdrop", attempts: airdropResult.attempts, signature: airdropResult.signature }; } attempts += airdropResult.attempts; log(`Airdrop failed after ${airdropResult.attempts} attempts`); } if (useTreasury && treasuryWallet) { log(`Attempting treasury wallet funding...`); const treasuryResult = await this.tryTreasuryFunding( targetWallet, needed, treasuryWallet, verbose ); if (treasuryResult.success) { const finalBalance = await this.getBalance(targetWallet); return { success: true, balance: finalBalance, method: "treasury", attempts: attempts + 1, signature: treasuryResult.signature }; } attempts++; log(`Treasury funding failed: ${treasuryResult.error}`); } for (const fundedWallet of fundedWallets) { log(`Attempting funding from additional wallet...`); const fundedResult =