@warlock.js/core 5.24.0 → 5.26.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 (256) hide show
  1. package/CHANGELOG.md +64 -1
  2. package/bin/warlock.js +0 -0
  3. package/esm/application/application.d.mts +21 -0
  4. package/esm/application/application.d.mts.map +1 -1
  5. package/esm/application/application.mjs +29 -1
  6. package/esm/application/application.mjs.map +1 -1
  7. package/esm/application/boot-signal.d.mts +2 -1
  8. package/esm/application/boot-signal.d.mts.map +1 -1
  9. package/esm/application/boot-signal.mjs.map +1 -1
  10. package/esm/application/index.d.mts +1 -0
  11. package/esm/application/index.mjs +1 -0
  12. package/esm/application/roles.d.mts +72 -0
  13. package/esm/application/roles.d.mts.map +1 -0
  14. package/esm/application/roles.mjs +124 -0
  15. package/esm/application/roles.mjs.map +1 -0
  16. package/esm/cli/commands/add.command.mjs.map +1 -1
  17. package/esm/cli/commands/create-database.command.mjs.map +1 -1
  18. package/esm/cli/commands/dev-server.command.mjs.map +1 -1
  19. package/esm/cli/commands/doctor/boot-for-diagnostics.mjs.map +1 -1
  20. package/esm/cli/commands/doctor/checks/index.mjs +2 -0
  21. package/esm/cli/commands/doctor/checks/index.mjs.map +1 -1
  22. package/esm/cli/commands/doctor/checks/locales-ts-deprecated.check.mjs +170 -0
  23. package/esm/cli/commands/doctor/checks/locales-ts-deprecated.check.mjs.map +1 -0
  24. package/esm/cli/commands/doctor/doctor-command.action.mjs +7 -2
  25. package/esm/cli/commands/doctor/doctor-command.action.mjs.map +1 -1
  26. package/esm/cli/commands/doctor.command.mjs +5 -0
  27. package/esm/cli/commands/doctor.command.mjs.map +1 -1
  28. package/esm/cli/commands/drop-tables.command.mjs.map +1 -1
  29. package/esm/cli/commands/generate/generators/module.generator.mjs +1 -12
  30. package/esm/cli/commands/generate/generators/module.generator.mjs.map +1 -1
  31. package/esm/cli/commands/generate/utils/path-resolver.mjs.map +1 -1
  32. package/esm/cli/commands/migrate.command.mjs.map +1 -1
  33. package/esm/cli/commands/routes.command.mjs.map +1 -1
  34. package/esm/cli/commands/seed.command.mjs.map +1 -1
  35. package/esm/cli/commands/start-production.command.mjs +54 -5
  36. package/esm/cli/commands/start-production.command.mjs.map +1 -1
  37. package/esm/cli/commands/storage-put.action.mjs.map +1 -1
  38. package/esm/cli/commands/storage-put.command.mjs.map +1 -1
  39. package/esm/cli/commands/typings-generator.command.mjs +20 -1
  40. package/esm/cli/commands/typings-generator.command.mjs.map +1 -1
  41. package/esm/cli/commands/update.command.mjs.map +1 -1
  42. package/esm/cli/commands-loader.mjs.map +1 -1
  43. package/esm/config/config-loader.d.mts.map +1 -1
  44. package/esm/config/config-loader.mjs +3 -1
  45. package/esm/config/config-loader.mjs.map +1 -1
  46. package/esm/connectors/connectors-manager.mjs.map +1 -1
  47. package/esm/connectors/database-connector.mjs.map +1 -1
  48. package/esm/connectors/herald-connector.mjs.map +1 -1
  49. package/esm/connectors/http-connector.d.mts.map +1 -1
  50. package/esm/connectors/http-connector.mjs +7 -0
  51. package/esm/connectors/http-connector.mjs.map +1 -1
  52. package/esm/connectors/logger-connector.mjs.map +1 -1
  53. package/esm/connectors/mail-connector.mjs.map +1 -1
  54. package/esm/connectors/types.d.mts +8 -0
  55. package/esm/connectors/types.d.mts.map +1 -1
  56. package/esm/connectors/types.mjs.map +1 -1
  57. package/esm/database/create-database-action.mjs.map +1 -1
  58. package/esm/database/drop-tables-action.mjs.map +1 -1
  59. package/esm/database/migrate-action.mjs +4 -3
  60. package/esm/database/migrate-action.mjs.map +1 -1
  61. package/esm/database/models/database-log/database-log.mjs.map +1 -1
  62. package/esm/database/seed-command-action.mjs +2 -1
  63. package/esm/database/seed-command-action.mjs.map +1 -1
  64. package/esm/dev-server/dependency-graph.mjs.map +1 -1
  65. package/esm/dev-server/development-server.mjs +2 -0
  66. package/esm/dev-server/development-server.mjs.map +1 -1
  67. package/esm/dev-server/files-orchestrator.mjs.map +1 -1
  68. package/esm/dev-server/layer-executor.mjs.map +1 -1
  69. package/esm/dev-server/legacy-locales-warning.mjs +16 -0
  70. package/esm/dev-server/legacy-locales-warning.mjs.map +1 -0
  71. package/esm/dev-server/manifest-manager.mjs.map +1 -1
  72. package/esm/dev-server/module-loader.mjs +26 -5
  73. package/esm/dev-server/module-loader.mjs.map +1 -1
  74. package/esm/dev-server/register-installed-devtools.mjs +47 -0
  75. package/esm/dev-server/register-installed-devtools.mjs.map +1 -0
  76. package/esm/dev-server/run-connector-typings.mjs +28 -0
  77. package/esm/dev-server/run-connector-typings.mjs.map +1 -0
  78. package/esm/dev-server/special-file-patterns.mjs +5 -3
  79. package/esm/dev-server/special-file-patterns.mjs.map +1 -1
  80. package/esm/dev-server/special-files-collector.d.mts +2 -2
  81. package/esm/dev-server/special-files-collector.d.mts.map +1 -1
  82. package/esm/dev-server/special-files-collector.mjs +7 -4
  83. package/esm/dev-server/special-files-collector.mjs.map +1 -1
  84. package/esm/dev-server/translation-keys-sources.mjs +7 -3
  85. package/esm/dev-server/translation-keys-sources.mjs.map +1 -1
  86. package/esm/dev-server/type-generator.mjs +27 -4
  87. package/esm/dev-server/type-generator.mjs.map +1 -1
  88. package/esm/encryption/password.mjs.map +1 -1
  89. package/esm/generations/add-command.action.mjs +3 -1
  90. package/esm/generations/add-command.action.mjs.map +1 -1
  91. package/esm/generations/features/access.feature.mjs +38 -18
  92. package/esm/generations/features/access.feature.mjs.map +1 -1
  93. package/esm/generations/features/ai-anthropic.feature.mjs.map +1 -1
  94. package/esm/generations/features/ai-bedrock.feature.mjs.map +1 -1
  95. package/esm/generations/features/ai-google.feature.mjs.map +1 -1
  96. package/esm/generations/features/ai-ollama.feature.mjs.map +1 -1
  97. package/esm/generations/features/ai-openai.feature.mjs.map +1 -1
  98. package/esm/generations/features/ai-panoptic.feature.mjs.map +1 -1
  99. package/esm/generations/features/ai-tools.feature.mjs.map +1 -1
  100. package/esm/generations/features/ai-workspace.feature.mjs.map +1 -1
  101. package/esm/generations/features/ai.feature.mjs.map +1 -1
  102. package/esm/generations/features/bull-board.feature.mjs +2 -2
  103. package/esm/generations/features/bull-board.feature.mjs.map +1 -1
  104. package/esm/generations/features/devtools.feature.mjs +23 -0
  105. package/esm/generations/features/devtools.feature.mjs.map +1 -0
  106. package/esm/generations/features/herald.feature.mjs.map +1 -1
  107. package/esm/generations/features/image.feature.mjs.map +1 -1
  108. package/esm/generations/features/index.mjs +2 -0
  109. package/esm/generations/features/index.mjs.map +1 -1
  110. package/esm/generations/features/mail.feature.mjs.map +1 -1
  111. package/esm/generations/features/mongodb.feature.mjs.map +1 -1
  112. package/esm/generations/features/notifications.feature.mjs.map +1 -1
  113. package/esm/generations/features/postgres.feature.mjs.map +1 -1
  114. package/esm/generations/features/react-email.feature.mjs.map +1 -1
  115. package/esm/generations/features/react.feature.mjs.map +1 -1
  116. package/esm/generations/features/redis.feature.mjs.map +1 -1
  117. package/esm/generations/features/s3.feature.mjs.map +1 -1
  118. package/esm/generations/features/scheduler.feature.mjs.map +1 -1
  119. package/esm/generations/features/ses.feature.mjs.map +1 -1
  120. package/esm/generations/features/socket.feature.mjs.map +1 -1
  121. package/esm/generations/features/test.feature.mjs +6 -2
  122. package/esm/generations/features/test.feature.mjs.map +1 -1
  123. package/esm/generations/features/types.mjs.map +1 -1
  124. package/esm/generations/features/web.feature.mjs.map +1 -1
  125. package/esm/http/build-rate-limit-options.d.mts +8 -2
  126. package/esm/http/build-rate-limit-options.d.mts.map +1 -1
  127. package/esm/http/build-rate-limit-options.mjs +1 -0
  128. package/esm/http/build-rate-limit-options.mjs.map +1 -1
  129. package/esm/http/database/RequestLog.mjs.map +1 -1
  130. package/esm/http/errors/errors.d.mts +1 -17
  131. package/esm/http/errors/errors.d.mts.map +1 -1
  132. package/esm/http/errors/errors.mjs +1 -20
  133. package/esm/http/errors/errors.mjs.map +1 -1
  134. package/esm/http/index.d.mts +4 -3
  135. package/esm/http/index.mjs +3 -2
  136. package/esm/http/middleware/inject-request-context.d.mts +1 -1
  137. package/esm/http/middleware/inject-request-context.d.mts.map +1 -1
  138. package/esm/http/middleware/inject-request-context.mjs +9 -1
  139. package/esm/http/middleware/inject-request-context.mjs.map +1 -1
  140. package/esm/http/middleware/rate-limit.middleware.d.mts.map +1 -1
  141. package/esm/http/middleware/rate-limit.middleware.mjs +5 -1
  142. package/esm/http/middleware/rate-limit.middleware.mjs.map +1 -1
  143. package/esm/http/request.d.mts +7 -24
  144. package/esm/http/request.d.mts.map +1 -1
  145. package/esm/http/request.mjs +1 -22
  146. package/esm/http/request.mjs.map +1 -1
  147. package/esm/http/response.d.mts +5 -5
  148. package/esm/http/response.d.mts.map +1 -1
  149. package/esm/http/response.mjs +4 -2
  150. package/esm/http/response.mjs.map +1 -1
  151. package/esm/http/server-rebuilt.d.mts +20 -0
  152. package/esm/http/server-rebuilt.d.mts.map +1 -0
  153. package/esm/http/server-rebuilt.mjs +21 -0
  154. package/esm/http/server-rebuilt.mjs.map +1 -0
  155. package/esm/http/tracing/index.mjs +1 -1
  156. package/esm/http/tracing/tracing-dispatcher.d.mts +13 -6
  157. package/esm/http/tracing/tracing-dispatcher.d.mts.map +1 -1
  158. package/esm/http/tracing/tracing-dispatcher.mjs +46 -14
  159. package/esm/http/tracing/tracing-dispatcher.mjs.map +1 -1
  160. package/esm/http/tracing/tracing.type.d.mts +2 -1
  161. package/esm/http/tracing/tracing.type.d.mts.map +1 -1
  162. package/esm/http/types.d.mts +9 -0
  163. package/esm/http/types.d.mts.map +1 -1
  164. package/esm/image/image.mjs.map +1 -1
  165. package/esm/index.d.mts +8 -4
  166. package/esm/index.mjs +8 -3
  167. package/esm/loader/app-module-importer.d.mts +17 -0
  168. package/esm/loader/app-module-importer.d.mts.map +1 -0
  169. package/esm/loader/app-module-importer.mjs +20 -0
  170. package/esm/loader/app-module-importer.mjs.map +1 -0
  171. package/esm/localization/index.mjs +4 -0
  172. package/esm/localization/parse-locale-dictionary.d.mts +23 -0
  173. package/esm/localization/parse-locale-dictionary.d.mts.map +1 -0
  174. package/esm/localization/parse-locale-dictionary.mjs +215 -0
  175. package/esm/localization/parse-locale-dictionary.mjs.map +1 -0
  176. package/esm/localization/register-locale-dictionary.d.mts +12 -0
  177. package/esm/localization/register-locale-dictionary.d.mts.map +1 -0
  178. package/esm/localization/register-locale-dictionary.mjs +58 -0
  179. package/esm/localization/register-locale-dictionary.mjs.map +1 -0
  180. package/esm/logger/logger.mjs.map +1 -1
  181. package/esm/mail/events.d.mts +7 -0
  182. package/esm/mail/events.d.mts.map +1 -1
  183. package/esm/mail/events.mjs +7 -0
  184. package/esm/mail/events.mjs.map +1 -1
  185. package/esm/mail/send-mail.d.mts.map +1 -1
  186. package/esm/mail/send-mail.mjs +23 -2
  187. package/esm/mail/send-mail.mjs.map +1 -1
  188. package/esm/mail/types.d.mts +5 -1
  189. package/esm/mail/types.d.mts.map +1 -1
  190. package/esm/mail/types.mjs.map +1 -1
  191. package/esm/manifest/manifest-manager.mjs.map +1 -1
  192. package/esm/production/build-contributions.mjs +19 -3
  193. package/esm/production/build-contributions.mjs.map +1 -1
  194. package/esm/production/production-builder.mjs +39 -10
  195. package/esm/production/production-builder.mjs.map +1 -1
  196. package/esm/production/production-supervisor.mjs +6 -0
  197. package/esm/production/production-supervisor.mjs.map +1 -1
  198. package/esm/production/resolve-build-config.d.mts +1 -1
  199. package/esm/production/resolve-build-config.mjs +15 -0
  200. package/esm/production/resolve-build-config.mjs.map +1 -1
  201. package/esm/production/route-registration-child.mjs +14 -2
  202. package/esm/production/route-registration-child.mjs.map +1 -1
  203. package/esm/production/route-registration-snapshot.mjs +9 -2
  204. package/esm/production/route-registration-snapshot.mjs.map +1 -1
  205. package/esm/resource/resource-field-builder.mjs +1 -1
  206. package/esm/resource/resource-field-builder.mjs.map +1 -1
  207. package/esm/resource/resource.d.mts +5 -0
  208. package/esm/resource/resource.d.mts.map +1 -1
  209. package/esm/resource/resource.mjs +17 -6
  210. package/esm/resource/resource.mjs.map +1 -1
  211. package/esm/router/router.d.mts.map +1 -1
  212. package/esm/router/router.mjs +1 -0
  213. package/esm/router/router.mjs.map +1 -1
  214. package/esm/router/types.d.mts +10 -1
  215. package/esm/router/types.d.mts.map +1 -1
  216. package/esm/tests/index.d.mts +3 -2
  217. package/esm/tests/index.mjs +3 -2
  218. package/esm/tests/start-http-development-server.d.mts +10 -0
  219. package/esm/tests/start-http-development-server.d.mts.map +1 -1
  220. package/esm/tests/start-http-development-server.mjs +16 -2
  221. package/esm/tests/start-http-development-server.mjs.map +1 -1
  222. package/esm/tests/vitest-setup.d.mts +16 -1
  223. package/esm/tests/vitest-setup.d.mts.map +1 -1
  224. package/esm/tests/vitest-setup.mjs +20 -2
  225. package/esm/tests/vitest-setup.mjs.map +1 -1
  226. package/esm/use-cases/use-case-events.mjs.map +1 -1
  227. package/esm/utils/is-test-file.mjs +15 -0
  228. package/esm/utils/is-test-file.mjs.map +1 -0
  229. package/esm/utils/normalized-path.d.mts +3 -1
  230. package/esm/utils/normalized-path.d.mts.map +1 -1
  231. package/esm/utils/normalized-path.mjs +4 -2
  232. package/esm/utils/normalized-path.mjs.map +1 -1
  233. package/esm/utils/paths.mjs.map +1 -1
  234. package/esm/validation/plugins/database-plugin.mjs.map +1 -1
  235. package/esm/validation/validateAll.mjs +57 -4
  236. package/esm/validation/validateAll.mjs.map +1 -1
  237. package/esm/warlock-config/default-configurations.mjs +1 -0
  238. package/esm/warlock-config/default-configurations.mjs.map +1 -1
  239. package/esm/warlock-config/types.d.mts +7 -0
  240. package/esm/warlock-config/types.d.mts.map +1 -1
  241. package/esm/warlock-config/warlock-config.manager.mjs.map +1 -1
  242. package/llms-full.txt +382 -214
  243. package/llms.txt +1 -1
  244. package/package.json +23 -19
  245. package/skills/README.md +1 -1
  246. package/skills/configure-app/SKILL.md +2 -0
  247. package/skills/create-controller/SKILL.md +4 -0
  248. package/skills/define-resource/SKILL.md +4 -0
  249. package/skills/request-tracing/SKILL.md +38 -15
  250. package/skills/run-app/SKILL.md +71 -34
  251. package/skills/send-mail/SKILL.md +55 -25
  252. package/skills/test-http/SKILL.md +28 -9
  253. package/skills/test-service/SKILL.md +61 -40
  254. package/skills/use-localization/SKILL.md +39 -26
  255. package/skills/warlock-conventions/SKILL.md +26 -18
  256. package/skills/write-cli-command/SKILL.md +50 -45
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devtools.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/devtools.feature.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\nimport { type FeatureDefinition, INSTALLED_WARLOCK_VERSION } from \"./types\";\n\n/**\n * `warlock add devtools` — the development dashboard at `/__warlock`.\n *\n * Installed as a DEV dependency and never named in `warlock.config.ts`: core\n * loads it on its own in development when it is installed. A production\n * install omits dev dependencies, so there is nothing to strip and no config\n * import that could fail to resolve.\n */\nexport const devtoolsFeature: FeatureDefinition = {\n description:\n \"Installs @warlock.js/devtools as a dev dependency — a development-only dashboard at /__warlock (request timeline, queries, N+1, mailbox, logs, cache, routes). Loaded automatically by `warlock dev`; never runs in production.\",\n devDependencies: {\n \"@warlock.js/devtools\": INSTALLED_WARLOCK_VERSION,\n },\n async onExecuting() {\n console.log(\n `${colors.green(\"✓\")} Devtools installed. Run ${colors.cyan(\"warlock dev\")} and open ${colors.cyan(\"/__warlock\")} on your app's URL.`,\n );\n },\n};\n"],"mappings":";;;;;;;;;;;;AAWA,MAAa,kBAAqC;CAChD,aACE;CACF,iBAAiB,EACf,wBAAwB,0BAC1B;CACA,MAAM,cAAc;EAClB,QAAQ,IACN,GAAG,OAAO,MAAM,GAAG,EAAE,2BAA2B,OAAO,KAAK,aAAa,EAAE,YAAY,OAAO,KAAK,YAAY,EAAE,oBACnH;CACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"herald.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/herald.feature.ts"],"sourcesContent":["import { communicatorsConfigStub } from \"../stubs\";\r\nimport { type FeatureDefinition, INSTALLED_WARLOCK_VERSION } from \"./types\";\r\n\r\nexport const heraldFeature: FeatureDefinition = {\r\n description: \"Installs herald for message broker (Herald Package)\",\r\n dependencies: {\r\n \"@warlock.js/herald\": INSTALLED_WARLOCK_VERSION,\r\n amqplib: \"^0.10.0\",\r\n },\r\n devDependencies: {\r\n \"@types/amqplib\": \"^0.10.0\",\r\n },\r\n ejectConfig: {\r\n content: communicatorsConfigStub,\r\n name: \"herald\",\r\n },\r\n};\r\n"],"mappings":";;;;AAGA,MAAa,gBAAmC;CAC9C,aAAa;CACb,cAAc;EACZ,sBAAsB;EACtB,SAAS;CACX;CACA,iBAAiB,EACf,kBAAkB,UACpB;CACA,aAAa;EACX,SAAS;EACT,MAAM;CACR;AACF"}
1
+ {"version":3,"file":"herald.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/herald.feature.ts"],"sourcesContent":["import { communicatorsConfigStub } from \"../stubs\";\nimport { type FeatureDefinition, INSTALLED_WARLOCK_VERSION } from \"./types\";\n\nexport const heraldFeature: FeatureDefinition = {\n description: \"Installs herald for message broker (Herald Package)\",\n dependencies: {\n \"@warlock.js/herald\": INSTALLED_WARLOCK_VERSION,\n amqplib: \"^0.10.0\",\n },\n devDependencies: {\n \"@types/amqplib\": \"^0.10.0\",\n },\n ejectConfig: {\n content: communicatorsConfigStub,\n name: \"herald\",\n },\n};\n"],"mappings":";;;;AAGA,MAAa,gBAAmC;CAC9C,aAAa;CACb,cAAc;EACZ,sBAAsB;EACtB,SAAS;CACX;CACA,iBAAiB,EACf,kBAAkB,UACpB;CACA,aAAa;EACX,SAAS;EACT,MAAM;CACR;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"image.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/image.feature.ts"],"sourcesContent":["import type { FeatureDefinition } from \"./types\";\r\n\r\nexport const imageFeature: FeatureDefinition = {\r\n description: \"Installs sharp for image processing\",\r\n dependencies: {\r\n sharp: \"^0.34.5\",\r\n },\r\n};\r\n"],"mappings":";AAEA,MAAa,eAAkC;CAC7C,aAAa;CACb,cAAc,EACZ,OAAO,UACT;AACF"}
1
+ {"version":3,"file":"image.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/image.feature.ts"],"sourcesContent":["import type { FeatureDefinition } from \"./types\";\n\nexport const imageFeature: FeatureDefinition = {\n description: \"Installs sharp for image processing\",\n dependencies: {\n sharp: \"^0.34.5\",\n },\n};\n"],"mappings":";AAEA,MAAa,eAAkC;CAC7C,aAAa;CACb,cAAc,EACZ,OAAO,UACT;AACF"}
@@ -11,6 +11,7 @@ import { aiFeature } from "./ai.feature.mjs";
11
11
  import { authGoogleFeature } from "./auth-google.feature.mjs";
12
12
  import { authPasskeysFeature } from "./auth-passkeys.feature.mjs";
13
13
  import { bullBoardFeature } from "./bull-board.feature.mjs";
14
+ import { devtoolsFeature } from "./devtools.feature.mjs";
14
15
  import { heraldFeature } from "./herald.feature.mjs";
15
16
  import { imageFeature } from "./image.feature.mjs";
16
17
  import { mailFeature } from "./mail.feature.mjs";
@@ -58,6 +59,7 @@ const featuresMap = {
58
59
  tailwind: tailwindFeature,
59
60
  shadcn: shadcnFeature,
60
61
  sitemap: sitemapFeature,
62
+ devtools: devtoolsFeature,
61
63
  herald: heraldFeature,
62
64
  queue: queueFeature,
63
65
  "bull-board": bullBoardFeature,
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/index.ts"],"sourcesContent":["import { accessFeature } from \"./access.feature\";\r\nimport { aiAnthropicFeature } from \"./ai-anthropic.feature\";\r\nimport { aiBedrockFeature } from \"./ai-bedrock.feature\";\r\nimport { aiGoogleFeature } from \"./ai-google.feature\";\r\nimport { aiOllamaFeature } from \"./ai-ollama.feature\";\r\nimport { aiOpenaiFeature } from \"./ai-openai.feature\";\r\nimport { aiPanopticFeature } from \"./ai-panoptic.feature\";\r\nimport { aiToolsFeature } from \"./ai-tools.feature\";\r\nimport { aiWorkspaceFeature } from \"./ai-workspace.feature\";\r\nimport { aiFeature } from \"./ai.feature\";\r\nimport { authGoogleFeature } from \"./auth-google.feature\";\r\nimport { authPasskeysFeature } from \"./auth-passkeys.feature\";\r\nimport { bullBoardFeature } from \"./bull-board.feature\";\r\nimport { heraldFeature } from \"./herald.feature\";\r\nimport { imageFeature } from \"./image.feature\";\r\nimport { mailFeature } from \"./mail.feature\";\r\nimport { mongodbFeature } from \"./mongodb.feature\";\r\nimport { mysqlFeature } from \"./mysql.feature\";\r\nimport { notificationsFeature } from \"./notifications.feature\";\r\nimport { postgresFeature } from \"./postgres.feature\";\r\nimport { queueFeature } from \"./queue.feature\";\r\nimport { reactEmailFeature } from \"./react-email.feature\";\r\nimport { reactFeature } from \"./react.feature\";\r\nimport { redisFeature } from \"./redis.feature\";\r\nimport { s3Feature } from \"./s3.feature\";\r\nimport { schedulerFeature } from \"./scheduler.feature\";\r\nimport { sesFeature } from \"./ses.feature\";\r\nimport { shadcnFeature } from \"./shadcn.feature\";\r\nimport { sitemapFeature } from \"./sitemap.feature\";\r\nimport { socketFeature } from \"./socket.feature\";\r\nimport { tailwindFeature } from \"./tailwind.feature\";\r\nimport { testFeature } from \"./test.feature\";\r\nimport type { FeatureDefinition } from \"./types\";\r\nimport { webFeature } from \"./web.feature\";\r\n\r\nexport type { FeatureDefinition } from \"./types\";\r\n\r\n/**\r\n * The feature registry `warlock add` dispatches against.\r\n *\r\n * This file is an INDEX, nothing more: every entry lives in its own module\r\n * alongside the `onExecuting` body it runs. Key order is load-bearing — it is\r\n * the order `--list` prints and the order the \"not allowed\" error lists — so\r\n * add new features in the place they should appear, not alphabetically.\r\n */\r\nexport const featuresMap: Record<string, FeatureDefinition> = {\r\n \"react-email\": reactEmailFeature,\r\n react: reactFeature,\r\n image: imageFeature,\r\n mail: mailFeature,\r\n ses: sesFeature,\r\n mongodb: mongodbFeature,\r\n scheduler: schedulerFeature,\r\n // swagger / postman intentionally omitted — those packages do not exist yet;\r\n // they will ship together in the unified @warlock.js/api-docs package.\r\n postgres: postgresFeature,\r\n mysql: mysqlFeature,\r\n redis: redisFeature,\r\n s3: s3Feature,\r\n test: testFeature,\r\n web: webFeature,\r\n // Directly after `web`, and only there: it `requires` it, it is useless\r\n // without it, and a reader scanning `--list` for the page stack should meet\r\n // the two together rather than find styling filed between queues and sockets.\r\n tailwind: tailwindFeature,\r\n // Immediately after `tailwind`, for the same reason `tailwind` follows `web`:\r\n // it `requires` it, it appends to the stylesheet that feature creates, and the\r\n // three of them are one stack a reader should meet in build order.\r\n shadcn: shadcnFeature,\r\n // Directly after the web/tailwind/shadcn stack, for the same reason: it\r\n // `requires` web (it reads the page registry `listRoutablePages()`\r\n // exposes) and a reader scanning `--list` for the page stack should meet it\r\n // there rather than filed between queues and sockets.\r\n sitemap: sitemapFeature,\r\n herald: heraldFeature,\r\n queue: queueFeature,\r\n // Directly after `queue`, for the same reason `tailwind` follows `web`: it\r\n // needs queue already installed and configured, and a reader scanning\r\n // `--list` for job-queue features should meet the two together.\r\n \"bull-board\": bullBoardFeature,\r\n socket: socketFeature,\r\n notifications: notificationsFeature,\r\n access: accessFeature,\r\n // Login methods for @warlock.js/auth — \"<package>-<vendor>\" like the ai-* entries.\r\n \"auth-google\": authGoogleFeature,\r\n \"auth-passkeys\": authPasskeysFeature,\r\n ai: aiFeature,\r\n \"ai-openai\": aiOpenaiFeature,\r\n \"ai-google\": aiGoogleFeature,\r\n \"ai-anthropic\": aiAnthropicFeature,\r\n \"ai-bedrock\": aiBedrockFeature,\r\n \"ai-ollama\": aiOllamaFeature,\r\n \"ai-tools\": aiToolsFeature,\r\n \"ai-panoptic\": aiPanopticFeature,\r\n \"ai-workspace\": aiWorkspaceFeature,\r\n};\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CA,MAAa,cAAiD;CAC5D,eAAe;CACf,OAAO;CACP,OAAO;CACP,MAAM;CACN,KAAK;CACL,SAAS;CACT,WAAW;CAGX,UAAU;CACV,OAAO;CACP,OAAO;CACP,IAAI;CACJ,MAAM;CACN,KAAK;CAIL,UAAU;CAIV,QAAQ;CAKR,SAAS;CACT,QAAQ;CACR,OAAO;CAIP,cAAc;CACd,QAAQ;CACR,eAAe;CACf,QAAQ;CAER,eAAe;CACf,iBAAiB;CACjB,IAAI;CACJ,aAAa;CACb,aAAa;CACb,gBAAgB;CAChB,cAAc;CACd,aAAa;CACb,YAAY;CACZ,eAAe;CACf,gBAAgB;AAClB"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/index.ts"],"sourcesContent":["import { accessFeature } from \"./access.feature\";\nimport { aiAnthropicFeature } from \"./ai-anthropic.feature\";\nimport { aiBedrockFeature } from \"./ai-bedrock.feature\";\nimport { aiGoogleFeature } from \"./ai-google.feature\";\nimport { aiOllamaFeature } from \"./ai-ollama.feature\";\nimport { aiOpenaiFeature } from \"./ai-openai.feature\";\nimport { aiPanopticFeature } from \"./ai-panoptic.feature\";\nimport { aiToolsFeature } from \"./ai-tools.feature\";\nimport { aiWorkspaceFeature } from \"./ai-workspace.feature\";\nimport { aiFeature } from \"./ai.feature\";\nimport { authGoogleFeature } from \"./auth-google.feature\";\nimport { authPasskeysFeature } from \"./auth-passkeys.feature\";\nimport { bullBoardFeature } from \"./bull-board.feature\";\nimport { devtoolsFeature } from \"./devtools.feature\";\nimport { heraldFeature } from \"./herald.feature\";\nimport { imageFeature } from \"./image.feature\";\nimport { mailFeature } from \"./mail.feature\";\nimport { mongodbFeature } from \"./mongodb.feature\";\nimport { mysqlFeature } from \"./mysql.feature\";\nimport { notificationsFeature } from \"./notifications.feature\";\nimport { postgresFeature } from \"./postgres.feature\";\nimport { queueFeature } from \"./queue.feature\";\nimport { reactEmailFeature } from \"./react-email.feature\";\nimport { reactFeature } from \"./react.feature\";\nimport { redisFeature } from \"./redis.feature\";\nimport { s3Feature } from \"./s3.feature\";\nimport { schedulerFeature } from \"./scheduler.feature\";\nimport { sesFeature } from \"./ses.feature\";\nimport { shadcnFeature } from \"./shadcn.feature\";\nimport { sitemapFeature } from \"./sitemap.feature\";\nimport { socketFeature } from \"./socket.feature\";\nimport { tailwindFeature } from \"./tailwind.feature\";\nimport { testFeature } from \"./test.feature\";\nimport type { FeatureDefinition } from \"./types\";\nimport { webFeature } from \"./web.feature\";\n\nexport type { FeatureDefinition } from \"./types\";\n\n/**\n * The feature registry `warlock add` dispatches against.\n *\n * This file is an INDEX, nothing more: every entry lives in its own module\n * alongside the `onExecuting` body it runs. Key order is load-bearing — it is\n * the order `--list` prints and the order the \"not allowed\" error lists — so\n * add new features in the place they should appear, not alphabetically.\n */\nexport const featuresMap: Record<string, FeatureDefinition> = {\n \"react-email\": reactEmailFeature,\n react: reactFeature,\n image: imageFeature,\n mail: mailFeature,\n ses: sesFeature,\n mongodb: mongodbFeature,\n scheduler: schedulerFeature,\n // swagger / postman intentionally omitted — those packages do not exist yet;\n // they will ship together in the unified @warlock.js/api-docs package.\n postgres: postgresFeature,\n mysql: mysqlFeature,\n redis: redisFeature,\n s3: s3Feature,\n test: testFeature,\n web: webFeature,\n // Directly after `web`, and only there: it `requires` it, it is useless\n // without it, and a reader scanning `--list` for the page stack should meet\n // the two together rather than find styling filed between queues and sockets.\n tailwind: tailwindFeature,\n // Immediately after `tailwind`, for the same reason `tailwind` follows `web`:\n // it `requires` it, it appends to the stylesheet that feature creates, and the\n // three of them are one stack a reader should meet in build order.\n shadcn: shadcnFeature,\n // Directly after the web/tailwind/shadcn stack, for the same reason: it\n // `requires` web (it reads the page registry `listRoutablePages()`\n // exposes) and a reader scanning `--list` for the page stack should meet it\n // there rather than filed between queues and sockets.\n sitemap: sitemapFeature,\n devtools: devtoolsFeature,\n herald: heraldFeature,\n queue: queueFeature,\n // Directly after `queue`, for the same reason `tailwind` follows `web`: it\n // needs queue already installed and configured, and a reader scanning\n // `--list` for job-queue features should meet the two together.\n \"bull-board\": bullBoardFeature,\n socket: socketFeature,\n notifications: notificationsFeature,\n access: accessFeature,\n // Login methods for @warlock.js/auth — \"<package>-<vendor>\" like the ai-* entries.\n \"auth-google\": authGoogleFeature,\n \"auth-passkeys\": authPasskeysFeature,\n ai: aiFeature,\n \"ai-openai\": aiOpenaiFeature,\n \"ai-google\": aiGoogleFeature,\n \"ai-anthropic\": aiAnthropicFeature,\n \"ai-bedrock\": aiBedrockFeature,\n \"ai-ollama\": aiOllamaFeature,\n \"ai-tools\": aiToolsFeature,\n \"ai-panoptic\": aiPanopticFeature,\n \"ai-workspace\": aiWorkspaceFeature,\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CA,MAAa,cAAiD;CAC5D,eAAe;CACf,OAAO;CACP,OAAO;CACP,MAAM;CACN,KAAK;CACL,SAAS;CACT,WAAW;CAGX,UAAU;CACV,OAAO;CACP,OAAO;CACP,IAAI;CACJ,MAAM;CACN,KAAK;CAIL,UAAU;CAIV,QAAQ;CAKR,SAAS;CACT,UAAU;CACV,QAAQ;CACR,OAAO;CAIP,cAAc;CACd,QAAQ;CACR,eAAe;CACf,QAAQ;CAER,eAAe;CACf,iBAAiB;CACjB,IAAI;CACJ,aAAa;CACb,aAAa;CACb,gBAAgB;CAChB,cAAc;CACd,aAAa;CACb,YAAY;CACZ,eAAe;CACf,gBAAgB;AAClB"}
@@ -1 +1 @@
1
- {"version":3,"file":"mail.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/mail.feature.ts"],"sourcesContent":["import type { FeatureDefinition } from \"./types\";\r\n\r\nexport const mailFeature: FeatureDefinition = {\r\n description: \"Installs nodemailer for sending emails\",\r\n dependencies: {\r\n nodemailer: \"^8.0.5\",\r\n },\r\n devDependencies: {\r\n \"@types/nodemailer\": \"^8.0.0\",\r\n },\r\n};\r\n"],"mappings":";AAEA,MAAa,cAAiC;CAC5C,aAAa;CACb,cAAc,EACZ,YAAY,SACd;CACA,iBAAiB,EACf,qBAAqB,SACvB;AACF"}
1
+ {"version":3,"file":"mail.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/mail.feature.ts"],"sourcesContent":["import type { FeatureDefinition } from \"./types\";\n\nexport const mailFeature: FeatureDefinition = {\n description: \"Installs nodemailer for sending emails\",\n dependencies: {\n nodemailer: \"^8.0.5\",\n },\n devDependencies: {\n \"@types/nodemailer\": \"^8.0.0\",\n },\n};\n"],"mappings":";AAEA,MAAa,cAAiC;CAC5C,aAAa;CACb,cAAc,EACZ,YAAY,SACd;CACA,iBAAiB,EACf,qBAAqB,SACvB;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"mongodb.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/mongodb.feature.ts"],"sourcesContent":["import type { FeatureDefinition } from \"./types\";\r\n\r\nexport const mongodbFeature: FeatureDefinition = {\r\n description: \"Installs mongodb driver for database driver (Cascade Package)\",\r\n dependencies: {\r\n mongodb: \"^7.0.0\",\r\n },\r\n};\r\n"],"mappings":";AAEA,MAAa,iBAAoC;CAC/C,aAAa;CACb,cAAc,EACZ,SAAS,SACX;AACF"}
1
+ {"version":3,"file":"mongodb.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/mongodb.feature.ts"],"sourcesContent":["import type { FeatureDefinition } from \"./types\";\n\nexport const mongodbFeature: FeatureDefinition = {\n description: \"Installs mongodb driver for database driver (Cascade Package)\",\n dependencies: {\n mongodb: \"^7.0.0\",\n },\n};\n"],"mappings":";AAEA,MAAa,iBAAoC;CAC/C,aAAa;CACb,cAAc,EACZ,SAAS,SACX;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"notifications.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/notifications.feature.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\r\nimport { ensureDirectoryAsync, fileExistsAsync, putFileAsync } from \"@warlock.js/fs\";\r\nimport type { CommandActionData } from \"../../commands/types\";\r\nimport { srcPath } from \"../../utils\";\r\nimport {\r\n notificationControllersStub,\r\n notificationMigrationStub,\r\n notificationModelStub,\r\n notificationRoutesStub,\r\n notificationsConfigStub,\r\n} from \"../stubs\";\r\nimport { migrationTimestamp } from \"./shared/migration-timestamp\";\r\nimport { type FeatureDefinition, INSTALLED_WARLOCK_VERSION } from \"./types\";\r\n\r\nasync function completeNotificationsInstallation(_options: CommandActionData) {\r\n const modelPath = srcPath(\"app/notifications/notification.model.ts\");\r\n\r\n // The model file is the sentinel for \"notifications already scaffolded\" —\r\n // its presence means the migration was created too (timestamped, so we must\r\n // not re-emit a duplicate on a second run).\r\n if (await fileExistsAsync(modelPath)) {\r\n console.log(\r\n `${colors.yellowBright(\"src/app/notifications\")} already scaffolded, skipping model + migration...`,\r\n );\r\n return;\r\n }\r\n\r\n // 1. Notification model — extends the package's DatabaseNotification base.\r\n await ensureDirectoryAsync(srcPath(\"app/notifications\"));\r\n await putFileAsync(modelPath, notificationModelStub);\r\n console.log(`${colors.green(\"✓\")} Created src/app/notifications/notification.model.ts`);\r\n\r\n // 2. Migration — timestamped MM-DD-YYYY_HH-MM-SS prefix so cascade infers its\r\n // createdAt and orders it deterministically (migrate-action discovers\r\n // src/app/*/migrations/*).\r\n await ensureDirectoryAsync(srcPath(\"app/notifications/migrations\"));\r\n\r\n const migrationFile = `${migrationTimestamp()}-notification.migration.ts`;\r\n\r\n await putFileAsync(\r\n srcPath(\"app/notifications/migrations\", migrationFile),\r\n notificationMigrationStub,\r\n );\r\n console.log(`${colors.green(\"✓\")} Created src/app/notifications/migrations/${migrationFile}`);\r\n\r\n // 3. HTTP surface — the in-app read/dismiss endpoints (routes + controllers),\r\n // gated by authMiddleware. Delete if the app exposes notifications another way.\r\n await ensureDirectoryAsync(srcPath(\"app/notifications/controllers\"));\r\n await putFileAsync(\r\n srcPath(\"app/notifications/controllers/notifications.controller.ts\"),\r\n notificationControllersStub,\r\n );\r\n await putFileAsync(srcPath(\"app/notifications/routes.ts\"), notificationRoutesStub);\r\n console.log(`${colors.green(\"✓\")} Created src/app/notifications/routes.ts + controllers`);\r\n}\r\n\r\nexport const notificationsFeature: FeatureDefinition = {\r\n description:\r\n \"Installs @warlock.js/notifications — multi-channel notifications (mail + in-app database). Pulls the mail feature, ejects config/notifications.ts, and scaffolds the Notification model + migration plus the recipient-scoped read/dismiss routes + controllers into src/app/notifications\",\r\n // The ejected config wires a `mail` channel by default (needs nodemailer,\r\n // via the `mail` feature); the scaffolded routes are gated by\r\n // `authMiddleware`, so `@warlock.js/auth` is pulled in too.\r\n requires: [\"mail\"],\r\n dependencies: {\r\n \"@warlock.js/notifications\": INSTALLED_WARLOCK_VERSION,\r\n \"@warlock.js/auth\": INSTALLED_WARLOCK_VERSION,\r\n },\r\n ejectConfig: {\r\n content: notificationsConfigStub,\r\n name: \"notifications\",\r\n },\r\n onExecuting: completeNotificationsInstallation,\r\n};\r\n"],"mappings":";;;;;;;;;AAcA,eAAe,kCAAkC,UAA6B;CAC5E,MAAM,YAAY,QAAQ,yCAAyC;CAKnE,IAAI,MAAM,gBAAgB,SAAS,GAAG;EACpC,QAAQ,IACN,GAAG,OAAO,aAAa,uBAAuB,EAAE,mDAClD;EACA;CACF;CAGA,MAAM,qBAAqB,QAAQ,mBAAmB,CAAC;CACvD,MAAM,aAAa,WAAW,qBAAqB;CACnD,QAAQ,IAAI,GAAG,OAAO,MAAM,GAAG,EAAE,qDAAqD;CAKtF,MAAM,qBAAqB,QAAQ,8BAA8B,CAAC;CAElE,MAAM,gBAAgB,GAAG,mBAAmB,EAAE;CAE9C,MAAM,aACJ,QAAQ,gCAAgC,aAAa,GACrD,yBACF;CACA,QAAQ,IAAI,GAAG,OAAO,MAAM,GAAG,EAAE,4CAA4C,eAAe;CAI5F,MAAM,qBAAqB,QAAQ,+BAA+B,CAAC;CACnE,MAAM,aACJ,QAAQ,2DAA2D,GACnE,2BACF;CACA,MAAM,aAAa,QAAQ,6BAA6B,GAAG,sBAAsB;CACjF,QAAQ,IAAI,GAAG,OAAO,MAAM,GAAG,EAAE,uDAAuD;AAC1F;AAEA,MAAa,uBAA0C;CACrD,aACE;CAIF,UAAU,CAAC,MAAM;CACjB,cAAc;EACZ,6BAA6B;EAC7B,oBAAoB;CACtB;CACA,aAAa;EACX,SAAS;EACT,MAAM;CACR;CACA,aAAa;AACf"}
1
+ {"version":3,"file":"notifications.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/notifications.feature.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\nimport { ensureDirectoryAsync, fileExistsAsync, putFileAsync } from \"@warlock.js/fs\";\nimport type { CommandActionData } from \"../../commands/types\";\nimport { srcPath } from \"../../utils\";\nimport {\n notificationControllersStub,\n notificationMigrationStub,\n notificationModelStub,\n notificationRoutesStub,\n notificationsConfigStub,\n} from \"../stubs\";\nimport { migrationTimestamp } from \"./shared/migration-timestamp\";\nimport { type FeatureDefinition, INSTALLED_WARLOCK_VERSION } from \"./types\";\n\nasync function completeNotificationsInstallation(_options: CommandActionData) {\n const modelPath = srcPath(\"app/notifications/notification.model.ts\");\n\n // The model file is the sentinel for \"notifications already scaffolded\" —\n // its presence means the migration was created too (timestamped, so we must\n // not re-emit a duplicate on a second run).\n if (await fileExistsAsync(modelPath)) {\n console.log(\n `${colors.yellowBright(\"src/app/notifications\")} already scaffolded, skipping model + migration...`,\n );\n return;\n }\n\n // 1. Notification model — extends the package's DatabaseNotification base.\n await ensureDirectoryAsync(srcPath(\"app/notifications\"));\n await putFileAsync(modelPath, notificationModelStub);\n console.log(`${colors.green(\"✓\")} Created src/app/notifications/notification.model.ts`);\n\n // 2. Migration — timestamped MM-DD-YYYY_HH-MM-SS prefix so cascade infers its\n // createdAt and orders it deterministically (migrate-action discovers\n // src/app/*/migrations/*).\n await ensureDirectoryAsync(srcPath(\"app/notifications/migrations\"));\n\n const migrationFile = `${migrationTimestamp()}-notification.migration.ts`;\n\n await putFileAsync(\n srcPath(\"app/notifications/migrations\", migrationFile),\n notificationMigrationStub,\n );\n console.log(`${colors.green(\"✓\")} Created src/app/notifications/migrations/${migrationFile}`);\n\n // 3. HTTP surface — the in-app read/dismiss endpoints (routes + controllers),\n // gated by authMiddleware. Delete if the app exposes notifications another way.\n await ensureDirectoryAsync(srcPath(\"app/notifications/controllers\"));\n await putFileAsync(\n srcPath(\"app/notifications/controllers/notifications.controller.ts\"),\n notificationControllersStub,\n );\n await putFileAsync(srcPath(\"app/notifications/routes.ts\"), notificationRoutesStub);\n console.log(`${colors.green(\"✓\")} Created src/app/notifications/routes.ts + controllers`);\n}\n\nexport const notificationsFeature: FeatureDefinition = {\n description:\n \"Installs @warlock.js/notifications — multi-channel notifications (mail + in-app database). Pulls the mail feature, ejects config/notifications.ts, and scaffolds the Notification model + migration plus the recipient-scoped read/dismiss routes + controllers into src/app/notifications\",\n // The ejected config wires a `mail` channel by default (needs nodemailer,\n // via the `mail` feature); the scaffolded routes are gated by\n // `authMiddleware`, so `@warlock.js/auth` is pulled in too.\n requires: [\"mail\"],\n dependencies: {\n \"@warlock.js/notifications\": INSTALLED_WARLOCK_VERSION,\n \"@warlock.js/auth\": INSTALLED_WARLOCK_VERSION,\n },\n ejectConfig: {\n content: notificationsConfigStub,\n name: \"notifications\",\n },\n onExecuting: completeNotificationsInstallation,\n};\n"],"mappings":";;;;;;;;;AAcA,eAAe,kCAAkC,UAA6B;CAC5E,MAAM,YAAY,QAAQ,yCAAyC;CAKnE,IAAI,MAAM,gBAAgB,SAAS,GAAG;EACpC,QAAQ,IACN,GAAG,OAAO,aAAa,uBAAuB,EAAE,mDAClD;EACA;CACF;CAGA,MAAM,qBAAqB,QAAQ,mBAAmB,CAAC;CACvD,MAAM,aAAa,WAAW,qBAAqB;CACnD,QAAQ,IAAI,GAAG,OAAO,MAAM,GAAG,EAAE,qDAAqD;CAKtF,MAAM,qBAAqB,QAAQ,8BAA8B,CAAC;CAElE,MAAM,gBAAgB,GAAG,mBAAmB,EAAE;CAE9C,MAAM,aACJ,QAAQ,gCAAgC,aAAa,GACrD,yBACF;CACA,QAAQ,IAAI,GAAG,OAAO,MAAM,GAAG,EAAE,4CAA4C,eAAe;CAI5F,MAAM,qBAAqB,QAAQ,+BAA+B,CAAC;CACnE,MAAM,aACJ,QAAQ,2DAA2D,GACnE,2BACF;CACA,MAAM,aAAa,QAAQ,6BAA6B,GAAG,sBAAsB;CACjF,QAAQ,IAAI,GAAG,OAAO,MAAM,GAAG,EAAE,uDAAuD;AAC1F;AAEA,MAAa,uBAA0C;CACrD,aACE;CAIF,UAAU,CAAC,MAAM;CACjB,cAAc;EACZ,6BAA6B;EAC7B,oBAAoB;CACtB;CACA,aAAa;EACX,SAAS;EACT,MAAM;CACR;CACA,aAAa;AACf"}
@@ -1 +1 @@
1
- {"version":3,"file":"postgres.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/postgres.feature.ts"],"sourcesContent":["import type { FeatureDefinition } from \"./types\";\r\n\r\nexport const postgresFeature: FeatureDefinition = {\r\n description: \"Installs pg for Postgres database (Cascade Package)\",\r\n dependencies: {\r\n pg: \"^8.11.0\",\r\n },\r\n};\r\n"],"mappings":";AAEA,MAAa,kBAAqC;CAChD,aAAa;CACb,cAAc,EACZ,IAAI,UACN;AACF"}
1
+ {"version":3,"file":"postgres.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/postgres.feature.ts"],"sourcesContent":["import type { FeatureDefinition } from \"./types\";\n\nexport const postgresFeature: FeatureDefinition = {\n description: \"Installs pg for Postgres database (Cascade Package)\",\n dependencies: {\n pg: \"^8.11.0\",\n },\n};\n"],"mappings":";AAEA,MAAa,kBAAqC;CAChD,aAAa;CACb,cAAc,EACZ,IAAI,UACN;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"react-email.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/react-email.feature.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\r\nimport { ensureDirectoryAsync, fileExistsAsync, putFileAsync } from \"@warlock.js/fs\";\r\nimport type { CommandActionData } from \"../../commands/types\";\r\nimport { rootPath } from \"../../utils\";\r\nimport { patchTsconfigInclude } from \"./shared/patch-tsconfig-include\";\r\nimport type { FeatureDefinition } from \"./types\";\r\n\r\nasync function completeReactEmailInstallation(_options: CommandActionData) {\r\n // 1. Create emails/ folder with a sample component\r\n const emailsFolderPath = rootPath(\"emails\");\r\n const sampleEmailPath = rootPath(\"emails/welcome-email.tsx\");\r\n\r\n if (!(await fileExistsAsync(sampleEmailPath))) {\r\n await ensureDirectoryAsync(emailsFolderPath);\r\n await putFileAsync(\r\n sampleEmailPath,\r\n `import { Body, Container, Head, Html, Text } from \"@react-email/components\";\r\nimport { Tailwind } from \"@react-email/tailwind\";\r\n\r\ninterface WelcomeEmailProps {\r\n name: string;\r\n}\r\n\r\n/**\r\n * Sample welcome email component.\r\n * Preview with: yarn email:preview\r\n */\r\nexport default function WelcomeEmail({ name }: WelcomeEmailProps) {\r\n return (\r\n <Html>\r\n <Head />\r\n <Tailwind>\r\n <Body className=\"bg-gray-100 font-sans\">\r\n <Container className=\"mx-auto max-w-xl py-8 px-4\">\r\n <Text className=\"text-2xl font-bold text-gray-900\">\r\n Welcome, {name}!\r\n </Text>\r\n <Text className=\"text-gray-600 mt-2\">\r\n You're all set. We're glad to have you on board.\r\n </Text>\r\n </Container>\r\n </Body>\r\n </Tailwind>\r\n </Html>\r\n );\r\n}\r\n`,\r\n );\r\n console.log(`${colors.green(\"✓\")} Created emails/welcome-email.tsx`);\r\n }\r\n\r\n // 2. Patch tsconfig.json — add \"emails\" to include if missing.\r\n await patchTsconfigInclude(\r\n \"emails\",\r\n \"Without it, the email components under emails/ are outside the project and do not typecheck.\",\r\n );\r\n}\r\n\r\nexport const reactEmailFeature: FeatureDefinition = {\r\n description: \"Installs react-email for building email templates with React and Tailwind\",\r\n requires: [\"mail\", \"react\"],\r\n dependencies: {\r\n \"react-email\": \"^5.2.10\",\r\n \"@react-email/components\": \"^1.0.11\",\r\n \"@react-email/render\": \"^2.0.5\",\r\n \"@react-email/tailwind\": \"^2.0.7\",\r\n },\r\n devDependencies: {\r\n \"@react-email/preview-server\": \"5.2.10\",\r\n },\r\n script: {\r\n \"email:preview\": \"npx react-email dev\",\r\n },\r\n onExecuting: completeReactEmailInstallation,\r\n};\r\n"],"mappings":";;;;;;;AAOA,eAAe,+BAA+B,UAA6B;CAEzE,MAAM,mBAAmB,SAAS,QAAQ;CAC1C,MAAM,kBAAkB,SAAS,0BAA0B;CAE3D,IAAI,CAAE,MAAM,gBAAgB,eAAe,GAAI;EAC7C,MAAM,qBAAqB,gBAAgB;EAC3C,MAAM,aACJ,iBACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BF;EACA,QAAQ,IAAI,GAAG,OAAO,MAAM,GAAG,EAAE,kCAAkC;CACrE;CAGA,MAAM,qBACJ,UACA,8FACF;AACF;AAEA,MAAa,oBAAuC;CAClD,aAAa;CACb,UAAU,CAAC,QAAQ,OAAO;CAC1B,cAAc;EACZ,eAAe;EACf,2BAA2B;EAC3B,uBAAuB;EACvB,yBAAyB;CAC3B;CACA,iBAAiB,EACf,+BAA+B,SACjC;CACA,QAAQ,EACN,iBAAiB,sBACnB;CACA,aAAa;AACf"}
1
+ {"version":3,"file":"react-email.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/react-email.feature.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\nimport { ensureDirectoryAsync, fileExistsAsync, putFileAsync } from \"@warlock.js/fs\";\nimport type { CommandActionData } from \"../../commands/types\";\nimport { rootPath } from \"../../utils\";\nimport { patchTsconfigInclude } from \"./shared/patch-tsconfig-include\";\nimport type { FeatureDefinition } from \"./types\";\n\nasync function completeReactEmailInstallation(_options: CommandActionData) {\n // 1. Create emails/ folder with a sample component\n const emailsFolderPath = rootPath(\"emails\");\n const sampleEmailPath = rootPath(\"emails/welcome-email.tsx\");\n\n if (!(await fileExistsAsync(sampleEmailPath))) {\n await ensureDirectoryAsync(emailsFolderPath);\n await putFileAsync(\n sampleEmailPath,\n `import { Body, Container, Head, Html, Text } from \"@react-email/components\";\nimport { Tailwind } from \"@react-email/tailwind\";\n\ninterface WelcomeEmailProps {\n name: string;\n}\n\n/**\n * Sample welcome email component.\n * Preview with: yarn email:preview\n */\nexport default function WelcomeEmail({ name }: WelcomeEmailProps) {\n return (\n <Html>\n <Head />\n <Tailwind>\n <Body className=\"bg-gray-100 font-sans\">\n <Container className=\"mx-auto max-w-xl py-8 px-4\">\n <Text className=\"text-2xl font-bold text-gray-900\">\n Welcome, {name}!\n </Text>\n <Text className=\"text-gray-600 mt-2\">\n You're all set. We're glad to have you on board.\n </Text>\n </Container>\n </Body>\n </Tailwind>\n </Html>\n );\n}\n`,\n );\n console.log(`${colors.green(\"✓\")} Created emails/welcome-email.tsx`);\n }\n\n // 2. Patch tsconfig.json — add \"emails\" to include if missing.\n await patchTsconfigInclude(\n \"emails\",\n \"Without it, the email components under emails/ are outside the project and do not typecheck.\",\n );\n}\n\nexport const reactEmailFeature: FeatureDefinition = {\n description: \"Installs react-email for building email templates with React and Tailwind\",\n requires: [\"mail\", \"react\"],\n dependencies: {\n \"react-email\": \"^5.2.10\",\n \"@react-email/components\": \"^1.0.11\",\n \"@react-email/render\": \"^2.0.5\",\n \"@react-email/tailwind\": \"^2.0.7\",\n },\n devDependencies: {\n \"@react-email/preview-server\": \"5.2.10\",\n },\n script: {\n \"email:preview\": \"npx react-email dev\",\n },\n onExecuting: completeReactEmailInstallation,\n};\n"],"mappings":";;;;;;;AAOA,eAAe,+BAA+B,UAA6B;CAEzE,MAAM,mBAAmB,SAAS,QAAQ;CAC1C,MAAM,kBAAkB,SAAS,0BAA0B;CAE3D,IAAI,CAAE,MAAM,gBAAgB,eAAe,GAAI;EAC7C,MAAM,qBAAqB,gBAAgB;EAC3C,MAAM,aACJ,iBACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BF;EACA,QAAQ,IAAI,GAAG,OAAO,MAAM,GAAG,EAAE,kCAAkC;CACrE;CAGA,MAAM,qBACJ,UACA,8FACF;AACF;AAEA,MAAa,oBAAuC;CAClD,aAAa;CACb,UAAU,CAAC,QAAQ,OAAO;CAC1B,cAAc;EACZ,eAAe;EACf,2BAA2B;EAC3B,uBAAuB;EACvB,yBAAyB;CAC3B;CACA,iBAAiB,EACf,+BAA+B,SACjC;CACA,QAAQ,EACN,iBAAiB,sBACnB;CACA,aAAa;AACf"}
@@ -1 +1 @@
1
- {"version":3,"file":"react.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/react.feature.ts"],"sourcesContent":["import type { FeatureDefinition } from \"./types\";\r\n\r\nexport const reactFeature: FeatureDefinition = {\r\n description:\r\n \"Installs React and React dom for rendering React components (non-interactive), useful for sending mails and generating HTML\",\r\n dependencies: {\r\n react: \"^19.2.3\",\r\n \"react-dom\": \"^19.2.3\",\r\n },\r\n devDependencies: {\r\n \"@types/react\": \"^19.2.7\",\r\n \"@types/react-dom\": \"^19.2.3\",\r\n },\r\n};\r\n"],"mappings":";AAEA,MAAa,eAAkC;CAC7C,aACE;CACF,cAAc;EACZ,OAAO;EACP,aAAa;CACf;CACA,iBAAiB;EACf,gBAAgB;EAChB,oBAAoB;CACtB;AACF"}
1
+ {"version":3,"file":"react.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/react.feature.ts"],"sourcesContent":["import type { FeatureDefinition } from \"./types\";\n\nexport const reactFeature: FeatureDefinition = {\n description:\n \"Installs React and React dom for rendering React components (non-interactive), useful for sending mails and generating HTML\",\n dependencies: {\n react: \"^19.2.3\",\n \"react-dom\": \"^19.2.3\",\n },\n devDependencies: {\n \"@types/react\": \"^19.2.7\",\n \"@types/react-dom\": \"^19.2.3\",\n },\n};\n"],"mappings":";AAEA,MAAa,eAAkC;CAC7C,aACE;CACF,cAAc;EACZ,OAAO;EACP,aAAa;CACf;CACA,iBAAiB;EACf,gBAAgB;EAChB,oBAAoB;CACtB;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"redis.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/redis.feature.ts"],"sourcesContent":["import type { FeatureDefinition } from \"./types\";\r\n\r\nexport const redisFeature: FeatureDefinition = {\r\n description: \"Installs redis for Redis cache driver (Cache Package)\",\r\n dependencies: {\r\n redis: \"^4.6.13\",\r\n },\r\n};\r\n"],"mappings":";AAEA,MAAa,eAAkC;CAC7C,aAAa;CACb,cAAc,EACZ,OAAO,UACT;AACF"}
1
+ {"version":3,"file":"redis.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/redis.feature.ts"],"sourcesContent":["import type { FeatureDefinition } from \"./types\";\n\nexport const redisFeature: FeatureDefinition = {\n description: \"Installs redis for Redis cache driver (Cache Package)\",\n dependencies: {\n redis: \"^4.6.13\",\n },\n};\n"],"mappings":";AAEA,MAAa,eAAkC;CAC7C,aAAa;CACb,cAAc,EACZ,OAAO,UACT;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"s3.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/s3.feature.ts"],"sourcesContent":["import type { FeatureDefinition } from \"./types\";\r\n\r\nexport const s3Feature: FeatureDefinition = {\r\n description: \"Installs AWS SDK for Cloud storage (Storage Package)\",\r\n dependencies: {\r\n \"@aws-sdk/client-s3\": \"^3.955.0\",\r\n \"@aws-sdk/lib-storage\": \"^3.955.0\",\r\n \"@aws-sdk/s3-request-presigner\": \"^3.955.0\",\r\n },\r\n};\r\n"],"mappings":";AAEA,MAAa,YAA+B;CAC1C,aAAa;CACb,cAAc;EACZ,sBAAsB;EACtB,wBAAwB;EACxB,iCAAiC;CACnC;AACF"}
1
+ {"version":3,"file":"s3.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/s3.feature.ts"],"sourcesContent":["import type { FeatureDefinition } from \"./types\";\n\nexport const s3Feature: FeatureDefinition = {\n description: \"Installs AWS SDK for Cloud storage (Storage Package)\",\n dependencies: {\n \"@aws-sdk/client-s3\": \"^3.955.0\",\n \"@aws-sdk/lib-storage\": \"^3.955.0\",\n \"@aws-sdk/s3-request-presigner\": \"^3.955.0\",\n },\n};\n"],"mappings":";AAEA,MAAa,YAA+B;CAC1C,aAAa;CACb,cAAc;EACZ,sBAAsB;EACtB,wBAAwB;EACxB,iCAAiC;CACnC;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"scheduler.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/scheduler.feature.ts"],"sourcesContent":["import { type FeatureDefinition, INSTALLED_WARLOCK_VERSION } from \"./types\";\r\n\r\nexport const schedulerFeature: FeatureDefinition = {\r\n description: \"Installs warlock scheduler for scheduling tasks\",\r\n dependencies: {\r\n \"@warlock.js/scheduler\": INSTALLED_WARLOCK_VERSION,\r\n },\r\n};\r\n"],"mappings":";;;AAEA,MAAa,mBAAsC;CACjD,aAAa;CACb,cAAc,EACZ,yBAAyB,0BAC3B;AACF"}
1
+ {"version":3,"file":"scheduler.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/scheduler.feature.ts"],"sourcesContent":["import { type FeatureDefinition, INSTALLED_WARLOCK_VERSION } from \"./types\";\n\nexport const schedulerFeature: FeatureDefinition = {\n description: \"Installs warlock scheduler for scheduling tasks\",\n dependencies: {\n \"@warlock.js/scheduler\": INSTALLED_WARLOCK_VERSION,\n },\n};\n"],"mappings":";;;AAEA,MAAa,mBAAsC;CACjD,aAAa;CACb,cAAc,EACZ,yBAAyB,0BAC3B;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"ses.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/ses.feature.ts"],"sourcesContent":["import type { FeatureDefinition } from \"./types\";\r\n\r\nexport const sesFeature: FeatureDefinition = {\r\n description: \"Installs AWS SES SDK for sending emails via Amazon SES\",\r\n dependencies: {\r\n \"@aws-sdk/client-sesv2\": \"^3.1025.0\",\r\n },\r\n};\r\n"],"mappings":";AAEA,MAAa,aAAgC;CAC3C,aAAa;CACb,cAAc,EACZ,yBAAyB,YAC3B;AACF"}
1
+ {"version":3,"file":"ses.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/ses.feature.ts"],"sourcesContent":["import type { FeatureDefinition } from \"./types\";\n\nexport const sesFeature: FeatureDefinition = {\n description: \"Installs AWS SES SDK for sending emails via Amazon SES\",\n dependencies: {\n \"@aws-sdk/client-sesv2\": \"^3.1025.0\",\n },\n};\n"],"mappings":";AAEA,MAAa,aAAgC;CAC3C,aAAa;CACb,cAAc,EACZ,yBAAyB,YAC3B;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"socket.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/socket.feature.ts"],"sourcesContent":["import { socketConfigStub } from \"../stubs\";\r\nimport type { FeatureDefinition } from \"./types\";\r\n\r\nexport const socketFeature: FeatureDefinition = {\r\n description: \"Installs socket.io for the realtime socket server (Socket Connector)\",\r\n dependencies: {\r\n \"socket.io\": \"^4.8.3\",\r\n },\r\n ejectConfig: {\r\n content: socketConfigStub,\r\n name: \"socket\",\r\n },\r\n};\r\n"],"mappings":";;;AAGA,MAAa,gBAAmC;CAC9C,aAAa;CACb,cAAc,EACZ,aAAa,SACf;CACA,aAAa;EACX,SAAS;EACT,MAAM;CACR;AACF"}
1
+ {"version":3,"file":"socket.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/socket.feature.ts"],"sourcesContent":["import { socketConfigStub } from \"../stubs\";\nimport type { FeatureDefinition } from \"./types\";\n\nexport const socketFeature: FeatureDefinition = {\n description: \"Installs socket.io for the realtime socket server (Socket Connector)\",\n dependencies: {\n \"socket.io\": \"^4.8.3\",\n },\n ejectConfig: {\n content: socketConfigStub,\n name: \"socket\",\n },\n};\n"],"mappings":";;;AAGA,MAAa,gBAAmC;CAC9C,aAAa;CACb,cAAc,EACZ,aAAa,SACf;CACA,aAAa;EACX,SAAS;EACT,MAAM;CACR;AACF"}
@@ -35,18 +35,22 @@ export async function teardown() {
35
35
  * registry with it, so this pair boots and closes the test runtime once per
36
36
  * test file.
37
37
  *
38
- * setupTest() is called with no options on purpose: an explicit connectors
38
+ * setupTest() gets no connectors option on purpose: an explicit connectors
39
39
  * value outranks tests.connectors from src/config/tests.ts, so passing one
40
40
  * here would erase your project config. Omitting it leaves the config in
41
41
  * charge.
42
42
  *
43
+ * importModule makes Warlock load your app modules (config, routes, ...)
44
+ * through THIS file's import(), which Vitest handles. Tests and the framework
45
+ * then share one copy of every class, so "owner instanceof User" works.
46
+ *
43
47
  * afterAll(teardownTest) is the other half of the pair: whoever calls
44
48
  * setupTest() owns closing it in the same runtime context.
45
49
  */
46
50
  import { setupTest, teardownTest } from "@warlock.js/core/tests";
47
51
  import { afterAll } from "vitest";
48
52
 
49
- await setupTest();
53
+ await setupTest({ importModule: (file) => import(file) });
50
54
 
51
55
  afterAll(teardownTest);
52
56
  `);
@@ -1 +1 @@
1
- {"version":3,"file":"test.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/test.feature.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\r\nimport { fileExistsAsync, putFileAsync } from \"@warlock.js/fs\";\r\nimport type { CommandActionData } from \"../../commands/types\";\r\nimport { rootPath, srcPath } from \"../../utils\";\r\nimport type { FeatureDefinition } from \"./types\";\r\nimport { VITE_RANGE } from \"./web.feature\";\r\n\r\nasync function completeTestInstallation(options: CommandActionData) {\r\n // Create test-global-setup.ts (runs once before all tests)\r\n const testGlobalSetupPath = srcPath(\"test-global-setup.ts\");\r\n const testGlobalSetupExists = await fileExistsAsync(testGlobalSetupPath);\r\n\r\n if (!testGlobalSetupExists) {\r\n await putFileAsync(\r\n testGlobalSetupPath,\r\n `/**\r\n * Global Test Setup\r\n *\r\n * Runs ONCE before all test workers.\r\n * Starts the HTTP server for integration tests.\r\n */\r\nimport { startHttpTestServer, stopHttpTestServer } from \"@warlock.js/core/tests\";\r\n\r\nexport async function setup() {\r\n await startHttpTestServer();\r\n}\r\n\r\nexport async function teardown() {\r\n await stopHttpTestServer();\r\n}\r\n`,\r\n );\r\n console.log(`${colors.green(\"✓\")} Created src/test-global-setup.ts`);\r\n }\r\n\r\n // Create test-setup.ts (runs before EVERY test file)\r\n const testSetupPath = srcPath(\"test-setup.ts\");\r\n const testSetupExists = await fileExistsAsync(testSetupPath);\r\n\r\n if (!testSetupExists) {\r\n await putFileAsync(\r\n testSetupPath,\r\n `/**\r\n * Test Setup - runs before EVERY test file\r\n *\r\n * Vitest runs setupFiles before each test file and rebuilds the module\r\n * registry with it, so this pair boots and closes the test runtime once per\r\n * test file.\r\n *\r\n * setupTest() is called with no options on purpose: an explicit connectors\r\n * value outranks tests.connectors from src/config/tests.ts, so passing one\r\n * here would erase your project config. Omitting it leaves the config in\r\n * charge.\r\n *\r\n * afterAll(teardownTest) is the other half of the pair: whoever calls\r\n * setupTest() owns closing it in the same runtime context.\r\n */\r\nimport { setupTest, teardownTest } from \"@warlock.js/core/tests\";\r\nimport { afterAll } from \"vitest\";\r\n\r\nawait setupTest();\r\n\r\nafterAll(teardownTest);\r\n`,\r\n );\r\n console.log(`${colors.green(\"✓\")} Created src/test-setup.ts`);\r\n }\r\n\r\n // Create vite.config.ts\r\n const viteConfigPath = rootPath(\"vite.config.ts\");\r\n const viteConfigExists = await fileExistsAsync(viteConfigPath);\r\n\r\n if (!viteConfigExists) {\r\n await putFileAsync(\r\n viteConfigPath,\r\n `import { lowerStage3Decorators } from \"@warlock.js/core/vite\";\r\nimport mongezVite from \"@mongez/vite\";\r\nimport { defineConfig } from \"vitest/config\";\r\n\r\nexport default defineConfig({\r\n // lowerStage3Decorators MUST come first: it lowers native (@RegisterModel, …)\r\n // decorators with esbuild before oxc / the SSR rewrite can mangle them, so\r\n // decorated Cascade models load under Vitest.\r\n plugins: [lowerStage3Decorators(), mongezVite()],\r\n test: {\r\n globalSetup: \"./src/test-global-setup.ts\", // HTTP server - runs once\r\n setupFiles: [\"./src/test-setup.ts\"], // DB/cache - runs per test file\r\n environment: \"node\",\r\n globals: false,\r\n include: [\"src/app/**/*.test.ts\"],\r\n },\r\n});\r\n`,\r\n );\r\n console.log(`${colors.green(\"✓\")} Created vite.config.ts`);\r\n }\r\n}\r\n\r\nexport const testFeature: FeatureDefinition = {\r\n description: \"Installs warlock test for testing\",\r\n onExecuting: completeTestInstallation,\r\n script: {\r\n test: \"vitest run\",\r\n \"test:coverage\": \"vitest run --coverage\",\r\n \"test:ui\": \"vitest --ui\",\r\n \"test:watch\": \"vitest --watch\",\r\n },\r\n devDependencies: {\r\n \"@mongez/vite\": \"^2.0.4\",\r\n vite: VITE_RANGE,\r\n vitest: \"^4.1.8\",\r\n \"@vitest/coverage-v8\": \"^4.1.8\",\r\n },\r\n};\r\n"],"mappings":";;;;;;;AAOA,eAAe,yBAAyB,SAA4B;CAElE,MAAM,sBAAsB,QAAQ,sBAAsB;CAG1D,IAAI,CAAC,MAF+B,gBAAgB,mBAAmB,GAE3C;EAC1B,MAAM,aACJ,qBACA;;;;;;;;;;;;;;;CAgBF;EACA,QAAQ,IAAI,GAAG,OAAO,MAAM,GAAG,EAAE,kCAAkC;CACrE;CAGA,MAAM,gBAAgB,QAAQ,eAAe;CAG7C,IAAI,CAAC,MAFyB,gBAAgB,aAAa,GAErC;EACpB,MAAM,aACJ,eACA;;;;;;;;;;;;;;;;;;;;;CAsBF;EACA,QAAQ,IAAI,GAAG,OAAO,MAAM,GAAG,EAAE,2BAA2B;CAC9D;CAGA,MAAM,iBAAiB,SAAS,gBAAgB;CAGhD,IAAI,CAAC,MAF0B,gBAAgB,cAAc,GAEtC;EACrB,MAAM,aACJ,gBACA;;;;;;;;;;;;;;;;;CAkBF;EACA,QAAQ,IAAI,GAAG,OAAO,MAAM,GAAG,EAAE,wBAAwB;CAC3D;AACF;AAEA,MAAa,cAAiC;CAC5C,aAAa;CACb,aAAa;CACb,QAAQ;EACN,MAAM;EACN,iBAAiB;EACjB,WAAW;EACX,cAAc;CAChB;CACA,iBAAiB;EACf,gBAAgB;EAChB,MAAM;EACN,QAAQ;EACR,uBAAuB;CACzB;AACF"}
1
+ {"version":3,"file":"test.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/test.feature.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\nimport { fileExistsAsync, putFileAsync } from \"@warlock.js/fs\";\nimport type { CommandActionData } from \"../../commands/types\";\nimport { rootPath, srcPath } from \"../../utils\";\nimport type { FeatureDefinition } from \"./types\";\nimport { VITE_RANGE } from \"./web.feature\";\n\nasync function completeTestInstallation(options: CommandActionData) {\n // Create test-global-setup.ts (runs once before all tests)\n const testGlobalSetupPath = srcPath(\"test-global-setup.ts\");\n const testGlobalSetupExists = await fileExistsAsync(testGlobalSetupPath);\n\n if (!testGlobalSetupExists) {\n await putFileAsync(\n testGlobalSetupPath,\n `/**\n * Global Test Setup\n *\n * Runs ONCE before all test workers.\n * Starts the HTTP server for integration tests.\n */\nimport { startHttpTestServer, stopHttpTestServer } from \"@warlock.js/core/tests\";\n\nexport async function setup() {\n await startHttpTestServer();\n}\n\nexport async function teardown() {\n await stopHttpTestServer();\n}\n`,\n );\n console.log(`${colors.green(\"✓\")} Created src/test-global-setup.ts`);\n }\n\n // Create test-setup.ts (runs before EVERY test file)\n const testSetupPath = srcPath(\"test-setup.ts\");\n const testSetupExists = await fileExistsAsync(testSetupPath);\n\n if (!testSetupExists) {\n await putFileAsync(\n testSetupPath,\n `/**\n * Test Setup - runs before EVERY test file\n *\n * Vitest runs setupFiles before each test file and rebuilds the module\n * registry with it, so this pair boots and closes the test runtime once per\n * test file.\n *\n * setupTest() gets no connectors option on purpose: an explicit connectors\n * value outranks tests.connectors from src/config/tests.ts, so passing one\n * here would erase your project config. Omitting it leaves the config in\n * charge.\n *\n * importModule makes Warlock load your app modules (config, routes, ...)\n * through THIS file's import(), which Vitest handles. Tests and the framework\n * then share one copy of every class, so \"owner instanceof User\" works.\n *\n * afterAll(teardownTest) is the other half of the pair: whoever calls\n * setupTest() owns closing it in the same runtime context.\n */\nimport { setupTest, teardownTest } from \"@warlock.js/core/tests\";\nimport { afterAll } from \"vitest\";\n\nawait setupTest({ importModule: (file) => import(file) });\n\nafterAll(teardownTest);\n`,\n );\n console.log(`${colors.green(\"✓\")} Created src/test-setup.ts`);\n }\n\n // Create vite.config.ts\n const viteConfigPath = rootPath(\"vite.config.ts\");\n const viteConfigExists = await fileExistsAsync(viteConfigPath);\n\n if (!viteConfigExists) {\n await putFileAsync(\n viteConfigPath,\n `import { lowerStage3Decorators } from \"@warlock.js/core/vite\";\nimport mongezVite from \"@mongez/vite\";\nimport { defineConfig } from \"vitest/config\";\n\nexport default defineConfig({\n // lowerStage3Decorators MUST come first: it lowers native (@RegisterModel, …)\n // decorators with esbuild before oxc / the SSR rewrite can mangle them, so\n // decorated Cascade models load under Vitest.\n plugins: [lowerStage3Decorators(), mongezVite()],\n test: {\n globalSetup: \"./src/test-global-setup.ts\", // HTTP server - runs once\n setupFiles: [\"./src/test-setup.ts\"], // DB/cache - runs per test file\n environment: \"node\",\n globals: false,\n include: [\"src/app/**/*.test.ts\"],\n },\n});\n`,\n );\n console.log(`${colors.green(\"✓\")} Created vite.config.ts`);\n }\n}\n\nexport const testFeature: FeatureDefinition = {\n description: \"Installs warlock test for testing\",\n onExecuting: completeTestInstallation,\n script: {\n test: \"vitest run\",\n \"test:coverage\": \"vitest run --coverage\",\n \"test:ui\": \"vitest --ui\",\n \"test:watch\": \"vitest --watch\",\n },\n devDependencies: {\n \"@mongez/vite\": \"^2.0.4\",\n vite: VITE_RANGE,\n vitest: \"^4.1.8\",\n \"@vitest/coverage-v8\": \"^4.1.8\",\n },\n};\n"],"mappings":";;;;;;;AAOA,eAAe,yBAAyB,SAA4B;CAElE,MAAM,sBAAsB,QAAQ,sBAAsB;CAG1D,IAAI,CAAC,MAF+B,gBAAgB,mBAAmB,GAE3C;EAC1B,MAAM,aACJ,qBACA;;;;;;;;;;;;;;;CAgBF;EACA,QAAQ,IAAI,GAAG,OAAO,MAAM,GAAG,EAAE,kCAAkC;CACrE;CAGA,MAAM,gBAAgB,QAAQ,eAAe;CAG7C,IAAI,CAAC,MAFyB,gBAAgB,aAAa,GAErC;EACpB,MAAM,aACJ,eACA;;;;;;;;;;;;;;;;;;;;;;;;;CA0BF;EACA,QAAQ,IAAI,GAAG,OAAO,MAAM,GAAG,EAAE,2BAA2B;CAC9D;CAGA,MAAM,iBAAiB,SAAS,gBAAgB;CAGhD,IAAI,CAAC,MAF0B,gBAAgB,cAAc,GAEtC;EACrB,MAAM,aACJ,gBACA;;;;;;;;;;;;;;;;;CAkBF;EACA,QAAQ,IAAI,GAAG,OAAO,MAAM,GAAG,EAAE,wBAAwB;CAC3D;AACF;AAEA,MAAa,cAAiC;CAC5C,aAAa;CACb,aAAa;CACb,QAAQ;EACN,MAAM;EACN,iBAAiB;EACjB,WAAW;EACX,cAAc;CAChB;CACA,iBAAiB;EACf,gBAAgB;EAChB,MAAM;EACN,QAAQ;EACR,uBAAuB;CACzB;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/types.ts"],"sourcesContent":["import type { CommandActionData } from \"../../commands/types\";\r\n\r\n/**\r\n * Internal placeholder for an @warlock.js dependency whose concrete version\r\n * comes from the installed Core package at command execution time.\r\n *\r\n * This is deliberately not a valid package-manager range. If a future code\r\n * path forgets to resolve it, installation fails loudly instead of silently\r\n * falling back to a stale framework major copied into a feature definition.\r\n */\r\nexport const INSTALLED_WARLOCK_VERSION = \"__INSTALLED_WARLOCK_VERSION__\";\r\n\r\n/**\r\n * One entry in the feature registry.\r\n *\r\n * Every feature owns a module of its own that exports a single value of this\r\n * shape, with its `onExecuting` body beside it; `features/index.ts` is only the\r\n * ordered index that collects them.\r\n */\r\nexport type FeatureDefinition = {\r\n dependencies?: Record<string, string>;\r\n devDependencies?: Record<string, string>;\r\n description: string;\r\n requires?: string[];\r\n script?: Record<string, string>;\r\n onExecuting?: (options: CommandActionData) => Promise<any>;\r\n ejectConfig?: {\r\n content: string;\r\n name: string;\r\n };\r\n};\r\n"],"mappings":";;;;;;;;;AAUA,MAAa,4BAA4B"}
1
+ {"version":3,"file":"types.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/types.ts"],"sourcesContent":["import type { CommandActionData } from \"../../commands/types\";\n\n/**\n * Internal placeholder for an @warlock.js dependency whose concrete version\n * comes from the installed Core package at command execution time.\n *\n * This is deliberately not a valid package-manager range. If a future code\n * path forgets to resolve it, installation fails loudly instead of silently\n * falling back to a stale framework major copied into a feature definition.\n */\nexport const INSTALLED_WARLOCK_VERSION = \"__INSTALLED_WARLOCK_VERSION__\";\n\n/**\n * One entry in the feature registry.\n *\n * Every feature owns a module of its own that exports a single value of this\n * shape, with its `onExecuting` body beside it; `features/index.ts` is only the\n * ordered index that collects them.\n */\nexport type FeatureDefinition = {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n description: string;\n requires?: string[];\n script?: Record<string, string>;\n onExecuting?: (options: CommandActionData) => Promise<any>;\n ejectConfig?: {\n content: string;\n name: string;\n };\n};\n"],"mappings":";;;;;;;;;AAUA,MAAa,4BAA4B"}
@@ -1 +1 @@
1
- {"version":3,"file":"web.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/web.feature.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\r\nimport { ensureDirectoryAsync, fileExistsAsync, getFileAsync, putFileAsync } from \"@warlock.js/fs\";\r\nimport type { CommandActionData } from \"../../commands/types\";\r\nimport { rootPath, srcPath } from \"../../utils\";\r\nimport { insertConnectorEntry } from \"./shared/insert-connector-entry\";\r\nimport { relocateConflictingHomeRoute } from \"./shared/relocate-conflicting-home-route\";\r\nimport { resolveContactScaffold } from \"./shared/resolve-contact-scaffold\";\r\nimport {\r\n webContactControllerStub,\r\n webContactRoutesStub,\r\n webHomePageStub,\r\n webHomeRegisterStub,\r\n webRootStub,\r\n} from \"../stubs\";\r\nimport { type FeatureDefinition, INSTALLED_WARLOCK_VERSION } from \"./types\";\r\n\r\n/** The one vite range shared by every feature (web's peer range is `>=7.3.5 <8`). */\r\nexport const VITE_RANGE = \"^7.3.5\";\r\n\r\n/**\r\n * Register the WebConnector in `warlock.config.ts`, and ONLY there.\r\n *\r\n * It belongs to the config array or to app code, never both. Both halves are\r\n * registered before app code loads — the CLI preloader in dev, the generated\r\n * entry in production — so also calling `connectorsManager.register(...)` in\r\n * `src/app/main.ts` boots the connector twice and installs every page route\r\n * twice. That surfaces at PRODUCTION boot as `Route name \"...\" is already\r\n * taken`, because pages and API routes share one route-name namespace.\r\n *\r\n * The config array is the half to prefer: `warlock build` reads the same array\r\n * to drain each connector's build contribution, so \"built for\" and \"boots with\"\r\n * cannot drift.\r\n *\r\n * String surgery rather than a TypeScript parse: `warlock.config.ts` is an\r\n * app-owned file that may carry any formatting, and a parse-and-print would\r\n * reformat the parts we did not come to change.\r\n */\r\nasync function registerWebConnector(): Promise<void> {\r\n const configPath = rootPath(\"warlock.config.ts\");\r\n\r\n if (!(await fileExistsAsync(configPath))) {\r\n console.log(\r\n `${colors.yellowBright(\"warlock.config.ts\")} not found — add this yourself:\\n` +\r\n ` import { webConnector } from \"@warlock.js/web/connector\";\\n` +\r\n ` export default defineConfig({ connectors: [webConnector()] });`,\r\n );\r\n\r\n return;\r\n }\r\n\r\n const current = await getFileAsync(configPath);\r\n\r\n if (current.includes(\"webConnector\")) {\r\n console.log(`${colors.yellowBright(\"webConnector\")} already registered, skipping...`);\r\n\r\n return;\r\n }\r\n\r\n const importLine = 'import { webConnector } from \"@warlock.js/web/connector\";';\r\n let next = current.includes(importLine) ? current : `${importLine}\\n${current}`;\r\n\r\n // An existing `connectors: [` gains one entry; otherwise the key is added to\r\n // the object `defineConfig` receives.\r\n const insertion = insertConnectorEntry(next, \"webConnector()\");\r\n\r\n if (insertion.status === \"already-present\") {\r\n return;\r\n }\r\n\r\n if (insertion.status === \"added\") {\r\n next = insertion.next;\r\n } else if (next.includes(\"defineConfig({\")) {\r\n next = next.replace(\"defineConfig({\", \"defineConfig({\\n connectors: [webConnector()],\");\r\n } else {\r\n console.log(\r\n `${colors.yellowBright(\"warlock.config.ts\")} has no recognisable defineConfig({...}) — ` +\r\n \"add `connectors: [webConnector()]` yourself.\",\r\n );\r\n\r\n return;\r\n }\r\n\r\n await putFileAsync(configPath, next);\r\n console.log(`${colors.green(\"✓\")} Registered webConnector in warlock.config.ts`);\r\n}\r\n\r\n/**\r\n * Scaffold the smallest page layer that renders, and register the connector.\r\n *\r\n * `src/web/root.tsx` is the sentinel for \"already scaffolded\" — the framework\r\n * ships a default root, so its presence means a human has been here.\r\n */\r\nasync function completeWebInstallation(_options: CommandActionData) {\r\n const rootFile = srcPath(\"web/root.tsx\");\r\n\r\n if (await fileExistsAsync(rootFile)) {\r\n console.log(`${colors.yellowBright(\"src/web\")} already scaffolded, skipping...`);\r\n } else {\r\n await ensureDirectoryAsync(srcPath(\"web\"));\r\n await putFileAsync(rootFile, webRootStub);\r\n console.log(`${colors.green(\"✓\")} Created src/web/root.tsx`);\r\n\r\n const collision = await relocateConflictingHomeRoute();\r\n\r\n if (collision.outcome === \"relocated\") {\r\n console.log(\r\n `${colors.green(\"✓\")} Moved the existing ${colors.yellowBright('GET \"/\"')} route to ` +\r\n `${colors.yellowBright('\"/welcome\"')} in ${colors.yellowBright(`src/${collision.relativePath}`)} — ` +\r\n \"the new page owns `/` now, and the JSON welcome route still answers at /welcome.\",\r\n );\r\n }\r\n\r\n // The page is written ONLY when `/` is provably free. Writing it while\r\n // another handler holds `/` produces a homepage that 500s on first request,\r\n // which is precisely the outcome a scaffolder must never hand back.\r\n if (collision.outcome === \"conflict\" || collision.outcome === \"failed\") {\r\n const verb =\r\n collision.outcome === \"failed\" ? colors.redBright(\"✗\") : colors.yellowBright(\"!\");\r\n\r\n console.log(\r\n `${verb} Did not create src/web/index.page.tsx: ${collision.reason}.\\n` +\r\n ` The page stub declares ${colors.yellowBright('route.path = \"/\"')}, and two handlers on one ` +\r\n \"path is a 500 at request time, not a startup error.\\n\" +\r\n ` Free up ${colors.yellowBright('GET \"/\"')} under src/app — move it to a path of its own, ` +\r\n \"or remove it — then create src/web/index.page.tsx yourself. Giving the page a `route` other \" +\r\n \"than `/` works too.\",\r\n );\r\n\r\n // Non-zero on BOTH branches. The page layer this command exists to\r\n // scaffold was not scaffolded, and a 0 here is the exact \"looked like it\r\n // worked\" signal that put `/` in this state to begin with — a conflict we\r\n // declined to guess at is still an incomplete install, not a success.\r\n //\r\n // `exitCode` rather than `exit(1)`: the connector below still has to be\r\n // registered, and any other feature in the same `warlock add` invocation\r\n // still has to install, or the project is left half-wired on top of this.\r\n process.exitCode = 1;\r\n } else {\r\n await putFileAsync(srcPath(\"web/index.page.tsx\"), webHomePageStub);\r\n await putFileAsync(srcPath(\"web/index.register.ts\"), webHomeRegisterStub);\r\n\r\n // Unlike root.tsx above, the contact controller and its routes file are\r\n // ordinary application files a project can already have — independently\r\n // of ever having run `warlock add web`. Each is guarded on its OWN\r\n // existence, not on the (already-consumed) root.tsx sentinel, so an\r\n // existing `contact` module is skipped rather than clobbered. See\r\n // resolveContactScaffold's doc comment for why.\r\n const contactPlan = resolveContactScaffold({\r\n controllerExists: await fileExistsAsync(\r\n srcPath(\"app/contact/controllers/contact.controller.ts\"),\r\n ),\r\n routesExists: await fileExistsAsync(srcPath(\"app/contact/routes.ts\")),\r\n });\r\n\r\n if (contactPlan.writeController) {\r\n await ensureDirectoryAsync(srcPath(\"app/contact/controllers\"));\r\n await putFileAsync(\r\n srcPath(\"app/contact/controllers/contact.controller.ts\"),\r\n webContactControllerStub,\r\n );\r\n }\r\n\r\n if (contactPlan.writeRoutes) {\r\n await ensureDirectoryAsync(srcPath(\"app/contact\"));\r\n await putFileAsync(srcPath(\"app/contact/routes.ts\"), webContactRoutesStub);\r\n }\r\n\r\n console.log(`${colors.green(\"✓\")} Created src/web/index.page.tsx`);\r\n\r\n for (const message of contactPlan.messages) {\r\n console.log(message);\r\n }\r\n }\r\n }\r\n\r\n await registerWebConnector();\r\n}\r\n\r\nexport const webFeature: FeatureDefinition = {\r\n description:\r\n \"Installs @warlock.js/web — SSR React pages served by the Warlock HTTP server. Scaffolds src/web (root.tsx + a home page) and registers the WebConnector in warlock.config.ts. Pages are opt-in: a Warlock app is an API until you add this.\",\r\n dependencies: {\r\n \"@warlock.js/web\": INSTALLED_WARLOCK_VERSION,\r\n \"@mongez/http\": \"^3.5.0\",\r\n \"@mongez/react-form\": \"^4.0.0\",\r\n \"@mongez/react-localization\": \"^3.4.7\",\r\n react: \"^19.2.3\",\r\n \"react-dom\": \"^19.2.3\",\r\n },\r\n devDependencies: {\r\n \"@types/react\": \"^19.2.7\",\r\n \"@types/react-dom\": \"^19.2.3\",\r\n // Loaded through `await import()` by the dev server only, so both are\r\n // optional peers of `web` rather than hard dependencies.\r\n vite: VITE_RANGE,\r\n \"@vitejs/plugin-react\": \"^5.2.0\",\r\n },\r\n onExecuting: completeWebInstallation,\r\n};\r\n"],"mappings":";;;;;;;;;;;;AAiBA,MAAa,aAAa;;;;;;;;;;;;;;;;;;;AAoB1B,eAAe,uBAAsC;CACnD,MAAM,aAAa,SAAS,mBAAmB;CAE/C,IAAI,CAAE,MAAM,gBAAgB,UAAU,GAAI;EACxC,QAAQ,IACN,GAAG,OAAO,aAAa,mBAAmB,EAAE,+JAG9C;EAEA;CACF;CAEA,MAAM,UAAU,MAAM,aAAa,UAAU;CAE7C,IAAI,QAAQ,SAAS,cAAc,GAAG;EACpC,QAAQ,IAAI,GAAG,OAAO,aAAa,cAAc,EAAE,iCAAiC;EAEpF;CACF;CAEA,MAAM,aAAa;CACnB,IAAI,OAAO,QAAQ,SAAS,UAAU,IAAI,UAAU,GAAG,WAAW,IAAI;CAItE,MAAM,YAAY,qBAAqB,MAAM,gBAAgB;CAE7D,IAAI,UAAU,WAAW,mBACvB;CAGF,IAAI,UAAU,WAAW,SACvB,OAAO,UAAU;MACZ,IAAI,KAAK,SAAS,gBAAgB,GACvC,OAAO,KAAK,QAAQ,kBAAkB,iDAAiD;MAClF;EACL,QAAQ,IACN,GAAG,OAAO,aAAa,mBAAmB,EAAE,0FAE9C;EAEA;CACF;CAEA,MAAM,aAAa,YAAY,IAAI;CACnC,QAAQ,IAAI,GAAG,OAAO,MAAM,GAAG,EAAE,8CAA8C;AACjF;;;;;;;AAQA,eAAe,wBAAwB,UAA6B;CAClE,MAAM,WAAW,QAAQ,cAAc;CAEvC,IAAI,MAAM,gBAAgB,QAAQ,GAChC,QAAQ,IAAI,GAAG,OAAO,aAAa,SAAS,EAAE,iCAAiC;MAC1E;EACL,MAAM,qBAAqB,QAAQ,KAAK,CAAC;EACzC,MAAM,aAAa,UAAU,WAAW;EACxC,QAAQ,IAAI,GAAG,OAAO,MAAM,GAAG,EAAE,0BAA0B;EAE3D,MAAM,YAAY,MAAM,6BAA6B;EAErD,IAAI,UAAU,YAAY,aACxB,QAAQ,IACN,GAAG,OAAO,MAAM,GAAG,EAAE,sBAAsB,OAAO,aAAa,WAAS,EAAE,YACrE,OAAO,aAAa,cAAY,EAAE,MAAM,OAAO,aAAa,OAAO,UAAU,cAAc,EAAE,sFAEpG;EAMF,IAAI,UAAU,YAAY,cAAc,UAAU,YAAY,UAAU;GACtE,MAAM,OACJ,UAAU,YAAY,WAAW,OAAO,UAAU,GAAG,IAAI,OAAO,aAAa,GAAG;GAElF,QAAQ,IACN,GAAG,KAAK,0CAA0C,UAAU,OAAO,8BACrC,OAAO,aAAa,oBAAkB,EAAE;YAEvD,OAAO,aAAa,WAAS,EAAE,mKAGhD;GAUA,QAAQ,WAAW;EACrB,OAAO;GACL,MAAM,aAAa,QAAQ,oBAAoB,GAAG,eAAe;GACjE,MAAM,aAAa,QAAQ,uBAAuB,GAAG,mBAAmB;GAQxE,MAAM,cAAc,uBAAuB;IACzC,kBAAkB,MAAM,gBACtB,QAAQ,+CAA+C,CACzD;IACA,cAAc,MAAM,gBAAgB,QAAQ,uBAAuB,CAAC;GACtE,CAAC;GAED,IAAI,YAAY,iBAAiB;IAC/B,MAAM,qBAAqB,QAAQ,yBAAyB,CAAC;IAC7D,MAAM,aACJ,QAAQ,+CAA+C,GACvD,wBACF;GACF;GAEA,IAAI,YAAY,aAAa;IAC3B,MAAM,qBAAqB,QAAQ,aAAa,CAAC;IACjD,MAAM,aAAa,QAAQ,uBAAuB,GAAG,oBAAoB;GAC3E;GAEA,QAAQ,IAAI,GAAG,OAAO,MAAM,GAAG,EAAE,gCAAgC;GAEjE,KAAK,MAAM,WAAW,YAAY,UAChC,QAAQ,IAAI,OAAO;EAEvB;CACF;CAEA,MAAM,qBAAqB;AAC7B;AAEA,MAAa,aAAgC;CAC3C,aACE;CACF,cAAc;EACZ,mBAAmB;EACnB,gBAAgB;EAChB,sBAAsB;EACtB,8BAA8B;EAC9B,OAAO;EACP,aAAa;CACf;CACA,iBAAiB;EACf,gBAAgB;EAChB,oBAAoB;EAGpB,MAAM;EACN,wBAAwB;CAC1B;CACA,aAAa;AACf"}
1
+ {"version":3,"file":"web.feature.mjs","names":[],"sources":["../../../../../../../../core/src/generations/features/web.feature.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\nimport { ensureDirectoryAsync, fileExistsAsync, getFileAsync, putFileAsync } from \"@warlock.js/fs\";\nimport type { CommandActionData } from \"../../commands/types\";\nimport { rootPath, srcPath } from \"../../utils\";\nimport { insertConnectorEntry } from \"./shared/insert-connector-entry\";\nimport { relocateConflictingHomeRoute } from \"./shared/relocate-conflicting-home-route\";\nimport { resolveContactScaffold } from \"./shared/resolve-contact-scaffold\";\nimport {\n webContactControllerStub,\n webContactRoutesStub,\n webHomePageStub,\n webHomeRegisterStub,\n webRootStub,\n} from \"../stubs\";\nimport { type FeatureDefinition, INSTALLED_WARLOCK_VERSION } from \"./types\";\n\n/** The one vite range shared by every feature (web's peer range is `>=7.3.5 <8`). */\nexport const VITE_RANGE = \"^7.3.5\";\n\n/**\n * Register the WebConnector in `warlock.config.ts`, and ONLY there.\n *\n * It belongs to the config array or to app code, never both. Both halves are\n * registered before app code loads — the CLI preloader in dev, the generated\n * entry in production — so also calling `connectorsManager.register(...)` in\n * `src/app/main.ts` boots the connector twice and installs every page route\n * twice. That surfaces at PRODUCTION boot as `Route name \"...\" is already\n * taken`, because pages and API routes share one route-name namespace.\n *\n * The config array is the half to prefer: `warlock build` reads the same array\n * to drain each connector's build contribution, so \"built for\" and \"boots with\"\n * cannot drift.\n *\n * String surgery rather than a TypeScript parse: `warlock.config.ts` is an\n * app-owned file that may carry any formatting, and a parse-and-print would\n * reformat the parts we did not come to change.\n */\nasync function registerWebConnector(): Promise<void> {\n const configPath = rootPath(\"warlock.config.ts\");\n\n if (!(await fileExistsAsync(configPath))) {\n console.log(\n `${colors.yellowBright(\"warlock.config.ts\")} not found — add this yourself:\\n` +\n ` import { webConnector } from \"@warlock.js/web/connector\";\\n` +\n ` export default defineConfig({ connectors: [webConnector()] });`,\n );\n\n return;\n }\n\n const current = await getFileAsync(configPath);\n\n if (current.includes(\"webConnector\")) {\n console.log(`${colors.yellowBright(\"webConnector\")} already registered, skipping...`);\n\n return;\n }\n\n const importLine = 'import { webConnector } from \"@warlock.js/web/connector\";';\n let next = current.includes(importLine) ? current : `${importLine}\\n${current}`;\n\n // An existing `connectors: [` gains one entry; otherwise the key is added to\n // the object `defineConfig` receives.\n const insertion = insertConnectorEntry(next, \"webConnector()\");\n\n if (insertion.status === \"already-present\") {\n return;\n }\n\n if (insertion.status === \"added\") {\n next = insertion.next;\n } else if (next.includes(\"defineConfig({\")) {\n next = next.replace(\"defineConfig({\", \"defineConfig({\\n connectors: [webConnector()],\");\n } else {\n console.log(\n `${colors.yellowBright(\"warlock.config.ts\")} has no recognisable defineConfig({...}) — ` +\n \"add `connectors: [webConnector()]` yourself.\",\n );\n\n return;\n }\n\n await putFileAsync(configPath, next);\n console.log(`${colors.green(\"✓\")} Registered webConnector in warlock.config.ts`);\n}\n\n/**\n * Scaffold the smallest page layer that renders, and register the connector.\n *\n * `src/web/root.tsx` is the sentinel for \"already scaffolded\" — the framework\n * ships a default root, so its presence means a human has been here.\n */\nasync function completeWebInstallation(_options: CommandActionData) {\n const rootFile = srcPath(\"web/root.tsx\");\n\n if (await fileExistsAsync(rootFile)) {\n console.log(`${colors.yellowBright(\"src/web\")} already scaffolded, skipping...`);\n } else {\n await ensureDirectoryAsync(srcPath(\"web\"));\n await putFileAsync(rootFile, webRootStub);\n console.log(`${colors.green(\"✓\")} Created src/web/root.tsx`);\n\n const collision = await relocateConflictingHomeRoute();\n\n if (collision.outcome === \"relocated\") {\n console.log(\n `${colors.green(\"✓\")} Moved the existing ${colors.yellowBright('GET \"/\"')} route to ` +\n `${colors.yellowBright('\"/welcome\"')} in ${colors.yellowBright(`src/${collision.relativePath}`)} — ` +\n \"the new page owns `/` now, and the JSON welcome route still answers at /welcome.\",\n );\n }\n\n // The page is written ONLY when `/` is provably free. Writing it while\n // another handler holds `/` produces a homepage that 500s on first request,\n // which is precisely the outcome a scaffolder must never hand back.\n if (collision.outcome === \"conflict\" || collision.outcome === \"failed\") {\n const verb =\n collision.outcome === \"failed\" ? colors.redBright(\"✗\") : colors.yellowBright(\"!\");\n\n console.log(\n `${verb} Did not create src/web/index.page.tsx: ${collision.reason}.\\n` +\n ` The page stub declares ${colors.yellowBright('route.path = \"/\"')}, and two handlers on one ` +\n \"path is a 500 at request time, not a startup error.\\n\" +\n ` Free up ${colors.yellowBright('GET \"/\"')} under src/app — move it to a path of its own, ` +\n \"or remove it — then create src/web/index.page.tsx yourself. Giving the page a `route` other \" +\n \"than `/` works too.\",\n );\n\n // Non-zero on BOTH branches. The page layer this command exists to\n // scaffold was not scaffolded, and a 0 here is the exact \"looked like it\n // worked\" signal that put `/` in this state to begin with — a conflict we\n // declined to guess at is still an incomplete install, not a success.\n //\n // `exitCode` rather than `exit(1)`: the connector below still has to be\n // registered, and any other feature in the same `warlock add` invocation\n // still has to install, or the project is left half-wired on top of this.\n process.exitCode = 1;\n } else {\n await putFileAsync(srcPath(\"web/index.page.tsx\"), webHomePageStub);\n await putFileAsync(srcPath(\"web/index.register.ts\"), webHomeRegisterStub);\n\n // Unlike root.tsx above, the contact controller and its routes file are\n // ordinary application files a project can already have — independently\n // of ever having run `warlock add web`. Each is guarded on its OWN\n // existence, not on the (already-consumed) root.tsx sentinel, so an\n // existing `contact` module is skipped rather than clobbered. See\n // resolveContactScaffold's doc comment for why.\n const contactPlan = resolveContactScaffold({\n controllerExists: await fileExistsAsync(\n srcPath(\"app/contact/controllers/contact.controller.ts\"),\n ),\n routesExists: await fileExistsAsync(srcPath(\"app/contact/routes.ts\")),\n });\n\n if (contactPlan.writeController) {\n await ensureDirectoryAsync(srcPath(\"app/contact/controllers\"));\n await putFileAsync(\n srcPath(\"app/contact/controllers/contact.controller.ts\"),\n webContactControllerStub,\n );\n }\n\n if (contactPlan.writeRoutes) {\n await ensureDirectoryAsync(srcPath(\"app/contact\"));\n await putFileAsync(srcPath(\"app/contact/routes.ts\"), webContactRoutesStub);\n }\n\n console.log(`${colors.green(\"✓\")} Created src/web/index.page.tsx`);\n\n for (const message of contactPlan.messages) {\n console.log(message);\n }\n }\n }\n\n await registerWebConnector();\n}\n\nexport const webFeature: FeatureDefinition = {\n description:\n \"Installs @warlock.js/web — SSR React pages served by the Warlock HTTP server. Scaffolds src/web (root.tsx + a home page) and registers the WebConnector in warlock.config.ts. Pages are opt-in: a Warlock app is an API until you add this.\",\n dependencies: {\n \"@warlock.js/web\": INSTALLED_WARLOCK_VERSION,\n \"@mongez/http\": \"^3.5.0\",\n \"@mongez/react-form\": \"^4.0.0\",\n \"@mongez/react-localization\": \"^3.4.7\",\n react: \"^19.2.3\",\n \"react-dom\": \"^19.2.3\",\n },\n devDependencies: {\n \"@types/react\": \"^19.2.7\",\n \"@types/react-dom\": \"^19.2.3\",\n // Loaded through `await import()` by the dev server only, so both are\n // optional peers of `web` rather than hard dependencies.\n vite: VITE_RANGE,\n \"@vitejs/plugin-react\": \"^5.2.0\",\n },\n onExecuting: completeWebInstallation,\n};\n"],"mappings":";;;;;;;;;;;;AAiBA,MAAa,aAAa;;;;;;;;;;;;;;;;;;;AAoB1B,eAAe,uBAAsC;CACnD,MAAM,aAAa,SAAS,mBAAmB;CAE/C,IAAI,CAAE,MAAM,gBAAgB,UAAU,GAAI;EACxC,QAAQ,IACN,GAAG,OAAO,aAAa,mBAAmB,EAAE,+JAG9C;EAEA;CACF;CAEA,MAAM,UAAU,MAAM,aAAa,UAAU;CAE7C,IAAI,QAAQ,SAAS,cAAc,GAAG;EACpC,QAAQ,IAAI,GAAG,OAAO,aAAa,cAAc,EAAE,iCAAiC;EAEpF;CACF;CAEA,MAAM,aAAa;CACnB,IAAI,OAAO,QAAQ,SAAS,UAAU,IAAI,UAAU,GAAG,WAAW,IAAI;CAItE,MAAM,YAAY,qBAAqB,MAAM,gBAAgB;CAE7D,IAAI,UAAU,WAAW,mBACvB;CAGF,IAAI,UAAU,WAAW,SACvB,OAAO,UAAU;MACZ,IAAI,KAAK,SAAS,gBAAgB,GACvC,OAAO,KAAK,QAAQ,kBAAkB,iDAAiD;MAClF;EACL,QAAQ,IACN,GAAG,OAAO,aAAa,mBAAmB,EAAE,0FAE9C;EAEA;CACF;CAEA,MAAM,aAAa,YAAY,IAAI;CACnC,QAAQ,IAAI,GAAG,OAAO,MAAM,GAAG,EAAE,8CAA8C;AACjF;;;;;;;AAQA,eAAe,wBAAwB,UAA6B;CAClE,MAAM,WAAW,QAAQ,cAAc;CAEvC,IAAI,MAAM,gBAAgB,QAAQ,GAChC,QAAQ,IAAI,GAAG,OAAO,aAAa,SAAS,EAAE,iCAAiC;MAC1E;EACL,MAAM,qBAAqB,QAAQ,KAAK,CAAC;EACzC,MAAM,aAAa,UAAU,WAAW;EACxC,QAAQ,IAAI,GAAG,OAAO,MAAM,GAAG,EAAE,0BAA0B;EAE3D,MAAM,YAAY,MAAM,6BAA6B;EAErD,IAAI,UAAU,YAAY,aACxB,QAAQ,IACN,GAAG,OAAO,MAAM,GAAG,EAAE,sBAAsB,OAAO,aAAa,WAAS,EAAE,YACrE,OAAO,aAAa,cAAY,EAAE,MAAM,OAAO,aAAa,OAAO,UAAU,cAAc,EAAE,sFAEpG;EAMF,IAAI,UAAU,YAAY,cAAc,UAAU,YAAY,UAAU;GACtE,MAAM,OACJ,UAAU,YAAY,WAAW,OAAO,UAAU,GAAG,IAAI,OAAO,aAAa,GAAG;GAElF,QAAQ,IACN,GAAG,KAAK,0CAA0C,UAAU,OAAO,8BACrC,OAAO,aAAa,oBAAkB,EAAE;YAEvD,OAAO,aAAa,WAAS,EAAE,mKAGhD;GAUA,QAAQ,WAAW;EACrB,OAAO;GACL,MAAM,aAAa,QAAQ,oBAAoB,GAAG,eAAe;GACjE,MAAM,aAAa,QAAQ,uBAAuB,GAAG,mBAAmB;GAQxE,MAAM,cAAc,uBAAuB;IACzC,kBAAkB,MAAM,gBACtB,QAAQ,+CAA+C,CACzD;IACA,cAAc,MAAM,gBAAgB,QAAQ,uBAAuB,CAAC;GACtE,CAAC;GAED,IAAI,YAAY,iBAAiB;IAC/B,MAAM,qBAAqB,QAAQ,yBAAyB,CAAC;IAC7D,MAAM,aACJ,QAAQ,+CAA+C,GACvD,wBACF;GACF;GAEA,IAAI,YAAY,aAAa;IAC3B,MAAM,qBAAqB,QAAQ,aAAa,CAAC;IACjD,MAAM,aAAa,QAAQ,uBAAuB,GAAG,oBAAoB;GAC3E;GAEA,QAAQ,IAAI,GAAG,OAAO,MAAM,GAAG,EAAE,gCAAgC;GAEjE,KAAK,MAAM,WAAW,YAAY,UAChC,QAAQ,IAAI,OAAO;EAEvB;CACF;CAEA,MAAM,qBAAqB;AAC7B;AAEA,MAAa,aAAgC;CAC3C,aACE;CACF,cAAc;EACZ,mBAAmB;EACnB,gBAAgB;EAChB,sBAAsB;EACtB,8BAA8B;EAC9B,OAAO;EACP,aAAa;CACf;CACA,iBAAiB;EACf,gBAAgB;EAChB,oBAAoB;EAGpB,MAAM;EACN,wBAAwB;CAC1B;CACA,aAAa;AACf"}
@@ -4,11 +4,17 @@ import { RateLimitPluginOptions } from "@fastify/rate-limit";
4
4
  /**
5
5
  * `@fastify/rate-limit` options that `http.rateLimit` passes straight through.
6
6
  */
7
- declare const passthroughKeys: readonly ["redis", "nameSpace", "keyGenerator", "skipOnError", "allowList", "continueExceeding", "enableDraftSpec", "global", "hook", "cache", "errorResponseBuilder", "addHeaders", "addHeadersOnExceeding"];
7
+ declare const passthroughKeys: readonly ["redis", "nameSpace", "keyGenerator", "ipv6Subnet", "skipOnError", "allowList", "continueExceeding", "enableDraftSpec", "global", "hook", "cache", "errorResponseBuilder", "addHeaders", "addHeadersOnExceeding"];
8
8
  /**
9
9
  * Shape of the `http.rateLimit` config.
10
10
  */
11
- type HttpRateLimitConfig = Pick<RateLimitPluginOptions, (typeof passthroughKeys)[number]> & {
11
+ type HttpRateLimitConfig = Omit<Pick<RateLimitPluginOptions, (typeof passthroughKeys)[number]>, "ipv6Subnet"> & {
12
+ /**
13
+ * IPv6 subnet size used to group client addresses.
14
+ *
15
+ * @default 64
16
+ */
17
+ ipv6Subnet?: RateLimitPluginOptions["ipv6Subnet"];
12
18
  /**
13
19
  * Set `false` to skip registering the global rate limiter.
14
20
  *
@@ -1 +1 @@
1
- {"version":3,"file":"build-rate-limit-options.d.mts","names":[],"sources":["../../../../../../../core/src/http/build-rate-limit-options.ts"],"mappings":";;;;;AAAkE;cAK5D,eAAA;;;AAcI;KAKE,mBAAA,GAAsB,IAAA,CAAK,sBAAA,UAAgC,eAAA;EAAxC;;;;;EAM7B,OAAA;EAgBmC;;;;;EAVnC,GAAA;EAAA;;;;;EAMA,QAAA;;;;EAIA,UAAA,GAAa,sBAAA;AAAA"}
1
+ {"version":3,"file":"build-rate-limit-options.d.mts","names":[],"sources":["../../../../../../../core/src/http/build-rate-limit-options.ts"],"mappings":";;;;;AAAkE;cAK5D,eAAA;;;AAeI;KAKE,mBAAA,GAAsB,IAAA,CAChC,IAAA,CAAK,sBAAA,UAAgC,eAAA;EADR;;;;;EAS7B,UAAA,GAAa,sBAAA;EAAA;;;;;EAMb,OAAA;EAdK;;;;;EAoBL,GAAA;EAMA;;;;AAImC;EAJnC,QAAA;;;;EAIA,UAAA,GAAa,sBAAA;AAAA"}
@@ -6,6 +6,7 @@ const passthroughKeys = [
6
6
  "redis",
7
7
  "nameSpace",
8
8
  "keyGenerator",
9
+ "ipv6Subnet",
9
10
  "skipOnError",
10
11
  "allowList",
11
12
  "continueExceeding",
@@ -1 +1 @@
1
- {"version":3,"file":"build-rate-limit-options.mjs","names":[],"sources":["../../../../../../../core/src/http/build-rate-limit-options.ts"],"sourcesContent":["import type { RateLimitPluginOptions } from \"@fastify/rate-limit\";\n\n/**\n * `@fastify/rate-limit` options that `http.rateLimit` passes straight through.\n */\nconst passthroughKeys = [\n \"redis\",\n \"nameSpace\",\n \"keyGenerator\",\n \"skipOnError\",\n \"allowList\",\n \"continueExceeding\",\n \"enableDraftSpec\",\n \"global\",\n \"hook\",\n \"cache\",\n \"errorResponseBuilder\",\n \"addHeaders\",\n \"addHeadersOnExceeding\",\n] as const;\n\n/**\n * Shape of the `http.rateLimit` config.\n */\nexport type HttpRateLimitConfig = Pick<RateLimitPluginOptions, (typeof passthroughKeys)[number]> & {\n /**\n * Set `false` to skip registering the global rate limiter.\n *\n * @default true\n */\n enabled?: boolean;\n /**\n * Max requests per time window.\n *\n * @default 60\n */\n max?: number;\n /**\n * Time window in milliseconds. Alias of `timeWindow`.\n *\n * @default 60 * 1000\n */\n duration?: number;\n /**\n * Time window; takes precedence over `duration` when both are set.\n */\n timeWindow?: RateLimitPluginOptions[\"timeWindow\"];\n};\n\n/**\n * Build the `@fastify/rate-limit` plugin options from `http.rateLimit`.\n * Returns `null` when the limiter is disabled.\n */\nexport function buildRateLimitOptions(\n config: HttpRateLimitConfig | undefined,\n): RateLimitPluginOptions | null {\n const source = config ?? {};\n\n if (source.enabled === false) {\n return null;\n }\n\n const options: Record<string, unknown> = {\n max: source.max ?? 60,\n timeWindow: source.timeWindow ?? source.duration ?? 60 * 1000,\n };\n\n for (const key of passthroughKeys) {\n if (source[key] !== undefined) {\n options[key] = source[key];\n }\n }\n\n return options as RateLimitPluginOptions;\n}\n"],"mappings":";;;;AAKA,MAAM,kBAAkB;CACtB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;AAkCA,SAAgB,sBACd,QAC+B;CAC/B,MAAM,SAAS,UAAU,CAAC;CAE1B,IAAI,OAAO,YAAY,OACrB,OAAO;CAGT,MAAM,UAAmC;EACvC,KAAK,OAAO,OAAO;EACnB,YAAY,OAAO,cAAc,OAAO,YAAY,KAAK;CAC3D;CAEA,KAAK,MAAM,OAAO,iBAChB,IAAI,OAAO,SAAS,QAClB,QAAQ,OAAO,OAAO;CAI1B,OAAO;AACT"}
1
+ {"version":3,"file":"build-rate-limit-options.mjs","names":[],"sources":["../../../../../../../core/src/http/build-rate-limit-options.ts"],"sourcesContent":["import type { RateLimitPluginOptions } from \"@fastify/rate-limit\";\n\n/**\n * `@fastify/rate-limit` options that `http.rateLimit` passes straight through.\n */\nconst passthroughKeys = [\n \"redis\",\n \"nameSpace\",\n \"keyGenerator\",\n \"ipv6Subnet\",\n \"skipOnError\",\n \"allowList\",\n \"continueExceeding\",\n \"enableDraftSpec\",\n \"global\",\n \"hook\",\n \"cache\",\n \"errorResponseBuilder\",\n \"addHeaders\",\n \"addHeadersOnExceeding\",\n] as const;\n\n/**\n * Shape of the `http.rateLimit` config.\n */\nexport type HttpRateLimitConfig = Omit<\n Pick<RateLimitPluginOptions, (typeof passthroughKeys)[number]>,\n \"ipv6Subnet\"\n> & {\n /**\n * IPv6 subnet size used to group client addresses.\n *\n * @default 64\n */\n ipv6Subnet?: RateLimitPluginOptions[\"ipv6Subnet\"];\n /**\n * Set `false` to skip registering the global rate limiter.\n *\n * @default true\n */\n enabled?: boolean;\n /**\n * Max requests per time window.\n *\n * @default 60\n */\n max?: number;\n /**\n * Time window in milliseconds. Alias of `timeWindow`.\n *\n * @default 60 * 1000\n */\n duration?: number;\n /**\n * Time window; takes precedence over `duration` when both are set.\n */\n timeWindow?: RateLimitPluginOptions[\"timeWindow\"];\n};\n\n/**\n * Build the `@fastify/rate-limit` plugin options from `http.rateLimit`.\n * Returns `null` when the limiter is disabled.\n */\nexport function buildRateLimitOptions(\n config: HttpRateLimitConfig | undefined,\n): RateLimitPluginOptions | null {\n const source = config ?? {};\n\n if (source.enabled === false) {\n return null;\n }\n\n const options: Record<string, unknown> = {\n max: source.max ?? 60,\n timeWindow: source.timeWindow ?? source.duration ?? 60 * 1000,\n };\n\n for (const key of passthroughKeys) {\n if (source[key] !== undefined) {\n options[key] = source[key];\n }\n }\n\n return options as RateLimitPluginOptions;\n}\n"],"mappings":";;;;AAKA,MAAM,kBAAkB;CACtB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;AA2CA,SAAgB,sBACd,QAC+B;CAC/B,MAAM,SAAS,UAAU,CAAC;CAE1B,IAAI,OAAO,YAAY,OACrB,OAAO;CAGT,MAAM,UAAmC;EACvC,KAAK,OAAO,OAAO;EACnB,YAAY,OAAO,cAAc,OAAO,YAAY,KAAK;CAC3D;CAEA,KAAK,MAAM,OAAO,iBAChB,IAAI,OAAO,SAAS,QAClB,QAAQ,OAAO,OAAO;CAI1B,OAAO;AACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"RequestLog.mjs","names":[],"sources":["../../../../../../../../core/src/http/database/RequestLog.ts"],"sourcesContent":["import { Model } from \"@warlock.js/cascade\";\r\nimport { type Infer, v } from \"@warlock.js/seal\";\r\n\r\nconst schema = v.object({\r\n statusCode: v.number(),\r\n responseTime: v.number(),\r\n responseSize: v.number(),\r\n responseBody: v.record(v.any()),\r\n responseHeaders: v.record(v.any()),\r\n ip: v.string(),\r\n method: v.string(),\r\n route: v.string(),\r\n requestHeaders: v.record(v.any()),\r\n userAgent: v.string(),\r\n referer: v.string(),\r\n requestBody: v.record(v.any()),\r\n requestParams: v.record(v.any()),\r\n requestQuery: v.record(v.any()),\r\n});\r\n\r\ntype RequestLogSchema = Infer.Output<typeof schema>;\r\n\r\nexport class RequestLog extends Model<RequestLogSchema> {\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public static table = \"request_logs\";\r\n\r\n /**\r\n * {@inheritdoc}\r\n */\r\n public static schema = schema;\r\n}\r\n"],"mappings":";;;;AAGA,MAAM,SAAS,EAAE,OAAO;CACtB,YAAY,EAAE,OAAO;CACrB,cAAc,EAAE,OAAO;CACvB,cAAc,EAAE,OAAO;CACvB,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC;CAC9B,iBAAiB,EAAE,OAAO,EAAE,IAAI,CAAC;CACjC,IAAI,EAAE,OAAO;CACb,QAAQ,EAAE,OAAO;CACjB,OAAO,EAAE,OAAO;CAChB,gBAAgB,EAAE,OAAO,EAAE,IAAI,CAAC;CAChC,WAAW,EAAE,OAAO;CACpB,SAAS,EAAE,OAAO;CAClB,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC;CAC7B,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC;CAC/B,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC;AAChC,CAAC;AAID,IAAa,aAAb,cAAgC,MAAwB;;eAIhC;;;gBAKC;;AACzB"}
1
+ {"version":3,"file":"RequestLog.mjs","names":[],"sources":["../../../../../../../../core/src/http/database/RequestLog.ts"],"sourcesContent":["import { Model } from \"@warlock.js/cascade\";\nimport { type Infer, v } from \"@warlock.js/seal\";\n\nconst schema = v.object({\n statusCode: v.number(),\n responseTime: v.number(),\n responseSize: v.number(),\n responseBody: v.record(v.any()),\n responseHeaders: v.record(v.any()),\n ip: v.string(),\n method: v.string(),\n route: v.string(),\n requestHeaders: v.record(v.any()),\n userAgent: v.string(),\n referer: v.string(),\n requestBody: v.record(v.any()),\n requestParams: v.record(v.any()),\n requestQuery: v.record(v.any()),\n});\n\ntype RequestLogSchema = Infer.Output<typeof schema>;\n\nexport class RequestLog extends Model<RequestLogSchema> {\n /**\n * {@inheritdoc}\n */\n public static table = \"request_logs\";\n\n /**\n * {@inheritdoc}\n */\n public static schema = schema;\n}\n"],"mappings":";;;;AAGA,MAAM,SAAS,EAAE,OAAO;CACtB,YAAY,EAAE,OAAO;CACrB,cAAc,EAAE,OAAO;CACvB,cAAc,EAAE,OAAO;CACvB,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC;CAC9B,iBAAiB,EAAE,OAAO,EAAE,IAAI,CAAC;CACjC,IAAI,EAAE,OAAO;CACb,QAAQ,EAAE,OAAO;CACjB,OAAO,EAAE,OAAO;CAChB,gBAAgB,EAAE,OAAO,EAAE,IAAI,CAAC;CAChC,WAAW,EAAE,OAAO;CACpB,SAAS,EAAE,OAAO;CAClB,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC;CAC7B,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC;CAC/B,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC;AAChC,CAAC;AAID,IAAa,aAAb,cAAgC,MAAwB;;eAIhC;;;gBAKC;;AACzB"}
@@ -52,22 +52,6 @@ declare class NotAllowedError extends HttpError {
52
52
  declare class CookieJarUnavailableError extends Error {
53
53
  constructor(cookieName: string);
54
54
  }
55
- /**
56
- * Thrown by `Request.prototype.user` in development to catch a call site
57
- * still reading the removed `request.user` getter/setter after the 5.12.0
58
- * move: the authenticated user now lives at `request.locals.user`, written
59
- * by `@warlock.js/auth`'s middleware.
60
- *
61
- * Development-only diagnostic, not a runtime contract other code should
62
- * catch — the getter itself is typed `never`, so a caller that still
63
- * compiles against `request.user` only does so via `any`/an outdated type.
64
- * Kept in core (not auth) because `request.user` is a core `Request`
65
- * accessor and core cannot depend on `@warlock.js/auth` to react to it.
66
- * Slated for removal one release after 5.12.0 — see the CHANGELOG.
67
- */
68
- declare class RequestUserMovedError extends Error {
69
- constructor();
70
- }
71
55
  //#endregion
72
- export { BadRequestError, ConflictError, CookieJarUnavailableError, ForbiddenError, HttpError, NotAcceptableError, NotAllowedError, RequestUserMovedError, ResourceNotFoundError, ServerError, UnAuthorizedError };
56
+ export { BadRequestError, ConflictError, CookieJarUnavailableError, ForbiddenError, HttpError, NotAcceptableError, NotAllowedError, ResourceNotFoundError, ServerError, UnAuthorizedError };
73
57
  //# sourceMappingURL=errors.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.mts","names":[],"sources":["../../../../../../../../core/src/http/errors/errors.ts"],"mappings":";cAAa,SAAA,SAAkB,KAAK;EAEzB,MAAA;EACA,OAAA;EACA,OAAA;cAFA,MAAA,UACA,OAAA,UACA,OAAA;AAAA;AAAA,cAOE,qBAAA,SAA8B,SAAS;EAGzC,OAAA;cADP,OAAA,UACO,OAAA;AAAA;AAAA,cAOE,iBAAA,SAA0B,SAAS;EAGrC,OAAA;cADP,OAAA,UACO,OAAA;AAAA;AAAA,cAOE,cAAA,SAAuB,SAAS;EAGlC,OAAA;cADP,OAAA,UACO,OAAA;AAAA;AAAA,cAOE,eAAA,SAAwB,SAAS;EAGnC,OAAA;cADP,OAAA,UACO,OAAA;AAAA;AAAA,cAOE,WAAA,SAAoB,SAAS;EAG/B,OAAA;cADP,OAAA,UACO,OAAA;AAAA;AAAA,cAOE,aAAA,SAAsB,SAAS;EAGjC,OAAA;cADP,OAAA,UACO,OAAA;AAAA;AAAA,cAOE,kBAAA,SAA2B,SAAS;EAGtC,OAAA;cADP,OAAA,UACO,OAAA;AAAA;AAAA,cAOE,eAAA,SAAwB,SAAS;EAGnC,OAAA;cADP,OAAA,UACO,OAAA;AAAA;;;;;;;;;;AAlDa;AAOxB;;cA8Da,yBAAA,SAAkC,KAAK;cAC/B,UAAA;AAAA;;;;;;AA5DG;AAOxB;;;;;;;cA6Ea,qBAAA,SAA8B,KAAK;EAAL,WAAA;AAAA"}
1
+ {"version":3,"file":"errors.d.mts","names":[],"sources":["../../../../../../../../core/src/http/errors/errors.ts"],"mappings":";cAAa,SAAA,SAAkB,KAAK;EAEzB,MAAA;EACA,OAAA;EACA,OAAA;cAFA,MAAA,UACA,OAAA,UACA,OAAA;AAAA;AAAA,cAOE,qBAAA,SAA8B,SAAS;EAGzC,OAAA;cADP,OAAA,UACO,OAAA;AAAA;AAAA,cAOE,iBAAA,SAA0B,SAAS;EAGrC,OAAA;cADP,OAAA,UACO,OAAA;AAAA;AAAA,cAOE,cAAA,SAAuB,SAAS;EAGlC,OAAA;cADP,OAAA,UACO,OAAA;AAAA;AAAA,cAOE,eAAA,SAAwB,SAAS;EAGnC,OAAA;cADP,OAAA,UACO,OAAA;AAAA;AAAA,cAOE,WAAA,SAAoB,SAAS;EAG/B,OAAA;cADP,OAAA,UACO,OAAA;AAAA;AAAA,cAOE,aAAA,SAAsB,SAAS;EAGjC,OAAA;cADP,OAAA,UACO,OAAA;AAAA;AAAA,cAOE,kBAAA,SAA2B,SAAS;EAGtC,OAAA;cADP,OAAA,UACO,OAAA;AAAA;AAAA,cAOE,eAAA,SAAwB,SAAS;EAGnC,OAAA;cADP,OAAA,UACO,OAAA;AAAA;;;;;;;;;;AAlDa;AAOxB;;cA8Da,yBAAA,SAAkC,KAAK;cAC/B,UAAA;AAAA"}
@@ -82,26 +82,7 @@ var CookieJarUnavailableError = class extends Error {
82
82
  this.name = "CookieJarUnavailableError";
83
83
  }
84
84
  };
85
- /**
86
- * Thrown by `Request.prototype.user` in development to catch a call site
87
- * still reading the removed `request.user` getter/setter after the 5.12.0
88
- * move: the authenticated user now lives at `request.locals.user`, written
89
- * by `@warlock.js/auth`'s middleware.
90
- *
91
- * Development-only diagnostic, not a runtime contract other code should
92
- * catch — the getter itself is typed `never`, so a caller that still
93
- * compiles against `request.user` only does so via `any`/an outdated type.
94
- * Kept in core (not auth) because `request.user` is a core `Request`
95
- * accessor and core cannot depend on `@warlock.js/auth` to react to it.
96
- * Slated for removal one release after 5.12.0 — see the CHANGELOG.
97
- */
98
- var RequestUserMovedError = class extends Error {
99
- constructor() {
100
- super("request.user has been removed. The authenticated user now lives at request.locals.user, set by @warlock.js/auth's middleware.");
101
- this.name = "RequestUserMovedError";
102
- }
103
- };
104
85
 
105
86
  //#endregion
106
- export { BadRequestError, ConflictError, CookieJarUnavailableError, ForbiddenError, HttpError, NotAcceptableError, NotAllowedError, RequestUserMovedError, ResourceNotFoundError, ServerError, UnAuthorizedError };
87
+ export { BadRequestError, ConflictError, CookieJarUnavailableError, ForbiddenError, HttpError, NotAcceptableError, NotAllowedError, ResourceNotFoundError, ServerError, UnAuthorizedError };
107
88
  //# sourceMappingURL=errors.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.mjs","names":[],"sources":["../../../../../../../../core/src/http/errors/errors.ts"],"sourcesContent":["export class HttpError extends Error {\n public constructor(\n public status: number,\n public message: string,\n public payload?: any,\n ) {\n super(message);\n this.name = \"HttpError\";\n }\n}\n\nexport class ResourceNotFoundError extends HttpError {\n public constructor(\n message: string,\n public payload?: any,\n ) {\n super(404, message, payload);\n this.name = \"ResourceNotFoundError\";\n }\n}\n\nexport class UnAuthorizedError extends HttpError {\n public constructor(\n message: string,\n public payload?: any,\n ) {\n super(401, message, payload);\n this.name = \"UnAuthorizedError\";\n }\n}\n\nexport class ForbiddenError extends HttpError {\n public constructor(\n message: string,\n public payload?: any,\n ) {\n super(403, message, payload);\n this.name = \"ForbiddenError\";\n }\n}\n\nexport class BadRequestError extends HttpError {\n public constructor(\n message: string,\n public payload?: any,\n ) {\n super(400, message, payload);\n this.name = \"BadRequestError\";\n }\n}\n\nexport class ServerError extends HttpError {\n public constructor(\n message: string,\n public payload?: any,\n ) {\n super(500, message, payload);\n this.name = \"ServerError\";\n }\n}\n\nexport class ConflictError extends HttpError {\n public constructor(\n message: string,\n public payload?: any,\n ) {\n super(409, message, payload);\n this.name = \"ConflictError\";\n }\n}\n\nexport class NotAcceptableError extends HttpError {\n public constructor(\n message: string,\n public payload?: any,\n ) {\n super(406, message, payload);\n this.name = \"NotAcceptableError\";\n }\n}\n\nexport class NotAllowedError extends HttpError {\n public constructor(\n message: string,\n public payload?: any,\n ) {\n super(405, message, payload);\n this.name = \"NotAllowedError\";\n }\n}\n\n/**\n * Thrown by `Request.prototype.cookie` / `Request.prototype.hasCookie` when\n * `@fastify/cookie` was never registered on this Fastify instance, so\n * `baseRequest.cookies` is `undefined` rather than an (possibly empty) object.\n *\n * A by-name cookie read is a deliberate assertion by the caller — \"this\n * cookie should be readable here\" — so an unavailable jar is a configuration\n * fault, not an absent cookie, and must not be swallowed into a default\n * value or a silent `false`. Contrast `Request.prototype.cookies`, which\n * stays lenient because the framework's own opportunistic reads (e.g.\n * locale resolution) must not throw on a request that simply has no jar.\n */\nexport class CookieJarUnavailableError extends Error {\n public constructor(cookieName: string) {\n super(\n `Cannot read cookie \"${cookieName}\": the cookie jar is unavailable because ` +\n \"@fastify/cookie is not registered on this Fastify instance. \" +\n \"Register the plugin (see core's http/plugins.ts) before reading cookies by name.\",\n );\n\n this.name = \"CookieJarUnavailableError\";\n }\n}\n\n/**\n * Thrown by `Request.prototype.user` in development to catch a call site\n * still reading the removed `request.user` getter/setter after the 5.12.0\n * move: the authenticated user now lives at `request.locals.user`, written\n * by `@warlock.js/auth`'s middleware.\n *\n * Development-only diagnostic, not a runtime contract other code should\n * catch — the getter itself is typed `never`, so a caller that still\n * compiles against `request.user` only does so via `any`/an outdated type.\n * Kept in core (not auth) because `request.user` is a core `Request`\n * accessor and core cannot depend on `@warlock.js/auth` to react to it.\n * Slated for removal one release after 5.12.0 — see the CHANGELOG.\n */\nexport class RequestUserMovedError extends Error {\n public constructor() {\n super(\n \"request.user has been removed. The authenticated user now lives at \" +\n \"request.locals.user, set by @warlock.js/auth's middleware.\",\n );\n this.name = \"RequestUserMovedError\";\n }\n}\n"],"mappings":";AAAA,IAAa,YAAb,cAA+B,MAAM;CACnC,AAAO,YACL,AAAO,QACP,AAAO,SACP,AAAO,SACP;EACA,MAAM,OAAO;EAJN;EACA;EACA;EAGP,KAAK,OAAO;CACd;AACF;AAEA,IAAa,wBAAb,cAA2C,UAAU;CACnD,AAAO,YACL,SACA,AAAO,SACP;EACA,MAAM,KAAK,SAAS,OAAO;EAFpB;EAGP,KAAK,OAAO;CACd;AACF;AAEA,IAAa,oBAAb,cAAuC,UAAU;CAC/C,AAAO,YACL,SACA,AAAO,SACP;EACA,MAAM,KAAK,SAAS,OAAO;EAFpB;EAGP,KAAK,OAAO;CACd;AACF;AAEA,IAAa,iBAAb,cAAoC,UAAU;CAC5C,AAAO,YACL,SACA,AAAO,SACP;EACA,MAAM,KAAK,SAAS,OAAO;EAFpB;EAGP,KAAK,OAAO;CACd;AACF;AAEA,IAAa,kBAAb,cAAqC,UAAU;CAC7C,AAAO,YACL,SACA,AAAO,SACP;EACA,MAAM,KAAK,SAAS,OAAO;EAFpB;EAGP,KAAK,OAAO;CACd;AACF;AAEA,IAAa,cAAb,cAAiC,UAAU;CACzC,AAAO,YACL,SACA,AAAO,SACP;EACA,MAAM,KAAK,SAAS,OAAO;EAFpB;EAGP,KAAK,OAAO;CACd;AACF;AAEA,IAAa,gBAAb,cAAmC,UAAU;CAC3C,AAAO,YACL,SACA,AAAO,SACP;EACA,MAAM,KAAK,SAAS,OAAO;EAFpB;EAGP,KAAK,OAAO;CACd;AACF;AAEA,IAAa,qBAAb,cAAwC,UAAU;CAChD,AAAO,YACL,SACA,AAAO,SACP;EACA,MAAM,KAAK,SAAS,OAAO;EAFpB;EAGP,KAAK,OAAO;CACd;AACF;AAEA,IAAa,kBAAb,cAAqC,UAAU;CAC7C,AAAO,YACL,SACA,AAAO,SACP;EACA,MAAM,KAAK,SAAS,OAAO;EAFpB;EAGP,KAAK,OAAO;CACd;AACF;;;;;;;;;;;;;AAcA,IAAa,4BAAb,cAA+C,MAAM;CACnD,AAAO,YAAY,YAAoB;EACrC,MACE,uBAAuB,WAAW,sLAGpC;EAEA,KAAK,OAAO;CACd;AACF;;;;;;;;;;;;;;AAeA,IAAa,wBAAb,cAA2C,MAAM;CAC/C,AAAO,cAAc;EACnB,MACE,+HAEF;EACA,KAAK,OAAO;CACd;AACF"}
1
+ {"version":3,"file":"errors.mjs","names":[],"sources":["../../../../../../../../core/src/http/errors/errors.ts"],"sourcesContent":["export class HttpError extends Error {\n public constructor(\n public status: number,\n public message: string,\n public payload?: any,\n ) {\n super(message);\n this.name = \"HttpError\";\n }\n}\n\nexport class ResourceNotFoundError extends HttpError {\n public constructor(\n message: string,\n public payload?: any,\n ) {\n super(404, message, payload);\n this.name = \"ResourceNotFoundError\";\n }\n}\n\nexport class UnAuthorizedError extends HttpError {\n public constructor(\n message: string,\n public payload?: any,\n ) {\n super(401, message, payload);\n this.name = \"UnAuthorizedError\";\n }\n}\n\nexport class ForbiddenError extends HttpError {\n public constructor(\n message: string,\n public payload?: any,\n ) {\n super(403, message, payload);\n this.name = \"ForbiddenError\";\n }\n}\n\nexport class BadRequestError extends HttpError {\n public constructor(\n message: string,\n public payload?: any,\n ) {\n super(400, message, payload);\n this.name = \"BadRequestError\";\n }\n}\n\nexport class ServerError extends HttpError {\n public constructor(\n message: string,\n public payload?: any,\n ) {\n super(500, message, payload);\n this.name = \"ServerError\";\n }\n}\n\nexport class ConflictError extends HttpError {\n public constructor(\n message: string,\n public payload?: any,\n ) {\n super(409, message, payload);\n this.name = \"ConflictError\";\n }\n}\n\nexport class NotAcceptableError extends HttpError {\n public constructor(\n message: string,\n public payload?: any,\n ) {\n super(406, message, payload);\n this.name = \"NotAcceptableError\";\n }\n}\n\nexport class NotAllowedError extends HttpError {\n public constructor(\n message: string,\n public payload?: any,\n ) {\n super(405, message, payload);\n this.name = \"NotAllowedError\";\n }\n}\n\n/**\n * Thrown by `Request.prototype.cookie` / `Request.prototype.hasCookie` when\n * `@fastify/cookie` was never registered on this Fastify instance, so\n * `baseRequest.cookies` is `undefined` rather than an (possibly empty) object.\n *\n * A by-name cookie read is a deliberate assertion by the caller — \"this\n * cookie should be readable here\" — so an unavailable jar is a configuration\n * fault, not an absent cookie, and must not be swallowed into a default\n * value or a silent `false`. Contrast `Request.prototype.cookies`, which\n * stays lenient because the framework's own opportunistic reads (e.g.\n * locale resolution) must not throw on a request that simply has no jar.\n */\nexport class CookieJarUnavailableError extends Error {\n public constructor(cookieName: string) {\n super(\n `Cannot read cookie \"${cookieName}\": the cookie jar is unavailable because ` +\n \"@fastify/cookie is not registered on this Fastify instance. \" +\n \"Register the plugin (see core's http/plugins.ts) before reading cookies by name.\",\n );\n\n this.name = \"CookieJarUnavailableError\";\n }\n}\n"],"mappings":";AAAA,IAAa,YAAb,cAA+B,MAAM;CACnC,AAAO,YACL,AAAO,QACP,AAAO,SACP,AAAO,SACP;EACA,MAAM,OAAO;EAJN;EACA;EACA;EAGP,KAAK,OAAO;CACd;AACF;AAEA,IAAa,wBAAb,cAA2C,UAAU;CACnD,AAAO,YACL,SACA,AAAO,SACP;EACA,MAAM,KAAK,SAAS,OAAO;EAFpB;EAGP,KAAK,OAAO;CACd;AACF;AAEA,IAAa,oBAAb,cAAuC,UAAU;CAC/C,AAAO,YACL,SACA,AAAO,SACP;EACA,MAAM,KAAK,SAAS,OAAO;EAFpB;EAGP,KAAK,OAAO;CACd;AACF;AAEA,IAAa,iBAAb,cAAoC,UAAU;CAC5C,AAAO,YACL,SACA,AAAO,SACP;EACA,MAAM,KAAK,SAAS,OAAO;EAFpB;EAGP,KAAK,OAAO;CACd;AACF;AAEA,IAAa,kBAAb,cAAqC,UAAU;CAC7C,AAAO,YACL,SACA,AAAO,SACP;EACA,MAAM,KAAK,SAAS,OAAO;EAFpB;EAGP,KAAK,OAAO;CACd;AACF;AAEA,IAAa,cAAb,cAAiC,UAAU;CACzC,AAAO,YACL,SACA,AAAO,SACP;EACA,MAAM,KAAK,SAAS,OAAO;EAFpB;EAGP,KAAK,OAAO;CACd;AACF;AAEA,IAAa,gBAAb,cAAmC,UAAU;CAC3C,AAAO,YACL,SACA,AAAO,SACP;EACA,MAAM,KAAK,SAAS,OAAO;EAFpB;EAGP,KAAK,OAAO;CACd;AACF;AAEA,IAAa,qBAAb,cAAwC,UAAU;CAChD,AAAO,YACL,SACA,AAAO,SACP;EACA,MAAM,KAAK,SAAS,OAAO;EAFpB;EAGP,KAAK,OAAO;CACd;AACF;AAEA,IAAa,kBAAb,cAAqC,UAAU;CAC7C,AAAO,YACL,SACA,AAAO,SACP;EACA,MAAM,KAAK,SAAS,OAAO;EAFpB;EAGP,KAAK,OAAO;CACd;AACF;;;;;;;;;;;;;AAcA,IAAa,4BAAb,cAA+C,MAAM;CACnD,AAAO,YAAY,YAAoB;EACrC,MACE,uBAAuB,WAAW,sLAGpC;EAEA,KAAK,OAAO;CACd;AACF"}
@@ -3,7 +3,7 @@ import { XMLable } from "./xmlable.mjs";
3
3
  import { CookieOptions, Response, ResponseStatus, SendBufferOptions, SendFileOptions } from "./response.mjs";
4
4
  import { FileNamingStrategy, ImageTransformCallback, ImageTransformConfig, ImageVariantDefinition, ImageVariantFit, ImageVariantOutputFormat, PrefixConfig, PrefixOptions, SaveAsOptions, SaveOptions, UploadedFileImageOptions, UploadsConfigurations, UploadsImagesConfigurations } from "./uploads-types.mjs";
5
5
  import { FileValidationOptions, UploadedFile, UploadedFileJson } from "./uploaded-file.mjs";
6
- import { Request } from "./request.mjs";
6
+ import { Request, RequestTranslator } from "./request.mjs";
7
7
  import { CspConfig, DEFAULT_CSP_DIRECTIVES, InvalidCspDirectiveError, applyCspHeader, buildCspHeaderValue, mergeCspDirectives, resolveCspConfig, serializeCspDirectives, validateCspConfigAtBoot, validateCspDirectives } from "./csp.mjs";
8
8
  import { HttpTracingConfig, TracingContext, TracingHooks, TracingPhaseInfo, TracingRequestEndInfo } from "./tracing/tracing.type.mjs";
9
9
  import { DecodedAccessToken, HttpConfigurations, PartialMiddleware, RequestEvent, RequestLocals, ResponseEvent, ResponseSSEController, ResponseStreamController, ReturnedResponse } from "./types.mjs";
@@ -21,7 +21,7 @@ import { DetectedImageFormat, GeneratedImageDescriptor, GeneratedImageVariant, R
21
21
  import { GenerateImageVariantsOptions, generateImageVariants } from "./uploads/generate-image-variants.mjs";
22
22
  import { ImageVariantsConfigError } from "./uploads/image-variants-config-error.mjs";
23
23
  import { uploadedFileController } from "./uploads/uploaded-file.controller.mjs";
24
- import { BadRequestError, ConflictError, CookieJarUnavailableError, ForbiddenError, HttpError, NotAcceptableError, NotAllowedError, RequestUserMovedError, ResourceNotFoundError, ServerError, UnAuthorizedError } from "./errors/errors.mjs";
24
+ import { BadRequestError, ConflictError, CookieJarUnavailableError, ForbiddenError, HttpError, NotAcceptableError, NotAllowedError, ResourceNotFoundError, ServerError, UnAuthorizedError } from "./errors/errors.mjs";
25
25
  import { CacheMiddlewareOptions } from "./middleware/cache-response-middleware.mjs";
26
26
  import { ConcurrencyLimitOptions } from "./middleware/concurrency-limit.middleware.mjs";
27
27
  import { IdempotencyOptions } from "./middleware/idempotency.middleware.mjs";
@@ -38,7 +38,8 @@ import { registerHttpPlugins } from "./plugins.mjs";
38
38
  import { assertConfiguredHttpPortIsFree, preflightConfiguredHttpPort, remedyLines, shouldPreflightHttpPort } from "./boot-port-preflight.mjs";
39
39
  import { PortInUseError, assertPortIsAvailable, isPortAvailable } from "./port-preflight.mjs";
40
40
  import { HttpReadyReport, getHttpReadyReport, resetHttpReadyReport, setHttpReadyReport } from "./ready-report.mjs";
41
+ import { HttpServerRebuiltListener, notifyHttpServerRebuilt, onHttpServerRebuilt } from "./server-rebuilt.mjs";
41
42
  import { deriveTraceId, parseTraceparentTraceId } from "./tracing/trace-id.mjs";
42
- import { TracingContextSource, buildTracingContext, dispatchPhase, dispatchRequestEnd, dispatchRequestStart, isTracingEnabled, resetTracingConfigForTests, resolveTracingConfig } from "./tracing/tracing-dispatcher.mjs";
43
+ import { TracingContextSource, buildTracingContext, dispatchPhase, dispatchRequestEnd, dispatchRequestStart, isTracingEnabled, registerTracingHooks, resetTracingConfigForTests, resolveTracingConfig } from "./tracing/tracing-dispatcher.mjs";
43
44
  import { RequestContextStore, requestContext, useCurrentUser, useRequest, useRequestStore } from "./context/request-context.mjs";
44
45
  import { requestMemo } from "./context/request-memo.mjs";
@@ -3,9 +3,9 @@ import { DEFAULT_CSP_DIRECTIVES, InvalidCspDirectiveError, applyCspHeader, build
3
3
  import { HttpErrorCodes } from "./error-codes.mjs";
4
4
  import { isAllowedCsrfOrigin, normalizeOrigin, originOf, ownOrigin, resolveCsrfOriginVerdict } from "./csrf-origin-policy.mjs";
5
5
  import { requiresDefaultCsrfGuard, runDefaultCsrfGuard } from "./csrf-default-guard.mjs";
6
- import { BadRequestError, ConflictError, CookieJarUnavailableError, ForbiddenError, HttpError, NotAcceptableError, NotAllowedError, RequestUserMovedError, ResourceNotFoundError, ServerError, UnAuthorizedError } from "./errors/errors.mjs";
6
+ import { BadRequestError, ConflictError, CookieJarUnavailableError, ForbiddenError, HttpError, NotAcceptableError, NotAllowedError, ResourceNotFoundError, ServerError, UnAuthorizedError } from "./errors/errors.mjs";
7
7
  import { deriveTraceId, parseTraceparentTraceId } from "./tracing/trace-id.mjs";
8
- import { buildTracingContext, dispatchPhase, dispatchRequestEnd, dispatchRequestStart, isTracingEnabled, resetTracingConfigForTests, resolveTracingConfig } from "./tracing/tracing-dispatcher.mjs";
8
+ import { buildTracingContext, dispatchPhase, dispatchRequestEnd, dispatchRequestStart, isTracingEnabled, registerTracingHooks, resetTracingConfigForTests, resolveTracingConfig } from "./tracing/tracing-dispatcher.mjs";
9
9
  import "./tracing/index.mjs";
10
10
  import { createRequestStore, t } from "./middleware/inject-request-context.mjs";
11
11
  import { defaultHttpConfigurations, httpConfig } from "./config.mjs";
@@ -33,6 +33,7 @@ import "./middleware/index.mjs";
33
33
  import { PortInUseError, assertPortIsAvailable, isPortAvailable } from "./port-preflight.mjs";
34
34
  import { assertConfiguredHttpPortIsFree, preflightConfiguredHttpPort, remedyLines, shouldPreflightHttpPort } from "./boot-port-preflight.mjs";
35
35
  import { getHttpReadyReport, resetHttpReadyReport, setHttpReadyReport } from "./ready-report.mjs";
36
+ import { notifyHttpServerRebuilt, onHttpServerRebuilt } from "./server-rebuilt.mjs";
36
37
  import { requestMemo } from "./context/request-memo.mjs";
37
38
 
38
39
  export { };
@@ -12,7 +12,7 @@ declare function createRequestStore(request: Request<any>, response: Response):
12
12
  /**
13
13
  * Translate a keyword (uses request context for locale)
14
14
  */
15
- declare function t(keyword: string, placeholders?: any): any;
15
+ declare function t(keyword: string, placeholders?: Record<string, unknown>): string;
16
16
  //#endregion
17
17
  export { createRequestStore, t };
18
18
  //# sourceMappingURL=inject-request-context.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"inject-request-context.d.mts","names":[],"sources":["../../../../../../../../core/src/http/middleware/inject-request-context.ts"],"mappings":";;;;;;;AA8CA;;;iBAAgB,kBAAA,CACd,OAAA,EAAS,OAAA,OACT,QAAA,EAAU,QAAA,GACT,OAAA,CAAQ,gBAAA;;;;iBA4JK,CAAA,CAAE,OAAA,UAAiB,YAAkB"}
1
+ {"version":3,"file":"inject-request-context.d.mts","names":[],"sources":["../../../../../../../../core/src/http/middleware/inject-request-context.ts"],"mappings":";;;;;;;AA8CA;;;iBAAgB,kBAAA,CACd,OAAA,EAAS,OAAA,OACT,QAAA,EAAU,QAAA,GACT,OAAA,CAAQ,gBAAA;;;;iBA2KK,CAAA,CAAE,OAAA,UAAiB,YAAA,GAAe,MAAM"}
@@ -97,7 +97,15 @@ function handleRequestError(error, response, request) {
97
97
  if (environment() === "development") payload.stack = error.stack;
98
98
  return response.setStatusCode(error.status).send(payload);
99
99
  }
100
- if (error instanceof DatabaseWriterValidationError) return response.badRequest({ errors: error.errors });
100
+ if (error instanceof DatabaseWriterValidationError) {
101
+ log.error("http", "model-write-validation-error", error, {
102
+ requestId: request.id,
103
+ errors: error.errors
104
+ });
105
+ const status = config.get("http.modelValidationErrorStatus", 500);
106
+ if (status < 500) return response.setStatusCode(status).send({ errors: error.errors });
107
+ return response.setStatusCode(status).send({ error: "Internal server error." });
108
+ }
101
109
  reportUnhandledRequestError(error, request);
102
110
  return response.serverError({ error: "Internal server error." });
103
111
  }