@agirails/sdk 2.0.1-beta → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +190 -0
- package/README.md +116 -108
- package/bin/actp +10 -0
- package/dist/ACTPClient.d.ts +456 -33
- package/dist/ACTPClient.d.ts.map +1 -1
- package/dist/ACTPClient.js +477 -93
- package/dist/ACTPClient.js.map +1 -1
- package/dist/abi/AgentRegistry.json +782 -0
- package/dist/abi/EscrowVault.json +106 -38
- package/dist/abi/IdentityRegistry.json +316 -0
- package/dist/adapters/BaseAdapter.d.ts +231 -0
- package/dist/adapters/BaseAdapter.d.ts.map +1 -0
- package/dist/adapters/BaseAdapter.js +393 -0
- package/dist/adapters/BaseAdapter.js.map +1 -0
- package/dist/adapters/BeginnerAdapter.d.ts +152 -0
- package/dist/adapters/BeginnerAdapter.d.ts.map +1 -0
- package/dist/adapters/BeginnerAdapter.js +168 -0
- package/dist/adapters/BeginnerAdapter.js.map +1 -0
- package/dist/adapters/IntermediateAdapter.d.ts +211 -0
- package/dist/adapters/IntermediateAdapter.d.ts.map +1 -0
- package/dist/adapters/IntermediateAdapter.js +260 -0
- package/dist/adapters/IntermediateAdapter.js.map +1 -0
- package/dist/adapters/index.d.ts +15 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +26 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/builders/DeliveryProofBuilder.d.ts +60 -1
- package/dist/builders/DeliveryProofBuilder.d.ts.map +1 -1
- package/dist/builders/DeliveryProofBuilder.js +81 -5
- package/dist/builders/DeliveryProofBuilder.js.map +1 -1
- package/dist/builders/QuoteBuilder.d.ts +101 -0
- package/dist/builders/QuoteBuilder.d.ts.map +1 -1
- package/dist/builders/QuoteBuilder.js +120 -3
- package/dist/builders/QuoteBuilder.js.map +1 -1
- package/dist/builders/index.d.ts +4 -0
- package/dist/builders/index.d.ts.map +1 -1
- package/dist/builders/index.js +4 -0
- package/dist/builders/index.js.map +1 -1
- package/dist/cli/commands/balance.d.ts +13 -0
- package/dist/cli/commands/balance.d.ts.map +1 -0
- package/dist/cli/commands/balance.js +89 -0
- package/dist/cli/commands/balance.js.map +1 -0
- package/dist/cli/commands/batch.d.ts +24 -0
- package/dist/cli/commands/batch.d.ts.map +1 -0
- package/dist/cli/commands/batch.js +424 -0
- package/dist/cli/commands/batch.js.map +1 -0
- package/dist/cli/commands/config.d.ts +13 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +192 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/init.d.ts +19 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +143 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/mint.d.ts +13 -0
- package/dist/cli/commands/mint.d.ts.map +1 -0
- package/dist/cli/commands/mint.js +91 -0
- package/dist/cli/commands/mint.js.map +1 -0
- package/dist/cli/commands/pay.d.ts +18 -0
- package/dist/cli/commands/pay.d.ts.map +1 -0
- package/dist/cli/commands/pay.js +87 -0
- package/dist/cli/commands/pay.js.map +1 -0
- package/dist/cli/commands/simulate.d.ts +32 -0
- package/dist/cli/commands/simulate.d.ts.map +1 -0
- package/dist/cli/commands/simulate.js +290 -0
- package/dist/cli/commands/simulate.js.map +1 -0
- package/dist/cli/commands/time.d.ts +29 -0
- package/dist/cli/commands/time.d.ts.map +1 -0
- package/dist/cli/commands/time.js +252 -0
- package/dist/cli/commands/time.js.map +1 -0
- package/dist/cli/commands/tx.d.ts +16 -0
- package/dist/cli/commands/tx.d.ts.map +1 -0
- package/dist/cli/commands/tx.js +379 -0
- package/dist/cli/commands/tx.js.map +1 -0
- package/dist/cli/commands/watch.d.ts +20 -0
- package/dist/cli/commands/watch.d.ts.map +1 -0
- package/dist/cli/commands/watch.js +160 -0
- package/dist/cli/commands/watch.js.map +1 -0
- package/dist/cli/index.d.ts +17 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +104 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/utils/client.d.ts +70 -0
- package/dist/cli/utils/client.d.ts.map +1 -0
- package/dist/cli/utils/client.js +240 -0
- package/dist/cli/utils/client.js.map +1 -0
- package/dist/cli/utils/config.d.ts +91 -0
- package/dist/cli/utils/config.d.ts.map +1 -0
- package/dist/cli/utils/config.js +240 -0
- package/dist/cli/utils/config.js.map +1 -0
- package/dist/cli/utils/output.d.ts +174 -0
- package/dist/cli/utils/output.d.ts.map +1 -0
- package/dist/cli/utils/output.js +380 -0
- package/dist/cli/utils/output.js.map +1 -0
- package/dist/config/networks.d.ts +28 -0
- package/dist/config/networks.d.ts.map +1 -1
- package/dist/config/networks.js +60 -12
- package/dist/config/networks.js.map +1 -1
- package/dist/errors/index.d.ts +165 -2
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +260 -2
- package/dist/errors/index.js.map +1 -1
- package/dist/index.d.ts +61 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +141 -36
- package/dist/index.js.map +1 -1
- package/dist/level0/Provider.d.ts +106 -0
- package/dist/level0/Provider.d.ts.map +1 -0
- package/dist/level0/Provider.js +10 -0
- package/dist/level0/Provider.js.map +1 -0
- package/dist/level0/ServiceDirectory.d.ts +74 -0
- package/dist/level0/ServiceDirectory.d.ts.map +1 -0
- package/dist/level0/ServiceDirectory.js +122 -0
- package/dist/level0/ServiceDirectory.js.map +1 -0
- package/dist/level0/index.d.ts +10 -0
- package/dist/level0/index.d.ts.map +1 -0
- package/dist/level0/index.js +15 -0
- package/dist/level0/index.js.map +1 -0
- package/dist/level0/provide.d.ts +51 -0
- package/dist/level0/provide.d.ts.map +1 -0
- package/dist/level0/provide.js +113 -0
- package/dist/level0/provide.js.map +1 -0
- package/dist/level0/request.d.ts +53 -0
- package/dist/level0/request.d.ts.map +1 -0
- package/dist/level0/request.js +462 -0
- package/dist/level0/request.js.map +1 -0
- package/dist/level1/Agent.d.ts +472 -0
- package/dist/level1/Agent.d.ts.map +1 -0
- package/dist/level1/Agent.js +1091 -0
- package/dist/level1/Agent.js.map +1 -0
- package/dist/level1/index.d.ts +10 -0
- package/dist/level1/index.d.ts.map +1 -0
- package/dist/level1/index.js +30 -0
- package/dist/level1/index.js.map +1 -0
- package/dist/level1/pricing/PriceCalculator.d.ts +62 -0
- package/dist/level1/pricing/PriceCalculator.d.ts.map +1 -0
- package/dist/level1/pricing/PriceCalculator.js +237 -0
- package/dist/level1/pricing/PriceCalculator.js.map +1 -0
- package/dist/level1/pricing/PricingStrategy.d.ts +179 -0
- package/dist/level1/pricing/PricingStrategy.d.ts.map +1 -0
- package/dist/level1/pricing/PricingStrategy.js +11 -0
- package/dist/level1/pricing/PricingStrategy.js.map +1 -0
- package/dist/level1/types/Job.d.ts +166 -0
- package/dist/level1/types/Job.d.ts.map +1 -0
- package/dist/level1/types/Job.js +11 -0
- package/dist/level1/types/Job.js.map +1 -0
- package/dist/level1/types/Options.d.ts +258 -0
- package/dist/level1/types/Options.d.ts.map +1 -0
- package/dist/level1/types/Options.js +8 -0
- package/dist/level1/types/Options.js.map +1 -0
- package/dist/level1/types/index.d.ts +8 -0
- package/dist/level1/types/index.d.ts.map +1 -0
- package/dist/level1/types/index.js +8 -0
- package/dist/level1/types/index.js.map +1 -0
- package/dist/protocol/ACTPKernel.d.ts +229 -2
- package/dist/protocol/ACTPKernel.d.ts.map +1 -1
- package/dist/protocol/ACTPKernel.js +367 -33
- package/dist/protocol/ACTPKernel.js.map +1 -1
- package/dist/protocol/AgentRegistry.d.ts +177 -0
- package/dist/protocol/AgentRegistry.d.ts.map +1 -0
- package/dist/protocol/AgentRegistry.js +449 -0
- package/dist/protocol/AgentRegistry.js.map +1 -0
- package/dist/protocol/DIDManager.d.ts +289 -0
- package/dist/protocol/DIDManager.d.ts.map +1 -0
- package/dist/protocol/DIDManager.js +481 -0
- package/dist/protocol/DIDManager.js.map +1 -0
- package/dist/protocol/DIDResolver.d.ts +236 -0
- package/dist/protocol/DIDResolver.d.ts.map +1 -0
- package/dist/protocol/DIDResolver.js +495 -0
- package/dist/protocol/DIDResolver.js.map +1 -0
- package/dist/protocol/EASHelper.d.ts +57 -2
- package/dist/protocol/EASHelper.d.ts.map +1 -1
- package/dist/protocol/EASHelper.js +230 -37
- package/dist/protocol/EASHelper.js.map +1 -1
- package/dist/protocol/EscrowVault.d.ts +93 -2
- package/dist/protocol/EscrowVault.d.ts.map +1 -1
- package/dist/protocol/EscrowVault.js +122 -33
- package/dist/protocol/EscrowVault.js.map +1 -1
- package/dist/protocol/EventMonitor.d.ts +45 -1
- package/dist/protocol/EventMonitor.d.ts.map +1 -1
- package/dist/protocol/EventMonitor.js +64 -8
- package/dist/protocol/EventMonitor.js.map +1 -1
- package/dist/protocol/MessageSigner.d.ts +116 -2
- package/dist/protocol/MessageSigner.d.ts.map +1 -1
- package/dist/protocol/MessageSigner.js +215 -9
- package/dist/protocol/MessageSigner.js.map +1 -1
- package/dist/protocol/ProofGenerator.d.ts +93 -0
- package/dist/protocol/ProofGenerator.d.ts.map +1 -1
- package/dist/protocol/ProofGenerator.js +194 -9
- package/dist/protocol/ProofGenerator.js.map +1 -1
- package/dist/protocol/QuoteBuilder.d.ts +8 -0
- package/dist/protocol/QuoteBuilder.d.ts.map +1 -1
- package/dist/protocol/QuoteBuilder.js +8 -0
- package/dist/protocol/QuoteBuilder.js.map +1 -1
- package/dist/runtime/BlockchainRuntime.d.ts +360 -0
- package/dist/runtime/BlockchainRuntime.d.ts.map +1 -0
- package/dist/runtime/BlockchainRuntime.js +767 -0
- package/dist/runtime/BlockchainRuntime.js.map +1 -0
- package/dist/runtime/IACTPRuntime.d.ts +271 -0
- package/dist/runtime/IACTPRuntime.d.ts.map +1 -0
- package/dist/runtime/IACTPRuntime.js +15 -0
- package/dist/runtime/IACTPRuntime.js.map +1 -0
- package/dist/runtime/MockRuntime.d.ts +445 -0
- package/dist/runtime/MockRuntime.d.ts.map +1 -0
- package/dist/runtime/MockRuntime.js +1065 -0
- package/dist/runtime/MockRuntime.js.map +1 -0
- package/dist/runtime/MockStateManager.d.ts +233 -0
- package/dist/runtime/MockStateManager.d.ts.map +1 -0
- package/dist/runtime/MockStateManager.js +533 -0
- package/dist/runtime/MockStateManager.js.map +1 -0
- package/dist/runtime/index.d.ts +14 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +42 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/types/MockState.d.ts +167 -0
- package/dist/runtime/types/MockState.d.ts.map +1 -0
- package/dist/runtime/types/MockState.js +43 -0
- package/dist/runtime/types/MockState.js.map +1 -0
- package/dist/types/agent.d.ts +76 -0
- package/dist/types/agent.d.ts.map +1 -0
- package/dist/types/agent.js +8 -0
- package/dist/types/agent.js.map +1 -0
- package/dist/types/did.d.ts +192 -0
- package/dist/types/did.d.ts.map +1 -0
- package/dist/types/did.js +38 -0
- package/dist/types/did.js.map +1 -0
- package/dist/types/eip712.d.ts +34 -0
- package/dist/types/eip712.d.ts.map +1 -1
- package/dist/types/eip712.js +31 -5
- package/dist/types/eip712.js.map +1 -1
- package/dist/types/escrow.d.ts +17 -10
- package/dist/types/escrow.d.ts.map +1 -1
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +8 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/message.d.ts +32 -0
- package/dist/types/message.d.ts.map +1 -1
- package/dist/types/message.js +4 -0
- package/dist/types/message.js.map +1 -1
- package/dist/types/state.d.ts +28 -0
- package/dist/types/state.d.ts.map +1 -1
- package/dist/types/state.js +37 -6
- package/dist/types/state.js.map +1 -1
- package/dist/types/transaction.d.ts +17 -0
- package/dist/types/transaction.d.ts.map +1 -1
- package/dist/utils/ErrorRecoveryGuide.d.ts +125 -0
- package/dist/utils/ErrorRecoveryGuide.d.ts.map +1 -0
- package/dist/utils/ErrorRecoveryGuide.js +579 -0
- package/dist/utils/ErrorRecoveryGuide.js.map +1 -0
- package/dist/utils/Helpers.d.ts +453 -0
- package/dist/utils/Helpers.d.ts.map +1 -0
- package/dist/utils/Helpers.js +623 -0
- package/dist/utils/Helpers.js.map +1 -0
- package/dist/utils/IPFSClient.d.ts +113 -0
- package/dist/utils/IPFSClient.d.ts.map +1 -1
- package/dist/utils/IPFSClient.js +128 -7
- package/dist/utils/IPFSClient.js.map +1 -1
- package/dist/utils/Logger.d.ts +195 -0
- package/dist/utils/Logger.d.ts.map +1 -0
- package/dist/utils/Logger.js +382 -0
- package/dist/utils/Logger.js.map +1 -0
- package/dist/utils/NonceManager.d.ts +234 -1
- package/dist/utils/NonceManager.d.ts.map +1 -1
- package/dist/utils/NonceManager.js +372 -7
- package/dist/utils/NonceManager.js.map +1 -1
- package/dist/utils/RateLimiter.d.ts +253 -0
- package/dist/utils/RateLimiter.d.ts.map +1 -0
- package/dist/utils/RateLimiter.js +424 -0
- package/dist/utils/RateLimiter.js.map +1 -0
- package/dist/utils/ReceivedNonceTracker.d.ts +175 -0
- package/dist/utils/ReceivedNonceTracker.d.ts.map +1 -1
- package/dist/utils/ReceivedNonceTracker.js +261 -5
- package/dist/utils/ReceivedNonceTracker.js.map +1 -1
- package/dist/utils/SDKLifecycle.d.ts +156 -0
- package/dist/utils/SDKLifecycle.d.ts.map +1 -0
- package/dist/utils/SDKLifecycle.js +347 -0
- package/dist/utils/SDKLifecycle.js.map +1 -0
- package/dist/utils/SecureNonce.d.ts +57 -0
- package/dist/utils/SecureNonce.d.ts.map +1 -0
- package/dist/utils/SecureNonce.js +80 -0
- package/dist/utils/SecureNonce.js.map +1 -0
- package/dist/utils/Semaphore.d.ts +123 -0
- package/dist/utils/Semaphore.d.ts.map +1 -0
- package/dist/utils/Semaphore.js +247 -0
- package/dist/utils/Semaphore.js.map +1 -0
- package/dist/utils/UsedAttestationTracker.d.ts +167 -0
- package/dist/utils/UsedAttestationTracker.d.ts.map +1 -0
- package/dist/utils/UsedAttestationTracker.js +309 -0
- package/dist/utils/UsedAttestationTracker.js.map +1 -0
- package/dist/utils/canonicalJson.d.ts +22 -0
- package/dist/utils/canonicalJson.d.ts.map +1 -1
- package/dist/utils/canonicalJson.js +26 -3
- package/dist/utils/canonicalJson.js.map +1 -1
- package/dist/utils/computeTypeHash.d.ts +14 -0
- package/dist/utils/computeTypeHash.d.ts.map +1 -1
- package/dist/utils/computeTypeHash.js +19 -2
- package/dist/utils/computeTypeHash.js.map +1 -1
- package/dist/utils/fsSafe.d.ts +14 -0
- package/dist/utils/fsSafe.d.ts.map +1 -0
- package/dist/utils/fsSafe.js +89 -0
- package/dist/utils/fsSafe.js.map +1 -0
- package/dist/utils/index.d.ts +15 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +51 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/security.d.ts +147 -0
- package/dist/utils/security.d.ts.map +1 -0
- package/dist/utils/security.js +391 -0
- package/dist/utils/security.js.map +1 -0
- package/dist/utils/validation.d.ts +40 -0
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +184 -7
- package/dist/utils/validation.js.map +1 -1
- package/package.json +54 -37
- package/src/ACTPClient.ts +692 -178
- package/src/abi/AgentRegistry.json +782 -0
- package/src/abi/EscrowVault.json +106 -38
- package/src/abi/IdentityRegistry.json +316 -0
- package/src/adapters/BaseAdapter.ts +473 -0
- package/src/adapters/BeginnerAdapter.ts +232 -0
- package/src/adapters/IntermediateAdapter.ts +316 -0
- package/src/adapters/index.ts +25 -0
- package/src/builders/DeliveryProofBuilder.ts +3 -2
- package/src/cli/commands/balance.ts +110 -0
- package/src/cli/commands/batch.ts +487 -0
- package/src/cli/commands/config.ts +231 -0
- package/src/cli/commands/init.ts +161 -0
- package/src/cli/commands/mint.ts +116 -0
- package/src/cli/commands/pay.ts +113 -0
- package/src/cli/commands/simulate.ts +345 -0
- package/src/cli/commands/time.ts +303 -0
- package/src/cli/commands/tx.ts +448 -0
- package/src/cli/commands/watch.ts +211 -0
- package/src/cli/index.ts +116 -0
- package/src/cli/utils/client.ts +249 -0
- package/src/cli/utils/config.ts +282 -0
- package/src/cli/utils/output.ts +465 -0
- package/src/config/networks.ts +32 -9
- package/src/errors/index.ts +298 -1
- package/src/index.ts +207 -71
- package/src/level0/Provider.ts +117 -0
- package/src/level0/ServiceDirectory.ts +131 -0
- package/src/level0/index.ts +10 -0
- package/src/level0/provide.ts +131 -0
- package/src/level0/request.ts +494 -0
- package/src/level1/Agent.ts +1432 -0
- package/src/level1/index.ts +10 -0
- package/src/level1/pricing/PriceCalculator.ts +255 -0
- package/src/level1/pricing/PricingStrategy.ts +198 -0
- package/src/level1/types/Job.ts +179 -0
- package/src/level1/types/Options.ts +291 -0
- package/src/level1/types/index.ts +8 -0
- package/src/protocol/ACTPKernel.ts +175 -23
- package/src/protocol/AgentRegistry.ts +559 -0
- package/src/protocol/DIDManager.ts +629 -0
- package/src/protocol/DIDResolver.ts +554 -0
- package/src/protocol/EASHelper.ts +230 -46
- package/src/protocol/EscrowVault.ts +68 -50
- package/src/protocol/EventMonitor.ts +44 -15
- package/src/protocol/MessageSigner.ts +193 -13
- package/src/protocol/ProofGenerator.ts +223 -4
- package/src/runtime/BlockchainRuntime.ts +993 -0
- package/src/runtime/IACTPRuntime.ts +284 -0
- package/src/runtime/MockRuntime.ts +1244 -0
- package/src/runtime/MockStateManager.ts +576 -0
- package/src/runtime/index.ts +25 -0
- package/src/runtime/types/MockState.ts +227 -0
- package/src/types/agent.ts +79 -0
- package/src/types/did.ts +223 -0
- package/src/types/escrow.ts +12 -11
- package/src/types/index.ts +5 -1
- package/src/types/state.ts +12 -3
- package/src/types/transaction.ts +4 -1
- package/src/utils/ErrorRecoveryGuide.ts +675 -0
- package/src/utils/Helpers.ts +688 -0
- package/src/utils/IPFSClient.ts +122 -5
- package/src/utils/Logger.ts +484 -0
- package/src/utils/NonceManager.ts +305 -8
- package/src/utils/RateLimiter.ts +534 -0
- package/src/utils/ReceivedNonceTracker.ts +170 -0
- package/src/utils/SDKLifecycle.ts +416 -0
- package/src/utils/SecureNonce.ts +78 -0
- package/src/utils/Semaphore.ts +276 -0
- package/src/utils/UsedAttestationTracker.ts +387 -0
- package/src/utils/fsSafe.ts +75 -0
- package/src/utils/index.ts +80 -0
- package/src/utils/security.ts +418 -0
- package/src/utils/validation.ts +164 -0
- package/src/__tests__/ProofGenerator.test.ts +0 -124
- package/src/__tests__/QuoteBuilder.test.ts +0 -516
- package/src/__tests__/StateMachine.test.ts +0 -82
- package/src/__tests__/builders/DeliveryProofBuilder.test.ts +0 -581
- package/src/__tests__/integration/ACTPClient.test.ts +0 -263
- package/src/__tests__/integration.test.ts +0 -289
- package/src/__tests__/protocol/EASHelper.test.ts +0 -472
- package/src/__tests__/protocol/EventMonitor.test.ts +0 -382
- package/src/__tests__/security/ACTPKernel.security.test.ts +0 -1167
- package/src/__tests__/security/EscrowVault.security.test.ts +0 -570
- package/src/__tests__/security/MessageSigner.security.test.ts +0 -286
- package/src/__tests__/security/NonceReplay.security.test.ts +0 -501
- package/src/__tests__/security/validation.security.test.ts +0 -376
- package/src/__tests__/utils/IPFSClient.test.ts +0 -262
- package/src/__tests__/utils/NonceManager.test.ts +0 -205
- package/src/__tests__/utils/canonicalJson.test.ts +0 -153
package/src/utils/IPFSClient.ts
CHANGED
|
@@ -59,6 +59,24 @@ export interface IPFSClientConfig {
|
|
|
59
59
|
* Default: 60000 (60 seconds)
|
|
60
60
|
*/
|
|
61
61
|
timeout?: number;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* SECURITY FIX (MEDIUM-3): Maximum content size in bytes
|
|
65
|
+
* Default: 50MB (50 * 1024 * 1024)
|
|
66
|
+
*/
|
|
67
|
+
maxSize?: number;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* SECURITY FIX (MEDIUM-3): Allowed URL protocols
|
|
71
|
+
* Default: ['http:', 'https:'] (http for localhost, https for remote)
|
|
72
|
+
*/
|
|
73
|
+
allowedProtocols?: string[];
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* SECURITY FIX (MEDIUM-3): Allow localhost URLs
|
|
77
|
+
* Default: true (required for local IPFS daemon)
|
|
78
|
+
*/
|
|
79
|
+
allowLocalhost?: boolean;
|
|
62
80
|
}
|
|
63
81
|
|
|
64
82
|
/**
|
|
@@ -81,21 +99,45 @@ export const IPFS_CONFIGS = {
|
|
|
81
99
|
/**
|
|
82
100
|
* IPFS HTTP Client Implementation
|
|
83
101
|
* Uses ipfs-http-client library
|
|
102
|
+
*
|
|
103
|
+
* SECURITY FIX (MEDIUM-3): Now includes URL and size validation
|
|
84
104
|
*/
|
|
85
105
|
export class IPFSHTTPClientImpl implements IPFSClient {
|
|
86
106
|
private client: IPFSHTTPClient;
|
|
87
|
-
private config: IPFSClientConfig
|
|
107
|
+
private config: Required<IPFSClientConfig>;
|
|
108
|
+
|
|
109
|
+
// SECURITY FIX (MEDIUM-3): Default security settings
|
|
110
|
+
private static readonly DEFAULT_MAX_SIZE = 50 * 1024 * 1024; // 50MB
|
|
111
|
+
private static readonly DEFAULT_ALLOWED_PROTOCOLS = ['http:', 'https:'];
|
|
112
|
+
private static readonly BLOCKED_HOSTS = [
|
|
113
|
+
'metadata.google.internal',
|
|
114
|
+
'169.254.169.254',
|
|
115
|
+
'metadata.aws.internal',
|
|
116
|
+
];
|
|
88
117
|
|
|
89
118
|
/**
|
|
90
119
|
* Create IPFS client
|
|
120
|
+
*
|
|
121
|
+
* SECURITY FIX (MEDIUM-3): Validates URL and adds size limits
|
|
122
|
+
*
|
|
91
123
|
* @param config - IPFS client configuration
|
|
124
|
+
* @throws Error if URL is invalid or blocked
|
|
92
125
|
*/
|
|
93
126
|
constructor(config: IPFSClientConfig = {}) {
|
|
127
|
+
const url = config.url || 'http://localhost:5001';
|
|
128
|
+
|
|
129
|
+
// SECURITY FIX (MEDIUM-3): Validate URL
|
|
130
|
+
this.validateUrl(url, config.allowLocalhost ?? true, config.allowedProtocols);
|
|
131
|
+
|
|
94
132
|
this.config = {
|
|
95
|
-
url
|
|
133
|
+
url,
|
|
96
134
|
timeout: config.timeout || 60000,
|
|
97
|
-
|
|
98
|
-
|
|
135
|
+
maxSize: config.maxSize || IPFSHTTPClientImpl.DEFAULT_MAX_SIZE,
|
|
136
|
+
allowedProtocols: config.allowedProtocols || IPFSHTTPClientImpl.DEFAULT_ALLOWED_PROTOCOLS,
|
|
137
|
+
allowLocalhost: config.allowLocalhost ?? true,
|
|
138
|
+
auth: config.auth,
|
|
139
|
+
headers: config.headers,
|
|
140
|
+
} as Required<IPFSClientConfig>;
|
|
99
141
|
|
|
100
142
|
const options: Options = {
|
|
101
143
|
url: this.config.url,
|
|
@@ -117,15 +159,76 @@ export class IPFSHTTPClientImpl implements IPFSClient {
|
|
|
117
159
|
this.client = create(options);
|
|
118
160
|
}
|
|
119
161
|
|
|
162
|
+
/**
|
|
163
|
+
* SECURITY FIX (MEDIUM-3): Validate IPFS endpoint URL
|
|
164
|
+
*/
|
|
165
|
+
private validateUrl(
|
|
166
|
+
url: string,
|
|
167
|
+
allowLocalhost: boolean,
|
|
168
|
+
allowedProtocols?: string[]
|
|
169
|
+
): void {
|
|
170
|
+
let parsed: URL;
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
parsed = new URL(url);
|
|
174
|
+
} catch {
|
|
175
|
+
throw new Error(`Invalid IPFS endpoint URL: ${url}`);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const protocols = allowedProtocols || IPFSHTTPClientImpl.DEFAULT_ALLOWED_PROTOCOLS;
|
|
179
|
+
if (!protocols.includes(parsed.protocol)) {
|
|
180
|
+
throw new Error(
|
|
181
|
+
`IPFS endpoint protocol "${parsed.protocol}" not allowed. ` +
|
|
182
|
+
`Allowed protocols: ${protocols.join(', ')}`
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const hostname = parsed.hostname.toLowerCase();
|
|
187
|
+
|
|
188
|
+
// Check blocked hosts (cloud metadata endpoints)
|
|
189
|
+
if (IPFSHTTPClientImpl.BLOCKED_HOSTS.includes(hostname)) {
|
|
190
|
+
throw new Error(
|
|
191
|
+
`IPFS endpoint hostname "${hostname}" is blocked for security reasons.`
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Check localhost
|
|
196
|
+
const isLocalhost = ['localhost', '127.0.0.1', '0.0.0.0', '[::1]'].includes(hostname);
|
|
197
|
+
if (isLocalhost && !allowLocalhost) {
|
|
198
|
+
throw new Error(
|
|
199
|
+
`Localhost IPFS endpoints are disabled. Set allowLocalhost: true to enable.`
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// For remote hosts, require HTTPS
|
|
204
|
+
if (!isLocalhost && parsed.protocol !== 'https:') {
|
|
205
|
+
console.warn(
|
|
206
|
+
`[SECURITY WARNING] Using non-HTTPS protocol "${parsed.protocol}" for remote IPFS endpoint "${hostname}". ` +
|
|
207
|
+
`This may expose data in transit. Consider using HTTPS.`
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
120
212
|
/**
|
|
121
213
|
* Upload data to IPFS
|
|
214
|
+
*
|
|
215
|
+
* SECURITY FIX (MEDIUM-3): Validates size before upload
|
|
216
|
+
*
|
|
122
217
|
* @param data - JSON string or buffer
|
|
123
218
|
* @returns CIDv1 string (base32)
|
|
219
|
+
* @throws Error if data exceeds maxSize
|
|
124
220
|
*/
|
|
125
221
|
async add(data: string | Buffer): Promise<string> {
|
|
126
222
|
try {
|
|
127
223
|
const content = typeof data === 'string' ? Buffer.from(data, 'utf-8') : data;
|
|
128
224
|
|
|
225
|
+
// SECURITY FIX (MEDIUM-3): Check size before upload
|
|
226
|
+
if (content.length > this.config.maxSize) {
|
|
227
|
+
throw new Error(
|
|
228
|
+
`Content too large: ${content.length} bytes exceeds maximum of ${this.config.maxSize} bytes`
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
129
232
|
const result = await this.client.add(content, {
|
|
130
233
|
cidVersion: 1, // Use CIDv1 (base32)
|
|
131
234
|
hashAlg: 'sha2-256',
|
|
@@ -153,19 +256,33 @@ export class IPFSHTTPClientImpl implements IPFSClient {
|
|
|
153
256
|
|
|
154
257
|
/**
|
|
155
258
|
* Retrieve content from IPFS
|
|
259
|
+
*
|
|
260
|
+
* SECURITY FIX (MEDIUM-3): Validates size during retrieval
|
|
261
|
+
*
|
|
156
262
|
* @param cid - IPFS CID
|
|
157
263
|
* @returns Content as string
|
|
264
|
+
* @throws Error if content exceeds maxSize
|
|
158
265
|
*/
|
|
159
266
|
async get(cid: string): Promise<string> {
|
|
160
267
|
try {
|
|
161
268
|
const chunks: Uint8Array[] = [];
|
|
269
|
+
let totalLength = 0;
|
|
162
270
|
|
|
163
271
|
for await (const chunk of this.client.cat(cid)) {
|
|
272
|
+
totalLength += chunk.length;
|
|
273
|
+
|
|
274
|
+
// SECURITY FIX (MEDIUM-3): Check size during streaming to prevent DoS
|
|
275
|
+
if (totalLength > this.config.maxSize) {
|
|
276
|
+
throw new Error(
|
|
277
|
+
`Content too large: ${totalLength}+ bytes exceeds maximum of ${this.config.maxSize} bytes. ` +
|
|
278
|
+
`Consider increasing maxSize in IPFSClientConfig if this is expected.`
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
164
282
|
chunks.push(chunk);
|
|
165
283
|
}
|
|
166
284
|
|
|
167
285
|
// Concatenate all chunks
|
|
168
|
-
const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
|
|
169
286
|
const result = new Uint8Array(totalLength);
|
|
170
287
|
let offset = 0;
|
|
171
288
|
|
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logger - Structured Logging Framework for ACTP SDK
|
|
3
|
+
*
|
|
4
|
+
* SECURITY FIX (M-6): Comprehensive logging with:
|
|
5
|
+
* - Log levels (debug, info, warn, error)
|
|
6
|
+
* - Structured metadata
|
|
7
|
+
* - Sensitive data filtering
|
|
8
|
+
* - Configurable output
|
|
9
|
+
*
|
|
10
|
+
* @module utils/Logger
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Log levels in order of severity
|
|
15
|
+
*/
|
|
16
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Log entry structure
|
|
20
|
+
*/
|
|
21
|
+
export interface LogEntry {
|
|
22
|
+
/** Timestamp */
|
|
23
|
+
timestamp: string;
|
|
24
|
+
/** Log level */
|
|
25
|
+
level: LogLevel;
|
|
26
|
+
/** Log message */
|
|
27
|
+
message: string;
|
|
28
|
+
/** Source module/component */
|
|
29
|
+
source?: string;
|
|
30
|
+
/** Additional metadata */
|
|
31
|
+
metadata?: Record<string, unknown>;
|
|
32
|
+
/** Error details (if applicable) */
|
|
33
|
+
error?: {
|
|
34
|
+
name: string;
|
|
35
|
+
message: string;
|
|
36
|
+
stack?: string;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Logger configuration
|
|
42
|
+
*/
|
|
43
|
+
export interface LoggerConfig {
|
|
44
|
+
/** Minimum log level to output */
|
|
45
|
+
minLevel?: LogLevel;
|
|
46
|
+
/** Source identifier for this logger */
|
|
47
|
+
source?: string;
|
|
48
|
+
/** Whether to include timestamps */
|
|
49
|
+
timestamps?: boolean;
|
|
50
|
+
/** Whether to filter sensitive data */
|
|
51
|
+
filterSensitive?: boolean;
|
|
52
|
+
/** Custom output handler */
|
|
53
|
+
output?: (entry: LogEntry) => void;
|
|
54
|
+
/** Whether logging is enabled */
|
|
55
|
+
enabled?: boolean;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Sensitive key name patterns (for checking object keys)
|
|
60
|
+
*
|
|
61
|
+
* SECURITY FIX (NEW-HIGH-3): NO GLOBAL FLAG on patterns used with .test()
|
|
62
|
+
* Global regex maintains lastIndex state, causing alternating match/no-match
|
|
63
|
+
* on consecutive calls, potentially leaking sensitive data intermittently.
|
|
64
|
+
*/
|
|
65
|
+
const SENSITIVE_KEY_PATTERNS: RegExp[] = [
|
|
66
|
+
/privateKey/i,
|
|
67
|
+
/secret/i,
|
|
68
|
+
/password/i,
|
|
69
|
+
/apiKey/i,
|
|
70
|
+
/authorization/i,
|
|
71
|
+
/mnemonic/i,
|
|
72
|
+
/seed/i,
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Sensitive value patterns (for redacting from string values)
|
|
77
|
+
*
|
|
78
|
+
* SECURITY FIX (NEW-HIGH-3): These are PATTERN STRINGS that get converted
|
|
79
|
+
* to fresh RegExp instances with /g flag for each replace() call.
|
|
80
|
+
* This avoids lastIndex state pollution between calls.
|
|
81
|
+
*/
|
|
82
|
+
const SENSITIVE_VALUE_PATTERNS: string[] = [
|
|
83
|
+
'bearer\\s+[a-zA-Z0-9\\-_.]+', // Bearer tokens
|
|
84
|
+
'0x[a-fA-F0-9]{64}', // Private keys (64 hex chars)
|
|
85
|
+
'0x[a-fA-F0-9]{128}', // Extended private keys
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Log level priority (higher = more severe)
|
|
90
|
+
*/
|
|
91
|
+
const LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {
|
|
92
|
+
debug: 0,
|
|
93
|
+
info: 1,
|
|
94
|
+
warn: 2,
|
|
95
|
+
error: 3,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Structured Logger for ACTP SDK
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* const logger = new Logger({ source: 'BlockchainRuntime', minLevel: 'info' });
|
|
104
|
+
*
|
|
105
|
+
* logger.info('Transaction created', { txId: '0x...' });
|
|
106
|
+
* logger.error('Transaction failed', { txId: '0x...' }, error);
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
export class Logger {
|
|
110
|
+
private config: Required<LoggerConfig>;
|
|
111
|
+
|
|
112
|
+
constructor(config: LoggerConfig = {}) {
|
|
113
|
+
this.config = {
|
|
114
|
+
minLevel: config.minLevel ?? 'info',
|
|
115
|
+
source: config.source ?? 'ACTP-SDK',
|
|
116
|
+
timestamps: config.timestamps ?? true,
|
|
117
|
+
filterSensitive: config.filterSensitive ?? true,
|
|
118
|
+
output: config.output ?? this.defaultOutput.bind(this),
|
|
119
|
+
enabled: config.enabled ?? true,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Create child logger with inherited config
|
|
125
|
+
*/
|
|
126
|
+
child(source: string): Logger {
|
|
127
|
+
return new Logger({
|
|
128
|
+
...this.config,
|
|
129
|
+
source: `${this.config.source}:${source}`,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Log debug message
|
|
135
|
+
*/
|
|
136
|
+
debug(message: string, metadata?: Record<string, unknown>): void {
|
|
137
|
+
this.log('debug', message, metadata);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Log info message
|
|
142
|
+
*/
|
|
143
|
+
info(message: string, metadata?: Record<string, unknown>): void {
|
|
144
|
+
this.log('info', message, metadata);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Log warning message
|
|
149
|
+
*/
|
|
150
|
+
warn(message: string, metadata?: Record<string, unknown>): void {
|
|
151
|
+
this.log('warn', message, metadata);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Log error message
|
|
156
|
+
*/
|
|
157
|
+
error(message: string, metadata?: Record<string, unknown>, error?: Error): void {
|
|
158
|
+
this.log('error', message, metadata, error);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Core logging method
|
|
163
|
+
*/
|
|
164
|
+
private log(
|
|
165
|
+
level: LogLevel,
|
|
166
|
+
message: string,
|
|
167
|
+
metadata?: Record<string, unknown>,
|
|
168
|
+
error?: Error
|
|
169
|
+
): void {
|
|
170
|
+
if (!this.config.enabled) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Check log level
|
|
175
|
+
if (LOG_LEVEL_PRIORITY[level] < LOG_LEVEL_PRIORITY[this.config.minLevel]) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Build log entry
|
|
180
|
+
const entry: LogEntry = {
|
|
181
|
+
timestamp: this.config.timestamps ? new Date().toISOString() : '',
|
|
182
|
+
level,
|
|
183
|
+
message,
|
|
184
|
+
source: this.config.source,
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
// Add metadata (filtered for sensitive data)
|
|
188
|
+
if (metadata) {
|
|
189
|
+
entry.metadata = this.config.filterSensitive
|
|
190
|
+
? this.filterSensitiveData(metadata)
|
|
191
|
+
: metadata;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Add error details
|
|
195
|
+
if (error) {
|
|
196
|
+
entry.error = {
|
|
197
|
+
name: error.name,
|
|
198
|
+
message: error.message,
|
|
199
|
+
stack: error.stack,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Output the log
|
|
204
|
+
this.config.output(entry);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Filter sensitive data from metadata
|
|
209
|
+
*
|
|
210
|
+
* SECURITY FIX (NEW-HIGH-3): Uses separate pattern arrays for keys and values.
|
|
211
|
+
* Key patterns have no /g flag (used with .test()).
|
|
212
|
+
* Value patterns are strings converted to fresh RegExp instances per call.
|
|
213
|
+
*/
|
|
214
|
+
private filterSensitiveData(obj: Record<string, unknown>): Record<string, unknown> {
|
|
215
|
+
const filtered: Record<string, unknown> = {};
|
|
216
|
+
|
|
217
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
218
|
+
// SECURITY FIX (NEW-HIGH-3): Check if key matches sensitive pattern
|
|
219
|
+
// Using patterns without /g flag - safe to use with .test()
|
|
220
|
+
const isSensitiveKey = SENSITIVE_KEY_PATTERNS.some((pattern) => pattern.test(key));
|
|
221
|
+
|
|
222
|
+
if (isSensitiveKey) {
|
|
223
|
+
filtered[key] = '[REDACTED]';
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Recursively filter nested objects
|
|
228
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
229
|
+
filtered[key] = this.filterSensitiveData(value as Record<string, unknown>);
|
|
230
|
+
} else if (Array.isArray(value)) {
|
|
231
|
+
// SECURITY FIX: Also filter arrays
|
|
232
|
+
filtered[key] = value.map((item) => {
|
|
233
|
+
if (typeof item === 'string') {
|
|
234
|
+
return this.redactSensitiveValues(item);
|
|
235
|
+
} else if (item && typeof item === 'object') {
|
|
236
|
+
return this.filterSensitiveData(item as Record<string, unknown>);
|
|
237
|
+
}
|
|
238
|
+
return item;
|
|
239
|
+
});
|
|
240
|
+
} else if (typeof value === 'string') {
|
|
241
|
+
// SECURITY FIX (NEW-HIGH-3): Redact sensitive patterns from values
|
|
242
|
+
filtered[key] = this.redactSensitiveValues(value);
|
|
243
|
+
} else {
|
|
244
|
+
filtered[key] = value;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return filtered;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Redact sensitive patterns from a string value
|
|
253
|
+
*
|
|
254
|
+
* SECURITY FIX (NEW-HIGH-3): Creates fresh RegExp instances with /gi flag
|
|
255
|
+
* for each call, avoiding lastIndex state pollution.
|
|
256
|
+
*/
|
|
257
|
+
private redactSensitiveValues(value: string): string {
|
|
258
|
+
let result = value;
|
|
259
|
+
|
|
260
|
+
for (const patternStr of SENSITIVE_VALUE_PATTERNS) {
|
|
261
|
+
// Create fresh RegExp instance with global+case-insensitive flags
|
|
262
|
+
// This avoids lastIndex state issues from reusing regex instances
|
|
263
|
+
const pattern = new RegExp(patternStr, 'gi');
|
|
264
|
+
result = result.replace(pattern, '[REDACTED]');
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return result;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Default console output handler
|
|
272
|
+
*/
|
|
273
|
+
private defaultOutput(entry: LogEntry): void {
|
|
274
|
+
const prefix = entry.timestamp ? `[${entry.timestamp}] ` : '';
|
|
275
|
+
const source = entry.source ? `[${entry.source}] ` : '';
|
|
276
|
+
const levelStr = entry.level.toUpperCase().padEnd(5);
|
|
277
|
+
|
|
278
|
+
const baseMessage = `${prefix}${levelStr} ${source}${entry.message}`;
|
|
279
|
+
|
|
280
|
+
switch (entry.level) {
|
|
281
|
+
case 'debug':
|
|
282
|
+
console.debug(baseMessage, entry.metadata || '');
|
|
283
|
+
break;
|
|
284
|
+
case 'info':
|
|
285
|
+
console.info(baseMessage, entry.metadata || '');
|
|
286
|
+
break;
|
|
287
|
+
case 'warn':
|
|
288
|
+
console.warn(baseMessage, entry.metadata || '');
|
|
289
|
+
break;
|
|
290
|
+
case 'error':
|
|
291
|
+
console.error(baseMessage, entry.metadata || '', entry.error || '');
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Enable logging
|
|
298
|
+
*/
|
|
299
|
+
enable(): void {
|
|
300
|
+
this.config.enabled = true;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Disable logging
|
|
305
|
+
*/
|
|
306
|
+
disable(): void {
|
|
307
|
+
this.config.enabled = false;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Set minimum log level
|
|
312
|
+
*/
|
|
313
|
+
setLevel(level: LogLevel): void {
|
|
314
|
+
this.config.minLevel = level;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Global SDK logger instance
|
|
320
|
+
*/
|
|
321
|
+
export const sdkLogger = new Logger({
|
|
322
|
+
source: 'ACTP-SDK',
|
|
323
|
+
minLevel: process.env.ACTP_LOG_LEVEL as LogLevel || 'info',
|
|
324
|
+
enabled: process.env.ACTP_LOGGING !== 'false',
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Metrics/monitoring hook interface
|
|
329
|
+
*
|
|
330
|
+
* SECURITY FIX (M-7): Metrics and monitoring hooks
|
|
331
|
+
*/
|
|
332
|
+
export interface MetricsHook {
|
|
333
|
+
/** Called when a transaction is created */
|
|
334
|
+
onTransactionCreated?: (txId: string, metadata: Record<string, unknown>) => void;
|
|
335
|
+
/** Called when escrow is linked */
|
|
336
|
+
onEscrowLinked?: (txId: string, escrowId: string, amount: string) => void;
|
|
337
|
+
/** Called when state transitions */
|
|
338
|
+
onStateTransition?: (txId: string, fromState: string, toState: string) => void;
|
|
339
|
+
/** Called when escrow is released */
|
|
340
|
+
onEscrowReleased?: (escrowId: string, amount: string) => void;
|
|
341
|
+
/** Called on errors */
|
|
342
|
+
onError?: (error: Error, context: Record<string, unknown>) => void;
|
|
343
|
+
/** Called for performance metrics */
|
|
344
|
+
onPerformance?: (operation: string, durationMs: number, metadata?: Record<string, unknown>) => void;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Metrics collector for SDK operations
|
|
349
|
+
*/
|
|
350
|
+
export class MetricsCollector {
|
|
351
|
+
private hooks: MetricsHook[] = [];
|
|
352
|
+
private readonly logger: Logger;
|
|
353
|
+
|
|
354
|
+
constructor(logger?: Logger) {
|
|
355
|
+
this.logger = logger ?? sdkLogger.child('Metrics');
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Register a metrics hook
|
|
360
|
+
*/
|
|
361
|
+
addHook(hook: MetricsHook): void {
|
|
362
|
+
this.hooks.push(hook);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Remove a metrics hook
|
|
367
|
+
*/
|
|
368
|
+
removeHook(hook: MetricsHook): void {
|
|
369
|
+
const index = this.hooks.indexOf(hook);
|
|
370
|
+
if (index > -1) {
|
|
371
|
+
this.hooks.splice(index, 1);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Emit transaction created event
|
|
377
|
+
*/
|
|
378
|
+
transactionCreated(txId: string, metadata: Record<string, unknown>): void {
|
|
379
|
+
this.logger.info('Transaction created', { txId, ...metadata });
|
|
380
|
+
for (const hook of this.hooks) {
|
|
381
|
+
try {
|
|
382
|
+
hook.onTransactionCreated?.(txId, metadata);
|
|
383
|
+
} catch (error) {
|
|
384
|
+
this.logger.error('Metrics hook error', { hook: 'onTransactionCreated' }, error as Error);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Emit escrow linked event
|
|
391
|
+
*/
|
|
392
|
+
escrowLinked(txId: string, escrowId: string, amount: string): void {
|
|
393
|
+
this.logger.info('Escrow linked', { txId, escrowId, amount });
|
|
394
|
+
for (const hook of this.hooks) {
|
|
395
|
+
try {
|
|
396
|
+
hook.onEscrowLinked?.(txId, escrowId, amount);
|
|
397
|
+
} catch (error) {
|
|
398
|
+
this.logger.error('Metrics hook error', { hook: 'onEscrowLinked' }, error as Error);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Emit state transition event
|
|
405
|
+
*/
|
|
406
|
+
stateTransition(txId: string, fromState: string, toState: string): void {
|
|
407
|
+
this.logger.info('State transition', { txId, fromState, toState });
|
|
408
|
+
for (const hook of this.hooks) {
|
|
409
|
+
try {
|
|
410
|
+
hook.onStateTransition?.(txId, fromState, toState);
|
|
411
|
+
} catch (error) {
|
|
412
|
+
this.logger.error('Metrics hook error', { hook: 'onStateTransition' }, error as Error);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Emit escrow released event
|
|
419
|
+
*/
|
|
420
|
+
escrowReleased(escrowId: string, amount: string): void {
|
|
421
|
+
this.logger.info('Escrow released', { escrowId, amount });
|
|
422
|
+
for (const hook of this.hooks) {
|
|
423
|
+
try {
|
|
424
|
+
hook.onEscrowReleased?.(escrowId, amount);
|
|
425
|
+
} catch (error) {
|
|
426
|
+
this.logger.error('Metrics hook error', { hook: 'onEscrowReleased' }, error as Error);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Emit error event
|
|
433
|
+
*/
|
|
434
|
+
recordError(error: Error, context: Record<string, unknown>): void {
|
|
435
|
+
this.logger.error('Error recorded', context, error);
|
|
436
|
+
for (const hook of this.hooks) {
|
|
437
|
+
try {
|
|
438
|
+
hook.onError?.(error, context);
|
|
439
|
+
} catch (hookError) {
|
|
440
|
+
this.logger.error('Metrics hook error', { hook: 'onError' }, hookError as Error);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Emit performance metric
|
|
447
|
+
*/
|
|
448
|
+
recordPerformance(operation: string, durationMs: number, metadata?: Record<string, unknown>): void {
|
|
449
|
+
this.logger.debug('Performance', { operation, durationMs, ...metadata });
|
|
450
|
+
for (const hook of this.hooks) {
|
|
451
|
+
try {
|
|
452
|
+
hook.onPerformance?.(operation, durationMs, metadata);
|
|
453
|
+
} catch (error) {
|
|
454
|
+
this.logger.error('Metrics hook error', { hook: 'onPerformance' }, error as Error);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Helper to time an operation
|
|
461
|
+
*/
|
|
462
|
+
async timeOperation<T>(
|
|
463
|
+
operation: string,
|
|
464
|
+
fn: () => Promise<T>,
|
|
465
|
+
metadata?: Record<string, unknown>
|
|
466
|
+
): Promise<T> {
|
|
467
|
+
const startTime = Date.now();
|
|
468
|
+
try {
|
|
469
|
+
const result = await fn();
|
|
470
|
+
const durationMs = Date.now() - startTime;
|
|
471
|
+
this.recordPerformance(operation, durationMs, { ...metadata, success: true });
|
|
472
|
+
return result;
|
|
473
|
+
} catch (error) {
|
|
474
|
+
const durationMs = Date.now() - startTime;
|
|
475
|
+
this.recordPerformance(operation, durationMs, { ...metadata, success: false });
|
|
476
|
+
throw error;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Global metrics collector instance
|
|
483
|
+
*/
|
|
484
|
+
export const sdkMetrics = new MetricsCollector();
|