@varity-labs/sdk 2.0.0-alpha.1

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 (295) hide show
  1. package/LICENSE +31 -0
  2. package/README.md +253 -0
  3. package/dist/analytics/index.d.ts +7 -0
  4. package/dist/analytics/index.d.ts.map +1 -0
  5. package/dist/analytics/index.js +6 -0
  6. package/dist/analytics/tracker.d.ts +128 -0
  7. package/dist/analytics/tracker.d.ts.map +1 -0
  8. package/dist/analytics/tracker.js +203 -0
  9. package/dist/blockchain/BlockchainService.d.ts +100 -0
  10. package/dist/blockchain/BlockchainService.d.ts.map +1 -0
  11. package/dist/blockchain/BlockchainService.js +188 -0
  12. package/dist/blockchain/NFTLicensingService.d.ts +69 -0
  13. package/dist/blockchain/NFTLicensingService.d.ts.map +1 -0
  14. package/dist/blockchain/NFTLicensingService.js +136 -0
  15. package/dist/blockchain/RevenueSplitService.d.ts +71 -0
  16. package/dist/blockchain/RevenueSplitService.d.ts.map +1 -0
  17. package/dist/blockchain/RevenueSplitService.js +111 -0
  18. package/dist/blockchain/index.d.ts +48 -0
  19. package/dist/blockchain/index.d.ts.map +1 -0
  20. package/dist/blockchain/index.js +46 -0
  21. package/dist/blockchain/types.d.ts +63 -0
  22. package/dist/blockchain/types.d.ts.map +1 -0
  23. package/dist/blockchain/types.js +6 -0
  24. package/dist/chains/arbitrum.d.ts +89 -0
  25. package/dist/chains/arbitrum.d.ts.map +1 -0
  26. package/dist/chains/arbitrum.js +134 -0
  27. package/dist/chains/base.d.ts +84 -0
  28. package/dist/chains/base.d.ts.map +1 -0
  29. package/dist/chains/base.js +131 -0
  30. package/dist/chains/index.d.ts +36 -0
  31. package/dist/chains/index.d.ts.map +1 -0
  32. package/dist/chains/index.js +32 -0
  33. package/dist/chains/registry.d.ts +113 -0
  34. package/dist/chains/registry.d.ts.map +1 -0
  35. package/dist/chains/registry.js +201 -0
  36. package/dist/chains/varityL3.d.ts +81 -0
  37. package/dist/chains/varityL3.d.ts.map +1 -0
  38. package/dist/chains/varityL3.js +125 -0
  39. package/dist/cli/commands/clone.d.ts +8 -0
  40. package/dist/cli/commands/clone.d.ts.map +1 -0
  41. package/dist/cli/commands/clone.js +391 -0
  42. package/dist/cli/commands/dev.d.ts +8 -0
  43. package/dist/cli/commands/dev.d.ts.map +1 -0
  44. package/dist/cli/commands/dev.js +40 -0
  45. package/dist/cli/commands/generate.d.ts +8 -0
  46. package/dist/cli/commands/generate.d.ts.map +1 -0
  47. package/dist/cli/commands/generate.js +303 -0
  48. package/dist/cli/commands/init.d.ts +8 -0
  49. package/dist/cli/commands/init.d.ts.map +1 -0
  50. package/dist/cli/commands/init.js +317 -0
  51. package/dist/cli/commands/validate.d.ts +8 -0
  52. package/dist/cli/commands/validate.d.ts.map +1 -0
  53. package/dist/cli/commands/validate.js +69 -0
  54. package/dist/cli/index.d.ts +8 -0
  55. package/dist/cli/index.d.ts.map +1 -0
  56. package/dist/cli/index.js +33 -0
  57. package/dist/cli/utils/logger.d.ts +17 -0
  58. package/dist/cli/utils/logger.d.ts.map +1 -0
  59. package/dist/cli/utils/logger.js +35 -0
  60. package/dist/cli/utils/prompts.d.ts +21 -0
  61. package/dist/cli/utils/prompts.d.ts.map +1 -0
  62. package/dist/cli/utils/prompts.js +103 -0
  63. package/dist/contracts/abis/iso/AccessControlRegistry.json +1468 -0
  64. package/dist/contracts/abis/iso/DataProofRegistry.json +797 -0
  65. package/dist/contracts/abis/iso/MerchantRegistry.json +1237 -0
  66. package/dist/contracts/abis/iso/RepPerformance.json +1351 -0
  67. package/dist/contracts/abis/iso/ResidualCalculator.json +1118 -0
  68. package/dist/contracts/abis/iso/TransactionVault.json +1588 -0
  69. package/dist/contracts/abis/iso/VarityWalletFactory.json +475 -0
  70. package/dist/contracts/addresses.d.ts +88 -0
  71. package/dist/contracts/addresses.d.ts.map +1 -0
  72. package/dist/contracts/addresses.js +94 -0
  73. package/dist/contracts/index.d.ts +7 -0
  74. package/dist/contracts/index.d.ts.map +1 -0
  75. package/dist/contracts/index.js +6 -0
  76. package/dist/core/VaritySDK.d.ts +177 -0
  77. package/dist/core/VaritySDK.d.ts.map +1 -0
  78. package/dist/core/VaritySDK.js +325 -0
  79. package/dist/core/config.d.ts +120 -0
  80. package/dist/core/config.d.ts.map +1 -0
  81. package/dist/core/config.js +187 -0
  82. package/dist/core/credentials-proxy.d.ts +157 -0
  83. package/dist/core/credentials-proxy.d.ts.map +1 -0
  84. package/dist/core/credentials-proxy.js +345 -0
  85. package/dist/core/credentials.d.ts +219 -0
  86. package/dist/core/credentials.d.ts.map +1 -0
  87. package/dist/core/credentials.js +345 -0
  88. package/dist/core/template-loader.d.ts +15 -0
  89. package/dist/core/template-loader.d.ts.map +1 -0
  90. package/dist/core/template-loader.js +380 -0
  91. package/dist/core/template.d.ts +321 -0
  92. package/dist/core/template.d.ts.map +1 -0
  93. package/dist/core/template.js +189 -0
  94. package/dist/core/types.d.ts +572 -0
  95. package/dist/core/types.d.ts.map +1 -0
  96. package/dist/core/types.js +52 -0
  97. package/dist/dev/dev-server.d.ts +16 -0
  98. package/dist/dev/dev-server.d.ts.map +1 -0
  99. package/dist/dev/dev-server.js +119 -0
  100. package/dist/generators/contracts/generator.d.ts +21 -0
  101. package/dist/generators/contracts/generator.d.ts.map +1 -0
  102. package/dist/generators/contracts/generator.js +252 -0
  103. package/dist/generators/tests/generator.d.ts +20 -0
  104. package/dist/generators/tests/generator.d.ts.map +1 -0
  105. package/dist/generators/tests/generator.js +375 -0
  106. package/dist/generators/types/generator.d.ts +19 -0
  107. package/dist/generators/types/generator.d.ts.map +1 -0
  108. package/dist/generators/types/generator.js +165 -0
  109. package/dist/generators/ui/component-generator.d.ts +20 -0
  110. package/dist/generators/ui/component-generator.d.ts.map +1 -0
  111. package/dist/generators/ui/component-generator.js +749 -0
  112. package/dist/generators/ui/dashboard-generator.d.ts +20 -0
  113. package/dist/generators/ui/dashboard-generator.d.ts.map +1 -0
  114. package/dist/generators/ui/dashboard-generator.js +349 -0
  115. package/dist/index.d.ts +61 -0
  116. package/dist/index.d.ts.map +1 -0
  117. package/dist/index.js +74 -0
  118. package/dist/modules/analytics/AnalyticsModule.d.ts +349 -0
  119. package/dist/modules/analytics/AnalyticsModule.d.ts.map +1 -0
  120. package/dist/modules/analytics/AnalyticsModule.js +274 -0
  121. package/dist/modules/analytics/index.d.ts +3 -0
  122. package/dist/modules/analytics/index.d.ts.map +1 -0
  123. package/dist/modules/analytics/index.js +1 -0
  124. package/dist/modules/auth/AccessKeyModule.d.ts +189 -0
  125. package/dist/modules/auth/AccessKeyModule.d.ts.map +1 -0
  126. package/dist/modules/auth/AccessKeyModule.js +322 -0
  127. package/dist/modules/auth/AuthModule.d.ts +133 -0
  128. package/dist/modules/auth/AuthModule.d.ts.map +1 -0
  129. package/dist/modules/auth/AuthModule.js +214 -0
  130. package/dist/modules/auth/index.d.ts +8 -0
  131. package/dist/modules/auth/index.d.ts.map +1 -0
  132. package/dist/modules/auth/index.js +6 -0
  133. package/dist/modules/cache/CacheModule.d.ts +279 -0
  134. package/dist/modules/cache/CacheModule.d.ts.map +1 -0
  135. package/dist/modules/cache/CacheModule.js +493 -0
  136. package/dist/modules/cache/index.d.ts +3 -0
  137. package/dist/modules/cache/index.d.ts.map +1 -0
  138. package/dist/modules/cache/index.js +1 -0
  139. package/dist/modules/compute/ComputeModule.d.ts +226 -0
  140. package/dist/modules/compute/ComputeModule.d.ts.map +1 -0
  141. package/dist/modules/compute/ComputeModule.js +379 -0
  142. package/dist/modules/compute/index.d.ts +6 -0
  143. package/dist/modules/compute/index.d.ts.map +1 -0
  144. package/dist/modules/compute/index.js +4 -0
  145. package/dist/modules/contracts/ContractsModule.d.ts +164 -0
  146. package/dist/modules/contracts/ContractsModule.d.ts.map +1 -0
  147. package/dist/modules/contracts/ContractsModule.js +242 -0
  148. package/dist/modules/contracts/index.d.ts +6 -0
  149. package/dist/modules/contracts/index.d.ts.map +1 -0
  150. package/dist/modules/contracts/index.js +4 -0
  151. package/dist/modules/export/ExportModule.d.ts +346 -0
  152. package/dist/modules/export/ExportModule.d.ts.map +1 -0
  153. package/dist/modules/export/ExportModule.js +432 -0
  154. package/dist/modules/export/index.d.ts +3 -0
  155. package/dist/modules/export/index.d.ts.map +1 -0
  156. package/dist/modules/export/index.js +1 -0
  157. package/dist/modules/forecasting/ForecastingModule.d.ts +579 -0
  158. package/dist/modules/forecasting/ForecastingModule.d.ts.map +1 -0
  159. package/dist/modules/forecasting/ForecastingModule.js +310 -0
  160. package/dist/modules/forecasting/index.d.ts +3 -0
  161. package/dist/modules/forecasting/index.d.ts.map +1 -0
  162. package/dist/modules/forecasting/index.js +1 -0
  163. package/dist/modules/monitoring/MonitoringModule.d.ts +359 -0
  164. package/dist/modules/monitoring/MonitoringModule.d.ts.map +1 -0
  165. package/dist/modules/monitoring/MonitoringModule.js +483 -0
  166. package/dist/modules/monitoring/index.d.ts +3 -0
  167. package/dist/modules/monitoring/index.d.ts.map +1 -0
  168. package/dist/modules/monitoring/index.js +1 -0
  169. package/dist/modules/notifications/NotificationsModule.d.ts +336 -0
  170. package/dist/modules/notifications/NotificationsModule.d.ts.map +1 -0
  171. package/dist/modules/notifications/NotificationsModule.js +418 -0
  172. package/dist/modules/notifications/index.d.ts +3 -0
  173. package/dist/modules/notifications/index.d.ts.map +1 -0
  174. package/dist/modules/notifications/index.js +1 -0
  175. package/dist/modules/oracle/OracleModule.d.ts +110 -0
  176. package/dist/modules/oracle/OracleModule.d.ts.map +1 -0
  177. package/dist/modules/oracle/OracleModule.js +151 -0
  178. package/dist/modules/oracle/index.d.ts +6 -0
  179. package/dist/modules/oracle/index.d.ts.map +1 -0
  180. package/dist/modules/oracle/index.js +4 -0
  181. package/dist/modules/storage/S3Module.d.ts +377 -0
  182. package/dist/modules/storage/S3Module.d.ts.map +1 -0
  183. package/dist/modules/storage/S3Module.js +680 -0
  184. package/dist/modules/storage/StorageModule.d.ts +157 -0
  185. package/dist/modules/storage/StorageModule.d.ts.map +1 -0
  186. package/dist/modules/storage/StorageModule.js +302 -0
  187. package/dist/modules/storage/adapters/AdapterFactory.d.ts +100 -0
  188. package/dist/modules/storage/adapters/AdapterFactory.d.ts.map +1 -0
  189. package/dist/modules/storage/adapters/AdapterFactory.js +209 -0
  190. package/dist/modules/storage/adapters/FilecoinAdapter.d.ts +94 -0
  191. package/dist/modules/storage/adapters/FilecoinAdapter.d.ts.map +1 -0
  192. package/dist/modules/storage/adapters/FilecoinAdapter.js +263 -0
  193. package/dist/modules/storage/adapters/IStorageAdapter.d.ts +287 -0
  194. package/dist/modules/storage/adapters/IStorageAdapter.d.ts.map +1 -0
  195. package/dist/modules/storage/adapters/IStorageAdapter.js +81 -0
  196. package/dist/modules/storage/adapters/MultiTierAdapter.d.ts +187 -0
  197. package/dist/modules/storage/adapters/MultiTierAdapter.d.ts.map +1 -0
  198. package/dist/modules/storage/adapters/MultiTierAdapter.js +430 -0
  199. package/dist/modules/storage/adapters/index.d.ts +12 -0
  200. package/dist/modules/storage/adapters/index.d.ts.map +1 -0
  201. package/dist/modules/storage/adapters/index.js +12 -0
  202. package/dist/modules/storage/index.d.ts +16 -0
  203. package/dist/modules/storage/index.d.ts.map +1 -0
  204. package/dist/modules/storage/index.js +15 -0
  205. package/dist/modules/storage/tiering/AccessAnalyzer.d.ts +227 -0
  206. package/dist/modules/storage/tiering/AccessAnalyzer.d.ts.map +1 -0
  207. package/dist/modules/storage/tiering/AccessAnalyzer.js +367 -0
  208. package/dist/modules/storage/tiering/CostOptimizer.d.ts +248 -0
  209. package/dist/modules/storage/tiering/CostOptimizer.d.ts.map +1 -0
  210. package/dist/modules/storage/tiering/CostOptimizer.js +356 -0
  211. package/dist/modules/storage/tiering/MetadataStore.d.ts +287 -0
  212. package/dist/modules/storage/tiering/MetadataStore.d.ts.map +1 -0
  213. package/dist/modules/storage/tiering/MetadataStore.js +535 -0
  214. package/dist/modules/storage/tiering/TieringEngine.d.ts +237 -0
  215. package/dist/modules/storage/tiering/TieringEngine.d.ts.map +1 -0
  216. package/dist/modules/storage/tiering/TieringEngine.js +419 -0
  217. package/dist/modules/storage/tiering/example.d.ts +8 -0
  218. package/dist/modules/storage/tiering/example.d.ts.map +1 -0
  219. package/dist/modules/storage/tiering/example.js +250 -0
  220. package/dist/modules/storage/tiering/index.d.ts +17 -0
  221. package/dist/modules/storage/tiering/index.d.ts.map +1 -0
  222. package/dist/modules/storage/tiering/index.js +13 -0
  223. package/dist/modules/webhooks/WebhooksModule.d.ts +476 -0
  224. package/dist/modules/webhooks/WebhooksModule.d.ts.map +1 -0
  225. package/dist/modules/webhooks/WebhooksModule.js +359 -0
  226. package/dist/modules/webhooks/index.d.ts +3 -0
  227. package/dist/modules/webhooks/index.d.ts.map +1 -0
  228. package/dist/modules/webhooks/index.js +1 -0
  229. package/dist/modules/zk/ZKModule.d.ts +153 -0
  230. package/dist/modules/zk/ZKModule.d.ts.map +1 -0
  231. package/dist/modules/zk/ZKModule.js +262 -0
  232. package/dist/modules/zk/index.d.ts +7 -0
  233. package/dist/modules/zk/index.d.ts.map +1 -0
  234. package/dist/modules/zk/index.js +4 -0
  235. package/dist/thirdweb/BridgeClient.d.ts +228 -0
  236. package/dist/thirdweb/BridgeClient.d.ts.map +1 -0
  237. package/dist/thirdweb/BridgeClient.js +160 -0
  238. package/dist/thirdweb/EngineClient.d.ts +396 -0
  239. package/dist/thirdweb/EngineClient.d.ts.map +1 -0
  240. package/dist/thirdweb/EngineClient.js +386 -0
  241. package/dist/thirdweb/GatewayClient.d.ts +190 -0
  242. package/dist/thirdweb/GatewayClient.d.ts.map +1 -0
  243. package/dist/thirdweb/GatewayClient.js +257 -0
  244. package/dist/thirdweb/NebulaClient.d.ts +292 -0
  245. package/dist/thirdweb/NebulaClient.d.ts.map +1 -0
  246. package/dist/thirdweb/NebulaClient.js +180 -0
  247. package/dist/thirdweb/StorageClient.d.ts +445 -0
  248. package/dist/thirdweb/StorageClient.d.ts.map +1 -0
  249. package/dist/thirdweb/StorageClient.js +405 -0
  250. package/dist/thirdweb/ThirdwebWrapper.d.ts +236 -0
  251. package/dist/thirdweb/ThirdwebWrapper.d.ts.map +1 -0
  252. package/dist/thirdweb/ThirdwebWrapper.js +332 -0
  253. package/dist/thirdweb/index.d.ts +21 -0
  254. package/dist/thirdweb/index.d.ts.map +1 -0
  255. package/dist/thirdweb/index.js +28 -0
  256. package/dist/thirdweb/varity-chain.d.ts +48 -0
  257. package/dist/thirdweb/varity-chain.d.ts.map +1 -0
  258. package/dist/thirdweb/varity-chain.js +64 -0
  259. package/dist/thirdweb/x402Client.d.ts +319 -0
  260. package/dist/thirdweb/x402Client.d.ts.map +1 -0
  261. package/dist/thirdweb/x402Client.js +223 -0
  262. package/dist/tracking/gasTracker.d.ts +158 -0
  263. package/dist/tracking/gasTracker.d.ts.map +1 -0
  264. package/dist/tracking/gasTracker.js +227 -0
  265. package/dist/tracking/index.d.ts +10 -0
  266. package/dist/tracking/index.d.ts.map +1 -0
  267. package/dist/tracking/index.js +8 -0
  268. package/dist/tracking/types.d.ts +327 -0
  269. package/dist/tracking/types.d.ts.map +1 -0
  270. package/dist/tracking/types.js +8 -0
  271. package/dist/ui/components/ChartWidget.d.ts +36 -0
  272. package/dist/ui/components/ChartWidget.d.ts.map +1 -0
  273. package/dist/ui/components/ChartWidget.js +82 -0
  274. package/dist/ui/components/DashboardLayout.d.ts +41 -0
  275. package/dist/ui/components/DashboardLayout.d.ts.map +1 -0
  276. package/dist/ui/components/DashboardLayout.js +102 -0
  277. package/dist/ui/components/DataTable.d.ts +49 -0
  278. package/dist/ui/components/DataTable.d.ts.map +1 -0
  279. package/dist/ui/components/DataTable.js +96 -0
  280. package/dist/ui/components/EntityForm.d.ts +60 -0
  281. package/dist/ui/components/EntityForm.d.ts.map +1 -0
  282. package/dist/ui/components/EntityForm.js +182 -0
  283. package/dist/ui/components/KPICard.d.ts +29 -0
  284. package/dist/ui/components/KPICard.d.ts.map +1 -0
  285. package/dist/ui/components/KPICard.js +61 -0
  286. package/dist/ui/components/Modal.d.ts +34 -0
  287. package/dist/ui/components/Modal.d.ts.map +1 -0
  288. package/dist/ui/components/Modal.js +30 -0
  289. package/dist/ui/components/index.d.ts +18 -0
  290. package/dist/ui/components/index.d.ts.map +1 -0
  291. package/dist/ui/components/index.js +11 -0
  292. package/dist/validation/template-validator.d.ts +25 -0
  293. package/dist/validation/template-validator.d.ts.map +1 -0
  294. package/dist/validation/template-validator.js +305 -0
  295. package/package.json +102 -0
@@ -0,0 +1,680 @@
1
+ /**
2
+ * Varity SDK - S3-Compatible Storage Module
3
+ *
4
+ * Provides S3-compatible methods backed by Filecoin/IPFS via S3 Gateway.
5
+ * Developers can use familiar S3 APIs (putObject, getObject, etc.) while
6
+ * benefiting from decentralized storage.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * const sdk = new VaritySDK({
11
+ * network: 'arbitrum-sepolia',
12
+ * s3Config: {
13
+ * endpoint: 'http://localhost:3001',
14
+ * accessKeyId: 'test-key',
15
+ * secretAccessKey: 'test-secret',
16
+ * bucket: 'my-bucket',
17
+ * region: 'us-east-1'
18
+ * }
19
+ * })
20
+ *
21
+ * // Upload object
22
+ * const result = await sdk.s3.putObject({
23
+ * Bucket: 'my-bucket',
24
+ * Key: 'document.txt',
25
+ * Body: 'Hello, World!'
26
+ * })
27
+ *
28
+ * // Download object
29
+ * const data = await sdk.s3.getObject({
30
+ * Bucket: 'my-bucket',
31
+ * Key: 'document.txt'
32
+ * })
33
+ * ```
34
+ */
35
+ import { StorageBackend } from '@varity-labs/types';
36
+ import { createHmac, createHash } from 'crypto';
37
+ /**
38
+ * S3Module - S3-Compatible Storage Interface
39
+ *
40
+ * Provides familiar S3 API methods backed by Filecoin/IPFS via S3 Gateway (Agent 2).
41
+ */
42
+ export class S3Module {
43
+ constructor(sdk, config) {
44
+ this.sdk = sdk;
45
+ this.config = config;
46
+ }
47
+ /**
48
+ * PUT object - S3-compatible upload
49
+ *
50
+ * @param params - PutObject parameters
51
+ * @returns Upload result with S3 metadata
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * const result = await sdk.s3.putObject({
56
+ * Bucket: 'my-bucket',
57
+ * Key: 'document.txt',
58
+ * Body: 'Hello, World!',
59
+ * ContentType: 'text/plain'
60
+ * })
61
+ * console.log(result.ETag)
62
+ * ```
63
+ */
64
+ async putObject(params) {
65
+ const endpoint = this.buildEndpoint();
66
+ const url = `${endpoint}/${params.Bucket}/${params.Key}`;
67
+ // Convert Body to Buffer
68
+ let body;
69
+ if (Buffer.isBuffer(params.Body)) {
70
+ body = params.Body;
71
+ }
72
+ else if (typeof params.Body === 'string') {
73
+ body = Buffer.from(params.Body, 'utf-8');
74
+ }
75
+ else {
76
+ // Blob
77
+ body = Buffer.from(await params.Body.arrayBuffer());
78
+ }
79
+ // Build headers
80
+ const headers = await this.buildAuthHeaders('PUT', params.Bucket, params.Key, {
81
+ 'Content-Type': params.ContentType || 'application/octet-stream',
82
+ 'Content-Length': body.length.toString(),
83
+ ...(params.ContentEncoding && { 'Content-Encoding': params.ContentEncoding }),
84
+ ...(params.ContentLanguage && { 'Content-Language': params.ContentLanguage }),
85
+ ...(params.CacheControl && { 'Cache-Control': params.CacheControl }),
86
+ ...(params.ContentDisposition && { 'Content-Disposition': params.ContentDisposition }),
87
+ ...(params.ServerSideEncryption && { 'x-amz-server-side-encryption': params.ServerSideEncryption }),
88
+ ...(params.SSEKMSKeyId && { 'x-amz-server-side-encryption-aws-kms-key-id': params.SSEKMSKeyId }),
89
+ ...(params.StorageClass && { 'x-amz-storage-class': params.StorageClass }),
90
+ ...(params.ACL && { 'x-amz-acl': params.ACL }),
91
+ ...(params.Tagging && { 'x-amz-tagging': params.Tagging }),
92
+ ...(params.Metadata && this.buildMetadataHeaders(params.Metadata))
93
+ });
94
+ const response = await fetch(url, {
95
+ method: 'PUT',
96
+ headers,
97
+ body: new Blob([new Uint8Array(body)])
98
+ });
99
+ if (!response.ok) {
100
+ const errorText = await response.text();
101
+ throw new Error(`S3 putObject failed: ${response.statusText} - ${errorText}`);
102
+ }
103
+ const etag = response.headers.get('ETag') || '';
104
+ const versionId = response.headers.get('x-amz-version-id') || undefined;
105
+ return {
106
+ backend: StorageBackend.FILECOIN_IPFS,
107
+ identifier: params.Key,
108
+ gatewayUrl: url,
109
+ size: body.length,
110
+ hash: this.calculateSHA256(body),
111
+ timestamp: Date.now(),
112
+ s3Key: params.Key,
113
+ bucket: params.Bucket,
114
+ region: this.config.region,
115
+ etag: etag.replace(/"/g, ''),
116
+ versionId,
117
+ storageClass: params.StorageClass
118
+ };
119
+ }
120
+ /**
121
+ * GET object - S3-compatible download
122
+ *
123
+ * @param params - GetObject parameters
124
+ * @returns Object data and metadata
125
+ *
126
+ * @example
127
+ * ```typescript
128
+ * const result = await sdk.s3.getObject({
129
+ * Bucket: 'my-bucket',
130
+ * Key: 'document.txt'
131
+ * })
132
+ * console.log(result.Body.toString())
133
+ * ```
134
+ */
135
+ async getObject(params) {
136
+ const endpoint = this.buildEndpoint();
137
+ const url = `${endpoint}/${params.Bucket}/${params.Key}${params.VersionId ? `?versionId=${params.VersionId}` : ''}`;
138
+ const headers = await this.buildAuthHeaders('GET', params.Bucket, params.Key, {
139
+ ...(params.Range && { 'Range': params.Range }),
140
+ ...(params.IfMatch && { 'If-Match': params.IfMatch }),
141
+ ...(params.IfNoneMatch && { 'If-None-Match': params.IfNoneMatch }),
142
+ ...(params.IfModifiedSince && { 'If-Modified-Since': params.IfModifiedSince.toUTCString() }),
143
+ ...(params.IfUnmodifiedSince && { 'If-Unmodified-Since': params.IfUnmodifiedSince.toUTCString() })
144
+ });
145
+ const response = await fetch(url, { headers });
146
+ if (!response.ok) {
147
+ const errorText = await response.text();
148
+ throw new Error(`S3 getObject failed: ${response.statusText} - ${errorText}`);
149
+ }
150
+ const body = Buffer.from(await response.arrayBuffer());
151
+ const metadata = this.extractMetadata(response.headers);
152
+ return {
153
+ Body: body,
154
+ ContentType: response.headers.get('Content-Type') || 'application/octet-stream',
155
+ ContentLength: parseInt(response.headers.get('Content-Length') || '0', 10),
156
+ ETag: (response.headers.get('ETag') || '').replace(/"/g, ''),
157
+ LastModified: new Date(response.headers.get('Last-Modified') || Date.now()),
158
+ Metadata: metadata,
159
+ VersionId: response.headers.get('x-amz-version-id') || undefined,
160
+ StorageClass: response.headers.get('x-amz-storage-class') || undefined
161
+ };
162
+ }
163
+ /**
164
+ * DELETE object - S3-compatible deletion
165
+ *
166
+ * @param params - DeleteObject parameters
167
+ *
168
+ * @example
169
+ * ```typescript
170
+ * await sdk.s3.deleteObject({
171
+ * Bucket: 'my-bucket',
172
+ * Key: 'document.txt'
173
+ * })
174
+ * ```
175
+ */
176
+ async deleteObject(params) {
177
+ const endpoint = this.buildEndpoint();
178
+ const url = `${endpoint}/${params.Bucket}/${params.Key}${params.VersionId ? `?versionId=${params.VersionId}` : ''}`;
179
+ const headers = await this.buildAuthHeaders('DELETE', params.Bucket, params.Key);
180
+ const response = await fetch(url, {
181
+ method: 'DELETE',
182
+ headers
183
+ });
184
+ if (!response.ok) {
185
+ const errorText = await response.text();
186
+ throw new Error(`S3 deleteObject failed: ${response.statusText} - ${errorText}`);
187
+ }
188
+ }
189
+ /**
190
+ * LIST objects - S3-compatible list operation
191
+ *
192
+ * @param params - ListObjects parameters
193
+ * @returns List of objects
194
+ *
195
+ * @example
196
+ * ```typescript
197
+ * const result = await sdk.s3.listObjects({
198
+ * Bucket: 'my-bucket',
199
+ * Prefix: 'documents/'
200
+ * })
201
+ * console.log(result.objects.length)
202
+ * ```
203
+ */
204
+ async listObjects(params) {
205
+ const endpoint = this.buildEndpoint();
206
+ const queryParams = new URLSearchParams();
207
+ queryParams.append('list-type', '2');
208
+ if (params.Prefix)
209
+ queryParams.append('prefix', params.Prefix);
210
+ if (params.Delimiter)
211
+ queryParams.append('delimiter', params.Delimiter);
212
+ if (params.MaxKeys)
213
+ queryParams.append('max-keys', params.MaxKeys.toString());
214
+ if (params.ContinuationToken)
215
+ queryParams.append('continuation-token', params.ContinuationToken);
216
+ if (params.StartAfter)
217
+ queryParams.append('start-after', params.StartAfter);
218
+ const url = `${endpoint}/${params.Bucket}?${queryParams}`;
219
+ const headers = await this.buildAuthHeaders('GET', params.Bucket, '');
220
+ const response = await fetch(url, { headers });
221
+ if (!response.ok) {
222
+ const errorText = await response.text();
223
+ throw new Error(`S3 listObjects failed: ${response.statusText} - ${errorText}`);
224
+ }
225
+ const xml = await response.text();
226
+ return this.parseListObjectsResponse(xml);
227
+ }
228
+ /**
229
+ * HEAD object - Get object metadata without downloading
230
+ *
231
+ * @param params - HeadObject parameters
232
+ * @returns Object metadata
233
+ *
234
+ * @example
235
+ * ```typescript
236
+ * const metadata = await sdk.s3.headObject({
237
+ * Bucket: 'my-bucket',
238
+ * Key: 'document.txt'
239
+ * })
240
+ * console.log(metadata.ContentLength)
241
+ * ```
242
+ */
243
+ async headObject(params) {
244
+ const endpoint = this.buildEndpoint();
245
+ const url = `${endpoint}/${params.Bucket}/${params.Key}${params.VersionId ? `?versionId=${params.VersionId}` : ''}`;
246
+ const headers = await this.buildAuthHeaders('HEAD', params.Bucket, params.Key);
247
+ const response = await fetch(url, {
248
+ method: 'HEAD',
249
+ headers
250
+ });
251
+ if (!response.ok) {
252
+ throw new Error(`S3 headObject failed: ${response.statusText}`);
253
+ }
254
+ const metadata = this.extractMetadata(response.headers);
255
+ return {
256
+ ContentType: response.headers.get('Content-Type') || 'application/octet-stream',
257
+ ContentLength: parseInt(response.headers.get('Content-Length') || '0', 10),
258
+ ETag: (response.headers.get('ETag') || '').replace(/"/g, ''),
259
+ LastModified: new Date(response.headers.get('Last-Modified') || Date.now()),
260
+ Metadata: metadata,
261
+ VersionId: response.headers.get('x-amz-version-id') || undefined,
262
+ StorageClass: response.headers.get('x-amz-storage-class') || undefined
263
+ };
264
+ }
265
+ /**
266
+ * Generate presigned URL for object access
267
+ *
268
+ * @param bucket - Bucket name
269
+ * @param key - Object key
270
+ * @param options - Presigned URL options
271
+ * @returns Presigned URL
272
+ *
273
+ * @example
274
+ * ```typescript
275
+ * const presignedUrl = await sdk.s3.getPresignedUrl(
276
+ * 'my-bucket',
277
+ * 'document.txt',
278
+ * { expiresIn: 3600, method: 'GET' }
279
+ * )
280
+ * console.log(presignedUrl.url)
281
+ * ```
282
+ */
283
+ async getPresignedUrl(bucket, key, options) {
284
+ const endpoint = this.buildEndpoint();
285
+ const method = options.method || 'GET';
286
+ const expiresIn = options.expiresIn;
287
+ const expiresAt = new Date(Date.now() + expiresIn * 1000);
288
+ // Build base URL
289
+ let url = `${endpoint}/${bucket}/${key}`;
290
+ // Add query parameters
291
+ const params = new URLSearchParams();
292
+ params.append('X-Amz-Algorithm', 'AWS4-HMAC-SHA256');
293
+ params.append('X-Amz-Credential', `${this.config.accessKeyId}/${this.getCredentialScope()}`);
294
+ params.append('X-Amz-Date', this.getAmzDate());
295
+ params.append('X-Amz-Expires', expiresIn.toString());
296
+ params.append('X-Amz-SignedHeaders', 'host');
297
+ // Add response headers if specified
298
+ if (options.responseHeaders) {
299
+ if (options.responseHeaders.contentType) {
300
+ params.append('response-content-type', options.responseHeaders.contentType);
301
+ }
302
+ if (options.responseHeaders.contentDisposition) {
303
+ params.append('response-content-disposition', options.responseHeaders.contentDisposition);
304
+ }
305
+ if (options.responseHeaders.cacheControl) {
306
+ params.append('response-cache-control', options.responseHeaders.cacheControl);
307
+ }
308
+ }
309
+ // Add version ID if specified
310
+ if (options.versionId) {
311
+ params.append('versionId', options.versionId);
312
+ }
313
+ // Generate signature
314
+ const stringToSign = this.buildStringToSign(method, bucket, key, params);
315
+ const signature = this.signString(stringToSign);
316
+ params.append('X-Amz-Signature', signature);
317
+ url += `?${params}`;
318
+ return {
319
+ url,
320
+ expiresAt,
321
+ method,
322
+ headers: options.requestHeaders
323
+ };
324
+ }
325
+ /**
326
+ * Initiate multipart upload
327
+ *
328
+ * @param bucket - Bucket name
329
+ * @param key - Object key
330
+ * @param options - Multipart upload options
331
+ * @returns Upload session
332
+ */
333
+ async createMultipartUpload(bucket, key, options) {
334
+ const endpoint = this.buildEndpoint();
335
+ const url = `${endpoint}/${bucket}/${key}?uploads`;
336
+ const headers = await this.buildAuthHeaders('POST', bucket, key, {
337
+ ...(options?.serverSideEncryption && { 'x-amz-server-side-encryption': options.serverSideEncryption }),
338
+ ...(options?.kmsKeyId && { 'x-amz-server-side-encryption-aws-kms-key-id': options.kmsKeyId }),
339
+ ...(options?.storageClass && { 'x-amz-storage-class': options.storageClass }),
340
+ ...(options?.metadata && this.buildMetadataHeaders(options.metadata))
341
+ });
342
+ const response = await fetch(url, {
343
+ method: 'POST',
344
+ headers
345
+ });
346
+ if (!response.ok) {
347
+ const errorText = await response.text();
348
+ throw new Error(`S3 createMultipartUpload failed: ${response.statusText} - ${errorText}`);
349
+ }
350
+ const xml = await response.text();
351
+ const uploadId = this.extractUploadId(xml);
352
+ return {
353
+ uploadId,
354
+ bucket,
355
+ key,
356
+ parts: [],
357
+ initiated: new Date()
358
+ };
359
+ }
360
+ /**
361
+ * Upload part for multipart upload
362
+ *
363
+ * @param bucket - Bucket name
364
+ * @param key - Object key
365
+ * @param uploadId - Upload ID
366
+ * @param partNumber - Part number (1-10000)
367
+ * @param body - Part data
368
+ * @returns Upload part result
369
+ */
370
+ async uploadPart(bucket, key, uploadId, partNumber, body) {
371
+ const endpoint = this.buildEndpoint();
372
+ const url = `${endpoint}/${bucket}/${key}?partNumber=${partNumber}&uploadId=${uploadId}`;
373
+ const headers = await this.buildAuthHeaders('PUT', bucket, key, {
374
+ 'Content-Length': body.length.toString()
375
+ });
376
+ const response = await fetch(url, {
377
+ method: 'PUT',
378
+ headers,
379
+ body: new Blob([new Uint8Array(body)])
380
+ });
381
+ if (!response.ok) {
382
+ const errorText = await response.text();
383
+ throw new Error(`S3 uploadPart failed: ${response.statusText} - ${errorText}`);
384
+ }
385
+ const etag = (response.headers.get('ETag') || '').replace(/"/g, '');
386
+ return {
387
+ partNumber,
388
+ etag,
389
+ size: body.length,
390
+ lastModified: new Date()
391
+ };
392
+ }
393
+ /**
394
+ * Complete multipart upload
395
+ *
396
+ * @param bucket - Bucket name
397
+ * @param key - Object key
398
+ * @param uploadId - Upload ID
399
+ * @param parts - Uploaded parts
400
+ * @returns Upload result
401
+ */
402
+ async completeMultipartUpload(bucket, key, uploadId, parts) {
403
+ const endpoint = this.buildEndpoint();
404
+ const url = `${endpoint}/${bucket}/${key}?uploadId=${uploadId}`;
405
+ // Build XML body
406
+ const xml = this.buildCompleteMultipartUploadXML(parts);
407
+ const body = Buffer.from(xml, 'utf-8');
408
+ const headers = await this.buildAuthHeaders('POST', bucket, key, {
409
+ 'Content-Type': 'application/xml',
410
+ 'Content-Length': body.length.toString()
411
+ });
412
+ const response = await fetch(url, {
413
+ method: 'POST',
414
+ headers,
415
+ body
416
+ });
417
+ if (!response.ok) {
418
+ const errorText = await response.text();
419
+ throw new Error(`S3 completeMultipartUpload failed: ${response.statusText} - ${errorText}`);
420
+ }
421
+ const etag = (response.headers.get('ETag') || '').replace(/"/g, '');
422
+ const totalSize = parts.reduce((sum, part) => sum + part.size, 0);
423
+ return {
424
+ backend: StorageBackend.FILECOIN_IPFS,
425
+ identifier: key,
426
+ gatewayUrl: `${endpoint}/${bucket}/${key}`,
427
+ size: totalSize,
428
+ hash: this.calculateSHA256(body),
429
+ timestamp: Date.now(),
430
+ s3Key: key,
431
+ bucket,
432
+ region: this.config.region,
433
+ etag
434
+ };
435
+ }
436
+ /**
437
+ * Abort multipart upload
438
+ *
439
+ * @param bucket - Bucket name
440
+ * @param key - Object key
441
+ * @param uploadId - Upload ID
442
+ */
443
+ async abortMultipartUpload(bucket, key, uploadId) {
444
+ const endpoint = this.buildEndpoint();
445
+ const url = `${endpoint}/${bucket}/${key}?uploadId=${uploadId}`;
446
+ const headers = await this.buildAuthHeaders('DELETE', bucket, key);
447
+ const response = await fetch(url, {
448
+ method: 'DELETE',
449
+ headers
450
+ });
451
+ if (!response.ok) {
452
+ const errorText = await response.text();
453
+ throw new Error(`S3 abortMultipartUpload failed: ${response.statusText} - ${errorText}`);
454
+ }
455
+ }
456
+ // ============================================================================
457
+ // Private Helper Methods
458
+ // ============================================================================
459
+ /**
460
+ * Build endpoint URL
461
+ */
462
+ buildEndpoint() {
463
+ const protocol = this.config.useSSL !== false ? 'https' : 'http';
464
+ const port = this.config.port || (this.config.useSSL !== false ? 443 : 80);
465
+ const portSuffix = (port === 443 && this.config.useSSL !== false) || (port === 80 && this.config.useSSL === false) ? '' : `:${port}`;
466
+ return `${protocol}://${this.config.endpoint}${portSuffix}`;
467
+ }
468
+ /**
469
+ * Build AWS Signature V4 headers
470
+ */
471
+ async buildAuthHeaders(method, bucket, key, additionalHeaders = {}) {
472
+ const host = this.config.endpoint;
473
+ const amzDate = this.getAmzDate();
474
+ const dateStamp = amzDate.substring(0, 8);
475
+ const headers = {
476
+ 'host': host,
477
+ 'x-amz-date': amzDate,
478
+ ...additionalHeaders
479
+ };
480
+ // Build canonical request
481
+ const canonicalUri = `/${bucket}/${key}`.replace(/\/+/g, '/');
482
+ const canonicalQueryString = '';
483
+ const canonicalHeaders = Object.keys(headers)
484
+ .sort()
485
+ .map(key => `${key.toLowerCase()}:${headers[key].trim()}`)
486
+ .join('\n') + '\n';
487
+ const signedHeaders = Object.keys(headers)
488
+ .sort()
489
+ .map(key => key.toLowerCase())
490
+ .join(';');
491
+ const payloadHash = 'UNSIGNED-PAYLOAD';
492
+ const canonicalRequest = [
493
+ method,
494
+ canonicalUri,
495
+ canonicalQueryString,
496
+ canonicalHeaders,
497
+ signedHeaders,
498
+ payloadHash
499
+ ].join('\n');
500
+ // Build string to sign
501
+ const credentialScope = `${dateStamp}/${this.config.region || 'us-east-1'}/s3/aws4_request`;
502
+ const stringToSign = [
503
+ 'AWS4-HMAC-SHA256',
504
+ amzDate,
505
+ credentialScope,
506
+ this.sha256(canonicalRequest)
507
+ ].join('\n');
508
+ // Calculate signature
509
+ const signingKey = this.getSignatureKey(this.config.secretAccessKey, dateStamp, this.config.region || 'us-east-1', 's3');
510
+ const signature = createHmac('sha256', signingKey)
511
+ .update(stringToSign)
512
+ .digest('hex');
513
+ // Build authorization header
514
+ const authorizationHeader = [
515
+ 'AWS4-HMAC-SHA256',
516
+ `Credential=${this.config.accessKeyId}/${credentialScope}`,
517
+ `SignedHeaders=${signedHeaders}`,
518
+ `Signature=${signature}`
519
+ ].join(' ');
520
+ headers['Authorization'] = authorizationHeader;
521
+ return headers;
522
+ }
523
+ /**
524
+ * Get AMZ date (ISO 8601 format)
525
+ */
526
+ getAmzDate() {
527
+ return new Date().toISOString().replace(/[:-]|\.\d{3}/g, '');
528
+ }
529
+ /**
530
+ * Get credential scope
531
+ */
532
+ getCredentialScope() {
533
+ const dateStamp = this.getAmzDate().substring(0, 8);
534
+ return `${dateStamp}/${this.config.region || 'us-east-1'}/s3/aws4_request`;
535
+ }
536
+ /**
537
+ * Build string to sign for presigned URL
538
+ */
539
+ buildStringToSign(method, bucket, key, params) {
540
+ const amzDate = this.getAmzDate();
541
+ const dateStamp = amzDate.substring(0, 8);
542
+ const credentialScope = `${dateStamp}/${this.config.region || 'us-east-1'}/s3/aws4_request`;
543
+ const canonicalUri = `/${bucket}/${key}`;
544
+ const canonicalQueryString = params.toString();
545
+ const canonicalHeaders = `host:${this.config.endpoint}\n`;
546
+ const signedHeaders = 'host';
547
+ const payloadHash = 'UNSIGNED-PAYLOAD';
548
+ const canonicalRequest = [
549
+ method,
550
+ canonicalUri,
551
+ canonicalQueryString,
552
+ canonicalHeaders,
553
+ signedHeaders,
554
+ payloadHash
555
+ ].join('\n');
556
+ return [
557
+ 'AWS4-HMAC-SHA256',
558
+ amzDate,
559
+ credentialScope,
560
+ this.sha256(canonicalRequest)
561
+ ].join('\n');
562
+ }
563
+ /**
564
+ * Sign string using AWS Signature V4
565
+ */
566
+ signString(stringToSign) {
567
+ const dateStamp = this.getAmzDate().substring(0, 8);
568
+ const signingKey = this.getSignatureKey(this.config.secretAccessKey, dateStamp, this.config.region || 'us-east-1', 's3');
569
+ return createHmac('sha256', signingKey)
570
+ .update(stringToSign)
571
+ .digest('hex');
572
+ }
573
+ /**
574
+ * Get AWS Signature V4 signing key
575
+ */
576
+ getSignatureKey(key, dateStamp, regionName, serviceName) {
577
+ const kDate = createHmac('sha256', 'AWS4' + key).update(dateStamp).digest();
578
+ const kRegion = createHmac('sha256', kDate).update(regionName).digest();
579
+ const kService = createHmac('sha256', kRegion).update(serviceName).digest();
580
+ const kSigning = createHmac('sha256', kService).update('aws4_request').digest();
581
+ return kSigning;
582
+ }
583
+ /**
584
+ * Calculate SHA256 hash
585
+ */
586
+ sha256(data) {
587
+ return createHash('sha256').update(data).digest('hex');
588
+ }
589
+ /**
590
+ * Calculate SHA256 hash of buffer
591
+ */
592
+ calculateSHA256(buffer) {
593
+ return createHash('sha256').update(buffer).digest('hex');
594
+ }
595
+ /**
596
+ * Build metadata headers (x-amz-meta-*)
597
+ */
598
+ buildMetadataHeaders(metadata) {
599
+ const headers = {};
600
+ for (const [key, value] of Object.entries(metadata)) {
601
+ headers[`x-amz-meta-${key.toLowerCase()}`] = value;
602
+ }
603
+ return headers;
604
+ }
605
+ /**
606
+ * Extract metadata from response headers
607
+ */
608
+ extractMetadata(headers) {
609
+ const metadata = {};
610
+ headers.forEach((value, key) => {
611
+ if (key.toLowerCase().startsWith('x-amz-meta-')) {
612
+ const metaKey = key.substring('x-amz-meta-'.length);
613
+ metadata[metaKey] = value;
614
+ }
615
+ });
616
+ return Object.keys(metadata).length > 0 ? metadata : undefined;
617
+ }
618
+ /**
619
+ * Parse S3 ListObjectsV2 XML response
620
+ */
621
+ parseListObjectsResponse(xml) {
622
+ // Simple XML parsing (production should use proper XML parser)
623
+ const objects = [];
624
+ const contentsRegex = /<Contents>(.*?)<\/Contents>/gs;
625
+ const matches = xml.matchAll(contentsRegex);
626
+ for (const match of matches) {
627
+ const content = match[1];
628
+ const key = this.extractXMLValue(content, 'Key');
629
+ const size = parseInt(this.extractXMLValue(content, 'Size') || '0', 10);
630
+ const lastModified = new Date(this.extractXMLValue(content, 'LastModified') || Date.now());
631
+ const etag = this.extractXMLValue(content, 'ETag')?.replace(/"/g, '') || '';
632
+ const storageClass = this.extractXMLValue(content, 'StorageClass');
633
+ if (key) {
634
+ objects.push({
635
+ key,
636
+ size,
637
+ lastModified,
638
+ etag,
639
+ storageClass
640
+ });
641
+ }
642
+ }
643
+ const isTruncated = this.extractXMLValue(xml, 'IsTruncated') === 'true';
644
+ const nextContinuationToken = this.extractXMLValue(xml, 'NextContinuationToken');
645
+ const keyCount = parseInt(this.extractXMLValue(xml, 'KeyCount') || '0', 10);
646
+ return {
647
+ objects,
648
+ isTruncated,
649
+ nextContinuationToken,
650
+ keyCount
651
+ };
652
+ }
653
+ /**
654
+ * Extract value from XML string
655
+ */
656
+ extractXMLValue(xml, tag) {
657
+ const regex = new RegExp(`<${tag}>(.*?)<\/${tag}>`, 's');
658
+ const match = xml.match(regex);
659
+ return match ? match[1] : undefined;
660
+ }
661
+ /**
662
+ * Extract upload ID from XML response
663
+ */
664
+ extractUploadId(xml) {
665
+ const uploadId = this.extractXMLValue(xml, 'UploadId');
666
+ if (!uploadId) {
667
+ throw new Error('Failed to extract UploadId from response');
668
+ }
669
+ return uploadId;
670
+ }
671
+ /**
672
+ * Build CompleteMultipartUpload XML body
673
+ */
674
+ buildCompleteMultipartUploadXML(parts) {
675
+ const partXMLs = parts
676
+ .map(part => ` <Part>\n <PartNumber>${part.partNumber}</PartNumber>\n <ETag>"${part.etag}"</ETag>\n </Part>`)
677
+ .join('\n');
678
+ return `<CompleteMultipartUpload>\n${partXMLs}\n</CompleteMultipartUpload>`;
679
+ }
680
+ }