@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,321 @@
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 { createHash } from "node:crypto";
37
+ import { createReadStream, createWriteStream, existsSync } from "node:fs";
38
+ import * as fs from "node:fs/promises";
39
+ import * as path from "node:path";
40
+ import { pipeline } from "node:stream/promises";
41
+ import { systemClock } from "streetjs";
42
+ import { NotFoundError } from "../errors.js";
43
+ import { buildObjectMetadata } from "../metadata.js";
44
+ /** Suffix identifying the metadata sidecar file for an object. */
45
+ const META_SUFFIX = ".meta.json";
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 class LocalStorageDriver {
54
+ /** Stable driver name. */
55
+ name = "local";
56
+ /** Filesystem root under which objects are stored. */
57
+ root;
58
+ /** Injected clock used for `createdAt` / `updatedAt` timestamps. */
59
+ clock;
60
+ constructor(options) {
61
+ this.root = path.resolve(options.root);
62
+ this.clock = options.clock ?? systemClock;
63
+ }
64
+ // ── Mandatory primitives ──────────────────────────────────────────────────
65
+ /**
66
+ * Persist `bytes` under `key`, computing size, sha-256 checksum/etag, and
67
+ * timestamps. Parent directories are created as needed for nested keys. When
68
+ * overwriting an existing key, the original `createdAt` is preserved and only
69
+ * `updatedAt` advances (Requirements 4.1, 10.1).
70
+ */
71
+ async put(key, bytes, metadata) {
72
+ // Copy defensively so later mutation of the caller's buffer cannot alter
73
+ // what we stored.
74
+ const stored = bytes.slice();
75
+ const checksum = sha256Hex(stored);
76
+ const now = this.clock();
77
+ const existing = await this.readMeta(key);
78
+ // Assemble the typed field set through the single source of truth so the
79
+ // shape and defaults stay identical across every driver (Requirement 10.1).
80
+ const objectMetadata = buildObjectMetadata({
81
+ key,
82
+ size: stored.byteLength,
83
+ checksum,
84
+ createdAt: existing?.createdAt ?? now,
85
+ updatedAt: now,
86
+ write: metadata,
87
+ });
88
+ const objectPath = this.objectPath(key);
89
+ await fs.mkdir(path.dirname(objectPath), { recursive: true });
90
+ await fs.writeFile(objectPath, stored);
91
+ await fs.writeFile(this.metaPath(key), JSON.stringify(objectMetadata), "utf8");
92
+ return objectMetadata;
93
+ }
94
+ /**
95
+ * Read the object at `key`. Returns a discriminated {@link MaybeObject} so
96
+ * absence is reported consistently rather than thrown (Requirements 4.2, 2.4).
97
+ */
98
+ async get(key) {
99
+ const metadata = await this.readMeta(key);
100
+ if (metadata === null) {
101
+ return { found: false };
102
+ }
103
+ let bytes;
104
+ try {
105
+ bytes = await fs.readFile(this.objectPath(key));
106
+ }
107
+ catch (error) {
108
+ if (isNotFound(error)) {
109
+ return { found: false };
110
+ }
111
+ throw error;
112
+ }
113
+ return { found: true, bytes: new Uint8Array(bytes), metadata };
114
+ }
115
+ /** Report whether an object is stored under `key` (Requirement 4.3). */
116
+ async exists(key) {
117
+ try {
118
+ await fs.access(this.objectPath(key));
119
+ return true;
120
+ }
121
+ catch {
122
+ return false;
123
+ }
124
+ }
125
+ /**
126
+ * Remove the object at `key` and its metadata sidecar. Deleting a missing key
127
+ * is a no-op so that a subsequent `exists` returns false either way
128
+ * (Requirement 4.4).
129
+ */
130
+ async delete(key) {
131
+ await this.unlinkIfExists(this.objectPath(key));
132
+ await this.unlinkIfExists(this.metaPath(key));
133
+ }
134
+ /**
135
+ * Return the metadata for `key` without its content, or `null` if absent
136
+ * (Requirement 4.10).
137
+ */
138
+ async stat(key) {
139
+ return this.readMeta(key);
140
+ }
141
+ /**
142
+ * Return list items for every key beginning with `prefix`, sorted by key for
143
+ * deterministic ordering (Requirement 4.9). Metadata sidecar files
144
+ * (`.meta.json`) are never surfaced as objects. Honors optional `cursor`
145
+ * (exclusive resume point), `limit`, and `delimiter` (collapse to immediate
146
+ * children on `/`) when supplied, matching {@link MemoryStorageDriver}.
147
+ */
148
+ async list(prefix, options) {
149
+ const cursor = options?.cursor;
150
+ const useDelimiter = options?.delimiter === true;
151
+ const allKeys = await this.collectKeys();
152
+ let matchedKeys = allKeys.filter((key) => key.startsWith(prefix)).sort();
153
+ if (cursor !== undefined) {
154
+ matchedKeys = matchedKeys.filter((key) => key > cursor);
155
+ }
156
+ const items = [];
157
+ const seenChildren = new Set();
158
+ for (const key of matchedKeys) {
159
+ if (useDelimiter) {
160
+ // Collapse to the immediate child segment under the prefix.
161
+ const rest = key.slice(prefix.length);
162
+ const slashIndex = rest.indexOf("/");
163
+ if (slashIndex !== -1) {
164
+ const child = prefix + rest.slice(0, slashIndex + 1);
165
+ if (seenChildren.has(child)) {
166
+ continue;
167
+ }
168
+ seenChildren.add(child);
169
+ }
170
+ }
171
+ const metadata = await this.readMeta(key);
172
+ if (metadata === null) {
173
+ continue;
174
+ }
175
+ items.push({
176
+ key,
177
+ size: metadata.size,
178
+ updatedAt: metadata.updatedAt,
179
+ });
180
+ if (options?.limit !== undefined && items.length >= options.limit) {
181
+ break;
182
+ }
183
+ }
184
+ return items;
185
+ }
186
+ // ── Streaming ───────────────────────────────────────────────────────────────
187
+ /**
188
+ * Persist a streamed upload to `root/<key>` using `fs.createWriteStream` so
189
+ * the object is never fully buffered in memory (Requirements 5.1, 5.3).
190
+ * Parent directories are created on demand. As bytes flow to disk they are
191
+ * piped through a sha-256 hash and the running byte count is tallied, giving
192
+ * the `checksum`/`etag`/`size` without a second pass. Once the stream is
193
+ * drained the metadata sidecar is written with the same semantics as
194
+ * {@link put}: an existing key's original `createdAt` is preserved and only
195
+ * `updatedAt` advances (Requirements 4.1, 10.1).
196
+ */
197
+ async putStream(key, stream, metadata) {
198
+ // Read any existing metadata up front so an overwrite preserves createdAt.
199
+ const existing = await this.readMeta(key);
200
+ const objectPath = this.objectPath(key);
201
+ await fs.mkdir(path.dirname(objectPath), { recursive: true });
202
+ const hash = createHash("sha256");
203
+ let size = 0;
204
+ // Pipe the source through a transform that hashes and counts each chunk on
205
+ // its way to the write stream. Nothing is retained in memory beyond the
206
+ // current chunk, so arbitrarily large uploads stream straight to disk.
207
+ await pipeline(stream, async function* hashAndCount(source) {
208
+ for await (const chunk of source) {
209
+ const buf = Buffer.isBuffer(chunk)
210
+ ? chunk
211
+ : Buffer.from(chunk);
212
+ hash.update(buf);
213
+ size += buf.byteLength;
214
+ yield buf;
215
+ }
216
+ }, createWriteStream(objectPath));
217
+ const checksum = hash.digest("hex");
218
+ const now = this.clock();
219
+ // Assemble the typed field set through the single source of truth so the
220
+ // shape and defaults stay identical across every driver (Requirement 10.1).
221
+ const objectMetadata = buildObjectMetadata({
222
+ key,
223
+ size,
224
+ checksum,
225
+ createdAt: existing?.createdAt ?? now,
226
+ updatedAt: now,
227
+ write: metadata,
228
+ });
229
+ await fs.writeFile(this.metaPath(key), JSON.stringify(objectMetadata), "utf8");
230
+ return objectMetadata;
231
+ }
232
+ /**
233
+ * Return a `fs.createReadStream` of the object at `key` so readers pull bytes
234
+ * incrementally without buffering the whole object (Requirements 5.2, 5.3).
235
+ * Throws {@link NotFoundError} when the key is missing (Requirement 5.5).
236
+ */
237
+ async getStream(key) {
238
+ const objectPath = this.objectPath(key);
239
+ try {
240
+ await fs.access(objectPath);
241
+ }
242
+ catch (error) {
243
+ if (isNotFound(error)) {
244
+ throw new NotFoundError(key);
245
+ }
246
+ throw error;
247
+ }
248
+ return createReadStream(objectPath);
249
+ }
250
+ // ── Internal helpers ────────────────────────────────────────────────────────
251
+ /** Absolute filesystem path to the object bytes for `key`. */
252
+ objectPath(key) {
253
+ return path.join(this.root, key);
254
+ }
255
+ /** Absolute filesystem path to the metadata sidecar for `key`. */
256
+ metaPath(key) {
257
+ return path.join(this.root, key + META_SUFFIX);
258
+ }
259
+ /** Read and parse the metadata sidecar for `key`, or `null` when absent. */
260
+ async readMeta(key) {
261
+ let raw;
262
+ try {
263
+ raw = await fs.readFile(this.metaPath(key), "utf8");
264
+ }
265
+ catch (error) {
266
+ if (isNotFound(error)) {
267
+ return null;
268
+ }
269
+ throw error;
270
+ }
271
+ return JSON.parse(raw);
272
+ }
273
+ /** Unlink a path, ignoring the case where it does not exist. */
274
+ async unlinkIfExists(target) {
275
+ try {
276
+ await fs.unlink(target);
277
+ }
278
+ catch (error) {
279
+ if (!isNotFound(error)) {
280
+ throw error;
281
+ }
282
+ }
283
+ }
284
+ /**
285
+ * Walk the storage root and return every object key (the relative path from
286
+ * `root`, using `/` separators). Metadata sidecar files are excluded so they
287
+ * are never surfaced as objects.
288
+ */
289
+ async collectKeys() {
290
+ if (!existsSync(this.root)) {
291
+ return [];
292
+ }
293
+ const keys = [];
294
+ const walk = async (dir) => {
295
+ const entries = await fs.readdir(dir, { withFileTypes: true });
296
+ for (const entry of entries) {
297
+ const full = path.join(dir, entry.name);
298
+ if (entry.isDirectory()) {
299
+ await walk(full);
300
+ }
301
+ else if (entry.isFile() && !entry.name.endsWith(META_SUFFIX)) {
302
+ const relative = path.relative(this.root, full).split(path.sep).join("/");
303
+ keys.push(relative);
304
+ }
305
+ }
306
+ };
307
+ await walk(this.root);
308
+ return keys;
309
+ }
310
+ }
311
+ /** Compute the lowercase sha-256 hex digest of `bytes`. */
312
+ function sha256Hex(bytes) {
313
+ return createHash("sha256").update(bytes).digest("hex");
314
+ }
315
+ /** True when `error` is a Node "file not found" (ENOENT) error. */
316
+ function isNotFound(error) {
317
+ return (typeof error === "object" &&
318
+ error !== null &&
319
+ error.code === "ENOENT");
320
+ }
321
+ //# sourceMappingURL=local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local.js","sourceRoot":"","sources":["../../src/drivers/local.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * @streetjs/storage — MemoryStorageDriver (zero-dependency).
3
+ *
4
+ * An in-memory implementation of the {@link StorageDriver} contract backed by a
5
+ * `Map<string, StoredEntry>` where every entry holds the object's `Uint8Array`
6
+ * bytes plus its computed {@link StorageObjectMetadata}. It requires no external
7
+ * runtime dependency (Requirement 3.2), making it ideal for tests and the
8
+ * example app while exercising the exact same facade code paths the cloud
9
+ * drivers use.
10
+ *
11
+ * This module (task 3.1) implements the mandatory primitive object operations:
12
+ * `put` / `get` / `exists` / `delete` / `stat` / `list`. Object identity fields
13
+ * (`etag`, `checksum`, `size`) and timestamps (`createdAt` / `updatedAt`) are
14
+ * computed at write time — the checksum/etag are the sha-256 hex digest of the
15
+ * stored bytes (via `node:crypto`), the size is the byte length, and timestamps
16
+ * come from an injected {@link Clock} (default `systemClock` from `streetjs`) so
17
+ * time is deterministic in tests.
18
+ *
19
+ * Streaming (`putStream` / `getStream`, task 3.2) is implemented over the
20
+ * in-memory buffer using Node stream primitives: `putStream` consumes the
21
+ * supplied `Readable` through a `pipeline` into a collecting `Writable`,
22
+ * assembling the bytes and persisting them with the same computed metadata as
23
+ * `put`; `getStream` returns a `Readable` that emits the stored bytes as a
24
+ * single chunk and throws {@link NotFoundError} for a missing key.
25
+ *
26
+ * _Requirements: 2.1, 3.2, 4.1, 4.2, 4.3, 4.4, 4.9, 4.10, 5.1, 5.2, 5.5, 10.1_
27
+ */
28
+ import { type Clock } from "streetjs";
29
+ import type { MaybeObject, NodeReadable, StorageDriver } from "../driver.js";
30
+ import type { ListOptions, StorageListItem, StorageObjectMetadata, WriteMetadata } from "../types.js";
31
+ /** Options for constructing a {@link MemoryStorageDriver}. */
32
+ export interface MemoryStorageDriverOptions {
33
+ /** Injected clock for deterministic timestamps in tests. Default `systemClock`. */
34
+ readonly clock?: Clock;
35
+ }
36
+ /**
37
+ * Zero-dependency in-memory {@link StorageDriver}.
38
+ *
39
+ * Backed by a `Map<string, StoredEntry>`. All bytes are copied on the way in and
40
+ * on the way out so external mutation of a caller's buffer never corrupts stored
41
+ * content and vice versa.
42
+ */
43
+ export declare class MemoryStorageDriver implements StorageDriver {
44
+ /** Stable driver name. */
45
+ readonly name = "memory";
46
+ /** Backing store: key → stored bytes + metadata. */
47
+ private readonly store;
48
+ /** Injected clock used for `createdAt` / `updatedAt` timestamps. */
49
+ private readonly clock;
50
+ constructor(options?: MemoryStorageDriverOptions);
51
+ /**
52
+ * Persist `bytes` under `key`, computing size, sha-256 checksum/etag, and
53
+ * timestamps. When overwriting an existing key, the original `createdAt` is
54
+ * preserved and only `updatedAt` advances (Requirements 4.1, 10.1).
55
+ */
56
+ put(key: string, bytes: Uint8Array, metadata: WriteMetadata): Promise<StorageObjectMetadata>;
57
+ /**
58
+ * Read the object at `key`. Returns a discriminated {@link MaybeObject} so
59
+ * absence is reported consistently rather than thrown (Requirements 4.2, 2.4).
60
+ * The returned bytes are a copy of the stored content.
61
+ */
62
+ get(key: string): Promise<MaybeObject>;
63
+ /** Report whether an object is stored under `key` (Requirement 4.3). */
64
+ exists(key: string): Promise<boolean>;
65
+ /**
66
+ * Remove the object at `key`. Deleting a missing key is a no-op so that a
67
+ * subsequent `exists` returns false either way (Requirement 4.4).
68
+ */
69
+ delete(key: string): Promise<void>;
70
+ /**
71
+ * Return the metadata for `key` without its content, or `null` if absent
72
+ * (Requirement 4.10).
73
+ */
74
+ stat(key: string): Promise<StorageObjectMetadata | null>;
75
+ /**
76
+ * Return list items for every key beginning with `prefix`, sorted by key for
77
+ * deterministic ordering (Requirement 4.9). Honors optional `cursor`
78
+ * (exclusive resume point), `limit`, and `delimiter` (collapse to immediate
79
+ * children on `/`) when supplied.
80
+ */
81
+ list(prefix: string, options?: ListOptions): Promise<StorageListItem[]>;
82
+ /**
83
+ * Consume a Node {@link Readable} and persist the assembled bytes under `key`
84
+ * with the same computed metadata as {@link put} (Requirement 5.1).
85
+ *
86
+ * The stream is drained through a `pipeline` into a collecting `Writable`,
87
+ * which gives correct backpressure and propagates read/abort errors (a failed
88
+ * source stream rejects the returned promise and stores nothing). Each chunk
89
+ * is normalized to a `Buffer`; the concatenation is handed to {@link put} so
90
+ * checksum/etag/size/timestamps are computed identically to a buffered write.
91
+ */
92
+ putStream(key: string, stream: NodeReadable, metadata: WriteMetadata): Promise<StorageObjectMetadata>;
93
+ /**
94
+ * Return a Node {@link Readable} of the stored bytes at `key` (Requirement
95
+ * 5.2). Throws {@link NotFoundError} for a missing key (Requirement 5.5).
96
+ *
97
+ * The stored bytes are copied and wrapped in a single-element array so
98
+ * `Readable.from` emits them as one intact chunk (passing a `Buffer` directly
99
+ * would iterate it byte-by-byte). The copy ensures a consumer draining the
100
+ * stream can never observe or mutate the backing store.
101
+ */
102
+ getStream(key: string): Promise<NodeReadable>;
103
+ }
104
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/drivers/memory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAMH,OAAO,EAAe,KAAK,KAAK,EAAE,MAAM,UAAU,CAAC;AAEnD,OAAO,KAAK,EACV,WAAW,EACX,YAAY,EACZ,aAAa,EACd,MAAM,cAAc,CAAC;AAGtB,OAAO,KAAK,EACV,WAAW,EACX,eAAe,EACf,qBAAqB,EACrB,aAAa,EACd,MAAM,aAAa,CAAC;AAQrB,8DAA8D;AAC9D,MAAM,WAAW,0BAA0B;IACzC,mFAAmF;IACnF,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;CACxB;AAED;;;;;;GAMG;AACH,qBAAa,mBAAoB,YAAW,aAAa;IACvD,0BAA0B;IAC1B,QAAQ,CAAC,IAAI,YAAY;IAEzB,oDAAoD;IACpD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkC;IAExD,oEAAoE;IACpE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;gBAElB,OAAO,GAAE,0BAA+B;IAMpD;;;;OAIG;IACG,GAAG,CACP,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,qBAAqB,CAAC;IAuBjC;;;;OAIG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAQ5C,wEAAwE;IAClE,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI3C;;;OAGG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxC;;;OAGG;IACG,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC;IAI9D;;;;;OAKG;IACG,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAiD7E;;;;;;;;;OASG;IACG,SAAS,CACb,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,qBAAqB,CAAC;IAkBjC;;;;;;;;OAQG;IACG,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;CAOpD"}
@@ -0,0 +1,197 @@
1
+ /**
2
+ * @streetjs/storage — MemoryStorageDriver (zero-dependency).
3
+ *
4
+ * An in-memory implementation of the {@link StorageDriver} contract backed by a
5
+ * `Map<string, StoredEntry>` where every entry holds the object's `Uint8Array`
6
+ * bytes plus its computed {@link StorageObjectMetadata}. It requires no external
7
+ * runtime dependency (Requirement 3.2), making it ideal for tests and the
8
+ * example app while exercising the exact same facade code paths the cloud
9
+ * drivers use.
10
+ *
11
+ * This module (task 3.1) implements the mandatory primitive object operations:
12
+ * `put` / `get` / `exists` / `delete` / `stat` / `list`. Object identity fields
13
+ * (`etag`, `checksum`, `size`) and timestamps (`createdAt` / `updatedAt`) are
14
+ * computed at write time — the checksum/etag are the sha-256 hex digest of the
15
+ * stored bytes (via `node:crypto`), the size is the byte length, and timestamps
16
+ * come from an injected {@link Clock} (default `systemClock` from `streetjs`) so
17
+ * time is deterministic in tests.
18
+ *
19
+ * Streaming (`putStream` / `getStream`, task 3.2) is implemented over the
20
+ * in-memory buffer using Node stream primitives: `putStream` consumes the
21
+ * supplied `Readable` through a `pipeline` into a collecting `Writable`,
22
+ * assembling the bytes and persisting them with the same computed metadata as
23
+ * `put`; `getStream` returns a `Readable` that emits the stored bytes as a
24
+ * single chunk and throws {@link NotFoundError} for a missing key.
25
+ *
26
+ * _Requirements: 2.1, 3.2, 4.1, 4.2, 4.3, 4.4, 4.9, 4.10, 5.1, 5.2, 5.5, 10.1_
27
+ */
28
+ import { createHash } from "node:crypto";
29
+ import { Readable, Writable } from "node:stream";
30
+ import { pipeline } from "node:stream/promises";
31
+ import { systemClock } from "streetjs";
32
+ import { NotFoundError } from "../errors.js";
33
+ import { buildObjectMetadata } from "../metadata.js";
34
+ /**
35
+ * Zero-dependency in-memory {@link StorageDriver}.
36
+ *
37
+ * Backed by a `Map<string, StoredEntry>`. All bytes are copied on the way in and
38
+ * on the way out so external mutation of a caller's buffer never corrupts stored
39
+ * content and vice versa.
40
+ */
41
+ export class MemoryStorageDriver {
42
+ /** Stable driver name. */
43
+ name = "memory";
44
+ /** Backing store: key → stored bytes + metadata. */
45
+ store = new Map();
46
+ /** Injected clock used for `createdAt` / `updatedAt` timestamps. */
47
+ clock;
48
+ constructor(options = {}) {
49
+ this.clock = options.clock ?? systemClock;
50
+ }
51
+ // ── Mandatory primitives ──────────────────────────────────────────────────
52
+ /**
53
+ * Persist `bytes` under `key`, computing size, sha-256 checksum/etag, and
54
+ * timestamps. When overwriting an existing key, the original `createdAt` is
55
+ * preserved and only `updatedAt` advances (Requirements 4.1, 10.1).
56
+ */
57
+ async put(key, bytes, metadata) {
58
+ // Copy defensively so later mutation of the caller's buffer cannot alter
59
+ // what we stored.
60
+ const stored = bytes.slice();
61
+ const checksum = sha256Hex(stored);
62
+ const now = this.clock();
63
+ const existing = this.store.get(key);
64
+ // Assemble the typed field set through the single source of truth so the
65
+ // shape and defaults stay identical across every driver (Requirement 10.1).
66
+ const objectMetadata = buildObjectMetadata({
67
+ key,
68
+ size: stored.byteLength,
69
+ checksum,
70
+ createdAt: existing?.metadata.createdAt ?? now,
71
+ updatedAt: now,
72
+ write: metadata,
73
+ });
74
+ this.store.set(key, { bytes: stored, metadata: objectMetadata });
75
+ return objectMetadata;
76
+ }
77
+ /**
78
+ * Read the object at `key`. Returns a discriminated {@link MaybeObject} so
79
+ * absence is reported consistently rather than thrown (Requirements 4.2, 2.4).
80
+ * The returned bytes are a copy of the stored content.
81
+ */
82
+ async get(key) {
83
+ const entry = this.store.get(key);
84
+ if (entry === undefined) {
85
+ return { found: false };
86
+ }
87
+ return { found: true, bytes: entry.bytes.slice(), metadata: entry.metadata };
88
+ }
89
+ /** Report whether an object is stored under `key` (Requirement 4.3). */
90
+ async exists(key) {
91
+ return this.store.has(key);
92
+ }
93
+ /**
94
+ * Remove the object at `key`. Deleting a missing key is a no-op so that a
95
+ * subsequent `exists` returns false either way (Requirement 4.4).
96
+ */
97
+ async delete(key) {
98
+ this.store.delete(key);
99
+ }
100
+ /**
101
+ * Return the metadata for `key` without its content, or `null` if absent
102
+ * (Requirement 4.10).
103
+ */
104
+ async stat(key) {
105
+ return this.store.get(key)?.metadata ?? null;
106
+ }
107
+ /**
108
+ * Return list items for every key beginning with `prefix`, sorted by key for
109
+ * deterministic ordering (Requirement 4.9). Honors optional `cursor`
110
+ * (exclusive resume point), `limit`, and `delimiter` (collapse to immediate
111
+ * children on `/`) when supplied.
112
+ */
113
+ async list(prefix, options) {
114
+ const cursor = options?.cursor;
115
+ const useDelimiter = options?.delimiter === true;
116
+ let matchedKeys = [...this.store.keys()]
117
+ .filter((key) => key.startsWith(prefix))
118
+ .sort();
119
+ if (cursor !== undefined) {
120
+ matchedKeys = matchedKeys.filter((key) => key > cursor);
121
+ }
122
+ const items = [];
123
+ const seenChildren = new Set();
124
+ for (const key of matchedKeys) {
125
+ if (useDelimiter) {
126
+ // Collapse to the immediate child segment under the prefix.
127
+ const rest = key.slice(prefix.length);
128
+ const slashIndex = rest.indexOf("/");
129
+ if (slashIndex !== -1) {
130
+ const child = prefix + rest.slice(0, slashIndex + 1);
131
+ if (seenChildren.has(child)) {
132
+ continue;
133
+ }
134
+ seenChildren.add(child);
135
+ }
136
+ }
137
+ const entry = this.store.get(key);
138
+ if (entry === undefined) {
139
+ continue;
140
+ }
141
+ items.push({
142
+ key,
143
+ size: entry.metadata.size,
144
+ updatedAt: entry.metadata.updatedAt,
145
+ });
146
+ if (options?.limit !== undefined && items.length >= options.limit) {
147
+ break;
148
+ }
149
+ }
150
+ return items;
151
+ }
152
+ // ── Streaming ───────────────────────────────────────────────────────────────
153
+ /**
154
+ * Consume a Node {@link Readable} and persist the assembled bytes under `key`
155
+ * with the same computed metadata as {@link put} (Requirement 5.1).
156
+ *
157
+ * The stream is drained through a `pipeline` into a collecting `Writable`,
158
+ * which gives correct backpressure and propagates read/abort errors (a failed
159
+ * source stream rejects the returned promise and stores nothing). Each chunk
160
+ * is normalized to a `Buffer`; the concatenation is handed to {@link put} so
161
+ * checksum/etag/size/timestamps are computed identically to a buffered write.
162
+ */
163
+ async putStream(key, stream, metadata) {
164
+ const chunks = [];
165
+ const collector = new Writable({
166
+ write(chunk, _encoding, callback) {
167
+ chunks.push(Buffer.isBuffer(chunk)
168
+ ? chunk
169
+ : Buffer.from(chunk));
170
+ callback();
171
+ },
172
+ });
173
+ await pipeline(stream, collector);
174
+ return this.put(key, new Uint8Array(Buffer.concat(chunks)), metadata);
175
+ }
176
+ /**
177
+ * Return a Node {@link Readable} of the stored bytes at `key` (Requirement
178
+ * 5.2). Throws {@link NotFoundError} for a missing key (Requirement 5.5).
179
+ *
180
+ * The stored bytes are copied and wrapped in a single-element array so
181
+ * `Readable.from` emits them as one intact chunk (passing a `Buffer` directly
182
+ * would iterate it byte-by-byte). The copy ensures a consumer draining the
183
+ * stream can never observe or mutate the backing store.
184
+ */
185
+ async getStream(key) {
186
+ const entry = this.store.get(key);
187
+ if (entry === undefined) {
188
+ throw new NotFoundError(key);
189
+ }
190
+ return Readable.from([Buffer.from(entry.bytes)]);
191
+ }
192
+ }
193
+ /** Compute the lowercase sha-256 hex digest of `bytes`. */
194
+ function sha256Hex(bytes) {
195
+ return createHash("sha256").update(bytes).digest("hex");
196
+ }
197
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/drivers/memory.ts"],"names":[],"mappings":"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"}