@ghostspeak/sdk
Version:
TypeScript SDK for GhostSpeak AI Agent Commerce Protocol - Production Ready Beta
1,456 lines (1,446 loc) • 73.7 kB
JavaScript
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 =