@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,200 @@
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 { Buffer } from "node:buffer";
42
+ import { createHash, randomUUID } from "node:crypto";
43
+ import { Readable } from "node:stream";
44
+ import { NotFoundError, StorageError } from "./errors.js";
45
+ import { normalizeMetadata } from "./metadata.js";
46
+ /**
47
+ * Reserved key prefix under which simulated multipart parts are persisted via
48
+ * the driver primitives. Parts live at `${PART_KEY_PREFIX}<uploadId>/<partNumber>`
49
+ * and are removed on `complete`/`abort`, so they never remain visible after a
50
+ * multipart upload finalizes.
51
+ */
52
+ const PART_KEY_PREFIX = ".multipart/";
53
+ /** Write metadata used when persisting an individual (transient) part. */
54
+ const PART_WRITE_METADATA = { contentType: "application/octet-stream" };
55
+ /**
56
+ * Provider-agnostic multipart upload manager built on the driver contract.
57
+ *
58
+ * A single instance is held by the facade and bound to one {@link StorageDriver}
59
+ * for its lifetime, so the native-vs-simulated decision (based on whether the
60
+ * driver exposes a `multipart` capability) is stable across every call for a
61
+ * given upload identifier.
62
+ */
63
+ export class MultipartManager {
64
+ /** The driver every operation is delegated to or simulated over. */
65
+ driver;
66
+ /**
67
+ * In-progress simulated sessions keyed by upload id. Empty when the driver
68
+ * provides a native `multipart` capability (that path keeps no local state).
69
+ */
70
+ sessions = new Map();
71
+ constructor(driver) {
72
+ this.driver = driver;
73
+ }
74
+ /** The driver's native multipart capability, when present. */
75
+ get native() {
76
+ return this.driver.multipart;
77
+ }
78
+ /**
79
+ * Begin a multipart upload for `key` and return its upload identifier
80
+ * (Requirement 6.1). When the driver has a native capability the driver mints
81
+ * the id; otherwise a fresh id is generated and a local session records the
82
+ * target key and its write-time metadata for assembly at completion.
83
+ */
84
+ async create(key, metadata) {
85
+ if (this.native !== undefined) {
86
+ return this.native.create(key, metadata);
87
+ }
88
+ const uploadId = randomUUID();
89
+ this.sessions.set(uploadId, { key, metadata, partNumbers: new Set() });
90
+ return uploadId;
91
+ }
92
+ /**
93
+ * Persist a single part for `uploadId` and return its {@link StoredPart}
94
+ * descriptor (Requirement 6.2). The part bytes are copied defensively before
95
+ * persistence so later mutation of the caller's buffer cannot corrupt a stored
96
+ * part. The returned `etag` is the sha-256 hex digest of the part bytes,
97
+ * matching the checksum scheme the drivers use elsewhere.
98
+ */
99
+ async uploadPart(uploadId, partNumber, bytes) {
100
+ if (this.native !== undefined) {
101
+ return this.native.uploadPart(uploadId, partNumber, bytes);
102
+ }
103
+ const session = this.requireSession(uploadId);
104
+ assertValidPartNumber(partNumber);
105
+ const stored = bytes.slice();
106
+ await this.driver.put(this.partKey(uploadId, partNumber), stored, PART_WRITE_METADATA);
107
+ session.partNumbers.add(partNumber);
108
+ return { partNumber, etag: sha256Hex(stored), size: stored.byteLength };
109
+ }
110
+ /**
111
+ * Assemble the supplied `parts` in order into the final object and return its
112
+ * metadata (Requirement 6.3). The assembled content equals the concatenation
113
+ * of the parts in the given order — equivalent to a single `put` of that
114
+ * concatenation.
115
+ *
116
+ * For the simulated path the parts are streamed back one at a time from the
117
+ * driver into a `Readable` piped through `driver.putStream`, so this layer
118
+ * never buffers the full object at once (Requirement 6.5). Every persisted
119
+ * part (whether or not it appears in `parts`) is discarded afterward and the
120
+ * session is closed.
121
+ */
122
+ async complete(uploadId, parts) {
123
+ if (this.native !== undefined) {
124
+ return normalizeMetadata(await this.native.complete(uploadId, parts));
125
+ }
126
+ const session = this.requireSession(uploadId);
127
+ const driver = this.driver;
128
+ const partKey = (partNumber) => this.partKey(uploadId, partNumber);
129
+ // Stream the parts in the supplied order so the concatenation is assembled
130
+ // incrementally rather than materialized in a single buffer here.
131
+ async function* assembleParts() {
132
+ for (const part of parts) {
133
+ const result = await driver.get(partKey(part.partNumber));
134
+ if (!result.found) {
135
+ throw new NotFoundError(partKey(part.partNumber), `Multipart part ${part.partNumber} for upload "${uploadId}" was not found.`);
136
+ }
137
+ yield Buffer.from(result.bytes);
138
+ }
139
+ }
140
+ const metadata = await driver.putStream(session.key, Readable.from(assembleParts()), session.metadata);
141
+ await this.discardParts(uploadId, session.partNumbers);
142
+ this.sessions.delete(uploadId);
143
+ return normalizeMetadata(metadata);
144
+ }
145
+ /**
146
+ * Discard every persisted part for `uploadId` and create no completed object
147
+ * (Requirement 6.4). Delegates to the native capability when present; for the
148
+ * simulated path it deletes all recorded part keys and closes the session. An
149
+ * unknown/already-finalized upload id is treated as an idempotent no-op.
150
+ */
151
+ async abort(uploadId) {
152
+ if (this.native !== undefined) {
153
+ await this.native.abort(uploadId);
154
+ return;
155
+ }
156
+ const session = this.sessions.get(uploadId);
157
+ if (session === undefined) {
158
+ return;
159
+ }
160
+ await this.discardParts(uploadId, session.partNumbers);
161
+ this.sessions.delete(uploadId);
162
+ }
163
+ /** Delete every persisted part for a simulated upload id. */
164
+ async discardParts(uploadId, partNumbers) {
165
+ for (const partNumber of partNumbers) {
166
+ await this.driver.delete(this.partKey(uploadId, partNumber));
167
+ }
168
+ }
169
+ /** The reserved driver key a simulated part is persisted under. */
170
+ partKey(uploadId, partNumber) {
171
+ return `${PART_KEY_PREFIX}${uploadId}/${partNumber}`;
172
+ }
173
+ /**
174
+ * Resolve the simulated session for `uploadId`, throwing a descriptive
175
+ * {@link StorageError} when the id is unknown or the upload has already been
176
+ * finalized.
177
+ */
178
+ requireSession(uploadId) {
179
+ const session = this.sessions.get(uploadId);
180
+ if (session === undefined) {
181
+ throw new StorageError(`Unknown or already-finalized multipart upload id "${uploadId}".`);
182
+ }
183
+ return session;
184
+ }
185
+ }
186
+ /** Compute the lowercase sha-256 hex digest of `bytes`. */
187
+ function sha256Hex(bytes) {
188
+ return createHash("sha256").update(bytes).digest("hex");
189
+ }
190
+ /**
191
+ * Guard that a part number is a positive integer. Part numbers identify the
192
+ * ordinal position of a part and must be well-formed for the reserved part key
193
+ * to be stable and for ordering to be meaningful.
194
+ */
195
+ function assertValidPartNumber(partNumber) {
196
+ if (!Number.isInteger(partNumber) || partNumber < 1) {
197
+ throw new StorageError(`Invalid multipart part number ${partNumber}; expected a positive integer.`);
198
+ }
199
+ }
200
+ //# sourceMappingURL=multipart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multipart.js","sourceRoot":"","sources":["../src/multipart.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ import type { HealthCheckRegistry, MetricsRegistry } from "streetjs";
2
+ import type { StorageStats, DriverProbe } from "./types.js";
3
+ /**
4
+ * The introspection slice of a {@link Storage} facade the observability layer
5
+ * reads: a synchronous stats snapshot and the best-effort driver probe.
6
+ */
7
+ export interface StorageIntrospect {
8
+ stats(): StorageStats;
9
+ probe(): Promise<DriverProbe>;
10
+ }
11
+ /** The name the storage health check is registered under. */
12
+ export declare const STORAGE_HEALTH_CHECK_NAME = "storage";
13
+ export declare const STORAGE_UPLOADS_METRIC = "storage_uploads_total";
14
+ export declare const STORAGE_DOWNLOADS_METRIC = "storage_downloads_total";
15
+ export declare const STORAGE_BYTES_UPLOADED_METRIC = "storage_bytes_uploaded_total";
16
+ export declare const STORAGE_BYTES_DOWNLOADED_METRIC = "storage_bytes_downloaded_total";
17
+ export declare const STORAGE_ACTIVE_UPLOADS_METRIC = "storage_active_uploads";
18
+ export declare const STORAGE_FAILED_UPLOADS_METRIC = "storage_failed_uploads_total";
19
+ export declare const STORAGE_USAGE_METRIC = "storage_usage_bytes";
20
+ export declare const STORAGE_LATENCY_METRIC = "storage_operation_latency_seconds";
21
+ export declare const STORAGE_MULTIPART_METRIC = "storage_multipart_uploads_total";
22
+ export declare const STORAGE_RESUMABLE_METRIC = "storage_resumable_sessions_total";
23
+ /**
24
+ * The live telemetry sink the facade feeds as operations occur. Every hook is
25
+ * optional so an inert sink (no metrics registry) is a complete no-op. All
26
+ * hooks are isolated by the facade so observability never destabilizes an
27
+ * operation.
28
+ */
29
+ export interface StorageTelemetry {
30
+ /** A successful upload persisted `bytes` in `latencySeconds`. */
31
+ onUpload?(bytes: number, latencySeconds: number): void;
32
+ /** A successful download returned `bytes` in `latencySeconds`. */
33
+ onDownload?(bytes: number, latencySeconds: number): void;
34
+ /** An upload failed (validation, authorization, or driver error). */
35
+ onUploadFailed?(): void;
36
+ /** The number of in-flight (streamed/resumable) uploads changed. */
37
+ onActiveUploadsChange?(active: number): void;
38
+ /** The tracked storage usage (bytes) changed. */
39
+ onStorageUsage?(bytes: number): void;
40
+ /** A multipart upload was created. */
41
+ onMultipartUpload?(): void;
42
+ /** A resumable upload session was started. */
43
+ onResumableSession?(): void;
44
+ }
45
+ /** Options for {@link registerStorageObservability}. */
46
+ export interface StorageObservabilityOptions {
47
+ /** Registry the `storage` health check is registered with (Req 23.3). */
48
+ health?: HealthCheckRegistry;
49
+ /** Registry the storage metrics are exported through (Req 23.1, 23.2). */
50
+ metrics?: MetricsRegistry;
51
+ /** Refresh cadence for gauges when `autoRefresh` is enabled. */
52
+ refreshIntervalMs?: number;
53
+ /**
54
+ * When `true`, an unref'd interval keeps the gauges primed. Default `false`
55
+ * (pull-based: the caller drives {@link StorageObservabilityHandle.refresh}).
56
+ */
57
+ autoRefresh?: boolean;
58
+ }
59
+ /** Handle returned by {@link registerStorageObservability}. */
60
+ export interface StorageObservabilityHandle {
61
+ /**
62
+ * The telemetry sink the facade feeds live. Drives the counters, gauges, and
63
+ * latency histogram as operations occur.
64
+ */
65
+ readonly telemetry: StorageTelemetry;
66
+ /**
67
+ * Register the `storage` health check against the created facade and prime the
68
+ * gauges from `storage.stats()`. Call once after `createStorage`.
69
+ */
70
+ attach(storage: StorageIntrospect): void;
71
+ /** Recompute the gauges from `storage.stats()` (best-effort; never throws). */
72
+ refresh(): void;
73
+ /** Stop any refresh timer and release resources. Safe to call once. */
74
+ close(): void;
75
+ }
76
+ /**
77
+ * Register storage observability. Returns a {@link StorageObservabilityHandle}
78
+ * whose `telemetry` the facade feeds live and whose `attach` wires the health
79
+ * check + primes the gauges from the created facade.
80
+ */
81
+ export declare function registerStorageObservability(options?: StorageObservabilityOptions): StorageObservabilityHandle;
82
+ //# sourceMappingURL=observability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observability.d.ts","sourceRoot":"","sources":["../src/observability.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EACV,mBAAmB,EACnB,eAAe,EAKhB,MAAM,UAAU,CAAC;AAElB,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE5D;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,IAAI,YAAY,CAAC;IACtB,KAAK,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;CAC/B;AAED,6DAA6D;AAC7D,eAAO,MAAM,yBAAyB,YAAY,CAAC;AAEnD,eAAO,MAAM,sBAAsB,0BAA0B,CAAC;AAC9D,eAAO,MAAM,wBAAwB,4BAA4B,CAAC;AAClE,eAAO,MAAM,6BAA6B,iCAAiC,CAAC;AAC5E,eAAO,MAAM,+BAA+B,mCAAmC,CAAC;AAChF,eAAO,MAAM,6BAA6B,2BAA2B,CAAC;AACtE,eAAO,MAAM,6BAA6B,iCAAiC,CAAC;AAC5E,eAAO,MAAM,oBAAoB,wBAAwB,CAAC;AAC1D,eAAO,MAAM,sBAAsB,sCAAsC,CAAC;AAC1E,eAAO,MAAM,wBAAwB,oCAAoC,CAAC;AAC1E,eAAO,MAAM,wBAAwB,qCAAqC,CAAC;AAI3E;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,iEAAiE;IACjE,QAAQ,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACvD,kEAAkE;IAClE,UAAU,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACzD,qEAAqE;IACrE,cAAc,CAAC,IAAI,IAAI,CAAC;IACxB,oEAAoE;IACpE,qBAAqB,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C,iDAAiD;IACjD,cAAc,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,sCAAsC;IACtC,iBAAiB,CAAC,IAAI,IAAI,CAAC;IAC3B,8CAA8C;IAC9C,kBAAkB,CAAC,IAAI,IAAI,CAAC;CAC7B;AAED,wDAAwD;AACxD,MAAM,WAAW,2BAA2B;IAC1C,yEAAyE;IACzE,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,0EAA0E;IAC1E,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,gEAAgE;IAChE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,+DAA+D;AAC/D,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC;IACrC;;;OAGG;IACH,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACzC,+EAA+E;IAC/E,OAAO,IAAI,IAAI,CAAC;IAChB,uEAAuE;IACvE,KAAK,IAAI,IAAI,CAAC;CACf;AAKD;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,GAAE,2BAAgC,GACxC,0BAA0B,CAoJ5B"}
@@ -0,0 +1,175 @@
1
+ // src/observability.ts
2
+ // @streetjs/storage — health check + metrics wiring over the reused core
3
+ // `HealthCheckRegistry` and `MetricsRegistry`.
4
+ //
5
+ // Following the events package's `observability.ts` pattern, this module
6
+ // exposes a single entry point, `registerStorageObservability`, that returns a
7
+ // handle with:
8
+ //
9
+ // 1. a `telemetry` sink the facade feeds live as operations occur — it drives
10
+ // the upload / download / bytes / failed-upload counters, the active-uploads
11
+ // and storage-usage gauges, the operation-latency histogram, and the
12
+ // multipart / resumable counters (Requirement 23.2);
13
+ // 2. an `attach(storage)` method that registers the `storage` health check
14
+ // against the `HealthCheckRegistry`, sourced from `storage.probe()` for
15
+ // provider connectivity, writability, readability, and quota availability
16
+ // (Requirement 23.3), and primes the gauges from `storage.stats()`.
17
+ //
18
+ // Everything is opt-in: with no `metrics` registry the telemetry is inert; with
19
+ // no `health` registry no check is registered. Registration is idempotent
20
+ // against a shared registry (reuses an existing metric rather than throwing —
21
+ // `reg.has(name) ? reg.get(name) : reg.counter(...)`), so several storage
22
+ // instances can share one registry (Requirement 23.1).
23
+ //
24
+ // Only the existing core primitives (`MetricsRegistry`, `HealthCheckRegistry`)
25
+ // are reused; no separate metrics / health / scheduling / retry / event system
26
+ // is introduced (Requirement 23.4).
27
+ /** The name the storage health check is registered under. */
28
+ export const STORAGE_HEALTH_CHECK_NAME = "storage";
29
+ export const STORAGE_UPLOADS_METRIC = "storage_uploads_total";
30
+ export const STORAGE_DOWNLOADS_METRIC = "storage_downloads_total";
31
+ export const STORAGE_BYTES_UPLOADED_METRIC = "storage_bytes_uploaded_total";
32
+ export const STORAGE_BYTES_DOWNLOADED_METRIC = "storage_bytes_downloaded_total";
33
+ export const STORAGE_ACTIVE_UPLOADS_METRIC = "storage_active_uploads";
34
+ export const STORAGE_FAILED_UPLOADS_METRIC = "storage_failed_uploads_total";
35
+ export const STORAGE_USAGE_METRIC = "storage_usage_bytes";
36
+ export const STORAGE_LATENCY_METRIC = "storage_operation_latency_seconds";
37
+ export const STORAGE_MULTIPART_METRIC = "storage_multipart_uploads_total";
38
+ export const STORAGE_RESUMABLE_METRIC = "storage_resumable_sessions_total";
39
+ const DEFAULT_REFRESH_INTERVAL_MS = 5_000;
40
+ /** An inert telemetry sink used when no metrics registry is provided. */
41
+ const NOOP_TELEMETRY = {};
42
+ /**
43
+ * Register storage observability. Returns a {@link StorageObservabilityHandle}
44
+ * whose `telemetry` the facade feeds live and whose `attach` wires the health
45
+ * check + primes the gauges from the created facade.
46
+ */
47
+ export function registerStorageObservability(options = {}) {
48
+ const { metrics, health } = options;
49
+ let storage;
50
+ let timer;
51
+ let closed = false;
52
+ // ── Metrics (idempotent registration) ─────────────────────────────────────
53
+ let uploadsCounter;
54
+ let downloadsCounter;
55
+ let bytesUploadedCounter;
56
+ let bytesDownloadedCounter;
57
+ let failedUploadsCounter;
58
+ let multipartCounter;
59
+ let resumableCounter;
60
+ let activeUploadsGauge;
61
+ let usageGauge;
62
+ let latencyHistogram;
63
+ if (metrics) {
64
+ uploadsCounter = counter(metrics, STORAGE_UPLOADS_METRIC, "Total objects uploaded.");
65
+ downloadsCounter = counter(metrics, STORAGE_DOWNLOADS_METRIC, "Total objects downloaded.");
66
+ bytesUploadedCounter = counter(metrics, STORAGE_BYTES_UPLOADED_METRIC, "Total bytes uploaded.");
67
+ bytesDownloadedCounter = counter(metrics, STORAGE_BYTES_DOWNLOADED_METRIC, "Total bytes downloaded.");
68
+ failedUploadsCounter = counter(metrics, STORAGE_FAILED_UPLOADS_METRIC, "Total failed uploads.");
69
+ multipartCounter = counter(metrics, STORAGE_MULTIPART_METRIC, "Total multipart uploads created.");
70
+ resumableCounter = counter(metrics, STORAGE_RESUMABLE_METRIC, "Total resumable upload sessions started.");
71
+ activeUploadsGauge = gauge(metrics, STORAGE_ACTIVE_UPLOADS_METRIC, "Uploads currently in flight.");
72
+ usageGauge = gauge(metrics, STORAGE_USAGE_METRIC, "Tracked storage usage in bytes.");
73
+ latencyHistogram = histogram(metrics, STORAGE_LATENCY_METRIC, "Storage operation latency in seconds.");
74
+ }
75
+ const telemetry = metrics
76
+ ? {
77
+ onUpload: (bytes, latencySeconds) => safe(() => {
78
+ uploadsCounter?.inc();
79
+ bytesUploadedCounter?.inc({}, bytes);
80
+ latencyHistogram?.observe(latencySeconds);
81
+ }),
82
+ onDownload: (bytes, latencySeconds) => safe(() => {
83
+ downloadsCounter?.inc();
84
+ bytesDownloadedCounter?.inc({}, bytes);
85
+ latencyHistogram?.observe(latencySeconds);
86
+ }),
87
+ onUploadFailed: () => safe(() => failedUploadsCounter?.inc()),
88
+ onActiveUploadsChange: (active) => safe(() => activeUploadsGauge?.set(active)),
89
+ onStorageUsage: (bytes) => safe(() => usageGauge?.set(bytes)),
90
+ onMultipartUpload: () => safe(() => multipartCounter?.inc()),
91
+ onResumableSession: () => safe(() => resumableCounter?.inc()),
92
+ }
93
+ : NOOP_TELEMETRY;
94
+ const refresh = () => {
95
+ if (!storage) {
96
+ return;
97
+ }
98
+ safe(() => {
99
+ const stats = storage.stats();
100
+ activeUploadsGauge?.set(stats.activeUploads);
101
+ usageGauge?.set(stats.storageUsage);
102
+ });
103
+ };
104
+ const attach = (created) => {
105
+ storage = created;
106
+ if (health) {
107
+ health.addCheck(STORAGE_HEALTH_CHECK_NAME, async () => {
108
+ try {
109
+ const probe = await created.probe();
110
+ // The provider is healthy only when it is reachable and all of the
111
+ // connectivity/writability/readability/quota dimensions hold
112
+ // (Requirement 23.3).
113
+ const status = probe.connectivity && probe.writable && probe.readable && probe.quotaAvailable
114
+ ? "up"
115
+ : "down";
116
+ return {
117
+ status,
118
+ details: {
119
+ connectivity: probe.connectivity,
120
+ writable: probe.writable,
121
+ readable: probe.readable,
122
+ quotaAvailable: probe.quotaAvailable,
123
+ },
124
+ };
125
+ }
126
+ catch (err) {
127
+ return {
128
+ status: "down",
129
+ details: { error: err instanceof Error ? err.message : String(err) },
130
+ };
131
+ }
132
+ });
133
+ }
134
+ // Prime the gauges immediately; optionally keep them fresh via an unref'd timer.
135
+ refresh();
136
+ if (options.autoRefresh) {
137
+ timer = setInterval(refresh, options.refreshIntervalMs ?? DEFAULT_REFRESH_INTERVAL_MS);
138
+ timer.unref?.();
139
+ }
140
+ };
141
+ return {
142
+ telemetry,
143
+ attach,
144
+ refresh,
145
+ close: () => {
146
+ if (closed) {
147
+ return;
148
+ }
149
+ closed = true;
150
+ if (timer !== undefined) {
151
+ clearInterval(timer);
152
+ timer = undefined;
153
+ }
154
+ },
155
+ };
156
+ }
157
+ // ── Idempotent metric helpers ────────────────────────────────────────────────
158
+ function counter(reg, name, help) {
159
+ return reg.has(name) ? reg.get(name) : reg.counter(name, help);
160
+ }
161
+ function gauge(reg, name, help, labels = []) {
162
+ return reg.has(name) ? reg.get(name) : reg.gauge(name, help, labels);
163
+ }
164
+ function histogram(reg, name, help) {
165
+ return reg.has(name) ? reg.get(name) : reg.histogram(name, help);
166
+ }
167
+ function safe(fn) {
168
+ try {
169
+ fn();
170
+ }
171
+ catch {
172
+ // Observability must never destabilize a storage operation or a scrape.
173
+ }
174
+ }
175
+ //# sourceMappingURL=observability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observability.js","sourceRoot":"","sources":["../src/observability.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ import { PluginModule } from "streetjs";
2
+ import type { SandboxedApp } from "streetjs";
3
+ import { type Storage } from "./facade.js";
4
+ import type { StorageConfig, StorageMetadataMap } from "./types.js";
5
+ /**
6
+ * Options for {@link StoragePlugin}.
7
+ *
8
+ * Extends {@link StorageConfig} directly, so every configuration value the
9
+ * facade accepts — provider, driver, validation, versioning, signing secret,
10
+ * the `metrics` / `health` registries the observability layer registers
11
+ * against, the structural auth / image codec, and the structural
12
+ * events / queue / realtime `bridges` the facade wires internally — is supplied
13
+ * through the plugin options. Because a `SandboxedApp` exposes no registry, the
14
+ * registries are resolved from these options rather than from the app.
15
+ *
16
+ * @typeParam T - Optional per-application custom metadata map.
17
+ */
18
+ export interface StoragePluginOptions<T extends StorageMetadataMap = StorageMetadataMap> extends StorageConfig {
19
+ /**
20
+ * Declarative, imperative bridge wiring composed on top of the constructed
21
+ * facade. Each entry is an attach function called with the live
22
+ * {@link Storage} facade; if it returns a detach function, that detach is
23
+ * invoked on `onUnload`. This keeps the plugin decoupled from any specific
24
+ * integration instance — compose custom bridges without the plugin depending
25
+ * on them, and have them torn down deterministically on unload:
26
+ *
27
+ * ```ts
28
+ * new StoragePlugin({
29
+ * provider: "memory",
30
+ * metrics,
31
+ * health,
32
+ * wireBridges: [
33
+ * (storage) => attachAuditLog(storage, auditSink), // returns () => void
34
+ * ],
35
+ * });
36
+ * ```
37
+ *
38
+ * Distinct from the inherited structural `bridges`
39
+ * (events / queue / realtime), which the facade wires internally at
40
+ * construction time.
41
+ */
42
+ wireBridges?: Array<(storage: Storage<T>) => (() => void) | void>;
43
+ }
44
+ /**
45
+ * Plugin entry point that constructs and wires the application storage layer.
46
+ *
47
+ * Compatible with the core {@link PluginModule} and safe to register with a
48
+ * `SandboxedApp` (Requirements 20.1, 20.2). Once loaded, the application
49
+ * retrieves the live {@link Storage} facade through the {@link storage}
50
+ * accessor without any existing public API being modified (Requirement 20.3).
51
+ *
52
+ * @typeParam T - Optional per-application custom metadata map.
53
+ */
54
+ export declare class StoragePlugin<T extends StorageMetadataMap = StorageMetadataMap> extends PluginModule {
55
+ readonly name = "@streetjs/storage";
56
+ readonly version = "1.0.0";
57
+ protected readonly options: StoragePluginOptions<T>;
58
+ private storageInstance?;
59
+ private bridgeDetachers;
60
+ constructor(options: StoragePluginOptions<T>);
61
+ /**
62
+ * The constructed facade, or `undefined` before load / after unload. Because
63
+ * the `SandboxedApp` has no registry to attach to, the application retrieves
64
+ * the live {@link Storage} facade through this accessor after the plugin
65
+ * loads (Requirement 20.3).
66
+ */
67
+ get storage(): Storage<T> | undefined;
68
+ /**
69
+ * Construct the facade (which wires observability from the configured
70
+ * `metrics` / `health` registries and the structural bridges), apply the
71
+ * declarative bridge wiring collecting any detach functions, and expose the
72
+ * facade. Idempotent per load: a second `onLoad` without an intervening
73
+ * `onUnload` reuses the already-constructed facade.
74
+ */
75
+ onLoad(_app: SandboxedApp): Promise<void>;
76
+ /**
77
+ * Detach the declarative bridges and close the facade gracefully (which stops
78
+ * the observability refresh timer). Safe if never loaded.
79
+ */
80
+ onUnload(_app: SandboxedApp): Promise<void>;
81
+ }
82
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,OAAO,EAAiB,KAAK,OAAO,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEpE;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,oBAAoB,CAAC,CAAC,SAAS,kBAAkB,GAAG,kBAAkB,CACrF,SAAQ,aAAa;IACrB;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;CACnE;AAED;;;;;;;;;GASG;AACH,qBAAa,aAAa,CACxB,CAAC,SAAS,kBAAkB,GAAG,kBAAkB,CACjD,SAAQ,YAAY;IACpB,QAAQ,CAAC,IAAI,uBAAuB;IACpC,QAAQ,CAAC,OAAO,WAAW;IAE3B,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,oBAAoB,CAAC,CAAC,CAAC,CAAC;IAEpD,OAAO,CAAC,eAAe,CAAC,CAAa;IACrC,OAAO,CAAC,eAAe,CAAyB;gBAEpC,OAAO,EAAE,oBAAoB,CAAC,CAAC,CAAC;IAK5C;;;;;OAKG;IACH,IAAI,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,SAAS,CAEpC;IAED;;;;;;OAMG;IACY,MAAM,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBxD;;;OAGG;IACY,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;CAiB3D"}