@ghostspeak/sdk 2.0.6 → 2.0.8

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 (118) hide show
  1. package/README.md +295 -30
  2. package/dist/GhostSpeakClient-bnXwUPHI.d.ts +1011 -0
  3. package/dist/StakingModule-DunDShLq.d.ts +2446 -0
  4. package/dist/{agent-M74TCRON.js → agent-S42FIMR7.js} +4 -4
  5. package/dist/{agent-M74TCRON.js.map → agent-S42FIMR7.js.map} +1 -1
  6. package/dist/batch-operations-45CQFEID.js +4 -0
  7. package/dist/batch-operations-45CQFEID.js.map +1 -0
  8. package/dist/browser-CI5_6Gzk.d.ts +234 -0
  9. package/dist/browser.d.ts +6 -576
  10. package/dist/browser.js +15 -842
  11. package/dist/browser.js.map +1 -1
  12. package/dist/chunk-46QWY3MG.js +156 -0
  13. package/dist/chunk-46QWY3MG.js.map +1 -0
  14. package/dist/{chunk-F3DZMBUA.js → chunk-5QBSC4T4.js} +327 -493
  15. package/dist/chunk-5QBSC4T4.js.map +1 -0
  16. package/dist/chunk-5QZVFUXB.js +4176 -0
  17. package/dist/chunk-5QZVFUXB.js.map +1 -0
  18. package/dist/chunk-6XCCMJ6M.js +1865 -0
  19. package/dist/chunk-6XCCMJ6M.js.map +1 -0
  20. package/dist/chunk-A7ALCVUI.js +98 -0
  21. package/dist/chunk-A7ALCVUI.js.map +1 -0
  22. package/dist/chunk-AWMGX3OX.js +814 -0
  23. package/dist/chunk-AWMGX3OX.js.map +1 -0
  24. package/dist/chunk-BF3IQ35I.js +284 -0
  25. package/dist/chunk-BF3IQ35I.js.map +1 -0
  26. package/dist/chunk-BQDGRTVP.js +168 -0
  27. package/dist/chunk-BQDGRTVP.js.map +1 -0
  28. package/dist/chunk-IQM5RASO.js +8502 -0
  29. package/dist/chunk-IQM5RASO.js.map +1 -0
  30. package/dist/chunk-JYXSOXCP.js +3850 -0
  31. package/dist/chunk-JYXSOXCP.js.map +1 -0
  32. package/dist/chunk-OXA7MECJ.js +7787 -0
  33. package/dist/chunk-OXA7MECJ.js.map +1 -0
  34. package/dist/chunk-QLRWUHN2.js +231 -0
  35. package/dist/chunk-QLRWUHN2.js.map +1 -0
  36. package/dist/chunk-SKMJJ3Q6.js +125 -0
  37. package/dist/chunk-SKMJJ3Q6.js.map +1 -0
  38. package/dist/chunk-TTB4OS2D.js +69 -0
  39. package/dist/chunk-TTB4OS2D.js.map +1 -0
  40. package/dist/chunk-UP2VWCW5.js +33 -0
  41. package/dist/{chunk-NSBPE2FW.js.map → chunk-UP2VWCW5.js.map} +1 -1
  42. package/dist/{chunk-UJUGGLMT.js → chunk-VQZQCHUT.js} +5 -5
  43. package/dist/{chunk-UJUGGLMT.js.map → chunk-VQZQCHUT.js.map} +1 -1
  44. package/dist/client.d.ts +4 -4
  45. package/dist/client.js +11 -10
  46. package/dist/createAgentAuthorization-KGZNXZBT.js +5 -0
  47. package/dist/createAgentAuthorization-KGZNXZBT.js.map +1 -0
  48. package/dist/credentials.js +1 -1
  49. package/dist/crypto.js +2 -2
  50. package/dist/errors.js +1 -1
  51. package/dist/feature-flags-B1g0DCPe.d.ts +1181 -0
  52. package/dist/generated-QJREJQ2C.js +9 -0
  53. package/dist/{generated-VNLHMR6Y.js.map → generated-QJREJQ2C.js.map} +1 -1
  54. package/dist/{ghostspeak_wasm-SB2RPJ3D.js → ghostspeak_wasm-F227HOSM.js} +3 -3
  55. package/dist/{ghostspeak_wasm-SB2RPJ3D.js.map → ghostspeak_wasm-F227HOSM.js.map} +1 -1
  56. package/dist/index.d.ts +1179 -1498
  57. package/dist/index.js +356 -3578
  58. package/dist/index.js.map +1 -1
  59. package/dist/metafile-esm.json +1 -1
  60. package/dist/minimal/core-minimal.d.ts +2446 -1245
  61. package/dist/minimal/core-minimal.js +9 -9
  62. package/dist/minimal/core-minimal.js.map +1 -1
  63. package/dist/nacl-fast-W5BJ3KZ2.js +2229 -0
  64. package/dist/nacl-fast-W5BJ3KZ2.js.map +1 -0
  65. package/dist/pda-4KP7CURF.js +4 -0
  66. package/dist/pda-4KP7CURF.js.map +1 -0
  67. package/dist/pda-Ce7VYg4T.d.ts +25 -0
  68. package/dist/reputation-types-Yebf0Rm_.d.ts +1071 -0
  69. package/dist/revokeAuthorization-2ZRO6GUZ.js +5 -0
  70. package/dist/revokeAuthorization-2ZRO6GUZ.js.map +1 -0
  71. package/dist/signature-verification-DGxR4aYQ.d.ts +448 -0
  72. package/dist/types.js +1 -1
  73. package/dist/updateReputationWithAuth-PCEUOCFV.js +5 -0
  74. package/dist/updateReputationWithAuth-PCEUOCFV.js.map +1 -0
  75. package/dist/utils.d.ts +69 -203
  76. package/dist/utils.js +15 -153
  77. package/dist/utils.js.map +1 -1
  78. package/package.json +27 -34
  79. package/dist/.tsbuildinfo +0 -1
  80. package/dist/GhostSpeakClient-D_66Uzsf.d.ts +0 -707
  81. package/dist/GovernanceModule-DQYYys-H.d.ts +0 -1766
  82. package/dist/chunk-APCKGD23.js +0 -1328
  83. package/dist/chunk-APCKGD23.js.map +0 -1
  84. package/dist/chunk-ASQXX4IT.js +0 -572
  85. package/dist/chunk-ASQXX4IT.js.map +0 -1
  86. package/dist/chunk-COGZFWOT.js +0 -19657
  87. package/dist/chunk-COGZFWOT.js.map +0 -1
  88. package/dist/chunk-F3DZMBUA.js.map +0 -1
  89. package/dist/chunk-GMHIUK2R.js +0 -7526
  90. package/dist/chunk-GMHIUK2R.js.map +0 -1
  91. package/dist/chunk-IAWBZYPE.js +0 -356
  92. package/dist/chunk-IAWBZYPE.js.map +0 -1
  93. package/dist/chunk-NSBPE2FW.js +0 -15
  94. package/dist/chunk-OWYHJG6H.js +0 -13311
  95. package/dist/chunk-OWYHJG6H.js.map +0 -1
  96. package/dist/chunk-RDDPOFR5.js +0 -3
  97. package/dist/chunk-RDDPOFR5.js.map +0 -1
  98. package/dist/chunk-RERCHKZP.js +0 -35
  99. package/dist/chunk-RERCHKZP.js.map +0 -1
  100. package/dist/chunk-TVVGXYCI.js +0 -2887
  101. package/dist/chunk-TVVGXYCI.js.map +0 -1
  102. package/dist/chunk-ZGP5552B.js +0 -377
  103. package/dist/chunk-ZGP5552B.js.map +0 -1
  104. package/dist/chunk-ZWOYNHVK.js +0 -196
  105. package/dist/chunk-ZWOYNHVK.js.map +0 -1
  106. package/dist/dist/.tsbuildinfo +0 -1
  107. package/dist/elgamal-VZLWB3XK.js +0 -5
  108. package/dist/elgamal-VZLWB3XK.js.map +0 -1
  109. package/dist/feature-flags-V722ZuXO.d.ts +0 -3512
  110. package/dist/generated-VNLHMR6Y.js +0 -5
  111. package/dist/ipfs-types-BOt9ZNg4.d.ts +0 -592
  112. package/dist/multisigConfig-BzEhy6jy.d.ts +0 -58
  113. package/dist/pda-B_nS8SbD.d.ts +0 -114
  114. package/dist/pda-S4BFJVGE.js +0 -4
  115. package/dist/pda-S4BFJVGE.js.map +0 -1
  116. package/dist/system-addresses-BFNLEbFx.d.ts +0 -857
  117. package/dist/token-2022-rpc-RALH4RK7.js +0 -593
  118. package/dist/token-2022-rpc-RALH4RK7.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,32 +1,28 @@
1
- export { WorkOrderModule } from './chunk-ZWOYNHVK.js';
2
- export { CredentialKind, CredentialModule, CredentialStatus, GhostSpeakClient, MultisigModule, UnifiedCredentialService, GhostSpeakClient_default as default, lamportsToSol, sol } from './chunk-APCKGD23.js';
3
- export { AgentModule, BaseModule, ChannelModule, DEFAULT_IPFS_CONFIG, EscrowModule, GHOSTSPEAK_PROGRAM_ID, GovernanceModule, IPFSUtils, InstructionBuilder, MarketplaceModule, RpcClient, Token2022Module, createIPFSUtils, createMetadataUri, determineStorageMethod } from './chunk-TVVGXYCI.js';
1
+ export { batchGetAccounts, batchGetAccountsWithRetry, batchGetAndMap, batchGetExistingAccounts, createBatchFetcher } from './chunk-SKMJJ3Q6.js';
2
+ export { BaseReputationAdapter, GHOSTSPEAK_PROGRAM_ID, ReputationSource } from './chunk-TTB4OS2D.js';
3
+ export { AuthorizationModule, DidModule, GhostSpeakClient, PrivacyModule, UnifiedCredentialService, calculateVisibleScore, canViewerAccess, GhostSpeakClient_default as default, filterMetricsByVisibility, getDefaultMetricVisibility, getRangeDisplayString, getReputationTier, getScoreRange, getTierDisplayName, lamportsToSol, sol, validatePrivacySettings } from './chunk-6XCCMJ6M.js';
4
+ import { init_MultiSourceAggregator } from './chunk-JYXSOXCP.js';
5
+ 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, VerificationMethodType, VerificationRelationship, canPerformAction, createEd25519VerificationMethod, createIPFSUtils, createMetadataUri, createServiceEndpoint, deriveDidDocumentPda, determineStorageMethod, didDocumentToJson, exportAsW3CDidDocument, generateDidString, getIdentifierFromDid, getMethodsForRelationship, getNetworkFromDid, isDidActive, parseDidString, validateDidString } from './chunk-JYXSOXCP.js';
4
6
  export { AccountNotFoundError, ErrorFactory, ErrorHandler, GhostSpeakError, InsufficientBalanceError, InvalidInputError, NetworkError, SimulationFailedError, TimeoutError, TransactionFailedError, ValidationError } from './chunk-5DMB3UAV.js';
5
- export { decrypt, elgamal_exports as elgamal, encrypt, generateKeypair, generateTransferProof, generateWithdrawProof, isWasmAvailable, loadWasmModule, wasm_bridge_exports as wasmBridge } from './chunk-UJUGGLMT.js';
6
- import { getFeatureFlags, ClientEncryptionService } from './chunk-F3DZMBUA.js';
7
- export { ClientEncryptionService, FeatureFlagManager, TokenAccountState, TokenExtension, TokenProgram, basisPointsToPercentage, calculateCompoundInterest, calculateInterest, calculateRequiredAmountForNetTransfer, calculateTransferFee, canTransfer, createDiscriminatorErrorMessage, createMigrationPlan, createMigrationReport, createTransferHookInstruction, deriveAssociatedTokenAddress, deriveSplTokenAssociatedTokenAddress, deriveToken2022AssociatedTokenAddress, deserializeTokenMetadata, detectTokenProgram, diagnoseAccountFromChain, diagnoseBatchFromChain, estimateAccumulatedFees, estimateComputeUnits, exportDiagnosticReport, extractLegacyData, formatBasisPoints, formatTokenAmount, generateConfidentialTransferProof, generateLocalPrivacyProof, getAllAssociatedTokenAddresses, getAssociatedTokenAccount, getConfidentialTransferConfig, getFeatureFlags, getInterestBearingConfig, getMigrationInstructions, getRequiredExtensions, getTokenProgramAddress, getTokenProgramFromAddress, getTokenProgramType, getTransferFeeConfig, hasConfidentialTransferExtension, hasInterestBearingExtension, hasTransferFeeExtension, inspectAccountData, isFeatureEnabled, isToken2022Mint, parseTokenAmount, percentageToBasisPoints, runAccountDiagnostics, runBatchDiagnostics, safeDecodeAgent, serializeTokenMetadata, simulateMigration, validateAccountDiscriminator, validateAssociatedTokenAddress, validateTransferHookInstruction, verifyConfidentialTransferProof, verifyLocalPrivacyProof } from './chunk-F3DZMBUA.js';
8
- import './chunk-IAWBZYPE.js';
9
- export { deriveMultisigPda, deriveProposalPda } from './chunk-ZGP5552B.js';
10
- export { ASSOCIATED_TOKEN_PROGRAM_ADDRESS, GhostSpeakSDKError, INSTRUCTION_MAPPINGS, IPFSClient, InstructionValidationError, NATIVE_MINT_ADDRESS, TOKEN_2022_PROGRAM_ADDRESS, TOKEN_PROGRAM_ADDRESS, createAccountMismatchError, createErrorContext, debugInstructionCall, enhanceErrorMessage, enhanceTransactionError, extractInstructionName, generateAccountValidationError, getAccountRequirements, getInstructionMapping, getPDAAccounts, getRequiredSigners, getWritableAccounts, isKnownInstruction, logEnhancedError, validateInstructionAccounts, validatePreconditions, withEnhancedErrors, withEnhancedErrorsSync } from './chunk-OWYHJG6H.js';
11
- import { GHOSTSPEAK_MARKETPLACE_PROGRAM_ADDRESS, getCreateA2aSessionInstructionAsync, fetchA2ASession, getSendA2aMessageInstruction, getUpdateA2aStatusInstruction, fetchMaybeA2ASession, fetchA2AMessage, fetchA2AStatus, getCreateCommunicationSessionInstructionAsync, getSendCommunicationMessageInstruction } from './chunk-COGZFWOT.js';
12
- export { GHOSTSPEAK_MARKETPLACE_PROGRAM_ADDRESS, getAddMessageReactionInstruction, getCancelEscrowInstruction, getChannelDecoder, getCompleteEscrowInstruction, getCreateEnhancedChannelInstructionAsync, getCreateEscrowInstructionAsync, getCreateWorkOrderInstruction, getDisputeEscrowInstruction, getEscrowDecoder, getJoinChannelInstruction, getLeaveChannelInstruction, getMessageDecoder, getProcessPartialRefundInstruction, getProcessPaymentInstruction, getRegisterAgentInstructionAsync, getRejectWorkDeliveryInstruction, getSendEnhancedMessageInstructionAsync, getSubmitWorkDeliveryInstruction, getUpdateChannelSettingsInstruction, getVerifyWorkDeliveryInstruction, getWorkDeliveryDecoder, getWorkOrderDecoder } from './chunk-COGZFWOT.js';
13
- import { getAgentDecoder, fetchMaybeAgent, getCommunicationSessionDataDecoder } from './chunk-GMHIUK2R.js';
14
- export { AuctionStatus, AuctionType, DisputeStatus, ParticipantType, ProposalStatus, WorkOrderStatus, getAgentDecoder } from './chunk-GMHIUK2R.js';
15
- export { deriveA2AMessagePda, deriveA2ASessionPda, deriveAgentPda, deriveAgentVerificationPda, deriveChannelPda, deriveEscrowPDA, deriveJobApplicationPda, deriveJobPostingPda, derivePaymentPda, deriveServiceListingPda, deriveServicePurchasePda, deriveUserRegistryPda, deriveWorkDeliveryPda, deriveWorkOrderPda, findProgramDerivedAddress } from './chunk-ASQXX4IT.js';
16
- import './chunk-RERCHKZP.js';
17
- import './chunk-RDDPOFR5.js';
18
- export { AgentType, ChannelType, ErrorCode, EscrowStatus, MessageType, isError, isSuccess, unwrap } from './chunk-SRS2SKFS.js';
7
+ export { decrypt, elgamal_exports as elgamal, encrypt, generateKeypair, generateTransferProof, generateWithdrawProof, isWasmAvailable, loadWasmModule, wasm_bridge_exports as wasmBridge } from './chunk-VQZQCHUT.js';
8
+ import { getFeatureFlags, ClientEncryptionService } from './chunk-5QBSC4T4.js';
9
+ 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-5QBSC4T4.js';
10
+ export { deriveAgentPda, deriveAgentVerificationPda, deriveUserRegistryPda, findProgramDerivedAddress } from './chunk-BF3IQ35I.js';
11
+ export { createAuthorizationMessage, createSignedAuthorization, deserializeAuthorization, generateNonce, getAuthorizationId, isAuthorizationExhausted, isAuthorizationExpired, serializeAuthorization, signAuthorizationMessage, validateAuthorizationNetwork, verifyAuthorizationSignature } from './chunk-BQDGRTVP.js';
12
+ import { init_reputation_tag_engine, init_reputation_tags, ExternalIdNotFoundError, GhostSpeakError, GhostNotFoundError } from './chunk-OXA7MECJ.js';
13
+ 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-OXA7MECJ.js';
14
+ export { getApproveDeliveryInstruction, getArbitrateDisputeInstruction, getClaimGhostInstruction, getCreateDidDocumentInstructionAsync, getCreateEscrowInstructionAsync, getDeactivateDidDocumentInstructionAsync, getFileDisputeInstruction, getGhostProtectEscrowDecoder, getInitializeStakingConfigInstructionAsync, getRegisterAgentInstructionAsync, getResolveDidDocumentInstructionAsync, getSlashStakeInstructionAsync, getStakeGhostInstructionAsync, getStakingAccountDecoder, getStakingConfigDecoder, getSubmitDeliveryInstruction, getUnstakeGhostInstructionAsync, getUpdateDidDocumentInstructionAsync, getUpdateReputationTagsInstructionAsync } from './chunk-IQM5RASO.js';
15
+ export { ProposalStatus, decodeAgent, fetchAgent, fetchMaybeAgent, getAgentDecoder } from './chunk-5QZVFUXB.js';
16
+ import './chunk-46QWY3MG.js';
17
+ import './chunk-A7ALCVUI.js';
18
+ import './chunk-QLRWUHN2.js';
19
+ export { GHOSTSPEAK_MARKETPLACE_PROGRAM_ADDRESS } from './chunk-AWMGX3OX.js';
20
+ export { AgentType, ChannelType, ErrorCode, EscrowStatus, MessageType, ParticipantType, isError, isSuccess, unwrap } from './chunk-SRS2SKFS.js';
19
21
  export { CrossmintVCClient, GHOSTSPEAK_CREDENTIAL_TYPES } from './chunk-RIZZPLLB.js';
20
- import { __export, __require } from './chunk-NSBPE2FW.js';
21
- import { createSolanaRpc, lamports, pipe, createTransactionMessage, setTransactionMessageFeePayer, setTransactionMessageLifetimeUsingBlockhash, appendTransactionMessageInstructions, signTransactionMessageWithSigners, getBase64EncodedWireTransaction, createKeyPairSignerFromBytes, generateKeyPairSigner, appendTransactionMessageInstruction, getProgramDerivedAddress, getBytesEncoder, getAddressEncoder } from '@solana/kit';
22
+ import { __require } from './chunk-UP2VWCW5.js';
23
+ import { createSolanaRpc, lamports, pipe, createTransactionMessage, setTransactionMessageFeePayer, setTransactionMessageLifetimeUsingBlockhash, appendTransactionMessageInstructions, signTransactionMessageWithSigners, getBase64EncodedWireTransaction, createKeyPairSignerFromBytes, generateKeyPairSigner } from '@solana/kit';
22
24
  export { address, createKeyPairSignerFromBytes, createSolanaRpc, generateKeyPairSigner } from '@solana/kit';
23
25
  import { address } from '@solana/addresses';
24
- import { pipe as pipe$1 } from '@solana/functional';
25
- import { EventEmitter } from 'events';
26
- import { eq, sql, and, desc } from 'drizzle-orm';
27
- import { drizzle } from 'drizzle-orm/libsql';
28
- import { createClient } from '@libsql/client';
29
- import { sqliteTable, integer, text, index, real } from 'drizzle-orm/sqlite-core';
30
26
  import { getTransferSolInstruction } from '@solana-program/system';
31
27
  import { promises } from 'fs';
32
28
  import process2 from 'process';
@@ -36,3625 +32,407 @@ import bs58 from 'bs58';
36
32
  import { sha256 } from '@noble/hashes/sha256';
37
33
  import { bytesToHex, hexToBytes } from '@noble/curves/abstract/utils';
38
34
 
39
- var X402Client = class extends EventEmitter {
40
- constructor(rpc, wallet) {
41
- super();
42
- this.rpc = rpc;
43
- this.wallet = wallet;
44
- }
45
- /**
46
- * Create an x402 payment request
47
- * Returns HTTP 402 compatible headers
48
- */
49
- createPaymentRequest(params) {
50
- if (!this.wallet) {
51
- throw new Error("Wallet required to create payment request");
52
- }
53
- const recipient = this.wallet.address;
54
- return {
55
- recipient,
56
- amount: params.amount,
57
- token: params.token,
58
- description: params.description,
59
- metadata: params.metadata,
60
- expiresAt: params.expiresAt ?? Date.now() + 3e5,
61
- // 5 minutes default
62
- requiresReceipt: true
63
- };
64
- }
65
- /**
66
- * Create HTTP 402 response headers
67
- */
68
- createPaymentHeaders(request) {
69
- const headers = {
70
- "X-Payment-Address": request.recipient,
71
- "X-Payment-Amount": request.amount.toString(),
72
- "X-Payment-Token": request.token,
73
- "X-Payment-Blockchain": "solana"
74
- };
75
- if (request.description) {
76
- headers["X-Payment-Description"] = request.description;
77
- }
78
- if (request.expiresAt) {
79
- headers["X-Payment-Expires-At"] = request.expiresAt.toString();
80
- }
81
- return headers;
82
- }
83
- /**
84
- * Execute an x402 payment
85
- */
86
- async pay(request) {
87
- if (!this.wallet) {
88
- throw new Error("Wallet required to make payment");
89
- }
90
- if (request.amount <= 0n) {
91
- throw new Error("Payment amount must be greater than zero");
92
- }
93
- if (!request.recipient) {
94
- throw new Error("Payment recipient address is required");
95
- }
96
- if (!request.token) {
97
- throw new Error("Payment token address is required");
98
- }
99
- this.emit("payment_created", {
100
- type: "payment_created",
101
- request,
102
- timestamp: Date.now()
103
- });
104
- try {
105
- const transferIx = await this.createTransferInstruction(
106
- request.recipient,
107
- request.amount,
108
- request.token
109
- ).catch((error) => {
110
- throw new Error(
111
- `Failed to create transfer instruction: ${error instanceof Error ? error.message : "Unknown error"}`
112
- );
113
- });
114
- const memoIx = this.createMemoInstruction(
115
- `x402:${request.description}:${JSON.stringify(request.metadata ?? {})}`
116
- );
117
- const { value: latestBlockhash } = await this.rpc.getLatestBlockhash().send().catch((error) => {
118
- throw new Error(
119
- `Failed to fetch latest blockhash: ${error instanceof Error ? error.message : "Unknown error"}`
120
- );
121
- });
122
- const feePayerAddress = this.wallet.address;
123
- const message = pipe$1(
124
- createTransactionMessage({ version: 0 }),
125
- (m) => setTransactionMessageFeePayer(feePayerAddress, m),
126
- (m) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, m),
127
- (m) => appendTransactionMessageInstruction(transferIx, m),
128
- (m) => appendTransactionMessageInstruction(memoIx, m)
129
- );
130
- const signedTransaction = await signTransactionMessageWithSigners(message).catch((error) => {
131
- throw new Error(
132
- `Failed to sign transaction: ${error instanceof Error ? error.message : "Unknown error"}`
133
- );
134
- });
135
- const signature = await this.sendAndConfirmTransactionManually(signedTransaction).catch((error) => {
136
- const errorMessage = error instanceof Error ? error.message : String(error);
137
- if (errorMessage.includes("insufficient funds")) {
138
- throw new Error("Insufficient funds to complete payment");
139
- }
140
- if (errorMessage.includes("Blockhash not found")) {
141
- throw new Error("Transaction expired. Please retry the payment.");
142
- }
143
- if (errorMessage.includes("InvalidAccountOwner")) {
144
- throw new Error(
145
- "Associated Token Account not found or invalid. Please ensure the token account exists for both sender and recipient."
146
- );
147
- }
148
- throw new Error(
149
- `Transaction failed: ${errorMessage}`
150
- );
151
- });
152
- this.emit("payment_sent", {
153
- type: "payment_sent",
154
- signature,
155
- request,
156
- timestamp: Date.now()
157
- });
158
- const tx = await this.rpc.getTransaction(signature, {
159
- encoding: "jsonParsed",
160
- maxSupportedTransactionVersion: 0
161
- }).send().catch((error) => {
162
- console.warn("Payment succeeded but failed to fetch transaction details:", error);
163
- return null;
164
- });
165
- const receipt = {
166
- signature,
167
- recipient: request.recipient,
168
- amount: request.amount,
169
- token: request.token,
170
- timestamp: Date.now(),
171
- metadata: request.metadata,
172
- blockTime: tx?.blockTime ? Number(tx.blockTime) : void 0,
173
- slot: tx?.slot ?? void 0
174
- };
175
- this.emit("payment_confirmed", {
176
- type: "payment_confirmed",
177
- signature,
178
- request,
179
- receipt,
180
- timestamp: Date.now()
181
- });
182
- return receipt;
183
- } catch (error) {
184
- const errorMessage = error instanceof Error ? error.message : String(error);
185
- this.emit("payment_failed", {
186
- type: "payment_failed",
187
- request,
188
- error: errorMessage,
189
- timestamp: Date.now()
190
- });
191
- if (error instanceof Error) {
192
- throw error;
193
- }
194
- throw new Error(`Payment failed: ${String(error)}`);
195
- }
196
- }
197
- /**
198
- * Verify an x402 payment
199
- */
200
- async verifyPayment(signature) {
201
- try {
202
- const tx = await this.rpc.getTransaction(signature, {
203
- encoding: "jsonParsed",
204
- maxSupportedTransactionVersion: 0
205
- }).send();
206
- if (!tx) {
207
- return {
208
- valid: false,
209
- error: "Transaction not found"
210
- };
211
- }
212
- if (tx.meta?.err !== null) {
213
- return {
214
- valid: false,
215
- error: "Transaction failed"
216
- };
217
- }
218
- const receipt = this.parseTransactionReceipt(tx, signature);
219
- return {
220
- valid: true,
221
- receipt
222
- };
223
- } catch (error) {
224
- return {
225
- valid: false,
226
- error: error instanceof Error ? error.message : "Unknown error"
227
- };
228
- }
229
- }
230
- /**
231
- * Verify payment for specific recipient and amount
232
- */
233
- async verifyPaymentDetails(params) {
234
- const result = await this.verifyPayment(params.signature);
235
- if (!result.valid || !result.receipt) {
236
- return result;
237
- }
238
- if (result.receipt.recipient !== params.expectedRecipient) {
239
- return {
240
- valid: false,
241
- error: "Recipient mismatch"
242
- };
243
- }
244
- if (result.receipt.amount !== params.expectedAmount) {
245
- return {
246
- valid: false,
247
- error: "Amount mismatch"
248
- };
249
- }
250
- if (result.receipt.token !== params.expectedToken) {
251
- return {
252
- valid: false,
253
- error: "Token mismatch"
254
- };
255
- }
256
- return {
257
- valid: true,
258
- receipt: result.receipt
259
- };
260
- }
261
- /**
262
- * Get payment status
263
- */
264
- async getPaymentStatus(signature) {
265
- try {
266
- const status = await this.rpc.getSignatureStatuses([signature]).send();
267
- if (!status.value[0]) {
268
- return { status: "not_found" };
269
- }
270
- const txStatus = status.value[0];
271
- if (txStatus.err) {
272
- return { status: "failed" };
273
- }
274
- if (txStatus.confirmationStatus === "finalized") {
275
- return { status: "finalized", confirmations: 32 };
276
- }
277
- if (txStatus.confirmationStatus === "confirmed") {
278
- return { status: "confirmed", confirmations: 1 };
279
- }
280
- return { status: "pending" };
281
- } catch {
282
- return { status: "not_found" };
283
- }
284
- }
285
- // =====================================================
286
- // PRIVATE HELPER METHODS
287
- // =====================================================
288
- async createTransferInstruction(recipient, amount, token) {
289
- if (!this.wallet) {
290
- throw new Error("Wallet required");
291
- }
292
- const sourceAccount = await this.getAssociatedTokenAddress(
293
- this.wallet.address,
294
- token
295
- );
296
- const destinationAccount = await this.getAssociatedTokenAddress(
297
- recipient,
298
- token
299
- );
300
- const TOKEN_PROGRAM_ID = address("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
301
- const keys = [
302
- { address: sourceAccount, role: 1, isWritable: true, isSigner: false },
303
- { address: destinationAccount, role: 1, isWritable: true, isSigner: false },
304
- { address: this.wallet.address, role: 2, isWritable: false, isSigner: true }
305
- ];
306
- const data = new Uint8Array(9);
307
- data[0] = 3;
308
- const amountBytes = new BigUint64Array([amount]);
309
- data.set(new Uint8Array(amountBytes.buffer), 1);
310
- return {
311
- programAddress: TOKEN_PROGRAM_ID,
312
- accounts: keys,
313
- data
314
- };
315
- }
316
- createMemoInstruction(memo) {
317
- const MEMO_PROGRAM_ID = address("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr");
318
- return {
319
- programAddress: MEMO_PROGRAM_ID,
320
- accounts: [],
321
- data: new TextEncoder().encode(memo)
322
- };
323
- }
324
- async getAssociatedTokenAddress(owner, token) {
325
- try {
326
- const response = await this.rpc.getTokenAccountsByOwner(
327
- owner,
328
- { mint: token },
329
- { encoding: "jsonParsed" }
330
- ).send();
331
- if (response.value.length > 0) {
332
- return response.value[0].pubkey;
333
- }
334
- throw new Error(
335
- `Associated Token Account not found for owner ${owner} and mint ${token}. Please ensure the ATA is initialized before making payments. Use createAssociatedTokenAccountInstruction to create it.`
336
- );
337
- } catch (error) {
338
- if (error instanceof Error && error.message.includes("Associated Token Account not found")) {
339
- throw error;
340
- }
341
- throw new Error(
342
- `Failed to get Associated Token Account: ${error instanceof Error ? error.message : "Unknown error"}`
343
- );
344
- }
345
- }
346
- parseTransactionReceipt(tx, signature) {
347
- const instructions = tx.transaction?.message?.instructions ?? [];
348
- const transferInstruction = instructions.find((ix) => {
349
- const parsed2 = typeof ix.parsed === "object" ? ix.parsed : null;
350
- return ix.program === "spl-token" && parsed2?.type === "transfer";
351
- });
352
- if (!transferInstruction) {
353
- throw new Error("No SPL token transfer found in transaction");
354
- }
355
- const parsed = typeof transferInstruction.parsed === "object" ? transferInstruction.parsed : null;
356
- const transferInfo = parsed?.info;
357
- if (!transferInfo) {
358
- throw new Error("Failed to parse SPL token transfer instruction");
359
- }
360
- const recipient = address(transferInfo.destination ?? transferInfo.account ?? "");
361
- const amount = BigInt(transferInfo.amount ?? transferInfo.tokenAmount?.amount ?? "0");
362
- let tokenMint;
363
- const tokenBalances = tx.meta?.preTokenBalances ?? [];
364
- if (tokenBalances.length > 0) {
365
- tokenMint = address(String(tokenBalances[0].mint));
366
- } else {
367
- throw new Error("Failed to extract token mint from transaction");
368
- }
369
- const memoInstruction = instructions.find((ix) => {
370
- const programIdStr = typeof ix.programId === "string" ? ix.programId : ix.programId?.toString() ?? "";
371
- return ix.program === "spl-memo" || programIdStr === "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr";
372
- });
373
- let metadata;
374
- if (memoInstruction) {
375
- try {
376
- const parsedMemo = typeof memoInstruction.parsed === "string" ? memoInstruction.parsed : typeof memoInstruction.parsed === "object" ? memoInstruction.parsed?.data ?? "" : "";
377
- const memoText = parsedMemo || (memoInstruction.data ? new TextDecoder().decode(Buffer.from(memoInstruction.data, "base64")) : "");
378
- if (typeof memoText === "string" && memoText.startsWith("x402:")) {
379
- const parts = memoText.split(":");
380
- if (parts.length >= 3) {
381
- try {
382
- metadata = JSON.parse(parts[2]);
383
- } catch {
384
- }
385
- }
386
- }
387
- } catch {
388
- }
389
- }
390
- const blockTimeNum = tx.blockTime != null ? typeof tx.blockTime === "bigint" ? Number(tx.blockTime) : tx.blockTime : void 0;
391
- return {
392
- signature,
393
- recipient,
394
- amount,
395
- token: tokenMint,
396
- timestamp: blockTimeNum != null ? blockTimeNum * 1e3 : Date.now(),
397
- metadata,
398
- blockTime: blockTimeNum,
399
- slot: tx.slot
400
- };
401
- }
402
- /**
403
- * Send and confirm transaction manually (simplified implementation)
404
- * This is a workaround for the missing rpcSubscriptions dependency
405
- */
406
- async sendAndConfirmTransactionManually(signedTransaction) {
407
- const signatures = Object.values(signedTransaction.signatures);
408
- if (signatures.length === 0) {
409
- throw new Error("Transaction has no signatures");
410
- }
411
- const firstSig = signatures[0];
412
- if (!firstSig) {
413
- throw new Error("Transaction signature is null");
414
- }
415
- const signature = firstSig;
416
- const wireTransaction = getBase64EncodedWireTransaction(signedTransaction);
417
- await this.rpc.sendTransaction(wireTransaction).send();
418
- for (let i = 0; i < 30; i++) {
419
- const status = await this.rpc.getSignatureStatuses([signature]).send();
420
- if (status.value[0]?.confirmationStatus === "confirmed" || status.value[0]?.confirmationStatus === "finalized") {
421
- return signature;
422
- }
423
- await new Promise((resolve) => setTimeout(resolve, 1e3));
424
- }
425
- throw new Error("Transaction confirmation timeout");
426
- }
427
- };
428
- function createX402Client(rpcUrl, wallet) {
429
- const rpc = createSolanaRpc(rpcUrl);
430
- return new X402Client(rpc, wallet);
431
- }
432
-
433
- // src/database/config.ts
434
- var DEFAULT_CONFIG = {
435
- mode: process.env.NODE_ENV === "production" ? "production" : "development",
436
- pool: {
437
- max: 10,
438
- min: 2,
439
- connectionTimeoutMs: 5e3,
440
- idleTimeoutMs: 3e4
441
- }
442
- };
443
- function getTursoConfig() {
444
- const url = process.env.TURSO_DATABASE_URL ?? null;
445
- const authToken = process.env.TURSO_AUTH_TOKEN ?? null;
446
- const enabled = Boolean(url && authToken);
447
- if (!enabled && (url ?? authToken)) {
448
- console.warn(
449
- "[GhostSpeak Database] Incomplete Turso configuration detected. Both TURSO_DATABASE_URL and TURSO_AUTH_TOKEN are required. Falling back to on-chain only mode."
450
- );
451
- }
452
- return {
453
- url,
454
- authToken,
455
- enabled,
456
- ...DEFAULT_CONFIG
457
- };
458
- }
459
- function validateConfig(config) {
460
- if (!config.enabled) {
461
- return false;
462
- }
463
- if (!config.url || !config.authToken) {
464
- return false;
465
- }
466
- if (!config.url.startsWith("libsql://") && !config.url.startsWith("http://") && !config.url.startsWith("https://")) {
467
- console.error("[GhostSpeak Database] Invalid TURSO_DATABASE_URL format. Expected libsql://, http://, or https://");
468
- return false;
469
- }
470
- return true;
471
- }
472
-
473
- // src/database/connection.ts
474
- var DEFAULT_RETRY_CONFIG = {
475
- maxRetries: 3,
476
- initialDelayMs: 1e3,
477
- maxDelayMs: 1e4,
478
- backoffMultiplier: 2
479
- };
480
- var connectionState = {
481
- client: null,
482
- initialized: false,
483
- healthy: false,
484
- lastError: null,
485
- retryCount: 0,
486
- lastConnectAttempt: 0
487
- };
488
- function sleep(ms) {
489
- return new Promise((resolve) => setTimeout(resolve, ms));
490
- }
491
- function getRetryDelay(retryCount, config) {
492
- const delay = Math.min(
493
- config.initialDelayMs * Math.pow(config.backoffMultiplier, retryCount),
494
- config.maxDelayMs
495
- );
496
- return delay;
497
- }
498
- async function initializeConnection(config, retryConfig = DEFAULT_RETRY_CONFIG) {
499
- let lastError = null;
500
- for (let attempt = 0; attempt <= retryConfig.maxRetries; attempt++) {
501
- try {
502
- connectionState.lastConnectAttempt = Date.now();
503
- if (attempt > 0) {
504
- const delay = getRetryDelay(attempt - 1, retryConfig);
505
- console.log(`[GhostSpeak Database] Retrying connection (attempt ${attempt + 1}/${retryConfig.maxRetries + 1}) after ${delay}ms...`);
506
- await sleep(delay);
507
- }
508
- const client = createClient({
509
- url: config.url,
510
- authToken: config.authToken
511
- });
512
- await client.execute("SELECT 1");
513
- console.log("[GhostSpeak Database] Connection established successfully");
514
- connectionState.retryCount = attempt;
515
- connectionState.healthy = true;
516
- connectionState.lastError = null;
517
- return client;
518
- } catch (error) {
519
- lastError = error instanceof Error ? error : new Error(String(error));
520
- console.error(`[GhostSpeak Database] Connection attempt ${attempt + 1} failed:`, lastError.message);
521
- if (attempt === retryConfig.maxRetries) {
522
- connectionState.healthy = false;
523
- connectionState.lastError = lastError;
524
- break;
525
- }
526
- }
527
- }
528
- throw new Error(
529
- `Failed to connect to Turso database after ${retryConfig.maxRetries + 1} attempts. Last error: ${lastError?.message ?? "Unknown error"}`
530
- );
531
- }
532
- async function getConnection() {
533
- const config = getTursoConfig();
534
- if (!config.enabled) {
535
- throw new Error(
536
- "Turso database not configured. Set TURSO_DATABASE_URL and TURSO_AUTH_TOKEN environment variables."
537
- );
538
- }
539
- if (!validateConfig(config)) {
540
- throw new Error("Invalid Turso database configuration");
541
- }
542
- if (connectionState.client && connectionState.healthy) {
543
- return connectionState.client;
544
- }
545
- if (!connectionState.initialized || !connectionState.healthy) {
546
- connectionState.initialized = true;
547
- connectionState.client = await initializeConnection(config);
548
- }
549
- return connectionState.client;
550
- }
551
- async function isAvailable() {
552
- const config = getTursoConfig();
553
- if (!config.enabled) {
554
- return false;
555
- }
556
- try {
557
- await getConnection();
558
- return true;
559
- } catch {
560
- return false;
561
- }
562
- }
563
-
564
- // src/database/schema/agents.ts
565
- var agents_exports = {};
566
- __export(agents_exports, {
567
- agentCapabilities: () => agentCapabilities,
568
- agentPricing: () => agentPricing,
569
- agents: () => agents
570
- });
571
- var agents = sqliteTable("agents", {
572
- // Primary key - Solana address
573
- agentAddress: text("agent_address").primaryKey(),
574
- // Basic info
575
- owner: text("owner").notNull(),
576
- name: text("name").notNull(),
577
- description: text("description").notNull(),
578
- // Reputation & stats
579
- reputationScore: integer("reputation_score").notNull().default(0),
580
- totalJobsCompleted: integer("total_jobs_completed").notNull().default(0),
581
- totalEarnings: text("total_earnings").notNull().default("0"),
582
- // Stored as text for u64
583
- // Status
584
- isActive: integer("is_active", { mode: "boolean" }).notNull().default(true),
585
- isVerified: integer("is_verified", { mode: "boolean" }).notNull().default(false),
586
- verificationTimestamp: integer("verification_timestamp").notNull().default(0),
587
- // Pricing
588
- originalPrice: text("original_price").notNull().default("0"),
589
- replicationFee: text("replication_fee").notNull().default("0"),
590
- // Configuration
591
- genomeHash: text("genome_hash").notNull().default(""),
592
- isReplicable: integer("is_replicable", { mode: "boolean" }).notNull().default(false),
593
- serviceEndpoint: text("service_endpoint").notNull().default(""),
594
- metadataUri: text("metadata_uri").notNull().default(""),
595
- // Framework & lineage
596
- frameworkOrigin: text("framework_origin").notNull().default(""),
597
- cnftMint: text("cnft_mint"),
598
- // Nullable
599
- merkleTree: text("merkle_tree"),
600
- // Nullable
601
- supportsA2a: integer("supports_a2a", { mode: "boolean" }).notNull().default(false),
602
- transferHook: text("transfer_hook"),
603
- // Nullable
604
- parentAgent: text("parent_agent"),
605
- // Nullable
606
- generation: integer("generation").notNull().default(0),
607
- // x402 Payment Protocol
608
- x402Enabled: integer("x402_enabled", { mode: "boolean" }).notNull().default(false),
609
- x402PaymentAddress: text("x402_payment_address").notNull(),
610
- x402PricePerCall: text("x402_price_per_call").notNull().default("0"),
611
- x402ServiceEndpoint: text("x402_service_endpoint").notNull().default(""),
612
- x402TotalPayments: text("x402_total_payments").notNull().default("0"),
613
- x402TotalCalls: text("x402_total_calls").notNull().default("0"),
614
- lastPaymentTimestamp: integer("last_payment_timestamp").notNull().default(0),
615
- // API Schema
616
- apiSpecUri: text("api_spec_uri").notNull().default(""),
617
- apiVersion: text("api_version").notNull().default(""),
618
- // Timestamps
619
- createdAt: integer("created_at").notNull(),
620
- updatedAt: integer("updated_at").notNull(),
621
- cachedAt: integer("cached_at").notNull(),
622
- // When cached from chain
623
- // Bump seed for PDA
624
- bump: integer("bump").notNull()
625
- }, (table) => ({
626
- // Indexes for common queries
627
- ownerIdx: index("idx_agents_owner").on(table.owner),
628
- x402EnabledIdx: index("idx_agents_x402_enabled").on(table.x402Enabled),
629
- reputationIdx: index("idx_agents_reputation").on(table.reputationScore),
630
- frameworkIdx: index("idx_agents_framework").on(table.frameworkOrigin),
631
- verifiedIdx: index("idx_agents_verified").on(table.isVerified),
632
- cachedAtIdx: index("idx_agents_cached_at").on(table.cachedAt)
633
- }));
634
- var agentCapabilities = sqliteTable("agent_capabilities", {
635
- id: integer("id").primaryKey({ autoIncrement: true }),
636
- agentAddress: text("agent_address").notNull().references(() => agents.agentAddress, { onDelete: "cascade" }),
637
- capability: text("capability").notNull()
638
- }, (table) => ({
639
- // Composite index for lookups
640
- agentCapabilityIdx: index("idx_agent_capability").on(table.agentAddress, table.capability)
641
- }));
642
- var agentPricing = sqliteTable("agent_pricing", {
643
- id: integer("id").primaryKey({ autoIncrement: true }),
644
- agentAddress: text("agent_address").notNull().references(() => agents.agentAddress, { onDelete: "cascade" }),
645
- tokenAddress: text("token_address").notNull(),
646
- // SPL token mint address
647
- decimals: integer("decimals").notNull(),
648
- symbol: text("symbol").notNull()
649
- }, (table) => ({
650
- // Index for token lookups
651
- agentTokenIdx: index("idx_agent_token").on(table.agentAddress, table.tokenAddress)
652
- }));
653
-
654
- // src/database/schema/transactions.ts
655
- var transactions_exports = {};
656
- __export(transactions_exports, {
657
- x402Transactions: () => x402Transactions
658
- });
659
- var x402Transactions = sqliteTable("x402_transactions", {
660
- // Primary key - Solana transaction signature
661
- signature: text("signature").primaryKey(),
662
- // Addresses
663
- agentAddress: text("agent_address").notNull(),
664
- // Agent that received payment
665
- payerAddress: text("payer_address").notNull(),
666
- // Who paid
667
- recipientAddress: text("recipient_address").notNull(),
668
- // Payment recipient
669
- // Payment details
670
- amount: text("amount").notNull(),
671
- // Amount in token's smallest unit (stored as text for bigint)
672
- tokenMint: text("token_mint").notNull(),
673
- // Token used for payment
674
- tokenDecimals: integer("token_decimals").notNull(),
675
- // Transaction status
676
- status: text("status").notNull().default("confirmed"),
677
- // 'confirmed', 'finalized', 'failed'
678
- // Timing
679
- blockTime: integer("block_time").notNull(),
680
- // Unix timestamp from Solana
681
- responseTimeMs: integer("response_time_ms"),
682
- // API response time (nullable)
683
- // Metadata
684
- metadataHash: text("metadata_hash"),
685
- // IPFS hash if applicable (nullable)
686
- // Timestamps
687
- createdAt: integer("created_at").notNull(),
688
- // When indexed
689
- updatedAt: integer("updated_at").notNull()
690
- // Last update
691
- }, (table) => ({
692
- // Indexes for common queries
693
- agentIdx: index("idx_tx_agent").on(table.agentAddress),
694
- payerIdx: index("idx_tx_payer").on(table.payerAddress),
695
- blockTimeIdx: index("idx_tx_block_time").on(table.blockTime),
696
- statusIdx: index("idx_tx_status").on(table.status),
697
- tokenIdx: index("idx_tx_token").on(table.tokenMint),
698
- // Composite index for agent + time range queries
699
- agentTimeIdx: index("idx_tx_agent_time").on(table.agentAddress, table.blockTime)
700
- }));
701
-
702
- // src/database/schema/analytics.ts
703
- var analytics_exports = {};
704
- __export(analytics_exports, {
705
- agentAnalytics: () => agentAnalytics,
706
- dailyMetrics: () => dailyMetrics,
707
- marketAnalytics: () => marketAnalytics
708
- });
709
- var agentAnalytics = sqliteTable("agent_analytics", {
710
- // Primary key - agent address
711
- agentAddress: text("agent_address").primaryKey(),
712
- // Revenue metrics
713
- totalRevenue: text("total_revenue").notNull().default("0"),
714
- // Stored as text for bigint
715
- // Transaction metrics
716
- totalTransactions: integer("total_transactions").notNull().default(0),
717
- successfulTransactions: integer("successful_transactions").notNull().default(0),
718
- successRate: real("success_rate").notNull().default(0),
719
- // Percentage 0-100
720
- // Quality metrics
721
- averageRating: real("average_rating").notNull().default(0),
722
- averageResponseTimeMs: integer("average_response_time_ms").notNull().default(0),
723
- // Activity
724
- lastTransactionAt: integer("last_transaction_at"),
725
- // Unix timestamp (nullable)
726
- // Timestamp
727
- updatedAt: integer("updated_at").notNull()
728
- }, (table) => ({
729
- updatedAtIdx: index("idx_agent_analytics_updated").on(table.updatedAt)
730
- }));
731
- var marketAnalytics = sqliteTable("market_analytics", {
732
- id: integer("id").primaryKey({ autoIncrement: true }),
733
- // Date for this snapshot
734
- metricDate: text("metric_date").notNull().unique(),
735
- // ISO date string (YYYY-MM-DD)
736
- // Volume metrics
737
- totalVolume: text("total_volume").notNull().default("0"),
738
- // Stored as text for bigint
739
- totalTransactions: integer("total_transactions").notNull().default(0),
740
- // Agent metrics
741
- activeAgentsCount: integer("active_agents_count").notNull().default(0),
742
- // Price metrics
743
- averagePrice: text("average_price").notNull().default("0"),
744
- // Average transaction amount
745
- // User metrics
746
- uniquePayers: integer("unique_payers").notNull().default(0),
747
- // Timestamp
748
- updatedAt: integer("updated_at").notNull()
749
- }, (table) => ({
750
- dateIdx: index("idx_market_analytics_date").on(table.metricDate)
751
- }));
752
- var dailyMetrics = sqliteTable("daily_metrics", {
753
- id: integer("id").primaryKey({ autoIncrement: true }),
754
- // Date and metric type
755
- metricDate: text("metric_date").notNull(),
756
- // ISO date (YYYY-MM-DD)
757
- metricType: text("metric_type").notNull(),
758
- // 'agent_revenue', 'market_volume', etc.
759
- // Optional agent address (null for market-wide metrics)
760
- agentAddress: text("agent_address"),
761
- // Nullable
762
- // Metric value and metadata
763
- value: text("value").notNull(),
764
- // Metric value as text (supports bigint)
765
- metadata: text("metadata"),
766
- // JSON string for additional data (nullable)
767
- // Timestamp
768
- createdAt: integer("created_at").notNull()
769
- }, (table) => ({
770
- // Composite index for date + type queries
771
- dateTypeIdx: index("idx_daily_metrics_date_type").on(table.metricDate, table.metricType),
772
- // Index for agent-specific queries
773
- agentIdx: index("idx_daily_metrics_agent").on(table.agentAddress),
774
- // Index for time-series queries
775
- dateIdx: index("idx_daily_metrics_date").on(table.metricDate)
776
- }));
777
-
778
- // src/database/schema/facilitators.ts
779
- var facilitators_exports = {};
780
- __export(facilitators_exports, {
781
- facilitatorApiKeys: () => facilitatorApiKeys,
782
- facilitatorHealthHistory: () => facilitatorHealthHistory,
783
- facilitators: () => facilitators
784
- });
785
- var facilitators = sqliteTable(
786
- "facilitators",
787
- {
788
- // Primary key - unique facilitator ID
789
- id: text("id").primaryKey(),
790
- // Basic info
791
- name: text("name").notNull(),
792
- description: text("description"),
793
- logo: text("logo"),
794
- website: text("website"),
795
- // Network configuration (JSON serialized)
796
- networks: text("networks").notNull(),
797
- // JSON array of Network enum values
798
- // Address configuration (JSON serialized)
799
- addresses: text("addresses").notNull(),
800
- // JSON Record<Network, FacilitatorAddress[]>
801
- // Endpoints
802
- discoveryUrl: text("discovery_url"),
803
- settleUrl: text("settle_url").notNull(),
804
- verifyUrl: text("verify_url").notNull(),
805
- // API configuration
806
- requiresApiKey: integer("requires_api_key", { mode: "boolean" }).notNull().default(false),
807
- apiKeyHeader: text("api_key_header"),
808
- // Status
809
- enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
810
- // Health metrics
811
- lastHealthCheck: integer("last_health_check"),
812
- // Unix timestamp
813
- healthStatus: text("health_status").default("unknown"),
814
- // healthy, degraded, unhealthy, unknown
815
- latencyMs: real("latency_ms"),
816
- uptimePercent: real("uptime_percent"),
817
- totalRequests: integer("total_requests").notNull().default(0),
818
- successfulRequests: integer("successful_requests").notNull().default(0),
819
- failedRequests: integer("failed_requests").notNull().default(0),
820
- // Timestamps
821
- createdAt: integer("created_at").notNull().default(0),
822
- updatedAt: integer("updated_at").notNull().default(0)
823
- },
824
- (table) => ({
825
- enabledIdx: index("facilitators_enabled_idx").on(table.enabled),
826
- healthStatusIdx: index("facilitators_health_status_idx").on(table.healthStatus)
827
- })
828
- );
829
- var facilitatorApiKeys = sqliteTable(
830
- "facilitator_api_keys",
831
- {
832
- // Composite key
833
- id: text("id").primaryKey(),
834
- // UUID or generated
835
- // Foreign keys
836
- facilitatorId: text("facilitator_id").notNull().references(() => facilitators.id),
837
- userId: text("user_id").notNull(),
838
- // User or wallet address
839
- // Key storage (encrypted)
840
- encryptedApiKey: text("encrypted_api_key").notNull(),
841
- keyLabel: text("key_label"),
842
- // User-friendly label
843
- // Metadata
844
- lastUsed: integer("last_used"),
845
- // Unix timestamp
846
- usageCount: integer("usage_count").notNull().default(0),
847
- // Timestamps
848
- createdAt: integer("created_at").notNull().default(0),
849
- updatedAt: integer("updated_at").notNull().default(0)
850
- },
851
- (table) => ({
852
- facilitatorUserIdx: index("api_keys_facilitator_user_idx").on(
853
- table.facilitatorId,
854
- table.userId
855
- )
856
- })
857
- );
858
- var facilitatorHealthHistory = sqliteTable(
859
- "facilitator_health_history",
860
- {
861
- // Primary key
862
- id: text("id").primaryKey(),
863
- // UUID
864
- // Foreign key
865
- facilitatorId: text("facilitator_id").notNull().references(() => facilitators.id),
866
- // Health check result
867
- status: text("status").notNull(),
868
- // healthy, degraded, unhealthy
869
- latencyMs: real("latency_ms").notNull(),
870
- errorMessage: text("error_message"),
871
- // Network-specific results (JSON serialized)
872
- networkResults: text("network_results"),
873
- // JSON array of network health
874
- // Timestamp
875
- checkedAt: integer("checked_at").notNull()
876
- },
877
- (table) => ({
878
- facilitatorTimeIdx: index("health_history_facilitator_time_idx").on(
879
- table.facilitatorId,
880
- table.checkedAt
881
- )
882
- })
883
- );
884
-
885
- // src/database/schema/resources.ts
886
- var resources_exports = {};
887
- __export(resources_exports, {
888
- resourceAccepts: () => resourceAccepts,
889
- resourceOrigins: () => resourceOrigins,
890
- resourcePingHistory: () => resourcePingHistory,
891
- resourceTags: () => resourceTags,
892
- resources: () => resources
893
- });
894
- var resourceOrigins = sqliteTable(
895
- "resource_origins",
896
- {
897
- // Primary key - UUID
898
- id: text("id").primaryKey(),
899
- // Origin URL (e.g., https://api.example.com)
900
- origin: text("origin").notNull().unique(),
901
- // Metadata from scraping
902
- name: text("name"),
903
- description: text("description"),
904
- faviconUrl: text("favicon_url"),
905
- ogImageUrl: text("og_image_url"),
906
- ogTitle: text("og_title"),
907
- ogDescription: text("og_description"),
908
- // Contact/attribution
909
- contactEmail: text("contact_email"),
910
- twitterHandle: text("twitter_handle"),
911
- githubRepo: text("github_repo"),
912
- // Verification
913
- isVerified: integer("is_verified", { mode: "boolean" }).notNull().default(false),
914
- verifiedAt: integer("verified_at"),
915
- verifiedBy: text("verified_by"),
916
- // Timestamps
917
- createdAt: integer("created_at").notNull().default(0),
918
- updatedAt: integer("updated_at").notNull().default(0),
919
- lastScrapedAt: integer("last_scraped_at")
920
- },
921
- (table) => ({
922
- originIdx: index("resource_origins_origin_idx").on(table.origin)
923
- })
924
- );
925
- var resources = sqliteTable(
926
- "resources",
927
- {
928
- // Primary key - UUID
929
- id: text("id").primaryKey(),
930
- // Resource URL (full endpoint URL)
931
- url: text("url").notNull().unique(),
932
- // Type of resource
933
- type: text("type").notNull().default("http"),
934
- // http, websocket, grpc
935
- // x402 protocol version
936
- x402Version: text("x402_version"),
937
- // Foreign keys
938
- originId: text("origin_id").references(() => resourceOrigins.id),
939
- facilitatorId: text("facilitator_id").references(() => facilitators.id),
940
- // Payment requirements (JSON serialized PaymentRequirement[])
941
- accepts: text("accepts").notNull(),
942
- // JSON array
943
- // Pricing
944
- maxAmount: text("max_amount"),
945
- // bigint as string
946
- minAmount: text("min_amount"),
947
- // bigint as string
948
- currency: text("currency").default("USDC"),
949
- // Enhanced schema for AI integration (JSON Schema)
950
- inputSchema: text("input_schema"),
951
- // JSON Schema for input
952
- outputSchema: text("output_schema"),
953
- // JSON Schema for output
954
- examplesJson: text("examples_json"),
955
- // JSON array of { input, output }
956
- // Metadata
957
- name: text("name"),
958
- description: text("description"),
959
- tags: text("tags"),
960
- // JSON array of strings
961
- capabilities: text("capabilities"),
962
- // JSON array of capabilities
963
- category: text("category"),
964
- // AI category
965
- // HTTP metadata
966
- httpMethod: text("http_method").default("POST"),
967
- contentType: text("content_type").default("application/json"),
968
- authType: text("auth_type"),
969
- // none, bearer, api_key, x402
970
- // Status
971
- isActive: integer("is_active", { mode: "boolean" }).notNull().default(true),
972
- isVerified: integer("is_verified", { mode: "boolean" }).notNull().default(false),
973
- lastPingAt: integer("last_ping_at"),
974
- lastPingStatus: integer("last_ping_status"),
975
- // HTTP status code
976
- lastPingLatencyMs: real("last_ping_latency_ms"),
977
- consecutiveFailures: integer("consecutive_failures").notNull().default(0),
978
- // Discovery source
979
- discoveredFrom: text("discovered_from"),
980
- // facilitator_id or 'manual'
981
- discoveredAt: integer("discovered_at"),
982
- // AI labeling
983
- aiGeneratedTags: text("ai_generated_tags"),
984
- // JSON array
985
- aiLabeledAt: integer("ai_labeled_at"),
986
- // Timestamps
987
- createdAt: integer("created_at").notNull().default(0),
988
- updatedAt: integer("updated_at").notNull().default(0)
989
- },
990
- (table) => ({
991
- originIdx: index("resources_origin_idx").on(table.originId),
992
- facilitatorIdx: index("resources_facilitator_idx").on(table.facilitatorId),
993
- activeIdx: index("resources_active_idx").on(table.isActive),
994
- categoryIdx: index("resources_category_idx").on(table.category)
995
- })
996
- );
997
- var resourceTags = sqliteTable(
998
- "resource_tags",
999
- {
1000
- // Composite key
1001
- id: text("id").primaryKey(),
1002
- // UUID
1003
- // Foreign key
1004
- resourceId: text("resource_id").notNull().references(() => resources.id),
1005
- // Tag
1006
- tag: text("tag").notNull(),
1007
- isAiGenerated: integer("is_ai_generated", { mode: "boolean" }).notNull().default(false),
1008
- // Timestamps
1009
- createdAt: integer("created_at").notNull().default(0)
1010
- },
1011
- (table) => ({
1012
- resourceIdx: index("resource_tags_resource_idx").on(table.resourceId),
1013
- tagIdx: index("resource_tags_tag_idx").on(table.tag)
1014
- })
1015
- );
1016
- var resourcePingHistory = sqliteTable(
1017
- "resource_ping_history",
1018
- {
1019
- // Primary key - UUID
1020
- id: text("id").primaryKey(),
1021
- // Foreign key
1022
- resourceId: text("resource_id").notNull().references(() => resources.id),
1023
- // Ping result
1024
- statusCode: integer("status_code"),
1025
- latencyMs: real("latency_ms"),
1026
- success: integer("success", { mode: "boolean" }).notNull(),
1027
- errorMessage: text("error_message"),
1028
- // x402 response validation
1029
- hasValidX402: integer("has_valid_x402", { mode: "boolean" }),
1030
- x402ParseError: text("x402_parse_error"),
1031
- // Response details
1032
- responseBodySize: integer("response_body_size"),
1033
- contentType: text("content_type"),
1034
- // Timestamp
1035
- pingedAt: integer("pinged_at").notNull()
1036
- },
1037
- (table) => ({
1038
- resourceTimeIdx: index("ping_history_resource_time_idx").on(
1039
- table.resourceId,
1040
- table.pingedAt
1041
- )
1042
- })
1043
- );
1044
- var resourceAccepts = sqliteTable(
1045
- "resource_accepts",
1046
- {
1047
- // Primary key - UUID
1048
- id: text("id").primaryKey(),
1049
- // Foreign key
1050
- resourceId: text("resource_id").notNull().references(() => resources.id),
1051
- // Payment requirement fields
1052
- scheme: text("scheme").notNull(),
1053
- // exact, upto, base, tiered
1054
- network: text("network").notNull(),
1055
- // solana, base, polygon
1056
- maxAmountRequired: text("max_amount_required").notNull(),
1057
- // bigint as string
1058
- payTo: text("pay_to").notNull(),
1059
- // facilitator address
1060
- asset: text("asset").notNull(),
1061
- // token address
1062
- maxTimeoutSeconds: integer("max_timeout_seconds"),
1063
- description: text("description"),
1064
- mimeType: text("mime_type"),
1065
- // Extra fields (JSON)
1066
- extra: text("extra"),
1067
- // Timestamps
1068
- createdAt: integer("created_at").notNull().default(0),
1069
- updatedAt: integer("updated_at").notNull().default(0)
1070
- },
1071
- (table) => ({
1072
- resourceIdx: index("resource_accepts_resource_idx").on(table.resourceId),
1073
- networkIdx: index("resource_accepts_network_idx").on(table.network),
1074
- assetIdx: index("resource_accepts_asset_idx").on(table.asset)
1075
- })
1076
- );
1077
-
1078
- // src/database/schema/resourceMetrics.ts
1079
- var resourceMetrics_exports = {};
1080
- __export(resourceMetrics_exports, {
1081
- TIME_WINDOWS: () => TIME_WINDOWS,
1082
- globalMetrics: () => globalMetrics,
1083
- resourceMetrics: () => resourceMetrics,
1084
- resourceOriginMetrics: () => resourceOriginMetrics
1085
- });
1086
- var TIME_WINDOWS = ["1h", "6h", "24h", "3d", "7d", "15d", "30d", "all"];
1087
- var resourceMetrics = sqliteTable(
1088
- "resource_metrics",
1089
- {
1090
- // Primary key
1091
- id: text("id").primaryKey(),
1092
- // Foreign key to resource
1093
- resourceId: text("resource_id").notNull().references(() => resources.id),
1094
- // Snapshot timestamp
1095
- createdAt: integer("created_at").notNull(),
1096
- // =========================================================
1097
- // REQUEST COUNTS (8 time windows each)
1098
- // =========================================================
1099
- // Total requests
1100
- totalRequests1h: integer("total_requests_1h").notNull().default(0),
1101
- totalRequests6h: integer("total_requests_6h").notNull().default(0),
1102
- totalRequests24h: integer("total_requests_24h").notNull().default(0),
1103
- totalRequests3d: integer("total_requests_3d").notNull().default(0),
1104
- totalRequests7d: integer("total_requests_7d").notNull().default(0),
1105
- totalRequests15d: integer("total_requests_15d").notNull().default(0),
1106
- totalRequests30d: integer("total_requests_30d").notNull().default(0),
1107
- totalRequestsAll: integer("total_requests_all").notNull().default(0),
1108
- // Successful requests (2xx)
1109
- successCount1h: integer("success_count_1h").notNull().default(0),
1110
- successCount6h: integer("success_count_6h").notNull().default(0),
1111
- successCount24h: integer("success_count_24h").notNull().default(0),
1112
- successCount3d: integer("success_count_3d").notNull().default(0),
1113
- successCount7d: integer("success_count_7d").notNull().default(0),
1114
- successCount15d: integer("success_count_15d").notNull().default(0),
1115
- successCount30d: integer("success_count_30d").notNull().default(0),
1116
- successCountAll: integer("success_count_all").notNull().default(0),
1117
- // Failed requests (4xx, 5xx)
1118
- failureCount1h: integer("failure_count_1h").notNull().default(0),
1119
- failureCount6h: integer("failure_count_6h").notNull().default(0),
1120
- failureCount24h: integer("failure_count_24h").notNull().default(0),
1121
- failureCount3d: integer("failure_count_3d").notNull().default(0),
1122
- failureCount7d: integer("failure_count_7d").notNull().default(0),
1123
- failureCount15d: integer("failure_count_15d").notNull().default(0),
1124
- failureCount30d: integer("failure_count_30d").notNull().default(0),
1125
- failureCountAll: integer("failure_count_all").notNull().default(0),
1126
- // =========================================================
1127
- // LATENCY PERCENTILES (p50, p90, p99 for each window)
1128
- // =========================================================
1129
- // P50 (median) latency in ms
1130
- latencyP50_1h: real("latency_p50_1h"),
1131
- latencyP50_6h: real("latency_p50_6h"),
1132
- latencyP50_24h: real("latency_p50_24h"),
1133
- latencyP50_3d: real("latency_p50_3d"),
1134
- latencyP50_7d: real("latency_p50_7d"),
1135
- latencyP50_15d: real("latency_p50_15d"),
1136
- latencyP50_30d: real("latency_p50_30d"),
1137
- latencyP50All: real("latency_p50_all"),
1138
- // P90 latency in ms
1139
- latencyP90_1h: real("latency_p90_1h"),
1140
- latencyP90_6h: real("latency_p90_6h"),
1141
- latencyP90_24h: real("latency_p90_24h"),
1142
- latencyP90_3d: real("latency_p90_3d"),
1143
- latencyP90_7d: real("latency_p90_7d"),
1144
- latencyP90_15d: real("latency_p90_15d"),
1145
- latencyP90_30d: real("latency_p90_30d"),
1146
- latencyP90All: real("latency_p90_all"),
1147
- // P99 latency in ms
1148
- latencyP99_1h: real("latency_p99_1h"),
1149
- latencyP99_6h: real("latency_p99_6h"),
1150
- latencyP99_24h: real("latency_p99_24h"),
1151
- latencyP99_3d: real("latency_p99_3d"),
1152
- latencyP99_7d: real("latency_p99_7d"),
1153
- latencyP99_15d: real("latency_p99_15d"),
1154
- latencyP99_30d: real("latency_p99_30d"),
1155
- latencyP99All: real("latency_p99_all"),
1156
- // =========================================================
1157
- // STATUS CODE DISTRIBUTION
1158
- // =========================================================
1159
- // 2xx responses
1160
- status2xx1h: integer("status_2xx_1h").notNull().default(0),
1161
- status2xx24h: integer("status_2xx_24h").notNull().default(0),
1162
- status2xx7d: integer("status_2xx_7d").notNull().default(0),
1163
- status2xxAll: integer("status_2xx_all").notNull().default(0),
1164
- // 3xx responses
1165
- status3xx1h: integer("status_3xx_1h").notNull().default(0),
1166
- status3xx24h: integer("status_3xx_24h").notNull().default(0),
1167
- status3xx7d: integer("status_3xx_7d").notNull().default(0),
1168
- status3xxAll: integer("status_3xx_all").notNull().default(0),
1169
- // 4xx responses
1170
- status4xx1h: integer("status_4xx_1h").notNull().default(0),
1171
- status4xx24h: integer("status_4xx_24h").notNull().default(0),
1172
- status4xx7d: integer("status_4xx_7d").notNull().default(0),
1173
- status4xxAll: integer("status_4xx_all").notNull().default(0),
1174
- // 5xx responses
1175
- status5xx1h: integer("status_5xx_1h").notNull().default(0),
1176
- status5xx24h: integer("status_5xx_24h").notNull().default(0),
1177
- status5xx7d: integer("status_5xx_7d").notNull().default(0),
1178
- status5xxAll: integer("status_5xx_all").notNull().default(0),
1179
- // =========================================================
1180
- // UPTIME & AVAILABILITY
1181
- // =========================================================
1182
- // Uptime percentage (0-100)
1183
- uptimePercent1h: real("uptime_percent_1h"),
1184
- uptimePercent24h: real("uptime_percent_24h"),
1185
- uptimePercent7d: real("uptime_percent_7d"),
1186
- uptimePercent30d: real("uptime_percent_30d"),
1187
- uptimePercentAll: real("uptime_percent_all"),
1188
- // Number of outages
1189
- outageCount1h: integer("outage_count_1h").notNull().default(0),
1190
- outageCount24h: integer("outage_count_24h").notNull().default(0),
1191
- outageCount7d: integer("outage_count_7d").notNull().default(0),
1192
- outageCount30d: integer("outage_count_30d").notNull().default(0),
1193
- // =========================================================
1194
- // PAYMENT METRICS
1195
- // =========================================================
1196
- // Total payment volume (stored as text for bigint)
1197
- paymentVolume1h: text("payment_volume_1h").notNull().default("0"),
1198
- paymentVolume24h: text("payment_volume_24h").notNull().default("0"),
1199
- paymentVolume7d: text("payment_volume_7d").notNull().default("0"),
1200
- paymentVolume30d: text("payment_volume_30d").notNull().default("0"),
1201
- paymentVolumeAll: text("payment_volume_all").notNull().default("0"),
1202
- // Number of payments
1203
- paymentCount1h: integer("payment_count_1h").notNull().default(0),
1204
- paymentCount24h: integer("payment_count_24h").notNull().default(0),
1205
- paymentCount7d: integer("payment_count_7d").notNull().default(0),
1206
- paymentCount30d: integer("payment_count_30d").notNull().default(0),
1207
- paymentCountAll: integer("payment_count_all").notNull().default(0),
1208
- // Average payment amount
1209
- avgPayment1h: text("avg_payment_1h"),
1210
- avgPayment24h: text("avg_payment_24h"),
1211
- avgPayment7d: text("avg_payment_7d"),
1212
- avgPaymentAll: text("avg_payment_all"),
1213
- // Unique payers
1214
- uniquePayers1h: integer("unique_payers_1h").notNull().default(0),
1215
- uniquePayers24h: integer("unique_payers_24h").notNull().default(0),
1216
- uniquePayers7d: integer("unique_payers_7d").notNull().default(0),
1217
- uniquePayersAll: integer("unique_payers_all").notNull().default(0)
1218
- },
1219
- (table) => ({
1220
- resourceIdx: index("resource_metrics_resource_idx").on(table.resourceId),
1221
- createdAtIdx: index("resource_metrics_created_at_idx").on(table.createdAt),
1222
- resourceCreatedIdx: index("resource_metrics_resource_created_idx").on(
1223
- table.resourceId,
1224
- table.createdAt
1225
- )
1226
- })
1227
- );
1228
- var resourceOriginMetrics = sqliteTable(
1229
- "resource_origin_metrics",
1230
- {
1231
- // Primary key
1232
- id: text("id").primaryKey(),
1233
- // Foreign key to origin
1234
- originId: text("origin_id").notNull().references(() => resourceOrigins.id),
1235
- // Snapshot timestamp
1236
- createdAt: integer("created_at").notNull(),
1237
- // Resource count
1238
- resourceCount: integer("resource_count").notNull().default(0),
1239
- activeResourceCount: integer("active_resource_count").notNull().default(0),
1240
- // Aggregated request counts
1241
- totalRequests1h: integer("total_requests_1h").notNull().default(0),
1242
- totalRequests24h: integer("total_requests_24h").notNull().default(0),
1243
- totalRequests7d: integer("total_requests_7d").notNull().default(0),
1244
- totalRequestsAll: integer("total_requests_all").notNull().default(0),
1245
- // Aggregated success counts
1246
- successCount1h: integer("success_count_1h").notNull().default(0),
1247
- successCount24h: integer("success_count_24h").notNull().default(0),
1248
- successCount7d: integer("success_count_7d").notNull().default(0),
1249
- successCountAll: integer("success_count_all").notNull().default(0),
1250
- // Aggregated failure counts
1251
- failureCount1h: integer("failure_count_1h").notNull().default(0),
1252
- failureCount24h: integer("failure_count_24h").notNull().default(0),
1253
- failureCount7d: integer("failure_count_7d").notNull().default(0),
1254
- failureCountAll: integer("failure_count_all").notNull().default(0),
1255
- // Average latency across resources
1256
- avgLatencyP50_1h: real("avg_latency_p50_1h"),
1257
- avgLatencyP50_24h: real("avg_latency_p50_24h"),
1258
- avgLatencyP50_7d: real("avg_latency_p50_7d"),
1259
- avgLatencyP50All: real("avg_latency_p50_all"),
1260
- avgLatencyP90_1h: real("avg_latency_p90_1h"),
1261
- avgLatencyP90_24h: real("avg_latency_p90_24h"),
1262
- avgLatencyP90_7d: real("avg_latency_p90_7d"),
1263
- avgLatencyP90All: real("avg_latency_p90_all"),
1264
- // Aggregated uptime
1265
- avgUptimePercent1h: real("avg_uptime_percent_1h"),
1266
- avgUptimePercent24h: real("avg_uptime_percent_24h"),
1267
- avgUptimePercent7d: real("avg_uptime_percent_7d"),
1268
- avgUptimePercentAll: real("avg_uptime_percent_all"),
1269
- // Aggregated payment metrics
1270
- paymentVolume1h: text("payment_volume_1h").notNull().default("0"),
1271
- paymentVolume24h: text("payment_volume_24h").notNull().default("0"),
1272
- paymentVolume7d: text("payment_volume_7d").notNull().default("0"),
1273
- paymentVolumeAll: text("payment_volume_all").notNull().default("0"),
1274
- paymentCount1h: integer("payment_count_1h").notNull().default(0),
1275
- paymentCount24h: integer("payment_count_24h").notNull().default(0),
1276
- paymentCount7d: integer("payment_count_7d").notNull().default(0),
1277
- paymentCountAll: integer("payment_count_all").notNull().default(0)
1278
- },
1279
- (table) => ({
1280
- originIdx: index("origin_metrics_origin_idx").on(table.originId),
1281
- createdAtIdx: index("origin_metrics_created_at_idx").on(table.createdAt)
1282
- })
1283
- );
1284
- var globalMetrics = sqliteTable("global_metrics", {
1285
- // Primary key (single row, use 'global')
1286
- id: text("id").primaryKey(),
1287
- // Snapshot timestamp
1288
- createdAt: integer("created_at").notNull(),
1289
- // Resource counts
1290
- totalResources: integer("total_resources").notNull().default(0),
1291
- activeResources: integer("active_resources").notNull().default(0),
1292
- totalOrigins: integer("total_origins").notNull().default(0),
1293
- totalFacilitators: integer("total_facilitators").notNull().default(0),
1294
- // Request aggregates
1295
- totalRequests1h: integer("total_requests_1h").notNull().default(0),
1296
- totalRequests24h: integer("total_requests_24h").notNull().default(0),
1297
- totalRequests7d: integer("total_requests_7d").notNull().default(0),
1298
- totalRequestsAll: integer("total_requests_all").notNull().default(0),
1299
- // Payment aggregates
1300
- paymentVolume1h: text("payment_volume_1h").notNull().default("0"),
1301
- paymentVolume24h: text("payment_volume_24h").notNull().default("0"),
1302
- paymentVolume7d: text("payment_volume_7d").notNull().default("0"),
1303
- paymentVolumeAll: text("payment_volume_all").notNull().default("0"),
1304
- paymentCount1h: integer("payment_count_1h").notNull().default(0),
1305
- paymentCount24h: integer("payment_count_24h").notNull().default(0),
1306
- paymentCount7d: integer("payment_count_7d").notNull().default(0),
1307
- paymentCountAll: integer("payment_count_all").notNull().default(0),
1308
- // Unique users
1309
- uniquePayers1h: integer("unique_payers_1h").notNull().default(0),
1310
- uniquePayers24h: integer("unique_payers_24h").notNull().default(0),
1311
- uniquePayers7d: integer("unique_payers_7d").notNull().default(0),
1312
- uniquePayersAll: integer("unique_payers_all").notNull().default(0),
1313
- // Network breakdown (JSON)
1314
- networkBreakdown: text("network_breakdown"),
1315
- // JSON object
1316
- // Top performers (JSON arrays)
1317
- topResourcesByVolume: text("top_resources_by_volume"),
1318
- // JSON array
1319
- topResourcesByRequests: text("top_resources_by_requests"),
1320
- // JSON array
1321
- topOriginsByVolume: text("top_origins_by_volume")
1322
- // JSON array
1323
- });
1324
-
1325
- // src/database/schema/index.ts
1326
- var schema = {
1327
- ...agents_exports,
1328
- ...transactions_exports,
1329
- ...analytics_exports,
1330
- ...facilitators_exports,
1331
- ...resources_exports,
1332
- ...resourceMetrics_exports
1333
- };
1334
-
1335
- // src/database/db.ts
1336
- async function getDb() {
1337
- const client = await getConnection();
1338
- return drizzle(client, { schema });
1339
- }
1340
-
1341
- // src/database/services/AgentCacheService.ts
1342
- var AgentCacheService = class _AgentCacheService {
1343
- static instance = null;
1344
- defaultMaxAge = 5 * 60 * 1e3;
1345
- // 5 minutes
1346
- constructor() {
1347
- }
1348
- /**
1349
- * Get singleton instance
1350
- */
1351
- static getInstance() {
1352
- if (!_AgentCacheService.instance) {
1353
- _AgentCacheService.instance = new _AgentCacheService();
1354
- }
1355
- return _AgentCacheService.instance;
1356
- }
1357
- /**
1358
- * Check if cache is available
1359
- */
1360
- async isCacheAvailable() {
1361
- return await isAvailable();
1362
- }
1363
- /**
1364
- * Get agent from cache
1365
- *
1366
- * @param agentAddress - Agent's Solana address
1367
- * @param options - Cache options
1368
- * @returns Agent data or null if not found/expired
1369
- */
1370
- async getAgent(agentAddress, options = {}) {
1371
- if (!await this.isCacheAvailable()) {
1372
- return null;
1373
- }
1374
- const { maxAge = this.defaultMaxAge, forceRefresh = false } = options;
1375
- if (forceRefresh) {
1376
- return null;
1377
- }
1378
- try {
1379
- const db = await getDb();
1380
- const results = await db.select().from(agents).where(eq(agents.agentAddress, agentAddress)).limit(1);
1381
- if (results.length === 0) {
1382
- return null;
1383
- }
1384
- const agent = results[0];
1385
- const age = Date.now() - agent.cachedAt;
1386
- if (age > maxAge) {
1387
- return null;
1388
- }
1389
- return agent;
1390
- } catch (error) {
1391
- console.warn("[AgentCacheService] Failed to get agent from cache:", error);
1392
- return null;
1393
- }
1394
- }
1395
- /**
1396
- * Get multiple agents from cache
1397
- *
1398
- * @param agentAddresses - Array of agent addresses
1399
- * @param options - Cache options
1400
- * @returns Map of address to agent data
1401
- */
1402
- async getAgents(agentAddresses, options = {}) {
1403
- if (!await this.isCacheAvailable() || agentAddresses.length === 0) {
1404
- return /* @__PURE__ */ new Map();
1405
- }
1406
- const { maxAge = this.defaultMaxAge } = options;
1407
- try {
1408
- const db = await getDb();
1409
- const results = await db.select().from(agents).where(sql`${agents.agentAddress} IN ${agentAddresses}`);
1410
- const now = Date.now();
1411
- const agentMap = /* @__PURE__ */ new Map();
1412
- for (const agent of results) {
1413
- const age = now - agent.cachedAt;
1414
- if (age <= maxAge) {
1415
- agentMap.set(agent.agentAddress, agent);
1416
- }
1417
- }
1418
- return agentMap;
1419
- } catch (error) {
1420
- console.warn("[AgentCacheService] Failed to get agents from cache:", error);
1421
- return /* @__PURE__ */ new Map();
1422
- }
1423
- }
1424
- /**
1425
- * Cache agent data
1426
- *
1427
- * @param agent - Agent data to cache
1428
- * @param capabilities - Agent capabilities
1429
- * @param pricing - Agent pricing info
1430
- */
1431
- async cacheAgent(agent, capabilities = [], pricing = []) {
1432
- if (!await this.isCacheAvailable()) {
1433
- return;
1434
- }
1435
- try {
1436
- const db = await getDb();
1437
- await db.insert(agents).values({
1438
- ...agent,
1439
- cachedAt: Date.now()
1440
- }).onConflictDoUpdate({
1441
- target: agents.agentAddress,
1442
- set: {
1443
- ...agent,
1444
- cachedAt: Date.now(),
1445
- updatedAt: Date.now()
1446
- }
1447
- });
1448
- await db.delete(agentCapabilities).where(eq(agentCapabilities.agentAddress, agent.agentAddress));
1449
- if (capabilities.length > 0) {
1450
- await db.insert(agentCapabilities).values(
1451
- capabilities.map((cap) => ({
1452
- agentAddress: agent.agentAddress,
1453
- capability: cap
1454
- }))
1455
- );
1456
- }
1457
- await db.delete(agentPricing).where(eq(agentPricing.agentAddress, agent.agentAddress));
1458
- if (pricing.length > 0) {
1459
- await db.insert(agentPricing).values(
1460
- pricing.map((p) => ({
1461
- agentAddress: agent.agentAddress,
1462
- ...p
1463
- }))
1464
- );
1465
- }
1466
- } catch (error) {
1467
- console.error("[AgentCacheService] Failed to cache agent:", error);
1468
- }
1469
- }
1470
- /**
1471
- * List agents with filters
1472
- *
1473
- * @param filters - Query filters
1474
- * @returns Array of agents
1475
- */
1476
- async listAgents(filters = {}) {
1477
- if (!await this.isCacheAvailable()) {
1478
- return [];
1479
- }
1480
- try {
1481
- const db = await getDb();
1482
- const {
1483
- x402Enabled,
1484
- framework,
1485
- isVerified,
1486
- minReputation,
1487
- limit = 50,
1488
- offset = 0
1489
- } = filters;
1490
- const conditions = [];
1491
- if (x402Enabled !== void 0) {
1492
- conditions.push(eq(agents.x402Enabled, x402Enabled));
1493
- }
1494
- if (framework) {
1495
- conditions.push(eq(agents.frameworkOrigin, framework));
1496
- }
1497
- if (isVerified !== void 0) {
1498
- conditions.push(eq(agents.isVerified, isVerified));
1499
- }
1500
- if (minReputation !== void 0) {
1501
- conditions.push(sql`${agents.reputationScore} >= ${minReputation}`);
1502
- }
1503
- if (conditions.length > 0) {
1504
- const results = await db.select().from(agents).where(and(...conditions)).orderBy(desc(agents.reputationScore)).limit(limit).offset(offset);
1505
- return results;
1506
- } else {
1507
- const results = await db.select().from(agents).orderBy(desc(agents.reputationScore)).limit(limit).offset(offset);
1508
- return results;
1509
- }
1510
- } catch (error) {
1511
- console.warn("[AgentCacheService] Failed to list agents:", error);
1512
- return [];
1513
- }
1514
- }
1515
- /**
1516
- * Invalidate cached agent
1517
- *
1518
- * @param agentAddress - Agent address to invalidate
1519
- */
1520
- async invalidateAgent(agentAddress) {
1521
- if (!await this.isCacheAvailable()) {
1522
- return;
1523
- }
1524
- try {
1525
- const db = await getDb();
1526
- await db.delete(agents).where(eq(agents.agentAddress, agentAddress));
1527
- } catch (error) {
1528
- console.warn("[AgentCacheService] Failed to invalidate agent:", error);
1529
- }
1530
- }
1531
- /**
1532
- * Clear all cached agents
1533
- */
1534
- async clearCache() {
1535
- if (!await this.isCacheAvailable()) {
1536
- return;
1537
- }
1538
- try {
1539
- const db = await getDb();
1540
- await db.delete(agents);
1541
- } catch (error) {
1542
- console.error("[AgentCacheService] Failed to clear cache:", error);
1543
- }
1544
- }
1545
- /**
1546
- * Get cache statistics
1547
- */
1548
- async getCacheStats() {
1549
- if (!await this.isCacheAvailable()) {
1550
- return null;
1551
- }
1552
- try {
1553
- const db = await getDb();
1554
- const result = await db.select({
1555
- count: sql`count(*)`,
1556
- avgAge: sql`avg(${Date.now()} - ${agents.cachedAt})`,
1557
- oldestCache: sql`min(${agents.cachedAt})`
1558
- }).from(agents);
1559
- return {
1560
- totalAgents: result[0].count,
1561
- averageAge: result[0].avgAge,
1562
- oldestCache: result[0].oldestCache
1563
- };
1564
- } catch (error) {
1565
- console.warn("[AgentCacheService] Failed to get cache stats:", error);
1566
- return null;
1567
- }
1568
- }
1569
- };
1570
- AgentCacheService.getInstance();
1571
-
1572
- // src/x402/AgentDiscoveryClient.ts
1573
- var REPUTATION_BASIS_POINTS_PER_STAR = 2e3;
1574
- var AgentDiscoveryClient = class {
1575
- rpc;
1576
- programId;
1577
- commitment;
1578
- cache = /* @__PURE__ */ new Map();
1579
- cacheEnabled;
1580
- cacheTTL;
1581
- useDatabaseCache;
1582
- dbCache;
1583
- constructor(options) {
1584
- this.rpc = createSolanaRpc(options.rpcEndpoint);
1585
- this.programId = options.programId;
1586
- this.commitment = options.commitment ?? "confirmed";
1587
- this.cacheEnabled = options.cacheEnabled ?? true;
1588
- this.cacheTTL = options.cacheTTL ?? 300;
1589
- this.useDatabaseCache = options.useDatabaseCache ?? true;
1590
- this.dbCache = AgentCacheService.getInstance();
1591
- }
1592
- /**
1593
- * Search for agents with filters
1594
- */
1595
- async searchAgents(params = {}) {
1596
- const cacheKey = this.getCacheKey("search", params);
1597
- if (this.cacheEnabled) {
1598
- const cached = this.getFromCache(cacheKey);
1599
- if (cached) return cached;
1600
- }
1601
- const page = params.page ?? 1;
1602
- const limit = Math.min(params.limit ?? 20, 100);
1603
- const sortBy = params.sort_by ?? "reputation";
1604
- const sortOrder = params.sort_order ?? "desc";
1605
- const allAgents = await this.fetchAgentsFromChain(params);
1606
- let filteredAgents = this.applyFilters(allAgents, params);
1607
- filteredAgents = this.sortAgents(filteredAgents, sortBy, sortOrder);
1608
- const total = filteredAgents.length;
1609
- const totalPages = Math.ceil(total / limit);
1610
- const startIndex = (page - 1) * limit;
1611
- const endIndex = startIndex + limit;
1612
- const paginatedAgents = filteredAgents.slice(startIndex, endIndex);
1613
- const response = {
1614
- agents: paginatedAgents,
1615
- pagination: {
1616
- page,
1617
- limit,
1618
- total,
1619
- totalPages
1620
- },
1621
- filters: params
1622
- };
1623
- if (this.cacheEnabled) {
1624
- this.setCache(cacheKey, response);
1625
- }
1626
- return response;
1627
- }
1628
- /**
1629
- * Get agent by address with database cache support
1630
- *
1631
- * Cache hierarchy:
1632
- * 1. Check Turso database cache (if enabled)
1633
- * 2. Fallback to RPC fetch
1634
- * 3. Cache result in database for future requests
1635
- */
1636
- async getAgent(address6, forceRefresh = false) {
1637
- const cacheKey = this.getCacheKey("agent", { address: address6 });
1638
- if (this.useDatabaseCache && !forceRefresh) {
1639
- const cachedAgent = await this.dbCache.getAgent(address6, {
1640
- maxAge: this.cacheTTL * 1e3,
1641
- forceRefresh
1642
- });
1643
- if (cachedAgent) {
1644
- console.log(`[AgentDiscovery] Cache HIT for agent ${address6}`);
1645
- return this.transformCachedAgent(cachedAgent);
1646
- }
1647
- }
1648
- if (this.cacheEnabled && !forceRefresh) {
1649
- const cached = this.getFromCache(cacheKey);
1650
- if (cached) {
1651
- console.log(`[AgentDiscovery] Memory cache HIT for agent ${address6}`);
1652
- return cached;
1653
- }
1654
- }
1655
- console.log(`[AgentDiscovery] Cache MISS for agent ${address6}, fetching from RPC`);
1656
- try {
1657
- const result = await this.rpc.getAccountInfo(address6, {
1658
- commitment: this.commitment,
1659
- encoding: "base64"
1660
- }).send();
1661
- const accountInfo = result;
1662
- if (!accountInfo.value) return null;
1663
- const agent = this.parseAgentAccount(address6, accountInfo.value.data);
1664
- if (agent) {
1665
- if (this.useDatabaseCache) {
1666
- this.cacheAgentInDatabase(agent).catch(
1667
- (err) => console.warn("[AgentDiscovery] Failed to cache agent in database:", err)
1668
- );
1669
- }
1670
- if (this.cacheEnabled) {
1671
- this.setCache(cacheKey, agent);
1672
- }
1673
- }
1674
- return agent;
1675
- } catch (error) {
1676
- console.error(`Failed to fetch agent ${address6}:`, error);
1677
- return null;
1678
- }
1679
- }
1680
- /**
1681
- * Helper to cache agent in database
1682
- */
1683
- async cacheAgentInDatabase(agent) {
1684
- await this.dbCache.cacheAgent(
1685
- {
1686
- agentAddress: agent.address,
1687
- owner: agent.owner,
1688
- name: agent.name,
1689
- description: agent.description,
1690
- reputationScore: agent.reputation_score,
1691
- totalJobsCompleted: Number(agent.total_jobs),
1692
- totalEarnings: agent.total_earnings.toString(),
1693
- x402Enabled: agent.x402_enabled,
1694
- x402PaymentAddress: agent.x402_payment_address,
1695
- x402PricePerCall: agent.x402_price_per_call.toString(),
1696
- x402ServiceEndpoint: agent.x402_service_endpoint,
1697
- x402TotalPayments: agent.x402_total_payments.toString(),
1698
- x402TotalCalls: agent.x402_total_calls.toString(),
1699
- lastPaymentTimestamp: Number(agent.last_payment_timestamp),
1700
- metadataUri: agent.metadata_uri,
1701
- frameworkOrigin: agent.framework_origin,
1702
- isVerified: agent.is_verified,
1703
- createdAt: Number(agent.created_at),
1704
- updatedAt: Date.now(),
1705
- cachedAt: Date.now(),
1706
- bump: 0
1707
- // Placeholder
1708
- },
1709
- agent.capabilities,
1710
- []
1711
- // Pricing info would be added here
1712
- );
1713
- }
1714
- /**
1715
- * Transform cached database agent to Agent interface
1716
- */
1717
- transformCachedAgent(cachedAgent) {
1718
- return {
1719
- address: cachedAgent.agentAddress,
1720
- owner: cachedAgent.owner,
1721
- name: cachedAgent.name,
1722
- description: cachedAgent.description,
1723
- capabilities: [],
1724
- // Would need to join from agentCapabilities table
1725
- x402_enabled: Boolean(cachedAgent.x402Enabled),
1726
- x402_payment_address: cachedAgent.x402PaymentAddress,
1727
- x402_accepted_tokens: [],
1728
- // Would join from agentPricing table
1729
- x402_price_per_call: BigInt(cachedAgent.x402PricePerCall),
1730
- x402_service_endpoint: cachedAgent.x402ServiceEndpoint,
1731
- x402_total_payments: BigInt(cachedAgent.x402TotalPayments),
1732
- x402_total_calls: BigInt(cachedAgent.x402TotalCalls),
1733
- last_payment_timestamp: BigInt(cachedAgent.lastPaymentTimestamp),
1734
- reputation_score: cachedAgent.reputationScore,
1735
- total_jobs: BigInt(cachedAgent.totalJobsCompleted),
1736
- successful_jobs: BigInt(cachedAgent.totalJobsCompleted),
1737
- total_earnings: BigInt(cachedAgent.totalEarnings),
1738
- average_rating: cachedAgent.reputationScore / REPUTATION_BASIS_POINTS_PER_STAR,
1739
- created_at: BigInt(cachedAgent.createdAt),
1740
- metadata_uri: cachedAgent.metadataUri,
1741
- framework_origin: cachedAgent.frameworkOrigin,
1742
- is_verified: Boolean(cachedAgent.isVerified)
1743
- };
1744
- }
1745
- /**
1746
- * Get agent pricing information
1747
- */
1748
- async getAgentPricing(address6) {
1749
- const agent = await this.getAgent(address6);
1750
- if (!agent?.x402_enabled) return null;
1751
- return {
1752
- price_per_call: agent.x402_price_per_call,
1753
- accepted_tokens: await this.getTokenInfo(agent.x402_accepted_tokens),
1754
- payment_address: agent.x402_payment_address,
1755
- service_endpoint: agent.x402_service_endpoint
1756
- };
1757
- }
1758
- /**
1759
- * Get recommended agents based on criteria
1760
- */
1761
- async getRecommendedAgents(capability, limit = 10) {
1762
- const params = {
1763
- capability,
1764
- x402_enabled: true,
1765
- sort_by: "reputation",
1766
- sort_order: "desc",
1767
- limit,
1768
- min_reputation: 7e3
1769
- // Only recommend highly rated agents (7.0+)
1770
- };
1771
- const response = await this.searchAgents(params);
1772
- return response.agents;
1773
- }
1774
- /**
1775
- * Get agents by capability
1776
- */
1777
- async getAgentsByCapability(capability) {
1778
- const response = await this.searchAgents({
1779
- capability,
1780
- x402_enabled: true
1781
- });
1782
- return response.agents;
1783
- }
1784
- /**
1785
- * Get agents accepting specific token
1786
- */
1787
- async getAgentsByToken(tokenAddress) {
1788
- const response = await this.searchAgents({
1789
- accepted_tokens: [tokenAddress],
1790
- x402_enabled: true
1791
- });
1792
- return response.agents;
1793
- }
1794
- /**
1795
- * Get agents within price range
1796
- */
1797
- async getAgentsByPriceRange(maxPrice, capability) {
1798
- const response = await this.searchAgents({
1799
- max_price: maxPrice,
1800
- capability,
1801
- x402_enabled: true,
1802
- sort_by: "price",
1803
- sort_order: "asc"
1804
- });
1805
- return response.agents;
1806
- }
1807
- /**
1808
- * Search agents by text query
1809
- */
1810
- async searchByQuery(query) {
1811
- const response = await this.searchAgents({
1812
- query,
1813
- x402_enabled: true
1814
- });
1815
- return response.agents;
1816
- }
1817
- // Private helper methods
1818
- async fetchAgentsFromChain(params) {
1819
- try {
1820
- const filters = [];
1821
- filters.push({ dataSize: 359n });
1822
- const accounts = await this.rpc.getProgramAccounts(this.programId, {
1823
- commitment: this.commitment,
1824
- encoding: "base64",
1825
- filters
1826
- }).send();
1827
- const agents2 = [];
1828
- for (const { pubkey, account } of accounts) {
1829
- const agent = this.parseAgentAccount(pubkey, account.data);
1830
- if (agent) {
1831
- agents2.push(agent);
1832
- }
1833
- }
1834
- return agents2;
1835
- } catch (error) {
1836
- console.error("Failed to fetch agents from chain:", error);
1837
- return [];
1838
- }
1839
- }
1840
- parseAgentAccount(address6, data) {
1841
- try {
1842
- let dataBytes;
1843
- if (typeof data === "string") {
1844
- dataBytes = Uint8Array.from(Buffer.from(data, "base64"));
1845
- } else if (Array.isArray(data)) {
1846
- if (data.length === 2 && typeof data[0] === "string" && typeof data[1] === "string" && data[1] === "base64") {
1847
- dataBytes = Uint8Array.from(Buffer.from(data[0], "base64"));
1848
- } else {
1849
- dataBytes = Uint8Array.from(data);
1850
- }
1851
- } else if (data instanceof Uint8Array) {
1852
- dataBytes = data;
1853
- } else {
1854
- throw new Error("Invalid data format");
1855
- }
1856
- const decoder = getAgentDecoder();
1857
- const decodedData = decoder.decode(dataBytes);
1858
- const decodedAgent = Array.isArray(decodedData) ? decodedData[0] : decodedData;
1859
- return {
1860
- address: address6,
1861
- owner: decodedAgent.owner,
1862
- name: decodedAgent.name,
1863
- description: decodedAgent.description,
1864
- capabilities: decodedAgent.capabilities,
1865
- // x402 fields
1866
- x402_enabled: decodedAgent.x402Enabled,
1867
- x402_payment_address: decodedAgent.x402PaymentAddress,
1868
- x402_accepted_tokens: decodedAgent.x402AcceptedTokens,
1869
- x402_price_per_call: decodedAgent.x402PricePerCall,
1870
- x402_service_endpoint: decodedAgent.x402ServiceEndpoint,
1871
- x402_total_payments: decodedAgent.x402TotalPayments,
1872
- x402_total_calls: decodedAgent.x402TotalCalls,
1873
- last_payment_timestamp: decodedAgent.lastPaymentTimestamp,
1874
- // Standard fields
1875
- reputation_score: decodedAgent.reputationScore,
1876
- total_jobs: BigInt(decodedAgent.totalJobsCompleted),
1877
- successful_jobs: BigInt(decodedAgent.totalJobsCompleted),
1878
- // Assuming successful = completed
1879
- total_earnings: decodedAgent.totalEarnings,
1880
- average_rating: decodedAgent.reputationScore / REPUTATION_BASIS_POINTS_PER_STAR,
1881
- // Convert from basis points to 1-5 scale
1882
- created_at: decodedAgent.createdAt,
1883
- metadata_uri: decodedAgent.metadataUri,
1884
- framework_origin: decodedAgent.frameworkOrigin,
1885
- is_verified: decodedAgent.isVerified
1886
- };
1887
- } catch (error) {
1888
- console.error("Failed to parse agent account:", error);
1889
- return null;
1890
- }
1891
- }
1892
- applyFilters(agents2, params) {
1893
- let filtered = agents2;
1894
- if (params.x402_enabled !== void 0) {
1895
- filtered = filtered.filter((a) => a.x402_enabled === params.x402_enabled);
1896
- }
1897
- if (params.capability) {
1898
- filtered = filtered.filter(
1899
- (a) => a.capabilities.some(
1900
- (c) => c.toLowerCase().includes(params.capability.toLowerCase())
1901
- )
1902
- );
1903
- }
1904
- if (params.accepted_tokens?.length) {
1905
- filtered = filtered.filter(
1906
- (a) => params.accepted_tokens.some(
1907
- (token) => a.x402_accepted_tokens.includes(token)
1908
- )
1909
- );
1910
- }
1911
- if (params.min_reputation !== void 0) {
1912
- filtered = filtered.filter((a) => a.reputation_score >= params.min_reputation);
1913
- }
1914
- if (params.max_price !== void 0) {
1915
- filtered = filtered.filter((a) => a.x402_price_per_call <= params.max_price);
1916
- }
1917
- if (params.framework_origin) {
1918
- filtered = filtered.filter(
1919
- (a) => a.framework_origin.toLowerCase() === params.framework_origin.toLowerCase()
1920
- );
1921
- }
1922
- if (params.is_verified !== void 0) {
1923
- filtered = filtered.filter((a) => a.is_verified === params.is_verified);
1924
- }
1925
- if (params.query) {
1926
- const query = params.query.toLowerCase();
1927
- filtered = filtered.filter(
1928
- (a) => a.name.toLowerCase().includes(query) || a.description.toLowerCase().includes(query)
1929
- );
1930
- }
1931
- return filtered;
1932
- }
1933
- sortAgents(agents2, sortBy, sortOrder) {
1934
- const sorted = [...agents2];
1935
- const order = sortOrder === "asc" ? 1 : -1;
1936
- sorted.sort((a, b) => {
1937
- let comparison = 0;
1938
- switch (sortBy) {
1939
- case "reputation":
1940
- comparison = a.reputation_score - b.reputation_score;
1941
- break;
1942
- case "price":
1943
- comparison = Number(a.x402_price_per_call - b.x402_price_per_call);
1944
- break;
1945
- case "total_jobs":
1946
- comparison = Number(a.total_jobs - b.total_jobs);
1947
- break;
1948
- case "created_at":
1949
- comparison = Number(a.created_at - b.created_at);
1950
- break;
1951
- }
1952
- return comparison * order;
1953
- });
1954
- return sorted;
1955
- }
1956
- async getTokenInfo(tokens) {
1957
- const tokenInfo = [];
1958
- for (const token of tokens) {
1959
- try {
1960
- const result = await this.rpc.getAccountInfo(token, {
1961
- commitment: this.commitment,
1962
- encoding: "base64"
1963
- }).send();
1964
- const mintInfo = result;
1965
- if (mintInfo.value) {
1966
- const data = Buffer.from(mintInfo.value.data[0], "base64");
1967
- const decimals = data[44];
1968
- tokenInfo.push({
1969
- token,
1970
- decimals,
1971
- symbol: "USDC"
1972
- // Placeholder - would look up from token registry or metadata
1973
- });
1974
- }
1975
- } catch (error) {
1976
- console.error(`Failed to fetch token info for ${token}:`, error);
1977
- }
1978
- }
1979
- return tokenInfo;
1980
- }
1981
- getCacheKey(prefix, params) {
1982
- return `${prefix}:${JSON.stringify(params)}`;
1983
- }
1984
- getFromCache(key) {
1985
- const cached = this.cache.get(key);
1986
- if (!cached) return null;
1987
- if (Date.now() > cached.expiry) {
1988
- this.cache.delete(key);
1989
- return null;
1990
- }
1991
- return cached.data;
1992
- }
1993
- setCache(key, data) {
1994
- const expiry = Date.now() + this.cacheTTL * 1e3;
1995
- this.cache.set(key, { data, expiry });
1996
- if (this.cache.size > 1e3) {
1997
- const entries = Array.from(this.cache.entries());
1998
- entries.sort((a, b) => a[1].expiry - b[1].expiry);
1999
- for (let i = 0; i < 100; i++) {
2000
- this.cache.delete(entries[i][0]);
2001
- }
2002
- }
2003
- }
2004
- /**
2005
- * Clear all cached data
2006
- */
2007
- clearCache() {
2008
- this.cache.clear();
2009
- }
2010
- /**
2011
- * Get cache statistics
2012
- */
2013
- getCacheStats() {
2014
- return {
2015
- size: this.cache.size,
2016
- enabled: this.cacheEnabled,
2017
- ttl: this.cacheTTL
2018
- };
2019
- }
2020
- };
2021
- function createAgentDiscoveryClient(options) {
2022
- return new AgentDiscoveryClient(options);
2023
- }
2024
- function toSignature(value) {
2025
- if (typeof value === "string") {
2026
- return value;
2027
- }
2028
- return value;
2029
- }
2030
- var SignatureCache = class {
2031
- cache = /* @__PURE__ */ new Map();
2032
- ttl;
2033
- cleanupInterval = null;
2034
- constructor(ttl = 3600) {
2035
- this.ttl = ttl * 1e3;
2036
- this.cleanupInterval = setInterval(() => this.cleanup(), 3e5);
2037
- if (this.cleanupInterval.unref) {
2038
- this.cleanupInterval.unref();
2039
- }
2040
- }
2041
- has(signature) {
2042
- const entry = this.cache.get(signature);
2043
- if (!entry) return false;
2044
- if (Date.now() > entry.expiresAt) {
2045
- this.cache.delete(signature);
2046
- return false;
2047
- }
2048
- return true;
2049
- }
2050
- add(signature) {
2051
- this.cache.set(signature, {
2052
- timestamp: Date.now(),
2053
- expiresAt: Date.now() + this.ttl
2054
- });
2055
- }
2056
- cleanup() {
2057
- const now = Date.now();
2058
- for (const [signature, entry] of this.cache.entries()) {
2059
- if (now > entry.expiresAt) {
2060
- this.cache.delete(signature);
2061
- }
2062
- }
2063
- }
2064
- getSize() {
2065
- return this.cache.size;
2066
- }
2067
- /**
2068
- * Destroy the cache and clear the cleanup interval
2069
- * Call this when shutting down to prevent memory leaks
2070
- */
2071
- destroy() {
2072
- if (this.cleanupInterval) {
2073
- clearInterval(this.cleanupInterval);
2074
- this.cleanupInterval = null;
2075
- }
2076
- this.cache.clear();
2077
- }
2078
- };
2079
- var globalSignatureCache = null;
2080
- function createX402Middleware(options) {
2081
- const preventDuplicates = options.preventDuplicatePayments ?? true;
2082
- const enforceExpiration = options.enforceExpiration ?? true;
2083
- const cacheTTL = options.signatureCacheTTL ?? 3600;
2084
- const signatureCache = preventDuplicates ? options.signatureCacheTTL ? new SignatureCache(cacheTTL) : globalSignatureCache : null;
2085
- return async (req, res, next) => {
2086
- const requestStartTime = Date.now();
2087
- const paymentSignature = req.headers["x-payment-signature"];
2088
- const paymentExpiresAt = req.headers["x-payment-expires-at"];
2089
- if (options.allowBypass && shouldBypass(req, options)) {
2090
- return next();
2091
- }
2092
- const paymentRequest = options.x402Client.createPaymentRequest({
2093
- amount: options.requiredPayment,
2094
- token: options.token,
2095
- description: options.description
2096
- });
2097
- if (!paymentSignature) {
2098
- const headers = options.x402Client.createPaymentHeaders(paymentRequest);
2099
- res.status(402).set(headers).json({
2100
- error: "Payment Required",
2101
- message: "This endpoint requires x402 payment",
2102
- code: "PAYMENT_REQUIRED",
2103
- paymentDetails: {
2104
- address: paymentRequest.recipient,
2105
- amount: paymentRequest.amount.toString(),
2106
- token: paymentRequest.token,
2107
- blockchain: "solana",
2108
- description: options.description,
2109
- expiresAt: paymentRequest.expiresAt
2110
- },
2111
- documentation: "https://docs.ghostspeak.ai/x402"
2112
- });
2113
- return;
2114
- }
2115
- if (preventDuplicates && signatureCache?.has(paymentSignature)) {
2116
- if (options.onPaymentFailed) {
2117
- await options.onPaymentFailed("Payment signature already used", req);
2118
- }
2119
- res.status(402).json({
2120
- error: "Payment Already Used",
2121
- message: "This payment signature has already been used. Please create a new payment.",
2122
- code: "PAYMENT_DUPLICATE"
2123
- });
2124
- return;
2125
- }
2126
- if (enforceExpiration && paymentExpiresAt) {
2127
- const now = Date.now();
2128
- const expiresAtTimestamp = parseInt(paymentExpiresAt, 10);
2129
- if (isNaN(expiresAtTimestamp)) {
2130
- if (options.onPaymentFailed) {
2131
- await options.onPaymentFailed("Invalid expiration timestamp", req);
2132
- }
2133
- res.status(402).json({
2134
- error: "Invalid Payment Expiration",
2135
- message: "The x-payment-expires-at header contains an invalid timestamp.",
2136
- code: "PAYMENT_INVALID_EXPIRY"
2137
- });
2138
- return;
2139
- }
2140
- if (now > expiresAtTimestamp) {
2141
- if (options.onPaymentFailed) {
2142
- await options.onPaymentFailed("Payment request expired", req);
2143
- }
2144
- res.status(402).json({
2145
- error: "Payment Expired",
2146
- message: "This payment request has expired. Please create a new payment.",
2147
- code: "PAYMENT_EXPIRED",
2148
- expiresAt: expiresAtTimestamp,
2149
- currentTime: now
2150
- });
2151
- return;
2152
- }
2153
- }
2154
- try {
2155
- const verification = await options.x402Client.verifyPaymentDetails({
2156
- signature: toSignature(paymentSignature),
2157
- expectedRecipient: paymentRequest.recipient,
2158
- expectedAmount: options.requiredPayment,
2159
- expectedToken: options.token
2160
- });
2161
- if (!verification.valid) {
2162
- if (options.onPaymentFailed) {
2163
- await options.onPaymentFailed(verification.error ?? "Unknown error", req);
2164
- }
2165
- res.status(402).json({
2166
- error: "Payment Verification Failed",
2167
- message: verification.error ?? "Invalid payment",
2168
- code: "PAYMENT_INVALID"
2169
- });
2170
- return;
2171
- }
2172
- const responseTimeMs = Date.now() - requestStartTime;
2173
- let callerIdentity;
2174
- if (options.lookupCallerIdentity) {
2175
- try {
2176
- callerIdentity = await lookupCallerIdentity(
2177
- verification.receipt.recipient,
2178
- options.rpcEndpoint,
2179
- options.programId
2180
- );
2181
- } catch (identityError) {
2182
- console.warn("[x402] Failed to lookup caller identity:", identityError);
2183
- }
2184
- }
2185
- req.x402Payment = {
2186
- signature: paymentSignature,
2187
- verified: true,
2188
- amount: verification.receipt.amount,
2189
- token: verification.receipt.token,
2190
- responseTimeMs,
2191
- timestamp: Date.now(),
2192
- caller: callerIdentity
2193
- };
2194
- if (preventDuplicates && signatureCache) {
2195
- signatureCache.add(paymentSignature);
2196
- }
2197
- if (options.recordPaymentOnChain && options.agentId) {
2198
- try {
2199
- console.log(`[x402] Would record payment on-chain for agent ${options.agentId}`);
2200
- } catch (reputationError) {
2201
- if (options.onReputationUpdateFailed && reputationError instanceof Error) {
2202
- options.onReputationUpdateFailed(reputationError);
2203
- } else {
2204
- console.error("[x402] Failed to record payment on-chain:", reputationError);
2205
- }
2206
- }
2207
- }
2208
- if (options.onPaymentVerified) {
2209
- await options.onPaymentVerified(paymentSignature, req);
2210
- }
2211
- next();
2212
- } catch (error) {
2213
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
2214
- if (options.onPaymentFailed) {
2215
- await options.onPaymentFailed(errorMessage, req);
2216
- }
2217
- res.status(500).json({
2218
- error: "Payment Verification Error",
2219
- message: errorMessage,
2220
- code: "PAYMENT_VERIFICATION_ERROR"
2221
- });
2222
- }
2223
- };
2224
- }
2225
- function x402FastifyPlugin(fastify, options) {
2226
- fastify.addHook("preHandler", async (request, reply) => {
2227
- const route = request.url ? options.routes[request.url] : void 0;
2228
- if (!route) {
2229
- return;
2230
- }
2231
- const paymentSignature = request.headers["x-payment-signature"];
2232
- const paymentRequest = options.x402Client.createPaymentRequest({
2233
- amount: route.payment,
2234
- token: route.token,
2235
- description: route.description
2236
- });
2237
- if (!paymentSignature) {
2238
- const headers = options.x402Client.createPaymentHeaders(paymentRequest);
2239
- reply.code(402).headers(headers).send({
2240
- error: "Payment Required",
2241
- paymentDetails: {
2242
- address: paymentRequest.recipient,
2243
- amount: paymentRequest.amount.toString(),
2244
- token: paymentRequest.token
2245
- }
2246
- });
2247
- return;
2248
- }
2249
- const verification = await options.x402Client.verifyPaymentDetails({
2250
- signature: toSignature(paymentSignature),
2251
- expectedRecipient: paymentRequest.recipient,
2252
- expectedAmount: route.payment,
2253
- expectedToken: route.token
2254
- });
2255
- if (!verification.valid) {
2256
- reply.code(402).send({
2257
- error: "Payment Verification Failed",
2258
- message: verification.error
2259
- });
2260
- return;
2261
- }
2262
- request.x402Payment = {
2263
- signature: paymentSignature,
2264
- verified: true,
2265
- amount: verification.receipt.amount,
2266
- token: verification.receipt.token
2267
- };
2268
- });
2269
- }
2270
- function shouldBypass(req, options) {
2271
- const clientAddress = req.headers["x-client-address"];
2272
- if (clientAddress && options.bypassAddresses) {
2273
- return options.bypassAddresses.includes(clientAddress);
2274
- }
2275
- return false;
2276
- }
2277
- async function lookupCallerIdentity(sourceAddress, rpcEndpoint, programId) {
2278
- if (!rpcEndpoint) {
2279
- return {
2280
- type: "unknown",
2281
- address: sourceAddress
2282
- };
2283
- }
2284
- try {
2285
- const rpc = createSolanaRpc(rpcEndpoint);
2286
- const maybeAgent = await fetchMaybeAgent(rpc, sourceAddress);
2287
- if (!maybeAgent.exists) {
2288
- return {
2289
- type: "unknown",
2290
- address: sourceAddress
2291
- };
2292
- }
2293
- const agent = maybeAgent.data;
2294
- return {
2295
- type: "agent",
2296
- address: sourceAddress,
2297
- agent: {
2298
- name: agent.name,
2299
- owner: agent.owner,
2300
- reputation_score: agent.reputationScore,
2301
- is_verified: agent.isVerified,
2302
- capabilities: agent.capabilities,
2303
- framework_origin: agent.frameworkOrigin,
2304
- x402_enabled: true
2305
- // Assume all agents support x402 (no explicit flag in schema)
2306
- }
2307
- };
2308
- } catch (error) {
2309
- console.warn("[x402] Agent lookup failed:", error);
2310
- return {
2311
- type: "unknown",
2312
- address: sourceAddress
2313
- };
2314
- }
2315
- }
2316
- function withX402RateLimit(options) {
2317
- const requests = /* @__PURE__ */ new Map();
2318
- return (target, propertyKey, descriptor) => {
2319
- const originalMethod = descriptor.value;
2320
- descriptor.value = async function(...args) {
2321
- const req = args[0];
2322
- const res = args[1];
2323
- const forwardedFor = req.headers["x-forwarded-for"];
2324
- const clientIp = forwardedFor?.split(",")[0]?.trim() ?? req.ip ?? "unknown";
2325
- const clientId = req.x402Payment?.signature ?? clientIp;
2326
- const now = Date.now();
2327
- const userRequests = requests.get(clientId) ?? [];
2328
- const recentRequests = userRequests.filter(
2329
- (timestamp) => now - timestamp < 6e4
2330
- );
2331
- if (recentRequests.length >= options.maxRequestsPerMinute) {
2332
- res.status(429).json({
2333
- error: "Rate Limit Exceeded",
2334
- message: `Maximum ${options.maxRequestsPerMinute} requests per minute`,
2335
- paymentRequired: options.paymentRequired.toString()
2336
- });
2337
- return;
2338
- }
2339
- recentRequests.push(now);
2340
- requests.set(clientId, recentRequests);
2341
- return originalMethod.apply(this, args);
2342
- };
2343
- };
2344
- }
2345
-
2346
- // src/x402/schemas/enhanced-x402.ts
2347
- function validatePaymentRequirement(req) {
2348
- const errors = [];
2349
- const r = req;
2350
- if (!r || typeof r !== "object") {
2351
- return { valid: false, errors: ["Payment requirement must be an object"] };
2352
- }
2353
- if (!r.network || typeof r.network !== "string") {
2354
- errors.push('Missing or invalid "network" field');
2355
- }
2356
- if (!r.maxAmountRequired && !r.max_amount_required && !r.amount) {
2357
- errors.push('Missing "maxAmountRequired" field');
2358
- }
2359
- if (!r.payTo && !r.pay_to && !r.recipient) {
2360
- errors.push('Missing "payTo" field');
2361
- }
2362
- if (!r.asset && !r.token) {
2363
- errors.push('Missing "asset" field');
2364
- }
2365
- if (errors.length > 0) {
2366
- return { valid: false, errors };
2367
- }
2368
- const requirement = {
2369
- scheme: r.scheme ?? "exact",
2370
- network: r.network ?? r.chain,
2371
- maxAmountRequired: String(r.maxAmountRequired ?? r.max_amount_required ?? r.amount),
2372
- resource: r.resource,
2373
- description: r.description,
2374
- mimeType: r.mimeType ?? r.mime_type,
2375
- payTo: String(r.payTo ?? r.pay_to ?? r.recipient),
2376
- maxTimeoutSeconds: r.maxTimeoutSeconds ?? r.max_timeout_seconds,
2377
- asset: String(r.asset ?? r.token),
2378
- extra: r.extra
2379
- };
2380
- return { valid: true, requirement };
2381
- }
2382
- function validateX402Response(response) {
2383
- const errors = [];
2384
- const r = response;
2385
- if (!r || typeof r !== "object") {
2386
- return { valid: false, errors: ["Response must be an object"] };
2387
- }
2388
- const version = r.x402Version ?? r.x402_version;
2389
- if (!version) {
2390
- errors.push('Missing "x402Version" field');
2391
- }
2392
- const accepts = r.accepts ?? r.payment_requirements;
2393
- if (!accepts || !Array.isArray(accepts)) {
2394
- errors.push('Missing or invalid "accepts" array');
2395
- } else if (accepts.length === 0) {
2396
- errors.push('"accepts" array must not be empty');
2397
- } else {
2398
- for (let i = 0; i < accepts.length; i++) {
2399
- const result = validatePaymentRequirement(accepts[i]);
2400
- if (!result.valid) {
2401
- errors.push(`accepts[${i}]: ${result.errors.join(", ")}`);
2402
- }
2403
- }
2404
- }
2405
- if (errors.length > 0) {
2406
- return { valid: false, errors };
2407
- }
2408
- const enhanced = {
2409
- x402Version: "1.0",
2410
- accepts: accepts.map((a) => {
2411
- const result = validatePaymentRequirement(a);
2412
- return result.valid ? result.requirement : {};
2413
- }),
2414
- error: r.error,
2415
- inputSchema: r.inputSchema ?? r.input_schema,
2416
- outputSchema: r.outputSchema ?? r.output_schema,
2417
- description: r.description,
2418
- name: r.name,
2419
- tags: r.tags,
2420
- category: r.category,
2421
- examples: r.examples,
2422
- apiVersion: r.apiVersion ?? r.api_version,
2423
- methods: r.methods,
2424
- rateLimit: r.rateLimit ?? r.rate_limit,
2425
- authRequired: r.authRequired ?? r.auth_required,
2426
- sla: r.sla,
2427
- termsUrl: r.termsUrl ?? r.terms_url,
2428
- privacyUrl: r.privacyUrl ?? r.privacy_url,
2429
- docsUrl: r.docsUrl ?? r.docs_url,
2430
- support: r.support
2431
- };
2432
- return { valid: true, response: enhanced };
2433
- }
2434
- function parseX402Response(body) {
2435
- try {
2436
- const parsed = JSON.parse(body);
2437
- return validateX402Response(parsed);
2438
- } catch (error) {
2439
- return {
2440
- valid: false,
2441
- errors: [`Failed to parse JSON: ${error instanceof Error ? error.message : "Unknown error"}`]
2442
- };
2443
- }
2444
- }
2445
- var FetchWithPaymentClient = class extends EventEmitter {
2446
- wallet;
2447
- createPaymentHeader;
2448
- maxPayment;
2449
- preferredNetwork;
2450
- preferredToken;
2451
- timeout;
2452
- retries;
2453
- userAgent;
2454
- constructor(options) {
2455
- super();
2456
- this.wallet = options.wallet;
2457
- this.createPaymentHeader = options.createPaymentHeader;
2458
- this.maxPayment = options.maxPayment ?? BigInt("1000000000");
2459
- this.preferredNetwork = options.preferredNetwork;
2460
- this.preferredToken = options.preferredToken;
2461
- this.timeout = options.timeout ?? 3e4;
2462
- this.retries = options.retries ?? 1;
2463
- this.userAgent = options.userAgent ?? "GhostSpeak-x402-Fetch/1.0";
2464
- }
2465
- /**
2466
- * Make an x402-enabled fetch request
2467
- */
2468
- async fetch(url, options) {
2469
- const mergedOptions = {
2470
- ...options,
2471
- maxPayment: options?.maxPayment ?? this.maxPayment,
2472
- preferredNetwork: options?.preferredNetwork ?? this.preferredNetwork,
2473
- preferredToken: options?.preferredToken ?? this.preferredToken,
2474
- timeout: options?.timeout ?? this.timeout,
2475
- retries: options?.retries ?? this.retries
2476
- };
2477
- return this.fetchWithPayment(url, mergedOptions);
2478
- }
2479
- /**
2480
- * Internal fetch with payment logic
2481
- */
2482
- async fetchWithPayment(url, options) {
2483
- const headers = new Headers(options.headers);
2484
- headers.set("User-Agent", this.userAgent);
2485
- const initialResponse = await fetch(url, {
2486
- ...options,
2487
- headers,
2488
- signal: options.timeout ? AbortSignal.timeout(options.timeout) : void 0
2489
- });
2490
- if (initialResponse.status !== 402) {
2491
- return initialResponse;
2492
- }
2493
- const body = await initialResponse.text();
2494
- const parseResult = parseX402Response(body);
2495
- if (!parseResult.valid) {
2496
- const errorResponse = new Response(body, {
2497
- status: 402,
2498
- statusText: "Payment Required - Invalid x402 Response",
2499
- headers: initialResponse.headers
2500
- });
2501
- errorResponse.x402Requirements = [];
2502
- return errorResponse;
2503
- }
2504
- const x402Response = parseResult.response;
2505
- this.emit("paymentRequired", x402Response.accepts);
2506
- options.onPaymentRequired?.(x402Response.accepts);
2507
- if (options.dryRun) {
2508
- const dryRunResponse = new Response(body, {
2509
- status: 402,
2510
- statusText: "Payment Required",
2511
- headers: initialResponse.headers
2512
- });
2513
- dryRunResponse.x402Requirements = x402Response.accepts;
2514
- return dryRunResponse;
2515
- }
2516
- const selectedRequirement = this.selectPaymentRequirement(
2517
- x402Response.accepts,
2518
- options
2519
- );
2520
- if (!selectedRequirement) {
2521
- throw new X402PaymentError(
2522
- "No suitable payment option found within max payment limit",
2523
- x402Response.accepts
2524
- );
2525
- }
2526
- const amount = BigInt(selectedRequirement.maxAmountRequired);
2527
- if (amount > (options.maxPayment ?? this.maxPayment)) {
2528
- throw new X402PaymentError(
2529
- `Payment amount ${amount} exceeds max payment ${options.maxPayment ?? this.maxPayment}`,
2530
- x402Response.accepts
2531
- );
2532
- }
2533
- let paymentHeader;
2534
- try {
2535
- paymentHeader = await this.createPaymentHeader(selectedRequirement, this.wallet);
2536
- } catch (error) {
2537
- throw new X402PaymentError(
2538
- `Failed to create payment header: ${error instanceof Error ? error.message : "Unknown error"}`,
2539
- x402Response.accepts
2540
- );
2541
- }
2542
- const retryHeaders = new Headers(headers);
2543
- retryHeaders.set("X-Payment", paymentHeader);
2544
- for (let attempt = 0; attempt <= (options.retries ?? this.retries); attempt++) {
2545
- try {
2546
- const paidResponse = await fetch(url, {
2547
- ...options,
2548
- headers: retryHeaders,
2549
- signal: options.timeout ? AbortSignal.timeout(options.timeout) : void 0
2550
- });
2551
- const paymentInfo = {
2552
- signature: paymentHeader.split(":")[0] ?? "",
2553
- amount,
2554
- recipient: selectedRequirement.payTo,
2555
- token: selectedRequirement.asset,
2556
- network: selectedRequirement.network,
2557
- timestamp: Date.now()
2558
- };
2559
- const response = paidResponse;
2560
- response.paymentInfo = paymentInfo;
2561
- response.x402Requirements = x402Response.accepts;
2562
- this.emit("payment", paymentInfo);
2563
- options.onPayment?.(paymentInfo);
2564
- return response;
2565
- } catch (error) {
2566
- if (attempt === (options.retries ?? this.retries)) {
2567
- throw error;
2568
- }
2569
- await new Promise((resolve) => setTimeout(resolve, 1e3 * (attempt + 1)));
2570
- }
2571
- }
2572
- throw new Error("Failed to complete payment request after retries");
2573
- }
2574
- /**
2575
- * Select the best payment requirement based on options
2576
- */
2577
- selectPaymentRequirement(accepts, options) {
2578
- let candidates = [...accepts];
2579
- if (options.preferredNetwork) {
2580
- const networkMatches = candidates.filter(
2581
- (a) => a.network === options.preferredNetwork
2582
- );
2583
- if (networkMatches.length > 0) {
2584
- candidates = networkMatches;
2585
- }
2586
- }
2587
- if (options.preferredToken) {
2588
- const tokenMatches = candidates.filter(
2589
- (a) => a.asset.toLowerCase() === options.preferredToken.toLowerCase()
2590
- );
2591
- if (tokenMatches.length > 0) {
2592
- candidates = tokenMatches;
2593
- }
2594
- }
2595
- const maxPayment = options.maxPayment ?? this.maxPayment;
2596
- candidates = candidates.filter((a) => BigInt(a.maxAmountRequired) <= maxPayment);
2597
- if (candidates.length === 0) {
2598
- return null;
2599
- }
2600
- return candidates.sort(
2601
- (a, b) => Number(BigInt(a.maxAmountRequired) - BigInt(b.maxAmountRequired))
2602
- )[0];
2603
- }
2604
- };
2605
- var X402PaymentError = class extends Error {
2606
- constructor(message, requirements) {
2607
- super(message);
2608
- this.requirements = requirements;
2609
- this.name = "X402PaymentError";
2610
- }
2611
- };
2612
- async function fetchWithX402Payment(url, options, wallet, createPaymentHeader, paymentOptions) {
2613
- const client = new FetchWithPaymentClient({
2614
- wallet,
2615
- createPaymentHeader,
2616
- maxPayment: paymentOptions?.maxPayment,
2617
- preferredNetwork: paymentOptions?.preferredNetwork,
2618
- preferredToken: paymentOptions?.preferredToken,
2619
- timeout: paymentOptions?.timeout,
2620
- retries: paymentOptions?.retries
2621
- });
2622
- return client.fetch(url, {
2623
- ...options,
2624
- ...paymentOptions
2625
- });
2626
- }
2627
- function wrapFetchWithPayment(wallet, createPaymentHeader, defaultOptions) {
2628
- const client = new FetchWithPaymentClient({
2629
- wallet,
2630
- createPaymentHeader,
2631
- ...defaultOptions
2632
- });
2633
- return (url, options) => client.fetch(url, options);
2634
- }
2635
- var X402AnalyticsTracker = class extends EventEmitter {
2636
- constructor(options = {}) {
2637
- super();
2638
- this.options = options;
2639
- }
2640
- paymentEvents = [];
2641
- agentEarnings = /* @__PURE__ */ new Map();
2642
- agentCallCounts = /* @__PURE__ */ new Map();
2643
- tokenVolumes = /* @__PURE__ */ new Map();
2644
- metricsTimer;
2645
- isActive = false;
2646
- // Integration with existing analytics system
2647
- analyticsStreamer;
2648
- analyticsAggregator;
2649
- /**
2650
- * Start analytics tracking
2651
- */
2652
- start() {
2653
- if (this.isActive) {
2654
- console.warn("x402 analytics tracker is already active");
2655
- return;
2656
- }
2657
- this.isActive = true;
2658
- if (this.options.metricsInterval) {
2659
- this.metricsTimer = setInterval(() => {
2660
- this.aggregateAndEmitMetrics();
2661
- }, this.options.metricsInterval);
2662
- }
2663
- this.emit("started");
2664
- }
2665
- /**
2666
- * Stop analytics tracking
2667
- */
2668
- stop() {
2669
- this.isActive = false;
2670
- if (this.metricsTimer) {
2671
- clearInterval(this.metricsTimer);
2672
- this.metricsTimer = void 0;
2673
- }
2674
- this.emit("stopped");
2675
- }
2676
- /**
2677
- * Record a new x402 payment event
2678
- */
2679
- recordPayment(event) {
2680
- if (!this.isActive) return;
2681
- this.paymentEvents.push(event);
2682
- if (event.agent && event.status === "confirmed") {
2683
- const currentEarnings = this.agentEarnings.get(event.agent) ?? 0n;
2684
- this.agentEarnings.set(event.agent, currentEarnings + event.amount);
2685
- const currentCalls = this.agentCallCounts.get(event.agent) ?? 0;
2686
- this.agentCallCounts.set(event.agent, currentCalls + 1);
2687
- }
2688
- if (event.status === "confirmed") {
2689
- const currentVolume = this.tokenVolumes.get(event.token) ?? 0n;
2690
- this.tokenVolumes.set(event.token, currentVolume + event.amount);
2691
- }
2692
- this.emit("payment", event);
2693
- if (this.options.onPayment) {
2694
- this.options.onPayment(event);
2695
- }
2696
- this.pruneOldEvents();
2697
- }
2698
- /**
2699
- * Record payment from transaction signature
2700
- */
2701
- async recordPaymentFromSignature(signature, payer, recipient, amount, token, agent) {
2702
- const event = {
2703
- signature,
2704
- timestamp: BigInt(Date.now()),
2705
- payer,
2706
- recipient,
2707
- amount,
2708
- token,
2709
- agent,
2710
- status: "pending"
2711
- };
2712
- this.recordPayment(event);
2713
- }
2714
- /**
2715
- * Update payment status
2716
- */
2717
- updatePaymentStatus(signature, status, metadata) {
2718
- const event = this.paymentEvents.find((e) => e.signature === signature);
2719
- if (event) {
2720
- event.status = status;
2721
- if (metadata) {
2722
- event.metadata = { ...event.metadata, ...metadata };
2723
- }
2724
- this.emit("paymentStatusChanged", event);
2725
- }
2726
- }
2727
- /**
2728
- * Get current metrics
2729
- */
2730
- getMetrics(periodSeconds) {
2731
- const now = BigInt(Date.now());
2732
- const startTime = periodSeconds ? now - BigInt(periodSeconds * 1e3) : this.getOldestEventTimestamp();
2733
- const periodEvents = this.paymentEvents.filter((e) => e.timestamp >= startTime);
2734
- const total = periodEvents.length;
2735
- const successful = periodEvents.filter((e) => e.status === "confirmed").length;
2736
- const failed = periodEvents.filter((e) => e.status === "failed").length;
2737
- const pending = periodEvents.filter((e) => e.status === "pending").length;
2738
- const successfulEvents = periodEvents.filter((e) => e.status === "confirmed");
2739
- const totalVolume = successfulEvents.reduce((sum, e) => sum + e.amount, 0n);
2740
- const averageVolume = successful > 0 ? totalVolume / BigInt(successful) : 0n;
2741
- const volumeByToken = /* @__PURE__ */ new Map();
2742
- for (const event of successfulEvents) {
2743
- const current = volumeByToken.get(event.token) ?? 0n;
2744
- volumeByToken.set(event.token, current + event.amount);
2745
- }
2746
- const activeAgents = new Set(
2747
- periodEvents.filter((e) => e.agent).map((e) => e.agent)
2748
- );
2749
- const topEarners = Array.from(this.agentEarnings.entries()).map(([agent, earnings]) => ({
2750
- agent,
2751
- earnings,
2752
- callCount: this.agentCallCounts.get(agent) ?? 0
2753
- })).sort((a, b) => Number(b.earnings - a.earnings)).slice(0, 10);
2754
- const confirmedEvents = periodEvents.filter((e) => e.status === "confirmed");
2755
- const confirmationTimes = confirmedEvents.map((e) => Number(e.metadata?.confirmationTime ?? 0)).filter((t) => t > 0);
2756
- const averageConfirmationTime = confirmationTimes.length > 0 ? confirmationTimes.reduce((a, b) => a + b, 0) / confirmationTimes.length : 0;
2757
- const successRate = total > 0 ? successful / total * 100 : 0;
2758
- const errorRate = total > 0 ? failed / total * 100 : 0;
2759
- return {
2760
- period: {
2761
- start: startTime,
2762
- end: now
2763
- },
2764
- payments: {
2765
- total,
2766
- successful,
2767
- failed,
2768
- pending
2769
- },
2770
- volume: {
2771
- total: totalVolume,
2772
- average: averageVolume,
2773
- byToken: volumeByToken
2774
- },
2775
- agents: {
2776
- totalActive: activeAgents.size,
2777
- topEarners
2778
- },
2779
- performance: {
2780
- averageConfirmationTime,
2781
- successRate,
2782
- errorRate
2783
- }
2784
- };
2785
- }
2786
- /**
2787
- * Get agent earnings
2788
- */
2789
- getAgentEarnings(agent) {
2790
- const totalEarnings = this.agentEarnings.get(agent) ?? 0n;
2791
- const totalCalls = this.agentCallCounts.get(agent) ?? 0;
2792
- const averagePerCall = totalCalls > 0 ? totalEarnings / BigInt(totalCalls) : 0n;
2793
- return {
2794
- totalEarnings,
2795
- totalCalls,
2796
- averagePerCall
2797
- };
2798
- }
2799
- /**
2800
- * Get token volume
2801
- */
2802
- getTokenVolume(token) {
2803
- return this.tokenVolumes.get(token) ?? 0n;
2804
- }
2805
- /**
2806
- * Get payment history for agent
2807
- */
2808
- getAgentPaymentHistory(agent, limit) {
2809
- const agentEvents = this.paymentEvents.filter((e) => e.agent === agent).sort((a, b) => Number(b.timestamp - a.timestamp));
2810
- return limit ? agentEvents.slice(0, limit) : agentEvents;
35
+ var DEFAULT_API_URL = "https://api.ghostspeak.ai";
36
+ var DEVNET_API_URL = "https://api-devnet.ghostspeak.ai";
37
+ var LOCALNET_API_URL = "http://localhost:3001";
38
+ var ExternalIdResolver = class {
39
+ apiUrl;
40
+ constructor(config) {
41
+ if (config?.apiUrl) {
42
+ this.apiUrl = config.apiUrl;
43
+ } else {
44
+ const cluster = config?.cluster || "devnet";
45
+ this.apiUrl = cluster === "mainnet-beta" ? DEFAULT_API_URL : cluster === "localnet" ? LOCALNET_API_URL : DEVNET_API_URL;
46
+ }
2811
47
  }
2812
48
  /**
2813
- * Get recent payments
49
+ * Resolve external ID to Ghost address
50
+ *
51
+ * @example
52
+ * const address = await resolver.resolve('payai', 'agent-123');
2814
53
  */
2815
- getRecentPayments(limit = 100) {
2816
- return this.paymentEvents.slice(-limit).sort((a, b) => Number(b.timestamp - a.timestamp));
54
+ async resolve(platform, externalId) {
55
+ const result = await this.lookup(platform, externalId);
56
+ return address(result.mapping.ghostAddress);
2817
57
  }
2818
58
  /**
2819
- * Integrate with existing analytics streamer
59
+ * Lookup external ID with full Ghost data
60
+ *
61
+ * @example
62
+ * const { mapping, ghost } = await resolver.lookup('payai', 'agent-123');
2820
63
  */
2821
- integrateWithStreamer(streamer) {
2822
- this.analyticsStreamer = streamer;
2823
- streamer.on("transactionAnalytics", (event) => {
2824
- if (this.isX402Transaction(event)) {
2825
- this.recordPaymentFromAnalyticsEvent(event);
64
+ async lookup(platform, externalId) {
65
+ try {
66
+ const response = await fetch(
67
+ `${this.apiUrl}/ghosts/external/${encodeURIComponent(platform)}/${encodeURIComponent(externalId)}`
68
+ );
69
+ if (response.status === 404) {
70
+ throw new ExternalIdNotFoundError(platform, externalId);
71
+ }
72
+ if (!response.ok) {
73
+ const error = await response.json().catch(() => ({}));
74
+ throw new GhostSpeakError(
75
+ error.message || "Failed to lookup external ID",
76
+ error.code || "LOOKUP_FAILED"
77
+ );
2826
78
  }
2827
- });
79
+ const data = await response.json();
80
+ return data;
81
+ } catch (error) {
82
+ if (error instanceof GhostSpeakError || error instanceof ExternalIdNotFoundError) throw error;
83
+ throw new GhostSpeakError(
84
+ "Failed to lookup external ID",
85
+ "LOOKUP_FAILED"
86
+ );
87
+ }
2828
88
  }
2829
89
  /**
2830
- * Integrate with existing analytics aggregator
90
+ * Get Ghost by Solana address via API
91
+ *
92
+ * Faster than on-chain lookup for read operations
2831
93
  */
2832
- integrateWithAggregator(aggregator) {
2833
- this.analyticsAggregator = aggregator;
2834
- this.on("payment", (event) => {
2835
- if (event.status === "confirmed" && this.analyticsAggregator) {
2836
- const txEvent = {
2837
- transactionType: "x402_payment",
2838
- amount: event.amount,
2839
- from: event.payer,
2840
- to: event.recipient,
2841
- status: "completed",
2842
- timestamp: BigInt(event.timestamp),
2843
- blockHeight: 0n
2844
- // Would be populated from actual blockchain data
2845
- };
2846
- this.analyticsAggregator.processTransactionEvent(txEvent);
94
+ async getGhost(ghostAddress) {
95
+ try {
96
+ const addrString = typeof ghostAddress === "string" ? ghostAddress : ghostAddress;
97
+ const response = await fetch(
98
+ `${this.apiUrl}/ghosts/${encodeURIComponent(addrString)}`
99
+ );
100
+ if (response.status === 404) {
101
+ throw new GhostNotFoundError(addrString);
102
+ }
103
+ if (!response.ok) {
104
+ const error = await response.json().catch(() => ({}));
105
+ throw new GhostSpeakError(
106
+ error.message || "Failed to fetch Ghost",
107
+ error.code || "FETCH_FAILED"
108
+ );
2847
109
  }
2848
- });
110
+ const ghost = await response.json();
111
+ return ghost;
112
+ } catch (error) {
113
+ if (error instanceof GhostSpeakError || error instanceof GhostNotFoundError) throw error;
114
+ throw new GhostSpeakError(
115
+ "Failed to fetch Ghost",
116
+ "FETCH_FAILED"
117
+ );
118
+ }
2849
119
  }
2850
120
  /**
2851
- * Get aggregated metrics from integrated aggregator
121
+ * Get Ghost Score via API
2852
122
  */
2853
- getAggregatedMetrics() {
2854
- return this.analyticsAggregator?.aggregate() ?? null;
2855
- }
2856
- // Private helper methods
2857
- aggregateAndEmitMetrics() {
123
+ async getGhostScore(ghostAddress) {
2858
124
  try {
2859
- const metrics = this.getMetrics();
2860
- this.emit("metrics", metrics);
2861
- if (this.options.onMetrics) {
2862
- this.options.onMetrics(metrics);
125
+ const addrString = typeof ghostAddress === "string" ? ghostAddress : ghostAddress;
126
+ const response = await fetch(
127
+ `${this.apiUrl}/ghosts/${encodeURIComponent(addrString)}/score`
128
+ );
129
+ if (response.status === 404) {
130
+ throw new GhostNotFoundError(addrString);
131
+ }
132
+ if (!response.ok) {
133
+ const error = await response.json().catch(() => ({}));
134
+ throw new GhostSpeakError(
135
+ error.message || "Failed to fetch Ghost Score",
136
+ error.code || "FETCH_FAILED"
137
+ );
2863
138
  }
139
+ const score = await response.json();
140
+ return score;
2864
141
  } catch (error) {
2865
- this.handleError(error);
2866
- }
2867
- }
2868
- pruneOldEvents() {
2869
- if (!this.options.retentionPeriod) return;
2870
- const cutoffTime = BigInt(Date.now()) - BigInt(this.options.retentionPeriod * 1e3);
2871
- this.paymentEvents = this.paymentEvents.filter((e) => e.timestamp > cutoffTime);
2872
- }
2873
- getOldestEventTimestamp() {
2874
- if (this.paymentEvents.length === 0) {
2875
- return BigInt(Date.now());
2876
- }
2877
- return this.paymentEvents[0].timestamp;
2878
- }
2879
- isX402Transaction(event) {
2880
- return event.transactionType === "x402_payment" || event.transactionType === "payment";
2881
- }
2882
- recordPaymentFromAnalyticsEvent(event) {
2883
- const paymentEvent = {
2884
- signature: "",
2885
- // Not available in TransactionAnalyticsEvent
2886
- timestamp: BigInt(event.timestamp),
2887
- payer: event.from,
2888
- recipient: event.to,
2889
- amount: event.amount,
2890
- token: "11111111111111111111111111111111",
2891
- // Would parse from event
2892
- status: event.status === "completed" ? "confirmed" : "failed"
2893
- };
2894
- this.recordPayment(paymentEvent);
2895
- }
2896
- handleError(error) {
2897
- this.emit("error", error);
2898
- if (this.options.onError) {
2899
- this.options.onError(error);
142
+ if (error instanceof GhostSpeakError || error instanceof GhostNotFoundError) throw error;
143
+ throw new GhostSpeakError(
144
+ "Failed to fetch Ghost Score",
145
+ "FETCH_FAILED"
146
+ );
2900
147
  }
2901
148
  }
2902
149
  /**
2903
- * Clear all tracked data
2904
- */
2905
- clearData() {
2906
- this.paymentEvents = [];
2907
- this.agentEarnings.clear();
2908
- this.agentCallCounts.clear();
2909
- this.tokenVolumes.clear();
2910
- }
2911
- /**
2912
- * Get tracker statistics
2913
- */
2914
- getStats() {
2915
- return {
2916
- eventsTracked: this.paymentEvents.length,
2917
- agentsTracked: this.agentEarnings.size,
2918
- tokensTracked: this.tokenVolumes.size,
2919
- isActive: this.isActive
2920
- };
2921
- }
2922
- };
2923
- function createX402AnalyticsTracker(options) {
2924
- return new X402AnalyticsTracker(options);
2925
- }
2926
- var PaymentStreamingManager = class extends EventEmitter {
2927
- streams;
2928
- intervals;
2929
- x402Client;
2930
- connection;
2931
- constructor(x402Client, connection) {
2932
- super();
2933
- this.streams = /* @__PURE__ */ new Map();
2934
- this.intervals = /* @__PURE__ */ new Map();
2935
- this.x402Client = x402Client;
2936
- this.connection = connection;
2937
- }
2938
- /**
2939
- * Create a new payment stream
150
+ * Get detailed reputation breakdown via API
2940
151
  */
2941
- async createStream(config) {
2942
- const streamId = this.generateStreamId(config);
2943
- this.validateStreamConfig(config);
2944
- const stream = {
2945
- id: streamId,
2946
- config,
2947
- status: "active",
2948
- amountPaid: 0n,
2949
- payments: [],
2950
- startedAt: Date.now(),
2951
- nextPaymentAt: Date.now() + config.intervalMs
2952
- };
2953
- this.streams.set(streamId, stream);
2954
- this.startStreamInterval(stream);
2955
- this.emit("stream_created", stream);
2956
- return stream;
2957
- }
2958
- /**
2959
- * Pause a payment stream
2960
- */
2961
- pauseStream(streamId) {
2962
- const stream = this.streams.get(streamId);
2963
- if (!stream) {
2964
- throw new Error(`Stream ${streamId} not found`);
2965
- }
2966
- if (stream.status !== "active") {
2967
- throw new Error(`Stream ${streamId} is not active`);
152
+ async getGhostReputation(ghostAddress) {
153
+ try {
154
+ const addrString = typeof ghostAddress === "string" ? ghostAddress : ghostAddress;
155
+ const response = await fetch(
156
+ `${this.apiUrl}/ghosts/${encodeURIComponent(addrString)}/reputation`
157
+ );
158
+ if (response.status === 404) {
159
+ throw new GhostNotFoundError(addrString);
160
+ }
161
+ if (!response.ok) {
162
+ const error = await response.json().catch(() => ({}));
163
+ throw new GhostSpeakError(
164
+ error.message || "Failed to fetch reputation",
165
+ error.code || "FETCH_FAILED"
166
+ );
167
+ }
168
+ return await response.json();
169
+ } catch (error) {
170
+ if (error instanceof GhostSpeakError || error instanceof GhostNotFoundError) throw error;
171
+ throw new GhostSpeakError(
172
+ "Failed to fetch reputation",
173
+ "FETCH_FAILED"
174
+ );
2968
175
  }
2969
- this.stopStreamInterval(streamId);
2970
- stream.status = "paused";
2971
- this.emit("stream_paused", stream);
2972
176
  }
2973
177
  /**
2974
- * Resume a paused payment stream
178
+ * Batch resolve multiple external IDs
2975
179
  */
2976
- resumeStream(streamId) {
2977
- const stream = this.streams.get(streamId);
2978
- if (!stream) {
2979
- throw new Error(`Stream ${streamId} not found`);
2980
- }
2981
- if (stream.status !== "paused") {
2982
- throw new Error(`Stream ${streamId} is not paused`);
2983
- }
2984
- stream.status = "active";
2985
- stream.nextPaymentAt = Date.now() + stream.config.intervalMs;
2986
- this.startStreamInterval(stream);
2987
- this.emit("stream_resumed", stream);
180
+ async resolveBatch(identifiers) {
181
+ const promises = identifiers.map(
182
+ ({ platform, externalId }) => this.resolve(platform, externalId).catch(() => null)
183
+ );
184
+ return Promise.all(promises);
2988
185
  }
2989
186
  /**
2990
- * Cancel a payment stream
187
+ * Check if external ID exists
2991
188
  */
2992
- cancelStream(streamId) {
2993
- const stream = this.streams.get(streamId);
2994
- if (!stream) {
2995
- throw new Error(`Stream ${streamId} not found`);
189
+ async exists(platform, externalId) {
190
+ try {
191
+ await this.resolve(platform, externalId);
192
+ return true;
193
+ } catch (error) {
194
+ if (error instanceof ExternalIdNotFoundError) return false;
195
+ throw error;
2996
196
  }
2997
- this.stopStreamInterval(streamId);
2998
- stream.status = "cancelled";
2999
- stream.endedAt = Date.now();
3000
- this.emit("stream_cancelled", stream);
3001
197
  }
3002
198
  /**
3003
- * Get stream by ID
199
+ * Get all external IDs for a Ghost
200
+ *
201
+ * Fetches Ghost data and returns external identifiers
3004
202
  */
3005
- getStream(streamId) {
3006
- return this.streams.get(streamId);
203
+ async getExternalIds(ghostAddress) {
204
+ const ghost = await this.getGhost(ghostAddress);
205
+ return ghost.externalIdentifiers;
3007
206
  }
3008
207
  /**
3009
- * Get all streams
208
+ * Search for Ghost by partial platform ID
209
+ *
210
+ * Note: This is a client-side filter, not server-side search
211
+ * For production, implement server-side search endpoint
3010
212
  */
3011
- getAllStreams() {
3012
- return Array.from(this.streams.values());
213
+ async searchByExternalId(platform, partialId) {
214
+ throw new GhostSpeakError(
215
+ "Search not yet implemented",
216
+ "NOT_IMPLEMENTED"
217
+ );
3013
218
  }
3014
219
  /**
3015
- * Get active streams
220
+ * Set custom API URL
3016
221
  */
3017
- getActiveStreams() {
3018
- return Array.from(this.streams.values()).filter((s) => s.status === "active");
222
+ setApiUrl(apiUrl) {
223
+ this.apiUrl = apiUrl;
3019
224
  }
3020
225
  /**
3021
- * Complete a milestone
226
+ * Get current API URL
3022
227
  */
3023
- async completeMilestone(streamId, milestoneId) {
3024
- const stream = this.streams.get(streamId);
3025
- if (!stream) {
3026
- throw new Error(`Stream ${streamId} not found`);
3027
- }
3028
- const milestone = stream.config.milestones?.find((m) => m.id === milestoneId);
3029
- if (!milestone) {
3030
- throw new Error(`Milestone ${milestoneId} not found`);
3031
- }
3032
- if (milestone.completed) {
3033
- throw new Error(`Milestone ${milestoneId} already completed`);
3034
- }
3035
- const conditionMet = await milestone.condition();
3036
- if (!conditionMet) {
3037
- throw new Error(`Milestone ${milestoneId} condition not met`);
3038
- }
3039
- try {
3040
- const paymentSignature = await this.makePayment(stream, milestone.amount, milestoneId);
3041
- milestone.completed = true;
3042
- milestone.completedAt = Date.now();
3043
- this.emit("milestone_completed", {
3044
- streamId,
3045
- milestoneId,
3046
- signature: paymentSignature
3047
- });
3048
- } catch (error) {
3049
- this.emit("milestone_failed", {
3050
- streamId,
3051
- milestoneId,
3052
- error
3053
- });
3054
- throw error;
3055
- }
228
+ getApiUrl() {
229
+ return this.apiUrl;
3056
230
  }
3057
231
  /**
3058
- * Cleanup: Stop all streams and clear intervals
232
+ * Check API health
3059
233
  */
3060
- cleanup() {
3061
- for (const streamId of this.intervals.keys()) {
3062
- this.stopStreamInterval(streamId);
3063
- }
3064
- this.streams.clear();
3065
- this.intervals.clear();
3066
- }
3067
- // Private methods
3068
- generateStreamId(config) {
3069
- const timestamp = Date.now();
3070
- const hash = `${config.agentAddress}-${config.clientAddress}-${timestamp}`;
3071
- return Buffer.from(hash).toString("base64").slice(0, 16);
3072
- }
3073
- validateStreamConfig(config) {
3074
- if (config.totalAmount <= 0n) {
3075
- throw new Error("Total amount must be positive");
3076
- }
3077
- if (config.intervalMs <= 0) {
3078
- throw new Error("Interval must be positive");
3079
- }
3080
- if (config.durationMs <= 0) {
3081
- throw new Error("Duration must be positive");
3082
- }
3083
- if (config.amountPerInterval <= 0n) {
3084
- throw new Error("Amount per interval must be positive");
3085
- }
3086
- const maxPayments = Math.ceil(config.durationMs / config.intervalMs);
3087
- const totalViaInterval = config.amountPerInterval * BigInt(maxPayments);
3088
- const milestoneTotal = config.milestones?.reduce((sum, m) => sum + m.amount, 0n) ?? 0n;
3089
- if (totalViaInterval + milestoneTotal > config.totalAmount * 110n / 100n) {
3090
- throw new Error("Payment schedule exceeds total amount (with 10% tolerance)");
3091
- }
3092
- }
3093
- startStreamInterval(stream) {
3094
- const interval = setInterval(async () => {
3095
- await this.processPayment(stream);
3096
- }, stream.config.intervalMs);
3097
- this.intervals.set(stream.id, interval);
3098
- }
3099
- stopStreamInterval(streamId) {
3100
- const interval = this.intervals.get(streamId);
3101
- if (interval) {
3102
- clearInterval(interval);
3103
- this.intervals.delete(streamId);
3104
- }
3105
- }
3106
- async processPayment(stream) {
3107
- if (stream.status !== "active") {
3108
- return;
3109
- }
3110
- if (stream.amountPaid >= stream.config.totalAmount) {
3111
- this.completeStream(stream);
3112
- return;
3113
- }
3114
- if (Date.now() >= stream.startedAt + stream.config.durationMs) {
3115
- this.completeStream(stream);
3116
- return;
3117
- }
234
+ async checkHealth() {
3118
235
  try {
3119
- const amount = stream.config.amountPerInterval;
3120
- const signature = await this.makePayment(stream, amount);
3121
- stream.lastPaymentAt = Date.now();
3122
- stream.nextPaymentAt = Date.now() + stream.config.intervalMs;
3123
- this.emit("payment_processed", {
3124
- streamId: stream.id,
3125
- amount,
3126
- signature
3127
- });
3128
- } catch (error) {
3129
- this.emit("payment_failed", {
3130
- streamId: stream.id,
3131
- error
3132
- });
3133
- if (stream.config.autoResume !== true) {
3134
- stream.status = "failed";
3135
- stream.error = error;
3136
- stream.endedAt = Date.now();
3137
- this.stopStreamInterval(stream.id);
236
+ const response = await fetch(`${this.apiUrl}/health`);
237
+ if (!response.ok) {
238
+ throw new Error(`HTTP ${response.status}`);
3138
239
  }
240
+ return await response.json();
241
+ } catch (error) {
242
+ throw new GhostSpeakError(
243
+ "Failed to check API health",
244
+ "HEALTH_CHECK_FAILED"
245
+ );
3139
246
  }
3140
247
  }
3141
- async makePayment(stream, amount, milestoneId) {
3142
- const paymentRequest = this.x402Client.createPaymentRequest({
3143
- amount,
3144
- token: stream.config.tokenMint,
3145
- description: milestoneId ? `Stream ${stream.id} - Milestone ${milestoneId}` : `Stream ${stream.id} - Interval payment`,
3146
- metadata: {
3147
- streamId: stream.id,
3148
- ...milestoneId && { milestoneId }
3149
- }
3150
- });
3151
- const receipt = await this.x402Client.pay(paymentRequest);
3152
- const payment = {
3153
- timestamp: Date.now(),
3154
- amount,
3155
- signature: receipt.signature,
3156
- milestoneId,
3157
- success: true
3158
- };
3159
- stream.payments.push(payment);
3160
- stream.amountPaid += amount;
3161
- return receipt.signature;
3162
- }
3163
- completeStream(stream) {
3164
- this.stopStreamInterval(stream.id);
3165
- stream.status = "completed";
3166
- stream.endedAt = Date.now();
3167
- this.emit("stream_completed", stream);
3168
- }
3169
248
  };
3170
- var A2AClient = class extends EventEmitter {
249
+
250
+ // src/index.ts
251
+ init_reputation_tag_engine();
252
+
253
+ // src/modules/indexer/X402TransactionIndexer.ts
254
+ var X402TransactionIndexer = class {
3171
255
  rpc;
3172
- programId;
3173
- wallet;
3174
- constructor(options, wallet) {
3175
- super();
3176
- this.rpc = createSolanaRpc(options.rpcEndpoint);
3177
- this.programId = options.programId ?? GHOSTSPEAK_MARKETPLACE_PROGRAM_ADDRESS;
3178
- this.wallet = wallet;
3179
- }
3180
- /**
3181
- * Create a new A2A communication session
3182
- *
3183
- * Establishes a secure communication channel between two agents.
3184
- *
3185
- * @param config - Session configuration
3186
- * @returns Session details including address
3187
- *
3188
- * @example
3189
- * ```typescript
3190
- * const session = await a2aClient.createSession({
3191
- * responder: 'AgentBpubkey...',
3192
- * sessionType: 'data_processing',
3193
- * metadata: 'Processing financial data',
3194
- * expiresIn: 7200 // 2 hours
3195
- * })
3196
- * console.log('Session created:', session.address)
3197
- * ```
3198
- */
3199
- async createSession(config) {
3200
- try {
3201
- const now = Math.floor(Date.now() / 1e3);
3202
- const expiresAt = now + (config.expiresIn ?? 3600);
3203
- const sessionId = BigInt(Date.now());
3204
- const instruction = await getCreateA2aSessionInstructionAsync({
3205
- creator: this.wallet,
3206
- sessionId,
3207
- initiator: this.wallet.address,
3208
- responder: config.responder,
3209
- sessionType: config.sessionType,
3210
- metadata: config.metadata ?? "",
3211
- expiresAt: BigInt(expiresAt)
3212
- }, { programAddress: this.programId });
3213
- const signature = await this.sendTransaction([instruction]);
3214
- const sessionAddress = instruction.accounts[0].address;
3215
- this.emit("session_created", {
3216
- type: "session_created",
3217
- timestamp: Date.now(),
3218
- data: { sessionAddress, signature }
3219
- });
3220
- const session = await fetchA2ASession(this.rpc, sessionAddress);
3221
- return {
3222
- ...session.data,
3223
- address: sessionAddress
3224
- };
3225
- } catch (error) {
3226
- const errorMessage = error instanceof Error ? error.message : String(error);
3227
- this.emit("error", {
3228
- type: "error",
3229
- timestamp: Date.now(),
3230
- error: errorMessage
3231
- });
3232
- throw new Error(`Failed to create A2A session: ${errorMessage}`);
3233
- }
3234
- }
3235
- /**
3236
- * Send a message in an A2A session
3237
- *
3238
- * Sends structured messages between agents with automatic context management.
3239
- *
3240
- * @param params - Message parameters
3241
- * @returns Transaction signature
3242
- *
3243
- * @example
3244
- * ```typescript
3245
- * await a2aClient.sendMessage({
3246
- * sessionAddress: session.address,
3247
- * content: 'Processing complete. Results: {...}',
3248
- * messageType: 'result'
3249
- * })
3250
- * ```
3251
- */
3252
- async sendMessage(params) {
3253
- try {
3254
- const messageId = BigInt(Date.now());
3255
- const sessionId = BigInt(Date.now());
3256
- const timestamp = BigInt(Math.floor(Date.now() / 1e3));
3257
- const instruction = getSendA2aMessageInstruction({
3258
- message: await this.deriveMessageAddress(params.sessionAddress),
3259
- session: params.sessionAddress,
3260
- sender: this.wallet,
3261
- messageId,
3262
- sessionId,
3263
- senderArg: this.wallet.address,
3264
- content: params.content,
3265
- messageType: params.messageType ?? "text",
3266
- timestamp
3267
- }, { programAddress: this.programId });
3268
- const signature = await this.sendTransaction([instruction]);
3269
- this.emit("message_sent", {
3270
- type: "message_sent",
3271
- timestamp: Date.now(),
3272
- data: { signature, content: params.content }
3273
- });
3274
- return signature;
3275
- } catch (error) {
3276
- const errorMessage = error instanceof Error ? error.message : String(error);
3277
- this.emit("error", {
3278
- type: "error",
3279
- timestamp: Date.now(),
3280
- error: errorMessage
3281
- });
3282
- throw new Error(`Failed to send A2A message: ${errorMessage}`);
3283
- }
256
+ facilitatorAddress;
257
+ network;
258
+ batchSize;
259
+ constructor(config) {
260
+ this.rpc = config.rpc;
261
+ this.facilitatorAddress = config.facilitatorAddress;
262
+ this.network = config.network || "solana";
263
+ this.batchSize = config.batchSize || 100;
3284
264
  }
265
+ // =====================================================
266
+ // PUBLIC METHODS
267
+ // =====================================================
3285
268
  /**
3286
- * Update agent status
3287
- *
3288
- * Updates agent availability, capabilities, and status for discovery.
3289
- *
3290
- * @param update - Status update
3291
- * @returns Transaction signature
269
+ * Poll for new x402 transactions since last sync
3292
270
  *
3293
- * @example
3294
- * ```typescript
3295
- * await a2aClient.updateStatus({
3296
- * status: 'busy',
3297
- * capabilities: ['nlp', 'translation'],
3298
- * availability: false
3299
- * })
3300
- * ```
271
+ * @param lastSignature - Last processed signature (for pagination)
272
+ * @param limit - Maximum transactions to fetch
273
+ * @returns Array of parsed x402 payment data
3301
274
  */
3302
- async updateStatus(update) {
275
+ async pollTransactions(lastSignature, limit) {
3303
276
  try {
3304
- const statusAddress = await this.deriveStatusAddress();
3305
- const instruction = getUpdateA2aStatusInstruction({
3306
- status: statusAddress,
3307
- session: address("11111111111111111111111111111111"),
3308
- // Placeholder - need actual session
3309
- updater: this.wallet,
3310
- statusId: BigInt(Date.now()),
3311
- agent: this.wallet.address,
3312
- statusArg: update.status,
3313
- capabilities: update.capabilities ?? [],
3314
- availability: update.availability ?? true,
3315
- lastUpdated: BigInt(Math.floor(Date.now() / 1e3))
3316
- }, { programAddress: this.programId });
3317
- const signature = await this.sendTransaction([instruction]);
3318
- this.emit("status_updated", {
3319
- type: "status_updated",
3320
- timestamp: Date.now(),
3321
- data: { signature, status: update.status }
3322
- });
3323
- return signature;
277
+ const signatures = await this.getSignatures(lastSignature, limit);
278
+ if (signatures.length === 0) {
279
+ return [];
280
+ }
281
+ console.log(`[X402 Indexer] Found ${signatures.length} new transactions`);
282
+ const payments = [];
283
+ for (const sig of signatures) {
284
+ try {
285
+ const payment = await this.parseTransaction(sig.signature);
286
+ if (payment) {
287
+ payments.push(payment);
288
+ }
289
+ } catch (error) {
290
+ console.error(`[X402 Indexer] Failed to parse transaction ${sig.signature}:`, error);
291
+ }
292
+ }
293
+ console.log(`[X402 Indexer] Parsed ${payments.length} x402 payments`);
294
+ return payments;
3324
295
  } catch (error) {
3325
- const errorMessage = error instanceof Error ? error.message : String(error);
3326
- this.emit("error", {
3327
- type: "error",
3328
- timestamp: Date.now(),
3329
- error: errorMessage
3330
- });
3331
- throw new Error(`Failed to update A2A status: ${errorMessage}`);
296
+ console.error("[X402 Indexer] Failed to poll transactions:", error);
297
+ throw error;
3332
298
  }
3333
299
  }
3334
300
  /**
3335
- * Get session details
3336
- *
3337
- * Fetches current session state from on-chain.
301
+ * Parse a specific transaction signature
3338
302
  *
3339
- * @param sessionAddress - Session PDA address
3340
- * @returns Session details
303
+ * @param signature - Transaction signature to parse
304
+ * @returns Parsed x402 payment data or null if not an x402 payment
3341
305
  */
3342
- async getSession(sessionAddress) {
306
+ async parseTransaction(sig) {
3343
307
  try {
3344
- const maybeSession = await fetchMaybeA2ASession(this.rpc, sessionAddress);
3345
- if (!maybeSession.exists) {
308
+ const txSignature = typeof sig === "string" ? sig : sig;
309
+ const response = await this.rpc.getTransaction(txSignature, {
310
+ maxSupportedTransactionVersion: 0,
311
+ encoding: "jsonParsed"
312
+ }).send();
313
+ if (!response || !response.transaction) {
3346
314
  return null;
3347
315
  }
3348
- return {
3349
- ...maybeSession.data,
3350
- address: sessionAddress
3351
- };
316
+ const isX402 = this.isX402Payment(response);
317
+ if (!isX402) {
318
+ return null;
319
+ }
320
+ return this.extractPaymentData(response, typeof sig === "string" ? sig : String(sig));
3352
321
  } catch (error) {
3353
- console.error("Failed to fetch A2A session:", error);
322
+ console.error(`[X402 Indexer] Failed to fetch transaction ${sig}:`, error);
3354
323
  return null;
3355
324
  }
3356
325
  }
326
+ // =====================================================
327
+ // PRIVATE METHODS
328
+ // =====================================================
3357
329
  /**
3358
- * Get message by address
3359
- *
3360
- * @param messageAddress - Message PDA address
3361
- * @returns Message data
330
+ * Fetch transaction signatures for the facilitator address
3362
331
  */
3363
- async getMessage(messageAddress) {
332
+ async getSignatures(before, limit) {
3364
333
  try {
3365
- const message = await fetchA2AMessage(this.rpc, messageAddress);
3366
- return message.data;
334
+ const config = {
335
+ limit: limit || this.batchSize
336
+ };
337
+ if (before) {
338
+ config.before = before;
339
+ }
340
+ const response = await this.rpc.getSignaturesForAddress(this.facilitatorAddress, config).send();
341
+ return response.map((sig) => ({
342
+ signature: sig.signature,
343
+ slot: sig.slot,
344
+ blockTime: sig.blockTime,
345
+ err: sig.err ?? null
346
+ }));
3367
347
  } catch (error) {
3368
- console.error("Failed to fetch A2A message:", error);
3369
- return null;
348
+ console.error("[X402 Indexer] Failed to fetch signatures:", error);
349
+ throw error;
3370
350
  }
3371
351
  }
3372
352
  /**
3373
- * Get agent status
353
+ * Check if transaction is an x402 payment
3374
354
  *
3375
- * @param statusAddress - Status PDA address
3376
- * @returns Status data
355
+ * x402 payments are characterized by:
356
+ * - SPL token transfer (TokenProgram or Token2022Program)
357
+ * - Transfer TO the facilitator address
358
+ * - Optional memo instruction with payment metadata
3377
359
  */
3378
- async getStatus(statusAddress) {
3379
- try {
3380
- const status = await fetchA2AStatus(this.rpc, statusAddress);
3381
- return status.data;
3382
- } catch (error) {
3383
- console.error("Failed to fetch A2A status:", error);
3384
- return null;
3385
- }
3386
- }
3387
- // =====================================================
3388
- // PRIVATE HELPER METHODS
3389
- // =====================================================
3390
- async sendTransaction(instructions) {
360
+ isX402Payment(transaction) {
3391
361
  try {
3392
- const { value: latestBlockhash } = await this.rpc.getLatestBlockhash().send();
3393
- let message = createTransactionMessage({ version: 0 });
3394
- message = setTransactionMessageFeePayer(this.wallet.address, message);
3395
- message = setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, message);
3396
- for (const ix of instructions) {
3397
- message = appendTransactionMessageInstruction(ix, message);
3398
- }
3399
- const signedTransaction = await signTransactionMessageWithSigners(message);
3400
- const signatures = Object.values(signedTransaction.signatures);
3401
- if (signatures.length === 0) {
3402
- throw new Error("Transaction has no signatures");
3403
- }
3404
- const signature = signatures[0];
3405
- const wireTransaction = getBase64EncodedWireTransaction(signedTransaction);
3406
- await this.rpc.sendTransaction(wireTransaction).send();
3407
- await this.confirmTransaction(signature);
3408
- return signature;
362
+ const instructions = transaction.transaction?.message?.instructions || [];
363
+ const hasTokenTransfer = instructions.some((ix) => {
364
+ const programId = ix.programId?.toString();
365
+ const isTokenProgram = programId === "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" || // SPL Token
366
+ programId === "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb";
367
+ if (!isTokenProgram) return false;
368
+ const parsed = ix.parsed;
369
+ if (parsed?.type === "transfer" || parsed?.type === "transferChecked") {
370
+ const destination = parsed.info?.destination;
371
+ return destination === this.facilitatorAddress.toString();
372
+ }
373
+ return false;
374
+ });
375
+ return hasTokenTransfer;
3409
376
  } catch (error) {
3410
- throw new Error(
3411
- `Transaction failed: ${error instanceof Error ? error.message : String(error)}`
3412
- );
3413
- }
3414
- }
3415
- async confirmTransaction(signature) {
3416
- for (let i = 0; i < 30; i++) {
3417
- const status = await this.rpc.getSignatureStatuses([signature]).send();
3418
- if (status.value[0]?.confirmationStatus === "confirmed" || status.value[0]?.confirmationStatus === "finalized") {
3419
- return;
3420
- }
3421
- await new Promise((resolve) => setTimeout(resolve, 1e3));
377
+ console.error("[X402 Indexer] Error checking if x402 payment:", error);
378
+ return false;
3422
379
  }
3423
- throw new Error("Transaction confirmation timeout");
3424
- }
3425
- async deriveMessageAddress(sessionAddress) {
3426
- return address("11111111111111111111111111111111");
3427
- }
3428
- async deriveStatusAddress() {
3429
- return address("11111111111111111111111111111111");
3430
- }
3431
- };
3432
- function createA2AClient(options, wallet) {
3433
- return new A2AClient(options, wallet);
3434
- }
3435
- var H2AClient = class extends EventEmitter {
3436
- rpc;
3437
- programId;
3438
- wallet;
3439
- constructor(options, wallet) {
3440
- super();
3441
- this.rpc = createSolanaRpc(options.rpcEndpoint);
3442
- this.programId = options.programId ?? GHOSTSPEAK_MARKETPLACE_PROGRAM_ADDRESS;
3443
- this.wallet = wallet;
3444
- }
3445
- /**
3446
- * Create a new communication session with an agent
3447
- *
3448
- * Establishes a communication channel between a human and an agent.
3449
- *
3450
- * @param config - Session configuration
3451
- * @returns Session details including address
3452
- *
3453
- * @throws {Error} Currently not implemented - requires IDL regeneration
3454
- *
3455
- * @example
3456
- * ```typescript
3457
- * const session = await h2aClient.createSession({
3458
- * agentAddress: 'Agent123...',
3459
- * sessionType: 'content_writing',
3460
- * metadata: 'Blog post about AI agents',
3461
- * expiresIn: 7200 // 2 hours
3462
- * })
3463
- * ```
3464
- */
3465
- async createSession(config) {
3466
- const expiresAt = BigInt(Math.floor(Date.now() / 1e3) + (config.expiresIn ?? 3600));
3467
- const sessionId = BigInt(Date.now());
3468
- const initiator = this.wallet.address;
3469
- const [sessionAddress] = await getProgramDerivedAddress({
3470
- programAddress: this.programId,
3471
- seeds: [
3472
- getBytesEncoder().encode(new Uint8Array([99, 111, 109, 109, 95, 115, 101, 115, 115, 105, 111, 110])),
3473
- // 'comm_session'
3474
- getAddressEncoder().encode(initiator)
3475
- ]
3476
- });
3477
- const instruction = await getCreateCommunicationSessionInstructionAsync({
3478
- session: sessionAddress,
3479
- creator: this.wallet,
3480
- sessionId,
3481
- initiator,
3482
- initiatorType: 0 /* Human */,
3483
- responder: config.agentAddress,
3484
- responderType: 1 /* Agent */,
3485
- sessionType: config.sessionType,
3486
- metadata: config.metadata ?? "",
3487
- expiresAt
3488
- }, { programAddress: this.programId });
3489
- const signature = await this.sendTransaction([instruction]);
3490
- this.emit("session_created", {
3491
- type: "session_created",
3492
- timestamp: Date.now(),
3493
- data: {
3494
- address: sessionAddress,
3495
- signature,
3496
- agent: config.agentAddress
3497
- }
3498
- });
3499
- return { address: sessionAddress, signature };
3500
- }
3501
- /**
3502
- * Send a service request to an agent
3503
- *
3504
- * Sends a work request to an agent with optional payment commitment.
3505
- *
3506
- * @param request - Service request parameters
3507
- * @returns Transaction signature
3508
- *
3509
- * @example
3510
- * ```typescript
3511
- * await h2aClient.sendServiceRequest({
3512
- * sessionAddress: session.address,
3513
- * content: 'Generate 10 social media posts about web3',
3514
- * messageType: 'service_request',
3515
- * attachments: ['ipfs://QmBrandGuidelines'],
3516
- * paymentAmount: 10_000_000n, // 10 USDC
3517
- * deadline: Date.now() / 1000 + 172800 // 48 hours
3518
- * })
3519
- * ```
3520
- */
3521
- async sendServiceRequest(request) {
3522
- const messageId = BigInt(Date.now());
3523
- const messageIdBytes = new Uint8Array(8);
3524
- const view = new DataView(messageIdBytes.buffer);
3525
- view.setBigUint64(0, messageId, true);
3526
- const [messageAddress] = await getProgramDerivedAddress({
3527
- programAddress: this.programId,
3528
- seeds: [
3529
- getBytesEncoder().encode(new Uint8Array([99, 111, 109, 109, 95, 109, 101, 115, 115, 97, 103, 101])),
3530
- // 'comm_message'
3531
- getAddressEncoder().encode(request.sessionAddress),
3532
- getBytesEncoder().encode(messageIdBytes)
3533
- ]
3534
- });
3535
- const instruction = getSendCommunicationMessageInstruction({
3536
- message: messageAddress,
3537
- session: request.sessionAddress,
3538
- sender: this.wallet,
3539
- messageId,
3540
- senderType: 0 /* Human */,
3541
- content: request.content,
3542
- messageType: request.messageType ?? "service_request",
3543
- attachments: request.attachments ?? []
3544
- }, { programAddress: this.programId });
3545
- const signature = await this.sendTransaction([instruction]);
3546
- this.emit("service_requested", {
3547
- type: "service_requested",
3548
- timestamp: Date.now(),
3549
- data: {
3550
- messageAddress,
3551
- sessionAddress: request.sessionAddress,
3552
- signature
3553
- }
3554
- });
3555
- return signature;
3556
- }
3557
- /**
3558
- * Send a message in an existing session
3559
- *
3560
- * Sends a message to an agent with support for file attachments.
3561
- *
3562
- * @param params - Message parameters
3563
- * @returns Transaction signature
3564
- */
3565
- async sendMessage(params) {
3566
- const messageId = BigInt(Date.now());
3567
- const messageIdBytes = new Uint8Array(8);
3568
- const view = new DataView(messageIdBytes.buffer);
3569
- view.setBigUint64(0, messageId, true);
3570
- const [messageAddress] = await getProgramDerivedAddress({
3571
- programAddress: this.programId,
3572
- seeds: [
3573
- getBytesEncoder().encode(new Uint8Array([99, 111, 109, 109, 95, 109, 101, 115, 115, 97, 103, 101])),
3574
- // 'comm_message'
3575
- getAddressEncoder().encode(params.sessionAddress),
3576
- getBytesEncoder().encode(messageIdBytes)
3577
- ]
3578
- });
3579
- const instruction = getSendCommunicationMessageInstruction({
3580
- message: messageAddress,
3581
- session: params.sessionAddress,
3582
- sender: this.wallet,
3583
- messageId,
3584
- senderType: 0 /* Human */,
3585
- content: params.content,
3586
- messageType: params.messageType ?? "text",
3587
- attachments: params.attachments ?? []
3588
- }, { programAddress: this.programId });
3589
- const signature = await this.sendTransaction([instruction]);
3590
- this.emit("message_sent", {
3591
- type: "message_sent",
3592
- timestamp: Date.now(),
3593
- data: {
3594
- messageAddress,
3595
- sessionAddress: params.sessionAddress,
3596
- signature
3597
- }
3598
- });
3599
- return signature;
3600
380
  }
3601
381
  /**
3602
- * Get session details
3603
- *
3604
- * @param sessionAddress - Session PDA address
382
+ * Extract payment data from transaction
3605
383
  */
3606
- async getSession(sessionAddress) {
3607
- const accountInfo = await this.rpc.getAccountInfo(sessionAddress, { encoding: "base64" }).send();
3608
- if (!accountInfo.value) {
3609
- throw new Error(`Session account not found: ${sessionAddress}`);
3610
- }
3611
- const data = accountInfo.value.data;
3612
- return getCommunicationSessionDataDecoder().decode(
3613
- typeof data === "string" ? Uint8Array.from(Buffer.from(data, "base64")) : new Uint8Array(data)
3614
- );
3615
- }
3616
- // =====================================================
3617
- // PRIVATE HELPER METHODS
3618
- // =====================================================
3619
- async sendTransaction(instructions) {
384
+ extractPaymentData(transaction, signature) {
3620
385
  try {
3621
- const { value: latestBlockhash } = await this.rpc.getLatestBlockhash().send();
3622
- let message = createTransactionMessage({ version: 0 });
3623
- message = setTransactionMessageFeePayer(this.wallet.address, message);
3624
- message = setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, message);
3625
- for (const ix of instructions) {
3626
- message = appendTransactionMessageInstruction(ix, message);
3627
- }
3628
- const signedTransaction = await signTransactionMessageWithSigners(message);
3629
- const signatures = Object.values(signedTransaction.signatures);
3630
- if (signatures.length === 0) {
3631
- throw new Error("Transaction has no signatures");
386
+ const instructions = transaction.transaction?.message?.instructions || [];
387
+ const transferIx = instructions.find((ix) => {
388
+ const parsed = ix.parsed;
389
+ return parsed?.type === "transfer" || parsed?.type === "transferChecked";
390
+ });
391
+ if (!transferIx) {
392
+ return null;
3632
393
  }
3633
- const signature = signatures[0];
3634
- const wireTransaction = getBase64EncodedWireTransaction(signedTransaction);
3635
- await this.rpc.sendTransaction(wireTransaction).send();
3636
- await this.confirmTransaction(signature);
3637
- return signature;
3638
- } catch (error) {
3639
- throw new Error(
3640
- `Transaction failed: ${error instanceof Error ? error.message : String(error)}`
394
+ const transferInfo = transferIx.parsed.info;
395
+ const merchant = transferInfo.destination;
396
+ const payer = transferInfo.source;
397
+ const amount = transferInfo.amount || transferInfo.tokenAmount?.amount || "0";
398
+ const success = transaction.meta?.err === null;
399
+ const blockTime = transaction.blockTime;
400
+ const timestamp = blockTime ? new Date(blockTime * 1e3) : /* @__PURE__ */ new Date();
401
+ const memoIx = instructions.find(
402
+ (ix) => ix.programId?.toString()?.includes("Memo")
3641
403
  );
3642
- }
3643
- }
3644
- async confirmTransaction(signature) {
3645
- for (let i = 0; i < 30; i++) {
3646
- const status = await this.rpc.getSignatureStatuses([signature]).send();
3647
- if (status.value[0]?.confirmationStatus === "confirmed" || status.value[0]?.confirmationStatus === "finalized") {
3648
- return;
404
+ let responseTimeMs;
405
+ let metadata;
406
+ if (memoIx && memoIx.data) {
407
+ try {
408
+ const memoText = Buffer.from(memoIx.data, "base64").toString("utf-8");
409
+ const memoData = JSON.parse(memoText);
410
+ responseTimeMs = memoData.responseTimeMs;
411
+ metadata = memoData;
412
+ } catch {
413
+ }
3649
414
  }
3650
- await new Promise((resolve) => setTimeout(resolve, 1e3));
415
+ return {
416
+ signature,
417
+ merchant,
418
+ payer,
419
+ amount,
420
+ success,
421
+ timestamp,
422
+ network: this.network,
423
+ responseTimeMs,
424
+ metadata
425
+ };
426
+ } catch (error) {
427
+ console.error("[X402 Indexer] Failed to extract payment data:", error);
428
+ return null;
3651
429
  }
3652
- throw new Error("Transaction confirmation timeout");
3653
430
  }
3654
431
  };
3655
- function createH2AClient(options, wallet) {
3656
- return new H2AClient(options, wallet);
3657
- }
432
+
433
+ // src/index.ts
434
+ init_reputation_tags();
435
+ init_MultiSourceAggregator();
3658
436
 
3659
437
  // src/utils/test-ipfs-config.ts
3660
438
  var TEST_IPFS_CONFIG = {
@@ -3698,7 +476,7 @@ var IPFSOperationError = class extends Error {
3698
476
  this.name = "IPFSOperationError";
3699
477
  }
3700
478
  };
3701
- var DEFAULT_RETRY_CONFIG2 = {
479
+ var DEFAULT_RETRY_CONFIG = {
3702
480
  maxRetries: 3,
3703
481
  baseDelay: 1e3,
3704
482
  maxDelay: 3e4,
@@ -3759,7 +537,7 @@ var CircuitBreaker = class {
3759
537
  }
3760
538
  };
3761
539
  var RetryHandler = class {
3762
- constructor(config = DEFAULT_RETRY_CONFIG2) {
540
+ constructor(config = DEFAULT_RETRY_CONFIG) {
3763
541
  this.config = config;
3764
542
  this.circuitBreaker = new CircuitBreaker();
3765
543
  }
@@ -3884,7 +662,7 @@ var IPFSErrorHandler = class {
3884
662
  retryHandler;
3885
663
  fallbackHandler;
3886
664
  constructor(retryConfig) {
3887
- this.retryHandler = new RetryHandler({ ...DEFAULT_RETRY_CONFIG2, ...retryConfig });
665
+ this.retryHandler = new RetryHandler({ ...DEFAULT_RETRY_CONFIG, ...retryConfig });
3888
666
  this.fallbackHandler = new FallbackHandler();
3889
667
  }
3890
668
  async executeWithErrorHandling(operation, context, fallbackValue) {
@@ -4096,12 +874,12 @@ function assembleStyles() {
4096
874
  if (colorString.length === 3) {
4097
875
  colorString = [...colorString].map((character) => character + character).join("");
4098
876
  }
4099
- const integer7 = Number.parseInt(colorString, 16);
877
+ const integer = Number.parseInt(colorString, 16);
4100
878
  return [
4101
879
  /* eslint-disable no-bitwise */
4102
- integer7 >> 16 & 255,
4103
- integer7 >> 8 & 255,
4104
- integer7 & 255
880
+ integer >> 16 & 255,
881
+ integer >> 8 & 255,
882
+ integer & 255
4105
883
  /* eslint-enable no-bitwise */
4106
884
  ];
4107
885
  },
@@ -4288,30 +1066,30 @@ var supports_color_default = supportsColor;
4288
1066
 
4289
1067
  // ../../node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/utilities.js
4290
1068
  function stringReplaceAll(string, substring, replacer) {
4291
- let index7 = string.indexOf(substring);
4292
- if (index7 === -1) {
1069
+ let index = string.indexOf(substring);
1070
+ if (index === -1) {
4293
1071
  return string;
4294
1072
  }
4295
1073
  const substringLength = substring.length;
4296
1074
  let endIndex = 0;
4297
1075
  let returnValue = "";
4298
1076
  do {
4299
- returnValue += string.slice(endIndex, index7) + substring + replacer;
4300
- endIndex = index7 + substringLength;
4301
- index7 = string.indexOf(substring, endIndex);
4302
- } while (index7 !== -1);
1077
+ returnValue += string.slice(endIndex, index) + substring + replacer;
1078
+ endIndex = index + substringLength;
1079
+ index = string.indexOf(substring, endIndex);
1080
+ } while (index !== -1);
4303
1081
  returnValue += string.slice(endIndex);
4304
1082
  return returnValue;
4305
1083
  }
4306
- function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index7) {
1084
+ function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
4307
1085
  let endIndex = 0;
4308
1086
  let returnValue = "";
4309
1087
  do {
4310
- const gotCR = string[index7 - 1] === "\r";
4311
- returnValue += string.slice(endIndex, gotCR ? index7 - 1 : index7) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
4312
- endIndex = index7 + 1;
4313
- index7 = string.indexOf("\n", endIndex);
4314
- } while (index7 !== -1);
1088
+ const gotCR = string[index - 1] === "\r";
1089
+ returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
1090
+ endIndex = index + 1;
1091
+ index = string.indexOf("\n", endIndex);
1092
+ } while (index !== -1);
4315
1093
  returnValue += string.slice(endIndex);
4316
1094
  return returnValue;
4317
1095
  }
@@ -4876,7 +1654,7 @@ var IPFSProvider = class {
4876
1654
  client;
4877
1655
  isPrivateNetwork;
4878
1656
  constructor(options) {
4879
- const createClient2 = __require("kubo-rpc-client").create;
1657
+ const createClient = __require("kubo-rpc-client").create;
4880
1658
  const ipfsNodeUrl = options?.ipfsNodeUrl || "http://localhost:5001";
4881
1659
  const headers = options?.headers || {};
4882
1660
  this.isPrivateNetwork = options?.usePrivateNetwork || false;
@@ -4891,7 +1669,7 @@ var IPFSProvider = class {
4891
1669
  if (typeof headers !== "object" || headers === null) {
4892
1670
  throw new Error("Headers must be a valid object");
4893
1671
  }
4894
- this.client = createClient2({
1672
+ this.client = createClient({
4895
1673
  url: ipfsNodeUrl,
4896
1674
  headers
4897
1675
  });
@@ -4923,9 +1701,9 @@ var IPFSProvider = class {
4923
1701
  * This is not foolproof but can catch obvious cases
4924
1702
  */
4925
1703
  isDataUnencrypted(data) {
4926
- const text7 = new TextDecoder("utf-8", { fatal: false }).decode(data.slice(0, 100));
1704
+ const text = new TextDecoder("utf-8", { fatal: false }).decode(data.slice(0, 100));
4927
1705
  const commonPatterns = ["{", "<", "BEGIN", "name", "address", "email", "password"];
4928
- return commonPatterns.some((pattern) => text7.toLowerCase().includes(pattern.toLowerCase()));
1706
+ return commonPatterns.some((pattern) => text.toLowerCase().includes(pattern.toLowerCase()));
4929
1707
  }
4930
1708
  async retrieve(hash) {
4931
1709
  try {
@@ -5278,6 +2056,6 @@ function clearFeatureGateCache() {
5278
2056
  featureCache.clear();
5279
2057
  }
5280
2058
 
5281
- export { A2AClient, AgentDiscoveryClient, CircuitBreaker, DEFAULT_RETRY_CONFIG2 as DEFAULT_RETRY_CONFIG, FEATURE_GATES, FallbackHandler, FetchWithPaymentClient, H2AClient, IPFSErrorHandler, IPFSOperationError, IPFSProvider, LocalStorageProvider, PaymentStreamingManager, PrivateDataQuery, PrivateMetadataStorage, RetryHandler, TEST_IPFS_CONFIG, WalletFundingService, X402AnalyticsTracker, X402Client, checkFeatureGate, clearFeatureGateCache, createA2AClient, createAgentDiscoveryClient, createH2AClient, createIPFSErrorHandler, createPrivacyManifest, createTestIPFSConfig, createX402AnalyticsTracker, createX402Client, createX402Middleware, defaultFundingService, ensureMinimumBalance, estimateStorageCost, fetchWithX402Payment, fundWallet, isIPFSError, withIPFSErrorHandling, withX402RateLimit, wrapFetchWithPayment, x402FastifyPlugin };
2059
+ export { CircuitBreaker, DEFAULT_RETRY_CONFIG, ExternalIdResolver, FEATURE_GATES, FallbackHandler, IPFSErrorHandler, IPFSOperationError, IPFSProvider, LocalStorageProvider, PrivateDataQuery, PrivateMetadataStorage, RetryHandler, TEST_IPFS_CONFIG, WalletFundingService, X402TransactionIndexer, checkFeatureGate, clearFeatureGateCache, createIPFSErrorHandler, createPrivacyManifest, createTestIPFSConfig, defaultFundingService, ensureMinimumBalance, estimateStorageCost, fundWallet, isIPFSError, withIPFSErrorHandling };
5282
2060
  //# sourceMappingURL=index.js.map
5283
2061
  //# sourceMappingURL=index.js.map