@warlock.js/core 5.27.0 → 5.29.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 (127) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/esm/cli/commands/openapi-generator.action.mjs +1 -1
  3. package/esm/cli/commands/openapi-generator.action.mjs.map +1 -1
  4. package/esm/cli/commands/postman-generator.action.mjs +47 -0
  5. package/esm/cli/commands/postman-generator.action.mjs.map +1 -0
  6. package/esm/cli/commands/postman-generator.command.mjs +43 -0
  7. package/esm/cli/commands/postman-generator.command.mjs.map +1 -0
  8. package/esm/cli/framework-cli-commands.mjs +2 -0
  9. package/esm/cli/framework-cli-commands.mjs.map +1 -1
  10. package/esm/container/development-app-modules.d.mts +31 -0
  11. package/esm/container/development-app-modules.d.mts.map +1 -0
  12. package/esm/container/index.d.mts +2 -0
  13. package/esm/container/index.d.mts.map +1 -1
  14. package/esm/container/index.mjs.map +1 -1
  15. package/esm/dev-server/app-module-registry.mjs +52 -0
  16. package/esm/dev-server/app-module-registry.mjs.map +1 -0
  17. package/esm/dev-server/files-orchestrator.mjs +13 -2
  18. package/esm/dev-server/files-orchestrator.mjs.map +1 -1
  19. package/esm/http/middleware/inject-request-context.d.mts.map +1 -1
  20. package/esm/http/middleware/inject-request-context.mjs +29 -3
  21. package/esm/http/middleware/inject-request-context.mjs.map +1 -1
  22. package/esm/http/request.d.mts +2 -2
  23. package/esm/http/request.d.mts.map +1 -1
  24. package/esm/index.d.mts +7 -2
  25. package/esm/index.mjs +5 -2
  26. package/esm/localization/parse-locale-dictionary.d.mts +6 -1
  27. package/esm/localization/parse-locale-dictionary.d.mts.map +1 -1
  28. package/esm/localization/parse-locale-dictionary.mjs +5 -1
  29. package/esm/localization/parse-locale-dictionary.mjs.map +1 -1
  30. package/esm/openapi/development-openapi-provider.d.mts +12 -1
  31. package/esm/openapi/development-openapi-provider.d.mts.map +1 -1
  32. package/esm/openapi/development-openapi-provider.mjs +15 -1
  33. package/esm/openapi/development-openapi-provider.mjs.map +1 -1
  34. package/esm/openapi/index.d.mts +5 -2
  35. package/esm/openapi/index.mjs +3 -1
  36. package/esm/openapi/postman/build-request-body.mjs +86 -0
  37. package/esm/openapi/postman/build-request-body.mjs.map +1 -0
  38. package/esm/openapi/postman/build-request-url.mjs +85 -0
  39. package/esm/openapi/postman/build-request-url.mjs.map +1 -0
  40. package/esm/openapi/postman/build-saved-responses.mjs +60 -0
  41. package/esm/openapi/postman/build-saved-responses.mjs.map +1 -0
  42. package/esm/openapi/postman/example-from-schema.d.mts +17 -0
  43. package/esm/openapi/postman/example-from-schema.d.mts.map +1 -0
  44. package/esm/openapi/postman/example-from-schema.mjs +92 -0
  45. package/esm/openapi/postman/example-from-schema.mjs.map +1 -0
  46. package/esm/openapi/postman/http-status-text.mjs +31 -0
  47. package/esm/openapi/postman/http-status-text.mjs.map +1 -0
  48. package/esm/openapi/postman/index.d.mts +3 -0
  49. package/esm/openapi/postman/openapi-to-postman-collection.d.mts +22 -0
  50. package/esm/openapi/postman/openapi-to-postman-collection.d.mts.map +1 -0
  51. package/esm/openapi/postman/openapi-to-postman-collection.mjs +109 -0
  52. package/esm/openapi/postman/openapi-to-postman-collection.mjs.map +1 -0
  53. package/esm/openapi/postman/postman-types.d.mts +119 -0
  54. package/esm/openapi/postman/postman-types.d.mts.map +1 -0
  55. package/esm/openapi/postman/resolve-operation-auth.mjs +51 -0
  56. package/esm/openapi/postman/resolve-operation-auth.mjs.map +1 -0
  57. package/esm/openapi/postman/schema-refs.d.mts +7 -0
  58. package/esm/openapi/postman/schema-refs.d.mts.map +1 -0
  59. package/esm/openapi/postman/schema-refs.mjs +41 -0
  60. package/esm/openapi/postman/schema-refs.mjs.map +1 -0
  61. package/esm/openapi/postman/uuid-v5.mjs +29 -0
  62. package/esm/openapi/postman/uuid-v5.mjs.map +1 -0
  63. package/esm/openapi/response-schemas.mjs +4 -1
  64. package/esm/openapi/response-schemas.mjs.map +1 -1
  65. package/esm/openapi/schema-registry.mjs +6 -0
  66. package/esm/openapi/schema-registry.mjs.map +1 -1
  67. package/esm/resource/index.d.mts +1 -0
  68. package/esm/resource/index.mjs +1 -0
  69. package/esm/resource/nullable-resource.d.mts +44 -0
  70. package/esm/resource/nullable-resource.d.mts.map +1 -0
  71. package/esm/resource/nullable-resource.mjs +38 -0
  72. package/esm/resource/nullable-resource.mjs.map +1 -0
  73. package/esm/resource/resource.d.mts.map +1 -1
  74. package/esm/resource/resource.mjs +24 -7
  75. package/esm/resource/resource.mjs.map +1 -1
  76. package/esm/resource/types.d.mts +10 -5
  77. package/esm/resource/types.d.mts.map +1 -1
  78. package/esm/restful/restful.d.mts +5 -5
  79. package/esm/restful/restful.d.mts.map +1 -1
  80. package/esm/router/response-schema-types.mjs +2 -0
  81. package/esm/router/response-schema-types.mjs.map +1 -1
  82. package/llms-full.txt +269 -241
  83. package/llms.txt +42 -42
  84. package/package.json +12 -12
  85. package/skills/README.md +39 -39
  86. package/skills/add-connector/SKILL.md +4 -4
  87. package/skills/benchmark-code/SKILL.md +3 -3
  88. package/skills/build-restful/SKILL.md +5 -5
  89. package/skills/build-url/SKILL.md +7 -7
  90. package/skills/configure-app/SKILL.md +7 -7
  91. package/skills/create-controller/SKILL.md +8 -8
  92. package/skills/create-module/SKILL.md +9 -9
  93. package/skills/define-resource/SKILL.md +4 -4
  94. package/skills/encrypt-data/SKILL.md +7 -7
  95. package/skills/generate-openapi/SKILL.md +33 -5
  96. package/skills/hash-password/SKILL.md +8 -8
  97. package/skills/health-checks/SKILL.md +6 -6
  98. package/skills/lower-stage3-decorators/SKILL.md +4 -4
  99. package/skills/process-image/SKILL.md +5 -5
  100. package/skills/register-route/SKILL.md +6 -6
  101. package/skills/request-memo/SKILL.md +4 -4
  102. package/skills/request-tracing/SKILL.md +6 -6
  103. package/skills/resolve-path/SKILL.md +6 -6
  104. package/skills/retry-operation/SKILL.md +4 -4
  105. package/skills/run-app/SKILL.md +11 -11
  106. package/skills/send-mail/SKILL.md +3 -3
  107. package/skills/send-response/SKILL.md +6 -6
  108. package/skills/store-file/SKILL.md +4 -4
  109. package/skills/test-http/SKILL.md +5 -5
  110. package/skills/test-service/SKILL.md +5 -5
  111. package/skills/update-packages/SKILL.md +6 -6
  112. package/skills/upload-file/SKILL.md +7 -7
  113. package/skills/use-app-context/SKILL.md +7 -7
  114. package/skills/use-localization/SKILL.md +6 -6
  115. package/skills/use-middleware/SKILL.md +6 -6
  116. package/skills/use-model-transformers/SKILL.md +6 -6
  117. package/skills/use-repository/SKILL.md +7 -7
  118. package/skills/use-request-locals/SKILL.md +4 -4
  119. package/skills/validate-input/SKILL.md +7 -7
  120. package/skills/warlock-conventions/SKILL.md +6 -6
  121. package/skills/warlock-doctor/SKILL.md +5 -5
  122. package/skills/warlock-routes/SKILL.md +6 -6
  123. package/skills/wire-socket/SKILL.md +4 -4
  124. package/skills/write-cli-command/SKILL.md +6 -6
  125. package/skills/write-middleware/SKILL.md +8 -8
  126. package/skills/write-seeder/SKILL.md +5 -5
  127. package/skills/write-use-case/SKILL.md +3 -3
package/llms-full.txt CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  ---
10
10
  name: add-connector
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.'
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 — the `use-app-context` topic; general config shape — the `configure-app` topic; competing pattern: hand-rolled process signal blocks, NestJS lifecycle hooks.'
12
12
  ---
13
13
 
14
14
  # Warlock — add a connector
@@ -243,16 +243,16 @@ See the [Registering a connector](#registering-a-connector) section above for th
243
243
 
244
244
  ## See also
245
245
 
246
- - [`configure-app/SKILL.md`](../configure-app/SKILL.md) — `warlock.config.ts`, config files, env.
247
- - [`use-app-context/SKILL.md`](../use-app-context/SKILL.md) — checking environment + paths inside `start()`.
248
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — module layout, canonical imports.
246
+ - The `configure-app` topic — `warlock.config.ts`, config files, env.
247
+ - The `use-app-context` topic — checking environment + paths inside `start()`.
248
+ - The `warlock-conventions` topic — module layout, canonical imports.
249
249
 
250
250
 
251
251
  ## benchmark-code `@warlock.js/core/benchmark-code/SKILL.md`
252
252
 
253
253
  ---
254
254
  name: benchmark-code
255
- description: 'Wrap a function with `measure(name, fn, options?)` to time it and classify the latency — onComplete/onError/onFinish hooks, `latencyRange` thresholds, `BenchmarkProfiler` for percentiles, `BenchmarkSnapshots` for raw captures. Triggers: `measure`, `BenchmarkProfiler`, `BenchmarkSnapshots`, `BenchmarkChannel`, `ConsoleChannel`, `latencyRange`, `shouldBenchmarkError`; "time this operation", "profile a slow service", "emit p50/p95/p99 metrics", "classify latency against thresholds"; typical import `import { measure, BenchmarkProfiler } from "@warlock.js/core"`. Skip: retry composition — `@warlock.js/core/retry-operation/SKILL.md`; benchmark config wiring — `@warlock.js/core/configure-app/SKILL.md`; competing libs `prom-client`, `pino`, `perf_hooks`, `console.time`.'
255
+ description: 'Wrap a function with `measure(name, fn, options?)` to time it and classify the latency — onComplete/onError/onFinish hooks, `latencyRange` thresholds, `BenchmarkProfiler` for percentiles, `BenchmarkSnapshots` for raw captures. Triggers: `measure`, `BenchmarkProfiler`, `BenchmarkSnapshots`, `BenchmarkChannel`, `ConsoleChannel`, `latencyRange`, `shouldBenchmarkError`; "time this operation", "profile a slow service", "emit p50/p95/p99 metrics", "classify latency against thresholds"; typical import `import { measure, BenchmarkProfiler } from "@warlock.js/core"`. Skip: retry composition — the `retry-operation` topic; benchmark config wiring — the `configure-app` topic; competing libs `prom-client`, `pino`, `perf_hooks`, `console.time`.'
256
256
  ---
257
257
 
258
258
  # Warlock — benchmark code
@@ -504,15 +504,15 @@ The `latency` is the *total* time including retries — useful for the SLO you a
504
504
 
505
505
  ## See also
506
506
 
507
- - [`retry-operation/SKILL.md`](../retry-operation/SKILL.md) — wrapping flaky operations with retry; composes inside `measure()`.
508
- - [`configure-app/SKILL.md`](../configure-app/SKILL.md) — wiring `src/config/benchmark.ts`.
507
+ - The `retry-operation` topic — wrapping flaky operations with retry; composes inside `measure()`.
508
+ - The `configure-app` topic — wiring `src/config/benchmark.ts`.
509
509
 
510
510
 
511
511
  ## build-restful `@warlock.js/core/build-restful/SKILL.md`
512
512
 
513
513
  ---
514
514
  name: build-restful
515
- description: 'Generate standard CRUD endpoints — via `router.route(path).list().show().create().update().destroy()` chain or the `Restful` base class. Pick the chain by default; reach for `Restful` when you want repository-bound defaults. Triggers: `router.route`, `Restful`, `router.restfulResource`, `RouteResource`, `.crud`, `.nest`, `beforeCreate`, `onCreate`; "build a CRUD API", "register list/show/create/update/destroy", "repository-bound default handlers", "override a single REST action"; typical import `import { router, Restful } from "@warlock.js/core"`. Skip: wider router surface — `@warlock.js/core/register-route/SKILL.md`; per-action controllers — `@warlock.js/core/create-controller/SKILL.md`; wire mapping — `@warlock.js/core/define-resource/SKILL.md`; competing pattern: hand-rolled controllers, `@nestjs/swagger` decorator-driven CRUD.'
515
+ description: 'Generate standard CRUD endpoints — via `router.route(path).list().show().create().update().destroy()` chain or the `Restful` base class. Pick the chain by default; reach for `Restful` when you want repository-bound defaults. Triggers: `router.route`, `Restful`, `router.restfulResource`, `RouteResource`, `.crud`, `.nest`, `beforeCreate`, `onCreate`; "build a CRUD API", "register list/show/create/update/destroy", "repository-bound default handlers", "override a single REST action"; typical import `import { router, Restful } from "@warlock.js/core"`. Skip: wider router surface — the `register-route` topic; per-action controllers — the `create-controller` topic; wire mapping — the `define-resource` topic; competing pattern: hand-rolled controllers, `@nestjs/swagger` decorator-driven CRUD.'
516
516
  ---
517
517
 
518
518
  # Warlock — build a RESTful resource
@@ -774,22 +774,22 @@ router.restfulResource("/orders", new OrdersRestful());
774
774
 
775
775
  ## See also
776
776
 
777
- - [`register-route/SKILL.md`](../register-route/SKILL.md) — the wider router surface (`group`, `prefix`, plain verbs).
778
- - [`create-controller/SKILL.md`](../create-controller/SKILL.md) — what the chain's handlers look like.
779
- - [`define-resource/SKILL.md`](../define-resource/SKILL.md) — wire shape for the records the chain returns.
780
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — controller/service/repository layering rules.
777
+ - The `register-route` topic — the wider router surface (`group`, `prefix`, plain verbs).
778
+ - The `create-controller` topic — what the chain's handlers look like.
779
+ - The `define-resource` topic — wire shape for the records the chain returns.
780
+ - The `warlock-conventions` topic — controller/service/repository layering rules.
781
781
 
782
782
 
783
783
  ## build-url `@warlock.js/core/build-url/SKILL.md`
784
784
 
785
785
  ---
786
786
  name: build-url
787
- description: 'HTTP URL helpers — `url`, `publicUrl`, `assetsUrl`, `uploadsUrl`, anchored at `app.baseUrl`. Use to render `src` / `href` / API URLs in resources and responses. `setBaseUrl` is wired by the HTTP connector from `config.get("app.baseUrl")`. Triggers: `url`, `publicUrl`, `assetsUrl`, `uploadsUrl`, `setBaseUrl`, `BASE_URL`; "render an avatar src URL", "absolute download link", "embed asset URL in email", "URL helpers vs path helpers"; typical import `import { url, publicUrl, uploadsUrl } from "@warlock.js/core"`. Skip: filesystem paths — `@warlock.js/core/resolve-path/SKILL.md`; signed CDN URLs — `@warlock.js/core/store-file/SKILL.md`; resource output — `@warlock.js/core/define-resource/SKILL.md`; competing patterns: hand-rolled `${baseUrl}/...` template strings.'
787
+ description: 'HTTP URL helpers — `url`, `publicUrl`, `assetsUrl`, `uploadsUrl`, anchored at `app.baseUrl`. Use to render `src` / `href` / API URLs in resources and responses. `setBaseUrl` is wired by the HTTP connector from `config.get("app.baseUrl")`. Triggers: `url`, `publicUrl`, `assetsUrl`, `uploadsUrl`, `setBaseUrl`, `BASE_URL`; "render an avatar src URL", "absolute download link", "embed asset URL in email", "URL helpers vs path helpers"; typical import `import { url, publicUrl, uploadsUrl } from "@warlock.js/core"`. Skip: filesystem paths — the `resolve-path` topic; signed CDN URLs — the `store-file` topic; resource output — the `define-resource` topic; competing patterns: hand-rolled `${baseUrl}/...` template strings.'
788
788
  ---
789
789
 
790
790
  # Warlock — build a URL
791
791
 
792
- Path helpers ([`resolve-path/SKILL.md`](../resolve-path/SKILL.md)) give you absolute filesystem paths. URL helpers give you absolute HTTP URLs. Different jobs, often confused.
792
+ Path helpers (the `resolve-path` topic) give you absolute filesystem paths. URL helpers give you absolute HTTP URLs. Different jobs, often confused.
793
793
 
794
794
  Use URL helpers whenever you need to render a string that goes into a browser, an HTTP client, or an email — `<img src=...>`, `<a href=...>`, an API response that includes a download link, a webhook payload.
795
795
 
@@ -957,18 +957,18 @@ Don't call `setBaseUrl` per request — it's process-global and races every othe
957
957
 
958
958
  ## See also
959
959
 
960
- - [`resolve-path/SKILL.md`](../resolve-path/SKILL.md) — filesystem path helpers (`uploadsPath`, `publicPath`, ...). Use for read/write; use the URL helpers for rendering.
961
- - [`store-file/SKILL.md`](../store-file/SKILL.md) — the `storage.url(path)` driver method, which can produce signed CDN URLs for non-local drivers (S3 etc.). Use that over `uploadsUrl` when you're on a remote driver.
962
- - [`upload-file/SKILL.md`](../upload-file/SKILL.md) — the `UploadedFile` lifecycle; where the path that feeds `uploadsUrl` comes from.
963
- - [`define-resource/SKILL.md`](../define-resource/SKILL.md) — the `url` / `uploadsUrl` / `storageUrl` casts (and resolver functions) are the right place to call URL helpers.
964
- - [`configure-app/SKILL.md`](../configure-app/SKILL.md) — `src/config/app.ts` and the `baseUrl` env wiring.
960
+ - The `resolve-path` topic — filesystem path helpers (`uploadsPath`, `publicPath`, ...). Use for read/write; use the URL helpers for rendering.
961
+ - The `store-file` topic — the `storage.url(path)` driver method, which can produce signed CDN URLs for non-local drivers (S3 etc.). Use that over `uploadsUrl` when you're on a remote driver.
962
+ - The `upload-file` topic — the `UploadedFile` lifecycle; where the path that feeds `uploadsUrl` comes from.
963
+ - The `define-resource` topic — the `url` / `uploadsUrl` / `storageUrl` casts (and resolver functions) are the right place to call URL helpers.
964
+ - The `configure-app` topic — `src/config/app.ts` and the `baseUrl` env wiring.
965
965
 
966
966
 
967
967
  ## configure-app `@warlock.js/core/configure-app/SKILL.md`
968
968
 
969
969
  ---
970
970
  name: configure-app
971
- description: 'Configure a Warlock app — the two layers (`warlock.config.ts` for framework-level wiring, `src/config/*.ts` for subsystems), `.env` + `env()`, the `config()` getter for runtime reads, and `app.publicUrl`/`PUBLIC_APP_URL` (the app''s public origin). Triggers: `defineConfig`, `config.get`, `config.key`, `env`, `ConfigRegistry`, `HttpConfigurations`, `AppConfigurations`, `publicUrl`, `PUBLIC_APP_URL`, `getPublicUrl`; "add a new config file", "warlock.config.ts vs src/config", "read env values", "runtime config lookup", "app public origin/URL"; typical import `import { defineConfig, config, env } from "@warlock.js/core"`. Skip: cache driver registration — `@warlock.js/cache/cache-basics/SKILL.md`; mail config — `@warlock.js/core/send-mail/SKILL.md`; storage config — `@warlock.js/core/store-file/SKILL.md`; sitemap refusal on a missing origin — `@warlock.js/web/generate-sitemap/SKILL.md`; competing libs `dotenv` direct, `convict`, `node-config`.'
971
+ description: 'Configure a Warlock app — the two layers (`warlock.config.ts` for framework-level wiring, `src/config/*.ts` for subsystems), `.env` + `env()`, the `config()` getter for runtime reads, and `app.publicUrl`/`PUBLIC_APP_URL` (the app''s public origin). Triggers: `defineConfig`, `config.get`, `config.key`, `env`, `ConfigRegistry`, `HttpConfigurations`, `AppConfigurations`, `publicUrl`, `PUBLIC_APP_URL`, `getPublicUrl`; "add a new config file", "warlock.config.ts vs src/config", "read env values", "runtime config lookup", "app public origin/URL"; typical import `import { defineConfig, config, env } from "@warlock.js/core"`. Skip: cache driver registration — the `cache-basics` topic of the `warlock-js-cache` skill; mail config — the `send-mail` topic; storage config — the `store-file` topic; sitemap refusal on a missing origin — the `generate-sitemap` topic of the `warlock-js-web` skill; competing libs `dotenv` direct, `convict`, `node-config`.'
972
972
  ---
973
973
 
974
974
  # Warlock — configure the app
@@ -1059,7 +1059,7 @@ for apps that don't opt in.
1059
1059
  A malformed directive value (containing `;`, or with an unbalanced `'`
1060
1060
  count) throws `InvalidCspDirectiveError` at boot, not silently — fix the
1061
1061
  value in `src/config/http.ts` rather than expecting the framework to repair
1062
- it. See [`send-response/SKILL.md`](../send-response/SKILL.md) for how the
1062
+ it. See the `send-response` topic for how the
1063
1063
  header lands on the response, and `@warlock.js/web`'s docs for how the
1064
1064
  same nonce reaches the page's `<script>` tags.
1065
1065
 
@@ -1240,7 +1240,7 @@ requires the value. `@warlock.js/web`'s sitemap is the first such consumer:
1240
1240
  with `web.sitemap.enabled: true` and no `app.publicUrl`/`PUBLIC_APP_URL` set,
1241
1241
  generation refuses (`MissingPublicUrlError`, naming both) rather than falling
1242
1242
  back to a request-derived host — a sitemap pointing at the wrong host is
1243
- worse than none. See `@warlock.js/web/generate-sitemap/SKILL.md`.
1243
+ worse than none. See the `generate-sitemap` topic of the `warlock-js-web` skill.
1244
1244
 
1245
1245
  ## Common patterns
1246
1246
 
@@ -1270,17 +1270,17 @@ Internal `@warlock.js/*` packages read from `config.get("<name>")` the same way
1270
1270
 
1271
1271
  ## See also
1272
1272
 
1273
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — module layout, canonical imports, framework-wide invariants.
1274
- - [`@warlock.js/cache/pick-cache-driver/SKILL.md`](../../../cache/skills/pick-cache-driver/SKILL.md) — picking and registering a cache driver in `src/config/cache.ts`.
1275
- - [`send-mail/SKILL.md`](../send-mail/SKILL.md) — the `src/config/mail.ts` shape.
1276
- - [`store-file/SKILL.md`](../store-file/SKILL.md) — the `src/config/storage.ts` shape.
1273
+ - The `warlock-conventions` topic — module layout, canonical imports, framework-wide invariants.
1274
+ - The `pick-cache-driver` topic of the `warlock-js-cache` skill — picking and registering a cache driver in `src/config/cache.ts`.
1275
+ - The `send-mail` topic — the `src/config/mail.ts` shape.
1276
+ - The `store-file` topic — the `src/config/storage.ts` shape.
1277
1277
 
1278
1278
 
1279
1279
  ## create-controller `@warlock.js/core/create-controller/SKILL.md`
1280
1280
 
1281
1281
  ---
1282
1282
  name: create-controller
1283
- description: 'Author HTTP controllers in @warlock.js/core — RequestHandler signature, validated input via seal schemas, response helpers, attaching metadata. Controllers are thin functions; business logic moves to services or use-cases. Triggers: `RequestHandler`, `Request<TSchema>`, `GuardedRequestHandler`, `request.validated`, `request.input`, `controller.validation`, `controller.responseSchema`, `response.success`, `response.successCreate`; "write a controller", "attach a schema to a handler", "thin controller pattern", "guarded request type", "type the API response"; typical import `import { type RequestHandler } from "@warlock.js/core"`. Skip: response helper menu — `@warlock.js/core/send-response/SKILL.md`; schema authoring — `@warlock.js/core/validate-input/SKILL.md`; URL wiring — `@warlock.js/core/register-route/SKILL.md`; competing patterns: `express` middleware functions, `@nestjs/common` `@Controller`/`@Get` decorators.'
1283
+ description: 'Author HTTP controllers in @warlock.js/core — RequestHandler signature, validated input via seal schemas, response helpers, attaching metadata. Controllers are thin functions; business logic moves to services or use-cases. Triggers: `RequestHandler`, `Request<TSchema>`, `GuardedRequestHandler`, `request.validated`, `request.input`, `controller.validation`, `controller.responseSchema`, `response.success`, `response.successCreate`; "write a controller", "attach a schema to a handler", "thin controller pattern", "guarded request type", "type the API response"; typical import `import { type RequestHandler } from "@warlock.js/core"`. Skip: response helper menu — the `send-response` topic; schema authoring — the `validate-input` topic; URL wiring — the `register-route` topic; competing patterns: `express` middleware functions, `@nestjs/common` `@Controller`/`@Get` decorators.'
1284
1284
  ---
1285
1285
 
1286
1286
  # Warlock — create a controller
@@ -1328,7 +1328,7 @@ Prefer `request.validated()` once a schema is attached — it's typed.
1328
1328
  | Content type | Parsed by | Notes |
1329
1329
  | ------------------------------------ | -------------------------------- | --------------------------------------------------------------------- |
1330
1330
  | `application/json` | Fastify (built-in) | objects/arrays parsed as-is |
1331
- | `multipart/form-data` | `@fastify/multipart` | fields + files; see [`upload-file`](../upload-file/SKILL.md) |
1331
+ | `multipart/form-data` | `@fastify/multipart` | fields + files; see the `upload-file` topic |
1332
1332
  | `application/x-www-form-urlencoded` | Warlock's own content-type parser (`http/parse-urlencoded-body.ts`) | plain HTML forms, OAuth `form_post` callbacks (e.g. Apple Sign in) |
1333
1333
 
1334
1334
  For urlencoded bodies: fields decode via `URLSearchParams`. A key sent more than once (`tag=a&tag=b`) becomes an array (`request.input("tag")` → `["a", "b"]`); every other key is a plain string. Bracket-notation keys (`a[b]=1`) are **not** expanded by the urlencoded parser itself — nesting only happens through the same shared bracket-key logic every body type already goes through, so it behaves exactly like a JSON or query-string key of that shape, no differently than today.
@@ -1337,7 +1337,7 @@ All three content types are held to the same `http.bodyLimit` — an over-limit
1337
1337
 
1338
1338
  ## Returning output
1339
1339
 
1340
- Pick the helper that matches the outcome. Full surface in [send-response](../send-response/SKILL.md). Quick map:
1340
+ Pick the helper that matches the outcome. Full surface in the `send-response` topic. Quick map:
1341
1341
 
1342
1342
  | Helper | Status | Use when |
1343
1343
  | ---------------------------------- | ------ | ----------------------------- |
@@ -1414,7 +1414,7 @@ Use `RequestHandler<Request<TSchema>>` for public routes, `GuardedRequestHandler
1414
1414
  createProductController.description = "Create a new product (admin only)";
1415
1415
  ```
1416
1416
 
1417
- `description` feeds the OpenAPI document (`warlock generate.openapi`, see [`generate-openapi`](../generate-openapi/SKILL.md)) and surfaces in dev-server logs.
1417
+ `description` feeds the OpenAPI document (`warlock generate.openapi`, see the `generate-openapi` topic) and surfaces in dev-server logs.
1418
1418
 
1419
1419
  ## Declaring response types with `responseSchema`
1420
1420
 
@@ -1542,7 +1542,7 @@ export const getProductController: RequestHandler = async ({ request, response }
1542
1542
  };
1543
1543
  ```
1544
1544
 
1545
- No `if (!product)` branch in the controller. The error class carries the HTTP semantic (`404` for `ResourceNotFoundError`, `403` for `ForbiddenError`, `400` for `BadRequestError`, `409` for `ConflictError`, `500` for `ServerError`). Full list in [`send-response`](../send-response/SKILL.md#throwing-http-errors). `product.notFound` is a translation key — see localization conventions in your project's `utils/locales.ts`.
1545
+ No `if (!product)` branch in the controller. The error class carries the HTTP semantic (`404` for `ResourceNotFoundError`, `403` for `ForbiddenError`, `400` for `BadRequestError`, `409` for `ConflictError`, `500` for `ServerError`). Full list in the `send-response` topic ("Throwing HTTP errors" section). `product.notFound` is a translation key — see localization conventions in your project's `utils/locales.ts`.
1546
1546
 
1547
1547
  ## Gotchas
1548
1548
 
@@ -1553,16 +1553,16 @@ No `if (!product)` branch in the controller. The error class carries the HTTP se
1553
1553
 
1554
1554
  ## See also
1555
1555
 
1556
- - [`register-route/SKILL.md`](../register-route/SKILL.md) — wiring a controller to a URL.
1557
- - [`send-response/SKILL.md`](../send-response/SKILL.md) — full Response helper surface.
1558
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — controller-service-repository layering.
1556
+ - The `register-route` topic — wiring a controller to a URL.
1557
+ - The `send-response` topic — full Response helper surface.
1558
+ - The `warlock-conventions` topic — controller-service-repository layering.
1559
1559
 
1560
1560
 
1561
1561
  ## create-module `@warlock.js/core/create-module/SKILL.md`
1562
1562
 
1563
1563
  ---
1564
1564
  name: create-module
1565
- 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 `npx 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.'
1565
+ 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 `npx warlock generate.module <name>`. Skip: framework-wide layout rules — the `warlock-conventions` topic; routes file shape — the `register-route` topic; controller shape — the `create-controller` topic; competing tooling: `@nestjs/cli`, `hygen`, hand-rolled folder layouts.'
1566
1566
  ---
1567
1567
 
1568
1568
  # Warlock — create a module
@@ -1742,21 +1742,21 @@ await warmupProductCache();
1742
1742
 
1743
1743
  ## See also
1744
1744
 
1745
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — module layout, file suffixes, path aliases.
1746
- - [`register-route/SKILL.md`](../register-route/SKILL.md) — what to put in `routes.ts`.
1747
- - [`create-controller/SKILL.md`](../create-controller/SKILL.md) — the handler shape, attaching validation.
1748
- - [`use-repository/SKILL.md`](../use-repository/SKILL.md) — what the generated `<module>.repository.ts` looks like and how to extend it.
1749
- - [`define-resource/SKILL.md`](../define-resource/SKILL.md) — the output mapper for the model.
1750
- - [`validate-input/SKILL.md`](../validate-input/SKILL.md) — wiring `schema/*.schema.ts` to controllers.
1751
- - [`write-seeder/SKILL.md`](../write-seeder/SKILL.md) — populating the generated `seeds/` folder.
1752
- - [`use-localization/SKILL.md`](../use-localization/SKILL.md) — populating the generated `utils/locales.ts`.
1745
+ - The `warlock-conventions` topic — module layout, file suffixes, path aliases.
1746
+ - The `register-route` topic — what to put in `routes.ts`.
1747
+ - The `create-controller` topic — the handler shape, attaching validation.
1748
+ - The `use-repository` topic — what the generated `<module>.repository.ts` looks like and how to extend it.
1749
+ - The `define-resource` topic — the output mapper for the model.
1750
+ - The `validate-input` topic — wiring `schema/*.schema.ts` to controllers.
1751
+ - The `write-seeder` topic — populating the generated `seeds/` folder.
1752
+ - The `use-localization` topic — populating the generated `utils/locales.ts`.
1753
1753
 
1754
1754
 
1755
1755
  ## define-resource `@warlock.js/core/define-resource/SKILL.md`
1756
1756
 
1757
1757
  ---
1758
1758
  name: define-resource
1759
- description: 'Map model fields to wire-shape via `defineResource()` or `Resource` subclasses. Output-only — never put business logic, hydration, or reconciliation in a resource. Also covers the typed output: `ResourceOutput<typeof R>`, `defineResource<Out>()`, `Serialized<T, W>` and `ModelResourceRegistry`. Triggers: `defineResource`, `Resource`, `RegisterResource`, `toJSON`, `ResourceOutput`, `Serialized`, `ModelResourceRegistry`, `"self"`, `"localized"`, `"uploadsUrl"`; "shape an API response", "type a resource''s output", "what does the client receive", "nest related resources", "rename a field on output", "self-referential tree resource"; typical import `import { defineResource } from "@warlock.js/core"`. Skip: localized columns — `@warlock.js/core/use-localization/SKILL.md`; URL casting — `@warlock.js/core/build-url/SKILL.md`; controller side — `@warlock.js/core/create-controller/SKILL.md`; competing libs `@nestjs/swagger` `@ApiProperty`, `class-transformer`, hand-rolled DTO mappers.'
1759
+ description: 'Map model fields to wire-shape via `defineResource()` or `Resource` subclasses. Output-only — never put business logic, hydration, or reconciliation in a resource. Also covers the typed output: `ResourceOutput<typeof R>`, `defineResource<Out>()`, `Serialized<T, W>` and `ModelResourceRegistry`. Triggers: `defineResource`, `Resource`, `RegisterResource`, `toJSON`, `ResourceOutput`, `Serialized`, `ModelResourceRegistry`, `"self"`, `"localized"`, `"uploadsUrl"`; "shape an API response", "type a resource''s output", "what does the client receive", "nest related resources", "rename a field on output", "self-referential tree resource"; typical import `import { defineResource } from "@warlock.js/core"`. Skip: localized columns — the `use-localization` topic; URL casting — the `build-url` topic; controller side — the `create-controller` topic; competing libs `@nestjs/swagger` `@ApiProperty`, `class-transformer`, hand-rolled DTO mappers.'
1760
1760
  ---
1761
1761
 
1762
1762
  # Warlock — define a resource
@@ -2151,16 +2151,16 @@ export const CommentResource = defineResource({
2151
2151
 
2152
2152
  ## See also
2153
2153
 
2154
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — the output-only rule and where logic actually lives.
2155
- - [`build-restful/SKILL.md`](../build-restful/SKILL.md) — wiring a resource into a CRUD pipeline.
2156
- - [`create-controller/SKILL.md`](../create-controller/SKILL.md) — calling `new XResource(record).toJSON()` from a controller.
2154
+ - The `warlock-conventions` topic — the output-only rule and where logic actually lives.
2155
+ - The `build-restful` topic — wiring a resource into a CRUD pipeline.
2156
+ - The `create-controller` topic — calling `new XResource(record).toJSON()` from a controller.
2157
2157
 
2158
2158
 
2159
2159
  ## encrypt-data `@warlock.js/core/encrypt-data/SKILL.md`
2160
2160
 
2161
2161
  ---
2162
2162
  name: encrypt-data
2163
- description: 'Reversible AES-256-GCM `encrypt` / `decrypt` for secrets you need to read back; one-way HMAC-SHA256 `hmacHash` for deterministic fingerprints (lookup/dedup of encrypted columns). Keys come from `src/config/encryption.ts`. Triggers: `encrypt`, `decrypt`, `hmacHash`, `EncryptionConfigurations`, `APP_ENCRYPTION_KEY`, `APP_HMAC_KEY`; "store an API key reversibly", "fingerprint an encrypted column for lookup", "AES-256-GCM secret", "HMAC-SHA256 dedup key"; typical import `import { encrypt, decrypt, hmacHash } from "@warlock.js/core"`. Skip: password hashing — `@warlock.js/core/hash-password/SKILL.md`; config wiring — `@warlock.js/core/configure-app/SKILL.md`; competing libs Node `crypto` direct, `crypto-js`, `libsodium-wrappers`.'
2163
+ description: 'Reversible AES-256-GCM `encrypt` / `decrypt` for secrets you need to read back; one-way HMAC-SHA256 `hmacHash` for deterministic fingerprints (lookup/dedup of encrypted columns). Keys come from `src/config/encryption.ts`. Triggers: `encrypt`, `decrypt`, `hmacHash`, `EncryptionConfigurations`, `APP_ENCRYPTION_KEY`, `APP_HMAC_KEY`; "store an API key reversibly", "fingerprint an encrypted column for lookup", "AES-256-GCM secret", "HMAC-SHA256 dedup key"; typical import `import { encrypt, decrypt, hmacHash } from "@warlock.js/core"`. Skip: password hashing — the `hash-password` topic; config wiring — the `configure-app` topic; competing libs Node `crypto` direct, `crypto-js`, `libsodium-wrappers`.'
2164
2164
  ---
2165
2165
 
2166
2166
  # Warlock — encrypt and fingerprint
@@ -2172,7 +2172,7 @@ Two helpers, two different jobs:
2172
2172
  | `encrypt` / `decrypt` | reversible | AES-256-GCM | Secrets you need to read back (API keys, OAuth tokens). |
2173
2173
  | `hmacHash` | one-way | HMAC-SHA256 | Deterministic fingerprint for lookup/dedup of encrypted values. |
2174
2174
 
2175
- Both live in `@warlock.js/core`. For **password hashing** (a one-way job with very different requirements), reach for [`hash-password/SKILL.md`](../hash-password/SKILL.md) instead — bcrypt is the right tool there, not encrypt.
2175
+ Both live in `@warlock.js/core`. For **password hashing** (a one-way job with very different requirements), reach for the `hash-password` topic instead — bcrypt is the right tool there, not encrypt.
2176
2176
 
2177
2177
  ## The shape
2178
2178
 
@@ -2284,7 +2284,7 @@ await idempotencyKeysRepository.first({ hash: hmacHash(JSON.stringify(request))
2284
2284
  log.info("api-key", "used", { fingerprint: hmacHash(apiKey).slice(0, 8) });
2285
2285
  ```
2286
2286
 
2287
- **Do not use `hmacHash` for passwords.** It's fast — a brute-force attack with a stolen database would clear common passwords in minutes. That's what bcrypt is for (see [`hash-password/SKILL.md`](../hash-password/SKILL.md)).
2287
+ **Do not use `hmacHash` for passwords.** It's fast — a brute-force attack with a stolen database would clear common passwords in minutes. That's what bcrypt is for (see the `hash-password` topic).
2288
2288
 
2289
2289
  ## Common patterns
2290
2290
 
@@ -2359,20 +2359,20 @@ Same payload → same key → returns the cached result. Different keys (because
2359
2359
 
2360
2360
  `encrypt` / `decrypt` / `hmacHash` use Node's built-in `crypto` — no extra dependency. They're available out of the box.
2361
2361
 
2362
- Password hashing (`hashPassword`) needs `bcryptjs`, which is its own install — see [`hash-password/SKILL.md`](../hash-password/SKILL.md).
2362
+ Password hashing (`hashPassword`) needs `bcryptjs`, which is its own install — see the `hash-password` topic.
2363
2363
 
2364
2364
  ## See also
2365
2365
 
2366
- - [`hash-password/SKILL.md`](../hash-password/SKILL.md) — bcrypt password hashing (the third member of the encryption module, but a different job entirely).
2367
- - [`configure-app/SKILL.md`](../configure-app/SKILL.md) — `src/config/encryption.ts` and env wiring.
2368
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — service layering, where the encryption boundary should sit.
2366
+ - The `hash-password` topic — bcrypt password hashing (the third member of the encryption module, but a different job entirely).
2367
+ - The `configure-app` topic — `src/config/encryption.ts` and env wiring.
2368
+ - The `warlock-conventions` topic — service layering, where the encryption boundary should sit.
2369
2369
 
2370
2370
 
2371
2371
  ## generate-openapi `@warlock.js/core/generate-openapi/SKILL.md`
2372
2372
 
2373
2373
  ---
2374
2374
  name: generate-openapi
2375
- description: 'Generate an OpenAPI 3.1 document from the registered routes with `warlock generate.openapi` (default `storage/openapi/openapi.json`) and read it live in the dev-only API docs page at `/__warlock/docs`. Documents paths, path/query parameters, request bodies from Seal validation, responses from `handler.responseSchema`, 401/422 and bearer/cookie security from `authMiddleware()`. Triggers: `generate.openapi`, `openApiGeneratorCommand`, `buildOpenApiDocument`, `getDevelopmentOpenApiDocument`, `responseSchema`, `--include-pages`, `/__warlock/docs`; "OpenAPI", "Swagger", "API docs", "import my API into Postman or Insomnia", "document my routes". Skip: declaring response types on a handler — `@warlock.js/core/create-controller/SKILL.md`; the devtools dashboard — `@warlock.js/devtools/devtools-overview/SKILL.md`; listing routes — `@warlock.js/core/warlock-routes/SKILL.md`.'
2375
+ description: 'Generate an OpenAPI 3.1 document from the registered routes with `warlock generate.openapi` (default `storage/openapi/openapi.json`), write a Postman collection from it with `warlock generate.postman` (default `storage/postman/collection.json`), and read it live in the dev-only API docs page at `/__warlock/docs`. Documents paths, path/query parameters, request bodies from Seal validation, responses from `handler.responseSchema`, 401/422 and bearer/cookie security from `authMiddleware()`. Triggers: `generate.openapi`, `openApiGeneratorCommand`, `buildOpenApiDocument`, `getDevelopmentOpenApiDocument`, `generate.postman`, `openApiToPostmanCollection`, `getDevelopmentPostmanCollection`, `responseSchema`, `--include-pages`, `/__warlock/docs`; "OpenAPI", "Swagger", "API docs", "import my API into Postman or Insomnia", "document my routes". Skip: declaring response types on a handler — the `create-controller` topic; the devtools dashboard — the `devtools-overview` topic of the `warlock-js-devtools` skill; listing routes — the `warlock-routes` topic.'
2376
2376
  ---
2377
2377
 
2378
2378
  # Warlock — generate an OpenAPI document
@@ -2416,7 +2416,7 @@ npx warlock generate.openapi --out docs/openapi.json --title "Shop API" --server
2416
2416
 
2417
2417
  ### Responses from `responseSchema`
2418
2418
 
2419
- The grammar is the one described in [`create-controller`](../create-controller/SKILL.md#declaring-response-types-with-responseschema): cast strings with suffixes, a resource, `[Resource]`, nested objects.
2419
+ The grammar is the one described in the `create-controller` topic ("Declaring response types with `responseSchema`" section): cast strings with suffixes, a resource, `[Resource]`, nested objects.
2420
2420
 
2421
2421
  ```ts
2422
2422
  loginController.responseSchema = {
@@ -2466,6 +2466,34 @@ With `@warlock.js/devtools` installed (`warlock add devtools`), `warlock dev` se
2466
2466
 
2467
2467
  The output is plain OpenAPI 3.1 JSON, so any tool that reads an OpenAPI file can use it: import `storage/openapi/openapi.json` into Postman or Insomnia (their Import action), or feed it to a client generator. Support for 3.1 is the tool's; if an old version refuses it, update the tool. Regenerate the file whenever routes change, or commit it if you publish it.
2468
2468
 
2469
+ ## Postman
2470
+
2471
+ `warlock generate.postman` writes a Postman Collection v2.1.0. It is derived from the OpenAPI document (the same registration child and options as `generate.openapi`), never from the routes directly, so the collection and the OpenAPI file always agree.
2472
+
2473
+ ```bash
2474
+ npx warlock generate.postman
2475
+ # Postman collection written to <root>/storage/postman/collection.json (3 folders, 17 requests). Import it in Postman and set the {{token}} variable.
2476
+ ```
2477
+
2478
+ | Option | Default | Meaning |
2479
+ | ----------------- | ----------------------------------------- | ------------------------------------------------------------------ |
2480
+ | `--out`, `-o` | `storage/postman/collection.json` | Output file, relative to the project root. |
2481
+ | `--title` | `name` in `package.json` | Collection name; the collection id is a stable hash of it. |
2482
+ | `--server` | `http://<host>:<port>` from the `http` config | Value of the `{{baseUrl}}` variable. |
2483
+ | `--include-pages` | off | Also include page (SSR) routes. |
2484
+
2485
+ What the collection contains:
2486
+
2487
+ - One folder per tag (the first path segment), in order of first appearance; untagged operations sit at the root.
2488
+ - One request per operation, named by its summary (the route `label`) or `operationId`. `{id}` becomes the `:id` path variable; query parameters are rows (optional ones disabled); the operation description and parameter descriptions carry over.
2489
+ - A JSON body with a `Content-Type` header and an **example generated from the schema** (strings by format such as `email` or `date-time`, `0`, `false`, the first `enum` value, one array item, resources resolved with cycles cut). A multipart body becomes form-data with file rows.
2490
+ - A saved response for every declared status, with an example body.
2491
+ - Collection variables `baseUrl` and `token`. When any route is guarded by `authMiddleware()`, the collection uses bearer auth with `{{token}}`; public routes are set to no auth so the token is not sent. A cookie-only route has a description note: Postman keeps cookies per domain, so sign in against `{{baseUrl}}` first.
2492
+
2493
+ To use it: in Postman choose **Import** and pick the file, open the collection's **Variables** tab, paste a token into `token` (for example the `token` from your login response), and adjust `baseUrl` if needed. Regenerate and re-import when routes change.
2494
+
2495
+ Programmatic use: `openApiToPostmanCollection(document, { title?, baseUrl? })` is exported from `@warlock.js/core` (pure and deterministic), and `getDevelopmentPostmanCollection()` returns `{ collection, warnings }` for the running dev process (it throws outside `warlock dev`, like `getDevelopmentOpenApiDocument`).
2496
+
2469
2497
  ## Programmatic use
2470
2498
 
2471
2499
  `buildOpenApiDocument(routes, context)` is exported from `@warlock.js/core`: a pure function from `router.list()` routes to `{ document, warnings }`. `context` carries `info`, `servers`, `includePages`, `resolveResourceName` and `validationResponse`. Use it to build the document inside your own tooling; the CLI uses the same function inside the registration child.
@@ -2487,23 +2515,23 @@ const { document, warnings } = buildOpenApiDocument(router.list(), {
2487
2515
 
2488
2516
  ## See also
2489
2517
 
2490
- - [`create-controller/SKILL.md`](../create-controller/SKILL.md) — `validation`, `description` and `responseSchema` on a handler.
2491
- - [`define-resource/SKILL.md`](../define-resource/SKILL.md) — resources, which become `components.schemas`.
2492
- - [`warlock-routes/SKILL.md`](../warlock-routes/SKILL.md) — list the routes the document is built from.
2518
+ - The `create-controller` topic — `validation`, `description` and `responseSchema` on a handler.
2519
+ - The `define-resource` topic — resources, which become `components.schemas`.
2520
+ - The `warlock-routes` topic — list the routes the document is built from.
2493
2521
 
2494
2522
 
2495
2523
  ## hash-password `@warlock.js/core/hash-password/SKILL.md`
2496
2524
 
2497
2525
  ---
2498
2526
  name: hash-password
2499
- description: 'One-way bcrypt password hashing — `hashPassword` / `verifyPassword`, plus the declarative `useHashedPassword()` schema transformer that auto-hashes a model''s password field on save. Salt rounds come from `src/config/encryption.ts`. Triggers: `hashPassword`, `verifyPassword`, `useHashedPassword`, `password.salt`, `bcryptjs`; "hash a user password", "verify login credentials", "auto-hash on save", "rotate a password"; typical import `import { hashPassword, verifyPassword } from "@warlock.js/core"`. Skip: reversible secrets — `@warlock.js/core/encrypt-data/SKILL.md`; the other transformers — `@warlock.js/core/use-model-transformers/SKILL.md`; config wiring — `@warlock.js/core/configure-app/SKILL.md`; competing libs `bcrypt` native, `argon2`, `scrypt`.'
2527
+ description: 'One-way bcrypt password hashing — `hashPassword` / `verifyPassword`, plus the declarative `useHashedPassword()` schema transformer that auto-hashes a model''s password field on save. Salt rounds come from `src/config/encryption.ts`. Triggers: `hashPassword`, `verifyPassword`, `useHashedPassword`, `password.salt`, `bcryptjs`; "hash a user password", "verify login credentials", "auto-hash on save", "rotate a password"; typical import `import { hashPassword, verifyPassword } from "@warlock.js/core"`. Skip: reversible secrets — the `encrypt-data` topic; the other transformers — the `use-model-transformers` topic; config wiring — the `configure-app` topic; competing libs `bcrypt` native, `argon2`, `scrypt`.'
2500
2528
  ---
2501
2529
 
2502
2530
  # Warlock — hash a password
2503
2531
 
2504
2532
  For storing user-typed passwords, bcrypt is the one right answer — and the only one. It's **deliberately slow** (~250ms per call with the default salt rounds), which is what makes it expensive to brute-force a stolen password database. Use it for nothing else: not API keys, not session tokens, not "this needs to be one-way."
2505
2533
 
2506
- If your value needs to be read back later → [`encrypt-data/SKILL.md`](../encrypt-data/SKILL.md).
2534
+ If your value needs to be read back later → the `encrypt-data` topic.
2507
2535
  If you need a fast searchable fingerprint of an encrypted value → also `encrypt-data` (`hmacHash`).
2508
2536
 
2509
2537
  ## The shape
@@ -2664,7 +2692,7 @@ There is no `warlock add` feature for password hashing — `bcryptjs` is a plain
2664
2692
 
2665
2693
  ## Gotchas
2666
2694
 
2667
- - **Never use `hashPassword` for non-password values.** A 250ms tax on every API request because someone reached for it as a "general one-way hash" — that's a performance bug waiting to happen. For one-way fingerprinting of encrypted values, use `hmacHash` (see [`encrypt-data/SKILL.md`](../encrypt-data/SKILL.md)).
2695
+ - **Never use `hashPassword` for non-password values.** A 250ms tax on every API request because someone reached for it as a "general one-way hash" — that's a performance bug waiting to happen. For one-way fingerprinting of encrypted values, use `hmacHash` (see the `encrypt-data` topic).
2668
2696
  - **Don't `hashPassword` on the request hot path twice.** Each call is ~250ms. If you `hashPassword(input)` then call it again as part of `verifyPassword`'s internals (you don't), you're stacking the tax. `verifyPassword(plain, storedHash)` takes the plaintext and the stored hash — that's the API.
2669
2697
  - **Don't swap `bcryptjs` for native `bcrypt` without a reason.** `bcryptjs` is portable across every platform (no native build), and the perf delta isn't meaningful in the password-verification workflow.
2670
2698
  - **The transformer detects changes by comparison.** If your model's password field is `null` and you save `null` again, it's a no-op. If it's a hash and you save the same hash string, also no-op. Only an actual value change triggers re-hashing.
@@ -2672,18 +2700,18 @@ There is no `warlock add` feature for password hashing — `bcryptjs` is a plain
2672
2700
 
2673
2701
  ## See also
2674
2702
 
2675
- - [`use-model-transformers/SKILL.md`](../use-model-transformers/SKILL.md) — `useHashedPassword` + the two other model transformers (`useComputedSlug`, `useComputedModel`).
2676
- - [`encrypt-data/SKILL.md`](../encrypt-data/SKILL.md) — reversible AES-256-GCM `encrypt`/`decrypt` + one-way HMAC `hmacHash` (the other two members of the encryption module).
2677
- - [`configure-app/SKILL.md`](../configure-app/SKILL.md) — `src/config/encryption.ts` and the `password.salt` knob.
2678
- - [`define-resource/SKILL.md`](../define-resource/SKILL.md) — where to filter the password field out of API responses.
2679
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — service layering, where the password boundary should sit.
2703
+ - The `use-model-transformers` topic — `useHashedPassword` + the two other model transformers (`useComputedSlug`, `useComputedModel`).
2704
+ - The `encrypt-data` topic — reversible AES-256-GCM `encrypt`/`decrypt` + one-way HMAC `hmacHash` (the other two members of the encryption module).
2705
+ - The `configure-app` topic — `src/config/encryption.ts` and the `password.salt` knob.
2706
+ - The `define-resource` topic — where to filter the password field out of API responses.
2707
+ - The `warlock-conventions` topic — service layering, where the password boundary should sit.
2680
2708
 
2681
2709
 
2682
2710
  ## health-checks `@warlock.js/core/health-checks/SKILL.md`
2683
2711
 
2684
2712
  ---
2685
2713
  name: health-checks
2686
- description: 'Built-in liveness (`/health`) and readiness (`/ready`) endpoints plus graceful HTTP request draining for zero-downtime deploys — the `health` registry (`health.addCheck`/`removeCheck`), the `http.health.*` and `http.gracefulShutdown.*` config, and how readiness ties into `Application.isShuttingDown`. Triggers: `health`, `health.addCheck`, `health.removeCheck`, `HealthCheck`, `/health`, `/ready`, `http.health`, `http.gracefulShutdown`, `forceCloseConnections`, "liveness probe", "readiness probe", "graceful shutdown", "drain in-flight requests", "zero-downtime deploy", "kubernetes health check", "503 until ready"; typical import `import { health } from "@warlock.js/core"`. Skip: the `Application.onShutdown` / `onceBooted` lifecycle hooks — `@warlock.js/core/use-app-context/SKILL.md`; maintenance-mode 503s — `@warlock.js/core/use-middleware/SKILL.md`; connector lifecycle — `@warlock.js/core/add-connector/SKILL.md`; competing libs `@fastify/under-pressure`, `terminus`, hand-rolled `/health` controllers.'
2714
+ description: 'Built-in liveness (`/health`) and readiness (`/ready`) endpoints plus graceful HTTP request draining for zero-downtime deploys — the `health` registry (`health.addCheck`/`removeCheck`), the `http.health.*` and `http.gracefulShutdown.*` config, and how readiness ties into `Application.isShuttingDown`. Triggers: `health`, `health.addCheck`, `health.removeCheck`, `HealthCheck`, `/health`, `/ready`, `http.health`, `http.gracefulShutdown`, `forceCloseConnections`, "liveness probe", "readiness probe", "graceful shutdown", "drain in-flight requests", "zero-downtime deploy", "kubernetes health check", "503 until ready"; typical import `import { health } from "@warlock.js/core"`. Skip: the `Application.onShutdown` / `onceBooted` lifecycle hooks — the `use-app-context` topic; maintenance-mode 503s — the `use-middleware` topic; connector lifecycle — the `add-connector` topic; competing libs `@fastify/under-pressure`, `terminus`, hand-rolled `/health` controllers.'
2687
2715
  ---
2688
2716
 
2689
2717
  # Warlock — health checks & graceful shutdown
@@ -2792,21 +2820,21 @@ For an even smoother handoff, give the load balancer time to observe the 503 bef
2792
2820
  - **`/health` is registered straight on Fastify, not the app router.** It's infra, so it's immune to HMR and route scanning — but if your app also defines a `/health` route you'll have a collision. Rename via `http.health.path`.
2793
2821
  - **Readiness needs a finished boot.** Before `Application.isBooted` (e.g. while late-phase connectors are still starting) `/ready` is 503 by design — that's the point.
2794
2822
  - **A hanging `onShutdown` hook delays the drain.** App hooks run before connector teardown and are only bounded by your process manager's kill timeout; keep them fast. The HTTP drain itself is bounded by `gracefulShutdown.timeout`.
2795
- - **The `maintenance` middleware is a different 503.** It allowlists `/health` by default so probes pass during maintenance — but maintenance mode is operator-toggled downtime, not readiness. See `@warlock.js/core/use-middleware/SKILL.md`.
2823
+ - **The `maintenance` middleware is a different 503.** It allowlists `/health` by default so probes pass during maintenance — but maintenance mode is operator-toggled downtime, not readiness. See the `use-middleware` topic.
2796
2824
 
2797
2825
  ## See also
2798
2826
 
2799
- - [`use-app-context/SKILL.md`](../use-app-context/SKILL.md) — `Application.onShutdown` / `onceBooted` / `isShuttingDown`, the lifecycle hooks the endpoints build on.
2800
- - [`configure-app/SKILL.md`](../configure-app/SKILL.md) — the `src/config/http.ts` shape.
2801
- - [`add-connector/SKILL.md`](../add-connector/SKILL.md) — connector boot/shutdown order, where draining slots in.
2802
- - [`use-middleware/SKILL.md`](../use-middleware/SKILL.md) — maintenance mode and other built-in middleware.
2827
+ - The `use-app-context` topic — `Application.onShutdown` / `onceBooted` / `isShuttingDown`, the lifecycle hooks the endpoints build on.
2828
+ - The `configure-app` topic — the `src/config/http.ts` shape.
2829
+ - The `add-connector` topic — connector boot/shutdown order, where draining slots in.
2830
+ - The `use-middleware` topic — maintenance mode and other built-in middleware.
2803
2831
 
2804
2832
 
2805
2833
  ## lower-stage3-decorators `@warlock.js/core/lower-stage3-decorators/SKILL.md`
2806
2834
 
2807
2835
  ---
2808
2836
  name: lower-stage3-decorators
2809
- description: 'Vite/Vitest plugin `lowerStage3Decorators()` that lowers TC39 Stage-3 (native) decorators with esbuild before oxc / the SSR rewrite mangles them — so `@RegisterModel`-decorated Cascade models load under Vitest 4 / Vite 8. Triggers: `lowerStage3Decorators`, "SyntaxError: Invalid or unexpected token" on a decorated class, "@(0, __vite_ssr_import__.X)()", "decorator crashes vitest", "models won''t load in tests", "Vite 8 oxc decorators"; typical import `import { lowerStage3Decorators } from "@warlock.js/core/vite"` in `vite.config.ts` / `vitest.config.ts`. Skip: writing the tests themselves — `@warlock.js/core/test-service/SKILL.md` / `@warlock.js/core/test-http/SKILL.md`; runtime migrations — `@warlock.js/cascade/write-migration/SKILL.md`.'
2837
+ description: 'Vite/Vitest plugin `lowerStage3Decorators()` that lowers TC39 Stage-3 (native) decorators with esbuild before oxc / the SSR rewrite mangles them — so `@RegisterModel`-decorated Cascade models load under Vitest 4 / Vite 8. Triggers: `lowerStage3Decorators`, "SyntaxError: Invalid or unexpected token" on a decorated class, "@(0, __vite_ssr_import__.X)()", "decorator crashes vitest", "models won''t load in tests", "Vite 8 oxc decorators"; typical import `import { lowerStage3Decorators } from "@warlock.js/core/vite"` in `vite.config.ts` / `vitest.config.ts`. Skip: writing the tests themselves — the `test-service` topic / the `test-http` topic; runtime migrations — the `write-migration` topic of the `warlock-js-cascade` skill.'
2810
2838
  ---
2811
2839
 
2812
2840
  # Lower Stage-3 decorators for Vite/Vitest
@@ -2857,16 +2885,16 @@ It's the **same esbuild transform the production `tsx`/build path uses**, so a f
2857
2885
 
2858
2886
  ## See also
2859
2887
 
2860
- - [`@warlock.js/core/test-service/SKILL.md`](@warlock.js/core/test-service/SKILL.md) — `setupTest()` bootstrap for unit-testing services/models once the harness loads.
2861
- - [`@warlock.js/core/test-http/SKILL.md`](@warlock.js/core/test-http/SKILL.md) — integration tests over the real HTTP server.
2862
- - [`@warlock.js/cascade/write-migration/SKILL.md`](@warlock.js/cascade/write-migration/SKILL.md) — the decorated models this plugin lets you load.
2888
+ - The `test-service` topic — `setupTest()` bootstrap for unit-testing services/models once the harness loads.
2889
+ - The `test-http` topic — integration tests over the real HTTP server.
2890
+ - The `write-migration` topic of the `warlock-js-cascade` skill — the decorated models this plugin lets you load.
2863
2891
 
2864
2892
 
2865
2893
  ## process-image `@warlock.js/core/process-image/SKILL.md`
2866
2894
 
2867
2895
  ---
2868
2896
  name: process-image
2869
- description: 'Transform images with the `Image` class — resize, crop, rotate, format, quality, watermark, blur, etc. — using a deferred pipeline that runs only at `save()` / `toBuffer()` / `toBase64()` / `toDataUrl()` time. Requires sharp via `warlock add image`. Triggers: `Image`, `Image.fromFile`, `Image.fromBuffer`, `Image.fromUrl`, `.resize`, `.crop`, `.watermark`, `.toBuffer`, `.toDataUrl`, `.apply`; "resize an image", "generate a thumbnail", "watermark a product photo", "build an image pipeline"; typical import `import { Image } from "@warlock.js/core"`. Skip: multipart upload entry — `@warlock.js/core/upload-file/SKILL.md`; storage persistence — `@warlock.js/core/store-file/SKILL.md`; competing libs `sharp` direct, `jimp`, `imagemagick`, `gm`.'
2897
+ description: 'Transform images with the `Image` class — resize, crop, rotate, format, quality, watermark, blur, etc. — using a deferred pipeline that runs only at `save()` / `toBuffer()` / `toBase64()` / `toDataUrl()` time. Requires sharp via `warlock add image`. Triggers: `Image`, `Image.fromFile`, `Image.fromBuffer`, `Image.fromUrl`, `.resize`, `.crop`, `.watermark`, `.toBuffer`, `.toDataUrl`, `.apply`; "resize an image", "generate a thumbnail", "watermark a product photo", "build an image pipeline"; typical import `import { Image } from "@warlock.js/core"`. Skip: multipart upload entry — the `upload-file` topic; storage persistence — the `store-file` topic; competing libs `sharp` direct, `jimp`, `imagemagick`, `gm`.'
2870
2898
  ---
2871
2899
 
2872
2900
  # Warlock — process an image
@@ -3019,7 +3047,7 @@ The wrapper exposes the underlying `sharp.Sharp` via `.image` for anything not s
3019
3047
 
3020
3048
  `UploadedFile` (from multipart uploads) has its own chainable `.resize().format().quality().save(...)` that runs through `Image` internally — same deferred execution, same transforms. Use it when the source is a multipart upload; reach for `new Image(...)` directly when the source is a buffer/path/URL.
3021
3049
 
3022
- See [`upload-file`](../upload-file/SKILL.md) for the multipart entry point and [`store-file`](../store-file/SKILL.md) for persisting the output through storage drivers.
3050
+ See the `upload-file` topic for the multipart entry point and the `store-file` topic for persisting the output through storage drivers.
3023
3051
 
3024
3052
  ## Gotchas
3025
3053
 
@@ -3032,16 +3060,16 @@ See [`upload-file`](../upload-file/SKILL.md) for the multipart entry point and [
3032
3060
 
3033
3061
  ## See also
3034
3062
 
3035
- - [`upload-file/SKILL.md`](../upload-file/SKILL.md) — multipart uploads, where image transforms typically start.
3036
- - [`store-file/SKILL.md`](../store-file/SKILL.md) — persisting image output through storage drivers (local / S3 / R2 / Spaces).
3037
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — where image-processing services live.
3063
+ - The `upload-file` topic — multipart uploads, where image transforms typically start.
3064
+ - The `store-file` topic — persisting image output through storage drivers (local / S3 / R2 / Spaces).
3065
+ - The `warlock-conventions` topic — where image-processing services live.
3038
3066
 
3039
3067
 
3040
3068
  ## register-route `@warlock.js/core/register-route/SKILL.md`
3041
3069
 
3042
3070
  ---
3043
3071
  name: register-route
3044
- description: 'Register HTTP routes via @warlock.js/core''s router — single routes, prefix groups, middleware-guarded blocks, and RESTful resource chains. Routes always live in `src/app/<module>/routes.ts`. Triggers: `router.get`, `router.post`, `router.prefix`, `router.group`, `router.route`, `guarded`; "add a route", "wire a controller to a URL", "group routes by prefix", "register a RESTful resource"; typical import `import { router } from "@warlock.js/core"`. Skip: handler shape — `@warlock.js/core/create-controller/SKILL.md`; CRUD chain details — `@warlock.js/core/build-restful/SKILL.md`; middleware authoring — `@warlock.js/core/write-middleware/SKILL.md`; competing libs `express`, `fastify`, `koa`, `@nestjs/common`.'
3072
+ description: 'Register HTTP routes via @warlock.js/core''s router — single routes, prefix groups, middleware-guarded blocks, and RESTful resource chains. Routes always live in `src/app/<module>/routes.ts`. Triggers: `router.get`, `router.post`, `router.prefix`, `router.group`, `router.route`, `guarded`; "add a route", "wire a controller to a URL", "group routes by prefix", "register a RESTful resource"; typical import `import { router } from "@warlock.js/core"`. Skip: handler shape — the `create-controller` topic; CRUD chain details — the `build-restful` topic; middleware authoring — the `write-middleware` topic; competing libs `express`, `fastify`, `koa`, `@nestjs/common`.'
3045
3073
  ---
3046
3074
 
3047
3075
  # Warlock — register a route
@@ -3070,7 +3098,7 @@ router.post("/orders/:id", createOrderController, { name: "orders.create" });
3070
3098
  Use a concrete HTTP verb for browser forms. `router.any()` is represented as
3071
3099
  `all` metadata and requires callers to choose an explicit path and method.
3072
3100
 
3073
- That's the entire contract for a simple route. `router` is a singleton; method calls register routes synchronously. The handler is a plain function (controllers are typed as `RequestHandler` — see [create-controller](../create-controller/SKILL.md)).
3101
+ That's the entire contract for a simple route. `router` is a singleton; method calls register routes synchronously. The handler is a plain function (controllers are typed as `RequestHandler` — see the `create-controller` topic).
3074
3102
 
3075
3103
  ## HTTP verbs
3076
3104
 
@@ -3139,7 +3167,7 @@ router.prefix("/products", () => {
3139
3167
  });
3140
3168
  ```
3141
3169
 
3142
- If `guarded` doesn't exist in your project yet, see the shared utility convention in [warlock-conventions](../warlock-conventions/SKILL.md).
3170
+ If `guarded` doesn't exist in your project yet, see the shared utility convention in the `warlock-conventions` topic.
3143
3171
 
3144
3172
  ## RESTful resource chain
3145
3173
 
@@ -3208,16 +3236,16 @@ router.get(["/health", "/healthz"], healthController);
3208
3236
 
3209
3237
  ## See also
3210
3238
 
3211
- - [`create-controller/SKILL.md`](../create-controller/SKILL.md) — the handler shape, validation, request/response surface.
3212
- - [`send-response/SKILL.md`](../send-response/SKILL.md) — picking the right `response.<helper>()`.
3213
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — module layout, the `guarded` convention, path aliases.
3239
+ - The `create-controller` topic — the handler shape, validation, request/response surface.
3240
+ - The `send-response` topic — picking the right `response.<helper>()`.
3241
+ - The `warlock-conventions` topic — module layout, the `guarded` convention, path aliases.
3214
3242
 
3215
3243
 
3216
3244
  ## request-memo `@warlock.js/core/request-memo/SKILL.md`
3217
3245
 
3218
3246
  ---
3219
3247
  name: request-memo
3220
- description: 'Memoize async work for one HTTP request with `requestMemo<T>(key, fn)` — the v5 replacement for removed `fromRequest`, with single-flight promise sharing, settled-success reuse, rejection eviction, and no cross-request fallback. Triggers: `requestMemo`, `fromRequest`, `fromRequest removed`, `request-scoped cache`, `single-flight`, `current request memo`; "migrate off fromRequest", "load this once per request", "deduplicate concurrent loaders", "cache a repository lookup during one request"; typical import `import { requestMemo } from "@warlock.js/core"`. Skip: middleware-written request state — `@warlock.js/core/use-request-locals/SKILL.md`; process-wide or cross-request caching — `@warlock.js/core/use-middleware/SKILL.md`; competing patterns: dynamic `request[key]` properties, module-global `Map`, payload `request.get()` / `request.set()`.'
3248
+ description: 'Memoize async work for one HTTP request with `requestMemo<T>(key, fn)` — the v5 replacement for removed `fromRequest`, with single-flight promise sharing, settled-success reuse, rejection eviction, and no cross-request fallback. Triggers: `requestMemo`, `fromRequest`, `fromRequest removed`, `request-scoped cache`, `single-flight`, `current request memo`; "migrate off fromRequest", "load this once per request", "deduplicate concurrent loaders", "cache a repository lookup during one request"; typical import `import { requestMemo } from "@warlock.js/core"`. Skip: middleware-written request state — the `use-request-locals` topic; process-wide or cross-request caching — the `use-middleware` topic; competing patterns: dynamic `request[key]` properties, module-global `Map`, payload `request.get()` / `request.set()`.'
3221
3249
  ---
3222
3250
 
3223
3251
  # Warlock — memoize work for one request
@@ -3354,16 +3382,16 @@ Reusing one key for different result types is a caller bug: TypeScript cannot co
3354
3382
 
3355
3383
  ## See also
3356
3384
 
3357
- - [`use-request-locals/SKILL.md`](../use-request-locals/SKILL.md) — typed per-request data written by middleware.
3358
- - [`write-middleware/SKILL.md`](../write-middleware/SKILL.md) — authoring and registering middleware.
3359
- - [`create-controller/SKILL.md`](../create-controller/SKILL.md) — consuming request-scoped values from controllers.
3385
+ - The `use-request-locals` topic — typed per-request data written by middleware.
3386
+ - The `write-middleware` topic — authoring and registering middleware.
3387
+ - The `create-controller` topic — consuming request-scoped values from controllers.
3360
3388
 
3361
3389
 
3362
3390
  ## request-tracing `@warlock.js/core/request-tracing/SKILL.md`
3363
3391
 
3364
3392
  ---
3365
3393
  name: request-tracing
3366
- description: 'Vendor-neutral request tracing hooks (`http.tracing`) — observe request start/end and named phase spans (`route.match`, `middleware`, `validation`, `handler`, `response.write`) without adopting an OTel/vendor dependency in `core`. Covers the `TracingHooks` shape, trace id derivation from an inbound W3C `traceparent` vs `request.id`, that a throwing hook is caught and reported once (never breaks the request), and zero overhead when disabled. Triggers: `http.tracing`, `TracingHooks`, `onRequestStart`, `onRequestEnd`, `onPhase`, `traceparent`, `traceId`, `dispatchPhase`, "instrument requests", "trace a request", "slow phase logging", "APM / OTel bridge for Warlock". Skip: request-id header echo/inheritance (`X-Request-Id`) — `@warlock.js/core/use-middleware/SKILL.md`; app-level structured logging — `@warlock.js/logger/logger-basics/SKILL.md`; competing libs `@opentelemetry/api` direct instrumentation, `express-request-id`, hand-rolled `X-Trace-Id` middleware.'
3394
+ description: 'Vendor-neutral request tracing hooks (`http.tracing`) — observe request start/end and named phase spans (`route.match`, `middleware`, `validation`, `handler`, `response.write`) without adopting an OTel/vendor dependency in `core`. Covers the `TracingHooks` shape, trace id derivation from an inbound W3C `traceparent` vs `request.id`, that a throwing hook is caught and reported once (never breaks the request), and zero overhead when disabled. Triggers: `http.tracing`, `TracingHooks`, `onRequestStart`, `onRequestEnd`, `onPhase`, `traceparent`, `traceId`, `dispatchPhase`, "instrument requests", "trace a request", "slow phase logging", "APM / OTel bridge for Warlock". Skip: request-id header echo/inheritance (`X-Request-Id`) — the `use-middleware` topic; app-level structured logging — the `logger-basics` topic of the `warlock-js-logger` skill; competing libs `@opentelemetry/api` direct instrumentation, `express-request-id`, hand-rolled `X-Trace-Id` middleware.'
3367
3395
  ---
3368
3396
 
3369
3397
  # Warlock — request tracing hooks
@@ -3494,7 +3522,7 @@ instead of adding a separate hook API. They add three phases:
3494
3522
  trace keeps the same id through Warlock.
3495
3523
  2. Otherwise `traceId` falls back to `request.id` (the framework's own
3496
3524
  per-request correlation id — see
3497
- [`use-middleware/SKILL.md`](../use-middleware/SKILL.md#request-id-correlation)
3525
+ the `use-middleware` topic (its "Request ID correlation" section)
3498
3526
  for how that id is generated/inherited/echoed).
3499
3527
 
3500
3528
  `ctx.requestId` is always `request.id`, regardless of which branch produced
@@ -3515,7 +3543,7 @@ deriveTraceId(undefined, "req-abc123");
3515
3543
 
3516
3544
  Tracing does **not** add a response header of its own. `core` already echoes
3517
3545
  `request.id` back as `X-Request-Id` on every response (see
3518
- [`use-middleware/SKILL.md`](../use-middleware/SKILL.md#request-id-correlation)) —
3546
+ the `use-middleware` topic, "Request ID correlation" section) —
3519
3547
  apps correlate through that existing header. When a valid inbound
3520
3548
  `traceparent` is present, `ctx.traceId` inside your hooks carries that trace
3521
3549
  id even though the response header still reflects `request.id`; if you need
@@ -3589,16 +3617,16 @@ export default {
3589
3617
 
3590
3618
  ## See also
3591
3619
 
3592
- - [`use-middleware/SKILL.md`](../use-middleware/SKILL.md#request-id-correlation) — `X-Request-Id` inheritance/echo, the header tracing correlates through.
3593
- - [`use-app-context/SKILL.md`](../use-app-context/SKILL.md) — request-scoped ALS context (`request`/`response`) tracing hooks run inside.
3594
- - [`@warlock.js/logger/logger-basics/SKILL.md`](../../../logger/skills/logger-basics/SKILL.md) — structured logging; tracing hooks are the place to bridge phase timing into your log channel.
3620
+ - The `use-middleware` topic ("Request ID correlation" section) — `X-Request-Id` inheritance/echo, the header tracing correlates through.
3621
+ - The `use-app-context` topic — request-scoped ALS context (`request`/`response`) tracing hooks run inside.
3622
+ - The `logger-basics` topic of the `warlock-js-logger` skill — structured logging; tracing hooks are the place to bridge phase timing into your log channel.
3595
3623
 
3596
3624
 
3597
3625
  ## resolve-path `@warlock.js/core/resolve-path/SKILL.md`
3598
3626
 
3599
3627
  ---
3600
3628
  name: resolve-path
3601
- description: 'Path helpers anchored at `process.cwd()` — `rootPath`, `srcPath`, `appPath`, `configPath`, `publicPath`, `storagePath`, `uploadsPath`, `cachePath`, `logsPath`, `tempPath`, `warlockPath`, `sanitizePath`. Optional `uploads.root` config overrides the uploads anchor. Triggers: `appPath`, `configPath`, `uploadsPath`, `storagePath`, `publicPath`, `cachePath`, `logsPath`, `tempPath`, `sanitizePath`, `paths`; "resolve a path inside src/app", "absolute upload destination", "sanitize a user filename", "ship uploads to a mounted volume"; typical import `import { appPath, uploadsPath } from "@warlock.js/core"`. Skip: HTTP URL helpers — `@warlock.js/core/build-url/SKILL.md`; app metadata — `@warlock.js/core/use-app-context/SKILL.md`; storage abstraction — `@warlock.js/core/store-file/SKILL.md`; competing patterns: `path.join(process.cwd(), ...)`, hand-rolled directory constants.'
3629
+ description: 'Path helpers anchored at `process.cwd()` — `rootPath`, `srcPath`, `appPath`, `configPath`, `publicPath`, `storagePath`, `uploadsPath`, `cachePath`, `logsPath`, `tempPath`, `warlockPath`, `sanitizePath`. Optional `uploads.root` config overrides the uploads anchor. Triggers: `appPath`, `configPath`, `uploadsPath`, `storagePath`, `publicPath`, `cachePath`, `logsPath`, `tempPath`, `sanitizePath`, `paths`; "resolve a path inside src/app", "absolute upload destination", "sanitize a user filename", "ship uploads to a mounted volume"; typical import `import { appPath, uploadsPath } from "@warlock.js/core"`. Skip: HTTP URL helpers — the `build-url` topic; app metadata — the `use-app-context` topic; storage abstraction — the `store-file` topic; competing patterns: `path.join(process.cwd(), ...)`, hand-rolled directory constants.'
3602
3630
  ---
3603
3631
 
3604
3632
  # Warlock — resolve a path
@@ -3761,18 +3789,18 @@ If you find yourself reaching for `path.join(process.cwd(), ...)` — that's a s
3761
3789
 
3762
3790
  ## See also
3763
3791
 
3764
- - [`build-url/SKILL.md`](../build-url/SKILL.md) — HTTP URL helpers (`url`, `uploadsUrl`, `publicUrl`, `assetsUrl`) — companion for rendering URLs (not filesystem paths).
3765
- - [`use-app-context/SKILL.md`](../use-app-context/SKILL.md) — `Application` static (env, runtime strategy, version, uptime) + `app` runtime accessor (Fastify, socket.io, router, database).
3766
- - [`configure-app/SKILL.md`](../configure-app/SKILL.md) — `src/config/uploads.ts` for the `root` override.
3767
- - [`store-file/SKILL.md`](../store-file/SKILL.md) — the storage abstraction (most uploads code goes through `storage.put(...)`, not raw paths).
3768
- - [`upload-file/SKILL.md`](../upload-file/SKILL.md) — the `UploadedFile` shape that pairs with `uploadsPath`.
3792
+ - The `build-url` topic — HTTP URL helpers (`url`, `uploadsUrl`, `publicUrl`, `assetsUrl`) — companion for rendering URLs (not filesystem paths).
3793
+ - The `use-app-context` topic — `Application` static (env, runtime strategy, version, uptime) + `app` runtime accessor (Fastify, socket.io, router, database).
3794
+ - The `configure-app` topic — `src/config/uploads.ts` for the `root` override.
3795
+ - The `store-file` topic — the storage abstraction (most uploads code goes through `storage.put(...)`, not raw paths).
3796
+ - The `upload-file` topic — the `UploadedFile` shape that pairs with `uploadsPath`.
3769
3797
 
3770
3798
 
3771
3799
  ## retry-operation `@warlock.js/core/retry-operation/SKILL.md`
3772
3800
 
3773
3801
  ---
3774
3802
  name: retry-operation
3775
- description: 'Wrap a flaky operation with `retry(fn, options)` — now provided by `@mongez/reinforcements` (not `@warlock.js/core`). `attempts` total tries, `delay` + `backoff` (linear/exponential/fn), `maxDelay`, `jitter`, `shouldRetry` to bail on permanent errors, `signal` to cancel, plus `retryable()` to pre-bind options. Triggers: `retry`, `retryable`, `RetryOptions`, `attempts`, `backoff`, `jitter`, `maxDelay`, `shouldRetry`, `signal`; "retry a flaky API call", "handle transient errors", "exponential backoff with jitter", "wrap an external request"; typical import `import { retry } from "@mongez/reinforcements"`. Skip: timing the retried op — `@warlock.js/core/benchmark-code/SKILL.md`; use-case-level `retry` option — `@warlock.js/core/write-use-case/SKILL.md`; competing libs `p-retry`, `async-retry`, `cockatiel`.'
3803
+ description: 'Wrap a flaky operation with `retry(fn, options)` — now provided by `@mongez/reinforcements` (not `@warlock.js/core`). `attempts` total tries, `delay` + `backoff` (linear/exponential/fn), `maxDelay`, `jitter`, `shouldRetry` to bail on permanent errors, `signal` to cancel, plus `retryable()` to pre-bind options. Triggers: `retry`, `retryable`, `RetryOptions`, `attempts`, `backoff`, `jitter`, `maxDelay`, `shouldRetry`, `signal`; "retry a flaky API call", "handle transient errors", "exponential backoff with jitter", "wrap an external request"; typical import `import { retry } from "@mongez/reinforcements"`. Skip: timing the retried op — the `benchmark-code` topic; use-case-level `retry` option — the `write-use-case` topic; competing libs `p-retry`, `async-retry`, `cockatiel`.'
3776
3804
  ---
3777
3805
 
3778
3806
  # Warlock — retry an operation
@@ -3865,7 +3893,7 @@ const result = await measure("publish-event", () =>
3865
3893
 
3866
3894
  ## Use-case integration
3867
3895
 
3868
- `useCase()` accepts a `retry` option (the same `RetryOptions`) that wraps the **handler** — see [`@warlock.js/core/write-use-case/SKILL.md`](@warlock.js/core/write-use-case/SKILL.md). Reach for that when "retry" means "re-run the handler"; reach for raw `retry()` when only one step inside is flaky.
3896
+ `useCase()` accepts a `retry` option (the same `RetryOptions`) that wraps the **handler** — see the `write-use-case` topic. Reach for that when "retry" means "re-run the handler"; reach for raw `retry()` when only one step inside is flaky.
3869
3897
 
3870
3898
  ## Gotchas
3871
3899
 
@@ -3877,15 +3905,15 @@ const result = await measure("publish-event", () =>
3877
3905
  ## See also
3878
3906
 
3879
3907
  - [`mongez-reinforcements-async`](mongez-reinforcements-async) — full `retry` / `retryable` reference.
3880
- - [`@warlock.js/core/benchmark-code/SKILL.md`](@warlock.js/core/benchmark-code/SKILL.md) — timing retried operations.
3881
- - [`@warlock.js/core/write-use-case/SKILL.md`](@warlock.js/core/write-use-case/SKILL.md) — the use-case `retry` option.
3908
+ - The `benchmark-code` topic — timing retried operations.
3909
+ - The `write-use-case` topic — the use-case `retry` option.
3882
3910
 
3883
3911
 
3884
3912
  ## run-app `@warlock.js/core/run-app/SKILL.md`
3885
3913
 
3886
3914
  ---
3887
3915
  name: run-app
3888
- 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`, `EsbuildBinaryMissingError`; "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.'
3916
+ 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`, `EsbuildBinaryMissingError`; "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 — the `write-cli-command` topic; config shape — the `configure-app` topic; competing tooling `nodemon`, `tsx`, `ts-node-dev`, `esbuild` direct.'
3889
3917
  ---
3890
3918
 
3891
3919
  # Warlock — run the app
@@ -3931,7 +3959,7 @@ Once the server is ready, `warlock dev` listens for single keypresses:
3931
3959
  | `c` | Clear the console. |
3932
3960
  | `q` | Graceful shutdown, exit `0` — the same path as `Ctrl+C`. |
3933
3961
  | `h` | Print the shortcuts that are armed right now. |
3934
- | `u` | **Only while an update notice is showing** — update every `@warlock.js/*` package, install, and restart. See [`update-packages/SKILL.md`](../update-packages/SKILL.md). |
3962
+ | `u` | **Only while an update notice is showing** — update every `@warlock.js/*` package, install, and restart. See the `update-packages` topic. |
3935
3963
  | `Ctrl+C` | Graceful shutdown, unchanged. |
3936
3964
 
3937
3965
  A "restart" is a fresh process (`r` and `u` both use it) — see [The supervisor](#the-supervisor) below for how that works.
@@ -4037,7 +4065,7 @@ export default defineConfig({
4037
4065
  - **`generateTypings`** — turn off if you're committing generated typings and don't want them rewritten on every boot. The `--skip-typings` flag is the per-run version.
4038
4066
  - **`healthCheckers`** — custom file health checker contracts (or `false` to disable). The `--skip-health` flag is the per-run version.
4039
4067
  - **`transpileCacheDebug`** — diagnostic only. Names `.warlock/transpile/*.js` files `<slug>.<hash>.js` and appends `// @source <path>` markers so you can eyeball which cache entry came from which source. Leave off in normal use.
4040
- - **`checkForUpdates`** — on `warlock dev` start, check npm for a newer `@warlock.js/core` and print a one-line notice if one exists. Best-effort and non-blocking; auto-skipped in CI and non-TTY shells. In an interactive terminal the notice arms a **`u` shortcut** that updates every `@warlock.js/*` package, installs, and restarts the server; elsewhere it prints `npx warlock update` instead. The registry answer is cached for 24h in `.warlock/update-check.json`, so a day of restarts costs one lookup. See [`update-packages/SKILL.md`](../update-packages/SKILL.md).
4068
+ - **`checkForUpdates`** — on `warlock dev` start, check npm for a newer `@warlock.js/core` and print a one-line notice if one exists. Best-effort and non-blocking; auto-skipped in CI and non-TTY shells. In an interactive terminal the notice arms a **`u` shortcut** that updates every `@warlock.js/*` package, installs, and restarts the server; elsewhere it prints `npx warlock update` instead. The registry answer is cached for 24h in `.warlock/update-check.json`, so a day of restarts costs one lookup. See the `update-packages` topic.
4041
4069
  - **`restartOnConfigChange`** — restart the dev server when `warlock.config.ts` or any `.env*` changes (default `true`). Set `false` to get a warning instead and restart by hand. Neither file can be hot-reloaded, so without a restart the running services keep the old values.
4042
4070
  - **`timings`** — print a one-line, per-phase breakdown next to the `hmr update` line on every hot reload: `watcher`, `debounce`, `graph`, `reimport`, `connectors`. `watcher` is the raw-fs-notification-to-stabilised-event gap (chokidar's `awaitWriteFinish` window); `debounce` is the handler's own adaptive wait; the rest are self-explanatory. Opt-in, off by default — a disabled flag costs one boolean check per reload, since the watcher-settle bookkeeping only runs when this is on. Use it to see which phase a slow reload is actually spending time in.
4043
4071
 
@@ -4104,7 +4132,7 @@ It exists so `warlock start` can tell a promoted build from a directory that mer
4104
4132
 
4105
4133
  `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.
4106
4134
 
4107
- 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).
4135
+ 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 the `warlock-routes` topic (its `routes:diff` section).
4108
4136
 
4109
4137
  ## `warlock start` — run the production bundle
4110
4138
 
@@ -4281,7 +4309,7 @@ If you need the same fact inside the app, use `Application.onceBooted()` / `Appl
4281
4309
 
4282
4310
  `*` — `environment` follows `NODE_ENV`. The dev command doesn't force it, but the default in most projects is `development`. `start` doesn't force it either; deployments set `NODE_ENV=production` themselves.
4283
4311
 
4284
- If you need conditional behavior, branch on `Application.environment` (the orthogonal "what world am I talking to?" axis), not `runtimeStrategy` (the "how is the framework itself running?" axis). See [`use-app-context/SKILL.md`](../use-app-context/SKILL.md).
4312
+ If you need conditional behavior, branch on `Application.environment` (the orthogonal "what world am I talking to?" axis), not `runtimeStrategy` (the "how is the framework itself running?" axis). See the `use-app-context` topic.
4285
4313
 
4286
4314
  ## Common patterns
4287
4315
 
@@ -4392,19 +4420,19 @@ NODE_OPTIONS=--max-old-space-size=4096 npx warlock start
4392
4420
 
4393
4421
  ## See also
4394
4422
 
4395
- - [`write-cli-command/SKILL.md`](../write-cli-command/SKILL.md) — author a custom CLI command + the rest of the built-in commands (migrate / seed / generate.* / add / storage.put / jwt.generate).
4396
- - [`configure-app/SKILL.md`](../configure-app/SKILL.md) — `warlock.config.ts` shape and `defineConfig`.
4397
- - [`use-app-context/SKILL.md`](../use-app-context/SKILL.md) — `Application.environment` vs `Application.runtimeStrategy`.
4398
- - [`add-connector/SKILL.md`](../add-connector/SKILL.md) — Early vs Late connector phases (why HTTP/socket boot late in dev).
4399
- - [`update-packages/SKILL.md`](../update-packages/SKILL.md) — `warlock update` + the dev-server update notice (`devServer.checkForUpdates`).
4400
- - [`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.
4423
+ - The `write-cli-command` topic — author a custom CLI command + the rest of the built-in commands (migrate / seed / generate.* / add / storage.put / jwt.generate).
4424
+ - The `configure-app` topic — `warlock.config.ts` shape and `defineConfig`.
4425
+ - The `use-app-context` topic — `Application.environment` vs `Application.runtimeStrategy`.
4426
+ - The `add-connector` topic — Early vs Late connector phases (why HTTP/socket boot late in dev).
4427
+ - The `update-packages` topic — `warlock update` + the dev-server update notice (`devServer.checkForUpdates`).
4428
+ - The `warlock-routes` topic — `warlock routes` / `warlock routes:diff`, the latter comparing live page routes against the manifest `warlock build` writes.
4401
4429
 
4402
4430
 
4403
4431
  ## send-mail `@warlock.js/core/send-mail/SKILL.md`
4404
4432
 
4405
4433
  ---
4406
4434
  name: send-mail
4407
- description: 'Send transactional email — `Mail` fluent builder, `sendMail()` direct call, React Email components. Test mode auto-captures into an in-memory mailbox; dev mode logs. Triggers: `Mail.to`, `sendMail`, `setMailMode`, `mailEvents`, `assertMailSent`, `getTestMailbox`, `wasMailSentTo`, `closeAllMailers`; "send a transactional email", "build a React Email template", "configure SMTP or SES", "assert an email was sent in tests"; typical import `import { Mail, sendMail } from "@warlock.js/core"`. Skip: per-config wiring — `@warlock.js/core/configure-app/SKILL.md`; layered service patterns — `@warlock.js/core/warlock-conventions/SKILL.md`; competing libs `nodemailer` direct, `@sendgrid/mail`, `resend`, `mailgun.js`.'
4435
+ description: 'Send transactional email — `Mail` fluent builder, `sendMail()` direct call, React Email components. Test mode auto-captures into an in-memory mailbox; dev mode logs. Triggers: `Mail.to`, `sendMail`, `setMailMode`, `mailEvents`, `assertMailSent`, `getTestMailbox`, `wasMailSentTo`, `closeAllMailers`; "send a transactional email", "build a React Email template", "configure SMTP or SES", "assert an email was sent in tests"; typical import `import { Mail, sendMail } from "@warlock.js/core"`. Skip: per-config wiring — the `configure-app` topic; layered service patterns — the `warlock-conventions` topic; competing libs `nodemailer` direct, `@sendgrid/mail`, `resend`, `mailgun.js`.'
4408
4436
  ---
4409
4437
 
4410
4438
  # Warlock — send a mail
@@ -4802,15 +4830,15 @@ await Mail.to(user.email)
4802
4830
 
4803
4831
  ## See also
4804
4832
 
4805
- - [`configure-app/SKILL.md`](../configure-app/SKILL.md) — `src/config/mail.ts` shape and `env()` patterns.
4806
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — where mail-sending services live.
4833
+ - The `configure-app` topic — `src/config/mail.ts` shape and `env()` patterns.
4834
+ - The `warlock-conventions` topic — where mail-sending services live.
4807
4835
 
4808
4836
 
4809
4837
  ## send-response `@warlock.js/core/send-response/SKILL.md`
4810
4838
 
4811
4839
  ---
4812
4840
  name: send-response
4813
- description: 'Send HTTP responses via @warlock.js/core''s Response helpers — success/error variants, status helpers, redirects, files, streams, and SSE. Picking the right helper carries the HTTP semantic without manual status codes. Triggers: `response.success`, `response.successCreate`, `response.notFound`, `response.forbidden`, `response.badRequest`, `response.sendFile`, `response.stream`, `response.sse`, `response.replay`, `ResourceNotFoundError`, `ForbiddenError`, `request.cookie`, `request.hasCookie`, `CookieJarUnavailableError`; "return a 201 from a controller", "send a file", "stream Server-Sent Events", "throw HTTP-shaped errors from services"; typical import `import type { RequestHandler, Response } from "@warlock.js/core"`. Skip: controller shape — `@warlock.js/core/create-controller/SKILL.md`; route registration — `@warlock.js/core/register-route/SKILL.md`; competing patterns: hand-rolled status codes via `reply.code(404).send(...)`, raw Fastify reply.'
4841
+ description: 'Send HTTP responses via @warlock.js/core''s Response helpers — success/error variants, status helpers, redirects, files, streams, and SSE. Picking the right helper carries the HTTP semantic without manual status codes. Triggers: `response.success`, `response.successCreate`, `response.notFound`, `response.forbidden`, `response.badRequest`, `response.sendFile`, `response.stream`, `response.sse`, `response.replay`, `ResourceNotFoundError`, `ForbiddenError`, `request.cookie`, `request.hasCookie`, `CookieJarUnavailableError`; "return a 201 from a controller", "send a file", "stream Server-Sent Events", "throw HTTP-shaped errors from services"; typical import `import type { RequestHandler, Response } from "@warlock.js/core"`. Skip: controller shape — the `create-controller` topic; route registration — the `register-route` topic; competing patterns: hand-rolled status codes via `reply.code(404).send(...)`, raw Fastify reply.'
4814
4842
  ---
4815
4843
 
4816
4844
  # Warlock — send a response
@@ -4955,7 +4983,7 @@ export const getProductController: RequestHandler = async ({ request, response }
4955
4983
  };
4956
4984
  ```
4957
4985
 
4958
- See [`create-controller`](../create-controller/SKILL.md) for the "throw from service, return from controller" pattern.
4986
+ See the `create-controller` topic for the "throw from service, return from controller" pattern.
4959
4987
 
4960
4988
  ## Server-Sent Events
4961
4989
 
@@ -5035,7 +5063,7 @@ These mutate the response in place; chain or call before the final `return respo
5035
5063
  ### `Content-Security-Policy` (5.12.0)
5036
5064
 
5037
5065
  Opt in via `http.csp.enabled` in `src/config/http.ts` (see
5038
- [`configure-app/SKILL.md`](../configure-app/SKILL.md) for the full shape).
5066
+ the `configure-app` topic for the full shape).
5039
5067
  When enabled, every response through the shared request funnel
5040
5068
  (`http/middleware/inject-request-context.ts`, the same seam that stamps
5041
5069
  `X-Request-Id`) gets a `Content-Security-Policy` header — `-Report-Only`
@@ -5115,16 +5143,16 @@ return response.header("X-Cache", "HIT").replay({
5115
5143
 
5116
5144
  ## See also
5117
5145
 
5118
- - [`create-controller/SKILL.md`](../create-controller/SKILL.md) — what calls `response.<helper>()` from.
5119
- - [`register-route/SKILL.md`](../register-route/SKILL.md) — wiring the controller to a URL.
5120
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — when to use HTTP error helpers vs `throw`.
5146
+ - The `create-controller` topic — what calls `response.<helper>()` from.
5147
+ - The `register-route` topic — wiring the controller to a URL.
5148
+ - The `warlock-conventions` topic — when to use HTTP error helpers vs `throw`.
5121
5149
 
5122
5150
 
5123
5151
  ## store-file `@warlock.js/core/store-file/SKILL.md`
5124
5152
 
5125
5153
  ---
5126
5154
  name: store-file
5127
- description: 'Read/write/delete files via the `storage` singleton — disks, drivers (local/S3/R2/DO Spaces), `storage.use(name)`, `StorageFile` handles, presigned URLs. Triggers: `storage.put`, `storage.get`, `storage.use`, `StorageFile`, `storageConfigurations`, `getPresignedUrl`, `getPresignedUploadUrl`; "save an uploaded file", "switch between local and S3", "generate a presigned URL", "read file metadata"; typical import `import { storage } from "@warlock.js/core"`. Skip: multipart parsing + image chain — `@warlock.js/core/upload-file/SKILL.md`; image transforms — `@warlock.js/core/process-image/SKILL.md`; storage config shape — `@warlock.js/core/configure-app/SKILL.md`; competing libs `@aws-sdk/client-s3`, `multer`, `formidable`.'
5155
+ description: 'Read/write/delete files via the `storage` singleton — disks, drivers (local/S3/R2/DO Spaces), `storage.use(name)`, `StorageFile` handles, presigned URLs. Triggers: `storage.put`, `storage.get`, `storage.use`, `StorageFile`, `storageConfigurations`, `getPresignedUrl`, `getPresignedUploadUrl`; "save an uploaded file", "switch between local and S3", "generate a presigned URL", "read file metadata"; typical import `import { storage } from "@warlock.js/core"`. Skip: multipart parsing + image chain — the `upload-file` topic; image transforms — the `process-image` topic; storage config shape — the `configure-app` topic; competing libs `@aws-sdk/client-s3`, `multer`, `formidable`.'
5128
5156
  ---
5129
5157
 
5130
5158
  # Warlock — store a file
@@ -5519,16 +5547,16 @@ Client `PUT`s the bytes straight to R2 — your server never sees them.
5519
5547
 
5520
5548
  ## See also
5521
5549
 
5522
- - [`configure-app/SKILL.md`](../configure-app/SKILL.md) — `src/config/storage.ts` shape and `env()` patterns.
5523
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — module layout for upload flows (`src/app/uploads/`).
5524
- - [`send-response/SKILL.md`](../send-response/SKILL.md) — `response.sendFile(absPath)` for serving local files.
5550
+ - The `configure-app` topic — `src/config/storage.ts` shape and `env()` patterns.
5551
+ - The `warlock-conventions` topic — module layout for upload flows (`src/app/uploads/`).
5552
+ - The `send-response` topic — `response.sendFile(absPath)` for serving local files.
5525
5553
 
5526
5554
 
5527
5555
  ## test-http `@warlock.js/core/test-http/SKILL.md`
5528
5556
 
5529
5557
  ---
5530
5558
  name: test-http
5531
- description: 'Integration tests against a real HTTP server — `startHttpTestServer()` boots one shared server in globalSetup, then `testGet` / `testPost` / `expectJson` make typed requests against it. Triggers: `startHttpTestServer`, `startHttpTestServer({ port })`, `stopHttpTestServer`, `testGet`, `testPost`, `testPut`, `testPatch`, `testDelete`, `expectJson`, `getTestServerUrl`, `testRequest`, `PortInUseError`, `assertPortIsAvailable`, `isPortAvailable`; "integration-test a controller", "end-to-end HTTP test", "globalSetup HTTP server", "assert status and body shape", "test server port already in use", "EADDRINUSE while running tests", "run tests while the dev server is up"; typical import `import { testGet, testPost, expectJson } from "@warlock.js/core/tests"`. Skip: pure unit tests — `@warlock.js/core/test-service/SKILL.md`; controller shape — `@warlock.js/core/create-controller/SKILL.md`; competing libs `supertest`, `light-my-request`, `nock`.'
5559
+ description: 'Integration tests against a real HTTP server — `startHttpTestServer()` boots one shared server in globalSetup, then `testGet` / `testPost` / `expectJson` make typed requests against it. Triggers: `startHttpTestServer`, `startHttpTestServer({ port })`, `stopHttpTestServer`, `testGet`, `testPost`, `testPut`, `testPatch`, `testDelete`, `expectJson`, `getTestServerUrl`, `testRequest`, `PortInUseError`, `assertPortIsAvailable`, `isPortAvailable`; "integration-test a controller", "end-to-end HTTP test", "globalSetup HTTP server", "assert status and body shape", "test server port already in use", "EADDRINUSE while running tests", "run tests while the dev server is up"; typical import `import { testGet, testPost, expectJson } from "@warlock.js/core/tests"`. Skip: pure unit tests — the `test-service` topic; controller shape — the `create-controller` topic; competing libs `supertest`, `light-my-request`, `nock`.'
5532
5560
  ---
5533
5561
 
5534
5562
  # Warlock — HTTP integration tests
@@ -5878,17 +5906,17 @@ This is fine for normal test flow. It bites when you're inside a transaction the
5878
5906
 
5879
5907
  ## See also
5880
5908
 
5881
- - [`test-service/SKILL.md`](../test-service/SKILL.md) — pure unit tests against services/repositories/models (no HTTP).
5882
- - [`create-controller/SKILL.md`](../create-controller/SKILL.md) — the controller shape your HTTP tests are exercising.
5883
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — module layout, where `tests/*.test.ts` files live.
5884
- - [`write-cli-command/SKILL.md`](../write-cli-command/SKILL.md) — `warlock add test` scaffolds both global + worker setup files.
5909
+ - The `test-service` topic — pure unit tests against services/repositories/models (no HTTP).
5910
+ - The `create-controller` topic — the controller shape your HTTP tests are exercising.
5911
+ - The `warlock-conventions` topic — module layout, where `tests/*.test.ts` files live.
5912
+ - The `write-cli-command` topic — `warlock add test` scaffolds both global + worker setup files.
5885
5913
 
5886
5914
 
5887
5915
  ## test-service `@warlock.js/core/test-service/SKILL.md`
5888
5916
 
5889
5917
  ---
5890
5918
  name: test-service
5891
- description: 'Pure unit tests against services, repositories, models, and use-cases — `setupTest({ connectors })` bootstraps the framework with its own DB/cache connections so you can call your code directly, and `teardownTest()` closes it. Triggers: `setupTest`, `teardownTest`, `src/test-setup.ts`, `tests.connectors`, `tests.setupTimeout`, `Application.setEnvironment`; "unit-test a service", "test a repository query", "vitest setupFiles", "skip connectors for pure-logic tests"; typical import `import { setupTest, teardownTest } from "@warlock.js/core/tests"`. Skip: HTTP integration — `@warlock.js/core/test-http/SKILL.md`; warlock add test scaffold — `@warlock.js/core/write-cli-command/SKILL.md`; competing tooling: jest direct, `supertest`, `nock`.'
5919
+ description: 'Pure unit tests against services, repositories, models, and use-cases — `setupTest({ connectors })` bootstraps the framework with its own DB/cache connections so you can call your code directly, and `teardownTest()` closes it. Triggers: `setupTest`, `teardownTest`, `src/test-setup.ts`, `tests.connectors`, `tests.setupTimeout`, `Application.setEnvironment`; "unit-test a service", "test a repository query", "vitest setupFiles", "skip connectors for pure-logic tests"; typical import `import { setupTest, teardownTest } from "@warlock.js/core/tests"`. Skip: HTTP integration — the `test-http` topic; warlock add test scaffold — the `write-cli-command` topic; competing tooling: jest direct, `supertest`, `nock`.'
5892
5920
  ---
5893
5921
 
5894
5922
  # Warlock — test a service
@@ -6039,7 +6067,7 @@ export default defineConfig({
6039
6067
  });
6040
6068
  ```
6041
6069
 
6042
- The `mongezVite()` plugin handles TypeScript path resolution and the framework's module shape. Without it, your imports break the moment vitest tries to load a Warlock module. `lowerStage3Decorators()` goes **first** — it lets decorated Cascade models (`@RegisterModel`, …) load under Vitest 4 / Vite 8; see [`@warlock.js/core/lower-stage3-decorators/SKILL.md`](@warlock.js/core/lower-stage3-decorators/SKILL.md).
6070
+ The `mongezVite()` plugin handles TypeScript path resolution and the framework's module shape. Without it, your imports break the moment vitest tries to load a Warlock module. `lowerStage3Decorators()` goes **first** — it lets decorated Cascade models (`@RegisterModel`, …) load under Vitest 4 / Vite 8; see the `lower-stage3-decorators` topic.
6043
6071
 
6044
6072
  ### Keep Vitest setup out of development
6045
6073
 
@@ -6279,9 +6307,9 @@ In both cases the guard's scope matches the resource's scope, which is the point
6279
6307
 
6280
6308
  ## See also
6281
6309
 
6282
- - [`test-http/SKILL.md`](../test-http/SKILL.md) — integration tests via the real HTTP server (`startHttpTestServer` + `testGet` / `testPost` / `expectJson`).
6283
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — where tests live in a module (`tests/*.test.ts`).
6284
- - [`write-cli-command/SKILL.md`](../write-cli-command/SKILL.md) — `warlock add test` for the initial scaffold.
6310
+ - The `test-http` topic — integration tests via the real HTTP server (`startHttpTestServer` + `testGet` / `testPost` / `expectJson`).
6311
+ - The `warlock-conventions` topic — where tests live in a module (`tests/*.test.ts`).
6312
+ - The `write-cli-command` topic — `warlock add test` for the initial scaffold.
6285
6313
 
6286
6314
  ## App modules and `importModule`
6287
6315
 
@@ -6298,7 +6326,7 @@ The generated `src/test-setup.ts` already does this. Without it, `setupTest()` u
6298
6326
 
6299
6327
  ---
6300
6328
  name: update-packages
6301
- description: 'Keep a project current with `warlock update` — bump every `@warlock.js/*` dependency in package.json to its latest published version (range operator preserved), then run the lockfile-detected package manager install. Also covers the `warlock dev` update notice, its `u` update-and-restart keyboard shortcut, and the `devServer.checkForUpdates` toggle. Triggers: `warlock update`, `--no-install`, `--dry-run`, `--check`, `checkForUpdates`, `fetchLatestVersion`, `isNewerVersion`; "update warlock packages", "upgrade the framework", "is there a new warlock version", "update notice in the dev server", "press u to update", "dev server keyboard shortcut", "update check offline", "bump @warlock.js/* to latest"; typical CLI `warlock update`. Skip: dev/build/start runtime — `@warlock.js/core/run-app/SKILL.md`; writing a custom command — `@warlock.js/core/write-cli-command/SKILL.md`; installing a NEW feature package (auth, mail, storage) — that is `warlock add`; releasing/publishing the framework — workspace release tooling, not this command.'
6329
+ description: 'Keep a project current with `warlock update` — bump every `@warlock.js/*` dependency in package.json to its latest published version (range operator preserved), then run the lockfile-detected package manager install. Also covers the `warlock dev` update notice, its `u` update-and-restart keyboard shortcut, and the `devServer.checkForUpdates` toggle. Triggers: `warlock update`, `--no-install`, `--dry-run`, `--check`, `checkForUpdates`, `fetchLatestVersion`, `isNewerVersion`; "update warlock packages", "upgrade the framework", "is there a new warlock version", "update notice in the dev server", "press u to update", "dev server keyboard shortcut", "update check offline", "bump @warlock.js/* to latest"; typical CLI `warlock update`. Skip: dev/build/start runtime — the `run-app` topic; writing a custom command — the `write-cli-command` topic; installing a NEW feature package (auth, mail, storage) — that is `warlock add`; releasing/publishing the framework — workspace release tooling, not this command.'
6302
6330
  ---
6303
6331
 
6304
6332
  # Warlock — update the framework
@@ -6377,7 +6405,7 @@ Pressing `u` on that notice runs the whole upgrade without leaving the dev serve
6377
6405
 
6378
6406
  1. The shortcut is disarmed and the terminal handed back, so the package manager owns stdin.
6379
6407
  2. Every `@warlock.js/*` dependency is rewritten to latest and installed — exactly what `warlock update` does.
6380
- 3. The worker shuts down (freeing the http port) and exits `75`; the `warlock dev` supervisor spawns a replacement on the new version. See [`run-app/SKILL.md`](../run-app/SKILL.md) for the supervisor.
6408
+ 3. The worker shuts down (freeing the http port) and exits `75`; the `warlock dev` supervisor spawns a replacement on the new version. See the `run-app` topic for the supervisor.
6381
6409
 
6382
6410
  What happens when it doesn't go to plan:
6383
6411
 
@@ -6389,7 +6417,7 @@ What happens when it doesn't go to plan:
6389
6417
 
6390
6418
  The shortcut is only offered when stdin is an interactive TTY. When it isn't (CI, piped stdin, a process supervisor), the notice falls back to the `Run npx warlock update` line instead — it never silently does nothing.
6391
6419
 
6392
- `u` joins the dev server's standing shortcut bar (`r` restart, `c` clear, `q` quit, `h` help) — press `h` to list whatever is armed. See [`run-app/SKILL.md`](../run-app/SKILL.md) for the bar and the raw-mode / `Ctrl+C` contract.
6420
+ `u` joins the dev server's standing shortcut bar (`r` restart, `c` clear, `q` quit, `h` help) — press `h` to list whatever is armed. See the `run-app` topic for the bar and the raw-mode / `Ctrl+C` contract.
6393
6421
 
6394
6422
  It is automatically skipped when:
6395
6423
 
@@ -6426,16 +6454,16 @@ Two small zero-dependency utilities back the tooling and are exported from `@war
6426
6454
 
6427
6455
  ## See also
6428
6456
 
6429
- - [`run-app/SKILL.md`](../run-app/SKILL.md) — `warlock dev` / `build` / `start` and the `devServer.*` config knobs.
6430
- - [`write-cli-command/SKILL.md`](../write-cli-command/SKILL.md) — author your own `warlock <cmd>`.
6431
- - [`configure-app/SKILL.md`](../configure-app/SKILL.md) — `warlock.config.ts` shape and `defineConfig`.
6457
+ - The `run-app` topic — `warlock dev` / `build` / `start` and the `devServer.*` config knobs.
6458
+ - The `write-cli-command` topic — author your own `warlock <cmd>`.
6459
+ - The `configure-app` topic — `warlock.config.ts` shape and `defineConfig`.
6432
6460
 
6433
6461
 
6434
6462
  ## upload-file `@warlock.js/core/upload-file/SKILL.md`
6435
6463
 
6436
6464
  ---
6437
6465
  name: upload-file
6438
- description: 'Handle multipart file uploads — read via `request.file()` or `request.validated()`, validate with `v.file()`, save via `UploadedFile.save()` or the storage layer, transform images inline. Triggers: `UploadedFile`, `request.file`, `v.file`, `.save`, `.saveAs`, `.resize`, `.format`, `.quality`, `.image`, `.mimeType`, `.maxSize`; "accept a file upload", "validate file size and mime", "save to S3 or local disk", "resize an uploaded image on save"; typical import `import type { UploadedFile, RequestHandler } from "@warlock.js/core"`. Skip: storage drivers + presigned URLs — `@warlock.js/core/store-file/SKILL.md`; image-only transforms — `@warlock.js/core/process-image/SKILL.md`; schema rules — `@warlock.js/core/validate-input/SKILL.md`; competing libs `multer`, `formidable`, `busboy`.'
6466
+ description: 'Handle multipart file uploads — read via `request.file()` or `request.validated()`, validate with `v.file()`, save via `UploadedFile.save()` or the storage layer, transform images inline. Triggers: `UploadedFile`, `request.file`, `v.file`, `.save`, `.saveAs`, `.resize`, `.format`, `.quality`, `.image`, `.mimeType`, `.maxSize`; "accept a file upload", "validate file size and mime", "save to S3 or local disk", "resize an uploaded image on save"; typical import `import type { UploadedFile, RequestHandler } from "@warlock.js/core"`. Skip: storage drivers + presigned URLs — the `store-file` topic; image-only transforms — the `process-image` topic; schema rules — the `validate-input` topic; competing libs `multer`, `formidable`, `busboy`.'
6439
6467
  ---
6440
6468
 
6441
6469
  # Warlock — upload a file
@@ -6643,7 +6671,7 @@ v.file() // must be UploadedFile
6643
6671
  .minHeight(200).maxHeight(4000);
6644
6672
  ```
6645
6673
 
6646
- Size accepts either bytes (`.maxSize(5_242_880)`) or `{ unit, size }` (`{ unit: "MB", size: 5 }`). See [`validate-input`](../validate-input/SKILL.md) for the full validation pattern.
6674
+ Size accepts either bytes (`.maxSize(5_242_880)`) or `{ unit, size }` (`{ unit: "MB", size: 5 }`). See the `validate-input` topic for the full validation pattern.
6647
6675
 
6648
6676
  ### Optional file field
6649
6677
 
@@ -6726,7 +6754,7 @@ await storage.use("s3").put(await uploadedFile.buffer(), "documents/report.pdf",
6726
6754
 
6727
6755
  ### Stream a download from a stored file
6728
6756
 
6729
- The reverse direction — sending a stored file back via `response.sendFile(...)` is the cleanest path. For dynamic content, use `response.stream(...)`. See [`send-response`](../send-response/SKILL.md).
6757
+ The reverse direction — sending a stored file back via `response.sendFile(...)` is the cleanest path. For dynamic content, use `response.stream(...)`. See the `send-response` topic.
6730
6758
 
6731
6759
  ## Gotchas
6732
6760
 
@@ -6740,17 +6768,17 @@ The reverse direction — sending a stored file back via `response.sendFile(...)
6740
6768
 
6741
6769
  ## See also
6742
6770
 
6743
- - [`validate-input/SKILL.md`](../validate-input/SKILL.md) — `v.file()` rules and the validation pipeline.
6744
- - [`create-controller/SKILL.md`](../create-controller/SKILL.md) — pulling files from `request.validated()` vs `request.file()`.
6745
- - [`send-response/SKILL.md`](../send-response/SKILL.md) — `response.sendFile(...)` for serving the stored file back.
6746
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — storage configuration and driver selection.
6771
+ - The `validate-input` topic — `v.file()` rules and the validation pipeline.
6772
+ - The `create-controller` topic — pulling files from `request.validated()` vs `request.file()`.
6773
+ - The `send-response` topic — `response.sendFile(...)` for serving the stored file back.
6774
+ - The `warlock-conventions` topic — storage configuration and driver selection.
6747
6775
 
6748
6776
 
6749
6777
  ## use-app-context `@warlock.js/core/use-app-context/SKILL.md`
6750
6778
 
6751
6779
  ---
6752
6780
  name: use-app-context
6753
- description: 'Read app-wide context — the `Application` static class (env, version, uptime, runtime strategy, boot lifecycle) plus the `app` runtime accessor (live Fastify, socket.io, router, database via the DI container). Triggers: `Application.isProduction`, `Application.environment`, `Application.runtimeStrategy`, `Application.uptime`, `Application.version`, `Application.onceBooted`, `Application.whenBooted`, `Application.isBooted`, `Application.onShutdown`, `Application.isShuttingDown`, `app.http`, `app.socket`, `app.database`, `app.router`; "branch on environment", "reach the live Fastify instance", "framework version in health endpoint", "dev vs production runtime check", "run code once the app is fully booted", "after all connectors started", "app booted hook", "run cleanup before shutdown", "graceful shutdown hook"; typical import `import { Application, app } from "@warlock.js/core"`. Skip: path helpers — `@warlock.js/core/resolve-path/SKILL.md`; connector start order — `@warlock.js/core/add-connector/SKILL.md`; competing patterns: bare `process.env.NODE_ENV`, ad-hoc Fastify imports.'
6781
+ description: 'Read app-wide context — the `Application` static class (env, version, uptime, runtime strategy, boot lifecycle) plus the `app` runtime accessor (live Fastify, socket.io, router, database via the DI container). Triggers: `Application.isProduction`, `Application.environment`, `Application.runtimeStrategy`, `Application.uptime`, `Application.version`, `Application.onceBooted`, `Application.whenBooted`, `Application.isBooted`, `Application.onShutdown`, `Application.isShuttingDown`, `app.http`, `app.socket`, `app.database`, `app.router`; "branch on environment", "reach the live Fastify instance", "framework version in health endpoint", "dev vs production runtime check", "run code once the app is fully booted", "after all connectors started", "app booted hook", "run cleanup before shutdown", "graceful shutdown hook"; typical import `import { Application, app } from "@warlock.js/core"`. Skip: path helpers — the `resolve-path` topic; connector start order — the `add-connector` topic; competing patterns: bare `process.env.NODE_ENV`, ad-hoc Fastify imports.'
6754
6782
  ---
6755
6783
 
6756
6784
  # Warlock — use the application context
@@ -6881,11 +6909,11 @@ Application.onceBooted(() => {
6881
6909
 
6882
6910
  Hooks run **LIFO** (reverse of registration — last opened, first closed), each is awaited, and a throwing hook is caught + logged so it can't block the rest. `Application.isShuttingDown` flips `true` the moment shutdown begins — the built-in `/ready` endpoint reads it to report not-ready so a load balancer drains the instance first. Like `onceBooted`, registering after shutdown has begun runs the callback immediately.
6883
6911
 
6884
- The framework triggers this for you (the connectors manager runs the hooks at the start of shutdown); app code only ever registers via `onShutdown`. For the HTTP-side story — `/health`, `/ready`, and graceful request draining — see `@warlock.js/core/health-checks/SKILL.md`.
6912
+ The framework triggers this for you (the connectors manager runs the hooks at the start of shutdown); app code only ever registers via `onShutdown`. For the HTTP-side story — `/health`, `/ready`, and graceful request draining — see the `health-checks` topic.
6885
6913
 
6886
6914
  ## Paths
6887
6915
 
6888
- For path helpers (`appPath`, `configPath`, `uploadsPath`, …) anchored at `process.cwd()`, the `paths.*` aggregate, and the `uploads.root` config override, see [`resolve-path/SKILL.md`](../resolve-path/SKILL.md).
6916
+ For path helpers (`appPath`, `configPath`, `uploadsPath`, …) anchored at `process.cwd()`, the `paths.*` aggregate, and the `uploads.root` config override, see the `resolve-path` topic.
6889
6917
 
6890
6918
  The most-used helpers are also surfaced as no-argument getters on `Application`:
6891
6919
 
@@ -7044,17 +7072,17 @@ cors: {
7044
7072
 
7045
7073
  ## See also
7046
7074
 
7047
- - [`resolve-path/SKILL.md`](../resolve-path/SKILL.md) — path helpers (`appPath`, `configPath`, `uploadsPath`, …) and the `paths.*` aggregate.
7048
- - [`configure-app/SKILL.md`](../configure-app/SKILL.md) — `src/config/*.ts` and `warlock.config.ts`.
7049
- - [`add-connector/SKILL.md`](../add-connector/SKILL.md) — using `Application.runtimeStrategy` inside a connector's `start()`.
7050
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — module layout, where paths point to.
7075
+ - The `resolve-path` topic — path helpers (`appPath`, `configPath`, `uploadsPath`, …) and the `paths.*` aggregate.
7076
+ - The `configure-app` topic — `src/config/*.ts` and `warlock.config.ts`.
7077
+ - The `add-connector` topic — using `Application.runtimeStrategy` inside a connector's `start()`.
7078
+ - The `warlock-conventions` topic — module layout, where paths point to.
7051
7079
 
7052
7080
 
7053
7081
  ## use-localization `@warlock.js/core/use-localization/SKILL.md`
7054
7082
 
7055
7083
  ---
7056
7084
  name: use-localization
7057
- description: 'Multi-locale translations via `groupedTranslations` (declare keys), `t()` (look up; always use it in app code, never `request.t()`), `request.getLocaleCode()` (detect locale from headers/query), `getLocalized` (pick the right value from a localized-array column). Triggers: `groupedTranslations`, `t`, `request.t`, `request.trans`, `request.transFrom`, `request.getLocaleCode`, `request.setLocaleCode`, `getLocalized`; "add a translation key", "resolve a localized error message", "detect request locale", "pick the right per-locale column value"; typical import `import { t, getLocalized } from "@warlock.js/core"`. Skip: resource output — `@warlock.js/core/define-resource/SKILL.md`; module scaffold — `@warlock.js/core/create-module/SKILL.md`; competing libs `i18next`, `react-intl`, raw `@mongez/localization`.'
7085
+ description: 'Multi-locale translations via `groupedTranslations` (declare keys), `t()` (look up; always use it in app code, never `request.t()`), `request.getLocaleCode()` (detect locale from headers/query), `getLocalized` (pick the right value from a localized-array column). Triggers: `groupedTranslations`, `t`, `request.t`, `request.trans`, `request.transFrom`, `request.getLocaleCode`, `request.setLocaleCode`, `getLocalized`; "add a translation key", "resolve a localized error message", "detect request locale", "pick the right per-locale column value"; typical import `import { t, getLocalized } from "@warlock.js/core"`. Skip: resource output — the `define-resource` topic; module scaffold — the `create-module` topic; competing libs `i18next`, `react-intl`, raw `@mongez/localization`.'
7058
7086
  ---
7059
7087
 
7060
7088
  # Warlock — translate keys + pick localized values
@@ -7169,7 +7197,7 @@ When an app uses `@warlock.js/web`, `warlock dev` writes `.warlock/typings/trans
7169
7197
  `useTrans()` now works correctly across hydration (5.15.0): the hydration
7170
7198
  payload ships a `translations` key with the active locale's keywords, and
7171
7199
  `@warlock.js/web` registers them into this same lookup table before the
7172
- client hydrates — see `@warlock.js/web/write-the-root/SKILL.md`'s "`useTrans()`
7200
+ client hydrates — see the `write-the-root` topic of the `warlock-js-web` skill's "`useTrans()`
7173
7201
  survives hydration" section for the failure this fixed.
7174
7202
 
7175
7203
  ### Locale on a specific lookup
@@ -7370,10 +7398,10 @@ GET /products/42?locale=ar
7370
7398
 
7371
7399
  ## See also
7372
7400
 
7373
- - [`send-response/SKILL.md`](../send-response/SKILL.md) — error helpers that pair with translated messages (`response.notFound({ error: t("...") })`).
7374
- - [`define-resource/SKILL.md`](../define-resource/SKILL.md) — using `getLocalized` inside resource output for clean per-locale responses.
7375
- - [`create-module/SKILL.md`](../create-module/SKILL.md) — the `utils/locales.json` file is part of the generated module scaffold.
7376
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — `utils/locales.json` is auto-loaded; the suffix is mandatory.
7401
+ - The `send-response` topic — error helpers that pair with translated messages (`response.notFound({ error: t("...") })`).
7402
+ - The `define-resource` topic — using `getLocalized` inside resource output for clean per-locale responses.
7403
+ - The `create-module` topic — the `utils/locales.json` file is part of the generated module scaffold.
7404
+ - The `warlock-conventions` topic — `utils/locales.json` is auto-loaded; the suffix is mandatory.
7377
7405
 
7378
7406
  ## Route-owned web translations (5.17)
7379
7407
 
@@ -7396,7 +7424,7 @@ When a route-locales snapshot applies, `t()` (through the request binding) and `
7396
7424
 
7397
7425
  ---
7398
7426
  name: use-middleware
7399
- description: 'Attach built-in HTTP middleware to routes via the `middleware` namespace from `@warlock.js/core` — rateLimit, concurrencyLimit, maxBodySize, idempotency, maintenance, ipFilter, cache. Plus `X-Request-Id` correlation, wired automatically. Triggers: `middleware.rateLimit`, `middleware.concurrencyLimit`, `middleware.maxBodySize`, `middleware.idempotency`, `middleware.maintenance`, `middleware.ipFilter`, `middleware.cache`, `X-Request-Id`, `Idempotency-Key`; "add rate limiting", "dedupe writes by idempotency key", "cap concurrent requests", "block IPs", "cache a GET response"; typical import `import { middleware } from "@warlock.js/core"`. Skip: author custom middleware — `@warlock.js/core/write-middleware/SKILL.md`; cache singleton — `@warlock.js/cache/cache-basics/SKILL.md`; competing libs `@fastify/rate-limit` direct, `express-rate-limit`, `helmet`.'
7427
+ description: 'Attach built-in HTTP middleware to routes via the `middleware` namespace from `@warlock.js/core` — rateLimit, concurrencyLimit, maxBodySize, idempotency, maintenance, ipFilter, cache. Plus `X-Request-Id` correlation, wired automatically. Triggers: `middleware.rateLimit`, `middleware.concurrencyLimit`, `middleware.maxBodySize`, `middleware.idempotency`, `middleware.maintenance`, `middleware.ipFilter`, `middleware.cache`, `X-Request-Id`, `Idempotency-Key`; "add rate limiting", "dedupe writes by idempotency key", "cap concurrent requests", "block IPs", "cache a GET response"; typical import `import { middleware } from "@warlock.js/core"`. Skip: author custom middleware — the `write-middleware` topic; cache singleton — the `cache-basics` topic of the `warlock-js-cache` skill; competing libs `@fastify/rate-limit` direct, `express-rate-limit`, `helmet`.'
7400
7428
  ---
7401
7429
 
7402
7430
  # Warlock — use built-in middleware
@@ -7412,7 +7440,7 @@ middleware.maxBodySize("2mb");
7412
7440
  // ... etc
7413
7441
  ```
7414
7442
 
7415
- For authoring your OWN middleware (custom guards, enrichment, etc.), see [`write-middleware`](../write-middleware/SKILL.md).
7443
+ For authoring your OWN middleware (custom guards, enrichment, etc.), see the `write-middleware` topic.
7416
7444
 
7417
7445
  ## The catalog
7418
7446
 
@@ -7664,17 +7692,17 @@ export default {
7664
7692
 
7665
7693
  ## See also
7666
7694
 
7667
- - [`write-middleware/SKILL.md`](../write-middleware/SKILL.md) — author your OWN middleware (custom guards, enrichment).
7668
- - [`register-route/SKILL.md`](../register-route/SKILL.md) — where middleware attaches: `router.group` and route-options.
7669
- - [`send-response/SKILL.md`](../send-response/SKILL.md) — the response helpers used to short-circuit (`tooManyRequests`, `contentTooLarge`, `serviceUnavailable`, etc.).
7670
- - [`@warlock.js/cache/cache-basics/SKILL.md`](../../../cache/skills/cache-basics/SKILL.md) — the cache singleton (`@warlock.js/cache`) that backs `middleware.idempotency` and `middleware.cache`.
7695
+ - The `write-middleware` topic — author your OWN middleware (custom guards, enrichment).
7696
+ - The `register-route` topic — where middleware attaches: `router.group` and route-options.
7697
+ - The `send-response` topic — the response helpers used to short-circuit (`tooManyRequests`, `contentTooLarge`, `serviceUnavailable`, etc.).
7698
+ - The `cache-basics` topic of the `warlock-js-cache` skill — the cache singleton (`@warlock.js/cache`) that backs `middleware.idempotency` and `middleware.cache`.
7671
7699
 
7672
7700
 
7673
7701
  ## use-model-transformers `@warlock.js/core/use-model-transformers/SKILL.md`
7674
7702
 
7675
7703
  ---
7676
7704
  name: use-model-transformers
7677
- description: 'Three schema-side helpers — `useHashedPassword()` (bcrypt on save) attaches via `.addTransformer(...)`; `useComputedSlug(field?, scope?)` (auto-slug from another field) and `useComputedModel(callback)` (arbitrary computed-on-save value) attach via `v.computed(...)`. Triggers: `useHashedPassword`, `useComputedSlug`, `useComputedModel`, `.addTransformer`, `v.computed`, `ComputedCallback`; "auto-hash a password field", "auto-slug from title on save", "derive a value at write time", "declarative model transformers"; typical import `import { useHashedPassword, useComputedSlug } from "@warlock.js/core"`. Skip: bcrypt setup details — `@warlock.js/core/hash-password/SKILL.md`; repository writes — `@warlock.js/core/use-repository/SKILL.md`; output filtering — `@warlock.js/core/define-resource/SKILL.md`; competing patterns: manual `await hashPassword(input)` in services, ORM lifecycle hooks.'
7705
+ description: 'Three schema-side helpers — `useHashedPassword()` (bcrypt on save) attaches via `.addTransformer(...)`; `useComputedSlug(field?, scope?)` (auto-slug from another field) and `useComputedModel(callback)` (arbitrary computed-on-save value) attach via `v.computed(...)`. Triggers: `useHashedPassword`, `useComputedSlug`, `useComputedModel`, `.addTransformer`, `v.computed`, `ComputedCallback`; "auto-hash a password field", "auto-slug from title on save", "derive a value at write time", "declarative model transformers"; typical import `import { useHashedPassword, useComputedSlug } from "@warlock.js/core"`. Skip: bcrypt setup details — the `hash-password` topic; repository writes — the `use-repository` topic; output filtering — the `define-resource` topic; competing patterns: manual `await hashPassword(input)` in services, ORM lifecycle hooks.'
7678
7706
  ---
7679
7707
 
7680
7708
  # Warlock — declare model transformers
@@ -7734,7 +7762,7 @@ What it does at save time:
7734
7762
  | Existing row, password unchanged | Pass through (no re-hashing — stored hash preserved). |
7735
7763
  | Empty / undefined value | Pass through untouched. |
7736
7764
 
7737
- 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, `npm install bcryptjs`).
7765
+ Calls `authService.hashPassword(String(value))` under the hood — same bcryptjs path as the standalone `hashPassword()` helper. See the `hash-password` topic for full bcrypt setup (salt rounds, `npm install bcryptjs`).
7738
7766
 
7739
7767
  ### Why declarative wins
7740
7768
 
@@ -7888,17 +7916,17 @@ Rule of thumb: transformers are for **pure, deterministic** transforms of the ro
7888
7916
 
7889
7917
  ## See also
7890
7918
 
7891
- - [`hash-password/SKILL.md`](../hash-password/SKILL.md) — the bcrypt setup that `useHashedPassword` calls under the hood; salt rounds, `npm install bcryptjs`.
7892
- - [`use-repository/SKILL.md`](../use-repository/SKILL.md) — where `create` / `save` calls happen that trigger the transformers.
7893
- - [`define-resource/SKILL.md`](../define-resource/SKILL.md) — filtering transformed fields (`password`) out of API responses.
7894
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — schema files live in `src/app/<module>/models/<entity>/<entity>.model.ts`.
7919
+ - The `hash-password` topic — the bcrypt setup that `useHashedPassword` calls under the hood; salt rounds, `npm install bcryptjs`.
7920
+ - The `use-repository` topic — where `create` / `save` calls happen that trigger the transformers.
7921
+ - The `define-resource` topic — filtering transformed fields (`password`) out of API responses.
7922
+ - The `warlock-conventions` topic — schema files live in `src/app/<module>/models/<entity>/<entity>.model.ts`.
7895
7923
 
7896
7924
 
7897
7925
  ## use-repository `@warlock.js/core/use-repository/SKILL.md`
7898
7926
 
7899
7927
  ---
7900
7928
  name: use-repository
7901
- description: 'Subclass `RepositoryManager` for data access — declare `source`, `filterBy`, `defaultOptions`, then call `list()`/`listCached()`/`find()`/`create()`/`update()`/`delete()`, the active/cached/cursor variants, and the `filterBy`-aware aggregates `sum()`/`avg()`/`min()`/`max()`/`groupBy()`/`aggregate()`. Triggers: `RepositoryManager`, `FilterRules`, `RepositoryOptions`, `.list`, `.listCached`, `.find`, `.findCached`, `.create`, `.update`, `.delete`, `.sum`, `.avg`, `.min`, `.max`, `.groupBy`, `.aggregate`, `simpleSelectColumns`; "create a repository", "filter rules for a list endpoint", "cursor vs page pagination", "cached vs uncached read", "sum/avg/group-by with filters"; typical import `import { RepositoryManager } from "@warlock.js/core"`. Skip: cache singleton — `@warlock.js/cache/cache-basics/SKILL.md`; use-case pipelines — `@warlock.js/core/write-use-case/SKILL.md`; wire mapping — `@warlock.js/core/define-resource/SKILL.md`; competing libs `typeorm` Repository, `prisma.client.<model>`, `@nestjs/typeorm`.'
7929
+ description: 'Subclass `RepositoryManager` for data access — declare `source`, `filterBy`, `defaultOptions`, then call `list()`/`listCached()`/`find()`/`create()`/`update()`/`delete()`, the active/cached/cursor variants, and the `filterBy`-aware aggregates `sum()`/`avg()`/`min()`/`max()`/`groupBy()`/`aggregate()`. Triggers: `RepositoryManager`, `FilterRules`, `RepositoryOptions`, `.list`, `.listCached`, `.find`, `.findCached`, `.create`, `.update`, `.delete`, `.sum`, `.avg`, `.min`, `.max`, `.groupBy`, `.aggregate`, `simpleSelectColumns`; "create a repository", "filter rules for a list endpoint", "cursor vs page pagination", "cached vs uncached read", "sum/avg/group-by with filters"; typical import `import { RepositoryManager } from "@warlock.js/core"`. Skip: cache singleton — the `cache-basics` topic of the `warlock-js-cache` skill; use-case pipelines — the `write-use-case` topic; wire mapping — the `define-resource` topic; competing libs `typeorm` Repository, `prisma.client.<model>`, `@nestjs/typeorm`.'
7902
7930
  ---
7903
7931
 
7904
7932
  # Warlock — use a repository
@@ -8320,19 +8348,19 @@ The third arg is a context object — `{ allValues, dateFormat, ... }` — for f
8320
8348
 
8321
8349
  ## See also
8322
8350
 
8323
- - [`create-module/SKILL.md`](../create-module/SKILL.md) — `warlock generate.repository` and where the file lives.
8324
- - [`@warlock.js/cache/cache-basics/SKILL.md`](../../../cache/skills/cache-basics/SKILL.md) — the cache singleton behind `listCached` / `getCached`. See sibling skills (`pick-cache-driver`, `use-swr`) for related tasks.
8325
- - [`write-use-case/SKILL.md`](../write-use-case/SKILL.md) — calling repositories from a use-case handler.
8326
- - [`define-resource/SKILL.md`](../define-resource/SKILL.md) — mapping repository output to the wire format.
8327
- - [`create-controller/SKILL.md`](../create-controller/SKILL.md) — services that consume repositories from the controller edge.
8328
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — controller → service → repository → model layering.
8351
+ - The `create-module` topic — `warlock generate.repository` and where the file lives.
8352
+ - The `cache-basics` topic of the `warlock-js-cache` skill — the cache singleton behind `listCached` / `getCached`. See sibling skills (`pick-cache-driver`, `use-swr`) for related tasks.
8353
+ - The `write-use-case` topic — calling repositories from a use-case handler.
8354
+ - The `define-resource` topic — mapping repository output to the wire format.
8355
+ - The `create-controller` topic — services that consume repositories from the controller edge.
8356
+ - The `warlock-conventions` topic — controller → service → repository → model layering.
8329
8357
 
8330
8358
 
8331
8359
  ## use-request-locals `@warlock.js/core/use-request-locals/SKILL.md`
8332
8360
 
8333
8361
  ---
8334
8362
  name: use-request-locals
8335
- description: 'Carry typed, server-only data through one HTTP request with `request.locals`, usually written by middleware and read by downstream middleware or controllers. Augment `RequestLocals` in the module that owns each key; v5 no longer permits arbitrary `request.foo` properties. Triggers: `request.locals`, `RequestLocals`, `request.post`, `request.organization`, `Property does not exist on type Request`, `Request index signature`; "attach data to a request", "share middleware data with a controller", "type request locals", "migrate dynamic request properties"; typical type augmentation `declare module "@warlock.js/core" { interface RequestLocals { ... } }`. Skip: computed-on-demand single-flight values and removed `fromRequest` — `@warlock.js/core/request-memo/SKILL.md`; middleware mechanics — `@warlock.js/core/write-middleware/SKILL.md`; authenticated user typing — augment `RequestUser`, not `RequestLocals`; competing patterns: `(request as any).foo`, `request.set()`, module-global mutable state.'
8363
+ description: 'Carry typed, server-only data through one HTTP request with `request.locals`, usually written by middleware and read by downstream middleware or controllers. Augment `RequestLocals` in the module that owns each key; v5 no longer permits arbitrary `request.foo` properties. Triggers: `request.locals`, `RequestLocals`, `request.post`, `request.organization`, `Property does not exist on type Request`, `Request index signature`; "attach data to a request", "share middleware data with a controller", "type request locals", "migrate dynamic request properties"; typical type augmentation `declare module "@warlock.js/core" { interface RequestLocals { ... } }`. Skip: computed-on-demand single-flight values and removed `fromRequest` — the `request-memo` topic; middleware mechanics — the `write-middleware` topic; authenticated user typing — augment `RequestUser`, not `RequestLocals`; competing patterns: `(request as any).foo`, `request.set()`, module-global mutable state.'
8336
8364
  ---
8337
8365
 
8338
8366
  # Warlock — use typed request locals
@@ -8494,16 +8522,16 @@ Writing `request.locals.organization` does not affect `request.all()`, `request.
8494
8522
 
8495
8523
  ## See also
8496
8524
 
8497
- - [`request-memo/SKILL.md`](../request-memo/SKILL.md) — the `fromRequest()` migration and single-flight request memoization.
8498
- - [`write-middleware/SKILL.md`](../write-middleware/SKILL.md) — middleware execution and registration.
8499
- - [`create-controller/SKILL.md`](../create-controller/SKILL.md) — reading locals in downstream controllers.
8525
+ - The `request-memo` topic — the `fromRequest()` migration and single-flight request memoization.
8526
+ - The `write-middleware` topic — middleware execution and registration.
8527
+ - The `create-controller` topic — reading locals in downstream controllers.
8500
8528
 
8501
8529
 
8502
8530
  ## validate-input `@warlock.js/core/validate-input/SKILL.md`
8503
8531
 
8504
8532
  ---
8505
8533
  name: validate-input
8506
- description: 'Author seal schemas, attach them to controllers via `controller.validation = { schema }`, infer types via `Infer<typeof schema>`, and layer DB-aware (`unique`/`exists`) and file validators on top. Triggers: `v.object`, `v.string`, `v.email`, `Infer`, `controller.validation`, `.unique`, `.exists`, `uniqueExceptCurrentId`, `request.validated`; "validate a request body", "attach a schema to a controller", "DB-aware unique rule", "infer schema types"; typical import `import { v, type Infer } from "@warlock.js/seal"`. Skip: schema authoring foundations — `@warlock.js/seal/seal-basics/SKILL.md`; controller wiring — `@warlock.js/core/create-controller/SKILL.md`; file rules deep-dive — `@warlock.js/core/upload-file/SKILL.md`; competing libs `zod`, `joi`, `yup`, `class-validator`.'
8534
+ description: 'Author seal schemas, attach them to controllers via `controller.validation = { schema }`, infer types via `Infer<typeof schema>`, and layer DB-aware (`unique`/`exists`) and file validators on top. Triggers: `v.object`, `v.string`, `v.email`, `Infer`, `controller.validation`, `.unique`, `.exists`, `uniqueExceptCurrentId`, `request.validated`; "validate a request body", "attach a schema to a controller", "DB-aware unique rule", "infer schema types"; typical import `import { v, type Infer } from "@warlock.js/seal"`. Skip: schema authoring foundations — the `seal-basics` topic of the `warlock-js-seal` skill; controller wiring — the `create-controller` topic; file rules deep-dive — the `upload-file` topic; competing libs `zod`, `joi`, `yup`, `class-validator`.'
8507
8535
  ---
8508
8536
 
8509
8537
  # Warlock — validate a request
@@ -8576,7 +8604,7 @@ From `@warlock.js/seal` — **always import from seal directly**. `@warlock.js/c
8576
8604
  | `v.literal(...values)` | exact literals | — |
8577
8605
  | `v.instanceof(Ctor, msg?)` | `Ctor` instances | — |
8578
8606
  | `v.lazy(() => schema)` | recursive/forward refs | — |
8579
- | `v.file(msg?)` | `UploadedFile` | `.image()`, `.accept(exts)`, `.mimeType(types)`, `.minSize(n)`, `.maxSize(n)`, `.minWidth(n)`, `.maxWidth(n)` — see [`upload-file`](../upload-file/SKILL.md) |
8607
+ | `v.file(msg?)` | `UploadedFile` | `.image()`, `.accept(exts)`, `.mimeType(types)`, `.minSize(n)`, `.maxSize(n)`, `.minWidth(n)`, `.maxWidth(n)` — see the `upload-file` topic |
8580
8608
  | `v.computed(callback)` | derived value | — |
8581
8609
  | `v.managed(callback)` | framework-injected value | — |
8582
8610
 
@@ -8671,7 +8699,7 @@ const uploadAvatarSchema = v.object({
8671
8699
  });
8672
8700
  ```
8673
8701
 
8674
- Full file chain: `.image()`, `.accept(extensions)`, `.mimeType(types)`, `.pdf()`, `.excel()`, `.word()`, `.minSize(n)`, `.maxSize(n)`, `.minWidth(px)`, `.maxWidth(px)`, `.minHeight(px)`, `.maxHeight(px)`. See [`upload-file`](../upload-file/SKILL.md) for the full upload flow.
8702
+ Full file chain: `.image()`, `.accept(extensions)`, `.mimeType(types)`, `.pdf()`, `.excel()`, `.word()`, `.minSize(n)`, `.maxSize(n)`, `.minWidth(px)`, `.maxWidth(px)`, `.minHeight(px)`, `.maxHeight(px)`. See the `upload-file` topic for the full upload flow.
8675
8703
 
8676
8704
  ### Optional file field
8677
8705
 
@@ -8807,17 +8835,17 @@ updateProductController.validation = {
8807
8835
 
8808
8836
  ## See also
8809
8837
 
8810
- - [`create-controller/SKILL.md`](../create-controller/SKILL.md) — how the schema attaches and how `request.validated()` reads.
8811
- - [`upload-file/SKILL.md`](../upload-file/SKILL.md) — `v.file()` and how it interacts with multipart uploads.
8812
- - [`send-response/SKILL.md`](../send-response/SKILL.md) — the 400 helper used internally by `failedSchema`.
8813
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — `Request<Schema>` type-alias convention.
8838
+ - The `create-controller` topic — how the schema attaches and how `request.validated()` reads.
8839
+ - The `upload-file` topic — `v.file()` and how it interacts with multipart uploads.
8840
+ - The `send-response` topic — the 400 helper used internally by `failedSchema`.
8841
+ - The `warlock-conventions` topic — `Request<Schema>` type-alias convention.
8814
8842
 
8815
8843
 
8816
8844
  ## warlock-conventions `@warlock.js/core/warlock-conventions/SKILL.md`
8817
8845
 
8818
8846
  ---
8819
8847
  name: warlock-conventions
8820
- description: 'Framework-wide invariants for projects built on @warlock.js/core — module layout, canonical imports, layered flow, file naming, and the non-negotiable rules every other warlock skill assumes. Triggers: `src/app/<module>`, `routes.ts`, `main.ts`, `Request<TSchema>`, `RequestHandler`, `GuardedRequestHandler`, `app/<module>/...`; "where do files go in this project", "canonical Warlock imports", "module layout rules", "controller-service-repository layering"; typical import `import { router, type RequestHandler } from "@warlock.js/core"`. Skip: scaffold a new module — `@warlock.js/core/create-module/SKILL.md`; route shape — `@warlock.js/core/register-route/SKILL.md`; controller shape — `@warlock.js/core/create-controller/SKILL.md`; competing patterns: `express` ad-hoc layouts, `@nestjs/common` decorator-driven structure.'
8848
+ description: 'Framework-wide invariants for projects built on @warlock.js/core — module layout, canonical imports, layered flow, file naming, and the non-negotiable rules every other warlock skill assumes. Triggers: `src/app/<module>`, `routes.ts`, `main.ts`, `Request<TSchema>`, `RequestHandler`, `GuardedRequestHandler`, `app/<module>/...`; "where do files go in this project", "canonical Warlock imports", "module layout rules", "controller-service-repository layering"; typical import `import { router, type RequestHandler } from "@warlock.js/core"`. Skip: scaffold a new module — the `create-module` topic; route shape — the `register-route` topic; controller shape — the `create-controller` topic; competing patterns: `express` ad-hoc layouts, `@nestjs/common` decorator-driven structure.'
8821
8849
  ---
8822
8850
 
8823
8851
  # Warlock — framework-wide conventions
@@ -8941,24 +8969,24 @@ Within the same module, use relative paths (`./`, `../`).
8941
8969
 
8942
8970
  ## Type augmentations
8943
8971
 
8944
- `src/typings.d.ts` is the project's module-augmentation file. It ships with the scaffold, is listed explicitly in `tsconfig.json`'s `include`, and is where application-wide `declare module "@warlock.js/core"` blocks live — `RequestLocals` and `RequestUser` are already there as empty interfaces. Keep its trailing `export {}` (without it the block declares an ambient module and erases the framework's real typings) and keep the augmented declarations as `interface`, the one sanctioned exception to this project's prefer-`type` rule, since declaration merging is interface-only. See [`use-request-locals`](../use-request-locals/SKILL.md).
8972
+ `src/typings.d.ts` is the project's module-augmentation file. It ships with the scaffold, is listed explicitly in `tsconfig.json`'s `include`, and is where application-wide `declare module "@warlock.js/core"` blocks live — `RequestLocals` and `RequestUser` are already there as empty interfaces. Keep its trailing `export {}` (without it the block declares an ambient module and erases the framework's real typings) and keep the augmented declarations as `interface`, the one sanctioned exception to this project's prefer-`type` rule, since declaration merging is interface-only. See the `use-request-locals` topic.
8945
8973
 
8946
8974
  ## Decorators
8947
8975
 
8948
- Cascade uses `@RegisterModel()` for the model registry and `@BelongsTo` / `@HasMany` / `@MorphTo` for relations. The scaffolded `tsconfig.json` has `"experimentalDecorators": false` — these are native Stage-3 decorators, not legacy. Never set that flag to `true`; see [`lower-stage3-decorators`](../lower-stage3-decorators/SKILL.md).
8976
+ Cascade uses `@RegisterModel()` for the model registry and `@BelongsTo` / `@HasMany` / `@MorphTo` for relations. The scaffolded `tsconfig.json` has `"experimentalDecorators": false` — these are native Stage-3 decorators, not legacy. Never set that flag to `true`; see the `lower-stage3-decorators` topic.
8949
8977
 
8950
8978
  ## See also
8951
8979
 
8952
- - [`register-route/SKILL.md`](../register-route/SKILL.md) — how to wire URLs to controllers.
8953
- - [`create-controller/SKILL.md`](../create-controller/SKILL.md) — controller signature, validation, response shape.
8954
- - [`send-response/SKILL.md`](../send-response/SKILL.md) — the full Response helper surface.
8980
+ - The `register-route` topic — how to wire URLs to controllers.
8981
+ - The `create-controller` topic — controller signature, validation, response shape.
8982
+ - The `send-response` topic — the full Response helper surface.
8955
8983
 
8956
8984
 
8957
8985
  ## warlock-doctor `@warlock.js/core/warlock-doctor/SKILL.md`
8958
8986
 
8959
8987
  ---
8960
8988
  name: warlock-doctor
8961
- 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 `npx 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.'
8989
+ 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 `npx warlock doctor`. Skip: the live `/health` + `/ready` HTTP probes — the `health-checks` topic; authoring a general CLI command — the `write-cli-command` topic; releasing the package — `releasing-warlock-monorepo`; competing tools `npm doctor`, `nest info`, hand-rolled preflight scripts.'
8962
8990
  ---
8963
8991
 
8964
8992
  # Warlock — `warlock doctor`
@@ -9090,22 +9118,22 @@ A `⚠ routes: 0 routes registered` line is the tell that a route module threw o
9090
9118
 
9091
9119
  ## See also
9092
9120
 
9093
- - [`health-checks/SKILL.md`](../health-checks/SKILL.md) — the live `/health` + `/ready` HTTP probes and the `health` registry the `health` doctor check reports on.
9094
- - [`write-cli-command/SKILL.md`](../write-cli-command/SKILL.md) — authoring a command + its `preload` plan, the shape `doctorCommand` is built from.
9095
- - [`add-connector/SKILL.md`](../add-connector/SKILL.md) — connector registration, which the `connectors` check enumerates.
9096
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — project layout the checks assume.
9121
+ - The `health-checks` topic — the live `/health` + `/ready` HTTP probes and the `health` registry the `health` doctor check reports on.
9122
+ - The `write-cli-command` topic — authoring a command + its `preload` plan, the shape `doctorCommand` is built from.
9123
+ - The `add-connector` topic — connector registration, which the `connectors` check enumerates.
9124
+ - The `warlock-conventions` topic — project layout the checks assume.
9097
9125
 
9098
9126
 
9099
9127
  ## warlock-routes `@warlock.js/core/warlock-routes/SKILL.md`
9100
9128
 
9101
9129
  ---
9102
9130
  name: warlock-routes
9103
- 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 `npx warlock routes` / `npx 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`.'
9131
+ 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 `npx warlock routes` / `npx warlock routes:diff`. Skip: read-only health/preflight checks — the `warlock-doctor` topic; defining/naming/grouping routes — the `register-route` topic; authoring a general CLI command — the `write-cli-command` topic; competing tools `nest`/`express` route listers, `php artisan route:list`.'
9104
9132
  ---
9105
9133
 
9106
9134
  # Warlock — `warlock routes`
9107
9135
 
9108
- `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.
9136
+ `warlock routes` lists every registered HTTP route as a table. It's the read-only sibling of the `warlock-doctor` topic: it boots the app far enough to register route modules — but **starts no connectors**, so it never opens a database, cache, or socket connection.
9109
9137
 
9110
9138
  ```bash
9111
9139
  npx warlock routes
@@ -9223,17 +9251,17 @@ and exits non-zero.
9223
9251
 
9224
9252
  ## See also
9225
9253
 
9226
- - [`warlock-doctor/SKILL.md`](../warlock-doctor/SKILL.md) — the read-only diagnostics sibling; its `routes` check warns when this table would be empty.
9227
- - [`register-route/SKILL.md`](../register-route/SKILL.md) — defining, naming, and grouping the routes this command lists.
9228
- - [`run-app/SKILL.md`](../run-app/SKILL.md) — `warlock build`, the command that produces the snapshot `routes:diff` compares against.
9229
- - [`write-cli-command/SKILL.md`](../write-cli-command/SKILL.md) — the command + `preload` shape `routesCommand` is built from.
9254
+ - The `warlock-doctor` topic — the read-only diagnostics sibling; its `routes` check warns when this table would be empty.
9255
+ - The `register-route` topic — defining, naming, and grouping the routes this command lists.
9256
+ - The `run-app` topic — `warlock build`, the command that produces the snapshot `routes:diff` compares against.
9257
+ - The `write-cli-command` topic — the command + `preload` shape `routesCommand` is built from.
9230
9258
 
9231
9259
 
9232
9260
  ## wire-socket `@warlock.js/core/wire-socket/SKILL.md`
9233
9261
 
9234
9262
  ---
9235
9263
  name: wire-socket
9236
- description: 'Configure Socket.IO via `src/config/socket.ts`, reach the live server through `getSocketServer()` (or `app.socket` post-bootstrap), register `connection` handlers once the late-phase socket connector has booted, emit from controllers/services, use rooms and namespaces. Triggers: `app.socket`, `getSocketServer`, `SocketOptions`, `socket.io` `Server`, `socket.join`, `socket.to`, `io.of`, `io.use`; "add realtime chat", "emit socket events from a service", "use rooms and namespaces", "per-socket JWT auth". Skip: connector lifecycle — `@warlock.js/core/add-connector/SKILL.md`; app context accessors — `@warlock.js/core/use-app-context/SKILL.md`; competing libs `ws`, `socket.io` direct without Warlock connector, `uWebSockets.js`.'
9264
+ description: 'Configure Socket.IO via `src/config/socket.ts`, reach the live server through `getSocketServer()` (or `app.socket` post-bootstrap), register `connection` handlers once the late-phase socket connector has booted, emit from controllers/services, use rooms and namespaces. Triggers: `app.socket`, `getSocketServer`, `SocketOptions`, `socket.io` `Server`, `socket.join`, `socket.to`, `io.of`, `io.use`; "add realtime chat", "emit socket events from a service", "use rooms and namespaces", "per-socket JWT auth". Skip: connector lifecycle — the `add-connector` topic; app context accessors — the `use-app-context` topic; competing libs `ws`, `socket.io` direct without Warlock connector, `uWebSockets.js`.'
9237
9265
  ---
9238
9266
 
9239
9267
  # Warlock — wire a Socket.IO server
@@ -9516,16 +9544,16 @@ CLI commands, scheduled jobs, queue workers — anything running outside an HTTP
9516
9544
 
9517
9545
  ## See also
9518
9546
 
9519
- - [`use-app-context/SKILL.md`](../use-app-context/SKILL.md) — `app.socket` runtime accessor + `Application` static metadata.
9520
- - [`add-connector/SKILL.md`](../add-connector/SKILL.md) — how connectors order their boot sequence around your modules.
9521
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — where socket-related code lives (a setup function for handler registration, `services/` for emit sites).
9547
+ - The `use-app-context` topic — `app.socket` runtime accessor + `Application` static metadata.
9548
+ - The `add-connector` topic — how connectors order their boot sequence around your modules.
9549
+ - The `warlock-conventions` topic — where socket-related code lives (a setup function for handler registration, `services/` for emit sites).
9522
9550
 
9523
9551
 
9524
9552
  ## write-cli-command `@warlock.js/core/write-cli-command/SKILL.md`
9525
9553
 
9526
9554
  ---
9527
9555
  name: write-cli-command
9528
- description: 'Author a custom `warlock <my-cmd>` command via the `command()` factory — name, description, action, options, preload, then register in `warlock.config.ts > cli.commands` or drop in `src/app/<module>/commands/`. Also covers built-in `warlock add` feature scaffolding, including the Web starter and `index.register.ts`. Triggers: `command`, `CLICommand`, `CLICommandPreload`, `CLICommandOption`, `preload`, `preAction`, `persistent`, `colors`, `warlock add`, `warlock add bull-board`, `index.register.ts`; "write a custom warlock command", "one-off maintenance task", "ship a CLI from a package", "framework built-in commands"; typical import `import { command } from "@warlock.js/core"`. Skip: framework dev/build/start — `@warlock.js/core/run-app/SKILL.md`; warlock.config.ts wiring — `@warlock.js/core/configure-app/SKILL.md`; competing libs `commander`, `yargs`, `oclif`.'
9556
+ description: 'Author a custom `warlock <my-cmd>` command via the `command()` factory — name, description, action, options, preload, then register in `warlock.config.ts > cli.commands` or drop in `src/app/<module>/commands/`. Also covers built-in `warlock add` feature scaffolding, including the Web starter and `index.register.ts`. Triggers: `command`, `CLICommand`, `CLICommandPreload`, `CLICommandOption`, `preload`, `preAction`, `persistent`, `colors`, `warlock add`, `warlock add bull-board`, `index.register.ts`; "write a custom warlock command", "one-off maintenance task", "ship a CLI from a package", "framework built-in commands"; typical import `import { command } from "@warlock.js/core"`. Skip: framework dev/build/start — the `run-app` topic; warlock.config.ts wiring — the `configure-app` topic; competing libs `commander`, `yargs`, `oclif`.'
9529
9557
  ---
9530
9558
 
9531
9559
  # Warlock — write a CLI command
@@ -9675,7 +9703,7 @@ console.log(colors.green("✓") + " user promoted");
9675
9703
 
9676
9704
  The framework ships a fixed set of commands you call but don't author. Knowing their flags up front saves a `--help` round-trip.
9677
9705
 
9678
- > For `warlock dev` / `warlock build` / `warlock start` — see [`run-app/SKILL.md`](../run-app/SKILL.md). Everything below covers the rest.
9706
+ > For `warlock dev` / `warlock build` / `warlock start` — see the `run-app` topic. Everything below covers the rest.
9679
9707
 
9680
9708
  ### Database + migrations
9681
9709
 
@@ -9721,7 +9749,7 @@ warlock generate.typings
9721
9749
  warlock generate (alias: g) — interactive picker
9722
9750
  ```
9723
9751
 
9724
- `<m>/<n>` is `<module>/<name>` (e.g. `products/create-product`). See [`create-module/SKILL.md`](../create-module/SKILL.md) for the full scaffolding flow.
9752
+ `<m>/<n>` is `<module>/<name>` (e.g. `products/create-product`). See the `create-module` topic for the full scaffolding flow.
9725
9753
 
9726
9754
  ### Feature installation
9727
9755
 
@@ -9836,16 +9864,16 @@ export default command({
9836
9864
 
9837
9865
  ## See also
9838
9866
 
9839
- - [`run-app/SKILL.md`](../run-app/SKILL.md) — the operational commands (`dev` / `build` / `start`) with all flags and config knobs.
9840
- - [`configure-app/SKILL.md`](../configure-app/SKILL.md) — wiring `defineConfig` and `warlock.config.ts`.
9841
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — module layout, canonical imports.
9867
+ - The `run-app` topic — the operational commands (`dev` / `build` / `start`) with all flags and config knobs.
9868
+ - The `configure-app` topic — wiring `defineConfig` and `warlock.config.ts`.
9869
+ - The `warlock-conventions` topic — module layout, canonical imports.
9842
9870
 
9843
9871
 
9844
9872
  ## write-middleware `@warlock.js/core/write-middleware/SKILL.md`
9845
9873
 
9846
9874
  ---
9847
9875
  name: write-middleware
9848
- description: 'Author HTTP middleware for @warlock.js/core — the `({ request, response })` signature, short-circuit by returning a response, enrich the request with extra fields, register per-route, per-group, or app-wide. Triggers: `Middleware`, `MiddlewareResponse`, `router.group`, `guarded`, `request.detectIp`, `authMiddleware`; "write a custom middleware", "short-circuit a request", "enrich the request with extra fields", "per-route vs per-group middleware"; typical import `import type { Middleware } from "@warlock.js/core"`. Skip: built-in middleware catalog — `@warlock.js/core/use-middleware/SKILL.md`; route attachment — `@warlock.js/core/register-route/SKILL.md`; response helpers — `@warlock.js/core/send-response/SKILL.md`; competing patterns: `express` `(req, res, next)` middleware, Fastify `preHandler` hooks.'
9876
+ description: 'Author HTTP middleware for @warlock.js/core — the `({ request, response })` signature, short-circuit by returning a response, enrich the request with extra fields, register per-route, per-group, or app-wide. Triggers: `Middleware`, `MiddlewareResponse`, `router.group`, `guarded`, `request.detectIp`, `authMiddleware`; "write a custom middleware", "short-circuit a request", "enrich the request with extra fields", "per-route vs per-group middleware"; typical import `import type { Middleware } from "@warlock.js/core"`. Skip: built-in middleware catalog — the `use-middleware` topic; route attachment — the `register-route` topic; response helpers — the `send-response` topic; competing patterns: `express` `(req, res, next)` middleware, Fastify `preHandler` hooks.'
9849
9877
  ---
9850
9878
 
9851
9879
  # Warlock — write a middleware
@@ -9896,7 +9924,7 @@ export const requireFeatureFlag: Middleware = async ({ request, response }) => {
9896
9924
  };
9897
9925
  ```
9898
9926
 
9899
- If you short-circuit, the controller never runs. The response helper you pick (`forbidden`, `unauthorized`, `badRequest`, etc.) sets the status — see [`send-response`](../send-response/SKILL.md).
9927
+ If you short-circuit, the controller never runs. The response helper you pick (`forbidden`, `unauthorized`, `badRequest`, etc.) sets the status — see the `send-response` topic.
9900
9928
 
9901
9929
  ## Enriching the request
9902
9930
 
@@ -10045,7 +10073,7 @@ export const optionalAuth: Middleware = async ({ request, response }) => {
10045
10073
 
10046
10074
  ## Using built-in middleware
10047
10075
 
10048
- `@warlock.js/core` ships seven built-in middlewares (rate limit, concurrency cap, body cap, idempotency, maintenance, IP filter, response cache) under the `middleware` namespace from `@warlock.js/core`. They cover the patterns most apps need — see [`use-middleware`](../use-middleware/SKILL.md) for the catalog, per-primitive deep-dives, error semantics, and gotchas specific to using them.
10076
+ `@warlock.js/core` ships seven built-in middlewares (rate limit, concurrency cap, body cap, idempotency, maintenance, IP filter, response cache) under the `middleware` namespace from `@warlock.js/core`. They cover the patterns most apps need — see the `use-middleware` topic for the catalog, per-primitive deep-dives, error semantics, and gotchas specific to using them.
10049
10077
 
10050
10078
  `X-Request-Id` correlation is wired automatically (inherit + echo on every response) — the same skill covers that too. It's not a middleware; nothing to register.
10051
10079
 
@@ -10062,18 +10090,18 @@ export const optionalAuth: Middleware = async ({ request, response }) => {
10062
10090
 
10063
10091
  ## See also
10064
10092
 
10065
- - [`use-middleware/SKILL.md`](../use-middleware/SKILL.md) — the built-in middleware catalog (`rateLimit`, `idempotency`, `maxBodySize`, etc.) + request-id correlation.
10066
- - [`register-route/SKILL.md`](../register-route/SKILL.md) — where middleware attaches: `router.group` and route-options.
10067
- - [`create-controller/SKILL.md`](../create-controller/SKILL.md) — how the controller picks up `request.locals.user`, `request.validated()`, etc., set by upstream middleware.
10068
- - [`send-response/SKILL.md`](../send-response/SKILL.md) — the response helpers used to short-circuit.
10069
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — the `guarded()` / `guardedAdmin()` / `publicRoutes()` convention.
10093
+ - The `use-middleware` topic — the built-in middleware catalog (`rateLimit`, `idempotency`, `maxBodySize`, etc.) + request-id correlation.
10094
+ - The `register-route` topic — where middleware attaches: `router.group` and route-options.
10095
+ - The `create-controller` topic — how the controller picks up `request.locals.user`, `request.validated()`, etc., set by upstream middleware.
10096
+ - The `send-response` topic — the response helpers used to short-circuit.
10097
+ - The `warlock-conventions` topic — the `guarded()` / `guardedAdmin()` / `publicRoutes()` convention.
10070
10098
 
10071
10099
 
10072
10100
  ## write-seeder `@warlock.js/core/write-seeder/SKILL.md`
10073
10101
 
10074
10102
  ---
10075
10103
  name: write-seeder
10076
- description: 'Author a seed file under `src/app/<module>/seeds/<name>.ts` using the `seeder()` factory — `name`, `dependsOn`, `once`, `order`, `batchSize`, `run({ track, now, batchSize })`. Auto-discovered by `warlock seed`; tracked in a `seeds` table; per-record refs in `seed_records` so `warlock seed --drop` can undo a seed. Triggers: `seeder`, `Seeder`, `SeedResult`, `SeedContext`, `SeedClock`, `track`, `now`, `batchSize`, `SeedersManager`, `warlock seed`, `--fresh`, `--drop`, `--list`, `--path`; "seed default roles", "undo a seed", "one-time data migration", "auto-discovered seeds", "order seeds by dependency", "deterministic seed timestamps", "inject a seed clock"; typical import `import { seeder } from "@warlock.js/core"`. Skip: module folder layout — `@warlock.js/core/create-module/SKILL.md`; repository CRUD — `@warlock.js/core/use-repository/SKILL.md`; CLI flags — `@warlock.js/core/write-cli-command/SKILL.md`; competing patterns: hand-rolled `node scripts/seed.js`, `typeorm-seeding`.'
10104
+ description: 'Author a seed file under `src/app/<module>/seeds/<name>.ts` using the `seeder()` factory — `name`, `dependsOn`, `once`, `order`, `batchSize`, `run({ track, now, batchSize })`. Auto-discovered by `warlock seed`; tracked in a `seeds` table; per-record refs in `seed_records` so `warlock seed --drop` can undo a seed. Triggers: `seeder`, `Seeder`, `SeedResult`, `SeedContext`, `SeedClock`, `track`, `now`, `batchSize`, `SeedersManager`, `warlock seed`, `--fresh`, `--drop`, `--list`, `--path`; "seed default roles", "undo a seed", "one-time data migration", "auto-discovered seeds", "order seeds by dependency", "deterministic seed timestamps", "inject a seed clock"; typical import `import { seeder } from "@warlock.js/core"`. Skip: module folder layout — the `create-module` topic; repository CRUD — the `use-repository` topic; CLI flags — the `write-cli-command` topic; competing patterns: hand-rolled `node scripts/seed.js`, `typeorm-seeding`.'
10077
10105
  ---
10078
10106
 
10079
10107
  # Warlock — write a seeder
@@ -10444,17 +10472,17 @@ warlock seed --transaction # (default true) — pass --transaction=false to s
10444
10472
 
10445
10473
  ## See also
10446
10474
 
10447
- - [`create-module/SKILL.md`](../create-module/SKILL.md) — the `seeds/` folder layout in a module, `generate.module` scaffolding.
10448
- - [`use-repository/SKILL.md`](../use-repository/SKILL.md) — the model `create` / `first` calls used inside seeds.
10449
- - [`write-cli-command/SKILL.md`](../write-cli-command/SKILL.md) — the `warlock seed` CLI flags and full preload shape.
10450
- - [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — `seeds/` is the canonical folder name (singular `seed/` is incorrect).
10475
+ - The `create-module` topic — the `seeds/` folder layout in a module, `generate.module` scaffolding.
10476
+ - The `use-repository` topic — the model `create` / `first` calls used inside seeds.
10477
+ - The `write-cli-command` topic — the `warlock seed` CLI flags and full preload shape.
10478
+ - The `warlock-conventions` topic — `seeds/` is the canonical folder name (singular `seed/` is incorrect).
10451
10479
 
10452
10480
 
10453
10481
  ## write-use-case `@warlock.js/core/write-use-case/SKILL.md`
10454
10482
 
10455
10483
  ---
10456
10484
  name: write-use-case
10457
- description: 'Author `useCase()` pipelines for business logic — guards, schema, before/after middleware, retry, benchmark, broadcast, lifecycle callbacks; transport-agnostic and observable by default. Input is inferred from the `schema`. Triggers: `useCase`, `UseCaseContext`, `UseCaseResult`, `retry`, `benchmark`, `broadcast`, `description`, `globalUseCasesEvents`, `UseCaseBroadcastChannel`; "encapsulate a business operation", "share logic between HTTP and CLI", "add guards and lifecycle hooks", "broadcast a use case result", "transport-agnostic pipeline"; typical import `import { useCase } from "@warlock.js/core"`. Skip: thin handler shape — `@warlock.js/core/create-controller/SKILL.md`; schema details — `@warlock.js/core/validate-input/SKILL.md`; the standalone retry util — `@warlock.js/core/retry-operation/SKILL.md`; competing libs `@nestjs/cqrs`, `inversify`, hand-rolled service classes.'
10485
+ description: 'Author `useCase()` pipelines for business logic — guards, schema, before/after middleware, retry, benchmark, broadcast, lifecycle callbacks; transport-agnostic and observable by default. Input is inferred from the `schema`. Triggers: `useCase`, `UseCaseContext`, `UseCaseResult`, `retry`, `benchmark`, `broadcast`, `description`, `globalUseCasesEvents`, `UseCaseBroadcastChannel`; "encapsulate a business operation", "share logic between HTTP and CLI", "add guards and lifecycle hooks", "broadcast a use case result", "transport-agnostic pipeline"; typical import `import { useCase } from "@warlock.js/core"`. Skip: thin handler shape — the `create-controller` topic; schema details — the `validate-input` topic; the standalone retry util — the `retry-operation` topic; competing libs `@nestjs/cqrs`, `inversify`, hand-rolled service classes.'
10458
10486
  ---
10459
10487
 
10460
10488
  # Warlock — write a use case
@@ -10744,8 +10772,8 @@ For the plain-function flavour (`warlock generate.use-case <module>/<verb-noun>`
10744
10772
 
10745
10773
  ## See also
10746
10774
 
10747
- - [`@warlock.js/core/create-controller/SKILL.md`](@warlock.js/core/create-controller/SKILL.md) — the usual next step: invoke this use case from an HTTP controller.
10748
- - [`@warlock.js/herald/publish-message/SKILL.md`](@warlock.js/herald/publish-message/SKILL.md) — the message bus the `broadcast` adapter publishes to (cross-package).
10775
+ - The `create-controller` topic — the usual next step: invoke this use case from an HTTP controller.
10776
+ - The `publish-message` topic of the `warlock-js-herald` skill — the message bus the `broadcast` adapter publishes to (cross-package).
10749
10777
 
10750
10778
 
10751
10779