@warlock.js/core 4.5.0 → 4.6.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 +27 -0
- package/esm/ai/src/agent/agent.mjs +126 -7
- package/esm/ai/src/agent/agent.mjs.map +1 -1
- package/esm/ai/src/agent/signature.mjs +57 -0
- package/esm/ai/src/agent/signature.mjs.map +1 -0
- package/esm/ai/src/agent/snapshot.mjs +101 -0
- package/esm/ai/src/agent/snapshot.mjs.map +1 -0
- package/esm/ai/src/ai.mjs +37 -1
- package/esm/ai/src/ai.mjs.map +1 -1
- package/esm/ai/src/errors/agent-drift-error.mjs +31 -0
- package/esm/ai/src/errors/agent-drift-error.mjs.map +1 -0
- package/esm/ai/src/errors/index.mjs +2 -0
- package/esm/ai/src/errors/planner-drift-error.mjs +33 -0
- package/esm/ai/src/errors/planner-drift-error.mjs.map +1 -0
- package/esm/ai/src/image/image-cost.mjs +55 -0
- package/esm/ai/src/image/image-cost.mjs.map +1 -0
- package/esm/ai/src/image/image.mjs +112 -0
- package/esm/ai/src/image/image.mjs.map +1 -0
- package/esm/ai/src/image/index.mjs +4 -0
- package/esm/ai/src/index.mjs +20 -0
- package/esm/ai/src/planner/planner-run.mjs +161 -6
- package/esm/ai/src/planner/planner-run.mjs.map +1 -1
- package/esm/ai/src/planner/planner.mjs +25 -1
- package/esm/ai/src/planner/planner.mjs.map +1 -1
- package/esm/ai/src/planner/snapshot.mjs +95 -0
- package/esm/ai/src/planner/snapshot.mjs.map +1 -0
- package/esm/ai/src/rag/hybrid/bm25.mjs +51 -0
- package/esm/ai/src/rag/hybrid/bm25.mjs.map +1 -0
- package/esm/ai/src/rag/hybrid/hybrid-rank.mjs +29 -0
- package/esm/ai/src/rag/hybrid/hybrid-rank.mjs.map +1 -0
- package/esm/ai/src/rag/hybrid/rrf.mjs +30 -0
- package/esm/ai/src/rag/hybrid/rrf.mjs.map +1 -0
- package/esm/ai/src/rag/index.mjs +11 -0
- package/esm/ai/src/rag/loaders/errors.mjs +25 -0
- package/esm/ai/src/rag/loaders/errors.mjs.map +1 -0
- package/esm/ai/src/rag/loaders/index.mjs +7 -0
- package/esm/ai/src/rag/loaders/load-html.mjs +138 -0
- package/esm/ai/src/rag/loaders/load-html.mjs.map +1 -0
- package/esm/ai/src/rag/loaders/load-pdf.mjs +150 -0
- package/esm/ai/src/rag/loaders/load-pdf.mjs.map +1 -0
- package/esm/ai/src/rag/loaders/load-text.mjs +60 -0
- package/esm/ai/src/rag/loaders/load-text.mjs.map +1 -0
- package/esm/ai/src/rag/loaders/load-web.mjs +89 -0
- package/esm/ai/src/rag/loaders/load-web.mjs.map +1 -0
- package/esm/ai/src/rag/store/pg-vector-store.mjs +328 -0
- package/esm/ai/src/rag/store/pg-vector-store.mjs.map +1 -0
- package/esm/ai/src/rag/transforms/multi-query.mjs +41 -0
- package/esm/ai/src/rag/transforms/multi-query.mjs.map +1 -0
- package/esm/ai/src/speech/index.mjs +3 -0
- package/esm/ai/src/speech/speech.mjs +122 -0
- package/esm/ai/src/speech/speech.mjs.map +1 -0
- package/esm/ai/src/supervisor/entries.mjs +2 -2
- package/esm/ai/src/supervisor/entries.mjs.map +1 -1
- package/esm/ai/src/transcribe/audio-input.mjs +84 -0
- package/esm/ai/src/transcribe/audio-input.mjs.map +1 -0
- package/esm/ai/src/transcribe/index.mjs +4 -0
- package/esm/ai/src/transcribe/transcribe.mjs +127 -0
- package/esm/ai/src/transcribe/transcribe.mjs.map +1 -0
- package/esm/ai-openai/src/image.mjs +5 -0
- package/esm/ai-openai/src/index.mjs +3 -0
- package/esm/ai-openai/src/sdk.mjs +3 -0
- package/esm/ai-openai/src/speech.mjs +5 -0
- package/esm/ai-openai/src/transcription.mjs +6 -0
- package/esm/ai-openai/src/utils/index.mjs +1 -0
- package/esm/ai-openai/src/utils/to-openai-messages.mjs +3 -0
- package/esm/cli/commands/doctor/checks/config.check.mjs +42 -0
- package/esm/cli/commands/doctor/checks/config.check.mjs.map +1 -0
- package/esm/cli/commands/doctor/checks/connectors.check.mjs +28 -0
- package/esm/cli/commands/doctor/checks/connectors.check.mjs.map +1 -0
- package/esm/cli/commands/doctor/checks/health.check.mjs +35 -0
- package/esm/cli/commands/doctor/checks/health.check.mjs.map +1 -0
- package/esm/cli/commands/doctor/checks/index.mjs +25 -0
- package/esm/cli/commands/doctor/checks/index.mjs.map +1 -0
- package/esm/cli/commands/doctor/checks/optional-peers.check.mjs +90 -0
- package/esm/cli/commands/doctor/checks/optional-peers.check.mjs.map +1 -0
- package/esm/cli/commands/doctor/checks/release-hygiene.check.mjs +69 -0
- package/esm/cli/commands/doctor/checks/release-hygiene.check.mjs.map +1 -0
- package/esm/cli/commands/doctor/checks/routes.check.mjs +30 -0
- package/esm/cli/commands/doctor/checks/routes.check.mjs.map +1 -0
- package/esm/cli/commands/doctor/doctor-command.action.mjs +28 -0
- package/esm/cli/commands/doctor/doctor-command.action.mjs.map +1 -0
- package/esm/cli/commands/doctor/format-report.mjs +44 -0
- package/esm/cli/commands/doctor/format-report.mjs.map +1 -0
- package/esm/cli/commands/doctor/run-checks.mjs +50 -0
- package/esm/cli/commands/doctor/run-checks.mjs.map +1 -0
- package/esm/cli/commands/doctor.command.mjs +29 -0
- package/esm/cli/commands/doctor.command.mjs.map +1 -0
- package/esm/cli/commands/generate/templates/stubs.mjs +6 -8
- package/esm/cli/commands/generate/templates/stubs.mjs.map +1 -1
- package/esm/cli/commands/routes/format-routes-table.mjs +129 -0
- package/esm/cli/commands/routes/format-routes-table.mjs.map +1 -0
- package/esm/cli/commands/routes/route-row.mjs +92 -0
- package/esm/cli/commands/routes/route-row.mjs.map +1 -0
- package/esm/cli/commands/routes/routes-command.action.mjs +43 -0
- package/esm/cli/commands/routes/routes-command.action.mjs.map +1 -0
- package/esm/cli/commands/routes.command.mjs +51 -0
- package/esm/cli/commands/routes.command.mjs.map +1 -0
- package/esm/cli/commands/seed.command.mjs +5 -0
- package/esm/cli/commands/seed.command.mjs.map +1 -1
- package/esm/cli/framework-cli-commands.mjs +4 -0
- package/esm/cli/framework-cli-commands.mjs.map +1 -1
- package/esm/config/config-getter.mjs +5 -5
- package/esm/config/config-getter.mjs.map +1 -1
- package/esm/config/config-loader.mjs +2 -2
- package/esm/config/config-loader.mjs.map +1 -1
- package/esm/connectors/access-connector.mjs +2 -2
- package/esm/connectors/access-connector.mjs.map +1 -1
- package/esm/connectors/ai-connector.mjs +2 -2
- package/esm/connectors/ai-connector.mjs.map +1 -1
- package/esm/connectors/cache-connector.mjs +2 -2
- package/esm/connectors/cache-connector.mjs.map +1 -1
- package/esm/connectors/database-connector.mjs +2 -2
- package/esm/connectors/database-connector.mjs.map +1 -1
- package/esm/connectors/herald-connector.mjs +2 -2
- package/esm/connectors/herald-connector.mjs.map +1 -1
- package/esm/connectors/http-connector.d.mts.map +1 -1
- package/esm/connectors/http-connector.mjs +9 -7
- package/esm/connectors/http-connector.mjs.map +1 -1
- package/esm/connectors/logger-connector.mjs +2 -2
- package/esm/connectors/logger-connector.mjs.map +1 -1
- package/esm/connectors/mail-connector.mjs +2 -2
- package/esm/connectors/mail-connector.mjs.map +1 -1
- package/esm/connectors/notifications-connector.mjs +2 -2
- package/esm/connectors/notifications-connector.mjs.map +1 -1
- package/esm/connectors/socket-connector.mjs +3 -3
- package/esm/connectors/socket-connector.mjs.map +1 -1
- package/esm/database/index.d.mts +2 -1
- package/esm/database/index.mjs +1 -0
- package/esm/database/seed-command-action.mjs +44 -4
- package/esm/database/seed-command-action.mjs.map +1 -1
- package/esm/database/seeds/seed-records-table-migration.mjs +36 -0
- package/esm/database/seeds/seed-records-table-migration.mjs.map +1 -0
- package/esm/database/seeds/seeder.d.mts +22 -5
- package/esm/database/seeds/seeder.d.mts.map +1 -1
- package/esm/database/seeds/seeder.errors.d.mts +22 -0
- package/esm/database/seeds/seeder.errors.d.mts.map +1 -0
- package/esm/database/seeds/seeder.errors.mjs +29 -0
- package/esm/database/seeds/seeder.errors.mjs.map +1 -0
- package/esm/database/seeds/seeder.mjs.map +1 -1
- package/esm/database/seeds/seeders.manager.mjs +90 -11
- package/esm/database/seeds/seeders.manager.mjs.map +1 -1
- package/esm/database/seeds/types.d.mts +117 -1
- package/esm/database/seeds/types.d.mts.map +1 -1
- package/esm/database/seeds/utils.mjs +6 -1
- package/esm/database/seeds/utils.mjs.map +1 -1
- package/esm/dev-server/module-loader.d.mts +12 -0
- package/esm/dev-server/module-loader.d.mts.map +1 -1
- package/esm/dev-server/module-loader.mjs +30 -2
- package/esm/dev-server/module-loader.mjs.map +1 -1
- package/esm/http/config.mjs +2 -2
- package/esm/http/config.mjs.map +1 -1
- package/esm/http/createHttpApplication.mjs +2 -2
- package/esm/http/createHttpApplication.mjs.map +1 -1
- package/esm/http/health.d.mts +14 -0
- package/esm/http/health.d.mts.map +1 -1
- package/esm/http/health.mjs +16 -0
- package/esm/http/health.mjs.map +1 -1
- package/esm/http/middleware/idempotency.middleware.mjs +5 -5
- package/esm/http/middleware/idempotency.middleware.mjs.map +1 -1
- package/esm/http/middleware/inject-request-context.mjs +2 -2
- package/esm/http/middleware/inject-request-context.mjs.map +1 -1
- package/esm/http/middleware/maintenance.middleware.mjs +4 -4
- package/esm/http/middleware/maintenance.middleware.mjs.map +1 -1
- package/esm/http/plugins.mjs +9 -9
- package/esm/http/plugins.mjs.map +1 -1
- package/esm/http/response.mjs +5 -5
- package/esm/http/response.mjs.map +1 -1
- package/esm/http/server.mjs +4 -4
- package/esm/http/server.mjs.map +1 -1
- package/esm/index.d.mts +4 -3
- package/esm/index.mjs +2 -1
- package/esm/repositories/adapters/cascade/cascade-query-builder.d.mts +28 -1
- package/esm/repositories/adapters/cascade/cascade-query-builder.d.mts.map +1 -1
- package/esm/repositories/adapters/cascade/cascade-query-builder.mjs +39 -0
- package/esm/repositories/adapters/cascade/cascade-query-builder.mjs.map +1 -1
- package/esm/repositories/contracts/index.d.mts +1 -1
- package/esm/repositories/contracts/query-builder.contract.d.mts +87 -1
- package/esm/repositories/contracts/query-builder.contract.d.mts.map +1 -1
- package/esm/repositories/index.d.mts +1 -1
- package/esm/repositories/repository.manager.d.mts +99 -1
- package/esm/repositories/repository.manager.d.mts.map +1 -1
- package/esm/repositories/repository.manager.mjs +128 -0
- package/esm/repositories/repository.manager.mjs.map +1 -1
- package/esm/router/router.d.mts +9 -0
- package/esm/router/router.d.mts.map +1 -1
- package/esm/router/router.mjs +21 -1
- package/esm/router/router.mjs.map +1 -1
- package/esm/utils/paths.mjs +2 -2
- package/esm/utils/paths.mjs.map +1 -1
- package/esm/validation/validateAll.mjs +2 -2
- package/esm/validation/validateAll.mjs.map +1 -1
- package/llms-full.txt +427 -45
- package/llms.txt +4 -2
- package/package.json +9 -9
- package/skills/README.md +65 -0
- package/skills/health-checks/SKILL.md +13 -0
- package/skills/use-repository/SKILL.md +38 -1
- package/skills/warlock-doctor/SKILL.md +135 -0
- package/skills/warlock-routes/SKILL.md +91 -0
- package/skills/write-seeder/SKILL.md +143 -45
package/llms.txt
CHANGED
|
@@ -34,11 +34,13 @@
|
|
|
34
34
|
- [use-localization](@warlock.js/core/use-localization/SKILL.md): Multi-locale translations via `groupedTranslations` (declare keys), `t()` / `request.t()` / `request.trans()` (look up), `request.getLocaleCode()` (detect locale from headers/query), `getLocalized` (pick the right value from a localized-array column). Triggers: `groupedTranslations`, `t`, `request.t`, `request.trans`, `request.transFrom`, `request.getLocaleCode`, `request.setLocaleCode`, `getLocalized`; "add a translation key", "resolve a localized error message", "detect request locale", "pick the right per-locale column value"; typical import `import { t, getLocalized } from "@warlock.js/core"`. Skip: resource output — `@warlock.js/core/define-resource/SKILL.md`; module scaffold — `@warlock.js/core/create-module/SKILL.md`; competing libs `i18next`, `react-intl`, raw `@mongez/localization`.
|
|
35
35
|
- [use-middleware](@warlock.js/core/use-middleware/SKILL.md): Attach built-in HTTP middleware to routes via the `middleware` namespace from `@warlock.js/core` — rateLimit, concurrencyLimit, maxBodySize, idempotency, maintenance, ipFilter, cache. Plus `X-Request-Id` correlation, wired automatically. Triggers: `middleware.rateLimit`, `middleware.concurrencyLimit`, `middleware.maxBodySize`, `middleware.idempotency`, `middleware.maintenance`, `middleware.ipFilter`, `middleware.cache`, `X-Request-Id`, `Idempotency-Key`; "add rate limiting", "dedupe writes by idempotency key", "cap concurrent requests", "block IPs", "cache a GET response"; typical import `import { middleware } from "@warlock.js/core"`. Skip: author custom middleware — `@warlock.js/core/write-middleware/SKILL.md`; cache singleton — `@warlock.js/cache/cache-basics/SKILL.md`; competing libs `@fastify/rate-limit` direct, `express-rate-limit`, `helmet`.
|
|
36
36
|
- [use-model-transformers](@warlock.js/core/use-model-transformers/SKILL.md): Three schema-side helpers — `useHashedPassword()` (bcrypt on save) attaches via `.addTransformer(...)`; `useComputedSlug(field?, scope?)` (auto-slug from another field) and `useComputedModel(callback)` (arbitrary computed-on-save value) attach via `v.computed(...)`. Triggers: `useHashedPassword`, `useComputedSlug`, `useComputedModel`, `.addTransformer`, `v.computed`, `ComputedCallback`; "auto-hash a password field", "auto-slug from title on save", "derive a value at write time", "declarative model transformers"; typical import `import { useHashedPassword, useComputedSlug } from "@warlock.js/core"`. Skip: bcrypt setup details — `@warlock.js/core/hash-password/SKILL.md`; repository writes — `@warlock.js/core/use-repository/SKILL.md`; output filtering — `@warlock.js/core/define-resource/SKILL.md`; competing patterns: manual `await hashPassword(input)` in services, ORM lifecycle hooks.
|
|
37
|
-
- [use-repository](@warlock.js/core/use-repository/SKILL.md): Subclass `RepositoryManager` for data access — declare `source`, `filterBy`, `defaultOptions`, then call `list()`/`listCached()`/`find()`/`create()`/`update()`/`delete()
|
|
37
|
+
- [use-repository](@warlock.js/core/use-repository/SKILL.md): Subclass `RepositoryManager` for data access — declare `source`, `filterBy`, `defaultOptions`, then call `list()`/`listCached()`/`find()`/`create()`/`update()`/`delete()`, the active/cached/cursor variants, and the `filterBy`-aware aggregates `sum()`/`avg()`/`min()`/`max()`/`groupBy()`/`aggregate()`. Triggers: `RepositoryManager`, `FilterRules`, `RepositoryOptions`, `.list`, `.listCached`, `.find`, `.findCached`, `.create`, `.update`, `.delete`, `.sum`, `.avg`, `.min`, `.max`, `.groupBy`, `.aggregate`, `simpleSelectColumns`; "create a repository", "filter rules for a list endpoint", "cursor vs page pagination", "cached vs uncached read", "sum/avg/group-by with filters"; typical import `import { RepositoryManager } from "@warlock.js/core"`. Skip: cache singleton — `@warlock.js/cache/cache-basics/SKILL.md`; use-case pipelines — `@warlock.js/core/write-use-case/SKILL.md`; wire mapping — `@warlock.js/core/define-resource/SKILL.md`; competing libs `typeorm` Repository, `prisma.client.<model>`, `@nestjs/typeorm`.
|
|
38
38
|
- [validate-input](@warlock.js/core/validate-input/SKILL.md): Author seal schemas, attach them to controllers via `controller.validation = { schema }`, infer types via `Infer<typeof schema>`, and layer DB-aware (`unique`/`exists`) and file validators on top. Triggers: `v.object`, `v.string`, `v.email`, `Infer`, `controller.validation`, `.unique`, `.exists`, `uniqueExceptCurrentId`, `request.validated`; "validate a request body", "attach a schema to a controller", "DB-aware unique rule", "infer schema types"; typical import `import { v, type Infer } from "@warlock.js/seal"`. Skip: schema authoring foundations — `@warlock.js/seal/seal-basics/SKILL.md`; controller wiring — `@warlock.js/core/create-controller/SKILL.md`; file rules deep-dive — `@warlock.js/core/upload-file/SKILL.md`; competing libs `zod`, `joi`, `yup`, `class-validator`.
|
|
39
39
|
- [warlock-conventions](@warlock.js/core/warlock-conventions/SKILL.md): Framework-wide invariants for projects built on @warlock.js/core — module layout, canonical imports, layered flow, file naming, and the non-negotiable rules every other warlock skill assumes. Triggers: `src/app/<module>`, `routes.ts`, `main.ts`, `Request<TSchema>`, `RequestHandler`, `GuardedRequestHandler`, `app/<module>/...`; "where do files go in this project", "canonical Warlock imports", "module layout rules", "controller-service-repository layering"; typical import `import { router, type RequestHandler } from "@warlock.js/core"`. Skip: scaffold a new module — `@warlock.js/core/create-module/SKILL.md`; route shape — `@warlock.js/core/register-route/SKILL.md`; controller shape — `@warlock.js/core/create-controller/SKILL.md`; competing patterns: `express` ad-hoc layouts, `@nestjs/common` decorator-driven structure.
|
|
40
|
+
- [warlock-doctor](@warlock.js/core/warlock-doctor/SKILL.md): Run `warlock doctor` — a read-only diagnostics command that checks routes / config / connectors / optional-peers / health endpoints / release hygiene and prints a pass/warn/fail report, exiting non-zero on any failure. Add your own probe with the `DoctorCheck` contract and `runChecks` / `formatReportLines`. Triggers: `warlock doctor`, `doctorCommand`, `DoctorCheck`, `CheckResult`, `CheckStatus`, `DoctorReport`, `runChecks`, `formatReportLines`, `printReport`, `defaultDoctorChecks`; "diagnose my app", "preflight / preflight check", "is the app healthy", "why are there 0 routes", "pre-release sanity check", "CI smoke check"; run as `yarn warlock doctor`. Skip: the live `/health` + `/ready` HTTP probes — `@warlock.js/core/health-checks/SKILL.md`; authoring a general CLI command — `@warlock.js/core/write-cli-command/SKILL.md`; releasing the package — `releasing-warlock-monorepo`; competing tools `npm doctor`, `nest info`, hand-rolled preflight scripts.
|
|
41
|
+
- [warlock-routes](@warlock.js/core/warlock-routes/SKILL.md): Run `warlock routes` — a read-only command that lists the registered HTTP routes as a verb-colored table (method / path / name / action / middleware-count / source), a sibling of `warlock doctor`. Filter with `--method` / `--path` / `--name`, or emit normalized rows as JSON with `--json`. Triggers: `warlock routes`, `routesCommand`, "list my routes", "show all routes", "route table", "what endpoints does my app expose", "dump routes as JSON", "which routes have middleware", "route map for CI"; run as `yarn warlock routes`. Skip: read-only health/preflight checks — `@warlock.js/core/warlock-doctor/SKILL.md`; defining/naming/grouping routes — `@warlock.js/core/register-route/SKILL.md`; authoring a general CLI command — `@warlock.js/core/write-cli-command/SKILL.md`; competing tools `nest`/`express` route listers, `php artisan route:list`.
|
|
40
42
|
- [wire-socket](@warlock.js/core/wire-socket/SKILL.md): Configure Socket.IO via `src/config/socket.ts`, reach the live server through `getSocketServer()` (or `app.socket` post-bootstrap), register `connection` handlers once the late-phase socket connector has booted, emit from controllers/services, use rooms and namespaces. Triggers: `app.socket`, `getSocketServer`, `SocketOptions`, `socket.io` `Server`, `socket.join`, `socket.to`, `io.of`, `io.use`; "add realtime chat", "emit socket events from a service", "use rooms and namespaces", "per-socket JWT auth". Skip: connector lifecycle — `@warlock.js/core/add-connector/SKILL.md`; app context accessors — `@warlock.js/core/use-app-context/SKILL.md`; competing libs `ws`, `socket.io` direct without Warlock connector, `uWebSockets.js`.
|
|
41
43
|
- [write-cli-command](@warlock.js/core/write-cli-command/SKILL.md): 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/`. Triggers: `command`, `CLICommand`, `CLICommandPreload`, `CLICommandOption`, `preload`, `preAction`, `persistent`, `colors`; "write a custom warlock command", "one-off maintenance task", "ship a CLI from a package", "framework built-in commands"; typical import `import { command } from "@warlock.js/core"`. Skip: framework dev/build/start — `@warlock.js/core/run-app/SKILL.md`; warlock.config.ts wiring — `@warlock.js/core/configure-app/SKILL.md`; competing libs `commander`, `yargs`, `oclif`.
|
|
42
44
|
- [write-middleware](@warlock.js/core/write-middleware/SKILL.md): Author HTTP middleware for @warlock.js/core — the `(request, response)` signature, short-circuit by returning a response, enrich the request with extra fields, register per-route, per-group, or app-wide. Triggers: `Middleware`, `MiddlewareResponse`, `router.group`, `guarded`, `request.detectIp`, `authMiddleware`; "write a custom middleware", "short-circuit a request", "enrich the request with extra fields", "per-route vs per-group middleware"; typical import `import type { Middleware } from "@warlock.js/core"`. Skip: built-in middleware catalog — `@warlock.js/core/use-middleware/SKILL.md`; route attachment — `@warlock.js/core/register-route/SKILL.md`; response helpers — `@warlock.js/core/send-response/SKILL.md`; competing patterns: `express` `(req, res, next)` middleware, Fastify `preHandler` hooks.
|
|
43
|
-
- [write-seeder](@warlock.js/core/write-seeder/SKILL.md): Author a seed file under `src/app/<module>/seeds/<name>.ts` using the `seeder()` factory — `name`, `dependsOn`, `once`, `order`, `batchSize`, `run()`. Auto-discovered by `warlock seed`; tracked in a `seeds` table. Triggers: `seeder`, `Seeder`, `SeedResult`, `SeedersManager`, `warlock seed`, `--fresh`, `--list`, `--path`; "seed default roles", "one-time data migration", "auto-discovered seeds", "order seeds by dependency"; typical import `import { seeder } from "@warlock.js/core"`. Skip: module folder layout — `@warlock.js/core/create-module/SKILL.md`; repository CRUD — `@warlock.js/core/use-repository/SKILL.md`; CLI flags — `@warlock.js/core/write-cli-command/SKILL.md`; competing patterns: hand-rolled `node scripts/seed.js`, `typeorm-seeding`.
|
|
45
|
+
- [write-seeder](@warlock.js/core/write-seeder/SKILL.md): Author a seed file under `src/app/<module>/seeds/<name>.ts` using the `seeder()` factory — `name`, `dependsOn`, `once`, `order`, `batchSize`, `run({ track, now, batchSize })`. Auto-discovered by `warlock seed`; tracked in a `seeds` table; per-record refs in `seed_records` so `warlock seed --drop` can undo a seed. Triggers: `seeder`, `Seeder`, `SeedResult`, `SeedContext`, `SeedClock`, `track`, `now`, `batchSize`, `SeedersManager`, `warlock seed`, `--fresh`, `--drop`, `--list`, `--path`; "seed default roles", "undo a seed", "one-time data migration", "auto-discovered seeds", "order seeds by dependency", "deterministic seed timestamps", "inject a seed clock"; typical import `import { seeder } from "@warlock.js/core"`. Skip: module folder layout — `@warlock.js/core/create-module/SKILL.md`; repository CRUD — `@warlock.js/core/use-repository/SKILL.md`; CLI flags — `@warlock.js/core/write-cli-command/SKILL.md`; competing patterns: hand-rolled `node scripts/seed.js`, `typeorm-seeding`.
|
|
44
46
|
- [write-use-case](@warlock.js/core/write-use-case/SKILL.md): Author `useCase()` pipelines for business logic — guards, schema, before/after middleware, retry, benchmark, broadcast, lifecycle callbacks; transport-agnostic and observable by default. Input is inferred from the `schema`. Triggers: `useCase`, `UseCaseContext`, `UseCaseResult`, `retry`, `benchmark`, `broadcast`, `description`, `globalUseCasesEvents`, `UseCaseBroadcastChannel`; "encapsulate a business operation", "share logic between HTTP and CLI", "add guards and lifecycle hooks", "broadcast a use case result", "transport-agnostic pipeline"; typical import `import { useCase } from "@warlock.js/core"`. Skip: thin handler shape — `@warlock.js/core/create-controller/SKILL.md`; schema details — `@warlock.js/core/validate-input/SKILL.md`; the standalone retry util — `@warlock.js/core/retry-operation/SKILL.md`; competing libs `@nestjs/cqrs`, `inversify`, hand-rolled service classes.
|
package/package.json
CHANGED
|
@@ -36,13 +36,13 @@
|
|
|
36
36
|
"@mongez/slug": "^1.0.7",
|
|
37
37
|
"@mongez/supportive-is": "^2.1.3",
|
|
38
38
|
"@mongez/time-wizard": "^1.0.6",
|
|
39
|
-
"@warlock.js/auth": "4.
|
|
40
|
-
"@warlock.js/cache": "4.
|
|
41
|
-
"@warlock.js/cascade": "4.
|
|
42
|
-
"@warlock.js/context": "4.
|
|
43
|
-
"@warlock.js/logger": "4.
|
|
44
|
-
"@warlock.js/seal": "4.
|
|
45
|
-
"@warlock.js/fs": "4.
|
|
39
|
+
"@warlock.js/auth": "4.6.0",
|
|
40
|
+
"@warlock.js/cache": "4.6.0",
|
|
41
|
+
"@warlock.js/cascade": "4.6.0",
|
|
42
|
+
"@warlock.js/context": "4.6.0",
|
|
43
|
+
"@warlock.js/logger": "4.6.0",
|
|
44
|
+
"@warlock.js/seal": "4.6.0",
|
|
45
|
+
"@warlock.js/fs": "4.6.0",
|
|
46
46
|
"chokidar": "^5.0.0",
|
|
47
47
|
"dayjs": "^1.11.19",
|
|
48
48
|
"es-module-lexer": "^2.0.0",
|
|
@@ -68,12 +68,12 @@
|
|
|
68
68
|
"react": "^19.2.3",
|
|
69
69
|
"react-dom": "^19.2.3",
|
|
70
70
|
"@react-email/render": "^2.0.5",
|
|
71
|
-
"@warlock.js/herald": "4.
|
|
71
|
+
"@warlock.js/herald": "4.6.0"
|
|
72
72
|
},
|
|
73
73
|
"bin": {
|
|
74
74
|
"warlock": "bin/warlock.js"
|
|
75
75
|
},
|
|
76
|
-
"version": "4.
|
|
76
|
+
"version": "4.6.0",
|
|
77
77
|
"type": "module",
|
|
78
78
|
"main": "./esm/index.mjs",
|
|
79
79
|
"module": "./esm/index.mjs",
|
package/skills/README.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# @warlock.js/core — skills index
|
|
2
|
+
|
|
3
|
+
Each folder holds one `SKILL.md` (an agent-facing how-to for a single task). The `llms.txt` / `llms-full.txt` at the package root are **generated projections** of this folder — run `node scripts/generate-llms.mjs` from the package root after any skill change; never hand-edit them.
|
|
4
|
+
|
|
5
|
+
## HTTP layer
|
|
6
|
+
|
|
7
|
+
- [register-route](register-route/SKILL.md) — register single routes, prefix groups, middleware-guarded blocks, and RESTful resource chains.
|
|
8
|
+
- [build-restful](build-restful/SKILL.md) — generate standard CRUD endpoints via the `router.route(...)` chain or the `Restful` base class.
|
|
9
|
+
- [create-controller](create-controller/SKILL.md) — author HTTP controllers: `RequestHandler` signature, validated input, response helpers, middleware.
|
|
10
|
+
- [send-response](send-response/SKILL.md) — `Response` helpers: success/error variants, status helpers, redirects, files, streams, SSE.
|
|
11
|
+
- [validate-input](validate-input/SKILL.md) — author seal schemas, attach them to controllers, infer types, layer DTOs.
|
|
12
|
+
- [use-middleware](use-middleware/SKILL.md) — attach built-in HTTP middleware (rateLimit, concurrencyLimit, maxBodySize, …) via the `middleware` namespace.
|
|
13
|
+
- [write-middleware](write-middleware/SKILL.md) — author HTTP middleware: the `(request, response)` signature, short-circuit, request enrichment.
|
|
14
|
+
- [build-url](build-url/SKILL.md) — HTTP URL helpers (`url`, `publicUrl`, `assetsUrl`, `uploadsUrl`) anchored at `app.baseUrl`.
|
|
15
|
+
- [upload-file](upload-file/SKILL.md) — handle multipart uploads: `request.file()`, `v.file()` validation, `UploadedFile.save()`.
|
|
16
|
+
- [health-checks](health-checks/SKILL.md) — built-in `/health` + `/ready` endpoints, the `health` registry, and graceful request draining.
|
|
17
|
+
|
|
18
|
+
## Data layer
|
|
19
|
+
|
|
20
|
+
- [use-repository](use-repository/SKILL.md) — subclass `RepositoryManager`: `source`/`filterBy`/`defaultOptions`, list/find/CRUD, cached/cursor variants, and the `filterBy`-aware aggregates (`sum`/`avg`/`min`/`max`/`groupBy`/`aggregate`).
|
|
21
|
+
- [use-model-transformers](use-model-transformers/SKILL.md) — schema-side helpers: `useHashedPassword()`, `useComputedSlug()`, and friends.
|
|
22
|
+
- [define-resource](define-resource/SKILL.md) — map model fields to wire-shape via `defineResource()` / `Resource` subclasses (output-only).
|
|
23
|
+
- [write-seeder](write-seeder/SKILL.md) — author a seed file with `seeder()` — `name`/`dependsOn`/`once`/`order`/`batchSize`, `run({ track, now, batchSize })`, `warlock seed --drop`.
|
|
24
|
+
|
|
25
|
+
## Files, media, mail
|
|
26
|
+
|
|
27
|
+
- [store-file](store-file/SKILL.md) — read/write/delete files via the `storage` singleton (local/S3/R2/DO Spaces), `StorageFile` handles, presigned URLs.
|
|
28
|
+
- [process-image](process-image/SKILL.md) — transform images with the `Image` class (resize, crop, rotate, format, watermark, …) on a deferred pipeline.
|
|
29
|
+
- [send-mail](send-mail/SKILL.md) — send transactional email: the `Mail` fluent builder, `sendMail()`, React Email, test-mode capture.
|
|
30
|
+
|
|
31
|
+
## App, config, lifecycle
|
|
32
|
+
|
|
33
|
+
- [configure-app](configure-app/SKILL.md) — the two config layers (`warlock.config.ts` vs `src/config/*.ts`), `.env` + `env()`.
|
|
34
|
+
- [use-app-context](use-app-context/SKILL.md) — read app-wide context via the `Application` static class and the `app` runtime accessor.
|
|
35
|
+
- [add-connector](add-connector/SKILL.md) — extend the lifecycle with a `BaseConnector` subclass (`start`/`shutdown`/`watchedFiles`).
|
|
36
|
+
- [wire-socket](wire-socket/SKILL.md) — configure Socket.IO, reach the live server via `getSocketServer()` / `app.socket`.
|
|
37
|
+
- [use-localization](use-localization/SKILL.md) — multi-locale translations: `groupedTranslations`, `t()` / `request.t()`, locale resolution.
|
|
38
|
+
|
|
39
|
+
## Use-cases & services
|
|
40
|
+
|
|
41
|
+
- [write-use-case](write-use-case/SKILL.md) — author `useCase()` pipelines: guards, schema, before/after, retry, benchmark, broadcast, lifecycle.
|
|
42
|
+
- [create-module](create-module/SKILL.md) — scaffold a feature module under `src/app/<name>/` via `warlock generate.module` + follow-up generators.
|
|
43
|
+
|
|
44
|
+
## CLI & operations
|
|
45
|
+
|
|
46
|
+
- [warlock-doctor](warlock-doctor/SKILL.md) — `warlock doctor`: read-only diagnostics (routes/config/connectors/optional-peers/health/release-hygiene) with a pass/warn/fail report and non-zero exit on failure.
|
|
47
|
+
- [warlock-routes](warlock-routes/SKILL.md) — `warlock routes`: list the registered HTTP routes as a verb-colored table (method/path/name/action/middleware/source); filter by method/path/name or emit JSON. Read-only, no connectors.
|
|
48
|
+
- [write-cli-command](write-cli-command/SKILL.md) — author a custom `warlock <cmd>` via the `command()` factory (name, action, options, preload).
|
|
49
|
+
- [run-app](run-app/SKILL.md) — `warlock dev` / `warlock build` / `warlock start` operational commands.
|
|
50
|
+
- [update-packages](update-packages/SKILL.md) — bump every `@warlock.js/*` dependency with `warlock update`.
|
|
51
|
+
|
|
52
|
+
## Testing
|
|
53
|
+
|
|
54
|
+
- [test-http](test-http/SKILL.md) — integration tests against a real HTTP server (`startHttpTestServer()`, `testGet` / `testPost`).
|
|
55
|
+
- [test-service](test-service/SKILL.md) — pure unit tests against services/repositories/models/use-cases via `setupTest({ connectors })`.
|
|
56
|
+
|
|
57
|
+
## Utilities
|
|
58
|
+
|
|
59
|
+
- [encrypt-data](encrypt-data/SKILL.md) — reversible AES-256-GCM `encrypt`/`decrypt`, plus one-way `hmacHash` fingerprints.
|
|
60
|
+
- [hash-password](hash-password/SKILL.md) — one-way bcrypt `hashPassword`/`verifyPassword` and the `useHashedPassword()` transformer.
|
|
61
|
+
- [resolve-path](resolve-path/SKILL.md) — path helpers anchored at `process.cwd()` (`rootPath`, `srcPath`, `appPath`, …).
|
|
62
|
+
- [benchmark-code](benchmark-code/SKILL.md) — time a function with `measure(name, fn, options?)` and classify the latency.
|
|
63
|
+
- [retry-operation](retry-operation/SKILL.md) — wrap a flaky operation with `retry(fn, options)` (now from `@mongez/reinforcements`).
|
|
64
|
+
- [lower-stage3-decorators](lower-stage3-decorators/SKILL.md) — the `lowerStage3Decorators()` Vite/Vitest plugin for native decorators.
|
|
65
|
+
- [warlock-conventions](warlock-conventions/SKILL.md) — framework-wide invariants: module layout, canonical imports, layered flow, file naming.
|
|
@@ -52,6 +52,19 @@ health.removeCheck("db"); // unregister later if needed
|
|
|
52
52
|
|
|
53
53
|
A check returns `boolean | Promise<boolean>`. **A thrown error counts as a failed check** (it's surfaced in the `checks` map + the 503, not logged — probes poll often, so a failure is a normal signal, not an error event). Keep checks cheap and fast; they run on every `/ready` poll.
|
|
54
54
|
|
|
55
|
+
### Routes-registered readiness signal
|
|
56
|
+
|
|
57
|
+
A booted HTTP app that ends up with **zero routes** almost always means a route module failed to register silently — without this check it would 404 every request while reporting ready. `health.addRoutesRegisteredCheck(getRouteCount)` registers a `"routes"` check that fails while the count is `0`:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { health, router } from "@warlock.js/core";
|
|
61
|
+
|
|
62
|
+
health.addRoutesRegisteredCheck(() => router.routeCount());
|
|
63
|
+
// pass a second arg to rename the check, e.g. "http-routes"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The count is passed as a getter so the registry stays decoupled from the router. Apps with no HTTP surface simply never register it.
|
|
67
|
+
|
|
55
68
|
## Graceful shutdown (request draining)
|
|
56
69
|
|
|
57
70
|
On SIGINT/SIGTERM the framework tears down in order: **app `onShutdown` hooks → connectors in reverse priority**. The HTTP connector's teardown drains instead of dropping:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: use-repository
|
|
3
|
-
description: 'Subclass `RepositoryManager` for data access — declare `source`, `filterBy`, `defaultOptions`, then call `list()`/`listCached()`/`find()`/`create()`/`update()`/`delete()
|
|
3
|
+
description: 'Subclass `RepositoryManager` for data access — declare `source`, `filterBy`, `defaultOptions`, then call `list()`/`listCached()`/`find()`/`create()`/`update()`/`delete()`, the active/cached/cursor variants, and the `filterBy`-aware aggregates `sum()`/`avg()`/`min()`/`max()`/`groupBy()`/`aggregate()`. Triggers: `RepositoryManager`, `FilterRules`, `RepositoryOptions`, `.list`, `.listCached`, `.find`, `.findCached`, `.create`, `.update`, `.delete`, `.sum`, `.avg`, `.min`, `.max`, `.groupBy`, `.aggregate`, `simpleSelectColumns`; "create a repository", "filter rules for a list endpoint", "cursor vs page pagination", "cached vs uncached read", "sum/avg/group-by with filters"; typical import `import { RepositoryManager } from "@warlock.js/core"`. Skip: cache singleton — `@warlock.js/cache/cache-basics/SKILL.md`; use-case pipelines — `@warlock.js/core/write-use-case/SKILL.md`; wire mapping — `@warlock.js/core/define-resource/SKILL.md`; competing libs `typeorm` Repository, `prisma.client.<model>`, `@nestjs/typeorm`.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Warlock — use a repository
|
|
@@ -191,6 +191,43 @@ await repo.countActive(options?);
|
|
|
191
191
|
await repo.countCached(options?);
|
|
192
192
|
```
|
|
193
193
|
|
|
194
|
+
### Aggregation
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
await repo.sum(field, options?); // → number
|
|
198
|
+
await repo.avg(field, options?); // → number
|
|
199
|
+
await repo.min(field, options?); // → number
|
|
200
|
+
await repo.max(field, options?); // → number
|
|
201
|
+
|
|
202
|
+
await repo.groupBy<R>(fields, aggregates, options?); // → R[]
|
|
203
|
+
await repo.aggregate<R>(aggregates, options?); // → R | null
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Every aggregate runs `applyOptionsToQuery(prepareOptions(options))` **first** — exactly like `count()` — so `filterBy` (and its operator-injection guard), `where`, scopes, and the rest of the repository options scope the aggregate before it executes. Pass the same filter inputs you'd pass to `list()`:
|
|
207
|
+
|
|
208
|
+
```ts
|
|
209
|
+
// filtered scalar aggregates — the filterBy rules apply
|
|
210
|
+
const paidTotal = await ordersRepository.sum("total", { status: "paid" });
|
|
211
|
+
const avgTicket = await ordersRepository.avg("total", { status: "paid" });
|
|
212
|
+
|
|
213
|
+
// group-by + aggregate expressions (use the cascade $agg helpers)
|
|
214
|
+
import { $agg } from "@warlock.js/cascade";
|
|
215
|
+
|
|
216
|
+
const byStatus = await ordersRepository.groupBy(
|
|
217
|
+
"status",
|
|
218
|
+
{ count: $agg.count(), total: $agg.sum("total") },
|
|
219
|
+
{ paidAfter: "2026-01-01" }, // a filterBy key
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
// one summary row over the whole filtered set (null when empty)
|
|
223
|
+
const summary = await ordersRepository.aggregate(
|
|
224
|
+
{ total: $agg.sum("total"), avg: $agg.avg("total") },
|
|
225
|
+
{ status: "paid" },
|
|
226
|
+
);
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
`fields` accepts a string, a `string[]`, or a column map; `aggregates` is a map of result alias → aggregate expression. Because filters are applied first, you never have to re-implement `filterBy` logic for a stats endpoint — the same inputs scope the count *and* the sums.
|
|
230
|
+
|
|
194
231
|
### Chunking
|
|
195
232
|
|
|
196
233
|
```ts
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: warlock-doctor
|
|
3
|
+
description: 'Run `warlock doctor` — a read-only diagnostics command that checks routes / config / connectors / optional-peers / health endpoints / release hygiene and prints a pass/warn/fail report, exiting non-zero on any failure. Add your own probe with the `DoctorCheck` contract and `runChecks` / `formatReportLines`. Triggers: `warlock doctor`, `doctorCommand`, `DoctorCheck`, `CheckResult`, `CheckStatus`, `DoctorReport`, `runChecks`, `formatReportLines`, `printReport`, `defaultDoctorChecks`; "diagnose my app", "preflight / preflight check", "is the app healthy", "why are there 0 routes", "pre-release sanity check", "CI smoke check"; run as `yarn warlock doctor`. Skip: the live `/health` + `/ready` HTTP probes — `@warlock.js/core/health-checks/SKILL.md`; authoring a general CLI command — `@warlock.js/core/write-cli-command/SKILL.md`; releasing the package — `releasing-warlock-monorepo`; competing tools `npm doctor`, `nest info`, hand-rolled preflight scripts.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Warlock — `warlock doctor`
|
|
7
|
+
|
|
8
|
+
`warlock doctor` is a read-only preflight. It boots the app far enough to introspect it — loads every config file and bootstrap code so routes and connectors register — but **starts no connectors**, so it never opens a database, cache, or socket connection. It then runs a set of checks and prints a grouped pass / warn / fail report.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
yarn warlock doctor
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
✓ routes: 42 registered
|
|
16
|
+
✓ config: required sections present (app, http)
|
|
17
|
+
✓ connectors: 3 registered, active: database, cache
|
|
18
|
+
⚠ optional-peers: not installed → unavailable: sharp (image processing); redis (Redis cache driver)
|
|
19
|
+
✓ health: liveness /health + readiness /ready registered
|
|
20
|
+
✓ release-hygiene: package.json and CHANGELOG agree on 4.6.0
|
|
21
|
+
|
|
22
|
+
Summary: 5 ok, 1 warn, 0 fail
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## What it checks
|
|
26
|
+
|
|
27
|
+
The default set is `defaultDoctorChecks` (in registration order — runtime-surface checks first, release hygiene last):
|
|
28
|
+
|
|
29
|
+
| Check | `ok` | `warn` | `fail` |
|
|
30
|
+
| --- | --- | --- | --- |
|
|
31
|
+
| `routes` | ≥ 1 route registered | 0 routes (a route module likely failed to load) | — |
|
|
32
|
+
| `config` | required sections (`app`, `http`) present | — | a required section is missing |
|
|
33
|
+
| `connectors` | manager enumerable; reports registered + active set | — | (only if the probe itself throws) |
|
|
34
|
+
| `optional-peers` | every known optional peer installed | a peer is missing → its feature is unavailable | — |
|
|
35
|
+
| `health` | `/health` + `/ready` will be exposed | `http.health.enabled = false` (probes off) | — |
|
|
36
|
+
| `release-hygiene` | `package.json` version matches the top `## x.y.z` CHANGELOG heading | no `CHANGELOG.md`, or no parseable heading | version ≠ top heading |
|
|
37
|
+
|
|
38
|
+
Optional peers are resolved from the **consuming app's** `node_modules` (via `createRequire(process.cwd())`), so the report reflects what *your* project has installed, not core's own deps.
|
|
39
|
+
|
|
40
|
+
## Exit code
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
warn only → exit 0 (warnings never fail the command)
|
|
44
|
+
any fail → exit 1 (so CI / a release script can gate on it)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`doctor` itself can never crash: a check that throws is caught by the runner and recorded as a `fail` (detail `check threw: <message>`), not re-thrown.
|
|
48
|
+
|
|
49
|
+
## The contract
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
type CheckStatus = "ok" | "warn" | "fail";
|
|
53
|
+
|
|
54
|
+
type CheckResult = {
|
|
55
|
+
name: string; // stable check name, e.g. "routes"
|
|
56
|
+
status: CheckStatus;
|
|
57
|
+
detail: string; // one-line, user-facing explanation
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
type DoctorCheck = {
|
|
61
|
+
name: string;
|
|
62
|
+
run: () => CheckResult | Promise<CheckResult>; // MUST be read-only
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
type DoctorReport = {
|
|
66
|
+
results: CheckResult[]; // in registration order
|
|
67
|
+
summary: Record<CheckStatus, number>; // counts per status
|
|
68
|
+
hasFailures: boolean; // true iff any fail
|
|
69
|
+
exitCode: 0 | 1; // 1 when hasFailures, else 0
|
|
70
|
+
};
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
A `DoctorCheck.run` must be **read-only** — it may introspect the router, connectors, config, and `package.json`, but must never mutate state or open a connection. It may be sync or async, and may throw (the runner degrades a throw to a `fail`).
|
|
74
|
+
|
|
75
|
+
## Running checks yourself
|
|
76
|
+
|
|
77
|
+
The runner and formatter are exported, so you can assemble your own check set — e.g. an app-specific preflight script or a custom CLI command:
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import {
|
|
81
|
+
runChecks,
|
|
82
|
+
formatReportLines,
|
|
83
|
+
printReport,
|
|
84
|
+
defaultDoctorChecks,
|
|
85
|
+
type DoctorCheck,
|
|
86
|
+
} from "@warlock.js/core";
|
|
87
|
+
|
|
88
|
+
const migrationsCheck: DoctorCheck = {
|
|
89
|
+
name: "migrations",
|
|
90
|
+
async run() {
|
|
91
|
+
const pending = await countPendingMigrations(); // your read-only probe
|
|
92
|
+
|
|
93
|
+
return pending === 0
|
|
94
|
+
? { name: "migrations", status: "ok", detail: "no pending migrations" }
|
|
95
|
+
: { name: "migrations", status: "warn", detail: `${pending} pending` };
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const report = await runChecks([...defaultDoctorChecks, migrationsCheck]);
|
|
100
|
+
|
|
101
|
+
printReport(report); // colored, to stdout
|
|
102
|
+
const lines = formatReportLines(report); // plain strings — snapshot-friendly
|
|
103
|
+
|
|
104
|
+
if (report.hasFailures) process.exit(report.exitCode);
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
`formatReportLines` returns plain (uncolored) `<symbol> <name>: <detail>` lines plus a `Summary: …` line — handy for tests. `printReport` is the colored stdout wrapper; the structured `DoctorReport` stays the source of truth for the exit code.
|
|
108
|
+
|
|
109
|
+
## Patterns
|
|
110
|
+
|
|
111
|
+
### CI / pre-release gate
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
yarn warlock doctor || exit 1 # non-zero exit fails the job
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
A red `release-hygiene` line catches the classic "bumped `package.json` but forgot the CHANGELOG heading" mistake before a publish.
|
|
118
|
+
|
|
119
|
+
### Diagnosing a silent 404 surface
|
|
120
|
+
|
|
121
|
+
A `⚠ routes: 0 routes registered` line is the tell that a route module threw on import or registration and the failure was surfaced (not swallowed). Re-run `warlock dev` and read the boot error.
|
|
122
|
+
|
|
123
|
+
## Gotchas
|
|
124
|
+
|
|
125
|
+
- **`doctor` starts no connectors.** It intentionally does not open DB / cache / socket connections — the `connectors` check reports the *registered* set and which are already active, without forcing any up. Don't expect it to detect a down database.
|
|
126
|
+
- **Optional-peers resolves from the project, not core.** A peer installed only inside core's own `node_modules` still reports as missing — the probe uses `process.cwd()`.
|
|
127
|
+
- **Warnings don't fail the command.** Only a `fail` flips the exit code. Missing optional peers and disabled health endpoints are deliberate-choice `warn`s.
|
|
128
|
+
- **Custom checks must stay read-only.** `run()` runs against a booted-but-not-connected app; mutating state or opening a connection breaks the contract and can hang the command.
|
|
129
|
+
|
|
130
|
+
## See also
|
|
131
|
+
|
|
132
|
+
- [`health-checks/SKILL.md`](../health-checks/SKILL.md) — the live `/health` + `/ready` HTTP probes and the `health` registry the `health` doctor check reports on.
|
|
133
|
+
- [`write-cli-command/SKILL.md`](../write-cli-command/SKILL.md) — authoring a command + its `preload` plan, the shape `doctorCommand` is built from.
|
|
134
|
+
- [`add-connector/SKILL.md`](../add-connector/SKILL.md) — connector registration, which the `connectors` check enumerates.
|
|
135
|
+
- [`warlock-conventions/SKILL.md`](../warlock-conventions/SKILL.md) — project layout the checks assume.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: warlock-routes
|
|
3
|
+
description: 'Run `warlock routes` — a read-only command that lists the registered HTTP routes as a verb-colored table (method / path / name / action / middleware-count / source), a sibling of `warlock doctor`. Filter with `--method` / `--path` / `--name`, or emit normalized rows as JSON with `--json`. Triggers: `warlock routes`, `routesCommand`, "list my routes", "show all routes", "route table", "what endpoints does my app expose", "dump routes as JSON", "which routes have middleware", "route map for CI"; run as `yarn warlock routes`. Skip: read-only health/preflight checks — `@warlock.js/core/warlock-doctor/SKILL.md`; defining/naming/grouping routes — `@warlock.js/core/register-route/SKILL.md`; authoring a general CLI command — `@warlock.js/core/write-cli-command/SKILL.md`; competing tools `nest`/`express` route listers, `php artisan route:list`.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Warlock — `warlock routes`
|
|
7
|
+
|
|
8
|
+
`warlock routes` lists every registered HTTP route as a table. It's the read-only sibling of [`warlock doctor`](../warlock-doctor/SKILL.md): it boots the app far enough to register route modules — but **starts no connectors**, so it never opens a database, cache, or socket connection.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
yarn warlock routes
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
METHOD PATH NAME ACTION MW SOURCE
|
|
16
|
+
GET /users users.list index 2 app/users/routes.ts
|
|
17
|
+
POST /users users.create store 2 app/users/routes.ts
|
|
18
|
+
GET /users/:id users.get show 2 app/users/routes.ts
|
|
19
|
+
DELETE /users/:id users.delete destroy 3 app/users/routes.ts
|
|
20
|
+
|
|
21
|
+
4 routes (2 GET · 1 POST · 1 DELETE)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The `METHOD` column is verb-colored (GET green, POST blue, PUT/PATCH yellow, DELETE red, `all`/OPTIONS/HEAD dim). Rows sort by path, then by HTTP-method order within a path.
|
|
25
|
+
|
|
26
|
+
## Columns
|
|
27
|
+
|
|
28
|
+
| Column | Meaning |
|
|
29
|
+
| -------- | ----------------------------------------------------------------------------- |
|
|
30
|
+
| `METHOD` | HTTP verb; a wildcard `all` route lists as `ALL`. |
|
|
31
|
+
| `PATH` | Full request path (group prefix already folded in). |
|
|
32
|
+
| `NAME` | Route name, or `—` when unnamed. |
|
|
33
|
+
| `ACTION` | Handler function name (`anonymous` for an unnamed handler). |
|
|
34
|
+
| `MW` | Count of middleware attached to the route. |
|
|
35
|
+
| `SOURCE` | Source file the route registered from, or `—`. |
|
|
36
|
+
|
|
37
|
+
## Filters
|
|
38
|
+
|
|
39
|
+
Optional, case-insensitive, AND-combined:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
yarn warlock routes --method GET # -m exact HTTP method
|
|
43
|
+
yarn warlock routes --path /users # -p path substring
|
|
44
|
+
yarn warlock routes --name users # -n route-name substring
|
|
45
|
+
yarn warlock routes -m POST -p /users
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## JSON output
|
|
49
|
+
|
|
50
|
+
`--json` (`-j`) emits the normalized rows instead of the table — for `jq`, a CI diff, or a generated API map. Filters apply before serialization.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
yarn warlock routes --json
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
[
|
|
58
|
+
{ "method": "GET", "path": "/users", "name": "users.list", "action": "index", "middleware": 2, "source": "app/users/routes.ts" }
|
|
59
|
+
]
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Patterns
|
|
63
|
+
|
|
64
|
+
### Audit which routes are guarded
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
yarn warlock routes --json | jq '[.[] | select(.middleware == 0)]'
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Surfaces public routes (no middleware) — a quick check that auth-protected paths actually carry a guard.
|
|
71
|
+
|
|
72
|
+
### Confirm a route registered
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
yarn warlock routes --name users.create
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
An empty result means the route isn't registered — re-run `warlock dev` and read the boot error (the route-module loader is fail-loud, so a throwing route file aborts boot rather than being silently dropped).
|
|
79
|
+
|
|
80
|
+
## Gotchas
|
|
81
|
+
|
|
82
|
+
- **No connectors are started.** The list reflects what's *registered*, not what would connect. It never opens a DB/cache/socket.
|
|
83
|
+
- **An empty table is a tell.** `No routes registered` is the same signal `warlock doctor`'s `routes` check warns on — a route module likely failed to load.
|
|
84
|
+
- **`MW` counts, it doesn't name.** It's a "is this route guarded?" signal; for the actual chain, read the route definition.
|
|
85
|
+
- **`ACTION` is the handler function name.** A controller method shows its method name; an inline anonymous handler shows `anonymous`.
|
|
86
|
+
|
|
87
|
+
## See also
|
|
88
|
+
|
|
89
|
+
- [`warlock-doctor/SKILL.md`](../warlock-doctor/SKILL.md) — the read-only diagnostics sibling; its `routes` check warns when this table would be empty.
|
|
90
|
+
- [`register-route/SKILL.md`](../register-route/SKILL.md) — defining, naming, and grouping the routes this command lists.
|
|
91
|
+
- [`write-cli-command/SKILL.md`](../write-cli-command/SKILL.md) — the command + `preload` shape `routesCommand` is built from.
|