@streetjs/storage 1.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 (363) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +719 -0
  3. package/dist/access.d.ts +95 -0
  4. package/dist/access.d.ts.map +1 -0
  5. package/dist/access.js +114 -0
  6. package/dist/access.js.map +1 -0
  7. package/dist/cli/commands.d.ts +88 -0
  8. package/dist/cli/commands.d.ts.map +1 -0
  9. package/dist/cli/commands.js +369 -0
  10. package/dist/cli/commands.js.map +1 -0
  11. package/dist/cli/generators.d.ts +41 -0
  12. package/dist/cli/generators.d.ts.map +1 -0
  13. package/dist/cli/generators.js +119 -0
  14. package/dist/cli/generators.js.map +1 -0
  15. package/dist/directory.d.ts +88 -0
  16. package/dist/directory.d.ts.map +1 -0
  17. package/dist/directory.js +148 -0
  18. package/dist/directory.js.map +1 -0
  19. package/dist/driver.d.ts +83 -0
  20. package/dist/driver.d.ts.map +1 -0
  21. package/dist/driver.js +16 -0
  22. package/dist/driver.js.map +1 -0
  23. package/dist/drivers/azure.d.ts +239 -0
  24. package/dist/drivers/azure.d.ts.map +1 -0
  25. package/dist/drivers/azure.js +476 -0
  26. package/dist/drivers/azure.js.map +1 -0
  27. package/dist/drivers/backblaze.d.ts +105 -0
  28. package/dist/drivers/backblaze.d.ts.map +1 -0
  29. package/dist/drivers/backblaze.js +279 -0
  30. package/dist/drivers/backblaze.js.map +1 -0
  31. package/dist/drivers/gcs.d.ts +239 -0
  32. package/dist/drivers/gcs.d.ts.map +1 -0
  33. package/dist/drivers/gcs.js +454 -0
  34. package/dist/drivers/gcs.js.map +1 -0
  35. package/dist/drivers/local.d.ts +126 -0
  36. package/dist/drivers/local.d.ts.map +1 -0
  37. package/dist/drivers/local.js +321 -0
  38. package/dist/drivers/local.js.map +1 -0
  39. package/dist/drivers/memory.d.ts +104 -0
  40. package/dist/drivers/memory.d.ts.map +1 -0
  41. package/dist/drivers/memory.js +197 -0
  42. package/dist/drivers/memory.js.map +1 -0
  43. package/dist/drivers/minio.d.ts +90 -0
  44. package/dist/drivers/minio.d.ts.map +1 -0
  45. package/dist/drivers/minio.js +276 -0
  46. package/dist/drivers/minio.js.map +1 -0
  47. package/dist/drivers/r2.d.ts +100 -0
  48. package/dist/drivers/r2.d.ts.map +1 -0
  49. package/dist/drivers/r2.js +240 -0
  50. package/dist/drivers/r2.js.map +1 -0
  51. package/dist/drivers/s3-base.d.ts +270 -0
  52. package/dist/drivers/s3-base.d.ts.map +1 -0
  53. package/dist/drivers/s3-base.js +436 -0
  54. package/dist/drivers/s3-base.js.map +1 -0
  55. package/dist/drivers/s3.d.ts +111 -0
  56. package/dist/drivers/s3.d.ts.map +1 -0
  57. package/dist/drivers/s3.js +311 -0
  58. package/dist/drivers/s3.js.map +1 -0
  59. package/dist/drivers/supabase.d.ts +246 -0
  60. package/dist/drivers/supabase.d.ts.map +1 -0
  61. package/dist/drivers/supabase.js +502 -0
  62. package/dist/drivers/supabase.js.map +1 -0
  63. package/dist/errors.d.ts +115 -0
  64. package/dist/errors.d.ts.map +1 -0
  65. package/dist/errors.js +131 -0
  66. package/dist/errors.js.map +1 -0
  67. package/dist/examples/storage-demo.d.ts +53 -0
  68. package/dist/examples/storage-demo.d.ts.map +1 -0
  69. package/dist/examples/storage-demo.js +242 -0
  70. package/dist/examples/storage-demo.js.map +1 -0
  71. package/dist/facade.d.ts +192 -0
  72. package/dist/facade.d.ts.map +1 -0
  73. package/dist/facade.js +898 -0
  74. package/dist/facade.js.map +1 -0
  75. package/dist/image.d.ts +94 -0
  76. package/dist/image.d.ts.map +1 -0
  77. package/dist/image.js +224 -0
  78. package/dist/image.js.map +1 -0
  79. package/dist/index.d.ts +47 -0
  80. package/dist/index.d.ts.map +1 -0
  81. package/dist/index.js +53 -0
  82. package/dist/index.js.map +1 -0
  83. package/dist/integrations/events.d.ts +108 -0
  84. package/dist/integrations/events.d.ts.map +1 -0
  85. package/dist/integrations/events.js +111 -0
  86. package/dist/integrations/events.js.map +1 -0
  87. package/dist/integrations/queue.d.ts +89 -0
  88. package/dist/integrations/queue.d.ts.map +1 -0
  89. package/dist/integrations/queue.js +91 -0
  90. package/dist/integrations/queue.js.map +1 -0
  91. package/dist/integrations/realtime.d.ts +95 -0
  92. package/dist/integrations/realtime.d.ts.map +1 -0
  93. package/dist/integrations/realtime.js +90 -0
  94. package/dist/integrations/realtime.js.map +1 -0
  95. package/dist/lifecycle.d.ts +137 -0
  96. package/dist/lifecycle.d.ts.map +1 -0
  97. package/dist/lifecycle.js +240 -0
  98. package/dist/lifecycle.js.map +1 -0
  99. package/dist/metadata.d.ts +109 -0
  100. package/dist/metadata.d.ts.map +1 -0
  101. package/dist/metadata.js +139 -0
  102. package/dist/metadata.js.map +1 -0
  103. package/dist/multipart.d.ts +108 -0
  104. package/dist/multipart.d.ts.map +1 -0
  105. package/dist/multipart.js +200 -0
  106. package/dist/multipart.js.map +1 -0
  107. package/dist/observability.d.ts +82 -0
  108. package/dist/observability.d.ts.map +1 -0
  109. package/dist/observability.js +175 -0
  110. package/dist/observability.js.map +1 -0
  111. package/dist/plugin.d.ts +82 -0
  112. package/dist/plugin.d.ts.map +1 -0
  113. package/dist/plugin.js +100 -0
  114. package/dist/plugin.js.map +1 -0
  115. package/dist/resumable.d.ts +118 -0
  116. package/dist/resumable.d.ts.map +1 -0
  117. package/dist/resumable.js +223 -0
  118. package/dist/resumable.js.map +1 -0
  119. package/dist/search.d.ts +57 -0
  120. package/dist/search.d.ts.map +1 -0
  121. package/dist/search.js +172 -0
  122. package/dist/search.js.map +1 -0
  123. package/dist/signed-url.d.ts +110 -0
  124. package/dist/signed-url.d.ts.map +1 -0
  125. package/dist/signed-url.js +237 -0
  126. package/dist/signed-url.js.map +1 -0
  127. package/dist/testing/index.d.ts +219 -0
  128. package/dist/testing/index.d.ts.map +1 -0
  129. package/dist/testing/index.js +393 -0
  130. package/dist/testing/index.js.map +1 -0
  131. package/dist/tests/access.test.d.ts +2 -0
  132. package/dist/tests/access.test.d.ts.map +1 -0
  133. package/dist/tests/access.test.js +270 -0
  134. package/dist/tests/access.test.js.map +1 -0
  135. package/dist/tests/azure-driver.test.d.ts +2 -0
  136. package/dist/tests/azure-driver.test.d.ts.map +1 -0
  137. package/dist/tests/azure-driver.test.js +183 -0
  138. package/dist/tests/azure-driver.test.js.map +1 -0
  139. package/dist/tests/backblaze-driver.test.d.ts +2 -0
  140. package/dist/tests/backblaze-driver.test.d.ts.map +1 -0
  141. package/dist/tests/backblaze-driver.test.js +185 -0
  142. package/dist/tests/backblaze-driver.test.js.map +1 -0
  143. package/dist/tests/bridge-degradation.test.d.ts +2 -0
  144. package/dist/tests/bridge-degradation.test.d.ts.map +1 -0
  145. package/dist/tests/bridge-degradation.test.js +138 -0
  146. package/dist/tests/bridge-degradation.test.js.map +1 -0
  147. package/dist/tests/cli.test.d.ts +2 -0
  148. package/dist/tests/cli.test.d.ts.map +1 -0
  149. package/dist/tests/cli.test.js +127 -0
  150. package/dist/tests/cli.test.js.map +1 -0
  151. package/dist/tests/contract.d.ts +131 -0
  152. package/dist/tests/contract.d.ts.map +1 -0
  153. package/dist/tests/contract.js +222 -0
  154. package/dist/tests/contract.js.map +1 -0
  155. package/dist/tests/contract.test.d.ts +2 -0
  156. package/dist/tests/contract.test.d.ts.map +1 -0
  157. package/dist/tests/contract.test.js +110 -0
  158. package/dist/tests/contract.test.js.map +1 -0
  159. package/dist/tests/directory.test.d.ts +2 -0
  160. package/dist/tests/directory.test.d.ts.map +1 -0
  161. package/dist/tests/directory.test.js +125 -0
  162. package/dist/tests/directory.test.js.map +1 -0
  163. package/dist/tests/errors.test.d.ts +2 -0
  164. package/dist/tests/errors.test.d.ts.map +1 -0
  165. package/dist/tests/errors.test.js +93 -0
  166. package/dist/tests/errors.test.js.map +1 -0
  167. package/dist/tests/events-bridge.test.d.ts +2 -0
  168. package/dist/tests/events-bridge.test.d.ts.map +1 -0
  169. package/dist/tests/events-bridge.test.js +228 -0
  170. package/dist/tests/events-bridge.test.js.map +1 -0
  171. package/dist/tests/example-smoke.test.d.ts +2 -0
  172. package/dist/tests/example-smoke.test.d.ts.map +1 -0
  173. package/dist/tests/example-smoke.test.js +34 -0
  174. package/dist/tests/example-smoke.test.js.map +1 -0
  175. package/dist/tests/gcs-driver.test.d.ts +2 -0
  176. package/dist/tests/gcs-driver.test.d.ts.map +1 -0
  177. package/dist/tests/gcs-driver.test.js +197 -0
  178. package/dist/tests/gcs-driver.test.js.map +1 -0
  179. package/dist/tests/image.test.d.ts +2 -0
  180. package/dist/tests/image.test.d.ts.map +1 -0
  181. package/dist/tests/image.test.js +102 -0
  182. package/dist/tests/image.test.js.map +1 -0
  183. package/dist/tests/lifecycle.test.d.ts +2 -0
  184. package/dist/tests/lifecycle.test.d.ts.map +1 -0
  185. package/dist/tests/lifecycle.test.js +171 -0
  186. package/dist/tests/lifecycle.test.js.map +1 -0
  187. package/dist/tests/local-driver.test.d.ts +2 -0
  188. package/dist/tests/local-driver.test.d.ts.map +1 -0
  189. package/dist/tests/local-driver.test.js +153 -0
  190. package/dist/tests/local-driver.test.js.map +1 -0
  191. package/dist/tests/local-streaming.test.d.ts +2 -0
  192. package/dist/tests/local-streaming.test.d.ts.map +1 -0
  193. package/dist/tests/local-streaming.test.js +121 -0
  194. package/dist/tests/local-streaming.test.js.map +1 -0
  195. package/dist/tests/memory-driver.test.d.ts +2 -0
  196. package/dist/tests/memory-driver.test.d.ts.map +1 -0
  197. package/dist/tests/memory-driver.test.js +180 -0
  198. package/dist/tests/memory-driver.test.js.map +1 -0
  199. package/dist/tests/memory-streaming.test.d.ts +2 -0
  200. package/dist/tests/memory-streaming.test.d.ts.map +1 -0
  201. package/dist/tests/memory-streaming.test.js +92 -0
  202. package/dist/tests/memory-streaming.test.js.map +1 -0
  203. package/dist/tests/minio-driver.test.d.ts +2 -0
  204. package/dist/tests/minio-driver.test.d.ts.map +1 -0
  205. package/dist/tests/minio-driver.test.js +146 -0
  206. package/dist/tests/minio-driver.test.js.map +1 -0
  207. package/dist/tests/non-s3-integration.test.d.ts +2 -0
  208. package/dist/tests/non-s3-integration.test.d.ts.map +1 -0
  209. package/dist/tests/non-s3-integration.test.js +201 -0
  210. package/dist/tests/non-s3-integration.test.js.map +1 -0
  211. package/dist/tests/observability.registration.test.d.ts +2 -0
  212. package/dist/tests/observability.registration.test.d.ts.map +1 -0
  213. package/dist/tests/observability.registration.test.js +103 -0
  214. package/dist/tests/observability.registration.test.js.map +1 -0
  215. package/dist/tests/observability.test.d.ts +2 -0
  216. package/dist/tests/observability.test.d.ts.map +1 -0
  217. package/dist/tests/observability.test.js +240 -0
  218. package/dist/tests/observability.test.js.map +1 -0
  219. package/dist/tests/plugin.test.d.ts +2 -0
  220. package/dist/tests/plugin.test.d.ts.map +1 -0
  221. package/dist/tests/plugin.test.js +112 -0
  222. package/dist/tests/plugin.test.js.map +1 -0
  223. package/dist/tests/prop-concurrent.test.d.ts +2 -0
  224. package/dist/tests/prop-concurrent.test.d.ts.map +1 -0
  225. package/dist/tests/prop-concurrent.test.js +59 -0
  226. package/dist/tests/prop-concurrent.test.js.map +1 -0
  227. package/dist/tests/prop-copy.test.d.ts +2 -0
  228. package/dist/tests/prop-copy.test.d.ts.map +1 -0
  229. package/dist/tests/prop-copy.test.js +63 -0
  230. package/dist/tests/prop-copy.test.js.map +1 -0
  231. package/dist/tests/prop-delete.test.d.ts +2 -0
  232. package/dist/tests/prop-delete.test.d.ts.map +1 -0
  233. package/dist/tests/prop-delete.test.js +35 -0
  234. package/dist/tests/prop-delete.test.js.map +1 -0
  235. package/dist/tests/prop-directory.test.d.ts +2 -0
  236. package/dist/tests/prop-directory.test.d.ts.map +1 -0
  237. package/dist/tests/prop-directory.test.js +118 -0
  238. package/dist/tests/prop-directory.test.js.map +1 -0
  239. package/dist/tests/prop-driver-conformance.test.d.ts +2 -0
  240. package/dist/tests/prop-driver-conformance.test.d.ts.map +1 -0
  241. package/dist/tests/prop-driver-conformance.test.js +110 -0
  242. package/dist/tests/prop-driver-conformance.test.js.map +1 -0
  243. package/dist/tests/prop-driver-equivalence.test.d.ts +2 -0
  244. package/dist/tests/prop-driver-equivalence.test.d.ts.map +1 -0
  245. package/dist/tests/prop-driver-equivalence.test.js +163 -0
  246. package/dist/tests/prop-driver-equivalence.test.js.map +1 -0
  247. package/dist/tests/prop-lifecycle.test.d.ts +2 -0
  248. package/dist/tests/prop-lifecycle.test.d.ts.map +1 -0
  249. package/dist/tests/prop-lifecycle.test.js +83 -0
  250. package/dist/tests/prop-lifecycle.test.js.map +1 -0
  251. package/dist/tests/prop-list.test.d.ts +2 -0
  252. package/dist/tests/prop-list.test.d.ts.map +1 -0
  253. package/dist/tests/prop-list.test.js +53 -0
  254. package/dist/tests/prop-list.test.js.map +1 -0
  255. package/dist/tests/prop-metadata.test.d.ts +2 -0
  256. package/dist/tests/prop-metadata.test.d.ts.map +1 -0
  257. package/dist/tests/prop-metadata.test.js +87 -0
  258. package/dist/tests/prop-metadata.test.js.map +1 -0
  259. package/dist/tests/prop-move.test.d.ts +2 -0
  260. package/dist/tests/prop-move.test.d.ts.map +1 -0
  261. package/dist/tests/prop-move.test.js +67 -0
  262. package/dist/tests/prop-move.test.js.map +1 -0
  263. package/dist/tests/prop-multipart-abort.test.d.ts +2 -0
  264. package/dist/tests/prop-multipart-abort.test.d.ts.map +1 -0
  265. package/dist/tests/prop-multipart-abort.test.js +48 -0
  266. package/dist/tests/prop-multipart-abort.test.js.map +1 -0
  267. package/dist/tests/prop-multipart.test.d.ts +2 -0
  268. package/dist/tests/prop-multipart.test.d.ts.map +1 -0
  269. package/dist/tests/prop-multipart.test.js +65 -0
  270. package/dist/tests/prop-multipart.test.js.map +1 -0
  271. package/dist/tests/prop-resumable.test.d.ts +2 -0
  272. package/dist/tests/prop-resumable.test.d.ts.map +1 -0
  273. package/dist/tests/prop-resumable.test.js +78 -0
  274. package/dist/tests/prop-resumable.test.js.map +1 -0
  275. package/dist/tests/prop-search.test.d.ts +2 -0
  276. package/dist/tests/prop-search.test.d.ts.map +1 -0
  277. package/dist/tests/prop-search.test.js +120 -0
  278. package/dist/tests/prop-search.test.js.map +1 -0
  279. package/dist/tests/prop-signed-url.test.d.ts +2 -0
  280. package/dist/tests/prop-signed-url.test.d.ts.map +1 -0
  281. package/dist/tests/prop-signed-url.test.js +74 -0
  282. package/dist/tests/prop-signed-url.test.js.map +1 -0
  283. package/dist/tests/prop-streaming.test.d.ts +2 -0
  284. package/dist/tests/prop-streaming.test.d.ts.map +1 -0
  285. package/dist/tests/prop-streaming.test.js +34 -0
  286. package/dist/tests/prop-streaming.test.js.map +1 -0
  287. package/dist/tests/prop-upload-download.test.d.ts +2 -0
  288. package/dist/tests/prop-upload-download.test.d.ts.map +1 -0
  289. package/dist/tests/prop-upload-download.test.js +30 -0
  290. package/dist/tests/prop-upload-download.test.js.map +1 -0
  291. package/dist/tests/prop-validation.test.d.ts +2 -0
  292. package/dist/tests/prop-validation.test.d.ts.map +1 -0
  293. package/dist/tests/prop-validation.test.js +50 -0
  294. package/dist/tests/prop-validation.test.js.map +1 -0
  295. package/dist/tests/prop-versioning.test.d.ts +2 -0
  296. package/dist/tests/prop-versioning.test.d.ts.map +1 -0
  297. package/dist/tests/prop-versioning.test.js +74 -0
  298. package/dist/tests/prop-versioning.test.js.map +1 -0
  299. package/dist/tests/queue-bridge.test.d.ts +2 -0
  300. package/dist/tests/queue-bridge.test.d.ts.map +1 -0
  301. package/dist/tests/queue-bridge.test.js +111 -0
  302. package/dist/tests/queue-bridge.test.js.map +1 -0
  303. package/dist/tests/r2-driver.test.d.ts +2 -0
  304. package/dist/tests/r2-driver.test.d.ts.map +1 -0
  305. package/dist/tests/r2-driver.test.js +143 -0
  306. package/dist/tests/r2-driver.test.js.map +1 -0
  307. package/dist/tests/realtime-bridge.test.d.ts +2 -0
  308. package/dist/tests/realtime-bridge.test.d.ts.map +1 -0
  309. package/dist/tests/realtime-bridge.test.js +106 -0
  310. package/dist/tests/realtime-bridge.test.js.map +1 -0
  311. package/dist/tests/resumable.test.d.ts +2 -0
  312. package/dist/tests/resumable.test.d.ts.map +1 -0
  313. package/dist/tests/resumable.test.js +104 -0
  314. package/dist/tests/resumable.test.js.map +1 -0
  315. package/dist/tests/s3-base.test.d.ts +2 -0
  316. package/dist/tests/s3-base.test.d.ts.map +1 -0
  317. package/dist/tests/s3-base.test.js +289 -0
  318. package/dist/tests/s3-base.test.js.map +1 -0
  319. package/dist/tests/s3-integration.test.d.ts +2 -0
  320. package/dist/tests/s3-integration.test.d.ts.map +1 -0
  321. package/dist/tests/s3-integration.test.js +270 -0
  322. package/dist/tests/s3-integration.test.js.map +1 -0
  323. package/dist/tests/s3.test.d.ts +2 -0
  324. package/dist/tests/s3.test.d.ts.map +1 -0
  325. package/dist/tests/s3.test.js +203 -0
  326. package/dist/tests/s3.test.js.map +1 -0
  327. package/dist/tests/scaffold.test.d.ts +2 -0
  328. package/dist/tests/scaffold.test.d.ts.map +1 -0
  329. package/dist/tests/scaffold.test.js +13 -0
  330. package/dist/tests/scaffold.test.js.map +1 -0
  331. package/dist/tests/search.test.d.ts +2 -0
  332. package/dist/tests/search.test.d.ts.map +1 -0
  333. package/dist/tests/search.test.js +106 -0
  334. package/dist/tests/search.test.js.map +1 -0
  335. package/dist/tests/supabase-driver.test.d.ts +2 -0
  336. package/dist/tests/supabase-driver.test.d.ts.map +1 -0
  337. package/dist/tests/supabase-driver.test.js +196 -0
  338. package/dist/tests/supabase-driver.test.js.map +1 -0
  339. package/dist/tests/testing-utilities.test.d.ts +2 -0
  340. package/dist/tests/testing-utilities.test.d.ts.map +1 -0
  341. package/dist/tests/testing-utilities.test.js +138 -0
  342. package/dist/tests/testing-utilities.test.js.map +1 -0
  343. package/dist/tests/validation.test.d.ts +2 -0
  344. package/dist/tests/validation.test.d.ts.map +1 -0
  345. package/dist/tests/validation.test.js +135 -0
  346. package/dist/tests/validation.test.js.map +1 -0
  347. package/dist/tests/versioning.test.d.ts +2 -0
  348. package/dist/tests/versioning.test.d.ts.map +1 -0
  349. package/dist/tests/versioning.test.js +128 -0
  350. package/dist/tests/versioning.test.js.map +1 -0
  351. package/dist/types.d.ts +232 -0
  352. package/dist/types.d.ts.map +1 -0
  353. package/dist/types.js +23 -0
  354. package/dist/types.js.map +1 -0
  355. package/dist/validation.d.ts +105 -0
  356. package/dist/validation.d.ts.map +1 -0
  357. package/dist/validation.js +225 -0
  358. package/dist/validation.js.map +1 -0
  359. package/dist/versioning.d.ts +100 -0
  360. package/dist/versioning.d.ts.map +1 -0
  361. package/dist/versioning.js +179 -0
  362. package/dist/versioning.js.map +1 -0
  363. package/package.json +137 -0
@@ -0,0 +1,454 @@
1
+ /**
2
+ * @streetjs/storage — GoogleCloudStorageDriver (submodule `@streetjs/storage/gcs`).
3
+ *
4
+ * Google Cloud Storage is **not** an S3-wire-compatible provider — its SDK
5
+ * exposes a bucket/file object model (`bucket.file(name).save/download/delete/
6
+ * exists/getMetadata`, `bucket.getFiles({ prefix })`) rather than the
7
+ * `putObject`/`getObject` verbs the S3-style base is built on. So, unlike
8
+ * `r2.ts`/`minio.ts`/`backblaze.ts`, this driver does **not** extend the shared
9
+ * S3 base ({@link ../drivers/s3-base}); it maps the {@link StorageDriver}
10
+ * contract directly onto a purpose-built structural {@link GcsClientLike} that
11
+ * mirrors just the GCS calls it needs.
12
+ *
13
+ * ## Two ways to obtain a driver
14
+ *
15
+ * - {@link createGoogleCloudStorageDriver} wraps an **already-constructed,
16
+ * injected** {@link GcsClientLike} and returns a driver synchronously. This is
17
+ * the SDK-free path: no provider SDK is touched, so it is fully testable with
18
+ * an in-memory fake and needs no `@google-cloud/storage` install.
19
+ * - {@link connectGoogleCloudStorageDriver} **builds its own client** from GCS
20
+ * connection config. It resolves `@google-cloud/storage` through a **lazy
21
+ * dynamic `import()` performed inside the function** (never at module top
22
+ * level), so the optional peer dependency is only required when this path is
23
+ * actually used. If the SDK is not installed and no client was injected, it
24
+ * throws {@link StorageConfigError} (Requirement 1.5).
25
+ *
26
+ * ## Capability delegation (Requirement 2.3)
27
+ *
28
+ * The driver implements only the **mandatory primitives** (`put`/`get`/`exists`/
29
+ * `delete`/`stat`/`list`/`putStream`/`getStream`), producing every
30
+ * {@link StorageObjectMetadata} through the shared metadata layer
31
+ * ({@link buildObjectMetadata}) so the field set is identical to Memory/Local/S3,
32
+ * and reporting a missing key consistently ({@link MaybeObject} `{ found: false }`
33
+ * for `get`, `null` for `stat`, {@link NotFoundError} for `getStream`). Advanced
34
+ * capabilities (`multipart`/`resumable`/`versioning`/`signedUrl`/`lifecycle`) are
35
+ * intentionally left `undefined` so the facade simulates them over the
36
+ * primitives, keeping behavior identical across providers.
37
+ *
38
+ * ## SDK isolation (Requirements 2.1, 3.3)
39
+ *
40
+ * This module imports **no provider SDK at the top level** — only Node built-ins,
41
+ * `streetjs` (for the injected {@link Clock}), and this package's own type
42
+ * surface. `@google-cloud/storage` is referenced solely via a dynamic `import()`
43
+ * with a non-literal specifier inside {@link connectGoogleCloudStorageDriver}, so
44
+ * `tsc` never requires the SDK to be present and `streetjs` stays the only
45
+ * runtime dependency. This driver is a submodule-only export
46
+ * (`./gcs` → `dist/drivers/gcs.js`); it is intentionally not re-exported from the
47
+ * package's main `index.ts`.
48
+ *
49
+ * _Requirements: 2.1, 2.3, 3.3_
50
+ */
51
+ import { createHash } from "node:crypto";
52
+ import { Readable, Writable } from "node:stream";
53
+ import { pipeline } from "node:stream/promises";
54
+ import { systemClock } from "streetjs";
55
+ import { NotFoundError, StorageConfigError } from "../errors.js";
56
+ import { buildObjectMetadata } from "../metadata.js";
57
+ /** The stable driver name surfaced as {@link StorageDriver.name} for GCS. */
58
+ const GCS_DRIVER_NAME = "gcs";
59
+ // ── Reserved user-metadata keys ────────────────────────────────────────────────
60
+ /**
61
+ * Reserved custom-metadata keys used to round-trip the typed metadata field set
62
+ * through GCS's string→string object-metadata map. Prefixed so they never
63
+ * collide with a caller's own custom fields.
64
+ */
65
+ const MK = {
66
+ checksum: "x-street-checksum",
67
+ createdAt: "x-street-created-at",
68
+ updatedAt: "x-street-updated-at",
69
+ owner: "x-street-owner",
70
+ tenant: "x-street-tenant",
71
+ accessLevel: "x-street-access-level",
72
+ custom: "x-street-custom",
73
+ };
74
+ // ── The GCS driver ─────────────────────────────────────────────────────────────
75
+ /**
76
+ * Maps the {@link StorageDriver} contract onto an injected {@link GcsClientLike}.
77
+ *
78
+ * Object identity fields (`etag`/`checksum`/`size`) and timestamps are computed
79
+ * locally at write time — the checksum/etag are the sha-256 hex digest of the
80
+ * stored bytes, the size is the byte length, and timestamps come from the
81
+ * injected {@link Clock} — then encoded into the object's custom metadata so they
82
+ * round-trip on read. Advanced capabilities are left `undefined` for facade
83
+ * simulation.
84
+ */
85
+ export class GoogleCloudStorageDriver {
86
+ /** Stable driver name. */
87
+ name = GCS_DRIVER_NAME;
88
+ client;
89
+ clock;
90
+ constructor(client, options = {}) {
91
+ this.client = client;
92
+ this.clock = options.clock ?? systemClock;
93
+ }
94
+ // ── Mandatory primitives ──────────────────────────────────────────────────
95
+ /**
96
+ * Store `bytes` under `key`, computing size and sha-256 checksum locally and
97
+ * taking timestamps from the injected clock. When overwriting, the original
98
+ * `createdAt` is preserved (a preceding attribute read). The typed metadata is
99
+ * encoded into the object's custom-metadata map so it round-trips on read
100
+ * (Requirements 4.1, 10.1, 10.2).
101
+ */
102
+ async put(key, bytes, metadata) {
103
+ const stored = bytes.slice();
104
+ const checksum = sha256Hex(stored);
105
+ const now = this.clock();
106
+ const existing = await this.stat(key);
107
+ const objectMetadata = buildObjectMetadata({
108
+ key,
109
+ size: stored.byteLength,
110
+ checksum,
111
+ createdAt: existing?.createdAt ?? now,
112
+ updatedAt: now,
113
+ write: metadata,
114
+ });
115
+ await this.client.save(key, stored, {
116
+ contentType: objectMetadata.contentType,
117
+ metadata: encodeUserMetadata(objectMetadata),
118
+ });
119
+ return objectMetadata;
120
+ }
121
+ /**
122
+ * Read the object at `key`, returning a discriminated {@link MaybeObject} so
123
+ * absence is reported rather than thrown (Requirements 4.2, 2.4). Metadata is
124
+ * rebuilt from the object's attributes and encoded custom metadata via the
125
+ * shared metadata layer.
126
+ */
127
+ async get(key) {
128
+ const bytes = await this.client.download(key);
129
+ if (bytes === null) {
130
+ return { found: false };
131
+ }
132
+ const attributes = await this.client.getMetadata(key);
133
+ const metadata = this.decodeMeta(key, bytes.byteLength, attributes);
134
+ return { found: true, bytes: bytes.slice(), metadata };
135
+ }
136
+ /** Report whether an object is stored under `key` (Requirement 4.3). */
137
+ async exists(key) {
138
+ return this.client.exists(key);
139
+ }
140
+ /** Delete the object at `key`; deleting a missing key is a no-op (Requirement 4.4). */
141
+ async delete(key) {
142
+ await this.client.delete(key);
143
+ }
144
+ /**
145
+ * Return the metadata for `key` without its content, or `null` when absent
146
+ * (Requirement 4.10).
147
+ */
148
+ async stat(key) {
149
+ const attributes = await this.client.getMetadata(key);
150
+ if (attributes === null) {
151
+ return null;
152
+ }
153
+ const size = parseSize(attributes.size);
154
+ return this.decodeMeta(key, size, attributes);
155
+ }
156
+ /**
157
+ * List objects whose key begins with `prefix`, sorted by key for deterministic
158
+ * ordering (Requirement 4.9). Honors optional `cursor` (exclusive resume
159
+ * point), `limit`, and `delimiter` (collapse to immediate children on `/`).
160
+ */
161
+ async list(prefix, options) {
162
+ const entries = await this.client.getFiles({
163
+ prefix,
164
+ delimiter: options?.delimiter === true ? "/" : undefined,
165
+ });
166
+ let items = entries
167
+ .filter((entry) => typeof entry.name === "string")
168
+ .map((entry) => ({
169
+ key: entry.name,
170
+ size: parseSize(entry.attributes?.size),
171
+ updatedAt: parseIso(entry.attributes?.updated) ?? 0,
172
+ }))
173
+ .sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
174
+ const cursor = options?.cursor;
175
+ if (cursor !== undefined) {
176
+ items = items.filter((item) => item.key > cursor);
177
+ }
178
+ return typeof options?.limit === "number" ? items.slice(0, options.limit) : items;
179
+ }
180
+ // ── Streaming ───────────────────────────────────────────────────────────────
181
+ /**
182
+ * Consume a Node {@link Readable} and persist the assembled bytes under `key`
183
+ * with the same computed metadata as {@link put} (Requirement 5.1). Chunks are
184
+ * drained through a `pipeline` (correct backpressure and error propagation),
185
+ * then handed to {@link put}.
186
+ */
187
+ async putStream(key, stream, metadata) {
188
+ const chunks = [];
189
+ const collector = new Writable({
190
+ write(chunk, _encoding, callback) {
191
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
192
+ callback();
193
+ },
194
+ });
195
+ await pipeline(stream, collector);
196
+ return this.put(key, new Uint8Array(Buffer.concat(chunks)), metadata);
197
+ }
198
+ /**
199
+ * Return a Node {@link Readable} of the stored bytes at `key` (Requirement
200
+ * 5.2). Throws {@link NotFoundError} for a missing key (Requirement 5.5).
201
+ */
202
+ async getStream(key) {
203
+ const bytes = await this.client.download(key);
204
+ if (bytes === null) {
205
+ throw new NotFoundError(key);
206
+ }
207
+ return Readable.from([Buffer.from(bytes)]);
208
+ }
209
+ // ── Internal helpers ──────────────────────────────────────────────────────
210
+ /**
211
+ * Rebuild the typed {@link StorageObjectMetadata} field set from the object's
212
+ * attributes and the encoded custom-metadata map, applying the shared layer's
213
+ * canonical defaults. Provider-supplied values are used as best-effort
214
+ * fallbacks when the encoded fields are absent (e.g. an object written outside
215
+ * this driver): `etag`/`md5Hash`/`timeCreated`/`updated` back-fill the
216
+ * identity/timestamp fields, keeping the shape consistent across providers.
217
+ */
218
+ decodeMeta(key, size, attributes) {
219
+ const attrs = attributes ?? {};
220
+ const um = attrs.metadata ?? {};
221
+ const now = this.clock();
222
+ const checksum = um[MK.checksum] ?? attrs.etag ?? attrs.md5Hash ?? "";
223
+ const createdAt = parseEpoch(um[MK.createdAt]) ?? parseIso(attrs.timeCreated) ?? now;
224
+ const updatedAt = parseEpoch(um[MK.updatedAt]) ?? parseIso(attrs.updated) ?? createdAt;
225
+ const write = {
226
+ contentType: attrs.contentType,
227
+ owner: um[MK.owner],
228
+ tenant: um[MK.tenant],
229
+ accessLevel: decodeAccessLevel(um[MK.accessLevel]),
230
+ custom: parseCustom(um[MK.custom]),
231
+ };
232
+ return buildObjectMetadata({
233
+ key,
234
+ size,
235
+ checksum,
236
+ etag: attrs.etag ?? checksum,
237
+ createdAt,
238
+ updatedAt,
239
+ write,
240
+ });
241
+ }
242
+ }
243
+ /**
244
+ * Wrap an injected {@link GcsClientLike} as a GCS driver. Synchronous and
245
+ * SDK-free: the caller supplies the client, so no provider SDK is resolved here.
246
+ *
247
+ * @throws {StorageConfigError} when no client is injected — use
248
+ * {@link connectGoogleCloudStorageDriver} to build a client from connection
249
+ * options instead.
250
+ */
251
+ export function createGoogleCloudStorageDriver(client, options = {}) {
252
+ if (client === undefined || client === null) {
253
+ throw new StorageConfigError("createGoogleCloudStorageDriver requires an injected GcsClientLike. " +
254
+ "Pass a structural client, or use connectGoogleCloudStorageDriver(config) " +
255
+ "to build one from a bucket using the optional '@google-cloud/storage' peer dependency.", { provider: GCS_DRIVER_NAME });
256
+ }
257
+ return new GoogleCloudStorageDriver(client, options);
258
+ }
259
+ /**
260
+ * Build a GCS driver that owns its client, resolving `@google-cloud/storage`
261
+ * lazily.
262
+ *
263
+ * The SDK is loaded through a dynamic `import()` with a non-literal specifier so
264
+ * it is never a static/top-level dependency: `tsc` does not require it to be
265
+ * installed, and it is only resolved when this function runs. When the SDK
266
+ * cannot be resolved, a {@link StorageConfigError} is thrown (Requirement 1.5) —
267
+ * callers that cannot install the SDK should use
268
+ * {@link createGoogleCloudStorageDriver} with their own {@link GcsClientLike}
269
+ * instead.
270
+ */
271
+ export async function connectGoogleCloudStorageDriver(config) {
272
+ if (!config.bucket) {
273
+ throw new StorageConfigError("GoogleCloudStorage requires a bucket name.", { provider: GCS_DRIVER_NAME });
274
+ }
275
+ // Lazy, non-literal dynamic import so the GCS SDK stays an optional peer that
276
+ // `tsc` never resolves statically and Node only loads on this path.
277
+ const specifier = "@google-cloud/storage";
278
+ let sdk;
279
+ try {
280
+ sdk = (await import(specifier));
281
+ }
282
+ catch (cause) {
283
+ throw new StorageConfigError('GoogleCloudStorage driver requires the optional peer dependency "@google-cloud/storage". ' +
284
+ "Install it, or inject your own GcsClientLike via createGoogleCloudStorageDriver().", { provider: GCS_DRIVER_NAME, cause });
285
+ }
286
+ let storage;
287
+ try {
288
+ storage = new sdk.Storage({
289
+ projectId: config.projectId,
290
+ keyFilename: config.keyFilename,
291
+ credentials: config.credentials,
292
+ apiEndpoint: config.apiEndpoint,
293
+ });
294
+ }
295
+ catch (cause) {
296
+ throw new StorageConfigError(`Failed to construct a Google Cloud Storage client for bucket "${config.bucket}".`, { provider: GCS_DRIVER_NAME, cause });
297
+ }
298
+ const client = adaptGcsSdkBucket(storage.bucket(config.bucket));
299
+ return createGoogleCloudStorageDriver(client, { clock: config.clock });
300
+ }
301
+ // ── SDK → GcsClientLike adapter ────────────────────────────────────────────────
302
+ /**
303
+ * Adapt a `@google-cloud/storage` `Bucket` into the structural
304
+ * {@link GcsClientLike} this driver consumes. Only the methods the driver uses
305
+ * are mapped; the SDK response shapes are narrowed through the local structural
306
+ * types below so this module never imports concrete SDK types. A missing object
307
+ * (`code === 404`) is mapped to `null` so not-found semantics stay consistent.
308
+ */
309
+ function adaptGcsSdkBucket(bucket) {
310
+ return {
311
+ async save(name, bytes, options) {
312
+ await bucket.file(name).save(Buffer.from(bytes), {
313
+ contentType: options?.contentType,
314
+ metadata: { metadata: options?.metadata },
315
+ });
316
+ },
317
+ async download(name) {
318
+ try {
319
+ const [buffer] = await bucket.file(name).download();
320
+ return new Uint8Array(buffer);
321
+ }
322
+ catch (error) {
323
+ if (isNotFound(error)) {
324
+ return null;
325
+ }
326
+ throw error;
327
+ }
328
+ },
329
+ async delete(name) {
330
+ await bucket.file(name).delete({ ignoreNotFound: true });
331
+ },
332
+ async exists(name) {
333
+ const [exists] = await bucket.file(name).exists();
334
+ return exists;
335
+ },
336
+ async getMetadata(name) {
337
+ try {
338
+ const [metadata] = await bucket.file(name).getMetadata();
339
+ return metadata;
340
+ }
341
+ catch (error) {
342
+ if (isNotFound(error)) {
343
+ return null;
344
+ }
345
+ throw error;
346
+ }
347
+ },
348
+ async getFiles(input) {
349
+ const [files] = await bucket.getFiles({
350
+ prefix: input.prefix,
351
+ delimiter: input.delimiter,
352
+ maxResults: input.maxResults,
353
+ });
354
+ return files.map((file) => ({
355
+ name: file.name,
356
+ attributes: file.metadata,
357
+ }));
358
+ },
359
+ };
360
+ }
361
+ /**
362
+ * Recognize the GCS "object does not exist" condition so `download`/`getMetadata`
363
+ * can return `null` (Requirement 4.2/4.10) rather than throwing. GCS surfaces a
364
+ * `code === 404` on the ApiError.
365
+ */
366
+ function isNotFound(error) {
367
+ if (error === null || typeof error !== "object") {
368
+ return false;
369
+ }
370
+ const code = error.code;
371
+ return code === 404;
372
+ }
373
+ // ── Module-private encoding helpers ────────────────────────────────────────────
374
+ /** Compute the lowercase sha-256 hex digest of `bytes`. */
375
+ function sha256Hex(bytes) {
376
+ return createHash("sha256").update(bytes).digest("hex");
377
+ }
378
+ /** Encode a built object's typed metadata into the GCS custom-metadata map. */
379
+ function encodeUserMetadata(metadata) {
380
+ const map = {
381
+ [MK.checksum]: metadata.checksum,
382
+ [MK.createdAt]: String(metadata.createdAt),
383
+ [MK.updatedAt]: String(metadata.updatedAt),
384
+ [MK.accessLevel]: metadata.accessLevel,
385
+ [MK.custom]: JSON.stringify(metadata.custom ?? {}),
386
+ };
387
+ if (metadata.owner !== undefined) {
388
+ map[MK.owner] = metadata.owner;
389
+ }
390
+ if (metadata.tenant !== undefined) {
391
+ map[MK.tenant] = metadata.tenant;
392
+ }
393
+ return map;
394
+ }
395
+ /** Parse a GCS `size` (numeric string or number), defaulting to `0`. */
396
+ function parseSize(value) {
397
+ if (typeof value === "number") {
398
+ return Number.isFinite(value) ? value : 0;
399
+ }
400
+ if (typeof value === "string") {
401
+ const parsed = Number(value);
402
+ return Number.isFinite(parsed) ? parsed : 0;
403
+ }
404
+ return 0;
405
+ }
406
+ /** Parse an epoch-ms string, returning `undefined` when absent or non-numeric. */
407
+ function parseEpoch(value) {
408
+ if (value === undefined) {
409
+ return undefined;
410
+ }
411
+ const parsed = Number(value);
412
+ return Number.isFinite(parsed) ? parsed : undefined;
413
+ }
414
+ /** Parse an RFC-3339 / ISO-8601 timestamp to epoch ms, or `undefined`. */
415
+ function parseIso(value) {
416
+ if (value === undefined) {
417
+ return undefined;
418
+ }
419
+ const parsed = Date.parse(value);
420
+ return Number.isFinite(parsed) ? parsed : undefined;
421
+ }
422
+ /** Parse the encoded custom-field JSON, tolerating malformed values. */
423
+ function parseCustom(value) {
424
+ if (value === undefined) {
425
+ return {};
426
+ }
427
+ try {
428
+ const parsed = JSON.parse(value);
429
+ if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
430
+ return parsed;
431
+ }
432
+ }
433
+ catch {
434
+ // Fall through to the empty default on malformed JSON.
435
+ }
436
+ return {};
437
+ }
438
+ /** The recognized access levels, used to validate the decoded value. */
439
+ const ACCESS_LEVELS = [
440
+ "public",
441
+ "private",
442
+ "signed",
443
+ "authenticated",
444
+ "role-based",
445
+ "tenant-aware",
446
+ ];
447
+ /** Decode an access-level string, returning `undefined` for an unknown value. */
448
+ function decodeAccessLevel(value) {
449
+ if (value !== undefined && ACCESS_LEVELS.includes(value)) {
450
+ return value;
451
+ }
452
+ return undefined;
453
+ }
454
+ //# sourceMappingURL=gcs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gcs.js","sourceRoot":"","sources":["../../src/drivers/gcs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * @streetjs/storage — LocalStorageDriver (zero-dependency).
3
+ *
4
+ * A filesystem-backed implementation of the {@link StorageDriver} contract that
5
+ * uses only Node's built-in `fs` module (part of the runtime, not an external
6
+ * dependency — Requirement 3.2). Object bytes are written to `root/<key>` and
7
+ * the computed {@link StorageObjectMetadata} is persisted alongside them in a
8
+ * sidecar file at `root/<key>.meta.json`. Parent directories are created on
9
+ * demand so nested key paths (e.g. `a/b/c.txt`) work transparently.
10
+ *
11
+ * The Local driver is observationally equivalent to
12
+ * {@link MemoryStorageDriver} (Requirement 2.2): identical `etag`/`checksum`
13
+ * (sha-256 hex of the stored bytes via `node:crypto`), `size` (byte length),
14
+ * timestamps sourced from an injected {@link Clock} (default `systemClock` from
15
+ * `streetjs`), and defaults (`contentType` `application/octet-stream`,
16
+ * `accessLevel` `private`, `custom` `{}`). Overwriting a key preserves the
17
+ * original `createdAt` and only advances `updatedAt` (Requirements 4.1, 10.1).
18
+ *
19
+ * This module (task 4.1) implements the mandatory primitive object operations:
20
+ * `put` / `get` / `exists` / `delete` / `stat` / `list`. `get` returns a
21
+ * discriminated {@link MaybeObject} so absence is reported consistently rather
22
+ * than thrown (Requirements 4.2, 2.4). `list` returns {@link StorageListItem}s
23
+ * sorted by key and never surfaces the `.meta.json` sidecar files as objects
24
+ * (Requirement 4.9).
25
+ *
26
+ * Streaming (task 4.2) uses `fs.createReadStream` / `fs.createWriteStream` so
27
+ * large files are never fully buffered in memory (Requirement 5.3). `putStream`
28
+ * pipes the incoming stream through a sha-256 hash on the way to disk, tallying
29
+ * the byte length as it goes, then writes the sidecar with the same metadata
30
+ * semantics as `put` (preserving the original `createdAt` on overwrite).
31
+ * `getStream` returns a `fs.createReadStream` of the object and throws
32
+ * {@link NotFoundError} for a missing key (Requirement 5.5).
33
+ *
34
+ * _Requirements: 2.1, 2.2, 3.2, 4.1, 4.2, 4.3, 4.4, 4.9, 4.10, 5.1, 5.2, 5.3, 5.5, 10.1_
35
+ */
36
+ import { type Clock } from "streetjs";
37
+ import type { MaybeObject, NodeReadable, StorageDriver } from "../driver.js";
38
+ import type { ListOptions, StorageListItem, StorageObjectMetadata, WriteMetadata } from "../types.js";
39
+ /** Options for constructing a {@link LocalStorageDriver}. */
40
+ export interface LocalStorageDriverOptions {
41
+ /** Filesystem root under which object bytes and sidecars are stored. */
42
+ readonly root: string;
43
+ /** Injected clock for deterministic timestamps in tests. Default `systemClock`. */
44
+ readonly clock?: Clock;
45
+ }
46
+ /**
47
+ * Zero-dependency filesystem {@link StorageDriver}.
48
+ *
49
+ * Object bytes live at `root/<key>`; their metadata is persisted in a sidecar
50
+ * `root/<key>.meta.json`. Observable behavior matches
51
+ * {@link MemoryStorageDriver} so the two drivers are interchangeable.
52
+ */
53
+ export declare class LocalStorageDriver implements StorageDriver {
54
+ /** Stable driver name. */
55
+ readonly name = "local";
56
+ /** Filesystem root under which objects are stored. */
57
+ private readonly root;
58
+ /** Injected clock used for `createdAt` / `updatedAt` timestamps. */
59
+ private readonly clock;
60
+ constructor(options: LocalStorageDriverOptions);
61
+ /**
62
+ * Persist `bytes` under `key`, computing size, sha-256 checksum/etag, and
63
+ * timestamps. Parent directories are created as needed for nested keys. When
64
+ * overwriting an existing key, the original `createdAt` is preserved and only
65
+ * `updatedAt` advances (Requirements 4.1, 10.1).
66
+ */
67
+ put(key: string, bytes: Uint8Array, metadata: WriteMetadata): Promise<StorageObjectMetadata>;
68
+ /**
69
+ * Read the object at `key`. Returns a discriminated {@link MaybeObject} so
70
+ * absence is reported consistently rather than thrown (Requirements 4.2, 2.4).
71
+ */
72
+ get(key: string): Promise<MaybeObject>;
73
+ /** Report whether an object is stored under `key` (Requirement 4.3). */
74
+ exists(key: string): Promise<boolean>;
75
+ /**
76
+ * Remove the object at `key` and its metadata sidecar. Deleting a missing key
77
+ * is a no-op so that a subsequent `exists` returns false either way
78
+ * (Requirement 4.4).
79
+ */
80
+ delete(key: string): Promise<void>;
81
+ /**
82
+ * Return the metadata for `key` without its content, or `null` if absent
83
+ * (Requirement 4.10).
84
+ */
85
+ stat(key: string): Promise<StorageObjectMetadata | null>;
86
+ /**
87
+ * Return list items for every key beginning with `prefix`, sorted by key for
88
+ * deterministic ordering (Requirement 4.9). Metadata sidecar files
89
+ * (`.meta.json`) are never surfaced as objects. Honors optional `cursor`
90
+ * (exclusive resume point), `limit`, and `delimiter` (collapse to immediate
91
+ * children on `/`) when supplied, matching {@link MemoryStorageDriver}.
92
+ */
93
+ list(prefix: string, options?: ListOptions): Promise<StorageListItem[]>;
94
+ /**
95
+ * Persist a streamed upload to `root/<key>` using `fs.createWriteStream` so
96
+ * the object is never fully buffered in memory (Requirements 5.1, 5.3).
97
+ * Parent directories are created on demand. As bytes flow to disk they are
98
+ * piped through a sha-256 hash and the running byte count is tallied, giving
99
+ * the `checksum`/`etag`/`size` without a second pass. Once the stream is
100
+ * drained the metadata sidecar is written with the same semantics as
101
+ * {@link put}: an existing key's original `createdAt` is preserved and only
102
+ * `updatedAt` advances (Requirements 4.1, 10.1).
103
+ */
104
+ putStream(key: string, stream: NodeReadable, metadata: WriteMetadata): Promise<StorageObjectMetadata>;
105
+ /**
106
+ * Return a `fs.createReadStream` of the object at `key` so readers pull bytes
107
+ * incrementally without buffering the whole object (Requirements 5.2, 5.3).
108
+ * Throws {@link NotFoundError} when the key is missing (Requirement 5.5).
109
+ */
110
+ getStream(key: string): Promise<NodeReadable>;
111
+ /** Absolute filesystem path to the object bytes for `key`. */
112
+ private objectPath;
113
+ /** Absolute filesystem path to the metadata sidecar for `key`. */
114
+ private metaPath;
115
+ /** Read and parse the metadata sidecar for `key`, or `null` when absent. */
116
+ private readMeta;
117
+ /** Unlink a path, ignoring the case where it does not exist. */
118
+ private unlinkIfExists;
119
+ /**
120
+ * Walk the storage root and return every object key (the relative path from
121
+ * `root`, using `/` separators). Metadata sidecar files are excluded so they
122
+ * are never surfaced as objects.
123
+ */
124
+ private collectKeys;
125
+ }
126
+ //# sourceMappingURL=local.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/drivers/local.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAQH,OAAO,EAAe,KAAK,KAAK,EAAE,MAAM,UAAU,CAAC;AAEnD,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAG7E,OAAO,KAAK,EACV,WAAW,EACX,eAAe,EACf,qBAAqB,EACrB,aAAa,EACd,MAAM,aAAa,CAAC;AAErB,6DAA6D;AAC7D,MAAM,WAAW,yBAAyB;IACxC,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,mFAAmF;IACnF,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;CACxB;AAKD;;;;;;GAMG;AACH,qBAAa,kBAAmB,YAAW,aAAa;IACtD,0BAA0B;IAC1B,QAAQ,CAAC,IAAI,WAAW;IAExB,sDAAsD;IACtD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAE9B,oEAAoE;IACpE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;gBAElB,OAAO,EAAE,yBAAyB;IAO9C;;;;;OAKG;IACG,GAAG,CACP,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,qBAAqB,CAAC;IA2BjC;;;OAGG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAiB5C,wEAAwE;IAClE,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS3C;;;;OAIG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKxC;;;OAGG;IACG,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC;IAI9D;;;;;;OAMG;IACG,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAgD7E;;;;;;;;;OASG;IACG,SAAS,CACb,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,qBAAqB,CAAC;IA+CjC;;;;OAIG;IACG,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAenD,8DAA8D;IAC9D,OAAO,CAAC,UAAU;IAIlB,kEAAkE;IAClE,OAAO,CAAC,QAAQ;IAIhB,4EAA4E;YAC9D,QAAQ;IAatB,gEAAgE;YAClD,cAAc;IAU5B;;;;OAIG;YACW,WAAW;CAoB1B"}