@warlock.js/core 5.2.3 → 5.3.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 (261) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/esm/application/application.d.mts.map +1 -1
  3. package/esm/application/application.mjs.map +1 -1
  4. package/esm/benchmark/benchmark-snapshots.d.mts.map +1 -1
  5. package/esm/benchmark/benchmark.d.mts.map +1 -1
  6. package/esm/benchmark/channels/console.channel.mjs.map +1 -1
  7. package/esm/benchmark/channels/noop.channel.d.mts.map +1 -1
  8. package/esm/benchmark/profiler.d.mts.map +1 -1
  9. package/esm/benchmark/profiler.mjs.map +1 -1
  10. package/esm/bootstrap/setup.d.mts.map +1 -1
  11. package/esm/bootstrap/setup.mjs.map +1 -1
  12. package/esm/bootstrap.d.mts.map +1 -1
  13. package/esm/cache/database-cache-driver.d.mts.map +1 -1
  14. package/esm/cache/database-cache-driver.mjs.map +1 -1
  15. package/esm/cli/cli-commands.manager.mjs.map +1 -1
  16. package/esm/cli/cli-commands.utils.mjs.map +1 -1
  17. package/esm/cli/commands/doctor/boot-for-diagnostics.mjs.map +1 -1
  18. package/esm/cli/commands/doctor/checks/connectors.check.mjs.map +1 -1
  19. package/esm/cli/commands/doctor/checks/handler-signature.check.mjs.map +1 -1
  20. package/esm/cli/commands/doctor/checks/health.check.mjs.map +1 -1
  21. package/esm/cli/commands/doctor/checks/optional-peers.check.mjs.map +1 -1
  22. package/esm/cli/commands/doctor/checks/routes.check.mjs.map +1 -1
  23. package/esm/cli/commands/generate/generate.command.mjs.map +1 -1
  24. package/esm/cli/commands/generate/generators/column-dsl-parser.mjs.map +1 -1
  25. package/esm/cli/commands/generate/generators/migration.generator.mjs.map +1 -1
  26. package/esm/cli/commands/generate/generators/model.generator.mjs.map +1 -1
  27. package/esm/cli/commands/generate/templates/stubs.mjs +13 -14
  28. package/esm/cli/commands/generate/templates/stubs.mjs.map +1 -1
  29. package/esm/cli/commands/generate/utils/name-parser.mjs.map +1 -1
  30. package/esm/cli/commands/generate/utils/prompt.mjs.map +1 -1
  31. package/esm/cli/commands/routes/diff-page-routes.mjs.map +1 -1
  32. package/esm/cli/commands/routes/format-routes-table.mjs.map +1 -1
  33. package/esm/cli/commands/routes/route-row.mjs.map +1 -1
  34. package/esm/cli/commands/routes/routes-command.action.mjs.map +1 -1
  35. package/esm/cli/commands/routes/routes-diff.action.mjs.map +1 -1
  36. package/esm/cli/commands/storage-put.action.mjs.map +1 -1
  37. package/esm/cli/commands/typings-generator.command.mjs.map +1 -1
  38. package/esm/cli/commands-loader.mjs.map +1 -1
  39. package/esm/cli/start.mjs.map +1 -1
  40. package/esm/cli/string-similarity.mjs.map +1 -1
  41. package/esm/commands/cli-command.mjs.map +1 -1
  42. package/esm/config/config-loader.mjs.map +1 -1
  43. package/esm/config/config-setter.d.mts.map +1 -1
  44. package/esm/config/load-config-files.mjs.map +1 -1
  45. package/esm/connectors/access-connector.d.mts.map +1 -1
  46. package/esm/connectors/ai-connector.d.mts.map +1 -1
  47. package/esm/connectors/assert-no-reserved-connector-names.mjs.map +1 -1
  48. package/esm/connectors/assert-unique-connector-names.mjs.map +1 -1
  49. package/esm/connectors/base-connector.d.mts.map +1 -1
  50. package/esm/connectors/base-connector.mjs.map +1 -1
  51. package/esm/connectors/cache-connector.d.mts.map +1 -1
  52. package/esm/connectors/connectors-manager.d.mts.map +1 -1
  53. package/esm/connectors/connectors-manager.mjs.map +1 -1
  54. package/esm/connectors/database-connector.d.mts.map +1 -1
  55. package/esm/connectors/describe-server-address.mjs.map +1 -1
  56. package/esm/connectors/herald-connector.d.mts.map +1 -1
  57. package/esm/connectors/http-connector.d.mts.map +1 -1
  58. package/esm/connectors/http-connector.mjs.map +1 -1
  59. package/esm/connectors/logger-connector.d.mts.map +1 -1
  60. package/esm/connectors/mail-connector.d.mts.map +1 -1
  61. package/esm/connectors/notifications-connector.d.mts.map +1 -1
  62. package/esm/connectors/register-configured-connectors.mjs.map +1 -1
  63. package/esm/connectors/socket-connector.d.mts.map +1 -1
  64. package/esm/connectors/socket-connector.mjs.map +1 -1
  65. package/esm/connectors/storage.connector.d.mts.map +1 -1
  66. package/esm/container/index.d.mts.map +1 -1
  67. package/esm/database/create-database-action.mjs.map +1 -1
  68. package/esm/database/drop-tables-action.mjs.map +1 -1
  69. package/esm/database/migrate-action.mjs.map +1 -1
  70. package/esm/database/seed-command-action.mjs.map +1 -1
  71. package/esm/database/seeds/seed-records-table-migration.mjs.map +1 -1
  72. package/esm/database/seeds/seeders.manager.mjs.map +1 -1
  73. package/esm/database/seeds/seeds-table-migration.mjs.map +1 -1
  74. package/esm/dev-server/check-for-updates.mjs.map +1 -1
  75. package/esm/dev-server/dependency-graph.d.mts.map +1 -1
  76. package/esm/dev-server/dependency-graph.mjs.map +1 -1
  77. package/esm/dev-server/dev-logger.mjs.map +1 -1
  78. package/esm/dev-server/development-server.mjs.map +1 -1
  79. package/esm/dev-server/file-event-handler.mjs.map +1 -1
  80. package/esm/dev-server/file-manager.d.mts.map +1 -1
  81. package/esm/dev-server/file-manager.mjs.map +1 -1
  82. package/esm/dev-server/file-operations.d.mts.map +1 -1
  83. package/esm/dev-server/files-orchestrator.mjs.map +1 -1
  84. package/esm/dev-server/files-watcher.mjs.map +1 -1
  85. package/esm/dev-server/health-checker/checkers/eslint-health-checker.mjs.map +1 -1
  86. package/esm/dev-server/health-checker/checkers/typescript-health-checker.mjs.map +1 -1
  87. package/esm/dev-server/health-checker/file-health-result.d.mts.map +1 -1
  88. package/esm/dev-server/health-checker/file-health-result.mjs.map +1 -1
  89. package/esm/dev-server/health-checker/files-healthcare.manager.mjs.map +1 -1
  90. package/esm/dev-server/layer-executor.mjs.map +1 -1
  91. package/esm/dev-server/loader/hook-thread.d.mts.map +1 -1
  92. package/esm/dev-server/loader/own-resolver.mjs.map +1 -1
  93. package/esm/dev-server/loader/register-loader.mjs.map +1 -1
  94. package/esm/dev-server/loader/resolve-hook.mjs.map +1 -1
  95. package/esm/dev-server/loader/source-slug.mjs.map +1 -1
  96. package/esm/dev-server/loader/transpile-cache.mjs.map +1 -1
  97. package/esm/dev-server/loader/version-registry.mjs.map +1 -1
  98. package/esm/dev-server/manifest-manager.d.mts.map +1 -1
  99. package/esm/dev-server/manifest-manager.mjs.map +1 -1
  100. package/esm/dev-server/module-loader.mjs.map +1 -1
  101. package/esm/dev-server/package-json-manager.mjs.map +1 -1
  102. package/esm/dev-server/parse-imports.mjs.map +1 -1
  103. package/esm/dev-server/ready-block.mjs.map +1 -1
  104. package/esm/dev-server/special-files-collector.d.mts.map +1 -1
  105. package/esm/dev-server/special-files-collector.mjs.map +1 -1
  106. package/esm/dev-server/tsconfig-manager.mjs.map +1 -1
  107. package/esm/dev-server/type-generator.mjs.map +1 -1
  108. package/esm/dev-server/utils.mjs.map +1 -1
  109. package/esm/encryption/encrypt.mjs.map +1 -1
  110. package/esm/encryption/hash.mjs.map +1 -1
  111. package/esm/generations/add-command.action.mjs.map +1 -1
  112. package/esm/generations/features/shadcn.feature.mjs.map +1 -1
  113. package/esm/generations/features/shared/migration-timestamp.mjs.map +1 -1
  114. package/esm/generations/features/tailwind.feature.mjs.map +1 -1
  115. package/esm/generations/features/web.feature.mjs +2 -1
  116. package/esm/generations/features/web.feature.mjs.map +1 -1
  117. package/esm/generations/stubs.mjs +53 -54
  118. package/esm/generations/stubs.mjs.map +1 -1
  119. package/esm/http/boot-port-preflight.d.mts.map +1 -1
  120. package/esm/http/context/request-context.d.mts.map +1 -1
  121. package/esm/http/context/request-context.mjs.map +1 -1
  122. package/esm/http/context/request-memo.d.mts.map +1 -1
  123. package/esm/http/context/request-memo.mjs.map +1 -1
  124. package/esm/http/createHttpApplication.d.mts.map +1 -1
  125. package/esm/http/createHttpApplication.mjs.map +1 -1
  126. package/esm/http/health.d.mts.map +1 -1
  127. package/esm/http/index.d.mts +1 -1
  128. package/esm/http/middleware/cache-response-middleware.mjs.map +1 -1
  129. package/esm/http/middleware/idempotency.middleware.mjs.map +1 -1
  130. package/esm/http/middleware/inject-request-context.d.mts.map +1 -1
  131. package/esm/http/middleware/inject-request-context.mjs +2 -21
  132. package/esm/http/middleware/inject-request-context.mjs.map +1 -1
  133. package/esm/http/middleware/maintenance.middleware.mjs.map +1 -1
  134. package/esm/http/middleware/utils/idempotency-key.mjs.map +1 -1
  135. package/esm/http/ready-report.d.mts.map +1 -1
  136. package/esm/http/request-controller.d.mts.map +1 -1
  137. package/esm/http/request.d.mts +25 -6
  138. package/esm/http/request.d.mts.map +1 -1
  139. package/esm/http/request.mjs +48 -0
  140. package/esm/http/request.mjs.map +1 -1
  141. package/esm/http/response.d.mts +3 -3
  142. package/esm/http/response.d.mts.map +1 -1
  143. package/esm/http/response.mjs.map +1 -1
  144. package/esm/http/server.d.mts.map +1 -1
  145. package/esm/http/server.mjs.map +1 -1
  146. package/esm/http/types.d.mts +36 -5
  147. package/esm/http/types.d.mts.map +1 -1
  148. package/esm/http/uploaded-file.d.mts.map +1 -1
  149. package/esm/http/uploaded-file.mjs.map +1 -1
  150. package/esm/http/uploads-config.d.mts.map +1 -1
  151. package/esm/image/image.d.mts.map +1 -1
  152. package/esm/image/image.mjs.map +1 -1
  153. package/esm/index.d.mts +2 -2
  154. package/esm/logger/logger.mjs.map +1 -1
  155. package/esm/mail/config.d.mts.map +1 -1
  156. package/esm/mail/events.d.mts.map +1 -1
  157. package/esm/mail/mail.d.mts.map +1 -1
  158. package/esm/mail/mail.mjs.map +1 -1
  159. package/esm/mail/mailer-pool.d.mts.map +1 -1
  160. package/esm/mail/mailer-pool.mjs.map +1 -1
  161. package/esm/mail/send-mail.mjs.map +1 -1
  162. package/esm/mail/test-mailbox.d.mts.map +1 -1
  163. package/esm/mail/test-mailbox.mjs.map +1 -1
  164. package/esm/production/assert-generated-imports.mjs.map +1 -1
  165. package/esm/production/build-app-production.mjs.map +1 -1
  166. package/esm/production/dist-build-manifest.mjs.map +1 -1
  167. package/esm/production/production-builder.mjs.map +1 -1
  168. package/esm/production/production-supervisor.mjs.map +1 -1
  169. package/esm/production/promote-dist.mjs.map +1 -1
  170. package/esm/production/resolve-build-config.mjs.map +1 -1
  171. package/esm/repositories/adapters/cascade/cascade-adapter.d.mts.map +1 -1
  172. package/esm/repositories/adapters/cascade/cascade-adapter.mjs.map +1 -1
  173. package/esm/repositories/adapters/cascade/cascade-query-builder.d.mts.map +1 -1
  174. package/esm/repositories/adapters/cascade/cascade-query-builder.mjs.map +1 -1
  175. package/esm/repositories/adapters/cascade/filter-applicator.mjs.map +1 -1
  176. package/esm/repositories/repository.manager.d.mts.map +1 -1
  177. package/esm/repositories/repository.manager.mjs.map +1 -1
  178. package/esm/resource/register-resource.d.mts.map +1 -1
  179. package/esm/resource/resource-field-builder.d.mts.map +1 -1
  180. package/esm/resource/resource-field-builder.mjs.map +1 -1
  181. package/esm/resource/resource.d.mts.map +1 -1
  182. package/esm/resource/resource.mjs.map +1 -1
  183. package/esm/restful/restful.d.mts.map +1 -1
  184. package/esm/restful/restful.mjs.map +1 -1
  185. package/esm/router/log-request-lifecycle.mjs.map +1 -1
  186. package/esm/router/normalize-route-path.d.mts.map +1 -1
  187. package/esm/router/positional-handler-diagnostics.d.mts.map +1 -1
  188. package/esm/router/positional-handler-diagnostics.mjs.map +1 -1
  189. package/esm/router/route-registry.d.mts.map +1 -1
  190. package/esm/router/route-registry.mjs.map +1 -1
  191. package/esm/router/router.d.mts.map +1 -1
  192. package/esm/router/router.mjs.map +1 -1
  193. package/esm/socket/utils.d.mts.map +1 -1
  194. package/esm/storage/config.d.mts.map +1 -1
  195. package/esm/storage/context/storage-driver-context.d.mts.map +1 -1
  196. package/esm/storage/drivers/cloud-driver.d.mts.map +1 -1
  197. package/esm/storage/drivers/cloud-driver.mjs.map +1 -1
  198. package/esm/storage/drivers/do-spaces-driver.d.mts.map +1 -1
  199. package/esm/storage/drivers/local-driver.d.mts.map +1 -1
  200. package/esm/storage/drivers/local-driver.mjs.map +1 -1
  201. package/esm/storage/drivers/r2-driver.d.mts.map +1 -1
  202. package/esm/storage/scoped-storage.d.mts.map +1 -1
  203. package/esm/storage/scoped-storage.mjs.map +1 -1
  204. package/esm/storage/storage-file.d.mts.map +1 -1
  205. package/esm/storage/storage-file.mjs.map +1 -1
  206. package/esm/storage/storage.d.mts.map +1 -1
  207. package/esm/storage/utils/safe-fetch.mjs.map +1 -1
  208. package/esm/tests/start-http-development-server.d.mts.map +1 -1
  209. package/esm/tests/test-connectors-selection.mjs.map +1 -1
  210. package/esm/tests/test-helpers.d.mts.map +1 -1
  211. package/esm/tests/test-setup-timeout.mjs.map +1 -1
  212. package/esm/tests/vitest-setup.d.mts.map +1 -1
  213. package/esm/tests/vitest-setup.mjs.map +1 -1
  214. package/esm/updater/update-warlock-packages.mjs.map +1 -1
  215. package/esm/use-cases/use-case-broadcast.d.mts.map +1 -1
  216. package/esm/use-cases/use-case-events.d.mts.map +1 -1
  217. package/esm/use-cases/use-case-pipeline.d.mts.map +1 -1
  218. package/esm/use-cases/use-case.d.mts.map +1 -1
  219. package/esm/use-cases/use-cases-registry.d.mts.map +1 -1
  220. package/esm/use-cases/use-cases-registry.mjs.map +1 -1
  221. package/esm/utils/database-log.d.mts.map +1 -1
  222. package/esm/utils/database-log.mjs.map +1 -1
  223. package/esm/utils/environment.d.mts.map +1 -1
  224. package/esm/utils/framework-vesion.mjs.map +1 -1
  225. package/esm/utils/get-localized.mjs.map +1 -1
  226. package/esm/utils/load-environment.mjs.map +1 -1
  227. package/esm/utils/normalized-path.d.mts.map +1 -1
  228. package/esm/utils/paths.d.mts.map +1 -1
  229. package/esm/utils/promise-all-object.d.mts.map +1 -1
  230. package/esm/utils/promise-all-object.mjs.map +1 -1
  231. package/esm/utils/sluggable.mjs.map +1 -1
  232. package/esm/utils/version-compare.mjs.map +1 -1
  233. package/esm/validation/database/exists-except-current-id.mjs.map +1 -1
  234. package/esm/validation/database/exists-except-current-user.mjs.map +1 -1
  235. package/esm/validation/database/unique-except-current-id.mjs.map +1 -1
  236. package/esm/validation/plugins/file-plugin.mjs.map +1 -1
  237. package/esm/validation/plugins/localized-plugin.mjs +2 -2
  238. package/esm/validation/plugins/localized-plugin.mjs.map +1 -1
  239. package/esm/validation/types.d.mts +17 -4
  240. package/esm/validation/types.d.mts.map +1 -1
  241. package/esm/validation/validators/file-validator.mjs.map +1 -1
  242. package/esm/vite/lower-stage3-decorators.d.mts.map +1 -1
  243. package/esm/warlock-config/warlock-config.manager.d.mts.map +1 -1
  244. package/esm/warlock-config/warlock-config.manager.mjs.map +1 -1
  245. package/llms-full.txt +113 -87
  246. package/llms.txt +2 -2
  247. package/package.json +12 -12
  248. package/skills/README.md +2 -2
  249. package/skills/create-controller/SKILL.md +9 -9
  250. package/skills/send-response/SKILL.md +51 -37
  251. package/skills/store-file/SKILL.md +8 -3
  252. package/skills/upload-file/SKILL.md +9 -7
  253. package/skills/use-app-context/SKILL.md +2 -2
  254. package/skills/use-localization/SKILL.md +6 -2
  255. package/skills/use-repository/SKILL.md +2 -2
  256. package/skills/use-request-locals/SKILL.md +3 -3
  257. package/skills/validate-input/SKILL.md +2 -2
  258. package/skills/warlock-conventions/SKILL.md +2 -2
  259. package/skills/wire-socket/SKILL.md +2 -2
  260. package/skills/write-cli-command/SKILL.md +4 -1
  261. package/skills/write-middleware/SKILL.md +13 -15
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: write-middleware
3
- 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.'
3
+ 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.'
4
4
  ---
5
5
 
6
6
  # Warlock — write a middleware
@@ -12,7 +12,7 @@ Middleware is a plain function that runs before the controller. Two outcomes: re
12
12
  ```ts title="src/app/<module>/utils/<name>.middleware.ts"
13
13
  import type { Middleware } from "@warlock.js/core";
14
14
 
15
- export const requireApiKey: Middleware = (request, response) => {
15
+ export const requireApiKey: Middleware = ({ request, response }) => {
16
16
  const key = request.header("X-API-Key");
17
17
 
18
18
  if (!key || key !== process.env.API_KEY) {
@@ -23,16 +23,14 @@ export const requireApiKey: Middleware = (request, response) => {
23
23
  };
24
24
  ```
25
25
 
26
- That's the contract: `(request: Request, response: Response) => Response | undefined | void`. Async is fine — return a `Promise<Response | undefined | void>`.
26
+ That's the contract: `(context: HttpContext<Request>) => Response | undefined | void`, where `context` is `{ request, response }`. Async is fine — return a `Promise<Response | undefined | void>`.
27
27
 
28
28
  The real type, from `@warlock.js/core/src/router/types.ts`:
29
29
 
30
30
  ```ts
31
31
  export type Middleware<MiddlewareRequest extends Request = Request> = {
32
- (request: MiddlewareRequest, response: Response): MiddlewareResponse;
32
+ (context: HttpContext<MiddlewareRequest>): MiddlewareResponse;
33
33
  };
34
-
35
- export type MiddlewareResponse = ReturnedResponse | undefined | void;
36
34
  ```
37
35
 
38
36
  ## Short-circuit vs continue
@@ -42,7 +40,7 @@ The pattern is "return a response to stop, return nothing to continue":
42
40
  ```ts
43
41
  import type { Middleware } from "@warlock.js/core";
44
42
 
45
- export const requireFeatureFlag: Middleware = async (request, response) => {
43
+ export const requireFeatureFlag: Middleware = async ({ request, response }) => {
46
44
  const flag = await loadFeatureFlag(request.input("organization_id"));
47
45
 
48
46
  if (!flag.enabled) {
@@ -60,8 +58,8 @@ If you short-circuit, the controller never runs. The response helper you pick (`
60
58
  You can attach arbitrary fields to `request` from a middleware, and they survive into the controller. The cleanest pattern is to extend `Request` via module augmentation in a `.d.ts` and assign in the middleware:
61
59
 
62
60
  ```ts title="src/app/feature-flags/middleware/load-feature-flag.middleware.ts"
63
- import type { Middleware } from "@warlock.js/core";
64
- import type { FeatureFlag } from "../models/feature-flag";
61
+ import type { Middleware, Request, RequestUser } from "@warlock.js/core";
62
+ import { FeatureFlag } from "../models/feature-flag";
65
63
 
66
64
  declare module "@warlock.js/core" {
67
65
  interface Request {
@@ -69,7 +67,7 @@ declare module "@warlock.js/core" {
69
67
  }
70
68
  }
71
69
 
72
- export const loadFeatureFlag: Middleware = async (request) => {
70
+ export const loadFeatureFlag: Middleware<Request & { user: RequestUser }> = async ({ request }) => {
73
71
  request.featureFlag = await FeatureFlag.findBy("organization_id", request.user.organizationId);
74
72
  };
75
73
  ```
@@ -139,7 +137,7 @@ export function guarded(callback: () => void) {
139
137
  }
140
138
 
141
139
  export function guardedAdmin(callback: () => void) {
142
- router.group({ prefix: "/admin", middleware: [authMiddleware()] }, callback);
140
+ router.group({ prefix: "/admin", middleware: [authMiddleware("admin")] }, callback);
143
141
  }
144
142
 
145
143
  export function publicRoutes(callback: () => void) {
@@ -157,7 +155,7 @@ guarded(() => {
157
155
  });
158
156
  ```
159
157
 
160
- `authMiddleware(allowedUserType?)` accepts a user-type string or array. Without an arg it just verifies the token is present; with `"user"` / `"admin"` it also checks the decoded `userType` matches.
158
+ `authMiddleware(allowedUserType, tokenFrom?)` requires a user-type string or array `[]` accepts any authenticated user without checking `userType`; `"user"` / `"admin"` also checks the decoded `userType` matches.
161
159
 
162
160
  ## Common patterns
163
161
 
@@ -184,13 +182,13 @@ router.group(
184
182
  ```ts
185
183
  import type { Middleware } from "@warlock.js/core";
186
184
 
187
- export const optionalAuth: Middleware = async (request, response) => {
185
+ export const optionalAuth: Middleware = async ({ request, response }) => {
188
186
  if (!request.authorizationValue) {
189
187
  return; // anonymous — let it through
190
188
  }
191
189
 
192
190
  // token present → enforce it
193
- return authMiddleware("user")(request, response);
191
+ return authMiddleware("user")({ request, response });
194
192
  };
195
193
  ```
196
194
 
@@ -206,7 +204,7 @@ export const optionalAuth: Middleware = async (request, response) => {
206
204
  - **Group middleware runs before per-route middleware**, in array order. The full chain is `app.all → group → per-route → controller`. Mind the order if you stack auth + rate-limit + audit.
207
205
  - **Middleware can be async.** Returning `Promise<undefined>` continues the chain. Returning `Promise<Response>` short-circuits. The framework awaits the result.
208
206
  - **Don't mutate `request.payload` directly.** Use `request.setValidatedData(...)` or attach a new named field (`request.featureFlag = ...`). The internals expect `payload.all` shapes to come from the validator pipeline.
209
- - **`Middleware` is generic over the request type.** For middleware that assumes a validated schema, narrow it: `const m: Middleware<CreateProductRequest> = (request) => { ... }`. But most middlewares run before validation, so the default `Middleware` is right.
207
+ - **`Middleware` is generic over the request type.** For middleware that assumes a validated schema, narrow it: `const m: Middleware<CreateProductRequest> = ({ request }) => { ... }`. But most middlewares run before validation, so the default `Middleware` is right.
210
208
  - **No `next()` parameter.** Express-style `next()` doesn't apply here. The framework chains based on return value.
211
209
  - **`request.baseRequest` / `response.baseResponse` are escape hatches, not API.** They expose the underlying Fastify primitives for cases the framework hasn't covered yet (streaming was the historical precedent). Prefer framework helpers first — `response.send()`, `response.header()`, `response.replay()`, `request.input()`, `request.detectIp()`, etc. If you find yourself reaching for `baseResponse` or `baseRequest` for non-streaming work, that's a missing helper — file an issue. The cache and idempotency middlewares both shipped with a quietly-broken FastifyReply-return bug because they bypassed the helper layer; the framework now guards `Response.send()` against double-send, but the right answer is "use the helper."
212
210
  - **Behind any proxy, use `request.detectIp()` not `request.ip`.** `request.ip` is the immediate peer (likely your load balancer); `request.detectIp()` honors `X-Real-IP` / `X-Forwarded-For`. Either way, only trust the result as far as you trust the upstream chain — those headers are client-settable; verify the request came through your trusted edge before treating the value as authoritative.