@warlock.js/core 5.30.0 → 5.31.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 (797) hide show
  1. package/CHANGELOG.md +142 -36
  2. package/README.md +28 -23
  3. package/bin/source-load-hook.mjs +63 -0
  4. package/bin/warlock.js +102 -42
  5. package/esm/cli/commands/add.command.mjs +4 -2
  6. package/esm/cli/commands/add.command.mjs.map +1 -1
  7. package/esm/cli/commands/agents-md/agents-md-command.action.mjs +69 -0
  8. package/esm/cli/commands/agents-md/agents-md-command.action.mjs.map +1 -0
  9. package/esm/cli/commands/agents-md.command.mjs +38 -0
  10. package/esm/cli/commands/agents-md.command.mjs.map +1 -0
  11. package/esm/cli/commands/board/board-command.action.mjs +279 -0
  12. package/esm/cli/commands/board/board-command.action.mjs.map +1 -0
  13. package/esm/cli/commands/board.command.mjs +78 -0
  14. package/esm/cli/commands/board.command.mjs.map +1 -0
  15. package/esm/cli/commands/build.command.mjs +6 -1
  16. package/esm/cli/commands/build.command.mjs.map +1 -1
  17. package/esm/cli/commands/check/check-command.action.mjs +57 -0
  18. package/esm/cli/commands/check/check-command.action.mjs.map +1 -0
  19. package/esm/cli/commands/check/child-typecheck.mjs +66 -0
  20. package/esm/cli/commands/check/child-typecheck.mjs.map +1 -0
  21. package/esm/cli/commands/check/format-problems.mjs +43 -0
  22. package/esm/cli/commands/check/format-problems.mjs.map +1 -0
  23. package/esm/cli/commands/check/typecheck-command.action.mjs +61 -0
  24. package/esm/cli/commands/check/typecheck-command.action.mjs.map +1 -0
  25. package/esm/cli/commands/check.command.mjs +50 -0
  26. package/esm/cli/commands/check.command.mjs.map +1 -0
  27. package/esm/cli/commands/dev-server.command.mjs +9 -1
  28. package/esm/cli/commands/dev-server.command.mjs.map +1 -1
  29. package/esm/cli/commands/doctor/boot-for-diagnostics.mjs +8 -3
  30. package/esm/cli/commands/doctor/boot-for-diagnostics.mjs.map +1 -1
  31. package/esm/cli/commands/doctor/check.types.d.mts +76 -0
  32. package/esm/cli/commands/doctor/check.types.d.mts.map +1 -0
  33. package/esm/cli/commands/doctor/checks/config.check.mjs +1 -0
  34. package/esm/cli/commands/doctor/checks/config.check.mjs.map +1 -1
  35. package/esm/cli/commands/doctor/checks/connectors.check.mjs +2 -0
  36. package/esm/cli/commands/doctor/checks/connectors.check.mjs.map +1 -1
  37. package/esm/cli/commands/doctor/checks/handler-signature.check.mjs +1 -0
  38. package/esm/cli/commands/doctor/checks/handler-signature.check.mjs.map +1 -1
  39. package/esm/cli/commands/doctor/checks/health.check.mjs +3 -0
  40. package/esm/cli/commands/doctor/checks/health.check.mjs.map +1 -1
  41. package/esm/cli/commands/doctor/checks/jwt-secret.check.mjs +1 -0
  42. package/esm/cli/commands/doctor/checks/jwt-secret.check.mjs.map +1 -1
  43. package/esm/cli/commands/doctor/checks/locales-ts-deprecated.check.mjs +1 -0
  44. package/esm/cli/commands/doctor/checks/locales-ts-deprecated.check.mjs.map +1 -1
  45. package/esm/cli/commands/doctor/checks/optional-peers.check.mjs +1 -0
  46. package/esm/cli/commands/doctor/checks/optional-peers.check.mjs.map +1 -1
  47. package/esm/cli/commands/doctor/checks/release-hygiene.check.mjs +4 -0
  48. package/esm/cli/commands/doctor/checks/release-hygiene.check.mjs.map +1 -1
  49. package/esm/cli/commands/doctor/checks/routes.check.mjs +3 -0
  50. package/esm/cli/commands/doctor/checks/routes.check.mjs.map +1 -1
  51. package/esm/cli/commands/doctor/doctor-command.action.mjs +14 -6
  52. package/esm/cli/commands/doctor/doctor-command.action.mjs.map +1 -1
  53. package/esm/cli/commands/doctor/format-report.mjs +30 -2
  54. package/esm/cli/commands/doctor/format-report.mjs.map +1 -1
  55. package/esm/cli/commands/doctor.command.mjs +4 -0
  56. package/esm/cli/commands/doctor.command.mjs.map +1 -1
  57. package/esm/cli/commands/explain/explain-command.action.mjs +64 -0
  58. package/esm/cli/commands/explain/explain-command.action.mjs.map +1 -0
  59. package/esm/cli/commands/explain.command.mjs +23 -0
  60. package/esm/cli/commands/explain.command.mjs.map +1 -0
  61. package/esm/cli/commands/generate/generate.command.mjs +124 -124
  62. package/esm/cli/commands/generate/generate.command.mjs.map +1 -1
  63. package/esm/cli/commands/generate/generators/endpoint.generator.mjs +311 -0
  64. package/esm/cli/commands/generate/generators/endpoint.generator.mjs.map +1 -0
  65. package/esm/cli/commands/generate/generators/migration.generator.mjs +1 -1
  66. package/esm/cli/commands/generate/generators/migration.generator.mjs.map +1 -1
  67. package/esm/cli/commands/generate/generators/model.generator.mjs +1 -1
  68. package/esm/cli/commands/generate/templates/endpoint-stubs.mjs +341 -0
  69. package/esm/cli/commands/generate/templates/endpoint-stubs.mjs.map +1 -0
  70. package/esm/cli/commands/generate/templates/stubs.mjs +19 -6
  71. package/esm/cli/commands/generate/templates/stubs.mjs.map +1 -1
  72. package/esm/cli/commands/generate/utils/endpoint-schema.mjs +137 -0
  73. package/esm/cli/commands/generate/utils/endpoint-schema.mjs.map +1 -0
  74. package/esm/cli/commands/generate/utils/name-parser.mjs +1 -1
  75. package/esm/cli/commands/generate/utils/name-parser.mjs.map +1 -1
  76. package/esm/cli/commands/generate/utils/prompt.mjs.map +1 -1
  77. package/esm/cli/commands/generate/utils/writer.mjs +38 -13
  78. package/esm/cli/commands/generate/utils/writer.mjs.map +1 -1
  79. package/esm/cli/commands/inspect/inspect-command.action.mjs +72 -0
  80. package/esm/cli/commands/inspect/inspect-command.action.mjs.map +1 -0
  81. package/esm/cli/commands/inspect.command.mjs +39 -0
  82. package/esm/cli/commands/inspect.command.mjs.map +1 -0
  83. package/esm/cli/commands/mcp/mcp-command.action.mjs +103 -0
  84. package/esm/cli/commands/mcp/mcp-command.action.mjs.map +1 -0
  85. package/esm/cli/commands/mcp.command.mjs +76 -0
  86. package/esm/cli/commands/mcp.command.mjs.map +1 -0
  87. package/esm/cli/commands/openapi-generator.action.mjs.map +1 -1
  88. package/esm/cli/commands/openapi-generator.command.mjs.map +1 -1
  89. package/esm/cli/commands/postman-generator.action.mjs.map +1 -1
  90. package/esm/cli/commands/postman-generator.command.mjs.map +1 -1
  91. package/esm/cli/commands/routes/routes-diff.action.mjs +1 -1
  92. package/esm/cli/commands/test.command.mjs +131 -0
  93. package/esm/cli/commands/test.command.mjs.map +1 -0
  94. package/esm/cli/commands/trace/trace-command.action.mjs +145 -0
  95. package/esm/cli/commands/trace/trace-command.action.mjs.map +1 -0
  96. package/esm/cli/commands/trace.command.mjs +60 -0
  97. package/esm/cli/commands/trace.command.mjs.map +1 -0
  98. package/esm/cli/commands/typecheck.command.mjs +40 -0
  99. package/esm/cli/commands/typecheck.command.mjs.map +1 -0
  100. package/esm/cli/commands/upgrade.command.mjs +46 -0
  101. package/esm/cli/commands/upgrade.command.mjs.map +1 -0
  102. package/esm/cli/flush-and-exit.mjs +34 -0
  103. package/esm/cli/flush-and-exit.mjs.map +1 -0
  104. package/esm/cli/framework-cli-commands.mjs +23 -1
  105. package/esm/cli/framework-cli-commands.mjs.map +1 -1
  106. package/esm/cli/parse-cli-args.mjs +1 -0
  107. package/esm/cli/parse-cli-args.mjs.map +1 -1
  108. package/esm/config/config-loader.d.mts.map +1 -1
  109. package/esm/config/config-loader.mjs +34 -13
  110. package/esm/config/config-loader.mjs.map +1 -1
  111. package/esm/config/config-schema.d.mts +67 -0
  112. package/esm/config/config-schema.d.mts.map +1 -0
  113. package/esm/config/config-schema.mjs +77 -0
  114. package/esm/config/config-schema.mjs.map +1 -0
  115. package/esm/config/index.d.mts +6 -0
  116. package/esm/config/index.mjs +1 -0
  117. package/esm/connectors/assert-no-reserved-connector-names.d.mts.map +1 -1
  118. package/esm/connectors/assert-no-reserved-connector-names.mjs +2 -1
  119. package/esm/connectors/assert-no-reserved-connector-names.mjs.map +1 -1
  120. package/esm/connectors/assert-unique-connector-names.d.mts.map +1 -1
  121. package/esm/connectors/assert-unique-connector-names.mjs +26 -2
  122. package/esm/connectors/assert-unique-connector-names.mjs.map +1 -1
  123. package/esm/connectors/http-connector.d.mts.map +1 -1
  124. package/esm/connectors/http-connector.mjs +3 -2
  125. package/esm/connectors/http-connector.mjs.map +1 -1
  126. package/esm/connectors/single-server-warnings.mjs.map +1 -1
  127. package/esm/connectors/socket-connector.d.mts.map +1 -1
  128. package/esm/connectors/socket-connector.mjs.map +1 -1
  129. package/esm/container/index.d.mts.map +1 -1
  130. package/esm/container/index.mjs.map +1 -1
  131. package/esm/database/migrate-action.mjs.map +1 -1
  132. package/esm/database/models/database-log/database-log.d.mts +0 -28
  133. package/esm/database/models/database-log/database-log.d.mts.map +1 -1
  134. package/esm/database/seeds/seeder.errors.d.mts +4 -0
  135. package/esm/database/seeds/seeder.errors.d.mts.map +1 -1
  136. package/esm/database/seeds/seeder.errors.mjs +2 -0
  137. package/esm/database/seeds/seeder.errors.mjs.map +1 -1
  138. package/esm/dev-server/boot-precondition-error.mjs +1 -0
  139. package/esm/dev-server/boot-precondition-error.mjs.map +1 -1
  140. package/esm/dev-server/create-worker.mjs +15 -9
  141. package/esm/dev-server/create-worker.mjs.map +1 -1
  142. package/esm/dev-server/dev-agent-tooling.mjs +135 -0
  143. package/esm/dev-server/dev-agent-tooling.mjs.map +1 -0
  144. package/esm/dev-server/dev-logger.mjs.map +1 -1
  145. package/esm/dev-server/development-server.mjs +8 -0
  146. package/esm/dev-server/development-server.mjs.map +1 -1
  147. package/esm/dev-server/files-orchestrator.mjs +4 -5
  148. package/esm/dev-server/files-orchestrator.mjs.map +1 -1
  149. package/esm/dev-server/files-watcher.mjs +1 -1
  150. package/esm/dev-server/health-checker/checkers/eslint-health-checker.mjs +2 -3
  151. package/esm/dev-server/health-checker/checkers/eslint-health-checker.mjs.map +1 -1
  152. package/esm/dev-server/health-checker/checkers/oxlint-health-checker.mjs +33 -0
  153. package/esm/dev-server/health-checker/checkers/oxlint-health-checker.mjs.map +1 -0
  154. package/esm/dev-server/health-checker/default-health-checkers.mjs +31 -0
  155. package/esm/dev-server/health-checker/default-health-checkers.mjs.map +1 -0
  156. package/esm/dev-server/health-checker/file-health-checker.contract.d.mts +9 -3
  157. package/esm/dev-server/health-checker/file-health-checker.contract.d.mts.map +1 -1
  158. package/esm/dev-server/health-checker/files-healthcare.manager.mjs +15 -4
  159. package/esm/dev-server/health-checker/files-healthcare.manager.mjs.map +1 -1
  160. package/esm/dev-server/health-checker/oxlint-runner.mjs +302 -0
  161. package/esm/dev-server/health-checker/oxlint-runner.mjs.map +1 -0
  162. package/esm/dev-server/health-checker/workers/oxlint-health.worker.d.mts +1 -0
  163. package/esm/dev-server/health-checker/workers/oxlint-health.worker.mjs +42 -0
  164. package/esm/dev-server/health-checker/workers/oxlint-health.worker.mjs.map +1 -0
  165. package/esm/dev-server/loader/loader-port-acks.mjs +1 -1
  166. package/esm/dev-server/loader/loader-port-acks.mjs.map +1 -1
  167. package/esm/dev-server/loader/register-loader.mjs +1 -1
  168. package/esm/dev-server/loader/register-loader.mjs.map +1 -1
  169. package/esm/dev-server/loader/resolve-hook.mjs +1 -1
  170. package/esm/dev-server/loader/transpile-cache.mjs +1 -1
  171. package/esm/dev-server/model-resource-typings.mjs.map +1 -1
  172. package/esm/dev-server/module-loader.mjs +1 -0
  173. package/esm/dev-server/module-loader.mjs.map +1 -1
  174. package/esm/dev-server/parse-imports.mjs +1 -1
  175. package/esm/dev-server/parse-imports.mjs.map +1 -1
  176. package/esm/dev-server/route-types-publisher.mjs +1 -1
  177. package/esm/dev-server/start-development-server.mjs.map +1 -1
  178. package/esm/dev-server/translation-keys-sources.mjs +1 -1
  179. package/esm/dev-server/translation-keys-sources.mjs.map +1 -1
  180. package/esm/dev-server/tsconfig-manager.mjs.map +1 -1
  181. package/esm/dev-server/type-generator.mjs +3 -3
  182. package/esm/dev-server/type-generator.mjs.map +1 -1
  183. package/esm/dev-server/types.d.mts.map +1 -1
  184. package/esm/errors/container-key-missing-error.mjs +1 -0
  185. package/esm/errors/container-key-missing-error.mjs.map +1 -1
  186. package/esm/errors/error-codes.d.mts +653 -0
  187. package/esm/errors/error-codes.d.mts.map +1 -0
  188. package/esm/errors/error-codes.mjs +634 -0
  189. package/esm/errors/error-codes.mjs.map +1 -0
  190. package/esm/errors/esbuild-binary-missing-error.mjs +1 -0
  191. package/esm/errors/esbuild-binary-missing-error.mjs.map +1 -1
  192. package/esm/errors/index.d.mts +3 -1
  193. package/esm/errors/index.mjs +3 -1
  194. package/esm/errors/unknown-locale-error.mjs +1 -0
  195. package/esm/errors/unknown-locale-error.mjs.map +1 -1
  196. package/esm/errors/warlock-error.d.mts +23 -0
  197. package/esm/errors/warlock-error.d.mts.map +1 -0
  198. package/esm/errors/warlock-error.mjs +22 -0
  199. package/esm/errors/warlock-error.mjs.map +1 -0
  200. package/esm/generations/add-command.action.mjs +19 -3
  201. package/esm/generations/add-command.action.mjs.map +1 -1
  202. package/esm/generations/features/access.feature.mjs +1 -1
  203. package/esm/generations/features/access.feature.mjs.map +1 -1
  204. package/esm/generations/features/bull-board.feature.mjs +1 -1
  205. package/esm/generations/features/bull-board.feature.mjs.map +1 -1
  206. package/esm/generations/features/mysql.feature.mjs.map +1 -1
  207. package/esm/generations/features/notifications.feature.mjs +5 -2
  208. package/esm/generations/features/notifications.feature.mjs.map +1 -1
  209. package/esm/generations/features/queue.feature.mjs +1 -1
  210. package/esm/generations/features/queue.feature.mjs.map +1 -1
  211. package/esm/generations/features/react-email.feature.mjs +1 -1
  212. package/esm/generations/features/react-email.feature.mjs.map +1 -1
  213. package/esm/generations/features/shadcn.feature.mjs +1 -1
  214. package/esm/generations/features/shadcn.feature.mjs.map +1 -1
  215. package/esm/generations/features/shared/link-ai-package-import.mjs +1 -1
  216. package/esm/generations/features/shared/link-ai-package-import.mjs.map +1 -1
  217. package/esm/generations/features/shared/merge-web-sitemap-config.mjs.map +1 -1
  218. package/esm/generations/features/shared/patch-tsconfig-include.mjs +1 -1
  219. package/esm/generations/features/shared/patch-tsconfig-include.mjs.map +1 -1
  220. package/esm/generations/features/shared/relocate-conflicting-home-route.mjs +1 -1
  221. package/esm/generations/features/shared/relocate-conflicting-home-route.mjs.map +1 -1
  222. package/esm/generations/features/sitemap.feature.mjs +1 -1
  223. package/esm/generations/features/sitemap.feature.mjs.map +1 -1
  224. package/esm/generations/features/tailwind.feature.mjs +1 -1
  225. package/esm/generations/features/tailwind.feature.mjs.map +1 -1
  226. package/esm/generations/features/test.feature.mjs +11 -6
  227. package/esm/generations/features/test.feature.mjs.map +1 -1
  228. package/esm/generations/features/web.feature.mjs +1 -1
  229. package/esm/generations/features/web.feature.mjs.map +1 -1
  230. package/esm/generations/generation-fs.mjs +73 -0
  231. package/esm/generations/generation-fs.mjs.map +1 -0
  232. package/esm/generations/generation-run.mjs +185 -0
  233. package/esm/generations/generation-run.mjs.map +1 -0
  234. package/esm/generations/stubs.mjs +155 -13
  235. package/esm/generations/stubs.mjs.map +1 -1
  236. package/esm/http/bounded-stream-queue.d.mts +10 -0
  237. package/esm/http/bounded-stream-queue.d.mts.map +1 -0
  238. package/esm/http/bounded-stream-queue.mjs +97 -0
  239. package/esm/http/bounded-stream-queue.mjs.map +1 -0
  240. package/esm/http/build-rate-limit-options.d.mts +13 -0
  241. package/esm/http/build-rate-limit-options.d.mts.map +1 -1
  242. package/esm/http/build-rate-limit-options.mjs.map +1 -1
  243. package/esm/http/conditional-request.d.mts +86 -0
  244. package/esm/http/conditional-request.d.mts.map +1 -0
  245. package/esm/http/conditional-request.mjs +121 -0
  246. package/esm/http/conditional-request.mjs.map +1 -0
  247. package/esm/http/csp.d.mts +2 -0
  248. package/esm/http/csp.d.mts.map +1 -1
  249. package/esm/http/csp.mjs +1 -0
  250. package/esm/http/csp.mjs.map +1 -1
  251. package/esm/http/csrf-origin-policy.mjs.map +1 -1
  252. package/esm/http/database/RequestLog.d.mts +24 -84
  253. package/esm/http/database/RequestLog.d.mts.map +1 -1
  254. package/esm/http/errors/errors.d.mts +2 -0
  255. package/esm/http/errors/errors.d.mts.map +1 -1
  256. package/esm/http/errors/errors.mjs +1 -0
  257. package/esm/http/errors/errors.mjs.map +1 -1
  258. package/esm/http/escape-header-value.d.mts +18 -0
  259. package/esm/http/escape-header-value.d.mts.map +1 -0
  260. package/esm/http/escape-header-value.mjs +27 -0
  261. package/esm/http/escape-header-value.mjs.map +1 -0
  262. package/esm/http/flush-pending-cookies.mjs.map +1 -1
  263. package/esm/http/index.d.mts +5 -2
  264. package/esm/http/index.mjs +4 -1
  265. package/esm/http/lazy-static.mjs +194 -0
  266. package/esm/http/lazy-static.mjs.map +1 -0
  267. package/esm/http/middleware/idempotency.middleware.mjs.map +1 -1
  268. package/esm/http/plugins.d.mts.map +1 -1
  269. package/esm/http/plugins.mjs +7 -4
  270. package/esm/http/plugins.mjs.map +1 -1
  271. package/esm/http/rate-limit-cache-store.mjs +2 -1
  272. package/esm/http/rate-limit-cache-store.mjs.map +1 -1
  273. package/esm/http/request-log-snapshot.d.mts +12 -5
  274. package/esm/http/request-log-snapshot.d.mts.map +1 -1
  275. package/esm/http/request-log-snapshot.mjs +83 -4
  276. package/esm/http/request-log-snapshot.mjs.map +1 -1
  277. package/esm/http/request.d.mts +2 -2
  278. package/esm/http/request.d.mts.map +1 -1
  279. package/esm/http/request.mjs +5 -4
  280. package/esm/http/request.mjs.map +1 -1
  281. package/esm/http/response.d.mts +11 -1
  282. package/esm/http/response.d.mts.map +1 -1
  283. package/esm/http/response.mjs +164 -76
  284. package/esm/http/response.mjs.map +1 -1
  285. package/esm/http/safe-redirect.d.mts +51 -0
  286. package/esm/http/safe-redirect.d.mts.map +1 -0
  287. package/esm/http/safe-redirect.mjs +80 -0
  288. package/esm/http/safe-redirect.mjs.map +1 -0
  289. package/esm/http/serialized.d.mts.map +1 -1
  290. package/esm/http/server.d.mts +3 -1
  291. package/esm/http/server.d.mts.map +1 -1
  292. package/esm/http/server.mjs +14 -4
  293. package/esm/http/server.mjs.map +1 -1
  294. package/esm/http/stream-transport.mjs +4 -2
  295. package/esm/http/stream-transport.mjs.map +1 -1
  296. package/esm/http/types.d.mts +44 -11
  297. package/esm/http/types.d.mts.map +1 -1
  298. package/esm/http/uploads/generate-image-variant.mjs +1 -1
  299. package/esm/http/uploads/generate-image-variants.d.mts +10 -7
  300. package/esm/http/uploads/generate-image-variants.d.mts.map +1 -1
  301. package/esm/http/uploads/generate-image-variants.mjs +61 -24
  302. package/esm/http/uploads/generate-image-variants.mjs.map +1 -1
  303. package/esm/http/uploads/image-variant-cache-entries.mjs +78 -0
  304. package/esm/http/uploads/image-variant-cache-entries.mjs.map +1 -0
  305. package/esm/http/uploads/image-variant-cache.mjs +72 -30
  306. package/esm/http/uploads/image-variant-cache.mjs.map +1 -1
  307. package/esm/http/uploads/image-variant-types.d.mts +2 -0
  308. package/esm/http/uploads/image-variant-types.d.mts.map +1 -1
  309. package/esm/http/uploads/image-variants-config-error.d.mts +3 -1
  310. package/esm/http/uploads/image-variants-config-error.d.mts.map +1 -1
  311. package/esm/http/uploads/image-variants-config-error.mjs +3 -2
  312. package/esm/http/uploads/image-variants-config-error.mjs.map +1 -1
  313. package/esm/http/uploads/load-variant-source.mjs +1 -1
  314. package/esm/http/uploads/load-variant-source.mjs.map +1 -1
  315. package/esm/http/uploads/purge-image-variants.d.mts +7 -2
  316. package/esm/http/uploads/purge-image-variants.d.mts.map +1 -1
  317. package/esm/http/uploads/purge-image-variants.mjs +16 -16
  318. package/esm/http/uploads/purge-image-variants.mjs.map +1 -1
  319. package/esm/http/uploads/remote-variant-source.mjs +115 -0
  320. package/esm/http/uploads/remote-variant-source.mjs.map +1 -0
  321. package/esm/http/uploads/resolve-image-variant.d.mts +3 -4
  322. package/esm/http/uploads/resolve-image-variant.d.mts.map +1 -1
  323. package/esm/http/uploads/resolve-image-variant.mjs +10 -18
  324. package/esm/http/uploads/resolve-image-variant.mjs.map +1 -1
  325. package/esm/http/uploads/resolve-image-variants-config.mjs +5 -3
  326. package/esm/http/uploads/resolve-image-variants-config.mjs.map +1 -1
  327. package/esm/http/uploads/resolve-remote-image-variant.mjs +89 -0
  328. package/esm/http/uploads/resolve-remote-image-variant.mjs.map +1 -0
  329. package/esm/http/uploads/trim-image-variant-cache.mjs +193 -0
  330. package/esm/http/uploads/trim-image-variant-cache.mjs.map +1 -0
  331. package/esm/http/uploads/uploaded-file.controller.d.mts +5 -3
  332. package/esm/http/uploads/uploaded-file.controller.d.mts.map +1 -1
  333. package/esm/http/uploads/uploaded-file.controller.mjs +16 -8
  334. package/esm/http/uploads/uploaded-file.controller.mjs.map +1 -1
  335. package/esm/http/uploads/variant-cache-key.mjs +1 -1
  336. package/esm/http/uploads-types.d.mts +6 -2
  337. package/esm/http/uploads-types.d.mts.map +1 -1
  338. package/esm/index.d.mts +17 -6
  339. package/esm/index.mjs +14 -3
  340. package/esm/localization/parse-locale-dictionary.d.mts +2 -0
  341. package/esm/localization/parse-locale-dictionary.d.mts.map +1 -1
  342. package/esm/localization/parse-locale-dictionary.mjs +1 -0
  343. package/esm/localization/parse-locale-dictionary.mjs.map +1 -1
  344. package/esm/mail/config.d.mts +12 -1
  345. package/esm/mail/config.d.mts.map +1 -1
  346. package/esm/mail/config.mjs +16 -1
  347. package/esm/mail/config.mjs.map +1 -1
  348. package/esm/mail/index.d.mts +1 -1
  349. package/esm/mail/index.mjs +1 -1
  350. package/esm/net/index.d.mts +2 -0
  351. package/esm/net/index.mjs +3 -0
  352. package/esm/openapi/build-openapi-document.d.mts.map +1 -1
  353. package/esm/openapi/build-openapi-document.mjs +8 -5
  354. package/esm/openapi/build-openapi-document.mjs.map +1 -1
  355. package/esm/openapi/error-responses.mjs +28 -2
  356. package/esm/openapi/error-responses.mjs.map +1 -1
  357. package/esm/openapi/postman/build-request-body.mjs.map +1 -1
  358. package/esm/openapi/postman/build-request-url.mjs.map +1 -1
  359. package/esm/openapi/postman/build-saved-responses.mjs.map +1 -1
  360. package/esm/openapi/postman/example-from-schema.d.mts.map +1 -1
  361. package/esm/openapi/postman/example-from-schema.mjs.map +1 -1
  362. package/esm/openapi/postman/openapi-to-postman-collection.d.mts.map +1 -1
  363. package/esm/openapi/postman/openapi-to-postman-collection.mjs.map +1 -1
  364. package/esm/openapi/postman/schema-refs.mjs.map +1 -1
  365. package/esm/openapi/postman/uuid-v5.mjs.map +1 -1
  366. package/esm/openapi/request-schemas.mjs.map +1 -1
  367. package/esm/openapi/response-schemas.mjs.map +1 -1
  368. package/esm/openapi/schema-registry.d.mts +1 -0
  369. package/esm/openapi/schema-registry.mjs.map +1 -1
  370. package/esm/openapi/security.mjs.map +1 -1
  371. package/esm/openapi/types.d.mts +3 -2
  372. package/esm/openapi/types.d.mts.map +1 -1
  373. package/esm/production/assert-generated-imports.mjs +1 -0
  374. package/esm/production/assert-generated-imports.mjs.map +1 -1
  375. package/esm/production/production-builder.mjs +12 -4
  376. package/esm/production/production-builder.mjs.map +1 -1
  377. package/esm/production/resolve-build-config.mjs +1 -0
  378. package/esm/production/resolve-build-config.mjs.map +1 -1
  379. package/esm/production/route-registration-child.mjs.map +1 -1
  380. package/esm/production/route-registration-snapshot.mjs.map +1 -1
  381. package/esm/repositories/contracts/query-builder.contract.d.mts.map +1 -1
  382. package/esm/repositories/contracts/types.d.mts.map +1 -1
  383. package/esm/repositories/repository.manager.mjs.map +1 -1
  384. package/esm/resource/resource.d.mts.map +1 -1
  385. package/esm/resource/resource.mjs.map +1 -1
  386. package/esm/resource/types.d.mts.map +1 -1
  387. package/esm/restful/restful.d.mts +5 -5
  388. package/esm/restful/restful.d.mts.map +1 -1
  389. package/esm/restful/restful.mjs.map +1 -1
  390. package/esm/router/build-route-rate-limit.mjs.map +1 -1
  391. package/esm/router/dev-dispatch.mjs +31 -12
  392. package/esm/router/dev-dispatch.mjs.map +1 -1
  393. package/esm/router/index.d.mts +4 -2
  394. package/esm/router/index.mjs +2 -0
  395. package/esm/router/log-request-lifecycle.mjs.map +1 -1
  396. package/esm/router/positional-handler-diagnostics.d.mts.map +1 -1
  397. package/esm/router/positional-handler-diagnostics.mjs.map +1 -1
  398. package/esm/router/resolve-route-rate-limit.mjs +47 -0
  399. package/esm/router/resolve-route-rate-limit.mjs.map +1 -0
  400. package/esm/router/resolve-route-validation.mjs +19 -0
  401. package/esm/router/resolve-route-validation.mjs.map +1 -0
  402. package/esm/router/route-guard-names.mjs +30 -0
  403. package/esm/router/route-guard-names.mjs.map +1 -0
  404. package/esm/router/route-name-taken-error.d.mts +14 -0
  405. package/esm/router/route-name-taken-error.d.mts.map +1 -0
  406. package/esm/router/route-name-taken-error.mjs +18 -0
  407. package/esm/router/route-name-taken-error.mjs.map +1 -0
  408. package/esm/router/router.d.mts +32 -13
  409. package/esm/router/router.d.mts.map +1 -1
  410. package/esm/router/router.mjs +71 -38
  411. package/esm/router/router.mjs.map +1 -1
  412. package/esm/router/types.d.mts +137 -17
  413. package/esm/router/types.d.mts.map +1 -1
  414. package/esm/router/unguarded-route-diagnostics.d.mts +40 -0
  415. package/esm/router/unguarded-route-diagnostics.d.mts.map +1 -0
  416. package/esm/router/unguarded-route-diagnostics.mjs +95 -0
  417. package/esm/router/unguarded-route-diagnostics.mjs.map +1 -0
  418. package/esm/storage/drivers/cloud-driver.d.mts.map +1 -1
  419. package/esm/storage/drivers/cloud-driver.mjs.map +1 -1
  420. package/esm/storage/drivers/local-driver.d.mts.map +1 -1
  421. package/esm/storage/drivers/local-driver.mjs.map +1 -1
  422. package/esm/storage/local-disk-roots.mjs +24 -0
  423. package/esm/storage/local-disk-roots.mjs.map +1 -0
  424. package/esm/storage/storage.d.mts +14 -0
  425. package/esm/storage/storage.d.mts.map +1 -1
  426. package/esm/storage/storage.mjs +22 -0
  427. package/esm/storage/storage.mjs.map +1 -1
  428. package/esm/storage/types.d.mts.map +1 -1
  429. package/esm/storage/utils/storage-not-initialized-error.d.mts +2 -0
  430. package/esm/storage/utils/storage-not-initialized-error.d.mts.map +1 -1
  431. package/esm/storage/utils/storage-not-initialized-error.mjs +1 -0
  432. package/esm/storage/utils/storage-not-initialized-error.mjs.map +1 -1
  433. package/esm/tests/authenticated-test-client.d.mts +32 -0
  434. package/esm/tests/authenticated-test-client.d.mts.map +1 -0
  435. package/esm/tests/authenticated-test-client.mjs +40 -0
  436. package/esm/tests/authenticated-test-client.mjs.map +1 -0
  437. package/esm/tests/factories.d.mts +59 -0
  438. package/esm/tests/factories.d.mts.map +1 -0
  439. package/esm/tests/factories.mjs +105 -0
  440. package/esm/tests/factories.mjs.map +1 -0
  441. package/esm/tests/fakes/cache-fake.d.mts +29 -0
  442. package/esm/tests/fakes/cache-fake.d.mts.map +1 -0
  443. package/esm/tests/fakes/cache-fake.mjs +79 -0
  444. package/esm/tests/fakes/cache-fake.mjs.map +1 -0
  445. package/esm/tests/fakes/clock-fake.d.mts +32 -0
  446. package/esm/tests/fakes/clock-fake.d.mts.map +1 -0
  447. package/esm/tests/fakes/clock-fake.mjs +69 -0
  448. package/esm/tests/fakes/clock-fake.mjs.map +1 -0
  449. package/esm/tests/fakes/fake-assertion-error.d.mts +13 -0
  450. package/esm/tests/fakes/fake-assertion-error.d.mts.map +1 -0
  451. package/esm/tests/fakes/fake-assertion-error.mjs +20 -0
  452. package/esm/tests/fakes/fake-assertion-error.mjs.map +1 -0
  453. package/esm/tests/fakes/ids-fake.d.mts +22 -0
  454. package/esm/tests/fakes/ids-fake.d.mts.map +1 -0
  455. package/esm/tests/fakes/ids-fake.mjs +57 -0
  456. package/esm/tests/fakes/ids-fake.mjs.map +1 -0
  457. package/esm/tests/fakes/index.d.mts +8 -0
  458. package/esm/tests/fakes/index.mjs +10 -0
  459. package/esm/tests/fakes/mail-fake.d.mts +41 -0
  460. package/esm/tests/fakes/mail-fake.d.mts.map +1 -0
  461. package/esm/tests/fakes/mail-fake.mjs +111 -0
  462. package/esm/tests/fakes/mail-fake.mjs.map +1 -0
  463. package/esm/tests/fakes/queue-fake.d.mts +48 -0
  464. package/esm/tests/fakes/queue-fake.d.mts.map +1 -0
  465. package/esm/tests/fakes/queue-fake.mjs +134 -0
  466. package/esm/tests/fakes/queue-fake.mjs.map +1 -0
  467. package/esm/tests/fakes/storage-fake.d.mts +31 -0
  468. package/esm/tests/fakes/storage-fake.d.mts.map +1 -0
  469. package/esm/tests/fakes/storage-fake.mjs +122 -0
  470. package/esm/tests/fakes/storage-fake.mjs.map +1 -0
  471. package/esm/tests/fakes/test-fakes.d.mts +39 -0
  472. package/esm/tests/fakes/test-fakes.d.mts.map +1 -0
  473. package/esm/tests/fakes/test-fakes.mjs +90 -0
  474. package/esm/tests/fakes/test-fakes.mjs.map +1 -0
  475. package/esm/tests/index.d.mts +14 -2
  476. package/esm/tests/index.mjs +15 -2
  477. package/esm/tests/snapshot-response.d.mts +34 -0
  478. package/esm/tests/snapshot-response.d.mts.map +1 -0
  479. package/esm/tests/snapshot-response.mjs +42 -0
  480. package/esm/tests/snapshot-response.mjs.map +1 -0
  481. package/esm/tests/start-http-development-server.d.mts +22 -0
  482. package/esm/tests/start-http-development-server.d.mts.map +1 -1
  483. package/esm/tests/start-http-development-server.mjs +36 -3
  484. package/esm/tests/start-http-development-server.mjs.map +1 -1
  485. package/esm/tests/test-helpers.d.mts +20 -1
  486. package/esm/tests/test-helpers.d.mts.map +1 -1
  487. package/esm/tests/test-helpers.mjs +40 -27
  488. package/esm/tests/test-helpers.mjs.map +1 -1
  489. package/esm/tests/test-http-server.d.mts +62 -0
  490. package/esm/tests/test-http-server.d.mts.map +1 -0
  491. package/esm/tests/test-http-server.mjs +119 -0
  492. package/esm/tests/test-http-server.mjs.map +1 -0
  493. package/esm/tests/vitest-setup.d.mts +11 -0
  494. package/esm/tests/vitest-setup.d.mts.map +1 -1
  495. package/esm/tests/vitest-setup.mjs +12 -4
  496. package/esm/tests/vitest-setup.mjs.map +1 -1
  497. package/esm/tooling/agents-md/agents-md-markers.d.mts +27 -0
  498. package/esm/tooling/agents-md/agents-md-markers.d.mts.map +1 -0
  499. package/esm/tooling/agents-md/agents-md-markers.mjs +59 -0
  500. package/esm/tooling/agents-md/agents-md-markers.mjs.map +1 -0
  501. package/esm/tooling/agents-md/agents-md-refresher.d.mts +36 -0
  502. package/esm/tooling/agents-md/agents-md-refresher.d.mts.map +1 -0
  503. package/esm/tooling/agents-md/agents-md-refresher.mjs +72 -0
  504. package/esm/tooling/agents-md/agents-md-refresher.mjs.map +1 -0
  505. package/esm/tooling/agents-md/index.mjs +7 -0
  506. package/esm/tooling/agents-md/installed-skills.d.mts +30 -0
  507. package/esm/tooling/agents-md/installed-skills.d.mts.map +1 -0
  508. package/esm/tooling/agents-md/installed-skills.mjs +74 -0
  509. package/esm/tooling/agents-md/installed-skills.mjs.map +1 -0
  510. package/esm/tooling/agents-md/render-agents-md.d.mts +33 -0
  511. package/esm/tooling/agents-md/render-agents-md.d.mts.map +1 -0
  512. package/esm/tooling/agents-md/render-agents-md.mjs +195 -0
  513. package/esm/tooling/agents-md/render-agents-md.mjs.map +1 -0
  514. package/esm/tooling/agents-md/write-agents-md.d.mts +33 -0
  515. package/esm/tooling/agents-md/write-agents-md.d.mts.map +1 -0
  516. package/esm/tooling/agents-md/write-agents-md.mjs +49 -0
  517. package/esm/tooling/agents-md/write-agents-md.mjs.map +1 -0
  518. package/esm/tooling/board/board-message.d.mts +31 -0
  519. package/esm/tooling/board/board-message.d.mts.map +1 -0
  520. package/esm/tooling/board/board-message.mjs +86 -0
  521. package/esm/tooling/board/board-message.mjs.map +1 -0
  522. package/esm/tooling/board/board.d.mts +109 -0
  523. package/esm/tooling/board/board.d.mts.map +1 -0
  524. package/esm/tooling/board/board.mjs +406 -0
  525. package/esm/tooling/board/board.mjs.map +1 -0
  526. package/esm/tooling/board/board.types.d.mts +72 -0
  527. package/esm/tooling/board/board.types.d.mts.map +1 -0
  528. package/esm/tooling/board/board.types.mjs +54 -0
  529. package/esm/tooling/board/board.types.mjs.map +1 -0
  530. package/esm/tooling/check/changed-files.d.mts +33 -0
  531. package/esm/tooling/check/changed-files.d.mts.map +1 -0
  532. package/esm/tooling/check/changed-files.mjs +73 -0
  533. package/esm/tooling/check/changed-files.mjs.map +1 -0
  534. package/esm/tooling/check/check-report.types.d.mts +62 -0
  535. package/esm/tooling/check/check-report.types.d.mts.map +1 -0
  536. package/esm/tooling/check/check-report.types.mjs +37 -0
  537. package/esm/tooling/check/check-report.types.mjs.map +1 -0
  538. package/esm/tooling/check/code-style-conventions.mjs +106 -0
  539. package/esm/tooling/check/code-style-conventions.mjs.map +1 -0
  540. package/esm/tooling/check/conventions-step.d.mts +34 -0
  541. package/esm/tooling/check/conventions-step.d.mts.map +1 -0
  542. package/esm/tooling/check/conventions-step.mjs +184 -0
  543. package/esm/tooling/check/conventions-step.mjs.map +1 -0
  544. package/esm/tooling/check/environment-step.d.mts +18 -0
  545. package/esm/tooling/check/environment-step.d.mts.map +1 -0
  546. package/esm/tooling/check/environment-step.mjs +78 -0
  547. package/esm/tooling/check/environment-step.mjs.map +1 -0
  548. package/esm/tooling/check/index.d.mts +8 -0
  549. package/esm/tooling/check/index.mjs +10 -0
  550. package/esm/tooling/check/lint-step.d.mts +19 -0
  551. package/esm/tooling/check/lint-step.d.mts.map +1 -0
  552. package/esm/tooling/check/lint-step.mjs +111 -0
  553. package/esm/tooling/check/lint-step.mjs.map +1 -0
  554. package/esm/tooling/check/request-input.mjs +132 -0
  555. package/esm/tooling/check/request-input.mjs.map +1 -0
  556. package/esm/tooling/check/run-check.d.mts +35 -0
  557. package/esm/tooling/check/run-check.d.mts.map +1 -0
  558. package/esm/tooling/check/run-check.mjs +192 -0
  559. package/esm/tooling/check/run-check.mjs.map +1 -0
  560. package/esm/tooling/check/run-tests.d.mts +48 -0
  561. package/esm/tooling/check/run-tests.d.mts.map +1 -0
  562. package/esm/tooling/check/run-tests.mjs +93 -0
  563. package/esm/tooling/check/run-tests.mjs.map +1 -0
  564. package/esm/tooling/check/security-conventions.mjs +648 -0
  565. package/esm/tooling/check/security-conventions.mjs.map +1 -0
  566. package/esm/tooling/check/source-ast.mjs +195 -0
  567. package/esm/tooling/check/source-ast.mjs.map +1 -0
  568. package/esm/tooling/check/source-files.mjs +27 -0
  569. package/esm/tooling/check/source-files.mjs.map +1 -0
  570. package/esm/tooling/check/tests-step.d.mts +34 -0
  571. package/esm/tooling/check/tests-step.d.mts.map +1 -0
  572. package/esm/tooling/check/tests-step.mjs +177 -0
  573. package/esm/tooling/check/tests-step.mjs.map +1 -0
  574. package/esm/tooling/dev-state/dev-server-state.d.mts +39 -0
  575. package/esm/tooling/dev-state/dev-server-state.d.mts.map +1 -0
  576. package/esm/tooling/dev-state/dev-server-state.mjs +67 -0
  577. package/esm/tooling/dev-state/dev-server-state.mjs.map +1 -0
  578. package/esm/tooling/devtools/devtools-client.d.mts +91 -0
  579. package/esm/tooling/devtools/devtools-client.d.mts.map +1 -0
  580. package/esm/tooling/devtools/devtools-client.mjs +155 -0
  581. package/esm/tooling/devtools/devtools-client.mjs.map +1 -0
  582. package/esm/tooling/generate/generation.d.mts +78 -0
  583. package/esm/tooling/generate/generation.d.mts.map +1 -0
  584. package/esm/tooling/generate/generation.mjs +123 -0
  585. package/esm/tooling/generate/generation.mjs.map +1 -0
  586. package/esm/tooling/generate/generator-spec.d.mts +57 -0
  587. package/esm/tooling/generate/generator-spec.d.mts.map +1 -0
  588. package/esm/tooling/generate/generator-spec.mjs +102 -0
  589. package/esm/tooling/generate/generator-spec.mjs.map +1 -0
  590. package/esm/tooling/generate/index.mjs +6 -0
  591. package/esm/tooling/generate/project-files.mjs +121 -0
  592. package/esm/tooling/generate/project-files.mjs.map +1 -0
  593. package/esm/tooling/generate/run-cli.d.mts +40 -0
  594. package/esm/tooling/generate/run-cli.d.mts.map +1 -0
  595. package/esm/tooling/generate/run-cli.mjs +93 -0
  596. package/esm/tooling/generate/run-cli.mjs.map +1 -0
  597. package/esm/tooling/generate/unified-diff.d.mts +37 -0
  598. package/esm/tooling/generate/unified-diff.d.mts.map +1 -0
  599. package/esm/tooling/generate/unified-diff.mjs +161 -0
  600. package/esm/tooling/generate/unified-diff.mjs.map +1 -0
  601. package/esm/tooling/index.d.mts +41 -0
  602. package/esm/tooling/index.mjs +45 -0
  603. package/esm/tooling/inspect/boot-for-inspect.d.mts +23 -0
  604. package/esm/tooling/inspect/boot-for-inspect.d.mts.map +1 -0
  605. package/esm/tooling/inspect/boot-for-inspect.mjs +63 -0
  606. package/esm/tooling/inspect/boot-for-inspect.mjs.map +1 -0
  607. package/esm/tooling/inspect/collect-config.mjs +77 -0
  608. package/esm/tooling/inspect/collect-config.mjs.map +1 -0
  609. package/esm/tooling/inspect/collect-models.d.mts +9 -0
  610. package/esm/tooling/inspect/collect-models.d.mts.map +1 -0
  611. package/esm/tooling/inspect/collect-models.mjs +154 -0
  612. package/esm/tooling/inspect/collect-models.mjs.map +1 -0
  613. package/esm/tooling/inspect/collect-packages.d.mts +10 -0
  614. package/esm/tooling/inspect/collect-packages.d.mts.map +1 -0
  615. package/esm/tooling/inspect/collect-packages.mjs +157 -0
  616. package/esm/tooling/inspect/collect-packages.mjs.map +1 -0
  617. package/esm/tooling/inspect/collect-pages.mjs +108 -0
  618. package/esm/tooling/inspect/collect-pages.mjs.map +1 -0
  619. package/esm/tooling/inspect/collect-routes.mjs +168 -0
  620. package/esm/tooling/inspect/collect-routes.mjs.map +1 -0
  621. package/esm/tooling/inspect/event-recorder.d.mts +37 -0
  622. package/esm/tooling/inspect/event-recorder.d.mts.map +1 -0
  623. package/esm/tooling/inspect/event-recorder.mjs +91 -0
  624. package/esm/tooling/inspect/event-recorder.mjs.map +1 -0
  625. package/esm/tooling/inspect/index.d.mts +7 -0
  626. package/esm/tooling/inspect/index.mjs +7 -0
  627. package/esm/tooling/inspect/inspect-app.d.mts +53 -0
  628. package/esm/tooling/inspect/inspect-app.d.mts.map +1 -0
  629. package/esm/tooling/inspect/inspect-app.mjs +92 -0
  630. package/esm/tooling/inspect/inspect-app.mjs.map +1 -0
  631. package/esm/tooling/inspect/inspect-report.schema.d.mts +15 -0
  632. package/esm/tooling/inspect/inspect-report.schema.d.mts.map +1 -0
  633. package/esm/tooling/inspect/inspect-report.schema.mjs +463 -0
  634. package/esm/tooling/inspect/inspect-report.schema.mjs.map +1 -0
  635. package/esm/tooling/inspect/inspect-report.types.d.mts +196 -0
  636. package/esm/tooling/inspect/inspect-report.types.d.mts.map +1 -0
  637. package/esm/tooling/inspect/inspect-report.types.mjs +33 -0
  638. package/esm/tooling/inspect/inspect-report.types.mjs.map +1 -0
  639. package/esm/tooling/mcp/create-mcp-context.d.mts +26 -0
  640. package/esm/tooling/mcp/create-mcp-context.d.mts.map +1 -0
  641. package/esm/tooling/mcp/create-mcp-context.mjs +75 -0
  642. package/esm/tooling/mcp/create-mcp-context.mjs.map +1 -0
  643. package/esm/tooling/mcp/db-schema.d.mts +49 -0
  644. package/esm/tooling/mcp/db-schema.d.mts.map +1 -0
  645. package/esm/tooling/mcp/db-schema.mjs +56 -0
  646. package/esm/tooling/mcp/db-schema.mjs.map +1 -0
  647. package/esm/tooling/mcp/docs-search.d.mts +72 -0
  648. package/esm/tooling/mcp/docs-search.d.mts.map +1 -0
  649. package/esm/tooling/mcp/docs-search.mjs +178 -0
  650. package/esm/tooling/mcp/docs-search.mjs.map +1 -0
  651. package/esm/tooling/mcp/index.mjs +9 -0
  652. package/esm/tooling/mcp/load-ai-tools.d.mts +62 -0
  653. package/esm/tooling/mcp/load-ai-tools.d.mts.map +1 -0
  654. package/esm/tooling/mcp/load-ai-tools.mjs +44 -0
  655. package/esm/tooling/mcp/load-ai-tools.mjs.map +1 -0
  656. package/esm/tooling/mcp/mcp-tools.d.mts +60 -0
  657. package/esm/tooling/mcp/mcp-tools.d.mts.map +1 -0
  658. package/esm/tooling/mcp/mcp-tools.mjs +513 -0
  659. package/esm/tooling/mcp/mcp-tools.mjs.map +1 -0
  660. package/esm/tooling/mcp/start-mcp-server.d.mts +56 -0
  661. package/esm/tooling/mcp/start-mcp-server.d.mts.map +1 -0
  662. package/esm/tooling/mcp/start-mcp-server.mjs +126 -0
  663. package/esm/tooling/mcp/start-mcp-server.mjs.map +1 -0
  664. package/esm/tooling/mcp/tool-input.d.mts +75 -0
  665. package/esm/tooling/mcp/tool-input.d.mts.map +1 -0
  666. package/esm/tooling/mcp/tool-input.mjs +72 -0
  667. package/esm/tooling/mcp/tool-input.mjs.map +1 -0
  668. package/esm/tooling/problem.d.mts +45 -0
  669. package/esm/tooling/problem.d.mts.map +1 -0
  670. package/esm/tooling/problem.mjs +28 -0
  671. package/esm/tooling/problem.mjs.map +1 -0
  672. package/esm/tooling/trace/trace-report.types.d.mts +71 -0
  673. package/esm/tooling/trace/trace-report.types.d.mts.map +1 -0
  674. package/esm/tooling/trace/trace-report.types.mjs +7 -0
  675. package/esm/tooling/trace/trace-report.types.mjs.map +1 -0
  676. package/esm/tooling/trace/trace-request.d.mts +83 -0
  677. package/esm/tooling/trace/trace-request.d.mts.map +1 -0
  678. package/esm/tooling/trace/trace-request.mjs +241 -0
  679. package/esm/tooling/trace/trace-request.mjs.map +1 -0
  680. package/esm/tooling/typecheck/index.d.mts +1 -0
  681. package/esm/tooling/typecheck/index.mjs +3 -0
  682. package/esm/tooling/typecheck/run-typecheck.d.mts +59 -0
  683. package/esm/tooling/typecheck/run-typecheck.d.mts.map +1 -0
  684. package/esm/tooling/typecheck/run-typecheck.mjs +153 -0
  685. package/esm/tooling/typecheck/run-typecheck.mjs.map +1 -0
  686. package/esm/upgrade/codemods/head-viewport.mjs +46 -0
  687. package/esm/upgrade/codemods/head-viewport.mjs.map +1 -0
  688. package/esm/upgrade/codemods/helpers.mjs +81 -0
  689. package/esm/upgrade/codemods/helpers.mjs.map +1 -0
  690. package/esm/upgrade/codemods/index.mjs +34 -0
  691. package/esm/upgrade/codemods/index.mjs.map +1 -0
  692. package/esm/upgrade/codemods/logger-sync-calls.mjs +57 -0
  693. package/esm/upgrade/codemods/logger-sync-calls.mjs.map +1 -0
  694. package/esm/upgrade/codemods/package-json.mjs +122 -0
  695. package/esm/upgrade/codemods/package-json.mjs.map +1 -0
  696. package/esm/upgrade/codemods/request-log-snapshot.mjs +82 -0
  697. package/esm/upgrade/codemods/request-log-snapshot.mjs.map +1 -0
  698. package/esm/upgrade/codemods/review-sites.mjs +262 -0
  699. package/esm/upgrade/codemods/review-sites.mjs.map +1 -0
  700. package/esm/upgrade/diff.mjs +119 -0
  701. package/esm/upgrade/diff.mjs.map +1 -0
  702. package/esm/upgrade/format-upgrade-report.mjs +32 -0
  703. package/esm/upgrade/format-upgrade-report.mjs.map +1 -0
  704. package/esm/upgrade/load-ts-morph.mjs +48 -0
  705. package/esm/upgrade/load-ts-morph.mjs.map +1 -0
  706. package/esm/upgrade/notes.mjs +16 -0
  707. package/esm/upgrade/notes.mjs.map +1 -0
  708. package/esm/upgrade/run-upgrade.mjs +246 -0
  709. package/esm/upgrade/run-upgrade.mjs.map +1 -0
  710. package/esm/upgrade/upgrade-command.action.mjs +37 -0
  711. package/esm/upgrade/upgrade-command.action.mjs.map +1 -0
  712. package/esm/upgrade/version.mjs +39 -0
  713. package/esm/upgrade/version.mjs.map +1 -0
  714. package/esm/use-cases/use-cases-registry.mjs.map +1 -1
  715. package/esm/utils/clock.d.mts +33 -0
  716. package/esm/utils/clock.d.mts.map +1 -0
  717. package/esm/utils/clock.mjs +27 -0
  718. package/esm/utils/clock.mjs.map +1 -0
  719. package/esm/utils/framework-vesion.mjs +1 -1
  720. package/esm/utils/framework-vesion.mjs.map +1 -1
  721. package/esm/utils/ids.d.mts +32 -0
  722. package/esm/utils/ids.d.mts.map +1 -0
  723. package/esm/utils/ids.mjs +33 -0
  724. package/esm/utils/ids.mjs.map +1 -0
  725. package/esm/utils/index.d.mts +3 -0
  726. package/esm/utils/index.mjs +3 -0
  727. package/esm/utils/runtime.d.mts +59 -0
  728. package/esm/utils/runtime.d.mts.map +1 -0
  729. package/esm/utils/runtime.mjs +85 -0
  730. package/esm/utils/runtime.mjs.map +1 -0
  731. package/esm/validation/index.d.mts +1 -1
  732. package/esm/validation/types.d.mts +57 -2
  733. package/esm/validation/types.d.mts.map +1 -1
  734. package/esm/validation/validateAll.mjs +19 -2
  735. package/esm/validation/validateAll.mjs.map +1 -1
  736. package/esm/validation/validation-failure-status.mjs +15 -0
  737. package/esm/validation/validation-failure-status.mjs.map +1 -0
  738. package/esm/validation/validators/file-validator.d.mts +0 -16
  739. package/esm/validation/validators/file-validator.d.mts.map +1 -1
  740. package/esm/warlock-config/bundle-config.mjs +1 -1
  741. package/esm/warlock-config/types.d.mts +27 -3
  742. package/esm/warlock-config/types.d.mts.map +1 -1
  743. package/llms-full.txt +3166 -736
  744. package/llms.txt +16 -6
  745. package/package.json +43 -13
  746. package/schemas/inspect-report.schema.json +554 -0
  747. package/skills/README.md +9 -0
  748. package/skills/add-connector/SKILL.md +26 -38
  749. package/skills/benchmark-code/SKILL.md +30 -24
  750. package/skills/build-restful/SKILL.md +14 -14
  751. package/skills/build-url/SKILL.md +18 -18
  752. package/skills/configure-app/SKILL.md +107 -14
  753. package/skills/create-controller/SKILL.md +25 -12
  754. package/skills/create-module/SKILL.md +3 -3
  755. package/skills/define-resource/SKILL.md +32 -29
  756. package/skills/encrypt-data/SKILL.md +21 -19
  757. package/skills/generate-openapi/SKILL.md +50 -24
  758. package/skills/hash-password/SKILL.md +2 -2
  759. package/skills/health-checks/SKILL.md +24 -7
  760. package/skills/index.md +9 -4
  761. package/skills/lower-stage3-decorators/SKILL.md +4 -4
  762. package/skills/make-endpoint/SKILL.md +110 -0
  763. package/skills/model-factories/SKILL.md +92 -0
  764. package/skills/process-image/SKILL.md +32 -30
  765. package/skills/register-route/SKILL.md +109 -10
  766. package/skills/request-memo/SKILL.md +1 -1
  767. package/skills/request-tracing/SKILL.md +4 -1
  768. package/skills/resolve-path/SKILL.md +45 -44
  769. package/skills/retry-operation/SKILL.md +20 -11
  770. package/skills/run-app/SKILL.md +106 -22
  771. package/skills/send-response/SKILL.md +179 -14
  772. package/skills/store-file/SKILL.md +93 -53
  773. package/skills/test-fakes/SKILL.md +123 -0
  774. package/skills/test-http/SKILL.md +125 -21
  775. package/skills/test-service/SKILL.md +41 -1
  776. package/skills/update-packages/SKILL.md +29 -18
  777. package/skills/upgrade-from-5-29/SKILL.md +413 -0
  778. package/skills/upload-file/SKILL.md +31 -33
  779. package/skills/use-app-context/SKILL.md +38 -31
  780. package/skills/use-middleware/SKILL.md +45 -25
  781. package/skills/use-model-transformers/SKILL.md +37 -28
  782. package/skills/use-repository/SKILL.md +2 -2
  783. package/skills/validate-input/SKILL.md +72 -28
  784. package/skills/warlock-agents-md/SKILL.md +96 -0
  785. package/skills/warlock-board/SKILL.md +123 -0
  786. package/skills/warlock-check/SKILL.md +132 -0
  787. package/skills/warlock-conventions/SKILL.md +115 -0
  788. package/skills/warlock-doctor/SKILL.md +55 -22
  789. package/skills/warlock-inspect/SKILL.md +134 -0
  790. package/skills/warlock-mcp/SKILL.md +120 -0
  791. package/skills/warlock-routes/SKILL.md +18 -11
  792. package/skills/warlock-trace/SKILL.md +81 -0
  793. package/skills/wire-socket/SKILL.md +8 -8
  794. package/skills/write-seeder/SKILL.md +46 -32
  795. package/skills/write-use-case/SKILL.md +40 -27
  796. package/esm/http/uploads/matches-if-none-match.mjs +0 -13
  797. package/esm/http/uploads/matches-if-none-match.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"local-driver.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/storage/drivers/local-driver.ts"],"mappings":";;;;;;;;AA6CA;;;;;;cAAa,WAAA,YAAuB,qBAAA;EA0BR,OAAA,EAAS,yBAAA;EAqDvB;;;EAAA,SA3EI,IAAA,EAAM,iBAAA;EA+GV;;;EAAA,UA1GF,IAAA;EA+JE;;;EAAA,UA1JF,SAAA;EA8L0B;;;EAAA,UAzL1B,kBAAA;EAmO4C;;;EAAA,UA9N5C,YAAA;cAEgB,OAAA,GAAS,yBAAA;EAuT4B;;;;;;;;;EAhSxD,WAAA,CAAY,QAAA;EAif4B;;;EAtdlC,GAAA,CACX,IAAA,EAAM,MAAA,YAAkB,YAAA,EACxB,QAAA,UACA,OAAA,GAAU,UAAA,GACT,OAAA,CAAQ,eAAA;EA4jBoB;;;;;;;;EA5hBlB,WAAA,CACX,IAAA,EAAM,MAAA,WACN,QAAA,UACA,OAAA,GAAU,UAAA,GACT,OAAA,CAAQ,eAAA;EApHuB;;;EAqKrB,SAAA,CACX,MAAA,EAAQ,QAAA,EACR,QAAA,UACA,OAAA,GAAU,UAAA,GACT,OAAA,CAAQ,eAAA;EArKW;;;EAwMT,GAAA,CAAI,QAAA,WAAmB,OAAA,CAAQ,MAAA;EApLlC;;;EAiMG,SAAA,CAAU,QAAA,WAAmB,OAAA,CAAQ,QAAA;EAxK3C;;;EAqLM,MAAA,CAAO,QAAA,WAAmB,OAAA;EAzJb;;;EAyKb,UAAA,CAAW,SAAA,aAAsB,OAAA,CAAQ,gBAAA;EAvKpD;;;;;;;EAiMW,eAAA,CAAgB,aAAA,UAAuB,OAAA;IAAY,SAAA;EAAA,IAAqB,OAAA;EA5J1E;;;;EAAA,UAuLK,oBAAA,CAAqB,SAAA,WAAoB,OAAA;EAnI7C;;;EAkJC,MAAA,CAAO,QAAA,WAAmB,OAAA;EA9G1B;;;EA0HN,GAAA,CAAI,QAAA;EA7GE;;;;;;;EAwHA,YAAA,CAAa,QAAA,UAAkB,SAAA,YAAmB,OAAA;EA3FvC;;;;;;EA6GjB,oBAAA,CAAqB,QAAA,UAAkB,SAAA;EAnFuC;;;;;;EA2GxE,sBAAA,CAAuB,KAAA,WAAgB,OAAA,CAAQ,wBAAA;EArDrD;;;EAiIM,QAAA,CAAS,QAAA,WAAmB,OAAA,CAAQ,eAAA;EAtHL;;;EA6I/B,IAAA,CAAK,QAAA,WAAmB,OAAA;EA3HS;;;EAuIjC,IAAA,CAAK,IAAA,UAAc,EAAA,WAAa,OAAA,CAAQ,eAAA;EA/GO;;;EA2I/C,IAAA,CAAK,IAAA,UAAc,EAAA,WAAa,OAAA,CAAQ,eAAA;EA/DJ;;;EA2FpC,IAAA,CAAK,SAAA,UAAmB,OAAA,GAAU,WAAA,GAAc,OAAA,CAAQ,eAAA;EAxDxD;;;EAwGN,IAAA,CAAK,QAAA;EAxGyC;;;EA+G9C,OAAA;EAnFsC;;;;;EAAA,UAgG7B,kBAAA,CAAmB,YAAA,WAAuB,OAAA;EApEG;;;;;;;EAAA,UAuFnD,eAAA,CAAgB,QAAA;EAAhB;;;EAAA,UAmBM,QAAA,CAAS,IAAA,EAAM,MAAA,YAAkB,YAAA,GAAe,OAAA,CAAQ,MAAA;EAAvB;;;EAAA,UAgBvC,aAAA,CAAc,MAAA,EAAQ,MAAA;EAAtB;;;EAAA,UAOM,QAAA,CAAS,YAAA,WAAuB,OAAA;EAAvB;;;EAAA,UAaf,aAAA,CAAc,QAAA;AAAA"}
1
+ {"version":3,"file":"local-driver.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/storage/drivers/local-driver.ts"],"mappings":";;;;;;;;AA6CA;;;;;;cAAa,WAAA,YAAuB,qBAAA;EA0BR,OAAA,EAAS,yBAAA;EAqDvB;;;EAAA,SA3EI,IAAA,EAAM,iBAAA;EA8GV;;;EAAA,UAzGF,IAAA;EA6JE;;;EAAA,UAxJF,SAAA;EA2L0B;;;EAAA,UAtL1B,kBAAA;EAgO4C;;;EAAA,UA3N5C,YAAA;cAEgB,OAAA,GAAS,yBAAA;EAoT4B;;;;;;;;;EA7RxD,WAAA,CAAY,QAAA;EA6e4B;;;EAldlC,GAAA,CACX,IAAA,EAAM,MAAA,YAAkB,YAAA,EACxB,QAAA,UACA,OAAA,GAAU,UAAA,GACT,OAAA,CAAQ,eAAA;EAwjBoB;;;;;;;;EAzhBlB,WAAA,CACX,IAAA,EAAM,MAAA,WACN,QAAA,UACA,OAAA,GAAU,UAAA,GACT,OAAA,CAAQ,eAAA;EAnHuB;;;EAmKrB,SAAA,CACX,MAAA,EAAQ,QAAA,EACR,QAAA,UACA,OAAA,GAAU,UAAA,GACT,OAAA,CAAQ,eAAA;EAnKW;;;EAqMT,GAAA,CAAI,QAAA,WAAmB,OAAA,CAAQ,MAAA;EAjLlC;;;EA8LG,SAAA,CAAU,QAAA,WAAmB,OAAA,CAAQ,QAAA;EArK3C;;;EAkLM,MAAA,CAAO,QAAA,WAAmB,OAAA;EAtJb;;;EAsKb,UAAA,CAAW,SAAA,aAAsB,OAAA,CAAQ,gBAAA;EApKpD;;;;;;;EA8LW,eAAA,CAAgB,aAAA,UAAuB,OAAA;IAAY,SAAA;EAAA,IAAqB,OAAA;EA1J1E;;;;EAAA,UAqLK,oBAAA,CAAqB,SAAA,WAAoB,OAAA;EAlI7C;;;EAiJC,MAAA,CAAO,QAAA,WAAmB,OAAA;EA9G1B;;;EA0HN,GAAA,CAAI,QAAA;EA7GE;;;;;;;EAwHA,YAAA,CAAa,QAAA,UAAkB,SAAA,YAAmB,OAAA;EA3FvC;;;;;;EA6GjB,oBAAA,CAAqB,QAAA,UAAkB,SAAA;EAnFuC;;;;;;EA2GxE,sBAAA,CAAuB,KAAA,WAAgB,OAAA,CAAQ,wBAAA;EArDrD;;;EAiIM,QAAA,CAAS,QAAA,WAAmB,OAAA,CAAQ,eAAA;EAtHL;;;EA6I/B,IAAA,CAAK,QAAA,WAAmB,OAAA;EA3HS;;;EAuIjC,IAAA,CAAK,IAAA,UAAc,EAAA,WAAa,OAAA,CAAQ,eAAA;EA/GO;;;EA0I/C,IAAA,CAAK,IAAA,UAAc,EAAA,WAAa,OAAA,CAAQ,eAAA;EA9DJ;;;EA0FpC,IAAA,CAAK,SAAA,UAAmB,OAAA,GAAU,WAAA,GAAc,OAAA,CAAQ,eAAA;EAvDxD;;;EAuGN,IAAA,CAAK,QAAA;EAvGyC;;;EA8G9C,OAAA;EAnFsC;;;;;EAAA,UAgG7B,kBAAA,CAAmB,YAAA,WAAuB,OAAA;EApEG;;;;;;;EAAA,UAuFnD,eAAA,CAAgB,QAAA;EAAhB;;;EAAA,UAmBM,QAAA,CAAS,IAAA,EAAM,MAAA,YAAkB,YAAA,GAAe,OAAA,CAAQ,MAAA;EAAvB;;;EAAA,UAgBvC,aAAA,CAAc,MAAA,EAAQ,MAAA;EAAtB;;;EAAA,UAOM,QAAA,CAAS,YAAA,WAAuB,OAAA;EAAvB;;;EAAA,UAaf,aAAA,CAAc,QAAA;AAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"local-driver.mjs","names":["fsPromises"],"sources":["../../../../../../../../../packages/core/src/storage/drivers/local-driver.ts"],"sourcesContent":["import {\n directoryExistsAsync,\n ensureDirectoryAsync,\n fileExistsAsync,\n removeDirectoryAsync,\n unlinkAsync,\n} from \"@warlock.js/fs\";\nimport { ltrim } from \"@mongez/reinforcements\";\nimport crypto from \"crypto\";\nimport { createReadStream, createWriteStream, promises as fsPromises } from \"fs\";\nimport { copyFile, readFile, readdir, rename, stat, unlink, writeFile } from \"fs/promises\";\nimport { basename, dirname, join, resolve } from \"path\";\nimport { Transform, type Readable } from \"stream\";\nimport { pipeline } from \"stream/promises\";\nimport { log } from \"@warlock.js/logger\";\nimport { UploadedFile } from \"../../http\";\nimport { purgeImageVariantsOfFile } from \"../../http/uploads/image-variant-cache\";\nimport { storagePath } from \"../../utils/paths\";\nimport { url } from \"../../utils/urls\";\nimport { storageDriverContext } from \"../context/storage-driver-context\";\nimport { resolveWithinRoot } from \"../utils/contain-path\";\nimport { StorageError } from \"../utils/storage-error\";\nimport type {\n DeleteManyResult,\n ListOptions,\n LocalStorageDriverOptions,\n PutOptions,\n StorageDriverContract,\n StorageDriverType,\n StorageFileData,\n StorageFileInfo,\n TemporaryTokenPayload,\n TemporaryTokenValidation,\n} from \"../types\";\nimport { getMimeType } from \"../utils/mime\";\n\n/**\n * Local filesystem storage driver\n *\n * Stores files on the local filesystem with support for:\n * - File operations (put, get, delete, copy, move)\n * - Stream operations for large files\n * - Batch operations\n * - Signed temporary URLs\n */\nexport class LocalDriver implements StorageDriverContract {\n /**\n * Driver name\n */\n public readonly name: StorageDriverType = \"local\";\n\n /**\n * Root path for storage\n */\n protected root: string;\n\n /**\n * URL prefix for file URLs\n */\n protected urlPrefix: string = \"\";\n\n /**\n * URL prefix for temporary file URLs\n */\n protected temporaryUrlPrefix: string;\n\n /**\n * Secret key for signing temporary URLs\n */\n protected signatureKey?: string;\n\n public constructor(public options: LocalStorageDriverOptions = {}) {\n // Resolve the root to an absolute, normalized path up front so the\n // path-traversal containment check (resolveWithinRoot) has a stable\n // anchor to compare resolved locations against.\n this.root = resolve(options.root ?? storagePath());\n this.urlPrefix = options.urlPrefix ?? \"\";\n this.temporaryUrlPrefix = options.temporaryUrlPrefix ?? \"/temp-files\";\n this.signatureKey = options.signatureKey;\n }\n\n // ============================================================\n // Prefix Operations\n // ============================================================\n\n /**\n * Apply prefix to location path\n *\n * Priority: context prefix > driver options prefix > no prefix\n * This allows multi-tenant scenarios where context overrides driver config.\n *\n * @param location - Original location path\n * @returns Location with prefix applied if one exists\n */\n public applyPrefix(location: string): string {\n // Check context prefix first (highest priority)\n const contextPrefix = storageDriverContext.getPrefix();\n const prefix = contextPrefix || this.options.prefix;\n\n if (!prefix) {\n return location;\n }\n\n const cleanPrefix = prefix.replace(/\\/+$/, \"\");\n const cleanLocation = location.replace(/^\\/+/, \"\");\n\n // Avoid double-prefixing\n if (cleanLocation.startsWith(cleanPrefix + \"/\") || cleanLocation === cleanPrefix) {\n return cleanLocation;\n }\n\n return `${cleanPrefix}/${cleanLocation}`;\n }\n\n // ============================================================\n // Core File Operations\n // ============================================================\n\n /**\n * Put file to local storage\n */\n public async put(\n file: Buffer | string | UploadedFile,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFileData> {\n const absolutePath = this.getAbsolutePath(location);\n\n await ensureDirectoryAsync(dirname(absolutePath));\n\n const fileBuffer = await this.toBuffer(file);\n const hash = this.calculateHash(fileBuffer);\n\n await writeFile(absolutePath, new Uint8Array(fileBuffer));\n\n\n const stats = await stat(absolutePath);\n const mimeType = options?.mimeType || this.guessMimeType(location);\n\n return {\n path: this.applyPrefix(location),\n url: this.url(location),\n size: stats.size,\n hash,\n mimeType,\n driver: this.name,\n };\n }\n\n /**\n * Atomically put a file only if nothing exists at `location`.\n *\n * Content is written to a temp file in the same directory, then hard-linked\n * to the target. `link()` fails with EEXIST if the target exists, so exactly\n * one concurrent caller wins, the object never appears half-written, and the\n * check is atomic on NFS too. Returns `null` only on EEXIST; other errors throw.\n */\n public async putIfAbsent(\n file: Buffer | string,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFileData | null> {\n const absolutePath = this.getAbsolutePath(location);\n const directory = dirname(absolutePath);\n\n await ensureDirectoryAsync(directory);\n\n // Unlike put(), a string here is CONTENT, never a source path (matches\n // the cloud driver): the objects this protects are small JSON bodies.\n const fileBuffer = typeof file === \"string\" ? Buffer.from(file) : file;\n const hash = this.calculateHash(fileBuffer);\n\n const tempPath = join(\n directory,\n `.${basename(absolutePath)}.${crypto.randomBytes(8).toString(\"hex\")}.tmp`,\n );\n\n try {\n await writeFile(tempPath, new Uint8Array(fileBuffer));\n\n try {\n await fsPromises.link(tempPath, absolutePath);\n } catch (error: any) {\n if (error?.code === \"EEXIST\") {\n return null;\n }\n\n throw error;\n }\n } finally {\n await unlink(tempPath).catch(() => undefined);\n }\n\n\n const stats = await stat(absolutePath);\n const mimeType = options?.mimeType || this.guessMimeType(location);\n\n return {\n path: this.applyPrefix(location),\n url: this.url(location),\n size: stats.size,\n hash,\n mimeType,\n driver: this.name,\n };\n }\n\n /**\n * Put file from a readable stream (for large files)\n */\n public async putStream(\n stream: Readable,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFileData> {\n const absolutePath = this.getAbsolutePath(location);\n\n await ensureDirectoryAsync(dirname(absolutePath));\n\n // Hash while streaming so large files are never read back into memory\n const hasher = crypto.createHash(\"sha256\");\n const hashTransform = new Transform({\n transform(chunk, _encoding, callback) {\n hasher.update(chunk);\n callback(null, chunk);\n },\n });\n\n const writeStream = createWriteStream(absolutePath);\n await pipeline(stream, hashTransform, writeStream);\n\n\n const hash = hasher.digest(\"hex\");\n const stats = await stat(absolutePath);\n const mimeType = options?.mimeType || this.guessMimeType(location);\n\n return {\n path: this.applyPrefix(location),\n url: this.url(location),\n size: stats.size,\n hash,\n mimeType,\n driver: this.name,\n };\n }\n\n /**\n * Get file contents as Buffer\n */\n public async get(location: string): Promise<Buffer> {\n const absolutePath = this.getAbsolutePath(location);\n\n if (!(await fileExistsAsync(absolutePath))) {\n throw new Error(`File not found: ${location}`);\n }\n\n return readFile(absolutePath);\n }\n\n /**\n * Get file as a readable stream (for large files)\n */\n public async getStream(location: string): Promise<Readable> {\n const absolutePath = this.getAbsolutePath(location);\n\n if (!(await fileExistsAsync(absolutePath))) {\n throw new Error(`File not found: ${location}`);\n }\n\n return createReadStream(absolutePath);\n }\n\n /**\n * Delete a file\n */\n public async delete(location: string): Promise<boolean> {\n const absolutePath = this.getAbsolutePath(location);\n\n if (!(await fileExistsAsync(absolutePath))) {\n return false;\n }\n\n await unlinkAsync(absolutePath);\n await this.purgeImageVariants(absolutePath);\n\n return true;\n }\n\n /**\n * Delete multiple files at once\n */\n public async deleteMany(locations: string[]): Promise<DeleteManyResult[]> {\n const results: DeleteManyResult[] = [];\n\n for (const location of locations) {\n try {\n const deleted = await this.delete(location);\n results.push({ location, deleted });\n } catch (error) {\n results.push({\n location,\n deleted: false,\n error: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n return results;\n }\n\n /**\n * Delete directory\n *\n * The directory path is resolved through {@link getAbsolutePath} so it is\n * contained within the storage root — the raw, caller-supplied argument is\n * never handed to the filesystem (preventing `../` traversal deletes).\n */\n public async deleteDirectory(directoryPath: string, options?: { allowRoot?: boolean }) {\n const absolutePath = this.getAbsolutePath(directoryPath);\n\n if (!options?.allowRoot && resolve(absolutePath) === this.root) {\n throw new StorageError(\n `Refusing to delete the storage root (\"${directoryPath}\"). Pass { allowRoot: true } to confirm.`,\n { context: { directoryPath } },\n );\n }\n\n // Listed before the delete: once the directory is gone there is nothing\n // left to tell which files had cached image derivatives.\n const files = await this.listFilesRecursively(absolutePath);\n\n await removeDirectoryAsync(absolutePath);\n\n for (const file of files) {\n await this.purgeImageVariants(file);\n }\n\n return true;\n }\n\n /**\n * Every file under `directory`, as absolute paths; empty when it cannot be\n * read. Used to purge the image derivatives of a deleted directory's files.\n */\n protected async listFilesRecursively(directory: string): Promise<string[]> {\n try {\n const entries = await readdir(directory, { recursive: true, withFileTypes: true });\n\n return entries\n .filter((entry) => entry.isFile())\n .map((entry) => join(entry.parentPath, entry.name));\n } catch {\n return [];\n }\n }\n\n /**\n * Check if file exists\n */\n public async exists(location: string): Promise<boolean> {\n const absolutePath = this.getAbsolutePath(location);\n return Boolean(await fileExistsAsync(absolutePath));\n }\n\n // ============================================================\n // URL Operations\n // ============================================================\n\n /**\n * Get public URL for file\n */\n public url(location: string): string {\n return url(this.urlPrefix + \"/\" + ltrim(this.applyPrefix(location), \"/\"));\n }\n\n /**\n * Get a temporary signed URL that expires\n * Returns a clean URL with encoded token: {temporaryUrlPrefix}/{token}\n *\n * @param location - File path\n * @param expiresIn - Seconds until expiration (default: 3600)\n */\n public async temporaryUrl(location: string, expiresIn = 3600): Promise<string> {\n if (!this.signatureKey) {\n throw new Error(\n \"Temporary URLs require a signatureKey in LocalDriver options. \" +\n \"Configure storage.drivers.local.signatureKey in your config.\",\n );\n }\n\n const token = this.encodeTemporaryToken(location, expiresIn);\n return `${this.temporaryUrlPrefix}/${token}`;\n }\n\n /**\n * Encode a temporary token containing path, expiry, and signature\n *\n * @param location - File path\n * @param expiresIn - Seconds until expiration\n */\n public encodeTemporaryToken(location: string, expiresIn: number): string {\n if (!this.signatureKey) {\n throw new Error(\"Temporary tokens require a signatureKey\");\n }\n\n const exp = Math.floor(Date.now() / 1000) + expiresIn;\n const sig = crypto\n .createHmac(\"sha256\", this.signatureKey)\n .update(`${location}:${exp}`)\n .digest(\"hex\");\n\n const payload: TemporaryTokenPayload = { path: location, exp, sig };\n const json = JSON.stringify(payload);\n\n // Use base64url encoding (URL-safe base64)\n return Buffer.from(json).toString(\"base64url\");\n }\n\n /**\n * Validate a temporary URL token\n * Returns a result object with validation status, file info, and convenience methods\n *\n * @param token - The token from the URL\n */\n public async validateTemporaryToken(token: string): Promise<TemporaryTokenValidation> {\n // Check signature key\n if (!this.signatureKey) {\n return { valid: false, error: \"missing_key\" };\n }\n\n // Decode token\n let payload: TemporaryTokenPayload;\n try {\n const json = Buffer.from(token, \"base64url\").toString(\"utf-8\");\n payload = JSON.parse(json);\n } catch {\n return { valid: false, error: \"invalid_token\" };\n }\n\n // Validate payload structure\n if (!payload.path || !payload.exp || !payload.sig) {\n return { valid: false, error: \"invalid_token\" };\n }\n\n // Check expiration\n const now = Math.floor(Date.now() / 1000);\n if (payload.exp < now) {\n return { valid: false, error: \"expired\" };\n }\n\n // Verify signature\n const expectedSig = crypto\n .createHmac(\"sha256\", this.signatureKey)\n .update(`${payload.path}:${payload.exp}`)\n .digest(\"hex\");\n\n const sigBuffer = Buffer.from(payload.sig, \"hex\");\n const expectedBuffer = Buffer.from(expectedSig, \"hex\");\n\n if (sigBuffer.length !== expectedBuffer.length) {\n return { valid: false, error: \"invalid_signature\" };\n }\n\n const isValidSig = crypto.timingSafeEqual(\n new Uint8Array(sigBuffer),\n new Uint8Array(expectedBuffer),\n );\n\n if (!isValidSig) {\n return { valid: false, error: \"invalid_signature\" };\n }\n\n // Check file exists\n const absolutePath = this.getAbsolutePath(payload.path);\n if (!(await fileExistsAsync(absolutePath))) {\n return { valid: false, error: \"file_not_found\" };\n }\n\n // Build successful result with convenience methods\n const result: TemporaryTokenValidation = {\n valid: true,\n path: payload.path,\n absolutePath,\n expiresAt: new Date(payload.exp * 1000),\n mimeType: this.guessMimeType(payload.path),\n driver: this,\n getFile: () => this.get(payload.path),\n getStream: () => this.getStream(payload.path),\n };\n\n return result;\n }\n\n // ============================================================\n // Metadata Operations\n // ============================================================\n\n /**\n * Get file info/metadata without downloading\n */\n public async metadata(location: string): Promise<StorageFileInfo> {\n const absolutePath = this.getAbsolutePath(location);\n\n if (!(await fileExistsAsync(absolutePath))) {\n throw new Error(`File not found: ${absolutePath}`);\n }\n\n const stats = await stat(absolutePath);\n const name = location.split(\"/\").pop() || \"\";\n\n return {\n path: location,\n name,\n size: stats.size,\n isDirectory: stats.isDirectory(),\n lastModified: stats.mtime,\n mimeType: this.guessMimeType(location),\n };\n }\n\n /**\n * Get file size in bytes (shortcut for metadata().size)\n */\n public async size(location: string): Promise<number> {\n const metadata = await this.metadata(location);\n return metadata.size;\n }\n\n // ============================================================\n // File Operations\n // ============================================================\n\n /**\n * Copy file to a new location\n */\n public async copy(from: string, to: string): Promise<StorageFileData> {\n const fromPath = this.getAbsolutePath(from);\n const toPath = this.getAbsolutePath(to);\n\n if (!(await fileExistsAsync(fromPath))) {\n throw new Error(`Source file not found: ${from}`);\n }\n\n await ensureDirectoryAsync(dirname(toPath));\n await copyFile(fromPath, toPath);\n\n\n const hash = await this.hashFile(toPath);\n const stats = await stat(toPath);\n\n return {\n path: this.applyPrefix(to),\n url: this.url(to),\n size: stats.size,\n hash,\n mimeType: this.guessMimeType(to),\n driver: this.name,\n };\n }\n\n /**\n * Move file to a new location\n */\n public async move(from: string, to: string): Promise<StorageFileData> {\n const fromPath = this.getAbsolutePath(from);\n const toPath = this.getAbsolutePath(to);\n\n if (!(await fileExistsAsync(fromPath))) {\n throw new Error(`Source file not found: ${from}`);\n }\n\n await ensureDirectoryAsync(dirname(toPath));\n await rename(fromPath, toPath);\n await this.purgeImageVariants(fromPath);\n\n const hash = await this.hashFile(toPath);\n const stats = await stat(toPath);\n\n return {\n path: this.applyPrefix(to),\n url: this.url(to),\n size: stats.size,\n hash,\n mimeType: this.guessMimeType(to),\n driver: this.name,\n };\n }\n\n /**\n * List files in a directory\n */\n public async list(directory: string, options?: ListOptions): Promise<StorageFileInfo[]> {\n const absolutePath = this.getAbsolutePath(directory);\n const files: StorageFileInfo[] = [];\n\n // A listing target is a DIRECTORY, so guard with `directoryExistsAsync`.\n // `fileExistsAsync` resolves `false` for a folder, which would make `list`\n // always return [] for a real, populated directory.\n if (!(await directoryExistsAsync(absolutePath))) {\n return files;\n }\n\n const entries = await readdir(absolutePath, { withFileTypes: true });\n\n for (const entry of entries) {\n const entryPath = join(directory, entry.name);\n const entryStats = await stat(this.getAbsolutePath(entryPath));\n\n files.push({\n path: entryPath,\n name: entry.name,\n size: entryStats.size,\n isDirectory: entry.isDirectory(),\n lastModified: entryStats.mtime,\n mimeType: entry.isFile() ? this.guessMimeType(entry.name) : undefined,\n });\n\n // Recursively list subdirectories if requested\n if (options?.recursive && entry.isDirectory()) {\n const subFiles = await this.list(entryPath, options);\n files.push(...subFiles);\n }\n\n // Respect limit\n if (options?.limit && files.length >= options.limit) {\n break;\n }\n }\n\n return files;\n }\n\n // ============================================================\n // Path Operations\n // ============================================================\n\n /**\n * Get absolute filesystem path for a location\n */\n public path(location: string): string {\n return this.getAbsolutePath(location);\n }\n\n /**\n * Get the storage root directory\n */\n public getRoot(): string {\n return this.root;\n }\n\n // ============================================================\n // Utilities\n // ============================================================\n\n /**\n * Remove the cached image derivatives of a file that was just deleted or\n * moved away. Best effort: the file operation has already succeeded, so a\n * cache that cannot be cleared is logged, never thrown.\n */\n protected async purgeImageVariants(absolutePath: string): Promise<void> {\n try {\n await purgeImageVariantsOfFile(this.root, absolutePath);\n } catch (error) {\n log.warn(\n \"storage.local\",\n \"purge-image-variants\",\n `Could not remove cached image variants: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n /**\n * Get absolute file path\n *\n * Routes through {@link resolveWithinRoot} so a location can never escape\n * the configured storage root via `..` traversal, an absolute path, or a\n * prefix breakout.\n */\n protected getAbsolutePath(location: string): string {\n const prefixedLocation = this.applyPrefix(location);\n const resolved = resolveWithinRoot(this.root, prefixedLocation);\n\n // The prefix is a containment boundary too: \"../t2/x\" under prefix \"t1\"\n // must not land in a sibling tenant's directory.\n const prefix = storageDriverContext.getPrefix() || this.options.prefix;\n\n if (prefix) {\n const prefixRoot = resolveWithinRoot(this.root, prefix.replace(/^[\\\\/]+|[\\\\/]+$/g, \"\"));\n resolveWithinRoot(prefixRoot, resolved);\n }\n\n return resolved;\n }\n\n /**\n * Convert various input types to Buffer\n */\n protected async toBuffer(file: Buffer | string | UploadedFile): Promise<Buffer> {\n if (Buffer.isBuffer(file)) {\n return file;\n }\n\n // A string is always content, never a source path\n if (typeof file === \"string\") {\n return Buffer.from(file);\n }\n\n return file.buffer();\n }\n\n /**\n * Calculate SHA-256 hash\n */\n protected calculateHash(buffer: Buffer): string {\n return crypto.createHash(\"sha256\").update(new Uint8Array(buffer)).digest(\"hex\");\n }\n\n /**\n * Calculate SHA-256 hash of a file by streaming it (constant memory)\n */\n protected async hashFile(absolutePath: string): Promise<string> {\n const hasher = crypto.createHash(\"sha256\");\n\n for await (const chunk of createReadStream(absolutePath)) {\n hasher.update(chunk);\n }\n\n return hasher.digest(\"hex\");\n }\n\n /**\n * Guess MIME type from file extension\n */\n protected guessMimeType(location: string): string {\n return getMimeType(location);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"local-driver.mjs","names":["fsPromises"],"sources":["../../../../../../../../../packages/core/src/storage/drivers/local-driver.ts"],"sourcesContent":["import {\n directoryExistsAsync,\n ensureDirectoryAsync,\n fileExistsAsync,\n removeDirectoryAsync,\n unlinkAsync,\n} from \"@warlock.js/fs\";\nimport { ltrim } from \"@mongez/reinforcements\";\nimport crypto from \"crypto\";\nimport { createReadStream, createWriteStream, promises as fsPromises } from \"fs\";\nimport { copyFile, readFile, readdir, rename, stat, unlink, writeFile } from \"fs/promises\";\nimport { basename, dirname, join, resolve } from \"path\";\nimport { Transform, type Readable } from \"stream\";\nimport { pipeline } from \"stream/promises\";\nimport { log } from \"@warlock.js/logger\";\nimport { UploadedFile } from \"../../http\";\nimport { purgeImageVariantsOfFile } from \"../../http/uploads/image-variant-cache\";\nimport { storagePath } from \"../../utils/paths\";\nimport { url } from \"../../utils/urls\";\nimport { storageDriverContext } from \"../context/storage-driver-context\";\nimport { resolveWithinRoot } from \"../utils/contain-path\";\nimport { StorageError } from \"../utils/storage-error\";\nimport type {\n DeleteManyResult,\n ListOptions,\n LocalStorageDriverOptions,\n PutOptions,\n StorageDriverContract,\n StorageDriverType,\n StorageFileData,\n StorageFileInfo,\n TemporaryTokenPayload,\n TemporaryTokenValidation,\n} from \"../types\";\nimport { getMimeType } from \"../utils/mime\";\n\n/**\n * Local filesystem storage driver\n *\n * Stores files on the local filesystem with support for:\n * - File operations (put, get, delete, copy, move)\n * - Stream operations for large files\n * - Batch operations\n * - Signed temporary URLs\n */\nexport class LocalDriver implements StorageDriverContract {\n /**\n * Driver name\n */\n public readonly name: StorageDriverType = \"local\";\n\n /**\n * Root path for storage\n */\n protected root: string;\n\n /**\n * URL prefix for file URLs\n */\n protected urlPrefix: string = \"\";\n\n /**\n * URL prefix for temporary file URLs\n */\n protected temporaryUrlPrefix: string;\n\n /**\n * Secret key for signing temporary URLs\n */\n protected signatureKey?: string;\n\n public constructor(public options: LocalStorageDriverOptions = {}) {\n // Resolve the root to an absolute, normalized path up front so the\n // path-traversal containment check (resolveWithinRoot) has a stable\n // anchor to compare resolved locations against.\n this.root = resolve(options.root ?? storagePath());\n this.urlPrefix = options.urlPrefix ?? \"\";\n this.temporaryUrlPrefix = options.temporaryUrlPrefix ?? \"/temp-files\";\n this.signatureKey = options.signatureKey;\n }\n\n // ============================================================\n // Prefix Operations\n // ============================================================\n\n /**\n * Apply prefix to location path\n *\n * Priority: context prefix > driver options prefix > no prefix\n * This allows multi-tenant scenarios where context overrides driver config.\n *\n * @param location - Original location path\n * @returns Location with prefix applied if one exists\n */\n public applyPrefix(location: string): string {\n // Check context prefix first (highest priority)\n const contextPrefix = storageDriverContext.getPrefix();\n const prefix = contextPrefix || this.options.prefix;\n\n if (!prefix) {\n return location;\n }\n\n const cleanPrefix = prefix.replace(/\\/+$/, \"\");\n const cleanLocation = location.replace(/^\\/+/, \"\");\n\n // Avoid double-prefixing\n if (cleanLocation.startsWith(cleanPrefix + \"/\") || cleanLocation === cleanPrefix) {\n return cleanLocation;\n }\n\n return `${cleanPrefix}/${cleanLocation}`;\n }\n\n // ============================================================\n // Core File Operations\n // ============================================================\n\n /**\n * Put file to local storage\n */\n public async put(\n file: Buffer | string | UploadedFile,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFileData> {\n const absolutePath = this.getAbsolutePath(location);\n\n await ensureDirectoryAsync(dirname(absolutePath));\n\n const fileBuffer = await this.toBuffer(file);\n const hash = this.calculateHash(fileBuffer);\n\n await writeFile(absolutePath, new Uint8Array(fileBuffer));\n\n const stats = await stat(absolutePath);\n const mimeType = options?.mimeType || this.guessMimeType(location);\n\n return {\n path: this.applyPrefix(location),\n url: this.url(location),\n size: stats.size,\n hash,\n mimeType,\n driver: this.name,\n };\n }\n\n /**\n * Atomically put a file only if nothing exists at `location`.\n *\n * Content is written to a temp file in the same directory, then hard-linked\n * to the target. `link()` fails with EEXIST if the target exists, so exactly\n * one concurrent caller wins, the object never appears half-written, and the\n * check is atomic on NFS too. Returns `null` only on EEXIST; other errors throw.\n */\n public async putIfAbsent(\n file: Buffer | string,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFileData | null> {\n const absolutePath = this.getAbsolutePath(location);\n const directory = dirname(absolutePath);\n\n await ensureDirectoryAsync(directory);\n\n // Unlike put(), a string here is CONTENT, never a source path (matches\n // the cloud driver): the objects this protects are small JSON bodies.\n const fileBuffer = typeof file === \"string\" ? Buffer.from(file) : file;\n const hash = this.calculateHash(fileBuffer);\n\n const tempPath = join(\n directory,\n `.${basename(absolutePath)}.${crypto.randomBytes(8).toString(\"hex\")}.tmp`,\n );\n\n try {\n await writeFile(tempPath, new Uint8Array(fileBuffer));\n\n try {\n await fsPromises.link(tempPath, absolutePath);\n } catch (error: any) {\n if (error?.code === \"EEXIST\") {\n return null;\n }\n\n throw error;\n }\n } finally {\n await unlink(tempPath).catch(() => undefined);\n }\n\n const stats = await stat(absolutePath);\n const mimeType = options?.mimeType || this.guessMimeType(location);\n\n return {\n path: this.applyPrefix(location),\n url: this.url(location),\n size: stats.size,\n hash,\n mimeType,\n driver: this.name,\n };\n }\n\n /**\n * Put file from a readable stream (for large files)\n */\n public async putStream(\n stream: Readable,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFileData> {\n const absolutePath = this.getAbsolutePath(location);\n\n await ensureDirectoryAsync(dirname(absolutePath));\n\n // Hash while streaming so large files are never read back into memory\n const hasher = crypto.createHash(\"sha256\");\n const hashTransform = new Transform({\n transform(chunk, _encoding, callback) {\n hasher.update(chunk);\n callback(null, chunk);\n },\n });\n\n const writeStream = createWriteStream(absolutePath);\n await pipeline(stream, hashTransform, writeStream);\n\n const hash = hasher.digest(\"hex\");\n const stats = await stat(absolutePath);\n const mimeType = options?.mimeType || this.guessMimeType(location);\n\n return {\n path: this.applyPrefix(location),\n url: this.url(location),\n size: stats.size,\n hash,\n mimeType,\n driver: this.name,\n };\n }\n\n /**\n * Get file contents as Buffer\n */\n public async get(location: string): Promise<Buffer> {\n const absolutePath = this.getAbsolutePath(location);\n\n if (!(await fileExistsAsync(absolutePath))) {\n throw new Error(`File not found: ${location}`);\n }\n\n return readFile(absolutePath);\n }\n\n /**\n * Get file as a readable stream (for large files)\n */\n public async getStream(location: string): Promise<Readable> {\n const absolutePath = this.getAbsolutePath(location);\n\n if (!(await fileExistsAsync(absolutePath))) {\n throw new Error(`File not found: ${location}`);\n }\n\n return createReadStream(absolutePath);\n }\n\n /**\n * Delete a file\n */\n public async delete(location: string): Promise<boolean> {\n const absolutePath = this.getAbsolutePath(location);\n\n if (!(await fileExistsAsync(absolutePath))) {\n return false;\n }\n\n await unlinkAsync(absolutePath);\n await this.purgeImageVariants(absolutePath);\n\n return true;\n }\n\n /**\n * Delete multiple files at once\n */\n public async deleteMany(locations: string[]): Promise<DeleteManyResult[]> {\n const results: DeleteManyResult[] = [];\n\n for (const location of locations) {\n try {\n const deleted = await this.delete(location);\n results.push({ location, deleted });\n } catch (error) {\n results.push({\n location,\n deleted: false,\n error: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n return results;\n }\n\n /**\n * Delete directory\n *\n * The directory path is resolved through {@link getAbsolutePath} so it is\n * contained within the storage root — the raw, caller-supplied argument is\n * never handed to the filesystem (preventing `../` traversal deletes).\n */\n public async deleteDirectory(directoryPath: string, options?: { allowRoot?: boolean }) {\n const absolutePath = this.getAbsolutePath(directoryPath);\n\n if (!options?.allowRoot && resolve(absolutePath) === this.root) {\n throw new StorageError(\n `Refusing to delete the storage root (\"${directoryPath}\"). Pass { allowRoot: true } to confirm.`,\n { context: { directoryPath } },\n );\n }\n\n // Listed before the delete: once the directory is gone there is nothing\n // left to tell which files had cached image derivatives.\n const files = await this.listFilesRecursively(absolutePath);\n\n await removeDirectoryAsync(absolutePath);\n\n for (const file of files) {\n await this.purgeImageVariants(file);\n }\n\n return true;\n }\n\n /**\n * Every file under `directory`, as absolute paths; empty when it cannot be\n * read. Used to purge the image derivatives of a deleted directory's files.\n */\n protected async listFilesRecursively(directory: string): Promise<string[]> {\n try {\n const entries = await readdir(directory, { recursive: true, withFileTypes: true });\n\n return entries\n .filter((entry) => entry.isFile())\n .map((entry) => join(entry.parentPath, entry.name));\n } catch {\n return [];\n }\n }\n\n /**\n * Check if file exists\n */\n public async exists(location: string): Promise<boolean> {\n const absolutePath = this.getAbsolutePath(location);\n return Boolean(await fileExistsAsync(absolutePath));\n }\n\n // ============================================================\n // URL Operations\n // ============================================================\n\n /**\n * Get public URL for file\n */\n public url(location: string): string {\n return url(this.urlPrefix + \"/\" + ltrim(this.applyPrefix(location), \"/\"));\n }\n\n /**\n * Get a temporary signed URL that expires\n * Returns a clean URL with encoded token: {temporaryUrlPrefix}/{token}\n *\n * @param location - File path\n * @param expiresIn - Seconds until expiration (default: 3600)\n */\n public async temporaryUrl(location: string, expiresIn = 3600): Promise<string> {\n if (!this.signatureKey) {\n throw new Error(\n \"Temporary URLs require a signatureKey in LocalDriver options. \" +\n \"Configure storage.drivers.local.signatureKey in your config.\",\n );\n }\n\n const token = this.encodeTemporaryToken(location, expiresIn);\n return `${this.temporaryUrlPrefix}/${token}`;\n }\n\n /**\n * Encode a temporary token containing path, expiry, and signature\n *\n * @param location - File path\n * @param expiresIn - Seconds until expiration\n */\n public encodeTemporaryToken(location: string, expiresIn: number): string {\n if (!this.signatureKey) {\n throw new Error(\"Temporary tokens require a signatureKey\");\n }\n\n const exp = Math.floor(Date.now() / 1000) + expiresIn;\n const sig = crypto\n .createHmac(\"sha256\", this.signatureKey)\n .update(`${location}:${exp}`)\n .digest(\"hex\");\n\n const payload: TemporaryTokenPayload = { path: location, exp, sig };\n const json = JSON.stringify(payload);\n\n // Use base64url encoding (URL-safe base64)\n return Buffer.from(json).toString(\"base64url\");\n }\n\n /**\n * Validate a temporary URL token\n * Returns a result object with validation status, file info, and convenience methods\n *\n * @param token - The token from the URL\n */\n public async validateTemporaryToken(token: string): Promise<TemporaryTokenValidation> {\n // Check signature key\n if (!this.signatureKey) {\n return { valid: false, error: \"missing_key\" };\n }\n\n // Decode token\n let payload: TemporaryTokenPayload;\n try {\n const json = Buffer.from(token, \"base64url\").toString(\"utf-8\");\n payload = JSON.parse(json);\n } catch {\n return { valid: false, error: \"invalid_token\" };\n }\n\n // Validate payload structure\n if (!payload.path || !payload.exp || !payload.sig) {\n return { valid: false, error: \"invalid_token\" };\n }\n\n // Check expiration\n const now = Math.floor(Date.now() / 1000);\n if (payload.exp < now) {\n return { valid: false, error: \"expired\" };\n }\n\n // Verify signature\n const expectedSig = crypto\n .createHmac(\"sha256\", this.signatureKey)\n .update(`${payload.path}:${payload.exp}`)\n .digest(\"hex\");\n\n const sigBuffer = Buffer.from(payload.sig, \"hex\");\n const expectedBuffer = Buffer.from(expectedSig, \"hex\");\n\n if (sigBuffer.length !== expectedBuffer.length) {\n return { valid: false, error: \"invalid_signature\" };\n }\n\n const isValidSig = crypto.timingSafeEqual(\n new Uint8Array(sigBuffer),\n new Uint8Array(expectedBuffer),\n );\n\n if (!isValidSig) {\n return { valid: false, error: \"invalid_signature\" };\n }\n\n // Check file exists\n const absolutePath = this.getAbsolutePath(payload.path);\n if (!(await fileExistsAsync(absolutePath))) {\n return { valid: false, error: \"file_not_found\" };\n }\n\n // Build successful result with convenience methods\n const result: TemporaryTokenValidation = {\n valid: true,\n path: payload.path,\n absolutePath,\n expiresAt: new Date(payload.exp * 1000),\n mimeType: this.guessMimeType(payload.path),\n driver: this,\n getFile: () => this.get(payload.path),\n getStream: () => this.getStream(payload.path),\n };\n\n return result;\n }\n\n // ============================================================\n // Metadata Operations\n // ============================================================\n\n /**\n * Get file info/metadata without downloading\n */\n public async metadata(location: string): Promise<StorageFileInfo> {\n const absolutePath = this.getAbsolutePath(location);\n\n if (!(await fileExistsAsync(absolutePath))) {\n throw new Error(`File not found: ${absolutePath}`);\n }\n\n const stats = await stat(absolutePath);\n const name = location.split(\"/\").pop() || \"\";\n\n return {\n path: location,\n name,\n size: stats.size,\n isDirectory: stats.isDirectory(),\n lastModified: stats.mtime,\n mimeType: this.guessMimeType(location),\n };\n }\n\n /**\n * Get file size in bytes (shortcut for metadata().size)\n */\n public async size(location: string): Promise<number> {\n const metadata = await this.metadata(location);\n return metadata.size;\n }\n\n // ============================================================\n // File Operations\n // ============================================================\n\n /**\n * Copy file to a new location\n */\n public async copy(from: string, to: string): Promise<StorageFileData> {\n const fromPath = this.getAbsolutePath(from);\n const toPath = this.getAbsolutePath(to);\n\n if (!(await fileExistsAsync(fromPath))) {\n throw new Error(`Source file not found: ${from}`);\n }\n\n await ensureDirectoryAsync(dirname(toPath));\n await copyFile(fromPath, toPath);\n\n const hash = await this.hashFile(toPath);\n const stats = await stat(toPath);\n\n return {\n path: this.applyPrefix(to),\n url: this.url(to),\n size: stats.size,\n hash,\n mimeType: this.guessMimeType(to),\n driver: this.name,\n };\n }\n\n /**\n * Move file to a new location\n */\n public async move(from: string, to: string): Promise<StorageFileData> {\n const fromPath = this.getAbsolutePath(from);\n const toPath = this.getAbsolutePath(to);\n\n if (!(await fileExistsAsync(fromPath))) {\n throw new Error(`Source file not found: ${from}`);\n }\n\n await ensureDirectoryAsync(dirname(toPath));\n await rename(fromPath, toPath);\n await this.purgeImageVariants(fromPath);\n\n const hash = await this.hashFile(toPath);\n const stats = await stat(toPath);\n\n return {\n path: this.applyPrefix(to),\n url: this.url(to),\n size: stats.size,\n hash,\n mimeType: this.guessMimeType(to),\n driver: this.name,\n };\n }\n\n /**\n * List files in a directory\n */\n public async list(directory: string, options?: ListOptions): Promise<StorageFileInfo[]> {\n const absolutePath = this.getAbsolutePath(directory);\n const files: StorageFileInfo[] = [];\n\n // A listing target is a DIRECTORY, so guard with `directoryExistsAsync`.\n // `fileExistsAsync` resolves `false` for a folder, which would make `list`\n // always return [] for a real, populated directory.\n if (!(await directoryExistsAsync(absolutePath))) {\n return files;\n }\n\n const entries = await readdir(absolutePath, { withFileTypes: true });\n\n for (const entry of entries) {\n const entryPath = join(directory, entry.name);\n const entryStats = await stat(this.getAbsolutePath(entryPath));\n\n files.push({\n path: entryPath,\n name: entry.name,\n size: entryStats.size,\n isDirectory: entry.isDirectory(),\n lastModified: entryStats.mtime,\n mimeType: entry.isFile() ? this.guessMimeType(entry.name) : undefined,\n });\n\n // Recursively list subdirectories if requested\n if (options?.recursive && entry.isDirectory()) {\n const subFiles = await this.list(entryPath, options);\n files.push(...subFiles);\n }\n\n // Respect limit\n if (options?.limit && files.length >= options.limit) {\n break;\n }\n }\n\n return files;\n }\n\n // ============================================================\n // Path Operations\n // ============================================================\n\n /**\n * Get absolute filesystem path for a location\n */\n public path(location: string): string {\n return this.getAbsolutePath(location);\n }\n\n /**\n * Get the storage root directory\n */\n public getRoot(): string {\n return this.root;\n }\n\n // ============================================================\n // Utilities\n // ============================================================\n\n /**\n * Remove the cached image derivatives of a file that was just deleted or\n * moved away. Best effort: the file operation has already succeeded, so a\n * cache that cannot be cleared is logged, never thrown.\n */\n protected async purgeImageVariants(absolutePath: string): Promise<void> {\n try {\n await purgeImageVariantsOfFile(this.root, absolutePath);\n } catch (error) {\n log.warn(\n \"storage.local\",\n \"purge-image-variants\",\n `Could not remove cached image variants: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n /**\n * Get absolute file path\n *\n * Routes through {@link resolveWithinRoot} so a location can never escape\n * the configured storage root via `..` traversal, an absolute path, or a\n * prefix breakout.\n */\n protected getAbsolutePath(location: string): string {\n const prefixedLocation = this.applyPrefix(location);\n const resolved = resolveWithinRoot(this.root, prefixedLocation);\n\n // The prefix is a containment boundary too: \"../t2/x\" under prefix \"t1\"\n // must not land in a sibling tenant's directory.\n const prefix = storageDriverContext.getPrefix() || this.options.prefix;\n\n if (prefix) {\n const prefixRoot = resolveWithinRoot(this.root, prefix.replace(/^[\\\\/]+|[\\\\/]+$/g, \"\"));\n resolveWithinRoot(prefixRoot, resolved);\n }\n\n return resolved;\n }\n\n /**\n * Convert various input types to Buffer\n */\n protected async toBuffer(file: Buffer | string | UploadedFile): Promise<Buffer> {\n if (Buffer.isBuffer(file)) {\n return file;\n }\n\n // A string is always content, never a source path\n if (typeof file === \"string\") {\n return Buffer.from(file);\n }\n\n return file.buffer();\n }\n\n /**\n * Calculate SHA-256 hash\n */\n protected calculateHash(buffer: Buffer): string {\n return crypto.createHash(\"sha256\").update(new Uint8Array(buffer)).digest(\"hex\");\n }\n\n /**\n * Calculate SHA-256 hash of a file by streaming it (constant memory)\n */\n protected async hashFile(absolutePath: string): Promise<string> {\n const hasher = crypto.createHash(\"sha256\");\n\n for await (const chunk of createReadStream(absolutePath)) {\n hasher.update(chunk);\n }\n\n return hasher.digest(\"hex\");\n }\n\n /**\n * Guess MIME type from file extension\n */\n protected guessMimeType(location: string): string {\n return getMimeType(location);\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { storagePath, uploadsPath } from "../utils/paths.mjs";
2
+ import config from "@mongez/config";
3
+
4
+ //#region ../../packages/core/src/storage/local-disk-roots.ts
5
+ let runtimeConfigurations;
6
+ /** The first manager is the singleton; keep storage out of cache-housekeeping imports. */
7
+ function registerLocalDiskConfigurations(read) {
8
+ runtimeConfigurations ??= read;
9
+ }
10
+ /** Configured and runtime-registered local roots, without instantiating any drivers. */
11
+ function configuredLocalDiskRoots() {
12
+ const configured = config.get("storage.drivers", {});
13
+ const runtime = runtimeConfigurations?.();
14
+ const entries = [...Object.values(configured), ...runtime?.values() ?? []];
15
+ if (!Object.hasOwn(configured, "local") && !runtime?.has("local")) entries.push({
16
+ driver: "local",
17
+ root: uploadsPath()
18
+ });
19
+ return entries.filter((entry) => entry.driver === "local").map((entry) => entry.root ?? storagePath());
20
+ }
21
+
22
+ //#endregion
23
+ export { configuredLocalDiskRoots, registerLocalDiskConfigurations };
24
+ //# sourceMappingURL=local-disk-roots.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-disk-roots.mjs","names":[],"sources":["../../../../../../../../packages/core/src/storage/local-disk-roots.ts"],"sourcesContent":["import config from \"@mongez/config\";\nimport { storagePath, uploadsPath } from \"../utils/paths\";\nimport type { StorageDriverConfig } from \"./types\";\n\nlet runtimeConfigurations: (() => ReadonlyMap<string, StorageDriverConfig>) | undefined;\n\n/** The first manager is the singleton; keep storage out of cache-housekeeping imports. */\nexport function registerLocalDiskConfigurations(\n read: () => ReadonlyMap<string, StorageDriverConfig>,\n): void {\n runtimeConfigurations ??= read;\n}\n\n/** Configured and runtime-registered local roots, without instantiating any drivers. */\nexport function configuredLocalDiskRoots(): string[] {\n const configured = config.get(\"storage.drivers\", {}) as Record<string, StorageDriverConfig>;\n const runtime = runtimeConfigurations?.();\n const entries = [...Object.values(configured), ...(runtime?.values() ?? [])];\n if (!Object.hasOwn(configured, \"local\") && !runtime?.has(\"local\")) {\n entries.push({ driver: \"local\", root: uploadsPath() });\n }\n return entries\n .filter((entry) => entry.driver === \"local\")\n .map((entry) => entry.root ?? storagePath());\n}\n"],"mappings":";;;;AAIA,IAAI;;AAGJ,SAAgB,gCACd,MACM;CACN,0BAA0B;AAC5B;;AAGA,SAAgB,2BAAqC;CACnD,MAAM,aAAa,OAAO,IAAI,mBAAmB,CAAC,CAAC;CACnD,MAAM,UAAU,wBAAwB;CACxC,MAAM,UAAU,CAAC,GAAG,OAAO,OAAO,UAAU,GAAG,GAAI,SAAS,OAAO,KAAK,CAAC,CAAE;CAC3E,IAAI,CAAC,OAAO,OAAO,YAAY,OAAO,KAAK,CAAC,SAAS,IAAI,OAAO,GAC9D,QAAQ,KAAK;EAAE,QAAQ;EAAS,MAAM,YAAY;CAAE,CAAC;CAEvD,OAAO,QACJ,QAAQ,UAAU,MAAM,WAAW,OAAO,CAAC,CAC3C,KAAK,UAAU,MAAM,QAAQ,YAAY,CAAC;AAC/C"}
@@ -79,6 +79,20 @@ declare class Storage extends ScopedStorage implements StorageManagerContract {
79
79
  * Called automatically on first driver access.
80
80
  */
81
81
  init(): Promise<void>;
82
+ /**
83
+ * Whether `init()` has run (and `reset()` has not run since).
84
+ */
85
+ get isInitialized(): boolean;
86
+ /**
87
+ * The names of every registered driver configuration, including the
88
+ * built-in `local` one. The test kit's storage fake reads it to replace
89
+ * every driver with a local one.
90
+ */
91
+ driverNames(): StorageDriverName[];
92
+ /**
93
+ * The name of the default driver, once initialized.
94
+ */
95
+ getDefaultName(): StorageDriverName | undefined;
82
96
  /**
83
97
  * Reset storage defaults
84
98
  */
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.mts","names":[],"sources":["../../../../../../../../packages/core/src/storage/storage.ts"],"mappings":"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"}
1
+ {"version":3,"file":"storage.d.mts","names":[],"sources":["../../../../../../../../packages/core/src/storage/storage.ts"],"mappings":"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"}
@@ -7,6 +7,7 @@ import { safeFetchToBuffer } from "./utils/safe-fetch.mjs";
7
7
  import { ScopedStorage } from "./scoped-storage.mjs";
8
8
  import { storageDriverContext } from "./context/storage-driver-context.mjs";
9
9
  import { DOSpacesDriver } from "./drivers/do-spaces-driver.mjs";
10
+ import { registerLocalDiskConfigurations } from "./local-disk-roots.mjs";
10
11
  import { LocalDriver } from "./drivers/local-driver.mjs";
11
12
  import { R2Driver } from "./drivers/r2-driver.mjs";
12
13
  import { S3Driver } from "./drivers/s3-driver.mjs";
@@ -66,6 +67,7 @@ var Storage = class extends ScopedStorage {
66
67
  this.drivers = /* @__PURE__ */ new Map();
67
68
  this.configs = /* @__PURE__ */ new Map();
68
69
  this.initialized = false;
70
+ registerLocalDiskConfigurations(() => this.configs);
69
71
  }
70
72
  /**
71
73
  * Ensure storage is initialized (lazy initialization)
@@ -81,6 +83,26 @@ var Storage = class extends ScopedStorage {
81
83
  this._driver = this.resolveDriver(this.defaultDriverName);
82
84
  }
83
85
  /**
86
+ * Whether `init()` has run (and `reset()` has not run since).
87
+ */
88
+ get isInitialized() {
89
+ return this.initialized;
90
+ }
91
+ /**
92
+ * The names of every registered driver configuration, including the
93
+ * built-in `local` one. The test kit's storage fake reads it to replace
94
+ * every driver with a local one.
95
+ */
96
+ driverNames() {
97
+ return [...this.configs.keys()];
98
+ }
99
+ /**
100
+ * The name of the default driver, once initialized.
101
+ */
102
+ getDefaultName() {
103
+ return this.defaultDriverName ?? void 0;
104
+ }
105
+ /**
84
106
  * Reset storage defaults
85
107
  */
86
108
  reset() {
@@ -1 +1 @@
1
- {"version":3,"file":"storage.mjs","names":[],"sources":["../../../../../../../../packages/core/src/storage/storage.ts"],"sourcesContent":["import events, { type EventSubscription } from \"@mongez/events\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport type { Readable } from \"stream\";\nimport type { UploadedFile } from \"../http\";\nimport { uploadsPath } from \"../utils/paths\";\nimport { storageConfig, storageConfigurations } from \"./config\";\nimport { storageDriverContext } from \"./context/storage-driver-context\";\nimport { DOSpacesDriver } from \"./drivers/do-spaces-driver\";\nimport { LocalDriver } from \"./drivers/local-driver\";\nimport { R2Driver } from \"./drivers/r2-driver\";\nimport { S3Driver } from \"./drivers/s3-driver\";\nimport { ScopedStorage } from \"./scoped-storage\";\nimport { StorageFile } from \"./storage-file\";\nimport { safeFetchToBuffer } from \"./utils/safe-fetch\";\nimport { StorageCapabilityError } from \"./utils/storage-capability-error\";\nimport { StorageNotInitializedError } from \"./utils/storage-not-initialized-error\";\nimport type {\n CloudStorageDriverContract,\n CloudStorageDriverOptions,\n DeleteManyResult,\n FileVisibility,\n ListOptions,\n LocalStorageDriverOptions,\n PresignedOptions,\n PresignedUploadOptions,\n PutFromUrlOptions,\n PutOptions,\n R2StorageDriverOptions,\n StorageCopyEventPayload,\n StorageDriverConfig,\n StorageDriverContract,\n StorageDriverName,\n StorageEventHandler,\n StorageEventPayload,\n StorageEventType,\n StorageFileInfo,\n StorageManagerContract,\n StoragePutEventPayload,\n TemporaryTokenValidation,\n} from \"./types\";\n\n/**\n * Storage Manager\n *\n * Provides a unified interface for file storage operations across multiple\n * drivers (local, S3, R2, DigitalOcean Spaces). Extends `ScopedStorage` to\n * inherit all base operations while adding driver management and events.\n *\n * All operations return `StorageFile` instances for a consistent, rich DX.\n *\n * @example\n * ```typescript\n * // Basic usage (uses default driver)\n * const file = await storage.put(buffer, \"uploads/image.jpg\");\n *\n * // With options\n * const file = await storage.put(buffer, \"uploads/image.jpg\", {\n * mimeType: \"image/jpeg\",\n * cacheControl: \"max-age=31536000\"\n * });\n *\n * // Using specific driver (also returns StorageFile)\n * const file = await storage.use(\"s3\").put(buffer, \"path/to/file\");\n *\n * // Get raw driver for advanced use\n * const driver = storage.driver(\"s3\");\n * const data = await driver.put(buffer, \"path/to/file\"); // Returns StorageFileData\n *\n * // Stream operations for large files\n * const stream = await storage.getStream(\"large-file.zip\");\n * await storage.putStream(readableStream, \"output/file.zip\");\n *\n * // Batch operations\n * const results = await storage.deleteMany([\"file1.txt\", \"file2.txt\"]);\n *\n * // Event hooks\n * storage.on(\"afterPut\", ({ location, file }) => {\n * console.log(`Uploaded ${location}`);\n * });\n * ```\n */\nexport class Storage extends ScopedStorage implements StorageManagerContract {\n /**\n * Registered drivers (cached instances)\n * @internal\n */\n protected drivers = new Map<string, StorageDriverContract>();\n\n /**\n * Driver configurations\n * @internal\n */\n protected configs = new Map<string, StorageDriverConfig>();\n\n /**\n * Default driver name\n * @internal\n */\n protected defaultDriverName!: StorageDriverName;\n\n /**\n * Whether the storage has been initialized\n * @internal\n */\n private initialized = false;\n\n /**\n * Create a new Storage manager instance\n *\n * Uses lazy initialization - driver is resolved on first access.\n */\n public constructor() {\n // Temp placeholder - will be replaced on first access\n super(null as unknown as StorageDriverContract);\n }\n\n /**\n * Ensure storage is initialized (lazy initialization)\n *\n * Called automatically on first driver access.\n */\n public async init(): Promise<void> {\n if (this.initialized) return;\n\n // Mark as initialized FIRST to prevent infinite recursion\n this.initialized = true;\n\n // Get default driver name from config\n\n const defaultName = storageConfig(\"default\", \"local\");\n\n this.defaultDriverName = defaultName as StorageDriverName;\n this.loadDriversFromConfig();\n\n // Now set the actual driver\n this._driver = this.resolveDriver(this.defaultDriverName);\n }\n\n /**\n * Reset storage defaults\n */\n public reset(): void {\n this.initialized = false;\n this.drivers.clear();\n this.configs.clear();\n this.defaultDriverName = null as unknown as StorageDriverName;\n this._driver = null as unknown as StorageDriverContract;\n }\n\n /**\n * Get the currently active driver (context-aware in future)\n *\n * Currently returns the default driver.\n * Will be enhanced to check AsyncLocalStorage context for multi-tenant support.\n *\n * @returns The active storage driver\n * @throws {StorageNotInitializedError} When neither a context driver nor\n * an initialized default driver is available\n */\n public override get activeDriver(): StorageDriverContract {\n // Check context for tenant-specific driver\n const contextDriver = storageDriverContext.getDriver();\n\n if (contextDriver) return contextDriver;\n\n if (!this._driver) throw new StorageNotInitializedError();\n\n return this._driver;\n }\n\n // ============================================================\n // Driver Management\n // ============================================================\n\n /**\n * Load drivers from configuration\n * @internal\n */\n protected loadDriversFromConfig(): void {\n // `activeDriver` is a synchronous getter, so an async resolver can never be\n // honoured. Fail loudly instead of silently ignoring it.\n if (storageConfig(\"resolver\")) {\n throw new Error(\n \"storage.resolver is not supported: use storageDriverContext (per-request driver) for multi-tenant storage.\",\n );\n }\n\n this.registerBuiltInLocalDriver();\n\n const drivers = storageConfig<Record<string, StorageDriverConfig>>(\"drivers\", {});\n\n for (const [name, config] of Object.entries(drivers)) {\n this.configs.set(name, config);\n }\n }\n\n /**\n * Register the built-in `local` driver, rooted at `uploadsPath()`.\n *\n * The storage connector starts unconditionally — unlike database, cache and\n * herald, it does not early-return when `config.get(\"storage\")` is absent —\n * on the stated grounds that `init()` falls back to a built-in local driver so\n * file storage works out of the box. That fallback did not exist: `init()`\n * resolved the default driver *name* and then found no config registered\n * under it, so **any app without `src/config/storage.ts` failed to boot**\n * with `Storage driver \"local\" is not configured`. Only scaffolded apps, which\n * always ship that file, hid it.\n *\n * Registered before the configured drivers so an app that defines its own\n * `local` entry overrides this one rather than fighting it.\n */\n protected registerBuiltInLocalDriver(): void {\n this.configs.set(\n \"local\",\n storageConfigurations.local({\n root: uploadsPath(),\n urlPrefix: \"/uploads\",\n }),\n );\n }\n\n /**\n * Get a scoped storage for a specific driver\n *\n * Returns a `ScopedStorage` instance that wraps the specified driver.\n * Operations on the returned instance also return `StorageFile` objects.\n *\n * @param name - Driver name as defined in configuration\n * @returns ScopedStorage instance for the specified driver\n *\n * @example\n * ```typescript\n * // Upload to S3\n * const s3File = await storage.use(\"s3\").put(buffer, \"images/photo.jpg\");\n *\n * // Upload to local\n * const localFile = await storage.use(\"local\").put(buffer, \"temp/file.txt\");\n *\n * // Both return StorageFile with identical API\n * console.log(s3File.url);\n * console.log(localFile.url);\n * ```\n */\n public use(name: StorageDriverName): ScopedStorage {\n return new ScopedStorage(this.getDriver(name));\n }\n\n /**\n * Get a raw driver instance\n *\n * Returns the underlying driver directly for advanced use cases.\n * Unlike `use()`, calling methods on the raw driver returns\n * `StorageFileData` instead of `StorageFile`.\n *\n * @param name - Driver name as defined in configuration\n * @returns Raw driver instance implementing StorageDriverContract\n *\n * @example\n * ```typescript\n * const driver = storage.getDriver(\"s3\");\n * const data = await driver.put(buffer, \"path/to/file\");\n * // data is StorageFileData, not StorageFile\n * ```\n */\n public getDriver(name: StorageDriverName): StorageDriverContract {\n return this.resolveDriver(name);\n }\n\n /**\n * Get root directory of current driver\n */\n public root(apepndedPath?: string): string {\n const rootPath = this.activeDriver.options?.root || \"\";\n\n return path.join(rootPath, apepndedPath || \"\");\n }\n\n /**\n * Use a cloud storage driver with extended cloud capabilities\n *\n * @param name - Cloud driver name (s3, r2, spaces)\n * @returns Driver instance implementing CloudStorageDriverContract\n * @throws Error if driver doesn't support cloud operations\n *\n * @example\n * ```typescript\n * const cloudDriver = storage.useCloud(\"s3\");\n * const presignedUrl = await cloudDriver.getPresignedUrl(\"private/doc.pdf\");\n * ```\n */\n public useCloud(name: StorageDriverName): CloudStorageDriverContract {\n const instance = this.getDriver(name);\n\n if (!this.isCloudDriver(instance)) {\n throw new Error(`Driver \"${name}\" does not support cloud operations`);\n }\n\n return instance as CloudStorageDriverContract;\n }\n\n /**\n * Register a new driver configuration at runtime\n *\n * Allows dynamic driver registration for multi-tenancy or\n * runtime configuration scenarios.\n *\n * @param name - Unique driver name\n * @param config - Driver configuration\n * @returns This instance for chaining\n *\n * @example\n * ```typescript\n * storage.register(\"tenant-s3\", {\n * driver: \"s3\",\n * bucket: \"tenant-bucket\",\n * region: \"us-east-1\",\n * accessKeyId: process.env.TENANT_AWS_KEY,\n * secretAccessKey: process.env.TENANT_AWS_SECRET\n * });\n *\n * await storage.use(\"tenant-s3\").put(buffer, \"file.txt\");\n * ```\n */\n public register(name: StorageDriverName, config: StorageDriverConfig): this {\n this.configs.set(name, config);\n this.drivers.delete(name); // Clear cached instance\n return this;\n }\n\n /**\n * Set the default driver name\n *\n * @param name - Driver name to use as default\n * @returns This instance for chaining\n *\n * @example\n * ```typescript\n * storage.setDefault(\"s3\");\n * await storage.put(buffer, \"file.txt\"); // Now uses S3\n * ```\n */\n public setDefault(name: StorageDriverName): this {\n this.defaultDriverName = name;\n this._driver = this.getDriver(name);\n return this;\n }\n\n /**\n * Check if current driver is a cloud driver\n *\n * @returns Promise resolving to true if the current driver supports cloud operations\n */\n public async isCloud(): Promise<boolean> {\n return this.isCloudDriver(this.activeDriver);\n }\n\n /**\n * Check if a driver instance supports cloud operations\n * @internal\n */\n protected isCloudDriver(driver: StorageDriverContract): driver is CloudStorageDriverContract {\n return \"getPresignedUrl\" in driver;\n }\n\n // ============================================================\n // Event System\n // ============================================================\n\n /**\n * Register an event handler\n *\n * Subscribe to storage events for logging, analytics, or side effects.\n *\n * @param event - Event type to listen for\n * @param handler - Handler function\n * @returns Event subscription for unsubscribing\n *\n * @example\n * ```typescript\n * // Log all uploads\n * storage.on(\"afterPut\", ({ location, file }) => {\n * console.log(`Uploaded ${file?.size} bytes to ${location}`);\n * });\n *\n * // Track deletions\n * storage.on(\"afterDelete\", ({ location }) => {\n * analytics.track(\"file_deleted\", { path: location });\n * });\n * ```\n */\n public on<T extends StorageEventPayload = StorageEventPayload>(\n event: StorageEventType,\n handler: StorageEventHandler<T>,\n ): EventSubscription {\n return events.subscribe(`storage.${event}`, handler);\n }\n\n /**\n * Remove all handlers for an event type\n *\n * @param event - Event type to remove handlers for\n * @returns This instance for chaining\n *\n * @example\n * ```typescript\n * storage.off(\"afterPut\"); // Remove all afterPut handlers\n * ```\n */\n public off(event: StorageEventType): this {\n events.off(`storage.${event}`);\n return this;\n }\n\n /**\n * Emit an event to all registered handlers\n * @internal\n */\n protected async emit<T extends StorageEventPayload>(\n event: StorageEventType,\n payload: T,\n ): Promise<void> {\n // `triggerAll` is synchronous — it never awaits its handlers, so awaiting it\n // would make async listeners fire-and-forget. `triggerAllAsync` takes the\n // same `(event, ...args)` shape and awaits each handler in turn.\n await events.triggerAllAsync(`storage.${event}`, payload);\n }\n\n // ============================================================\n // Overridden Operations with Events\n // ============================================================\n\n /**\n * Store a file in storage\n *\n * Extends base `put()` with event emission for beforePut/afterPut hooks.\n *\n * @param file - File content as Buffer, string, UploadedFile, or Readable stream\n * @param location - Destination path\n * @param options - Storage options (mimeType, cacheControl, etc.)\n * @returns StorageFile instance with cached metadata\n */\n public override async put(\n file: UploadedFile | Buffer | string | Readable,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFile> {\n const driver = this.activeDriver;\n const buffer = await this.toBuffer(file);\n\n await this.emit<StoragePutEventPayload>(\"beforePut\", {\n driver: driver.name,\n location,\n timestamp: new Date(),\n size: buffer.length,\n });\n\n const result = await driver.put(buffer, location, options);\n\n await this.emit<StoragePutEventPayload>(\"afterPut\", {\n driver: driver.name,\n location,\n timestamp: new Date(),\n file: result,\n });\n\n if (!result.size) {\n result.size = buffer.length;\n }\n\n return StorageFile.fromData(result, driver);\n }\n\n /**\n * Atomically store a file only if nothing exists at `location`.\n *\n * Emits the same beforePut/afterPut events as `put()` when the file is\n * written; emits nothing when the location already exists (`null`).\n * Because the outcome is unknown until the driver returns, both events\n * fire after the write, for the winner only.\n *\n * @throws StorageCapabilityError when the driver has no `putIfAbsent`\n */\n public override async putIfAbsent(\n file: Buffer | string,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFile | null> {\n const driver = this.activeDriver;\n\n if (typeof driver.putIfAbsent !== \"function\") {\n throw new StorageCapabilityError(\"putIfAbsent\", driver.name);\n }\n\n const result = await driver.putIfAbsent(file, location, options);\n\n if (!result) {\n return null;\n }\n\n const size = typeof file === \"string\" ? Buffer.byteLength(file) : file.length;\n\n await this.emit<StoragePutEventPayload>(\"beforePut\", {\n driver: driver.name,\n location,\n timestamp: new Date(),\n size,\n });\n\n await this.emit<StoragePutEventPayload>(\"afterPut\", {\n driver: driver.name,\n location,\n timestamp: new Date(),\n file: result,\n });\n\n if (!result.size) {\n result.size = size;\n }\n\n return StorageFile.fromData(result, driver);\n }\n\n /**\n * Store a file from a readable stream (for large files)\n *\n * Extends base `putStream()` with event emission.\n *\n * @param stream - Readable stream\n * @param location - Destination path\n * @param options - Storage options\n * @returns StorageFile instance with cached metadata\n */\n public override async putStream(\n stream: Readable | string,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFile> {\n const driver = this.activeDriver;\n\n await this.emit<StoragePutEventPayload>(\"beforePut\", {\n driver: driver.name,\n location,\n timestamp: new Date(),\n });\n\n if (typeof stream === \"string\") {\n stream = fs.createReadStream(stream);\n }\n\n const result = await driver.putStream(stream, location, options);\n\n await this.emit<StoragePutEventPayload>(\"afterPut\", {\n driver: driver.name,\n location,\n timestamp: new Date(),\n file: result,\n });\n\n return StorageFile.fromData(result, driver);\n }\n\n /**\n * Store a file from a URL\n *\n * Downloads content from the URL and stores it at the specified location.\n *\n * The download is SSRF-guarded by default: the URL scheme must be\n * https/http, the host must not resolve to a private / loopback /\n * link-local / cloud-metadata address, the body is capped, and the\n * request times out. Tune or relax via the {@link PutFromUrlOptions}\n * guard fields.\n *\n * @param url - Source URL to download from\n * @param location - Destination path\n * @param options - Storage + outbound-download guard options\n * @returns StorageFile instance with cached metadata\n *\n * @example\n * ```typescript\n * const file = await storage.putFromUrl(\n * \"https://example.com/image.jpg\",\n * \"downloads/image.jpg\"\n * );\n * ```\n */\n public async putFromUrl(\n url: string,\n location: string,\n options?: PutFromUrlOptions,\n ): Promise<StorageFile> {\n const { allowPrivateHosts, maxBytes, timeoutMs, allowedSchemes, ...putOptions } = options ?? {};\n\n const result = await safeFetchToBuffer(url, {\n allowPrivateHosts,\n maxBytes,\n timeoutMs,\n allowedSchemes,\n });\n\n if (!result.ok) {\n throw new Error(`Failed to fetch file from URL: ${result.statusText}`);\n }\n\n if (!result.contentType && !putOptions.mimeType) {\n throw new Error(`Failed to fetch file from URL: missing content-type header`);\n }\n\n const mimeType = putOptions.mimeType || result.contentType || undefined;\n\n return this.put(result.buffer, location, { ...putOptions, mimeType });\n }\n\n /**\n * Store a file from base64 encoded string\n *\n * Decodes base64 content (with optional data URL prefix) and stores it.\n *\n * @param base64 - Base64 encoded file content (or data URL)\n * @param location - Destination path\n * @param options - Storage options\n * @returns StorageFile instance with cached metadata\n *\n * @example\n * ```typescript\n * // From plain base64\n * const file = await storage.putFromBase64(base64String, \"images/photo.jpg\");\n *\n * // From data URL (auto-extracts MIME type)\n * const file = await storage.putFromBase64(\n * \"data:image/png;base64,iVBORw0KGgo...\",\n * \"images/photo.png\"\n * );\n * ```\n */\n public async putFromBase64(\n base64: string,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFile> {\n let data = base64;\n let mimeType = options?.mimeType;\n\n if (base64.startsWith(\"data:\")) {\n const match = base64.match(/^data:([^;]+);base64,(.+)$/);\n if (match) {\n const matchedMimeType = match[1];\n const matchedData = match[2];\n\n if (matchedMimeType !== undefined && matchedData !== undefined) {\n mimeType = mimeType || matchedMimeType;\n data = matchedData;\n }\n }\n }\n\n const buffer = Buffer.from(data, \"base64\");\n return this.put(buffer, location, { ...options, mimeType });\n }\n\n /**\n * Retrieve file contents as Buffer\n *\n * Uses the current driver (with async resolution).\n *\n * @param location - File path\n * @returns Buffer containing file contents\n */\n public override async get(location: string): Promise<Buffer> {\n return this.activeDriver.get(location);\n }\n\n /**\n * Get JSON content from a file\n *\n * Downloads and parses JSON file content.\n *\n * @param location - File path\n * @returns Parsed JSON content\n *\n * @example\n * ```typescript\n * const config = await storage.getJson(\"config/settings.json\");\n * console.log(config.apiKey);\n * ```\n */\n public async getJson(location: string): Promise<any> {\n const buffer = await this.get(location);\n return JSON.parse(buffer.toString());\n }\n\n /**\n * Retrieve a file as a readable stream (for large files)\n *\n * @param location - File path\n * @returns Readable stream of file contents\n */\n public override async getStream(location: string): Promise<Readable> {\n return this.activeDriver.getStream(location);\n }\n\n /**\n * Delete a file\n *\n * Extends base `delete()` with event emission.\n *\n * @param location - File path or StorageFile\n * @returns true if deleted, false if not found\n */\n public override async delete(location: string | StorageFile): Promise<boolean> {\n const driver = this.activeDriver;\n const path = typeof location === \"string\" ? location : location.path;\n\n await this.emit<StorageEventPayload>(\"beforeDelete\", {\n driver: driver.name,\n location: path,\n timestamp: new Date(),\n });\n\n const result = await driver.delete(path);\n\n await this.emit<StorageEventPayload>(\"afterDelete\", {\n driver: driver.name,\n location: path,\n timestamp: new Date(),\n });\n\n return result;\n }\n\n /**\n * Delete multiple files at once\n *\n * @param locations - Array of file paths\n * @returns Array of delete results with status for each file\n */\n public override async deleteMany(locations: string[]): Promise<DeleteManyResult[]> {\n return this.activeDriver.deleteMany(locations);\n }\n\n /**\n * Check if a file exists\n *\n * @param location - File path\n * @returns true if file exists\n */\n public override async exists(location: string): Promise<boolean> {\n return this.activeDriver.exists(location);\n }\n\n /**\n * Copy a file to a new location\n *\n * Extends base `copy()` with event emission.\n *\n * @param from - Source path or StorageFile\n * @param to - Destination path\n * @returns StorageFile instance at destination\n */\n public override async copy(from: string | StorageFile, to: string): Promise<StorageFile> {\n const driver = this.activeDriver;\n const fromPath = typeof from === \"string\" ? from : from.path;\n\n await this.emit<StorageCopyEventPayload>(\"beforeCopy\", {\n driver: driver.name,\n location: to,\n from: fromPath,\n to,\n timestamp: new Date(),\n });\n\n const result = await driver.copy(fromPath, to);\n\n await this.emit<StorageCopyEventPayload>(\"afterCopy\", {\n driver: driver.name,\n location: to,\n from: fromPath,\n to,\n timestamp: new Date(),\n file: result,\n });\n\n return StorageFile.fromData(result, driver);\n }\n\n /**\n * Move a file to a new location\n *\n * Extends base `move()` with event emission.\n *\n * @param from - Source path or StorageFile\n * @param to - Destination path\n * @returns StorageFile instance at destination\n */\n public override async move(from: string | StorageFile, to: string): Promise<StorageFile> {\n const driver = this.activeDriver;\n const fromPath = typeof from === \"string\" ? from : from.path;\n\n await this.emit<StorageCopyEventPayload>(\"beforeMove\", {\n driver: driver.name,\n location: to,\n from: fromPath,\n to,\n timestamp: new Date(),\n });\n\n const result = await driver.move(fromPath, to);\n\n await this.emit<StorageCopyEventPayload>(\"afterMove\", {\n driver: driver.name,\n location: to,\n from: fromPath,\n to,\n timestamp: new Date(),\n file: result,\n });\n\n return StorageFile.fromData(result, driver);\n }\n\n /**\n * List files in a directory\n *\n * @param directory - Directory path (defaults to root)\n * @param options - List options (recursive, limit, etc.)\n * @returns Array of file information objects\n */\n public override async list(\n directory?: string,\n options?: ListOptions,\n ): Promise<StorageFileInfo[]> {\n return this.activeDriver.list(directory || \"\", options);\n }\n\n // ============================================================\n // Metadata Operations\n // ============================================================\n\n /**\n * Get file metadata without downloading\n *\n * @param location - File path\n * @returns File information object\n */\n public override async metadata(location: string): Promise<StorageFileInfo> {\n return this.activeDriver.metadata(location);\n }\n\n /**\n * Get file size in bytes\n *\n * @param location - File path\n * @returns File size in bytes\n */\n public override async size(location: string): Promise<number> {\n return this.activeDriver.size(location);\n }\n\n // ============================================================\n // Path Operations (Local Driver Only)\n // ============================================================\n\n /**\n * Get the absolute filesystem path for a location\n *\n * Only available for local driver.\n *\n * @param location - File path\n * @throws Error if current driver is not a local driver\n * @returns Absolute filesystem path\n */\n public async path(location: string): Promise<string> {\n const driver = this.activeDriver;\n\n if (!(\"path\" in driver) || typeof driver.path !== \"function\") {\n throw new Error(\"path() is only available for local storage drivers\");\n }\n\n return driver.path(location);\n }\n\n // ============================================================\n // Cloud-Specific Operations\n // ============================================================\n\n /**\n * Get a presigned URL for downloading a file\n *\n * Only available for cloud drivers.\n *\n * @param location - File path\n * @param options - Presigned URL options (expiresIn)\n * @throws Error if current driver is not a cloud driver\n * @returns Presigned download URL\n *\n * @example\n * ```typescript\n * const url = await storage.getPresignedUrl(\"private/document.pdf\", {\n * expiresIn: 3600 // 1 hour\n * });\n * ```\n */\n public async getPresignedUrl(location: string, options?: PresignedOptions): Promise<string> {\n const driver = this.activeDriver;\n\n if (!this.isCloudDriver(driver)) {\n throw new Error(\"Presigned URLs are only available for cloud storage drivers\");\n }\n\n return driver.getPresignedUrl(location, options);\n }\n\n /**\n * Get a presigned URL for uploading a file directly to cloud storage\n *\n * Only available for cloud drivers.\n *\n * @param location - Destination path\n * @param options - Upload options (expiresIn, contentType, metadata).\n * There is no size cap: a presigned PUT URL cannot enforce one — verify\n * the uploaded size server-side or use a presigned POST policy instead.\n * @throws Error if current driver is not a cloud driver\n * @returns Presigned upload URL\n *\n * @example\n * ```typescript\n * const uploadUrl = await storage.getPresignedUploadUrl(\"uploads/file.pdf\", {\n * expiresIn: 3600,\n * contentType: \"application/pdf\"\n * });\n *\n * // Client can PUT directly to this URL\n * ```\n */\n public async getPresignedUploadUrl(\n location: string,\n options?: PresignedUploadOptions,\n ): Promise<string> {\n const driver = this.activeDriver;\n\n if (!this.isCloudDriver(driver)) {\n throw new Error(\"Presigned upload URLs are only available for cloud storage drivers\");\n }\n\n return driver.getPresignedUploadUrl(location, options);\n }\n\n /**\n * Get the bucket name for cloud storage\n *\n * Only available for cloud drivers.\n *\n * @throws Error if current driver is not a cloud driver\n * @returns Bucket name\n */\n public async getBucket(): Promise<string> {\n const driver = this.activeDriver;\n\n if (!this.isCloudDriver(driver)) {\n throw new Error(\"Bucket information is only available for cloud storage drivers\");\n }\n\n return driver.getBucket();\n }\n\n /**\n * Get the region for cloud storage\n *\n * Only available for cloud drivers.\n *\n * @throws Error if current driver is not a cloud driver\n * @returns Region name\n */\n public async getRegion(): Promise<string> {\n const driver = this.activeDriver;\n\n if (!this.isCloudDriver(driver)) {\n throw new Error(\"Region information is only available for cloud storage drivers\");\n }\n\n return driver.getRegion();\n }\n\n /**\n * Set storage class for a file (e.g., STANDARD, GLACIER, etc.)\n *\n * Only available for cloud drivers.\n *\n * @param location - File path\n * @param storageClass - Target storage class\n * @throws Error if current driver is not a cloud driver\n */\n public async setStorageClass(location: string, storageClass: string): Promise<void> {\n const driver = this.activeDriver;\n\n if (!this.isCloudDriver(driver)) {\n throw new Error(\"Storage class is only available for cloud storage drivers\");\n }\n\n return driver.setStorageClass(location, storageClass);\n }\n\n /**\n * Set file visibility (public or private)\n *\n * Only available for cloud drivers.\n *\n * @param location - File path\n * @param visibility - \"public\" or \"private\"\n * @throws Error if current driver is not a cloud driver\n */\n public async setVisibility(location: string, visibility: FileVisibility): Promise<void> {\n const driver = this.activeDriver;\n\n if (!this.isCloudDriver(driver)) {\n throw new Error(\"Visibility is only available for cloud storage drivers\");\n }\n\n return driver.setVisibility(location, visibility);\n }\n\n /**\n * Get file visibility\n *\n * Only available for cloud drivers.\n *\n * @param location - File path\n * @throws Error if current driver is not a cloud driver\n * @returns Current visibility setting\n */\n public async getVisibility(location: string): Promise<FileVisibility> {\n const driver = this.activeDriver;\n\n if (!this.isCloudDriver(driver)) {\n throw new Error(\"Visibility is only available for cloud storage drivers\");\n }\n\n return driver.getVisibility(location);\n }\n\n /**\n * Get a temporary signed URL\n *\n * Creates a URL that provides temporary access to the file.\n *\n * @param location - File path\n * @param expiresIn - Seconds until expiration (default: 3600)\n * @returns Signed URL string\n */\n public override async temporaryUrl(location: string, expiresIn?: number): Promise<string> {\n return this.activeDriver.temporaryUrl(location, expiresIn);\n }\n\n /**\n * Validate a temporary URL token\n *\n * For local driver: validates HMAC-signed tokens\n * For cloud drivers: returns invalid (cloud validates via presigned URL)\n *\n * @param token - The token from the temporary URL\n * @returns Validation result with file info and convenience methods\n *\n * @example\n * ```typescript\n * const result = await storage.validateTemporaryToken(token);\n *\n * if (!result.valid) {\n * return response.status(403).send(result.error);\n * }\n *\n * // For local driver - use sendFile for efficiency\n * if (result.absolutePath) {\n * return response.sendFile(result.absolutePath);\n * }\n *\n * // For cloud driver - stream the file\n * const stream = await result.getStream!();\n * stream.pipe(response.raw);\n * ```\n */\n public async validateTemporaryToken(token: string): Promise<TemporaryTokenValidation> {\n // Check if driver supports token validation\n if (\n !(\"validateTemporaryToken\" in this.activeDriver) ||\n typeof this.activeDriver.validateTemporaryToken !== \"function\"\n ) {\n // For cloud drivers, temporary URLs are presigned and validated by the cloud provider\n return {\n valid: false,\n error: \"invalid_token\",\n };\n }\n\n return this.activeDriver.validateTemporaryToken(token);\n }\n\n // ============================================================\n // Configuration Parsing\n // ============================================================\n\n /**\n * Parse config into driver-specific options\n * @internal\n */\n protected parseOptions(\n config: StorageDriverConfig,\n ): LocalStorageDriverOptions | CloudStorageDriverOptions | R2StorageDriverOptions {\n const { driver, ...options } = config;\n\n switch (driver) {\n case \"local\":\n return {\n root: options.root,\n prefix: options.prefix,\n urlPrefix: options.urlPrefix,\n temporaryUrlPrefix: options.temporaryUrlPrefix,\n signatureKey: options.signatureKey,\n } satisfies LocalStorageDriverOptions;\n\n case \"s3\":\n this.validateCloudConfig(config, \"s3\");\n return {\n ...options,\n bucket: options.bucket!,\n region: options.region!,\n accessKeyId: options.accessKeyId,\n secretAccessKey: options.secretAccessKey,\n endpoint: options.endpoint,\n urlPrefix: options.urlPrefix,\n } satisfies CloudStorageDriverOptions;\n\n case \"r2\":\n this.validateCloudConfig(config, \"r2\");\n if (!options.accountId) {\n throw new Error('R2 driver requires \"accountId\" configuration');\n }\n\n return {\n ...options,\n region: options.region || \"auto\",\n bucket: options.bucket!,\n accessKeyId: options.accessKeyId,\n secretAccessKey: options.secretAccessKey,\n endpoint: options.endpoint,\n urlPrefix: options.urlPrefix,\n accountId: options.accountId,\n publicDomain: options.publicDomain,\n } satisfies R2StorageDriverOptions;\n\n case \"spaces\":\n this.validateCloudConfig(config, \"spaces\");\n return {\n ...options,\n bucket: options.bucket!,\n region: options.region!,\n accessKeyId: options.accessKeyId,\n secretAccessKey: options.secretAccessKey,\n endpoint: options.endpoint,\n urlPrefix: options.urlPrefix,\n } satisfies CloudStorageDriverOptions;\n\n default:\n throw new Error(`Unknown driver type: ${driver}`);\n }\n }\n\n /**\n * Validate cloud driver configuration has required fields\n * @internal\n */\n protected validateCloudConfig(config: StorageDriverConfig, driverName: string): void {\n // Credentials are optional: when absent, the AWS default provider chain\n // applies (IAM roles, ECS task roles, IRSA, SSO profiles).\n const required = [\"bucket\"];\n\n if (driverName !== \"r2\") {\n required.push(\"region\");\n }\n\n for (const field of required) {\n if (!config[field as keyof StorageDriverConfig]) {\n throw new Error(`${driverName.toUpperCase()} driver requires \"${field}\" configuration`);\n }\n }\n\n if (Boolean(config.accessKeyId) !== Boolean(config.secretAccessKey)) {\n throw new Error(\n `${driverName.toUpperCase()} driver requires both \"accessKeyId\" and \"secretAccessKey\", or neither`,\n );\n }\n }\n\n /**\n * Get or create driver instance from cache\n * @internal\n */\n protected resolveDriver(name: string): StorageDriverContract {\n // Ensure configs are loaded\n\n if (this.drivers.has(name)) {\n return this.drivers.get(name)!;\n }\n\n const config = this.configs.get(name);\n\n if (!config) {\n throw new Error(`Storage driver \"${name}\" is not configured`);\n }\n\n const options = this.parseOptions(config);\n let driver: StorageDriverContract;\n\n switch (config.driver) {\n case \"local\":\n driver = new LocalDriver(options as LocalStorageDriverOptions);\n break;\n case \"s3\":\n driver = new S3Driver(options as CloudStorageDriverOptions);\n break;\n case \"r2\":\n driver = new R2Driver(options as R2StorageDriverOptions);\n break;\n case \"spaces\":\n driver = new DOSpacesDriver(options as CloudStorageDriverOptions);\n break;\n default:\n throw new Error(`Unknown storage driver type: ${config.driver}`);\n }\n\n this.drivers.set(name, driver);\n return driver;\n }\n}\n\n/**\n * Singleton storage instance\n *\n * Pre-configured storage manager ready for use throughout the application.\n *\n * @example\n * ```typescript\n * import { storage } from \"@warlock.js/core\";\n *\n * const file = await storage.put(buffer, \"uploads/file.txt\");\n * ```\n */\nexport const storage = new Storage();\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkFA,IAAa,UAAb,cAA6B,cAAgD;;;;;;CA8B3E,AAAO,cAAc;EAEnB,MAAM,IAAwC;iCA3B5B,IAAI,IAAmC;iCAMvC,IAAI,IAAiC;qBAYnC;CAUtB;;;;;;CAOA,MAAa,OAAsB;EACjC,IAAI,KAAK,aAAa;EAGtB,KAAK,cAAc;EAInB,MAAM,cAAc,cAAc,WAAW,OAAO;EAEpD,KAAK,oBAAoB;EACzB,KAAK,sBAAsB;EAG3B,KAAK,UAAU,KAAK,cAAc,KAAK,iBAAiB;CAC1D;;;;CAKA,AAAO,QAAc;EACnB,KAAK,cAAc;EACnB,KAAK,QAAQ,MAAM;EACnB,KAAK,QAAQ,MAAM;EACnB,KAAK,oBAAoB;EACzB,KAAK,UAAU;CACjB;;;;;;;;;;;CAYA,IAAoB,eAAsC;EAExD,MAAM,gBAAgB,qBAAqB,UAAU;EAErD,IAAI,eAAe,OAAO;EAE1B,IAAI,CAAC,KAAK,SAAS,MAAM,IAAI,2BAA2B;EAExD,OAAO,KAAK;CACd;;;;;CAUA,AAAU,wBAA8B;EAGtC,IAAI,cAAc,UAAU,GAC1B,MAAM,IAAI,MACR,4GACF;EAGF,KAAK,2BAA2B;EAEhC,MAAM,UAAU,cAAmD,WAAW,CAAC,CAAC;EAEhF,KAAK,MAAM,CAAC,MAAM,WAAW,OAAO,QAAQ,OAAO,GACjD,KAAK,QAAQ,IAAI,MAAM,MAAM;CAEjC;;;;;;;;;;;;;;;;CAiBA,AAAU,6BAAmC;EAC3C,KAAK,QAAQ,IACX,SACA,sBAAsB,MAAM;GAC1B,MAAM,YAAY;GAClB,WAAW;EACb,CAAC,CACH;CACF;;;;;;;;;;;;;;;;;;;;;;;CAwBA,AAAO,IAAI,MAAwC;EACjD,OAAO,IAAI,cAAc,KAAK,UAAU,IAAI,CAAC;CAC/C;;;;;;;;;;;;;;;;;;CAmBA,AAAO,UAAU,MAAgD;EAC/D,OAAO,KAAK,cAAc,IAAI;CAChC;;;;CAKA,AAAO,KAAK,cAA+B;EACzC,MAAM,WAAW,KAAK,aAAa,SAAS,QAAQ;EAEpD,OAAO,KAAK,KAAK,UAAU,gBAAgB,EAAE;CAC/C;;;;;;;;;;;;;;CAeA,AAAO,SAAS,MAAqD;EACnE,MAAM,WAAW,KAAK,UAAU,IAAI;EAEpC,IAAI,CAAC,KAAK,cAAc,QAAQ,GAC9B,MAAM,IAAI,MAAM,WAAW,KAAK,oCAAoC;EAGtE,OAAO;CACT;;;;;;;;;;;;;;;;;;;;;;;;CAyBA,AAAO,SAAS,MAAyB,QAAmC;EAC1E,KAAK,QAAQ,IAAI,MAAM,MAAM;EAC7B,KAAK,QAAQ,OAAO,IAAI;EACxB,OAAO;CACT;;;;;;;;;;;;;CAcA,AAAO,WAAW,MAA+B;EAC/C,KAAK,oBAAoB;EACzB,KAAK,UAAU,KAAK,UAAU,IAAI;EAClC,OAAO;CACT;;;;;;CAOA,MAAa,UAA4B;EACvC,OAAO,KAAK,cAAc,KAAK,YAAY;CAC7C;;;;;CAMA,AAAU,cAAc,QAAqE;EAC3F,OAAO,qBAAqB;CAC9B;;;;;;;;;;;;;;;;;;;;;;;CA4BA,AAAO,GACL,OACA,SACmB;EACnB,OAAO,OAAO,UAAU,WAAW,SAAS,OAAO;CACrD;;;;;;;;;;;;CAaA,AAAO,IAAI,OAA+B;EACxC,OAAO,IAAI,WAAW,OAAO;EAC7B,OAAO;CACT;;;;;CAMA,MAAgB,KACd,OACA,SACe;EAIf,MAAM,OAAO,gBAAgB,WAAW,SAAS,OAAO;CAC1D;;;;;;;;;;;CAgBA,MAAsB,IACpB,MACA,UACA,SACsB;EACtB,MAAM,SAAS,KAAK;EACpB,MAAM,SAAS,MAAM,KAAK,SAAS,IAAI;EAEvC,MAAM,KAAK,KAA6B,aAAa;GACnD,QAAQ,OAAO;GACf;GACA,2BAAW,IAAI,KAAK;GACpB,MAAM,OAAO;EACf,CAAC;EAED,MAAM,SAAS,MAAM,OAAO,IAAI,QAAQ,UAAU,OAAO;EAEzD,MAAM,KAAK,KAA6B,YAAY;GAClD,QAAQ,OAAO;GACf;GACA,2BAAW,IAAI,KAAK;GACpB,MAAM;EACR,CAAC;EAED,IAAI,CAAC,OAAO,MACV,OAAO,OAAO,OAAO;EAGvB,OAAO,YAAY,SAAS,QAAQ,MAAM;CAC5C;;;;;;;;;;;CAYA,MAAsB,YACpB,MACA,UACA,SAC6B;EAC7B,MAAM,SAAS,KAAK;EAEpB,IAAI,OAAO,OAAO,gBAAgB,YAChC,MAAM,IAAI,uBAAuB,eAAe,OAAO,IAAI;EAG7D,MAAM,SAAS,MAAM,OAAO,YAAY,MAAM,UAAU,OAAO;EAE/D,IAAI,CAAC,QACH,OAAO;EAGT,MAAM,OAAO,OAAO,SAAS,WAAW,OAAO,WAAW,IAAI,IAAI,KAAK;EAEvE,MAAM,KAAK,KAA6B,aAAa;GACnD,QAAQ,OAAO;GACf;GACA,2BAAW,IAAI,KAAK;GACpB;EACF,CAAC;EAED,MAAM,KAAK,KAA6B,YAAY;GAClD,QAAQ,OAAO;GACf;GACA,2BAAW,IAAI,KAAK;GACpB,MAAM;EACR,CAAC;EAED,IAAI,CAAC,OAAO,MACV,OAAO,OAAO;EAGhB,OAAO,YAAY,SAAS,QAAQ,MAAM;CAC5C;;;;;;;;;;;CAYA,MAAsB,UACpB,QACA,UACA,SACsB;EACtB,MAAM,SAAS,KAAK;EAEpB,MAAM,KAAK,KAA6B,aAAa;GACnD,QAAQ,OAAO;GACf;GACA,2BAAW,IAAI,KAAK;EACtB,CAAC;EAED,IAAI,OAAO,WAAW,UACpB,SAAS,GAAG,iBAAiB,MAAM;EAGrC,MAAM,SAAS,MAAM,OAAO,UAAU,QAAQ,UAAU,OAAO;EAE/D,MAAM,KAAK,KAA6B,YAAY;GAClD,QAAQ,OAAO;GACf;GACA,2BAAW,IAAI,KAAK;GACpB,MAAM;EACR,CAAC;EAED,OAAO,YAAY,SAAS,QAAQ,MAAM;CAC5C;;;;;;;;;;;;;;;;;;;;;;;;;CA0BA,MAAa,WACX,KACA,UACA,SACsB;EACtB,MAAM,EAAE,mBAAmB,UAAU,WAAW,gBAAgB,GAAG,eAAe,WAAW,CAAC;EAE9F,MAAM,SAAS,MAAM,kBAAkB,KAAK;GAC1C;GACA;GACA;GACA;EACF,CAAC;EAED,IAAI,CAAC,OAAO,IACV,MAAM,IAAI,MAAM,kCAAkC,OAAO,YAAY;EAGvE,IAAI,CAAC,OAAO,eAAe,CAAC,WAAW,UACrC,MAAM,IAAI,MAAM,4DAA4D;EAG9E,MAAM,WAAW,WAAW,YAAY,OAAO,eAAe;EAE9D,OAAO,KAAK,IAAI,OAAO,QAAQ,UAAU;GAAE,GAAG;GAAY;EAAS,CAAC;CACtE;;;;;;;;;;;;;;;;;;;;;;;CAwBA,MAAa,cACX,QACA,UACA,SACsB;EACtB,IAAI,OAAO;EACX,IAAI,WAAW,SAAS;EAExB,IAAI,OAAO,WAAW,OAAO,GAAG;GAC9B,MAAM,QAAQ,OAAO,MAAM,4BAA4B;GACvD,IAAI,OAAO;IACT,MAAM,kBAAkB,MAAM;IAC9B,MAAM,cAAc,MAAM;IAE1B,IAAI,oBAAoB,UAAa,gBAAgB,QAAW;KAC9D,WAAW,YAAY;KACvB,OAAO;IACT;GACF;EACF;EAEA,MAAM,SAAS,OAAO,KAAK,MAAM,QAAQ;EACzC,OAAO,KAAK,IAAI,QAAQ,UAAU;GAAE,GAAG;GAAS;EAAS,CAAC;CAC5D;;;;;;;;;CAUA,MAAsB,IAAI,UAAmC;EAC3D,OAAO,KAAK,aAAa,IAAI,QAAQ;CACvC;;;;;;;;;;;;;;;CAgBA,MAAa,QAAQ,UAAgC;EACnD,MAAM,SAAS,MAAM,KAAK,IAAI,QAAQ;EACtC,OAAO,KAAK,MAAM,OAAO,SAAS,CAAC;CACrC;;;;;;;CAQA,MAAsB,UAAU,UAAqC;EACnE,OAAO,KAAK,aAAa,UAAU,QAAQ;CAC7C;;;;;;;;;CAUA,MAAsB,OAAO,UAAkD;EAC7E,MAAM,SAAS,KAAK;EACpB,MAAM,OAAO,OAAO,aAAa,WAAW,WAAW,SAAS;EAEhE,MAAM,KAAK,KAA0B,gBAAgB;GACnD,QAAQ,OAAO;GACf,UAAU;GACV,2BAAW,IAAI,KAAK;EACtB,CAAC;EAED,MAAM,SAAS,MAAM,OAAO,OAAO,IAAI;EAEvC,MAAM,KAAK,KAA0B,eAAe;GAClD,QAAQ,OAAO;GACf,UAAU;GACV,2BAAW,IAAI,KAAK;EACtB,CAAC;EAED,OAAO;CACT;;;;;;;CAQA,MAAsB,WAAW,WAAkD;EACjF,OAAO,KAAK,aAAa,WAAW,SAAS;CAC/C;;;;;;;CAQA,MAAsB,OAAO,UAAoC;EAC/D,OAAO,KAAK,aAAa,OAAO,QAAQ;CAC1C;;;;;;;;;;CAWA,MAAsB,KAAK,MAA4B,IAAkC;EACvF,MAAM,SAAS,KAAK;EACpB,MAAM,WAAW,OAAO,SAAS,WAAW,OAAO,KAAK;EAExD,MAAM,KAAK,KAA8B,cAAc;GACrD,QAAQ,OAAO;GACf,UAAU;GACV,MAAM;GACN;GACA,2BAAW,IAAI,KAAK;EACtB,CAAC;EAED,MAAM,SAAS,MAAM,OAAO,KAAK,UAAU,EAAE;EAE7C,MAAM,KAAK,KAA8B,aAAa;GACpD,QAAQ,OAAO;GACf,UAAU;GACV,MAAM;GACN;GACA,2BAAW,IAAI,KAAK;GACpB,MAAM;EACR,CAAC;EAED,OAAO,YAAY,SAAS,QAAQ,MAAM;CAC5C;;;;;;;;;;CAWA,MAAsB,KAAK,MAA4B,IAAkC;EACvF,MAAM,SAAS,KAAK;EACpB,MAAM,WAAW,OAAO,SAAS,WAAW,OAAO,KAAK;EAExD,MAAM,KAAK,KAA8B,cAAc;GACrD,QAAQ,OAAO;GACf,UAAU;GACV,MAAM;GACN;GACA,2BAAW,IAAI,KAAK;EACtB,CAAC;EAED,MAAM,SAAS,MAAM,OAAO,KAAK,UAAU,EAAE;EAE7C,MAAM,KAAK,KAA8B,aAAa;GACpD,QAAQ,OAAO;GACf,UAAU;GACV,MAAM;GACN;GACA,2BAAW,IAAI,KAAK;GACpB,MAAM;EACR,CAAC;EAED,OAAO,YAAY,SAAS,QAAQ,MAAM;CAC5C;;;;;;;;CASA,MAAsB,KACpB,WACA,SAC4B;EAC5B,OAAO,KAAK,aAAa,KAAK,aAAa,IAAI,OAAO;CACxD;;;;;;;CAYA,MAAsB,SAAS,UAA4C;EACzE,OAAO,KAAK,aAAa,SAAS,QAAQ;CAC5C;;;;;;;CAQA,MAAsB,KAAK,UAAmC;EAC5D,OAAO,KAAK,aAAa,KAAK,QAAQ;CACxC;;;;;;;;;;CAeA,MAAa,KAAK,UAAmC;EACnD,MAAM,SAAS,KAAK;EAEpB,IAAI,EAAE,UAAU,WAAW,OAAO,OAAO,SAAS,YAChD,MAAM,IAAI,MAAM,oDAAoD;EAGtE,OAAO,OAAO,KAAK,QAAQ;CAC7B;;;;;;;;;;;;;;;;;;CAuBA,MAAa,gBAAgB,UAAkB,SAA6C;EAC1F,MAAM,SAAS,KAAK;EAEpB,IAAI,CAAC,KAAK,cAAc,MAAM,GAC5B,MAAM,IAAI,MAAM,6DAA6D;EAG/E,OAAO,OAAO,gBAAgB,UAAU,OAAO;CACjD;;;;;;;;;;;;;;;;;;;;;;;CAwBA,MAAa,sBACX,UACA,SACiB;EACjB,MAAM,SAAS,KAAK;EAEpB,IAAI,CAAC,KAAK,cAAc,MAAM,GAC5B,MAAM,IAAI,MAAM,oEAAoE;EAGtF,OAAO,OAAO,sBAAsB,UAAU,OAAO;CACvD;;;;;;;;;CAUA,MAAa,YAA6B;EACxC,MAAM,SAAS,KAAK;EAEpB,IAAI,CAAC,KAAK,cAAc,MAAM,GAC5B,MAAM,IAAI,MAAM,gEAAgE;EAGlF,OAAO,OAAO,UAAU;CAC1B;;;;;;;;;CAUA,MAAa,YAA6B;EACxC,MAAM,SAAS,KAAK;EAEpB,IAAI,CAAC,KAAK,cAAc,MAAM,GAC5B,MAAM,IAAI,MAAM,gEAAgE;EAGlF,OAAO,OAAO,UAAU;CAC1B;;;;;;;;;;CAWA,MAAa,gBAAgB,UAAkB,cAAqC;EAClF,MAAM,SAAS,KAAK;EAEpB,IAAI,CAAC,KAAK,cAAc,MAAM,GAC5B,MAAM,IAAI,MAAM,2DAA2D;EAG7E,OAAO,OAAO,gBAAgB,UAAU,YAAY;CACtD;;;;;;;;;;CAWA,MAAa,cAAc,UAAkB,YAA2C;EACtF,MAAM,SAAS,KAAK;EAEpB,IAAI,CAAC,KAAK,cAAc,MAAM,GAC5B,MAAM,IAAI,MAAM,wDAAwD;EAG1E,OAAO,OAAO,cAAc,UAAU,UAAU;CAClD;;;;;;;;;;CAWA,MAAa,cAAc,UAA2C;EACpE,MAAM,SAAS,KAAK;EAEpB,IAAI,CAAC,KAAK,cAAc,MAAM,GAC5B,MAAM,IAAI,MAAM,wDAAwD;EAG1E,OAAO,OAAO,cAAc,QAAQ;CACtC;;;;;;;;;;CAWA,MAAsB,aAAa,UAAkB,WAAqC;EACxF,OAAO,KAAK,aAAa,aAAa,UAAU,SAAS;CAC3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BA,MAAa,uBAAuB,OAAkD;EAEpF,IACE,EAAE,4BAA4B,KAAK,iBACnC,OAAO,KAAK,aAAa,2BAA2B,YAGpD,OAAO;GACL,OAAO;GACP,OAAO;EACT;EAGF,OAAO,KAAK,aAAa,uBAAuB,KAAK;CACvD;;;;;CAUA,AAAU,aACR,QACgF;EAChF,MAAM,EAAE,QAAQ,GAAG,YAAY;EAE/B,QAAQ,QAAR;GACE,KAAK,SACH,OAAO;IACL,MAAM,QAAQ;IACd,QAAQ,QAAQ;IAChB,WAAW,QAAQ;IACnB,oBAAoB,QAAQ;IAC5B,cAAc,QAAQ;GACxB;GAEF,KAAK;IACH,KAAK,oBAAoB,QAAQ,IAAI;IACrC,OAAO;KACL,GAAG;KACH,QAAQ,QAAQ;KAChB,QAAQ,QAAQ;KAChB,aAAa,QAAQ;KACrB,iBAAiB,QAAQ;KACzB,UAAU,QAAQ;KAClB,WAAW,QAAQ;IACrB;GAEF,KAAK;IACH,KAAK,oBAAoB,QAAQ,IAAI;IACrC,IAAI,CAAC,QAAQ,WACX,MAAM,IAAI,MAAM,gDAA8C;IAGhE,OAAO;KACL,GAAG;KACH,QAAQ,QAAQ,UAAU;KAC1B,QAAQ,QAAQ;KAChB,aAAa,QAAQ;KACrB,iBAAiB,QAAQ;KACzB,UAAU,QAAQ;KAClB,WAAW,QAAQ;KACnB,WAAW,QAAQ;KACnB,cAAc,QAAQ;IACxB;GAEF,KAAK;IACH,KAAK,oBAAoB,QAAQ,QAAQ;IACzC,OAAO;KACL,GAAG;KACH,QAAQ,QAAQ;KAChB,QAAQ,QAAQ;KAChB,aAAa,QAAQ;KACrB,iBAAiB,QAAQ;KACzB,UAAU,QAAQ;KAClB,WAAW,QAAQ;IACrB;GAEF,SACE,MAAM,IAAI,MAAM,wBAAwB,QAAQ;EACpD;CACF;;;;;CAMA,AAAU,oBAAoB,QAA6B,YAA0B;EAGnF,MAAM,WAAW,CAAC,QAAQ;EAE1B,IAAI,eAAe,MACjB,SAAS,KAAK,QAAQ;EAGxB,KAAK,MAAM,SAAS,UAClB,IAAI,CAAC,OAAO,QACV,MAAM,IAAI,MAAM,GAAG,WAAW,YAAY,EAAE,oBAAoB,MAAM,gBAAgB;EAI1F,IAAI,QAAQ,OAAO,WAAW,MAAM,QAAQ,OAAO,eAAe,GAChE,MAAM,IAAI,MACR,GAAG,WAAW,YAAY,EAAE,sEAC9B;CAEJ;;;;;CAMA,AAAU,cAAc,MAAqC;EAG3D,IAAI,KAAK,QAAQ,IAAI,IAAI,GACvB,OAAO,KAAK,QAAQ,IAAI,IAAI;EAG9B,MAAM,SAAS,KAAK,QAAQ,IAAI,IAAI;EAEpC,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,mBAAmB,KAAK,oBAAoB;EAG9D,MAAM,UAAU,KAAK,aAAa,MAAM;EACxC,IAAI;EAEJ,QAAQ,OAAO,QAAf;GACE,KAAK;IACH,SAAS,IAAI,YAAY,OAAoC;IAC7D;GACF,KAAK;IACH,SAAS,IAAI,SAAS,OAAoC;IAC1D;GACF,KAAK;IACH,SAAS,IAAI,SAAS,OAAiC;IACvD;GACF,KAAK;IACH,SAAS,IAAI,eAAe,OAAoC;IAChE;GACF,SACE,MAAM,IAAI,MAAM,gCAAgC,OAAO,QAAQ;EACnE;EAEA,KAAK,QAAQ,IAAI,MAAM,MAAM;EAC7B,OAAO;CACT;AACF;;;;;;;;;;;;;AAcA,MAAa,UAAU,IAAI,QAAQ"}
1
+ {"version":3,"file":"storage.mjs","names":[],"sources":["../../../../../../../../packages/core/src/storage/storage.ts"],"sourcesContent":["import events, { type EventSubscription } from \"@mongez/events\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport type { Readable } from \"stream\";\nimport type { UploadedFile } from \"../http\";\nimport { uploadsPath } from \"../utils/paths\";\nimport { storageConfig, storageConfigurations } from \"./config\";\nimport { storageDriverContext } from \"./context/storage-driver-context\";\nimport { DOSpacesDriver } from \"./drivers/do-spaces-driver\";\nimport { LocalDriver } from \"./drivers/local-driver\";\nimport { R2Driver } from \"./drivers/r2-driver\";\nimport { S3Driver } from \"./drivers/s3-driver\";\nimport { ScopedStorage } from \"./scoped-storage\";\nimport { StorageFile } from \"./storage-file\";\nimport { registerLocalDiskConfigurations } from \"./local-disk-roots\";\nimport { safeFetchToBuffer } from \"./utils/safe-fetch\";\nimport { StorageCapabilityError } from \"./utils/storage-capability-error\";\nimport { StorageNotInitializedError } from \"./utils/storage-not-initialized-error\";\nimport type {\n CloudStorageDriverContract,\n CloudStorageDriverOptions,\n DeleteManyResult,\n FileVisibility,\n ListOptions,\n LocalStorageDriverOptions,\n PresignedOptions,\n PresignedUploadOptions,\n PutFromUrlOptions,\n PutOptions,\n R2StorageDriverOptions,\n StorageCopyEventPayload,\n StorageDriverConfig,\n StorageDriverContract,\n StorageDriverName,\n StorageEventHandler,\n StorageEventPayload,\n StorageEventType,\n StorageFileInfo,\n StorageManagerContract,\n StoragePutEventPayload,\n TemporaryTokenValidation,\n} from \"./types\";\n\n/**\n * Storage Manager\n *\n * Provides a unified interface for file storage operations across multiple\n * drivers (local, S3, R2, DigitalOcean Spaces). Extends `ScopedStorage` to\n * inherit all base operations while adding driver management and events.\n *\n * All operations return `StorageFile` instances for a consistent, rich DX.\n *\n * @example\n * ```typescript\n * // Basic usage (uses default driver)\n * const file = await storage.put(buffer, \"uploads/image.jpg\");\n *\n * // With options\n * const file = await storage.put(buffer, \"uploads/image.jpg\", {\n * mimeType: \"image/jpeg\",\n * cacheControl: \"max-age=31536000\"\n * });\n *\n * // Using specific driver (also returns StorageFile)\n * const file = await storage.use(\"s3\").put(buffer, \"path/to/file\");\n *\n * // Get raw driver for advanced use\n * const driver = storage.driver(\"s3\");\n * const data = await driver.put(buffer, \"path/to/file\"); // Returns StorageFileData\n *\n * // Stream operations for large files\n * const stream = await storage.getStream(\"large-file.zip\");\n * await storage.putStream(readableStream, \"output/file.zip\");\n *\n * // Batch operations\n * const results = await storage.deleteMany([\"file1.txt\", \"file2.txt\"]);\n *\n * // Event hooks\n * storage.on(\"afterPut\", ({ location, file }) => {\n * console.log(`Uploaded ${location}`);\n * });\n * ```\n */\nexport class Storage extends ScopedStorage implements StorageManagerContract {\n /**\n * Registered drivers (cached instances)\n * @internal\n */\n protected drivers = new Map<string, StorageDriverContract>();\n\n /**\n * Driver configurations\n * @internal\n */\n protected configs = new Map<string, StorageDriverConfig>();\n\n /**\n * Default driver name\n * @internal\n */\n protected defaultDriverName!: StorageDriverName;\n\n /**\n * Whether the storage has been initialized\n * @internal\n */\n private initialized = false;\n\n /**\n * Create a new Storage manager instance\n *\n * Uses lazy initialization - driver is resolved on first access.\n */\n public constructor() {\n // Temp placeholder - will be replaced on first access\n super(null as unknown as StorageDriverContract);\n registerLocalDiskConfigurations(() => this.configs);\n }\n\n /**\n * Ensure storage is initialized (lazy initialization)\n *\n * Called automatically on first driver access.\n */\n public async init(): Promise<void> {\n if (this.initialized) return;\n\n // Mark as initialized FIRST to prevent infinite recursion\n this.initialized = true;\n\n // Get default driver name from config\n\n const defaultName = storageConfig(\"default\", \"local\");\n\n this.defaultDriverName = defaultName as StorageDriverName;\n this.loadDriversFromConfig();\n\n // Now set the actual driver\n this._driver = this.resolveDriver(this.defaultDriverName);\n }\n\n /**\n * Whether `init()` has run (and `reset()` has not run since).\n */\n public get isInitialized(): boolean {\n return this.initialized;\n }\n\n /**\n * The names of every registered driver configuration, including the\n * built-in `local` one. The test kit's storage fake reads it to replace\n * every driver with a local one.\n */\n public driverNames(): StorageDriverName[] {\n return [...this.configs.keys()] as StorageDriverName[];\n }\n\n /**\n * The name of the default driver, once initialized.\n */\n public getDefaultName(): StorageDriverName | undefined {\n return this.defaultDriverName ?? undefined;\n }\n\n /**\n * Reset storage defaults\n */\n public reset(): void {\n this.initialized = false;\n this.drivers.clear();\n this.configs.clear();\n this.defaultDriverName = null as unknown as StorageDriverName;\n this._driver = null as unknown as StorageDriverContract;\n }\n\n /**\n * Get the currently active driver (context-aware in future)\n *\n * Currently returns the default driver.\n * Will be enhanced to check AsyncLocalStorage context for multi-tenant support.\n *\n * @returns The active storage driver\n * @throws {StorageNotInitializedError} When neither a context driver nor\n * an initialized default driver is available\n */\n public override get activeDriver(): StorageDriverContract {\n // Check context for tenant-specific driver\n const contextDriver = storageDriverContext.getDriver();\n\n if (contextDriver) return contextDriver;\n\n if (!this._driver) throw new StorageNotInitializedError();\n\n return this._driver;\n }\n\n // ============================================================\n // Driver Management\n // ============================================================\n\n /**\n * Load drivers from configuration\n * @internal\n */\n protected loadDriversFromConfig(): void {\n // `activeDriver` is a synchronous getter, so an async resolver can never be\n // honoured. Fail loudly instead of silently ignoring it.\n if (storageConfig(\"resolver\")) {\n throw new Error(\n \"storage.resolver is not supported: use storageDriverContext (per-request driver) for multi-tenant storage.\",\n );\n }\n\n this.registerBuiltInLocalDriver();\n\n const drivers = storageConfig<Record<string, StorageDriverConfig>>(\"drivers\", {});\n\n for (const [name, config] of Object.entries(drivers)) {\n this.configs.set(name, config);\n }\n }\n\n /**\n * Register the built-in `local` driver, rooted at `uploadsPath()`.\n *\n * The storage connector starts unconditionally — unlike database, cache and\n * herald, it does not early-return when `config.get(\"storage\")` is absent —\n * on the stated grounds that `init()` falls back to a built-in local driver so\n * file storage works out of the box. That fallback did not exist: `init()`\n * resolved the default driver *name* and then found no config registered\n * under it, so **any app without `src/config/storage.ts` failed to boot**\n * with `Storage driver \"local\" is not configured`. Only scaffolded apps, which\n * always ship that file, hid it.\n *\n * Registered before the configured drivers so an app that defines its own\n * `local` entry overrides this one rather than fighting it.\n */\n protected registerBuiltInLocalDriver(): void {\n this.configs.set(\n \"local\",\n storageConfigurations.local({\n root: uploadsPath(),\n urlPrefix: \"/uploads\",\n }),\n );\n }\n\n /**\n * Get a scoped storage for a specific driver\n *\n * Returns a `ScopedStorage` instance that wraps the specified driver.\n * Operations on the returned instance also return `StorageFile` objects.\n *\n * @param name - Driver name as defined in configuration\n * @returns ScopedStorage instance for the specified driver\n *\n * @example\n * ```typescript\n * // Upload to S3\n * const s3File = await storage.use(\"s3\").put(buffer, \"images/photo.jpg\");\n *\n * // Upload to local\n * const localFile = await storage.use(\"local\").put(buffer, \"temp/file.txt\");\n *\n * // Both return StorageFile with identical API\n * console.log(s3File.url);\n * console.log(localFile.url);\n * ```\n */\n public use(name: StorageDriverName): ScopedStorage {\n return new ScopedStorage(this.getDriver(name));\n }\n\n /**\n * Get a raw driver instance\n *\n * Returns the underlying driver directly for advanced use cases.\n * Unlike `use()`, calling methods on the raw driver returns\n * `StorageFileData` instead of `StorageFile`.\n *\n * @param name - Driver name as defined in configuration\n * @returns Raw driver instance implementing StorageDriverContract\n *\n * @example\n * ```typescript\n * const driver = storage.getDriver(\"s3\");\n * const data = await driver.put(buffer, \"path/to/file\");\n * // data is StorageFileData, not StorageFile\n * ```\n */\n public getDriver(name: StorageDriverName): StorageDriverContract {\n return this.resolveDriver(name);\n }\n\n /**\n * Get root directory of current driver\n */\n public root(apepndedPath?: string): string {\n const rootPath = this.activeDriver.options?.root || \"\";\n\n return path.join(rootPath, apepndedPath || \"\");\n }\n\n /**\n * Use a cloud storage driver with extended cloud capabilities\n *\n * @param name - Cloud driver name (s3, r2, spaces)\n * @returns Driver instance implementing CloudStorageDriverContract\n * @throws Error if driver doesn't support cloud operations\n *\n * @example\n * ```typescript\n * const cloudDriver = storage.useCloud(\"s3\");\n * const presignedUrl = await cloudDriver.getPresignedUrl(\"private/doc.pdf\");\n * ```\n */\n public useCloud(name: StorageDriverName): CloudStorageDriverContract {\n const instance = this.getDriver(name);\n\n if (!this.isCloudDriver(instance)) {\n throw new Error(`Driver \"${name}\" does not support cloud operations`);\n }\n\n return instance as CloudStorageDriverContract;\n }\n\n /**\n * Register a new driver configuration at runtime\n *\n * Allows dynamic driver registration for multi-tenancy or\n * runtime configuration scenarios.\n *\n * @param name - Unique driver name\n * @param config - Driver configuration\n * @returns This instance for chaining\n *\n * @example\n * ```typescript\n * storage.register(\"tenant-s3\", {\n * driver: \"s3\",\n * bucket: \"tenant-bucket\",\n * region: \"us-east-1\",\n * accessKeyId: process.env.TENANT_AWS_KEY,\n * secretAccessKey: process.env.TENANT_AWS_SECRET\n * });\n *\n * await storage.use(\"tenant-s3\").put(buffer, \"file.txt\");\n * ```\n */\n public register(name: StorageDriverName, config: StorageDriverConfig): this {\n this.configs.set(name, config);\n this.drivers.delete(name); // Clear cached instance\n return this;\n }\n\n /**\n * Set the default driver name\n *\n * @param name - Driver name to use as default\n * @returns This instance for chaining\n *\n * @example\n * ```typescript\n * storage.setDefault(\"s3\");\n * await storage.put(buffer, \"file.txt\"); // Now uses S3\n * ```\n */\n public setDefault(name: StorageDriverName): this {\n this.defaultDriverName = name;\n this._driver = this.getDriver(name);\n return this;\n }\n\n /**\n * Check if current driver is a cloud driver\n *\n * @returns Promise resolving to true if the current driver supports cloud operations\n */\n public async isCloud(): Promise<boolean> {\n return this.isCloudDriver(this.activeDriver);\n }\n\n /**\n * Check if a driver instance supports cloud operations\n * @internal\n */\n protected isCloudDriver(driver: StorageDriverContract): driver is CloudStorageDriverContract {\n return \"getPresignedUrl\" in driver;\n }\n\n // ============================================================\n // Event System\n // ============================================================\n\n /**\n * Register an event handler\n *\n * Subscribe to storage events for logging, analytics, or side effects.\n *\n * @param event - Event type to listen for\n * @param handler - Handler function\n * @returns Event subscription for unsubscribing\n *\n * @example\n * ```typescript\n * // Log all uploads\n * storage.on(\"afterPut\", ({ location, file }) => {\n * console.log(`Uploaded ${file?.size} bytes to ${location}`);\n * });\n *\n * // Track deletions\n * storage.on(\"afterDelete\", ({ location }) => {\n * analytics.track(\"file_deleted\", { path: location });\n * });\n * ```\n */\n public on<T extends StorageEventPayload = StorageEventPayload>(\n event: StorageEventType,\n handler: StorageEventHandler<T>,\n ): EventSubscription {\n return events.subscribe(`storage.${event}`, handler);\n }\n\n /**\n * Remove all handlers for an event type\n *\n * @param event - Event type to remove handlers for\n * @returns This instance for chaining\n *\n * @example\n * ```typescript\n * storage.off(\"afterPut\"); // Remove all afterPut handlers\n * ```\n */\n public off(event: StorageEventType): this {\n events.off(`storage.${event}`);\n return this;\n }\n\n /**\n * Emit an event to all registered handlers\n * @internal\n */\n protected async emit<T extends StorageEventPayload>(\n event: StorageEventType,\n payload: T,\n ): Promise<void> {\n // `triggerAll` is synchronous — it never awaits its handlers, so awaiting it\n // would make async listeners fire-and-forget. `triggerAllAsync` takes the\n // same `(event, ...args)` shape and awaits each handler in turn.\n await events.triggerAllAsync(`storage.${event}`, payload);\n }\n\n // ============================================================\n // Overridden Operations with Events\n // ============================================================\n\n /**\n * Store a file in storage\n *\n * Extends base `put()` with event emission for beforePut/afterPut hooks.\n *\n * @param file - File content as Buffer, string, UploadedFile, or Readable stream\n * @param location - Destination path\n * @param options - Storage options (mimeType, cacheControl, etc.)\n * @returns StorageFile instance with cached metadata\n */\n public override async put(\n file: UploadedFile | Buffer | string | Readable,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFile> {\n const driver = this.activeDriver;\n const buffer = await this.toBuffer(file);\n\n await this.emit<StoragePutEventPayload>(\"beforePut\", {\n driver: driver.name,\n location,\n timestamp: new Date(),\n size: buffer.length,\n });\n\n const result = await driver.put(buffer, location, options);\n\n await this.emit<StoragePutEventPayload>(\"afterPut\", {\n driver: driver.name,\n location,\n timestamp: new Date(),\n file: result,\n });\n\n if (!result.size) {\n result.size = buffer.length;\n }\n\n return StorageFile.fromData(result, driver);\n }\n\n /**\n * Atomically store a file only if nothing exists at `location`.\n *\n * Emits the same beforePut/afterPut events as `put()` when the file is\n * written; emits nothing when the location already exists (`null`).\n * Because the outcome is unknown until the driver returns, both events\n * fire after the write, for the winner only.\n *\n * @throws StorageCapabilityError when the driver has no `putIfAbsent`\n */\n public override async putIfAbsent(\n file: Buffer | string,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFile | null> {\n const driver = this.activeDriver;\n\n if (typeof driver.putIfAbsent !== \"function\") {\n throw new StorageCapabilityError(\"putIfAbsent\", driver.name);\n }\n\n const result = await driver.putIfAbsent(file, location, options);\n\n if (!result) {\n return null;\n }\n\n const size = typeof file === \"string\" ? Buffer.byteLength(file) : file.length;\n\n await this.emit<StoragePutEventPayload>(\"beforePut\", {\n driver: driver.name,\n location,\n timestamp: new Date(),\n size,\n });\n\n await this.emit<StoragePutEventPayload>(\"afterPut\", {\n driver: driver.name,\n location,\n timestamp: new Date(),\n file: result,\n });\n\n if (!result.size) {\n result.size = size;\n }\n\n return StorageFile.fromData(result, driver);\n }\n\n /**\n * Store a file from a readable stream (for large files)\n *\n * Extends base `putStream()` with event emission.\n *\n * @param stream - Readable stream\n * @param location - Destination path\n * @param options - Storage options\n * @returns StorageFile instance with cached metadata\n */\n public override async putStream(\n stream: Readable | string,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFile> {\n const driver = this.activeDriver;\n\n await this.emit<StoragePutEventPayload>(\"beforePut\", {\n driver: driver.name,\n location,\n timestamp: new Date(),\n });\n\n if (typeof stream === \"string\") {\n stream = fs.createReadStream(stream);\n }\n\n const result = await driver.putStream(stream, location, options);\n\n await this.emit<StoragePutEventPayload>(\"afterPut\", {\n driver: driver.name,\n location,\n timestamp: new Date(),\n file: result,\n });\n\n return StorageFile.fromData(result, driver);\n }\n\n /**\n * Store a file from a URL\n *\n * Downloads content from the URL and stores it at the specified location.\n *\n * The download is SSRF-guarded by default: the URL scheme must be\n * https/http, the host must not resolve to a private / loopback /\n * link-local / cloud-metadata address, the body is capped, and the\n * request times out. Tune or relax via the {@link PutFromUrlOptions}\n * guard fields.\n *\n * @param url - Source URL to download from\n * @param location - Destination path\n * @param options - Storage + outbound-download guard options\n * @returns StorageFile instance with cached metadata\n *\n * @example\n * ```typescript\n * const file = await storage.putFromUrl(\n * \"https://example.com/image.jpg\",\n * \"downloads/image.jpg\"\n * );\n * ```\n */\n public async putFromUrl(\n url: string,\n location: string,\n options?: PutFromUrlOptions,\n ): Promise<StorageFile> {\n const { allowPrivateHosts, maxBytes, timeoutMs, allowedSchemes, ...putOptions } = options ?? {};\n\n const result = await safeFetchToBuffer(url, {\n allowPrivateHosts,\n maxBytes,\n timeoutMs,\n allowedSchemes,\n });\n\n if (!result.ok) {\n throw new Error(`Failed to fetch file from URL: ${result.statusText}`);\n }\n\n if (!result.contentType && !putOptions.mimeType) {\n throw new Error(`Failed to fetch file from URL: missing content-type header`);\n }\n\n const mimeType = putOptions.mimeType || result.contentType || undefined;\n\n return this.put(result.buffer, location, { ...putOptions, mimeType });\n }\n\n /**\n * Store a file from base64 encoded string\n *\n * Decodes base64 content (with optional data URL prefix) and stores it.\n *\n * @param base64 - Base64 encoded file content (or data URL)\n * @param location - Destination path\n * @param options - Storage options\n * @returns StorageFile instance with cached metadata\n *\n * @example\n * ```typescript\n * // From plain base64\n * const file = await storage.putFromBase64(base64String, \"images/photo.jpg\");\n *\n * // From data URL (auto-extracts MIME type)\n * const file = await storage.putFromBase64(\n * \"data:image/png;base64,iVBORw0KGgo...\",\n * \"images/photo.png\"\n * );\n * ```\n */\n public async putFromBase64(\n base64: string,\n location: string,\n options?: PutOptions,\n ): Promise<StorageFile> {\n let data = base64;\n let mimeType = options?.mimeType;\n\n if (base64.startsWith(\"data:\")) {\n const match = base64.match(/^data:([^;]+);base64,(.+)$/);\n if (match) {\n const matchedMimeType = match[1];\n const matchedData = match[2];\n\n if (matchedMimeType !== undefined && matchedData !== undefined) {\n mimeType = mimeType || matchedMimeType;\n data = matchedData;\n }\n }\n }\n\n const buffer = Buffer.from(data, \"base64\");\n return this.put(buffer, location, { ...options, mimeType });\n }\n\n /**\n * Retrieve file contents as Buffer\n *\n * Uses the current driver (with async resolution).\n *\n * @param location - File path\n * @returns Buffer containing file contents\n */\n public override async get(location: string): Promise<Buffer> {\n return this.activeDriver.get(location);\n }\n\n /**\n * Get JSON content from a file\n *\n * Downloads and parses JSON file content.\n *\n * @param location - File path\n * @returns Parsed JSON content\n *\n * @example\n * ```typescript\n * const config = await storage.getJson(\"config/settings.json\");\n * console.log(config.apiKey);\n * ```\n */\n public async getJson(location: string): Promise<any> {\n const buffer = await this.get(location);\n return JSON.parse(buffer.toString());\n }\n\n /**\n * Retrieve a file as a readable stream (for large files)\n *\n * @param location - File path\n * @returns Readable stream of file contents\n */\n public override async getStream(location: string): Promise<Readable> {\n return this.activeDriver.getStream(location);\n }\n\n /**\n * Delete a file\n *\n * Extends base `delete()` with event emission.\n *\n * @param location - File path or StorageFile\n * @returns true if deleted, false if not found\n */\n public override async delete(location: string | StorageFile): Promise<boolean> {\n const driver = this.activeDriver;\n const path = typeof location === \"string\" ? location : location.path;\n\n await this.emit<StorageEventPayload>(\"beforeDelete\", {\n driver: driver.name,\n location: path,\n timestamp: new Date(),\n });\n\n const result = await driver.delete(path);\n\n await this.emit<StorageEventPayload>(\"afterDelete\", {\n driver: driver.name,\n location: path,\n timestamp: new Date(),\n });\n\n return result;\n }\n\n /**\n * Delete multiple files at once\n *\n * @param locations - Array of file paths\n * @returns Array of delete results with status for each file\n */\n public override async deleteMany(locations: string[]): Promise<DeleteManyResult[]> {\n return this.activeDriver.deleteMany(locations);\n }\n\n /**\n * Check if a file exists\n *\n * @param location - File path\n * @returns true if file exists\n */\n public override async exists(location: string): Promise<boolean> {\n return this.activeDriver.exists(location);\n }\n\n /**\n * Copy a file to a new location\n *\n * Extends base `copy()` with event emission.\n *\n * @param from - Source path or StorageFile\n * @param to - Destination path\n * @returns StorageFile instance at destination\n */\n public override async copy(from: string | StorageFile, to: string): Promise<StorageFile> {\n const driver = this.activeDriver;\n const fromPath = typeof from === \"string\" ? from : from.path;\n\n await this.emit<StorageCopyEventPayload>(\"beforeCopy\", {\n driver: driver.name,\n location: to,\n from: fromPath,\n to,\n timestamp: new Date(),\n });\n\n const result = await driver.copy(fromPath, to);\n\n await this.emit<StorageCopyEventPayload>(\"afterCopy\", {\n driver: driver.name,\n location: to,\n from: fromPath,\n to,\n timestamp: new Date(),\n file: result,\n });\n\n return StorageFile.fromData(result, driver);\n }\n\n /**\n * Move a file to a new location\n *\n * Extends base `move()` with event emission.\n *\n * @param from - Source path or StorageFile\n * @param to - Destination path\n * @returns StorageFile instance at destination\n */\n public override async move(from: string | StorageFile, to: string): Promise<StorageFile> {\n const driver = this.activeDriver;\n const fromPath = typeof from === \"string\" ? from : from.path;\n\n await this.emit<StorageCopyEventPayload>(\"beforeMove\", {\n driver: driver.name,\n location: to,\n from: fromPath,\n to,\n timestamp: new Date(),\n });\n\n const result = await driver.move(fromPath, to);\n\n await this.emit<StorageCopyEventPayload>(\"afterMove\", {\n driver: driver.name,\n location: to,\n from: fromPath,\n to,\n timestamp: new Date(),\n file: result,\n });\n\n return StorageFile.fromData(result, driver);\n }\n\n /**\n * List files in a directory\n *\n * @param directory - Directory path (defaults to root)\n * @param options - List options (recursive, limit, etc.)\n * @returns Array of file information objects\n */\n public override async list(\n directory?: string,\n options?: ListOptions,\n ): Promise<StorageFileInfo[]> {\n return this.activeDriver.list(directory || \"\", options);\n }\n\n // ============================================================\n // Metadata Operations\n // ============================================================\n\n /**\n * Get file metadata without downloading\n *\n * @param location - File path\n * @returns File information object\n */\n public override async metadata(location: string): Promise<StorageFileInfo> {\n return this.activeDriver.metadata(location);\n }\n\n /**\n * Get file size in bytes\n *\n * @param location - File path\n * @returns File size in bytes\n */\n public override async size(location: string): Promise<number> {\n return this.activeDriver.size(location);\n }\n\n // ============================================================\n // Path Operations (Local Driver Only)\n // ============================================================\n\n /**\n * Get the absolute filesystem path for a location\n *\n * Only available for local driver.\n *\n * @param location - File path\n * @throws Error if current driver is not a local driver\n * @returns Absolute filesystem path\n */\n public async path(location: string): Promise<string> {\n const driver = this.activeDriver;\n\n if (!(\"path\" in driver) || typeof driver.path !== \"function\") {\n throw new Error(\"path() is only available for local storage drivers\");\n }\n\n return driver.path(location);\n }\n\n // ============================================================\n // Cloud-Specific Operations\n // ============================================================\n\n /**\n * Get a presigned URL for downloading a file\n *\n * Only available for cloud drivers.\n *\n * @param location - File path\n * @param options - Presigned URL options (expiresIn)\n * @throws Error if current driver is not a cloud driver\n * @returns Presigned download URL\n *\n * @example\n * ```typescript\n * const url = await storage.getPresignedUrl(\"private/document.pdf\", {\n * expiresIn: 3600 // 1 hour\n * });\n * ```\n */\n public async getPresignedUrl(location: string, options?: PresignedOptions): Promise<string> {\n const driver = this.activeDriver;\n\n if (!this.isCloudDriver(driver)) {\n throw new Error(\"Presigned URLs are only available for cloud storage drivers\");\n }\n\n return driver.getPresignedUrl(location, options);\n }\n\n /**\n * Get a presigned URL for uploading a file directly to cloud storage\n *\n * Only available for cloud drivers.\n *\n * @param location - Destination path\n * @param options - Upload options (expiresIn, contentType, metadata).\n * There is no size cap: a presigned PUT URL cannot enforce one — verify\n * the uploaded size server-side or use a presigned POST policy instead.\n * @throws Error if current driver is not a cloud driver\n * @returns Presigned upload URL\n *\n * @example\n * ```typescript\n * const uploadUrl = await storage.getPresignedUploadUrl(\"uploads/file.pdf\", {\n * expiresIn: 3600,\n * contentType: \"application/pdf\"\n * });\n *\n * // Client can PUT directly to this URL\n * ```\n */\n public async getPresignedUploadUrl(\n location: string,\n options?: PresignedUploadOptions,\n ): Promise<string> {\n const driver = this.activeDriver;\n\n if (!this.isCloudDriver(driver)) {\n throw new Error(\"Presigned upload URLs are only available for cloud storage drivers\");\n }\n\n return driver.getPresignedUploadUrl(location, options);\n }\n\n /**\n * Get the bucket name for cloud storage\n *\n * Only available for cloud drivers.\n *\n * @throws Error if current driver is not a cloud driver\n * @returns Bucket name\n */\n public async getBucket(): Promise<string> {\n const driver = this.activeDriver;\n\n if (!this.isCloudDriver(driver)) {\n throw new Error(\"Bucket information is only available for cloud storage drivers\");\n }\n\n return driver.getBucket();\n }\n\n /**\n * Get the region for cloud storage\n *\n * Only available for cloud drivers.\n *\n * @throws Error if current driver is not a cloud driver\n * @returns Region name\n */\n public async getRegion(): Promise<string> {\n const driver = this.activeDriver;\n\n if (!this.isCloudDriver(driver)) {\n throw new Error(\"Region information is only available for cloud storage drivers\");\n }\n\n return driver.getRegion();\n }\n\n /**\n * Set storage class for a file (e.g., STANDARD, GLACIER, etc.)\n *\n * Only available for cloud drivers.\n *\n * @param location - File path\n * @param storageClass - Target storage class\n * @throws Error if current driver is not a cloud driver\n */\n public async setStorageClass(location: string, storageClass: string): Promise<void> {\n const driver = this.activeDriver;\n\n if (!this.isCloudDriver(driver)) {\n throw new Error(\"Storage class is only available for cloud storage drivers\");\n }\n\n return driver.setStorageClass(location, storageClass);\n }\n\n /**\n * Set file visibility (public or private)\n *\n * Only available for cloud drivers.\n *\n * @param location - File path\n * @param visibility - \"public\" or \"private\"\n * @throws Error if current driver is not a cloud driver\n */\n public async setVisibility(location: string, visibility: FileVisibility): Promise<void> {\n const driver = this.activeDriver;\n\n if (!this.isCloudDriver(driver)) {\n throw new Error(\"Visibility is only available for cloud storage drivers\");\n }\n\n return driver.setVisibility(location, visibility);\n }\n\n /**\n * Get file visibility\n *\n * Only available for cloud drivers.\n *\n * @param location - File path\n * @throws Error if current driver is not a cloud driver\n * @returns Current visibility setting\n */\n public async getVisibility(location: string): Promise<FileVisibility> {\n const driver = this.activeDriver;\n\n if (!this.isCloudDriver(driver)) {\n throw new Error(\"Visibility is only available for cloud storage drivers\");\n }\n\n return driver.getVisibility(location);\n }\n\n /**\n * Get a temporary signed URL\n *\n * Creates a URL that provides temporary access to the file.\n *\n * @param location - File path\n * @param expiresIn - Seconds until expiration (default: 3600)\n * @returns Signed URL string\n */\n public override async temporaryUrl(location: string, expiresIn?: number): Promise<string> {\n return this.activeDriver.temporaryUrl(location, expiresIn);\n }\n\n /**\n * Validate a temporary URL token\n *\n * For local driver: validates HMAC-signed tokens\n * For cloud drivers: returns invalid (cloud validates via presigned URL)\n *\n * @param token - The token from the temporary URL\n * @returns Validation result with file info and convenience methods\n *\n * @example\n * ```typescript\n * const result = await storage.validateTemporaryToken(token);\n *\n * if (!result.valid) {\n * return response.status(403).send(result.error);\n * }\n *\n * // For local driver - use sendFile for efficiency\n * if (result.absolutePath) {\n * return response.sendFile(result.absolutePath);\n * }\n *\n * // For cloud driver - stream the file\n * const stream = await result.getStream!();\n * stream.pipe(response.raw);\n * ```\n */\n public async validateTemporaryToken(token: string): Promise<TemporaryTokenValidation> {\n // Check if driver supports token validation\n if (\n !(\"validateTemporaryToken\" in this.activeDriver) ||\n typeof this.activeDriver.validateTemporaryToken !== \"function\"\n ) {\n // For cloud drivers, temporary URLs are presigned and validated by the cloud provider\n return {\n valid: false,\n error: \"invalid_token\",\n };\n }\n\n return this.activeDriver.validateTemporaryToken(token);\n }\n\n // ============================================================\n // Configuration Parsing\n // ============================================================\n\n /**\n * Parse config into driver-specific options\n * @internal\n */\n protected parseOptions(\n config: StorageDriverConfig,\n ): LocalStorageDriverOptions | CloudStorageDriverOptions | R2StorageDriverOptions {\n const { driver, ...options } = config;\n\n switch (driver) {\n case \"local\":\n return {\n root: options.root,\n prefix: options.prefix,\n urlPrefix: options.urlPrefix,\n temporaryUrlPrefix: options.temporaryUrlPrefix,\n signatureKey: options.signatureKey,\n } satisfies LocalStorageDriverOptions;\n\n case \"s3\":\n this.validateCloudConfig(config, \"s3\");\n return {\n ...options,\n bucket: options.bucket!,\n region: options.region!,\n accessKeyId: options.accessKeyId,\n secretAccessKey: options.secretAccessKey,\n endpoint: options.endpoint,\n urlPrefix: options.urlPrefix,\n } satisfies CloudStorageDriverOptions;\n\n case \"r2\":\n this.validateCloudConfig(config, \"r2\");\n if (!options.accountId) {\n throw new Error('R2 driver requires \"accountId\" configuration');\n }\n\n return {\n ...options,\n region: options.region || \"auto\",\n bucket: options.bucket!,\n accessKeyId: options.accessKeyId,\n secretAccessKey: options.secretAccessKey,\n endpoint: options.endpoint,\n urlPrefix: options.urlPrefix,\n accountId: options.accountId,\n publicDomain: options.publicDomain,\n } satisfies R2StorageDriverOptions;\n\n case \"spaces\":\n this.validateCloudConfig(config, \"spaces\");\n return {\n ...options,\n bucket: options.bucket!,\n region: options.region!,\n accessKeyId: options.accessKeyId,\n secretAccessKey: options.secretAccessKey,\n endpoint: options.endpoint,\n urlPrefix: options.urlPrefix,\n } satisfies CloudStorageDriverOptions;\n\n default:\n throw new Error(`Unknown driver type: ${driver}`);\n }\n }\n\n /**\n * Validate cloud driver configuration has required fields\n * @internal\n */\n protected validateCloudConfig(config: StorageDriverConfig, driverName: string): void {\n // Credentials are optional: when absent, the AWS default provider chain\n // applies (IAM roles, ECS task roles, IRSA, SSO profiles).\n const required = [\"bucket\"];\n\n if (driverName !== \"r2\") {\n required.push(\"region\");\n }\n\n for (const field of required) {\n if (!config[field as keyof StorageDriverConfig]) {\n throw new Error(`${driverName.toUpperCase()} driver requires \"${field}\" configuration`);\n }\n }\n\n if (Boolean(config.accessKeyId) !== Boolean(config.secretAccessKey)) {\n throw new Error(\n `${driverName.toUpperCase()} driver requires both \"accessKeyId\" and \"secretAccessKey\", or neither`,\n );\n }\n }\n\n /**\n * Get or create driver instance from cache\n * @internal\n */\n protected resolveDriver(name: string): StorageDriverContract {\n // Ensure configs are loaded\n\n if (this.drivers.has(name)) {\n return this.drivers.get(name)!;\n }\n\n const config = this.configs.get(name);\n\n if (!config) {\n throw new Error(`Storage driver \"${name}\" is not configured`);\n }\n\n const options = this.parseOptions(config);\n let driver: StorageDriverContract;\n\n switch (config.driver) {\n case \"local\":\n driver = new LocalDriver(options as LocalStorageDriverOptions);\n break;\n case \"s3\":\n driver = new S3Driver(options as CloudStorageDriverOptions);\n break;\n case \"r2\":\n driver = new R2Driver(options as R2StorageDriverOptions);\n break;\n case \"spaces\":\n driver = new DOSpacesDriver(options as CloudStorageDriverOptions);\n break;\n default:\n throw new Error(`Unknown storage driver type: ${config.driver}`);\n }\n\n this.drivers.set(name, driver);\n return driver;\n }\n}\n\n/**\n * Singleton storage instance\n *\n * Pre-configured storage manager ready for use throughout the application.\n *\n * @example\n * ```typescript\n * import { storage } from \"@warlock.js/core\";\n *\n * const file = await storage.put(buffer, \"uploads/file.txt\");\n * ```\n */\nexport const storage = new Storage();\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.mts","names":[],"sources":["../../../../../../../../packages/core/src/storage/types.ts"],"mappings":"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"}
1
+ {"version":3,"file":"types.d.mts","names":[],"sources":["../../../../../../../../packages/core/src/storage/types.ts"],"mappings":"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"}
@@ -13,6 +13,8 @@
13
13
  * `null`. This error names that cause and the fix directly instead.
14
14
  */
15
15
  declare class StorageNotInitializedError extends Error {
16
+ /** Stable Warlock error code; `warlock explain WL2006` prints the fix. */
17
+ readonly code = "WL2006";
16
18
  constructor(options?: {
17
19
  cause?: unknown;
18
20
  });
@@ -1 +1 @@
1
- {"version":3,"file":"storage-not-initialized-error.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/storage/utils/storage-not-initialized-error.ts"],"mappings":";;AAaA;;;;;;;;;AACkD;;;cADrC,0BAAA,SAAmC,KAAK;cAChC,OAAA;IAAY,KAAA;EAAA;AAAA"}
1
+ {"version":3,"file":"storage-not-initialized-error.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/storage/utils/storage-not-initialized-error.ts"],"mappings":";;AAaA;;;;;;;;;;AAIkD;;cAJrC,0BAAA,SAAmC,KAAK;;WAEnC,IAAA;cAEG,OAAA;IAAY,KAAA;EAAA;AAAA"}
@@ -15,6 +15,7 @@
15
15
  var StorageNotInitializedError = class extends Error {
16
16
  constructor(options) {
17
17
  super("Storage is not initialized in this process. This happens when the `storage` connector never ran, so `Storage.init()` was never called.\n\nCheck that `src/config/storage.ts` exists. If this is a custom CLI command, add \"storage\" to its `preload.connectors` list so the connector runs before your command's action executes.", options);
18
+ this.code = "WL2006";
18
19
  this.name = "StorageNotInitializedError";
19
20
  }
20
21
  };
@@ -1 +1 @@
1
- {"version":3,"file":"storage-not-initialized-error.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/storage/utils/storage-not-initialized-error.ts"],"sourcesContent":["/**\n * Thrown when storage is accessed (e.g. `storage.put(...)`) before it has\n * been initialized in this process — no context driver and no default\n * driver resolved yet.\n *\n * Previously this fell through to a bare `null` `activeDriver`, and the\n * first thing every call site did with it was read `.name` or call a\n * method on it, surfacing as `TypeError: Cannot read properties of null\n * (reading 'name')` deep inside `Storage#put()`. That told the caller\n * nothing about the real cause: the `storage` connector never ran in this\n * process, so `Storage#init()` was never called and `_driver` stayed\n * `null`. This error names that cause and the fix directly instead.\n */\nexport class StorageNotInitializedError extends Error {\n public constructor(options?: { cause?: unknown }) {\n super(\n \"Storage is not initialized in this process. This happens when the `storage` \" +\n \"connector never ran, so `Storage.init()` was never called.\\n\\n\" +\n \"Check that `src/config/storage.ts` exists. If this is a custom CLI command, \" +\n 'add \"storage\" to its `preload.connectors` list so the connector runs before ' +\n \"your command's action executes.\",\n options,\n );\n\n this.name = \"StorageNotInitializedError\";\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAaA,IAAa,6BAAb,cAAgD,MAAM;CACpD,AAAO,YAAY,SAA+B;EAChD,MACE,uUAKA,OACF;EAEA,KAAK,OAAO;CACd;AACF"}
1
+ {"version":3,"file":"storage-not-initialized-error.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/storage/utils/storage-not-initialized-error.ts"],"sourcesContent":["/**\n * Thrown when storage is accessed (e.g. `storage.put(...)`) before it has\n * been initialized in this process — no context driver and no default\n * driver resolved yet.\n *\n * Previously this fell through to a bare `null` `activeDriver`, and the\n * first thing every call site did with it was read `.name` or call a\n * method on it, surfacing as `TypeError: Cannot read properties of null\n * (reading 'name')` deep inside `Storage#put()`. That told the caller\n * nothing about the real cause: the `storage` connector never ran in this\n * process, so `Storage#init()` was never called and `_driver` stayed\n * `null`. This error names that cause and the fix directly instead.\n */\nexport class StorageNotInitializedError extends Error {\n /** Stable Warlock error code; `warlock explain WL2006` prints the fix. */\n public readonly code = \"WL2006\";\n\n public constructor(options?: { cause?: unknown }) {\n super(\n \"Storage is not initialized in this process. This happens when the `storage` \" +\n \"connector never ran, so `Storage.init()` was never called.\\n\\n\" +\n \"Check that `src/config/storage.ts` exists. If this is a custom CLI command, \" +\n 'add \"storage\" to its `preload.connectors` list so the connector runs before ' +\n \"your command's action executes.\",\n options,\n );\n\n this.name = \"StorageNotInitializedError\";\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAaA,IAAa,6BAAb,cAAgD,MAAM;CAIpD,AAAO,YAAY,SAA+B;EAChD,MACE,uUAKA,OACF;cAVqB;EAYrB,KAAK,OAAO;CACd;AACF"}