@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,222 @@
1
+ /**
2
+ * @streetjs/storage — the shared, parameterized contract-conformance suite.
3
+ *
4
+ * Requirement 2 states that every provider implements one `StorageDriver`
5
+ * contract with identical observable behavior: object existence, content bytes,
6
+ * and returned metadata must be equivalent across drivers (Requirement 2.1,
7
+ * 2.3), and a missing key must be reported the same way everywhere
8
+ * (Requirement 2.4). This module encodes the observable core of that contract
9
+ * as a **reusable, driver-agnostic conformance suite** so the exact same checks
10
+ * can be run against any {@link StorageDriver} — the zero-dependency Memory and
11
+ * Local drivers, the in-process testing doubles, and every cloud driver.
12
+ *
13
+ * The suite is designed to be consumed in two ways from one definition:
14
+ *
15
+ * - **Programmatically** (returns pass/fail results). {@link runStorageDriverContract}
16
+ * runs every check against a freshly constructed driver and returns a
17
+ * {@link ContractReport} describing which checks passed. This is what the
18
+ * `storage:verify` CLI command (task 24.2) uses to report whether the
19
+ * configured driver satisfies the contract, and what Property 19 (task 27.3)
20
+ * uses to assert that every driver conforms.
21
+ * - **As node:test tests**. {@link registerStorageDriverContractTests} turns each
22
+ * check into a `node:test` case using a caller-supplied `test` function, so a
23
+ * thin `*.test.js` can run the suite against Memory + Local without this
24
+ * support module importing `node:test` itself (keeping it importable from the
25
+ * CLI, which has no test runner in scope).
26
+ *
27
+ * Each check receives its **own freshly constructed driver** (from the supplied
28
+ * factory) so checks are fully isolated and order-independent. Assertions use
29
+ * `node:assert/strict`; a check throws on failure and returns normally on
30
+ * success. The checked behaviors are:
31
+ *
32
+ * 1. **existence** — `put` then `exists(key)` is `true`; `exists(other)` is `false`.
33
+ * 2. **byte round-trip** — `put(key, bytes)` then `get(key)` yields
34
+ * `{ found: true }` with content bytes exactly equal to the input.
35
+ * 3. **not-found (get)** — `get(missing)` yields `{ found: false }`.
36
+ * 4. **not-found (stat)** — `stat(missing)` yields `null`.
37
+ * 5. **metadata shape** — `put` returns the complete typed
38
+ * {@link StorageObjectMetadata} field set with correctly typed values.
39
+ *
40
+ * This module is a support module under `src/tests/` (not itself a `*.test.js`
41
+ * picked up by the default test glob); it is imported by tests and by the CLI.
42
+ *
43
+ * _Requirements: 2.1, 2.3, 2.4_
44
+ */
45
+ import assert from "node:assert/strict";
46
+ import { STORAGE_METADATA_FIELDS } from "../metadata.js";
47
+ // ── Test fixtures ─────────────────────────────────────────────────────────────
48
+ /** Encode a UTF-8 string into a Uint8Array for storage. */
49
+ function bytesOf(str) {
50
+ return new TextEncoder().encode(str);
51
+ }
52
+ /** The full set of access levels, used to validate the `accessLevel` field. */
53
+ const ACCESS_LEVELS = [
54
+ "public",
55
+ "private",
56
+ "signed",
57
+ "authenticated",
58
+ "role-based",
59
+ "tenant-aware",
60
+ ];
61
+ /**
62
+ * Assert that `metadata` carries the complete typed {@link StorageObjectMetadata}
63
+ * field set with correctly typed values. Uses {@link STORAGE_METADATA_FIELDS} as
64
+ * the single source of truth for the required field names so this check tracks
65
+ * the canonical shape automatically (Requirement 2.1, 10.1).
66
+ */
67
+ function assertMetadataShape(metadata, expected) {
68
+ assert.ok(metadata !== null && typeof metadata === "object", "put must return a metadata object");
69
+ // Every canonical field must be present as an own key.
70
+ for (const field of STORAGE_METADATA_FIELDS) {
71
+ assert.ok(field in metadata, `metadata is missing required field "${field}"`);
72
+ }
73
+ // Identity / value fields must be correctly typed.
74
+ assert.equal(metadata.key, expected.key, "metadata.key must equal the stored key");
75
+ assert.equal(metadata.size, expected.size, "metadata.size must equal the byte length");
76
+ assert.equal(typeof metadata.contentType, "string", "metadata.contentType must be a string");
77
+ assert.equal(typeof metadata.etag, "string", "metadata.etag must be a string");
78
+ assert.equal(typeof metadata.checksum, "string", "metadata.checksum must be a string");
79
+ assert.equal(typeof metadata.createdAt, "number", "metadata.createdAt must be a number");
80
+ assert.equal(typeof metadata.updatedAt, "number", "metadata.updatedAt must be a number");
81
+ assert.ok(metadata.custom !== null && typeof metadata.custom === "object", "metadata.custom must be an object");
82
+ assert.ok(ACCESS_LEVELS.includes(metadata.accessLevel), `metadata.accessLevel must be a valid AccessLevel (got "${metadata.accessLevel}")`);
83
+ // owner/tenant are optional: absent (undefined) or a string.
84
+ if (metadata.owner !== undefined) {
85
+ assert.equal(typeof metadata.owner, "string", "metadata.owner must be a string when present");
86
+ }
87
+ if (metadata.tenant !== undefined) {
88
+ assert.equal(typeof metadata.tenant, "string", "metadata.tenant must be a string when present");
89
+ }
90
+ }
91
+ // ── The checks ────────────────────────────────────────────────────────────────
92
+ /**
93
+ * The ordered set of observable-behavior checks that make up the driver
94
+ * contract-conformance suite. Exported so consumers can inspect, subset, or
95
+ * extend the list; most callers use {@link runStorageDriverContract} or
96
+ * {@link registerStorageDriverContractTests} instead.
97
+ */
98
+ export const storageDriverContractChecks = [
99
+ {
100
+ name: "existence: put then exists reports presence and absence",
101
+ requirement: "2.1",
102
+ async run(driver) {
103
+ const key = "contract/existence.txt";
104
+ assert.equal(await driver.exists(key), false, "exists must be false before the object is stored");
105
+ await driver.put(key, bytesOf("present"), {});
106
+ assert.equal(await driver.exists(key), true, "exists must be true after put");
107
+ assert.equal(await driver.exists("contract/never-written.txt"), false, "exists must be false for an unrelated key");
108
+ },
109
+ },
110
+ {
111
+ name: "byte round-trip: get returns the stored bytes unchanged",
112
+ requirement: "2.1",
113
+ async run(driver) {
114
+ const key = "contract/round-trip.bin";
115
+ // Include boundary byte values so a lossy round-trip is caught.
116
+ const content = new Uint8Array([0, 1, 127, 128, 254, 255, 65, 66, 67]);
117
+ await driver.put(key, content, {});
118
+ const result = await driver.get(key);
119
+ assert.equal(result.found, true, "get must report found:true for a stored key");
120
+ assert.ok(result.found === true, "narrowing: result must be the found variant");
121
+ assert.deepEqual(result.bytes, content, "get must return the exact stored bytes");
122
+ },
123
+ },
124
+ {
125
+ name: "not-found (get): missing key reports found:false",
126
+ requirement: "2.4",
127
+ async run(driver) {
128
+ const result = await driver.get("contract/absent-get.txt");
129
+ assert.equal(result.found, false, "get on a missing key must report found:false");
130
+ assert.ok(result.found === false, "the not-found result must be the { found: false } variant");
131
+ },
132
+ },
133
+ {
134
+ name: "not-found (stat): missing key reports null",
135
+ requirement: "2.4",
136
+ async run(driver) {
137
+ const meta = await driver.stat("contract/absent-stat.txt");
138
+ assert.equal(meta, null, "stat on a missing key must return null");
139
+ },
140
+ },
141
+ {
142
+ name: "metadata shape: put returns the complete typed field set",
143
+ requirement: "2.1",
144
+ async run(driver) {
145
+ const key = "contract/metadata-shape.txt";
146
+ const content = bytesOf("shape check");
147
+ const metadata = await driver.put(key, content, {
148
+ contentType: "text/plain",
149
+ owner: "user-1",
150
+ tenant: "tenant-a",
151
+ accessLevel: "public",
152
+ custom: { label: "invoice" },
153
+ });
154
+ assertMetadataShape(metadata, { key, size: content.byteLength });
155
+ },
156
+ },
157
+ ];
158
+ /**
159
+ * Run the contract-conformance suite against a driver and return a pass/fail
160
+ * {@link ContractReport}. Each check is executed against a freshly constructed
161
+ * driver from `makeDriver` so the checks never interfere with one another.
162
+ *
163
+ * This never throws for a contract violation — a failing check is captured as a
164
+ * `passed: false` entry with its error message — so a consumer such as the
165
+ * `storage:verify` CLI (task 24.2) can render every result. Property 19
166
+ * (task 27.3) uses the returned {@link ContractReport.passed} to assert
167
+ * conformance across drivers.
168
+ *
169
+ * @param makeDriver Factory producing a fresh driver for each check.
170
+ * @param options Optional override of the checks to run.
171
+ */
172
+ export async function runStorageDriverContract(makeDriver, options) {
173
+ const checks = options?.checks ?? storageDriverContractChecks;
174
+ const results = [];
175
+ let driverName = "unknown";
176
+ for (const check of checks) {
177
+ const driver = await makeDriver();
178
+ driverName = driver.name;
179
+ try {
180
+ await check.run(driver);
181
+ results.push({ name: check.name, requirement: check.requirement, passed: true });
182
+ }
183
+ catch (error) {
184
+ results.push({
185
+ name: check.name,
186
+ requirement: check.requirement,
187
+ passed: false,
188
+ error: error instanceof Error ? error.message : String(error),
189
+ });
190
+ }
191
+ }
192
+ return {
193
+ driver: driverName,
194
+ passed: results.every((result) => result.passed),
195
+ results,
196
+ };
197
+ }
198
+ // ── node:test integration ─────────────────────────────────────────────────────
199
+ /**
200
+ * Register each contract check as an individual `node:test` case using the
201
+ * supplied `test` runner. A thin `*.test.js` passes `test` from `node:test` and
202
+ * a driver factory; each check runs against a fresh driver and fails the test if
203
+ * the driver violates the contract.
204
+ *
205
+ * Taking the runner as a parameter keeps this module free of a hard `node:test`
206
+ * import, so it remains importable from non-test contexts (e.g. the CLI's
207
+ * `storage:verify`).
208
+ *
209
+ * @param label Prefix for each generated test name (e.g. the driver label).
210
+ * @param makeDriver Factory producing a fresh driver for each check.
211
+ * @param runner The `test` function from `node:test` (or a compatible runner).
212
+ * @param checks Optional override of the checks to run.
213
+ */
214
+ export function registerStorageDriverContractTests(label, makeDriver, runner, checks = storageDriverContractChecks) {
215
+ for (const check of checks) {
216
+ runner(`${label}: ${check.name}`, async () => {
217
+ const driver = await makeDriver();
218
+ await check.run(driver);
219
+ });
220
+ }
221
+ }
222
+ //# sourceMappingURL=contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../../src/tests/contract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=contract.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.test.d.ts","sourceRoot":"","sources":["../../src/tests/contract.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,110 @@
1
+ // Contract-conformance suite run against the two zero-dependency drivers.
2
+ //
3
+ // Exercises the shared, parameterized suite from `./contract.js` (task 27.1)
4
+ // against MemoryStorageDriver and LocalStorageDriver, verifying both directions
5
+ // it is consumed in production:
6
+ //
7
+ // - as node:test cases via registerStorageDriverContractTests (what a driver's
8
+ // own test file would do), and
9
+ // - programmatically via runStorageDriverContract (what `storage:verify` and
10
+ // Property 19 use), asserting the returned report passes for every check.
11
+ //
12
+ // Each check receives a freshly constructed driver from the supplied factory;
13
+ // the Local driver gets a fresh temp directory per instance so checks stay
14
+ // isolated. Executed via `node --test dist/tests/*.test.js`.
15
+ //
16
+ // Requirements: 2.1, 2.3, 2.4
17
+ import test from "node:test";
18
+ import assert from "node:assert/strict";
19
+ import { mkdtempSync, rmSync } from "node:fs";
20
+ import { tmpdir } from "node:os";
21
+ import { join } from "node:path";
22
+ import { runStorageDriverContract, registerStorageDriverContractTests, storageDriverContractChecks, } from "./contract.js";
23
+ import { MemoryStorageDriver } from "../drivers/memory.js";
24
+ import { LocalStorageDriver } from "../drivers/local.js";
25
+ /** A fixed clock for deterministic timestamps. */
26
+ const fixedClock = () => 1_700_000_000_000;
27
+ /** Factory: a fresh in-memory driver per call. */
28
+ function makeMemoryDriver() {
29
+ return new MemoryStorageDriver({ clock: fixedClock });
30
+ }
31
+ /** Temp roots allocated for Local drivers, cleaned up after the run. */
32
+ const tempRoots = [];
33
+ /** Factory: a fresh filesystem driver rooted at a unique temp dir per call. */
34
+ function makeLocalDriver() {
35
+ const root = mkdtempSync(join(tmpdir(), "streetjs-storage-contract-"));
36
+ tempRoots.push(root);
37
+ return new LocalStorageDriver({ root, clock: fixedClock });
38
+ }
39
+ test.after(() => {
40
+ for (const root of tempRoots) {
41
+ rmSync(root, { recursive: true, force: true });
42
+ }
43
+ });
44
+ // ── As node:test cases (per-driver, per-check) ────────────────────────────────
45
+ registerStorageDriverContractTests("memory driver contract", makeMemoryDriver, test);
46
+ registerStorageDriverContractTests("local driver contract", makeLocalDriver, test);
47
+ // ── Programmatically (the storage:verify / Property 19 consumption path) ──────
48
+ test("runStorageDriverContract reports a full pass for the memory driver", async () => {
49
+ const report = await runStorageDriverContract(makeMemoryDriver);
50
+ assert.equal(report.driver, "memory");
51
+ assert.equal(report.passed, true);
52
+ assert.equal(report.results.length, storageDriverContractChecks.length);
53
+ assert.ok(report.results.every((result) => result.passed), `all checks must pass, got: ${JSON.stringify(report.results)}`);
54
+ });
55
+ test("runStorageDriverContract reports a full pass for the local driver", async () => {
56
+ const report = await runStorageDriverContract(makeLocalDriver);
57
+ assert.equal(report.driver, "local");
58
+ assert.equal(report.passed, true);
59
+ assert.equal(report.results.length, storageDriverContractChecks.length);
60
+ assert.ok(report.results.every((result) => result.passed), `all checks must pass, got: ${JSON.stringify(report.results)}`);
61
+ });
62
+ test("a non-conforming driver is reported as failed, not thrown", async () => {
63
+ // A driver that always reports a missing object exists violates the
64
+ // not-found and round-trip checks; the runner must capture this as failures
65
+ // rather than throwing.
66
+ const brokenDriver = {
67
+ name: "broken",
68
+ async put(key, bytes) {
69
+ return {
70
+ key,
71
+ size: bytes.byteLength,
72
+ contentType: "application/octet-stream",
73
+ etag: "x",
74
+ checksum: "x",
75
+ accessLevel: "private",
76
+ createdAt: 0,
77
+ updatedAt: 0,
78
+ custom: {},
79
+ };
80
+ },
81
+ async get() {
82
+ return { found: false };
83
+ },
84
+ async exists() {
85
+ return false;
86
+ },
87
+ async delete() { },
88
+ async stat() {
89
+ return null;
90
+ },
91
+ async list() {
92
+ return [];
93
+ },
94
+ async putStream(key, _stream, _metadata) {
95
+ return this.put(key, new Uint8Array(), {});
96
+ },
97
+ async getStream() {
98
+ throw new Error("unsupported");
99
+ },
100
+ };
101
+ const report = await runStorageDriverContract(() => brokenDriver);
102
+ assert.equal(report.driver, "broken");
103
+ assert.equal(report.passed, false);
104
+ // existence and byte round-trip must fail (get always reports not-found);
105
+ // the two not-found checks and metadata shape still pass.
106
+ const failed = report.results.filter((result) => !result.passed).map((r) => r.name);
107
+ assert.ok(failed.some((name) => name.startsWith("existence")), "existence check should fail for the broken driver");
108
+ assert.ok(failed.some((name) => name.startsWith("byte round-trip")), "byte round-trip check should fail for the broken driver");
109
+ });
110
+ //# sourceMappingURL=contract.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.test.js","sourceRoot":"","sources":["../../src/tests/contract.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=directory.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directory.test.d.ts","sourceRoot":"","sources":["../../src/tests/directory.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,125 @@
1
+ // Unit tests for the Directory API wired into the storage facade (task 17.1).
2
+ //
3
+ // Verifies the Requirement 15 semantics over the zero-dependency `memory`
4
+ // provider, exercised through `storage.directory`:
5
+ //
6
+ // - mkdir(path) makes the path available as a directory prefix (15.1).
7
+ // - listDirectory(path) returns only the IMMEDIATE children, collapsing
8
+ // deeper keys into a single sub-directory entry (15.2).
9
+ // - removeDirectory(path) removes every object under the prefix (15.3), and is
10
+ // a success no-op returning { removed: false } for an empty/missing prefix
11
+ // (15.6).
12
+ // - walk(path) returns every object key beneath the prefix (15.4).
13
+ //
14
+ // Uses the Node.js built-in test runner (node:test); executed via
15
+ // `node --test dist/tests/*.test.js`.
16
+ //
17
+ // Requirements: 15.1, 15.2, 15.3, 15.4, 15.5, 15.6
18
+ import test from "node:test";
19
+ import assert from "node:assert/strict";
20
+ import { createStorage } from "../facade.js";
21
+ import { MemoryStorageDriver } from "../drivers/memory.js";
22
+ /** Build a facade backed by a fresh in-memory driver. */
23
+ function makeStorage() {
24
+ const driver = new MemoryStorageDriver({});
25
+ return createStorage({ provider: "memory", driver });
26
+ }
27
+ /** Seed the store with a small hierarchy of objects. */
28
+ async function seed(storage) {
29
+ await storage.put("photos/a.jpg", "a");
30
+ await storage.put("photos/b.jpg", "bb");
31
+ await storage.put("photos/2024/c.jpg", "ccc");
32
+ await storage.put("photos/2024/holidays/d.jpg", "dddd");
33
+ await storage.put("docs/readme.txt", "hello");
34
+ }
35
+ test("directory getter returns a working, cached DirectoryApi", () => {
36
+ const storage = makeStorage();
37
+ const dir = storage.directory;
38
+ assert.equal(typeof dir.mkdir, "function");
39
+ assert.equal(typeof dir.listDirectory, "function");
40
+ assert.equal(typeof dir.removeDirectory, "function");
41
+ assert.equal(typeof dir.walk, "function");
42
+ // Same instance is reused across accesses (lazily constructed once).
43
+ assert.equal(storage.directory, dir);
44
+ });
45
+ test("mkdir makes the path available as a directory prefix (15.1)", async () => {
46
+ const storage = makeStorage();
47
+ await storage.directory.mkdir("uploads");
48
+ // The marker key exists so the empty directory is discoverable.
49
+ assert.equal(await storage.exists("uploads/"), true);
50
+ // A freshly-made directory has no child entries yet.
51
+ const listing = await storage.directory.listDirectory("uploads");
52
+ assert.deepEqual(listing, []);
53
+ });
54
+ test("mkdir on the root/empty path is a no-op (15.1)", async () => {
55
+ const storage = makeStorage();
56
+ await storage.directory.mkdir("");
57
+ await storage.directory.mkdir("/");
58
+ // No marker keys were written for the root.
59
+ const keys = await storage.directory.walk("");
60
+ assert.deepEqual(keys, []);
61
+ });
62
+ test("listDirectory returns only immediate children (15.2)", async () => {
63
+ const storage = makeStorage();
64
+ await seed(storage);
65
+ const listing = await storage.directory.listDirectory("photos");
66
+ const keys = listing.map((item) => item.key).sort();
67
+ // Immediate children of photos/: two files and one sub-directory entry;
68
+ // deeper keys (photos/2024/holidays/...) collapse into photos/2024/.
69
+ assert.deepEqual(keys, ["photos/2024/", "photos/a.jpg", "photos/b.jpg"]);
70
+ // The sub-directory entry is synthesized with size 0.
71
+ const subdir = listing.find((item) => item.key === "photos/2024/");
72
+ assert.equal(subdir.size, 0);
73
+ // File entries carry their real byte sizes.
74
+ const fileA = listing.find((item) => item.key === "photos/a.jpg");
75
+ assert.equal(fileA.size, 1);
76
+ const fileB = listing.find((item) => item.key === "photos/b.jpg");
77
+ assert.equal(fileB.size, 2);
78
+ });
79
+ test("listDirectory accepts leading/trailing delimiters equivalently (15.2)", async () => {
80
+ const storage = makeStorage();
81
+ await seed(storage);
82
+ const a = (await storage.directory.listDirectory("photos")).map((i) => i.key).sort();
83
+ const b = (await storage.directory.listDirectory("/photos/")).map((i) => i.key).sort();
84
+ assert.deepEqual(a, b);
85
+ });
86
+ test("walk returns every object key beneath the prefix (15.4)", async () => {
87
+ const storage = makeStorage();
88
+ await seed(storage);
89
+ const keys = (await storage.directory.walk("photos")).sort();
90
+ assert.deepEqual(keys, [
91
+ "photos/2024/c.jpg",
92
+ "photos/2024/holidays/d.jpg",
93
+ "photos/a.jpg",
94
+ "photos/b.jpg",
95
+ ]);
96
+ // walk excludes the directory's own marker key.
97
+ await storage.directory.mkdir("photos");
98
+ const withMarker = (await storage.directory.walk("photos")).sort();
99
+ assert.equal(withMarker.includes("photos/"), false);
100
+ });
101
+ test("removeDirectory removes every object under the prefix (15.3)", async () => {
102
+ const storage = makeStorage();
103
+ await seed(storage);
104
+ const result = await storage.directory.removeDirectory("photos");
105
+ assert.deepEqual(result, { removed: true });
106
+ // Nothing remains beneath photos/.
107
+ assert.deepEqual(await storage.directory.walk("photos"), []);
108
+ assert.equal(await storage.exists("photos/a.jpg"), false);
109
+ assert.equal(await storage.exists("photos/2024/holidays/d.jpg"), false);
110
+ // Sibling directories are untouched.
111
+ assert.equal(await storage.exists("docs/readme.txt"), true);
112
+ });
113
+ test("removeDirectory of an empty/missing prefix is a success no-op (15.6)", async () => {
114
+ const storage = makeStorage();
115
+ await seed(storage);
116
+ // Missing prefix: no objects removed, success result, siblings intact.
117
+ const missing = await storage.directory.removeDirectory("does-not-exist");
118
+ assert.deepEqual(missing, { removed: false });
119
+ assert.equal(await storage.exists("docs/readme.txt"), true);
120
+ // Removing twice: second call finds nothing and reports removed: false.
121
+ await storage.directory.removeDirectory("docs");
122
+ const second = await storage.directory.removeDirectory("docs");
123
+ assert.deepEqual(second, { removed: false });
124
+ });
125
+ //# sourceMappingURL=directory.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directory.test.js","sourceRoot":"","sources":["../../src/tests/directory.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=errors.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.test.d.ts","sourceRoot":"","sources":["../../src/tests/errors.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,93 @@
1
+ // Unit tests for the typed error hierarchy of @streetjs/storage.
2
+ //
3
+ // Verifies that every concrete error subclass derives from both StorageError
4
+ // and the native Error (so consumers can catch the whole family or discriminate
5
+ // on a subclass), that each carries its descriptive typed fields, and that each
6
+ // sets `name` correctly. Uses the Node.js built-in test runner (node:test) and
7
+ // is executed via `node --test dist/tests/*.test.js`.
8
+ //
9
+ // Requirements: 1.5, 9.4, 11.3
10
+ import test from "node:test";
11
+ import assert from "node:assert/strict";
12
+ import { StorageError, StorageConfigError, NotFoundError, ValidationError, AuthorizationError, UnsupportedImageError, } from "../index.js";
13
+ test("StorageError is a native Error and sets its name", () => {
14
+ const err = new StorageError("boom");
15
+ assert.ok(err instanceof Error);
16
+ assert.ok(err instanceof StorageError);
17
+ assert.equal(err.name, "StorageError");
18
+ assert.equal(err.message, "boom");
19
+ });
20
+ test("StorageError carries an optional cause", () => {
21
+ const underlying = new Error("root cause");
22
+ const err = new StorageError("wrapped", { cause: underlying });
23
+ assert.equal(err.cause, underlying);
24
+ });
25
+ test("StorageConfigError is instanceof StorageError and Error", () => {
26
+ const err = new StorageConfigError("bad config", { provider: "s3" });
27
+ assert.ok(err instanceof Error);
28
+ assert.ok(err instanceof StorageError);
29
+ assert.ok(err instanceof StorageConfigError);
30
+ });
31
+ test("StorageConfigError carries provider and name", () => {
32
+ const err = new StorageConfigError("unknown provider", { provider: "nope" });
33
+ assert.equal(err.name, "StorageConfigError");
34
+ assert.equal(err.provider, "nope");
35
+ });
36
+ test("NotFoundError is instanceof StorageError and Error", () => {
37
+ const err = new NotFoundError("photos/1.png");
38
+ assert.ok(err instanceof Error);
39
+ assert.ok(err instanceof StorageError);
40
+ assert.ok(err instanceof NotFoundError);
41
+ });
42
+ test("NotFoundError carries key, name, and default message", () => {
43
+ const err = new NotFoundError("photos/1.png");
44
+ assert.equal(err.name, "NotFoundError");
45
+ assert.equal(err.key, "photos/1.png");
46
+ assert.equal(err.message, 'Object not found for key "photos/1.png"');
47
+ });
48
+ test("ValidationError is instanceof StorageError and Error", () => {
49
+ const err = new ValidationError("file too large");
50
+ assert.ok(err instanceof Error);
51
+ assert.ok(err instanceof StorageError);
52
+ assert.ok(err instanceof ValidationError);
53
+ });
54
+ test("ValidationError carries validationError, optional key, and name", () => {
55
+ const err = new ValidationError("file too large", { key: "uploads/big.zip" });
56
+ assert.equal(err.name, "ValidationError");
57
+ assert.equal(err.validationError, "file too large");
58
+ assert.equal(err.key, "uploads/big.zip");
59
+ assert.equal(err.message, "Upload validation failed: file too large");
60
+ });
61
+ test("AuthorizationError is instanceof StorageError and Error", () => {
62
+ const err = new AuthorizationError("denied");
63
+ assert.ok(err instanceof Error);
64
+ assert.ok(err instanceof StorageError);
65
+ assert.ok(err instanceof AuthorizationError);
66
+ });
67
+ test("AuthorizationError carries key, operation, accessLevel, and name", () => {
68
+ const err = new AuthorizationError("access denied", {
69
+ key: "private/secret.txt",
70
+ operation: "read",
71
+ accessLevel: "private",
72
+ });
73
+ assert.equal(err.name, "AuthorizationError");
74
+ assert.equal(err.key, "private/secret.txt");
75
+ assert.equal(err.operation, "read");
76
+ assert.equal(err.accessLevel, "private");
77
+ });
78
+ test("UnsupportedImageError is instanceof StorageError and Error", () => {
79
+ const err = new UnsupportedImageError("cannot process");
80
+ assert.ok(err instanceof Error);
81
+ assert.ok(err instanceof StorageError);
82
+ assert.ok(err instanceof UnsupportedImageError);
83
+ });
84
+ test("UnsupportedImageError carries format, key, and name", () => {
85
+ const err = new UnsupportedImageError("unsupported format", {
86
+ format: "image/tiff",
87
+ key: "images/scan.tiff",
88
+ });
89
+ assert.equal(err.name, "UnsupportedImageError");
90
+ assert.equal(err.format, "image/tiff");
91
+ assert.equal(err.key, "images/scan.tiff");
92
+ });
93
+ //# sourceMappingURL=errors.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.test.js","sourceRoot":"","sources":["../../src/tests/errors.test.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,EAAE;AACF,6EAA6E;AAC7E,gFAAgF;AAChF,gFAAgF;AAChF,+EAA+E;AAC/E,sDAAsD;AACtD,EAAE;AACF,+BAA+B;AAE/B,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AAExC,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,aAAa,CAAC;AAErB,IAAI,CAAC,kDAAkD,EAAE,GAAG,EAAE;IAC5D,MAAM,GAAG,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,CAAC,EAAE,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,CAAC,GAAG,YAAY,YAAY,CAAC,CAAC;IACvC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;IACvC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AACpC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,wCAAwC,EAAE,GAAG,EAAE;IAClD,MAAM,UAAU,GAAG,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC;IAC3C,MAAM,GAAG,GAAG,IAAI,YAAY,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;IAC/D,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;AACtC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,yDAAyD,EAAE,GAAG,EAAE;IACnE,MAAM,GAAG,GAAG,IAAI,kBAAkB,CAAC,YAAY,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IACrE,MAAM,CAAC,EAAE,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,CAAC,GAAG,YAAY,YAAY,CAAC,CAAC;IACvC,MAAM,CAAC,EAAE,CAAC,GAAG,YAAY,kBAAkB,CAAC,CAAC;AAC/C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,8CAA8C,EAAE,GAAG,EAAE;IACxD,MAAM,GAAG,GAAG,IAAI,kBAAkB,CAAC,kBAAkB,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7E,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC;IAC7C,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AACrC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,oDAAoD,EAAE,GAAG,EAAE;IAC9D,MAAM,GAAG,GAAG,IAAI,aAAa,CAAC,cAAc,CAAC,CAAC;IAC9C,MAAM,CAAC,EAAE,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,CAAC,GAAG,YAAY,YAAY,CAAC,CAAC;IACvC,MAAM,CAAC,EAAE,CAAC,GAAG,YAAY,aAAa,CAAC,CAAC;AAC1C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,sDAAsD,EAAE,GAAG,EAAE;IAChE,MAAM,GAAG,GAAG,IAAI,aAAa,CAAC,cAAc,CAAC,CAAC;IAC9C,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;IACxC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IACtC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,yCAAyC,CAAC,CAAC;AACvE,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,sDAAsD,EAAE,GAAG,EAAE;IAChE,MAAM,GAAG,GAAG,IAAI,eAAe,CAAC,gBAAgB,CAAC,CAAC;IAClD,MAAM,CAAC,EAAE,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,CAAC,GAAG,YAAY,YAAY,CAAC,CAAC;IACvC,MAAM,CAAC,EAAE,CAAC,GAAG,YAAY,eAAe,CAAC,CAAC;AAC5C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,iEAAiE,EAAE,GAAG,EAAE;IAC3E,MAAM,GAAG,GAAG,IAAI,eAAe,CAAC,gBAAgB,EAAE,EAAE,GAAG,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAC9E,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC;IAC1C,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,eAAe,EAAE,gBAAgB,CAAC,CAAC;IACpD,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;IACzC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,0CAA0C,CAAC,CAAC;AACxE,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,yDAAyD,EAAE,GAAG,EAAE;IACnE,MAAM,GAAG,GAAG,IAAI,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,CAAC,EAAE,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,CAAC,GAAG,YAAY,YAAY,CAAC,CAAC;IACvC,MAAM,CAAC,EAAE,CAAC,GAAG,YAAY,kBAAkB,CAAC,CAAC;AAC/C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,kEAAkE,EAAE,GAAG,EAAE;IAC5E,MAAM,GAAG,GAAG,IAAI,kBAAkB,CAAC,eAAe,EAAE;QAClD,GAAG,EAAE,oBAAoB;QACzB,SAAS,EAAE,MAAM;QACjB,WAAW,EAAE,SAAS;KACvB,CAAC,CAAC;IACH,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC;IAC7C,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC;IAC5C,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACpC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;AAC3C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,4DAA4D,EAAE,GAAG,EAAE;IACtE,MAAM,GAAG,GAAG,IAAI,qBAAqB,CAAC,gBAAgB,CAAC,CAAC;IACxD,MAAM,CAAC,EAAE,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,CAAC,GAAG,YAAY,YAAY,CAAC,CAAC;IACvC,MAAM,CAAC,EAAE,CAAC,GAAG,YAAY,qBAAqB,CAAC,CAAC;AAClD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,qDAAqD,EAAE,GAAG,EAAE;IAC/D,MAAM,GAAG,GAAG,IAAI,qBAAqB,CAAC,oBAAoB,EAAE;QAC1D,MAAM,EAAE,YAAY;QACpB,GAAG,EAAE,kBAAkB;KACxB,CAAC,CAAC;IACH,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,uBAAuB,CAAC,CAAC;IAChD,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACvC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC;AAC5C,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=events-bridge.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events-bridge.test.d.ts","sourceRoot":"","sources":["../../src/tests/events-bridge.test.ts"],"names":[],"mappings":""}