@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
@@ -0,0 +1,57 @@
1
+ import { setIdsSource } from "../../utils/ids.mjs";
2
+
3
+ //#region ../../packages/core/src/tests/fakes/ids-fake.ts
4
+ let uuidSequence = 0;
5
+ let tokenSequence = 0;
6
+ let installed = false;
7
+ /** `00000000-0000-4000-8000-000000000001` for 1: a valid v4-shaped UUID. */
8
+ function sequentialUuid(value) {
9
+ return `00000000-0000-4000-8000-${String(value).padStart(12, "0")}`;
10
+ }
11
+ /** `token0001token0001…` cut to `length`: URL-safe and readable in a diff. */
12
+ function sequentialToken(value, length) {
13
+ const unit = `token${String(value).padStart(4, "0")}`;
14
+ return unit.repeat(Math.ceil(length / unit.length)).slice(0, length);
15
+ }
16
+ /**
17
+ * Deterministic `ids` (from `@warlock.js/core`): numbered UUIDs and tokens.
18
+ *
19
+ * Installed by default in the test environment. Each sequence restarts on
20
+ * install and on `reset()`, so the n-th id in a test is the same on every run.
21
+ *
22
+ * @example
23
+ * const file = await storeReport(report); // named ids.uuid() + ".pdf"
24
+ *
25
+ * expect(file.path).toBe("reports/00000000-0000-4000-8000-000000000001.pdf");
26
+ */
27
+ const idsFake = {
28
+ install() {
29
+ installed = true;
30
+ idsFake.reset();
31
+ setIdsSource({
32
+ uuid: () => sequentialUuid(++uuidSequence),
33
+ token: (length) => sequentialToken(++tokenSequence, length)
34
+ });
35
+ },
36
+ restore() {
37
+ installed = false;
38
+ idsFake.reset();
39
+ setIdsSource(void 0);
40
+ },
41
+ isInstalled() {
42
+ return installed;
43
+ },
44
+ /** Restart both sequences. */
45
+ reset() {
46
+ uuidSequence = 0;
47
+ tokenSequence = 0;
48
+ },
49
+ /** The UUID the n-th `ids.uuid()` call returns (1-based). */
50
+ uuid(n) {
51
+ return sequentialUuid(n);
52
+ }
53
+ };
54
+
55
+ //#endregion
56
+ export { idsFake };
57
+ //# sourceMappingURL=ids-fake.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ids-fake.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/tests/fakes/ids-fake.ts"],"sourcesContent":["import { setIdsSource } from \"../../utils/ids\";\n\nlet uuidSequence = 0;\nlet tokenSequence = 0;\nlet installed = false;\n\n/** `00000000-0000-4000-8000-000000000001` for 1: a valid v4-shaped UUID. */\nfunction sequentialUuid(value: number): string {\n return `00000000-0000-4000-8000-${String(value).padStart(12, \"0\")}`;\n}\n\n/** `token0001token0001…` cut to `length`: URL-safe and readable in a diff. */\nfunction sequentialToken(value: number, length: number): string {\n const unit = `token${String(value).padStart(4, \"0\")}`;\n\n return unit.repeat(Math.ceil(length / unit.length)).slice(0, length);\n}\n\n/**\n * Deterministic `ids` (from `@warlock.js/core`): numbered UUIDs and tokens.\n *\n * Installed by default in the test environment. Each sequence restarts on\n * install and on `reset()`, so the n-th id in a test is the same on every run.\n *\n * @example\n * const file = await storeReport(report); // named ids.uuid() + \".pdf\"\n *\n * expect(file.path).toBe(\"reports/00000000-0000-4000-8000-000000000001.pdf\");\n */\nexport const idsFake = {\n install(): void {\n installed = true;\n idsFake.reset();\n setIdsSource({\n uuid: () => sequentialUuid(++uuidSequence),\n token: (length) => sequentialToken(++tokenSequence, length),\n });\n },\n\n restore(): void {\n installed = false;\n idsFake.reset();\n setIdsSource(undefined);\n },\n\n isInstalled(): boolean {\n return installed;\n },\n\n /** Restart both sequences. */\n reset(): void {\n uuidSequence = 0;\n tokenSequence = 0;\n },\n\n /** The UUID the n-th `ids.uuid()` call returns (1-based). */\n uuid(n: number): string {\n return sequentialUuid(n);\n },\n};\n"],"mappings":";;;AAEA,IAAI,eAAe;AACnB,IAAI,gBAAgB;AACpB,IAAI,YAAY;;AAGhB,SAAS,eAAe,OAAuB;CAC7C,OAAO,2BAA2B,OAAO,KAAK,CAAC,CAAC,SAAS,IAAI,GAAG;AAClE;;AAGA,SAAS,gBAAgB,OAAe,QAAwB;CAC9D,MAAM,OAAO,QAAQ,OAAO,KAAK,CAAC,CAAC,SAAS,GAAG,GAAG;CAElD,OAAO,KAAK,OAAO,KAAK,KAAK,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM;AACrE;;;;;;;;;;;;AAaA,MAAa,UAAU;CACrB,UAAgB;EACd,YAAY;EACZ,QAAQ,MAAM;EACd,aAAa;GACX,YAAY,eAAe,EAAE,YAAY;GACzC,QAAQ,WAAW,gBAAgB,EAAE,eAAe,MAAM;EAC5D,CAAC;CACH;CAEA,UAAgB;EACd,YAAY;EACZ,QAAQ,MAAM;EACd,aAAa,MAAS;CACxB;CAEA,cAAuB;EACrB,OAAO;CACT;;CAGA,QAAc;EACZ,eAAe;EACf,gBAAgB;CAClB;;CAGA,KAAK,GAAmB;EACtB,OAAO,eAAe,CAAC;CACzB;AACF"}
@@ -0,0 +1,8 @@
1
+ import { TEST_FAKE_NAMES, TestFakeName, TestFakesSelection, installTestFakes, installedTestFakes, readConfiguredFakes, resolveTestFakes, restoreTestFakes } from "./test-fakes.mjs";
2
+ import { cacheFake } from "./cache-fake.mjs";
3
+ import { DEFAULT_FAKE_NOW, clockFake } from "./clock-fake.mjs";
4
+ import { FakeAssertionError, describeRecorded } from "./fake-assertion-error.mjs";
5
+ import { idsFake } from "./ids-fake.mjs";
6
+ import { MailMatcher, mailFake } from "./mail-fake.mjs";
7
+ import { JobReference, PushedJob, PushedJobMatcher, queueFake } from "./queue-fake.mjs";
8
+ import { storageFake } from "./storage-fake.mjs";
@@ -0,0 +1,10 @@
1
+ import { FakeAssertionError, describeRecorded } from "./fake-assertion-error.mjs";
2
+ import { cacheFake } from "./cache-fake.mjs";
3
+ import { DEFAULT_FAKE_NOW, clockFake } from "./clock-fake.mjs";
4
+ import { idsFake } from "./ids-fake.mjs";
5
+ import { mailFake } from "./mail-fake.mjs";
6
+ import { queueFake } from "./queue-fake.mjs";
7
+ import { storageFake } from "./storage-fake.mjs";
8
+ import { TEST_FAKE_NAMES, installTestFakes, installedTestFakes, readConfiguredFakes, resolveTestFakes, restoreTestFakes } from "./test-fakes.mjs";
9
+
10
+ export { };
@@ -0,0 +1,41 @@
1
+ import { CapturedMail } from "../../mail/types.mjs";
2
+
3
+ //#region ../../packages/core/src/tests/fakes/mail-fake.d.ts
4
+ /**
5
+ * Which mails an assertion is about: a predicate, or fields that must all
6
+ * match. `to` matches any recipient (to, cc or bcc); `subject` is an exact
7
+ * string or a pattern.
8
+ */
9
+ type MailMatcher = ((mail: CapturedMail) => boolean) | {
10
+ to?: string;
11
+ subject?: string | RegExp;
12
+ from?: string; /** Text the HTML or plain-text body contains. */
13
+ contains?: string;
14
+ };
15
+ /**
16
+ * Captures every `sendMail()` / `Mail` send instead of delivering it.
17
+ *
18
+ * Installed by default in the test environment (see `installTestFakes`). It
19
+ * switches the mailer to its `test` mode, which records into the test mailbox
20
+ * and never opens an SMTP or SES connection.
21
+ *
22
+ * @example
23
+ * await registerUser({ email: "ada@example.test" });
24
+ *
25
+ * mailFake.assertSent({ to: "ada@example.test", subject: /welcome/i });
26
+ * mailFake.assertSentCount(1);
27
+ */
28
+ declare const mailFake: {
29
+ /** Start capturing (idempotent). Clears anything captured before. */install(): void; /** Stop capturing and restore the mode that was in force before. */
30
+ restore(): void; /** Whether the fake is installed. */
31
+ isInstalled(): boolean; /** Forget captured mails, e.g. in `beforeEach`. */
32
+ clear(): void; /** The captured mails, oldest first, optionally filtered. */
33
+ sent(matcher?: MailMatcher): CapturedMail[]; /** Assert at least one matching mail was sent; returns the first. */
34
+ assertSent(matcher?: MailMatcher): CapturedMail; /** Assert no matching mail was sent. */
35
+ assertNotSent(matcher?: MailMatcher): void; /** Assert exactly `count` matching mails were sent. */
36
+ assertSentCount(count: number, matcher?: MailMatcher): void; /** Assert nothing at all was sent. */
37
+ assertNothingSent(): void;
38
+ };
39
+ //#endregion
40
+ export { MailMatcher, mailFake };
41
+ //# sourceMappingURL=mail-fake.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mail-fake.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/tests/fakes/mail-fake.ts"],"mappings":";;;;;AAUA;;;KAAY,WAAA,KACN,IAAA,EAAM,YAAA;EAEN,EAAA;EACA,OAAA,YAAmB,MAAM;EACzB,IAAA,WADA;EAGA,QAAA;AAAA;;;AAAQ;AA0Ed;;;;;;;;;;cAAa,QAAA;;;;;iBAmCI,WAAA,GAAc,YAAA;uBAKR,WAAA,GAAc,YAAA;0BAaX,WAAA;iCAWK,OAAA,GAAY,WAAA"}
@@ -0,0 +1,111 @@
1
+ import { getExplicitMailMode, resetMailMode, setMailMode } from "../../mail/config.mjs";
2
+ import { clearTestMailbox, getTestMailbox } from "../../mail/test-mailbox.mjs";
3
+ import { FakeAssertionError, describeRecorded } from "./fake-assertion-error.mjs";
4
+
5
+ //#region ../../packages/core/src/tests/fakes/mail-fake.ts
6
+ function fromAddress(mail) {
7
+ const from = mail.normalized?.from ?? mail.options.from;
8
+ if (!from) return "";
9
+ return typeof from === "string" ? from : from.address;
10
+ }
11
+ function recipients(mail) {
12
+ const list = (value) => value === void 0 ? [] : Array.isArray(value) ? value : [value];
13
+ return [
14
+ ...list(mail.options.to),
15
+ ...list(mail.options.cc),
16
+ ...list(mail.options.bcc)
17
+ ];
18
+ }
19
+ function matches(mail, matcher) {
20
+ if (matcher === void 0) return true;
21
+ if (typeof matcher === "function") return matcher(mail);
22
+ if (matcher.to !== void 0 && !recipients(mail).includes(matcher.to)) return false;
23
+ if (matcher.subject !== void 0) {
24
+ const subject = mail.options.subject;
25
+ if (!(typeof matcher.subject === "string" ? subject === matcher.subject : matcher.subject.test(subject))) return false;
26
+ }
27
+ if (matcher.from !== void 0 && fromAddress(mail) !== matcher.from) return false;
28
+ if (matcher.contains !== void 0) {
29
+ if (!`${mail.normalized?.html ?? mail.options.html ?? ""}\n${mail.normalized?.text ?? mail.options.text ?? ""}`.includes(matcher.contains)) return false;
30
+ }
31
+ return true;
32
+ }
33
+ function describeMatcher(matcher) {
34
+ if (matcher === void 0) return "any mail";
35
+ if (typeof matcher === "function") return "a mail matching the predicate";
36
+ return `a mail with ${JSON.stringify(matcher, (_key, value) => value instanceof RegExp ? String(value) : value)}`;
37
+ }
38
+ function describeMail(mail) {
39
+ return `to ${recipients(mail).join(", ") || "(nobody)"} — "${mail.options.subject}"`;
40
+ }
41
+ let previousMode;
42
+ let installed = false;
43
+ /**
44
+ * Captures every `sendMail()` / `Mail` send instead of delivering it.
45
+ *
46
+ * Installed by default in the test environment (see `installTestFakes`). It
47
+ * switches the mailer to its `test` mode, which records into the test mailbox
48
+ * and never opens an SMTP or SES connection.
49
+ *
50
+ * @example
51
+ * await registerUser({ email: "ada@example.test" });
52
+ *
53
+ * mailFake.assertSent({ to: "ada@example.test", subject: /welcome/i });
54
+ * mailFake.assertSentCount(1);
55
+ */
56
+ const mailFake = {
57
+ /** Start capturing (idempotent). Clears anything captured before. */
58
+ install() {
59
+ if (!installed) {
60
+ previousMode = getExplicitMailMode();
61
+ installed = true;
62
+ }
63
+ setMailMode("test");
64
+ clearTestMailbox();
65
+ },
66
+ /** Stop capturing and restore the mode that was in force before. */
67
+ restore() {
68
+ if (!installed) return;
69
+ if (previousMode === void 0) resetMailMode();
70
+ else setMailMode(previousMode);
71
+ clearTestMailbox();
72
+ previousMode = void 0;
73
+ installed = false;
74
+ },
75
+ /** Whether the fake is installed. */
76
+ isInstalled() {
77
+ return installed;
78
+ },
79
+ /** Forget captured mails, e.g. in `beforeEach`. */
80
+ clear() {
81
+ clearTestMailbox();
82
+ },
83
+ /** The captured mails, oldest first, optionally filtered. */
84
+ sent(matcher) {
85
+ return getTestMailbox().filter((mail) => matches(mail, matcher));
86
+ },
87
+ /** Assert at least one matching mail was sent; returns the first. */
88
+ assertSent(matcher) {
89
+ const found = mailFake.sent(matcher)[0];
90
+ if (!found) throw new FakeAssertionError(`Expected ${describeMatcher(matcher)} to be sent. ${describeRecorded(getTestMailbox(), describeMail, "sent")}`);
91
+ return found;
92
+ },
93
+ /** Assert no matching mail was sent. */
94
+ assertNotSent(matcher) {
95
+ const found = mailFake.sent(matcher);
96
+ if (found.length > 0) throw new FakeAssertionError(`Expected ${describeMatcher(matcher)} not to be sent. ${describeRecorded(found, describeMail, "sent")}`);
97
+ },
98
+ /** Assert exactly `count` matching mails were sent. */
99
+ assertSentCount(count, matcher) {
100
+ const found = mailFake.sent(matcher);
101
+ if (found.length !== count) throw new FakeAssertionError(`Expected ${count} × ${describeMatcher(matcher)}, found ${found.length}. ${describeRecorded(getTestMailbox(), describeMail, "sent")}`);
102
+ },
103
+ /** Assert nothing at all was sent. */
104
+ assertNothingSent() {
105
+ mailFake.assertNotSent();
106
+ }
107
+ };
108
+
109
+ //#endregion
110
+ export { mailFake };
111
+ //# sourceMappingURL=mail-fake.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mail-fake.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/tests/fakes/mail-fake.ts"],"sourcesContent":["import { getExplicitMailMode, resetMailMode, setMailMode } from \"../../mail/config\";\nimport { clearTestMailbox, getTestMailbox } from \"../../mail/test-mailbox\";\nimport type { CapturedMail, MailMode } from \"../../mail/types\";\nimport { FakeAssertionError, describeRecorded } from \"./fake-assertion-error\";\n\n/**\n * Which mails an assertion is about: a predicate, or fields that must all\n * match. `to` matches any recipient (to, cc or bcc); `subject` is an exact\n * string or a pattern.\n */\nexport type MailMatcher =\n | ((mail: CapturedMail) => boolean)\n | {\n to?: string;\n subject?: string | RegExp;\n from?: string;\n /** Text the HTML or plain-text body contains. */\n contains?: string;\n };\n\nfunction fromAddress(mail: CapturedMail): string {\n const from = mail.normalized?.from ?? mail.options.from;\n\n if (!from) return \"\";\n\n return typeof from === \"string\" ? from : from.address;\n}\n\nfunction recipients(mail: CapturedMail): string[] {\n const list = (value: string | string[] | undefined) =>\n value === undefined ? [] : Array.isArray(value) ? value : [value];\n\n return [...list(mail.options.to), ...list(mail.options.cc), ...list(mail.options.bcc)];\n}\n\nfunction matches(mail: CapturedMail, matcher: MailMatcher | undefined): boolean {\n if (matcher === undefined) return true;\n if (typeof matcher === \"function\") return matcher(mail);\n\n if (matcher.to !== undefined && !recipients(mail).includes(matcher.to)) return false;\n\n if (matcher.subject !== undefined) {\n const subject = mail.options.subject;\n const ok =\n typeof matcher.subject === \"string\"\n ? subject === matcher.subject\n : matcher.subject.test(subject);\n\n if (!ok) return false;\n }\n\n if (matcher.from !== undefined && fromAddress(mail) !== matcher.from) return false;\n\n if (matcher.contains !== undefined) {\n const body = `${mail.normalized?.html ?? mail.options.html ?? \"\"}\\n${mail.normalized?.text ?? mail.options.text ?? \"\"}`;\n\n if (!body.includes(matcher.contains)) return false;\n }\n\n return true;\n}\n\nfunction describeMatcher(matcher: MailMatcher | undefined): string {\n if (matcher === undefined) return \"any mail\";\n if (typeof matcher === \"function\") return \"a mail matching the predicate\";\n\n return `a mail with ${JSON.stringify(matcher, (_key, value: unknown) =>\n value instanceof RegExp ? String(value) : value,\n )}`;\n}\n\nfunction describeMail(mail: CapturedMail): string {\n return `to ${recipients(mail).join(\", \") || \"(nobody)\"} — \"${mail.options.subject}\"`;\n}\n\nlet previousMode: MailMode | undefined;\nlet installed = false;\n\n/**\n * Captures every `sendMail()` / `Mail` send instead of delivering it.\n *\n * Installed by default in the test environment (see `installTestFakes`). It\n * switches the mailer to its `test` mode, which records into the test mailbox\n * and never opens an SMTP or SES connection.\n *\n * @example\n * await registerUser({ email: \"ada@example.test\" });\n *\n * mailFake.assertSent({ to: \"ada@example.test\", subject: /welcome/i });\n * mailFake.assertSentCount(1);\n */\nexport const mailFake = {\n /** Start capturing (idempotent). Clears anything captured before. */\n install(): void {\n if (!installed) {\n previousMode = getExplicitMailMode();\n installed = true;\n }\n\n setMailMode(\"test\");\n clearTestMailbox();\n },\n\n /** Stop capturing and restore the mode that was in force before. */\n restore(): void {\n if (!installed) return;\n\n if (previousMode === undefined) resetMailMode();\n else setMailMode(previousMode);\n\n clearTestMailbox();\n previousMode = undefined;\n installed = false;\n },\n\n /** Whether the fake is installed. */\n isInstalled(): boolean {\n return installed;\n },\n\n /** Forget captured mails, e.g. in `beforeEach`. */\n clear(): void {\n clearTestMailbox();\n },\n\n /** The captured mails, oldest first, optionally filtered. */\n sent(matcher?: MailMatcher): CapturedMail[] {\n return getTestMailbox().filter((mail) => matches(mail, matcher));\n },\n\n /** Assert at least one matching mail was sent; returns the first. */\n assertSent(matcher?: MailMatcher): CapturedMail {\n const found = mailFake.sent(matcher)[0];\n\n if (!found) {\n throw new FakeAssertionError(\n `Expected ${describeMatcher(matcher)} to be sent. ${describeRecorded(getTestMailbox(), describeMail, \"sent\")}`,\n );\n }\n\n return found;\n },\n\n /** Assert no matching mail was sent. */\n assertNotSent(matcher?: MailMatcher): void {\n const found = mailFake.sent(matcher);\n\n if (found.length > 0) {\n throw new FakeAssertionError(\n `Expected ${describeMatcher(matcher)} not to be sent. ${describeRecorded(found, describeMail, \"sent\")}`,\n );\n }\n },\n\n /** Assert exactly `count` matching mails were sent. */\n assertSentCount(count: number, matcher?: MailMatcher): void {\n const found = mailFake.sent(matcher);\n\n if (found.length !== count) {\n throw new FakeAssertionError(\n `Expected ${count} × ${describeMatcher(matcher)}, found ${found.length}. ${describeRecorded(getTestMailbox(), describeMail, \"sent\")}`,\n );\n }\n },\n\n /** Assert nothing at all was sent. */\n assertNothingSent(): void {\n mailFake.assertNotSent();\n },\n};\n"],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ //#region ../../packages/core/src/tests/fakes/queue-fake.d.ts
2
+ /**
3
+ * One job `dispatch()`ed while the fake was installed.
4
+ *
5
+ * Structural on purpose: core has no dependency on `@warlock.js/queue`. The
6
+ * fake talks to it through the global dispatch-interceptor slot that package
7
+ * reads (`setDispatchInterceptor`).
8
+ */
9
+ type PushedJob = {
10
+ id: string;
11
+ name: string;
12
+ queue: string;
13
+ payload: unknown; /** The dispatch options (`delay`, `priority`, `jobId`, ...). */
14
+ options: Record<string, unknown>;
15
+ pushedAt: Date;
16
+ };
17
+ /** A job name, or anything with a `name` — the object `defineJob()` returns. */
18
+ type JobReference = string | {
19
+ readonly name: string;
20
+ };
21
+ /** Which pushed jobs an assertion is about: a predicate, or a payload subset. */
22
+ type PushedJobMatcher = ((job: PushedJob) => boolean) | Record<string, unknown>;
23
+ /**
24
+ * Records every `@warlock.js/queue` dispatch instead of pushing it to Redis.
25
+ *
26
+ * Installed by default in the test environment. Jobs are recorded, not run:
27
+ * call the job's handler directly to test what it does.
28
+ *
29
+ * @example
30
+ * await placeOrder(order);
31
+ *
32
+ * queueFake.assertPushed(sendInvoice, { orderId: order.id });
33
+ * queueFake.assertPushedCount(1);
34
+ */
35
+ declare const queueFake: {
36
+ /** Start recording (idempotent). Clears anything recorded before. */install(): void; /** Stop recording; dispatches reach the broker again. */
37
+ restore(): void;
38
+ isInstalled(): boolean; /** Forget recorded jobs. */
39
+ clear(): void; /** Recorded jobs, oldest first; optionally only one job type. */
40
+ pushed(job?: JobReference, matcher?: PushedJobMatcher): PushedJob[]; /** Assert `job` was pushed (with a payload matching `matcher`); returns the first match. */
41
+ assertPushed(job: JobReference, matcher?: PushedJobMatcher): PushedJob; /** Assert `job` was not pushed (with a matching payload). */
42
+ assertNotPushed(job: JobReference, matcher?: PushedJobMatcher): void; /** Assert exactly `count` jobs were pushed — of type `job` when given. */
43
+ assertPushedCount(count: number, job?: JobReference): void; /** Assert nothing was pushed. */
44
+ assertNothingPushed(): void;
45
+ };
46
+ //#endregion
47
+ export { JobReference, PushedJob, PushedJobMatcher, queueFake };
48
+ //# sourceMappingURL=queue-fake.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue-fake.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/tests/fakes/queue-fake.ts"],"mappings":";;AAUA;;;;;;KAAY,SAAA;EACV,EAAA;EACA,IAAA;EACA,KAAA;EACA,OAAA,WAGU;EADV,OAAA,EAAS,MAAA;EACT,QAAA,EAAU,IAAI;AAAA;;KAIJ,YAAA;EAAA,SAAmC,IAAI;AAAA;AAGnD;AAAA,KAAY,gBAAA,KAAqB,GAAA,EAAK,SAAA,gBAAyB,MAAM;;;;;;;AAAA;AAoGrE;;;;;cAAa,SAAA;EA0CO,sFAA2C;;0BAwBtB;iBAAY;eA/BtC,YAAA,EAAY,OAAA,GAAY,gBAAA,GAAmB,SAAA;oBAOtC,YAAA,EAAY,OAAA,GAAY,gBAAA,GAAmB,SAAA;uBAaxC,YAAA,EAAY,OAAA,GAAY,gBAAA,SApBhC;mCA+BkB,GAAA,GAAQ,YAAA,SA/BF"}
@@ -0,0 +1,134 @@
1
+ import { clock } from "../../utils/clock.mjs";
2
+ import { FakeAssertionError, describeRecorded } from "./fake-assertion-error.mjs";
3
+
4
+ //#region ../../packages/core/src/tests/fakes/queue-fake.ts
5
+ const INTERCEPTOR_KEY = Symbol.for("warlock.queue.dispatchInterceptor");
6
+ const pushed = [];
7
+ let sequence = 0;
8
+ let previous;
9
+ let installed = false;
10
+ function nameOf(job) {
11
+ return typeof job === "string" ? job : job.name;
12
+ }
13
+ function isSubset(expected, actual) {
14
+ if (expected === actual) return true;
15
+ if (typeof expected !== "object" || expected === null) return false;
16
+ if (typeof actual !== "object" || actual === null) return false;
17
+ return Object.entries(expected).every(([key, value]) => isSubset(value, actual[key]));
18
+ }
19
+ function matches(job, matcher) {
20
+ if (matcher === void 0) return true;
21
+ if (typeof matcher === "function") return matcher(job);
22
+ return isSubset(matcher, job.payload);
23
+ }
24
+ function describeJob(job) {
25
+ return `${job.name} on "${job.queue}" with ${JSON.stringify(job.payload)}`;
26
+ }
27
+ const interceptor = {
28
+ dispatch({ name, queue, payload, options }) {
29
+ const explicitId = typeof options.jobId === "string" ? options.jobId : void 0;
30
+ const existing = explicitId ? pushed.find((job) => job.id === explicitId) : void 0;
31
+ if (existing) return {
32
+ id: existing.id,
33
+ name: existing.name,
34
+ queue: existing.queue
35
+ };
36
+ sequence += 1;
37
+ const job = {
38
+ id: explicitId ?? `fake-${sequence}`,
39
+ name,
40
+ queue,
41
+ payload,
42
+ options: { ...options },
43
+ pushedAt: clock.now()
44
+ };
45
+ pushed.push(job);
46
+ return {
47
+ id: job.id,
48
+ name,
49
+ queue
50
+ };
51
+ },
52
+ find({ name, id }) {
53
+ const job = pushed.find((entry) => entry.id === id && entry.name === name);
54
+ if (!job) return void 0;
55
+ return {
56
+ id: job.id,
57
+ name: job.name,
58
+ queue: job.queue,
59
+ state: "waiting",
60
+ payload: job.payload,
61
+ progress: 0,
62
+ attemptsMade: 0,
63
+ createdAt: job.pushedAt
64
+ };
65
+ }
66
+ };
67
+ /**
68
+ * Records every `@warlock.js/queue` dispatch instead of pushing it to Redis.
69
+ *
70
+ * Installed by default in the test environment. Jobs are recorded, not run:
71
+ * call the job's handler directly to test what it does.
72
+ *
73
+ * @example
74
+ * await placeOrder(order);
75
+ *
76
+ * queueFake.assertPushed(sendInvoice, { orderId: order.id });
77
+ * queueFake.assertPushedCount(1);
78
+ */
79
+ const queueFake = {
80
+ /** Start recording (idempotent). Clears anything recorded before. */
81
+ install() {
82
+ const holder = globalThis;
83
+ if (!installed) {
84
+ previous = holder[INTERCEPTOR_KEY];
85
+ installed = true;
86
+ }
87
+ holder[INTERCEPTOR_KEY] = interceptor;
88
+ queueFake.clear();
89
+ },
90
+ /** Stop recording; dispatches reach the broker again. */
91
+ restore() {
92
+ if (!installed) return;
93
+ globalThis[INTERCEPTOR_KEY] = previous;
94
+ previous = void 0;
95
+ installed = false;
96
+ queueFake.clear();
97
+ },
98
+ isInstalled() {
99
+ return installed;
100
+ },
101
+ /** Forget recorded jobs. */
102
+ clear() {
103
+ pushed.length = 0;
104
+ sequence = 0;
105
+ },
106
+ /** Recorded jobs, oldest first; optionally only one job type. */
107
+ pushed(job, matcher) {
108
+ return pushed.filter((entry) => (job === void 0 || entry.name === nameOf(job)) && matches(entry, matcher));
109
+ },
110
+ /** Assert `job` was pushed (with a payload matching `matcher`); returns the first match. */
111
+ assertPushed(job, matcher) {
112
+ const found = queueFake.pushed(job, matcher)[0];
113
+ if (!found) throw new FakeAssertionError(`Expected ${nameOf(job)} to be pushed${matcher === void 0 ? "" : " with a matching payload"}. ${describeRecorded(pushed, describeJob, "pushed")}`);
114
+ return found;
115
+ },
116
+ /** Assert `job` was not pushed (with a matching payload). */
117
+ assertNotPushed(job, matcher) {
118
+ const found = queueFake.pushed(job, matcher);
119
+ if (found.length > 0) throw new FakeAssertionError(`Expected ${nameOf(job)} not to be pushed. ${describeRecorded(found, describeJob, "pushed")}`);
120
+ },
121
+ /** Assert exactly `count` jobs were pushed — of type `job` when given. */
122
+ assertPushedCount(count, job) {
123
+ const found = queueFake.pushed(job);
124
+ if (found.length !== count) throw new FakeAssertionError(`Expected ${count} ${job === void 0 ? "job(s)" : nameOf(job)} pushed, found ${found.length}. ${describeRecorded(pushed, describeJob, "pushed")}`);
125
+ },
126
+ /** Assert nothing was pushed. */
127
+ assertNothingPushed() {
128
+ queueFake.assertPushedCount(0);
129
+ }
130
+ };
131
+
132
+ //#endregion
133
+ export { queueFake };
134
+ //# sourceMappingURL=queue-fake.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue-fake.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/tests/fakes/queue-fake.ts"],"sourcesContent":["import { clock } from \"../../utils/clock\";\nimport { FakeAssertionError, describeRecorded } from \"./fake-assertion-error\";\n\n/**\n * One job `dispatch()`ed while the fake was installed.\n *\n * Structural on purpose: core has no dependency on `@warlock.js/queue`. The\n * fake talks to it through the global dispatch-interceptor slot that package\n * reads (`setDispatchInterceptor`).\n */\nexport type PushedJob = {\n id: string;\n name: string;\n queue: string;\n payload: unknown;\n /** The dispatch options (`delay`, `priority`, `jobId`, ...). */\n options: Record<string, unknown>;\n pushedAt: Date;\n};\n\n/** A job name, or anything with a `name` — the object `defineJob()` returns. */\nexport type JobReference = string | { readonly name: string };\n\n/** Which pushed jobs an assertion is about: a predicate, or a payload subset. */\nexport type PushedJobMatcher = ((job: PushedJob) => boolean) | Record<string, unknown>;\n\nconst INTERCEPTOR_KEY = Symbol.for(\"warlock.queue.dispatchInterceptor\");\n\ntype Interceptor = {\n dispatch(job: {\n name: string;\n queue: string;\n payload: unknown;\n options: Record<string, unknown>;\n }): { id: string; name: string; queue: string };\n find(job: { name: string; id: string }): unknown;\n};\n\ntype InterceptorHolder = { [INTERCEPTOR_KEY]?: Interceptor };\n\nconst pushed: PushedJob[] = [];\nlet sequence = 0;\nlet previous: Interceptor | undefined;\nlet installed = false;\n\nfunction nameOf(job: JobReference): string {\n return typeof job === \"string\" ? job : job.name;\n}\n\nfunction isSubset(expected: unknown, actual: unknown): boolean {\n if (expected === actual) return true;\n if (typeof expected !== \"object\" || expected === null) return false;\n if (typeof actual !== \"object\" || actual === null) return false;\n\n return Object.entries(expected).every(([key, value]) =>\n isSubset(value, (actual as Record<string, unknown>)[key]),\n );\n}\n\nfunction matches(job: PushedJob, matcher: PushedJobMatcher | undefined): boolean {\n if (matcher === undefined) return true;\n if (typeof matcher === \"function\") return matcher(job);\n\n return isSubset(matcher, job.payload);\n}\n\nfunction describeJob(job: PushedJob): string {\n return `${job.name} on \"${job.queue}\" with ${JSON.stringify(job.payload)}`;\n}\n\nconst interceptor: Interceptor = {\n dispatch({ name, queue, payload, options }) {\n // An explicit jobId makes a real dispatch idempotent; keep that contract.\n const explicitId = typeof options.jobId === \"string\" ? options.jobId : undefined;\n const existing = explicitId ? pushed.find((job) => job.id === explicitId) : undefined;\n\n if (existing) return { id: existing.id, name: existing.name, queue: existing.queue };\n\n sequence += 1;\n\n const job: PushedJob = {\n id: explicitId ?? `fake-${sequence}`,\n name,\n queue,\n payload,\n options: { ...options },\n pushedAt: clock.now(),\n };\n\n pushed.push(job);\n\n return { id: job.id, name, queue };\n },\n\n find({ name, id }) {\n const job = pushed.find((entry) => entry.id === id && entry.name === name);\n\n if (!job) return undefined;\n\n return {\n id: job.id,\n name: job.name,\n queue: job.queue,\n state: \"waiting\",\n payload: job.payload,\n progress: 0,\n attemptsMade: 0,\n createdAt: job.pushedAt,\n };\n },\n};\n\n/**\n * Records every `@warlock.js/queue` dispatch instead of pushing it to Redis.\n *\n * Installed by default in the test environment. Jobs are recorded, not run:\n * call the job's handler directly to test what it does.\n *\n * @example\n * await placeOrder(order);\n *\n * queueFake.assertPushed(sendInvoice, { orderId: order.id });\n * queueFake.assertPushedCount(1);\n */\nexport const queueFake = {\n /** Start recording (idempotent). Clears anything recorded before. */\n install(): void {\n const holder = globalThis as InterceptorHolder;\n\n if (!installed) {\n previous = holder[INTERCEPTOR_KEY];\n installed = true;\n }\n\n holder[INTERCEPTOR_KEY] = interceptor;\n queueFake.clear();\n },\n\n /** Stop recording; dispatches reach the broker again. */\n restore(): void {\n if (!installed) return;\n\n (globalThis as InterceptorHolder)[INTERCEPTOR_KEY] = previous;\n previous = undefined;\n installed = false;\n queueFake.clear();\n },\n\n isInstalled(): boolean {\n return installed;\n },\n\n /** Forget recorded jobs. */\n clear(): void {\n pushed.length = 0;\n sequence = 0;\n },\n\n /** Recorded jobs, oldest first; optionally only one job type. */\n pushed(job?: JobReference, matcher?: PushedJobMatcher): PushedJob[] {\n return pushed.filter(\n (entry) => (job === undefined || entry.name === nameOf(job)) && matches(entry, matcher),\n );\n },\n\n /** Assert `job` was pushed (with a payload matching `matcher`); returns the first match. */\n assertPushed(job: JobReference, matcher?: PushedJobMatcher): PushedJob {\n const found = queueFake.pushed(job, matcher)[0];\n\n if (!found) {\n throw new FakeAssertionError(\n `Expected ${nameOf(job)} to be pushed${matcher === undefined ? \"\" : \" with a matching payload\"}. ${describeRecorded(pushed, describeJob, \"pushed\")}`,\n );\n }\n\n return found;\n },\n\n /** Assert `job` was not pushed (with a matching payload). */\n assertNotPushed(job: JobReference, matcher?: PushedJobMatcher): void {\n const found = queueFake.pushed(job, matcher);\n\n if (found.length > 0) {\n throw new FakeAssertionError(\n `Expected ${nameOf(job)} not to be pushed. ${describeRecorded(found, describeJob, \"pushed\")}`,\n );\n }\n },\n\n /** Assert exactly `count` jobs were pushed — of type `job` when given. */\n assertPushedCount(count: number, job?: JobReference): void {\n const found = queueFake.pushed(job);\n\n if (found.length !== count) {\n throw new FakeAssertionError(\n `Expected ${count} ${job === undefined ? \"job(s)\" : nameOf(job)} pushed, found ${found.length}. ${describeRecorded(pushed, describeJob, \"pushed\")}`,\n );\n }\n },\n\n /** Assert nothing was pushed. */\n assertNothingPushed(): void {\n queueFake.assertPushedCount(0);\n },\n};\n"],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import { StorageDriverName } from "../../storage/types.mjs";
2
+
3
+ //#region ../../packages/core/src/tests/fakes/storage-fake.d.ts
4
+ /**
5
+ * Points every configured storage driver — local, S3, R2, Spaces — at a
6
+ * local temporary directory.
7
+ *
8
+ * Installed by default in the test environment: uploads and `storage.put()`
9
+ * calls land on disk under one temp root (a folder per driver name), never in
10
+ * a bucket and never in the app's real `storage/` folder. The root is shared
11
+ * with the HTTP test server, so a file an HTTP request stored is visible to
12
+ * the test that sent it. The process that created the root deletes it on
13
+ * restore.
14
+ *
15
+ * @example
16
+ * await uploadAvatar(user, file);
17
+ *
18
+ * await storageFake.assertExists(`avatars/${user.id}.png`);
19
+ */
20
+ declare const storageFake: {
21
+ /** Re-register every driver as a local one under the temp root. */install(): Promise<void>; /** Drop the fake drivers; the real configuration is read again on next use. */
22
+ restore(): Promise<void>;
23
+ isInstalled(): boolean; /** The temp directory every fake driver lives under. */
24
+ root(): string; /** Every stored file, as `<driver>/<path>`, sorted. */
25
+ files(driver?: StorageDriverName): string[]; /** Assert a file exists, on the default driver unless `driver` is given. */
26
+ assertExists(location: string, driver?: StorageDriverName): Promise<void>; /** Assert a file does not exist, on the default driver unless `driver` is given. */
27
+ assertMissing(location: string, driver?: StorageDriverName): Promise<void>;
28
+ };
29
+ //#endregion
30
+ export { storageFake };
31
+ //# sourceMappingURL=storage-fake.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-fake.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/tests/fakes/storage-fake.ts"],"mappings":";;;;;;;;;;;;;;;;;;;cA2Da,WAAA;gFAEM,OAAA,QA6EkB;aAtClB,OAAA;;kBAmDmB;iBArBrB,iBAAA,aAqB2D;iCAbvC,MAAA,GAAW,iBAAA,GAAoB,OAAA;kCAa9B,MAAA,GAAW,iBAAA,GAAoB,OAAA;AAAA"}
@@ -0,0 +1,122 @@
1
+ import { storageConfigurations } from "../../storage/config.mjs";
2
+ import { storage } from "../../storage/storage.mjs";
3
+ import "../../storage/index.mjs";
4
+ import { FakeAssertionError } from "./fake-assertion-error.mjs";
5
+ import path from "node:path";
6
+ import { existsSync, mkdirSync, mkdtempSync, readdirSync, rmSync } from "node:fs";
7
+ import os from "node:os";
8
+
9
+ //#region ../../packages/core/src/tests/fakes/storage-fake.ts
10
+ /**
11
+ * The env var that carries the fake storage root from the process that
12
+ * created it (the HTTP test server, in `globalSetup`) to the test workers it
13
+ * spawns, so both sides read and write the same files. Like
14
+ * `WARLOCK_TEST_SERVER_PORT`, it is plumbing between the kit's own processes.
15
+ */
16
+ const TEST_STORAGE_ROOT_ENV_KEY = "WARLOCK_TEST_STORAGE_ROOT";
17
+ let root;
18
+ let ownsRoot = false;
19
+ let installed = false;
20
+ let wasInitialized = false;
21
+ function currentRoot() {
22
+ if (!root) throw new FakeAssertionError("storageFake is not installed. It installs by default in the test environment; check `tests.fakes` in src/config/tests.ts, or call storageFake.install().");
23
+ return root;
24
+ }
25
+ function listFiles(directory, base) {
26
+ if (!existsSync(directory)) return [];
27
+ return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
28
+ const absolute = path.join(directory, entry.name);
29
+ return entry.isDirectory() ? listFiles(absolute, base) : [path.relative(base, absolute).split(path.sep).join("/")];
30
+ });
31
+ }
32
+ /**
33
+ * Points every configured storage driver — local, S3, R2, Spaces — at a
34
+ * local temporary directory.
35
+ *
36
+ * Installed by default in the test environment: uploads and `storage.put()`
37
+ * calls land on disk under one temp root (a folder per driver name), never in
38
+ * a bucket and never in the app's real `storage/` folder. The root is shared
39
+ * with the HTTP test server, so a file an HTTP request stored is visible to
40
+ * the test that sent it. The process that created the root deletes it on
41
+ * restore.
42
+ *
43
+ * @example
44
+ * await uploadAvatar(user, file);
45
+ *
46
+ * await storageFake.assertExists(`avatars/${user.id}.png`);
47
+ */
48
+ const storageFake = {
49
+ /** Re-register every driver as a local one under the temp root. */
50
+ async install() {
51
+ if (!installed) {
52
+ wasInitialized = storage.isInitialized;
53
+ installed = true;
54
+ }
55
+ if (!root) {
56
+ const shared = process.env[TEST_STORAGE_ROOT_ENV_KEY];
57
+ if (shared) {
58
+ root = shared;
59
+ ownsRoot = false;
60
+ } else {
61
+ root = mkdtempSync(path.join(os.tmpdir(), "warlock-test-storage-"));
62
+ ownsRoot = true;
63
+ process.env[TEST_STORAGE_ROOT_ENV_KEY] = root;
64
+ }
65
+ }
66
+ await storage.init();
67
+ const fakeRoot = root;
68
+ for (const name of storage.driverNames()) {
69
+ const driverRoot = path.join(fakeRoot, name);
70
+ mkdirSync(driverRoot, { recursive: true });
71
+ storage.register(name, storageConfigurations.local({
72
+ root: driverRoot,
73
+ urlPrefix: `/test-storage/${name}`
74
+ }));
75
+ }
76
+ const defaultName = storage.getDefaultName();
77
+ if (defaultName) storage.setDefault(defaultName);
78
+ },
79
+ /** Drop the fake drivers; the real configuration is read again on next use. */
80
+ async restore() {
81
+ if (!installed) return;
82
+ installed = false;
83
+ storage.reset();
84
+ if (wasInitialized) await storage.init();
85
+ if (root && ownsRoot) {
86
+ rmSync(root, {
87
+ recursive: true,
88
+ force: true
89
+ });
90
+ if (process.env["WARLOCK_TEST_STORAGE_ROOT"] === root) delete process.env[TEST_STORAGE_ROOT_ENV_KEY];
91
+ }
92
+ root = void 0;
93
+ ownsRoot = false;
94
+ },
95
+ isInstalled() {
96
+ return installed;
97
+ },
98
+ /** The temp directory every fake driver lives under. */
99
+ root() {
100
+ return currentRoot();
101
+ },
102
+ /** Every stored file, as `<driver>/<path>`, sorted. */
103
+ files(driver) {
104
+ const base = currentRoot();
105
+ const directory = driver ? path.join(base, driver) : base;
106
+ return listFiles(directory, directory).sort();
107
+ },
108
+ /** Assert a file exists, on the default driver unless `driver` is given. */
109
+ async assertExists(location, driver) {
110
+ currentRoot();
111
+ if (!await (driver ? storage.use(driver) : storage).exists(location)) throw new FakeAssertionError(`Expected ${JSON.stringify(location)} to be stored${driver ? ` on "${driver}"` : ""}. Stored files: ${JSON.stringify(storageFake.files())}.`);
112
+ },
113
+ /** Assert a file does not exist, on the default driver unless `driver` is given. */
114
+ async assertMissing(location, driver) {
115
+ currentRoot();
116
+ if (await (driver ? storage.use(driver) : storage).exists(location)) throw new FakeAssertionError(`Expected ${JSON.stringify(location)} not to be stored${driver ? ` on "${driver}"` : ""}, but it is.`);
117
+ }
118
+ };
119
+
120
+ //#endregion
121
+ export { storageFake };
122
+ //# sourceMappingURL=storage-fake.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-fake.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/tests/fakes/storage-fake.ts"],"sourcesContent":["import { existsSync, mkdirSync, mkdtempSync, readdirSync, rmSync } from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { storage } from \"../../storage\";\nimport { storageConfigurations } from \"../../storage/config\";\nimport type { StorageDriverName } from \"../../storage/types\";\nimport { FakeAssertionError } from \"./fake-assertion-error\";\n\n/**\n * The env var that carries the fake storage root from the process that\n * created it (the HTTP test server, in `globalSetup`) to the test workers it\n * spawns, so both sides read and write the same files. Like\n * `WARLOCK_TEST_SERVER_PORT`, it is plumbing between the kit's own processes.\n */\nexport const TEST_STORAGE_ROOT_ENV_KEY = \"WARLOCK_TEST_STORAGE_ROOT\";\n\nlet root: string | undefined;\nlet ownsRoot = false;\nlet installed = false;\nlet wasInitialized = false;\n\nfunction currentRoot(): string {\n if (!root) {\n throw new FakeAssertionError(\n \"storageFake is not installed. It installs by default in the test environment; check `tests.fakes` in src/config/tests.ts, or call storageFake.install().\",\n );\n }\n\n return root;\n}\n\nfunction listFiles(directory: string, base: string): string[] {\n if (!existsSync(directory)) return [];\n\n return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {\n const absolute = path.join(directory, entry.name);\n\n return entry.isDirectory()\n ? listFiles(absolute, base)\n : [path.relative(base, absolute).split(path.sep).join(\"/\")];\n });\n}\n\n/**\n * Points every configured storage driver — local, S3, R2, Spaces — at a\n * local temporary directory.\n *\n * Installed by default in the test environment: uploads and `storage.put()`\n * calls land on disk under one temp root (a folder per driver name), never in\n * a bucket and never in the app's real `storage/` folder. The root is shared\n * with the HTTP test server, so a file an HTTP request stored is visible to\n * the test that sent it. The process that created the root deletes it on\n * restore.\n *\n * @example\n * await uploadAvatar(user, file);\n *\n * await storageFake.assertExists(`avatars/${user.id}.png`);\n */\nexport const storageFake = {\n /** Re-register every driver as a local one under the temp root. */\n async install(): Promise<void> {\n if (!installed) {\n wasInitialized = storage.isInitialized;\n installed = true;\n }\n\n if (!root) {\n const shared = process.env[TEST_STORAGE_ROOT_ENV_KEY];\n\n if (shared) {\n root = shared;\n ownsRoot = false;\n } else {\n root = mkdtempSync(path.join(os.tmpdir(), \"warlock-test-storage-\"));\n ownsRoot = true;\n process.env[TEST_STORAGE_ROOT_ENV_KEY] = root;\n }\n }\n\n await storage.init();\n\n const fakeRoot = root;\n\n for (const name of storage.driverNames()) {\n const driverRoot = path.join(fakeRoot, name);\n\n mkdirSync(driverRoot, { recursive: true });\n storage.register(\n name,\n storageConfigurations.local({ root: driverRoot, urlPrefix: `/test-storage/${name}` }),\n );\n }\n\n const defaultName = storage.getDefaultName();\n\n if (defaultName) storage.setDefault(defaultName);\n },\n\n /** Drop the fake drivers; the real configuration is read again on next use. */\n async restore(): Promise<void> {\n if (!installed) return;\n\n installed = false;\n storage.reset();\n\n if (wasInitialized) await storage.init();\n\n if (root && ownsRoot) {\n rmSync(root, { recursive: true, force: true });\n\n if (process.env[TEST_STORAGE_ROOT_ENV_KEY] === root) {\n delete process.env[TEST_STORAGE_ROOT_ENV_KEY];\n }\n }\n\n root = undefined;\n ownsRoot = false;\n },\n\n isInstalled(): boolean {\n return installed;\n },\n\n /** The temp directory every fake driver lives under. */\n root(): string {\n return currentRoot();\n },\n\n /** Every stored file, as `<driver>/<path>`, sorted. */\n files(driver?: StorageDriverName): string[] {\n const base = currentRoot();\n const directory = driver ? path.join(base, driver) : base;\n\n return listFiles(directory, directory).sort();\n },\n\n /** Assert a file exists, on the default driver unless `driver` is given. */\n async assertExists(location: string, driver?: StorageDriverName): Promise<void> {\n currentRoot();\n\n const target = driver ? storage.use(driver) : storage;\n\n if (!(await target.exists(location))) {\n throw new FakeAssertionError(\n `Expected ${JSON.stringify(location)} to be stored${driver ? ` on \"${driver}\"` : \"\"}. Stored files: ${JSON.stringify(storageFake.files())}.`,\n );\n }\n },\n\n /** Assert a file does not exist, on the default driver unless `driver` is given. */\n async assertMissing(location: string, driver?: StorageDriverName): Promise<void> {\n currentRoot();\n\n const target = driver ? storage.use(driver) : storage;\n\n if (await target.exists(location)) {\n throw new FakeAssertionError(\n `Expected ${JSON.stringify(location)} not to be stored${driver ? ` on \"${driver}\"` : \"\"}, but it is.`,\n );\n }\n },\n};\n"],"mappings":";;;;;;;;;;;;;;;AAcA,MAAa,4BAA4B;AAEzC,IAAI;AACJ,IAAI,WAAW;AACf,IAAI,YAAY;AAChB,IAAI,iBAAiB;AAErB,SAAS,cAAsB;CAC7B,IAAI,CAAC,MACH,MAAM,IAAI,mBACR,0JACF;CAGF,OAAO;AACT;AAEA,SAAS,UAAU,WAAmB,MAAwB;CAC5D,IAAI,CAAC,WAAW,SAAS,GAAG,OAAO,CAAC;CAEpC,OAAO,YAAY,WAAW,EAAE,eAAe,KAAK,CAAC,CAAC,CAAC,SAAS,UAAU;EACxE,MAAM,WAAW,KAAK,KAAK,WAAW,MAAM,IAAI;EAEhD,OAAO,MAAM,YAAY,IACrB,UAAU,UAAU,IAAI,IACxB,CAAC,KAAK,SAAS,MAAM,QAAQ,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC;CAC9D,CAAC;AACH;;;;;;;;;;;;;;;;;AAkBA,MAAa,cAAc;;CAEzB,MAAM,UAAyB;EAC7B,IAAI,CAAC,WAAW;GACd,iBAAiB,QAAQ;GACzB,YAAY;EACd;EAEA,IAAI,CAAC,MAAM;GACT,MAAM,SAAS,QAAQ,IAAI;GAE3B,IAAI,QAAQ;IACV,OAAO;IACP,WAAW;GACb,OAAO;IACL,OAAO,YAAY,KAAK,KAAK,GAAG,OAAO,GAAG,uBAAuB,CAAC;IAClE,WAAW;IACX,QAAQ,IAAI,6BAA6B;GAC3C;EACF;EAEA,MAAM,QAAQ,KAAK;EAEnB,MAAM,WAAW;EAEjB,KAAK,MAAM,QAAQ,QAAQ,YAAY,GAAG;GACxC,MAAM,aAAa,KAAK,KAAK,UAAU,IAAI;GAE3C,UAAU,YAAY,EAAE,WAAW,KAAK,CAAC;GACzC,QAAQ,SACN,MACA,sBAAsB,MAAM;IAAE,MAAM;IAAY,WAAW,iBAAiB;GAAO,CAAC,CACtF;EACF;EAEA,MAAM,cAAc,QAAQ,eAAe;EAE3C,IAAI,aAAa,QAAQ,WAAW,WAAW;CACjD;;CAGA,MAAM,UAAyB;EAC7B,IAAI,CAAC,WAAW;EAEhB,YAAY;EACZ,QAAQ,MAAM;EAEd,IAAI,gBAAgB,MAAM,QAAQ,KAAK;EAEvC,IAAI,QAAQ,UAAU;GACpB,OAAO,MAAM;IAAE,WAAW;IAAM,OAAO;GAAK,CAAC;GAE7C,IAAI,QAAQ,qCAAmC,MAC7C,OAAO,QAAQ,IAAI;EAEvB;EAEA,OAAO;EACP,WAAW;CACb;CAEA,cAAuB;EACrB,OAAO;CACT;;CAGA,OAAe;EACb,OAAO,YAAY;CACrB;;CAGA,MAAM,QAAsC;EAC1C,MAAM,OAAO,YAAY;EACzB,MAAM,YAAY,SAAS,KAAK,KAAK,MAAM,MAAM,IAAI;EAErD,OAAO,UAAU,WAAW,SAAS,CAAC,CAAC,KAAK;CAC9C;;CAGA,MAAM,aAAa,UAAkB,QAA2C;EAC9E,YAAY;EAIZ,IAAI,CAAE,OAFS,SAAS,QAAQ,IAAI,MAAM,IAAI,QAE5B,CAAC,OAAO,QAAQ,GAChC,MAAM,IAAI,mBACR,YAAY,KAAK,UAAU,QAAQ,EAAE,eAAe,SAAS,QAAQ,OAAO,KAAK,GAAG,kBAAkB,KAAK,UAAU,YAAY,MAAM,CAAC,EAAE,EAC5I;CAEJ;;CAGA,MAAM,cAAc,UAAkB,QAA2C;EAC/E,YAAY;EAIZ,IAAI,OAFW,SAAS,QAAQ,IAAI,MAAM,IAAI,QAE9B,CAAC,OAAO,QAAQ,GAC9B,MAAM,IAAI,mBACR,YAAY,KAAK,UAAU,QAAQ,EAAE,mBAAmB,SAAS,QAAQ,OAAO,KAAK,GAAG,aAC1F;CAEJ;AACF"}