@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.
- package/CHANGELOG.md +24 -0
- package/esm/cli/commands/openapi-generator.action.mjs +1 -1
- package/esm/cli/commands/openapi-generator.action.mjs.map +1 -1
- package/esm/cli/commands/postman-generator.action.mjs +47 -0
- package/esm/cli/commands/postman-generator.action.mjs.map +1 -0
- package/esm/cli/commands/postman-generator.command.mjs +43 -0
- package/esm/cli/commands/postman-generator.command.mjs.map +1 -0
- package/esm/cli/framework-cli-commands.mjs +2 -0
- package/esm/cli/framework-cli-commands.mjs.map +1 -1
- package/esm/container/development-app-modules.d.mts +31 -0
- package/esm/container/development-app-modules.d.mts.map +1 -0
- package/esm/container/index.d.mts +2 -0
- package/esm/container/index.d.mts.map +1 -1
- package/esm/container/index.mjs.map +1 -1
- package/esm/dev-server/app-module-registry.mjs +52 -0
- package/esm/dev-server/app-module-registry.mjs.map +1 -0
- package/esm/dev-server/files-orchestrator.mjs +13 -2
- package/esm/dev-server/files-orchestrator.mjs.map +1 -1
- package/esm/http/middleware/inject-request-context.d.mts.map +1 -1
- package/esm/http/middleware/inject-request-context.mjs +29 -3
- package/esm/http/middleware/inject-request-context.mjs.map +1 -1
- package/esm/http/request.d.mts +2 -2
- package/esm/http/request.d.mts.map +1 -1
- package/esm/index.d.mts +7 -2
- package/esm/index.mjs +5 -2
- package/esm/localization/parse-locale-dictionary.d.mts +6 -1
- package/esm/localization/parse-locale-dictionary.d.mts.map +1 -1
- package/esm/localization/parse-locale-dictionary.mjs +5 -1
- package/esm/localization/parse-locale-dictionary.mjs.map +1 -1
- package/esm/openapi/development-openapi-provider.d.mts +12 -1
- package/esm/openapi/development-openapi-provider.d.mts.map +1 -1
- package/esm/openapi/development-openapi-provider.mjs +15 -1
- package/esm/openapi/development-openapi-provider.mjs.map +1 -1
- package/esm/openapi/index.d.mts +5 -2
- package/esm/openapi/index.mjs +3 -1
- package/esm/openapi/postman/build-request-body.mjs +86 -0
- package/esm/openapi/postman/build-request-body.mjs.map +1 -0
- package/esm/openapi/postman/build-request-url.mjs +85 -0
- package/esm/openapi/postman/build-request-url.mjs.map +1 -0
- package/esm/openapi/postman/build-saved-responses.mjs +60 -0
- package/esm/openapi/postman/build-saved-responses.mjs.map +1 -0
- package/esm/openapi/postman/example-from-schema.d.mts +17 -0
- package/esm/openapi/postman/example-from-schema.d.mts.map +1 -0
- package/esm/openapi/postman/example-from-schema.mjs +92 -0
- package/esm/openapi/postman/example-from-schema.mjs.map +1 -0
- package/esm/openapi/postman/http-status-text.mjs +31 -0
- package/esm/openapi/postman/http-status-text.mjs.map +1 -0
- package/esm/openapi/postman/index.d.mts +3 -0
- package/esm/openapi/postman/openapi-to-postman-collection.d.mts +22 -0
- package/esm/openapi/postman/openapi-to-postman-collection.d.mts.map +1 -0
- package/esm/openapi/postman/openapi-to-postman-collection.mjs +109 -0
- package/esm/openapi/postman/openapi-to-postman-collection.mjs.map +1 -0
- package/esm/openapi/postman/postman-types.d.mts +119 -0
- package/esm/openapi/postman/postman-types.d.mts.map +1 -0
- package/esm/openapi/postman/resolve-operation-auth.mjs +51 -0
- package/esm/openapi/postman/resolve-operation-auth.mjs.map +1 -0
- package/esm/openapi/postman/schema-refs.d.mts +7 -0
- package/esm/openapi/postman/schema-refs.d.mts.map +1 -0
- package/esm/openapi/postman/schema-refs.mjs +41 -0
- package/esm/openapi/postman/schema-refs.mjs.map +1 -0
- package/esm/openapi/postman/uuid-v5.mjs +29 -0
- package/esm/openapi/postman/uuid-v5.mjs.map +1 -0
- package/esm/openapi/response-schemas.mjs +4 -1
- package/esm/openapi/response-schemas.mjs.map +1 -1
- package/esm/openapi/schema-registry.mjs +6 -0
- package/esm/openapi/schema-registry.mjs.map +1 -1
- package/esm/resource/index.d.mts +1 -0
- package/esm/resource/index.mjs +1 -0
- package/esm/resource/nullable-resource.d.mts +44 -0
- package/esm/resource/nullable-resource.d.mts.map +1 -0
- package/esm/resource/nullable-resource.mjs +38 -0
- package/esm/resource/nullable-resource.mjs.map +1 -0
- package/esm/resource/resource.d.mts.map +1 -1
- package/esm/resource/resource.mjs +24 -7
- package/esm/resource/resource.mjs.map +1 -1
- package/esm/resource/types.d.mts +10 -5
- package/esm/resource/types.d.mts.map +1 -1
- package/esm/restful/restful.d.mts +5 -5
- package/esm/restful/restful.d.mts.map +1 -1
- package/esm/router/response-schema-types.mjs +2 -0
- package/esm/router/response-schema-types.mjs.map +1 -1
- package/llms-full.txt +269 -241
- package/llms.txt +42 -42
- package/package.json +12 -12
- package/skills/README.md +39 -39
- package/skills/add-connector/SKILL.md +4 -4
- package/skills/benchmark-code/SKILL.md +3 -3
- package/skills/build-restful/SKILL.md +5 -5
- package/skills/build-url/SKILL.md +7 -7
- package/skills/configure-app/SKILL.md +7 -7
- package/skills/create-controller/SKILL.md +8 -8
- package/skills/create-module/SKILL.md +9 -9
- package/skills/define-resource/SKILL.md +4 -4
- package/skills/encrypt-data/SKILL.md +7 -7
- package/skills/generate-openapi/SKILL.md +33 -5
- package/skills/hash-password/SKILL.md +8 -8
- package/skills/health-checks/SKILL.md +6 -6
- package/skills/lower-stage3-decorators/SKILL.md +4 -4
- package/skills/process-image/SKILL.md +5 -5
- package/skills/register-route/SKILL.md +6 -6
- package/skills/request-memo/SKILL.md +4 -4
- package/skills/request-tracing/SKILL.md +6 -6
- package/skills/resolve-path/SKILL.md +6 -6
- package/skills/retry-operation/SKILL.md +4 -4
- package/skills/run-app/SKILL.md +11 -11
- package/skills/send-mail/SKILL.md +3 -3
- package/skills/send-response/SKILL.md +6 -6
- package/skills/store-file/SKILL.md +4 -4
- package/skills/test-http/SKILL.md +5 -5
- package/skills/test-service/SKILL.md +5 -5
- package/skills/update-packages/SKILL.md +6 -6
- package/skills/upload-file/SKILL.md +7 -7
- package/skills/use-app-context/SKILL.md +7 -7
- package/skills/use-localization/SKILL.md +6 -6
- package/skills/use-middleware/SKILL.md +6 -6
- package/skills/use-model-transformers/SKILL.md +6 -6
- package/skills/use-repository/SKILL.md +7 -7
- package/skills/use-request-locals/SKILL.md +4 -4
- package/skills/validate-input/SKILL.md +7 -7
- package/skills/warlock-conventions/SKILL.md +6 -6
- package/skills/warlock-doctor/SKILL.md +5 -5
- package/skills/warlock-routes/SKILL.md +6 -6
- package/skills/wire-socket/SKILL.md +4 -4
- package/skills/write-cli-command/SKILL.md +6 -6
- package/skills/write-middleware/SKILL.md +8 -8
- package/skills/write-seeder/SKILL.md +5 -5
- 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 —
|
|
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
|
-
-
|
|
247
|
-
-
|
|
248
|
-
-
|
|
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 —
|
|
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
|
-
-
|
|
508
|
-
-
|
|
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 —
|
|
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
|
-
-
|
|
778
|
-
-
|
|
779
|
-
-
|
|
780
|
-
-
|
|
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 —
|
|
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 (
|
|
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
|
-
-
|
|
961
|
-
-
|
|
962
|
-
-
|
|
963
|
-
-
|
|
964
|
-
-
|
|
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 —
|
|
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
|
|
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
|
|
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
|
-
-
|
|
1274
|
-
-
|
|
1275
|
-
-
|
|
1276
|
-
-
|
|
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 —
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
-
|
|
1557
|
-
-
|
|
1558
|
-
-
|
|
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 —
|
|
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
|
-
-
|
|
1746
|
-
-
|
|
1747
|
-
-
|
|
1748
|
-
-
|
|
1749
|
-
-
|
|
1750
|
-
-
|
|
1751
|
-
-
|
|
1752
|
-
-
|
|
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 —
|
|
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
|
-
-
|
|
2155
|
-
-
|
|
2156
|
-
-
|
|
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 —
|
|
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
|
|
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
|
|
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
|
|
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
|
-
-
|
|
2367
|
-
-
|
|
2368
|
-
-
|
|
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 —
|
|
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
|
|
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
|
-
-
|
|
2491
|
-
-
|
|
2492
|
-
-
|
|
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 —
|
|
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 →
|
|
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
|
|
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
|
-
-
|
|
2676
|
-
-
|
|
2677
|
-
-
|
|
2678
|
-
-
|
|
2679
|
-
-
|
|
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 —
|
|
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
|
|
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
|
-
-
|
|
2800
|
-
-
|
|
2801
|
-
-
|
|
2802
|
-
-
|
|
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 —
|
|
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
|
-
-
|
|
2861
|
-
-
|
|
2862
|
-
-
|
|
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 —
|
|
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
|
|
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
|
-
-
|
|
3036
|
-
-
|
|
3037
|
-
-
|
|
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 —
|
|
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
|
|
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
|
|
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
|
-
-
|
|
3212
|
-
-
|
|
3213
|
-
-
|
|
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 —
|
|
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
|
-
-
|
|
3358
|
-
-
|
|
3359
|
-
-
|
|
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`) —
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
-
|
|
3593
|
-
-
|
|
3594
|
-
-
|
|
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 —
|
|
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
|
-
-
|
|
3765
|
-
-
|
|
3766
|
-
-
|
|
3767
|
-
-
|
|
3768
|
-
-
|
|
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 —
|
|
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
|
|
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
|
-
-
|
|
3881
|
-
-
|
|
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 —
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
-
|
|
4396
|
-
-
|
|
4397
|
-
-
|
|
4398
|
-
-
|
|
4399
|
-
-
|
|
4400
|
-
-
|
|
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 —
|
|
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
|
-
-
|
|
4806
|
-
-
|
|
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 —
|
|
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
|
|
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
|
-
|
|
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
|
-
-
|
|
5119
|
-
-
|
|
5120
|
-
-
|
|
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 —
|
|
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
|
-
-
|
|
5523
|
-
-
|
|
5524
|
-
-
|
|
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 —
|
|
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
|
-
-
|
|
5882
|
-
-
|
|
5883
|
-
-
|
|
5884
|
-
-
|
|
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 —
|
|
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
|
|
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
|
-
-
|
|
6283
|
-
-
|
|
6284
|
-
-
|
|
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 —
|
|
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
|
|
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
|
|
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
|
-
-
|
|
6430
|
-
-
|
|
6431
|
-
-
|
|
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 —
|
|
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
|
|
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
|
|
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
|
-
-
|
|
6744
|
-
-
|
|
6745
|
-
-
|
|
6746
|
-
-
|
|
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 —
|
|
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
|
|
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
|
|
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
|
-
-
|
|
7048
|
-
-
|
|
7049
|
-
-
|
|
7050
|
-
-
|
|
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 —
|
|
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
|
|
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
|
-
-
|
|
7374
|
-
-
|
|
7375
|
-
-
|
|
7376
|
-
-
|
|
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 —
|
|
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
|
|
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
|
-
-
|
|
7668
|
-
-
|
|
7669
|
-
-
|
|
7670
|
-
-
|
|
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 —
|
|
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
|
|
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
|
-
-
|
|
7892
|
-
-
|
|
7893
|
-
-
|
|
7894
|
-
-
|
|
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 —
|
|
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
|
-
-
|
|
8324
|
-
-
|
|
8325
|
-
-
|
|
8326
|
-
-
|
|
8327
|
-
-
|
|
8328
|
-
-
|
|
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` —
|
|
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
|
-
-
|
|
8498
|
-
-
|
|
8499
|
-
-
|
|
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 —
|
|
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
|
|
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
|
|
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
|
-
-
|
|
8811
|
-
-
|
|
8812
|
-
-
|
|
8813
|
-
-
|
|
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 —
|
|
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
|
|
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
|
|
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
|
-
-
|
|
8953
|
-
-
|
|
8954
|
-
-
|
|
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 —
|
|
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
|
-
-
|
|
9094
|
-
-
|
|
9095
|
-
-
|
|
9096
|
-
-
|
|
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 —
|
|
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
|
|
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
|
-
-
|
|
9227
|
-
-
|
|
9228
|
-
-
|
|
9229
|
-
-
|
|
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 —
|
|
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
|
-
-
|
|
9520
|
-
-
|
|
9521
|
-
-
|
|
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 —
|
|
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
|
|
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
|
|
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
|
-
-
|
|
9840
|
-
-
|
|
9841
|
-
-
|
|
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 —
|
|
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
|
|
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
|
|
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
|
-
-
|
|
10066
|
-
-
|
|
10067
|
-
-
|
|
10068
|
-
-
|
|
10069
|
-
-
|
|
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 —
|
|
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
|
-
-
|
|
10448
|
-
-
|
|
10449
|
-
-
|
|
10450
|
-
-
|
|
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 —
|
|
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
|
-
-
|
|
10748
|
-
-
|
|
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
|
|