@warlock.js/core 5.1.0 → 5.2.1

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 (356) hide show
  1. package/CHANGELOG.md +152 -0
  2. package/esm/application/application.d.mts.map +1 -1
  3. package/esm/application/application.mjs.map +1 -1
  4. package/esm/benchmark/benchmark-snapshots.d.mts.map +1 -1
  5. package/esm/benchmark/benchmark.d.mts.map +1 -1
  6. package/esm/benchmark/channels/console.channel.mjs.map +1 -1
  7. package/esm/benchmark/channels/noop.channel.d.mts.map +1 -1
  8. package/esm/benchmark/profiler.d.mts.map +1 -1
  9. package/esm/benchmark/profiler.mjs.map +1 -1
  10. package/esm/bootstrap/setup.d.mts.map +1 -1
  11. package/esm/bootstrap/setup.mjs.map +1 -1
  12. package/esm/bootstrap.d.mts.map +1 -1
  13. package/esm/cache/database-cache-driver.d.mts.map +1 -1
  14. package/esm/cache/database-cache-driver.mjs.map +1 -1
  15. package/esm/cli/cli-commands.manager.mjs.map +1 -1
  16. package/esm/cli/cli-commands.utils.mjs +16 -10
  17. package/esm/cli/cli-commands.utils.mjs.map +1 -1
  18. package/esm/cli/commands/doctor/boot-for-diagnostics.mjs.map +1 -1
  19. package/esm/cli/commands/doctor/checks/connectors.check.mjs.map +1 -1
  20. package/esm/cli/commands/doctor/checks/handler-signature.check.mjs.map +1 -1
  21. package/esm/cli/commands/doctor/checks/health.check.mjs.map +1 -1
  22. package/esm/cli/commands/doctor/checks/optional-peers.check.mjs.map +1 -1
  23. package/esm/cli/commands/doctor/checks/routes.check.mjs.map +1 -1
  24. package/esm/cli/commands/generate/generate.command.mjs.map +1 -1
  25. package/esm/cli/commands/generate/generators/column-dsl-parser.mjs.map +1 -1
  26. package/esm/cli/commands/generate/generators/migration.generator.mjs.map +1 -1
  27. package/esm/cli/commands/generate/generators/model.generator.mjs.map +1 -1
  28. package/esm/cli/commands/generate/templates/stubs.mjs.map +1 -1
  29. package/esm/cli/commands/generate/utils/name-parser.mjs.map +1 -1
  30. package/esm/cli/commands/generate/utils/prompt.mjs.map +1 -1
  31. package/esm/cli/commands/routes/diff-page-routes.mjs +84 -0
  32. package/esm/cli/commands/routes/diff-page-routes.mjs.map +1 -0
  33. package/esm/cli/commands/routes/format-routes-table.mjs.map +1 -1
  34. package/esm/cli/commands/routes/route-row.mjs.map +1 -1
  35. package/esm/cli/commands/routes/routes-command.action.mjs.map +1 -1
  36. package/esm/cli/commands/routes/routes-diff.action.mjs +84 -0
  37. package/esm/cli/commands/routes/routes-diff.action.mjs.map +1 -0
  38. package/esm/cli/commands/routes.command.mjs +15 -1
  39. package/esm/cli/commands/routes.command.mjs.map +1 -1
  40. package/esm/cli/commands/start-production.command.mjs +8 -1
  41. package/esm/cli/commands/start-production.command.mjs.map +1 -1
  42. package/esm/cli/commands/storage-put.action.mjs.map +1 -1
  43. package/esm/cli/commands/typings-generator.command.mjs.map +1 -1
  44. package/esm/cli/commands-loader.mjs.map +1 -1
  45. package/esm/cli/framework-cli-commands.mjs +2 -1
  46. package/esm/cli/framework-cli-commands.mjs.map +1 -1
  47. package/esm/cli/start.mjs.map +1 -1
  48. package/esm/cli/string-similarity.mjs.map +1 -1
  49. package/esm/commands/cli-command.mjs.map +1 -1
  50. package/esm/config/config-loader.d.mts +1 -1
  51. package/esm/config/config-loader.d.mts.map +1 -1
  52. package/esm/config/config-loader.mjs.map +1 -1
  53. package/esm/config/config-setter.d.mts.map +1 -1
  54. package/esm/config/config-special-handlers.d.mts +1 -1
  55. package/esm/config/config-special-handlers.mjs.map +1 -1
  56. package/esm/config/load-config-files.mjs.map +1 -1
  57. package/esm/connectors/access-connector.d.mts.map +1 -1
  58. package/esm/connectors/ai-connector.d.mts.map +1 -1
  59. package/esm/connectors/assert-no-reserved-connector-names.mjs.map +1 -1
  60. package/esm/connectors/assert-unique-connector-names.mjs.map +1 -1
  61. package/esm/connectors/base-connector.d.mts.map +1 -1
  62. package/esm/connectors/base-connector.mjs.map +1 -1
  63. package/esm/connectors/cache-connector.d.mts.map +1 -1
  64. package/esm/connectors/connectors-manager.d.mts.map +1 -1
  65. package/esm/connectors/connectors-manager.mjs.map +1 -1
  66. package/esm/connectors/database-connector.d.mts.map +1 -1
  67. package/esm/connectors/describe-server-address.mjs +20 -3
  68. package/esm/connectors/describe-server-address.mjs.map +1 -1
  69. package/esm/connectors/herald-connector.d.mts.map +1 -1
  70. package/esm/connectors/http-connector.d.mts.map +1 -1
  71. package/esm/connectors/http-connector.mjs +5 -1
  72. package/esm/connectors/http-connector.mjs.map +1 -1
  73. package/esm/connectors/logger-connector.d.mts.map +1 -1
  74. package/esm/connectors/mail-connector.d.mts.map +1 -1
  75. package/esm/connectors/notifications-connector.d.mts.map +1 -1
  76. package/esm/connectors/register-configured-connectors.mjs.map +1 -1
  77. package/esm/connectors/socket-connector.d.mts.map +1 -1
  78. package/esm/connectors/socket-connector.mjs.map +1 -1
  79. package/esm/connectors/storage.connector.d.mts.map +1 -1
  80. package/esm/container/index.d.mts.map +1 -1
  81. package/esm/database/create-database-action.mjs.map +1 -1
  82. package/esm/database/drop-tables-action.mjs.map +1 -1
  83. package/esm/database/migrate-action.mjs.map +1 -1
  84. package/esm/database/models/database-log/database-log.mjs.map +1 -1
  85. package/esm/database/seed-command-action.mjs.map +1 -1
  86. package/esm/database/seeds/seed-records-table-migration.mjs +1 -1
  87. package/esm/database/seeds/seed-records-table-migration.mjs.map +1 -1
  88. package/esm/database/seeds/seeder.mjs.map +1 -1
  89. package/esm/database/seeds/seeders.manager.mjs.map +1 -1
  90. package/esm/database/seeds/seeds-table-migration.mjs +1 -1
  91. package/esm/database/seeds/seeds-table-migration.mjs.map +1 -1
  92. package/esm/database/utils.mjs.map +1 -1
  93. package/esm/dev-server/check-for-updates.mjs.map +1 -1
  94. package/esm/dev-server/dependency-graph.d.mts.map +1 -1
  95. package/esm/dev-server/dependency-graph.mjs.map +1 -1
  96. package/esm/dev-server/dev-logger.mjs.map +1 -1
  97. package/esm/dev-server/development-server.mjs.map +1 -1
  98. package/esm/dev-server/file-event-handler.mjs.map +1 -1
  99. package/esm/dev-server/file-manager.d.mts.map +1 -1
  100. package/esm/dev-server/file-manager.mjs.map +1 -1
  101. package/esm/dev-server/file-operations.d.mts.map +1 -1
  102. package/esm/dev-server/files-orchestrator.mjs.map +1 -1
  103. package/esm/dev-server/files-watcher.mjs.map +1 -1
  104. package/esm/dev-server/health-checker/checkers/eslint-health-checker.mjs.map +1 -1
  105. package/esm/dev-server/health-checker/checkers/typescript-health-checker.mjs.map +1 -1
  106. package/esm/dev-server/health-checker/file-health-result.d.mts.map +1 -1
  107. package/esm/dev-server/health-checker/file-health-result.mjs.map +1 -1
  108. package/esm/dev-server/health-checker/files-healthcare.manager.mjs.map +1 -1
  109. package/esm/dev-server/layer-executor.mjs +10 -3
  110. package/esm/dev-server/layer-executor.mjs.map +1 -1
  111. package/esm/dev-server/loader/hook-thread.d.mts.map +1 -1
  112. package/esm/dev-server/loader/own-resolver.mjs.map +1 -1
  113. package/esm/dev-server/loader/register-loader.mjs.map +1 -1
  114. package/esm/dev-server/loader/resolve-hook.mjs.map +1 -1
  115. package/esm/dev-server/loader/source-slug.mjs.map +1 -1
  116. package/esm/dev-server/loader/transpile-cache.mjs +12 -3
  117. package/esm/dev-server/loader/transpile-cache.mjs.map +1 -1
  118. package/esm/dev-server/loader/version-registry.mjs.map +1 -1
  119. package/esm/dev-server/manifest-manager.d.mts.map +1 -1
  120. package/esm/dev-server/manifest-manager.mjs.map +1 -1
  121. package/esm/dev-server/module-loader.mjs.map +1 -1
  122. package/esm/dev-server/package-json-manager.mjs.map +1 -1
  123. package/esm/dev-server/parse-imports.mjs.map +1 -1
  124. package/esm/dev-server/ready-block.mjs.map +1 -1
  125. package/esm/dev-server/special-files-collector.d.mts.map +1 -1
  126. package/esm/dev-server/special-files-collector.mjs.map +1 -1
  127. package/esm/dev-server/supervisor.mjs +9 -6
  128. package/esm/dev-server/supervisor.mjs.map +1 -1
  129. package/esm/dev-server/tsconfig-manager.mjs.map +1 -1
  130. package/esm/dev-server/type-generator.mjs.map +1 -1
  131. package/esm/dev-server/utils.mjs.map +1 -1
  132. package/esm/encryption/encrypt.mjs.map +1 -1
  133. package/esm/encryption/hash.mjs.map +1 -1
  134. package/esm/encryption/password.mjs.map +1 -1
  135. package/esm/generations/add-command.action.mjs +11 -4
  136. package/esm/generations/add-command.action.mjs.map +1 -1
  137. package/esm/generations/features/access.feature.mjs +2 -1
  138. package/esm/generations/features/access.feature.mjs.map +1 -1
  139. package/esm/generations/features/ai-anthropic.feature.mjs +3 -1
  140. package/esm/generations/features/ai-anthropic.feature.mjs.map +1 -1
  141. package/esm/generations/features/ai-bedrock.feature.mjs +3 -1
  142. package/esm/generations/features/ai-bedrock.feature.mjs.map +1 -1
  143. package/esm/generations/features/ai-google.feature.mjs +3 -1
  144. package/esm/generations/features/ai-google.feature.mjs.map +1 -1
  145. package/esm/generations/features/ai-ollama.feature.mjs +3 -1
  146. package/esm/generations/features/ai-ollama.feature.mjs.map +1 -1
  147. package/esm/generations/features/ai-openai.feature.mjs +3 -1
  148. package/esm/generations/features/ai-openai.feature.mjs.map +1 -1
  149. package/esm/generations/features/ai-panoptic.feature.mjs +2 -1
  150. package/esm/generations/features/ai-panoptic.feature.mjs.map +1 -1
  151. package/esm/generations/features/ai-tools.feature.mjs +2 -1
  152. package/esm/generations/features/ai-tools.feature.mjs.map +1 -1
  153. package/esm/generations/features/ai-workspace.feature.mjs +2 -1
  154. package/esm/generations/features/ai-workspace.feature.mjs.map +1 -1
  155. package/esm/generations/features/ai.feature.mjs +2 -1
  156. package/esm/generations/features/ai.feature.mjs.map +1 -1
  157. package/esm/generations/features/herald.feature.mjs +2 -1
  158. package/esm/generations/features/herald.feature.mjs.map +1 -1
  159. package/esm/generations/features/notifications.feature.mjs +3 -2
  160. package/esm/generations/features/notifications.feature.mjs.map +1 -1
  161. package/esm/generations/features/scheduler.feature.mjs +3 -1
  162. package/esm/generations/features/scheduler.feature.mjs.map +1 -1
  163. package/esm/generations/features/shadcn.feature.mjs.map +1 -1
  164. package/esm/generations/features/shared/migration-timestamp.mjs.map +1 -1
  165. package/esm/generations/features/tailwind.feature.mjs.map +1 -1
  166. package/esm/generations/features/types.mjs +14 -0
  167. package/esm/generations/features/types.mjs.map +1 -0
  168. package/esm/generations/features/web.feature.mjs +10 -2
  169. package/esm/generations/features/web.feature.mjs.map +1 -1
  170. package/esm/generations/stubs.mjs +169 -28
  171. package/esm/generations/stubs.mjs.map +1 -1
  172. package/esm/http/boot-port-preflight.d.mts +46 -0
  173. package/esm/http/boot-port-preflight.d.mts.map +1 -0
  174. package/esm/http/boot-port-preflight.mjs +87 -0
  175. package/esm/http/boot-port-preflight.mjs.map +1 -0
  176. package/esm/http/context/request-context.d.mts.map +1 -1
  177. package/esm/http/context/request-context.mjs.map +1 -1
  178. package/esm/http/context/request-memo.d.mts.map +1 -1
  179. package/esm/http/context/request-memo.mjs.map +1 -1
  180. package/esm/http/createHttpApplication.d.mts.map +1 -1
  181. package/esm/http/createHttpApplication.mjs.map +1 -1
  182. package/esm/http/health.d.mts.map +1 -1
  183. package/esm/http/index.d.mts +1 -0
  184. package/esm/http/index.mjs +1 -0
  185. package/esm/http/middleware/cache-response-middleware.mjs.map +1 -1
  186. package/esm/http/middleware/idempotency.middleware.mjs.map +1 -1
  187. package/esm/http/middleware/inject-request-context.mjs.map +1 -1
  188. package/esm/http/middleware/ip-filter.middleware.d.mts +1 -1
  189. package/esm/http/middleware/ip-filter.middleware.mjs +1 -1
  190. package/esm/http/middleware/ip-filter.middleware.mjs.map +1 -1
  191. package/esm/http/middleware/maintenance.middleware.mjs.map +1 -1
  192. package/esm/http/middleware/utils/idempotency-key.mjs.map +1 -1
  193. package/esm/http/port-preflight.d.mts +8 -0
  194. package/esm/http/port-preflight.d.mts.map +1 -1
  195. package/esm/http/port-preflight.mjs +8 -1
  196. package/esm/http/port-preflight.mjs.map +1 -1
  197. package/esm/http/ready-report.d.mts.map +1 -1
  198. package/esm/http/request-controller.d.mts.map +1 -1
  199. package/esm/http/request.d.mts +14 -2
  200. package/esm/http/request.d.mts.map +1 -1
  201. package/esm/http/request.mjs +16 -2
  202. package/esm/http/request.mjs.map +1 -1
  203. package/esm/http/response.d.mts +3 -3
  204. package/esm/http/response.d.mts.map +1 -1
  205. package/esm/http/response.mjs.map +1 -1
  206. package/esm/http/server.d.mts.map +1 -1
  207. package/esm/http/server.mjs +26 -2
  208. package/esm/http/server.mjs.map +1 -1
  209. package/esm/http/types.d.mts +1 -3
  210. package/esm/http/types.d.mts.map +1 -1
  211. package/esm/http/uploaded-file.d.mts.map +1 -1
  212. package/esm/http/uploaded-file.mjs.map +1 -1
  213. package/esm/http/uploads-config.d.mts.map +1 -1
  214. package/esm/image/image.d.mts.map +1 -1
  215. package/esm/image/image.mjs.map +1 -1
  216. package/esm/index.d.mts +6 -1
  217. package/esm/index.mjs +6 -1
  218. package/esm/logger/fatal-visibility.d.mts +25 -0
  219. package/esm/logger/fatal-visibility.d.mts.map +1 -0
  220. package/esm/logger/fatal-visibility.mjs +31 -0
  221. package/esm/logger/fatal-visibility.mjs.map +1 -0
  222. package/esm/logger/index.d.mts +1 -0
  223. package/esm/logger/index.mjs +1 -0
  224. package/esm/logger/logger.mjs.map +1 -1
  225. package/esm/mail/config.d.mts.map +1 -1
  226. package/esm/mail/events.d.mts.map +1 -1
  227. package/esm/mail/mail.d.mts.map +1 -1
  228. package/esm/mail/mail.mjs.map +1 -1
  229. package/esm/mail/mailer-pool.d.mts.map +1 -1
  230. package/esm/mail/mailer-pool.mjs +2 -0
  231. package/esm/mail/mailer-pool.mjs.map +1 -1
  232. package/esm/mail/send-mail.mjs.map +1 -1
  233. package/esm/mail/test-mailbox.d.mts.map +1 -1
  234. package/esm/mail/test-mailbox.mjs.map +1 -1
  235. package/esm/production/assert-dist-ready-to-start.mjs +24 -0
  236. package/esm/production/assert-dist-ready-to-start.mjs.map +1 -0
  237. package/esm/production/assert-generated-imports.mjs.map +1 -1
  238. package/esm/production/build-app-production.mjs.map +1 -1
  239. package/esm/production/dist-build-manifest.mjs +47 -0
  240. package/esm/production/dist-build-manifest.mjs.map +1 -0
  241. package/esm/production/production-builder.mjs +68 -13
  242. package/esm/production/production-builder.mjs.map +1 -1
  243. package/esm/production/production-supervisor.mjs +21 -9
  244. package/esm/production/production-supervisor.mjs.map +1 -1
  245. package/esm/production/promote-dist.mjs +115 -0
  246. package/esm/production/promote-dist.mjs.map +1 -0
  247. package/esm/production/resolve-build-config.mjs.map +1 -1
  248. package/esm/repositories/adapters/cascade/cascade-adapter.d.mts.map +1 -1
  249. package/esm/repositories/adapters/cascade/cascade-adapter.mjs.map +1 -1
  250. package/esm/repositories/adapters/cascade/cascade-query-builder.d.mts.map +1 -1
  251. package/esm/repositories/adapters/cascade/cascade-query-builder.mjs.map +1 -1
  252. package/esm/repositories/adapters/cascade/filter-applicator.mjs.map +1 -1
  253. package/esm/repositories/repository.manager.d.mts.map +1 -1
  254. package/esm/repositories/repository.manager.mjs.map +1 -1
  255. package/esm/resource/register-resource.d.mts.map +1 -1
  256. package/esm/resource/resource-field-builder.d.mts.map +1 -1
  257. package/esm/resource/resource-field-builder.mjs.map +1 -1
  258. package/esm/resource/resource.d.mts.map +1 -1
  259. package/esm/resource/resource.mjs.map +1 -1
  260. package/esm/restful/restful.d.mts.map +1 -1
  261. package/esm/restful/restful.mjs.map +1 -1
  262. package/esm/router/index.d.mts +3 -0
  263. package/esm/router/index.mjs +3 -0
  264. package/esm/router/log-request-lifecycle.mjs.map +1 -1
  265. package/esm/router/normalize-request-path.d.mts +14 -0
  266. package/esm/router/normalize-request-path.d.mts.map +1 -0
  267. package/esm/router/normalize-request-path.mjs +18 -0
  268. package/esm/router/normalize-request-path.mjs.map +1 -0
  269. package/esm/router/normalize-route-path.d.mts +28 -0
  270. package/esm/router/normalize-route-path.d.mts.map +1 -0
  271. package/esm/router/normalize-route-path.mjs +33 -0
  272. package/esm/router/normalize-route-path.mjs.map +1 -0
  273. package/esm/router/positional-handler-diagnostics.d.mts.map +1 -1
  274. package/esm/router/positional-handler-diagnostics.mjs.map +1 -1
  275. package/esm/router/route-name-method-suffix.d.mts +33 -0
  276. package/esm/router/route-name-method-suffix.d.mts.map +1 -0
  277. package/esm/router/route-name-method-suffix.mjs +39 -0
  278. package/esm/router/route-name-method-suffix.mjs.map +1 -0
  279. package/esm/router/route-registry.d.mts.map +1 -1
  280. package/esm/router/route-registry.mjs +3 -2
  281. package/esm/router/route-registry.mjs.map +1 -1
  282. package/esm/router/router.d.mts +14 -0
  283. package/esm/router/router.d.mts.map +1 -1
  284. package/esm/router/router.mjs +50 -11
  285. package/esm/router/router.mjs.map +1 -1
  286. package/esm/socket/utils.d.mts.map +1 -1
  287. package/esm/storage/config.d.mts.map +1 -1
  288. package/esm/storage/context/storage-driver-context.d.mts.map +1 -1
  289. package/esm/storage/drivers/cloud-driver.d.mts.map +1 -1
  290. package/esm/storage/drivers/cloud-driver.mjs.map +1 -1
  291. package/esm/storage/drivers/do-spaces-driver.d.mts.map +1 -1
  292. package/esm/storage/drivers/local-driver.d.mts.map +1 -1
  293. package/esm/storage/drivers/local-driver.mjs.map +1 -1
  294. package/esm/storage/drivers/r2-driver.d.mts.map +1 -1
  295. package/esm/storage/scoped-storage.d.mts.map +1 -1
  296. package/esm/storage/scoped-storage.mjs.map +1 -1
  297. package/esm/storage/storage-file.d.mts.map +1 -1
  298. package/esm/storage/storage-file.mjs.map +1 -1
  299. package/esm/storage/storage.d.mts.map +1 -1
  300. package/esm/storage/types.d.mts +14 -0
  301. package/esm/storage/types.d.mts.map +1 -1
  302. package/esm/storage/utils/safe-fetch.mjs.map +1 -1
  303. package/esm/tests/start-http-development-server.d.mts.map +1 -1
  304. package/esm/tests/start-http-development-server.mjs +2 -1
  305. package/esm/tests/start-http-development-server.mjs.map +1 -1
  306. package/esm/tests/test-connectors-selection.mjs.map +1 -1
  307. package/esm/tests/test-helpers.d.mts.map +1 -1
  308. package/esm/tests/test-setup-timeout.mjs.map +1 -1
  309. package/esm/tests/vitest-setup.d.mts.map +1 -1
  310. package/esm/tests/vitest-setup.mjs.map +1 -1
  311. package/esm/updater/update-warlock-packages.mjs.map +1 -1
  312. package/esm/use-cases/use-case-broadcast.d.mts.map +1 -1
  313. package/esm/use-cases/use-case-events.d.mts.map +1 -1
  314. package/esm/use-cases/use-case-pipeline.d.mts.map +1 -1
  315. package/esm/use-cases/use-case.d.mts.map +1 -1
  316. package/esm/use-cases/use-cases-registry.d.mts.map +1 -1
  317. package/esm/use-cases/use-cases-registry.mjs.map +1 -1
  318. package/esm/utils/database-log.d.mts.map +1 -1
  319. package/esm/utils/database-log.mjs.map +1 -1
  320. package/esm/utils/environment.d.mts.map +1 -1
  321. package/esm/utils/framework-vesion.mjs.map +1 -1
  322. package/esm/utils/get-localized.mjs.map +1 -1
  323. package/esm/utils/load-environment.mjs.map +1 -1
  324. package/esm/utils/normalized-path.d.mts.map +1 -1
  325. package/esm/utils/paths.d.mts.map +1 -1
  326. package/esm/utils/promise-all-object.d.mts.map +1 -1
  327. package/esm/utils/promise-all-object.mjs.map +1 -1
  328. package/esm/utils/sluggable.mjs.map +1 -1
  329. package/esm/utils/version-compare.mjs.map +1 -1
  330. package/esm/validation/database/exists-except-current-id.mjs.map +1 -1
  331. package/esm/validation/database/exists-except-current-user.mjs.map +1 -1
  332. package/esm/validation/database/unique-except-current-id.mjs.map +1 -1
  333. package/esm/validation/plugins/localized-plugin.mjs.map +1 -1
  334. package/esm/validation/validators/file-validator.mjs.map +1 -1
  335. package/esm/vite/lower-stage3-decorators.d.mts.map +1 -1
  336. package/esm/warlock-config/default-configurations.mjs.map +1 -1
  337. package/esm/warlock-config/warlock-config.manager.d.mts.map +1 -1
  338. package/esm/warlock-config/warlock-config.manager.mjs.map +1 -1
  339. package/llms-full.txt +205 -90
  340. package/llms.txt +5 -5
  341. package/package.json +12 -12
  342. package/skills/add-connector/SKILL.md +35 -28
  343. package/skills/create-controller/SKILL.md +1 -1
  344. package/skills/create-module/SKILL.md +12 -12
  345. package/skills/hash-password/SKILL.md +4 -4
  346. package/skills/run-app/SKILL.md +77 -16
  347. package/skills/send-mail/SKILL.md +2 -2
  348. package/skills/use-middleware/SKILL.md +13 -4
  349. package/skills/use-model-transformers/SKILL.md +2 -2
  350. package/skills/use-repository/SKILL.md +1 -1
  351. package/skills/validate-input/SKILL.md +1 -1
  352. package/skills/warlock-conventions/SKILL.md +1 -1
  353. package/skills/warlock-doctor/SKILL.md +3 -3
  354. package/skills/warlock-routes/SKILL.md +47 -9
  355. package/skills/write-cli-command/SKILL.md +1 -1
  356. package/skills/write-seeder/SKILL.md +8 -8
package/llms-full.txt CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  ---
10
10
  name: add-connector
11
- description: 'Extend Warlock''s lifecycle with a `BaseConnector` subclass `name`, `priority`, `lifecyclePhase`, `start()`, `shutdown()`, `watchedFiles`. Register the instance via `connectorsManager.register(...)`; framework-level `warlock.config.ts > connectors` is planned but not shipped yet. Triggers: `BaseConnector`, `connectorsManager.register`, `ConnectorLifecyclePhase`, `ConnectorPriority`, `ConnectorName`; "add a queue worker", "wire a scheduler into bootstrap", "control startup ordering", "graceful shutdown hook"; typical import `import { BaseConnector, connectorsManager } from "@warlock.js/core"`. Skip: app context accessors — `@warlock.js/core/use-app-context/SKILL.md`; warlock.config.ts surface — `@warlock.js/core/configure-app/SKILL.md`; competing pattern: hand-rolled `process.on("SIGINT")` blocks, NestJS `OnModuleInit` lifecycle.'
11
+ description: 'Extend Warlock with a `BaseConnector` subclass and register its instance in `warlock.config.ts > connectors`. Covers runtime lifecycle (`boot`, `start`, `shutdown`, priority, phase, watched files) and the optional static `build.generate` / `build.emit` contribution used by `warlock build`. Triggers: `BaseConnector`, `connectors`, `ConnectorLifecyclePhase`, `ConnectorBuildContribution`, `build.generate`, `build.emit`; "add a queue worker", "wire a subsystem into bootstrap", "contribute files to warlock build", "control startup ordering", "graceful shutdown hook". Skip: app context accessors — `@warlock.js/core/use-app-context/SKILL.md`; general config shape — `@warlock.js/core/configure-app/SKILL.md`; competing pattern: hand-rolled process signal blocks, NestJS lifecycle hooks.'
12
12
  ---
13
13
 
14
14
  # Warlock — add a connector
@@ -44,7 +44,7 @@ export class QueueConnector extends BaseConnector {
44
44
  }
45
45
  ```
46
46
 
47
- That's the connector class. The file's home is `src/connectors/<name>.ts` by convention — but **placing it there does not register it**. Custom connectors must be registered explicitly via `connectorsManager.register(...)` (see [Registering a connector](#registering-a-connector) below).
47
+ That's the connector class. The file's home is `src/connectors/<name>.ts` by convention — but **placing it there does not register it**. Add an instance to `warlock.config.ts > connectors` (see [Registering a connector](#registering-a-connector) below).
48
48
 
49
49
  ## `BaseConnector` — required surface
50
50
 
@@ -100,37 +100,44 @@ If your connector is a self-contained service (queue client, scheduler), `Early`
100
100
 
101
101
  ## Registering a connector
102
102
 
103
- `connectorsManager.register(new YourConnector())` is the only path today. Nothing scans `src/connectors/` automatically the folder is a convention for *where the file lives*, not a discovery mechanism. Place the registration call in your project's `src/app/main.ts` (auto-loaded once at boot, before the manager runs the early-phase startup):
103
+ `warlock.config.ts > connectors` is the canonical source for both runtime boot and production-build contributions. Nothing scans `src/connectors/` automatically.
104
104
 
105
- ```ts title="src/app/main.ts"
106
- import { connectorsManager } from "@warlock.js/core";
107
- import { QueueConnector } from "../connectors/queue-connector";
105
+ ```ts title="warlock.config.ts"
106
+ import { defineConfig } from "@warlock.js/core";
107
+ import { QueueConnector } from "./src/connectors/queue-connector";
108
108
 
109
- connectorsManager.register(new QueueConnector());
109
+ export default defineConfig({
110
+ connectors: [new QueueConnector()],
111
+ });
110
112
  ```
111
113
 
112
- `connectorsManager` is the singleton instance of `ConnectorsManager` exported from `@warlock.js/core`. `register(...connectors)` accepts one or many; it appends each to the list and re-sorts by priority.
114
+ Order the array deliberately: runtime startup still follows connector priority, while build hooks are drained sequentially in array order. Names must be unique and must not claim a built-in connector name; Warlock rejects either mistake before boot or build work begins.
113
115
 
114
- Conditional registration is just an `if`:
116
+ ## Optional production-build contribution
115
117
 
116
- ```ts title="src/app/main.ts"
117
- import { config, connectorsManager } from "@warlock.js/core";
118
- import { ExperimentalIndexerConnector } from "../connectors/experimental-indexer-connector";
118
+ A connector may expose a static `build` object with `generate` and/or `emit`. Import `ConnectorBuildContribution` as a type and add the following property to the connector class. `warlock build` reads it from the configured instance without calling runtime `boot()` or `start()`.
119
119
 
120
- if (config.key("search.experimental.enabled")) {
121
- connectorsManager.register(new ExperimentalIndexerConnector());
122
- }
120
+ ```ts title="inside your connector class"
121
+ public readonly build: ConnectorBuildContribution = {
122
+ generate: async context => {
123
+ // Write generated server files beneath context.productionDir.
124
+ // Import optional build tooling inside this hook, not at module scope.
125
+ return {
126
+ entryImports: ['await import("./pages");'],
127
+ esbuild: { external: ["optional-server-peer"] },
128
+ };
129
+ },
130
+ emit: async context => {
131
+ // Emit non-esbuild artifacts after the server bundle is complete.
132
+ },
133
+ };
123
134
  ```
124
135
 
125
- > **Heads up planned change.** A framework-level `warlock.config.ts > connectors: [...]` field is planned so connectors register the same way `cli.commands` do today. Once shipped, the canonical pattern becomes:
126
- >
127
- > ```ts title="warlock.config.ts (planned)"
128
- > export default defineConfig({
129
- > connectors: [new QueueConnector(), new SchedulerConnector()],
130
- > });
131
- > ```
132
- >
133
- > Tracking: [`domains/core/plans/2026-05-23-connectors-in-warlock-config.md`](../../../../domains/core/plans/2026-05-23-connectors-in-warlock-config.md). Until that lands, use `connectorsManager.register(...)` in `main.ts`.
136
+ - `generate(context)` runs before esbuild. It may write into `context.productionDir`, append generated-entry imports, and return a narrow esbuild patch (`jsx`, `jsxImportSource`, `define`, `external`, or `loader`). Generated files are dependency-checked again before bundling.
137
+ - `emit(context)` runs after esbuild and before `.warlock/production` is removed; use it for artifacts esbuild does not produce, such as a client bundle or manifest.
138
+ - Hooks are awaited sequentially in configured array order. A throw names the connector and fails the build.
139
+ - The `build` object is closed to these two hooks. Construct plugins, pipelines, and aliases inside a hook via dynamic import so build-only dependencies do not enter the connector's runtime import graph.
140
+ - Contributor esbuild patches merge before the user's `build` config; user values win. `define` and `loader` merge by key, while `external` concatenates and deduplicates.
134
141
 
135
142
  ## `watchedFiles` and dev restarts
136
143
 
@@ -227,7 +234,7 @@ See the [Registering a connector](#registering-a-connector) section above for th
227
234
  - **Set `this.active = true` only on success.** If `start()` throws partway, leaving `active` true means `shutdown()` thinks it has work to do and may double-close half-initialized resources.
228
235
  - **`shutdown()` must be idempotent.** SIGINT can fire twice on Windows. The manager guards re-entry with its own flag, but individual connectors get called once per shutdown loop — guard with `if (!this.active) return`.
229
236
  - **Don't reach across connector boundaries in `start()`.** The manager's `start()` loop runs all `boot()`s first, then all `start()`s — wiring across connectors goes through the `container` (`container.get("http.server")`), not through imports.
230
- - **Production build still needs registration.** Placing the connector under `src/connectors/<name>.ts` doesn't auto-register it in dev or prod. The connector exists wherever its `connectorsManager.register(...)` call runs typically `src/app/main.ts`. The production bundle picks up that registration because `main.ts` is auto-loaded.
237
+ - **Production build still needs config registration.** Placing the connector under `src/connectors/<name>.ts` does not auto-register it. Put the same instance in `warlock.config.ts > connectors`; that array is what build-time contribution discovery and runtime boot share.
231
238
  - **`watchedFiles` is restart-trigger, not dependency.** It says "I want to restart when this file changes." It does *not* mean the framework reloads that file first — that's the file orchestrator's job.
232
239
 
233
240
  ## See also
@@ -1228,7 +1235,7 @@ That's the full contract. The `RequestHandler` annotation carries both parameter
1228
1235
  - File: `src/app/<module>/controllers/<action>.controller.ts`.
1229
1236
  - Export name matches the action in camelCase + `Controller` suffix: `listProductsController`, `createProductController`, `getProductController`.
1230
1237
 
1231
- Scaffold with: `yarn warlock generate.controller <module>/<action>` (add `--with-validation` to get the schema generated alongside).
1238
+ Scaffold with: `pnpm warlock generate.controller <module>/<action>` (add `--with-validation` to get the schema generated alongside).
1232
1239
 
1233
1240
  ## Reading input
1234
1241
 
@@ -1430,18 +1437,18 @@ No `if (!product)` branch in the controller. The error class carries the HTTP se
1430
1437
 
1431
1438
  ---
1432
1439
  name: create-module
1433
- description: 'Scaffold a new feature module under `src/app/<name>/` via `warlock generate.module` and the follow-up generators for controllers, models, repositories, resources, and validation schemas. Triggers: `warlock generate.module`, `generate.controller`, `generate.service`, `generate.model`, `generate.repository`, `generate.resource`, `generate.migration`, `--minimal`, `gen.m`; "scaffold a new module", "create CRUD bootstrap", "add a controller to a module", "generate a model"; typical CLI `yarn warlock generate.module <name>`. Skip: framework-wide layout rules — `@warlock.js/core/warlock-conventions/SKILL.md`; routes file shape — `@warlock.js/core/register-route/SKILL.md`; controller shape — `@warlock.js/core/create-controller/SKILL.md`; competing tooling: `@nestjs/cli`, `hygen`, hand-rolled folder layouts.'
1440
+ description: 'Scaffold a new feature module under `src/app/<name>/` via `warlock generate.module` and the follow-up generators for controllers, models, repositories, resources, and validation schemas. Triggers: `warlock generate.module`, `generate.controller`, `generate.service`, `generate.model`, `generate.repository`, `generate.resource`, `generate.migration`, `--minimal`, `gen.m`; "scaffold a new module", "create CRUD bootstrap", "add a controller to a module", "generate a model"; typical CLI `pnpm warlock generate.module <name>`. Skip: framework-wide layout rules — `@warlock.js/core/warlock-conventions/SKILL.md`; routes file shape — `@warlock.js/core/register-route/SKILL.md`; controller shape — `@warlock.js/core/create-controller/SKILL.md`; competing tooling: `@nestjs/cli`, `hygen`, hand-rolled folder layouts.'
1434
1441
  ---
1435
1442
 
1436
1443
  # Warlock — create a module
1437
1444
 
1438
- A module is a self-contained feature folder under `src/app/<name>/`. The CLI scaffolds the standard subfolders; the framework auto-loads `routes.ts`, `main.ts`, every `.ts(x)` file inside `events/`, and `utils/locales.ts`. You never `import` those files. (`src/app/main.ts` at the project root is also auto-loaded — that's the home for global one-time setup like `connectorsManager.register(...)`.)
1445
+ A module is a self-contained feature folder under `src/app/<name>/`. The CLI scaffolds the standard subfolders; the framework auto-loads `routes.ts`, `main.ts`, every `.ts(x)` file inside `events/`, and `utils/locales.ts`. You never `import` those files. (`src/app/main.ts` at the project root is also auto-loaded for global one-time application setup; connector instances belong in `warlock.config.ts > connectors`.)
1439
1446
 
1440
1447
  ## The shape
1441
1448
 
1442
1449
  ```bash
1443
- yarn warlock generate.module products # full CRUD bootstrap (default — controllers, model, services, repository, resource, schemas, routes, seed)
1444
- yarn warlock generate.module products --minimal # bare bones (routes.ts + main.ts + utils/locales.ts + empty subfolders)
1450
+ pnpm warlock generate.module products # full CRUD bootstrap (default — controllers, model, services, repository, resource, schemas, routes, seed)
1451
+ pnpm warlock generate.module products --minimal # bare bones (routes.ts + main.ts + utils/locales.ts + empty subfolders)
1445
1452
  ```
1446
1453
 
1447
1454
  Full CRUD is the default — opt down to a bare skeleton with `--minimal` (`-m`) when you want to build the module piece by piece. `--force` (`-f`) overwrites existing files. The plural form is auto-derived: `generate.module product` and `generate.module products` produce the same `src/app/products/` folder.
@@ -1547,9 +1554,9 @@ Inside the same module, plain relative imports (`./`, `../`).
1547
1554
  ### Full CRUD bootstrap
1548
1555
 
1549
1556
  ```bash
1550
- yarn warlock generate.module products
1557
+ pnpm warlock generate.module products
1551
1558
  # edit schemas + model fields, then
1552
- yarn warlock migrate
1559
+ pnpm warlock migrate
1553
1560
  ```
1554
1561
 
1555
1562
  The CRUD scaffold's `routes.ts` already chains the five controllers behind `guarded(...)`:
@@ -1577,11 +1584,11 @@ guarded(() => {
1577
1584
  ### Skeleton module, add pieces piecemeal
1578
1585
 
1579
1586
  ```bash
1580
- yarn warlock generate.module orders --minimal
1581
- yarn warlock generate.model orders/order --with-resource
1582
- yarn warlock generate.repository orders/order
1583
- yarn warlock generate.controller orders/place-order --with-validation
1584
- yarn warlock generate.controller orders/list-orders
1587
+ pnpm warlock generate.module orders --minimal
1588
+ pnpm warlock generate.model orders/order --with-resource
1589
+ pnpm warlock generate.repository orders/order
1590
+ pnpm warlock generate.controller orders/place-order --with-validation
1591
+ pnpm warlock generate.controller orders/list-orders
1585
1592
  ```
1586
1593
 
1587
1594
  Then wire URLs by editing `src/app/orders/routes.ts` and the schema rules in `src/app/orders/schema/`.
@@ -1602,7 +1609,7 @@ await warmupProductCache();
1602
1609
  - **There's no standalone `generate.validation` command.** Validation is no longer scaffolded on its own — each controller carries its own schema (imported from `schema/` and bound via `controller.validation`). Generate the controller with `--with-validation` to get the paired schema file, or hand-write the `schema/*.schema.ts`.
1603
1610
  - **No `requests/` folder.** Controllers import the schema's exported type + value directly from `schema/*.schema.ts`; there is no `*.request.ts` alias.
1604
1611
  - **Subfolder is `seeds/` (plural), not `seed/`.** The seed file is `<module>.seed.ts`.
1605
- - **`generate.module` does not run the migration.** It only creates the migration file. Run `yarn warlock migrate` separately to apply it.
1612
+ - **`generate.module` does not run the migration.** It only creates the migration file. Run `pnpm warlock migrate` separately to apply it.
1606
1613
  - **`models/<entity>/` is its own folder, not a flat file.** The generator puts `product.model.ts` inside `models/product/` so migrations can sit beside the model in `models/product/migrations/`.
1607
1614
  - **Don't import `routes.ts`, `main.ts`, or anything in `events/`.** They're auto-loaded; double-loading errors out at boot.
1608
1615
  - **`utils/locales.ts` is mandatory for translation keys.** Skip it and `t("products.notFound")` silently falls back to the key itself.
@@ -2285,7 +2292,7 @@ The "same error for missing user vs wrong password" pattern is deliberate — it
2285
2292
  `hashPassword` / `verifyPassword` need `bcryptjs`. Install it directly:
2286
2293
 
2287
2294
  ```bash
2288
- yarn add bcryptjs
2295
+ pnpm add bcryptjs
2289
2296
  ```
2290
2297
 
2291
2298
  If you skip the install, the first call throws with the framework's install hint:
@@ -2294,14 +2301,14 @@ If you skip the install, the first call throws with the framework's install hint
2294
2301
  Password encryption requires the bcryptjs package.
2295
2302
  Install it with:
2296
2303
 
2297
- yarn add bcryptjs
2304
+ pnpm add bcryptjs
2298
2305
 
2299
2306
  Or with your preferred package manager:
2300
2307
 
2301
- yarn add bcryptjs
2308
+ pnpm add bcryptjs
2302
2309
  ```
2303
2310
 
2304
- There is no `warlock add` feature for password hashing — `bcryptjs` is a plain dependency, so install it directly with `yarn add bcryptjs`.
2311
+ There is no `warlock add` feature for password hashing — `bcryptjs` is a plain dependency, so install it directly with `pnpm add bcryptjs`.
2305
2312
 
2306
2313
  ## Gotchas
2307
2314
 
@@ -3270,7 +3277,7 @@ const result = await measure("publish-event", () =>
3270
3277
 
3271
3278
  ---
3272
3279
  name: run-app
3273
- description: 'Three operational commands — `warlock dev` (HMR + type-gen + health checks), `warlock build` (esbuild bundle), `warlock start` (spawn the production bundle). All flags, all `warlock.config.ts` knobs that shape them. Triggers: `warlock dev`, `warlock build`, `warlock start`, `devServer`, `--fresh`, `--skip-typings`, `--skip-health`, `outdir`, `outFile`, `sourcemap`; "start the dev server", "build for production", "run the bundle", "skip type generation", "tune watch globs", "dev server keyboard shortcuts", "press r to restart", "press q to quit", "restart the dev server"; typical config `warlock.config.ts > devServer / build`. Skip: writing a custom CLI — `@warlock.js/core/write-cli-command/SKILL.md`; config shape — `@warlock.js/core/configure-app/SKILL.md`; competing tooling `nodemon`, `tsx`, `ts-node-dev`, `esbuild` direct.'
3280
+ description: 'Three operational commands — `warlock dev` (HMR + type-gen + health checks), `warlock build` (esbuild bundle), `warlock start` (spawn the production bundle). All flags, all `warlock.config.ts` knobs that shape them. Triggers: `warlock dev`, `warlock build`, `warlock start`, `devServer`, `--fresh`, `--skip-typings`, `--skip-health`, `outdir`, `outFile`, `sourcemap`, `PortInUseError`, `assertPortIsAvailable`, `EADDRINUSE`; "start the dev server", "build for production", "run the bundle", "skip type generation", "tune watch globs", "dev server keyboard shortcuts", "press r to restart", "press q to quit", "restart the dev server", "port already in use"; typical config `warlock.config.ts > devServer / build`. Skip: writing a custom CLI — `@warlock.js/core/write-cli-command/SKILL.md`; config shape — `@warlock.js/core/configure-app/SKILL.md`; competing tooling `nodemon`, `tsx`, `ts-node-dev`, `esbuild` direct.'
3274
3281
  ---
3275
3282
 
3276
3283
  # Warlock — run the app
@@ -3281,13 +3288,13 @@ Three commands move the app through its lifecycle: `dev` while you're editing, `
3281
3288
 
3282
3289
  ```bash
3283
3290
  # Local development
3284
- yarn warlock dev
3291
+ pnpm warlock dev
3285
3292
 
3286
3293
  # Production build
3287
- yarn warlock build
3294
+ pnpm warlock build
3288
3295
 
3289
3296
  # Run the built bundle
3290
- yarn warlock start
3297
+ pnpm warlock start
3291
3298
  ```
3292
3299
 
3293
3300
  `dev` and `start` are **persistent** (long-running, no auto-exit). `build` is one-shot — it exits when the bundle is written.
@@ -3353,6 +3360,8 @@ A worker that dies **after running healthily for at least 5s** — OOM, a native
3353
3360
 
3354
3361
  A worker that dies *sooner* than that failed to **boot** — a broken config, a port already taken — and it has already printed why. Restarting there would just reprint the same error and bury it, so the supervisor mirrors the exit code and stops.
3355
3362
 
3363
+ A busy port is now caught *before* the bind attempt: the HTTP connector calls `assertPortIsAvailable(port, host)` immediately before `listen()`, so the failure is `Port <port> is already in use on <host>. Stop the dev server (or whatever else is listening on port <port>) and run again, or start on a free port…` — not a raw `EADDRINUSE` surfacing from inside Fastify. Same connector, same preflight, for `warlock start`.
3364
+
3356
3365
  Flapping is capped: more than 3 crashes inside 60s and the supervisor gives up rather than restarting behind your back.
3357
3366
 
3358
3367
  An explicit restart (`r`, `u`, a config change) is a *request*, not a crash, so the uptime rule never swallows it.
@@ -3457,6 +3466,23 @@ Defaults are sensible for the typical "Node service" deployment. Knobs to actual
3457
3466
 
3458
3467
  Just `warlockConfig: true`. Build doesn't need the app booted — it reads `warlock.config.ts`, runs esbuild, writes the file. Fast.
3459
3468
 
3469
+ ### The build is all-or-nothing (5.2)
3470
+
3471
+ `warlock build` never writes into `outdir` while it works. It builds into a hidden **sibling** temp directory — `.<outdir-basename>.build-<12 hex>`, e.g. `./.dist.build-9f1c2ab40de7` next to `./dist` — and only when every step has succeeded does it promote that directory into place with a rename. Same volume, so the promotion is atomic.
3472
+
3473
+ Two consequences you can rely on:
3474
+
3475
+ - **A successful build leaves no stale files.** Promotion replaces `outdir` wholesale (the old one is moved aside, the temp is renamed in, the old one is deleted). A file that an earlier build emitted and this one did not is gone — it is not merged over.
3476
+ - **A failed build leaves no usable `dist`.** The error path removes the temp directory and rethrows without ever touching `outdir`. A previous good `dist` is left exactly as it was; if there was none, none appears.
3477
+
3478
+ The last thing written into the temp directory before promotion is `.warlock-build.json`, a two-field marker:
3479
+
3480
+ ```json
3481
+ { "status": "success", "builtAt": "2026-09-01T12:34:56.789Z" }
3482
+ ```
3483
+
3484
+ It exists so `warlock start` can tell a promoted build from a directory that merely looks like one.
3485
+
3460
3486
  ### Where the bundle lands
3461
3487
 
3462
3488
  ```
@@ -3466,16 +3492,28 @@ Just `warlockConfig: true`. Build doesn't need the app booted — it reads `warl
3466
3492
 
3467
3493
  `warlock start` uses the same `resolveBuildConfig()` helper to find the bundle, so the two commands stay in sync no matter how you override the config. If `build` and `start` disagree on where the bundle is, it's because `warlock.config.ts` is being read with different cwds — never the case in normal operation.
3468
3494
 
3495
+ If the app uses `@warlock.js/web` page routes, a successful `warlock build` also writes `page-routes.manifest.json` next to the bundle (same `outdir`) — the snapshot `warlock routes:diff` compares the live dev surface against. See [`warlock-routes/SKILL.md`](../warlock-routes/SKILL.md#warlock-routesdiff--catch-page-route-drift-before-it-ships).
3496
+
3469
3497
  ## `warlock start` — run the production bundle
3470
3498
 
3471
3499
  Spawns `node <entryPath>` as a child process, forwarding signals (SIGINT / SIGTERM). `entryPath` is resolved from the same `build` config that produced the bundle.
3472
3500
 
3501
+ ### It refuses a `dist` no successful build produced (5.2)
3502
+
3503
+ Before spawning anything, `start` looks for the `.warlock-build.json` success marker in `outdir`. Missing, unreadable, malformed, or `status !== "success"` all collapse to one refusal on **stderr**, exit code `1`:
3504
+
3505
+ ```
3506
+ ✖ "dist" was not produced by a successful `warlock build` run (no build-success marker found). Run `warlock build` before `warlock start`.
3507
+ ```
3508
+
3509
+ The three cases that reach it are: never built; a build that failed before promotion; and a directory assembled or edited by hand. They are deliberately not distinguished — the answer to all three is the same command. Note this replaces the old behaviour where `start` ran whatever happened to be sitting in `dist/`.
3510
+
3473
3511
  ### Behavior
3474
3512
 
3475
3513
  ```bash
3476
- yarn warlock start # → spawns node --enable-source-maps dist/app.js
3477
- yarn warlock start --inspect # → spawns node --enable-source-maps --inspect dist/app.js
3478
- yarn warlock start --max-old-space-size=4096 # → spawns node --enable-source-maps --max-old-space-size=4096 dist/app.js
3514
+ pnpm warlock start # → spawns node --enable-source-maps dist/app.js
3515
+ pnpm warlock start --inspect # → spawns node --enable-source-maps --inspect dist/app.js
3516
+ pnpm warlock start --max-old-space-size=4096 # → spawns node --enable-source-maps --max-old-space-size=4096 dist/app.js
3479
3517
  ```
3480
3518
 
3481
3519
  Everything you pass after `start` is forwarded to the spawned Node process. Use this to attach a debugger (`--inspect`), tune memory (`--max-old-space-size`), or pass any other Node flag without editing the command.
@@ -3527,9 +3565,37 @@ The started banner prints **only** when the running application reports a comple
3527
3565
 
3528
3566
  ```bash
3529
3567
  # a CI gate can be this blunt, and it is now correct
3530
- yarn warlock start | grep -q "production server started"
3568
+ pnpm warlock start | grep -q "production server started"
3569
+ ```
3570
+
3571
+ ### Reading a failed start (5.2)
3572
+
3573
+ The child is spawned with piped stdout/stderr and **every chunk is forwarded verbatim, live**, to the parent's matching stream. The application's own boot error is the thing you read — `warlock start` adds a summary underneath it, it does not replace it:
3574
+
3575
+ ```
3576
+ ✖ warlock start failed — the server never finished booting
3577
+ the application process exited with code 1
3578
+ the cause is printed above, in the application's own output
3531
3579
  ```
3532
3580
 
3581
+ The third line is conditional on the parent having actually seen child output. When the child produced none, it says so instead of pointing at something that isn't there:
3582
+
3583
+ ```
3584
+ no output was captured from the application process — its cause did not reach this terminal
3585
+ ```
3586
+
3587
+ That distinction is the point of the change: an unhelpful "see above" printed above an empty terminal used to be the entire diagnostic.
3588
+
3589
+ **Port already in use.** The HTTP connector preflights the port immediately before `listen()`, so a collision is named rather than surfacing as a raw `EADDRINUSE` from inside Fastify:
3590
+
3591
+ ```
3592
+ EADDRINUSE: Port 3000 is already in use on 127.0.0.1. Stop the dev server (or whatever
3593
+ else is listening on port 3000) and run again, or start on a free port — e.g.
3594
+ startHttpTestServer({ port: 3001 }).
3595
+ ```
3596
+
3597
+ The connector logs it fatally and exits `1`; the supervisor forwards that text and then prints the failure summary above it. `EACCES` on the port is treated the same way as `EADDRINUSE` (a privileged port you may not bind is also "not available"); anything else the probe throws is rethrown untouched.
3598
+
3533
3599
  ### How readiness is reported
3534
3600
 
3535
3601
  `warlock start` spawns the bundle with an IPC channel and sets `WARLOCK_BOOT_SIGNAL=1` on it. `Application.markBooted()` — which the production entry calls after the late-phase connectors (http, socket) are up — sends one versioned message and closes the channel:
@@ -3574,7 +3640,7 @@ If you need conditional behavior, branch on `Application.environment` (the ortho
3574
3640
  }
3575
3641
  ```
3576
3642
 
3577
- Now `yarn dev` / `yarn build` / `yarn start`. Standard Node hosting providers (Render, Fly, Railway, Heroku) recognize this layout.
3643
+ Now `pnpm dev` / `pnpm build` / `pnpm start`. Standard Node hosting providers (Render, Fly, Railway, Heroku) recognize this layout.
3578
3644
 
3579
3645
  ### Production Dockerfile
3580
3646
 
@@ -3582,9 +3648,9 @@ Now `yarn dev` / `yarn build` / `yarn start`. Standard Node hosting providers (R
3582
3648
  FROM node:20-alpine AS build
3583
3649
  WORKDIR /app
3584
3650
  COPY package.json yarn.lock ./
3585
- RUN yarn install --frozen-lockfile
3651
+ RUN pnpm install --frozen-lockfile
3586
3652
  COPY . .
3587
- RUN yarn warlock build
3653
+ RUN pnpm warlock build
3588
3654
 
3589
3655
  FROM node:20-alpine
3590
3656
  WORKDIR /app
@@ -3628,7 +3694,7 @@ That is deliberate: `build` and `start` do **not** force `production`. Forcing i
3628
3694
  ### Skip type-gen on machines without write access
3629
3695
 
3630
3696
  ```bash
3631
- yarn warlock dev --skip-typings
3697
+ pnpm warlock dev --skip-typings
3632
3698
  ```
3633
3699
 
3634
3700
  Or persist it:
@@ -3646,21 +3712,22 @@ Useful in a containerized dev environment where `.warlock/typings.d.ts` is read-
3646
3712
  ### Memory-tune the production process
3647
3713
 
3648
3714
  ```bash
3649
- yarn warlock start --max-old-space-size=4096
3715
+ pnpm warlock start --max-old-space-size=4096
3650
3716
  ```
3651
3717
 
3652
3718
  Or via `NODE_OPTIONS` in the deployment env if you don't want to change the start invocation:
3653
3719
 
3654
3720
  ```bash
3655
- NODE_OPTIONS=--max-old-space-size=4096 yarn warlock start
3721
+ NODE_OPTIONS=--max-old-space-size=4096 pnpm warlock start
3656
3722
  ```
3657
3723
 
3658
3724
  ## Gotchas
3659
3725
 
3660
3726
  - **`warlock dev` is persistent — `Ctrl+C` to stop.** The framework's `persistent: true` flag keeps the process alive after `action` returns. Same for `start`.
3661
3727
  - **`--fresh` only deletes the manifest, not the transpile cache.** If you're chasing a stale-compile bug, `rm -rf .warlock/` clears everything. The manifest restoring is what `--fresh` solves.
3662
- - **`warlock build` does NOT run migrations.** Production bundles ship the migration files but don't apply them. Run `yarn warlock migrate` against the production DB separately.
3663
- - **`warlock start` requires a built bundle.** Run `warlock build` first, or you'll spawn `node` against a non-existent file and crash immediately.
3728
+ - **`warlock build` does NOT run migrations.** Production bundles ship the migration files but don't apply them. Run `pnpm warlock migrate` against the production DB separately.
3729
+ - **`warlock start` requires a build it can vouch for.** Since 5.2 it refuses any `outdir` without the `.warlock-build.json` success marker a hand-assembled `dist/`, or one left behind by a build that failed, is rejected by that reason instead of being spawned and crashing halfway through boot. Run `warlock build` first.
3730
+ - **Do not add `.warlock-build.json` to `.gitignore`-driven artifact pruning.** Stripping it from a `dist/` you ship makes `warlock start` refuse the artifact on the target host. Copy `outdir` whole.
3664
3731
  - **`outdir` is the directory, `outFile` is the filename within it.** A common mistake is putting the full path in one and leaving the other default — you end up with `<full-path>/app.js` or `dist/<full-path>`. They concatenate.
3665
3732
  - **`sourcemap: false` cascades to `start`.** Stack traces lose `.ts` precision. Keep sourcemaps on unless artifact size is a hard constraint.
3666
3733
  - **`NODE_ENV` is not set by these commands.** The deployment env (your Dockerfile, CI, hosting provider) sets it. Forget it on a production server and `Application.isProduction` returns `false`, which flips cookie security, CORS, logging — silently. Always set `NODE_ENV=production` in production deployments.
@@ -3673,6 +3740,7 @@ NODE_OPTIONS=--max-old-space-size=4096 yarn warlock start
3673
3740
  - [`use-app-context/SKILL.md`](../use-app-context/SKILL.md) — `Application.environment` vs `Application.runtimeStrategy`.
3674
3741
  - [`add-connector/SKILL.md`](../add-connector/SKILL.md) — Early vs Late connector phases (why HTTP/socket boot late in dev).
3675
3742
  - [`update-packages/SKILL.md`](../update-packages/SKILL.md) — `warlock update` + the dev-server update notice (`devServer.checkForUpdates`).
3743
+ - [`warlock-routes/SKILL.md`](../warlock-routes/SKILL.md) — `warlock routes` / `warlock routes:diff`, the latter comparing live page routes against the manifest `warlock build` writes.
3676
3744
 
3677
3745
 
3678
3746
  ## send-mail `@warlock.js/core/send-mail/SKILL.md`
@@ -3764,7 +3832,7 @@ const config: MailConfigurations = {
3764
3832
  };
3765
3833
  ```
3766
3834
 
3767
- Requires `@aws-sdk/client-sesv2` installed (`yarn add @aws-sdk/client-sesv2`).
3835
+ Requires `@aws-sdk/client-sesv2` installed (`pnpm add @aws-sdk/client-sesv2`).
3768
3836
 
3769
3837
  ## Mail modes
3770
3838
 
@@ -4040,7 +4108,7 @@ await Mail.to(user.email)
4040
4108
 
4041
4109
  - **`.send()` validates** — `to`, `subject`, and at least one of `text`/`html`/`component` are required. Missing any throws synchronously.
4042
4110
  - **`@react-email/render` is optional.** Without it you get the basic fallback (inline styles, no MSO conditionals). Install it for production-quality HTML.
4043
- - **`nodemailer` is loaded lazily** at import time. If you see `nodemailer is not installed` errors, run `warlock add mail` (or `yarn add nodemailer`).
4111
+ - **`nodemailer` is loaded lazily** at import time. If you see `nodemailer is not installed` errors, run `warlock add mail` (or `pnpm add nodemailer`).
4044
4112
  - **`secure: true` requires port 465.** For port 587 use `secure: false` and `tls: true` (STARTTLS).
4045
4113
  - **Test mode is process-global.** Set it in `beforeAll`/`beforeEach`; reset with `setMailMode("production")` (or rely on test runner isolation).
4046
4114
  - **Per-mail handlers don't replace global ones** — both fire. Avoid double-counting metrics.
@@ -6601,16 +6669,25 @@ export default {
6601
6669
 
6602
6670
  ⚠ **Since 4.13.0 `http.trustProxy` defaults to `false`**, so `request.detectIp()` returns the socket address and **`X-Real-IP` / `X-Forwarded-For` are ignored unless you opt in.** Before 4.13.0 the default was `true`, which meant any client could set its own forwarding header and be believed.
6603
6671
 
6604
- ⚠ **Opt in with the narrowest shape your topology allows, not with `true`.** Since 4.15.0 `http.trustProxy` takes a hop count or a trusted-proxy list, and `detectIp()` resolves the chain the same way Fastify's `request.ip` does:
6672
+ ⚠ **Opt in with the narrowest shape your topology allows, not with `true`.** `http.trustProxy` takes a trusted-proxy list, and `detectIp()` resolves the chain the same way Fastify's `request.ip` does:
6605
6673
 
6606
6674
  | `http.trustProxy` | Client IP |
6607
6675
  | --- | --- |
6608
6676
  | `false` *(default)* | Socket peer address |
6609
- | `2` | Walks past the 2 rightmost `X-Forwarded-For` hops for an edge that **appends** (the usual case: nginx, ALB, most CDNs) |
6610
- | `"10.0.0.0/8"` / `["10.0.0.0/8", "192.168.0.0/16"]` | Walks left while each hop is a listed proxy |
6677
+ | `"10.0.0.0/8"` / `"loopback, 10.0.0.0/8"` / `["10.0.0.0/8", "192.168.0.0/16"]` | Walks left while each hop is a listed proxy, stops at the first that isn't |
6678
+ | `(address, hop) => boolean` | Your own predicate |
6611
6679
  | `true` | Trusts the whole chain — the leftmost hop, i.e. **whatever the client put there** if your edge appends rather than overwrites |
6612
6680
 
6613
- With `true`, any client that can reach the process directly picks its own IP and this allowlist is decorative. `X-Real-IP` is honoured only under `true` it carries no chain to check a hop count or proxy list against so if your edge sets only that header, have it set `X-Forwarded-For` too.
6681
+ **Since 5.2 the value is validated at boot, and a hop count is refused.** The accepted shapes are exactly `boolean`, a non-empty string (comma-separated IPs/CIDRs), a non-empty `string[]`, and an `(address, hop) => boolean` predicate. Missing or nullish means `false`. Anything else a **number**, `""`, `[]`, a mixed array, a plain objectthrows a `TypeError` while the HTTP server is being constructed instead of being silently coerced:
6682
+
6683
+ ```
6684
+ Invalid http.trustProxy configuration: expected a boolean, a non-empty IP/CIDR string,
6685
+ a non-empty string array, or a predicate function; received number.
6686
+ ```
6687
+
6688
+ A hop count (`trustProxy: 2`) used to be documented as the shape to prefer. It is now refused **loudly**, because the Fastify version Warlock builds against treats a number as always-false at runtime: it silently degraded to "trust nothing" rather than walking past your proxies. Express the same topology as a proxy list (`"10.0.0.0/8"`) or a predicate.
6689
+
6690
+ With `true`, any client that can reach the process directly picks its own IP and this allowlist is decorative. `X-Real-IP` is honoured only under `true` — it carries no chain to check a proxy list against — so if your edge sets only that header, have it set `X-Forwarded-For` too.
6614
6691
 
6615
6692
  ```ts
6616
6693
  import { middleware } from "@warlock.js/core";
@@ -6784,7 +6861,7 @@ What it does at save time:
6784
6861
  | Existing row, password unchanged | Pass through (no re-hashing — stored hash preserved). |
6785
6862
  | Empty / undefined value | Pass through untouched. |
6786
6863
 
6787
- Calls `authService.hashPassword(String(value))` under the hood — same bcryptjs path as the standalone `hashPassword()` helper. See [`hash-password/SKILL.md`](../hash-password/SKILL.md) for full bcrypt setup (salt rounds, `yarn add bcryptjs`).
6864
+ Calls `authService.hashPassword(String(value))` under the hood — same bcryptjs path as the standalone `hashPassword()` helper. See [`hash-password/SKILL.md`](../hash-password/SKILL.md) for full bcrypt setup (salt rounds, `pnpm add bcryptjs`).
6788
6865
 
6789
6866
  ### Why declarative wins
6790
6867
 
@@ -6938,7 +7015,7 @@ Rule of thumb: transformers are for **pure, deterministic** transforms of the ro
6938
7015
 
6939
7016
  ## See also
6940
7017
 
6941
- - [`hash-password/SKILL.md`](../hash-password/SKILL.md) — the bcrypt setup that `useHashedPassword` calls under the hood; salt rounds, `yarn add bcryptjs`.
7018
+ - [`hash-password/SKILL.md`](../hash-password/SKILL.md) — the bcrypt setup that `useHashedPassword` calls under the hood; salt rounds, `pnpm add bcryptjs`.
6942
7019
  - [`use-repository/SKILL.md`](../use-repository/SKILL.md) — where `create` / `save` calls happen that trigger the transformers.
6943
7020
  - [`define-resource/SKILL.md`](../define-resource/SKILL.md) — filtering transformed fields (`password`) out of API responses.
6944
7021
  - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — schema files live in `src/app/<module>/models/<entity>/<entity>.model.ts`.
@@ -7001,7 +7078,7 @@ Five lines do the heavy lifting:
7001
7078
  4. **`defaultOptions`** — applied to every call (`orderBy`, default `limit`, etc.).
7002
7079
  5. **`new FaqsRepository()`** singleton — import this everywhere; never instantiate again.
7003
7080
 
7004
- The class is intentionally private — only the singleton escapes the module. Scaffold with `yarn warlock generate.repository <module>/<entity>`.
7081
+ The class is intentionally private — only the singleton escapes the module. Scaffold with `pnpm warlock generate.repository <module>/<entity>`.
7005
7082
 
7006
7083
  ## The `filterBy` rules
7007
7084
 
@@ -7600,7 +7677,7 @@ Two pieces, always:
7600
7677
 
7601
7678
  No separate `*.request.ts` alias file. `RequestHandler<Request<TSchema>>` types `request.validated()` directly off the schema's inferred type.
7602
7679
 
7603
- Scaffold with `yarn warlock generate.controller <module>/<action> --with-validation`. If the scaffolder emits a `requests/<action>.request.ts` file, delete it — the inline pattern is the convention.
7680
+ Scaffold with `pnpm warlock generate.controller <module>/<action> --with-validation`. If the scaffolder emits a `requests/<action>.request.ts` file, delete it — the inline pattern is the convention.
7604
7681
 
7605
7682
  ## The `v.*` factory surface
7606
7683
 
@@ -7867,7 +7944,7 @@ This skill is the foundation. Every other warlock skill (`register-route`, `crea
7867
7944
  2. **Several files are auto-loaded — never `import` them.** The dev-server file watcher and the production builder categorize these as "special" and load them on boot.
7868
7945
  - `src/app/<module>/routes.ts` — route declarations
7869
7946
  - `src/app/<module>/main.ts` — per-module one-time setup
7870
- - `src/app/main.ts` — **project-level** one-time setup (where `connectorsManager.register(...)`, global hooks, etc. live)
7947
+ - `src/app/main.ts` — **project-level** one-time application setup (global hooks and other app initialization; connector instances belong in `warlock.config.ts > connectors`)
7871
7948
  - `src/app/<module>/events/*.ts(x)` — **any** `.ts(x)` file inside the `events/` folder (the `*.event.ts` suffix is convention, not a framework requirement)
7872
7949
  - `src/app/<module>/utils/locales.ts` — module translations via `groupedTranslations(...)`
7873
7950
  - `src/config/*.ts(x)` — subsystem config files
@@ -7987,7 +8064,7 @@ Cascade uses `@RegisterModel()` for the model registry and `@BelongsTo` / `@HasM
7987
8064
 
7988
8065
  ---
7989
8066
  name: warlock-doctor
7990
- description: 'Run `warlock doctor` — a read-only diagnostics command that checks routes / config / connectors / optional-peers / health endpoints / release hygiene and prints a pass/warn/fail report, exiting non-zero on any failure. Add your own probe with the `DoctorCheck` contract and `runChecks` / `formatReportLines`. Triggers: `warlock doctor`, `doctorCommand`, `DoctorCheck`, `CheckResult`, `CheckStatus`, `DoctorReport`, `runChecks`, `formatReportLines`, `printReport`, `defaultDoctorChecks`; "diagnose my app", "preflight / preflight check", "is the app healthy", "why are there 0 routes", "pre-release sanity check", "CI smoke check"; run as `yarn warlock doctor`. Skip: the live `/health` + `/ready` HTTP probes — `@warlock.js/core/health-checks/SKILL.md`; authoring a general CLI command — `@warlock.js/core/write-cli-command/SKILL.md`; releasing the package — `releasing-warlock-monorepo`; competing tools `npm doctor`, `nest info`, hand-rolled preflight scripts.'
8067
+ description: 'Run `warlock doctor` — a read-only diagnostics command that checks routes / config / connectors / optional-peers / health endpoints / release hygiene and prints a pass/warn/fail report, exiting non-zero on any failure. Add your own probe with the `DoctorCheck` contract and `runChecks` / `formatReportLines`. Triggers: `warlock doctor`, `doctorCommand`, `DoctorCheck`, `CheckResult`, `CheckStatus`, `DoctorReport`, `runChecks`, `formatReportLines`, `printReport`, `defaultDoctorChecks`; "diagnose my app", "preflight / preflight check", "is the app healthy", "why are there 0 routes", "pre-release sanity check", "CI smoke check"; run as `pnpm warlock doctor`. Skip: the live `/health` + `/ready` HTTP probes — `@warlock.js/core/health-checks/SKILL.md`; authoring a general CLI command — `@warlock.js/core/write-cli-command/SKILL.md`; releasing the package — `releasing-warlock-monorepo`; competing tools `npm doctor`, `nest info`, hand-rolled preflight scripts.'
7991
8068
  ---
7992
8069
 
7993
8070
  # Warlock — `warlock doctor`
@@ -7995,7 +8072,7 @@ description: 'Run `warlock doctor` — a read-only diagnostics command that chec
7995
8072
  `warlock doctor` is a read-only preflight. It boots the app far enough to introspect it — loads every config file and bootstrap code so routes and connectors register — but **starts no connectors**, so it never opens a database, cache, or socket connection. It then runs a set of checks and prints a grouped pass / warn / fail report.
7996
8073
 
7997
8074
  ```bash
7998
- yarn warlock doctor
8075
+ pnpm warlock doctor
7999
8076
  ```
8000
8077
 
8001
8078
  ```
@@ -8098,7 +8175,7 @@ if (report.hasFailures) process.exit(report.exitCode);
8098
8175
  ### CI / pre-release gate
8099
8176
 
8100
8177
  ```bash
8101
- yarn warlock doctor || exit 1 # non-zero exit fails the job
8178
+ pnpm warlock doctor || exit 1 # non-zero exit fails the job
8102
8179
  ```
8103
8180
 
8104
8181
  A red `release-hygiene` line catches the classic "bumped `package.json` but forgot the CHANGELOG heading" mistake before a publish.
@@ -8126,7 +8203,7 @@ A `⚠ routes: 0 routes registered` line is the tell that a route module threw o
8126
8203
 
8127
8204
  ---
8128
8205
  name: warlock-routes
8129
- description: 'Run `warlock routes` — a read-only command that lists the registered HTTP routes as a verb-colored table (method / path / name / action / middleware-count / source), a sibling of `warlock doctor`. Filter with `--method` / `--path` / `--name`, or emit normalized rows as JSON with `--json`. Triggers: `warlock routes`, `routesCommand`, "list my routes", "show all routes", "route table", "what endpoints does my app expose", "dump routes as JSON", "which routes have middleware", "route map for CI"; run as `yarn warlock routes`. Skip: read-only health/preflight checks — `@warlock.js/core/warlock-doctor/SKILL.md`; defining/naming/grouping routes — `@warlock.js/core/register-route/SKILL.md`; authoring a general CLI command — `@warlock.js/core/write-cli-command/SKILL.md`; competing tools `nest`/`express` route listers, `php artisan route:list`.'
8206
+ description: 'Run `warlock routes` — a read-only command that lists the registered HTTP routes as a verb-colored table (method / path / name / action / middleware-count / source), a sibling of `warlock doctor`. Filter with `--method` / `--path` / `--name`, or emit normalized rows as JSON with `--json`. Also covers `warlock routes:diff`, which compares live page routes against the last `warlock build`''s route snapshot and exits non-zero on drift. Triggers: `warlock routes`, `routesCommand`, `warlock routes:diff`, `routesDiffCommand`, "list my routes", "show all routes", "route table", "what endpoints does my app expose", "dump routes as JSON", "which routes have middleware", "route map for CI", "did my page routes drift from the last build"; run as `pnpm warlock routes` / `pnpm warlock routes:diff`. Skip: read-only health/preflight checks — `@warlock.js/core/warlock-doctor/SKILL.md`; defining/naming/grouping routes — `@warlock.js/core/register-route/SKILL.md`; authoring a general CLI command — `@warlock.js/core/write-cli-command/SKILL.md`; competing tools `nest`/`express` route listers, `php artisan route:list`.'
8130
8207
  ---
8131
8208
 
8132
8209
  # Warlock — `warlock routes`
@@ -8134,7 +8211,7 @@ description: 'Run `warlock routes` — a read-only command that lists the regist
8134
8211
  `warlock routes` lists every registered HTTP route as a table. It's the read-only sibling of [`warlock doctor`](../warlock-doctor/SKILL.md): it boots the app far enough to register route modules — but **starts no connectors**, so it never opens a database, cache, or socket connection.
8135
8212
 
8136
8213
  ```bash
8137
- yarn warlock routes
8214
+ pnpm warlock routes
8138
8215
  ```
8139
8216
 
8140
8217
  ```
@@ -8165,10 +8242,10 @@ The `METHOD` column is verb-colored (GET green, POST blue, PUT/PATCH yellow, DEL
8165
8242
  Optional, case-insensitive, AND-combined:
8166
8243
 
8167
8244
  ```bash
8168
- yarn warlock routes --method GET # -m exact HTTP method
8169
- yarn warlock routes --path /users # -p path substring
8170
- yarn warlock routes --name users # -n route-name substring
8171
- yarn warlock routes -m POST -p /users
8245
+ pnpm warlock routes --method GET # -m exact HTTP method
8246
+ pnpm warlock routes --path /users # -p path substring
8247
+ pnpm warlock routes --name users # -n route-name substring
8248
+ pnpm warlock routes -m POST -p /users
8172
8249
  ```
8173
8250
 
8174
8251
  ## JSON output
@@ -8176,7 +8253,7 @@ yarn warlock routes -m POST -p /users
8176
8253
  `--json` (`-j`) emits the normalized rows instead of the table — for `jq`, a CI diff, or a generated API map. Filters apply before serialization.
8177
8254
 
8178
8255
  ```bash
8179
- yarn warlock routes --json
8256
+ pnpm warlock routes --json
8180
8257
  ```
8181
8258
 
8182
8259
  ```json
@@ -8190,7 +8267,7 @@ yarn warlock routes --json
8190
8267
  ### Audit which routes are guarded
8191
8268
 
8192
8269
  ```bash
8193
- yarn warlock routes --json | jq '[.[] | select(.middleware == 0)]'
8270
+ pnpm warlock routes --json | jq '[.[] | select(.middleware == 0)]'
8194
8271
  ```
8195
8272
 
8196
8273
  Surfaces public routes (no middleware) — a quick check that auth-protected paths actually carry a guard.
@@ -8198,11 +8275,48 @@ Surfaces public routes (no middleware) — a quick check that auth-protected pat
8198
8275
  ### Confirm a route registered
8199
8276
 
8200
8277
  ```bash
8201
- yarn warlock routes --name users.create
8278
+ pnpm warlock routes --name users.create
8202
8279
  ```
8203
8280
 
8204
8281
  An empty result means the route isn't registered — re-run `warlock dev` and read the boot error (the route-module loader is fail-loud, so a throwing route file aborts boot rather than being silently dropped).
8205
8282
 
8283
+ ## `warlock routes:diff` — catch page-route drift before it ships
8284
+
8285
+ Compares the **live dev-server page routes** (`router.list().filter(r => r.isPage)`) against a **snapshot written by the last successful `warlock build`** (`page-routes.manifest.json` in `resolveBuildConfig().outdir`, e.g. `dist/page-routes.manifest.json`). Boots the same diagnostic way as `warlock routes` — route modules registered, no connectors started — then diffs.
8286
+
8287
+ ```bash
8288
+ pnpm warlock routes:diff
8289
+ ```
8290
+
8291
+ ```
8292
+ Page routes match (4 routes).
8293
+ Note: page names are compared as DERIVED by the build, so a clean diff does not prove
8294
+ that no route name collided at registration (the router appends `.<method>` to a name
8295
+ already claimed by another method). Run `warlock routes` to see the registered names.
8296
+ ```
8297
+
8298
+ **A clean baseline is now expected immediately after a successful `warlock build`.** Through 5.1, running `routes:diff` on an untouched checkout right after a green build reported drift, because the manifest recorded the catch-all as `"*"` while the router serves it as `"/*"`. The manifest is now written through the router's own path normalizer, so the two sides agree and a clean tree reports clean. If you see drift on a tree you have not edited since building, that is a bug worth reporting — it is no longer the expected greeting.
8299
+
8300
+ ⚠ **What a clean diff does NOT prove.** The manifest records what each page's name was **derived** as, not what it was **registered** as. `warlock build` never boots connectors, so it cannot see the API routes a page name might collide with; when a name is already claimed by another method the router appends a `.<method>` suffix at registration, and the comparison accepts that suffix rather than reporting it as drift. So `Page routes match` means *the page surface did not move since the build* — it does not mean *no page route name collided*. Use `warlock routes` to see the names as actually registered.
8301
+
8302
+ or, on drift:
8303
+
8304
+ ```
8305
+ changed - GET /blog/:slug blog.post (src/web/blog/[slug].page.tsx)
8306
+ + GET /blog/:id blog.post (src/web/blog/[slug].page.tsx)
8307
+ removed - GET /legacy legacy.home
8308
+ added + GET /promo promo.home (src/web/promo.page.tsx)
8309
+ Page route drift: 1 changed, 1 removed, 1 added. Run `warlock build` after reviewing these changes.
8310
+ ```
8311
+
8312
+ and exits non-zero.
8313
+
8314
+ - **Identity is `method` + `path` + `name`.** A route is only reported `changed` — instead of one `removed` line and one unrelated `added` line — when it shares its **`source` file** with the route it's being paired against. A moved checkout (same source, different absolute path on disk) never shows as drift; a route whose declared path/name literally changed in the same file does.
8315
+ - **Requires a prior successful build.** No `page-routes.manifest.json` yet, or a malformed one → the command refuses to run and tells you to `warlock build` first, rather than diffing against nothing.
8316
+ - **Fails loudly on a broken dev boot**, same as `warlock routes` / `warlock doctor` — a route module that throws on import, or a connector registration error, aborts before any comparison happens.
8317
+ - **Only page routes are compared.** API routes registered without `isPage` never appear on either side of the diff; this command exists for the file-system page-routing surface `@warlock.js/web` adds, not the general route table.
8318
+ - **Core reads the snapshot; it does not write it.** `warlock build` writes `page-routes.manifest.json` through a connector's `build`/`emit` contribution (`@warlock.js/web`'s build integration, keyed off pages it discovers) — a project with no `@warlock.js/web` page routes never produces one, and `routes:diff` has nothing to compare against.
8319
+
8206
8320
  ## Gotchas
8207
8321
 
8208
8322
  - **No connectors are started.** The list reflects what's *registered*, not what would connect. It never opens a DB/cache/socket.
@@ -8214,6 +8328,7 @@ An empty result means the route isn't registered — re-run `warlock dev` and re
8214
8328
 
8215
8329
  - [`warlock-doctor/SKILL.md`](../warlock-doctor/SKILL.md) — the read-only diagnostics sibling; its `routes` check warns when this table would be empty.
8216
8330
  - [`register-route/SKILL.md`](../register-route/SKILL.md) — defining, naming, and grouping the routes this command lists.
8331
+ - [`run-app/SKILL.md`](../run-app/SKILL.md) — `warlock build`, the command that produces the snapshot `routes:diff` compares against.
8217
8332
  - [`write-cli-command/SKILL.md`](../write-cli-command/SKILL.md) — the command + `preload` shape `routesCommand` is built from.
8218
8333
 
8219
8334
 
@@ -8548,7 +8663,7 @@ export default command({
8548
8663
  });
8549
8664
  ```
8550
8665
 
8551
- Run it: `yarn warlock users.promote --email=hasan@example.com` (or `yarn warlock up -e hasan@example.com`).
8666
+ Run it: `pnpm warlock users.promote --email=hasan@example.com` (or `pnpm warlock up -e hasan@example.com`).
8552
8667
 
8553
8668
  ## `CLICommandOptions` — the factory input
8554
8669
 
@@ -9080,12 +9195,12 @@ export default seeder({
9080
9195
  Run them:
9081
9196
 
9082
9197
  ```bash
9083
- yarn warlock seed # discover + run all
9084
- yarn warlock seed --list # show registry, don't run
9085
- yarn warlock seed --path=src/app/roles/seeds/default-roles.seed.ts # one file
9086
- yarn warlock seed --fresh # truncate every table first, then run all
9087
- yarn warlock seed --drop # undo every tracked record, reset the log
9088
- yarn warlock seed --drop=default-roles # undo just one seeder's records
9198
+ pnpm warlock seed # discover + run all
9199
+ pnpm warlock seed --list # show registry, don't run
9200
+ pnpm warlock seed --path=src/app/roles/seeds/default-roles.seed.ts # one file
9201
+ pnpm warlock seed --fresh # truncate every table first, then run all
9202
+ pnpm warlock seed --drop # undo every tracked record, reset the log
9203
+ pnpm warlock seed --drop=default-roles # undo just one seeder's records
9089
9204
  ```
9090
9205
 
9091
9206
  `--fresh` truncates **every** table in the DB (`datasource.driver.truncateTable(table, { cascade: true })`), including the `seeds` tracking table. After `--fresh`, `once: true` seeds will run again.
@@ -9223,8 +9338,8 @@ Every record you `track()` is written to a `seed_records` table (created on firs
9223
9338
  `warlock seed --drop` reads those refs and undoes the seed:
9224
9339
 
9225
9340
  ```bash
9226
- yarn warlock seed --drop # undo every tracked record across all seeders
9227
- yarn warlock seed --drop=default-roles # undo just one seeder's records
9341
+ pnpm warlock seed --drop # undo every tracked record across all seeders
9342
+ pnpm warlock seed --drop=default-roles # undo just one seeder's records
9228
9343
  ```
9229
9344
 
9230
9345
  What it does, inside a single transaction: