@warlock.js/core 4.3.0 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/CHANGELOG.md +16 -1
  2. package/esm/application/application.d.mts +126 -4
  3. package/esm/application/application.d.mts.map +1 -1
  4. package/esm/application/application.mjs +133 -0
  5. package/esm/application/application.mjs.map +1 -1
  6. package/esm/application/index.d.mts +1 -1
  7. package/esm/cli/types.d.mts +2 -1
  8. package/esm/cli/types.d.mts.map +1 -1
  9. package/esm/config/config-getter.mjs +5 -5
  10. package/esm/config/config-getter.mjs.map +1 -1
  11. package/esm/config/config-loader.mjs +2 -2
  12. package/esm/config/config-loader.mjs.map +1 -1
  13. package/esm/connectors/access-connector.mjs +2 -2
  14. package/esm/connectors/access-connector.mjs.map +1 -1
  15. package/esm/connectors/cache-connector.mjs +2 -2
  16. package/esm/connectors/cache-connector.mjs.map +1 -1
  17. package/esm/connectors/connectors-manager.d.mts.map +1 -1
  18. package/esm/connectors/connectors-manager.mjs +4 -1
  19. package/esm/connectors/connectors-manager.mjs.map +1 -1
  20. package/esm/connectors/database-connector.mjs +2 -2
  21. package/esm/connectors/database-connector.mjs.map +1 -1
  22. package/esm/connectors/herald-connector.mjs +2 -2
  23. package/esm/connectors/herald-connector.mjs.map +1 -1
  24. package/esm/connectors/http-connector.d.mts +8 -0
  25. package/esm/connectors/http-connector.d.mts.map +1 -1
  26. package/esm/connectors/http-connector.mjs +40 -7
  27. package/esm/connectors/http-connector.mjs.map +1 -1
  28. package/esm/connectors/logger-connector.mjs +2 -2
  29. package/esm/connectors/logger-connector.mjs.map +1 -1
  30. package/esm/connectors/mail-connector.mjs +2 -2
  31. package/esm/connectors/mail-connector.mjs.map +1 -1
  32. package/esm/connectors/notifications-connector.mjs +2 -2
  33. package/esm/connectors/notifications-connector.mjs.map +1 -1
  34. package/esm/connectors/socket-connector.mjs +3 -3
  35. package/esm/connectors/socket-connector.mjs.map +1 -1
  36. package/esm/dev-server/development-server.mjs +7 -0
  37. package/esm/dev-server/development-server.mjs.map +1 -1
  38. package/esm/dev-server/loader/transpile-cache.mjs +1 -1
  39. package/esm/http/config.mjs +2 -2
  40. package/esm/http/config.mjs.map +1 -1
  41. package/esm/http/createHttpApplication.mjs +2 -2
  42. package/esm/http/createHttpApplication.mjs.map +1 -1
  43. package/esm/http/health.d.mts +57 -0
  44. package/esm/http/health.d.mts.map +1 -0
  45. package/esm/http/health.mjs +75 -0
  46. package/esm/http/health.mjs.map +1 -0
  47. package/esm/http/index.d.mts +2 -1
  48. package/esm/http/index.mjs +2 -1
  49. package/esm/http/middleware/idempotency.middleware.mjs +5 -5
  50. package/esm/http/middleware/idempotency.middleware.mjs.map +1 -1
  51. package/esm/http/middleware/inject-request-context.mjs +2 -2
  52. package/esm/http/middleware/inject-request-context.mjs.map +1 -1
  53. package/esm/http/middleware/maintenance.middleware.mjs +4 -4
  54. package/esm/http/middleware/maintenance.middleware.mjs.map +1 -1
  55. package/esm/http/plugins.mjs +9 -9
  56. package/esm/http/plugins.mjs.map +1 -1
  57. package/esm/http/response.mjs +5 -5
  58. package/esm/http/response.mjs.map +1 -1
  59. package/esm/http/server.d.mts +16 -1
  60. package/esm/http/server.d.mts.map +1 -1
  61. package/esm/http/server.mjs +23 -3
  62. package/esm/http/server.mjs.map +1 -1
  63. package/esm/http/types.d.mts +45 -0
  64. package/esm/http/types.d.mts.map +1 -1
  65. package/esm/index.d.mts +5 -4
  66. package/esm/index.mjs +6 -5
  67. package/esm/production/production-builder.mjs +2 -2
  68. package/esm/production/production-builder.mjs.map +1 -1
  69. package/esm/utils/environment.d.mts +6 -1
  70. package/esm/utils/environment.d.mts.map +1 -1
  71. package/esm/utils/environment.mjs.map +1 -1
  72. package/esm/utils/index.d.mts +1 -1
  73. package/esm/utils/paths.mjs +2 -2
  74. package/esm/utils/paths.mjs.map +1 -1
  75. package/esm/validation/validateAll.mjs +2 -2
  76. package/esm/validation/validateAll.mjs.map +1 -1
  77. package/llms-full.txt +164 -2
  78. package/llms.txt +2 -1
  79. package/package.json +9 -9
  80. package/skills/health-checks/SKILL.md +98 -0
  81. package/skills/use-app-context/SKILL.md +62 -2
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: use-app-context
3
- description: 'Read app-wide context — the `Application` static class (env, version, uptime, runtime strategy) 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`, `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"; typical import `import { Application, app } from "@warlock.js/core"`. Skip: path helpers — `@warlock.js/core/resolve-path/SKILL.md`; connector start order — `@warlock.js/core/add-connector/SKILL.md`; competing patterns: bare `process.env.NODE_ENV`, ad-hoc Fastify imports.'
3
+ description: 'Read app-wide context — the `Application` static class (env, version, uptime, runtime strategy, boot lifecycle) plus the `app` runtime accessor (live Fastify, socket.io, router, database via the DI container). Triggers: `Application.isProduction`, `Application.environment`, `Application.runtimeStrategy`, `Application.uptime`, `Application.version`, `Application.onceBooted`, `Application.whenBooted`, `Application.isBooted`, `Application.onShutdown`, `Application.isShuttingDown`, `app.http`, `app.socket`, `app.database`, `app.router`; "branch on environment", "reach the live Fastify instance", "framework version in health endpoint", "dev vs production runtime check", "run code once the app is fully booted", "after all connectors started", "app booted hook", "run cleanup before shutdown", "graceful shutdown hook"; typical import `import { Application, app } from "@warlock.js/core"`. Skip: path helpers — `@warlock.js/core/resolve-path/SKILL.md`; connector start order — `@warlock.js/core/add-connector/SKILL.md`; competing patterns: bare `process.env.NODE_ENV`, ad-hoc Fastify imports.'
4
4
  ---
5
5
 
6
6
  # Warlock — use the application context
@@ -75,6 +75,64 @@ The dev-server CLI command sets it to `"development"`. The `build` command and `
75
75
 
76
76
  Most app code shouldn't care about `runtimeStrategy` — branch on `environment` instead, which is the orthogonal "what world is this code talking to?" axis.
77
77
 
78
+ ## Lifecycle: boot & shutdown
79
+
80
+ `Application.onceBooted(callback)` runs a callback the moment the app is fully booted — every connector in **both** phases is active and all app files (locales, events, main, routes) are loaded. It's the only hook that fires *after* the late phase (http, socket) is up.
81
+
82
+ ```ts
83
+ import { Application } from "@warlock.js/core";
84
+
85
+ Application.onceBooted(({ environment, runtimeStrategy, bootDurationMs }) => {
86
+ // http is listening, socket is bound, every model is registered
87
+ });
88
+ ```
89
+
90
+ Why a dedicated hook instead of code at the bottom of `main.ts`? **App files load before the late phase.** `main.ts`, `events.ts`, `routes.ts`, and locales are all imported *between* the early and late connector phases — so when `main.ts` runs, http/socket are not listening yet. `onceBooted` defers your callback until the whole sequence finishes, which makes it the safe place to touch `app.http` / `app.socket` from `main.ts`-level code.
91
+
92
+ It's a **latch**, not a plain event listener: register before boot and it queues; register *after* boot and it fires on the next microtask. A late subscriber never silently misses the signal.
93
+
94
+ ```ts
95
+ Application.isBooted; // boolean — has boot finished?
96
+ await Application.whenBooted(); // Promise<BootContext> — await instead of a callback
97
+ ```
98
+
99
+ `whenBooted()` is the promise form, resolving with the same `BootContext` (`{ environment, runtimeStrategy, bootDurationMs? }`). `bootDurationMs` is set by the dev server (which times boot) and omitted by the production entry.
100
+
101
+ The framework fires the latch for you — the dev server and the production bundle each call it once, right after the late phase. App code only ever *reads* it via `onceBooted` / `whenBooted` / `isBooted`; the internal `markBooted` is a framework entry point, not for application use.
102
+
103
+ ### Run something once everything is listening
104
+
105
+ ```ts title="src/app/main.ts"
106
+ import { Application } from "@warlock.js/core";
107
+ import { log } from "@warlock.js/logger";
108
+
109
+ Application.onceBooted(({ environment, bootDurationMs }) => {
110
+ log.success("app", "booted", `ready in ${environment}`, { bootDurationMs });
111
+ });
112
+ ```
113
+
114
+ This is the right home for "warm a cache", "register a recurring job", "ping a readiness endpoint", or "open an outbound connection that needs the http server already listening" — anything that must wait for a complete boot.
115
+
116
+ ### Shutdown — clean up before the app goes down
117
+
118
+ `Application.onShutdown(callback)` is the mirror of `onceBooted`: it runs your teardown **once**, when the process is shutting down (SIGINT/SIGTERM, or the dev server stopping) — and crucially **before** the connectors (db, cache, http) are torn down, so your cleanup can still use them.
119
+
120
+ ```ts title="src/app/main.ts"
121
+ import { Application } from "@warlock.js/core";
122
+
123
+ Application.onceBooted(() => {
124
+ const consumer = startQueueConsumer();
125
+
126
+ Application.onShutdown(async () => {
127
+ await consumer.stop(); // db / cache / http are still up here
128
+ });
129
+ });
130
+ ```
131
+
132
+ 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.
133
+
134
+ The framework triggers this for you (the connectors manager runs the hooks at the start of shutdown); app code only ever registers via `onShutdown`. For the HTTP-side story — `/health`, `/ready`, and graceful request draining — see `@warlock.js/core/health-checks/SKILL.md`.
135
+
78
136
  ## Paths
79
137
 
80
138
  For path helpers (`appPath`, `configPath`, `uploadsPath`, …) anchored at `process.cwd()`, the `paths.*` aggregate, and the `uploads.root` config override, see [`resolve-path/SKILL.md`](../resolve-path/SKILL.md).
@@ -230,7 +288,9 @@ cors: {
230
288
 
231
289
  - **`version` is `null` until the first `await`.** The version loader is async (it reads `package.json`). On a cold start before any framework code has run `getWarlockVersion()`, `Application.version` returns `null`. The framework does load it during bootstrap, so anywhere downstream of bootstrap is fine — controllers, services, connectors after `start()`. CLI commands without `preload.bootstrap` may see `null`.
232
290
  - **`Application` is static, not a DI registration.** Don't try to inject it. There's nothing to inject — it's a class with only static members.
233
- - **`app.*` accessors return `undefined` before their connector boots — they don't throw.** `app.socket` / `app.database` / `app.http` are populated by their respective connectors during boot; until then each getter returns `undefined` (a bare `container.get(...)`). Reading them earlier (eager module-load code, the top level of a `main.ts` for the late-phase `http`/`socket`, certain CLI commands without the right `preload.connectors`) hands you `undefined`, and chaining off it throws. Safe everywhere downstream of bootstrap.
291
+ - **`app.*` accessors return `undefined` before their connector boots — they don't throw.** `app.socket` / `app.database` / `app.http` are populated by their respective connectors during boot; until then each getter returns `undefined` (a bare `container.get(...)`). Reading them earlier (eager module-load code, the top level of a `main.ts` for the late-phase `http`/`socket`, certain CLI commands without the right `preload.connectors`) hands you `undefined`, and chaining off it throws. Safe everywhere downstream of bootstrap — including inside `Application.onceBooted(...)`.
292
+ - **`onceBooted` is a latch, not `events.on`.** A callback registered *after* boot completed still runs (next microtask) instead of silently missing the signal — so register it wherever it reads best, including module top-level in `main.ts`. A listener that throws is caught and logged; it can't break boot or the other listeners.
293
+ - **`onShutdown` runs before connectors close, not after.** That ordering is deliberate so cleanup can still use db/cache/http — but it means a hook that hangs delays connector teardown (bounded only by your process manager's kill timeout). Keep teardown fast; for HTTP draining the framework already bounds it via `http.gracefulShutdown.timeout`.
234
294
 
235
295
  ## See also
236
296