@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.
Files changed (351) hide show
  1. package/dist/browser.cjs.map +1 -1
  2. package/dist/browser.d.ts +33 -1
  3. package/dist/browser.js.map +1 -1
  4. package/dist/chains/index.cjs.map +1 -1
  5. package/dist/chains/index.d.ts +30 -1
  6. package/dist/chains/index.js.map +1 -1
  7. package/dist/client/__tests__/enhancedResponse.test.d.ts +1 -0
  8. package/dist/client/enhancedResponse.cjs +164 -0
  9. package/dist/client/enhancedResponse.cjs.map +1 -0
  10. package/dist/client/enhancedResponse.d.ts +120 -0
  11. package/dist/client/enhancedResponse.js +138 -0
  12. package/dist/client/enhancedResponse.js.map +1 -0
  13. package/dist/config/chains.cjs.map +1 -1
  14. package/dist/config/chains.d.ts +99 -0
  15. package/dist/config/chains.js.map +1 -1
  16. package/dist/contracts/contractController.cjs.map +1 -1
  17. package/dist/contracts/contractController.d.ts +66 -10
  18. package/dist/contracts/contractController.js.map +1 -1
  19. package/dist/controllers/__tests__/data-consistency-integration.test.d.ts +7 -0
  20. package/dist/controllers/__tests__/operations.processQueue.test.d.ts +1 -0
  21. package/dist/controllers/base.cjs +33 -0
  22. package/dist/controllers/base.cjs.map +1 -1
  23. package/dist/controllers/base.d.ts +10 -0
  24. package/dist/controllers/base.js +33 -0
  25. package/dist/controllers/base.js.map +1 -1
  26. package/dist/controllers/data.cjs +417 -276
  27. package/dist/controllers/data.cjs.map +1 -1
  28. package/dist/controllers/data.d.ts +246 -193
  29. package/dist/controllers/data.js +430 -279
  30. package/dist/controllers/data.js.map +1 -1
  31. package/dist/controllers/operations.cjs +430 -0
  32. package/dist/controllers/operations.cjs.map +1 -0
  33. package/dist/controllers/operations.d.ts +229 -0
  34. package/dist/controllers/operations.js +406 -0
  35. package/dist/controllers/operations.js.map +1 -0
  36. package/dist/controllers/permissions.cjs +690 -209
  37. package/dist/controllers/permissions.cjs.map +1 -1
  38. package/dist/controllers/permissions.d.ts +196 -68
  39. package/dist/controllers/permissions.js +690 -209
  40. package/dist/controllers/permissions.js.map +1 -1
  41. package/dist/controllers/protocol.cjs.map +1 -1
  42. package/dist/controllers/protocol.d.ts +27 -28
  43. package/dist/controllers/protocol.js.map +1 -1
  44. package/dist/controllers/schemas.cjs +104 -25
  45. package/dist/controllers/schemas.cjs.map +1 -1
  46. package/dist/controllers/schemas.d.ts +88 -40
  47. package/dist/controllers/schemas.js +104 -25
  48. package/dist/controllers/schemas.js.map +1 -1
  49. package/dist/controllers/server.cjs +269 -58
  50. package/dist/controllers/server.cjs.map +1 -1
  51. package/dist/controllers/server.d.ts +157 -52
  52. package/dist/controllers/server.js +269 -58
  53. package/dist/controllers/server.js.map +1 -1
  54. package/dist/core/__tests__/health.test.d.ts +1 -0
  55. package/dist/core/__tests__/inMemoryNonceManager.test.d.ts +1 -0
  56. package/dist/core/__tests__/nonceManager.test.d.ts +1 -0
  57. package/dist/core/__tests__/pollingManager.test.d.ts +4 -0
  58. package/dist/core/apiClient.cjs +53 -3
  59. package/dist/core/apiClient.cjs.map +1 -1
  60. package/dist/core/apiClient.d.ts +132 -7
  61. package/dist/core/apiClient.js +53 -3
  62. package/dist/core/apiClient.js.map +1 -1
  63. package/dist/core/generics.cjs +30 -3
  64. package/dist/core/generics.cjs.map +1 -1
  65. package/dist/core/generics.d.ts +95 -6
  66. package/dist/core/generics.js +30 -3
  67. package/dist/core/generics.js.map +1 -1
  68. package/dist/core/health.cjs +289 -0
  69. package/dist/core/health.cjs.map +1 -0
  70. package/dist/core/health.d.ts +143 -0
  71. package/dist/core/health.js +265 -0
  72. package/dist/core/health.js.map +1 -0
  73. package/dist/core/inMemoryNonceManager.cjs +138 -0
  74. package/dist/core/inMemoryNonceManager.cjs.map +1 -0
  75. package/dist/core/inMemoryNonceManager.d.ts +69 -0
  76. package/dist/core/inMemoryNonceManager.js +114 -0
  77. package/dist/core/inMemoryNonceManager.js.map +1 -0
  78. package/dist/core/nonceManager.cjs +304 -0
  79. package/dist/core/nonceManager.cjs.map +1 -0
  80. package/dist/core/nonceManager.d.ts +116 -0
  81. package/dist/core/nonceManager.js +280 -0
  82. package/dist/core/nonceManager.js.map +1 -0
  83. package/dist/core/pollingManager.cjs +292 -0
  84. package/dist/core/pollingManager.cjs.map +1 -0
  85. package/dist/core/pollingManager.d.ts +120 -0
  86. package/dist/core/pollingManager.js +268 -0
  87. package/dist/core/pollingManager.js.map +1 -0
  88. package/dist/core.cjs +55 -1
  89. package/dist/core.cjs.map +1 -1
  90. package/dist/core.d.ts +54 -3
  91. package/dist/core.js +55 -1
  92. package/dist/core.js.map +1 -1
  93. package/dist/crypto/ecies/base.cjs +16 -3
  94. package/dist/crypto/ecies/base.cjs.map +1 -1
  95. package/dist/crypto/ecies/base.js +16 -3
  96. package/dist/crypto/ecies/base.js.map +1 -1
  97. package/dist/errors.cjs +29 -0
  98. package/dist/errors.cjs.map +1 -1
  99. package/dist/errors.d.ts +64 -0
  100. package/dist/errors.js +28 -0
  101. package/dist/errors.js.map +1 -1
  102. package/dist/generated/abi/ComputeInstructionRegistryImplementation.cjs.map +1 -1
  103. package/dist/generated/abi/ComputeInstructionRegistryImplementation.js.map +1 -1
  104. package/dist/generated/abi/DLPPerformanceImplementation.cjs +42 -0
  105. package/dist/generated/abi/DLPPerformanceImplementation.cjs.map +1 -1
  106. package/dist/generated/abi/DLPPerformanceImplementation.d.ts +32 -0
  107. package/dist/generated/abi/DLPPerformanceImplementation.js +42 -0
  108. package/dist/generated/abi/DLPPerformanceImplementation.js.map +1 -1
  109. package/dist/generated/abi/DLPRegistryImplementation.cjs +5 -5
  110. package/dist/generated/abi/DLPRegistryImplementation.cjs.map +1 -1
  111. package/dist/generated/abi/DLPRegistryImplementation.d.ts +4 -4
  112. package/dist/generated/abi/DLPRegistryImplementation.js +5 -5
  113. package/dist/generated/abi/DLPRegistryImplementation.js.map +1 -1
  114. package/dist/generated/abi/DLPRewardDeployerImplementation.cjs +166 -2
  115. package/dist/generated/abi/DLPRewardDeployerImplementation.cjs.map +1 -1
  116. package/dist/generated/abi/DLPRewardDeployerImplementation.d.ts +129 -2
  117. package/dist/generated/abi/DLPRewardDeployerImplementation.js +166 -2
  118. package/dist/generated/abi/DLPRewardDeployerImplementation.js.map +1 -1
  119. package/dist/generated/abi/DataPortabilityGranteesImplementation.cjs +167 -19
  120. package/dist/generated/abi/DataPortabilityGranteesImplementation.cjs.map +1 -1
  121. package/dist/generated/abi/DataPortabilityGranteesImplementation.d.ts +127 -14
  122. package/dist/generated/abi/DataPortabilityGranteesImplementation.js +167 -19
  123. package/dist/generated/abi/DataPortabilityGranteesImplementation.js.map +1 -1
  124. package/dist/generated/abi/DataPortabilityPermissionsImplementation.cjs +0 -19
  125. package/dist/generated/abi/DataPortabilityPermissionsImplementation.cjs.map +1 -1
  126. package/dist/generated/abi/DataPortabilityPermissionsImplementation.d.ts +0 -14
  127. package/dist/generated/abi/DataPortabilityPermissionsImplementation.js +0 -19
  128. package/dist/generated/abi/DataPortabilityPermissionsImplementation.js.map +1 -1
  129. package/dist/generated/abi/DataPortabilityServersImplementation.cjs +0 -19
  130. package/dist/generated/abi/DataPortabilityServersImplementation.cjs.map +1 -1
  131. package/dist/generated/abi/DataPortabilityServersImplementation.d.ts +0 -14
  132. package/dist/generated/abi/DataPortabilityServersImplementation.js +0 -19
  133. package/dist/generated/abi/DataPortabilityServersImplementation.js.map +1 -1
  134. package/dist/generated/abi/DataRegistryImplementation.cjs +0 -13
  135. package/dist/generated/abi/DataRegistryImplementation.cjs.map +1 -1
  136. package/dist/generated/abi/DataRegistryImplementation.d.ts +0 -10
  137. package/dist/generated/abi/DataRegistryImplementation.js +0 -13
  138. package/dist/generated/abi/DataRegistryImplementation.js.map +1 -1
  139. package/dist/generated/abi/SwapHelperImplementation.cjs +0 -43
  140. package/dist/generated/abi/SwapHelperImplementation.cjs.map +1 -1
  141. package/dist/generated/abi/SwapHelperImplementation.d.ts +0 -35
  142. package/dist/generated/abi/SwapHelperImplementation.js +0 -43
  143. package/dist/generated/abi/SwapHelperImplementation.js.map +1 -1
  144. package/dist/generated/abi/VanaEpochImplementation.cjs +195 -0
  145. package/dist/generated/abi/VanaEpochImplementation.cjs.map +1 -1
  146. package/dist/generated/abi/VanaEpochImplementation.d.ts +151 -0
  147. package/dist/generated/abi/VanaEpochImplementation.js +195 -0
  148. package/dist/generated/abi/VanaEpochImplementation.js.map +1 -1
  149. package/dist/generated/abi/VanaPoolEntityImplementation.cjs +22 -65
  150. package/dist/generated/abi/VanaPoolEntityImplementation.cjs.map +1 -1
  151. package/dist/generated/abi/VanaPoolEntityImplementation.d.ts +17 -51
  152. package/dist/generated/abi/VanaPoolEntityImplementation.js +22 -65
  153. package/dist/generated/abi/VanaPoolEntityImplementation.js.map +1 -1
  154. package/dist/generated/abi/VanaPoolStakingImplementation.cjs +113 -1
  155. package/dist/generated/abi/VanaPoolStakingImplementation.cjs.map +1 -1
  156. package/dist/generated/abi/VanaPoolStakingImplementation.d.ts +85 -1
  157. package/dist/generated/abi/VanaPoolStakingImplementation.js +113 -1
  158. package/dist/generated/abi/VanaPoolStakingImplementation.js.map +1 -1
  159. package/dist/generated/abi/index.d.ts +546 -146
  160. package/dist/generated/event-types.cjs.map +1 -1
  161. package/dist/generated/event-types.d.ts +14 -8
  162. package/dist/generated/eventRegistry.cjs +42 -18
  163. package/dist/generated/eventRegistry.cjs.map +1 -1
  164. package/dist/generated/eventRegistry.js +42 -18
  165. package/dist/generated/eventRegistry.js.map +1 -1
  166. package/dist/generated/server/server-exports.cjs +22 -0
  167. package/dist/generated/server/server-exports.cjs.map +1 -1
  168. package/dist/generated/server/server-exports.d.ts +27 -10
  169. package/dist/generated/server/server-exports.js +17 -0
  170. package/dist/generated/server/server-exports.js.map +1 -1
  171. package/dist/generated/server/server.cjs.map +1 -1
  172. package/dist/generated/server/server.d.ts +771 -402
  173. package/dist/generated/subgraph.cjs +797 -32
  174. package/dist/generated/subgraph.cjs.map +1 -1
  175. package/dist/generated/subgraph.d.ts +135 -0
  176. package/dist/generated/subgraph.js +792 -32
  177. package/dist/generated/subgraph.js.map +1 -1
  178. package/dist/index.browser.d.ts +2 -0
  179. package/dist/index.browser.js +10 -0
  180. package/dist/index.browser.js.map +1 -1
  181. package/dist/index.cjs.map +1 -1
  182. package/dist/index.js.map +1 -1
  183. package/dist/index.node.cjs +26 -0
  184. package/dist/index.node.cjs.map +1 -1
  185. package/dist/index.node.d.ts +49 -5
  186. package/dist/index.node.js +25 -1
  187. package/dist/index.node.js.map +1 -1
  188. package/dist/lib/__tests__/redisAtomicStore.test.d.ts +1 -0
  189. package/dist/lib/redisAtomicStore.cjs +201 -0
  190. package/dist/lib/redisAtomicStore.cjs.map +1 -0
  191. package/dist/lib/redisAtomicStore.d.ts +120 -0
  192. package/dist/lib/redisAtomicStore.js +177 -0
  193. package/dist/lib/redisAtomicStore.js.map +1 -0
  194. package/dist/node.cjs.map +1 -1
  195. package/dist/node.d.ts +39 -1
  196. package/dist/node.js.map +1 -1
  197. package/dist/platform/browser.cjs +160 -2
  198. package/dist/platform/browser.cjs.map +1 -1
  199. package/dist/platform/browser.d.ts +232 -12
  200. package/dist/platform/browser.js +160 -2
  201. package/dist/platform/browser.js.map +1 -1
  202. package/dist/platform/interface.cjs.map +1 -1
  203. package/dist/platform/interface.d.ts +283 -90
  204. package/dist/platform/node.cjs +163 -2
  205. package/dist/platform/node.cjs.map +1 -1
  206. package/dist/platform/node.d.ts +69 -6
  207. package/dist/platform/node.js +163 -2
  208. package/dist/platform/node.js.map +1 -1
  209. package/dist/server/relayerHandler.cjs +315 -81
  210. package/dist/server/relayerHandler.cjs.map +1 -1
  211. package/dist/server/relayerHandler.d.ts +35 -2
  212. package/dist/server/relayerHandler.js +315 -81
  213. package/dist/server/relayerHandler.js.map +1 -1
  214. package/dist/storage/index.cjs +3 -0
  215. package/dist/storage/index.cjs.map +1 -1
  216. package/dist/storage/index.d.ts +1 -0
  217. package/dist/storage/index.js +2 -0
  218. package/dist/storage/index.js.map +1 -1
  219. package/dist/storage/manager.cjs +108 -25
  220. package/dist/storage/manager.cjs.map +1 -1
  221. package/dist/storage/manager.d.ts +119 -25
  222. package/dist/storage/manager.js +108 -25
  223. package/dist/storage/manager.js.map +1 -1
  224. package/dist/storage/providers/callback-storage.cjs +86 -15
  225. package/dist/storage/providers/callback-storage.cjs.map +1 -1
  226. package/dist/storage/providers/callback-storage.d.ts +109 -20
  227. package/dist/storage/providers/callback-storage.js +86 -15
  228. package/dist/storage/providers/callback-storage.js.map +1 -1
  229. package/dist/storage/providers/dropbox.cjs +237 -0
  230. package/dist/storage/providers/dropbox.cjs.map +1 -0
  231. package/dist/storage/providers/dropbox.d.ts +39 -0
  232. package/dist/storage/providers/dropbox.js +215 -0
  233. package/dist/storage/providers/dropbox.js.map +1 -0
  234. package/dist/storage/providers/dropbox.test.d.ts +1 -0
  235. package/dist/storage/providers/pinata.cjs.map +1 -1
  236. package/dist/storage/providers/pinata.d.ts +12 -14
  237. package/dist/storage/providers/pinata.js.map +1 -1
  238. package/dist/tests/data-upload-owner-validation.test.d.ts +1 -0
  239. package/dist/tests/permissions-transaction-options.test.d.ts +1 -0
  240. package/dist/types/atomicStore.cjs +31 -0
  241. package/dist/types/atomicStore.cjs.map +1 -0
  242. package/dist/types/atomicStore.d.ts +236 -0
  243. package/dist/types/atomicStore.js +7 -0
  244. package/dist/types/atomicStore.js.map +1 -0
  245. package/dist/types/blockchain.cjs.map +1 -1
  246. package/dist/types/blockchain.d.ts +39 -11
  247. package/dist/types/chains.cjs.map +1 -1
  248. package/dist/types/chains.d.ts +74 -7
  249. package/dist/types/chains.js.map +1 -1
  250. package/dist/types/config.cjs.map +1 -1
  251. package/dist/types/config.d.ts +38 -4
  252. package/dist/types/config.js.map +1 -1
  253. package/dist/types/contracts.cjs.map +1 -1
  254. package/dist/types/contracts.d.ts +71 -7
  255. package/dist/types/controller-context.cjs.map +1 -1
  256. package/dist/types/controller-context.d.ts +4 -1
  257. package/dist/types/data.cjs.map +1 -1
  258. package/dist/types/data.d.ts +11 -10
  259. package/dist/types/generics.cjs.map +1 -1
  260. package/dist/types/generics.d.ts +81 -10
  261. package/dist/types/index.cjs.map +1 -1
  262. package/dist/types/index.d.ts +31 -3
  263. package/dist/types/index.js.map +1 -1
  264. package/dist/types/operationStore.cjs +17 -0
  265. package/dist/types/operationStore.cjs.map +1 -0
  266. package/dist/types/operationStore.d.ts +171 -0
  267. package/dist/types/operationStore.js +1 -0
  268. package/dist/types/operationStore.js.map +1 -0
  269. package/dist/types/operations.cjs +3 -15
  270. package/dist/types/operations.cjs.map +1 -1
  271. package/dist/types/operations.d.ts +131 -39
  272. package/dist/types/operations.js +2 -13
  273. package/dist/types/operations.js.map +1 -1
  274. package/dist/types/options.cjs +17 -0
  275. package/dist/types/options.cjs.map +1 -0
  276. package/dist/types/options.d.ts +308 -0
  277. package/dist/types/options.js +1 -0
  278. package/dist/types/options.js.map +1 -0
  279. package/dist/types/permissions.cjs.map +1 -1
  280. package/dist/types/permissions.d.ts +19 -20
  281. package/dist/types/personal.cjs.map +1 -1
  282. package/dist/types/personal.d.ts +150 -14
  283. package/dist/types/relayer.cjs.map +1 -1
  284. package/dist/types/relayer.d.ts +145 -24
  285. package/dist/types/storage.cjs.map +1 -1
  286. package/dist/types/storage.d.ts +9 -21
  287. package/dist/types/storage.js.map +1 -1
  288. package/dist/types/utils.cjs.map +1 -1
  289. package/dist/types/utils.d.ts +0 -45
  290. package/dist/utils/__tests__/chainQuery.test.d.ts +1 -0
  291. package/dist/utils/__tests__/subgraphConsistency.test.d.ts +4 -0
  292. package/dist/utils/__tests__/subgraphPagination.test.d.ts +4 -0
  293. package/dist/utils/chainQuery.cjs +107 -0
  294. package/dist/utils/chainQuery.cjs.map +1 -0
  295. package/dist/utils/chainQuery.d.ts +31 -0
  296. package/dist/utils/chainQuery.js +82 -0
  297. package/dist/utils/chainQuery.js.map +1 -0
  298. package/dist/utils/grantFiles.cjs +4 -1
  299. package/dist/utils/grantFiles.cjs.map +1 -1
  300. package/dist/utils/grantFiles.d.ts +10 -20
  301. package/dist/utils/grantFiles.js +4 -1
  302. package/dist/utils/grantFiles.js.map +1 -1
  303. package/dist/utils/grantValidation.cjs.map +1 -1
  304. package/dist/utils/grantValidation.d.ts +95 -16
  305. package/dist/utils/grantValidation.js.map +1 -1
  306. package/dist/utils/grants.cjs.map +1 -1
  307. package/dist/utils/grants.d.ts +93 -12
  308. package/dist/utils/grants.js.map +1 -1
  309. package/dist/utils/ipfs.cjs +2 -4
  310. package/dist/utils/ipfs.cjs.map +1 -1
  311. package/dist/utils/ipfs.d.ts +1 -1
  312. package/dist/utils/ipfs.js +2 -4
  313. package/dist/utils/ipfs.js.map +1 -1
  314. package/dist/utils/lazy-import.cjs.map +1 -1
  315. package/dist/utils/lazy-import.d.ts +32 -7
  316. package/dist/utils/lazy-import.js.map +1 -1
  317. package/dist/utils/signatureCache.cjs +8 -2
  318. package/dist/utils/signatureCache.cjs.map +1 -1
  319. package/dist/utils/signatureCache.d.ts +49 -8
  320. package/dist/utils/signatureCache.js +8 -2
  321. package/dist/utils/signatureCache.js.map +1 -1
  322. package/dist/utils/subgraphConsistency.cjs +184 -0
  323. package/dist/utils/subgraphConsistency.cjs.map +1 -0
  324. package/dist/utils/subgraphConsistency.d.ts +65 -0
  325. package/dist/utils/subgraphConsistency.js +155 -0
  326. package/dist/utils/subgraphConsistency.js.map +1 -0
  327. package/dist/utils/subgraphMetaCache.cjs +101 -0
  328. package/dist/utils/subgraphMetaCache.cjs.map +1 -0
  329. package/dist/utils/subgraphMetaCache.d.ts +56 -0
  330. package/dist/utils/subgraphMetaCache.js +76 -0
  331. package/dist/utils/subgraphMetaCache.js.map +1 -0
  332. package/dist/utils/subgraphPagination.cjs +104 -0
  333. package/dist/utils/subgraphPagination.cjs.map +1 -0
  334. package/dist/utils/subgraphPagination.d.ts +78 -0
  335. package/dist/utils/subgraphPagination.js +78 -0
  336. package/dist/utils/subgraphPagination.js.map +1 -0
  337. package/dist/utils/transactionHelpers.cjs.map +1 -1
  338. package/dist/utils/transactionHelpers.d.ts +12 -12
  339. package/dist/utils/transactionHelpers.js.map +1 -1
  340. package/dist/utils/typedDataConverter.cjs.map +1 -1
  341. package/dist/utils/typedDataConverter.d.ts +39 -3
  342. package/dist/utils/typedDataConverter.js.map +1 -1
  343. package/dist/utils/urlResolver.cjs +7 -0
  344. package/dist/utils/urlResolver.cjs.map +1 -1
  345. package/dist/utils/urlResolver.d.ts +22 -4
  346. package/dist/utils/urlResolver.js +7 -0
  347. package/dist/utils/urlResolver.js.map +1 -1
  348. package/dist/utils/wallet.cjs.map +1 -1
  349. package/dist/utils/wallet.d.ts +78 -16
  350. package/dist/utils/wallet.js.map +1 -1
  351. package/package.json +3 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/storage/manager.ts"],"sourcesContent":["import type {\n StorageProvider,\n StorageUploadResult,\n StorageFile,\n StorageListOptions,\n} from \"../types/storage\";\nimport { StorageError } from \"../types/storage\";\n\n/**\n * Manages multiple storage providers with a unified interface for file operations.\n *\n * @remarks\n * The StorageManager provides a consistent API for uploading, downloading, and managing\n * files across different storage backends including IPFS, Pinata, Google Drive, and\n * server-managed storage. It handles provider registration, default provider selection,\n * and automatic fallback scenarios for robust file operations.\n *\n * Used internally by DataController for encrypted file storage, but can also be used\n * directly for custom storage workflows. Each provider implements the `StorageProvider`\n * interface to ensure consistent behavior across different storage backends.\n *\n * The manager supports provider-specific configurations and features while maintaining\n * a uniform API surface for applications.\n * @example\n * ```typescript\n * import { StorageManager, IPFSStorage, PinataStorage } from '@opendatalabs/vana-sdk';\n *\n * const storage = new StorageManager();\n *\n * // Register multiple providers\n * storage.register('ipfs', new IPFSStorage({\n * apiEndpoint: 'https://api.pinata.cloud/pinning/pinFileToIPFS'\n * }), true);\n * storage.register('pinata', new PinataStorage({\n * jwt: 'your-pinata-jwt-token'\n * }));\n *\n * // Upload to default provider\n * const result = await storage.upload(fileBlob, 'myfile.json');\n *\n * // Upload to specific provider\n * const result2 = await storage.upload(fileBlob, 'myfile.json', 'pinata');\n * ```\n * @category Storage\n * @see {@link https://docs.vana.com/developer/vana-sdk-documentation/core-modules/storage-providers | Storage Providers Guide} for configuration details\n */\nexport class StorageManager {\n private providers: Map<string, StorageProvider> = new Map();\n private defaultProvider: string | null = null;\n\n /**\n * Registers a storage provider with the manager.\n *\n * @remarks\n * This method adds a new storage provider to the manager's registry and optionally\n * sets it as the default provider for subsequent operations. If no default provider\n * is currently set, the first registered provider automatically becomes the default.\n * @param name - Unique identifier for the provider\n * @param provider - The storage provider instance implementing the `StorageProvider` interface\n * @param isDefault - Whether this provider should be set as the default (defaults to `false`)\n * @example\n * ```typescript\n * const pinata = new PinataStorage({ jwt: 'your-jwt-token' });\n * storage.register('pinata', pinata, true); // Set as default\n *\n * const ipfs = new IPFSStorage({ apiEndpoint: 'https://...' });\n * storage.register('ipfs', ipfs); // Not default\n * ```\n */\n register(name: string, provider: StorageProvider, isDefault = false): void {\n this.providers.set(name, provider);\n\n if (isDefault || this.defaultProvider === null) {\n this.defaultProvider = name;\n }\n }\n\n /**\n * Get a registered storage provider\n *\n * @param name - Provider identifier, uses default if not specified\n * @returns Storage provider instance\n */\n getProvider(name?: string): StorageProvider {\n const providerName = name ?? this.defaultProvider;\n\n if (!providerName) {\n throw new StorageError(\n \"No storage provider specified and no default provider set\",\n \"NO_PROVIDER\",\n \"manager\",\n );\n }\n\n const provider = this.providers.get(providerName);\n if (!provider) {\n throw new StorageError(\n `Storage provider '${providerName}' not found`,\n \"PROVIDER_NOT_FOUND\",\n \"manager\",\n );\n }\n\n return provider;\n }\n\n /**\n * List all registered providers\n *\n * @returns Array of provider names\n */\n listProviders(): string[] {\n return Array.from(this.providers.keys());\n }\n\n /**\n * Get the default provider name\n *\n * @returns Default provider name or null\n */\n getDefaultProvider(): string | null {\n return this.defaultProvider;\n }\n\n /**\n * Set the default provider\n *\n * @param name - Provider identifier\n */\n setDefaultProvider(name: string): void {\n if (!this.providers.has(name)) {\n throw new StorageError(\n `Cannot set default provider '${name}': provider not registered`,\n \"PROVIDER_NOT_FOUND\",\n \"manager\",\n );\n }\n this.defaultProvider = name;\n }\n\n /**\n * Uploads a file using the specified or default storage provider.\n *\n * @remarks\n * This method uploads a file to the specified provider or falls back to the default\n * provider if none is specified. The upload result includes the storage URL, file size,\n * content type, and provider-specific metadata that can be used for subsequent operations.\n * @param file - The file blob to upload\n * @param filename - Optional custom filename (defaults to auto-generated name)\n * @param providerName - Optional provider identifier (uses default if not specified)\n * @returns A Promise that resolves to the storage upload result with URL and metadata\n * @throws {StorageError} When no provider is available or upload fails\n * @example\n * ```typescript\n * // Upload to default provider\n * const result = await storage.upload(fileBlob, 'data.json');\n * console.log(`Uploaded to: ${result.url}`);\n *\n * // Upload to specific provider\n * const result2 = await storage.upload(fileBlob, 'data.json', 'pinata');\n * ```\n */\n async upload(\n file: Blob,\n filename?: string,\n providerName?: string,\n ): Promise<StorageUploadResult> {\n const provider = this.getProvider(providerName);\n return provider.upload(file, filename);\n }\n\n /**\n * Download a file using the specified or default provider\n *\n * @param url - The storage URL\n * @param providerName - Optional provider to use\n * @returns Promise with file blob\n */\n async download(url: string, providerName?: string): Promise<Blob> {\n const provider = this.getProvider(providerName);\n return provider.download(url);\n }\n\n /**\n * List files using the specified or default provider\n *\n * @param options - Optional filtering and pagination\n * @param providerName - Optional provider to use\n * @returns Promise with file list\n */\n async list(\n options?: StorageListOptions,\n providerName?: string,\n ): Promise<StorageFile[]> {\n const provider = this.getProvider(providerName);\n return provider.list(options);\n }\n\n /**\n * Delete a file using the specified or default provider\n *\n * @param url - The storage URL\n * @param providerName - Optional provider to use\n * @returns Promise with success status\n */\n async delete(url: string, providerName?: string): Promise<boolean> {\n const provider = this.getProvider(providerName);\n return provider.delete(url);\n }\n\n /**\n * Get list of registered storage provider names\n *\n * @returns Array of provider names\n */\n getStorageProviders(): string[] {\n return Array.from(this.providers.keys());\n }\n\n /**\n * Get the default storage provider name\n *\n * @returns Default provider name or undefined\n */\n getDefaultStorageProvider(): string | undefined {\n return this.defaultProvider ?? undefined;\n }\n}\n"],"mappings":"AAMA,SAAS,oBAAoB;AAwCtB,MAAM,eAAe;AAAA,EAClB,YAA0C,oBAAI,IAAI;AAAA,EAClD,kBAAiC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBzC,SAAS,MAAc,UAA2B,YAAY,OAAa;AACzE,SAAK,UAAU,IAAI,MAAM,QAAQ;AAEjC,QAAI,aAAa,KAAK,oBAAoB,MAAM;AAC9C,WAAK,kBAAkB;AAAA,IACzB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAY,MAAgC;AAC1C,UAAM,eAAe,QAAQ,KAAK;AAElC,QAAI,CAAC,cAAc;AACjB,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,WAAW,KAAK,UAAU,IAAI,YAAY;AAChD,QAAI,CAAC,UAAU;AACb,YAAM,IAAI;AAAA,QACR,qBAAqB,YAAY;AAAA,QACjC;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,gBAA0B;AACxB,WAAO,MAAM,KAAK,KAAK,UAAU,KAAK,CAAC;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,qBAAoC;AAClC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,mBAAmB,MAAoB;AACrC,QAAI,CAAC,KAAK,UAAU,IAAI,IAAI,GAAG;AAC7B,YAAM,IAAI;AAAA,QACR,gCAAgC,IAAI;AAAA,QACpC;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,SAAK,kBAAkB;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAwBA,MAAM,OACJ,MACA,UACA,cAC8B;AAC9B,UAAM,WAAW,KAAK,YAAY,YAAY;AAC9C,WAAO,SAAS,OAAO,MAAM,QAAQ;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,SAAS,KAAa,cAAsC;AAChE,UAAM,WAAW,KAAK,YAAY,YAAY;AAC9C,WAAO,SAAS,SAAS,GAAG;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,KACJ,SACA,cACwB;AACxB,UAAM,WAAW,KAAK,YAAY,YAAY;AAC9C,WAAO,SAAS,KAAK,OAAO;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,OAAO,KAAa,cAAyC;AACjE,UAAM,WAAW,KAAK,YAAY,YAAY;AAC9C,WAAO,SAAS,OAAO,GAAG;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,sBAAgC;AAC9B,WAAO,MAAM,KAAK,KAAK,UAAU,KAAK,CAAC;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,4BAAgD;AAC9C,WAAO,KAAK,mBAAmB;AAAA,EACjC;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/storage/manager.ts"],"sourcesContent":["/**\n * Manages multiple storage providers with a unified interface.\n *\n * @remarks\n * This module provides centralized management of storage providers, enabling\n * applications to work with multiple storage backends through a single API.\n * It handles provider registration, default selection, and operation routing.\n *\n * @category Storage\n * @module storage/manager\n */\n\nimport type {\n StorageProvider,\n StorageUploadResult,\n StorageFile,\n StorageListOptions,\n} from \"../types/storage\";\nimport { StorageError } from \"../types/storage\";\n\n/**\n * Manages multiple storage providers with a unified interface for file operations.\n *\n * @remarks\n * The StorageManager provides a consistent API for uploading, downloading, and managing\n * files across different storage backends including IPFS, Pinata, Google Drive, and\n * server-managed storage. It handles provider registration, default provider selection,\n * and automatic fallback scenarios for robust file operations.\n *\n * Used internally by DataController for encrypted file storage, but can also be used\n * directly for custom storage workflows. Each provider implements the `StorageProvider`\n * interface to ensure consistent behavior across different storage backends.\n *\n * The manager supports provider-specific configurations and features while maintaining\n * a uniform API surface for applications.\n * @example\n * ```typescript\n * import { StorageManager, IPFSStorage, PinataStorage } from '@opendatalabs/vana-sdk';\n *\n * const storage = new StorageManager();\n *\n * // Register multiple providers\n * storage.register('ipfs', new IPFSStorage({\n * apiEndpoint: 'https://api.pinata.cloud/pinning/pinFileToIPFS'\n * }), true);\n * storage.register('pinata', new PinataStorage({\n * jwt: 'your-pinata-jwt-token'\n * }));\n *\n * // Upload to default provider\n * const result = await storage.upload(fileBlob, 'myfile.json');\n *\n * // Upload to specific provider\n * const result2 = await storage.upload(fileBlob, 'myfile.json', 'pinata');\n * ```\n * @category Storage\n * @see {@link https://docs.vana.com/developer/vana-sdk-documentation/core-modules/storage-providers | Storage Providers Guide} for configuration details\n */\nexport class StorageManager {\n private providers: Map<string, StorageProvider> = new Map();\n private defaultProvider: string | null = null;\n\n /**\n * Registers a storage provider with the manager.\n *\n * @remarks\n * This method adds a new storage provider to the manager's registry and optionally\n * sets it as the default provider for subsequent operations. If no default provider\n * is currently set, the first registered provider automatically becomes the default.\n * @param name - Unique identifier for the provider\n * @param provider - The storage provider instance implementing the `StorageProvider` interface\n * @param isDefault - Whether this provider should be set as the default (defaults to `false`)\n * @example\n * ```typescript\n * const pinata = new PinataStorage({ jwt: 'your-jwt-token' });\n * storage.register('pinata', pinata, true); // Set as default\n *\n * const ipfs = new IPFSStorage({ apiEndpoint: 'https://...' });\n * storage.register('ipfs', ipfs); // Not default\n * ```\n */\n register(name: string, provider: StorageProvider, isDefault = false): void {\n this.providers.set(name, provider);\n\n if (isDefault || this.defaultProvider === null) {\n this.defaultProvider = name;\n }\n }\n\n /**\n * Retrieves a registered storage provider.\n *\n * @param name - Provider identifier.\n * If not specified, returns the default provider.\n * @returns The requested storage provider instance\n *\n * @throws {StorageError} With code 'NO_PROVIDER' if no provider available\n * @throws {StorageError} With code 'PROVIDER_NOT_FOUND' if named provider doesn't exist\n *\n * @example\n * ```typescript\n * const provider = storage.getProvider('pinata');\n * const config = provider.getConfig();\n * ```\n */\n getProvider(name?: string): StorageProvider {\n const providerName = name ?? this.defaultProvider;\n\n if (!providerName) {\n throw new StorageError(\n \"No storage provider specified and no default provider set\",\n \"NO_PROVIDER\",\n \"manager\",\n );\n }\n\n const provider = this.providers.get(providerName);\n if (!provider) {\n throw new StorageError(\n `Storage provider '${providerName}' not found`,\n \"PROVIDER_NOT_FOUND\",\n \"manager\",\n );\n }\n\n return provider;\n }\n\n /**\n * Lists all registered provider names.\n *\n * @returns Array of registered provider identifiers\n *\n * @example\n * ```typescript\n * const providers = storage.listProviders();\n * console.log('Available providers:', providers);\n * // Output: ['ipfs', 'pinata', 'google-drive']\n * ```\n */\n listProviders(): string[] {\n return Array.from(this.providers.keys());\n }\n\n /**\n * Gets the current default provider name.\n *\n * @returns Default provider identifier or null if none set\n *\n * @example\n * ```typescript\n * const defaultName = storage.getDefaultProvider();\n * if (defaultName) {\n * console.log(`Using ${defaultName} by default`);\n * }\n * ```\n */\n getDefaultProvider(): string | null {\n return this.defaultProvider;\n }\n\n /**\n * Sets the default storage provider.\n *\n * @param name - Provider identifier to set as default.\n * Must be a registered provider name.\n *\n * @throws {StorageError} With code 'PROVIDER_NOT_FOUND' if provider not registered\n *\n * @example\n * ```typescript\n * storage.setDefaultProvider('pinata');\n * // Now all operations without provider name will use Pinata\n * ```\n */\n setDefaultProvider(name: string): void {\n if (!this.providers.has(name)) {\n throw new StorageError(\n `Cannot set default provider '${name}': provider not registered`,\n \"PROVIDER_NOT_FOUND\",\n \"manager\",\n );\n }\n this.defaultProvider = name;\n }\n\n /**\n * Uploads a file using the specified or default storage provider.\n *\n * @remarks\n * This method uploads a file to the specified provider or falls back to the default\n * provider if none is specified. The upload result includes the storage URL, file size,\n * content type, and provider-specific metadata that can be used for subsequent operations.\n * @param file - The file blob to upload\n * @param filename - Optional custom filename (defaults to auto-generated name)\n * @param providerName - Optional provider identifier (uses default if not specified)\n * @returns A Promise that resolves to the storage upload result with URL and metadata\n * @throws {StorageError} When no provider is available or upload fails\n * @example\n * ```typescript\n * // Upload to default provider\n * const result = await storage.upload(fileBlob, 'data.json');\n * console.log(`Uploaded to: ${result.url}`);\n *\n * // Upload to specific provider\n * const result2 = await storage.upload(fileBlob, 'data.json', 'pinata');\n * ```\n */\n async upload(\n file: Blob,\n filename?: string,\n providerName?: string,\n ): Promise<StorageUploadResult> {\n const provider = this.getProvider(providerName);\n return provider.upload(file, filename);\n }\n\n /**\n * Downloads a file from storage.\n *\n * @param url - The storage URL to download from.\n * Format depends on the storage provider.\n * @param providerName - Optional provider identifier.\n * Uses default provider if not specified.\n * @returns The downloaded file as a Blob\n *\n * @throws {StorageError} If download fails or provider unavailable\n *\n * @example\n * ```typescript\n * const blob = await storage.download('ipfs://QmXxx...');\n * const text = await blob.text();\n * ```\n */\n async download(url: string, providerName?: string): Promise<Blob> {\n const provider = this.getProvider(providerName);\n return provider.download(url);\n }\n\n /**\n * Lists files in storage.\n *\n * @param options - Optional filtering and pagination.\n * @param options.namePattern - Pattern to filter files.\n * @param options.limit - Maximum files to return.\n * @param providerName - Optional provider identifier.\n * Uses default provider if not specified.\n * @returns Array of file metadata\n *\n * @throws {StorageError} If listing fails or not supported by provider\n *\n * @example\n * ```typescript\n * const files = await storage.list(\n * { namePattern: '*.json', limit: 10 },\n * 'google-drive'\n * );\n * ```\n */\n async list(\n options?: StorageListOptions,\n providerName?: string,\n ): Promise<StorageFile[]> {\n const provider = this.getProvider(providerName);\n return provider.list(options);\n }\n\n /**\n * Deletes a file from storage.\n *\n * @param url - The storage URL to delete.\n * Must be a valid URL for the provider.\n * @param providerName - Optional provider identifier.\n * Uses default provider if not specified.\n * @returns True if deletion succeeded, false otherwise\n *\n * @throws {StorageError} If deletion fails or not supported by provider\n *\n * @example\n * ```typescript\n * const success = await storage.delete('ipfs://QmXxx...');\n * if (success) {\n * console.log('File deleted successfully');\n * }\n * ```\n */\n async delete(url: string, providerName?: string): Promise<boolean> {\n const provider = this.getProvider(providerName);\n return provider.delete(url);\n }\n\n /**\n * Gets all registered storage provider names.\n *\n * @returns Array of provider identifiers\n *\n * @deprecated Use `listProviders()` instead\n *\n * @example\n * ```typescript\n * const providers = storage.getStorageProviders();\n * ```\n */\n getStorageProviders(): string[] {\n return Array.from(this.providers.keys());\n }\n\n /**\n * Gets the default storage provider name.\n *\n * @returns Default provider identifier or undefined if none set\n *\n * @deprecated Use `getDefaultProvider()` instead\n *\n * @example\n * ```typescript\n * const defaultProvider = storage.getDefaultStorageProvider();\n * ```\n */\n getDefaultStorageProvider(): string | undefined {\n return this.defaultProvider ?? undefined;\n }\n}\n"],"mappings":"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","names":[]}
@@ -23,6 +23,13 @@ __export(callback_storage_exports, {
23
23
  module.exports = __toCommonJS(callback_storage_exports);
24
24
  var import_storage = require("../../types/storage");
25
25
  class CallbackStorage {
26
+ /**
27
+ * Creates a new callback-based storage provider.
28
+ *
29
+ * @param callbacks - User-provided storage operation callbacks.
30
+ * Must include at minimum `upload` and `download` functions.
31
+ * @throws {Error} If required callbacks are missing
32
+ */
26
33
  constructor(callbacks) {
27
34
  this.callbacks = callbacks;
28
35
  if (!callbacks.upload || !callbacks.download) {
@@ -32,11 +39,23 @@ class CallbackStorage {
32
39
  }
33
40
  }
34
41
  /**
35
- * Upload a file using the provided callback
42
+ * Uploads a file using the user-provided callback.
43
+ *
44
+ * @param file - The blob to upload.
45
+ * Can be any Blob-compatible object including File.
46
+ * @param filename - Optional filename for the upload.
47
+ * If not provided, callback may generate a name.
48
+ * @returns Upload result containing URL and metadata
36
49
  *
37
- * @param file - The blob to upload
38
- * @param filename - Optional filename for the upload
39
- * @returns The upload result with URL and metadata
50
+ * @throws {StorageError} With code 'INVALID_UPLOAD_RESULT' if callback returns invalid data
51
+ * @throws {StorageError} With code 'UPLOAD_ERROR' if upload fails
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * const file = new File(['content'], 'data.json');
56
+ * const result = await storage.upload(file);
57
+ * console.log('Uploaded to:', result.url);
58
+ * ```
40
59
  */
41
60
  async upload(file, filename) {
42
61
  try {
@@ -62,10 +81,20 @@ class CallbackStorage {
62
81
  }
63
82
  }
64
83
  /**
65
- * Download a file using the provided callback
84
+ * Downloads a file using the user-provided callback.
85
+ *
86
+ * @param url - The URL or identifier to download.
87
+ * If `extractIdentifier` callback is provided, it will be used to extract the identifier.
88
+ * @returns The downloaded file as a Blob
89
+ *
90
+ * @throws {StorageError} With code 'INVALID_DOWNLOAD_RESULT' if callback returns non-Blob
91
+ * @throws {StorageError} With code 'DOWNLOAD_ERROR' if download fails
66
92
  *
67
- * @param url - The URL or identifier to download
68
- * @returns The downloaded blob
93
+ * @example
94
+ * ```typescript
95
+ * const blob = await storage.download('https://storage.example.com/file123');
96
+ * const text = await blob.text();
97
+ * ```
69
98
  */
70
99
  async download(url) {
71
100
  try {
@@ -92,10 +121,27 @@ class CallbackStorage {
92
121
  }
93
122
  }
94
123
  /**
95
- * List files using the provided callback (if available)
124
+ * Lists files using the user-provided callback.
96
125
  *
97
- * @param options - Optional list options including filters and pagination
98
- * @returns Array of storage files
126
+ * @param options - Optional list options.
127
+ * @param options.namePattern - Pattern to filter files by name.
128
+ * Implementation depends on callback.
129
+ * @param options.limit - Maximum number of files to return.
130
+ * Implementation depends on callback.
131
+ * @returns Array of storage file metadata
132
+ *
133
+ * @throws {StorageError} With code 'NOT_SUPPORTED' if list callback not provided
134
+ * @throws {StorageError} With code 'LIST_ERROR' if listing fails
135
+ *
136
+ * @remarks
137
+ * This operation is optional and only available if a `list` callback
138
+ * is provided during construction.
139
+ *
140
+ * @example
141
+ * ```typescript
142
+ * const files = await storage.list({ namePattern: '*.json' });
143
+ * files.forEach(file => console.log(file.name, file.size));
144
+ * ```
99
145
  */
100
146
  async list(options) {
101
147
  if (!this.callbacks.list) {
@@ -126,10 +172,26 @@ class CallbackStorage {
126
172
  }
127
173
  }
128
174
  /**
129
- * Delete a file using the provided callback (if available)
175
+ * Deletes a file using the user-provided callback.
176
+ *
177
+ * @param url - The URL or identifier to delete.
178
+ * If `extractIdentifier` callback is provided, it will be used to extract the identifier.
179
+ * @returns True if deletion succeeded, false otherwise
130
180
  *
131
- * @param url - The URL or identifier to delete
132
- * @returns True if deletion succeeded
181
+ * @throws {StorageError} With code 'NOT_SUPPORTED' if delete callback not provided
182
+ * @throws {StorageError} With code 'DELETE_ERROR' if deletion fails
183
+ *
184
+ * @remarks
185
+ * This operation is optional and only available if a `delete` callback
186
+ * is provided during construction.
187
+ *
188
+ * @example
189
+ * ```typescript
190
+ * const deleted = await storage.delete('https://storage.example.com/file123');
191
+ * if (deleted) {
192
+ * console.log('File deleted successfully');
193
+ * }
194
+ * ```
133
195
  */
134
196
  async delete(url) {
135
197
  if (!this.callbacks.delete) {
@@ -152,9 +214,18 @@ class CallbackStorage {
152
214
  }
153
215
  }
154
216
  /**
155
- * Get provider configuration
217
+ * Returns the provider's configuration and capabilities.
218
+ *
219
+ * @returns Configuration object indicating supported features
156
220
  *
157
- * @returns Provider configuration metadata
221
+ * @example
222
+ * ```typescript
223
+ * const config = storage.getConfig();
224
+ * if (config.features.list) {
225
+ * // List operation is supported
226
+ * const files = await storage.list();
227
+ * }
228
+ * ```
158
229
  */
159
230
  getConfig() {
160
231
  return {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/storage/providers/callback-storage.ts"],"sourcesContent":["import type { StorageCallbacks } from \"../../types/config\";\nimport {\n StorageError,\n type StorageProvider,\n type StorageUploadResult,\n type StorageFile,\n type StorageListOptions,\n type StorageProviderConfig,\n} from \"../../types/storage\";\n\n/**\n * Storage provider that delegates all operations to user-provided callbacks.\n *\n * This provider follows the same flexible pattern as relayer callbacks,\n * allowing users to implement storage operations in any way they choose\n * (HTTP, WebSocket, direct cloud APIs, local filesystem, etc.).\n *\n * @category Storage\n * @example\n * ```typescript\n * // HTTP-based implementation\n * const httpCallbacks: StorageCallbacks = {\n * async upload(blob, filename) {\n * const formData = new FormData();\n * formData.append('file', blob, filename);\n * const response = await fetch('/api/storage/upload', {\n * method: 'POST',\n * body: formData\n * });\n * const data = await response.json();\n * return {\n * url: data.url,\n * size: blob.size,\n * contentType: blob.type\n * };\n * },\n * async download(identifier) {\n * const response = await fetch(`/api/storage/download/${identifier}`);\n * return response.blob();\n * }\n * };\n *\n * const storage = new CallbackStorage(httpCallbacks);\n *\n * // Direct S3 implementation\n * const s3Callbacks: StorageCallbacks = {\n * async upload(blob, filename) {\n * const url = await getPresignedUploadUrl(filename);\n * await fetch(url, { method: 'PUT', body: blob });\n * return {\n * url: `s3://my-bucket/${filename}`,\n * size: blob.size,\n * contentType: blob.type\n * };\n * },\n * async download(identifier) {\n * const url = await getPresignedDownloadUrl(identifier);\n * const response = await fetch(url);\n * return response.blob();\n * }\n * };\n * ```\n */\nexport class CallbackStorage implements StorageProvider {\n constructor(private readonly callbacks: StorageCallbacks) {\n if (!callbacks.upload || !callbacks.download) {\n throw new Error(\n \"CallbackStorage requires both upload and download callbacks\",\n );\n }\n }\n\n /**\n * Upload a file using the provided callback\n *\n * @param file - The blob to upload\n * @param filename - Optional filename for the upload\n * @returns The upload result with URL and metadata\n */\n async upload(file: Blob, filename?: string): Promise<StorageUploadResult> {\n try {\n const result = await this.callbacks.upload(file, filename);\n\n // Validate the result has required fields\n if (!result.url || result.url.trim() === \"\") {\n throw new StorageError(\n \"Upload callback returned invalid result: missing or empty url\",\n \"INVALID_UPLOAD_RESULT\",\n \"callback-storage\",\n );\n }\n\n return result;\n } catch (error) {\n if (error instanceof StorageError) {\n throw error;\n }\n throw new StorageError(\n `Upload failed: ${error instanceof Error ? error.message : String(error)}`,\n \"UPLOAD_ERROR\",\n \"callback-storage\",\n { cause: error instanceof Error ? error : undefined },\n );\n }\n }\n\n /**\n * Download a file using the provided callback\n *\n * @param url - The URL or identifier to download\n * @returns The downloaded blob\n */\n async download(url: string): Promise<Blob> {\n try {\n // Extract identifier if callback is provided, otherwise use URL as-is\n const identifier = this.callbacks.extractIdentifier\n ? this.callbacks.extractIdentifier(url)\n : url;\n\n const blob = await this.callbacks.download(identifier);\n\n if (!(blob instanceof Blob)) {\n throw new StorageError(\n \"Download callback returned invalid result: expected Blob\",\n \"INVALID_DOWNLOAD_RESULT\",\n \"callback-storage\",\n );\n }\n\n return blob;\n } catch (error) {\n if (error instanceof StorageError) {\n throw error;\n }\n throw new StorageError(\n `Download failed: ${error instanceof Error ? error.message : String(error)}`,\n \"DOWNLOAD_ERROR\",\n \"callback-storage\",\n { cause: error instanceof Error ? error : undefined },\n );\n }\n }\n\n /**\n * List files using the provided callback (if available)\n *\n * @param options - Optional list options including filters and pagination\n * @returns Array of storage files\n */\n async list(options?: StorageListOptions): Promise<StorageFile[]> {\n if (!this.callbacks.list) {\n throw new StorageError(\n \"List operation not supported - no list callback provided\",\n \"NOT_SUPPORTED\",\n \"callback-storage\",\n );\n }\n\n try {\n const result = await this.callbacks.list(options?.namePattern, options);\n\n // Convert list result to StorageFile format\n return result.items.map((item, index) => ({\n id: item.identifier,\n name: item.identifier.split(\"/\").pop() ?? `file-${index}`,\n url: item.identifier,\n size: item.size ?? 0,\n contentType: \"application/octet-stream\",\n createdAt: item.lastModified ?? new Date(),\n metadata: item.metadata,\n }));\n } catch (error) {\n throw new StorageError(\n `List failed: ${error instanceof Error ? error.message : String(error)}`,\n \"LIST_ERROR\",\n \"callback-storage\",\n { cause: error instanceof Error ? error : undefined },\n );\n }\n }\n\n /**\n * Delete a file using the provided callback (if available)\n *\n * @param url - The URL or identifier to delete\n * @returns True if deletion succeeded\n */\n async delete(url: string): Promise<boolean> {\n if (!this.callbacks.delete) {\n throw new StorageError(\n \"Delete operation not supported - no delete callback provided\",\n \"NOT_SUPPORTED\",\n \"callback-storage\",\n );\n }\n\n try {\n // Extract identifier if callback is provided, otherwise use URL as-is\n const identifier = this.callbacks.extractIdentifier\n ? this.callbacks.extractIdentifier(url)\n : url;\n\n return await this.callbacks.delete(identifier);\n } catch (error) {\n throw new StorageError(\n `Delete failed: ${error instanceof Error ? error.message : String(error)}`,\n \"DELETE_ERROR\",\n \"callback-storage\",\n { cause: error instanceof Error ? error : undefined },\n );\n }\n }\n\n /**\n * Get provider configuration\n *\n * @returns Provider configuration metadata\n */\n getConfig(): StorageProviderConfig {\n return {\n name: \"callback-storage\",\n type: \"callback\",\n requiresAuth: false,\n features: {\n upload: true,\n download: true,\n list: !!this.callbacks.list,\n delete: !!this.callbacks.delete,\n },\n };\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/storage/providers/callback-storage.ts"],"sourcesContent":["/**\n * Provides user-defined storage operations through callback functions.\n *\n * @remarks\n * This module implements a flexible storage provider that delegates all\n * operations to user-provided callbacks. It enables custom storage\n * integrations without modifying the SDK, supporting any backend including\n * HTTP APIs, WebSocket servers, cloud storage services, or local filesystems.\n *\n * @category Storage\n * @module storage/providers/callback-storage\n */\n\nimport type { StorageCallbacks } from \"../../types/config\";\nimport {\n StorageError,\n type StorageProvider,\n type StorageUploadResult,\n type StorageFile,\n type StorageListOptions,\n type StorageProviderConfig,\n} from \"../../types/storage\";\n\n/**\n * Delegates storage operations to user-provided callback functions.\n *\n * @remarks\n * This provider enables custom storage integrations by delegating all\n * operations to user-defined callbacks. It follows the same flexible\n * pattern as relayer callbacks, allowing implementations via HTTP,\n * WebSocket, direct cloud APIs, local filesystem, or any other backend.\n *\n * The provider validates callback results and wraps errors in consistent\n * `StorageError` types for uniform error handling across the SDK.\n *\n * @example\n * ```typescript\n * // HTTP-based implementation\n * const httpCallbacks: StorageCallbacks = {\n * async upload(blob, filename) {\n * const formData = new FormData();\n * formData.append('file', blob, filename);\n * const response = await fetch('/api/storage/upload', {\n * method: 'POST',\n * body: formData\n * });\n * const data = await response.json();\n * return {\n * url: data.url,\n * size: blob.size,\n * contentType: blob.type\n * };\n * },\n * async download(identifier) {\n * const response = await fetch(`/api/storage/download/${identifier}`);\n * return response.blob();\n * }\n * };\n *\n * const storage = new CallbackStorage(httpCallbacks);\n *\n * // Direct S3 implementation\n * const s3Callbacks: StorageCallbacks = {\n * async upload(blob, filename) {\n * const url = await getPresignedUploadUrl(filename);\n * await fetch(url, { method: 'PUT', body: blob });\n * return {\n * url: `s3://my-bucket/${filename}`,\n * size: blob.size,\n * contentType: blob.type\n * };\n * },\n * async download(identifier) {\n * const url = await getPresignedDownloadUrl(identifier);\n * const response = await fetch(url);\n * return response.blob();\n * }\n * };\n * ```\n *\n * @category Storage\n */\nexport class CallbackStorage implements StorageProvider {\n /**\n * Creates a new callback-based storage provider.\n *\n * @param callbacks - User-provided storage operation callbacks.\n * Must include at minimum `upload` and `download` functions.\n * @throws {Error} If required callbacks are missing\n */\n constructor(private readonly callbacks: StorageCallbacks) {\n if (!callbacks.upload || !callbacks.download) {\n throw new Error(\n \"CallbackStorage requires both upload and download callbacks\",\n );\n }\n }\n\n /**\n * Uploads a file using the user-provided callback.\n *\n * @param file - The blob to upload.\n * Can be any Blob-compatible object including File.\n * @param filename - Optional filename for the upload.\n * If not provided, callback may generate a name.\n * @returns Upload result containing URL and metadata\n *\n * @throws {StorageError} With code 'INVALID_UPLOAD_RESULT' if callback returns invalid data\n * @throws {StorageError} With code 'UPLOAD_ERROR' if upload fails\n *\n * @example\n * ```typescript\n * const file = new File(['content'], 'data.json');\n * const result = await storage.upload(file);\n * console.log('Uploaded to:', result.url);\n * ```\n */\n async upload(file: Blob, filename?: string): Promise<StorageUploadResult> {\n try {\n const result = await this.callbacks.upload(file, filename);\n\n // Validate the result has required fields\n if (!result.url || result.url.trim() === \"\") {\n throw new StorageError(\n \"Upload callback returned invalid result: missing or empty url\",\n \"INVALID_UPLOAD_RESULT\",\n \"callback-storage\",\n );\n }\n\n return result;\n } catch (error) {\n if (error instanceof StorageError) {\n throw error;\n }\n throw new StorageError(\n `Upload failed: ${error instanceof Error ? error.message : String(error)}`,\n \"UPLOAD_ERROR\",\n \"callback-storage\",\n { cause: error instanceof Error ? error : undefined },\n );\n }\n }\n\n /**\n * Downloads a file using the user-provided callback.\n *\n * @param url - The URL or identifier to download.\n * If `extractIdentifier` callback is provided, it will be used to extract the identifier.\n * @returns The downloaded file as a Blob\n *\n * @throws {StorageError} With code 'INVALID_DOWNLOAD_RESULT' if callback returns non-Blob\n * @throws {StorageError} With code 'DOWNLOAD_ERROR' if download fails\n *\n * @example\n * ```typescript\n * const blob = await storage.download('https://storage.example.com/file123');\n * const text = await blob.text();\n * ```\n */\n async download(url: string): Promise<Blob> {\n try {\n // Extract identifier if callback is provided, otherwise use URL as-is\n const identifier = this.callbacks.extractIdentifier\n ? this.callbacks.extractIdentifier(url)\n : url;\n\n const blob = await this.callbacks.download(identifier);\n\n if (!(blob instanceof Blob)) {\n throw new StorageError(\n \"Download callback returned invalid result: expected Blob\",\n \"INVALID_DOWNLOAD_RESULT\",\n \"callback-storage\",\n );\n }\n\n return blob;\n } catch (error) {\n if (error instanceof StorageError) {\n throw error;\n }\n throw new StorageError(\n `Download failed: ${error instanceof Error ? error.message : String(error)}`,\n \"DOWNLOAD_ERROR\",\n \"callback-storage\",\n { cause: error instanceof Error ? error : undefined },\n );\n }\n }\n\n /**\n * Lists files using the user-provided callback.\n *\n * @param options - Optional list options.\n * @param options.namePattern - Pattern to filter files by name.\n * Implementation depends on callback.\n * @param options.limit - Maximum number of files to return.\n * Implementation depends on callback.\n * @returns Array of storage file metadata\n *\n * @throws {StorageError} With code 'NOT_SUPPORTED' if list callback not provided\n * @throws {StorageError} With code 'LIST_ERROR' if listing fails\n *\n * @remarks\n * This operation is optional and only available if a `list` callback\n * is provided during construction.\n *\n * @example\n * ```typescript\n * const files = await storage.list({ namePattern: '*.json' });\n * files.forEach(file => console.log(file.name, file.size));\n * ```\n */\n async list(options?: StorageListOptions): Promise<StorageFile[]> {\n if (!this.callbacks.list) {\n throw new StorageError(\n \"List operation not supported - no list callback provided\",\n \"NOT_SUPPORTED\",\n \"callback-storage\",\n );\n }\n\n try {\n const result = await this.callbacks.list(options?.namePattern, options);\n\n // Convert list result to StorageFile format\n return result.items.map((item, index) => ({\n id: item.identifier,\n name: item.identifier.split(\"/\").pop() ?? `file-${index}`,\n url: item.identifier,\n size: item.size ?? 0,\n contentType: \"application/octet-stream\",\n createdAt: item.lastModified ?? new Date(),\n metadata: item.metadata,\n }));\n } catch (error) {\n throw new StorageError(\n `List failed: ${error instanceof Error ? error.message : String(error)}`,\n \"LIST_ERROR\",\n \"callback-storage\",\n { cause: error instanceof Error ? error : undefined },\n );\n }\n }\n\n /**\n * Deletes a file using the user-provided callback.\n *\n * @param url - The URL or identifier to delete.\n * If `extractIdentifier` callback is provided, it will be used to extract the identifier.\n * @returns True if deletion succeeded, false otherwise\n *\n * @throws {StorageError} With code 'NOT_SUPPORTED' if delete callback not provided\n * @throws {StorageError} With code 'DELETE_ERROR' if deletion fails\n *\n * @remarks\n * This operation is optional and only available if a `delete` callback\n * is provided during construction.\n *\n * @example\n * ```typescript\n * const deleted = await storage.delete('https://storage.example.com/file123');\n * if (deleted) {\n * console.log('File deleted successfully');\n * }\n * ```\n */\n async delete(url: string): Promise<boolean> {\n if (!this.callbacks.delete) {\n throw new StorageError(\n \"Delete operation not supported - no delete callback provided\",\n \"NOT_SUPPORTED\",\n \"callback-storage\",\n );\n }\n\n try {\n // Extract identifier if callback is provided, otherwise use URL as-is\n const identifier = this.callbacks.extractIdentifier\n ? this.callbacks.extractIdentifier(url)\n : url;\n\n return await this.callbacks.delete(identifier);\n } catch (error) {\n throw new StorageError(\n `Delete failed: ${error instanceof Error ? error.message : String(error)}`,\n \"DELETE_ERROR\",\n \"callback-storage\",\n { cause: error instanceof Error ? error : undefined },\n );\n }\n }\n\n /**\n * Returns the provider's configuration and capabilities.\n *\n * @returns Configuration object indicating supported features\n *\n * @example\n * ```typescript\n * const config = storage.getConfig();\n * if (config.features.list) {\n * // List operation is supported\n * const files = await storage.list();\n * }\n * ```\n */\n getConfig(): StorageProviderConfig {\n return {\n name: \"callback-storage\",\n type: \"callback\",\n requiresAuth: false,\n features: {\n upload: true,\n download: true,\n list: !!this.callbacks.list,\n delete: !!this.callbacks.delete,\n },\n };\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,13 +1,29 @@
1
+ /**
2
+ * Provides user-defined storage operations through callback functions.
3
+ *
4
+ * @remarks
5
+ * This module implements a flexible storage provider that delegates all
6
+ * operations to user-provided callbacks. It enables custom storage
7
+ * integrations without modifying the SDK, supporting any backend including
8
+ * HTTP APIs, WebSocket servers, cloud storage services, or local filesystems.
9
+ *
10
+ * @category Storage
11
+ * @module storage/providers/callback-storage
12
+ */
1
13
  import type { StorageCallbacks } from "../../types/config";
2
14
  import { type StorageProvider, type StorageUploadResult, type StorageFile, type StorageListOptions, type StorageProviderConfig } from "../../types/storage";
3
15
  /**
4
- * Storage provider that delegates all operations to user-provided callbacks.
16
+ * Delegates storage operations to user-provided callback functions.
5
17
  *
6
- * This provider follows the same flexible pattern as relayer callbacks,
7
- * allowing users to implement storage operations in any way they choose
8
- * (HTTP, WebSocket, direct cloud APIs, local filesystem, etc.).
18
+ * @remarks
19
+ * This provider enables custom storage integrations by delegating all
20
+ * operations to user-defined callbacks. It follows the same flexible
21
+ * pattern as relayer callbacks, allowing implementations via HTTP,
22
+ * WebSocket, direct cloud APIs, local filesystem, or any other backend.
23
+ *
24
+ * The provider validates callback results and wraps errors in consistent
25
+ * `StorageError` types for uniform error handling across the SDK.
9
26
  *
10
- * @category Storage
11
27
  * @example
12
28
  * ```typescript
13
29
  * // HTTP-based implementation
@@ -52,43 +68,116 @@ import { type StorageProvider, type StorageUploadResult, type StorageFile, type
52
68
  * }
53
69
  * };
54
70
  * ```
71
+ *
72
+ * @category Storage
55
73
  */
56
74
  export declare class CallbackStorage implements StorageProvider {
57
75
  private readonly callbacks;
76
+ /**
77
+ * Creates a new callback-based storage provider.
78
+ *
79
+ * @param callbacks - User-provided storage operation callbacks.
80
+ * Must include at minimum `upload` and `download` functions.
81
+ * @throws {Error} If required callbacks are missing
82
+ */
58
83
  constructor(callbacks: StorageCallbacks);
59
84
  /**
60
- * Upload a file using the provided callback
85
+ * Uploads a file using the user-provided callback.
61
86
  *
62
- * @param file - The blob to upload
63
- * @param filename - Optional filename for the upload
64
- * @returns The upload result with URL and metadata
87
+ * @param file - The blob to upload.
88
+ * Can be any Blob-compatible object including File.
89
+ * @param filename - Optional filename for the upload.
90
+ * If not provided, callback may generate a name.
91
+ * @returns Upload result containing URL and metadata
92
+ *
93
+ * @throws {StorageError} With code 'INVALID_UPLOAD_RESULT' if callback returns invalid data
94
+ * @throws {StorageError} With code 'UPLOAD_ERROR' if upload fails
95
+ *
96
+ * @example
97
+ * ```typescript
98
+ * const file = new File(['content'], 'data.json');
99
+ * const result = await storage.upload(file);
100
+ * console.log('Uploaded to:', result.url);
101
+ * ```
65
102
  */
66
103
  upload(file: Blob, filename?: string): Promise<StorageUploadResult>;
67
104
  /**
68
- * Download a file using the provided callback
105
+ * Downloads a file using the user-provided callback.
106
+ *
107
+ * @param url - The URL or identifier to download.
108
+ * If `extractIdentifier` callback is provided, it will be used to extract the identifier.
109
+ * @returns The downloaded file as a Blob
69
110
  *
70
- * @param url - The URL or identifier to download
71
- * @returns The downloaded blob
111
+ * @throws {StorageError} With code 'INVALID_DOWNLOAD_RESULT' if callback returns non-Blob
112
+ * @throws {StorageError} With code 'DOWNLOAD_ERROR' if download fails
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * const blob = await storage.download('https://storage.example.com/file123');
117
+ * const text = await blob.text();
118
+ * ```
72
119
  */
73
120
  download(url: string): Promise<Blob>;
74
121
  /**
75
- * List files using the provided callback (if available)
122
+ * Lists files using the user-provided callback.
123
+ *
124
+ * @param options - Optional list options.
125
+ * @param options.namePattern - Pattern to filter files by name.
126
+ * Implementation depends on callback.
127
+ * @param options.limit - Maximum number of files to return.
128
+ * Implementation depends on callback.
129
+ * @returns Array of storage file metadata
130
+ *
131
+ * @throws {StorageError} With code 'NOT_SUPPORTED' if list callback not provided
132
+ * @throws {StorageError} With code 'LIST_ERROR' if listing fails
76
133
  *
77
- * @param options - Optional list options including filters and pagination
78
- * @returns Array of storage files
134
+ * @remarks
135
+ * This operation is optional and only available if a `list` callback
136
+ * is provided during construction.
137
+ *
138
+ * @example
139
+ * ```typescript
140
+ * const files = await storage.list({ namePattern: '*.json' });
141
+ * files.forEach(file => console.log(file.name, file.size));
142
+ * ```
79
143
  */
80
144
  list(options?: StorageListOptions): Promise<StorageFile[]>;
81
145
  /**
82
- * Delete a file using the provided callback (if available)
146
+ * Deletes a file using the user-provided callback.
147
+ *
148
+ * @param url - The URL or identifier to delete.
149
+ * If `extractIdentifier` callback is provided, it will be used to extract the identifier.
150
+ * @returns True if deletion succeeded, false otherwise
151
+ *
152
+ * @throws {StorageError} With code 'NOT_SUPPORTED' if delete callback not provided
153
+ * @throws {StorageError} With code 'DELETE_ERROR' if deletion fails
83
154
  *
84
- * @param url - The URL or identifier to delete
85
- * @returns True if deletion succeeded
155
+ * @remarks
156
+ * This operation is optional and only available if a `delete` callback
157
+ * is provided during construction.
158
+ *
159
+ * @example
160
+ * ```typescript
161
+ * const deleted = await storage.delete('https://storage.example.com/file123');
162
+ * if (deleted) {
163
+ * console.log('File deleted successfully');
164
+ * }
165
+ * ```
86
166
  */
87
167
  delete(url: string): Promise<boolean>;
88
168
  /**
89
- * Get provider configuration
169
+ * Returns the provider's configuration and capabilities.
170
+ *
171
+ * @returns Configuration object indicating supported features
90
172
  *
91
- * @returns Provider configuration metadata
173
+ * @example
174
+ * ```typescript
175
+ * const config = storage.getConfig();
176
+ * if (config.features.list) {
177
+ * // List operation is supported
178
+ * const files = await storage.list();
179
+ * }
180
+ * ```
92
181
  */
93
182
  getConfig(): StorageProviderConfig;
94
183
  }
@@ -2,6 +2,13 @@ import {
2
2
  StorageError
3
3
  } from "../../types/storage";
4
4
  class CallbackStorage {
5
+ /**
6
+ * Creates a new callback-based storage provider.
7
+ *
8
+ * @param callbacks - User-provided storage operation callbacks.
9
+ * Must include at minimum `upload` and `download` functions.
10
+ * @throws {Error} If required callbacks are missing
11
+ */
5
12
  constructor(callbacks) {
6
13
  this.callbacks = callbacks;
7
14
  if (!callbacks.upload || !callbacks.download) {
@@ -11,11 +18,23 @@ class CallbackStorage {
11
18
  }
12
19
  }
13
20
  /**
14
- * Upload a file using the provided callback
21
+ * Uploads a file using the user-provided callback.
22
+ *
23
+ * @param file - The blob to upload.
24
+ * Can be any Blob-compatible object including File.
25
+ * @param filename - Optional filename for the upload.
26
+ * If not provided, callback may generate a name.
27
+ * @returns Upload result containing URL and metadata
15
28
  *
16
- * @param file - The blob to upload
17
- * @param filename - Optional filename for the upload
18
- * @returns The upload result with URL and metadata
29
+ * @throws {StorageError} With code 'INVALID_UPLOAD_RESULT' if callback returns invalid data
30
+ * @throws {StorageError} With code 'UPLOAD_ERROR' if upload fails
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * const file = new File(['content'], 'data.json');
35
+ * const result = await storage.upload(file);
36
+ * console.log('Uploaded to:', result.url);
37
+ * ```
19
38
  */
20
39
  async upload(file, filename) {
21
40
  try {
@@ -41,10 +60,20 @@ class CallbackStorage {
41
60
  }
42
61
  }
43
62
  /**
44
- * Download a file using the provided callback
63
+ * Downloads a file using the user-provided callback.
64
+ *
65
+ * @param url - The URL or identifier to download.
66
+ * If `extractIdentifier` callback is provided, it will be used to extract the identifier.
67
+ * @returns The downloaded file as a Blob
68
+ *
69
+ * @throws {StorageError} With code 'INVALID_DOWNLOAD_RESULT' if callback returns non-Blob
70
+ * @throws {StorageError} With code 'DOWNLOAD_ERROR' if download fails
45
71
  *
46
- * @param url - The URL or identifier to download
47
- * @returns The downloaded blob
72
+ * @example
73
+ * ```typescript
74
+ * const blob = await storage.download('https://storage.example.com/file123');
75
+ * const text = await blob.text();
76
+ * ```
48
77
  */
49
78
  async download(url) {
50
79
  try {
@@ -71,10 +100,27 @@ class CallbackStorage {
71
100
  }
72
101
  }
73
102
  /**
74
- * List files using the provided callback (if available)
103
+ * Lists files using the user-provided callback.
75
104
  *
76
- * @param options - Optional list options including filters and pagination
77
- * @returns Array of storage files
105
+ * @param options - Optional list options.
106
+ * @param options.namePattern - Pattern to filter files by name.
107
+ * Implementation depends on callback.
108
+ * @param options.limit - Maximum number of files to return.
109
+ * Implementation depends on callback.
110
+ * @returns Array of storage file metadata
111
+ *
112
+ * @throws {StorageError} With code 'NOT_SUPPORTED' if list callback not provided
113
+ * @throws {StorageError} With code 'LIST_ERROR' if listing fails
114
+ *
115
+ * @remarks
116
+ * This operation is optional and only available if a `list` callback
117
+ * is provided during construction.
118
+ *
119
+ * @example
120
+ * ```typescript
121
+ * const files = await storage.list({ namePattern: '*.json' });
122
+ * files.forEach(file => console.log(file.name, file.size));
123
+ * ```
78
124
  */
79
125
  async list(options) {
80
126
  if (!this.callbacks.list) {
@@ -105,10 +151,26 @@ class CallbackStorage {
105
151
  }
106
152
  }
107
153
  /**
108
- * Delete a file using the provided callback (if available)
154
+ * Deletes a file using the user-provided callback.
155
+ *
156
+ * @param url - The URL or identifier to delete.
157
+ * If `extractIdentifier` callback is provided, it will be used to extract the identifier.
158
+ * @returns True if deletion succeeded, false otherwise
109
159
  *
110
- * @param url - The URL or identifier to delete
111
- * @returns True if deletion succeeded
160
+ * @throws {StorageError} With code 'NOT_SUPPORTED' if delete callback not provided
161
+ * @throws {StorageError} With code 'DELETE_ERROR' if deletion fails
162
+ *
163
+ * @remarks
164
+ * This operation is optional and only available if a `delete` callback
165
+ * is provided during construction.
166
+ *
167
+ * @example
168
+ * ```typescript
169
+ * const deleted = await storage.delete('https://storage.example.com/file123');
170
+ * if (deleted) {
171
+ * console.log('File deleted successfully');
172
+ * }
173
+ * ```
112
174
  */
113
175
  async delete(url) {
114
176
  if (!this.callbacks.delete) {
@@ -131,9 +193,18 @@ class CallbackStorage {
131
193
  }
132
194
  }
133
195
  /**
134
- * Get provider configuration
196
+ * Returns the provider's configuration and capabilities.
197
+ *
198
+ * @returns Configuration object indicating supported features
135
199
  *
136
- * @returns Provider configuration metadata
200
+ * @example
201
+ * ```typescript
202
+ * const config = storage.getConfig();
203
+ * if (config.features.list) {
204
+ * // List operation is supported
205
+ * const files = await storage.list();
206
+ * }
207
+ * ```
137
208
  */
138
209
  getConfig() {
139
210
  return {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/storage/providers/callback-storage.ts"],"sourcesContent":["import type { StorageCallbacks } from \"../../types/config\";\nimport {\n StorageError,\n type StorageProvider,\n type StorageUploadResult,\n type StorageFile,\n type StorageListOptions,\n type StorageProviderConfig,\n} from \"../../types/storage\";\n\n/**\n * Storage provider that delegates all operations to user-provided callbacks.\n *\n * This provider follows the same flexible pattern as relayer callbacks,\n * allowing users to implement storage operations in any way they choose\n * (HTTP, WebSocket, direct cloud APIs, local filesystem, etc.).\n *\n * @category Storage\n * @example\n * ```typescript\n * // HTTP-based implementation\n * const httpCallbacks: StorageCallbacks = {\n * async upload(blob, filename) {\n * const formData = new FormData();\n * formData.append('file', blob, filename);\n * const response = await fetch('/api/storage/upload', {\n * method: 'POST',\n * body: formData\n * });\n * const data = await response.json();\n * return {\n * url: data.url,\n * size: blob.size,\n * contentType: blob.type\n * };\n * },\n * async download(identifier) {\n * const response = await fetch(`/api/storage/download/${identifier}`);\n * return response.blob();\n * }\n * };\n *\n * const storage = new CallbackStorage(httpCallbacks);\n *\n * // Direct S3 implementation\n * const s3Callbacks: StorageCallbacks = {\n * async upload(blob, filename) {\n * const url = await getPresignedUploadUrl(filename);\n * await fetch(url, { method: 'PUT', body: blob });\n * return {\n * url: `s3://my-bucket/${filename}`,\n * size: blob.size,\n * contentType: blob.type\n * };\n * },\n * async download(identifier) {\n * const url = await getPresignedDownloadUrl(identifier);\n * const response = await fetch(url);\n * return response.blob();\n * }\n * };\n * ```\n */\nexport class CallbackStorage implements StorageProvider {\n constructor(private readonly callbacks: StorageCallbacks) {\n if (!callbacks.upload || !callbacks.download) {\n throw new Error(\n \"CallbackStorage requires both upload and download callbacks\",\n );\n }\n }\n\n /**\n * Upload a file using the provided callback\n *\n * @param file - The blob to upload\n * @param filename - Optional filename for the upload\n * @returns The upload result with URL and metadata\n */\n async upload(file: Blob, filename?: string): Promise<StorageUploadResult> {\n try {\n const result = await this.callbacks.upload(file, filename);\n\n // Validate the result has required fields\n if (!result.url || result.url.trim() === \"\") {\n throw new StorageError(\n \"Upload callback returned invalid result: missing or empty url\",\n \"INVALID_UPLOAD_RESULT\",\n \"callback-storage\",\n );\n }\n\n return result;\n } catch (error) {\n if (error instanceof StorageError) {\n throw error;\n }\n throw new StorageError(\n `Upload failed: ${error instanceof Error ? error.message : String(error)}`,\n \"UPLOAD_ERROR\",\n \"callback-storage\",\n { cause: error instanceof Error ? error : undefined },\n );\n }\n }\n\n /**\n * Download a file using the provided callback\n *\n * @param url - The URL or identifier to download\n * @returns The downloaded blob\n */\n async download(url: string): Promise<Blob> {\n try {\n // Extract identifier if callback is provided, otherwise use URL as-is\n const identifier = this.callbacks.extractIdentifier\n ? this.callbacks.extractIdentifier(url)\n : url;\n\n const blob = await this.callbacks.download(identifier);\n\n if (!(blob instanceof Blob)) {\n throw new StorageError(\n \"Download callback returned invalid result: expected Blob\",\n \"INVALID_DOWNLOAD_RESULT\",\n \"callback-storage\",\n );\n }\n\n return blob;\n } catch (error) {\n if (error instanceof StorageError) {\n throw error;\n }\n throw new StorageError(\n `Download failed: ${error instanceof Error ? error.message : String(error)}`,\n \"DOWNLOAD_ERROR\",\n \"callback-storage\",\n { cause: error instanceof Error ? error : undefined },\n );\n }\n }\n\n /**\n * List files using the provided callback (if available)\n *\n * @param options - Optional list options including filters and pagination\n * @returns Array of storage files\n */\n async list(options?: StorageListOptions): Promise<StorageFile[]> {\n if (!this.callbacks.list) {\n throw new StorageError(\n \"List operation not supported - no list callback provided\",\n \"NOT_SUPPORTED\",\n \"callback-storage\",\n );\n }\n\n try {\n const result = await this.callbacks.list(options?.namePattern, options);\n\n // Convert list result to StorageFile format\n return result.items.map((item, index) => ({\n id: item.identifier,\n name: item.identifier.split(\"/\").pop() ?? `file-${index}`,\n url: item.identifier,\n size: item.size ?? 0,\n contentType: \"application/octet-stream\",\n createdAt: item.lastModified ?? new Date(),\n metadata: item.metadata,\n }));\n } catch (error) {\n throw new StorageError(\n `List failed: ${error instanceof Error ? error.message : String(error)}`,\n \"LIST_ERROR\",\n \"callback-storage\",\n { cause: error instanceof Error ? error : undefined },\n );\n }\n }\n\n /**\n * Delete a file using the provided callback (if available)\n *\n * @param url - The URL or identifier to delete\n * @returns True if deletion succeeded\n */\n async delete(url: string): Promise<boolean> {\n if (!this.callbacks.delete) {\n throw new StorageError(\n \"Delete operation not supported - no delete callback provided\",\n \"NOT_SUPPORTED\",\n \"callback-storage\",\n );\n }\n\n try {\n // Extract identifier if callback is provided, otherwise use URL as-is\n const identifier = this.callbacks.extractIdentifier\n ? this.callbacks.extractIdentifier(url)\n : url;\n\n return await this.callbacks.delete(identifier);\n } catch (error) {\n throw new StorageError(\n `Delete failed: ${error instanceof Error ? error.message : String(error)}`,\n \"DELETE_ERROR\",\n \"callback-storage\",\n { cause: error instanceof Error ? error : undefined },\n );\n }\n }\n\n /**\n * Get provider configuration\n *\n * @returns Provider configuration metadata\n */\n getConfig(): StorageProviderConfig {\n return {\n name: \"callback-storage\",\n type: \"callback\",\n requiresAuth: false,\n features: {\n upload: true,\n download: true,\n list: !!this.callbacks.list,\n delete: !!this.callbacks.delete,\n },\n };\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/storage/providers/callback-storage.ts"],"sourcesContent":["/**\n * Provides user-defined storage operations through callback functions.\n *\n * @remarks\n * This module implements a flexible storage provider that delegates all\n * operations to user-provided callbacks. It enables custom storage\n * integrations without modifying the SDK, supporting any backend including\n * HTTP APIs, WebSocket servers, cloud storage services, or local filesystems.\n *\n * @category Storage\n * @module storage/providers/callback-storage\n */\n\nimport type { StorageCallbacks } from \"../../types/config\";\nimport {\n StorageError,\n type StorageProvider,\n type StorageUploadResult,\n type StorageFile,\n type StorageListOptions,\n type StorageProviderConfig,\n} from \"../../types/storage\";\n\n/**\n * Delegates storage operations to user-provided callback functions.\n *\n * @remarks\n * This provider enables custom storage integrations by delegating all\n * operations to user-defined callbacks. It follows the same flexible\n * pattern as relayer callbacks, allowing implementations via HTTP,\n * WebSocket, direct cloud APIs, local filesystem, or any other backend.\n *\n * The provider validates callback results and wraps errors in consistent\n * `StorageError` types for uniform error handling across the SDK.\n *\n * @example\n * ```typescript\n * // HTTP-based implementation\n * const httpCallbacks: StorageCallbacks = {\n * async upload(blob, filename) {\n * const formData = new FormData();\n * formData.append('file', blob, filename);\n * const response = await fetch('/api/storage/upload', {\n * method: 'POST',\n * body: formData\n * });\n * const data = await response.json();\n * return {\n * url: data.url,\n * size: blob.size,\n * contentType: blob.type\n * };\n * },\n * async download(identifier) {\n * const response = await fetch(`/api/storage/download/${identifier}`);\n * return response.blob();\n * }\n * };\n *\n * const storage = new CallbackStorage(httpCallbacks);\n *\n * // Direct S3 implementation\n * const s3Callbacks: StorageCallbacks = {\n * async upload(blob, filename) {\n * const url = await getPresignedUploadUrl(filename);\n * await fetch(url, { method: 'PUT', body: blob });\n * return {\n * url: `s3://my-bucket/${filename}`,\n * size: blob.size,\n * contentType: blob.type\n * };\n * },\n * async download(identifier) {\n * const url = await getPresignedDownloadUrl(identifier);\n * const response = await fetch(url);\n * return response.blob();\n * }\n * };\n * ```\n *\n * @category Storage\n */\nexport class CallbackStorage implements StorageProvider {\n /**\n * Creates a new callback-based storage provider.\n *\n * @param callbacks - User-provided storage operation callbacks.\n * Must include at minimum `upload` and `download` functions.\n * @throws {Error} If required callbacks are missing\n */\n constructor(private readonly callbacks: StorageCallbacks) {\n if (!callbacks.upload || !callbacks.download) {\n throw new Error(\n \"CallbackStorage requires both upload and download callbacks\",\n );\n }\n }\n\n /**\n * Uploads a file using the user-provided callback.\n *\n * @param file - The blob to upload.\n * Can be any Blob-compatible object including File.\n * @param filename - Optional filename for the upload.\n * If not provided, callback may generate a name.\n * @returns Upload result containing URL and metadata\n *\n * @throws {StorageError} With code 'INVALID_UPLOAD_RESULT' if callback returns invalid data\n * @throws {StorageError} With code 'UPLOAD_ERROR' if upload fails\n *\n * @example\n * ```typescript\n * const file = new File(['content'], 'data.json');\n * const result = await storage.upload(file);\n * console.log('Uploaded to:', result.url);\n * ```\n */\n async upload(file: Blob, filename?: string): Promise<StorageUploadResult> {\n try {\n const result = await this.callbacks.upload(file, filename);\n\n // Validate the result has required fields\n if (!result.url || result.url.trim() === \"\") {\n throw new StorageError(\n \"Upload callback returned invalid result: missing or empty url\",\n \"INVALID_UPLOAD_RESULT\",\n \"callback-storage\",\n );\n }\n\n return result;\n } catch (error) {\n if (error instanceof StorageError) {\n throw error;\n }\n throw new StorageError(\n `Upload failed: ${error instanceof Error ? error.message : String(error)}`,\n \"UPLOAD_ERROR\",\n \"callback-storage\",\n { cause: error instanceof Error ? error : undefined },\n );\n }\n }\n\n /**\n * Downloads a file using the user-provided callback.\n *\n * @param url - The URL or identifier to download.\n * If `extractIdentifier` callback is provided, it will be used to extract the identifier.\n * @returns The downloaded file as a Blob\n *\n * @throws {StorageError} With code 'INVALID_DOWNLOAD_RESULT' if callback returns non-Blob\n * @throws {StorageError} With code 'DOWNLOAD_ERROR' if download fails\n *\n * @example\n * ```typescript\n * const blob = await storage.download('https://storage.example.com/file123');\n * const text = await blob.text();\n * ```\n */\n async download(url: string): Promise<Blob> {\n try {\n // Extract identifier if callback is provided, otherwise use URL as-is\n const identifier = this.callbacks.extractIdentifier\n ? this.callbacks.extractIdentifier(url)\n : url;\n\n const blob = await this.callbacks.download(identifier);\n\n if (!(blob instanceof Blob)) {\n throw new StorageError(\n \"Download callback returned invalid result: expected Blob\",\n \"INVALID_DOWNLOAD_RESULT\",\n \"callback-storage\",\n );\n }\n\n return blob;\n } catch (error) {\n if (error instanceof StorageError) {\n throw error;\n }\n throw new StorageError(\n `Download failed: ${error instanceof Error ? error.message : String(error)}`,\n \"DOWNLOAD_ERROR\",\n \"callback-storage\",\n { cause: error instanceof Error ? error : undefined },\n );\n }\n }\n\n /**\n * Lists files using the user-provided callback.\n *\n * @param options - Optional list options.\n * @param options.namePattern - Pattern to filter files by name.\n * Implementation depends on callback.\n * @param options.limit - Maximum number of files to return.\n * Implementation depends on callback.\n * @returns Array of storage file metadata\n *\n * @throws {StorageError} With code 'NOT_SUPPORTED' if list callback not provided\n * @throws {StorageError} With code 'LIST_ERROR' if listing fails\n *\n * @remarks\n * This operation is optional and only available if a `list` callback\n * is provided during construction.\n *\n * @example\n * ```typescript\n * const files = await storage.list({ namePattern: '*.json' });\n * files.forEach(file => console.log(file.name, file.size));\n * ```\n */\n async list(options?: StorageListOptions): Promise<StorageFile[]> {\n if (!this.callbacks.list) {\n throw new StorageError(\n \"List operation not supported - no list callback provided\",\n \"NOT_SUPPORTED\",\n \"callback-storage\",\n );\n }\n\n try {\n const result = await this.callbacks.list(options?.namePattern, options);\n\n // Convert list result to StorageFile format\n return result.items.map((item, index) => ({\n id: item.identifier,\n name: item.identifier.split(\"/\").pop() ?? `file-${index}`,\n url: item.identifier,\n size: item.size ?? 0,\n contentType: \"application/octet-stream\",\n createdAt: item.lastModified ?? new Date(),\n metadata: item.metadata,\n }));\n } catch (error) {\n throw new StorageError(\n `List failed: ${error instanceof Error ? error.message : String(error)}`,\n \"LIST_ERROR\",\n \"callback-storage\",\n { cause: error instanceof Error ? error : undefined },\n );\n }\n }\n\n /**\n * Deletes a file using the user-provided callback.\n *\n * @param url - The URL or identifier to delete.\n * If `extractIdentifier` callback is provided, it will be used to extract the identifier.\n * @returns True if deletion succeeded, false otherwise\n *\n * @throws {StorageError} With code 'NOT_SUPPORTED' if delete callback not provided\n * @throws {StorageError} With code 'DELETE_ERROR' if deletion fails\n *\n * @remarks\n * This operation is optional and only available if a `delete` callback\n * is provided during construction.\n *\n * @example\n * ```typescript\n * const deleted = await storage.delete('https://storage.example.com/file123');\n * if (deleted) {\n * console.log('File deleted successfully');\n * }\n * ```\n */\n async delete(url: string): Promise<boolean> {\n if (!this.callbacks.delete) {\n throw new StorageError(\n \"Delete operation not supported - no delete callback provided\",\n \"NOT_SUPPORTED\",\n \"callback-storage\",\n );\n }\n\n try {\n // Extract identifier if callback is provided, otherwise use URL as-is\n const identifier = this.callbacks.extractIdentifier\n ? this.callbacks.extractIdentifier(url)\n : url;\n\n return await this.callbacks.delete(identifier);\n } catch (error) {\n throw new StorageError(\n `Delete failed: ${error instanceof Error ? error.message : String(error)}`,\n \"DELETE_ERROR\",\n \"callback-storage\",\n { cause: error instanceof Error ? error : undefined },\n );\n }\n }\n\n /**\n * Returns the provider's configuration and capabilities.\n *\n * @returns Configuration object indicating supported features\n *\n * @example\n * ```typescript\n * const config = storage.getConfig();\n * if (config.features.list) {\n * // List operation is supported\n * const files = await storage.list();\n * }\n * ```\n */\n getConfig(): StorageProviderConfig {\n return {\n name: \"callback-storage\",\n type: \"callback\",\n requiresAuth: false,\n features: {\n upload: true,\n download: true,\n list: !!this.callbacks.list,\n delete: !!this.callbacks.delete,\n },\n };\n }\n}\n"],"mappings":"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","names":[]}