@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,240 @@
1
+ /**
2
+ * @streetjs/storage — the lifecycle engine.
3
+ *
4
+ * Lifecycle rules act on objects automatically based on their age or state, so
5
+ * stored objects are cleaned up, archived, or tiered over time (Requirement
6
+ * 13). {@link LifecycleEngine} evaluates a single {@link LifecycleRule} and
7
+ * applies its action to every qualifying object in a **provider-agnostic** way:
8
+ *
9
+ * - When the backing {@link StorageDriver} implements the optional native
10
+ * `lifecycle` capability, the engine delegates evaluation to the driver so a
11
+ * provider with first-class lifecycle policies (e.g. S3 lifecycle
12
+ * configuration) is used directly.
13
+ * - Otherwise the engine **simulates** the rule over the mandatory driver
14
+ * primitives (`list`/`stat`/`get`/`put`/`delete`). It enumerates candidate
15
+ * keys with `list`, reads each object's `createdAt` with `stat`, computes the
16
+ * object's age relative to the injected {@link Clock}, and applies the rule's
17
+ * action to the objects whose age meets the rule's threshold. This is what
18
+ * lets the zero-dependency drivers simulate lifecycle entirely in memory /
19
+ * over the local filesystem (Requirement 13.3).
20
+ *
21
+ * Supported rule types (Requirement 13.1):
22
+ * - `delete-after-days` — delete objects older than `days`.
23
+ * - `archive-after-months` — archive objects older than `months` by relocating
24
+ * them under the reserved {@link ARCHIVE_KEY_PREFIX}.
25
+ * - `expire-temp-uploads` — delete transient multipart-part / resumable-session
26
+ * state older than `afterMs` (the reserved temp-upload key spaces).
27
+ * - `move-to-cold` — relocate objects older than `afterDays` under `coldPrefix`.
28
+ *
29
+ * **Exactly-once (Requirement 13.2).** Each action removes the qualifying object
30
+ * from the space that a subsequent evaluation scans: `delete`/`expire` remove
31
+ * the object outright, and `archive`/`move-to-cold` relocate it to a prefix that
32
+ * the scan excludes (the reserved archive prefix, or `coldPrefix`). Because the
33
+ * relocated copy is written with a fresh `createdAt` at the evaluation instant,
34
+ * it is also too young to re-qualify at the same `now`. The net effect is that a
35
+ * second evaluation produces no further action on an already-actioned object.
36
+ *
37
+ * The module depends only on the driver contract, the shared type surface, the
38
+ * metadata layer, and the core `Clock`, keeping the dependency direction
39
+ * acyclic. Event publication for applied actions (Requirement 13.4) is wired
40
+ * separately by the Events bridge (task 21.1); this engine only performs the
41
+ * actions and returns their {@link LifecycleOutcome} descriptors.
42
+ *
43
+ * _Requirements: 13.1, 13.2, 13.3_
44
+ */
45
+ import { systemClock } from "streetjs";
46
+ import { toWriteMetadata } from "./metadata.js";
47
+ /** Milliseconds in a single day, used to convert day-based thresholds. */
48
+ const MS_PER_DAY = 24 * 60 * 60 * 1000;
49
+ /**
50
+ * The number of days used to approximate one month when converting a
51
+ * month-based threshold to milliseconds. Lifecycle thresholds are coarse
52
+ * age policies rather than calendar arithmetic, so a fixed 30-day month keeps
53
+ * the simulation deterministic and provider-agnostic.
54
+ */
55
+ const DAYS_PER_MONTH = 30;
56
+ /**
57
+ * Reserved key prefix under which objects archived by an `archive-after-months`
58
+ * rule are relocated. An archived `<key>` lives at `${ARCHIVE_KEY_PREFIX}<key>`.
59
+ * The prefix is excluded from every lifecycle scan so an archived object is
60
+ * never re-actioned (Requirement 13.2).
61
+ */
62
+ export const ARCHIVE_KEY_PREFIX = ".archive/";
63
+ /**
64
+ * Reserved key prefixes that hold transient upload state (multipart parts and
65
+ * resumable session bytes), mirroring the `.multipart/<uploadId>/…` and
66
+ * `.resumable/<sessionId>` layouts used by the session managers. These are the
67
+ * key spaces an `expire-temp-uploads` rule scans and expires.
68
+ */
69
+ const TEMP_UPLOAD_PREFIXES = [".multipart/", ".resumable/"];
70
+ /**
71
+ * Reserved key prefixes that are internal bookkeeping rather than
72
+ * application-visible objects. Age-based rules (`delete-after-days`,
73
+ * `archive-after-months`, `move-to-cold`) never touch keys under these prefixes
74
+ * so lifecycle policies act only on real objects, not on version snapshots,
75
+ * multipart parts, resumable session bytes, or already-archived copies.
76
+ */
77
+ const RESERVED_KEY_PREFIXES = [
78
+ ".versions/",
79
+ ".multipart/",
80
+ ".resumable/",
81
+ ARCHIVE_KEY_PREFIX,
82
+ ];
83
+ /**
84
+ * Provider-agnostic lifecycle engine built on the driver contract.
85
+ *
86
+ * A single instance is held by the facade and bound to one {@link StorageDriver}
87
+ * for its lifetime, so the native-vs-simulated decision (based on whether the
88
+ * driver exposes a `lifecycle` capability) is stable across every call.
89
+ */
90
+ export class LifecycleEngine {
91
+ /** The driver every action is delegated to or simulated over. */
92
+ driver;
93
+ /** Injected clock used to compute object age at evaluation time. */
94
+ clock;
95
+ constructor(options) {
96
+ this.driver = options.driver;
97
+ this.clock = options.clock ?? systemClock;
98
+ }
99
+ /** The driver's native lifecycle capability, when present. */
100
+ get native() {
101
+ return this.driver.lifecycle;
102
+ }
103
+ /**
104
+ * Evaluate `rule` against the current object set and apply its action to every
105
+ * qualifying object, returning one {@link LifecycleOutcome} per actioned
106
+ * object (Requirements 13.1, 13.2). Object age is measured relative to `now`,
107
+ * which defaults to the injected clock. When the driver exposes a native
108
+ * `lifecycle` capability the evaluation is delegated to it; otherwise the rule
109
+ * is simulated over the driver primitives.
110
+ */
111
+ async apply(rule, now = this.clock()) {
112
+ if (this.native !== undefined) {
113
+ return this.native.apply(rule, now);
114
+ }
115
+ switch (rule.type) {
116
+ case "delete-after-days":
117
+ return this.applyDelete(rule.prefix ?? "", rule.days * MS_PER_DAY, now);
118
+ case "archive-after-months":
119
+ return this.applyArchive(rule.prefix ?? "", rule.months * DAYS_PER_MONTH * MS_PER_DAY, now);
120
+ case "expire-temp-uploads":
121
+ return this.applyExpire(rule.afterMs, now);
122
+ case "move-to-cold":
123
+ return this.applyMoveToCold(rule.prefix ?? "", rule.coldPrefix, rule.afterDays * MS_PER_DAY, now);
124
+ }
125
+ }
126
+ /**
127
+ * Delete every managed object under `prefix` whose age is at least
128
+ * `thresholdMs`. The deletion removes the object from the scanned space, so a
129
+ * repeated evaluation finds nothing further to delete (Requirement 13.2).
130
+ */
131
+ async applyDelete(prefix, thresholdMs, now) {
132
+ const keys = await this.collectQualifying(prefix, thresholdMs, now, (key) => this.isManagedKey(key));
133
+ const outcomes = [];
134
+ for (const key of keys) {
135
+ await this.driver.delete(key);
136
+ outcomes.push({ key, action: "deleted" });
137
+ }
138
+ return outcomes;
139
+ }
140
+ /**
141
+ * Archive every managed object under `prefix` whose age is at least
142
+ * `thresholdMs` by relocating it under {@link ARCHIVE_KEY_PREFIX}. The archive
143
+ * prefix is excluded from the scan, so an archived object is never re-archived
144
+ * (Requirement 13.2).
145
+ */
146
+ async applyArchive(prefix, thresholdMs, now) {
147
+ const keys = await this.collectQualifying(prefix, thresholdMs, now, (key) => this.isManagedKey(key));
148
+ const outcomes = [];
149
+ for (const key of keys) {
150
+ const moved = await this.relocate(key, `${ARCHIVE_KEY_PREFIX}${key}`);
151
+ if (moved) {
152
+ outcomes.push({ key, action: "archived" });
153
+ }
154
+ }
155
+ return outcomes;
156
+ }
157
+ /**
158
+ * Expire (delete) transient upload state older than `afterMs` across the
159
+ * reserved temp-upload key spaces (multipart parts and resumable session
160
+ * bytes). Because expiration deletes the state, a repeated evaluation finds
161
+ * nothing further to expire (Requirement 13.2).
162
+ */
163
+ async applyExpire(afterMs, now) {
164
+ const outcomes = [];
165
+ for (const prefix of TEMP_UPLOAD_PREFIXES) {
166
+ // Every key under a temp-upload prefix is transient state, so no further
167
+ // managed-key filtering is applied here.
168
+ const keys = await this.collectQualifying(prefix, afterMs, now, () => true);
169
+ for (const key of keys) {
170
+ await this.driver.delete(key);
171
+ outcomes.push({ key, action: "expired" });
172
+ }
173
+ }
174
+ return outcomes;
175
+ }
176
+ /**
177
+ * Relocate every managed object under `prefix` whose age is at least
178
+ * `thresholdMs` to `${coldPrefix}<key>`. Keys already residing under
179
+ * `coldPrefix` are excluded from the scan, so a repeated evaluation does not
180
+ * move an already-tiered object again (Requirement 13.2).
181
+ */
182
+ async applyMoveToCold(prefix, coldPrefix, thresholdMs, now) {
183
+ const keys = await this.collectQualifying(prefix, thresholdMs, now, (key) => this.isManagedKey(key) && !key.startsWith(coldPrefix));
184
+ const outcomes = [];
185
+ for (const key of keys) {
186
+ const moved = await this.relocate(key, `${coldPrefix}${key}`);
187
+ if (moved) {
188
+ outcomes.push({ key, action: "moved" });
189
+ }
190
+ }
191
+ return outcomes;
192
+ }
193
+ /**
194
+ * List candidate keys under `prefix`, keep those accepted by `accept`, and
195
+ * return the subset whose age (`now - createdAt`, read via `stat`) is at least
196
+ * `thresholdMs`. Keys that vanish between `list` and `stat` are skipped.
197
+ */
198
+ async collectQualifying(prefix, thresholdMs, now, accept) {
199
+ const items = await this.driver.list(prefix);
200
+ const qualifying = [];
201
+ for (const item of items) {
202
+ if (!accept(item.key)) {
203
+ continue;
204
+ }
205
+ const metadata = await this.driver.stat(item.key);
206
+ if (metadata === null) {
207
+ continue;
208
+ }
209
+ if (now - metadata.createdAt >= thresholdMs) {
210
+ qualifying.push(item.key);
211
+ }
212
+ }
213
+ return qualifying;
214
+ }
215
+ /**
216
+ * Move the object at `sourceKey` to `destinationKey` over the driver
217
+ * primitives: the content and preserved write-time metadata are written to the
218
+ * destination and the source is then removed. Returns `false` without writing
219
+ * when the source has vanished.
220
+ */
221
+ async relocate(sourceKey, destinationKey) {
222
+ const result = await this.driver.get(sourceKey);
223
+ if (!result.found) {
224
+ return false;
225
+ }
226
+ await this.driver.put(destinationKey, result.bytes, toWriteMetadata(result.metadata));
227
+ await this.driver.delete(sourceKey);
228
+ return true;
229
+ }
230
+ /**
231
+ * Report whether `key` is an application-visible object (as opposed to
232
+ * internal bookkeeping such as version snapshots, multipart parts, resumable
233
+ * session bytes, or already-archived copies). Age-based rules act only on
234
+ * managed keys.
235
+ */
236
+ isManagedKey(key) {
237
+ return !RESERVED_KEY_PREFIXES.some((reserved) => key.startsWith(reserved));
238
+ }
239
+ }
240
+ //# sourceMappingURL=lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * @streetjs/storage — the typed metadata layer (single source of truth).
3
+ *
4
+ * Every stored object carries a typed {@link StorageObjectMetadata} field set:
5
+ * `key`, `size`, `contentType`, `etag`, `checksum`, `owner`, `tenant`,
6
+ * `accessLevel`, `createdAt`, `updatedAt`, `custom` (and an optional
7
+ * `versionId`). Requirement 10 states this field set must be **complete**,
8
+ * **consistent across providers**, and must **round-trip** through write and
9
+ * read unchanged. Historically each driver assembled that object literal on its
10
+ * own and duplicated the field defaults (`contentType` →
11
+ * `application/octet-stream`, `accessLevel` → `private`, `custom` → `{}`), which
12
+ * risked the shape drifting between drivers over time.
13
+ *
14
+ * This module centralizes that shape in one place so it is preserved
15
+ * identically no matter which {@link StorageDriver} backs the facade:
16
+ *
17
+ * - {@link buildObjectMetadata} is the single constructor for the metadata
18
+ * field set. Drivers compute the provider-specific identity fields
19
+ * (`etag`/`checksum`/`size`) and timestamps (`createdAt`/`updatedAt`) and hand
20
+ * them here together with the caller's {@link WriteMetadata}; this function
21
+ * applies the canonical defaults and produces the complete, typed object. It
22
+ * never recomputes the identity fields, so driver-computed values are the
23
+ * source of truth for content hashing (Requirement 10.1, 10.2).
24
+ * - {@link normalizeMetadata} guarantees the full field set is present on any
25
+ * metadata surfaced by the facade (`put`/`stat`/`get`), filling the canonical
26
+ * defaults for any field a driver (e.g. a future cloud driver) left
27
+ * unpopulated while leaving identity/timestamp fields untouched. It is
28
+ * idempotent for metadata already produced by {@link buildObjectMetadata}
29
+ * (Requirement 10.1, 10.3).
30
+ * - {@link toWriteMetadata} projects a stored object's metadata back onto the
31
+ * write-time subset, used when copying/moving so the destination preserves the
32
+ * source's content type, ownership, tenancy, access level, and custom fields.
33
+ *
34
+ * The module depends only on the shared type surface (`types.ts`), keeping the
35
+ * dependency direction acyclic (leaf module → types).
36
+ *
37
+ * _Requirements: 10.1, 10.2, 10.3_
38
+ */
39
+ import type { AccessLevel, StorageObjectMetadata, WriteMetadata } from "./types.js";
40
+ /** Default content type applied when a write does not specify one. */
41
+ export declare const DEFAULT_CONTENT_TYPE: "application/octet-stream";
42
+ /** Default access level applied when a write does not specify one. */
43
+ export declare const DEFAULT_ACCESS_LEVEL: AccessLevel;
44
+ /**
45
+ * The canonical, ordered set of typed metadata field names every object carries
46
+ * (Requirement 10.1). `versionId` is intentionally excluded — it is an optional
47
+ * field present only on versioned objects, not part of the guaranteed base set.
48
+ */
49
+ export declare const STORAGE_METADATA_FIELDS: readonly ["key", "size", "contentType", "etag", "checksum", "owner", "tenant", "accessLevel", "createdAt", "updatedAt", "custom"];
50
+ /**
51
+ * The inputs a driver supplies to build an object's metadata. The driver is
52
+ * responsible for the provider-specific identity fields and timestamps; this
53
+ * layer owns the field-set shape and the caller-facing defaults.
54
+ */
55
+ export interface BuildMetadataInput {
56
+ /** The object key. */
57
+ readonly key: string;
58
+ /** Byte length of the stored content, computed by the driver. */
59
+ readonly size: number;
60
+ /** Content hash (e.g. sha-256 hex), computed by the driver. */
61
+ readonly checksum: string;
62
+ /** Entity tag; defaults to {@link checksum} when the driver omits it. */
63
+ readonly etag?: string;
64
+ /** Creation timestamp (epoch ms) from the injected clock. */
65
+ readonly createdAt: number;
66
+ /** Last-updated timestamp (epoch ms) from the injected clock. */
67
+ readonly updatedAt: number;
68
+ /** The caller-supplied write-time metadata. */
69
+ readonly write: WriteMetadata;
70
+ /** Optional version identifier for versioned objects. */
71
+ readonly versionId?: string;
72
+ }
73
+ /**
74
+ * Build the complete, typed {@link StorageObjectMetadata} field set from the
75
+ * driver-computed identity/timestamp values and the caller's
76
+ * {@link WriteMetadata}. This is the single place the metadata shape and its
77
+ * defaults are defined, so every driver produces an identical field set
78
+ * (Requirement 10.1, 10.2, 10.3).
79
+ *
80
+ * The identity fields (`etag`/`checksum`/`size`) and timestamps are used exactly
81
+ * as provided — this function never recomputes them — so the driver's computed
82
+ * values remain the source of truth and cannot diverge from what was persisted.
83
+ */
84
+ export declare function buildObjectMetadata(input: BuildMetadataInput): StorageObjectMetadata;
85
+ /**
86
+ * Return a copy of `metadata` with the complete typed field set guaranteed
87
+ * present, applying the canonical defaults for any missing `contentType`,
88
+ * `accessLevel`, or `custom` field while preserving the driver-computed
89
+ * identity fields (`etag`/`checksum`/`size`) and timestamps untouched
90
+ * (Requirement 10.1, 10.3).
91
+ *
92
+ * The facade runs the metadata it surfaces on `put`/`stat`/`get` through this
93
+ * function so the full field set is consistently present regardless of which
94
+ * driver produced it. It is idempotent for metadata already built by
95
+ * {@link buildObjectMetadata}, so wiring it in adds no behavioral change for the
96
+ * zero-dependency drivers while shielding the public surface from a future
97
+ * driver that returns a partially populated record.
98
+ */
99
+ export declare function normalizeMetadata(metadata: StorageObjectMetadata): StorageObjectMetadata;
100
+ /**
101
+ * Project a stored object's {@link StorageObjectMetadata} onto the write-time
102
+ * {@link WriteMetadata} subset. Used when copying/moving an object so the
103
+ * destination preserves the source's content type, ownership, tenancy, access
104
+ * level, and custom fields. The identity/timestamp fields (`etag`/`checksum`/
105
+ * `size`/`createdAt`/`updatedAt`) are intentionally omitted — the driver
106
+ * recomputes them for the destination object.
107
+ */
108
+ export declare function toWriteMetadata(metadata: StorageObjectMetadata): WriteMetadata;
109
+ //# sourceMappingURL=metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAIpF,sEAAsE;AACtE,eAAO,MAAM,oBAAoB,EAAG,0BAAmC,CAAC;AAExE,sEAAsE;AACtE,eAAO,MAAM,oBAAoB,EAAE,WAAuB,CAAC;AAE3D;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,mIAY1B,CAAC;AAIX;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,sBAAsB;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,iEAAiE;IACjE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+DAA+D;IAC/D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,yEAAyE;IACzE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,6DAA6D;IAC7D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,iEAAiE;IACjE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,+CAA+C;IAC/C,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,yDAAyD;IACzD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,GAAG,qBAAqB,CAiBpF;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,qBAAqB,CAgBxF;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,qBAAqB,GAAG,aAAa,CAQ9E"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * @streetjs/storage — the typed metadata layer (single source of truth).
3
+ *
4
+ * Every stored object carries a typed {@link StorageObjectMetadata} field set:
5
+ * `key`, `size`, `contentType`, `etag`, `checksum`, `owner`, `tenant`,
6
+ * `accessLevel`, `createdAt`, `updatedAt`, `custom` (and an optional
7
+ * `versionId`). Requirement 10 states this field set must be **complete**,
8
+ * **consistent across providers**, and must **round-trip** through write and
9
+ * read unchanged. Historically each driver assembled that object literal on its
10
+ * own and duplicated the field defaults (`contentType` →
11
+ * `application/octet-stream`, `accessLevel` → `private`, `custom` → `{}`), which
12
+ * risked the shape drifting between drivers over time.
13
+ *
14
+ * This module centralizes that shape in one place so it is preserved
15
+ * identically no matter which {@link StorageDriver} backs the facade:
16
+ *
17
+ * - {@link buildObjectMetadata} is the single constructor for the metadata
18
+ * field set. Drivers compute the provider-specific identity fields
19
+ * (`etag`/`checksum`/`size`) and timestamps (`createdAt`/`updatedAt`) and hand
20
+ * them here together with the caller's {@link WriteMetadata}; this function
21
+ * applies the canonical defaults and produces the complete, typed object. It
22
+ * never recomputes the identity fields, so driver-computed values are the
23
+ * source of truth for content hashing (Requirement 10.1, 10.2).
24
+ * - {@link normalizeMetadata} guarantees the full field set is present on any
25
+ * metadata surfaced by the facade (`put`/`stat`/`get`), filling the canonical
26
+ * defaults for any field a driver (e.g. a future cloud driver) left
27
+ * unpopulated while leaving identity/timestamp fields untouched. It is
28
+ * idempotent for metadata already produced by {@link buildObjectMetadata}
29
+ * (Requirement 10.1, 10.3).
30
+ * - {@link toWriteMetadata} projects a stored object's metadata back onto the
31
+ * write-time subset, used when copying/moving so the destination preserves the
32
+ * source's content type, ownership, tenancy, access level, and custom fields.
33
+ *
34
+ * The module depends only on the shared type surface (`types.ts`), keeping the
35
+ * dependency direction acyclic (leaf module → types).
36
+ *
37
+ * _Requirements: 10.1, 10.2, 10.3_
38
+ */
39
+ // ── Canonical field-set defaults ──────────────────────────────────────────────
40
+ /** Default content type applied when a write does not specify one. */
41
+ export const DEFAULT_CONTENT_TYPE = "application/octet-stream";
42
+ /** Default access level applied when a write does not specify one. */
43
+ export const DEFAULT_ACCESS_LEVEL = "private";
44
+ /**
45
+ * The canonical, ordered set of typed metadata field names every object carries
46
+ * (Requirement 10.1). `versionId` is intentionally excluded — it is an optional
47
+ * field present only on versioned objects, not part of the guaranteed base set.
48
+ */
49
+ export const STORAGE_METADATA_FIELDS = [
50
+ "key",
51
+ "size",
52
+ "contentType",
53
+ "etag",
54
+ "checksum",
55
+ "owner",
56
+ "tenant",
57
+ "accessLevel",
58
+ "createdAt",
59
+ "updatedAt",
60
+ "custom",
61
+ ];
62
+ /**
63
+ * Build the complete, typed {@link StorageObjectMetadata} field set from the
64
+ * driver-computed identity/timestamp values and the caller's
65
+ * {@link WriteMetadata}. This is the single place the metadata shape and its
66
+ * defaults are defined, so every driver produces an identical field set
67
+ * (Requirement 10.1, 10.2, 10.3).
68
+ *
69
+ * The identity fields (`etag`/`checksum`/`size`) and timestamps are used exactly
70
+ * as provided — this function never recomputes them — so the driver's computed
71
+ * values remain the source of truth and cannot diverge from what was persisted.
72
+ */
73
+ export function buildObjectMetadata(input) {
74
+ const { key, size, checksum, createdAt, updatedAt, write, versionId } = input;
75
+ const metadata = {
76
+ key,
77
+ size,
78
+ contentType: write.contentType ?? DEFAULT_CONTENT_TYPE,
79
+ etag: input.etag ?? checksum,
80
+ checksum,
81
+ owner: write.owner,
82
+ tenant: write.tenant,
83
+ accessLevel: write.accessLevel ?? DEFAULT_ACCESS_LEVEL,
84
+ createdAt,
85
+ updatedAt,
86
+ custom: write.custom ?? {},
87
+ ...(versionId !== undefined ? { versionId } : {}),
88
+ };
89
+ return metadata;
90
+ }
91
+ /**
92
+ * Return a copy of `metadata` with the complete typed field set guaranteed
93
+ * present, applying the canonical defaults for any missing `contentType`,
94
+ * `accessLevel`, or `custom` field while preserving the driver-computed
95
+ * identity fields (`etag`/`checksum`/`size`) and timestamps untouched
96
+ * (Requirement 10.1, 10.3).
97
+ *
98
+ * The facade runs the metadata it surfaces on `put`/`stat`/`get` through this
99
+ * function so the full field set is consistently present regardless of which
100
+ * driver produced it. It is idempotent for metadata already built by
101
+ * {@link buildObjectMetadata}, so wiring it in adds no behavioral change for the
102
+ * zero-dependency drivers while shielding the public surface from a future
103
+ * driver that returns a partially populated record.
104
+ */
105
+ export function normalizeMetadata(metadata) {
106
+ const normalized = {
107
+ key: metadata.key,
108
+ size: metadata.size,
109
+ contentType: metadata.contentType ?? DEFAULT_CONTENT_TYPE,
110
+ etag: metadata.etag,
111
+ checksum: metadata.checksum,
112
+ owner: metadata.owner,
113
+ tenant: metadata.tenant,
114
+ accessLevel: metadata.accessLevel ?? DEFAULT_ACCESS_LEVEL,
115
+ createdAt: metadata.createdAt,
116
+ updatedAt: metadata.updatedAt,
117
+ custom: metadata.custom ?? {},
118
+ ...(metadata.versionId !== undefined ? { versionId: metadata.versionId } : {}),
119
+ };
120
+ return normalized;
121
+ }
122
+ /**
123
+ * Project a stored object's {@link StorageObjectMetadata} onto the write-time
124
+ * {@link WriteMetadata} subset. Used when copying/moving an object so the
125
+ * destination preserves the source's content type, ownership, tenancy, access
126
+ * level, and custom fields. The identity/timestamp fields (`etag`/`checksum`/
127
+ * `size`/`createdAt`/`updatedAt`) are intentionally omitted — the driver
128
+ * recomputes them for the destination object.
129
+ */
130
+ export function toWriteMetadata(metadata) {
131
+ return {
132
+ contentType: metadata.contentType,
133
+ owner: metadata.owner,
134
+ tenant: metadata.tenant,
135
+ accessLevel: metadata.accessLevel,
136
+ custom: metadata.custom,
137
+ };
138
+ }
139
+ //# sourceMappingURL=metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAIH,iFAAiF;AAEjF,sEAAsE;AACtE,MAAM,CAAC,MAAM,oBAAoB,GAAG,0BAAmC,CAAC;AAExE,sEAAsE;AACtE,MAAM,CAAC,MAAM,oBAAoB,GAAgB,SAAS,CAAC;AAE3D;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,KAAK;IACL,MAAM;IACN,aAAa;IACb,MAAM;IACN,UAAU;IACV,OAAO;IACP,QAAQ;IACR,aAAa;IACb,WAAW;IACX,WAAW;IACX,QAAQ;CACA,CAAC;AA4BX;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAyB;IAC3D,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IAC9E,MAAM,QAAQ,GAA0B;QACtC,GAAG;QACH,IAAI;QACJ,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,oBAAoB;QACtD,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,QAAQ;QAC5B,QAAQ;QACR,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,oBAAoB;QACtD,SAAS;QACT,SAAS;QACT,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE;QAC1B,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAClD,CAAC;IACF,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAA+B;IAC/D,MAAM,UAAU,GAA0B;QACxC,GAAG,EAAE,QAAQ,CAAC,GAAG;QACjB,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,WAAW,EAAE,QAAQ,CAAC,WAAW,IAAI,oBAAoB;QACzD,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,WAAW,EAAE,QAAQ,CAAC,WAAW,IAAI,oBAAoB;QACzD,SAAS,EAAE,QAAQ,CAAC,SAAS;QAC7B,SAAS,EAAE,QAAQ,CAAC,SAAS;QAC7B,MAAM,EAAE,QAAQ,CAAC,MAAM,IAAI,EAAE;QAC7B,GAAG,CAAC,QAAQ,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/E,CAAC;IACF,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,QAA+B;IAC7D,OAAO;QACL,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,MAAM,EAAE,QAAQ,CAAC,MAAM;KACxB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * @streetjs/storage — the multipart upload manager.
3
+ *
4
+ * A {@link Multipart_Upload} splits a large object into independently uploaded
5
+ * parts that are later assembled into a single object whose content equals the
6
+ * concatenation of those parts in order (Requirement 6). {@link MultipartManager}
7
+ * provides this capability in a **provider-agnostic** way:
8
+ *
9
+ * - When the backing {@link StorageDriver} implements the optional native
10
+ * `multipart` capability, the manager delegates each operation to the driver
11
+ * so a provider that has first-class multipart support (e.g. S3) is used
12
+ * directly.
13
+ * - Otherwise the manager **simulates** multipart over the mandatory driver
14
+ * primitives (`put`/`get`/`putStream`/`delete`). Each `uploadPart` persists
15
+ * the part bytes under a reserved key derived from `(uploadId, partNumber)`
16
+ * (mirroring the design's `.multipart/<uploadId>/<partNumber>` layout), and
17
+ * `complete` streams the persisted parts back in the supplied order into the
18
+ * final object. Because completion assembles the object by reading one part at
19
+ * a time into a `Readable` and piping it through `driver.putStream`, the whole
20
+ * object is never required to be materialized in a single buffer by this
21
+ * layer — the design streams the concatenation and therefore imposes **no
22
+ * artificial size cap** (objects of a gigabyte or more are supported,
23
+ * Requirement 6.5).
24
+ *
25
+ * Semantics (Requirement 6):
26
+ * - {@link MultipartManager.create} mints and returns an upload identifier.
27
+ * - {@link MultipartManager.uploadPart} persists a part keyed by
28
+ * `(uploadId, partNumber)` and returns a {@link StoredPart} descriptor.
29
+ * - {@link MultipartManager.complete} concatenates the parts in the supplied
30
+ * order into the final object — equivalent to a single `put` of the
31
+ * concatenation — and returns the resulting metadata.
32
+ * - {@link MultipartManager.abort} discards every persisted part and creates no
33
+ * object.
34
+ *
35
+ * The module depends only on the driver contract, the shared type surface, the
36
+ * error hierarchy, and the metadata layer, keeping the dependency direction
37
+ * acyclic.
38
+ *
39
+ * _Requirements: 6.1, 6.2, 6.3, 6.4, 6.5_
40
+ */
41
+ import type { StorageDriver, StoredPart } from "./driver.js";
42
+ import type { StorageObjectMetadata, WriteMetadata } from "./types.js";
43
+ /**
44
+ * Provider-agnostic multipart upload manager built on the driver contract.
45
+ *
46
+ * A single instance is held by the facade and bound to one {@link StorageDriver}
47
+ * for its lifetime, so the native-vs-simulated decision (based on whether the
48
+ * driver exposes a `multipart` capability) is stable across every call for a
49
+ * given upload identifier.
50
+ */
51
+ export declare class MultipartManager {
52
+ /** The driver every operation is delegated to or simulated over. */
53
+ private readonly driver;
54
+ /**
55
+ * In-progress simulated sessions keyed by upload id. Empty when the driver
56
+ * provides a native `multipart` capability (that path keeps no local state).
57
+ */
58
+ private readonly sessions;
59
+ constructor(driver: StorageDriver);
60
+ /** The driver's native multipart capability, when present. */
61
+ private get native();
62
+ /**
63
+ * Begin a multipart upload for `key` and return its upload identifier
64
+ * (Requirement 6.1). When the driver has a native capability the driver mints
65
+ * the id; otherwise a fresh id is generated and a local session records the
66
+ * target key and its write-time metadata for assembly at completion.
67
+ */
68
+ create(key: string, metadata: WriteMetadata): Promise<string>;
69
+ /**
70
+ * Persist a single part for `uploadId` and return its {@link StoredPart}
71
+ * descriptor (Requirement 6.2). The part bytes are copied defensively before
72
+ * persistence so later mutation of the caller's buffer cannot corrupt a stored
73
+ * part. The returned `etag` is the sha-256 hex digest of the part bytes,
74
+ * matching the checksum scheme the drivers use elsewhere.
75
+ */
76
+ uploadPart(uploadId: string, partNumber: number, bytes: Uint8Array): Promise<StoredPart>;
77
+ /**
78
+ * Assemble the supplied `parts` in order into the final object and return its
79
+ * metadata (Requirement 6.3). The assembled content equals the concatenation
80
+ * of the parts in the given order — equivalent to a single `put` of that
81
+ * concatenation.
82
+ *
83
+ * For the simulated path the parts are streamed back one at a time from the
84
+ * driver into a `Readable` piped through `driver.putStream`, so this layer
85
+ * never buffers the full object at once (Requirement 6.5). Every persisted
86
+ * part (whether or not it appears in `parts`) is discarded afterward and the
87
+ * session is closed.
88
+ */
89
+ complete(uploadId: string, parts: readonly StoredPart[]): Promise<StorageObjectMetadata>;
90
+ /**
91
+ * Discard every persisted part for `uploadId` and create no completed object
92
+ * (Requirement 6.4). Delegates to the native capability when present; for the
93
+ * simulated path it deletes all recorded part keys and closes the session. An
94
+ * unknown/already-finalized upload id is treated as an idempotent no-op.
95
+ */
96
+ abort(uploadId: string): Promise<void>;
97
+ /** Delete every persisted part for a simulated upload id. */
98
+ private discardParts;
99
+ /** The reserved driver key a simulated part is persisted under. */
100
+ private partKey;
101
+ /**
102
+ * Resolve the simulated session for `uploadId`, throwing a descriptive
103
+ * {@link StorageError} when the id is unknown or the upload has already been
104
+ * finalized.
105
+ */
106
+ private requireSession;
107
+ }
108
+ //# sourceMappingURL=multipart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multipart.d.ts","sourceRoot":"","sources":["../src/multipart.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAMH,OAAO,KAAK,EAAuB,aAAa,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGlF,OAAO,KAAK,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA6BvE;;;;;;;GAOG;AACH,qBAAa,gBAAgB;IAC3B,oEAAoE;IACpE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IAEvC;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuC;gBAEpD,MAAM,EAAE,aAAa;IAIjC,8DAA8D;IAC9D,OAAO,KAAK,MAAM,GAEjB;IAED;;;;;OAKG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IASnE;;;;;;OAMG;IACG,UAAU,CACd,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,UAAU,GAChB,OAAO,CAAC,UAAU,CAAC;IActB;;;;;;;;;;;OAWG;IACG,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAmC9F;;;;;OAKG;IACG,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAa5C,6DAA6D;YAC/C,YAAY;IAM1B,mEAAmE;IACnE,OAAO,CAAC,OAAO;IAIf;;;;OAIG;IACH,OAAO,CAAC,cAAc;CASvB"}