@warlock.js/core 5.30.0 → 5.32.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 (1374) hide show
  1. package/CHANGELOG.md +165 -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/application/app.d.mts +3 -3
  6. package/esm/application/app.d.mts.map +1 -1
  7. package/esm/application/application-config-types.d.mts +1 -2
  8. package/esm/application/application-config-types.d.mts.map +1 -1
  9. package/esm/application/application.d.mts +5 -7
  10. package/esm/application/application.d.mts.map +1 -1
  11. package/esm/application/application.mjs +3 -1
  12. package/esm/application/application.mjs.map +1 -1
  13. package/esm/application/boot-signal.d.mts +14 -12
  14. package/esm/application/boot-signal.d.mts.map +1 -1
  15. package/esm/application/index.d.mts +2 -1
  16. package/esm/application/index.mjs +1 -1
  17. package/esm/application/public-url.d.mts +1 -2
  18. package/esm/application/public-url.d.mts.map +1 -1
  19. package/esm/application/roles.d.mts +10 -11
  20. package/esm/application/roles.d.mts.map +1 -1
  21. package/esm/benchmark/benchmark-snapshots.d.mts +1 -3
  22. package/esm/benchmark/benchmark-snapshots.d.mts.map +1 -1
  23. package/esm/benchmark/benchmark.d.mts +1 -3
  24. package/esm/benchmark/benchmark.d.mts.map +1 -1
  25. package/esm/benchmark/channels/console.channel.d.mts +1 -3
  26. package/esm/benchmark/channels/console.channel.d.mts.map +1 -1
  27. package/esm/benchmark/channels/noop.channel.d.mts +1 -3
  28. package/esm/benchmark/channels/noop.channel.d.mts.map +1 -1
  29. package/esm/benchmark/index.mjs +1 -1
  30. package/esm/benchmark/profiler.d.mts +1 -3
  31. package/esm/benchmark/profiler.d.mts.map +1 -1
  32. package/esm/benchmark/profiler.mjs +2 -1
  33. package/esm/benchmark/profiler.mjs.map +1 -1
  34. package/esm/benchmark/types.d.mts +22 -17
  35. package/esm/benchmark/types.d.mts.map +1 -1
  36. package/esm/bootstrap/setup.d.mts +1 -2
  37. package/esm/bootstrap/setup.d.mts.map +1 -1
  38. package/esm/bootstrap.d.mts +1 -2
  39. package/esm/bootstrap.d.mts.map +1 -1
  40. package/esm/cache/database-cache-driver.d.mts +3 -5
  41. package/esm/cache/database-cache-driver.d.mts.map +1 -1
  42. package/esm/cache/database-cache-driver.mjs +1 -1
  43. package/esm/cache/index.d.mts +2 -1
  44. package/esm/cache/index.mjs +1 -1
  45. package/esm/cli/cli-commands.manager.mjs +6 -3
  46. package/esm/cli/cli-commands.manager.mjs.map +1 -1
  47. package/esm/cli/commands/add.command.mjs +4 -2
  48. package/esm/cli/commands/add.command.mjs.map +1 -1
  49. package/esm/cli/commands/agents-md/agents-md-command.action.mjs +70 -0
  50. package/esm/cli/commands/agents-md/agents-md-command.action.mjs.map +1 -0
  51. package/esm/cli/commands/agents-md.command.mjs +38 -0
  52. package/esm/cli/commands/agents-md.command.mjs.map +1 -0
  53. package/esm/cli/commands/board/board-command.action.mjs +279 -0
  54. package/esm/cli/commands/board/board-command.action.mjs.map +1 -0
  55. package/esm/cli/commands/board.command.mjs +78 -0
  56. package/esm/cli/commands/board.command.mjs.map +1 -0
  57. package/esm/cli/commands/build.command.mjs +6 -1
  58. package/esm/cli/commands/build.command.mjs.map +1 -1
  59. package/esm/cli/commands/check/check-command.action.mjs +57 -0
  60. package/esm/cli/commands/check/check-command.action.mjs.map +1 -0
  61. package/esm/cli/commands/check/child-typecheck.mjs +66 -0
  62. package/esm/cli/commands/check/child-typecheck.mjs.map +1 -0
  63. package/esm/cli/commands/check/format-problems.mjs +43 -0
  64. package/esm/cli/commands/check/format-problems.mjs.map +1 -0
  65. package/esm/cli/commands/check/typecheck-command.action.mjs +61 -0
  66. package/esm/cli/commands/check/typecheck-command.action.mjs.map +1 -0
  67. package/esm/cli/commands/check.command.mjs +50 -0
  68. package/esm/cli/commands/check.command.mjs.map +1 -0
  69. package/esm/cli/commands/dev-server.command.mjs +12 -3
  70. package/esm/cli/commands/dev-server.command.mjs.map +1 -1
  71. package/esm/cli/commands/doctor/boot-for-diagnostics.mjs +8 -3
  72. package/esm/cli/commands/doctor/boot-for-diagnostics.mjs.map +1 -1
  73. package/esm/cli/commands/doctor/check.types.d.mts +89 -0
  74. package/esm/cli/commands/doctor/check.types.d.mts.map +1 -0
  75. package/esm/cli/commands/doctor/checks/config.check.mjs +1 -0
  76. package/esm/cli/commands/doctor/checks/config.check.mjs.map +1 -1
  77. package/esm/cli/commands/doctor/checks/connectors.check.mjs +2 -0
  78. package/esm/cli/commands/doctor/checks/connectors.check.mjs.map +1 -1
  79. package/esm/cli/commands/doctor/checks/handler-signature.check.mjs +1 -0
  80. package/esm/cli/commands/doctor/checks/handler-signature.check.mjs.map +1 -1
  81. package/esm/cli/commands/doctor/checks/health.check.mjs +3 -0
  82. package/esm/cli/commands/doctor/checks/health.check.mjs.map +1 -1
  83. package/esm/cli/commands/doctor/checks/jwt-secret.check.mjs +1 -0
  84. package/esm/cli/commands/doctor/checks/jwt-secret.check.mjs.map +1 -1
  85. package/esm/cli/commands/doctor/checks/locales-ts-deprecated.check.mjs +23 -27
  86. package/esm/cli/commands/doctor/checks/locales-ts-deprecated.check.mjs.map +1 -1
  87. package/esm/cli/commands/doctor/checks/optional-peers.check.mjs +1 -0
  88. package/esm/cli/commands/doctor/checks/optional-peers.check.mjs.map +1 -1
  89. package/esm/cli/commands/doctor/checks/release-hygiene.check.mjs +4 -0
  90. package/esm/cli/commands/doctor/checks/release-hygiene.check.mjs.map +1 -1
  91. package/esm/cli/commands/doctor/checks/routes.check.mjs +3 -0
  92. package/esm/cli/commands/doctor/checks/routes.check.mjs.map +1 -1
  93. package/esm/cli/commands/doctor/doctor-command.action.mjs +15 -6
  94. package/esm/cli/commands/doctor/doctor-command.action.mjs.map +1 -1
  95. package/esm/cli/commands/doctor/format-report.mjs +30 -2
  96. package/esm/cli/commands/doctor/format-report.mjs.map +1 -1
  97. package/esm/cli/commands/doctor.command.mjs +4 -0
  98. package/esm/cli/commands/doctor.command.mjs.map +1 -1
  99. package/esm/cli/commands/explain/explain-command.action.mjs +64 -0
  100. package/esm/cli/commands/explain/explain-command.action.mjs.map +1 -0
  101. package/esm/cli/commands/explain.command.mjs +23 -0
  102. package/esm/cli/commands/explain.command.mjs.map +1 -0
  103. package/esm/cli/commands/generate/generate.command.mjs +124 -124
  104. package/esm/cli/commands/generate/generate.command.mjs.map +1 -1
  105. package/esm/cli/commands/generate/generators/controller.generator.mjs +5 -2
  106. package/esm/cli/commands/generate/generators/controller.generator.mjs.map +1 -1
  107. package/esm/cli/commands/generate/generators/endpoint.generator.mjs +313 -0
  108. package/esm/cli/commands/generate/generators/endpoint.generator.mjs.map +1 -0
  109. package/esm/cli/commands/generate/generators/migration.generator.mjs +1 -1
  110. package/esm/cli/commands/generate/generators/migration.generator.mjs.map +1 -1
  111. package/esm/cli/commands/generate/generators/model.generator.mjs +4 -3
  112. package/esm/cli/commands/generate/generators/model.generator.mjs.map +1 -1
  113. package/esm/cli/commands/generate/generators/repository.generator.mjs +3 -1
  114. package/esm/cli/commands/generate/generators/repository.generator.mjs.map +1 -1
  115. package/esm/cli/commands/generate/generators/resource.generator.mjs +3 -1
  116. package/esm/cli/commands/generate/generators/resource.generator.mjs.map +1 -1
  117. package/esm/cli/commands/generate/generators/service.generator.mjs +3 -1
  118. package/esm/cli/commands/generate/generators/service.generator.mjs.map +1 -1
  119. package/esm/cli/commands/generate/templates/endpoint-stubs.mjs +341 -0
  120. package/esm/cli/commands/generate/templates/endpoint-stubs.mjs.map +1 -0
  121. package/esm/cli/commands/generate/templates/stubs.mjs +19 -6
  122. package/esm/cli/commands/generate/templates/stubs.mjs.map +1 -1
  123. package/esm/cli/commands/generate/utils/endpoint-schema.mjs +136 -0
  124. package/esm/cli/commands/generate/utils/endpoint-schema.mjs.map +1 -0
  125. package/esm/cli/commands/generate/utils/name-parser.mjs +2 -2
  126. package/esm/cli/commands/generate/utils/name-parser.mjs.map +1 -1
  127. package/esm/cli/commands/generate/utils/path-resolver.mjs +1 -1
  128. package/esm/cli/commands/generate/utils/prompt.mjs.map +1 -1
  129. package/esm/cli/commands/generate/utils/writer.mjs +38 -13
  130. package/esm/cli/commands/generate/utils/writer.mjs.map +1 -1
  131. package/esm/cli/commands/inspect/inspect-command.action.mjs +73 -0
  132. package/esm/cli/commands/inspect/inspect-command.action.mjs.map +1 -0
  133. package/esm/cli/commands/inspect.command.mjs +39 -0
  134. package/esm/cli/commands/inspect.command.mjs.map +1 -0
  135. package/esm/cli/commands/issue/collect-environment.mjs +187 -0
  136. package/esm/cli/commands/issue/collect-environment.mjs.map +1 -0
  137. package/esm/cli/commands/issue/issue-command.action.mjs +70 -0
  138. package/esm/cli/commands/issue/issue-command.action.mjs.map +1 -0
  139. package/esm/cli/commands/issue.command.mjs +31 -0
  140. package/esm/cli/commands/issue.command.mjs.map +1 -0
  141. package/esm/cli/commands/mcp/mcp-command.action.mjs +104 -0
  142. package/esm/cli/commands/mcp/mcp-command.action.mjs.map +1 -0
  143. package/esm/cli/commands/mcp.command.mjs +76 -0
  144. package/esm/cli/commands/mcp.command.mjs.map +1 -0
  145. package/esm/cli/commands/openapi-generator.action.mjs +1 -1
  146. package/esm/cli/commands/openapi-generator.action.mjs.map +1 -1
  147. package/esm/cli/commands/openapi-generator.command.mjs.map +1 -1
  148. package/esm/cli/commands/postman-generator.action.mjs +1 -1
  149. package/esm/cli/commands/postman-generator.action.mjs.map +1 -1
  150. package/esm/cli/commands/postman-generator.command.mjs.map +1 -1
  151. package/esm/cli/commands/routes/format-routes-table.mjs +1 -1
  152. package/esm/cli/commands/routes/route-row.mjs +1 -1
  153. package/esm/cli/commands/routes/routes-diff.action.mjs +3 -3
  154. package/esm/cli/commands/routes/routes-diff.action.mjs.map +1 -1
  155. package/esm/cli/commands/test.command.mjs +131 -0
  156. package/esm/cli/commands/test.command.mjs.map +1 -0
  157. package/esm/cli/commands/trace/trace-command.action.mjs +145 -0
  158. package/esm/cli/commands/trace/trace-command.action.mjs.map +1 -0
  159. package/esm/cli/commands/trace.command.mjs +60 -0
  160. package/esm/cli/commands/trace.command.mjs.map +1 -0
  161. package/esm/cli/commands/typecheck.command.mjs +40 -0
  162. package/esm/cli/commands/typecheck.command.mjs.map +1 -0
  163. package/esm/cli/commands/upgrade.command.mjs +46 -0
  164. package/esm/cli/commands/upgrade.command.mjs.map +1 -0
  165. package/esm/cli/commands-loader.mjs +1 -1
  166. package/esm/cli/flush-and-exit.mjs +34 -0
  167. package/esm/cli/flush-and-exit.mjs.map +1 -0
  168. package/esm/cli/framework-cli-commands.mjs +25 -1
  169. package/esm/cli/framework-cli-commands.mjs.map +1 -1
  170. package/esm/cli/parse-cli-args.mjs +3 -2
  171. package/esm/cli/parse-cli-args.mjs.map +1 -1
  172. package/esm/cli/start.d.mts +1 -1
  173. package/esm/cli/string-similarity.mjs +1 -1
  174. package/esm/commands/cli-command.d.mts +2 -4
  175. package/esm/commands/cli-command.d.mts.map +1 -1
  176. package/esm/commands/index.d.mts +2 -1
  177. package/esm/commands/index.mjs +1 -1
  178. package/esm/commands/types.d.mts +8 -8
  179. package/esm/commands/types.d.mts.map +1 -1
  180. package/esm/config/config-getter.d.mts +2 -3
  181. package/esm/config/config-getter.d.mts.map +1 -1
  182. package/esm/config/config-getter.mjs +5 -5
  183. package/esm/config/config-getter.mjs.map +1 -1
  184. package/esm/config/config-handlers.d.mts +1 -3
  185. package/esm/config/config-handlers.d.mts.map +1 -1
  186. package/esm/config/config-loader.d.mts +1 -2
  187. package/esm/config/config-loader.d.mts.map +1 -1
  188. package/esm/config/config-loader.mjs +35 -14
  189. package/esm/config/config-loader.mjs.map +1 -1
  190. package/esm/config/config-manager.mjs +1 -1
  191. package/esm/config/config-schema.d.mts +70 -0
  192. package/esm/config/config-schema.d.mts.map +1 -0
  193. package/esm/config/config-schema.mjs +77 -0
  194. package/esm/config/config-schema.mjs.map +1 -0
  195. package/esm/config/config-setter.d.mts +2 -4
  196. package/esm/config/config-setter.d.mts.map +1 -1
  197. package/esm/config/config-setter.mjs +2 -2
  198. package/esm/config/config-setter.mjs.map +1 -1
  199. package/esm/config/config-special-handlers.d.mts +2 -4
  200. package/esm/config/config-special-handlers.d.mts.map +1 -1
  201. package/esm/config/index.d.mts +7 -0
  202. package/esm/config/index.mjs +2 -1
  203. package/esm/config/types.d.mts +4 -5
  204. package/esm/config/types.d.mts.map +1 -1
  205. package/esm/connectors/access-connector.d.mts +1 -3
  206. package/esm/connectors/access-connector.d.mts.map +1 -1
  207. package/esm/connectors/access-connector.mjs +2 -2
  208. package/esm/connectors/access-connector.mjs.map +1 -1
  209. package/esm/connectors/ai-connector.d.mts +1 -3
  210. package/esm/connectors/ai-connector.d.mts.map +1 -1
  211. package/esm/connectors/ai-connector.mjs +2 -2
  212. package/esm/connectors/ai-connector.mjs.map +1 -1
  213. package/esm/connectors/assert-no-reserved-connector-names.d.mts +1 -3
  214. package/esm/connectors/assert-no-reserved-connector-names.d.mts.map +1 -1
  215. package/esm/connectors/assert-no-reserved-connector-names.mjs +2 -1
  216. package/esm/connectors/assert-no-reserved-connector-names.mjs.map +1 -1
  217. package/esm/connectors/assert-unique-connector-names.d.mts +1 -3
  218. package/esm/connectors/assert-unique-connector-names.d.mts.map +1 -1
  219. package/esm/connectors/assert-unique-connector-names.mjs +26 -1
  220. package/esm/connectors/assert-unique-connector-names.mjs.map +1 -1
  221. package/esm/connectors/base-connector.d.mts +1 -3
  222. package/esm/connectors/base-connector.d.mts.map +1 -1
  223. package/esm/connectors/cache-connector.d.mts +1 -3
  224. package/esm/connectors/cache-connector.d.mts.map +1 -1
  225. package/esm/connectors/cache-connector.mjs +3 -3
  226. package/esm/connectors/cache-connector.mjs.map +1 -1
  227. package/esm/connectors/connectors-manager.d.mts +2 -4
  228. package/esm/connectors/connectors-manager.d.mts.map +1 -1
  229. package/esm/connectors/connectors-manager.mjs +2 -2
  230. package/esm/connectors/connectors-manager.mjs.map +1 -1
  231. package/esm/connectors/database-connector.d.mts +1 -3
  232. package/esm/connectors/database-connector.d.mts.map +1 -1
  233. package/esm/connectors/database-connector.mjs +2 -2
  234. package/esm/connectors/database-connector.mjs.map +1 -1
  235. package/esm/connectors/describe-server-address.mjs +4 -4
  236. package/esm/connectors/describe-server-address.mjs.map +1 -1
  237. package/esm/connectors/herald-connector.d.mts +1 -3
  238. package/esm/connectors/herald-connector.d.mts.map +1 -1
  239. package/esm/connectors/herald-connector.mjs +2 -2
  240. package/esm/connectors/herald-connector.mjs.map +1 -1
  241. package/esm/connectors/http-connector.d.mts +1 -3
  242. package/esm/connectors/http-connector.d.mts.map +1 -1
  243. package/esm/connectors/http-connector.mjs +11 -9
  244. package/esm/connectors/http-connector.mjs.map +1 -1
  245. package/esm/connectors/index.d.mts +2 -1
  246. package/esm/connectors/index.mjs +1 -1
  247. package/esm/connectors/logger-connector.d.mts +1 -3
  248. package/esm/connectors/logger-connector.d.mts.map +1 -1
  249. package/esm/connectors/logger-connector.mjs +2 -2
  250. package/esm/connectors/logger-connector.mjs.map +1 -1
  251. package/esm/connectors/mail-connector.d.mts +1 -3
  252. package/esm/connectors/mail-connector.d.mts.map +1 -1
  253. package/esm/connectors/mail-connector.mjs +2 -2
  254. package/esm/connectors/mail-connector.mjs.map +1 -1
  255. package/esm/connectors/notifications-connector.d.mts +1 -3
  256. package/esm/connectors/notifications-connector.d.mts.map +1 -1
  257. package/esm/connectors/notifications-connector.mjs +2 -2
  258. package/esm/connectors/notifications-connector.mjs.map +1 -1
  259. package/esm/connectors/register-configured-connectors.d.mts +2 -4
  260. package/esm/connectors/register-configured-connectors.d.mts.map +1 -1
  261. package/esm/connectors/single-server-warnings.mjs.map +1 -1
  262. package/esm/connectors/socket-connector.d.mts +1 -3
  263. package/esm/connectors/socket-connector.d.mts.map +1 -1
  264. package/esm/connectors/socket-connector.mjs +12 -10
  265. package/esm/connectors/socket-connector.mjs.map +1 -1
  266. package/esm/connectors/storage.connector.d.mts +1 -3
  267. package/esm/connectors/storage.connector.d.mts.map +1 -1
  268. package/esm/connectors/storage.connector.mjs +2 -2
  269. package/esm/connectors/storage.connector.mjs.map +1 -1
  270. package/esm/connectors/types.d.mts +17 -14
  271. package/esm/connectors/types.d.mts.map +1 -1
  272. package/esm/container/container-instance-registry.mjs.map +1 -1
  273. package/esm/container/development-app-modules.d.mts +7 -5
  274. package/esm/container/development-app-modules.d.mts.map +1 -1
  275. package/esm/container/development-model-modules.d.mts +6 -5
  276. package/esm/container/development-model-modules.d.mts.map +1 -1
  277. package/esm/container/index.d.mts +4 -4
  278. package/esm/container/index.d.mts.map +1 -1
  279. package/esm/container/index.mjs.map +1 -1
  280. package/esm/database/index.d.mts +3 -1
  281. package/esm/database/index.mjs +1 -1
  282. package/esm/database/migrate-action.mjs +1 -1
  283. package/esm/database/migrate-action.mjs.map +1 -1
  284. package/esm/database/models/database-log/database-log.d.mts +2 -31
  285. package/esm/database/models/database-log/database-log.d.mts.map +1 -1
  286. package/esm/database/models/database-log/index.d.mts +2 -1
  287. package/esm/database/models/database-log/index.mjs +1 -1
  288. package/esm/database/seed-command-action.mjs +1 -1
  289. package/esm/database/seeds/seeder.d.mts +2 -4
  290. package/esm/database/seeds/seeder.d.mts.map +1 -1
  291. package/esm/database/seeds/seeder.errors.d.mts +6 -3
  292. package/esm/database/seeds/seeder.errors.d.mts.map +1 -1
  293. package/esm/database/seeds/seeder.errors.mjs +2 -0
  294. package/esm/database/seeds/seeder.errors.mjs.map +1 -1
  295. package/esm/database/seeds/seeders.manager.mjs +2 -1
  296. package/esm/database/seeds/seeders.manager.mjs.map +1 -1
  297. package/esm/database/seeds/types.d.mts +7 -8
  298. package/esm/database/seeds/types.d.mts.map +1 -1
  299. package/esm/database/utils.d.mts +4 -5
  300. package/esm/database/utils.d.mts.map +1 -1
  301. package/esm/dev-server/app-module-registry.mjs +1 -1
  302. package/esm/dev-server/boot-precondition-error.mjs +1 -0
  303. package/esm/dev-server/boot-precondition-error.mjs.map +1 -1
  304. package/esm/dev-server/create-worker.mjs +17 -9
  305. package/esm/dev-server/create-worker.mjs.map +1 -1
  306. package/esm/dev-server/dependency-graph.d.mts +1 -3
  307. package/esm/dev-server/dependency-graph.d.mts.map +1 -1
  308. package/esm/dev-server/dependency-graph.mjs +1 -1
  309. package/esm/dev-server/dependency-graph.mjs.map +1 -1
  310. package/esm/dev-server/dev-agent-tooling.mjs +135 -0
  311. package/esm/dev-server/dev-agent-tooling.mjs.map +1 -0
  312. package/esm/dev-server/dev-logger.mjs.map +1 -1
  313. package/esm/dev-server/development-server.mjs +8 -0
  314. package/esm/dev-server/development-server.mjs.map +1 -1
  315. package/esm/dev-server/extract-translation-keys.mjs +16 -17
  316. package/esm/dev-server/extract-translation-keys.mjs.map +1 -1
  317. package/esm/dev-server/file-manager.d.mts +3 -7
  318. package/esm/dev-server/file-manager.d.mts.map +1 -1
  319. package/esm/dev-server/file-operations.d.mts +1 -3
  320. package/esm/dev-server/file-operations.d.mts.map +1 -1
  321. package/esm/dev-server/files-orchestrator.mjs +4 -5
  322. package/esm/dev-server/files-orchestrator.mjs.map +1 -1
  323. package/esm/dev-server/files-watcher.mjs +12 -11
  324. package/esm/dev-server/files-watcher.mjs.map +1 -1
  325. package/esm/dev-server/health-checker/checkers/eslint-health-checker.mjs +2 -3
  326. package/esm/dev-server/health-checker/checkers/eslint-health-checker.mjs.map +1 -1
  327. package/esm/dev-server/health-checker/checkers/oxlint-health-checker.mjs +33 -0
  328. package/esm/dev-server/health-checker/checkers/oxlint-health-checker.mjs.map +1 -0
  329. package/esm/dev-server/health-checker/checkers/typescript-health-checker.mjs +36 -115
  330. package/esm/dev-server/health-checker/checkers/typescript-health-checker.mjs.map +1 -1
  331. package/esm/dev-server/health-checker/default-health-checkers.mjs +31 -0
  332. package/esm/dev-server/health-checker/default-health-checkers.mjs.map +1 -0
  333. package/esm/dev-server/health-checker/file-health-checker.contract.d.mts +12 -6
  334. package/esm/dev-server/health-checker/file-health-checker.contract.d.mts.map +1 -1
  335. package/esm/dev-server/health-checker/file-health-result.d.mts +2 -2
  336. package/esm/dev-server/health-checker/file-health-result.d.mts.map +1 -1
  337. package/esm/dev-server/health-checker/files-healthcare.manager.mjs +16 -4
  338. package/esm/dev-server/health-checker/files-healthcare.manager.mjs.map +1 -1
  339. package/esm/dev-server/health-checker/oxlint-runner.mjs +303 -0
  340. package/esm/dev-server/health-checker/oxlint-runner.mjs.map +1 -0
  341. package/esm/dev-server/health-checker/workers/eslint-health.worker.d.mts +1 -1
  342. package/esm/dev-server/health-checker/workers/oxlint-health.worker.d.mts +1 -0
  343. package/esm/dev-server/health-checker/workers/oxlint-health.worker.mjs +42 -0
  344. package/esm/dev-server/health-checker/workers/oxlint-health.worker.mjs.map +1 -0
  345. package/esm/dev-server/health-checker/workers/ts-health.worker.d.mts +1 -1
  346. package/esm/dev-server/health-checker/workers/ts-health.worker.mjs +40 -174
  347. package/esm/dev-server/health-checker/workers/ts-health.worker.mjs.map +1 -1
  348. package/esm/dev-server/loader/hook-thread.d.mts +4 -8
  349. package/esm/dev-server/loader/hook-thread.d.mts.map +1 -1
  350. package/esm/dev-server/loader/load-hook.d.mts +10 -6
  351. package/esm/dev-server/loader/load-hook.d.mts.map +1 -1
  352. package/esm/dev-server/loader/load-hook.mjs +4 -3
  353. package/esm/dev-server/loader/load-hook.mjs.map +1 -1
  354. package/esm/dev-server/loader/loader-port-acks.mjs +1 -1
  355. package/esm/dev-server/loader/loader-port-acks.mjs.map +1 -1
  356. package/esm/dev-server/loader/own-resolver.mjs +1 -1
  357. package/esm/dev-server/loader/register-loader.mjs +4 -3
  358. package/esm/dev-server/loader/register-loader.mjs.map +1 -1
  359. package/esm/dev-server/loader/resolve-hook.d.mts +2 -2
  360. package/esm/dev-server/loader/resolve-hook.d.mts.map +1 -1
  361. package/esm/dev-server/loader/resolve-hook.mjs +3 -2
  362. package/esm/dev-server/loader/resolve-hook.mjs.map +1 -1
  363. package/esm/dev-server/loader/transpile-cache.mjs +3 -2
  364. package/esm/dev-server/loader/transpile-cache.mjs.map +1 -1
  365. package/esm/dev-server/manifest-manager.d.mts +1 -3
  366. package/esm/dev-server/manifest-manager.d.mts.map +1 -1
  367. package/esm/dev-server/model-module-registry.mjs +3 -3
  368. package/esm/dev-server/model-module-registry.mjs.map +1 -1
  369. package/esm/dev-server/model-resource-typings.mjs +40 -47
  370. package/esm/dev-server/model-resource-typings.mjs.map +1 -1
  371. package/esm/dev-server/module-loader.mjs +3 -2
  372. package/esm/dev-server/module-loader.mjs.map +1 -1
  373. package/esm/dev-server/package-json-manager.mjs +1 -1
  374. package/esm/dev-server/parse-imports.mjs +7 -39
  375. package/esm/dev-server/parse-imports.mjs.map +1 -1
  376. package/esm/dev-server/read-config-ast.mjs +3 -33
  377. package/esm/dev-server/read-config-ast.mjs.map +1 -1
  378. package/esm/dev-server/ready-block.mjs +1 -1
  379. package/esm/dev-server/route-types-publisher.mjs +1 -1
  380. package/esm/dev-server/shortcuts.mjs +1 -1
  381. package/esm/dev-server/special-files-collector.d.mts +2 -4
  382. package/esm/dev-server/special-files-collector.d.mts.map +1 -1
  383. package/esm/dev-server/start-development-server.mjs.map +1 -1
  384. package/esm/dev-server/supervisor.mjs +1 -1
  385. package/esm/dev-server/translation-keys-sources.mjs +1 -1
  386. package/esm/dev-server/translation-keys-sources.mjs.map +1 -1
  387. package/esm/dev-server/tsconfig-manager.mjs +3 -3
  388. package/esm/dev-server/tsconfig-manager.mjs.map +1 -1
  389. package/esm/dev-server/type-generator.mjs +31 -38
  390. package/esm/dev-server/type-generator.mjs.map +1 -1
  391. package/esm/dev-server/types.d.mts +3 -4
  392. package/esm/dev-server/types.d.mts.map +1 -1
  393. package/esm/dev-server/update-check-cache.mjs +2 -2
  394. package/esm/dev-server/update-check-cache.mjs.map +1 -1
  395. package/esm/encryption/encrypt.d.mts +2 -3
  396. package/esm/encryption/encrypt.d.mts.map +1 -1
  397. package/esm/encryption/hash.d.mts +1 -2
  398. package/esm/encryption/hash.d.mts.map +1 -1
  399. package/esm/encryption/index.mjs +1 -1
  400. package/esm/encryption/password.d.mts +2 -3
  401. package/esm/encryption/password.d.mts.map +1 -1
  402. package/esm/encryption/types.d.mts +2 -3
  403. package/esm/encryption/types.d.mts.map +1 -1
  404. package/esm/errors/container-key-missing-error.mjs +1 -0
  405. package/esm/errors/container-key-missing-error.mjs.map +1 -1
  406. package/esm/errors/error-codes.d.mts +660 -0
  407. package/esm/errors/error-codes.d.mts.map +1 -0
  408. package/esm/errors/error-codes.mjs +634 -0
  409. package/esm/errors/error-codes.mjs.map +1 -0
  410. package/esm/errors/esbuild-binary-missing-error.mjs +1 -0
  411. package/esm/errors/esbuild-binary-missing-error.mjs.map +1 -1
  412. package/esm/errors/index.d.mts +3 -1
  413. package/esm/errors/index.mjs +3 -1
  414. package/esm/errors/unknown-locale-error.mjs +1 -0
  415. package/esm/errors/unknown-locale-error.mjs.map +1 -1
  416. package/esm/errors/warlock-error.d.mts +21 -0
  417. package/esm/errors/warlock-error.d.mts.map +1 -0
  418. package/esm/errors/warlock-error.mjs +22 -0
  419. package/esm/errors/warlock-error.mjs.map +1 -0
  420. package/esm/generations/add-command.action.mjs +22 -5
  421. package/esm/generations/add-command.action.mjs.map +1 -1
  422. package/esm/generations/features/access.feature.mjs +1 -1
  423. package/esm/generations/features/access.feature.mjs.map +1 -1
  424. package/esm/generations/features/bull-board.feature.mjs +3 -2
  425. package/esm/generations/features/bull-board.feature.mjs.map +1 -1
  426. package/esm/generations/features/mysql.feature.mjs.map +1 -1
  427. package/esm/generations/features/notifications.feature.mjs +7 -3
  428. package/esm/generations/features/notifications.feature.mjs.map +1 -1
  429. package/esm/generations/features/queue.feature.mjs +1 -1
  430. package/esm/generations/features/queue.feature.mjs.map +1 -1
  431. package/esm/generations/features/react-email.feature.mjs +1 -1
  432. package/esm/generations/features/react-email.feature.mjs.map +1 -1
  433. package/esm/generations/features/shadcn.feature.mjs +1 -1
  434. package/esm/generations/features/shadcn.feature.mjs.map +1 -1
  435. package/esm/generations/features/shared/link-ai-package-import.mjs +1 -1
  436. package/esm/generations/features/shared/link-ai-package-import.mjs.map +1 -1
  437. package/esm/generations/features/shared/merge-web-sitemap-config.mjs +16 -23
  438. package/esm/generations/features/shared/merge-web-sitemap-config.mjs.map +1 -1
  439. package/esm/generations/features/shared/patch-tsconfig-include.mjs +2 -2
  440. package/esm/generations/features/shared/patch-tsconfig-include.mjs.map +1 -1
  441. package/esm/generations/features/shared/relocate-conflicting-home-route.mjs +2 -2
  442. package/esm/generations/features/shared/relocate-conflicting-home-route.mjs.map +1 -1
  443. package/esm/generations/features/sitemap.feature.mjs +3 -2
  444. package/esm/generations/features/sitemap.feature.mjs.map +1 -1
  445. package/esm/generations/features/tailwind.feature.mjs +1 -1
  446. package/esm/generations/features/tailwind.feature.mjs.map +1 -1
  447. package/esm/generations/features/test.feature.mjs +11 -6
  448. package/esm/generations/features/test.feature.mjs.map +1 -1
  449. package/esm/generations/features/web.feature.mjs +1 -1
  450. package/esm/generations/features/web.feature.mjs.map +1 -1
  451. package/esm/generations/generation-fs.mjs +73 -0
  452. package/esm/generations/generation-fs.mjs.map +1 -0
  453. package/esm/generations/generation-run.mjs +185 -0
  454. package/esm/generations/generation-run.mjs.map +1 -0
  455. package/esm/generations/stubs.mjs +156 -14
  456. package/esm/generations/stubs.mjs.map +1 -1
  457. package/esm/http/boot-port-preflight.d.mts +4 -5
  458. package/esm/http/boot-port-preflight.d.mts.map +1 -1
  459. package/esm/http/boot-port-preflight.mjs +2 -2
  460. package/esm/http/boot-port-preflight.mjs.map +1 -1
  461. package/esm/http/bounded-stream-queue.d.mts +10 -0
  462. package/esm/http/bounded-stream-queue.d.mts.map +1 -0
  463. package/esm/http/bounded-stream-queue.mjs +97 -0
  464. package/esm/http/bounded-stream-queue.mjs.map +1 -0
  465. package/esm/http/build-cors-options.mjs +2 -2
  466. package/esm/http/build-cors-options.mjs.map +1 -1
  467. package/esm/http/build-rate-limit-options.d.mts +15 -3
  468. package/esm/http/build-rate-limit-options.d.mts.map +1 -1
  469. package/esm/http/build-rate-limit-options.mjs +1 -1
  470. package/esm/http/build-rate-limit-options.mjs.map +1 -1
  471. package/esm/http/conditional-request.d.mts +87 -0
  472. package/esm/http/conditional-request.d.mts.map +1 -0
  473. package/esm/http/conditional-request.mjs +121 -0
  474. package/esm/http/conditional-request.mjs.map +1 -0
  475. package/esm/http/config.d.mts +2 -4
  476. package/esm/http/config.d.mts.map +1 -1
  477. package/esm/http/config.mjs +2 -2
  478. package/esm/http/config.mjs.map +1 -1
  479. package/esm/http/context/request-context.d.mts +6 -7
  480. package/esm/http/context/request-context.d.mts.map +1 -1
  481. package/esm/http/context/request-memo.d.mts +1 -2
  482. package/esm/http/context/request-memo.d.mts.map +1 -1
  483. package/esm/http/createHttpApplication.d.mts +2 -3
  484. package/esm/http/createHttpApplication.d.mts.map +1 -1
  485. package/esm/http/createHttpApplication.mjs +2 -2
  486. package/esm/http/createHttpApplication.mjs.map +1 -1
  487. package/esm/http/csp.d.mts +12 -12
  488. package/esm/http/csp.d.mts.map +1 -1
  489. package/esm/http/csp.mjs +3 -2
  490. package/esm/http/csp.mjs.map +1 -1
  491. package/esm/http/csrf-default-guard.d.mts +2 -4
  492. package/esm/http/csrf-default-guard.d.mts.map +1 -1
  493. package/esm/http/csrf-default-guard.mjs +1 -1
  494. package/esm/http/csrf-default-guard.mjs.map +1 -1
  495. package/esm/http/csrf-origin-policy.d.mts +7 -9
  496. package/esm/http/csrf-origin-policy.d.mts.map +1 -1
  497. package/esm/http/csrf-origin-policy.mjs +2 -2
  498. package/esm/http/csrf-origin-policy.mjs.map +1 -1
  499. package/esm/http/database/RequestLog.d.mts +26 -87
  500. package/esm/http/database/RequestLog.d.mts.map +1 -1
  501. package/esm/http/error-codes.d.mts +1 -2
  502. package/esm/http/error-codes.d.mts.map +1 -1
  503. package/esm/http/error-mapper.d.mts +2 -4
  504. package/esm/http/error-mapper.d.mts.map +1 -1
  505. package/esm/http/error-mapper.mjs +2 -2
  506. package/esm/http/error-mapper.mjs.map +1 -1
  507. package/esm/http/errors/errors.d.mts +30 -29
  508. package/esm/http/errors/errors.d.mts.map +1 -1
  509. package/esm/http/errors/errors.mjs +1 -0
  510. package/esm/http/errors/errors.mjs.map +1 -1
  511. package/esm/http/escape-header-value.d.mts +17 -0
  512. package/esm/http/escape-header-value.d.mts.map +1 -0
  513. package/esm/http/escape-header-value.mjs +27 -0
  514. package/esm/http/escape-header-value.mjs.map +1 -0
  515. package/esm/http/events.d.mts +2 -4
  516. package/esm/http/events.d.mts.map +1 -1
  517. package/esm/http/flush-pending-cookies.mjs.map +1 -1
  518. package/esm/http/health.d.mts +4 -4
  519. package/esm/http/health.d.mts.map +1 -1
  520. package/esm/http/index.d.mts +9 -3
  521. package/esm/http/index.mjs +5 -2
  522. package/esm/http/lazy-static.mjs +194 -0
  523. package/esm/http/lazy-static.mjs.map +1 -0
  524. package/esm/http/middleware/cache-response-middleware.d.mts +2 -4
  525. package/esm/http/middleware/cache-response-middleware.d.mts.map +1 -1
  526. package/esm/http/middleware/concurrency-limit.middleware.d.mts +3 -3
  527. package/esm/http/middleware/concurrency-limit.middleware.d.mts.map +1 -1
  528. package/esm/http/middleware/idempotency.middleware.d.mts +3 -3
  529. package/esm/http/middleware/idempotency.middleware.d.mts.map +1 -1
  530. package/esm/http/middleware/idempotency.middleware.mjs +6 -6
  531. package/esm/http/middleware/idempotency.middleware.mjs.map +1 -1
  532. package/esm/http/middleware/index.d.mts +3 -1
  533. package/esm/http/middleware/index.mjs +1 -1
  534. package/esm/http/middleware/inject-request-context.d.mts +2 -4
  535. package/esm/http/middleware/inject-request-context.d.mts.map +1 -1
  536. package/esm/http/middleware/inject-request-context.mjs +3 -3
  537. package/esm/http/middleware/inject-request-context.mjs.map +1 -1
  538. package/esm/http/middleware/ip-filter.middleware.d.mts +3 -3
  539. package/esm/http/middleware/ip-filter.middleware.d.mts.map +1 -1
  540. package/esm/http/middleware/maintenance.middleware.d.mts +3 -3
  541. package/esm/http/middleware/maintenance.middleware.d.mts.map +1 -1
  542. package/esm/http/middleware/maintenance.middleware.mjs +4 -4
  543. package/esm/http/middleware/maintenance.middleware.mjs.map +1 -1
  544. package/esm/http/middleware/max-body-size.middleware.d.mts +2 -2
  545. package/esm/http/middleware/max-body-size.middleware.d.mts.map +1 -1
  546. package/esm/http/middleware/middleware-list.d.mts +1 -3
  547. package/esm/http/middleware/middleware-list.d.mts.map +1 -1
  548. package/esm/http/middleware/rate-limit.middleware.d.mts +3 -3
  549. package/esm/http/middleware/rate-limit.middleware.d.mts.map +1 -1
  550. package/esm/http/middleware/rate-limit.middleware.mjs +2 -2
  551. package/esm/http/middleware/rate-limit.middleware.mjs.map +1 -1
  552. package/esm/http/middleware/utils/cidr-match.d.mts +2 -3
  553. package/esm/http/middleware/utils/cidr-match.d.mts.map +1 -1
  554. package/esm/http/middleware/utils/idempotency-key.d.mts +3 -5
  555. package/esm/http/middleware/utils/idempotency-key.d.mts.map +1 -1
  556. package/esm/http/middleware/utils/index.d.mts +2 -1
  557. package/esm/http/middleware/utils/parse-size.d.mts +1 -2
  558. package/esm/http/middleware/utils/parse-size.d.mts.map +1 -1
  559. package/esm/http/middleware/utils/parse-size.mjs +2 -2
  560. package/esm/http/middleware/utils/parse-size.mjs.map +1 -1
  561. package/esm/http/plugins.d.mts +2 -4
  562. package/esm/http/plugins.d.mts.map +1 -1
  563. package/esm/http/plugins.mjs +17 -14
  564. package/esm/http/plugins.mjs.map +1 -1
  565. package/esm/http/port-preflight.d.mts +3 -4
  566. package/esm/http/port-preflight.d.mts.map +1 -1
  567. package/esm/http/rate-limit-cache-store.mjs +6 -4
  568. package/esm/http/rate-limit-cache-store.mjs.map +1 -1
  569. package/esm/http/ready-report.d.mts +15 -10
  570. package/esm/http/ready-report.d.mts.map +1 -1
  571. package/esm/http/request-controller.d.mts +1 -3
  572. package/esm/http/request-controller.d.mts.map +1 -1
  573. package/esm/http/request-log-snapshot.d.mts +26 -15
  574. package/esm/http/request-log-snapshot.d.mts.map +1 -1
  575. package/esm/http/request-log-snapshot.mjs +85 -6
  576. package/esm/http/request-log-snapshot.mjs.map +1 -1
  577. package/esm/http/request.d.mts +6 -5
  578. package/esm/http/request.d.mts.map +1 -1
  579. package/esm/http/request.mjs +13 -11
  580. package/esm/http/request.mjs.map +1 -1
  581. package/esm/http/response.d.mts +23 -12
  582. package/esm/http/response.d.mts.map +1 -1
  583. package/esm/http/response.mjs +169 -81
  584. package/esm/http/response.mjs.map +1 -1
  585. package/esm/http/safe-redirect.d.mts +50 -0
  586. package/esm/http/safe-redirect.d.mts.map +1 -0
  587. package/esm/http/safe-redirect.mjs +80 -0
  588. package/esm/http/safe-redirect.mjs.map +1 -0
  589. package/esm/http/serialized.d.mts +12 -13
  590. package/esm/http/serialized.d.mts.map +1 -1
  591. package/esm/http/server-rebuilt.d.mts +3 -5
  592. package/esm/http/server-rebuilt.d.mts.map +1 -1
  593. package/esm/http/server.d.mts +11 -9
  594. package/esm/http/server.d.mts.map +1 -1
  595. package/esm/http/server.mjs +17 -7
  596. package/esm/http/server.mjs.map +1 -1
  597. package/esm/http/stream-react-response.d.mts +7 -7
  598. package/esm/http/stream-react-response.d.mts.map +1 -1
  599. package/esm/http/stream-transport.mjs +4 -2
  600. package/esm/http/stream-transport.mjs.map +1 -1
  601. package/esm/http/tracing/index.mjs +1 -1
  602. package/esm/http/tracing/trace-id.d.mts +2 -3
  603. package/esm/http/tracing/trace-id.d.mts.map +1 -1
  604. package/esm/http/tracing/tracing-dispatcher.d.mts +10 -11
  605. package/esm/http/tracing/tracing-dispatcher.d.mts.map +1 -1
  606. package/esm/http/tracing/tracing-dispatcher.mjs +2 -2
  607. package/esm/http/tracing/tracing-dispatcher.mjs.map +1 -1
  608. package/esm/http/tracing/tracing.type.d.mts +11 -9
  609. package/esm/http/tracing/tracing.type.d.mts.map +1 -1
  610. package/esm/http/types.d.mts +78 -39
  611. package/esm/http/types.d.mts.map +1 -1
  612. package/esm/http/uploaded-file.d.mts +6 -5
  613. package/esm/http/uploaded-file.d.mts.map +1 -1
  614. package/esm/http/uploads/generate-image-variant.mjs +1 -1
  615. package/esm/http/uploads/generate-image-variants.d.mts +13 -10
  616. package/esm/http/uploads/generate-image-variants.d.mts.map +1 -1
  617. package/esm/http/uploads/generate-image-variants.mjs +62 -25
  618. package/esm/http/uploads/generate-image-variants.mjs.map +1 -1
  619. package/esm/http/uploads/image-variant-cache-entries.mjs +78 -0
  620. package/esm/http/uploads/image-variant-cache-entries.mjs.map +1 -0
  621. package/esm/http/uploads/image-variant-cache.mjs +72 -30
  622. package/esm/http/uploads/image-variant-cache.mjs.map +1 -1
  623. package/esm/http/uploads/image-variant-types.d.mts +9 -9
  624. package/esm/http/uploads/image-variant-types.d.mts.map +1 -1
  625. package/esm/http/uploads/image-variants-config-error.d.mts +4 -3
  626. package/esm/http/uploads/image-variants-config-error.d.mts.map +1 -1
  627. package/esm/http/uploads/image-variants-config-error.mjs +3 -2
  628. package/esm/http/uploads/image-variants-config-error.mjs.map +1 -1
  629. package/esm/http/uploads/index.d.mts +2 -1
  630. package/esm/http/uploads/index.mjs +1 -1
  631. package/esm/http/uploads/load-variant-source.mjs +1 -1
  632. package/esm/http/uploads/load-variant-source.mjs.map +1 -1
  633. package/esm/http/uploads/parse-uploaded-file-query.mjs +1 -1
  634. package/esm/http/uploads/parse-uploaded-file-query.mjs.map +1 -1
  635. package/esm/http/uploads/purge-image-variants.d.mts +9 -6
  636. package/esm/http/uploads/purge-image-variants.d.mts.map +1 -1
  637. package/esm/http/uploads/purge-image-variants.mjs +16 -16
  638. package/esm/http/uploads/purge-image-variants.mjs.map +1 -1
  639. package/esm/http/uploads/remote-variant-source.mjs +115 -0
  640. package/esm/http/uploads/remote-variant-source.mjs.map +1 -0
  641. package/esm/http/uploads/resolve-image-variant.d.mts +6 -9
  642. package/esm/http/uploads/resolve-image-variant.d.mts.map +1 -1
  643. package/esm/http/uploads/resolve-image-variant.mjs +10 -18
  644. package/esm/http/uploads/resolve-image-variant.mjs.map +1 -1
  645. package/esm/http/uploads/resolve-image-variants-config.mjs +7 -5
  646. package/esm/http/uploads/resolve-image-variants-config.mjs.map +1 -1
  647. package/esm/http/uploads/resolve-original-content-type.mjs +1 -1
  648. package/esm/http/uploads/resolve-original-content-type.mjs.map +1 -1
  649. package/esm/http/uploads/resolve-remote-image-variant.mjs +89 -0
  650. package/esm/http/uploads/resolve-remote-image-variant.mjs.map +1 -0
  651. package/esm/http/uploads/trim-image-variant-cache.mjs +193 -0
  652. package/esm/http/uploads/trim-image-variant-cache.mjs.map +1 -0
  653. package/esm/http/uploads/uploaded-file.controller.d.mts +9 -6
  654. package/esm/http/uploads/uploaded-file.controller.d.mts.map +1 -1
  655. package/esm/http/uploads/uploaded-file.controller.mjs +18 -9
  656. package/esm/http/uploads/uploaded-file.controller.mjs.map +1 -1
  657. package/esm/http/uploads/variant-cache-key.mjs +2 -2
  658. package/esm/http/uploads-config.d.mts +2 -4
  659. package/esm/http/uploads-config.d.mts.map +1 -1
  660. package/esm/http/uploads-types.d.mts +22 -16
  661. package/esm/http/uploads-types.d.mts.map +1 -1
  662. package/esm/http/xmlable.d.mts +1 -2
  663. package/esm/http/xmlable.d.mts.map +1 -1
  664. package/esm/image/image.d.mts +6 -7
  665. package/esm/image/image.d.mts.map +1 -1
  666. package/esm/image/image.mjs.map +1 -1
  667. package/esm/image/index.d.mts +2 -1
  668. package/esm/image/index.mjs +1 -1
  669. package/esm/index.d.mts +38 -6
  670. package/esm/index.mjs +14 -3
  671. package/esm/loader/app-module-importer.d.mts +1 -2
  672. package/esm/loader/app-module-importer.d.mts.map +1 -1
  673. package/esm/localization/index.mjs +1 -1
  674. package/esm/localization/parse-locale-dictionary.d.mts +6 -5
  675. package/esm/localization/parse-locale-dictionary.d.mts.map +1 -1
  676. package/esm/localization/parse-locale-dictionary.mjs +2 -1
  677. package/esm/localization/parse-locale-dictionary.mjs.map +1 -1
  678. package/esm/localization/register-locale-dictionary.d.mts +3 -4
  679. package/esm/localization/register-locale-dictionary.d.mts.map +1 -1
  680. package/esm/localization/register-locale-dictionary.mjs +2 -2
  681. package/esm/localization/register-locale-dictionary.mjs.map +1 -1
  682. package/esm/logger/fatal-visibility.d.mts +1 -2
  683. package/esm/logger/fatal-visibility.d.mts.map +1 -1
  684. package/esm/logger/index.d.mts +2 -1
  685. package/esm/logger/index.mjs +1 -1
  686. package/esm/logger/logger.d.mts +1 -3
  687. package/esm/logger/logger.d.mts.map +1 -1
  688. package/esm/logger/types.d.mts +2 -3
  689. package/esm/logger/types.d.mts.map +1 -1
  690. package/esm/mail/config.d.mts +21 -12
  691. package/esm/mail/config.d.mts.map +1 -1
  692. package/esm/mail/config.mjs +16 -1
  693. package/esm/mail/config.mjs.map +1 -1
  694. package/esm/mail/events.d.mts +4 -6
  695. package/esm/mail/events.d.mts.map +1 -1
  696. package/esm/mail/index.d.mts +3 -2
  697. package/esm/mail/index.mjs +2 -2
  698. package/esm/mail/mail.d.mts +1 -3
  699. package/esm/mail/mail.d.mts.map +1 -1
  700. package/esm/mail/mailer-pool.d.mts +5 -7
  701. package/esm/mail/mailer-pool.d.mts.map +1 -1
  702. package/esm/mail/react-mail.d.mts +1 -3
  703. package/esm/mail/react-mail.d.mts.map +1 -1
  704. package/esm/mail/send-mail.d.mts +1 -3
  705. package/esm/mail/send-mail.d.mts.map +1 -1
  706. package/esm/mail/send-mail.mjs +2 -1
  707. package/esm/mail/send-mail.mjs.map +1 -1
  708. package/esm/mail/test-mailbox.d.mts +11 -13
  709. package/esm/mail/test-mailbox.d.mts.map +1 -1
  710. package/esm/mail/types.d.mts +17 -18
  711. package/esm/mail/types.d.mts.map +1 -1
  712. package/esm/manifest/manifest-manager.mjs +1 -1
  713. package/esm/net/index.d.mts +2 -0
  714. package/esm/net/index.mjs +3 -0
  715. package/esm/openapi/build-openapi-document.d.mts +2 -4
  716. package/esm/openapi/build-openapi-document.d.mts.map +1 -1
  717. package/esm/openapi/build-openapi-document.mjs +8 -5
  718. package/esm/openapi/build-openapi-document.mjs.map +1 -1
  719. package/esm/openapi/cast-schema.mjs +1 -1
  720. package/esm/openapi/development-openapi-provider.d.mts +5 -6
  721. package/esm/openapi/development-openapi-provider.d.mts.map +1 -1
  722. package/esm/openapi/error-responses.mjs +28 -2
  723. package/esm/openapi/error-responses.mjs.map +1 -1
  724. package/esm/openapi/index.d.mts +3 -1
  725. package/esm/openapi/index.mjs +1 -1
  726. package/esm/openapi/openapi-child-output.mjs +2 -2
  727. package/esm/openapi/openapi-child-output.mjs.map +1 -1
  728. package/esm/openapi/postman/build-request-body.mjs.map +1 -1
  729. package/esm/openapi/postman/build-request-url.mjs +1 -1
  730. package/esm/openapi/postman/build-request-url.mjs.map +1 -1
  731. package/esm/openapi/postman/build-saved-responses.mjs.map +1 -1
  732. package/esm/openapi/postman/example-from-schema.d.mts +1 -3
  733. package/esm/openapi/postman/example-from-schema.d.mts.map +1 -1
  734. package/esm/openapi/postman/example-from-schema.mjs.map +1 -1
  735. package/esm/openapi/postman/index.d.mts +2 -1
  736. package/esm/openapi/postman/openapi-to-postman-collection.d.mts +3 -5
  737. package/esm/openapi/postman/openapi-to-postman-collection.d.mts.map +1 -1
  738. package/esm/openapi/postman/openapi-to-postman-collection.mjs.map +1 -1
  739. package/esm/openapi/postman/postman-types.d.mts +19 -18
  740. package/esm/openapi/postman/postman-types.d.mts.map +1 -1
  741. package/esm/openapi/postman/schema-refs.d.mts +1 -3
  742. package/esm/openapi/postman/schema-refs.d.mts.map +1 -1
  743. package/esm/openapi/postman/schema-refs.mjs.map +1 -1
  744. package/esm/openapi/postman/uuid-v5.mjs +1 -1
  745. package/esm/openapi/postman/uuid-v5.mjs.map +1 -1
  746. package/esm/openapi/request-schemas.mjs.map +1 -1
  747. package/esm/openapi/response-schemas.mjs.map +1 -1
  748. package/esm/openapi/schema-registry.d.mts +1 -0
  749. package/esm/openapi/schema-registry.mjs.map +1 -1
  750. package/esm/openapi/security.mjs +1 -1
  751. package/esm/openapi/security.mjs.map +1 -1
  752. package/esm/openapi/types.d.mts +23 -20
  753. package/esm/openapi/types.d.mts.map +1 -1
  754. package/esm/production/assert-generated-imports.mjs +2 -1
  755. package/esm/production/assert-generated-imports.mjs.map +1 -1
  756. package/esm/production/build-contributions.mjs +1 -1
  757. package/esm/production/bundle-framework-dependencies.mjs +1 -1
  758. package/esm/production/dist-build-manifest.mjs +1 -1
  759. package/esm/production/esbuild-plugins.mjs.map +1 -1
  760. package/esm/production/esbuild-preflight.mjs +1 -1
  761. package/esm/production/production-builder.mjs +14 -5
  762. package/esm/production/production-builder.mjs.map +1 -1
  763. package/esm/production/production-supervisor.mjs +1 -1
  764. package/esm/production/registration-child-runner.mjs +4 -3
  765. package/esm/production/registration-child-runner.mjs.map +1 -1
  766. package/esm/production/resolve-build-config.d.mts +4 -4
  767. package/esm/production/resolve-build-config.d.mts.map +1 -1
  768. package/esm/production/resolve-build-config.mjs +2 -1
  769. package/esm/production/resolve-build-config.mjs.map +1 -1
  770. package/esm/production/route-registration-child.d.mts +1 -1
  771. package/esm/production/route-registration-child.mjs +8 -7
  772. package/esm/production/route-registration-child.mjs.map +1 -1
  773. package/esm/production/route-registration-snapshot.mjs.map +1 -1
  774. package/esm/production/tsconfig-path-aliases.mjs +1 -1
  775. package/esm/react/index.d.mts +1 -3
  776. package/esm/react/index.d.mts.map +1 -1
  777. package/esm/react/index.mjs.map +1 -1
  778. package/esm/repositories/adapters/cascade/cascade-adapter.d.mts +3 -4
  779. package/esm/repositories/adapters/cascade/cascade-adapter.d.mts.map +1 -1
  780. package/esm/repositories/adapters/cascade/cascade-query-builder.d.mts +2 -3
  781. package/esm/repositories/adapters/cascade/cascade-query-builder.d.mts.map +1 -1
  782. package/esm/repositories/adapters/cascade/filter-applicator.mjs +10 -9
  783. package/esm/repositories/adapters/cascade/filter-applicator.mjs.map +1 -1
  784. package/esm/repositories/adapters/cascade/index.d.mts +2 -1
  785. package/esm/repositories/adapters/cascade/index.mjs +1 -1
  786. package/esm/repositories/contracts/index.d.mts +2 -1
  787. package/esm/repositories/contracts/query-builder.contract.d.mts +4 -6
  788. package/esm/repositories/contracts/query-builder.contract.d.mts.map +1 -1
  789. package/esm/repositories/contracts/repository-adapter.contract.d.mts +1 -3
  790. package/esm/repositories/contracts/repository-adapter.contract.d.mts.map +1 -1
  791. package/esm/repositories/contracts/types.d.mts +23 -25
  792. package/esm/repositories/contracts/types.d.mts.map +1 -1
  793. package/esm/repositories/index.d.mts +4 -1
  794. package/esm/repositories/index.mjs +1 -1
  795. package/esm/repositories/repository.manager.d.mts +2 -3
  796. package/esm/repositories/repository.manager.d.mts.map +1 -1
  797. package/esm/repositories/repository.manager.mjs +2 -2
  798. package/esm/repositories/repository.manager.mjs.map +1 -1
  799. package/esm/resource/define-resource.d.mts +3 -5
  800. package/esm/resource/define-resource.d.mts.map +1 -1
  801. package/esm/resource/index.d.mts +2 -1
  802. package/esm/resource/index.mjs +1 -1
  803. package/esm/resource/nullable-resource.d.mts +5 -7
  804. package/esm/resource/nullable-resource.d.mts.map +1 -1
  805. package/esm/resource/register-resource.d.mts +1 -3
  806. package/esm/resource/register-resource.d.mts.map +1 -1
  807. package/esm/resource/resource-field-builder.d.mts +1 -3
  808. package/esm/resource/resource-field-builder.d.mts.map +1 -1
  809. package/esm/resource/resource.d.mts +3 -5
  810. package/esm/resource/resource.d.mts.map +1 -1
  811. package/esm/resource/resource.mjs +4 -2
  812. package/esm/resource/resource.mjs.map +1 -1
  813. package/esm/resource/types.d.mts +21 -21
  814. package/esm/resource/types.d.mts.map +1 -1
  815. package/esm/restful/index.d.mts +2 -1
  816. package/esm/restful/index.mjs +1 -1
  817. package/esm/restful/restful.d.mts +11 -31
  818. package/esm/restful/restful.d.mts.map +1 -1
  819. package/esm/restful/restful.mjs.map +1 -1
  820. package/esm/router/build-route-rate-limit.mjs.map +1 -1
  821. package/esm/router/dev-dispatch.mjs +31 -12
  822. package/esm/router/dev-dispatch.mjs.map +1 -1
  823. package/esm/router/index.d.mts +5 -2
  824. package/esm/router/index.mjs +3 -1
  825. package/esm/router/log-request-lifecycle.mjs.map +1 -1
  826. package/esm/router/named-api-routes-with-responses.mjs +2 -1
  827. package/esm/router/named-api-routes-with-responses.mjs.map +1 -1
  828. package/esm/router/normalize-request-path.d.mts +1 -2
  829. package/esm/router/normalize-request-path.d.mts.map +1 -1
  830. package/esm/router/normalize-route-path.d.mts +1 -2
  831. package/esm/router/normalize-route-path.d.mts.map +1 -1
  832. package/esm/router/positional-handler-diagnostics.d.mts +15 -13
  833. package/esm/router/positional-handler-diagnostics.d.mts.map +1 -1
  834. package/esm/router/positional-handler-diagnostics.mjs.map +1 -1
  835. package/esm/router/resolve-route-rate-limit.mjs +47 -0
  836. package/esm/router/resolve-route-rate-limit.mjs.map +1 -0
  837. package/esm/router/resolve-route-validation.mjs +19 -0
  838. package/esm/router/resolve-route-validation.mjs.map +1 -0
  839. package/esm/router/route-builder.d.mts +1 -3
  840. package/esm/router/route-builder.d.mts.map +1 -1
  841. package/esm/router/route-guard-names.mjs +30 -0
  842. package/esm/router/route-guard-names.mjs.map +1 -0
  843. package/esm/router/route-name-method-suffix.d.mts +2 -3
  844. package/esm/router/route-name-method-suffix.d.mts.map +1 -1
  845. package/esm/router/route-name-taken-error.d.mts +12 -0
  846. package/esm/router/route-name-taken-error.d.mts.map +1 -0
  847. package/esm/router/route-name-taken-error.mjs +18 -0
  848. package/esm/router/route-name-taken-error.mjs.map +1 -0
  849. package/esm/router/route-registry.d.mts +1 -3
  850. package/esm/router/route-registry.d.mts.map +1 -1
  851. package/esm/router/router.d.mts +34 -17
  852. package/esm/router/router.d.mts.map +1 -1
  853. package/esm/router/router.mjs +74 -39
  854. package/esm/router/router.mjs.map +1 -1
  855. package/esm/router/types.d.mts +156 -37
  856. package/esm/router/types.d.mts.map +1 -1
  857. package/esm/router/unguarded-route-diagnostics.d.mts +38 -0
  858. package/esm/router/unguarded-route-diagnostics.d.mts.map +1 -0
  859. package/esm/router/unguarded-route-diagnostics.mjs +95 -0
  860. package/esm/router/unguarded-route-diagnostics.mjs.map +1 -0
  861. package/esm/socket/index.d.mts +2 -1
  862. package/esm/socket/index.mjs +1 -1
  863. package/esm/socket/types.d.mts +2 -4
  864. package/esm/socket/types.d.mts.map +1 -1
  865. package/esm/socket/utils.d.mts +1 -3
  866. package/esm/socket/utils.d.mts.map +1 -1
  867. package/esm/storage/config.d.mts +4 -6
  868. package/esm/storage/config.d.mts.map +1 -1
  869. package/esm/storage/context/storage-driver-context.d.mts +3 -4
  870. package/esm/storage/context/storage-driver-context.d.mts.map +1 -1
  871. package/esm/storage/drivers/cloud-driver.d.mts +2 -4
  872. package/esm/storage/drivers/cloud-driver.d.mts.map +1 -1
  873. package/esm/storage/drivers/cloud-driver.mjs.map +1 -1
  874. package/esm/storage/drivers/do-spaces-driver.d.mts +1 -3
  875. package/esm/storage/drivers/do-spaces-driver.d.mts.map +1 -1
  876. package/esm/storage/drivers/local-driver.d.mts +2 -3
  877. package/esm/storage/drivers/local-driver.d.mts.map +1 -1
  878. package/esm/storage/drivers/local-driver.mjs +8 -3
  879. package/esm/storage/drivers/local-driver.mjs.map +1 -1
  880. package/esm/storage/drivers/r2-driver.d.mts +1 -3
  881. package/esm/storage/drivers/r2-driver.d.mts.map +1 -1
  882. package/esm/storage/drivers/s3-driver.d.mts +1 -3
  883. package/esm/storage/drivers/s3-driver.d.mts.map +1 -1
  884. package/esm/storage/index.d.mts +2 -1
  885. package/esm/storage/index.mjs +1 -1
  886. package/esm/storage/local-disk-roots.mjs +24 -0
  887. package/esm/storage/local-disk-roots.mjs.map +1 -0
  888. package/esm/storage/scoped-storage.d.mts +2 -3
  889. package/esm/storage/scoped-storage.d.mts.map +1 -1
  890. package/esm/storage/storage-file.d.mts +1 -3
  891. package/esm/storage/storage-file.d.mts.map +1 -1
  892. package/esm/storage/storage.d.mts +17 -4
  893. package/esm/storage/storage.d.mts.map +1 -1
  894. package/esm/storage/storage.mjs +22 -0
  895. package/esm/storage/storage.mjs.map +1 -1
  896. package/esm/storage/types.d.mts +36 -36
  897. package/esm/storage/types.d.mts.map +1 -1
  898. package/esm/storage/utils/classify-ip-address.d.mts +1 -2
  899. package/esm/storage/utils/classify-ip-address.d.mts.map +1 -1
  900. package/esm/storage/utils/contain-path.d.mts +1 -2
  901. package/esm/storage/utils/contain-path.d.mts.map +1 -1
  902. package/esm/storage/utils/mime.d.mts +2 -3
  903. package/esm/storage/utils/mime.d.mts.map +1 -1
  904. package/esm/storage/utils/safe-fetch.d.mts +6 -6
  905. package/esm/storage/utils/safe-fetch.d.mts.map +1 -1
  906. package/esm/storage/utils/safe-fetch.mjs +3 -3
  907. package/esm/storage/utils/safe-fetch.mjs.map +1 -1
  908. package/esm/storage/utils/storage-capability-error.d.mts +1 -3
  909. package/esm/storage/utils/storage-capability-error.d.mts.map +1 -1
  910. package/esm/storage/utils/storage-error.d.mts +2 -3
  911. package/esm/storage/utils/storage-error.d.mts.map +1 -1
  912. package/esm/storage/utils/storage-not-initialized-error.d.mts +3 -2
  913. package/esm/storage/utils/storage-not-initialized-error.d.mts.map +1 -1
  914. package/esm/storage/utils/storage-not-initialized-error.mjs +1 -0
  915. package/esm/storage/utils/storage-not-initialized-error.mjs.map +1 -1
  916. package/esm/tests/authenticated-test-client.d.mts +31 -0
  917. package/esm/tests/authenticated-test-client.d.mts.map +1 -0
  918. package/esm/tests/authenticated-test-client.mjs +40 -0
  919. package/esm/tests/authenticated-test-client.mjs.map +1 -0
  920. package/esm/tests/factories.d.mts +74 -0
  921. package/esm/tests/factories.d.mts.map +1 -0
  922. package/esm/tests/factories.mjs +105 -0
  923. package/esm/tests/factories.mjs.map +1 -0
  924. package/esm/tests/fakes/cache-fake.d.mts +34 -0
  925. package/esm/tests/fakes/cache-fake.d.mts.map +1 -0
  926. package/esm/tests/fakes/cache-fake.mjs +79 -0
  927. package/esm/tests/fakes/cache-fake.mjs.map +1 -0
  928. package/esm/tests/fakes/clock-fake.d.mts +37 -0
  929. package/esm/tests/fakes/clock-fake.d.mts.map +1 -0
  930. package/esm/tests/fakes/clock-fake.mjs +69 -0
  931. package/esm/tests/fakes/clock-fake.mjs.map +1 -0
  932. package/esm/tests/fakes/fake-assertion-error.d.mts +12 -0
  933. package/esm/tests/fakes/fake-assertion-error.d.mts.map +1 -0
  934. package/esm/tests/fakes/fake-assertion-error.mjs +20 -0
  935. package/esm/tests/fakes/fake-assertion-error.mjs.map +1 -0
  936. package/esm/tests/fakes/ids-fake.d.mts +23 -0
  937. package/esm/tests/fakes/ids-fake.d.mts.map +1 -0
  938. package/esm/tests/fakes/ids-fake.mjs +57 -0
  939. package/esm/tests/fakes/ids-fake.mjs.map +1 -0
  940. package/esm/tests/fakes/index.d.mts +9 -0
  941. package/esm/tests/fakes/index.mjs +10 -0
  942. package/esm/tests/fakes/mail-fake.d.mts +49 -0
  943. package/esm/tests/fakes/mail-fake.d.mts.map +1 -0
  944. package/esm/tests/fakes/mail-fake.mjs +111 -0
  945. package/esm/tests/fakes/mail-fake.mjs.map +1 -0
  946. package/esm/tests/fakes/queue-fake.d.mts +56 -0
  947. package/esm/tests/fakes/queue-fake.d.mts.map +1 -0
  948. package/esm/tests/fakes/queue-fake.mjs +134 -0
  949. package/esm/tests/fakes/queue-fake.mjs.map +1 -0
  950. package/esm/tests/fakes/storage-fake.d.mts +35 -0
  951. package/esm/tests/fakes/storage-fake.d.mts.map +1 -0
  952. package/esm/tests/fakes/storage-fake.mjs +122 -0
  953. package/esm/tests/fakes/storage-fake.mjs.map +1 -0
  954. package/esm/tests/fakes/test-fakes.d.mts +38 -0
  955. package/esm/tests/fakes/test-fakes.d.mts.map +1 -0
  956. package/esm/tests/fakes/test-fakes.mjs +90 -0
  957. package/esm/tests/fakes/test-fakes.mjs.map +1 -0
  958. package/esm/tests/index.d.mts +15 -2
  959. package/esm/tests/index.mjs +15 -2
  960. package/esm/tests/snapshot-response.d.mts +33 -0
  961. package/esm/tests/snapshot-response.d.mts.map +1 -0
  962. package/esm/tests/snapshot-response.mjs +42 -0
  963. package/esm/tests/snapshot-response.mjs.map +1 -0
  964. package/esm/tests/start-http-development-server.d.mts +25 -5
  965. package/esm/tests/start-http-development-server.d.mts.map +1 -1
  966. package/esm/tests/start-http-development-server.mjs +41 -8
  967. package/esm/tests/start-http-development-server.mjs.map +1 -1
  968. package/esm/tests/test-connectors-selection.d.mts +2 -2
  969. package/esm/tests/test-connectors-selection.d.mts.map +1 -1
  970. package/esm/tests/test-connectors-selection.mjs +1 -1
  971. package/esm/tests/test-helpers.d.mts +28 -10
  972. package/esm/tests/test-helpers.d.mts.map +1 -1
  973. package/esm/tests/test-helpers.mjs +40 -27
  974. package/esm/tests/test-helpers.mjs.map +1 -1
  975. package/esm/tests/test-http-server.d.mts +66 -0
  976. package/esm/tests/test-http-server.d.mts.map +1 -0
  977. package/esm/tests/test-http-server.mjs +119 -0
  978. package/esm/tests/test-http-server.mjs.map +1 -0
  979. package/esm/tests/test-lifecycle-state.mjs +1 -1
  980. package/esm/tests/vitest-setup.d.mts +17 -7
  981. package/esm/tests/vitest-setup.d.mts.map +1 -1
  982. package/esm/tests/vitest-setup.mjs +12 -4
  983. package/esm/tests/vitest-setup.mjs.map +1 -1
  984. package/esm/tooling/agents-md/agents-md-markers.d.mts +26 -0
  985. package/esm/tooling/agents-md/agents-md-markers.d.mts.map +1 -0
  986. package/esm/tooling/agents-md/agents-md-markers.mjs +60 -0
  987. package/esm/tooling/agents-md/agents-md-markers.mjs.map +1 -0
  988. package/esm/tooling/agents-md/agents-md-refresher.d.mts +43 -0
  989. package/esm/tooling/agents-md/agents-md-refresher.d.mts.map +1 -0
  990. package/esm/tooling/agents-md/agents-md-refresher.mjs +72 -0
  991. package/esm/tooling/agents-md/agents-md-refresher.mjs.map +1 -0
  992. package/esm/tooling/agents-md/index.mjs +7 -0
  993. package/esm/tooling/agents-md/installed-skills.d.mts +34 -0
  994. package/esm/tooling/agents-md/installed-skills.d.mts.map +1 -0
  995. package/esm/tooling/agents-md/installed-skills.mjs +74 -0
  996. package/esm/tooling/agents-md/installed-skills.mjs.map +1 -0
  997. package/esm/tooling/agents-md/render-agents-md.d.mts +34 -0
  998. package/esm/tooling/agents-md/render-agents-md.d.mts.map +1 -0
  999. package/esm/tooling/agents-md/render-agents-md.mjs +195 -0
  1000. package/esm/tooling/agents-md/render-agents-md.mjs.map +1 -0
  1001. package/esm/tooling/agents-md/write-agents-md.d.mts +38 -0
  1002. package/esm/tooling/agents-md/write-agents-md.d.mts.map +1 -0
  1003. package/esm/tooling/agents-md/write-agents-md.mjs +49 -0
  1004. package/esm/tooling/agents-md/write-agents-md.mjs.map +1 -0
  1005. package/esm/tooling/board/board-message.d.mts +29 -0
  1006. package/esm/tooling/board/board-message.d.mts.map +1 -0
  1007. package/esm/tooling/board/board-message.mjs +86 -0
  1008. package/esm/tooling/board/board-message.mjs.map +1 -0
  1009. package/esm/tooling/board/board.d.mts +121 -0
  1010. package/esm/tooling/board/board.d.mts.map +1 -0
  1011. package/esm/tooling/board/board.mjs +407 -0
  1012. package/esm/tooling/board/board.mjs.map +1 -0
  1013. package/esm/tooling/board/board.types.d.mts +81 -0
  1014. package/esm/tooling/board/board.types.d.mts.map +1 -0
  1015. package/esm/tooling/board/board.types.mjs +54 -0
  1016. package/esm/tooling/board/board.types.mjs.map +1 -0
  1017. package/esm/tooling/check/changed-files.d.mts +31 -0
  1018. package/esm/tooling/check/changed-files.d.mts.map +1 -0
  1019. package/esm/tooling/check/changed-files.mjs +73 -0
  1020. package/esm/tooling/check/changed-files.mjs.map +1 -0
  1021. package/esm/tooling/check/check-report.types.d.mts +67 -0
  1022. package/esm/tooling/check/check-report.types.d.mts.map +1 -0
  1023. package/esm/tooling/check/check-report.types.mjs +37 -0
  1024. package/esm/tooling/check/check-report.types.mjs.map +1 -0
  1025. package/esm/tooling/check/code-style-conventions.mjs +106 -0
  1026. package/esm/tooling/check/code-style-conventions.mjs.map +1 -0
  1027. package/esm/tooling/check/conventions-step.d.mts +32 -0
  1028. package/esm/tooling/check/conventions-step.d.mts.map +1 -0
  1029. package/esm/tooling/check/conventions-step.mjs +173 -0
  1030. package/esm/tooling/check/conventions-step.mjs.map +1 -0
  1031. package/esm/tooling/check/environment-step.d.mts +16 -0
  1032. package/esm/tooling/check/environment-step.d.mts.map +1 -0
  1033. package/esm/tooling/check/environment-step.mjs +78 -0
  1034. package/esm/tooling/check/environment-step.mjs.map +1 -0
  1035. package/esm/tooling/check/index.mjs +10 -0
  1036. package/esm/tooling/check/lint-step.d.mts +18 -0
  1037. package/esm/tooling/check/lint-step.d.mts.map +1 -0
  1038. package/esm/tooling/check/lint-step.mjs +112 -0
  1039. package/esm/tooling/check/lint-step.mjs.map +1 -0
  1040. package/esm/tooling/check/request-input.mjs +132 -0
  1041. package/esm/tooling/check/request-input.mjs.map +1 -0
  1042. package/esm/tooling/check/run-check.d.mts +43 -0
  1043. package/esm/tooling/check/run-check.d.mts.map +1 -0
  1044. package/esm/tooling/check/run-check.mjs +192 -0
  1045. package/esm/tooling/check/run-check.mjs.map +1 -0
  1046. package/esm/tooling/check/run-tests.d.mts +55 -0
  1047. package/esm/tooling/check/run-tests.d.mts.map +1 -0
  1048. package/esm/tooling/check/run-tests.mjs +93 -0
  1049. package/esm/tooling/check/run-tests.mjs.map +1 -0
  1050. package/esm/tooling/check/security-conventions.mjs +650 -0
  1051. package/esm/tooling/check/security-conventions.mjs.map +1 -0
  1052. package/esm/tooling/check/source-ast.mjs +155 -0
  1053. package/esm/tooling/check/source-ast.mjs.map +1 -0
  1054. package/esm/tooling/check/source-files.mjs +27 -0
  1055. package/esm/tooling/check/source-files.mjs.map +1 -0
  1056. package/esm/tooling/check/tests-step.d.mts +33 -0
  1057. package/esm/tooling/check/tests-step.d.mts.map +1 -0
  1058. package/esm/tooling/check/tests-step.mjs +177 -0
  1059. package/esm/tooling/check/tests-step.mjs.map +1 -0
  1060. package/esm/tooling/dev-state/dev-server-state.d.mts +43 -0
  1061. package/esm/tooling/dev-state/dev-server-state.d.mts.map +1 -0
  1062. package/esm/tooling/dev-state/dev-server-state.mjs +67 -0
  1063. package/esm/tooling/dev-state/dev-server-state.mjs.map +1 -0
  1064. package/esm/tooling/devtools/devtools-client.d.mts +100 -0
  1065. package/esm/tooling/devtools/devtools-client.d.mts.map +1 -0
  1066. package/esm/tooling/devtools/devtools-client.mjs +155 -0
  1067. package/esm/tooling/devtools/devtools-client.mjs.map +1 -0
  1068. package/esm/tooling/generate/generation.d.mts +90 -0
  1069. package/esm/tooling/generate/generation.d.mts.map +1 -0
  1070. package/esm/tooling/generate/generation.mjs +127 -0
  1071. package/esm/tooling/generate/generation.mjs.map +1 -0
  1072. package/esm/tooling/generate/generator-spec.d.mts +57 -0
  1073. package/esm/tooling/generate/generator-spec.d.mts.map +1 -0
  1074. package/esm/tooling/generate/generator-spec.mjs +102 -0
  1075. package/esm/tooling/generate/generator-spec.mjs.map +1 -0
  1076. package/esm/tooling/generate/index.mjs +6 -0
  1077. package/esm/tooling/generate/project-files.mjs +121 -0
  1078. package/esm/tooling/generate/project-files.mjs.map +1 -0
  1079. package/esm/tooling/generate/run-cli.d.mts +43 -0
  1080. package/esm/tooling/generate/run-cli.d.mts.map +1 -0
  1081. package/esm/tooling/generate/run-cli.mjs +93 -0
  1082. package/esm/tooling/generate/run-cli.mjs.map +1 -0
  1083. package/esm/tooling/generate/unified-diff.d.mts +40 -0
  1084. package/esm/tooling/generate/unified-diff.d.mts.map +1 -0
  1085. package/esm/tooling/generate/unified-diff.mjs +161 -0
  1086. package/esm/tooling/generate/unified-diff.mjs.map +1 -0
  1087. package/esm/tooling/index.d.mts +42 -0
  1088. package/esm/tooling/index.mjs +45 -0
  1089. package/esm/tooling/inspect/boot-for-inspect.d.mts +23 -0
  1090. package/esm/tooling/inspect/boot-for-inspect.d.mts.map +1 -0
  1091. package/esm/tooling/inspect/boot-for-inspect.mjs +63 -0
  1092. package/esm/tooling/inspect/boot-for-inspect.mjs.map +1 -0
  1093. package/esm/tooling/inspect/collect-config.mjs +77 -0
  1094. package/esm/tooling/inspect/collect-config.mjs.map +1 -0
  1095. package/esm/tooling/inspect/collect-models.d.mts +10 -0
  1096. package/esm/tooling/inspect/collect-models.d.mts.map +1 -0
  1097. package/esm/tooling/inspect/collect-models.mjs +154 -0
  1098. package/esm/tooling/inspect/collect-models.mjs.map +1 -0
  1099. package/esm/tooling/inspect/collect-packages.d.mts +9 -0
  1100. package/esm/tooling/inspect/collect-packages.d.mts.map +1 -0
  1101. package/esm/tooling/inspect/collect-packages.mjs +157 -0
  1102. package/esm/tooling/inspect/collect-packages.mjs.map +1 -0
  1103. package/esm/tooling/inspect/collect-pages.mjs +108 -0
  1104. package/esm/tooling/inspect/collect-pages.mjs.map +1 -0
  1105. package/esm/tooling/inspect/collect-routes.mjs +168 -0
  1106. package/esm/tooling/inspect/collect-routes.mjs.map +1 -0
  1107. package/esm/tooling/inspect/event-recorder.d.mts +37 -0
  1108. package/esm/tooling/inspect/event-recorder.d.mts.map +1 -0
  1109. package/esm/tooling/inspect/event-recorder.mjs +91 -0
  1110. package/esm/tooling/inspect/event-recorder.mjs.map +1 -0
  1111. package/esm/tooling/inspect/index.d.mts +8 -0
  1112. package/esm/tooling/inspect/index.mjs +7 -0
  1113. package/esm/tooling/inspect/inspect-app.d.mts +62 -0
  1114. package/esm/tooling/inspect/inspect-app.d.mts.map +1 -0
  1115. package/esm/tooling/inspect/inspect-app.mjs +92 -0
  1116. package/esm/tooling/inspect/inspect-app.mjs.map +1 -0
  1117. package/esm/tooling/inspect/inspect-report.schema.d.mts +14 -0
  1118. package/esm/tooling/inspect/inspect-report.schema.d.mts.map +1 -0
  1119. package/esm/tooling/inspect/inspect-report.schema.mjs +463 -0
  1120. package/esm/tooling/inspect/inspect-report.schema.mjs.map +1 -0
  1121. package/esm/tooling/inspect/inspect-report.types.d.mts +228 -0
  1122. package/esm/tooling/inspect/inspect-report.types.d.mts.map +1 -0
  1123. package/esm/tooling/inspect/inspect-report.types.mjs +33 -0
  1124. package/esm/tooling/inspect/inspect-report.types.mjs.map +1 -0
  1125. package/esm/tooling/mcp/create-mcp-context.d.mts +29 -0
  1126. package/esm/tooling/mcp/create-mcp-context.d.mts.map +1 -0
  1127. package/esm/tooling/mcp/create-mcp-context.mjs +75 -0
  1128. package/esm/tooling/mcp/create-mcp-context.mjs.map +1 -0
  1129. package/esm/tooling/mcp/db-schema.d.mts +50 -0
  1130. package/esm/tooling/mcp/db-schema.d.mts.map +1 -0
  1131. package/esm/tooling/mcp/db-schema.mjs +56 -0
  1132. package/esm/tooling/mcp/db-schema.mjs.map +1 -0
  1133. package/esm/tooling/mcp/docs-search.d.mts +77 -0
  1134. package/esm/tooling/mcp/docs-search.d.mts.map +1 -0
  1135. package/esm/tooling/mcp/docs-search.mjs +178 -0
  1136. package/esm/tooling/mcp/docs-search.mjs.map +1 -0
  1137. package/esm/tooling/mcp/index.mjs +9 -0
  1138. package/esm/tooling/mcp/load-ai-tools.d.mts +61 -0
  1139. package/esm/tooling/mcp/load-ai-tools.d.mts.map +1 -0
  1140. package/esm/tooling/mcp/load-ai-tools.mjs +45 -0
  1141. package/esm/tooling/mcp/load-ai-tools.mjs.map +1 -0
  1142. package/esm/tooling/mcp/mcp-tools.d.mts +70 -0
  1143. package/esm/tooling/mcp/mcp-tools.d.mts.map +1 -0
  1144. package/esm/tooling/mcp/mcp-tools.mjs +514 -0
  1145. package/esm/tooling/mcp/mcp-tools.mjs.map +1 -0
  1146. package/esm/tooling/mcp/start-mcp-server.d.mts +63 -0
  1147. package/esm/tooling/mcp/start-mcp-server.d.mts.map +1 -0
  1148. package/esm/tooling/mcp/start-mcp-server.mjs +126 -0
  1149. package/esm/tooling/mcp/start-mcp-server.mjs.map +1 -0
  1150. package/esm/tooling/mcp/tool-input.d.mts +75 -0
  1151. package/esm/tooling/mcp/tool-input.d.mts.map +1 -0
  1152. package/esm/tooling/mcp/tool-input.mjs +72 -0
  1153. package/esm/tooling/mcp/tool-input.mjs.map +1 -0
  1154. package/esm/tooling/problem.d.mts +55 -0
  1155. package/esm/tooling/problem.d.mts.map +1 -0
  1156. package/esm/tooling/problem.mjs +28 -0
  1157. package/esm/tooling/problem.mjs.map +1 -0
  1158. package/esm/tooling/syntax/ast.mjs +230 -0
  1159. package/esm/tooling/syntax/ast.mjs.map +1 -0
  1160. package/esm/tooling/syntax/imports.mjs +34 -0
  1161. package/esm/tooling/syntax/imports.mjs.map +1 -0
  1162. package/esm/tooling/trace/trace-report.types.d.mts +85 -0
  1163. package/esm/tooling/trace/trace-report.types.d.mts.map +1 -0
  1164. package/esm/tooling/trace/trace-report.types.mjs +7 -0
  1165. package/esm/tooling/trace/trace-report.types.mjs.map +1 -0
  1166. package/esm/tooling/trace/trace-request.d.mts +90 -0
  1167. package/esm/tooling/trace/trace-request.d.mts.map +1 -0
  1168. package/esm/tooling/trace/trace-request.mjs +241 -0
  1169. package/esm/tooling/trace/trace-request.mjs.map +1 -0
  1170. package/esm/tooling/typecheck/index.mjs +3 -0
  1171. package/esm/tooling/typecheck/run-typecheck.d.mts +26 -0
  1172. package/esm/tooling/typecheck/run-typecheck.d.mts.map +1 -0
  1173. package/esm/tooling/typecheck/run-typecheck.mjs +90 -0
  1174. package/esm/tooling/typecheck/run-typecheck.mjs.map +1 -0
  1175. package/esm/tooling/typescript/compiler.d.mts +31 -0
  1176. package/esm/tooling/typescript/compiler.d.mts.map +1 -0
  1177. package/esm/tooling/typescript/compiler.mjs +120 -0
  1178. package/esm/tooling/typescript/compiler.mjs.map +1 -0
  1179. package/esm/updater/update-warlock-packages.mjs +3 -2
  1180. package/esm/updater/update-warlock-packages.mjs.map +1 -1
  1181. package/esm/upgrade/codemods/head-viewport.mjs +46 -0
  1182. package/esm/upgrade/codemods/head-viewport.mjs.map +1 -0
  1183. package/esm/upgrade/codemods/helpers.mjs +81 -0
  1184. package/esm/upgrade/codemods/helpers.mjs.map +1 -0
  1185. package/esm/upgrade/codemods/index.mjs +34 -0
  1186. package/esm/upgrade/codemods/index.mjs.map +1 -0
  1187. package/esm/upgrade/codemods/logger-sync-calls.mjs +57 -0
  1188. package/esm/upgrade/codemods/logger-sync-calls.mjs.map +1 -0
  1189. package/esm/upgrade/codemods/package-json.mjs +122 -0
  1190. package/esm/upgrade/codemods/package-json.mjs.map +1 -0
  1191. package/esm/upgrade/codemods/request-log-snapshot.mjs +82 -0
  1192. package/esm/upgrade/codemods/request-log-snapshot.mjs.map +1 -0
  1193. package/esm/upgrade/codemods/review-sites.mjs +262 -0
  1194. package/esm/upgrade/codemods/review-sites.mjs.map +1 -0
  1195. package/esm/upgrade/diff.mjs +119 -0
  1196. package/esm/upgrade/diff.mjs.map +1 -0
  1197. package/esm/upgrade/format-upgrade-report.mjs +32 -0
  1198. package/esm/upgrade/format-upgrade-report.mjs.map +1 -0
  1199. package/esm/upgrade/load-ts-morph.mjs +49 -0
  1200. package/esm/upgrade/load-ts-morph.mjs.map +1 -0
  1201. package/esm/upgrade/notes.mjs +16 -0
  1202. package/esm/upgrade/notes.mjs.map +1 -0
  1203. package/esm/upgrade/run-upgrade.mjs +246 -0
  1204. package/esm/upgrade/run-upgrade.mjs.map +1 -0
  1205. package/esm/upgrade/upgrade-command.action.mjs +37 -0
  1206. package/esm/upgrade/upgrade-command.action.mjs.map +1 -0
  1207. package/esm/upgrade/version.mjs +39 -0
  1208. package/esm/upgrade/version.mjs.map +1 -0
  1209. package/esm/use-cases/index.d.mts +2 -1
  1210. package/esm/use-cases/index.mjs +1 -1
  1211. package/esm/use-cases/types.d.mts +116 -63
  1212. package/esm/use-cases/types.d.mts.map +1 -1
  1213. package/esm/use-cases/use-case-broadcast.d.mts +1 -3
  1214. package/esm/use-cases/use-case-broadcast.d.mts.map +1 -1
  1215. package/esm/use-cases/use-case-events.d.mts +3 -5
  1216. package/esm/use-cases/use-case-events.d.mts.map +1 -1
  1217. package/esm/use-cases/use-case-pipeline.d.mts +6 -6
  1218. package/esm/use-cases/use-case-pipeline.d.mts.map +1 -1
  1219. package/esm/use-cases/use-case.d.mts +2 -4
  1220. package/esm/use-cases/use-case.d.mts.map +1 -1
  1221. package/esm/use-cases/use-case.errors.d.mts +1 -3
  1222. package/esm/use-cases/use-case.errors.d.mts.map +1 -1
  1223. package/esm/use-cases/use-cases-registry.d.mts +8 -10
  1224. package/esm/use-cases/use-cases-registry.d.mts.map +1 -1
  1225. package/esm/use-cases/use-cases-registry.mjs.map +1 -1
  1226. package/esm/utils/app-log.d.mts +1 -2
  1227. package/esm/utils/app-log.d.mts.map +1 -1
  1228. package/esm/utils/clock.d.mts +35 -0
  1229. package/esm/utils/clock.d.mts.map +1 -0
  1230. package/esm/utils/clock.mjs +27 -0
  1231. package/esm/utils/clock.mjs.map +1 -0
  1232. package/esm/utils/database-log.d.mts +3 -4
  1233. package/esm/utils/database-log.d.mts.map +1 -1
  1234. package/esm/utils/environment.d.mts +4 -5
  1235. package/esm/utils/environment.d.mts.map +1 -1
  1236. package/esm/utils/framework-vesion.mjs +1 -1
  1237. package/esm/utils/framework-vesion.mjs.map +1 -1
  1238. package/esm/utils/get-localized.d.mts +2 -3
  1239. package/esm/utils/get-localized.d.mts.map +1 -1
  1240. package/esm/utils/ids.d.mts +35 -0
  1241. package/esm/utils/ids.d.mts.map +1 -0
  1242. package/esm/utils/ids.mjs +33 -0
  1243. package/esm/utils/ids.mjs.map +1 -0
  1244. package/esm/utils/index.d.mts +5 -1
  1245. package/esm/utils/index.mjs +4 -1
  1246. package/esm/utils/normalized-path.d.mts +1 -2
  1247. package/esm/utils/normalized-path.d.mts.map +1 -1
  1248. package/esm/utils/npm-registry.d.mts +1 -2
  1249. package/esm/utils/npm-registry.d.mts.map +1 -1
  1250. package/esm/utils/paths.d.mts +13 -14
  1251. package/esm/utils/paths.d.mts.map +1 -1
  1252. package/esm/utils/paths.mjs +2 -2
  1253. package/esm/utils/paths.mjs.map +1 -1
  1254. package/esm/utils/promise-all-object.d.mts +1 -2
  1255. package/esm/utils/promise-all-object.d.mts.map +1 -1
  1256. package/esm/utils/queue.d.mts +1 -2
  1257. package/esm/utils/queue.d.mts.map +1 -1
  1258. package/esm/utils/runtime.d.mts +60 -0
  1259. package/esm/utils/runtime.d.mts.map +1 -0
  1260. package/esm/utils/runtime.mjs +85 -0
  1261. package/esm/utils/runtime.mjs.map +1 -0
  1262. package/esm/utils/sleep.d.mts +1 -2
  1263. package/esm/utils/sleep.d.mts.map +1 -1
  1264. package/esm/utils/sluggable.d.mts +1 -3
  1265. package/esm/utils/sluggable.d.mts.map +1 -1
  1266. package/esm/utils/to-json.d.mts +1 -2
  1267. package/esm/utils/to-json.d.mts.map +1 -1
  1268. package/esm/utils/types.d.mts +1 -2
  1269. package/esm/utils/types.d.mts.map +1 -1
  1270. package/esm/utils/urls.d.mts +5 -6
  1271. package/esm/utils/urls.d.mts.map +1 -1
  1272. package/esm/utils/version-compare.d.mts +1 -2
  1273. package/esm/utils/version-compare.d.mts.map +1 -1
  1274. package/esm/validation/database/exists-except-current-id.d.mts +2 -3
  1275. package/esm/validation/database/exists-except-current-id.d.mts.map +1 -1
  1276. package/esm/validation/database/exists-except-current-user.d.mts +2 -3
  1277. package/esm/validation/database/exists-except-current-user.d.mts.map +1 -1
  1278. package/esm/validation/database/index.d.mts +2 -1
  1279. package/esm/validation/database/index.mjs +1 -1
  1280. package/esm/validation/database/types.d.mts +14 -10
  1281. package/esm/validation/database/types.d.mts.map +1 -1
  1282. package/esm/validation/database/unique-except-current-id.d.mts +2 -3
  1283. package/esm/validation/database/unique-except-current-id.d.mts.map +1 -1
  1284. package/esm/validation/database/unique-except-current-user.d.mts +2 -3
  1285. package/esm/validation/database/unique-except-current-user.d.mts.map +1 -1
  1286. package/esm/validation/file/file.d.mts +4 -6
  1287. package/esm/validation/file/file.d.mts.map +1 -1
  1288. package/esm/validation/file/index.d.mts +2 -1
  1289. package/esm/validation/file/index.mjs +1 -1
  1290. package/esm/validation/index.d.mts +6 -2
  1291. package/esm/validation/index.mjs +1 -1
  1292. package/esm/validation/plugins/index.mjs +1 -1
  1293. package/esm/validation/types.d.mts +61 -4
  1294. package/esm/validation/types.d.mts.map +1 -1
  1295. package/esm/validation/validateAll.mjs +21 -4
  1296. package/esm/validation/validateAll.mjs.map +1 -1
  1297. package/esm/validation/validation-failure-status.mjs +15 -0
  1298. package/esm/validation/validation-failure-status.mjs.map +1 -0
  1299. package/esm/validation/validators/file-validator.d.mts +2 -20
  1300. package/esm/validation/validators/file-validator.d.mts.map +1 -1
  1301. package/esm/validation/validators/index.d.mts +2 -1
  1302. package/esm/validation/validators/index.mjs +1 -1
  1303. package/esm/vite/lower-stage3-decorators.d.mts +2 -3
  1304. package/esm/vite/lower-stage3-decorators.d.mts.map +1 -1
  1305. package/esm/warlock-config/bundle-config.mjs +1 -1
  1306. package/esm/warlock-config/define-config.d.mts +1 -3
  1307. package/esm/warlock-config/define-config.d.mts.map +1 -1
  1308. package/esm/warlock-config/define-config.mjs +3 -2
  1309. package/esm/warlock-config/define-config.mjs.map +1 -1
  1310. package/esm/warlock-config/index.d.mts +2 -1
  1311. package/esm/warlock-config/index.mjs +1 -1
  1312. package/esm/warlock-config/types.d.mts +31 -6
  1313. package/esm/warlock-config/types.d.mts.map +1 -1
  1314. package/esm/warlock-config/warlock-config.manager.d.mts +5 -7
  1315. package/esm/warlock-config/warlock-config.manager.d.mts.map +1 -1
  1316. package/esm/warlock-config/warlock-config.manager.mjs +2 -1
  1317. package/esm/warlock-config/warlock-config.manager.mjs.map +1 -1
  1318. package/esm/warlock-config/warn-deprecated-config.mjs +1 -1
  1319. package/llms-full.txt +3211 -731
  1320. package/llms.txt +16 -6
  1321. package/package.json +47 -15
  1322. package/schemas/inspect-report.schema.json +554 -0
  1323. package/skills/README.md +9 -0
  1324. package/skills/add-connector/SKILL.md +26 -38
  1325. package/skills/benchmark-code/SKILL.md +30 -24
  1326. package/skills/build-restful/SKILL.md +14 -14
  1327. package/skills/build-url/SKILL.md +18 -18
  1328. package/skills/configure-app/SKILL.md +107 -14
  1329. package/skills/create-controller/SKILL.md +25 -12
  1330. package/skills/create-module/SKILL.md +10 -3
  1331. package/skills/define-resource/SKILL.md +32 -29
  1332. package/skills/encrypt-data/SKILL.md +21 -19
  1333. package/skills/generate-openapi/SKILL.md +50 -24
  1334. package/skills/hash-password/SKILL.md +2 -2
  1335. package/skills/health-checks/SKILL.md +24 -7
  1336. package/skills/index.md +11 -4
  1337. package/skills/lower-stage3-decorators/SKILL.md +4 -4
  1338. package/skills/make-endpoint/SKILL.md +110 -0
  1339. package/skills/model-factories/SKILL.md +92 -0
  1340. package/skills/process-image/SKILL.md +32 -30
  1341. package/skills/register-route/SKILL.md +109 -10
  1342. package/skills/report-framework-issue.md +154 -0
  1343. package/skills/request-memo/SKILL.md +1 -1
  1344. package/skills/request-tracing/SKILL.md +4 -1
  1345. package/skills/resolve-path/SKILL.md +45 -44
  1346. package/skills/retry-operation/SKILL.md +20 -11
  1347. package/skills/run-app/SKILL.md +107 -22
  1348. package/skills/send-response/SKILL.md +179 -14
  1349. package/skills/store-file/SKILL.md +93 -53
  1350. package/skills/test-fakes/SKILL.md +123 -0
  1351. package/skills/test-http/SKILL.md +125 -21
  1352. package/skills/test-service/SKILL.md +41 -1
  1353. package/skills/update-packages/SKILL.md +29 -18
  1354. package/skills/upgrade-from-5-29/SKILL.md +454 -0
  1355. package/skills/upload-file/SKILL.md +31 -33
  1356. package/skills/use-app-context/SKILL.md +38 -31
  1357. package/skills/use-middleware/SKILL.md +45 -25
  1358. package/skills/use-model-transformers/SKILL.md +37 -28
  1359. package/skills/use-repository/SKILL.md +2 -2
  1360. package/skills/validate-input/SKILL.md +72 -28
  1361. package/skills/warlock-agents-md/SKILL.md +96 -0
  1362. package/skills/warlock-board/SKILL.md +123 -0
  1363. package/skills/warlock-check/SKILL.md +133 -0
  1364. package/skills/warlock-conventions/SKILL.md +115 -0
  1365. package/skills/warlock-doctor/SKILL.md +55 -22
  1366. package/skills/warlock-inspect/SKILL.md +134 -0
  1367. package/skills/warlock-mcp/SKILL.md +120 -0
  1368. package/skills/warlock-routes/SKILL.md +18 -11
  1369. package/skills/warlock-trace/SKILL.md +81 -0
  1370. package/skills/wire-socket/SKILL.md +8 -8
  1371. package/skills/write-seeder/SKILL.md +46 -32
  1372. package/skills/write-use-case/SKILL.md +40 -27
  1373. package/esm/http/uploads/matches-if-none-match.mjs +0 -13
  1374. package/esm/http/uploads/matches-if-none-match.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"generate-image-variants.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/generate-image-variants.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport { Image } from \"../../image\";\nimport { storage } from \"../../storage\";\nimport { HttpError } from \"../errors\";\nimport { uploadsConfig } from \"../uploads-config\";\nimport type { ImageVariantOutputFormat } from \"../uploads-types\";\nimport { generateImageVariant } from \"./generate-image-variant\";\nimport {\n pruneStaleVariantGenerationsIfCurrent,\n retryOnVanishedDirectory,\n warnIfVariantCacheIsPublic,\n} from \"./image-variant-cache\";\nimport { ImageVariantsConfigError } from \"./image-variants-config-error\";\nimport type {\n GeneratedImageDescriptor,\n GeneratedImageVariant,\n VariantOutputFormat,\n} from \"./image-variant-types\";\nimport { loadVariantSource } from \"./load-variant-source\";\nimport { resolveImageVariantsConfig } from \"./resolve-image-variants-config\";\nimport { resolveVariantCandidate } from \"./resolve-variant-candidate\";\nimport {\n variantCacheKey,\n variantCachePath,\n variantGenerationTag,\n variantSourceDirectory,\n variantSourceKey,\n} from \"./variant-cache-key\";\nimport { variantGenerations } from \"./variant-generations\";\n\n/**\n * Options for `generateImageVariants`\n */\nexport type GenerateImageVariantsOptions = {\n /**\n * Limit generation to these variant names, instead of every variant in\n * `uploads.images.variants`.\n */\n variants?: readonly string[];\n};\n\nasync function exists(target: string): Promise<boolean> {\n try {\n await fs.access(target);\n\n return true;\n } catch {\n return false;\n }\n}\n\nfunction encodeUploadsPath(relativePath: string): string {\n return relativePath.split(\"/\").map(encodeURIComponent).join(\"/\");\n}\n\nfunction variantUrl(src: string, name: string, format?: VariantOutputFormat): string {\n const query = format\n ? `variant=${encodeURIComponent(name)}&format=${format}`\n : `variant=${encodeURIComponent(name)}`;\n\n return `${src}?${query}`;\n}\n\nasync function readDerivativeDimensions(\n target: string,\n): Promise<{ width: number; height: number }> {\n const derivative = new Image(await fs.readFile(target));\n const { width, height } = await derivative.metadata();\n\n return { width: width ?? 0, height: height ?? 0 };\n}\n\n/**\n * Every distinct format a variant is rendered in: the source format plus\n * whatever `uploads.images.formats` adds, with duplicates dropped so a format\n * that is both the source format and an allowed format is generated once.\n */\nfunction outputFormatsFor(\n sourceFormat: VariantOutputFormat,\n configuredFormats: readonly ImageVariantOutputFormat[],\n): VariantOutputFormat[] {\n return [...new Set<VariantOutputFormat>([sourceFormat, ...configuredFormats])];\n}\n\n/**\n * Render every configured variant of one uploaded image, right after it is\n * saved.\n *\n * Uses the exact same normalized config (`uploads.images`), cache key and\n * derivative path as `uploadedFileController`, so a variant generated here is\n * already on disk the first time `GET /uploads/<path>?variant=<name>` is\n * requested — no second render. `variantGenerations` (the single-flight used\n * by the route) is reused, so a concurrent request for a variant this call is\n * still generating joins the same run instead of starting a second one.\n *\n * The returned descriptor is plain JSON, safe to store next to the record\n * that owns the image, or to carry through loader data. On local storage the\n * `url`/`urls` already point at `uploadedFileController`; an app serving\n * uploads from object storage or a CDN should not proxy the remote files\n * through this route at all — store the descriptor once generation runs\n * against the same bucket the CDN serves from, or resolve its URLs through a\n * custom `ImageLoader` on the client instead.\n *\n * @param relativePath - path of the saved upload, relative to the storage root\n * @param options.variants - limit generation to these variant names\n * @throws ImageVariantsConfigError when there is no local storage root, or\n * `uploads.images` is not configured — both are server misconfiguration, not\n * a bad request\n * @throws HttpError(400) when a name in `options.variants` is not declared in\n * `uploads.images.variants`\n * @throws HttpError(404) when `relativePath` does not resolve to a file\n * inside the storage root\n * @throws HttpError(413) when the source is over `maxSourceBytes` or\n * `maxSourcePixels`\n * @throws HttpError(415) when the source is not jpeg, png, webp or avif\n */\nexport async function generateImageVariants(\n relativePath: string,\n options: GenerateImageVariantsOptions = {},\n): Promise<GeneratedImageDescriptor> {\n const storageRoot = storage.root();\n\n if (!storageRoot || storageRoot === \".\") {\n throw new ImageVariantsConfigError(\n \"generateImageVariants needs a local storage driver with a root.\",\n );\n }\n\n const images = resolveImageVariantsConfig(uploadsConfig(\"images\"), storageRoot);\n\n if (!images) {\n throw new ImageVariantsConfigError(\"uploads.images is not configured.\");\n }\n\n const names = options.variants ?? Object.keys(images.variants);\n\n for (const name of names) {\n if (!Object.prototype.hasOwnProperty.call(images.variants, name)) {\n throw new HttpError(400, `Unknown variant \"${name}\".`);\n }\n }\n\n const candidate = await resolveVariantCandidate(relativePath, storageRoot, images);\n\n if (!candidate) {\n throw new HttpError(404, \"File Not Found\");\n }\n\n const { source, stats, sourceFormat } = candidate;\n\n const image = await loadVariantSource(source.absolutePath, {\n maxSourceBytes: images.maxSourceBytes,\n maxSourcePixels: images.maxSourcePixels,\n expectedFormat: sourceFormat,\n });\n\n const { width: sourceWidth, height: sourceHeight } = await image.metadata();\n warnIfVariantCacheIsPublic(images.cacheDirectory);\n\n const src = `/uploads/${encodeUploadsPath(source.relativePath)}`;\n const variants: Record<string, GeneratedImageVariant> = {};\n\n for (const name of names) {\n const variant = images.variants[name];\n if (variant === undefined) {\n throw new HttpError(400, `Unknown variant \"${name}\".`);\n }\n const formats = outputFormatsFor(sourceFormat, images.formats);\n let dimensions: { width: number; height: number } | undefined;\n\n for (const format of formats) {\n const hash = variantCacheKey({\n relativePath: source.relativePath,\n sourceSize: stats.size,\n sourceMtimeMs: stats.mtimeMs,\n variant,\n format,\n });\n const sourceKey = variantSourceKey(source.root, source.relativePath);\n const generation = variantGenerationTag(stats.size, stats.mtimeMs);\n const target = variantCachePath(\n images.cacheDirectory,\n { sourceKey, generation },\n hash,\n format,\n );\n\n if (!(await exists(target))) {\n // keyed on the target, which includes the disk root (see resolveImageVariant)\n await variantGenerations.run(target, async () => {\n if (await exists(target)) return;\n\n await retryOnVanishedDirectory(() =>\n generateImageVariant({ image: image.clone(), variant, format, targetPath: target }),\n );\n await pruneStaleVariantGenerationsIfCurrent(\n source.absolutePath,\n variantSourceDirectory(images.cacheDirectory, sourceKey),\n generation,\n );\n });\n }\n\n if (dimensions === undefined) {\n dimensions = await readDerivativeDimensions(target);\n }\n }\n\n const urls: Partial<Record<ImageVariantOutputFormat, string>> = {};\n\n for (const format of images.formats) {\n urls[format] = variantUrl(src, name, format);\n }\n\n variants[name] = {\n width: dimensions?.width ?? variant.width,\n height:\n dimensions?.height ??\n variant.height ??\n Math.round(variant.width * ((sourceHeight ?? 1) / (sourceWidth ?? 1))),\n url: variantUrl(src, name),\n ...(Object.keys(urls).length > 0 ? { urls } : {}),\n };\n }\n\n return {\n src,\n width: sourceWidth ?? 0,\n height: sourceHeight ?? 0,\n variants,\n ...(images.formats.length > 0 ? { formats: images.formats } : {}),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAyCA,eAAe,OAAO,QAAkC;CACtD,IAAI;EACF,MAAM,GAAG,OAAO,MAAM;EAEtB,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,kBAAkB,cAA8B;CACvD,OAAO,aAAa,MAAM,GAAG,CAAC,CAAC,IAAI,kBAAkB,CAAC,CAAC,KAAK,GAAG;AACjE;AAEA,SAAS,WAAW,KAAa,MAAc,QAAsC;CAKnF,OAAO,GAAG,IAAI,GAJA,SACV,WAAW,mBAAmB,IAAI,EAAE,UAAU,WAC9C,WAAW,mBAAmB,IAAI;AAGxC;AAEA,eAAe,yBACb,QAC4C;CAE5C,MAAM,EAAE,OAAO,WAAW,MAAM,IADT,MAAM,MAAM,GAAG,SAAS,MAAM,CACZ,CAAC,CAAC,SAAS;CAEpD,OAAO;EAAE,OAAO,SAAS;EAAG,QAAQ,UAAU;CAAE;AAClD;;;;;;AAOA,SAAS,iBACP,cACA,mBACuB;CACvB,OAAO,CAAC,GAAG,IAAI,IAAyB,CAAC,cAAc,GAAG,iBAAiB,CAAC,CAAC;AAC/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,eAAsB,sBACpB,cACA,UAAwC,CAAC,GACN;CACnC,MAAM,cAAc,QAAQ,KAAK;CAEjC,IAAI,CAAC,eAAe,gBAAgB,KAClC,MAAM,IAAI,yBACR,iEACF;CAGF,MAAM,SAAS,2BAA2B,cAAc,QAAQ,GAAG,WAAW;CAE9E,IAAI,CAAC,QACH,MAAM,IAAI,yBAAyB,mCAAmC;CAGxE,MAAM,QAAQ,QAAQ,YAAY,OAAO,KAAK,OAAO,QAAQ;CAE7D,KAAK,MAAM,QAAQ,OACjB,IAAI,CAAC,OAAO,UAAU,eAAe,KAAK,OAAO,UAAU,IAAI,GAC7D,MAAM,IAAI,UAAU,KAAK,oBAAoB,KAAK,GAAG;CAIzD,MAAM,YAAY,MAAM,wBAAwB,cAAc,aAAa,MAAM;CAEjF,IAAI,CAAC,WACH,MAAM,IAAI,UAAU,KAAK,gBAAgB;CAG3C,MAAM,EAAE,QAAQ,OAAO,iBAAiB;CAExC,MAAM,QAAQ,MAAM,kBAAkB,OAAO,cAAc;EACzD,gBAAgB,OAAO;EACvB,iBAAiB,OAAO;EACxB,gBAAgB;CAClB,CAAC;CAED,MAAM,EAAE,OAAO,aAAa,QAAQ,iBAAiB,MAAM,MAAM,SAAS;CAC1E,2BAA2B,OAAO,cAAc;CAEhD,MAAM,MAAM,YAAY,kBAAkB,OAAO,YAAY;CAC7D,MAAM,WAAkD,CAAC;CAEzD,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,UAAU,OAAO,SAAS;EAChC,IAAI,YAAY,QACd,MAAM,IAAI,UAAU,KAAK,oBAAoB,KAAK,GAAG;EAEvD,MAAM,UAAU,iBAAiB,cAAc,OAAO,OAAO;EAC7D,IAAI;EAEJ,KAAK,MAAM,UAAU,SAAS;GAC5B,MAAM,OAAO,gBAAgB;IAC3B,cAAc,OAAO;IACrB,YAAY,MAAM;IAClB,eAAe,MAAM;IACrB;IACA;GACF,CAAC;GACD,MAAM,YAAY,iBAAiB,OAAO,MAAM,OAAO,YAAY;GACnE,MAAM,aAAa,qBAAqB,MAAM,MAAM,MAAM,OAAO;GACjE,MAAM,SAAS,iBACb,OAAO,gBACP;IAAE;IAAW;GAAW,GACxB,MACA,MACF;GAEA,IAAI,CAAE,MAAM,OAAO,MAAM,GAEvB,MAAM,mBAAmB,IAAI,QAAQ,YAAY;IAC/C,IAAI,MAAM,OAAO,MAAM,GAAG;IAE1B,MAAM,+BACJ,qBAAqB;KAAE,OAAO,MAAM,MAAM;KAAG;KAAS;KAAQ,YAAY;IAAO,CAAC,CACpF;IACA,MAAM,sCACJ,OAAO,cACP,uBAAuB,OAAO,gBAAgB,SAAS,GACvD,UACF;GACF,CAAC;GAGH,IAAI,eAAe,QACjB,aAAa,MAAM,yBAAyB,MAAM;EAEtD;EAEA,MAAM,OAA0D,CAAC;EAEjE,KAAK,MAAM,UAAU,OAAO,SAC1B,KAAK,UAAU,WAAW,KAAK,MAAM,MAAM;EAG7C,SAAS,QAAQ;GACf,OAAO,YAAY,SAAS,QAAQ;GACpC,QACE,YAAY,UACZ,QAAQ,UACR,KAAK,MAAM,QAAQ,UAAU,gBAAgB,MAAM,eAAe,GAAG;GACvE,KAAK,WAAW,KAAK,IAAI;GACzB,GAAI,OAAO,KAAK,IAAI,CAAC,CAAC,SAAS,IAAI,EAAE,KAAK,IAAI,CAAC;EACjD;CACF;CAEA,OAAO;EACL;EACA,OAAO,eAAe;EACtB,QAAQ,gBAAgB;EACxB;EACA,GAAI,OAAO,QAAQ,SAAS,IAAI,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;CACjE;AACF"}
1
+ {"version":3,"file":"generate-image-variants.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/generate-image-variants.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport { Image } from \"../../image\";\nimport type { StorageDriverName } from \"../../storage/types\";\nimport { localDiskRoot } from \"./local-disk-root\";\nimport { remoteVariantDisk, remoteVariantSource } from \"./remote-variant-source\";\nimport { renderRemoteImageVariant } from \"./resolve-remote-image-variant\";\nimport { HttpError } from \"../errors\";\nimport { uploadsConfig } from \"../uploads-config\";\nimport type { ImageVariantOutputFormat } from \"../uploads-types\";\nimport { generateImageVariant } from \"./generate-image-variant\";\nimport {\n pruneStaleVariantGenerationsIfCurrent,\n retryOnVanishedDirectory,\n warnIfVariantCacheIsPublic,\n} from \"./image-variant-cache\";\nimport { ImageVariantsConfigError } from \"./image-variants-config-error\";\nimport type {\n GeneratedImageDescriptor,\n GeneratedImageVariant,\n VariantOutputFormat,\n} from \"./image-variant-types\";\nimport { loadVariantSource } from \"./load-variant-source\";\nimport { resolveImageVariantsConfig } from \"./resolve-image-variants-config\";\nimport { resolveVariantCandidate } from \"./resolve-variant-candidate\";\nimport {\n variantCacheKey,\n variantCachePath,\n variantGenerationTag,\n variantSourceDirectory,\n variantSourceKey,\n} from \"./variant-cache-key\";\nimport { freshImageVariant, scheduleImageVariantCacheTrim } from \"./trim-image-variant-cache\";\nimport { variantGenerations } from \"./variant-generations\";\n\n/**\n * Options for `generateImageVariants`\n */\nexport type GenerateImageVariantsOptions = {\n /**\n * Limit generation to these variant names, instead of every variant in\n * `uploads.images.variants`.\n */\n variants?: readonly string[];\n\n /** Disk holding the source; defaults to the active disk. */\n disk?: StorageDriverName;\n\n /** Route prefix serving variants of this disk (and originals for local disks). Default /uploads. */\n urlPrefix?: string;\n};\n\nfunction encodeUploadsPath(relativePath: string): string {\n return relativePath.split(\"/\").map(encodeURIComponent).join(\"/\");\n}\n\nfunction variantUrl(src: string, name: string, format?: VariantOutputFormat): string {\n const query = format\n ? `variant=${encodeURIComponent(name)}&format=${format}`\n : `variant=${encodeURIComponent(name)}`;\n\n return `${src}?${query}`;\n}\n\nasync function readDerivativeDimensions(\n target: string,\n): Promise<{ width: number; height: number }> {\n const derivative = new Image(await fs.readFile(target));\n const { width, height } = await derivative.metadata();\n\n return { width: width ?? 0, height: height ?? 0 };\n}\n\n/**\n * Every distinct format a variant is rendered in: the source format plus\n * whatever `uploads.images.formats` adds, with duplicates dropped so a format\n * that is both the source format and an allowed format is generated once.\n */\nfunction outputFormatsFor(\n sourceFormat: VariantOutputFormat,\n configuredFormats: readonly ImageVariantOutputFormat[],\n): VariantOutputFormat[] {\n return [...new Set<VariantOutputFormat>([sourceFormat, ...configuredFormats])];\n}\n\n/**\n * Render every configured variant of one uploaded image, right after it is\n * saved.\n *\n * Uses the exact same normalized config (`uploads.images`), cache key and\n * derivative path as `uploadedFileController`, so a variant generated here is\n * already on disk the first time `GET /uploads/<path>?variant=<name>` is\n * requested — no second render. `variantGenerations` (the single-flight used\n * by the route) is reused, so a concurrent request for a variant this call is\n * still generating joins the same run instead of starting a second one.\n *\n * The returned descriptor is plain JSON, safe to store next to the record\n * that owns the image, or to carry through loader data. On local storage the\n * `url`/`urls` already point at `uploadedFileController`; an app serving\n * uploads from object storage use the driver URL for the original, and\n * `options.urlPrefix` for the route serving locally cached derivatives.\n * Ingest downloads a remote source once for all variants and formats.\n * On-demand cache hits use ETag metadata; sources without ETags are hashed.\n *\n * @param relativePath - path of the saved upload, relative to the storage root\n * @param options.variants - limit generation to these variant names\n * @throws ImageVariantsConfigError when `uploads.images` is not\n * configured — this is server misconfiguration, not\n * a bad request\n * @throws HttpError(400) when a name in `options.variants` is not declared in\n * `uploads.images.variants`\n * @throws HttpError(404) when `relativePath` does not resolve to a file\n * inside the storage root\n * @throws HttpError(413) when the source is over `maxSourceBytes` or\n * `maxSourcePixels`\n * @throws HttpError(415) when the source is not jpeg, png, webp or avif\n */\nexport async function generateImageVariants(\n relativePath: string,\n options: GenerateImageVariantsOptions = {},\n): Promise<GeneratedImageDescriptor> {\n const storageRoot = localDiskRoot(options.disk);\n\n if (!storageRoot) return generateRemoteImageVariants(relativePath, options);\n\n const images = resolveImageVariantsConfig(uploadsConfig(\"images\"), storageRoot);\n\n if (!images) {\n throw new ImageVariantsConfigError(\"uploads.images is not configured.\");\n }\n\n const names = options.variants ?? Object.keys(images.variants);\n\n for (const name of names) {\n if (!Object.prototype.hasOwnProperty.call(images.variants, name)) {\n throw new HttpError(400, `Unknown variant \"${name}\".`);\n }\n }\n\n const candidate = await resolveVariantCandidate(relativePath, storageRoot, images);\n\n if (!candidate) {\n throw new HttpError(404, \"File Not Found\");\n }\n\n const { source, stats, sourceFormat } = candidate;\n\n const image = await loadVariantSource(source.absolutePath, {\n maxSourceBytes: images.maxSourceBytes,\n maxSourcePixels: images.maxSourcePixels,\n expectedFormat: sourceFormat,\n });\n\n const { width: sourceWidth, height: sourceHeight } = await image.metadata();\n warnIfVariantCacheIsPublic(images.cacheDirectory);\n\n const src = `${(options.urlPrefix ?? \"/uploads\").replace(/\\/$/, \"\")}/${encodeUploadsPath(source.relativePath)}`;\n const variants: Record<string, GeneratedImageVariant> = {};\n\n for (const name of names) {\n const variant = images.variants[name];\n if (variant === undefined) {\n throw new HttpError(400, `Unknown variant \"${name}\".`);\n }\n const formats = outputFormatsFor(sourceFormat, images.formats);\n let dimensions: { width: number; height: number } | undefined;\n\n for (const format of formats) {\n const hash = variantCacheKey({\n relativePath: source.relativePath,\n sourceSize: stats.size,\n sourceMtimeMs: stats.mtimeMs,\n variant,\n format,\n });\n const sourceKey = variantSourceKey(source.root, source.relativePath);\n const generation = variantGenerationTag(stats.size, stats.mtimeMs);\n const target = variantCachePath(\n images.cacheDirectory,\n { sourceKey, generation },\n hash,\n format,\n );\n\n if (!(await freshImageVariant(target, images.maxCacheAge))) {\n // keyed on the target, which includes the disk root (see resolveImageVariant)\n await variantGenerations.run(target, async () => {\n if (await freshImageVariant(target, images.maxCacheAge)) return;\n\n await retryOnVanishedDirectory(() =>\n generateImageVariant({ image: image.clone(), variant, format, targetPath: target }),\n );\n scheduleImageVariantCacheTrim(images, target);\n await pruneStaleVariantGenerationsIfCurrent(\n source.absolutePath,\n variantSourceDirectory(images.cacheDirectory, sourceKey),\n generation,\n );\n });\n }\n\n if (dimensions === undefined) {\n dimensions = await readDerivativeDimensions(target);\n }\n }\n\n const urls: Partial<Record<ImageVariantOutputFormat, string>> = {};\n\n for (const format of images.formats) {\n urls[format] = variantUrl(src, name, format);\n }\n\n variants[name] = {\n width: dimensions?.width ?? variant.width,\n height:\n dimensions?.height ??\n variant.height ??\n Math.round(variant.width * ((sourceHeight ?? 1) / (sourceWidth ?? 1))),\n url: variantUrl(src, name),\n ...(Object.keys(urls).length > 0 ? { urls } : {}),\n };\n }\n\n return {\n src,\n width: sourceWidth ?? 0,\n height: sourceHeight ?? 0,\n variants,\n ...(images.formats.length > 0 ? { formats: images.formats } : {}),\n };\n}\n\nasync function generateRemoteImageVariants(\n relativePath: string,\n options: GenerateImageVariantsOptions,\n): Promise<GeneratedImageDescriptor> {\n const disk = remoteVariantDisk(options.disk);\n const images = resolveImageVariantsConfig(uploadsConfig(\"images\"), disk.cacheRoot);\n if (!images) throw new ImageVariantsConfigError(\"uploads.images is not configured.\");\n const names = options.variants ?? Object.keys(images.variants);\n for (const name of names) {\n if (!Object.prototype.hasOwnProperty.call(images.variants, name))\n throw new HttpError(400, `Unknown variant \"${name}\".`);\n }\n const source = await remoteVariantSource(relativePath, disk, images);\n if (!source) throw new HttpError(404, \"File Not Found\");\n try {\n const { image, sourceFormat } = await source.load();\n const { width, height } = await image.metadata();\n const variantSrc = `${(options.urlPrefix ?? \"/uploads\").replace(/\\/$/, \"\")}/${encodeUploadsPath(source.relativePath)}`;\n const variants: Record<string, GeneratedImageVariant> = {};\n for (const name of names) {\n let dimensions: { width: number; height: number } | undefined;\n for (const format of outputFormatsFor(sourceFormat, images.formats)) {\n const resolved = await renderRemoteImageVariant(\n {\n path: relativePath,\n variant: name,\n ...(format === sourceFormat ? {} : { format }),\n },\n disk,\n images,\n source,\n );\n if (!resolved) throw new HttpError(404, \"File Not Found\");\n dimensions ??= await readDerivativeDimensions(resolved.absolutePath);\n }\n variants[name] = {\n width: dimensions?.width ?? 0,\n height: dimensions?.height ?? 0,\n url: variantUrl(variantSrc, name),\n ...(images.formats.length\n ? {\n urls: Object.fromEntries(\n images.formats.map((format) => [format, variantUrl(variantSrc, name, format)]),\n ),\n }\n : {}),\n };\n }\n return {\n src: disk.driver.url(source.relativePath),\n width: width ?? 0,\n height: height ?? 0,\n variants,\n ...(images.formats.length ? { formats: images.formats } : {}),\n };\n } finally {\n source.release();\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ import path from "node:path";
2
+ import fs from "node:fs/promises";
3
+
4
+ //#region ../../packages/core/src/http/uploads/image-variant-cache-entries.ts
5
+ const SHARD = /^[a-f0-9]{2}$/;
6
+ const SOURCE = /^[a-f0-9]{64}$/;
7
+ const GENERATION = /^(?:\d+--?\d+|[a-f0-9]{64})$/;
8
+ const DERIVATIVE = /^[a-f0-9]{64}\.(?:jpg|png|webp|avif)$/;
9
+ const TEMPORARY = /^(?:[a-f0-9]{64}\.(?:jpg|png|webp|avif)\.tmp-[a-f0-9]{16}|\.source\.json\.[a-f0-9]{12}\.tmp)$/;
10
+ async function entries(directory) {
11
+ try {
12
+ return await fs.readdir(directory, { withFileTypes: true });
13
+ } catch (error) {
14
+ if (error.code === "ENOENT") return [];
15
+ throw error;
16
+ }
17
+ }
18
+ /** Recognize only generation directories and files emitted by the image writers; never traverse symlinks. */
19
+ async function* variantSourceCacheGenerations(sourceDirectory, keepGeneration) {
20
+ try {
21
+ for (const directory of [path.dirname(sourceDirectory), sourceDirectory]) if (!(await fs.lstat(directory)).isDirectory()) return;
22
+ } catch (error) {
23
+ if (error.code === "ENOENT") return;
24
+ throw error;
25
+ }
26
+ for (const generation of await entries(sourceDirectory)) {
27
+ if (generation.name === keepGeneration || !generation.isDirectory() || !GENERATION.test(generation.name)) continue;
28
+ const directory = path.join(sourceDirectory, generation.name);
29
+ const found = [];
30
+ for (const file of await entries(directory)) {
31
+ if (!file.isFile()) continue;
32
+ const type = DERIVATIVE.test(file.name) ? "derivative" : file.name === "source.json" ? "manifest" : TEMPORARY.test(file.name) ? "temporary" : void 0;
33
+ if (type) found.push({
34
+ target: path.join(directory, file.name),
35
+ type
36
+ });
37
+ }
38
+ yield {
39
+ directory,
40
+ entries: found
41
+ };
42
+ }
43
+ }
44
+ /** Every directory component must match the generated cache layout. */
45
+ async function* variantCacheGenerations(cacheDirectory) {
46
+ for (const shard of await entries(cacheDirectory)) {
47
+ if (!shard.isDirectory() || !SHARD.test(shard.name)) continue;
48
+ const directory = path.join(cacheDirectory, shard.name);
49
+ for (const source of await entries(directory)) {
50
+ if (!source.isDirectory() || !SOURCE.test(source.name) || !source.name.startsWith(shard.name)) continue;
51
+ yield* variantSourceCacheGenerations(path.join(directory, source.name));
52
+ }
53
+ }
54
+ }
55
+ async function* flatten(generations) {
56
+ for await (const generation of generations) yield* generation.entries;
57
+ }
58
+ /** Recognized files of one source's generations, optionally skipping the `keepGeneration` directory. */
59
+ function variantSourceCacheEntries(sourceDirectory, keepGeneration) {
60
+ return flatten(variantSourceCacheGenerations(sourceDirectory, keepGeneration));
61
+ }
62
+ /** Recognized files of every source in the cache. */
63
+ function variantCacheEntries(cacheDirectory) {
64
+ return flatten(variantCacheGenerations(cacheDirectory));
65
+ }
66
+ /** Keep directories in place so removing cache data cannot remove user folders. */
67
+ async function purgeVariantCacheEntries(entries) {
68
+ let removed = false;
69
+ for await (const entry of entries) {
70
+ await fs.rm(entry.target, { force: true });
71
+ removed = true;
72
+ }
73
+ return removed;
74
+ }
75
+
76
+ //#endregion
77
+ export { purgeVariantCacheEntries, variantCacheEntries, variantCacheGenerations, variantSourceCacheEntries, variantSourceCacheGenerations };
78
+ //# sourceMappingURL=image-variant-cache-entries.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-variant-cache-entries.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/image-variant-cache-entries.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\nconst SHARD = /^[a-f0-9]{2}$/;\nconst SOURCE = /^[a-f0-9]{64}$/;\nconst GENERATION = /^(?:\\d+--?\\d+|[a-f0-9]{64})$/;\nconst DERIVATIVE = /^[a-f0-9]{64}\\.(?:jpg|png|webp|avif)$/;\nconst TEMPORARY =\n /^(?:[a-f0-9]{64}\\.(?:jpg|png|webp|avif)\\.tmp-[a-f0-9]{16}|\\.source\\.json\\.[a-f0-9]{12}\\.tmp)$/;\n\nexport type VariantCacheEntry = {\n target: string;\n type: \"derivative\" | \"manifest\" | \"temporary\";\n};\n\n/** One generation-shaped directory (a real directory, never a symlink) and its recognized files. */\nexport type VariantCacheGeneration = {\n directory: string;\n entries: VariantCacheEntry[];\n};\n\nasync function entries(directory: string) {\n try {\n return await fs.readdir(directory, { withFileTypes: true });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return [];\n throw error;\n }\n}\n\n/** Recognize only generation directories and files emitted by the image writers; never traverse symlinks. */\nexport async function* variantSourceCacheGenerations(\n sourceDirectory: string,\n keepGeneration?: string,\n): AsyncGenerator<VariantCacheGeneration> {\n try {\n // Checking the final component alone still follows a symlinked shard.\n for (const directory of [path.dirname(sourceDirectory), sourceDirectory]) {\n if (!(await fs.lstat(directory)).isDirectory()) return;\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return;\n throw error;\n }\n for (const generation of await entries(sourceDirectory)) {\n if (\n generation.name === keepGeneration ||\n !generation.isDirectory() ||\n !GENERATION.test(generation.name)\n )\n continue;\n const directory = path.join(sourceDirectory, generation.name);\n const found: VariantCacheEntry[] = [];\n for (const file of await entries(directory)) {\n if (!file.isFile()) continue;\n const type = DERIVATIVE.test(file.name)\n ? \"derivative\"\n : file.name === \"source.json\"\n ? \"manifest\"\n : TEMPORARY.test(file.name)\n ? \"temporary\"\n : undefined;\n if (type) found.push({ target: path.join(directory, file.name), type });\n }\n yield { directory, entries: found };\n }\n}\n\n/** Every directory component must match the generated cache layout. */\nexport async function* variantCacheGenerations(\n cacheDirectory: string,\n): AsyncGenerator<VariantCacheGeneration> {\n for (const shard of await entries(cacheDirectory)) {\n if (!shard.isDirectory() || !SHARD.test(shard.name)) continue;\n const directory = path.join(cacheDirectory, shard.name);\n for (const source of await entries(directory)) {\n if (!source.isDirectory() || !SOURCE.test(source.name) || !source.name.startsWith(shard.name))\n continue;\n yield* variantSourceCacheGenerations(path.join(directory, source.name));\n }\n }\n}\n\nasync function* flatten(\n generations: AsyncIterable<VariantCacheGeneration>,\n): AsyncGenerator<VariantCacheEntry> {\n for await (const generation of generations) yield* generation.entries;\n}\n\n/** Recognized files of one source's generations, optionally skipping the `keepGeneration` directory. */\nexport function variantSourceCacheEntries(\n sourceDirectory: string,\n keepGeneration?: string,\n): AsyncGenerator<VariantCacheEntry> {\n return flatten(variantSourceCacheGenerations(sourceDirectory, keepGeneration));\n}\n\n/** Recognized files of every source in the cache. */\nexport function variantCacheEntries(cacheDirectory: string): AsyncGenerator<VariantCacheEntry> {\n return flatten(variantCacheGenerations(cacheDirectory));\n}\n\n/** Keep directories in place so removing cache data cannot remove user folders. */\nexport async function purgeVariantCacheEntries(\n entries: AsyncIterable<VariantCacheEntry>,\n): Promise<boolean> {\n let removed = false;\n for await (const entry of entries) {\n await fs.rm(entry.target, { force: true });\n removed = true;\n }\n return removed;\n}\n"],"mappings":";;;;AAGA,MAAM,QAAQ;AACd,MAAM,SAAS;AACf,MAAM,aAAa;AACnB,MAAM,aAAa;AACnB,MAAM,YACJ;AAaF,eAAe,QAAQ,WAAmB;CACxC,IAAI;EACF,OAAO,MAAM,GAAG,QAAQ,WAAW,EAAE,eAAe,KAAK,CAAC;CAC5D,SAAS,OAAO;EACd,IAAK,MAAgC,SAAS,UAAU,OAAO,CAAC;EAChE,MAAM;CACR;AACF;;AAGA,gBAAuB,8BACrB,iBACA,gBACwC;CACxC,IAAI;EAEF,KAAK,MAAM,aAAa,CAAC,KAAK,QAAQ,eAAe,GAAG,eAAe,GACrE,IAAI,EAAE,MAAM,GAAG,MAAM,SAAS,EAAC,CAAE,YAAY,GAAG;CAEpD,SAAS,OAAO;EACd,IAAK,MAAgC,SAAS,UAAU;EACxD,MAAM;CACR;CACA,KAAK,MAAM,cAAc,MAAM,QAAQ,eAAe,GAAG;EACvD,IACE,WAAW,SAAS,kBACpB,CAAC,WAAW,YAAY,KACxB,CAAC,WAAW,KAAK,WAAW,IAAI,GAEhC;EACF,MAAM,YAAY,KAAK,KAAK,iBAAiB,WAAW,IAAI;EAC5D,MAAM,QAA6B,CAAC;EACpC,KAAK,MAAM,QAAQ,MAAM,QAAQ,SAAS,GAAG;GAC3C,IAAI,CAAC,KAAK,OAAO,GAAG;GACpB,MAAM,OAAO,WAAW,KAAK,KAAK,IAAI,IAClC,eACA,KAAK,SAAS,gBACZ,aACA,UAAU,KAAK,KAAK,IAAI,IACtB,cACA;GACR,IAAI,MAAM,MAAM,KAAK;IAAE,QAAQ,KAAK,KAAK,WAAW,KAAK,IAAI;IAAG;GAAK,CAAC;EACxE;EACA,MAAM;GAAE;GAAW,SAAS;EAAM;CACpC;AACF;;AAGA,gBAAuB,wBACrB,gBACwC;CACxC,KAAK,MAAM,SAAS,MAAM,QAAQ,cAAc,GAAG;EACjD,IAAI,CAAC,MAAM,YAAY,KAAK,CAAC,MAAM,KAAK,MAAM,IAAI,GAAG;EACrD,MAAM,YAAY,KAAK,KAAK,gBAAgB,MAAM,IAAI;EACtD,KAAK,MAAM,UAAU,MAAM,QAAQ,SAAS,GAAG;GAC7C,IAAI,CAAC,OAAO,YAAY,KAAK,CAAC,OAAO,KAAK,OAAO,IAAI,KAAK,CAAC,OAAO,KAAK,WAAW,MAAM,IAAI,GAC1F;GACF,OAAO,8BAA8B,KAAK,KAAK,WAAW,OAAO,IAAI,CAAC;EACxE;CACF;AACF;AAEA,gBAAgB,QACd,aACmC;CACnC,WAAW,MAAM,cAAc,aAAa,OAAO,WAAW;AAChE;;AAGA,SAAgB,0BACd,iBACA,gBACmC;CACnC,OAAO,QAAQ,8BAA8B,iBAAiB,cAAc,CAAC;AAC/E;;AAGA,SAAgB,oBAAoB,gBAA2D;CAC7F,OAAO,QAAQ,wBAAwB,cAAc,CAAC;AACxD;;AAGA,eAAsB,yBACpB,SACkB;CAClB,IAAI,UAAU;CACd,WAAW,MAAM,SAAS,SAAS;EACjC,MAAM,GAAG,GAAG,MAAM,QAAQ,EAAE,OAAO,KAAK,CAAC;EACzC,UAAU;CACZ;CACA,OAAO;AACT"}
@@ -1,10 +1,14 @@
1
1
  import { rootPath } from "../../utils/paths.mjs";
2
+ import { configuredLocalDiskRoots } from "../../storage/local-disk-roots.mjs";
3
+ import { ImageVariantsConfigError } from "./image-variants-config-error.mjs";
4
+ import { purgeVariantCacheEntries, variantSourceCacheEntries } from "./image-variant-cache-entries.mjs";
2
5
  import { uploadsConfig } from "../uploads-config.mjs";
3
- import { isPathInside } from "./is-path-inside.mjs";
6
+ import { isPathInside, isPathWithin } from "./is-path-inside.mjs";
4
7
  import { variantGenerationTag, variantSourceDirectory, variantSourceKey } from "./variant-cache-key.mjs";
5
- import config from "@mongez/config";
8
+ import baseConfig from "@mongez/config";
6
9
  import { log } from "@warlock.js/logger";
7
10
  import path from "node:path";
11
+ import fsSync from "node:fs";
8
12
  import fs from "node:fs/promises";
9
13
 
10
14
  //#region ../../packages/core/src/http/uploads/image-variant-cache.ts
@@ -15,16 +19,70 @@ async function realpathOrSelf(target) {
15
19
  return target;
16
20
  }
17
21
  }
22
+ function canonicalDirectory(target) {
23
+ const resolved = path.resolve(target);
24
+ try {
25
+ return fsSync.realpathSync(resolved);
26
+ } catch (error) {
27
+ const code = error.code;
28
+ if (code !== "ENOENT") throw new ImageVariantsConfigError(`uploads.images.cacheDirectory (or a local disk root) could not be resolved: ${resolved} (${code ?? "unknown error"})`, { cause: error });
29
+ const parent = path.dirname(resolved);
30
+ if (parent === resolved) throw error;
31
+ return path.join(canonicalDirectory(parent), path.basename(resolved));
32
+ }
33
+ }
34
+ /** Most distinct cache/disk-root combinations whose overlap check is remembered. */
35
+ const OVERLAP_CHECKS_LIMIT = 64;
36
+ /**
37
+ * Overlap check outcomes, keyed by the cache directory, the disk root and
38
+ * every configured local root. A disk registered later changes the key, so
39
+ * it is checked again; the stored error is rethrown for a refused layout.
40
+ */
41
+ const overlapChecks = /* @__PURE__ */ new Map();
42
+ function checkCacheOverlap(directory, diskRoot) {
43
+ const roots = [diskRoot, ...configuredLocalDiskRoots()];
44
+ const key = [directory, ...roots].join("\0");
45
+ if (overlapChecks.has(key)) {
46
+ const failure = overlapChecks.get(key);
47
+ if (failure) throw failure;
48
+ return;
49
+ }
50
+ let failure;
51
+ try {
52
+ const realCache = canonicalDirectory(directory);
53
+ for (const root of roots) if (isPathWithin(canonicalDirectory(root), realCache)) {
54
+ failure = new ImageVariantsConfigError("uploads.images.cacheDirectory must not equal or contain the storage root of any local disk (including symlinks).");
55
+ break;
56
+ }
57
+ } catch (error) {
58
+ if (!(error instanceof ImageVariantsConfigError)) throw error;
59
+ failure = error;
60
+ }
61
+ if (overlapChecks.size >= OVERLAP_CHECKS_LIMIT) {
62
+ const oldest = overlapChecks.keys().next();
63
+ if (!oldest.done) overlapChecks.delete(oldest.value);
64
+ }
65
+ overlapChecks.set(key, failure);
66
+ if (failure) throw failure;
67
+ }
18
68
  /**
19
69
  * The derivative cache directory for a local disk: `uploads.images.cacheDirectory`
20
70
  * when the app sets one (shared by every disk; derivatives are keyed by the
21
71
  * disk's real root, so they never collide), otherwise
22
72
  * `<diskRoot>/.cache/image-variants`. The same rule as
23
- * `resolveImageVariantsConfig`.
73
+ * `resolveImageVariantsConfig`. Refuses any cache that equals or contains
74
+ * any configured local root, resolving symlinks before comparison. The
75
+ * outcome is remembered per cache, disk root and configured local roots, so
76
+ * repeated requests do not resolve the same paths again.
77
+ *
78
+ * @throws ImageVariantsConfigError when a cache overlaps a local disk root, or
79
+ * when the cache or a root cannot be resolved (for example `ENOTDIR`, `EACCES`)
24
80
  */
25
- function variantCacheDirectoryFor(diskRoot) {
26
- const configured = uploadsConfig("images")?.cacheDirectory;
27
- return configured ? path.resolve(configured) : path.join(path.resolve(diskRoot), ".cache", "image-variants");
81
+ function variantCacheDirectoryFor(diskRoot, images = uploadsConfig("images")) {
82
+ const configured = images?.cacheDirectory;
83
+ const directory = configured ? path.resolve(configured) : path.join(path.resolve(diskRoot), ".cache", "image-variants");
84
+ checkCacheOverlap(directory, diskRoot);
85
+ return directory;
28
86
  }
29
87
  /**
30
88
  * The directory holding every derivative of one file on a local disk, or
@@ -44,39 +102,23 @@ async function variantSourceDirectoryForFile(diskRoot, absolutePath) {
44
102
  /**
45
103
  * Remove every cached derivative of one file on a local disk.
46
104
  *
47
- * @returns `true` when a cache directory for the file existed and was removed
105
+ * @returns `true` when recognized cache files were removed
48
106
  */
49
107
  async function purgeImageVariantsOfFile(diskRoot, absolutePath) {
50
108
  const directory = await variantSourceDirectoryForFile(diskRoot, absolutePath);
51
109
  if (!directory) return false;
52
- try {
53
- await fs.access(directory);
54
- } catch {
55
- return false;
56
- }
57
- await fs.rm(directory, {
58
- recursive: true,
59
- force: true
60
- });
61
- return true;
110
+ return purgeVariantCacheEntries(variantSourceCacheEntries(directory));
62
111
  }
63
112
  /**
64
113
  * Remove derivatives made from older versions of a source (a different size
65
114
  * or mtime), keeping only the `keep` generation. Called after a derivative of
66
115
  * the current version has been written, so a source rewritten in place does
67
- * not leave its old derivatives behind.
116
+ * not leave its old derivatives behind. Only recognized cache files in
117
+ * generation-shaped directories are removed; unrelated entries and all
118
+ * directories and symlinks stay in place.
68
119
  */
69
120
  async function pruneStaleVariantGenerations(sourceDirectory, keep) {
70
- let entries;
71
- try {
72
- entries = await fs.readdir(sourceDirectory);
73
- } catch {
74
- return;
75
- }
76
- await Promise.all(entries.filter((entry) => entry !== keep).map((entry) => fs.rm(path.join(sourceDirectory, entry), {
77
- recursive: true,
78
- force: true
79
- })));
121
+ await purgeVariantCacheEntries(variantSourceCacheEntries(sourceDirectory, keep));
80
122
  }
81
123
  /**
82
124
  * {@link pruneStaleVariantGenerations}, but only while `keep` is still the
@@ -130,7 +172,7 @@ let warnedPublicCache = false;
130
172
  */
131
173
  function warnIfVariantCacheIsPublic(cacheDirectory) {
132
174
  if (warnedPublicCache) return;
133
- const configured = config.get("storage.publicRoot", rootPath("public"));
175
+ const configured = baseConfig.get("storage.publicRoot", rootPath("public"));
134
176
  const publicRoots = (Array.isArray(configured) ? configured : [configured]).filter((root) => typeof root === "string" && root.length > 0).map((root) => path.resolve(root));
135
177
  const resolved = path.resolve(cacheDirectory);
136
178
  if (!publicRoots.some((root) => resolved === root || isPathInside(resolved, root))) return;
@@ -139,5 +181,5 @@ function warnIfVariantCacheIsPublic(cacheDirectory) {
139
181
  }
140
182
 
141
183
  //#endregion
142
- export { isMissingFileError, pruneStaleVariantGenerationsIfCurrent, purgeImageVariantsOfFile, retryOnVanishedDirectory, variantCacheDirectoryFor, warnIfVariantCacheIsPublic };
184
+ export { isMissingFileError, pruneStaleVariantGenerations, pruneStaleVariantGenerationsIfCurrent, purgeImageVariantsOfFile, retryOnVanishedDirectory, variantCacheDirectoryFor, variantSourceDirectoryForFile, warnIfVariantCacheIsPublic };
143
185
  //# sourceMappingURL=image-variant-cache.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"image-variant-cache.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/image-variant-cache.ts"],"sourcesContent":["import config from \"@mongez/config\";\nimport { log } from \"@warlock.js/logger\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { rootPath } from \"../../utils/paths\";\nimport { uploadsConfig } from \"../uploads-config\";\nimport { isPathInside } from \"./is-path-inside\";\nimport {\n variantGenerationTag,\n variantSourceDirectory,\n variantSourceKey,\n} from \"./variant-cache-key\";\n\n/*\n * Cache housekeeping for image derivatives. Deliberately free of any\n * `storage` import: the local storage driver calls into this module when it\n * deletes or moves a file, and storage must not import back into the HTTP\n * layer that already imports storage.\n */\n\nasync function realpathOrSelf(target: string): Promise<string> {\n try {\n return await fs.realpath(target);\n } catch {\n return target;\n }\n}\n\n/**\n * The derivative cache directory for a local disk: `uploads.images.cacheDirectory`\n * when the app sets one (shared by every disk; derivatives are keyed by the\n * disk's real root, so they never collide), otherwise\n * `<diskRoot>/.cache/image-variants`. The same rule as\n * `resolveImageVariantsConfig`.\n */\nexport function variantCacheDirectoryFor(diskRoot: string): string {\n const configured = uploadsConfig(\"images\")?.cacheDirectory;\n\n return configured\n ? path.resolve(configured)\n : path.join(path.resolve(diskRoot), \".cache\", \"image-variants\");\n}\n\n/**\n * The directory holding every derivative of one file on a local disk, or\n * `undefined` when the file is not inside the disk root. The file does not\n * need to exist any more: only its parent directory is resolved through\n * symlinks, exactly as `resolveUploadPath` resolved it when the derivative\n * was made.\n */\nexport async function variantSourceDirectoryForFile(\n diskRoot: string,\n absolutePath: string,\n): Promise<string | undefined> {\n const realRoot = await realpathOrSelf(path.resolve(diskRoot));\n const realParent = await realpathOrSelf(path.dirname(path.resolve(absolutePath)));\n const realPath = path.join(realParent, path.basename(absolutePath));\n\n if (!isPathInside(realPath, realRoot)) return undefined;\n\n const relativePath = path.relative(realRoot, realPath).split(path.sep).join(\"/\");\n\n return variantSourceDirectory(\n variantCacheDirectoryFor(diskRoot),\n variantSourceKey(realRoot, relativePath),\n );\n}\n\n/**\n * Remove every cached derivative of one file on a local disk.\n *\n * @returns `true` when a cache directory for the file existed and was removed\n */\nexport async function purgeImageVariantsOfFile(\n diskRoot: string,\n absolutePath: string,\n): Promise<boolean> {\n const directory = await variantSourceDirectoryForFile(diskRoot, absolutePath);\n\n if (!directory) return false;\n\n try {\n await fs.access(directory);\n } catch {\n return false;\n }\n\n await fs.rm(directory, { recursive: true, force: true });\n\n return true;\n}\n\n/**\n * Remove derivatives made from older versions of a source (a different size\n * or mtime), keeping only the `keep` generation. Called after a derivative of\n * the current version has been written, so a source rewritten in place does\n * not leave its old derivatives behind.\n */\nexport async function pruneStaleVariantGenerations(\n sourceDirectory: string,\n keep: string,\n): Promise<void> {\n let entries: string[];\n\n try {\n entries = await fs.readdir(sourceDirectory);\n } catch {\n return;\n }\n\n await Promise.all(\n entries\n .filter((entry) => entry !== keep)\n .map((entry) => fs.rm(path.join(sourceDirectory, entry), { recursive: true, force: true })),\n );\n}\n\n/**\n * {@link pruneStaleVariantGenerations}, but only while `keep` is still the\n * source's current generation.\n *\n * A request that read the source before it was rewritten renders an old\n * generation; if it pruned afterwards it would delete the derivatives of the\n * newer version another request had just written. Re-reading the source's\n * size and mtime right before pruning keeps a stale request from doing that.\n */\nexport async function pruneStaleVariantGenerationsIfCurrent(\n sourceAbsolutePath: string,\n sourceDirectory: string,\n keep: string,\n): Promise<void> {\n let current: string;\n\n try {\n const stats = await fs.stat(sourceAbsolutePath);\n current = variantGenerationTag(stats.size, stats.mtimeMs);\n } catch {\n // the source is gone; its derivatives are purged by the delete itself\n return;\n }\n\n if (current !== keep) return;\n\n await pruneStaleVariantGenerations(sourceDirectory, keep);\n}\n\n/**\n * True for \"no such file or directory\"\n */\nexport function isMissingFileError(error: unknown): boolean {\n return (error as NodeJS.ErrnoException | undefined)?.code === \"ENOENT\";\n}\n\n/**\n * Run a derivative write, once more if it fails because its directory\n * vanished: a concurrent request for a newer version of the source may prune\n * the generation directory between `mkdir` and the atomic rename.\n */\nexport async function retryOnVanishedDirectory(write: () => Promise<void>): Promise<void> {\n try {\n await write();\n } catch (error) {\n if (!isMissingFileError(error)) throw error;\n\n await write();\n }\n}\n\nlet warnedPublicCache = false;\n\n/**\n * Warn once when the derivative cache sits inside the public folder.\n *\n * A configured `uploads.images.cacheDirectory` is shared by every local disk,\n * so derivatives of a private disk land beside public ones. Inside\n * `public/` (or `storage.publicRoot`) they are served to anyone, bypassing\n * whatever guards the private disk's own route. The paths are hashes, but\n * they are derived from the disk root and the file path, which are not\n * secret.\n */\nexport function warnIfVariantCacheIsPublic(cacheDirectory: string): void {\n if (warnedPublicCache) return;\n\n const configured = config.get(\"storage.publicRoot\", rootPath(\"public\")) as unknown;\n const publicRoots = (Array.isArray(configured) ? configured : [configured])\n .filter((root): root is string => typeof root === \"string\" && root.length > 0)\n .map((root) => path.resolve(root));\n const resolved = path.resolve(cacheDirectory);\n\n if (!publicRoots.some((root) => resolved === root || isPathInside(resolved, root))) return;\n\n warnedPublicCache = true;\n log.warn(\n \"uploads\",\n \"image-variants\",\n `The image variant cache (${resolved}) is inside the public folder, so every cached derivative, private disks included, is publicly served. Move uploads.images.cacheDirectory outside public/.`,\n );\n}\n\n/**\n * Forget that the public-cache warning was shown (tests).\n */\nexport function resetVariantCacheWarnings(): void {\n warnedPublicCache = false;\n}\n"],"mappings":";;;;;;;;;;AAoBA,eAAe,eAAe,QAAiC;CAC7D,IAAI;EACF,OAAO,MAAM,GAAG,SAAS,MAAM;CACjC,QAAQ;EACN,OAAO;CACT;AACF;;;;;;;;AASA,SAAgB,yBAAyB,UAA0B;CACjE,MAAM,aAAa,cAAc,QAAQ,CAAC,EAAE;CAE5C,OAAO,aACH,KAAK,QAAQ,UAAU,IACvB,KAAK,KAAK,KAAK,QAAQ,QAAQ,GAAG,UAAU,gBAAgB;AAClE;;;;;;;;AASA,eAAsB,8BACpB,UACA,cAC6B;CAC7B,MAAM,WAAW,MAAM,eAAe,KAAK,QAAQ,QAAQ,CAAC;CAC5D,MAAM,aAAa,MAAM,eAAe,KAAK,QAAQ,KAAK,QAAQ,YAAY,CAAC,CAAC;CAChF,MAAM,WAAW,KAAK,KAAK,YAAY,KAAK,SAAS,YAAY,CAAC;CAElE,IAAI,CAAC,aAAa,UAAU,QAAQ,GAAG,OAAO;CAE9C,MAAM,eAAe,KAAK,SAAS,UAAU,QAAQ,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG;CAE/E,OAAO,uBACL,yBAAyB,QAAQ,GACjC,iBAAiB,UAAU,YAAY,CACzC;AACF;;;;;;AAOA,eAAsB,yBACpB,UACA,cACkB;CAClB,MAAM,YAAY,MAAM,8BAA8B,UAAU,YAAY;CAE5E,IAAI,CAAC,WAAW,OAAO;CAEvB,IAAI;EACF,MAAM,GAAG,OAAO,SAAS;CAC3B,QAAQ;EACN,OAAO;CACT;CAEA,MAAM,GAAG,GAAG,WAAW;EAAE,WAAW;EAAM,OAAO;CAAK,CAAC;CAEvD,OAAO;AACT;;;;;;;AAQA,eAAsB,6BACpB,iBACA,MACe;CACf,IAAI;CAEJ,IAAI;EACF,UAAU,MAAM,GAAG,QAAQ,eAAe;CAC5C,QAAQ;EACN;CACF;CAEA,MAAM,QAAQ,IACZ,QACG,QAAQ,UAAU,UAAU,IAAI,CAAC,CACjC,KAAK,UAAU,GAAG,GAAG,KAAK,KAAK,iBAAiB,KAAK,GAAG;EAAE,WAAW;EAAM,OAAO;CAAK,CAAC,CAAC,CAC9F;AACF;;;;;;;;;;AAWA,eAAsB,sCACpB,oBACA,iBACA,MACe;CACf,IAAI;CAEJ,IAAI;EACF,MAAM,QAAQ,MAAM,GAAG,KAAK,kBAAkB;EAC9C,UAAU,qBAAqB,MAAM,MAAM,MAAM,OAAO;CAC1D,QAAQ;EAEN;CACF;CAEA,IAAI,YAAY,MAAM;CAEtB,MAAM,6BAA6B,iBAAiB,IAAI;AAC1D;;;;AAKA,SAAgB,mBAAmB,OAAyB;CAC1D,OAAQ,OAA6C,SAAS;AAChE;;;;;;AAOA,eAAsB,yBAAyB,OAA2C;CACxF,IAAI;EACF,MAAM,MAAM;CACd,SAAS,OAAO;EACd,IAAI,CAAC,mBAAmB,KAAK,GAAG,MAAM;EAEtC,MAAM,MAAM;CACd;AACF;AAEA,IAAI,oBAAoB;;;;;;;;;;;AAYxB,SAAgB,2BAA2B,gBAA8B;CACvE,IAAI,mBAAmB;CAEvB,MAAM,aAAa,OAAO,IAAI,sBAAsB,SAAS,QAAQ,CAAC;CACtE,MAAM,eAAe,MAAM,QAAQ,UAAU,IAAI,aAAa,CAAC,UAAU,EAAC,CACvE,QAAQ,SAAyB,OAAO,SAAS,YAAY,KAAK,SAAS,CAAC,CAAC,CAC7E,KAAK,SAAS,KAAK,QAAQ,IAAI,CAAC;CACnC,MAAM,WAAW,KAAK,QAAQ,cAAc;CAE5C,IAAI,CAAC,YAAY,MAAM,SAAS,aAAa,QAAQ,aAAa,UAAU,IAAI,CAAC,GAAG;CAEpF,oBAAoB;CACpB,IAAI,KACF,WACA,kBACA,4BAA4B,SAAS,2JACvC;AACF"}
1
+ {"version":3,"file":"image-variant-cache.mjs","names":["config"],"sources":["../../../../../../../../../packages/core/src/http/uploads/image-variant-cache.ts"],"sourcesContent":["import config from \"@mongez/config\";\nimport { log } from \"@warlock.js/logger\";\nimport fs from \"node:fs/promises\";\nimport fsSync from \"node:fs\";\nimport { configuredLocalDiskRoots } from \"../../storage/local-disk-roots\";\nimport type { UploadsImagesConfigurations } from \"../uploads-types\";\nimport { ImageVariantsConfigError } from \"./image-variants-config-error\";\nimport { purgeVariantCacheEntries, variantSourceCacheEntries } from \"./image-variant-cache-entries\";\nimport path from \"node:path\";\nimport { rootPath } from \"../../utils/paths\";\nimport { uploadsConfig } from \"../uploads-config\";\nimport { isPathInside, isPathWithin } from \"./is-path-inside\";\nimport {\n variantGenerationTag,\n variantSourceDirectory,\n variantSourceKey,\n} from \"./variant-cache-key\";\n\n/*\n * Cache housekeeping for image derivatives. Deliberately free of any\n * import of the storage manager or drivers: the local driver calls into this module when it\n * deletes or moves a file, and storage must not import back into the HTTP\n * layer that already imports storage.\n */\n\nasync function realpathOrSelf(target: string): Promise<string> {\n try {\n return await fs.realpath(target);\n } catch {\n return target;\n }\n}\n\nfunction canonicalDirectory(target: string): string {\n const resolved = path.resolve(target);\n try {\n return fsSync.realpathSync(resolved);\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== \"ENOENT\") {\n // ENOTDIR, EACCES, ELOOP, ...: a configuration problem, reported as one.\n throw new ImageVariantsConfigError(\n `uploads.images.cacheDirectory (or a local disk root) could not be resolved: ${resolved} (${code ?? \"unknown error\"})`,\n { cause: error },\n );\n }\n const parent = path.dirname(resolved);\n if (parent === resolved) throw error;\n // Resolve the nearest existing ancestor too, so a symlink followed by a\n // not-yet-created directory cannot hide an overlap with a future disk root.\n return path.join(canonicalDirectory(parent), path.basename(resolved));\n }\n}\n\n/** Most distinct cache/disk-root combinations whose overlap check is remembered. */\nconst OVERLAP_CHECKS_LIMIT = 64;\n\n/**\n * Overlap check outcomes, keyed by the cache directory, the disk root and\n * every configured local root. A disk registered later changes the key, so\n * it is checked again; the stored error is rethrown for a refused layout.\n */\nconst overlapChecks = new Map<string, ImageVariantsConfigError | undefined>();\n\nfunction checkCacheOverlap(directory: string, diskRoot: string): void {\n const roots = [diskRoot, ...configuredLocalDiskRoots()];\n const key = [directory, ...roots].join(\"\\0\");\n if (overlapChecks.has(key)) {\n const failure = overlapChecks.get(key);\n if (failure) throw failure;\n return;\n }\n let failure: ImageVariantsConfigError | undefined;\n try {\n const realCache = canonicalDirectory(directory);\n for (const root of roots) {\n if (isPathWithin(canonicalDirectory(root), realCache)) {\n failure = new ImageVariantsConfigError(\n \"uploads.images.cacheDirectory must not equal or contain the storage root of any local disk (including symlinks).\",\n );\n break;\n }\n }\n } catch (error) {\n // Only configuration errors are remembered; anything else is retried next time.\n if (!(error instanceof ImageVariantsConfigError)) throw error;\n failure = error;\n }\n if (overlapChecks.size >= OVERLAP_CHECKS_LIMIT) {\n const oldest = overlapChecks.keys().next();\n if (!oldest.done) overlapChecks.delete(oldest.value);\n }\n overlapChecks.set(key, failure);\n if (failure) throw failure;\n}\n\n/**\n * Forget remembered cache overlap checks, so the next check resolves every\n * path again (tests). Changes to the configured disks are detected without it;\n * a directory replaced by a symlink at runtime is not.\n */\nexport function resetVariantCacheOverlapChecks(): void {\n overlapChecks.clear();\n}\n\n/**\n * The derivative cache directory for a local disk: `uploads.images.cacheDirectory`\n * when the app sets one (shared by every disk; derivatives are keyed by the\n * disk's real root, so they never collide), otherwise\n * `<diskRoot>/.cache/image-variants`. The same rule as\n * `resolveImageVariantsConfig`. Refuses any cache that equals or contains\n * any configured local root, resolving symlinks before comparison. The\n * outcome is remembered per cache, disk root and configured local roots, so\n * repeated requests do not resolve the same paths again.\n *\n * @throws ImageVariantsConfigError when a cache overlaps a local disk root, or\n * when the cache or a root cannot be resolved (for example `ENOTDIR`, `EACCES`)\n */\nexport function variantCacheDirectoryFor(\n diskRoot: string,\n images: Pick<UploadsImagesConfigurations, \"cacheDirectory\"> | undefined = uploadsConfig(\"images\"),\n): string {\n const configured = images?.cacheDirectory;\n const directory = configured\n ? path.resolve(configured)\n : path.join(path.resolve(diskRoot), \".cache\", \"image-variants\");\n checkCacheOverlap(directory, diskRoot);\n return directory;\n}\n\n/**\n * The directory holding every derivative of one file on a local disk, or\n * `undefined` when the file is not inside the disk root. The file does not\n * need to exist any more: only its parent directory is resolved through\n * symlinks, exactly as `resolveUploadPath` resolved it when the derivative\n * was made.\n */\nexport async function variantSourceDirectoryForFile(\n diskRoot: string,\n absolutePath: string,\n): Promise<string | undefined> {\n const realRoot = await realpathOrSelf(path.resolve(diskRoot));\n const realParent = await realpathOrSelf(path.dirname(path.resolve(absolutePath)));\n const realPath = path.join(realParent, path.basename(absolutePath));\n\n if (!isPathInside(realPath, realRoot)) return undefined;\n\n const relativePath = path.relative(realRoot, realPath).split(path.sep).join(\"/\");\n\n return variantSourceDirectory(\n variantCacheDirectoryFor(diskRoot),\n variantSourceKey(realRoot, relativePath),\n );\n}\n\n/**\n * Remove every cached derivative of one file on a local disk.\n *\n * @returns `true` when recognized cache files were removed\n */\nexport async function purgeImageVariantsOfFile(\n diskRoot: string,\n absolutePath: string,\n): Promise<boolean> {\n const directory = await variantSourceDirectoryForFile(diskRoot, absolutePath);\n\n if (!directory) return false;\n\n return purgeVariantCacheEntries(variantSourceCacheEntries(directory));\n}\n\n/**\n * Remove derivatives made from older versions of a source (a different size\n * or mtime), keeping only the `keep` generation. Called after a derivative of\n * the current version has been written, so a source rewritten in place does\n * not leave its old derivatives behind. Only recognized cache files in\n * generation-shaped directories are removed; unrelated entries and all\n * directories and symlinks stay in place.\n */\nexport async function pruneStaleVariantGenerations(\n sourceDirectory: string,\n keep: string,\n): Promise<void> {\n await purgeVariantCacheEntries(variantSourceCacheEntries(sourceDirectory, keep));\n}\n\n/**\n * {@link pruneStaleVariantGenerations}, but only while `keep` is still the\n * source's current generation.\n *\n * A request that read the source before it was rewritten renders an old\n * generation; if it pruned afterwards it would delete the derivatives of the\n * newer version another request had just written. Re-reading the source's\n * size and mtime right before pruning keeps a stale request from doing that.\n */\nexport async function pruneStaleVariantGenerationsIfCurrent(\n sourceAbsolutePath: string,\n sourceDirectory: string,\n keep: string,\n): Promise<void> {\n let current: string;\n\n try {\n const stats = await fs.stat(sourceAbsolutePath);\n current = variantGenerationTag(stats.size, stats.mtimeMs);\n } catch {\n // the source is gone; its derivatives are purged by the delete itself\n return;\n }\n\n if (current !== keep) return;\n\n await pruneStaleVariantGenerations(sourceDirectory, keep);\n}\n\n/**\n * True for \"no such file or directory\"\n */\nexport function isMissingFileError(error: unknown): boolean {\n return (error as NodeJS.ErrnoException | undefined)?.code === \"ENOENT\";\n}\n\n/**\n * Run a derivative write, once more if it fails because its directory\n * vanished: a concurrent request for a newer version of the source may prune\n * the generation directory between `mkdir` and the atomic rename.\n */\nexport async function retryOnVanishedDirectory(write: () => Promise<void>): Promise<void> {\n try {\n await write();\n } catch (error) {\n if (!isMissingFileError(error)) throw error;\n\n await write();\n }\n}\n\nlet warnedPublicCache = false;\n\n/**\n * Warn once when the derivative cache sits inside the public folder.\n *\n * A configured `uploads.images.cacheDirectory` is shared by every local disk,\n * so derivatives of a private disk land beside public ones. Inside\n * `public/` (or `storage.publicRoot`) they are served to anyone, bypassing\n * whatever guards the private disk's own route. The paths are hashes, but\n * they are derived from the disk root and the file path, which are not\n * secret.\n */\nexport function warnIfVariantCacheIsPublic(cacheDirectory: string): void {\n if (warnedPublicCache) return;\n\n const configured = config.get(\"storage.publicRoot\", rootPath(\"public\")) as unknown;\n const publicRoots = (Array.isArray(configured) ? configured : [configured])\n .filter((root): root is string => typeof root === \"string\" && root.length > 0)\n .map((root) => path.resolve(root));\n const resolved = path.resolve(cacheDirectory);\n\n if (!publicRoots.some((root) => resolved === root || isPathInside(resolved, root))) return;\n\n warnedPublicCache = true;\n log.warn(\n \"uploads\",\n \"image-variants\",\n `The image variant cache (${resolved}) is inside the public folder, so every cached derivative, private disks included, is publicly served. Move uploads.images.cacheDirectory outside public/.`,\n );\n}\n\n/**\n * Forget that the public-cache warning was shown (tests).\n */\nexport function resetVariantCacheWarnings(): void {\n warnedPublicCache = false;\n}\n"],"mappings":"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"}
@@ -1,32 +1,33 @@
1
1
  import { ImageVariantDefinition, ImageVariantOutputFormat } from "../uploads-types.mjs";
2
-
3
2
  //#region ../../packages/core/src/http/uploads/image-variant-types.d.ts
4
3
  /**
5
4
  * The `uploads.images` config after validation, with every default applied
6
5
  */
7
- type ResolvedImageVariantsConfig = {
6
+ export type ResolvedImageVariantsConfig = {
8
7
  variants: Readonly<Record<string, ImageVariantDefinition>>;
9
8
  formats: readonly ImageVariantOutputFormat[];
10
9
  maxSourceBytes: number;
11
10
  maxSourcePixels: number;
12
11
  cacheDirectory: string;
12
+ maxCacheBytes: number;
13
+ maxCacheAge: number;
13
14
  };
14
15
  /**
15
16
  * Raster formats a variant can be generated from, detected by magic bytes
16
17
  */
17
- type VariantSourceFormat = "jpeg" | "png" | "webp" | "avif";
18
+ export type VariantSourceFormat = "jpeg" | "png" | "webp" | "avif";
18
19
  /**
19
20
  * Every format `detectImageFormat` can recognise, including the refused ones
20
21
  */
21
- type DetectedImageFormat = VariantSourceFormat | "gif" | "svg";
22
+ export type DetectedImageFormat = VariantSourceFormat | "gif" | "svg";
22
23
  /**
23
24
  * Format a derivative is written in
24
25
  */
25
- type VariantOutputFormat = VariantSourceFormat;
26
+ export type VariantOutputFormat = VariantSourceFormat;
26
27
  /**
27
28
  * What the query string of an uploads request asks for
28
29
  */
29
- type UploadedFileQuery = {
30
+ export type UploadedFileQuery = {
30
31
  type: "original";
31
32
  } | {
32
33
  type: "variant";
@@ -44,7 +45,7 @@ type UploadedFileQuery = {
44
45
  * passed through loader data as is. Core does not import that type — web
45
46
  * depends on core, not the other way around — this is a structural match.
46
47
  */
47
- type GeneratedImageVariant = {
48
+ export type GeneratedImageVariant = {
48
49
  /**
49
50
  * Actual rendered width, in pixels
50
51
  */
@@ -66,7 +67,7 @@ type GeneratedImageVariant = {
66
67
  * Serializable descriptor returned by `generateImageVariants`, matching web's
67
68
  * `ImageDescriptor` field for field.
68
69
  */
69
- type GeneratedImageDescriptor = {
70
+ export type GeneratedImageDescriptor = {
70
71
  /**
71
72
  * The original source path: `/uploads/<path>`
72
73
  */
@@ -89,5 +90,4 @@ type GeneratedImageDescriptor = {
89
90
  formats?: readonly ImageVariantOutputFormat[];
90
91
  };
91
92
  //#endregion
92
- export { DetectedImageFormat, GeneratedImageDescriptor, GeneratedImageVariant, ResolvedImageVariantsConfig, UploadedFileQuery, VariantOutputFormat, VariantSourceFormat };
93
93
  //# sourceMappingURL=image-variant-types.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"image-variant-types.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/image-variant-types.ts"],"mappings":";;;;;AAKA;KAAY,2BAAA;EACV,QAAA,EAAU,QAAA,CAAS,MAAA,SAAe,sBAAA;EAClC,OAAA,WAAkB,wBAAA;EAClB,cAAA;EACA,eAAA;EACA,cAAA;AAAA;;;;KAMU,mBAAA;;;;KAKA,mBAAA,GAAsB,mBAAmB;;;;KAKzC,mBAAA,GAAsB,mBAAmB;AAVrD;;;AAAA,KAeY,iBAAA;EACN,IAAA;AAAA;EACA,IAAA;EAAiB,OAAA;EAAiB,MAAA;AAAA;EAClC,IAAA;EAAiB,MAAA;AAAA;;AAR8B;AAKrD;;;;;;KAaY,qBAAA;EAX4B;;;EAetC,KAAA;EAd2B;AAU7B;;EASE,MAAA;EAUsB;;;EALtB,GAAA;EAKc;;;EAAd,IAAA,GAAO,OAAA,CAAQ,MAAA,CAAO,wBAAA;AAAA;;;;;KAOZ,wBAAA;EAAA;;;EAIV,GAAA;EAemB;;;EAVnB,KAAA;EAe2C;;;EAV3C,MAAA;EAKA;;;EAAA,QAAA,EAAU,QAAA,CAAS,MAAA,SAAe,qBAAA;EAKlC;;;EAAA,OAAA,YAAmB,wBAAA;AAAA"}
1
+ {"version":3,"file":"image-variant-types.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/image-variant-types.ts"],"mappings":";;;;;YAKY;EACV,UAAU,SAAS,eAAe;EAClC,kBAAkB;EAClB;EACA;EACA;EACA;EACA;;;;;YAMU;;;;YAKA,sBAAsB;;;;YAKtB,sBAAsB;;;;YAKtB;EACN;;EACA;EAAiB;EAAiB;;EAClC;EAAiB;;;;;;;;;;YAUX;;;;EAIV;;;;EAKA;;;;EAKA;;;;EAKA,OAAO,QAAQ,OAAO;;;;;;YAOZ;;;;EAIV;;;;EAKA;;;;EAKA;;;;EAKA,UAAU,SAAS,eAAe;;;;EAKlC,mBAAmB"}
@@ -5,9 +5,10 @@
5
5
  * Raised the first time a variant is requested, so a bad config fails loudly
6
6
  * on the first image instead of producing unbounded or surprising derivatives.
7
7
  */
8
- declare class ImageVariantsConfigError extends Error {
9
- constructor(message: string);
8
+ export declare class ImageVariantsConfigError extends Error {
9
+ /** Stable Warlock error code; `warlock explain WL1005` prints the fix. */
10
+ readonly code = "WL1005";
11
+ constructor(message: string, options?: ErrorOptions);
10
12
  }
11
13
  //#endregion
12
- export { ImageVariantsConfigError };
13
14
  //# sourceMappingURL=image-variants-config-error.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"image-variants-config-error.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/image-variants-config-error.ts"],"mappings":";;AAMA;;;;;cAAa,wBAAA,SAAiC,KAAK;cAC9B,OAAA;AAAA"}
1
+ {"version":3,"file":"image-variants-config-error.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/image-variants-config-error.ts"],"mappings":";;;;;;;qBAMa,iCAAiC;;WAE5B;EAEhB,YAAmB,iBAAiB,UAAU"}
@@ -6,8 +6,9 @@
6
6
  * on the first image instead of producing unbounded or surprising derivatives.
7
7
  */
8
8
  var ImageVariantsConfigError = class extends Error {
9
- constructor(message) {
10
- super(`Invalid uploads.images configuration: ${message}`);
9
+ constructor(message, options) {
10
+ super(`Invalid uploads.images configuration: ${message}`, options);
11
+ this.code = "WL1005";
11
12
  this.name = "ImageVariantsConfigError";
12
13
  }
13
14
  };
@@ -1 +1 @@
1
- {"version":3,"file":"image-variants-config-error.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/image-variants-config-error.ts"],"sourcesContent":["/**\n * Thrown when the `uploads.images` configuration is invalid.\n *\n * Raised the first time a variant is requested, so a bad config fails loudly\n * on the first image instead of producing unbounded or surprising derivatives.\n */\nexport class ImageVariantsConfigError extends Error {\n public constructor(message: string) {\n super(`Invalid uploads.images configuration: ${message}`);\n\n this.name = \"ImageVariantsConfigError\";\n }\n}\n"],"mappings":";;;;;;;AAMA,IAAa,2BAAb,cAA8C,MAAM;CAClD,AAAO,YAAY,SAAiB;EAClC,MAAM,yCAAyC,SAAS;EAExD,KAAK,OAAO;CACd;AACF"}
1
+ {"version":3,"file":"image-variants-config-error.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/image-variants-config-error.ts"],"sourcesContent":["/**\n * Thrown when the `uploads.images` configuration is invalid.\n *\n * Raised the first time a variant is requested, so a bad config fails loudly\n * on the first image instead of producing unbounded or surprising derivatives.\n */\nexport class ImageVariantsConfigError extends Error {\n /** Stable Warlock error code; `warlock explain WL1005` prints the fix. */\n public readonly code = \"WL1005\";\n\n public constructor(message: string, options?: ErrorOptions) {\n super(`Invalid uploads.images configuration: ${message}`, options);\n\n this.name = \"ImageVariantsConfigError\";\n }\n}\n"],"mappings":";;;;;;;AAMA,IAAa,2BAAb,cAA8C,MAAM;CAIlD,AAAO,YAAY,SAAiB,SAAwB;EAC1D,MAAM,yCAAyC,WAAW,OAAO;cAH5C;EAKrB,KAAK,OAAO;CACd;AACF"}
@@ -3,4 +3,5 @@ import { GenerateImageVariantsOptions, generateImageVariants } from "./generate-
3
3
  import { ImageVariantsConfigError } from "./image-variants-config-error.mjs";
4
4
  import { PurgeImageVariantsOptions, purgeImageVariants } from "./purge-image-variants.mjs";
5
5
  import { ResolveImageVariantInput, ResolvedImageVariant, resolveImageVariant } from "./resolve-image-variant.mjs";
6
- import { UploadedFileControllerOptions, createUploadedFileController, uploadedFileController } from "./uploaded-file.controller.mjs";
6
+ import { UploadedFileControllerOptions, createUploadedFileController, uploadedFileController } from "./uploaded-file.controller.mjs";
7
+ export { DetectedImageFormat, GenerateImageVariantsOptions, GeneratedImageDescriptor, GeneratedImageVariant, ImageVariantsConfigError, PurgeImageVariantsOptions, ResolveImageVariantInput, ResolvedImageVariant, ResolvedImageVariantsConfig, UploadedFileControllerOptions, UploadedFileQuery, VariantOutputFormat, VariantSourceFormat, createUploadedFileController, generateImageVariants, purgeImageVariants, resolveImageVariant, uploadedFileController };
@@ -4,4 +4,4 @@ import { purgeImageVariants } from "./purge-image-variants.mjs";
4
4
  import { resolveImageVariant } from "./resolve-image-variant.mjs";
5
5
  import { createUploadedFileController, uploadedFileController } from "./uploaded-file.controller.mjs";
6
6
 
7
- export { };
7
+ export { ImageVariantsConfigError, createUploadedFileController, generateImageVariants, purgeImageVariants, resolveImageVariant, uploadedFileController };
@@ -21,7 +21,7 @@ import fs from "node:fs/promises";
21
21
  * I/O) propagates unchanged.
22
22
  */
23
23
  async function loadVariantSource(absolutePath, { maxSourceBytes, maxSourcePixels, expectedFormat }) {
24
- const buffer = await fs.readFile(absolutePath);
24
+ const buffer = Buffer.isBuffer(absolutePath) ? absolutePath : await fs.readFile(absolutePath);
25
25
  if (buffer.length > maxSourceBytes) throw new HttpError(413, "The source image is too large.");
26
26
  if (detectImageFormat(buffer) !== expectedFormat) throw new HttpError(415, "The source image changed format while it was read.");
27
27
  const image = new Image(buffer);
@@ -1 +1 @@
1
- {"version":3,"file":"load-variant-source.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/load-variant-source.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport { Image } from \"../../image\";\nimport { HttpError } from \"../errors\";\nimport { detectImageFormat } from \"./detect-image-format\";\nimport type { VariantSourceFormat } from \"./image-variant-types\";\n\n/**\n * Bounds and the expected format a source must match\n */\nexport type LoadVariantSourceOptions = {\n maxSourceBytes: number;\n maxSourcePixels: number;\n expectedFormat: VariantSourceFormat;\n};\n\n/**\n * Read a variant source in full and check it before it is decoded.\n *\n * The caller has already sniffed the format from the file head; this re-checks\n * the bytes actually read, the same buffer that is then resized, so the file\n * cannot be swapped between the check and the render.\n *\n * - bytes over `maxSourceBytes` → 413\n * - magic bytes that no longer match `expectedFormat` → 415\n * - a header sharp cannot read (e.g. avif without a decoder) → 415\n * - width × height over `maxSourcePixels` → 413, read from the header only\n *\n * @throws HttpError with status 413 or 415. Any other error (sharp missing,\n * I/O) propagates unchanged.\n */\nexport async function loadVariantSource(\n absolutePath: string,\n { maxSourceBytes, maxSourcePixels, expectedFormat }: LoadVariantSourceOptions,\n): Promise<Image> {\n const buffer = await fs.readFile(absolutePath);\n\n if (buffer.length > maxSourceBytes) {\n throw new HttpError(413, \"The source image is too large.\");\n }\n\n if (detectImageFormat(buffer) !== expectedFormat) {\n throw new HttpError(415, \"The source image changed format while it was read.\");\n }\n\n // Constructed outside the try below: sharp being absent is a server fault\n // (500 with the install hint), not an unsupported image.\n const image = new Image(buffer);\n\n let width: number | undefined;\n let height: number | undefined;\n\n try {\n ({ width, height } = await image.metadata());\n } catch {\n throw new HttpError(415, \"The source image cannot be decoded.\");\n }\n\n if (!width || !height) {\n throw new HttpError(415, \"The source image cannot be decoded.\");\n }\n\n if (width * height > maxSourcePixels) {\n throw new HttpError(413, \"The source image has too many pixels.\");\n }\n\n return image;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA8BA,eAAsB,kBACpB,cACA,EAAE,gBAAgB,iBAAiB,kBACnB;CAChB,MAAM,SAAS,MAAM,GAAG,SAAS,YAAY;CAE7C,IAAI,OAAO,SAAS,gBAClB,MAAM,IAAI,UAAU,KAAK,gCAAgC;CAG3D,IAAI,kBAAkB,MAAM,MAAM,gBAChC,MAAM,IAAI,UAAU,KAAK,oDAAoD;CAK/E,MAAM,QAAQ,IAAI,MAAM,MAAM;CAE9B,IAAI;CACJ,IAAI;CAEJ,IAAI;EACF,CAAC,CAAE,OAAO,UAAW,MAAM,MAAM,SAAS;CAC5C,QAAQ;EACN,MAAM,IAAI,UAAU,KAAK,qCAAqC;CAChE;CAEA,IAAI,CAAC,SAAS,CAAC,QACb,MAAM,IAAI,UAAU,KAAK,qCAAqC;CAGhE,IAAI,QAAQ,SAAS,iBACnB,MAAM,IAAI,UAAU,KAAK,uCAAuC;CAGlE,OAAO;AACT"}
1
+ {"version":3,"file":"load-variant-source.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/load-variant-source.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport { Image } from \"../../image\";\nimport { HttpError } from \"../errors\";\nimport { detectImageFormat } from \"./detect-image-format\";\nimport type { VariantSourceFormat } from \"./image-variant-types\";\n\n/**\n * Bounds and the expected format a source must match\n */\nexport type LoadVariantSourceOptions = {\n maxSourceBytes: number;\n maxSourcePixels: number;\n expectedFormat: VariantSourceFormat;\n};\n\n/**\n * Read a variant source in full and check it before it is decoded.\n *\n * The caller has already sniffed the format from the file head; this re-checks\n * the bytes actually read, the same buffer that is then resized, so the file\n * cannot be swapped between the check and the render.\n *\n * - bytes over `maxSourceBytes` → 413\n * - magic bytes that no longer match `expectedFormat` → 415\n * - a header sharp cannot read (e.g. avif without a decoder) → 415\n * - width × height over `maxSourcePixels` → 413, read from the header only\n *\n * @throws HttpError with status 413 or 415. Any other error (sharp missing,\n * I/O) propagates unchanged.\n */\nexport async function loadVariantSource(\n absolutePath: string | Buffer,\n { maxSourceBytes, maxSourcePixels, expectedFormat }: LoadVariantSourceOptions,\n): Promise<Image> {\n const buffer = Buffer.isBuffer(absolutePath) ? absolutePath : await fs.readFile(absolutePath);\n\n if (buffer.length > maxSourceBytes) {\n throw new HttpError(413, \"The source image is too large.\");\n }\n\n if (detectImageFormat(buffer) !== expectedFormat) {\n throw new HttpError(415, \"The source image changed format while it was read.\");\n }\n\n // Constructed outside the try below: sharp being absent is a server fault\n // (500 with the install hint), not an unsupported image.\n const image = new Image(buffer);\n\n let width: number | undefined;\n let height: number | undefined;\n\n try {\n ({ width, height } = await image.metadata());\n } catch {\n throw new HttpError(415, \"The source image cannot be decoded.\");\n }\n\n if (!width || !height) {\n throw new HttpError(415, \"The source image cannot be decoded.\");\n }\n\n if (width * height > maxSourcePixels) {\n throw new HttpError(413, \"The source image has too many pixels.\");\n }\n\n return image;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA8BA,eAAsB,kBACpB,cACA,EAAE,gBAAgB,iBAAiB,kBACnB;CAChB,MAAM,SAAS,OAAO,SAAS,YAAY,IAAI,eAAe,MAAM,GAAG,SAAS,YAAY;CAE5F,IAAI,OAAO,SAAS,gBAClB,MAAM,IAAI,UAAU,KAAK,gCAAgC;CAG3D,IAAI,kBAAkB,MAAM,MAAM,gBAChC,MAAM,IAAI,UAAU,KAAK,oDAAoD;CAK/E,MAAM,QAAQ,IAAI,MAAM,MAAM;CAE9B,IAAI;CACJ,IAAI;CAEJ,IAAI;EACF,CAAC,CAAE,OAAO,UAAW,MAAM,MAAM,SAAS;CAC5C,QAAQ;EACN,MAAM,IAAI,UAAU,KAAK,qCAAqC;CAChE;CAEA,IAAI,CAAC,SAAS,CAAC,QACb,MAAM,IAAI,UAAU,KAAK,qCAAqC;CAGhE,IAAI,QAAQ,SAAS,iBACnB,MAAM,IAAI,UAAU,KAAK,uCAAuC;CAGlE,OAAO;AACT"}
@@ -1,5 +1,5 @@
1
1
  //#region ../../packages/core/src/http/uploads/parse-uploaded-file-query.ts
2
- const ALLOWED_KEYS = new Set(["variant", "format"]);
2
+ const ALLOWED_KEYS = /* @__PURE__ */ new Set(["variant", "format"]);
3
3
  /**
4
4
  * Read the query string of an uploads request, strictly.
5
5
  *
@@ -1 +1 @@
1
- {"version":3,"file":"parse-uploaded-file-query.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/parse-uploaded-file-query.ts"],"sourcesContent":["import type { UploadedFileQuery } from \"./image-variant-types\";\n\nconst ALLOWED_KEYS = new Set([\"variant\", \"format\"]);\n\n/**\n * Read the query string of an uploads request, strictly.\n *\n * It parses the raw URL rather than the framework's parsed query, because the\n * parsed form folds a repeated key into an array and a lone key into a string,\n * and a strict allowlist has to see both. Only `variant` and `format` are\n * accepted, each at most once, and `format` only next to `variant`.\n *\n * @param url - the raw request URL, path and query\n */\nexport function parseUploadedFileQuery(url: string): UploadedFileQuery {\n const queryStart = url.indexOf(\"?\");\n const rawQuery = queryStart === -1 ? \"\" : url.slice(queryStart + 1);\n\n if (rawQuery === \"\") return { type: \"original\" };\n\n const values = new Map<string, string>();\n\n for (const [key, value] of new URLSearchParams(rawQuery)) {\n if (!ALLOWED_KEYS.has(key)) {\n return { type: \"invalid\", reason: `Unknown query parameter \"${key}\".` };\n }\n\n if (values.has(key)) {\n return { type: \"invalid\", reason: `Query parameter \"${key}\" is repeated.` };\n }\n\n values.set(key, value);\n }\n\n const variant = values.get(\"variant\");\n const format = values.get(\"format\");\n\n if (variant === undefined) {\n return values.size === 0\n ? { type: \"original\" }\n : { type: \"invalid\", reason: `\"format\" requires \"variant\".` };\n }\n\n if (variant === \"\") {\n return { type: \"invalid\", reason: `\"variant\" must not be empty.` };\n }\n\n return format === undefined ? { type: \"variant\", variant } : { type: \"variant\", variant, format };\n}\n"],"mappings":";AAEA,MAAM,eAAe,IAAI,IAAI,CAAC,WAAW,QAAQ,CAAC;;;;;;;;;;;AAYlD,SAAgB,uBAAuB,KAAgC;CACrE,MAAM,aAAa,IAAI,QAAQ,GAAG;CAClC,MAAM,WAAW,eAAe,KAAK,KAAK,IAAI,MAAM,aAAa,CAAC;CAElE,IAAI,aAAa,IAAI,OAAO,EAAE,MAAM,WAAW;CAE/C,MAAM,yBAAS,IAAI,IAAoB;CAEvC,KAAK,MAAM,CAAC,KAAK,UAAU,IAAI,gBAAgB,QAAQ,GAAG;EACxD,IAAI,CAAC,aAAa,IAAI,GAAG,GACvB,OAAO;GAAE,MAAM;GAAW,QAAQ,4BAA4B,IAAI;EAAI;EAGxE,IAAI,OAAO,IAAI,GAAG,GAChB,OAAO;GAAE,MAAM;GAAW,QAAQ,oBAAoB,IAAI;EAAgB;EAG5E,OAAO,IAAI,KAAK,KAAK;CACvB;CAEA,MAAM,UAAU,OAAO,IAAI,SAAS;CACpC,MAAM,SAAS,OAAO,IAAI,QAAQ;CAElC,IAAI,YAAY,QACd,OAAO,OAAO,SAAS,IACnB,EAAE,MAAM,WAAW,IACnB;EAAE,MAAM;EAAW,QAAQ;CAA+B;CAGhE,IAAI,YAAY,IACd,OAAO;EAAE,MAAM;EAAW,QAAQ;CAA+B;CAGnE,OAAO,WAAW,SAAY;EAAE,MAAM;EAAW;CAAQ,IAAI;EAAE,MAAM;EAAW;EAAS;CAAO;AAClG"}
1
+ {"version":3,"file":"parse-uploaded-file-query.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/parse-uploaded-file-query.ts"],"sourcesContent":["import type { UploadedFileQuery } from \"./image-variant-types\";\n\nconst ALLOWED_KEYS = new Set([\"variant\", \"format\"]);\n\n/**\n * Read the query string of an uploads request, strictly.\n *\n * It parses the raw URL rather than the framework's parsed query, because the\n * parsed form folds a repeated key into an array and a lone key into a string,\n * and a strict allowlist has to see both. Only `variant` and `format` are\n * accepted, each at most once, and `format` only next to `variant`.\n *\n * @param url - the raw request URL, path and query\n */\nexport function parseUploadedFileQuery(url: string): UploadedFileQuery {\n const queryStart = url.indexOf(\"?\");\n const rawQuery = queryStart === -1 ? \"\" : url.slice(queryStart + 1);\n\n if (rawQuery === \"\") return { type: \"original\" };\n\n const values = new Map<string, string>();\n\n for (const [key, value] of new URLSearchParams(rawQuery)) {\n if (!ALLOWED_KEYS.has(key)) {\n return { type: \"invalid\", reason: `Unknown query parameter \"${key}\".` };\n }\n\n if (values.has(key)) {\n return { type: \"invalid\", reason: `Query parameter \"${key}\" is repeated.` };\n }\n\n values.set(key, value);\n }\n\n const variant = values.get(\"variant\");\n const format = values.get(\"format\");\n\n if (variant === undefined) {\n return values.size === 0\n ? { type: \"original\" }\n : { type: \"invalid\", reason: `\"format\" requires \"variant\".` };\n }\n\n if (variant === \"\") {\n return { type: \"invalid\", reason: `\"variant\" must not be empty.` };\n }\n\n return format === undefined ? { type: \"variant\", variant } : { type: \"variant\", variant, format };\n}\n"],"mappings":";AAEA,MAAM,+BAAe,IAAI,IAAI,CAAC,WAAW,QAAQ,CAAC;;;;;;;;;;;AAYlD,SAAgB,uBAAuB,KAAgC;CACrE,MAAM,aAAa,IAAI,QAAQ,GAAG;CAClC,MAAM,WAAW,eAAe,KAAK,KAAK,IAAI,MAAM,aAAa,CAAC;CAElE,IAAI,aAAa,IAAI,OAAO,EAAE,MAAM,WAAW;CAE/C,MAAM,yBAAS,IAAI,IAAoB;CAEvC,KAAK,MAAM,CAAC,KAAK,UAAU,IAAI,gBAAgB,QAAQ,GAAG;EACxD,IAAI,CAAC,aAAa,IAAI,GAAG,GACvB,OAAO;GAAE,MAAM;GAAW,QAAQ,4BAA4B,IAAI;EAAI;EAGxE,IAAI,OAAO,IAAI,GAAG,GAChB,OAAO;GAAE,MAAM;GAAW,QAAQ,oBAAoB,IAAI;EAAgB;EAG5E,OAAO,IAAI,KAAK,KAAK;CACvB;CAEA,MAAM,UAAU,OAAO,IAAI,SAAS;CACpC,MAAM,SAAS,OAAO,IAAI,QAAQ;CAElC,IAAI,YAAY,QACd,OAAO,OAAO,SAAS,IACnB,EAAE,MAAM,WAAW,IACnB;EAAE,MAAM;EAAW,QAAQ;CAA+B;CAGhE,IAAI,YAAY,IACd,OAAO;EAAE,MAAM;EAAW,QAAQ;CAA+B;CAGnE,OAAO,WAAW,SAAY;EAAE,MAAM;EAAW;CAAQ,IAAI;EAAE,MAAM;EAAW;EAAS;CAAO;AAClG"}
@@ -1,12 +1,11 @@
1
1
  import { StorageDriverName } from "../../storage/types.mjs";
2
-
3
2
  //#region ../../packages/core/src/http/uploads/purge-image-variants.d.ts
4
3
  /**
5
4
  * Options for {@link purgeImageVariants}
6
5
  */
7
- type PurgeImageVariantsOptions = {
6
+ export type PurgeImageVariantsOptions = {
8
7
  /**
9
- * Local disk the source lives on; the default disk when omitted
8
+ * Disk the source lives on; the default disk when omitted
10
9
  */
11
10
  disk?: StorageDriverName;
12
11
  };
@@ -19,14 +18,18 @@ type PurgeImageVariantsOptions = {
19
18
  * `uploads.images.cacheDirectory` is set, that directory is shared by every
20
19
  * local disk, so this clears all of them.
21
20
  *
21
+ * Only recognized derivative, source-manifest and temporary files in the
22
+ * generated cache layout are removed. The cache root, directories, unrelated
23
+ * files and symlinks stay in place. Use a dedicated folder for derivatives.
24
+ *
22
25
  * Deleting or moving a file through local storage (`storage.delete`,
23
26
  * `deleteMany`, `move`) already purges its derivatives; call this for files
24
27
  * removed some other way.
25
28
  *
29
+ * @throws ImageVariantsConfigError when the cache equals or contains any
30
+ * configured local disk root, including through a symlink
26
31
  * @returns `true` when something was removed
27
- * @throws ImageVariantsConfigError when the disk is not a local disk
28
32
  */
29
- declare function purgeImageVariants(relativePath?: string, options?: PurgeImageVariantsOptions): Promise<boolean>;
33
+ export declare function purgeImageVariants(relativePath?: string, options?: PurgeImageVariantsOptions): Promise<boolean>;
30
34
  //#endregion
31
- export { PurgeImageVariantsOptions, purgeImageVariants };
32
35
  //# sourceMappingURL=purge-image-variants.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"purge-image-variants.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/purge-image-variants.ts"],"mappings":";;;;;AAUA;KAAY,yBAAA;;;AAIc;EAAxB,IAAA,GAAO,iBAAiB;AAAA;;;;;;;;AAsBhB;;;;;;;;;iBAHY,kBAAA,CACpB,YAAA,WACA,OAAA,GAAS,yBAAA,GACR,OAAO"}
1
+ {"version":3,"file":"purge-image-variants.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/purge-image-variants.ts"],"mappings":";;;;;YAeY;;;;EAIV,OAAO;;;;;;;;;;;;;;;;;;;;;;;wBAwBa,mBACpB,uBACA,UAAS,4BACR"}