@opendatalabs/vana-sdk 0.1.0-alpha.fd33fc9 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.ts +33 -1
- package/dist/browser.js.map +1 -1
- package/dist/chains/index.cjs.map +1 -1
- package/dist/chains/index.d.ts +30 -1
- package/dist/chains/index.js.map +1 -1
- package/dist/client/__tests__/enhancedResponse.test.d.ts +1 -0
- package/dist/client/enhancedResponse.cjs +164 -0
- package/dist/client/enhancedResponse.cjs.map +1 -0
- package/dist/client/enhancedResponse.d.ts +120 -0
- package/dist/client/enhancedResponse.js +138 -0
- package/dist/client/enhancedResponse.js.map +1 -0
- package/dist/config/chains.cjs.map +1 -1
- package/dist/config/chains.d.ts +99 -0
- package/dist/config/chains.js.map +1 -1
- package/dist/contracts/contractController.cjs.map +1 -1
- package/dist/contracts/contractController.d.ts +66 -10
- package/dist/contracts/contractController.js.map +1 -1
- package/dist/controllers/__tests__/data-consistency-integration.test.d.ts +7 -0
- package/dist/controllers/__tests__/operations.processQueue.test.d.ts +1 -0
- package/dist/controllers/base.cjs +33 -0
- package/dist/controllers/base.cjs.map +1 -1
- package/dist/controllers/base.d.ts +10 -0
- package/dist/controllers/base.js +33 -0
- package/dist/controllers/base.js.map +1 -1
- package/dist/controllers/data.cjs +417 -276
- package/dist/controllers/data.cjs.map +1 -1
- package/dist/controllers/data.d.ts +246 -193
- package/dist/controllers/data.js +430 -279
- package/dist/controllers/data.js.map +1 -1
- package/dist/controllers/operations.cjs +430 -0
- package/dist/controllers/operations.cjs.map +1 -0
- package/dist/controllers/operations.d.ts +229 -0
- package/dist/controllers/operations.js +406 -0
- package/dist/controllers/operations.js.map +1 -0
- package/dist/controllers/permissions.cjs +690 -209
- package/dist/controllers/permissions.cjs.map +1 -1
- package/dist/controllers/permissions.d.ts +196 -68
- package/dist/controllers/permissions.js +690 -209
- package/dist/controllers/permissions.js.map +1 -1
- package/dist/controllers/protocol.cjs.map +1 -1
- package/dist/controllers/protocol.d.ts +27 -28
- package/dist/controllers/protocol.js.map +1 -1
- package/dist/controllers/schemas.cjs +104 -25
- package/dist/controllers/schemas.cjs.map +1 -1
- package/dist/controllers/schemas.d.ts +88 -40
- package/dist/controllers/schemas.js +104 -25
- package/dist/controllers/schemas.js.map +1 -1
- package/dist/controllers/server.cjs +269 -58
- package/dist/controllers/server.cjs.map +1 -1
- package/dist/controllers/server.d.ts +157 -52
- package/dist/controllers/server.js +269 -58
- package/dist/controllers/server.js.map +1 -1
- package/dist/core/__tests__/health.test.d.ts +1 -0
- package/dist/core/__tests__/inMemoryNonceManager.test.d.ts +1 -0
- package/dist/core/__tests__/nonceManager.test.d.ts +1 -0
- package/dist/core/__tests__/pollingManager.test.d.ts +4 -0
- package/dist/core/apiClient.cjs +53 -3
- package/dist/core/apiClient.cjs.map +1 -1
- package/dist/core/apiClient.d.ts +132 -7
- package/dist/core/apiClient.js +53 -3
- package/dist/core/apiClient.js.map +1 -1
- package/dist/core/generics.cjs +30 -3
- package/dist/core/generics.cjs.map +1 -1
- package/dist/core/generics.d.ts +95 -6
- package/dist/core/generics.js +30 -3
- package/dist/core/generics.js.map +1 -1
- package/dist/core/health.cjs +289 -0
- package/dist/core/health.cjs.map +1 -0
- package/dist/core/health.d.ts +143 -0
- package/dist/core/health.js +265 -0
- package/dist/core/health.js.map +1 -0
- package/dist/core/inMemoryNonceManager.cjs +138 -0
- package/dist/core/inMemoryNonceManager.cjs.map +1 -0
- package/dist/core/inMemoryNonceManager.d.ts +69 -0
- package/dist/core/inMemoryNonceManager.js +114 -0
- package/dist/core/inMemoryNonceManager.js.map +1 -0
- package/dist/core/nonceManager.cjs +304 -0
- package/dist/core/nonceManager.cjs.map +1 -0
- package/dist/core/nonceManager.d.ts +116 -0
- package/dist/core/nonceManager.js +280 -0
- package/dist/core/nonceManager.js.map +1 -0
- package/dist/core/pollingManager.cjs +292 -0
- package/dist/core/pollingManager.cjs.map +1 -0
- package/dist/core/pollingManager.d.ts +120 -0
- package/dist/core/pollingManager.js +268 -0
- package/dist/core/pollingManager.js.map +1 -0
- package/dist/core.cjs +55 -1
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.ts +54 -3
- package/dist/core.js +55 -1
- package/dist/core.js.map +1 -1
- package/dist/crypto/ecies/base.cjs +16 -3
- package/dist/crypto/ecies/base.cjs.map +1 -1
- package/dist/crypto/ecies/base.js +16 -3
- package/dist/crypto/ecies/base.js.map +1 -1
- package/dist/errors.cjs +29 -0
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.ts +64 -0
- package/dist/errors.js +28 -0
- package/dist/errors.js.map +1 -1
- package/dist/generated/abi/ComputeInstructionRegistryImplementation.cjs.map +1 -1
- package/dist/generated/abi/ComputeInstructionRegistryImplementation.js.map +1 -1
- package/dist/generated/abi/DLPPerformanceImplementation.cjs +42 -0
- package/dist/generated/abi/DLPPerformanceImplementation.cjs.map +1 -1
- package/dist/generated/abi/DLPPerformanceImplementation.d.ts +32 -0
- package/dist/generated/abi/DLPPerformanceImplementation.js +42 -0
- package/dist/generated/abi/DLPPerformanceImplementation.js.map +1 -1
- package/dist/generated/abi/DLPRegistryImplementation.cjs +5 -5
- package/dist/generated/abi/DLPRegistryImplementation.cjs.map +1 -1
- package/dist/generated/abi/DLPRegistryImplementation.d.ts +4 -4
- package/dist/generated/abi/DLPRegistryImplementation.js +5 -5
- package/dist/generated/abi/DLPRegistryImplementation.js.map +1 -1
- package/dist/generated/abi/DLPRewardDeployerImplementation.cjs +166 -2
- package/dist/generated/abi/DLPRewardDeployerImplementation.cjs.map +1 -1
- package/dist/generated/abi/DLPRewardDeployerImplementation.d.ts +129 -2
- package/dist/generated/abi/DLPRewardDeployerImplementation.js +166 -2
- package/dist/generated/abi/DLPRewardDeployerImplementation.js.map +1 -1
- package/dist/generated/abi/DataPortabilityGranteesImplementation.cjs +167 -19
- package/dist/generated/abi/DataPortabilityGranteesImplementation.cjs.map +1 -1
- package/dist/generated/abi/DataPortabilityGranteesImplementation.d.ts +127 -14
- package/dist/generated/abi/DataPortabilityGranteesImplementation.js +167 -19
- package/dist/generated/abi/DataPortabilityGranteesImplementation.js.map +1 -1
- package/dist/generated/abi/DataPortabilityPermissionsImplementation.cjs +0 -19
- package/dist/generated/abi/DataPortabilityPermissionsImplementation.cjs.map +1 -1
- package/dist/generated/abi/DataPortabilityPermissionsImplementation.d.ts +0 -14
- package/dist/generated/abi/DataPortabilityPermissionsImplementation.js +0 -19
- package/dist/generated/abi/DataPortabilityPermissionsImplementation.js.map +1 -1
- package/dist/generated/abi/DataPortabilityServersImplementation.cjs +0 -19
- package/dist/generated/abi/DataPortabilityServersImplementation.cjs.map +1 -1
- package/dist/generated/abi/DataPortabilityServersImplementation.d.ts +0 -14
- package/dist/generated/abi/DataPortabilityServersImplementation.js +0 -19
- package/dist/generated/abi/DataPortabilityServersImplementation.js.map +1 -1
- package/dist/generated/abi/DataRegistryImplementation.cjs +0 -13
- package/dist/generated/abi/DataRegistryImplementation.cjs.map +1 -1
- package/dist/generated/abi/DataRegistryImplementation.d.ts +0 -10
- package/dist/generated/abi/DataRegistryImplementation.js +0 -13
- package/dist/generated/abi/DataRegistryImplementation.js.map +1 -1
- package/dist/generated/abi/SwapHelperImplementation.cjs +0 -43
- package/dist/generated/abi/SwapHelperImplementation.cjs.map +1 -1
- package/dist/generated/abi/SwapHelperImplementation.d.ts +0 -35
- package/dist/generated/abi/SwapHelperImplementation.js +0 -43
- package/dist/generated/abi/SwapHelperImplementation.js.map +1 -1
- package/dist/generated/abi/VanaEpochImplementation.cjs +195 -0
- package/dist/generated/abi/VanaEpochImplementation.cjs.map +1 -1
- package/dist/generated/abi/VanaEpochImplementation.d.ts +151 -0
- package/dist/generated/abi/VanaEpochImplementation.js +195 -0
- package/dist/generated/abi/VanaEpochImplementation.js.map +1 -1
- package/dist/generated/abi/VanaPoolEntityImplementation.cjs +22 -65
- package/dist/generated/abi/VanaPoolEntityImplementation.cjs.map +1 -1
- package/dist/generated/abi/VanaPoolEntityImplementation.d.ts +17 -51
- package/dist/generated/abi/VanaPoolEntityImplementation.js +22 -65
- package/dist/generated/abi/VanaPoolEntityImplementation.js.map +1 -1
- package/dist/generated/abi/VanaPoolStakingImplementation.cjs +113 -1
- package/dist/generated/abi/VanaPoolStakingImplementation.cjs.map +1 -1
- package/dist/generated/abi/VanaPoolStakingImplementation.d.ts +85 -1
- package/dist/generated/abi/VanaPoolStakingImplementation.js +113 -1
- package/dist/generated/abi/VanaPoolStakingImplementation.js.map +1 -1
- package/dist/generated/abi/index.d.ts +546 -146
- package/dist/generated/event-types.cjs.map +1 -1
- package/dist/generated/event-types.d.ts +14 -8
- package/dist/generated/eventRegistry.cjs +42 -18
- package/dist/generated/eventRegistry.cjs.map +1 -1
- package/dist/generated/eventRegistry.js +42 -18
- package/dist/generated/eventRegistry.js.map +1 -1
- package/dist/generated/server/server-exports.cjs +22 -0
- package/dist/generated/server/server-exports.cjs.map +1 -1
- package/dist/generated/server/server-exports.d.ts +27 -10
- package/dist/generated/server/server-exports.js +17 -0
- package/dist/generated/server/server-exports.js.map +1 -1
- package/dist/generated/server/server.cjs.map +1 -1
- package/dist/generated/server/server.d.ts +771 -402
- package/dist/generated/subgraph.cjs +797 -32
- package/dist/generated/subgraph.cjs.map +1 -1
- package/dist/generated/subgraph.d.ts +135 -0
- package/dist/generated/subgraph.js +792 -32
- package/dist/generated/subgraph.js.map +1 -1
- package/dist/index.browser.d.ts +2 -0
- package/dist/index.browser.js +10 -0
- package/dist/index.browser.js.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.node.cjs +26 -0
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.d.ts +49 -5
- package/dist/index.node.js +25 -1
- package/dist/index.node.js.map +1 -1
- package/dist/lib/__tests__/redisAtomicStore.test.d.ts +1 -0
- package/dist/lib/redisAtomicStore.cjs +201 -0
- package/dist/lib/redisAtomicStore.cjs.map +1 -0
- package/dist/lib/redisAtomicStore.d.ts +120 -0
- package/dist/lib/redisAtomicStore.js +177 -0
- package/dist/lib/redisAtomicStore.js.map +1 -0
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.ts +39 -1
- package/dist/node.js.map +1 -1
- package/dist/platform/browser.cjs +160 -2
- package/dist/platform/browser.cjs.map +1 -1
- package/dist/platform/browser.d.ts +232 -12
- package/dist/platform/browser.js +160 -2
- package/dist/platform/browser.js.map +1 -1
- package/dist/platform/interface.cjs.map +1 -1
- package/dist/platform/interface.d.ts +283 -90
- package/dist/platform/node.cjs +163 -2
- package/dist/platform/node.cjs.map +1 -1
- package/dist/platform/node.d.ts +69 -6
- package/dist/platform/node.js +163 -2
- package/dist/platform/node.js.map +1 -1
- package/dist/server/relayerHandler.cjs +315 -81
- package/dist/server/relayerHandler.cjs.map +1 -1
- package/dist/server/relayerHandler.d.ts +35 -2
- package/dist/server/relayerHandler.js +315 -81
- package/dist/server/relayerHandler.js.map +1 -1
- package/dist/storage/index.cjs +3 -0
- package/dist/storage/index.cjs.map +1 -1
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/index.js +2 -0
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/manager.cjs +108 -25
- package/dist/storage/manager.cjs.map +1 -1
- package/dist/storage/manager.d.ts +119 -25
- package/dist/storage/manager.js +108 -25
- package/dist/storage/manager.js.map +1 -1
- package/dist/storage/providers/callback-storage.cjs +86 -15
- package/dist/storage/providers/callback-storage.cjs.map +1 -1
- package/dist/storage/providers/callback-storage.d.ts +109 -20
- package/dist/storage/providers/callback-storage.js +86 -15
- package/dist/storage/providers/callback-storage.js.map +1 -1
- package/dist/storage/providers/dropbox.cjs +237 -0
- package/dist/storage/providers/dropbox.cjs.map +1 -0
- package/dist/storage/providers/dropbox.d.ts +39 -0
- package/dist/storage/providers/dropbox.js +215 -0
- package/dist/storage/providers/dropbox.js.map +1 -0
- package/dist/storage/providers/dropbox.test.d.ts +1 -0
- package/dist/storage/providers/pinata.cjs.map +1 -1
- package/dist/storage/providers/pinata.d.ts +12 -14
- package/dist/storage/providers/pinata.js.map +1 -1
- package/dist/tests/data-upload-owner-validation.test.d.ts +1 -0
- package/dist/tests/permissions-transaction-options.test.d.ts +1 -0
- package/dist/types/atomicStore.cjs +31 -0
- package/dist/types/atomicStore.cjs.map +1 -0
- package/dist/types/atomicStore.d.ts +236 -0
- package/dist/types/atomicStore.js +7 -0
- package/dist/types/atomicStore.js.map +1 -0
- package/dist/types/blockchain.cjs.map +1 -1
- package/dist/types/blockchain.d.ts +39 -11
- package/dist/types/chains.cjs.map +1 -1
- package/dist/types/chains.d.ts +74 -7
- package/dist/types/chains.js.map +1 -1
- package/dist/types/config.cjs.map +1 -1
- package/dist/types/config.d.ts +38 -4
- package/dist/types/config.js.map +1 -1
- package/dist/types/contracts.cjs.map +1 -1
- package/dist/types/contracts.d.ts +71 -7
- package/dist/types/controller-context.cjs.map +1 -1
- package/dist/types/controller-context.d.ts +4 -1
- package/dist/types/data.cjs.map +1 -1
- package/dist/types/data.d.ts +11 -10
- package/dist/types/generics.cjs.map +1 -1
- package/dist/types/generics.d.ts +81 -10
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.d.ts +31 -3
- package/dist/types/index.js.map +1 -1
- package/dist/types/operationStore.cjs +17 -0
- package/dist/types/operationStore.cjs.map +1 -0
- package/dist/types/operationStore.d.ts +171 -0
- package/dist/types/operationStore.js +1 -0
- package/dist/types/operationStore.js.map +1 -0
- package/dist/types/operations.cjs +3 -15
- package/dist/types/operations.cjs.map +1 -1
- package/dist/types/operations.d.ts +131 -39
- package/dist/types/operations.js +2 -13
- package/dist/types/operations.js.map +1 -1
- package/dist/types/options.cjs +17 -0
- package/dist/types/options.cjs.map +1 -0
- package/dist/types/options.d.ts +308 -0
- package/dist/types/options.js +1 -0
- package/dist/types/options.js.map +1 -0
- package/dist/types/permissions.cjs.map +1 -1
- package/dist/types/permissions.d.ts +19 -20
- package/dist/types/personal.cjs.map +1 -1
- package/dist/types/personal.d.ts +150 -14
- package/dist/types/relayer.cjs.map +1 -1
- package/dist/types/relayer.d.ts +145 -24
- package/dist/types/storage.cjs.map +1 -1
- package/dist/types/storage.d.ts +9 -21
- package/dist/types/storage.js.map +1 -1
- package/dist/types/utils.cjs.map +1 -1
- package/dist/types/utils.d.ts +0 -45
- package/dist/utils/__tests__/chainQuery.test.d.ts +1 -0
- package/dist/utils/__tests__/subgraphConsistency.test.d.ts +4 -0
- package/dist/utils/__tests__/subgraphPagination.test.d.ts +4 -0
- package/dist/utils/chainQuery.cjs +107 -0
- package/dist/utils/chainQuery.cjs.map +1 -0
- package/dist/utils/chainQuery.d.ts +31 -0
- package/dist/utils/chainQuery.js +82 -0
- package/dist/utils/chainQuery.js.map +1 -0
- package/dist/utils/grantFiles.cjs +4 -1
- package/dist/utils/grantFiles.cjs.map +1 -1
- package/dist/utils/grantFiles.d.ts +10 -20
- package/dist/utils/grantFiles.js +4 -1
- package/dist/utils/grantFiles.js.map +1 -1
- package/dist/utils/grantValidation.cjs.map +1 -1
- package/dist/utils/grantValidation.d.ts +95 -16
- package/dist/utils/grantValidation.js.map +1 -1
- package/dist/utils/grants.cjs.map +1 -1
- package/dist/utils/grants.d.ts +93 -12
- package/dist/utils/grants.js.map +1 -1
- package/dist/utils/ipfs.cjs +2 -4
- package/dist/utils/ipfs.cjs.map +1 -1
- package/dist/utils/ipfs.d.ts +1 -1
- package/dist/utils/ipfs.js +2 -4
- package/dist/utils/ipfs.js.map +1 -1
- package/dist/utils/lazy-import.cjs.map +1 -1
- package/dist/utils/lazy-import.d.ts +32 -7
- package/dist/utils/lazy-import.js.map +1 -1
- package/dist/utils/signatureCache.cjs +8 -2
- package/dist/utils/signatureCache.cjs.map +1 -1
- package/dist/utils/signatureCache.d.ts +49 -8
- package/dist/utils/signatureCache.js +8 -2
- package/dist/utils/signatureCache.js.map +1 -1
- package/dist/utils/subgraphConsistency.cjs +184 -0
- package/dist/utils/subgraphConsistency.cjs.map +1 -0
- package/dist/utils/subgraphConsistency.d.ts +65 -0
- package/dist/utils/subgraphConsistency.js +155 -0
- package/dist/utils/subgraphConsistency.js.map +1 -0
- package/dist/utils/subgraphMetaCache.cjs +101 -0
- package/dist/utils/subgraphMetaCache.cjs.map +1 -0
- package/dist/utils/subgraphMetaCache.d.ts +56 -0
- package/dist/utils/subgraphMetaCache.js +76 -0
- package/dist/utils/subgraphMetaCache.js.map +1 -0
- package/dist/utils/subgraphPagination.cjs +104 -0
- package/dist/utils/subgraphPagination.cjs.map +1 -0
- package/dist/utils/subgraphPagination.d.ts +78 -0
- package/dist/utils/subgraphPagination.js +78 -0
- package/dist/utils/subgraphPagination.js.map +1 -0
- package/dist/utils/transactionHelpers.cjs.map +1 -1
- package/dist/utils/transactionHelpers.d.ts +12 -12
- package/dist/utils/transactionHelpers.js.map +1 -1
- package/dist/utils/typedDataConverter.cjs.map +1 -1
- package/dist/utils/typedDataConverter.d.ts +39 -3
- package/dist/utils/typedDataConverter.js.map +1 -1
- package/dist/utils/urlResolver.cjs +7 -0
- package/dist/utils/urlResolver.cjs.map +1 -1
- package/dist/utils/urlResolver.d.ts +22 -4
- package/dist/utils/urlResolver.js +7 -0
- package/dist/utils/urlResolver.js.map +1 -1
- package/dist/utils/wallet.cjs.map +1 -1
- package/dist/utils/wallet.d.ts +78 -16
- package/dist/utils/wallet.js.map +1 -1
- package/package.json +3 -1
package/dist/core.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core.ts"],"sourcesContent":["import type {\n VanaConfig,\n VanaConfigWithStorage,\n RuntimeConfig,\n VanaChainId,\n StorageRequiredMarker,\n} from \"./types\";\nimport {\n isWalletConfig,\n isChainConfig,\n isReadOnlyConfig,\n isAddressOnlyConfig,\n isVanaChainId,\n hasStorageConfig,\n} from \"./types\";\nimport type { DownloadRelayerCallbacks } from \"./types/config\";\nimport type {\n RelayerConfig,\n UnifiedRelayerRequest,\n UnifiedRelayerResponse,\n} from \"./types/relayer\";\nimport { InvalidConfigurationError } from \"./errors\";\nimport type { ControllerContext } from \"./controllers/permissions\";\nimport { PermissionsController } from \"./controllers/permissions\";\nimport { DataController } from \"./controllers/data\";\nimport { SchemaController } from \"./controllers/schemas\";\nimport { ServerController } from \"./controllers/server\";\nimport { ProtocolController } from \"./controllers/protocol\";\nimport { StorageManager } from \"./storage\";\nimport { createWalletClient, createPublicClient, http } from \"viem\";\nimport type {\n PublicClient,\n WalletClient,\n Address,\n Hash,\n TransactionReceipt,\n Chain,\n} from \"viem\";\nimport { extractAddress } from \"./utils/wallet\";\nimport type {\n Operation,\n PollingOptions,\n TransactionResult,\n TransactionWaitOptions,\n} from \"./types/operations\";\nimport type {\n Contract,\n Fn,\n TypedTransactionResult,\n} from \"./generated/event-types\";\nimport { chains } from \"./config/chains\";\nimport { getChainConfig, vanaMainnet } from \"./chains\";\nimport type { VanaPlatformAdapter } from \"./platform/interface\";\nimport {\n encryptBlobWithSignedKey,\n decryptBlobWithSignedKey,\n} from \"./utils/encryption\";\n\n/**\n * Factory functions for creating VanaCore instances with proper type safety\n */\nexport class VanaCoreFactory {\n /**\n * Creates a VanaCore instance that enforces storage requirements at compile time.\n * Use this factory when you know you'll need storage-dependent operations.\n *\n * @param platform - The platform adapter for environment-specific operations\n * @param config - Configuration that includes required storage providers\n * @returns VanaCore instance with storage validation\n * @example\n * ```typescript\n * const vanaCore = VanaCoreFactory.createWithStorage(platformAdapter, {\n * walletClient: myWalletClient,\n * storage: {\n * providers: { ipfs: new IPFSStorage() },\n * defaultProvider: 'ipfs'\n * }\n * });\n * ```\n */\n static createWithStorage(\n platform: VanaPlatformAdapter,\n config: VanaConfigWithStorage,\n ): VanaCore & StorageRequiredMarker {\n const core = new VanaCore(platform, config);\n return core as VanaCore & StorageRequiredMarker;\n }\n\n /**\n * Creates a VanaCore instance without storage requirements.\n * Storage-dependent operations will fail at runtime if not configured.\n *\n * @param platform - The platform adapter for environment-specific operations\n * @param config - Basic configuration without required storage\n * @returns VanaCore instance\n * @example\n * ```typescript\n * const vanaCore = VanaCoreFactory.create(platformAdapter, {\n * walletClient: myWalletClient\n * });\n * ```\n */\n static create(platform: VanaPlatformAdapter, config: VanaConfig): VanaCore {\n return new VanaCore(platform, config);\n }\n}\n\n/**\n * Provides the core SDK functionality for interacting with the Vana network.\n *\n * @remarks\n * This environment-agnostic class contains all SDK logic and accepts a platform\n * adapter to handle environment-specific operations. It initializes all controllers\n * and manages shared context between them, providing a unified interface for\n * data management, permissions, smart contracts, and storage operations.\n *\n * The class uses TypeScript overloading to enforce storage requirements at compile time.\n * Methods that require storage will throw `InvalidConfigurationError` at runtime if\n * storage providers are not configured, implementing a fail-fast approach to prevent\n * errors during expensive operations.\n *\n * **Core Architecture:**\n * - **Controllers**: Specialized modules for different Vana features (data, permissions, etc.)\n * - **Platform Adapters**: Environment-specific implementations (browser vs Node.js)\n * - **Storage Managers**: Abstraction layer for multiple storage providers\n * - **Context Sharing**: Unified configuration and services across all controllers\n *\n * For public usage, use the platform-specific factory functions:\n * - Browser: `import { Vana } from '@opendatalabs/vana-sdk/browser'`\n * - Node.js: `import { Vana } from '@opendatalabs/vana-sdk/node'`\n *\n * @example\n * ```typescript\n * // Direct instantiation (advanced usage)\n * import { VanaCore, BrowserPlatformAdapter } from '@opendatalabs/vana-sdk/browser';\n *\n * const core = new VanaCore(new BrowserPlatformAdapter(), {\n * walletClient: myWalletClient,\n * storage: {\n * providers: { ipfs: new IPFSStorage() },\n * defaultProvider: 'ipfs'\n * }\n * });\n *\n * // Access all controllers\n * const files = await core.data.getUserFiles();\n * const permissions = await core.permissions.grant({\n * grantee: '0x742d35...',\n * operation: 'read'\n * });\n * ```\n * @category Core SDK\n */\nexport class VanaCore {\n /** Manages gasless data access permissions and trusted server registry. */\n public readonly permissions: PermissionsController;\n\n /** Handles user data file operations. */\n public readonly data: DataController;\n\n /** Manages data schemas and refiners. */\n public readonly schemas: SchemaController;\n\n /** Provides personal server setup and trusted server interactions. */\n public readonly server: ServerController;\n\n /** Offers low-level access to Vana protocol smart contracts. */\n public readonly protocol: ProtocolController;\n\n /** Handles environment-specific operations like encryption and file systems. */\n protected platform: VanaPlatformAdapter;\n\n private readonly relayerConfig?: RelayerConfig;\n private readonly relayerCallback?: (\n request: UnifiedRelayerRequest,\n ) => Promise<UnifiedRelayerResponse>;\n private readonly downloadRelayer?: DownloadRelayerCallbacks;\n private readonly storageManager?: StorageManager;\n private readonly hasRequiredStorage: boolean;\n private readonly ipfsGateways?: string[];\n private readonly publicClient: PublicClient;\n private readonly walletClient?: WalletClient;\n private readonly _staticUserAddress?: Address; // For read-only mode\n\n /**\n * Initializes a new VanaCore client instance with the provided configuration.\n *\n * @remarks\n * The constructor validates the configuration, initializes storage providers if configured,\n * creates wallet and public clients, and sets up all SDK controllers with shared context.\n *\n * IMPORTANT: This constructor will validate storage requirements at runtime to fail fast.\n * Methods that require storage will throw runtime errors if storage is not configured.\n *\n * @param platform - The platform adapter for environment-specific operations\n * @param config - The configuration object specifying wallet or chain settings\n * @throws {InvalidConfigurationError} When the configuration is invalid or incomplete\n * @example\n * ```typescript\n * // Direct instantiation (consider using factory methods instead)\n * const vanaCore = new VanaCore(platformAdapter, {\n * walletClient: myWalletClient,\n * });\n * ```\n */\n constructor(platform: VanaPlatformAdapter, config: VanaConfig) {\n // Store the platform adapter\n this.platform = platform;\n\n // Validate configuration\n this.validateConfig(config);\n\n // Store relayer config and set up callback\n this.relayerConfig = config.relayer;\n if (config.relayer) {\n // Validate relayer type\n if (\n typeof config.relayer !== \"string\" &&\n typeof config.relayer !== \"function\"\n ) {\n throw new InvalidConfigurationError(\n \"Relayer must be either a URL string or a callback function\",\n );\n }\n\n if (typeof config.relayer === \"string\") {\n // Convenience: URL string - create HTTP transport\n const url = config.relayer;\n this.relayerCallback = async (request: UnifiedRelayerRequest) => {\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(request),\n });\n if (!response.ok) {\n throw new Error(`Relayer request failed: ${response.statusText}`);\n }\n return response.json();\n };\n } else {\n // Direct callback function\n this.relayerCallback = config.relayer;\n }\n }\n\n // Store download relayer if provided\n this.downloadRelayer = config.downloadRelayer;\n\n // Store IPFS gateways if provided\n this.ipfsGateways = config.ipfsGateways;\n\n // Check if storage is properly configured\n this.hasRequiredStorage = hasStorageConfig(config);\n\n // Initialize storage manager if storage providers are provided\n if (config.storage?.providers) {\n this.storageManager = new StorageManager();\n\n // Register all provided storage providers\n for (const [name, provider] of Object.entries(config.storage.providers)) {\n const isDefault = name === config.storage.defaultProvider;\n this.storageManager.register(name, provider, isDefault);\n }\n\n // If no default was explicitly set but providers exist, use the first one\n if (\n !config.storage.defaultProvider &&\n Object.keys(config.storage.providers).length > 0\n ) {\n const firstProviderName = Object.keys(config.storage.providers)[0];\n this.storageManager.setDefaultProvider(firstProviderName);\n }\n }\n\n // Initialize clients based on configuration type\n let walletClient: WalletClient | undefined;\n let publicClient: PublicClient;\n let staticUserAddress: Address | undefined; // Only for read-only mode\n let chainToUse: Chain;\n\n if (isWalletConfig(config)) {\n // Full mode with wallet client\n walletClient = config.walletClient;\n chainToUse = (walletClient.chain as Chain) ?? vanaMainnet;\n\n // In wallet mode, address is dynamic (not stored)\n staticUserAddress = undefined;\n\n // Use provided publicClient or create one\n if (\"publicClient\" in config && config.publicClient) {\n publicClient = config.publicClient;\n } else {\n publicClient = createPublicClient({\n chain: chainToUse,\n transport: http(),\n });\n }\n } else if (isReadOnlyConfig(config)) {\n // Read-only mode with public client and address\n walletClient = undefined;\n publicClient = config.publicClient;\n staticUserAddress = config.address;\n chainToUse = config.publicClient.chain ?? vanaMainnet;\n } else if (isAddressOnlyConfig(config)) {\n // Read-only mode with just address (create public client)\n walletClient = undefined;\n staticUserAddress = config.address;\n chainToUse = config.chain ?? vanaMainnet;\n\n publicClient = createPublicClient({\n chain: chainToUse,\n transport: http(),\n });\n } else if (isChainConfig(config)) {\n // Legacy chain configuration - create wallet client\n if (!config.account) {\n throw new InvalidConfigurationError(\n \"Account is required when using ChainConfig\",\n );\n }\n\n const chain = chains[config.chainId];\n if (!chain) {\n throw new InvalidConfigurationError(\n `Unsupported chain ID: ${config.chainId}`,\n );\n }\n\n chainToUse = chain;\n walletClient = createWalletClient({\n chain,\n transport: http(config.rpcUrl ?? chain.rpcUrls.default.http[0]),\n account: config.account,\n });\n // In wallet mode, address is dynamic (not stored)\n staticUserAddress = undefined;\n publicClient = createPublicClient({\n chain,\n transport: http(),\n });\n } else {\n throw new InvalidConfigurationError(\n \"Invalid configuration: must provide either walletClient, publicClient + address, or address alone\",\n );\n }\n\n // Store the clients and static address for later use\n this.publicClient = publicClient;\n this.walletClient = walletClient;\n this._staticUserAddress = staticUserAddress;\n\n // Get default service URLs from chain config if not provided\n const chainConfig = getChainConfig(chainToUse.id);\n const subgraphUrl = config.subgraphUrl ?? chainConfig?.subgraphUrl;\n const personalServerUrl =\n config.defaultPersonalServerUrl ?? chainConfig?.personalServerUrl;\n\n // Create shared context for all controllers with dynamic userAddress getter\n const self = this; // Capture VanaCore instance for getter delegation\n const sharedContext: ControllerContext = {\n walletClient,\n publicClient,\n get userAddress() {\n // Delegate to VanaCore's getter for dynamic resolution\n return self.userAddress;\n },\n applicationClient: walletClient, // Using same wallet for now\n relayer: this.relayerCallback,\n downloadRelayer: this.downloadRelayer,\n storageManager: this.storageManager,\n subgraphUrl,\n platform: this.platform, // Pass the platform adapter to controllers\n validateStorageRequired: this.validateStorageRequired.bind(this),\n hasStorage: this.hasStorage.bind(this),\n ipfsGateways: this.ipfsGateways,\n defaultPersonalServerUrl: personalServerUrl,\n waitForTransactionEvents: this.waitForTransactionEvents.bind(this),\n waitForOperation: this.waitForOperation.bind(this),\n };\n\n // Initialize controllers\n this.permissions = new PermissionsController(sharedContext);\n this.data = new DataController(sharedContext);\n this.schemas = new SchemaController(sharedContext);\n this.server = new ServerController(sharedContext);\n this.protocol = new ProtocolController(sharedContext);\n }\n\n /**\n * Validates that storage is available for storage-dependent operations.\n * This method enforces the fail-fast principle by checking storage availability\n * at method call time rather than during expensive operations.\n *\n * @throws {InvalidConfigurationError} When storage is required but not configured\n * @example\n * ```typescript\n * // This will throw if storage is not configured\n * vana.validateStorageRequired();\n * await vana.data.uploadFile(file); // Safe to proceed\n * ```\n */\n public validateStorageRequired(): void {\n if (!this.hasRequiredStorage) {\n throw new InvalidConfigurationError(\n \"Storage configuration is required for this operation. \" +\n \"Please configure storage providers in VanaConfig.storage, \" +\n \"provide a relayer configuration, \" +\n \"or pass pre-stored URLs to avoid this dependency. \" +\n \"\\n\\nFor better type safety, consider using VanaCoreFactory.createWithStorage() \" +\n \"with VanaConfigWithStorage to catch this error at compile time.\",\n );\n }\n }\n\n /**\n * Checks whether storage is configured without throwing an error.\n *\n * @returns True if storage is properly configured\n * @example\n * ```typescript\n * if (vana.hasStorage()) {\n * await vana.data.uploadFile(file);\n * } else {\n * console.warn('Storage not configured - using pre-stored URLs only');\n * }\n * ```\n */\n public hasStorage(): boolean {\n return this.hasRequiredStorage;\n }\n\n /**\n * Type guard to check if this instance has storage enabled at compile time.\n * Use this when you need TypeScript to understand that storage is available.\n *\n * @returns True if storage is configured, with type narrowing\n * @example\n * ```typescript\n * if (vana.isStorageEnabled()) {\n * // TypeScript knows storage is available here\n * await vana.data.uploadFile(file);\n * }\n * ```\n */\n public isStorageEnabled(): this is VanaCore & StorageRequiredMarker {\n return this.hasRequiredStorage;\n }\n\n /**\n * Validates the provided configuration object against all requirements.\n *\n * @remarks\n * This method performs comprehensive validation of wallet client configuration,\n * chain configuration, storage providers, and relayer callbacks.\n * @param config - The configuration object to validate\n * @throws {InvalidConfigurationError} When any configuration parameter is invalid\n */\n private validateConfig(config: VanaConfig): void {\n if (!config) {\n throw new InvalidConfigurationError(\"Configuration object is required\");\n }\n\n // Validate storage configuration if provided\n if (config.storage?.providers) {\n if (typeof config.storage.providers !== \"object\") {\n throw new InvalidConfigurationError(\n \"storage.providers must be an object\",\n );\n }\n\n // Validate that all providers have required methods\n for (const [name, provider] of Object.entries(config.storage.providers)) {\n if (!provider || typeof provider !== \"object\") {\n throw new InvalidConfigurationError(\n `Storage provider '${name}' must be a valid StorageProvider object`,\n );\n }\n }\n\n // Validate default provider if specified\n if (config.storage.defaultProvider) {\n if (!(config.storage.defaultProvider in config.storage.providers)) {\n throw new InvalidConfigurationError(\n `Default storage provider '${config.storage.defaultProvider}' not found in providers`,\n );\n }\n }\n }\n\n if (isWalletConfig(config)) {\n // Validate WalletConfig\n if (!config.walletClient) {\n throw new InvalidConfigurationError(\"walletClient is required\");\n }\n\n // Validate that walletClient is actually a WalletClient\n if (\n typeof config.walletClient !== \"object\" ||\n !config.walletClient.signTypedData\n ) {\n throw new InvalidConfigurationError(\n \"walletClient must be a valid viem WalletClient\",\n );\n }\n\n // Validate that wallet client has a chain\n if (!config.walletClient.chain) {\n throw new InvalidConfigurationError(\n \"walletClient must have a chain configured\",\n );\n }\n\n // Validate that the chain is supported\n if (!isVanaChainId(config.walletClient.chain.id)) {\n throw new InvalidConfigurationError(\n `Unsupported chain ID: ${String(config.walletClient.chain.id)}. Supported chains: 14800 (Moksha testnet), 1480 (Vana mainnet)`,\n );\n }\n } else if (isChainConfig(config)) {\n // Validate ChainConfig\n if (!isVanaChainId(config.chainId)) {\n throw new InvalidConfigurationError(\n `Unsupported chain ID: ${String(config.chainId)}. Supported chains: 14800 (Moksha testnet), 1480 (Vana mainnet)`,\n );\n }\n\n // Validate rpcUrl if provided\n if (config.rpcUrl) {\n if (typeof config.rpcUrl !== \"string\") {\n throw new InvalidConfigurationError(\"rpcUrl must be a string\");\n }\n\n if (config.rpcUrl.trim() === \"\") {\n throw new InvalidConfigurationError(\"rpcUrl cannot be empty\");\n }\n\n // Basic URL validation for RPC URL\n try {\n new URL(config.rpcUrl);\n } catch {\n throw new InvalidConfigurationError(\"rpcUrl must be a valid URL\");\n }\n }\n\n // Account is optional for ChainConfig, but if provided, validate it\n if (config.account) {\n if (typeof config.account !== \"object\" || !config.account.address) {\n throw new InvalidConfigurationError(\n \"account must be a valid viem Account object\",\n );\n }\n }\n } else if (isReadOnlyConfig(config)) {\n // Validate read-only config with publicClient and address\n if (!config.publicClient) {\n throw new InvalidConfigurationError(\n \"publicClient is required for read-only configuration\",\n );\n }\n if (!config.address) {\n throw new InvalidConfigurationError(\n \"address is required for read-only configuration\",\n );\n }\n } else if (isAddressOnlyConfig(config)) {\n // Validate address-only config\n if (!config.address) {\n throw new InvalidConfigurationError(\n \"address is required for address-only configuration\",\n );\n }\n // chain is optional, will use default\n } else {\n throw new InvalidConfigurationError(\n \"Invalid configuration: must provide either walletClient, publicClient + address, or address alone\",\n );\n }\n }\n\n /**\n * Gets the current chain ID from the wallet client.\n *\n * @returns The numeric chain ID of the connected network\n * @example\n * ```typescript\n * const chainId = vana.chainId;\n * console.log(`Connected to chain: ${chainId}`); // e.g., \"Connected to chain: 14800\"\n * ```\n */\n get chainId(): number {\n return this.protocol.getChainId();\n }\n\n /**\n * Gets the current chain name from the wallet client.\n *\n * @returns The human-readable name of the connected network\n * @example\n * ```typescript\n * const chainName = vana.chainName;\n * console.log(`Connected to: ${chainName}`); // e.g., \"Connected to: Moksha Testnet\"\n * ```\n */\n get chainName(): string {\n return this.protocol.getChainName();\n }\n\n /**\n * The user's wallet address.\n * In wallet mode, this always returns the current wallet account address.\n * In read-only mode, this returns the static address provided during initialization.\n *\n * @example\n * ```typescript\n * const address = vana.userAddress;\n * console.log(`User address: ${address}`); // e.g., \"User address: 0x742d35...\"\n * ```\n */\n get userAddress(): Address {\n // In wallet mode: dynamically read from wallet\n if (this.walletClient?.account) {\n return extractAddress(this.walletClient.account);\n }\n\n // In read-only mode: use static address\n if (this._staticUserAddress) {\n return this._staticUserAddress;\n }\n\n throw new Error(\"No user address available\");\n }\n\n /**\n * Retrieves comprehensive runtime configuration information.\n *\n * @returns The current runtime configuration including chain, storage, and relayer settings\n * @example\n * ```typescript\n * const config = vana.getConfig();\n * console.log(`Chain: ${config.chainName} (${config.chainId})`);\n * console.log(`Storage providers: ${config.storageProviders.join(\", \")}`);\n * ```\n */\n getConfig(): RuntimeConfig {\n return {\n chainId: this.chainId as VanaChainId,\n chainName: this.chainName,\n relayerConfig: this.relayerConfig,\n storageProviders: this.storageManager?.getStorageProviders() ?? [],\n defaultStorageProvider: this.storageManager?.getDefaultStorageProvider(),\n };\n }\n\n /**\n * Sets the platform adapter for environment-specific operations.\n * This is useful for testing and advanced use cases where you need\n * to override the default platform detection.\n *\n * @param adapter - The platform adapter to use\n * @example\n * ```typescript\n * // For testing with a mock adapter\n * const mockAdapter = new MockPlatformAdapter();\n * vana.setPlatformAdapter(mockAdapter);\n *\n * // For advanced use cases with custom adapters\n * const customAdapter = new CustomPlatformAdapter();\n * vana.setPlatformAdapter(customAdapter);\n * ```\n */\n setPlatformAdapter(adapter: VanaPlatformAdapter): void {\n this.platform = adapter;\n\n // Note: Controllers will use the new platform adapter on their next operation\n // since they access this.platform from the shared context\n }\n\n /**\n * Gets the current platform adapter.\n * This is useful for advanced use cases where you need to access\n * the platform adapter directly.\n *\n * @returns The current platform adapter\n * @example\n * ```typescript\n * const adapter = vana.getPlatformAdapter();\n * const encrypted = await adapter.encrypt(data, key);\n * ```\n */\n getPlatformAdapter(): VanaPlatformAdapter {\n return this.platform;\n }\n\n /**\n * Encrypts data using the Vana protocol standard encryption.\n *\n * @remarks\n * This method implements the Vana network's standard encryption protocol using\n * platform-appropriate cryptographic libraries. It automatically handles different\n * input types (string or Blob) and produces encrypted output suitable for secure\n * storage or transmission. The encryption is compatible with the network's\n * decryption protocols and can be decrypted by authorized parties.\n *\n * @param data - The data to encrypt (string or Blob)\n * @param key - The encryption key (typically generated via `generateEncryptionKey`)\n * @returns The encrypted data as a Blob\n * @throws {Error} When encryption fails due to invalid key or data format\n * @example\n * ```typescript\n * import { generateEncryptionKey } from '@opendatalabs/vana-sdk/node';\n *\n * // Generate encryption key from wallet signature\n * const encryptionKey = await generateEncryptionKey(vana.walletClient);\n *\n * // Encrypt string data\n * const sensitiveData = \"User's private information\";\n * const encrypted = await vana.encryptBlob(sensitiveData, encryptionKey);\n *\n * // Encrypt file data\n * const fileBlob = new Blob([fileContent], { type: 'application/json' });\n * const encryptedFile = await vana.encryptBlob(fileBlob, encryptionKey);\n *\n * // Store encrypted data safely\n * await storageProvider.upload(encrypted, 'encrypted-data.bin');\n * ```\n */\n public async encryptBlob(data: string | Blob, key: string): Promise<Blob> {\n return encryptBlobWithSignedKey(data, key, this.platform);\n }\n\n /**\n * Decrypts data that was encrypted using the Vana protocol.\n *\n * @remarks\n * This method decrypts data that was previously encrypted using the Vana network's\n * standard encryption protocol. It requires the same wallet signature that was used\n * for encryption and automatically uses the appropriate platform adapter for\n * cryptographic operations. The decrypted output maintains the original data format.\n *\n * @param encryptedData - The encrypted data (string or Blob)\n * @param walletSignature - The wallet signature used as decryption key\n * @returns The decrypted data as a Blob\n * @throws {Error} When decryption fails due to invalid signature or corrupted data\n * @example\n * ```typescript\n * import { generateEncryptionKey } from '@opendatalabs/vana-sdk/node';\n *\n * // Retrieve encrypted data from storage\n * const encryptedBlob = await storageProvider.download('encrypted-data.bin');\n *\n * // Generate the same key used for encryption\n * const decryptionKey = await generateEncryptionKey(vana.walletClient);\n *\n * // Decrypt the data\n * const decrypted = await vana.decryptBlob(encryptedBlob, decryptionKey);\n *\n * // Convert back to original format\n * const originalText = await decrypted.text();\n * const originalJson = JSON.parse(originalText);\n *\n * console.log('Decrypted data:', originalJson);\n * ```\n *\n * @example\n * ```typescript\n * // Decrypt file downloaded from Vana network\n * const userFiles = await vana.data.getUserFiles();\n * const file = userFiles[0];\n *\n * // Download encrypted content\n * const encrypted = await fetch(file.url).then(r => r.blob());\n *\n * // Decrypt with user's key\n * const decryptionKey = await generateEncryptionKey(vana.walletClient);\n * const decrypted = await vana.decryptBlob(encrypted, decryptionKey);\n *\n * // Process original data\n * const fileContent = await decrypted.arrayBuffer();\n * ```\n */\n public async decryptBlob(\n encryptedData: string | Blob,\n walletSignature: string,\n ): Promise<Blob> {\n return decryptBlobWithSignedKey(\n encryptedData,\n walletSignature,\n this.platform,\n );\n }\n\n /**\n * Waits for an operation to complete and returns the final result.\n *\n * @remarks\n * This method polls the operation status at regular intervals until it\n * reaches a terminal state (succeeded, failed, or canceled). Supports\n * ergonomic overloads to accept either an Operation object or just the ID.\n *\n * @param opOrId - Either an Operation object or operation ID string\n * @param options - Optional polling configuration\n * @returns The completed operation with result or error\n * @throws {PersonalServerError} When the operation fails or times out\n * @example\n * ```typescript\n * // Using operation object\n * const operation = await vana.server.createOperation({ permissionId: 123 });\n * const completed = await vana.waitForOperation(operation);\n *\n * // Using just the ID\n * const completed = await vana.waitForOperation(\"op_abc123\");\n *\n * // With custom timeout\n * const completed = await vana.waitForOperation(operation, {\n * timeout: 60000,\n * pollingInterval: 1000\n * });\n * ```\n */\n public async waitForOperation<T = unknown>(\n opOrId: Operation<T> | string,\n options?: PollingOptions,\n ): Promise<Operation<T>> {\n return this.server.waitForOperation(opOrId, options);\n }\n\n /**\n * Waits for a transaction to be confirmed and returns the receipt.\n *\n * @remarks\n * This method polls for transaction confirmation on the blockchain.\n * Supports ergonomic overloads to accept either a transaction result\n * object or just the hash string.\n *\n * @param hashOrObj - Either a TransactionResult object or hash string\n * @param options - Optional wait configuration\n * @returns The transaction receipt with logs and status\n * @example\n * ```typescript\n * // Using transaction result object\n * const tx = await vana.permissions.grant(params);\n * const receipt = await vana.waitForTransactionReceipt(tx);\n *\n * // Using just the hash\n * const receipt = await vana.waitForTransactionReceipt(\"0x123...\");\n *\n * // With custom confirmations\n * const receipt = await vana.waitForTransactionReceipt(tx, {\n * confirmations: 3,\n * timeout: 60000\n * });\n * ```\n */\n public async waitForTransactionReceipt(\n hashOrObj: TransactionResult | { hash: Hash } | Hash,\n options?: TransactionWaitOptions,\n ): Promise<TransactionReceipt> {\n const hash = typeof hashOrObj === \"string\" ? hashOrObj : hashOrObj.hash;\n\n return this.publicClient.waitForTransactionReceipt({\n hash,\n confirmations: options?.confirmations,\n pollingInterval: options?.pollingInterval,\n timeout: options?.timeout,\n });\n }\n\n /**\n * Waits for transaction confirmation and extracts blockchain event data.\n *\n * @remarks\n * This method leverages the context-carrying POJO architecture. When passed a\n * `TransactionResult` with an `operation` field, it automatically parses the\n * correct events from the transaction logs. For legacy compatibility, it accepts\n * raw hashes but will not parse events without operation context.\n *\n * @param transaction - Transaction result with operation context\n * @param options - Optional confirmation and timeout settings\n * @returns Parsed event data specific to the transaction's operation type\n * @throws {NetworkError} When transaction confirmation times out\n * @throws {BlockchainError} When expected events are not found in the transaction\n *\n * @example\n * ```typescript\n * // Recommended: Pass the transaction result for automatic event parsing\n * const tx = await vana.permissions.submitAddServerFilesAndPermissions(params);\n * const events = await vana.waitForTransactionEvents<{ permissionId: bigint }>(tx);\n * console.log(`Permission ID: ${events.permissionId}`);\n *\n * // Legacy: Raw hash without event parsing (returns receipt)\n * const receipt = await vana.waitForTransactionEvents(\"0x123...\");\n * ```\n *\n * @see For understanding transaction flows, visit https://docs.vana.org/docs/transactions\n */\n public async waitForTransactionEvents<C extends Contract, F extends Fn<C>>(\n transaction: TransactionResult<C, F>,\n options?: TransactionWaitOptions,\n ): Promise<TypedTransactionResult<C, F>> {\n // Import the POJO-based parser\n const { parseTransaction } = await import(\"./utils/parseTransactionPojo\");\n\n // Wait for the transaction to be mined\n const receipt = await this.waitForTransactionReceipt(\n transaction.hash,\n options,\n );\n\n // Parse events using our heuristic-free POJO system\n const result = parseTransaction(transaction, receipt);\n\n // Return the strongly-typed result\n // TypeScript knows exactly what events are possible!\n return result;\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/core.ts"],"sourcesContent":["import type {\n VanaConfig,\n VanaConfigWithStorage,\n RuntimeConfig,\n VanaChainId,\n StorageRequiredMarker,\n} from \"./types\";\nimport {\n isWalletConfig,\n isChainConfig,\n isReadOnlyConfig,\n isAddressOnlyConfig,\n isVanaChainId,\n hasStorageConfig,\n} from \"./types\";\nimport type { DownloadRelayerCallbacks } from \"./types/config\";\nimport type {\n RelayerConfig,\n UnifiedRelayerRequest,\n UnifiedRelayerResponse,\n} from \"./types/relayer\";\nimport { InvalidConfigurationError } from \"./errors\";\nimport type { ControllerContext } from \"./controllers/permissions\";\nimport { PermissionsController } from \"./controllers/permissions\";\nimport { DataController } from \"./controllers/data\";\nimport { SchemaController } from \"./controllers/schemas\";\nimport { ServerController } from \"./controllers/server\";\nimport { ProtocolController } from \"./controllers/protocol\";\nimport { OperationsController } from \"./controllers/operations\";\nimport { StorageManager } from \"./storage\";\nimport { createWalletClient, createPublicClient, http } from \"viem\";\nimport type {\n PublicClient,\n WalletClient,\n Address,\n Hash,\n TransactionReceipt,\n Chain,\n} from \"viem\";\nimport { extractAddress } from \"./utils/wallet\";\nimport type {\n Operation,\n PollingOptions,\n TransactionResult,\n TransactionWaitOptions,\n} from \"./types/operations\";\nimport type {\n IOperationStore,\n IRelayerStateStore,\n} from \"./types/operationStore\";\nimport type { IAtomicStore } from \"./types/atomicStore\";\nimport type {\n Contract,\n Fn,\n TypedTransactionResult,\n} from \"./generated/event-types\";\nimport { chains } from \"./config/chains\";\nimport { getChainConfig, vanaMainnet } from \"./chains\";\nimport type { VanaPlatformAdapter } from \"./platform/interface\";\nimport {\n encryptBlobWithSignedKey,\n decryptBlobWithSignedKey,\n} from \"./utils/encryption\";\n\n/**\n * Factory functions for creating VanaCore instances with proper type safety\n */\nexport class VanaCoreFactory {\n /**\n * Creates a VanaCore instance that enforces storage requirements at compile time.\n * Use this factory when you know you'll need storage-dependent operations.\n *\n * @param platform - The platform adapter for environment-specific operations\n * @param config - Configuration that includes required storage providers\n * @returns VanaCore instance with storage validation\n * @example\n * ```typescript\n * const vanaCore = VanaCoreFactory.createWithStorage(platformAdapter, {\n * walletClient: myWalletClient,\n * storage: {\n * providers: { ipfs: new IPFSStorage() },\n * defaultProvider: 'ipfs'\n * }\n * });\n * ```\n */\n static createWithStorage(\n platform: VanaPlatformAdapter,\n config: VanaConfigWithStorage,\n ): VanaCore & StorageRequiredMarker {\n const core = new VanaCore(platform, config);\n return core as VanaCore & StorageRequiredMarker;\n }\n\n /**\n * Creates a VanaCore instance without storage requirements.\n * Storage-dependent operations will fail at runtime if not configured.\n *\n * @param platform - The platform adapter for environment-specific operations\n * @param config - Basic configuration without required storage\n * @returns VanaCore instance\n * @example\n * ```typescript\n * const vanaCore = VanaCoreFactory.create(platformAdapter, {\n * walletClient: myWalletClient\n * });\n * ```\n */\n static create(platform: VanaPlatformAdapter, config: VanaConfig): VanaCore {\n return new VanaCore(platform, config);\n }\n}\n\n/**\n * Provides the core SDK functionality for interacting with the Vana network.\n *\n * @remarks\n * This environment-agnostic class contains all SDK logic and accepts a platform\n * adapter to handle environment-specific operations. It initializes all controllers\n * and manages shared context between them, providing a unified interface for\n * data management, permissions, smart contracts, and storage operations.\n *\n * The class uses TypeScript overloading to enforce storage requirements at compile time.\n * Methods that require storage will throw `InvalidConfigurationError` at runtime if\n * storage providers are not configured, implementing a fail-fast approach to prevent\n * errors during expensive operations.\n *\n * **Core Architecture:**\n * - **Controllers**: Specialized modules for different Vana features (data, permissions, etc.)\n * - **Platform Adapters**: Environment-specific implementations (browser vs Node.js)\n * - **Storage Managers**: Abstraction layer for multiple storage providers\n * - **Context Sharing**: Unified configuration and services across all controllers\n *\n * For public usage, use the platform-specific factory functions:\n * - Browser: `import { Vana } from '@opendatalabs/vana-sdk/browser'`\n * - Node.js: `import { Vana } from '@opendatalabs/vana-sdk/node'`\n *\n * @example\n * ```typescript\n * // Direct instantiation (advanced usage)\n * import { VanaCore, BrowserPlatformAdapter } from '@opendatalabs/vana-sdk/browser';\n *\n * const core = new VanaCore(new BrowserPlatformAdapter(), {\n * walletClient: myWalletClient,\n * storage: {\n * providers: { ipfs: new IPFSStorage() },\n * defaultProvider: 'ipfs'\n * }\n * });\n *\n * // Access all controllers\n * const files = await core.data.getUserFiles();\n * const permissions = await core.permissions.grant({\n * grantee: '0x742d35...',\n * operation: 'read'\n * });\n * ```\n * @category Core SDK\n */\nexport class VanaCore {\n /** Manages gasless data access permissions and trusted server registry. */\n public readonly permissions: PermissionsController;\n\n /** Handles user data file operations. */\n public readonly data: DataController;\n\n /** Manages data schemas and refiners. */\n public readonly schemas: SchemaController;\n\n /** Manages asynchronous operation recovery and status checking. */\n public readonly operations: OperationsController;\n\n /** Provides personal server setup and trusted server interactions. */\n public readonly server: ServerController;\n\n /** Offers low-level access to Vana protocol smart contracts. */\n public readonly protocol: ProtocolController;\n\n /** Handles environment-specific operations like encryption and file systems. */\n protected platform: VanaPlatformAdapter;\n\n private readonly relayerConfig?: RelayerConfig;\n private readonly relayerCallback?: (\n request: UnifiedRelayerRequest,\n ) => Promise<UnifiedRelayerResponse>;\n private readonly downloadRelayer?: DownloadRelayerCallbacks;\n private readonly storageManager?: StorageManager;\n private readonly hasRequiredStorage: boolean;\n private readonly ipfsGateways?: string[];\n public readonly publicClient: PublicClient;\n private readonly walletClient?: WalletClient;\n private readonly _staticUserAddress?: Address; // For read-only mode\n protected readonly operationStore?: IOperationStore | IRelayerStateStore;\n protected readonly atomicStore?: IAtomicStore;\n\n /**\n * Initializes a new VanaCore client instance with the provided configuration.\n *\n * @remarks\n * The constructor validates the configuration, initializes storage providers if configured,\n * creates wallet and public clients, and sets up all SDK controllers with shared context.\n *\n * IMPORTANT: This constructor will validate storage requirements at runtime to fail fast.\n * Methods that require storage will throw runtime errors if storage is not configured.\n *\n * @param platform - The platform adapter for environment-specific operations\n * @param config - The configuration object specifying wallet or chain settings\n * @throws {InvalidConfigurationError} When the configuration is invalid or incomplete\n * @example\n * ```typescript\n * // Direct instantiation (consider using factory methods instead)\n * const vanaCore = new VanaCore(platformAdapter, {\n * walletClient: myWalletClient,\n * });\n * ```\n */\n constructor(platform: VanaPlatformAdapter, config: VanaConfig) {\n // Store the platform adapter\n this.platform = platform;\n\n // Validate configuration\n this.validateConfig(config);\n\n // Store operation store if provided\n this.operationStore = config?.operationStore;\n\n // Store relayer config and set up callback\n this.relayerConfig = config.relayer;\n if (config.relayer) {\n // Validate relayer type\n if (\n typeof config.relayer !== \"string\" &&\n typeof config.relayer !== \"function\"\n ) {\n throw new InvalidConfigurationError(\n \"Relayer must be either a URL string or a callback function\",\n );\n }\n\n if (typeof config.relayer === \"string\") {\n // Convenience: URL string - create HTTP transport\n const url = config.relayer;\n this.relayerCallback = async (request: UnifiedRelayerRequest) => {\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(request),\n });\n if (!response.ok) {\n throw new Error(`Relayer request failed: ${response.statusText}`);\n }\n return response.json();\n };\n } else {\n // Direct callback function\n this.relayerCallback = config.relayer;\n }\n }\n\n // Store download relayer if provided\n this.downloadRelayer = config.downloadRelayer;\n\n // Store IPFS gateways if provided\n this.ipfsGateways = config.ipfsGateways;\n\n // Check if storage is properly configured\n this.hasRequiredStorage = hasStorageConfig(config);\n\n // Initialize storage manager if storage providers are provided\n if (config.storage?.providers) {\n this.storageManager = new StorageManager();\n\n // Register all provided storage providers\n for (const [name, provider] of Object.entries(config.storage.providers)) {\n const isDefault = name === config.storage.defaultProvider;\n this.storageManager.register(name, provider, isDefault);\n }\n\n // If no default was explicitly set but providers exist, use the first one\n if (\n !config.storage.defaultProvider &&\n Object.keys(config.storage.providers).length > 0\n ) {\n const firstProviderName = Object.keys(config.storage.providers)[0];\n this.storageManager.setDefaultProvider(firstProviderName);\n }\n }\n\n // Initialize clients based on configuration type\n let walletClient: WalletClient | undefined;\n let publicClient: PublicClient;\n let staticUserAddress: Address | undefined; // Only for read-only mode\n let chainToUse: Chain;\n\n if (isWalletConfig(config)) {\n // Full mode with wallet client\n walletClient = config.walletClient;\n chainToUse = (walletClient.chain as Chain) ?? vanaMainnet;\n\n // In wallet mode, address is dynamic (not stored)\n staticUserAddress = undefined;\n\n // Use provided publicClient or create one\n if (\"publicClient\" in config && config.publicClient) {\n publicClient = config.publicClient;\n } else {\n publicClient = createPublicClient({\n chain: chainToUse,\n transport: http(),\n });\n }\n } else if (isReadOnlyConfig(config)) {\n // Read-only mode with public client and address\n walletClient = undefined;\n publicClient = config.publicClient;\n staticUserAddress = config.address;\n chainToUse = config.publicClient.chain ?? vanaMainnet;\n } else if (isAddressOnlyConfig(config)) {\n // Read-only mode with just address (create public client)\n walletClient = undefined;\n staticUserAddress = config.address;\n chainToUse = config.chain ?? vanaMainnet;\n\n publicClient = createPublicClient({\n chain: chainToUse,\n transport: http(),\n });\n } else if (isChainConfig(config)) {\n // Legacy chain configuration - create wallet client\n if (!config.account) {\n throw new InvalidConfigurationError(\n \"Account is required when using ChainConfig\",\n );\n }\n\n const chain = chains[config.chainId];\n if (!chain) {\n throw new InvalidConfigurationError(\n `Unsupported chain ID: ${config.chainId}`,\n );\n }\n\n chainToUse = chain;\n walletClient = createWalletClient({\n chain,\n transport: http(config.rpcUrl ?? chain.rpcUrls.default.http[0]),\n account: config.account,\n });\n // In wallet mode, address is dynamic (not stored)\n staticUserAddress = undefined;\n publicClient = createPublicClient({\n chain,\n transport: http(),\n });\n } else {\n throw new InvalidConfigurationError(\n \"Invalid configuration: must provide either walletClient, publicClient + address, or address alone\",\n );\n }\n\n // Store the clients and static address for later use\n this.publicClient = publicClient;\n this.walletClient = walletClient;\n this._staticUserAddress = staticUserAddress;\n\n // Get default service URLs from chain config if not provided\n const chainConfig = getChainConfig(chainToUse.id);\n const subgraphUrl = config.subgraphUrl ?? chainConfig?.subgraphUrl;\n const personalServerUrl =\n config.defaultPersonalServerUrl ?? chainConfig?.personalServerUrl;\n\n // Create shared context for all controllers with dynamic userAddress getter\n const self = this; // Capture VanaCore instance for getter delegation\n const sharedContext: ControllerContext = {\n walletClient,\n publicClient,\n get userAddress() {\n // Delegate to VanaCore's getter for dynamic resolution\n return self.userAddress;\n },\n applicationClient: walletClient, // Using same wallet for now\n relayer: this.relayerCallback,\n downloadRelayer: this.downloadRelayer,\n storageManager: this.storageManager,\n subgraphUrl,\n platform: this.platform, // Pass the platform adapter to controllers\n validateStorageRequired: this.validateStorageRequired.bind(this),\n hasStorage: this.hasStorage.bind(this),\n ipfsGateways: this.ipfsGateways,\n defaultPersonalServerUrl: personalServerUrl,\n waitForTransactionEvents: this.waitForTransactionEvents.bind(this),\n waitForOperation: this.waitForOperation.bind(this),\n operationStore: this.operationStore,\n };\n\n // Initialize controllers\n this.permissions = new PermissionsController(sharedContext);\n this.data = new DataController(sharedContext);\n this.schemas = new SchemaController(sharedContext);\n this.operations = new OperationsController(sharedContext);\n this.server = new ServerController(sharedContext);\n this.protocol = new ProtocolController(sharedContext);\n }\n\n /**\n * Validates that storage is available for storage-dependent operations.\n * This method enforces the fail-fast principle by checking storage availability\n * at method call time rather than during expensive operations.\n *\n * @throws {InvalidConfigurationError} When storage is required but not configured\n * @example\n * ```typescript\n * // This will throw if storage is not configured\n * vana.validateStorageRequired();\n * await vana.data.uploadFile(file); // Safe to proceed\n * ```\n */\n public validateStorageRequired(): void {\n if (!this.hasRequiredStorage) {\n throw new InvalidConfigurationError(\n \"Storage configuration is required for this operation. \" +\n \"Please configure storage providers in VanaConfig.storage, \" +\n \"provide a relayer configuration, \" +\n \"or pass pre-stored URLs to avoid this dependency. \" +\n \"\\n\\nFor better type safety, consider using VanaCoreFactory.createWithStorage() \" +\n \"with VanaConfigWithStorage to catch this error at compile time.\",\n );\n }\n }\n\n /**\n * Checks whether storage is configured without throwing an error.\n *\n * @returns True if storage is properly configured\n * @example\n * ```typescript\n * if (vana.hasStorage()) {\n * await vana.data.uploadFile(file);\n * } else {\n * console.warn('Storage not configured - using pre-stored URLs only');\n * }\n * ```\n */\n public hasStorage(): boolean {\n return this.hasRequiredStorage;\n }\n\n /**\n * Type guard to check if this instance has storage enabled at compile time.\n * Use this when you need TypeScript to understand that storage is available.\n *\n * @returns True if storage is configured, with type narrowing\n * @example\n * ```typescript\n * if (vana.isStorageEnabled()) {\n * // TypeScript knows storage is available here\n * await vana.data.uploadFile(file);\n * }\n * ```\n */\n public isStorageEnabled(): this is VanaCore & StorageRequiredMarker {\n return this.hasRequiredStorage;\n }\n\n /**\n * Validates the provided configuration object against all requirements.\n *\n * @remarks\n * This method performs comprehensive validation of wallet client configuration,\n * chain configuration, storage providers, and relayer callbacks.\n * @param config - The configuration object to validate\n * @throws {InvalidConfigurationError} When any configuration parameter is invalid\n */\n private validateConfig(config: VanaConfig): void {\n if (!config) {\n throw new InvalidConfigurationError(\"Configuration object is required\");\n }\n\n // Validate storage configuration if provided\n if (config.storage?.providers) {\n if (typeof config.storage.providers !== \"object\") {\n throw new InvalidConfigurationError(\n \"storage.providers must be an object\",\n );\n }\n\n // Validate that all providers have required methods\n for (const [name, provider] of Object.entries(config.storage.providers)) {\n if (!provider || typeof provider !== \"object\") {\n throw new InvalidConfigurationError(\n `Storage provider '${name}' must be a valid StorageProvider object`,\n );\n }\n }\n\n // Validate default provider if specified\n if (config.storage.defaultProvider) {\n if (!(config.storage.defaultProvider in config.storage.providers)) {\n throw new InvalidConfigurationError(\n `Default storage provider '${config.storage.defaultProvider}' not found in providers`,\n );\n }\n }\n }\n\n if (isWalletConfig(config)) {\n // Validate WalletConfig\n if (!config.walletClient) {\n throw new InvalidConfigurationError(\"walletClient is required\");\n }\n\n // Validate that walletClient is actually a WalletClient\n if (\n typeof config.walletClient !== \"object\" ||\n !config.walletClient.signTypedData\n ) {\n throw new InvalidConfigurationError(\n \"walletClient must be a valid viem WalletClient\",\n );\n }\n\n // Validate that wallet client has a chain\n if (!config.walletClient.chain) {\n throw new InvalidConfigurationError(\n \"walletClient must have a chain configured\",\n );\n }\n\n // Validate that the chain is supported\n if (!isVanaChainId(config.walletClient.chain.id)) {\n throw new InvalidConfigurationError(\n `Unsupported chain ID: ${String(config.walletClient.chain.id)}. Supported chains: 14800 (Moksha testnet), 1480 (Vana mainnet)`,\n );\n }\n } else if (isChainConfig(config)) {\n // Validate ChainConfig\n if (!isVanaChainId(config.chainId)) {\n throw new InvalidConfigurationError(\n `Unsupported chain ID: ${String(config.chainId)}. Supported chains: 14800 (Moksha testnet), 1480 (Vana mainnet)`,\n );\n }\n\n // Validate rpcUrl if provided\n if (config.rpcUrl) {\n if (typeof config.rpcUrl !== \"string\") {\n throw new InvalidConfigurationError(\"rpcUrl must be a string\");\n }\n\n if (config.rpcUrl.trim() === \"\") {\n throw new InvalidConfigurationError(\"rpcUrl cannot be empty\");\n }\n\n // Basic URL validation for RPC URL\n try {\n new URL(config.rpcUrl);\n } catch {\n throw new InvalidConfigurationError(\"rpcUrl must be a valid URL\");\n }\n }\n\n // Account is optional for ChainConfig, but if provided, validate it\n if (config.account) {\n if (typeof config.account !== \"object\" || !config.account.address) {\n throw new InvalidConfigurationError(\n \"account must be a valid viem Account object\",\n );\n }\n }\n } else if (isReadOnlyConfig(config)) {\n // Validate read-only config with publicClient and address\n if (!config.publicClient) {\n throw new InvalidConfigurationError(\n \"publicClient is required for read-only configuration\",\n );\n }\n if (!config.address) {\n throw new InvalidConfigurationError(\n \"address is required for read-only configuration\",\n );\n }\n } else if (isAddressOnlyConfig(config)) {\n // Validate address-only config\n if (!config.address) {\n throw new InvalidConfigurationError(\n \"address is required for address-only configuration\",\n );\n }\n // chain is optional, will use default\n } else {\n throw new InvalidConfigurationError(\n \"Invalid configuration: must provide either walletClient, publicClient + address, or address alone\",\n );\n }\n }\n\n /**\n * Gets the current chain ID from the wallet client.\n *\n * @returns The numeric chain ID of the connected network\n * @example\n * ```typescript\n * const chainId = vana.chainId;\n * console.log(`Connected to chain: ${chainId}`); // e.g., \"Connected to chain: 14800\"\n * ```\n */\n get chainId(): number {\n return this.protocol.getChainId();\n }\n\n /**\n * Gets the current chain name from the wallet client.\n *\n * @returns The human-readable name of the connected network\n * @example\n * ```typescript\n * const chainName = vana.chainName;\n * console.log(`Connected to: ${chainName}`); // e.g., \"Connected to: Moksha Testnet\"\n * ```\n */\n get chainName(): string {\n return this.protocol.getChainName();\n }\n\n /**\n * The user's wallet address.\n * In wallet mode, this always returns the current wallet account address.\n * In read-only mode, this returns the static address provided during initialization.\n *\n * @example\n * ```typescript\n * const address = vana.userAddress;\n * console.log(`User address: ${address}`); // e.g., \"User address: 0x742d35...\"\n * ```\n */\n get userAddress(): Address {\n // In wallet mode: dynamically read from wallet\n if (this.walletClient?.account) {\n return extractAddress(this.walletClient.account);\n }\n\n // In read-only mode: use static address\n if (this._staticUserAddress) {\n return this._staticUserAddress;\n }\n\n throw new Error(\"No user address available\");\n }\n\n /**\n * Retrieves comprehensive runtime configuration information.\n *\n * @returns The current runtime configuration including chain, storage, and relayer settings\n * @example\n * ```typescript\n * const config = vana.getConfig();\n * console.log(`Chain: ${config.chainName} (${config.chainId})`);\n * console.log(`Storage providers: ${config.storageProviders.join(\", \")}`);\n * ```\n */\n getConfig(): RuntimeConfig {\n return {\n chainId: this.chainId as VanaChainId,\n chainName: this.chainName,\n relayerConfig: this.relayerConfig,\n storageProviders: this.storageManager?.getStorageProviders() ?? [],\n defaultStorageProvider: this.storageManager?.getDefaultStorageProvider(),\n };\n }\n\n /**\n * Sets the platform adapter for environment-specific operations.\n * This is useful for testing and advanced use cases where you need\n * to override the default platform detection.\n *\n * @param adapter - The platform adapter to use\n * @example\n * ```typescript\n * // For testing with a mock adapter\n * const mockAdapter = new MockPlatformAdapter();\n * vana.setPlatformAdapter(mockAdapter);\n *\n * // For advanced use cases with custom adapters\n * const customAdapter = new CustomPlatformAdapter();\n * vana.setPlatformAdapter(customAdapter);\n * ```\n */\n setPlatformAdapter(adapter: VanaPlatformAdapter): void {\n this.platform = adapter;\n\n // Note: Controllers will use the new platform adapter on their next operation\n // since they access this.platform from the shared context\n }\n\n /**\n * Gets the current platform adapter.\n * This is useful for advanced use cases where you need to access\n * the platform adapter directly.\n *\n * @returns The current platform adapter\n * @example\n * ```typescript\n * const adapter = vana.getPlatformAdapter();\n * const encrypted = await adapter.encrypt(data, key);\n * ```\n */\n getPlatformAdapter(): VanaPlatformAdapter {\n return this.platform;\n }\n\n /**\n * Encrypts data using the Vana protocol standard encryption.\n *\n * @remarks\n * This method implements the Vana network's standard encryption protocol using\n * platform-appropriate cryptographic libraries. It automatically handles different\n * input types (string or Blob) and produces encrypted output suitable for secure\n * storage or transmission. The encryption is compatible with the network's\n * decryption protocols and can be decrypted by authorized parties.\n *\n * @param data - The data to encrypt (string or Blob)\n * @param key - The encryption key (typically generated via `generateEncryptionKey`)\n * @returns The encrypted data as a Blob\n * @throws {Error} When encryption fails due to invalid key or data format\n * @example\n * ```typescript\n * import { generateEncryptionKey } from '@opendatalabs/vana-sdk/node';\n *\n * // Generate encryption key from wallet signature\n * const encryptionKey = await generateEncryptionKey(vana.walletClient);\n *\n * // Encrypt string data\n * const sensitiveData = \"User's private information\";\n * const encrypted = await vana.encryptBlob(sensitiveData, encryptionKey);\n *\n * // Encrypt file data\n * const fileBlob = new Blob([fileContent], { type: 'application/json' });\n * const encryptedFile = await vana.encryptBlob(fileBlob, encryptionKey);\n *\n * // Store encrypted data safely\n * await storageProvider.upload(encrypted, 'encrypted-data.bin');\n * ```\n */\n public async encryptBlob(data: string | Blob, key: string): Promise<Blob> {\n return encryptBlobWithSignedKey(data, key, this.platform);\n }\n\n /**\n * Decrypts data that was encrypted using the Vana protocol.\n *\n * @remarks\n * This method decrypts data that was previously encrypted using the Vana network's\n * standard encryption protocol. It requires the same wallet signature that was used\n * for encryption and automatically uses the appropriate platform adapter for\n * cryptographic operations. The decrypted output maintains the original data format.\n *\n * @param encryptedData - The encrypted data (string or Blob)\n * @param walletSignature - The wallet signature used as decryption key\n * @returns The decrypted data as a Blob\n * @throws {Error} When decryption fails due to invalid signature or corrupted data\n * @example\n * ```typescript\n * import { generateEncryptionKey } from '@opendatalabs/vana-sdk/node';\n *\n * // Retrieve encrypted data from storage\n * const encryptedBlob = await storageProvider.download('encrypted-data.bin');\n *\n * // Generate the same key used for encryption\n * const decryptionKey = await generateEncryptionKey(vana.walletClient);\n *\n * // Decrypt the data\n * const decrypted = await vana.decryptBlob(encryptedBlob, decryptionKey);\n *\n * // Convert back to original format\n * const originalText = await decrypted.text();\n * const originalJson = JSON.parse(originalText);\n *\n * console.log('Decrypted data:', originalJson);\n * ```\n *\n * @example\n * ```typescript\n * // Decrypt file downloaded from Vana network\n * const userFiles = await vana.data.getUserFiles();\n * const file = userFiles[0];\n *\n * // Download encrypted content\n * const encrypted = await fetch(file.url).then(r => r.blob());\n *\n * // Decrypt with user's key\n * const decryptionKey = await generateEncryptionKey(vana.walletClient);\n * const decrypted = await vana.decryptBlob(encrypted, decryptionKey);\n *\n * // Process original data\n * const fileContent = await decrypted.arrayBuffer();\n * ```\n */\n public async decryptBlob(\n encryptedData: string | Blob,\n walletSignature: string,\n ): Promise<Blob> {\n return decryptBlobWithSignedKey(\n encryptedData,\n walletSignature,\n this.platform,\n );\n }\n\n /**\n * Waits for an operation to complete and returns the final result.\n *\n * @remarks\n * This method polls the operation status at regular intervals until it\n * reaches a terminal state (succeeded, failed, or canceled). Supports\n * ergonomic overloads to accept either an Operation object or just the ID.\n *\n * @param opOrId - Either an Operation object or operation ID string\n * @param options - Optional polling configuration\n * @returns The completed operation with result or error\n * @throws {PersonalServerError} When the operation fails or times out\n * @example\n * ```typescript\n * // Using operation object\n * const operation = await vana.server.createOperation({ permissionId: 123 });\n * const completed = await vana.waitForOperation(operation);\n *\n * // Using just the ID\n * const completed = await vana.waitForOperation(\"op_abc123\");\n *\n * // With custom timeout\n * const completed = await vana.waitForOperation(operation, {\n * timeout: 60000,\n * pollingInterval: 1000\n * });\n * ```\n */\n public async waitForOperation(\n opOrId: Operation | string,\n options?: PollingOptions,\n ): Promise<Operation> {\n return this.server.waitForOperation(opOrId, options);\n }\n\n /**\n * Waits for a transaction to be confirmed and returns the receipt.\n *\n * @remarks\n * This method polls for transaction confirmation on the blockchain.\n * Supports ergonomic overloads to accept either a transaction result\n * object or just the hash string.\n *\n * @param hashOrObj - Either a TransactionResult object or hash string\n * @param options - Optional wait configuration\n * @returns The transaction receipt with logs and status\n * @example\n * ```typescript\n * // Using transaction result object\n * const tx = await vana.permissions.grant(params);\n * const receipt = await vana.waitForTransactionReceipt(tx);\n *\n * // Using just the hash\n * const receipt = await vana.waitForTransactionReceipt(\"0x123...\");\n *\n * // With custom confirmations\n * const receipt = await vana.waitForTransactionReceipt(tx, {\n * confirmations: 3,\n * timeout: 60000\n * });\n * ```\n */\n public async waitForTransactionReceipt(\n hashOrObj: TransactionResult | { hash: Hash } | Hash,\n options?: TransactionWaitOptions,\n ): Promise<TransactionReceipt> {\n const hash = typeof hashOrObj === \"string\" ? hashOrObj : hashOrObj.hash;\n\n return this.publicClient.waitForTransactionReceipt({\n hash,\n confirmations: options?.confirmations,\n pollingInterval: options?.pollingInterval,\n timeout: options?.timeout,\n });\n }\n\n /**\n * Waits for transaction confirmation and extracts blockchain event data.\n *\n * @remarks\n * This method leverages the context-carrying POJO architecture. When passed a\n * `TransactionResult` with an `operation` field, it automatically parses the\n * correct events from the transaction logs. For legacy compatibility, it accepts\n * raw hashes but will not parse events without operation context.\n *\n * @param transaction - Transaction result with operation context\n * @param options - Optional confirmation and timeout settings\n * @returns Parsed event data specific to the transaction's operation type\n * @throws {NetworkError} When transaction confirmation times out\n * @throws {BlockchainError} When expected events are not found in the transaction\n *\n * @example\n * ```typescript\n * // Recommended: Pass the transaction result for automatic event parsing\n * const tx = await vana.permissions.submitAddServerFilesAndPermissions(params);\n * const events = await vana.waitForTransactionEvents<{ permissionId: bigint }>(tx);\n * console.log(`Permission ID: ${events.permissionId}`);\n *\n * // Legacy: Raw hash without event parsing (returns receipt)\n * const receipt = await vana.waitForTransactionEvents(\"0x123...\");\n * ```\n *\n * @see For understanding transaction flows, visit https://docs.vana.org/docs/transactions\n */\n public async waitForTransactionEvents<C extends Contract, F extends Fn<C>>(\n transaction: TransactionResult<C, F>,\n options?: TransactionWaitOptions,\n ): Promise<TypedTransactionResult<C, F>> {\n // Import the POJO-based parser\n const { parseTransaction } = await import(\"./utils/parseTransactionPojo\");\n\n // Wait for the transaction to be mined\n const receipt = await this.waitForTransactionReceipt(\n transaction.hash,\n options,\n );\n\n // Parse events using our heuristic-free POJO system\n const result = parseTransaction(transaction, receipt);\n\n // Return the strongly-typed result\n // TypeScript knows exactly what events are possible!\n return result;\n }\n\n /**\n * Enhances a unified relayer response with client-side behavior.\n *\n * @remarks\n * This method wraps a relayer response in an enhanced object that provides\n * a fluent `.wait()` method for handling asynchronous operations. The enhanced\n * response intelligently handles both submitted transactions (via hash) and\n * pending operations (via operationId).\n *\n * @param response - The unified relayer response to enhance\n * @returns EnhancedTransactionResponse if the response can be enhanced, null otherwise\n *\n * @example\n * ```typescript\n * // Enhance a relayer response for fluent waiting\n * const response = await handleRelayerOperation(vana, request);\n * const enhanced = vana.enhanceRelayerResponse(response);\n * if (enhanced) {\n * const result = await enhanced.wait();\n * if (result.expectedEvents?.FileAdded) {\n * console.log('File ID:', result.expectedEvents.FileAdded.fileId);\n * }\n * }\n * ```\n *\n * @example\n * ```typescript\n * // With status updates for pending operations\n * const enhanced = vana.enhanceRelayerResponse(response);\n * if (enhanced) {\n * const result = await enhanced.wait({\n * onStatusUpdate: (status) => {\n * console.log('Operation status:', status.type);\n * },\n * timeout: 60000 // 1 minute timeout\n * });\n * }\n * ```\n *\n * @category Relayer\n * @since 0.2.0\n */\n public async enhanceRelayerResponse(\n response: UnifiedRelayerResponse,\n ): Promise<any> {\n const { enhanceResponse } = await import(\"./client/enhancedResponse\");\n return enhanceResponse(response, this);\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -162,9 +162,22 @@ class BaseECIESUint8 {
|
|
|
162
162
|
if (!this.verifyPrivateKey(privateKey)) {
|
|
163
163
|
throw new import_interface.ECIESError("Invalid private key", "INVALID_KEY");
|
|
164
164
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
165
|
+
if (encrypted.ephemPublicKey.length !== import_constants.CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH) {
|
|
166
|
+
throw new import_interface.ECIESError(
|
|
167
|
+
`Invalid ephemeral public key: expected ${import_constants.CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH} bytes (uncompressed), got ${encrypted.ephemPublicKey.length} bytes`,
|
|
168
|
+
"INVALID_KEY"
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
if (encrypted.ephemPublicKey[0] !== import_constants.CURVE.PREFIX.UNCOMPRESSED) {
|
|
172
|
+
throw new import_interface.ECIESError(
|
|
173
|
+
"Invalid ephemeral public key: must be uncompressed format with 0x04 prefix (eccrypto standard)",
|
|
174
|
+
"INVALID_KEY"
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
if (!this.validatePublicKey(encrypted.ephemPublicKey)) {
|
|
178
|
+
throw new import_interface.ECIESError("Invalid ephemeral public key", "INVALID_KEY");
|
|
179
|
+
}
|
|
180
|
+
const ephemeralPublicKey = encrypted.ephemPublicKey;
|
|
168
181
|
const sharedSecret = this.performECDH(ephemeralPublicKey, privateKey);
|
|
169
182
|
const kdf = this.sha512(sharedSecret);
|
|
170
183
|
const encryptionKey = kdf.slice(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/crypto/ecies/base.ts"],"sourcesContent":["import type { ECIESProvider, ECIESEncrypted } from \"./interface\";\nimport { ECIESError, isECIESEncrypted } from \"./interface\";\nimport { CURVE, CIPHER, KDF } from \"./constants\";\nimport { constantTimeEqual } from \"./utils\";\nimport { concat } from \"viem\";\n\n/**\n * Provides shared ECIES encryption logic across platforms using Uint8Array.\n *\n * @remarks\n * Platform implementations extend this class and provide crypto primitives.\n * The base class handles the ECIES protocol flow while maintaining\n * compatibility with the eccrypto data format.\n *\n * **Implementation details:**\n * - KDF: SHA-512(shared_secret) → encKey (32B) || macKey (32B)\n * - Cipher: AES-256-CBC with random 16-byte IV\n * - MAC: HMAC-SHA256(macKey, iv || ephemPublicKey || ciphertext)\n *\n * @category Cryptography\n */\nexport abstract class BaseECIESUint8 implements ECIESProvider {\n // Cache for validated public keys to avoid repeated validation\n private static readonly validatedKeys = new WeakMap<Uint8Array, boolean>();\n\n /**\n * Generates cryptographically secure random bytes.\n *\n * @param length - Number of random bytes to generate.\n * @returns Random bytes array.\n */\n protected abstract generateRandomBytes(length: number): Uint8Array;\n\n /**\n * Verifies a private key is valid for secp256k1.\n *\n * @param privateKey - Private key to verify (32 bytes).\n * @returns `true` if valid private key.\n */\n protected abstract verifyPrivateKey(privateKey: Uint8Array): boolean;\n\n /**\n * Creates a public key from a private key.\n *\n * @param privateKey - Source private key (32 bytes).\n * @param compressed - Generate compressed (33B) or uncompressed (65B) format.\n * @returns Public key or `null` if creation failed.\n */\n protected abstract createPublicKey(\n privateKey: Uint8Array,\n compressed: boolean,\n ): Uint8Array | null;\n\n /**\n * Validates a public key on the secp256k1 curve.\n *\n * @param publicKey - Public key to validate.\n * @returns `true` if valid public key.\n */\n protected abstract validatePublicKey(publicKey: Uint8Array): boolean;\n\n /**\n * Decompresses a compressed public key.\n *\n * @param publicKey - Compressed public key (33 bytes).\n * @returns Uncompressed public key (65 bytes) or `null` if decompression failed.\n */\n protected abstract decompressPublicKey(\n publicKey: Uint8Array,\n ): Uint8Array | null;\n\n /**\n * Performs ECDH key agreement.\n *\n * @param publicKey - Other party's public key.\n * @param privateKey - Your private key.\n * @returns Raw X coordinate of shared point (32 bytes).\n */\n protected abstract performECDH(\n publicKey: Uint8Array,\n privateKey: Uint8Array,\n ): Uint8Array;\n\n /**\n * Computes SHA-512 hash.\n *\n * @param data - Data to hash.\n * @returns SHA-512 hash (64 bytes).\n */\n protected abstract sha512(data: Uint8Array): Uint8Array;\n\n /**\n * Computes HMAC-SHA256 authentication tag.\n *\n * @param key - HMAC key.\n * @param data - Data to authenticate.\n * @returns HMAC-SHA256 (32 bytes).\n */\n protected abstract hmacSha256(key: Uint8Array, data: Uint8Array): Uint8Array;\n\n /**\n * Encrypts data using AES-256-CBC.\n *\n * @param key - Encryption key (32 bytes).\n * @param iv - Initialization vector (16 bytes).\n * @param plaintext - Data to encrypt.\n * @returns Ciphertext with PKCS#7 padding.\n */\n protected abstract aesEncrypt(\n key: Uint8Array,\n iv: Uint8Array,\n plaintext: Uint8Array,\n ): Promise<Uint8Array>;\n\n /**\n * Decrypts data using AES-256-CBC.\n *\n * @param key - Decryption key (32 bytes).\n * @param iv - Initialization vector (16 bytes).\n * @param ciphertext - Data to decrypt.\n * @returns Plaintext with padding removed.\n */\n protected abstract aesDecrypt(\n key: Uint8Array,\n iv: Uint8Array,\n ciphertext: Uint8Array,\n ): Promise<Uint8Array>;\n\n /**\n * Normalizes a public key to uncompressed format.\n *\n * @param publicKey - Public key in any format.\n * @returns Uncompressed public key (65 bytes).\n * @throws {ECIESError} If key format is invalid.\n */\n protected normalizePublicKey(publicKey: Uint8Array): Uint8Array {\n // Check cache first\n if (BaseECIESUint8.validatedKeys.has(publicKey)) {\n return publicKey;\n }\n\n if (publicKey.length === CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH) {\n if (publicKey[0] !== CURVE.PREFIX.UNCOMPRESSED) {\n throw new ECIESError(\n \"Invalid uncompressed public key prefix\",\n \"INVALID_KEY\",\n );\n }\n // Validate and cache\n if (!this.validatePublicKey(publicKey)) {\n throw new ECIESError(\"Invalid public key\", \"INVALID_KEY\");\n }\n BaseECIESUint8.validatedKeys.set(publicKey, true);\n return publicKey;\n }\n\n if (publicKey.length === CURVE.COMPRESSED_PUBLIC_KEY_LENGTH) {\n const decompressed = this.decompressPublicKey(publicKey);\n if (!decompressed) {\n throw new ECIESError(\"Failed to decompress public key\", \"INVALID_KEY\");\n }\n // Cache the decompressed key\n BaseECIESUint8.validatedKeys.set(decompressed, true);\n return decompressed;\n }\n\n throw new ECIESError(\n `Invalid public key length: ${publicKey.length}`,\n \"INVALID_KEY\",\n );\n }\n\n /**\n * Normalizes a public key to uncompressed format (65 bytes with 0x04 prefix).\n * Must be implemented by derived classes to handle platform-specific operations.\n *\n * @param publicKey - The public key to normalize\n * @returns The normalized uncompressed public key\n */\n public abstract normalizeToUncompressed(publicKey: Uint8Array): Uint8Array;\n\n /**\n * Encrypts data using ECIES.\n *\n * @param publicKey - The recipient's public key (compressed or uncompressed)\n * @param message - The data to encrypt\n * @returns Promise resolving to encrypted data structure\n */\n async encrypt(\n publicKey: Uint8Array,\n message: Uint8Array,\n ): Promise<ECIESEncrypted> {\n try {\n // Validate inputs\n if (!(publicKey instanceof Uint8Array)) {\n throw new ECIESError(\"Public key must be a Uint8Array\", \"INVALID_KEY\");\n }\n if (!(message instanceof Uint8Array)) {\n throw new ECIESError(\n \"Message must be a Uint8Array\",\n \"ENCRYPTION_FAILED\",\n );\n }\n if (publicKey.length === 0) {\n throw new ECIESError(\"Public key cannot be empty\", \"INVALID_KEY\");\n }\n\n // Normalize public key to uncompressed format\n const pubKey = this.normalizePublicKey(publicKey);\n\n // Generate ephemeral key pair\n let ephemeralPrivateKey: Uint8Array;\n do {\n ephemeralPrivateKey = this.generateRandomBytes(\n CURVE.PRIVATE_KEY_LENGTH,\n );\n } while (!this.verifyPrivateKey(ephemeralPrivateKey));\n\n const ephemeralPublicKey = this.createPublicKey(\n ephemeralPrivateKey,\n false,\n );\n if (!ephemeralPublicKey) {\n throw new ECIESError(\n \"Failed to generate ephemeral public key\",\n \"ENCRYPTION_FAILED\",\n );\n }\n\n // Perform ECDH to get shared secret (raw X coordinate)\n const sharedSecret = this.performECDH(pubKey, ephemeralPrivateKey);\n\n // Derive keys using SHA-512 (eccrypto-compatible KDF)\n const kdf = this.sha512(sharedSecret);\n const encryptionKey = kdf.slice(\n KDF.ENCRYPTION_KEY_OFFSET,\n KDF.ENCRYPTION_KEY_OFFSET + KDF.ENCRYPTION_KEY_LENGTH,\n );\n const macKey = kdf.slice(\n KDF.MAC_KEY_OFFSET,\n KDF.MAC_KEY_OFFSET + KDF.MAC_KEY_LENGTH,\n );\n\n // Generate random IV and encrypt\n const iv = this.generateRandomBytes(CIPHER.IV_LENGTH);\n const ciphertext = await this.aesEncrypt(encryptionKey, iv, message);\n\n // Calculate MAC (Encrypt-then-MAC)\n const macData = concat([iv, ephemeralPublicKey, ciphertext]);\n const mac = this.hmacSha256(macKey, macData);\n\n // Clear sensitive data\n this.clearBuffer(ephemeralPrivateKey);\n this.clearBuffer(sharedSecret);\n this.clearBuffer(kdf);\n\n return {\n iv,\n ephemPublicKey: ephemeralPublicKey,\n ciphertext,\n mac,\n };\n } catch (error) {\n if (error instanceof ECIESError) throw error;\n throw new ECIESError(\n `Encryption failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n \"ENCRYPTION_FAILED\",\n error instanceof Error ? error : undefined,\n );\n }\n }\n\n /**\n * Decrypts ECIES encrypted data.\n *\n * @param privateKey - The recipient's private key (32 bytes)\n * @param encrypted - The encrypted data structure from encrypt()\n * @returns Promise resolving to the original plaintext\n */\n async decrypt(\n privateKey: Uint8Array,\n encrypted: ECIESEncrypted,\n ): Promise<Uint8Array> {\n try {\n // Validate inputs\n if (!(privateKey instanceof Uint8Array)) {\n throw new ECIESError(\"Private key must be a Uint8Array\", \"INVALID_KEY\");\n }\n if (!isECIESEncrypted(encrypted)) {\n throw new ECIESError(\n \"Invalid encrypted data structure\",\n \"DECRYPTION_FAILED\",\n );\n }\n if (privateKey.length !== CURVE.PRIVATE_KEY_LENGTH) {\n throw new ECIESError(\n `Invalid private key length: ${privateKey.length}`,\n \"INVALID_KEY\",\n );\n }\n if (!this.verifyPrivateKey(privateKey)) {\n throw new ECIESError(\"Invalid private key\", \"INVALID_KEY\");\n }\n\n // Normalize ephemeral public key to uncompressed format\n const ephemeralPublicKey = this.normalizePublicKey(\n encrypted.ephemPublicKey,\n );\n\n // Perform ECDH to recover shared secret\n const sharedSecret = this.performECDH(ephemeralPublicKey, privateKey);\n\n // Derive keys using SHA-512 (eccrypto-compatible KDF)\n const kdf = this.sha512(sharedSecret);\n const encryptionKey = kdf.slice(\n KDF.ENCRYPTION_KEY_OFFSET,\n KDF.ENCRYPTION_KEY_OFFSET + KDF.ENCRYPTION_KEY_LENGTH,\n );\n const macKey = kdf.slice(\n KDF.MAC_KEY_OFFSET,\n KDF.MAC_KEY_OFFSET + KDF.MAC_KEY_LENGTH,\n );\n\n // Verify MAC before decryption (Encrypt-then-MAC)\n const macData = concat([\n encrypted.iv,\n encrypted.ephemPublicKey,\n encrypted.ciphertext,\n ]);\n const expectedMac = this.hmacSha256(macKey, macData);\n\n if (!constantTimeEqual(encrypted.mac, expectedMac)) {\n throw new ECIESError(\"MAC verification failed\", \"MAC_MISMATCH\");\n }\n\n // Decrypt the ciphertext\n const decrypted = await this.aesDecrypt(\n encryptionKey,\n encrypted.iv,\n encrypted.ciphertext,\n );\n\n // Clear sensitive data\n this.clearBuffer(sharedSecret);\n this.clearBuffer(kdf);\n\n return decrypted;\n } catch (error) {\n if (error instanceof ECIESError) throw error;\n throw new ECIESError(\n `Decryption failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n \"DECRYPTION_FAILED\",\n error instanceof Error ? error : undefined,\n );\n }\n }\n\n /**\n * Clears sensitive data from memory using multi-pass overwrite.\n *\n * @remarks\n * Uses multiple passes with different patterns to make it harder\n * for JIT compilers to optimize away the operation. While not\n * guaranteed in JavaScript, this is a best-effort approach to\n * clear sensitive data from memory.\n *\n * @param buffer - The buffer to clear\n */\n protected clearBuffer(buffer: Uint8Array): void {\n if (buffer && buffer.length > 0) {\n // Multi-pass overwrite to resist compiler optimization\n buffer.fill(0x00); // Fill with zeros\n buffer.fill(0xff); // Fill with ones\n buffer.fill(0xaa); // Fill with alternating pattern\n buffer.fill(0x00); // Final zero fill\n\n // Additional pattern write to further discourage optimization\n for (let i = 0; i < buffer.length; i++) {\n buffer[i] = (i & 0xff) ^ 0x5a; // XOR with pattern\n }\n buffer.fill(0x00); // Final clear\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/crypto/ecies/base.ts"],"sourcesContent":["import type { ECIESProvider, ECIESEncrypted } from \"./interface\";\nimport { ECIESError, isECIESEncrypted } from \"./interface\";\nimport { CURVE, CIPHER, KDF } from \"./constants\";\nimport { constantTimeEqual } from \"./utils\";\nimport { concat } from \"viem\";\n\n/**\n * Provides shared ECIES encryption logic across platforms using Uint8Array.\n *\n * @remarks\n * Platform implementations extend this class and provide crypto primitives.\n * The base class handles the ECIES protocol flow while maintaining\n * compatibility with the eccrypto data format.\n *\n * **Implementation details:**\n * - KDF: SHA-512(shared_secret) → encKey (32B) || macKey (32B)\n * - Cipher: AES-256-CBC with random 16-byte IV\n * - MAC: HMAC-SHA256(macKey, iv || ephemPublicKey || ciphertext)\n *\n * @category Cryptography\n */\nexport abstract class BaseECIESUint8 implements ECIESProvider {\n // Cache for validated public keys to avoid repeated validation\n private static readonly validatedKeys = new WeakMap<Uint8Array, boolean>();\n\n /**\n * Generates cryptographically secure random bytes.\n *\n * @param length - Number of random bytes to generate.\n * @returns Random bytes array.\n */\n protected abstract generateRandomBytes(length: number): Uint8Array;\n\n /**\n * Verifies a private key is valid for secp256k1.\n *\n * @param privateKey - Private key to verify (32 bytes).\n * @returns `true` if valid private key.\n */\n protected abstract verifyPrivateKey(privateKey: Uint8Array): boolean;\n\n /**\n * Creates a public key from a private key.\n *\n * @param privateKey - Source private key (32 bytes).\n * @param compressed - Generate compressed (33B) or uncompressed (65B) format.\n * @returns Public key or `null` if creation failed.\n */\n protected abstract createPublicKey(\n privateKey: Uint8Array,\n compressed: boolean,\n ): Uint8Array | null;\n\n /**\n * Validates a public key on the secp256k1 curve.\n *\n * @param publicKey - Public key to validate.\n * @returns `true` if valid public key.\n */\n protected abstract validatePublicKey(publicKey: Uint8Array): boolean;\n\n /**\n * Decompresses a compressed public key.\n *\n * @param publicKey - Compressed public key (33 bytes).\n * @returns Uncompressed public key (65 bytes) or `null` if decompression failed.\n */\n protected abstract decompressPublicKey(\n publicKey: Uint8Array,\n ): Uint8Array | null;\n\n /**\n * Performs ECDH key agreement.\n *\n * @param publicKey - Other party's public key.\n * @param privateKey - Your private key.\n * @returns Raw X coordinate of shared point (32 bytes).\n */\n protected abstract performECDH(\n publicKey: Uint8Array,\n privateKey: Uint8Array,\n ): Uint8Array;\n\n /**\n * Computes SHA-512 hash.\n *\n * @param data - Data to hash.\n * @returns SHA-512 hash (64 bytes).\n */\n protected abstract sha512(data: Uint8Array): Uint8Array;\n\n /**\n * Computes HMAC-SHA256 authentication tag.\n *\n * @param key - HMAC key.\n * @param data - Data to authenticate.\n * @returns HMAC-SHA256 (32 bytes).\n */\n protected abstract hmacSha256(key: Uint8Array, data: Uint8Array): Uint8Array;\n\n /**\n * Encrypts data using AES-256-CBC.\n *\n * @param key - Encryption key (32 bytes).\n * @param iv - Initialization vector (16 bytes).\n * @param plaintext - Data to encrypt.\n * @returns Ciphertext with PKCS#7 padding.\n */\n protected abstract aesEncrypt(\n key: Uint8Array,\n iv: Uint8Array,\n plaintext: Uint8Array,\n ): Promise<Uint8Array>;\n\n /**\n * Decrypts data using AES-256-CBC.\n *\n * @param key - Decryption key (32 bytes).\n * @param iv - Initialization vector (16 bytes).\n * @param ciphertext - Data to decrypt.\n * @returns Plaintext with padding removed.\n */\n protected abstract aesDecrypt(\n key: Uint8Array,\n iv: Uint8Array,\n ciphertext: Uint8Array,\n ): Promise<Uint8Array>;\n\n /**\n * Normalizes a public key to uncompressed format.\n *\n * @param publicKey - Public key in any format.\n * @returns Uncompressed public key (65 bytes).\n * @throws {ECIESError} If key format is invalid.\n */\n protected normalizePublicKey(publicKey: Uint8Array): Uint8Array {\n // Check cache first\n if (BaseECIESUint8.validatedKeys.has(publicKey)) {\n return publicKey;\n }\n\n if (publicKey.length === CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH) {\n if (publicKey[0] !== CURVE.PREFIX.UNCOMPRESSED) {\n throw new ECIESError(\n \"Invalid uncompressed public key prefix\",\n \"INVALID_KEY\",\n );\n }\n // Validate and cache\n if (!this.validatePublicKey(publicKey)) {\n throw new ECIESError(\"Invalid public key\", \"INVALID_KEY\");\n }\n BaseECIESUint8.validatedKeys.set(publicKey, true);\n return publicKey;\n }\n\n if (publicKey.length === CURVE.COMPRESSED_PUBLIC_KEY_LENGTH) {\n const decompressed = this.decompressPublicKey(publicKey);\n if (!decompressed) {\n throw new ECIESError(\"Failed to decompress public key\", \"INVALID_KEY\");\n }\n // Cache the decompressed key\n BaseECIESUint8.validatedKeys.set(decompressed, true);\n return decompressed;\n }\n\n throw new ECIESError(\n `Invalid public key length: ${publicKey.length}`,\n \"INVALID_KEY\",\n );\n }\n\n /**\n * Normalizes a public key to uncompressed format (65 bytes with 0x04 prefix).\n * Must be implemented by derived classes to handle platform-specific operations.\n *\n * @param publicKey - The public key to normalize\n * @returns The normalized uncompressed public key\n */\n public abstract normalizeToUncompressed(publicKey: Uint8Array): Uint8Array;\n\n /**\n * Encrypts data using ECIES.\n *\n * @param publicKey - The recipient's public key (compressed or uncompressed)\n * @param message - The data to encrypt\n * @returns Promise resolving to encrypted data structure\n */\n async encrypt(\n publicKey: Uint8Array,\n message: Uint8Array,\n ): Promise<ECIESEncrypted> {\n try {\n // Validate inputs\n if (!(publicKey instanceof Uint8Array)) {\n throw new ECIESError(\"Public key must be a Uint8Array\", \"INVALID_KEY\");\n }\n if (!(message instanceof Uint8Array)) {\n throw new ECIESError(\n \"Message must be a Uint8Array\",\n \"ENCRYPTION_FAILED\",\n );\n }\n if (publicKey.length === 0) {\n throw new ECIESError(\"Public key cannot be empty\", \"INVALID_KEY\");\n }\n\n // Normalize public key to uncompressed format\n const pubKey = this.normalizePublicKey(publicKey);\n\n // Generate ephemeral key pair\n let ephemeralPrivateKey: Uint8Array;\n do {\n ephemeralPrivateKey = this.generateRandomBytes(\n CURVE.PRIVATE_KEY_LENGTH,\n );\n } while (!this.verifyPrivateKey(ephemeralPrivateKey));\n\n const ephemeralPublicKey = this.createPublicKey(\n ephemeralPrivateKey,\n false,\n );\n if (!ephemeralPublicKey) {\n throw new ECIESError(\n \"Failed to generate ephemeral public key\",\n \"ENCRYPTION_FAILED\",\n );\n }\n\n // Perform ECDH to get shared secret (raw X coordinate)\n const sharedSecret = this.performECDH(pubKey, ephemeralPrivateKey);\n\n // Derive keys using SHA-512 (eccrypto-compatible KDF)\n const kdf = this.sha512(sharedSecret);\n const encryptionKey = kdf.slice(\n KDF.ENCRYPTION_KEY_OFFSET,\n KDF.ENCRYPTION_KEY_OFFSET + KDF.ENCRYPTION_KEY_LENGTH,\n );\n const macKey = kdf.slice(\n KDF.MAC_KEY_OFFSET,\n KDF.MAC_KEY_OFFSET + KDF.MAC_KEY_LENGTH,\n );\n\n // Generate random IV and encrypt\n const iv = this.generateRandomBytes(CIPHER.IV_LENGTH);\n const ciphertext = await this.aesEncrypt(encryptionKey, iv, message);\n\n // Calculate MAC (Encrypt-then-MAC)\n const macData = concat([iv, ephemeralPublicKey, ciphertext]);\n const mac = this.hmacSha256(macKey, macData);\n\n // Clear sensitive data\n this.clearBuffer(ephemeralPrivateKey);\n this.clearBuffer(sharedSecret);\n this.clearBuffer(kdf);\n\n return {\n iv,\n ephemPublicKey: ephemeralPublicKey,\n ciphertext,\n mac,\n };\n } catch (error) {\n if (error instanceof ECIESError) throw error;\n throw new ECIESError(\n `Encryption failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n \"ENCRYPTION_FAILED\",\n error instanceof Error ? error : undefined,\n );\n }\n }\n\n /**\n * Decrypts ECIES encrypted data.\n *\n * @param privateKey - The recipient's private key (32 bytes)\n * @param encrypted - The encrypted data structure from encrypt()\n * @returns Promise resolving to the original plaintext\n */\n async decrypt(\n privateKey: Uint8Array,\n encrypted: ECIESEncrypted,\n ): Promise<Uint8Array> {\n try {\n // Validate inputs\n if (!(privateKey instanceof Uint8Array)) {\n throw new ECIESError(\"Private key must be a Uint8Array\", \"INVALID_KEY\");\n }\n if (!isECIESEncrypted(encrypted)) {\n throw new ECIESError(\n \"Invalid encrypted data structure\",\n \"DECRYPTION_FAILED\",\n );\n }\n if (privateKey.length !== CURVE.PRIVATE_KEY_LENGTH) {\n throw new ECIESError(\n `Invalid private key length: ${privateKey.length}`,\n \"INVALID_KEY\",\n );\n }\n if (!this.verifyPrivateKey(privateKey)) {\n throw new ECIESError(\"Invalid private key\", \"INVALID_KEY\");\n }\n\n // Strict validation: ephemeral keys must be 65-byte uncompressed (eccrypto standard)\n if (\n encrypted.ephemPublicKey.length !== CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH\n ) {\n throw new ECIESError(\n `Invalid ephemeral public key: expected ${CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH} bytes (uncompressed), got ${encrypted.ephemPublicKey.length} bytes`,\n \"INVALID_KEY\",\n );\n }\n if (encrypted.ephemPublicKey[0] !== CURVE.PREFIX.UNCOMPRESSED) {\n throw new ECIESError(\n \"Invalid ephemeral public key: must be uncompressed format with 0x04 prefix (eccrypto standard)\",\n \"INVALID_KEY\",\n );\n }\n if (!this.validatePublicKey(encrypted.ephemPublicKey)) {\n throw new ECIESError(\"Invalid ephemeral public key\", \"INVALID_KEY\");\n }\n const ephemeralPublicKey = encrypted.ephemPublicKey;\n\n // Perform ECDH to recover shared secret\n const sharedSecret = this.performECDH(ephemeralPublicKey, privateKey);\n\n // Derive keys using SHA-512 (eccrypto-compatible KDF)\n const kdf = this.sha512(sharedSecret);\n const encryptionKey = kdf.slice(\n KDF.ENCRYPTION_KEY_OFFSET,\n KDF.ENCRYPTION_KEY_OFFSET + KDF.ENCRYPTION_KEY_LENGTH,\n );\n const macKey = kdf.slice(\n KDF.MAC_KEY_OFFSET,\n KDF.MAC_KEY_OFFSET + KDF.MAC_KEY_LENGTH,\n );\n\n // Verify MAC before decryption (Encrypt-then-MAC)\n const macData = concat([\n encrypted.iv,\n encrypted.ephemPublicKey,\n encrypted.ciphertext,\n ]);\n const expectedMac = this.hmacSha256(macKey, macData);\n\n if (!constantTimeEqual(encrypted.mac, expectedMac)) {\n throw new ECIESError(\"MAC verification failed\", \"MAC_MISMATCH\");\n }\n\n // Decrypt the ciphertext\n const decrypted = await this.aesDecrypt(\n encryptionKey,\n encrypted.iv,\n encrypted.ciphertext,\n );\n\n // Clear sensitive data\n this.clearBuffer(sharedSecret);\n this.clearBuffer(kdf);\n\n return decrypted;\n } catch (error) {\n if (error instanceof ECIESError) throw error;\n throw new ECIESError(\n `Decryption failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n \"DECRYPTION_FAILED\",\n error instanceof Error ? error : undefined,\n );\n }\n }\n\n /**\n * Clears sensitive data from memory using multi-pass overwrite.\n *\n * @remarks\n * Uses multiple passes with different patterns to make it harder\n * for JIT compilers to optimize away the operation. While not\n * guaranteed in JavaScript, this is a best-effort approach to\n * clear sensitive data from memory.\n *\n * @param buffer - The buffer to clear\n */\n protected clearBuffer(buffer: Uint8Array): void {\n if (buffer && buffer.length > 0) {\n // Multi-pass overwrite to resist compiler optimization\n buffer.fill(0x00); // Fill with zeros\n buffer.fill(0xff); // Fill with ones\n buffer.fill(0xaa); // Fill with alternating pattern\n buffer.fill(0x00); // Final zero fill\n\n // Additional pattern write to further discourage optimization\n for (let i = 0; i < buffer.length; i++) {\n buffer[i] = (i & 0xff) ^ 0x5a; // XOR with pattern\n }\n buffer.fill(0x00); // Final clear\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -139,9 +139,22 @@ class BaseECIESUint8 {
|
|
|
139
139
|
if (!this.verifyPrivateKey(privateKey)) {
|
|
140
140
|
throw new ECIESError("Invalid private key", "INVALID_KEY");
|
|
141
141
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
142
|
+
if (encrypted.ephemPublicKey.length !== CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH) {
|
|
143
|
+
throw new ECIESError(
|
|
144
|
+
`Invalid ephemeral public key: expected ${CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH} bytes (uncompressed), got ${encrypted.ephemPublicKey.length} bytes`,
|
|
145
|
+
"INVALID_KEY"
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
if (encrypted.ephemPublicKey[0] !== CURVE.PREFIX.UNCOMPRESSED) {
|
|
149
|
+
throw new ECIESError(
|
|
150
|
+
"Invalid ephemeral public key: must be uncompressed format with 0x04 prefix (eccrypto standard)",
|
|
151
|
+
"INVALID_KEY"
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
if (!this.validatePublicKey(encrypted.ephemPublicKey)) {
|
|
155
|
+
throw new ECIESError("Invalid ephemeral public key", "INVALID_KEY");
|
|
156
|
+
}
|
|
157
|
+
const ephemeralPublicKey = encrypted.ephemPublicKey;
|
|
145
158
|
const sharedSecret = this.performECDH(ephemeralPublicKey, privateKey);
|
|
146
159
|
const kdf = this.sha512(sharedSecret);
|
|
147
160
|
const encryptionKey = kdf.slice(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/crypto/ecies/base.ts"],"sourcesContent":["import type { ECIESProvider, ECIESEncrypted } from \"./interface\";\nimport { ECIESError, isECIESEncrypted } from \"./interface\";\nimport { CURVE, CIPHER, KDF } from \"./constants\";\nimport { constantTimeEqual } from \"./utils\";\nimport { concat } from \"viem\";\n\n/**\n * Provides shared ECIES encryption logic across platforms using Uint8Array.\n *\n * @remarks\n * Platform implementations extend this class and provide crypto primitives.\n * The base class handles the ECIES protocol flow while maintaining\n * compatibility with the eccrypto data format.\n *\n * **Implementation details:**\n * - KDF: SHA-512(shared_secret) → encKey (32B) || macKey (32B)\n * - Cipher: AES-256-CBC with random 16-byte IV\n * - MAC: HMAC-SHA256(macKey, iv || ephemPublicKey || ciphertext)\n *\n * @category Cryptography\n */\nexport abstract class BaseECIESUint8 implements ECIESProvider {\n // Cache for validated public keys to avoid repeated validation\n private static readonly validatedKeys = new WeakMap<Uint8Array, boolean>();\n\n /**\n * Generates cryptographically secure random bytes.\n *\n * @param length - Number of random bytes to generate.\n * @returns Random bytes array.\n */\n protected abstract generateRandomBytes(length: number): Uint8Array;\n\n /**\n * Verifies a private key is valid for secp256k1.\n *\n * @param privateKey - Private key to verify (32 bytes).\n * @returns `true` if valid private key.\n */\n protected abstract verifyPrivateKey(privateKey: Uint8Array): boolean;\n\n /**\n * Creates a public key from a private key.\n *\n * @param privateKey - Source private key (32 bytes).\n * @param compressed - Generate compressed (33B) or uncompressed (65B) format.\n * @returns Public key or `null` if creation failed.\n */\n protected abstract createPublicKey(\n privateKey: Uint8Array,\n compressed: boolean,\n ): Uint8Array | null;\n\n /**\n * Validates a public key on the secp256k1 curve.\n *\n * @param publicKey - Public key to validate.\n * @returns `true` if valid public key.\n */\n protected abstract validatePublicKey(publicKey: Uint8Array): boolean;\n\n /**\n * Decompresses a compressed public key.\n *\n * @param publicKey - Compressed public key (33 bytes).\n * @returns Uncompressed public key (65 bytes) or `null` if decompression failed.\n */\n protected abstract decompressPublicKey(\n publicKey: Uint8Array,\n ): Uint8Array | null;\n\n /**\n * Performs ECDH key agreement.\n *\n * @param publicKey - Other party's public key.\n * @param privateKey - Your private key.\n * @returns Raw X coordinate of shared point (32 bytes).\n */\n protected abstract performECDH(\n publicKey: Uint8Array,\n privateKey: Uint8Array,\n ): Uint8Array;\n\n /**\n * Computes SHA-512 hash.\n *\n * @param data - Data to hash.\n * @returns SHA-512 hash (64 bytes).\n */\n protected abstract sha512(data: Uint8Array): Uint8Array;\n\n /**\n * Computes HMAC-SHA256 authentication tag.\n *\n * @param key - HMAC key.\n * @param data - Data to authenticate.\n * @returns HMAC-SHA256 (32 bytes).\n */\n protected abstract hmacSha256(key: Uint8Array, data: Uint8Array): Uint8Array;\n\n /**\n * Encrypts data using AES-256-CBC.\n *\n * @param key - Encryption key (32 bytes).\n * @param iv - Initialization vector (16 bytes).\n * @param plaintext - Data to encrypt.\n * @returns Ciphertext with PKCS#7 padding.\n */\n protected abstract aesEncrypt(\n key: Uint8Array,\n iv: Uint8Array,\n plaintext: Uint8Array,\n ): Promise<Uint8Array>;\n\n /**\n * Decrypts data using AES-256-CBC.\n *\n * @param key - Decryption key (32 bytes).\n * @param iv - Initialization vector (16 bytes).\n * @param ciphertext - Data to decrypt.\n * @returns Plaintext with padding removed.\n */\n protected abstract aesDecrypt(\n key: Uint8Array,\n iv: Uint8Array,\n ciphertext: Uint8Array,\n ): Promise<Uint8Array>;\n\n /**\n * Normalizes a public key to uncompressed format.\n *\n * @param publicKey - Public key in any format.\n * @returns Uncompressed public key (65 bytes).\n * @throws {ECIESError} If key format is invalid.\n */\n protected normalizePublicKey(publicKey: Uint8Array): Uint8Array {\n // Check cache first\n if (BaseECIESUint8.validatedKeys.has(publicKey)) {\n return publicKey;\n }\n\n if (publicKey.length === CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH) {\n if (publicKey[0] !== CURVE.PREFIX.UNCOMPRESSED) {\n throw new ECIESError(\n \"Invalid uncompressed public key prefix\",\n \"INVALID_KEY\",\n );\n }\n // Validate and cache\n if (!this.validatePublicKey(publicKey)) {\n throw new ECIESError(\"Invalid public key\", \"INVALID_KEY\");\n }\n BaseECIESUint8.validatedKeys.set(publicKey, true);\n return publicKey;\n }\n\n if (publicKey.length === CURVE.COMPRESSED_PUBLIC_KEY_LENGTH) {\n const decompressed = this.decompressPublicKey(publicKey);\n if (!decompressed) {\n throw new ECIESError(\"Failed to decompress public key\", \"INVALID_KEY\");\n }\n // Cache the decompressed key\n BaseECIESUint8.validatedKeys.set(decompressed, true);\n return decompressed;\n }\n\n throw new ECIESError(\n `Invalid public key length: ${publicKey.length}`,\n \"INVALID_KEY\",\n );\n }\n\n /**\n * Normalizes a public key to uncompressed format (65 bytes with 0x04 prefix).\n * Must be implemented by derived classes to handle platform-specific operations.\n *\n * @param publicKey - The public key to normalize\n * @returns The normalized uncompressed public key\n */\n public abstract normalizeToUncompressed(publicKey: Uint8Array): Uint8Array;\n\n /**\n * Encrypts data using ECIES.\n *\n * @param publicKey - The recipient's public key (compressed or uncompressed)\n * @param message - The data to encrypt\n * @returns Promise resolving to encrypted data structure\n */\n async encrypt(\n publicKey: Uint8Array,\n message: Uint8Array,\n ): Promise<ECIESEncrypted> {\n try {\n // Validate inputs\n if (!(publicKey instanceof Uint8Array)) {\n throw new ECIESError(\"Public key must be a Uint8Array\", \"INVALID_KEY\");\n }\n if (!(message instanceof Uint8Array)) {\n throw new ECIESError(\n \"Message must be a Uint8Array\",\n \"ENCRYPTION_FAILED\",\n );\n }\n if (publicKey.length === 0) {\n throw new ECIESError(\"Public key cannot be empty\", \"INVALID_KEY\");\n }\n\n // Normalize public key to uncompressed format\n const pubKey = this.normalizePublicKey(publicKey);\n\n // Generate ephemeral key pair\n let ephemeralPrivateKey: Uint8Array;\n do {\n ephemeralPrivateKey = this.generateRandomBytes(\n CURVE.PRIVATE_KEY_LENGTH,\n );\n } while (!this.verifyPrivateKey(ephemeralPrivateKey));\n\n const ephemeralPublicKey = this.createPublicKey(\n ephemeralPrivateKey,\n false,\n );\n if (!ephemeralPublicKey) {\n throw new ECIESError(\n \"Failed to generate ephemeral public key\",\n \"ENCRYPTION_FAILED\",\n );\n }\n\n // Perform ECDH to get shared secret (raw X coordinate)\n const sharedSecret = this.performECDH(pubKey, ephemeralPrivateKey);\n\n // Derive keys using SHA-512 (eccrypto-compatible KDF)\n const kdf = this.sha512(sharedSecret);\n const encryptionKey = kdf.slice(\n KDF.ENCRYPTION_KEY_OFFSET,\n KDF.ENCRYPTION_KEY_OFFSET + KDF.ENCRYPTION_KEY_LENGTH,\n );\n const macKey = kdf.slice(\n KDF.MAC_KEY_OFFSET,\n KDF.MAC_KEY_OFFSET + KDF.MAC_KEY_LENGTH,\n );\n\n // Generate random IV and encrypt\n const iv = this.generateRandomBytes(CIPHER.IV_LENGTH);\n const ciphertext = await this.aesEncrypt(encryptionKey, iv, message);\n\n // Calculate MAC (Encrypt-then-MAC)\n const macData = concat([iv, ephemeralPublicKey, ciphertext]);\n const mac = this.hmacSha256(macKey, macData);\n\n // Clear sensitive data\n this.clearBuffer(ephemeralPrivateKey);\n this.clearBuffer(sharedSecret);\n this.clearBuffer(kdf);\n\n return {\n iv,\n ephemPublicKey: ephemeralPublicKey,\n ciphertext,\n mac,\n };\n } catch (error) {\n if (error instanceof ECIESError) throw error;\n throw new ECIESError(\n `Encryption failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n \"ENCRYPTION_FAILED\",\n error instanceof Error ? error : undefined,\n );\n }\n }\n\n /**\n * Decrypts ECIES encrypted data.\n *\n * @param privateKey - The recipient's private key (32 bytes)\n * @param encrypted - The encrypted data structure from encrypt()\n * @returns Promise resolving to the original plaintext\n */\n async decrypt(\n privateKey: Uint8Array,\n encrypted: ECIESEncrypted,\n ): Promise<Uint8Array> {\n try {\n // Validate inputs\n if (!(privateKey instanceof Uint8Array)) {\n throw new ECIESError(\"Private key must be a Uint8Array\", \"INVALID_KEY\");\n }\n if (!isECIESEncrypted(encrypted)) {\n throw new ECIESError(\n \"Invalid encrypted data structure\",\n \"DECRYPTION_FAILED\",\n );\n }\n if (privateKey.length !== CURVE.PRIVATE_KEY_LENGTH) {\n throw new ECIESError(\n `Invalid private key length: ${privateKey.length}`,\n \"INVALID_KEY\",\n );\n }\n if (!this.verifyPrivateKey(privateKey)) {\n throw new ECIESError(\"Invalid private key\", \"INVALID_KEY\");\n }\n\n // Normalize ephemeral public key to uncompressed format\n const ephemeralPublicKey = this.normalizePublicKey(\n encrypted.ephemPublicKey,\n );\n\n // Perform ECDH to recover shared secret\n const sharedSecret = this.performECDH(ephemeralPublicKey, privateKey);\n\n // Derive keys using SHA-512 (eccrypto-compatible KDF)\n const kdf = this.sha512(sharedSecret);\n const encryptionKey = kdf.slice(\n KDF.ENCRYPTION_KEY_OFFSET,\n KDF.ENCRYPTION_KEY_OFFSET + KDF.ENCRYPTION_KEY_LENGTH,\n );\n const macKey = kdf.slice(\n KDF.MAC_KEY_OFFSET,\n KDF.MAC_KEY_OFFSET + KDF.MAC_KEY_LENGTH,\n );\n\n // Verify MAC before decryption (Encrypt-then-MAC)\n const macData = concat([\n encrypted.iv,\n encrypted.ephemPublicKey,\n encrypted.ciphertext,\n ]);\n const expectedMac = this.hmacSha256(macKey, macData);\n\n if (!constantTimeEqual(encrypted.mac, expectedMac)) {\n throw new ECIESError(\"MAC verification failed\", \"MAC_MISMATCH\");\n }\n\n // Decrypt the ciphertext\n const decrypted = await this.aesDecrypt(\n encryptionKey,\n encrypted.iv,\n encrypted.ciphertext,\n );\n\n // Clear sensitive data\n this.clearBuffer(sharedSecret);\n this.clearBuffer(kdf);\n\n return decrypted;\n } catch (error) {\n if (error instanceof ECIESError) throw error;\n throw new ECIESError(\n `Decryption failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n \"DECRYPTION_FAILED\",\n error instanceof Error ? error : undefined,\n );\n }\n }\n\n /**\n * Clears sensitive data from memory using multi-pass overwrite.\n *\n * @remarks\n * Uses multiple passes with different patterns to make it harder\n * for JIT compilers to optimize away the operation. While not\n * guaranteed in JavaScript, this is a best-effort approach to\n * clear sensitive data from memory.\n *\n * @param buffer - The buffer to clear\n */\n protected clearBuffer(buffer: Uint8Array): void {\n if (buffer && buffer.length > 0) {\n // Multi-pass overwrite to resist compiler optimization\n buffer.fill(0x00); // Fill with zeros\n buffer.fill(0xff); // Fill with ones\n buffer.fill(0xaa); // Fill with alternating pattern\n buffer.fill(0x00); // Final zero fill\n\n // Additional pattern write to further discourage optimization\n for (let i = 0; i < buffer.length; i++) {\n buffer[i] = (i & 0xff) ^ 0x5a; // XOR with pattern\n }\n buffer.fill(0x00); // Final clear\n }\n }\n}\n"],"mappings":"AACA,SAAS,YAAY,wBAAwB;AAC7C,SAAS,OAAO,QAAQ,WAAW;AACnC,SAAS,yBAAyB;AAClC,SAAS,cAAc;AAiBhB,MAAe,eAAwC;AAAA;AAAA,EAE5D,OAAwB,gBAAgB,oBAAI,QAA6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgH/D,mBAAmB,WAAmC;AAE9D,QAAI,eAAe,cAAc,IAAI,SAAS,GAAG;AAC/C,aAAO;AAAA,IACT;AAEA,QAAI,UAAU,WAAW,MAAM,gCAAgC;AAC7D,UAAI,UAAU,CAAC,MAAM,MAAM,OAAO,cAAc;AAC9C,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAEA,UAAI,CAAC,KAAK,kBAAkB,SAAS,GAAG;AACtC,cAAM,IAAI,WAAW,sBAAsB,aAAa;AAAA,MAC1D;AACA,qBAAe,cAAc,IAAI,WAAW,IAAI;AAChD,aAAO;AAAA,IACT;AAEA,QAAI,UAAU,WAAW,MAAM,8BAA8B;AAC3D,YAAM,eAAe,KAAK,oBAAoB,SAAS;AACvD,UAAI,CAAC,cAAc;AACjB,cAAM,IAAI,WAAW,mCAAmC,aAAa;AAAA,MACvE;AAEA,qBAAe,cAAc,IAAI,cAAc,IAAI;AACnD,aAAO;AAAA,IACT;AAEA,UAAM,IAAI;AAAA,MACR,8BAA8B,UAAU,MAAM;AAAA,MAC9C;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,MAAM,QACJ,WACA,SACyB;AACzB,QAAI;AAEF,UAAI,EAAE,qBAAqB,aAAa;AACtC,cAAM,IAAI,WAAW,mCAAmC,aAAa;AAAA,MACvE;AACA,UAAI,EAAE,mBAAmB,aAAa;AACpC,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,UAAI,UAAU,WAAW,GAAG;AAC1B,cAAM,IAAI,WAAW,8BAA8B,aAAa;AAAA,MAClE;AAGA,YAAM,SAAS,KAAK,mBAAmB,SAAS;AAGhD,UAAI;AACJ,SAAG;AACD,8BAAsB,KAAK;AAAA,UACzB,MAAM;AAAA,QACR;AAAA,MACF,SAAS,CAAC,KAAK,iBAAiB,mBAAmB;AAEnD,YAAM,qBAAqB,KAAK;AAAA,QAC9B;AAAA,QACA;AAAA,MACF;AACA,UAAI,CAAC,oBAAoB;AACvB,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAGA,YAAM,eAAe,KAAK,YAAY,QAAQ,mBAAmB;AAGjE,YAAM,MAAM,KAAK,OAAO,YAAY;AACpC,YAAM,gBAAgB,IAAI;AAAA,QACxB,IAAI;AAAA,QACJ,IAAI,wBAAwB,IAAI;AAAA,MAClC;AACA,YAAM,SAAS,IAAI;AAAA,QACjB,IAAI;AAAA,QACJ,IAAI,iBAAiB,IAAI;AAAA,MAC3B;AAGA,YAAM,KAAK,KAAK,oBAAoB,OAAO,SAAS;AACpD,YAAM,aAAa,MAAM,KAAK,WAAW,eAAe,IAAI,OAAO;AAGnE,YAAM,UAAU,OAAO,CAAC,IAAI,oBAAoB,UAAU,CAAC;AAC3D,YAAM,MAAM,KAAK,WAAW,QAAQ,OAAO;AAG3C,WAAK,YAAY,mBAAmB;AACpC,WAAK,YAAY,YAAY;AAC7B,WAAK,YAAY,GAAG;AAEpB,aAAO;AAAA,QACL;AAAA,QACA,gBAAgB;AAAA,QAChB;AAAA,QACA;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,UAAI,iBAAiB,WAAY,OAAM;AACvC,YAAM,IAAI;AAAA,QACR,sBAAsB,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,QAC9E;AAAA,QACA,iBAAiB,QAAQ,QAAQ;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,QACJ,YACA,WACqB;AACrB,QAAI;AAEF,UAAI,EAAE,sBAAsB,aAAa;AACvC,cAAM,IAAI,WAAW,oCAAoC,aAAa;AAAA,MACxE;AACA,UAAI,CAAC,iBAAiB,SAAS,GAAG;AAChC,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,UAAI,WAAW,WAAW,MAAM,oBAAoB;AAClD,cAAM,IAAI;AAAA,UACR,+BAA+B,WAAW,MAAM;AAAA,UAChD;AAAA,QACF;AAAA,MACF;AACA,UAAI,CAAC,KAAK,iBAAiB,UAAU,GAAG;AACtC,cAAM,IAAI,WAAW,uBAAuB,aAAa;AAAA,MAC3D;AAGA,YAAM,qBAAqB,KAAK;AAAA,QAC9B,UAAU;AAAA,MACZ;AAGA,YAAM,eAAe,KAAK,YAAY,oBAAoB,UAAU;AAGpE,YAAM,MAAM,KAAK,OAAO,YAAY;AACpC,YAAM,gBAAgB,IAAI;AAAA,QACxB,IAAI;AAAA,QACJ,IAAI,wBAAwB,IAAI;AAAA,MAClC;AACA,YAAM,SAAS,IAAI;AAAA,QACjB,IAAI;AAAA,QACJ,IAAI,iBAAiB,IAAI;AAAA,MAC3B;AAGA,YAAM,UAAU,OAAO;AAAA,QACrB,UAAU;AAAA,QACV,UAAU;AAAA,QACV,UAAU;AAAA,MACZ,CAAC;AACD,YAAM,cAAc,KAAK,WAAW,QAAQ,OAAO;AAEnD,UAAI,CAAC,kBAAkB,UAAU,KAAK,WAAW,GAAG;AAClD,cAAM,IAAI,WAAW,2BAA2B,cAAc;AAAA,MAChE;AAGA,YAAM,YAAY,MAAM,KAAK;AAAA,QAC3B;AAAA,QACA,UAAU;AAAA,QACV,UAAU;AAAA,MACZ;AAGA,WAAK,YAAY,YAAY;AAC7B,WAAK,YAAY,GAAG;AAEpB,aAAO;AAAA,IACT,SAAS,OAAO;AACd,UAAI,iBAAiB,WAAY,OAAM;AACvC,YAAM,IAAI;AAAA,QACR,sBAAsB,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,QAC9E;AAAA,QACA,iBAAiB,QAAQ,QAAQ;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaU,YAAY,QAA0B;AAC9C,QAAI,UAAU,OAAO,SAAS,GAAG;AAE/B,aAAO,KAAK,CAAI;AAChB,aAAO,KAAK,GAAI;AAChB,aAAO,KAAK,GAAI;AAChB,aAAO,KAAK,CAAI;AAGhB,eAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,eAAO,CAAC,IAAK,IAAI,MAAQ;AAAA,MAC3B;AACA,aAAO,KAAK,CAAI;AAAA,IAClB;AAAA,EACF;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/crypto/ecies/base.ts"],"sourcesContent":["import type { ECIESProvider, ECIESEncrypted } from \"./interface\";\nimport { ECIESError, isECIESEncrypted } from \"./interface\";\nimport { CURVE, CIPHER, KDF } from \"./constants\";\nimport { constantTimeEqual } from \"./utils\";\nimport { concat } from \"viem\";\n\n/**\n * Provides shared ECIES encryption logic across platforms using Uint8Array.\n *\n * @remarks\n * Platform implementations extend this class and provide crypto primitives.\n * The base class handles the ECIES protocol flow while maintaining\n * compatibility with the eccrypto data format.\n *\n * **Implementation details:**\n * - KDF: SHA-512(shared_secret) → encKey (32B) || macKey (32B)\n * - Cipher: AES-256-CBC with random 16-byte IV\n * - MAC: HMAC-SHA256(macKey, iv || ephemPublicKey || ciphertext)\n *\n * @category Cryptography\n */\nexport abstract class BaseECIESUint8 implements ECIESProvider {\n // Cache for validated public keys to avoid repeated validation\n private static readonly validatedKeys = new WeakMap<Uint8Array, boolean>();\n\n /**\n * Generates cryptographically secure random bytes.\n *\n * @param length - Number of random bytes to generate.\n * @returns Random bytes array.\n */\n protected abstract generateRandomBytes(length: number): Uint8Array;\n\n /**\n * Verifies a private key is valid for secp256k1.\n *\n * @param privateKey - Private key to verify (32 bytes).\n * @returns `true` if valid private key.\n */\n protected abstract verifyPrivateKey(privateKey: Uint8Array): boolean;\n\n /**\n * Creates a public key from a private key.\n *\n * @param privateKey - Source private key (32 bytes).\n * @param compressed - Generate compressed (33B) or uncompressed (65B) format.\n * @returns Public key or `null` if creation failed.\n */\n protected abstract createPublicKey(\n privateKey: Uint8Array,\n compressed: boolean,\n ): Uint8Array | null;\n\n /**\n * Validates a public key on the secp256k1 curve.\n *\n * @param publicKey - Public key to validate.\n * @returns `true` if valid public key.\n */\n protected abstract validatePublicKey(publicKey: Uint8Array): boolean;\n\n /**\n * Decompresses a compressed public key.\n *\n * @param publicKey - Compressed public key (33 bytes).\n * @returns Uncompressed public key (65 bytes) or `null` if decompression failed.\n */\n protected abstract decompressPublicKey(\n publicKey: Uint8Array,\n ): Uint8Array | null;\n\n /**\n * Performs ECDH key agreement.\n *\n * @param publicKey - Other party's public key.\n * @param privateKey - Your private key.\n * @returns Raw X coordinate of shared point (32 bytes).\n */\n protected abstract performECDH(\n publicKey: Uint8Array,\n privateKey: Uint8Array,\n ): Uint8Array;\n\n /**\n * Computes SHA-512 hash.\n *\n * @param data - Data to hash.\n * @returns SHA-512 hash (64 bytes).\n */\n protected abstract sha512(data: Uint8Array): Uint8Array;\n\n /**\n * Computes HMAC-SHA256 authentication tag.\n *\n * @param key - HMAC key.\n * @param data - Data to authenticate.\n * @returns HMAC-SHA256 (32 bytes).\n */\n protected abstract hmacSha256(key: Uint8Array, data: Uint8Array): Uint8Array;\n\n /**\n * Encrypts data using AES-256-CBC.\n *\n * @param key - Encryption key (32 bytes).\n * @param iv - Initialization vector (16 bytes).\n * @param plaintext - Data to encrypt.\n * @returns Ciphertext with PKCS#7 padding.\n */\n protected abstract aesEncrypt(\n key: Uint8Array,\n iv: Uint8Array,\n plaintext: Uint8Array,\n ): Promise<Uint8Array>;\n\n /**\n * Decrypts data using AES-256-CBC.\n *\n * @param key - Decryption key (32 bytes).\n * @param iv - Initialization vector (16 bytes).\n * @param ciphertext - Data to decrypt.\n * @returns Plaintext with padding removed.\n */\n protected abstract aesDecrypt(\n key: Uint8Array,\n iv: Uint8Array,\n ciphertext: Uint8Array,\n ): Promise<Uint8Array>;\n\n /**\n * Normalizes a public key to uncompressed format.\n *\n * @param publicKey - Public key in any format.\n * @returns Uncompressed public key (65 bytes).\n * @throws {ECIESError} If key format is invalid.\n */\n protected normalizePublicKey(publicKey: Uint8Array): Uint8Array {\n // Check cache first\n if (BaseECIESUint8.validatedKeys.has(publicKey)) {\n return publicKey;\n }\n\n if (publicKey.length === CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH) {\n if (publicKey[0] !== CURVE.PREFIX.UNCOMPRESSED) {\n throw new ECIESError(\n \"Invalid uncompressed public key prefix\",\n \"INVALID_KEY\",\n );\n }\n // Validate and cache\n if (!this.validatePublicKey(publicKey)) {\n throw new ECIESError(\"Invalid public key\", \"INVALID_KEY\");\n }\n BaseECIESUint8.validatedKeys.set(publicKey, true);\n return publicKey;\n }\n\n if (publicKey.length === CURVE.COMPRESSED_PUBLIC_KEY_LENGTH) {\n const decompressed = this.decompressPublicKey(publicKey);\n if (!decompressed) {\n throw new ECIESError(\"Failed to decompress public key\", \"INVALID_KEY\");\n }\n // Cache the decompressed key\n BaseECIESUint8.validatedKeys.set(decompressed, true);\n return decompressed;\n }\n\n throw new ECIESError(\n `Invalid public key length: ${publicKey.length}`,\n \"INVALID_KEY\",\n );\n }\n\n /**\n * Normalizes a public key to uncompressed format (65 bytes with 0x04 prefix).\n * Must be implemented by derived classes to handle platform-specific operations.\n *\n * @param publicKey - The public key to normalize\n * @returns The normalized uncompressed public key\n */\n public abstract normalizeToUncompressed(publicKey: Uint8Array): Uint8Array;\n\n /**\n * Encrypts data using ECIES.\n *\n * @param publicKey - The recipient's public key (compressed or uncompressed)\n * @param message - The data to encrypt\n * @returns Promise resolving to encrypted data structure\n */\n async encrypt(\n publicKey: Uint8Array,\n message: Uint8Array,\n ): Promise<ECIESEncrypted> {\n try {\n // Validate inputs\n if (!(publicKey instanceof Uint8Array)) {\n throw new ECIESError(\"Public key must be a Uint8Array\", \"INVALID_KEY\");\n }\n if (!(message instanceof Uint8Array)) {\n throw new ECIESError(\n \"Message must be a Uint8Array\",\n \"ENCRYPTION_FAILED\",\n );\n }\n if (publicKey.length === 0) {\n throw new ECIESError(\"Public key cannot be empty\", \"INVALID_KEY\");\n }\n\n // Normalize public key to uncompressed format\n const pubKey = this.normalizePublicKey(publicKey);\n\n // Generate ephemeral key pair\n let ephemeralPrivateKey: Uint8Array;\n do {\n ephemeralPrivateKey = this.generateRandomBytes(\n CURVE.PRIVATE_KEY_LENGTH,\n );\n } while (!this.verifyPrivateKey(ephemeralPrivateKey));\n\n const ephemeralPublicKey = this.createPublicKey(\n ephemeralPrivateKey,\n false,\n );\n if (!ephemeralPublicKey) {\n throw new ECIESError(\n \"Failed to generate ephemeral public key\",\n \"ENCRYPTION_FAILED\",\n );\n }\n\n // Perform ECDH to get shared secret (raw X coordinate)\n const sharedSecret = this.performECDH(pubKey, ephemeralPrivateKey);\n\n // Derive keys using SHA-512 (eccrypto-compatible KDF)\n const kdf = this.sha512(sharedSecret);\n const encryptionKey = kdf.slice(\n KDF.ENCRYPTION_KEY_OFFSET,\n KDF.ENCRYPTION_KEY_OFFSET + KDF.ENCRYPTION_KEY_LENGTH,\n );\n const macKey = kdf.slice(\n KDF.MAC_KEY_OFFSET,\n KDF.MAC_KEY_OFFSET + KDF.MAC_KEY_LENGTH,\n );\n\n // Generate random IV and encrypt\n const iv = this.generateRandomBytes(CIPHER.IV_LENGTH);\n const ciphertext = await this.aesEncrypt(encryptionKey, iv, message);\n\n // Calculate MAC (Encrypt-then-MAC)\n const macData = concat([iv, ephemeralPublicKey, ciphertext]);\n const mac = this.hmacSha256(macKey, macData);\n\n // Clear sensitive data\n this.clearBuffer(ephemeralPrivateKey);\n this.clearBuffer(sharedSecret);\n this.clearBuffer(kdf);\n\n return {\n iv,\n ephemPublicKey: ephemeralPublicKey,\n ciphertext,\n mac,\n };\n } catch (error) {\n if (error instanceof ECIESError) throw error;\n throw new ECIESError(\n `Encryption failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n \"ENCRYPTION_FAILED\",\n error instanceof Error ? error : undefined,\n );\n }\n }\n\n /**\n * Decrypts ECIES encrypted data.\n *\n * @param privateKey - The recipient's private key (32 bytes)\n * @param encrypted - The encrypted data structure from encrypt()\n * @returns Promise resolving to the original plaintext\n */\n async decrypt(\n privateKey: Uint8Array,\n encrypted: ECIESEncrypted,\n ): Promise<Uint8Array> {\n try {\n // Validate inputs\n if (!(privateKey instanceof Uint8Array)) {\n throw new ECIESError(\"Private key must be a Uint8Array\", \"INVALID_KEY\");\n }\n if (!isECIESEncrypted(encrypted)) {\n throw new ECIESError(\n \"Invalid encrypted data structure\",\n \"DECRYPTION_FAILED\",\n );\n }\n if (privateKey.length !== CURVE.PRIVATE_KEY_LENGTH) {\n throw new ECIESError(\n `Invalid private key length: ${privateKey.length}`,\n \"INVALID_KEY\",\n );\n }\n if (!this.verifyPrivateKey(privateKey)) {\n throw new ECIESError(\"Invalid private key\", \"INVALID_KEY\");\n }\n\n // Strict validation: ephemeral keys must be 65-byte uncompressed (eccrypto standard)\n if (\n encrypted.ephemPublicKey.length !== CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH\n ) {\n throw new ECIESError(\n `Invalid ephemeral public key: expected ${CURVE.UNCOMPRESSED_PUBLIC_KEY_LENGTH} bytes (uncompressed), got ${encrypted.ephemPublicKey.length} bytes`,\n \"INVALID_KEY\",\n );\n }\n if (encrypted.ephemPublicKey[0] !== CURVE.PREFIX.UNCOMPRESSED) {\n throw new ECIESError(\n \"Invalid ephemeral public key: must be uncompressed format with 0x04 prefix (eccrypto standard)\",\n \"INVALID_KEY\",\n );\n }\n if (!this.validatePublicKey(encrypted.ephemPublicKey)) {\n throw new ECIESError(\"Invalid ephemeral public key\", \"INVALID_KEY\");\n }\n const ephemeralPublicKey = encrypted.ephemPublicKey;\n\n // Perform ECDH to recover shared secret\n const sharedSecret = this.performECDH(ephemeralPublicKey, privateKey);\n\n // Derive keys using SHA-512 (eccrypto-compatible KDF)\n const kdf = this.sha512(sharedSecret);\n const encryptionKey = kdf.slice(\n KDF.ENCRYPTION_KEY_OFFSET,\n KDF.ENCRYPTION_KEY_OFFSET + KDF.ENCRYPTION_KEY_LENGTH,\n );\n const macKey = kdf.slice(\n KDF.MAC_KEY_OFFSET,\n KDF.MAC_KEY_OFFSET + KDF.MAC_KEY_LENGTH,\n );\n\n // Verify MAC before decryption (Encrypt-then-MAC)\n const macData = concat([\n encrypted.iv,\n encrypted.ephemPublicKey,\n encrypted.ciphertext,\n ]);\n const expectedMac = this.hmacSha256(macKey, macData);\n\n if (!constantTimeEqual(encrypted.mac, expectedMac)) {\n throw new ECIESError(\"MAC verification failed\", \"MAC_MISMATCH\");\n }\n\n // Decrypt the ciphertext\n const decrypted = await this.aesDecrypt(\n encryptionKey,\n encrypted.iv,\n encrypted.ciphertext,\n );\n\n // Clear sensitive data\n this.clearBuffer(sharedSecret);\n this.clearBuffer(kdf);\n\n return decrypted;\n } catch (error) {\n if (error instanceof ECIESError) throw error;\n throw new ECIESError(\n `Decryption failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n \"DECRYPTION_FAILED\",\n error instanceof Error ? error : undefined,\n );\n }\n }\n\n /**\n * Clears sensitive data from memory using multi-pass overwrite.\n *\n * @remarks\n * Uses multiple passes with different patterns to make it harder\n * for JIT compilers to optimize away the operation. While not\n * guaranteed in JavaScript, this is a best-effort approach to\n * clear sensitive data from memory.\n *\n * @param buffer - The buffer to clear\n */\n protected clearBuffer(buffer: Uint8Array): void {\n if (buffer && buffer.length > 0) {\n // Multi-pass overwrite to resist compiler optimization\n buffer.fill(0x00); // Fill with zeros\n buffer.fill(0xff); // Fill with ones\n buffer.fill(0xaa); // Fill with alternating pattern\n buffer.fill(0x00); // Final zero fill\n\n // Additional pattern write to further discourage optimization\n for (let i = 0; i < buffer.length; i++) {\n buffer[i] = (i & 0xff) ^ 0x5a; // XOR with pattern\n }\n buffer.fill(0x00); // Final clear\n }\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/errors.cjs
CHANGED
|
@@ -30,6 +30,7 @@ __export(errors_exports, {
|
|
|
30
30
|
SerializationError: () => SerializationError,
|
|
31
31
|
ServerUrlMismatchError: () => ServerUrlMismatchError,
|
|
32
32
|
SignatureError: () => SignatureError,
|
|
33
|
+
TransactionPendingError: () => TransactionPendingError,
|
|
33
34
|
UserRejectedRequestError: () => UserRejectedRequestError,
|
|
34
35
|
VanaError: () => VanaError
|
|
35
36
|
});
|
|
@@ -137,6 +138,33 @@ class ReadOnlyError extends VanaError {
|
|
|
137
138
|
/** Suggested solution for fixing the error */
|
|
138
139
|
suggestion;
|
|
139
140
|
}
|
|
141
|
+
class TransactionPendingError extends VanaError {
|
|
142
|
+
constructor(operationId, message, lastKnownStatus) {
|
|
143
|
+
super(
|
|
144
|
+
`Transaction operation pending: ${message} (operationId: ${operationId})`,
|
|
145
|
+
"TRANSACTION_PENDING"
|
|
146
|
+
);
|
|
147
|
+
this.operationId = operationId;
|
|
148
|
+
this.lastKnownStatus = lastKnownStatus;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Converts the error to a JSON-serializable format.
|
|
152
|
+
*
|
|
153
|
+
* @remarks
|
|
154
|
+
* Useful for logging, storage, or transmission of error details.
|
|
155
|
+
*
|
|
156
|
+
* @returns JSON representation of the error
|
|
157
|
+
*/
|
|
158
|
+
toJSON() {
|
|
159
|
+
return {
|
|
160
|
+
name: this.name,
|
|
161
|
+
code: this.code,
|
|
162
|
+
message: this.message,
|
|
163
|
+
operationId: this.operationId,
|
|
164
|
+
lastKnownStatus: this.lastKnownStatus
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
}
|
|
140
168
|
// Annotate the CommonJS export names for ESM import in node:
|
|
141
169
|
0 && (module.exports = {
|
|
142
170
|
BlockchainError,
|
|
@@ -151,6 +179,7 @@ class ReadOnlyError extends VanaError {
|
|
|
151
179
|
SerializationError,
|
|
152
180
|
ServerUrlMismatchError,
|
|
153
181
|
SignatureError,
|
|
182
|
+
TransactionPendingError,
|
|
154
183
|
UserRejectedRequestError,
|
|
155
184
|
VanaError
|
|
156
185
|
});
|
package/dist/errors.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts"],"sourcesContent":["/**\n * Base error class for all Vana SDK errors with structured error codes.\n *\n * @remarks\n * This abstract base class provides a foundation for all SDK-specific errors with\n * consistent error codes and stack trace handling. All Vana SDK errors extend this\n * class to provide structured error information that applications can handle\n * programmatically. The error code enables differentiation between error types\n * without relying on string matching.\n * @category Error Handling\n */\nexport class VanaError extends Error {\n constructor(\n message: string,\n public readonly code?: string,\n ) {\n super(message);\n this.name = this.constructor.name;\n\n // Maintains proper stack trace for where our error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, this.constructor);\n }\n }\n}\n\n/**\n * Thrown when gasless transaction submission via relayer fails.\n *\n * @remarks\n * This error occurs when the relayer service is unavailable, returns an error,\n * or fails to process a gasless transaction. It includes the HTTP status code\n * and response details when available to help with debugging relayer issues.\n * @category Error Handling\n */\nexport class RelayerError extends VanaError {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly response?: unknown,\n ) {\n super(message, \"RELAYER_ERROR\");\n }\n}\n\n/**\n * Thrown when the user rejects a wallet signature request.\n *\n * @remarks\n * This error occurs when users decline to sign transactions or typed data through\n * their wallet interface. It's a normal part of user interaction and should be\n * handled gracefully by applications without treating it as a system error.\n * @category Error Handling\n */\nexport class UserRejectedRequestError extends VanaError {\n constructor(message: string = \"User rejected the signature request\") {\n super(message, \"USER_REJECTED_REQUEST\");\n }\n}\n\n/**\n * Thrown when the SDK configuration contains invalid or missing parameters.\n *\n * @remarks\n * This error occurs during SDK initialization when required configuration\n * parameters are missing, invalid, or incompatible. Common causes include\n * missing wallet clients, invalid chain IDs, malformed storage provider\n * configurations, or incompatible parameter combinations.\n *\n * Applications should catch this error during initialization and provide\n * clear feedback to users about configuration requirements.\n *\n * @example\n * ```typescript\n * try {\n * const vana = Vana({\n * chainId: 999999, // Invalid chain ID\n * account: null // Missing account\n * });\n * } catch (error) {\n * if (error instanceof InvalidConfigurationError) {\n * console.error('Configuration error:', error.message);\n * // Show user-friendly configuration help\n * }\n * }\n * ```\n * @category Error Handling\n */\nexport class InvalidConfigurationError extends VanaError {\n constructor(message: string) {\n super(message, \"INVALID_CONFIGURATION\");\n }\n}\n\n/**\n * Thrown when a required Vana protocol contract is not deployed on the current chain.\n *\n * @remarks\n * This error occurs when attempting to interact with contracts that are not\n * available on the connected blockchain network. It includes the contract name\n * and chain ID to help identify deployment issues or incorrect network configuration.\n * @category Error Handling\n */\nexport class ContractNotFoundError extends VanaError {\n constructor(contractName: string, chainId: number) {\n super(\n `Contract ${contractName} not found on chain ${chainId}`,\n \"CONTRACT_NOT_FOUND\",\n );\n }\n}\n\n/**\n * Thrown when blockchain operations fail due to network, contract, or transaction issues.\n *\n * @remarks\n * This error encompasses various blockchain-related failures including network\n * connectivity issues, contract execution failures, insufficient gas, invalid\n * transaction parameters, or smart contract reverts. The original error is\n * preserved to provide detailed debugging information while maintaining a\n * consistent SDK error interface.\n *\n * Common causes:\n * - Network connectivity problems\n * - Insufficient gas or gas price too low\n * - Contract function reverts\n * - Invalid transaction parameters\n * - Blockchain congestion or downtime\n *\n * @example\n * ```typescript\n * try {\n * await vana.permissions.grant({\n * grantee: '0x742d35...',\n * operation: 'read'\n * });\n * } catch (error) {\n * if (error instanceof BlockchainError) {\n * console.error('Blockchain operation failed:', error.message);\n *\n * // Check if it's a network issue\n * if (error.originalError?.message.includes('network')) {\n * // Retry with exponential backoff\n * await retryOperation();\n * }\n * }\n * }\n * ```\n * @category Error Handling\n */\nexport class BlockchainError extends VanaError {\n constructor(\n message: string,\n public readonly originalError?: Error,\n ) {\n super(message, \"BLOCKCHAIN_ERROR\");\n }\n}\n\n/**\n * Thrown when data serialization or deserialization operations fail.\n *\n * @remarks\n * This error occurs when the SDK cannot properly serialize parameters for\n * blockchain transactions, IPFS storage, or API calls. Common causes include\n * circular references in objects, unsupported data types, or malformed JSON.\n * It's typically encountered during grant file creation, storage operations,\n * or when preparing transaction data.\n *\n * @example\n * ```typescript\n * try {\n * // Object with circular reference causes serialization error\n * const obj = { name: 'test' };\n * obj.self = obj; // Circular reference\n *\n * await vana.data.upload({\n * content: obj,\n * filename: 'data.json'\n * });\n * } catch (error) {\n * if (error instanceof SerializationError) {\n * console.error('Data serialization failed:', error.message);\n * // Clean data before retry\n * const cleanedData = removeCircularReferences(obj);\n * await vana.data.upload({\n * content: cleanedData,\n * filename: 'data.json'\n * });\n * }\n * }\n * ```\n * @category Error Handling\n */\nexport class SerializationError extends VanaError {\n constructor(message: string) {\n super(message, \"SERIALIZATION_ERROR\");\n }\n}\n\n/**\n * Thrown when a signature operation fails or cannot be completed.\n *\n * @remarks\n * This error occurs when wallet signature operations fail due to disconnection,\n * locked accounts, or other wallet-related issues. It preserves the original\n * error for debugging while providing consistent error handling across the SDK.\n *\n * Recovery strategies:\n * - Check wallet connection and account unlock status\n * - Retry operation with explicit user interaction\n * - For gasless operations, consider switching to direct transactions\n *\n * @example\n * ```typescript\n * try {\n * await vana.permissions.grant({ grantee: '0x...' });\n * } catch (error) {\n * if (error instanceof SignatureError) {\n * // Prompt user to unlock wallet\n * await promptWalletUnlock();\n * // Retry operation\n * }\n * }\n * ```\n * @category Error Handling\n */\nexport class SignatureError extends VanaError {\n constructor(\n message: string,\n public readonly originalError?: Error,\n ) {\n super(message, \"SIGNATURE_ERROR\");\n }\n}\n\n/**\n * Thrown when network communication fails during API calls or blockchain interactions.\n *\n * @remarks\n * This error encompasses network connectivity issues, API unavailability,\n * timeout errors, and CORS restrictions. It's commonly encountered during\n * IPFS operations, subgraph queries, or RPC calls.\n *\n * Recovery strategies:\n * - Check network connectivity\n * - Retry with exponential backoff\n * - Verify API endpoints are accessible\n * - Switch to alternative network providers or gateways\n *\n * @example\n * ```typescript\n * try {\n * const files = await vana.data.getUserFiles({ owner: '0x...' });\n * } catch (error) {\n * if (error instanceof NetworkError) {\n * // Implement retry with exponential backoff\n * await retryWithBackoff(() => vana.data.getUserFiles({ owner: '0x...' }));\n * }\n * }\n * ```\n * @category Error Handling\n */\nexport class NetworkError extends VanaError {\n constructor(\n message: string,\n public readonly originalError?: Error,\n ) {\n super(message, \"NETWORK_ERROR\");\n }\n}\n\n/**\n * Thrown when transaction nonce retrieval fails during gasless operations.\n *\n * @remarks\n * This error occurs when the SDK cannot retrieve the user's current nonce from\n * smart contracts, preventing gasless transaction submission. Nonces are critical\n * for preventing replay attacks in signed transactions.\n *\n * Recovery strategies:\n * - Retry nonce retrieval after brief delay\n * - Check wallet connection and account status\n * - Use manual nonce specification if supported by the operation\n * - Switch to direct transactions as fallback\n *\n * @example\n * ```typescript\n * try {\n * await vana.permissions.grant({ grantee: '0x...' });\n * } catch (error) {\n * if (error instanceof NonceError) {\n * // Wait and retry\n * await delay(1000);\n * await vana.permissions.grant({ grantee: '0x...' });\n * }\n * }\n * ```\n * @category Error Handling\n */\nexport class NonceError extends VanaError {\n constructor(message: string) {\n super(message, \"NONCE_ERROR\");\n }\n}\n\n/**\n * Thrown when personal server operations fail or cannot be completed.\n *\n * @remarks\n * This error occurs during interactions with personal servers for computation\n * requests, identity retrieval, or operation status checks. Common causes include\n * server unavailability, untrusted server status, or invalid permission grants.\n *\n * Recovery strategies:\n * - Verify server URL accessibility\n * - Check server trust status via `vana.permissions.getTrustedServers()`\n * - Ensure valid permissions exist for the operation\n * - Retry after server becomes available\n *\n * @example\n * ```typescript\n * try {\n * const result = await vana.server.createOperation({ permissionId: 123 });\n * } catch (error) {\n * if (error instanceof PersonalServerError) {\n * // Check if server is trusted\n * const trustedServers = await vana.permissions.getTrustedServers();\n * if (!trustedServers.includes(serverId)) {\n * await vana.permissions.trustServer({ serverId });\n * }\n * }\n * }\n * ```\n * @category Error Handling\n */\nexport class PersonalServerError extends VanaError {\n constructor(\n message: string,\n public readonly originalError?: Error,\n ) {\n super(message, \"PERSONAL_SERVER_ERROR\");\n }\n}\n\n/**\n * Thrown when attempting to register a server with a URL different from its existing registration.\n *\n * @remarks\n * This error occurs when trying to add or trust a server that's already registered\n * on-chain with a different URL. Server URLs are immutable once registered to\n * maintain consistency and security. Applications should use the existing URL\n * or register a new server with a different ID.\n *\n * @example\n * ```typescript\n * try {\n * await vana.permissions.addAndTrustServer({\n * serverId: 1,\n * serverUrl: 'https://new-url.com',\n * publicKey: '0x...'\n * });\n * } catch (error) {\n * if (error instanceof ServerUrlMismatchError) {\n * console.log(`Server already registered with: ${error.existingUrl}`);\n * // Use existing URL or register new server\n * }\n * }\n * ```\n * @category Error Handling\n */\nexport class ServerUrlMismatchError extends VanaError {\n constructor(existingUrl: string, providedUrl: string, serverId: string) {\n super(\n `Server ${serverId} is already registered with URL \"${existingUrl}\". Cannot change to \"${providedUrl}\".`,\n \"SERVER_URL_MISMATCH\",\n );\n this.existingUrl = existingUrl;\n this.providedUrl = providedUrl;\n this.serverId = serverId;\n }\n\n public readonly existingUrl: string;\n public readonly providedUrl: string;\n public readonly serverId: string;\n}\n\n/**\n * Thrown when permission grant, revoke, or validation operations fail.\n *\n * @remarks\n * This error occurs during permission management operations including grants,\n * revocations, and permission validation checks. Common causes include invalid\n * grantee addresses, expired permissions, or insufficient privileges.\n *\n * @example\n * ```typescript\n * try {\n * await vana.permissions.revoke({ permissionId: 999999 });\n * } catch (error) {\n * if (error instanceof PermissionError) {\n * console.error('Permission operation failed:', error.message);\n * // Permission may not exist or user may not be owner\n * }\n * }\n * ```\n * @category Error Handling\n */\nexport class PermissionError extends VanaError {\n constructor(\n message: string,\n public readonly originalError?: Error,\n ) {\n super(message, \"PERMISSION_ERROR\");\n }\n}\n\n/**\n * Thrown when attempting to perform write operations without a wallet client.\n *\n * @remarks\n * This error occurs when trying to execute operations that require wallet\n * interaction (signing, encrypting, or submitting transactions) while the SDK\n * is initialized in read-only mode without a wallet client. To perform write\n * operations, the SDK must be initialized with a wallet client.\n *\n * Common operations that require a wallet:\n * - Signing transactions or typed data\n * - Encrypting or decrypting files\n * - Granting or revoking permissions\n * - Uploading data to IPFS\n * - Submitting blockchain transactions\n *\n * @example\n * ```typescript\n * try {\n * // This will throw if no wallet client is provided\n * await vana.data.decryptFile({ fileId: 'abc123' });\n * } catch (error) {\n * if (error instanceof ReadOnlyError) {\n * console.error(`Cannot ${error.operation}: ${error.message}`);\n * // Initialize with wallet client to enable write operations\n * const vanaWithWallet = Vana({\n * walletClient: createWalletClient(...)\n * });\n * }\n * }\n * ```\n * @category Error Handling\n */\nexport class ReadOnlyError extends VanaError {\n constructor(\n operation: string,\n suggestion: string = \"Initialize the SDK with a walletClient to perform this operation\",\n ) {\n super(\n `Operation '${operation}' requires a wallet client. ${suggestion}`,\n \"READ_ONLY_ERROR\",\n );\n this.operation = operation;\n this.suggestion = suggestion;\n }\n\n /** The operation that was attempted */\n public readonly operation: string;\n /** Suggested solution for fixing the error */\n public readonly suggestion: string;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWO,MAAM,kBAAkB,MAAM;AAAA,EACnC,YACE,SACgB,MAChB;AACA,UAAM,OAAO;AAFG;AAGhB,SAAK,OAAO,KAAK,YAAY;AAG7B,QAAI,MAAM,mBAAmB;AAC3B,YAAM,kBAAkB,MAAM,KAAK,WAAW;AAAA,IAChD;AAAA,EACF;AACF;AAWO,MAAM,qBAAqB,UAAU;AAAA,EAC1C,YACE,SACgB,YACA,UAChB;AACA,UAAM,SAAS,eAAe;AAHd;AACA;AAAA,EAGlB;AACF;AAWO,MAAM,iCAAiC,UAAU;AAAA,EACtD,YAAY,UAAkB,uCAAuC;AACnE,UAAM,SAAS,uBAAuB;AAAA,EACxC;AACF;AA8BO,MAAM,kCAAkC,UAAU;AAAA,EACvD,YAAY,SAAiB;AAC3B,UAAM,SAAS,uBAAuB;AAAA,EACxC;AACF;AAWO,MAAM,8BAA8B,UAAU;AAAA,EACnD,YAAY,cAAsB,SAAiB;AACjD;AAAA,MACE,YAAY,YAAY,uBAAuB,OAAO;AAAA,MACtD;AAAA,IACF;AAAA,EACF;AACF;AAwCO,MAAM,wBAAwB,UAAU;AAAA,EAC7C,YACE,SACgB,eAChB;AACA,UAAM,SAAS,kBAAkB;AAFjB;AAAA,EAGlB;AACF;AAqCO,MAAM,2BAA2B,UAAU;AAAA,EAChD,YAAY,SAAiB;AAC3B,UAAM,SAAS,qBAAqB;AAAA,EACtC;AACF;AA6BO,MAAM,uBAAuB,UAAU;AAAA,EAC5C,YACE,SACgB,eAChB;AACA,UAAM,SAAS,iBAAiB;AAFhB;AAAA,EAGlB;AACF;AA6BO,MAAM,qBAAqB,UAAU;AAAA,EAC1C,YACE,SACgB,eAChB;AACA,UAAM,SAAS,eAAe;AAFd;AAAA,EAGlB;AACF;AA8BO,MAAM,mBAAmB,UAAU;AAAA,EACxC,YAAY,SAAiB;AAC3B,UAAM,SAAS,aAAa;AAAA,EAC9B;AACF;AAgCO,MAAM,4BAA4B,UAAU;AAAA,EACjD,YACE,SACgB,eAChB;AACA,UAAM,SAAS,uBAAuB;AAFtB;AAAA,EAGlB;AACF;AA4BO,MAAM,+BAA+B,UAAU;AAAA,EACpD,YAAY,aAAqB,aAAqB,UAAkB;AACtE;AAAA,MACE,UAAU,QAAQ,oCAAoC,WAAW,wBAAwB,WAAW;AAAA,MACpG;AAAA,IACF;AACA,SAAK,cAAc;AACnB,SAAK,cAAc;AACnB,SAAK,WAAW;AAAA,EAClB;AAAA,EAEgB;AAAA,EACA;AAAA,EACA;AAClB;AAuBO,MAAM,wBAAwB,UAAU;AAAA,EAC7C,YACE,SACgB,eAChB;AACA,UAAM,SAAS,kBAAkB;AAFjB;AAAA,EAGlB;AACF;AAmCO,MAAM,sBAAsB,UAAU;AAAA,EAC3C,YACE,WACA,aAAqB,oEACrB;AACA;AAAA,MACE,cAAc,SAAS,+BAA+B,UAAU;AAAA,MAChE;AAAA,IACF;AACA,SAAK,YAAY;AACjB,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA,EAGgB;AAAA;AAAA,EAEA;AAClB;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts"],"sourcesContent":["/**\n * Base error class for all Vana SDK errors with structured error codes.\n *\n * @remarks\n * This abstract base class provides a foundation for all SDK-specific errors with\n * consistent error codes and stack trace handling. All Vana SDK errors extend this\n * class to provide structured error information that applications can handle\n * programmatically. The error code enables differentiation between error types\n * without relying on string matching.\n * @category Error Handling\n */\nexport class VanaError extends Error {\n constructor(\n message: string,\n public readonly code?: string,\n ) {\n super(message);\n this.name = this.constructor.name;\n\n // Maintains proper stack trace for where our error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, this.constructor);\n }\n }\n}\n\n/**\n * Thrown when gasless transaction submission via relayer fails.\n *\n * @remarks\n * This error occurs when the relayer service is unavailable, returns an error,\n * or fails to process a gasless transaction. It includes the HTTP status code\n * and response details when available to help with debugging relayer issues.\n * @category Error Handling\n */\nexport class RelayerError extends VanaError {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly response?: unknown,\n ) {\n super(message, \"RELAYER_ERROR\");\n }\n}\n\n/**\n * Thrown when the user rejects a wallet signature request.\n *\n * @remarks\n * This error occurs when users decline to sign transactions or typed data through\n * their wallet interface. It's a normal part of user interaction and should be\n * handled gracefully by applications without treating it as a system error.\n * @category Error Handling\n */\nexport class UserRejectedRequestError extends VanaError {\n constructor(message: string = \"User rejected the signature request\") {\n super(message, \"USER_REJECTED_REQUEST\");\n }\n}\n\n/**\n * Thrown when the SDK configuration contains invalid or missing parameters.\n *\n * @remarks\n * This error occurs during SDK initialization when required configuration\n * parameters are missing, invalid, or incompatible. Common causes include\n * missing wallet clients, invalid chain IDs, malformed storage provider\n * configurations, or incompatible parameter combinations.\n *\n * Applications should catch this error during initialization and provide\n * clear feedback to users about configuration requirements.\n *\n * @example\n * ```typescript\n * try {\n * const vana = Vana({\n * chainId: 999999, // Invalid chain ID\n * account: null // Missing account\n * });\n * } catch (error) {\n * if (error instanceof InvalidConfigurationError) {\n * console.error('Configuration error:', error.message);\n * // Show user-friendly configuration help\n * }\n * }\n * ```\n * @category Error Handling\n */\nexport class InvalidConfigurationError extends VanaError {\n constructor(message: string) {\n super(message, \"INVALID_CONFIGURATION\");\n }\n}\n\n/**\n * Thrown when a required Vana protocol contract is not deployed on the current chain.\n *\n * @remarks\n * This error occurs when attempting to interact with contracts that are not\n * available on the connected blockchain network. It includes the contract name\n * and chain ID to help identify deployment issues or incorrect network configuration.\n * @category Error Handling\n */\nexport class ContractNotFoundError extends VanaError {\n constructor(contractName: string, chainId: number) {\n super(\n `Contract ${contractName} not found on chain ${chainId}`,\n \"CONTRACT_NOT_FOUND\",\n );\n }\n}\n\n/**\n * Thrown when blockchain operations fail due to network, contract, or transaction issues.\n *\n * @remarks\n * This error encompasses various blockchain-related failures including network\n * connectivity issues, contract execution failures, insufficient gas, invalid\n * transaction parameters, or smart contract reverts. The original error is\n * preserved to provide detailed debugging information while maintaining a\n * consistent SDK error interface.\n *\n * Common causes:\n * - Network connectivity problems\n * - Insufficient gas or gas price too low\n * - Contract function reverts\n * - Invalid transaction parameters\n * - Blockchain congestion or downtime\n *\n * @example\n * ```typescript\n * try {\n * await vana.permissions.grant({\n * grantee: '0x742d35...',\n * operation: 'read'\n * });\n * } catch (error) {\n * if (error instanceof BlockchainError) {\n * console.error('Blockchain operation failed:', error.message);\n *\n * // Check if it's a network issue\n * if (error.originalError?.message.includes('network')) {\n * // Retry with exponential backoff\n * await retryOperation();\n * }\n * }\n * }\n * ```\n * @category Error Handling\n */\nexport class BlockchainError extends VanaError {\n constructor(\n message: string,\n public readonly originalError?: Error,\n ) {\n super(message, \"BLOCKCHAIN_ERROR\");\n }\n}\n\n/**\n * Thrown when data serialization or deserialization operations fail.\n *\n * @remarks\n * This error occurs when the SDK cannot properly serialize parameters for\n * blockchain transactions, IPFS storage, or API calls. Common causes include\n * circular references in objects, unsupported data types, or malformed JSON.\n * It's typically encountered during grant file creation, storage operations,\n * or when preparing transaction data.\n *\n * @example\n * ```typescript\n * try {\n * // Object with circular reference causes serialization error\n * const obj = { name: 'test' };\n * obj.self = obj; // Circular reference\n *\n * await vana.data.upload({\n * content: obj,\n * filename: 'data.json'\n * });\n * } catch (error) {\n * if (error instanceof SerializationError) {\n * console.error('Data serialization failed:', error.message);\n * // Clean data before retry\n * const cleanedData = removeCircularReferences(obj);\n * await vana.data.upload({\n * content: cleanedData,\n * filename: 'data.json'\n * });\n * }\n * }\n * ```\n * @category Error Handling\n */\nexport class SerializationError extends VanaError {\n constructor(message: string) {\n super(message, \"SERIALIZATION_ERROR\");\n }\n}\n\n/**\n * Thrown when a signature operation fails or cannot be completed.\n *\n * @remarks\n * This error occurs when wallet signature operations fail due to disconnection,\n * locked accounts, or other wallet-related issues. It preserves the original\n * error for debugging while providing consistent error handling across the SDK.\n *\n * Recovery strategies:\n * - Check wallet connection and account unlock status\n * - Retry operation with explicit user interaction\n * - For gasless operations, consider switching to direct transactions\n *\n * @example\n * ```typescript\n * try {\n * await vana.permissions.grant({ grantee: '0x...' });\n * } catch (error) {\n * if (error instanceof SignatureError) {\n * // Prompt user to unlock wallet\n * await promptWalletUnlock();\n * // Retry operation\n * }\n * }\n * ```\n * @category Error Handling\n */\nexport class SignatureError extends VanaError {\n constructor(\n message: string,\n public readonly originalError?: Error,\n ) {\n super(message, \"SIGNATURE_ERROR\");\n }\n}\n\n/**\n * Thrown when network communication fails during API calls or blockchain interactions.\n *\n * @remarks\n * This error encompasses network connectivity issues, API unavailability,\n * timeout errors, and CORS restrictions. It's commonly encountered during\n * IPFS operations, subgraph queries, or RPC calls.\n *\n * Recovery strategies:\n * - Check network connectivity\n * - Retry with exponential backoff\n * - Verify API endpoints are accessible\n * - Switch to alternative network providers or gateways\n *\n * @example\n * ```typescript\n * try {\n * const files = await vana.data.getUserFiles({ owner: '0x...' });\n * } catch (error) {\n * if (error instanceof NetworkError) {\n * // Implement retry with exponential backoff\n * await retryWithBackoff(() => vana.data.getUserFiles({ owner: '0x...' }));\n * }\n * }\n * ```\n * @category Error Handling\n */\nexport class NetworkError extends VanaError {\n constructor(\n message: string,\n public readonly originalError?: Error,\n ) {\n super(message, \"NETWORK_ERROR\");\n }\n}\n\n/**\n * Thrown when transaction nonce retrieval fails during gasless operations.\n *\n * @remarks\n * This error occurs when the SDK cannot retrieve the user's current nonce from\n * smart contracts, preventing gasless transaction submission. Nonces are critical\n * for preventing replay attacks in signed transactions.\n *\n * Recovery strategies:\n * - Retry nonce retrieval after brief delay\n * - Check wallet connection and account status\n * - Use manual nonce specification if supported by the operation\n * - Switch to direct transactions as fallback\n *\n * @example\n * ```typescript\n * try {\n * await vana.permissions.grant({ grantee: '0x...' });\n * } catch (error) {\n * if (error instanceof NonceError) {\n * // Wait and retry\n * await delay(1000);\n * await vana.permissions.grant({ grantee: '0x...' });\n * }\n * }\n * ```\n * @category Error Handling\n */\nexport class NonceError extends VanaError {\n constructor(message: string) {\n super(message, \"NONCE_ERROR\");\n }\n}\n\n/**\n * Thrown when personal server operations fail or cannot be completed.\n *\n * @remarks\n * This error occurs during interactions with personal servers for computation\n * requests, identity retrieval, or operation status checks. Common causes include\n * server unavailability, untrusted server status, or invalid permission grants.\n *\n * Recovery strategies:\n * - Verify server URL accessibility\n * - Check server trust status via `vana.permissions.getTrustedServers()`\n * - Ensure valid permissions exist for the operation\n * - Retry after server becomes available\n *\n * @example\n * ```typescript\n * try {\n * const result = await vana.server.createOperation({ permissionId: 123 });\n * } catch (error) {\n * if (error instanceof PersonalServerError) {\n * // Check if server is trusted\n * const trustedServers = await vana.permissions.getTrustedServers();\n * if (!trustedServers.includes(serverId)) {\n * await vana.permissions.trustServer({ serverId });\n * }\n * }\n * }\n * ```\n * @category Error Handling\n */\nexport class PersonalServerError extends VanaError {\n constructor(\n message: string,\n public readonly originalError?: Error,\n ) {\n super(message, \"PERSONAL_SERVER_ERROR\");\n }\n}\n\n/**\n * Thrown when attempting to register a server with a URL different from its existing registration.\n *\n * @remarks\n * This error occurs when trying to add or trust a server that's already registered\n * on-chain with a different URL. Server URLs are immutable once registered to\n * maintain consistency and security. Applications should use the existing URL\n * or register a new server with a different ID.\n *\n * @example\n * ```typescript\n * try {\n * await vana.permissions.addAndTrustServer({\n * serverId: 1,\n * serverUrl: 'https://new-url.com',\n * publicKey: '0x...'\n * });\n * } catch (error) {\n * if (error instanceof ServerUrlMismatchError) {\n * console.log(`Server already registered with: ${error.existingUrl}`);\n * // Use existing URL or register new server\n * }\n * }\n * ```\n * @category Error Handling\n */\nexport class ServerUrlMismatchError extends VanaError {\n constructor(existingUrl: string, providedUrl: string, serverId: string) {\n super(\n `Server ${serverId} is already registered with URL \"${existingUrl}\". Cannot change to \"${providedUrl}\".`,\n \"SERVER_URL_MISMATCH\",\n );\n this.existingUrl = existingUrl;\n this.providedUrl = providedUrl;\n this.serverId = serverId;\n }\n\n public readonly existingUrl: string;\n public readonly providedUrl: string;\n public readonly serverId: string;\n}\n\n/**\n * Thrown when permission grant, revoke, or validation operations fail.\n *\n * @remarks\n * This error occurs during permission management operations including grants,\n * revocations, and permission validation checks. Common causes include invalid\n * grantee addresses, expired permissions, or insufficient privileges.\n *\n * @example\n * ```typescript\n * try {\n * await vana.permissions.revoke({ permissionId: 999999 });\n * } catch (error) {\n * if (error instanceof PermissionError) {\n * console.error('Permission operation failed:', error.message);\n * // Permission may not exist or user may not be owner\n * }\n * }\n * ```\n * @category Error Handling\n */\nexport class PermissionError extends VanaError {\n constructor(\n message: string,\n public readonly originalError?: Error,\n ) {\n super(message, \"PERMISSION_ERROR\");\n }\n}\n\n/**\n * Thrown when attempting to perform write operations without a wallet client.\n *\n * @remarks\n * This error occurs when trying to execute operations that require wallet\n * interaction (signing, encrypting, or submitting transactions) while the SDK\n * is initialized in read-only mode without a wallet client. To perform write\n * operations, the SDK must be initialized with a wallet client.\n *\n * Common operations that require a wallet:\n * - Signing transactions or typed data\n * - Encrypting or decrypting files\n * - Granting or revoking permissions\n * - Uploading data to IPFS\n * - Submitting blockchain transactions\n *\n * @example\n * ```typescript\n * try {\n * // This will throw if no wallet client is provided\n * await vana.data.decryptFile({ fileId: 'abc123' });\n * } catch (error) {\n * if (error instanceof ReadOnlyError) {\n * console.error(`Cannot ${error.operation}: ${error.message}`);\n * // Initialize with wallet client to enable write operations\n * const vanaWithWallet = Vana({\n * walletClient: createWalletClient(...)\n * });\n * }\n * }\n * ```\n * @category Error Handling\n */\nexport class ReadOnlyError extends VanaError {\n constructor(\n operation: string,\n suggestion: string = \"Initialize the SDK with a walletClient to perform this operation\",\n ) {\n super(\n `Operation '${operation}' requires a wallet client. ${suggestion}`,\n \"READ_ONLY_ERROR\",\n );\n this.operation = operation;\n this.suggestion = suggestion;\n }\n\n /** The operation that was attempted */\n public readonly operation: string;\n /** Suggested solution for fixing the error */\n public readonly suggestion: string;\n}\n\n/**\n * Thrown when a long-running transaction operation times out or fails during polling.\n *\n * @remarks\n * This error occurs when asynchronous relayer operations exceed the configured timeout\n * or encounter non-recoverable errors during status polling. It preserves the operation ID\n * to allow recovery and status checking at a later time.\n *\n * The error includes:\n * - Operation ID for recovery and status checking\n * - Last known status before failure\n * - Original error details\n *\n * Recovery strategies:\n * - Save the operation ID for later status checking\n * - Implement manual recovery flow using the operation ID\n * - Check transaction status through alternative means\n * - Contact support if operation remains stuck\n *\n * @example\n * ```typescript\n * try {\n * const result = await vana.permissions.grant({\n * grantee: '0x...',\n * files: [1, 2, 3]\n * });\n * } catch (error) {\n * if (error instanceof TransactionPendingError) {\n * // Save operation ID for recovery\n * localStorage.setItem('pending_operation', error.operationId);\n *\n * // Show recovery UI\n * showRecoveryDialog({\n * operationId: error.operationId,\n * lastStatus: error.lastKnownStatus\n * });\n *\n * // Attempt recovery later\n * const status = await vana.checkOperationStatus(error.operationId);\n * }\n * }\n * ```\n * @category Error Handling\n */\nexport class TransactionPendingError extends VanaError {\n constructor(\n /** The operation ID that can be used for status checking */\n public readonly operationId: string,\n message: string,\n /** The last known status of the operation before failure */\n public readonly lastKnownStatus?: unknown,\n ) {\n super(\n `Transaction operation pending: ${message} (operationId: ${operationId})`,\n \"TRANSACTION_PENDING\",\n );\n }\n\n /**\n * Converts the error to a JSON-serializable format.\n *\n * @remarks\n * Useful for logging, storage, or transmission of error details.\n *\n * @returns JSON representation of the error\n */\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n operationId: this.operationId,\n lastKnownStatus: this.lastKnownStatus,\n };\n }\n}\n"],"mappings":"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","names":[]}
|