exisjs 0.9.2 → 0.10.0-alpha.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 (135) hide show
  1. package/README.md +3 -0
  2. package/bin/exis.js +76 -1
  3. package/dist/config/types.d.ts +11 -2
  4. package/dist/config/types.d.ts.map +1 -1
  5. package/dist/docs/content/README.md +1 -0
  6. package/dist/docs/content/cli/commands.mdx +23 -1
  7. package/dist/docs/content/cli/usage.mdx +2 -1
  8. package/dist/docs/content/config.mdx +47 -3
  9. package/dist/docs/content/deployment.mdx +163 -0
  10. package/dist/docs/content/installation.mdx +1 -1
  11. package/dist/docs/content/introduction.mdx +3 -0
  12. package/dist/docs/content/validation.mdx +1 -1
  13. package/dist/docs/reference/config.mdx +2 -1
  14. package/dist/docs/reference/validator.mdx +4 -0
  15. package/dist/internal.d.ts +16 -0
  16. package/dist/internal.d.ts.map +1 -0
  17. package/dist/internal.js +45 -0
  18. package/dist/internal.js.map +1 -0
  19. package/dist/{cli → lib}/resolve-aliases.d.ts.map +1 -1
  20. package/dist/{cli → lib}/resolve-aliases.js.map +1 -1
  21. package/dist/lib/start-command.d.ts +11 -0
  22. package/dist/lib/start-command.d.ts.map +1 -0
  23. package/dist/lib/start-command.js +79 -0
  24. package/dist/lib/start-command.js.map +1 -0
  25. package/dist/lib/start-server.js +4 -2
  26. package/dist/lib/start-server.js.map +1 -1
  27. package/dist/middleware/backpressure.d.ts +5 -0
  28. package/dist/middleware/backpressure.d.ts.map +1 -1
  29. package/dist/middleware/backpressure.js +66 -36
  30. package/dist/middleware/backpressure.js.map +1 -1
  31. package/dist/router/route-scanner.d.ts.map +1 -1
  32. package/dist/router/route-scanner.js +19 -20
  33. package/dist/router/route-scanner.js.map +1 -1
  34. package/dist/server/app.d.ts.map +1 -1
  35. package/dist/server/app.js +24 -1
  36. package/dist/server/app.js.map +1 -1
  37. package/dist/server/bootstrapper.d.ts.map +1 -1
  38. package/dist/server/bootstrapper.js +3 -1
  39. package/dist/server/bootstrapper.js.map +1 -1
  40. package/dist/server/cluster.d.ts.map +1 -1
  41. package/dist/server/cluster.js +3 -0
  42. package/dist/server/cluster.js.map +1 -1
  43. package/dist/server/metrics.d.ts +43 -0
  44. package/dist/server/metrics.d.ts.map +1 -0
  45. package/dist/server/metrics.js +254 -0
  46. package/dist/server/metrics.js.map +1 -0
  47. package/dist/utils/logger.d.ts.map +1 -1
  48. package/dist/utils/logger.js +31 -3
  49. package/dist/utils/logger.js.map +1 -1
  50. package/dist/validator/builder.d.ts +20 -16
  51. package/dist/validator/builder.d.ts.map +1 -1
  52. package/dist/validator/builder.js +21 -1
  53. package/dist/validator/builder.js.map +1 -1
  54. package/dist/validator/engine.d.ts.map +1 -1
  55. package/dist/validator/engine.js +8 -1
  56. package/dist/validator/engine.js.map +1 -1
  57. package/dist/validator/index.d.ts +4 -1
  58. package/dist/validator/index.d.ts.map +1 -1
  59. package/dist/validator/index.js +5 -1
  60. package/dist/validator/index.js.map +1 -1
  61. package/dist/validator/tex.d.ts +1 -1
  62. package/dist/validator/tex.d.ts.map +1 -1
  63. package/dist/validator/types.d.ts +7 -0
  64. package/dist/validator/types.d.ts.map +1 -1
  65. package/package.json +81 -9
  66. package/dist/cli/commands/build.d.ts +0 -11
  67. package/dist/cli/commands/build.d.ts.map +0 -1
  68. package/dist/cli/commands/build.js +0 -344
  69. package/dist/cli/commands/build.js.map +0 -1
  70. package/dist/cli/commands/clean.d.ts +0 -5
  71. package/dist/cli/commands/clean.d.ts.map +0 -1
  72. package/dist/cli/commands/clean.js +0 -30
  73. package/dist/cli/commands/clean.js.map +0 -1
  74. package/dist/cli/commands/dev.d.ts +0 -21
  75. package/dist/cli/commands/dev.d.ts.map +0 -1
  76. package/dist/cli/commands/dev.js +0 -842
  77. package/dist/cli/commands/dev.js.map +0 -1
  78. package/dist/cli/commands/doctor.d.ts +0 -2
  79. package/dist/cli/commands/doctor.d.ts.map +0 -1
  80. package/dist/cli/commands/doctor.js +0 -228
  81. package/dist/cli/commands/doctor.js.map +0 -1
  82. package/dist/cli/commands/exports.d.ts +0 -2
  83. package/dist/cli/commands/exports.d.ts.map +0 -1
  84. package/dist/cli/commands/exports.js +0 -48
  85. package/dist/cli/commands/exports.js.map +0 -1
  86. package/dist/cli/commands/generate.d.ts +0 -33
  87. package/dist/cli/commands/generate.d.ts.map +0 -1
  88. package/dist/cli/commands/generate.js +0 -469
  89. package/dist/cli/commands/generate.js.map +0 -1
  90. package/dist/cli/commands/init.d.ts +0 -2
  91. package/dist/cli/commands/init.d.ts.map +0 -1
  92. package/dist/cli/commands/init.js +0 -37
  93. package/dist/cli/commands/init.js.map +0 -1
  94. package/dist/cli/commands/repl.d.ts +0 -6
  95. package/dist/cli/commands/repl.d.ts.map +0 -1
  96. package/dist/cli/commands/repl.js +0 -75
  97. package/dist/cli/commands/repl.js.map +0 -1
  98. package/dist/cli/commands/run.d.ts +0 -7
  99. package/dist/cli/commands/run.d.ts.map +0 -1
  100. package/dist/cli/commands/run.js +0 -101
  101. package/dist/cli/commands/run.js.map +0 -1
  102. package/dist/cli/commands/start.d.ts +0 -8
  103. package/dist/cli/commands/start.d.ts.map +0 -1
  104. package/dist/cli/commands/start.js +0 -155
  105. package/dist/cli/commands/start.js.map +0 -1
  106. package/dist/cli/commands/test.d.ts +0 -8
  107. package/dist/cli/commands/test.d.ts.map +0 -1
  108. package/dist/cli/commands/test.js +0 -165
  109. package/dist/cli/commands/test.js.map +0 -1
  110. package/dist/cli/index.d.ts +0 -3
  111. package/dist/cli/index.d.ts.map +0 -1
  112. package/dist/cli/index.js +0 -268
  113. package/dist/cli/index.js.map +0 -1
  114. package/dist/cli/manifest.d.ts +0 -4
  115. package/dist/cli/manifest.d.ts.map +0 -1
  116. package/dist/cli/manifest.js +0 -489
  117. package/dist/cli/manifest.js.map +0 -1
  118. package/dist/cli/routes.d.ts +0 -17
  119. package/dist/cli/routes.d.ts.map +0 -1
  120. package/dist/cli/routes.js +0 -317
  121. package/dist/cli/routes.js.map +0 -1
  122. package/dist/cli/utils.d.ts +0 -24
  123. package/dist/cli/utils.d.ts.map +0 -1
  124. package/dist/cli/utils.js +0 -54
  125. package/dist/cli/utils.js.map +0 -1
  126. package/dist/lib/inspect-routes.d.ts +0 -2
  127. package/dist/lib/inspect-routes.d.ts.map +0 -1
  128. package/dist/lib/inspect-routes.js +0 -150
  129. package/dist/lib/inspect-routes.js.map +0 -1
  130. package/dist/lib/start-repl.d.ts +0 -2
  131. package/dist/lib/start-repl.d.ts.map +0 -1
  132. package/dist/lib/start-repl.js +0 -120
  133. package/dist/lib/start-repl.js.map +0 -1
  134. /package/dist/{cli → lib}/resolve-aliases.d.ts +0 -0
  135. /package/dist/{cli → lib}/resolve-aliases.js +0 -0
package/README.md CHANGED
@@ -14,8 +14,11 @@ Install `exisjs` via npm:
14
14
 
15
15
  ```bash
16
16
  npm install exisjs
17
+ npm install -D @exisjs/cli typescript
17
18
  ```
18
19
 
20
+ The `exisjs` command (`dev`, `build`, `test`) is in [`@exisjs/cli`](https://www.npmjs.com/package/@exisjs/cli), a development dependency; production installs only need `exisjs`.
21
+
19
22
  Or initialize a new project using the scaffolding CLI:
20
23
 
21
24
  ```bash
package/bin/exis.js CHANGED
@@ -1,2 +1,77 @@
1
1
  #!/usr/bin/env node
2
- require('../dist/cli/index.js');
2
+ // `exisjs start` runs here, from the runtime, so production installs need no
3
+ // development tools. Every other command is in @exisjs/cli; this binary
4
+ // forwards to it.
5
+ const fs = require('node:fs')
6
+ const path = require('node:path')
7
+
8
+ const [command, ...args] = process.argv.slice(2)
9
+
10
+ if (command === 'start') {
11
+ const options = {}
12
+ const names = {
13
+ '-p': 'port',
14
+ '--port': 'port',
15
+ '-H': 'host',
16
+ '--host': 'host',
17
+ '-e': 'entry',
18
+ '--entry': 'entry',
19
+ }
20
+ for (let i = 0; i < args.length; i++) {
21
+ const [flag, inline] = args[i].split('=')
22
+ if (flag === '-h' || flag === '--help') {
23
+ console.log(
24
+ 'Usage: exisjs start [--port <port>] [--host <host>] [--entry <file>]'
25
+ )
26
+ process.exit(0)
27
+ }
28
+ const name = names[flag]
29
+ if (!name) {
30
+ console.error(`Unknown option for exisjs start: ${args[i]}`)
31
+ process.exit(1)
32
+ }
33
+ options[name] = inline ?? args[++i]
34
+ }
35
+ require('../dist/lib/start-command.js')
36
+ .startBuiltServer(options)
37
+ .catch((err) => {
38
+ console.error(err)
39
+ process.exit(1)
40
+ })
41
+ return
42
+ }
43
+
44
+ let cli
45
+ try {
46
+ cli = require.resolve('@exisjs/cli/bin/exisjs.js', {
47
+ paths: [process.cwd(), __dirname],
48
+ })
49
+ } catch {
50
+ console.error(
51
+ `\n \`exisjs ${command ?? ''}\` is in the @exisjs/cli package, which is not installed.\n` +
52
+ ' Install it as a development dependency:\n\n' +
53
+ ' npm install -D @exisjs/cli\n\n' +
54
+ ' (`exisjs start` needs only exisjs, so production installs can leave it out.)\n'
55
+ )
56
+ process.exit(1)
57
+ }
58
+
59
+ // One line, only for projects that rely on the package installed through
60
+ // the runtime instead of listing it themselves
61
+ try {
62
+ const pkg = JSON.parse(
63
+ fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf8')
64
+ )
65
+ const listed =
66
+ pkg.devDependencies?.['@exisjs/cli'] || pkg.dependencies?.['@exisjs/cli']
67
+ if (!listed && command !== 'migrate' && !process.env.EXIS_NO_CLI_NOTICE) {
68
+ console.error(
69
+ '\x1b[33m[exis]\x1b[0m The CLI moved to @exisjs/cli; exisjs 0.11 stops installing it. ' +
70
+ 'Run \x1b[36mnpx exisjs migrate\x1b[0m to update this project.'
71
+ )
72
+ }
73
+ } catch {
74
+ // no package.json: nothing to suggest
75
+ }
76
+
77
+ require(cli)
@@ -143,11 +143,20 @@ export interface ExisConfig {
143
143
  * 'auto' will use Bun if detected, otherwise Node.
144
144
  */
145
145
  server?: 'auto' | 'node' | 'bun' | 'uws';
146
+ /**
147
+ * Limits how many requests the app handles at once. Requests over
148
+ * `maxConcurrent` wait in this process (up to `maxQueue`, for at most
149
+ * `timeoutMs`), then get 503. Unknown keys and drivers stop the start.
150
+ */
146
151
  queue?: {
147
- driver?: 'memory' | 'redis' | string;
152
+ /** Only `'memory'`: waiting requests live in this process */
153
+ driver?: 'memory';
154
+ /** Requests handled at once. Default 1000 */
148
155
  maxConcurrent?: number;
156
+ /** Requests allowed to wait. Default 500 */
149
157
  maxQueue?: number;
150
- [key: string]: any;
158
+ /** How long a request may wait, in ms. Default 10000 */
159
+ timeoutMs?: number;
151
160
  };
152
161
  watch?: WatchConfig;
153
162
  dev?: DevConfig;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"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"}
@@ -33,6 +33,7 @@ Documentation follows the [Diátaxis Framework](https://diataxis.fr/), separatin
33
33
  - [`cron.mdx`](./cron.mdx): Background task scheduling (`cron()` and `@Cron()`) with drift correction and overlap protection.
34
34
  - [`swagger.mdx`](./swagger.mdx): Automatic OpenAPI 3.1 schema extraction, Swagger UI (`/docs`), and JSON documentation endpoints.
35
35
  - [`testing.mdx`](./testing.mdx): Test harness (`createTestContext`, `createTestApp`), mocking utilities (`ex`), and CLI test runner.
36
+ - [`deployment.mdx`](./deployment.mdx): Docker images, build-time secrets (`--skip-env-check`), graceful shutdown, health checks and migrations.
36
37
  - [`config.mdx`](./config.mdx): Global configuration options in `exis.config.ts`, lifecycle phases, clustering, and file watcher settings.
37
38
  - [`exisjs-mcp.mdx`](./exisjs-mcp.mdx): Model Context Protocol (MCP) server integration for IDE AI assistants.
38
39
 
@@ -55,6 +55,10 @@ npx exisjs build [options]
55
55
  ### Type-checking on deployment hosts
56
56
  Some hosts (Render, Heroku and others) install with `NODE_ENV=production`, which leaves out `devDependencies` such as `@types/node`. When `@types/*` packages listed in your `devDependencies` are not installed, `exisjs build` skips the type-check with a warning and still compiles. To keep the type-check on the host, set the install command to `npm install --include=dev`.
57
57
 
58
+ The same applies to the CLI itself: `exisjs build` comes from `@exisjs/cli`, a development dependency. Build where development dependencies are installed (a Docker build stage, or `npm install --include=dev` on the host), then install production dependencies only for the running server.
59
+
60
+ `exisjs build` also writes `.exis/server/main.js`, the production entry: `node .exis/server/main.js` starts the server in that one process, with `NODE_ENV=production` unless set otherwise.
61
+
58
62
  ### Build Outputs
59
63
  - Compiles application source code into the specified `outDir`.
60
64
  - Emits pre-computed route manifests (`.exis/routes-manifest.js`) for O(1) route discovery at runtime.
@@ -81,7 +85,9 @@ npx exisjs cl [options]
81
85
 
82
86
  ## `exisjs start`
83
87
 
84
- Starts the compiled production server from the build output directory.
88
+ Starts the built server in the current process (the same as `node .exis/server/main.js`), with `NODE_ENV=production`. The server receives `SIGINT` / `SIGTERM` itself and shuts down gracefully.
89
+
90
+ `exisjs start` is part of the `exisjs` runtime package, not of `@exisjs/cli`: it works in production installs that leave out development dependencies (`npm ci --omit=dev`), so `"start": "exisjs start"` and `npm start` work on every platform. The other commands need `@exisjs/cli`.
85
91
 
86
92
  ```bash
87
93
  npx exisjs start [options]
@@ -97,6 +103,22 @@ npx exisjs start [options]
97
103
 
98
104
  ---
99
105
 
106
+ ## `exisjs migrate`
107
+
108
+ Updates a project created before 0.10 to the current layout:
109
+
110
+ - adds `@exisjs/cli` to `devDependencies` (and `typescript`, if the project has a `tsconfig.json` but did not list it);
111
+ - lists the `Dockerfile` lines to change (it does not edit the `Dockerfile`).
112
+
113
+ ```bash
114
+ npx exisjs migrate # writes package.json
115
+ npx exisjs migrate --dry-run # only shows the changes
116
+ ```
117
+
118
+ Then run `npm install`. Running it again changes nothing.
119
+
120
+ ---
121
+
100
122
  ## `exisjs generate`
101
123
 
102
124
  Scaffolds framework components and files according to ExisJS file conventions.
@@ -68,6 +68,7 @@ Applications initialized with `npx exisjs init` include standard npm lifecycle s
68
68
  "exisjs": "^1.0.0"
69
69
  },
70
70
  "devDependencies": {
71
+ "@exisjs/cli": "^0.10.0",
71
72
  "typescript": "^5.0.0"
72
73
  }
73
74
  }
@@ -82,7 +83,7 @@ npm run dev
82
83
  # Compile TypeScript and build route manifests
83
84
  npm run build
84
85
 
85
- # Start production server
86
+ # Start the production server (one process, no CLI needed)
86
87
  npm run start
87
88
 
88
89
  # Run native test runner
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  title: "Configuration"
3
3
  description: "Global runtime configuration, phases, environment loading, server engine selection, and cluster options in exis.config.ts."
4
- nextUrl: "/docs/exisjs-mcp"
5
- nextTitle: "AI Integration (MCP)"
4
+ nextUrl: "/docs/deployment"
5
+ nextTitle: "Deploying with Docker"
6
6
  ---
7
7
 
8
8
  # Configuration (`exis.config.ts`)
@@ -166,7 +166,7 @@ export default defineConfig({
166
166
  | `asyncContext` | `boolean` | `false` | Enables `AsyncLocalStorage` context tracking (`getContext()`). |
167
167
  | `docs` / `swagger` | `boolean \| SwaggerConfig` | `{ enabled: false }` | OpenAPI 3.1 specification and Swagger UI endpoint generation. Served in every environment when enabled; the project template uses `enabled: process.env.NODE_ENV !== 'production'` so published API docs do not help attackers. |
168
168
  | `healthcheck` | `boolean \| HealthCheckConfig` | `{ enabled: false }` | `path` (`/_health`): liveness, runs `checks`. `readyPath` (`/_ready`, `false` to disable): readiness, `503` unless `checks` pass, registered databases are healthy and the app is not shutting down. |
169
- | `metrics` | `boolean \| MetricsConfig` | `{ enabled: false }` | Prometheus metrics endpoint (`path: '/metrics'`). |
169
+ | `metrics` | `boolean \| MetricsConfig` | `{ enabled: false }` | Prometheus metrics endpoint (`path: '/metrics'`). See [Prometheus Metrics](#prometheus-metrics). |
170
170
  | `telemetry` | `boolean \| TelemetryConfig` | `{ enabled: false }` | OpenTelemetry tracing and metrics export. |
171
171
 
172
172
  ### Concurrency & Clustering
@@ -182,6 +182,24 @@ export default defineConfig({
182
182
  })
183
183
  ```
184
184
 
185
+ #### Limiting concurrent requests (`queue`)
186
+
187
+ `queue` caps how many requests the app handles at once, so a traffic spike slows down instead of exhausting memory or the database pool:
188
+
189
+ ```typescript filename="exis.config.ts"
190
+ export default defineConfig({
191
+ queue: {
192
+ maxConcurrent: 500, // handled at once (default 1000)
193
+ maxQueue: 200, // may wait for a free slot (default 500)
194
+ timeoutMs: 10_000, // longest wait (default 10 s)
195
+ },
196
+ })
197
+ ```
198
+
199
+ A request over the limit waits in this process; when `maxQueue` is full, or the wait exceeds `timeoutMs`, it gets `503 Service Unavailable`. A client that disconnects frees its place. The limit is per process (per worker in cluster mode).
200
+
201
+ The only `driver` is `'memory'`. Any other driver, unknown keys and invalid numbers stop the server at start-up with a message naming the option. ExisJS has no shared or durable queue yet, so a setting that pretended to provide one would be silently ignored.
202
+
185
203
  ---
186
204
 
187
205
  ## File Watcher & Development Configuration
@@ -215,6 +233,32 @@ ExisJS automatically excludes build output and temp folders from triggering watc
215
233
 
216
234
  ---
217
235
 
236
+ ## Prometheus Metrics
237
+
238
+ Set `metrics: { enabled: true }` (or `metrics: true`) to serve request and process metrics in the Prometheus text format at `GET /metrics` (change it with `path`).
239
+
240
+ ```typescript filename="exis.config.ts"
241
+ export default defineConfig({
242
+ metrics: { enabled: true, path: '/metrics' },
243
+ })
244
+ ```
245
+
246
+ | Metric | Type | Labels |
247
+ | :--- | :--- | :--- |
248
+ | `http_requests_total` | counter | `method`, `route`, `status` |
249
+ | `http_request_duration_seconds` | histogram (5 ms to 10 s) | `method`, `route` |
250
+ | `http_requests_in_flight` | gauge | |
251
+ | `process_resident_memory_bytes`, `nodejs_heap_used_bytes` | gauge | `worker` in cluster mode |
252
+ | `nodejs_eventloop_lag_p99_seconds` | gauge | `worker` in cluster mode |
253
+ | `process_start_time_seconds` | gauge | `worker` in cluster mode |
254
+
255
+ - **`route` is the route pattern** (`/users/:id`), never the requested URL, so the number of series stays bounded. Requests that match no route are counted under `(unmatched)`.
256
+ - **Status `499`** counts requests whose client disconnected before the response finished.
257
+ - **Cluster mode:** a scrape can reach any worker; that worker collects the numbers of every worker through the primary process, so the request counters are always the whole server's. Memory and event-loop lag are reported per worker.
258
+ - **Keep the endpoint private.** It lists every route of the API. Expose it only on an internal network, or block it at the proxy for public traffic.
259
+
260
+ ---
261
+
218
262
  ## Plugin Integration
219
263
 
220
264
  Plugins extend framework capabilities by intercepting server configuration or registering global routes:
@@ -0,0 +1,163 @@
1
+ ---
2
+ title: "Deploying with Docker"
3
+ description: "Build an ExisJS app into a small production image, keep secrets out of the build, run the server as one process that shuts down gracefully, and wire up health checks."
4
+ nextUrl: "/docs/exisjs-mcp"
5
+ nextTitle: "AI Integration (MCP)"
6
+ ---
7
+
8
+ # Deploying with Docker
9
+
10
+ This page builds an ExisJS app into a production image that:
11
+
12
+ - builds without secrets, because container platforms provide them only when the container runs;
13
+ - refuses to start when a required secret is missing;
14
+ - runs the server as one process that stops gracefully on `docker stop` and on every redeploy;
15
+ - contains no build tools: no TypeScript, esbuild or CLI.
16
+
17
+ The Dockerfile below was tested end to end with an app created by `npm create exisjs`.
18
+
19
+ ---
20
+
21
+ ## The Dockerfile
22
+
23
+ ```dockerfile filename="Dockerfile"
24
+ # syntax=docker/dockerfile:1
25
+
26
+ # ── Build: full toolchain ────────────────────────────────────────────────────
27
+ FROM node:24-slim AS build
28
+ WORKDIR /app
29
+ COPY package*.json ./
30
+ RUN npm ci
31
+ COPY . .
32
+ # Secrets are injected when the container runs, not while the image builds
33
+ RUN npx exisjs build --skip-env-check
34
+
35
+ # ── Runtime: production dependencies only ────────────────────────────────────
36
+ FROM node:24-slim
37
+ WORKDIR /app
38
+ ENV NODE_ENV=production PORT=3000
39
+ COPY package*.json ./
40
+ RUN npm ci --omit=dev --omit=optional && npm cache clean --force
41
+ COPY --from=build /app/.exis ./.exis
42
+ USER node
43
+ EXPOSE 3000
44
+ HEALTHCHECK --interval=30s --timeout=5s --start-period=10s \
45
+ CMD node -e "fetch('http://127.0.0.1:3000/health').then(r => process.exit(r.ok ? 0 : 1), () => process.exit(1))"
46
+ CMD ["node_modules/.bin/exisjs", "start"]
47
+ ```
48
+
49
+ `exisjs build` writes everything the server needs into `.exis/`: the compiled code, the route manifest, the compiled `exis.config` and `main.js`, the entry that starts the server. The runtime image needs only `.exis/`, `package.json` and the production dependencies; it contains no source files.
50
+
51
+ - **`--omit=optional`** keeps the CLI out of the image. Until 0.11, `exisjs` lists `@exisjs/cli` as an optional dependency so that projects created before 0.10 keep working. If you use the uWebSockets.js engine (`server: 'uws'`), list `uWebSockets.js` in your own `dependencies`, since it is optional too.
52
+ - **`npm ci`** in the build stage installs `devDependencies`, which include `@exisjs/cli` and `typescript`.
53
+
54
+ Add a `.dockerignore`, so local files never reach the image. **`.env` must be in it**, or your local secrets are copied into every image layer:
55
+
56
+ ```text filename=".dockerignore"
57
+ node_modules
58
+ .exis
59
+ dist
60
+ .git
61
+ .env
62
+ .env.*
63
+ !.env.example
64
+ *.log
65
+ coverage
66
+ ```
67
+
68
+ ---
69
+
70
+ ## Secrets: `--skip-env-check`
71
+
72
+ `exisjs build` loads your route files to check them, and a route that imports `tex.env` validates the environment while it loads. In a Docker build the secrets don't exist yet, so a plain `RUN npx exisjs build` fails:
73
+
74
+ ```text
75
+ ✗ BUILD_VALIDATION_FAILED: Validation Error: DATABASE_URL: Expected value, received undefined
76
+ ```
77
+
78
+ `--skip-env-check` skips that check **for the build only**. When the container starts, `tex.env` validates the real environment, and a missing or invalid value stops the server with exit code 1:
79
+
80
+ ```text
81
+ [ExisJS] the routes manifest failed to load, so the server will not start:
82
+ Validation Error: DATABASE_URL: Expected value, received undefined
83
+ ```
84
+
85
+ Pass the secrets when you run the container (`docker run -e DATABASE_URL=...`, or your platform's environment settings). Never set `EXIS_SKIP_ENV_CHECK` in the runtime environment: it is the build flag, and would let the server start with placeholder values.
86
+
87
+ ---
88
+
89
+ ## One process, graceful shutdown
90
+
91
+ `exisjs start` comes with the `exisjs` runtime, so the image needs no CLI, and it runs the server in its own process: Node is PID 1 in the container and receives `SIGTERM` directly. (`node .exis/server/main.js`, written by `exisjs build`, does the same.)
92
+
93
+ In the `CMD`, call the binary itself rather than `npm start`: with npm in between, a redeploy's `SIGTERM` shows up as `npm error signal SIGTERM`, and some platforms stop the container early when they detach its input. `npm start` with `"start": "exisjs start"` works too, for platforms that only run npm scripts.
94
+
95
+ On `docker stop`:
96
+
97
+ 1. The server stops accepting new connections, and the readiness probe (`/_ready`, if enabled) answers `503`.
98
+ 2. Requests in progress finish.
99
+ 3. `onClose` hooks run and registered databases disconnect.
100
+ 4. The process exits with code 0.
101
+
102
+ ExisJS waits up to 10 seconds for this, and Docker also waits 10 seconds by default before it kills the container. If your requests can take longer, raise both: `docker stop -t 60` / `stop_grace_period: 60s` in Compose, and the platform's equivalent.
103
+
104
+ With `cluster: { workers }` set, that process is the cluster primary and forks the workers itself.
105
+
106
+ ---
107
+
108
+ ## Health checks
109
+
110
+ The project template has a `GET /health` route, which the `HEALTHCHECK` above calls. `node:24-slim` has no `curl`, so the check uses Node's `fetch`.
111
+
112
+ For a load balancer or Kubernetes, turn on the built-in probes instead:
113
+
114
+ ```typescript filename="exis.config.ts"
115
+ export default defineConfig({
116
+ healthcheck: { enabled: true }, // GET /_health (liveness) and GET /_ready (readiness)
117
+ })
118
+ ```
119
+
120
+ Point the load balancer, or the Kubernetes `readinessProbe`, at `/_ready`: it answers `503` while a registered database is down and during shutdown. Use `/_health` only to decide whether to restart the container.
121
+
122
+ ---
123
+
124
+ ## Database migrations and scripts
125
+
126
+ The runtime image has no source files and no CLI, so run one-off tasks from the build stage, which has the whole project and toolchain:
127
+
128
+ ```sh
129
+ docker build --target build -t my-api:build .
130
+ docker run --rm -e DATABASE_URL="$DATABASE_URL" my-api:build npx exisjs run scripts/migrate.ts
131
+ ```
132
+
133
+ Run it as a separate step of your deployment, before the new version starts.
134
+
135
+ ---
136
+
137
+ ## Projects created before 0.10
138
+
139
+ Run `npx exisjs migrate` once. It adds `@exisjs/cli` to `devDependencies` and lists the Dockerfile lines to change (`--omit=optional`, and a `CMD` that goes through `npm start`). `"start": "exisjs start"` stays as it is: it now runs the server in its own process, without the CLI.
140
+
141
+ ---
142
+
143
+ ## Platform notes
144
+
145
+ - **Pin the Node.js version.** Use an explicit image (`node:24-slim`). Builders that pick Node for you, such as Nixpacks, may default to an older version than your dependencies need; set it explicitly (for Nixpacks, `nodejs_22` or later in `nixpacks.toml`).
146
+ - **Builds on the host.** Platforms that build without a Dockerfile must install `devDependencies` for the build (`npm install --include=dev`), because `exisjs build` comes from `@exisjs/cli`.
147
+ - **Start command.** On platforms that ask for a start command instead of a Dockerfile `CMD`, enter `npx exisjs start` or `npm start`.
148
+ - **Long requests behind a CDN.** A proxy such as Cloudflare ends requests after about 100 seconds, whatever the server allows. Serve long-running endpoints from a hostname that is not proxied.
149
+
150
+ ---
151
+
152
+ ## Image size
153
+
154
+ Measured with an app created by `npm create exisjs`, on `node:24-slim`:
155
+
156
+ | | Before 0.10 | 0.10 |
157
+ | :--- | ---: | ---: |
158
+ | Production `node_modules` | 45 MB | 8 MB |
159
+ | Build tooling in it (`typescript`, `esbuild`, `tsx`, the CLI) | 34 MB | none |
160
+ | Image | 274 MB | 237 MB |
161
+ | Node processes in the container | 2 | 1 |
162
+
163
+ Most of the remaining image is the `node:24-slim` base. The production install is checked in CI on every change, against a size budget that fails if build tooling returns.
@@ -139,7 +139,7 @@ To install ExisJS into an existing repository without scaffolding:
139
139
 
140
140
  ```bash
141
141
  npm install exisjs
142
- npm install -D typescript @types/node prettier
142
+ npm install -D @exisjs/cli typescript @types/node prettier
143
143
  ```
144
144
 
145
145
  ### Step 2: Configure `tsconfig.json`
@@ -224,8 +224,11 @@ Install the framework into an existing Node.js project:
224
224
 
225
225
  ```bash
226
226
  npm install exisjs
227
+ npm install -D @exisjs/cli typescript
227
228
  ```
228
229
 
230
+ `exisjs` is the runtime your server needs in production; `@exisjs/cli` is the `exisjs` command (dev server, build, tests), a development tool.
231
+
229
232
  Create an application configuration file:
230
233
 
231
234
  ```typescript filename="exis.config.ts"
@@ -63,7 +63,7 @@ ExisJS provides type-safe primitives that accept modifier options and configurat
63
63
  | `tex.record()` | `tex.record(valueSchema, options?)` | Validates dynamic key-value dictionaries (`Record<string, T>`). |
64
64
  | `tex.any()` | `tex.any(options?)` | Pass-through validator without schema constraints. |
65
65
  | `tex.file()` | `tex.file(options?)` | Validates multipart file uploads. Supports `{ maxSize, mimeTypes }`. |
66
- | `tex.object()` | `tex.object(shape, options?)` | Compiles an object schema. Supports `{ strict: true }` to reject unlisted keys. |
66
+ | `tex.object()` | `tex.object(shape, options?)` | Compiles an object schema. Supports `{ strict, optional, nullable, nullish }`: `strict: true` rejects unlisted keys; the others work as for fields when the object is nested. An unknown option throws. |
67
67
  | `tex.coerce.*` | `tex.coerce.number() \| boolean() \| date() \| string()` | Explicit coercion namespace for query strings, route parameters, and form inputs. |
68
68
  | `tex.pagination()` | `tex.pagination(options?)` | Predefined schema for `page`, `limit`, `sort`, and `order` query parameters. |
69
69
  | `tex.env()` | `tex.env(shape, options?)` | Environment variable schema parser with automatic type coercion from string values. |
@@ -172,6 +172,7 @@ The root configuration schema accepted by `exis.config.ts`:
172
172
  | `host` | `string` | `'0.0.0.0'` | Network interface binding. |
173
173
  | `server` | `'auto' \| 'node' \| 'bun' \| 'uws'` | `'auto'` | HTTP server backend. Automatically selects Bun or Node when detected. |
174
174
  | `cluster` | `{ workers?: number \| 'auto' \| 'safe' \| 'max' }` | `{ workers: 1 }` | Multi-process worker clustering. `'safe'` uses available CPU cores minus 1; `'max'` uses all available cores. |
175
+ | `queue` | `{ driver?: 'memory', maxConcurrent?, maxQueue?, timeoutMs? }` | not set | Limits concurrent requests per process; extra requests wait, then get `503`. Unknown keys or another driver stop the start. |
175
176
  | `trustProxy` | `boolean \| number` | `false` | `true`: trust all proxy headers (`X-Forwarded-For`, `CF-Connecting-IP`, `True-Client-IP`, `X-Real-IP`). `N`: trust only the N closest hops in `X-Forwarded-For`, counting the socket peer; CDN headers are ignored. |
176
177
  | `bodyLimit` | `number` | `10485760` (10MB) | Maximum payload size in bytes for JSON and URL-encoded request bodies. |
177
178
  | `compression` | `boolean` | `false` | Enables gzip and Brotli response compression. |
@@ -195,7 +196,7 @@ The root configuration schema accepted by `exis.config.ts`:
195
196
  | Property | Type | Default | Description |
196
197
  | :--- | :--- | :--- | :--- |
197
198
  | `telemetry` | `boolean \| TelemetryConfig` | `{ enabled: false, exporter: 'console' }` | OpenTelemetry tracing and span reporting (`'otlp'` or `'console'`). |
198
- | `metrics` | `boolean \| MetricsConfig` | `{ enabled: false, path: '/metrics' }` | Prometheus-compatible metrics endpoint. |
199
+ | `metrics` | `boolean \| MetricsConfig` | `{ enabled: false, path: '/metrics' }` | Prometheus text-format endpoint: request counts and duration histograms by route pattern, in-flight requests, memory and event-loop lag; aggregated across cluster workers. |
199
200
  | `healthcheck` | `boolean \| HealthCheckConfig` | `{ enabled: false, path: '/_health' }` | Liveness and readiness health probe route. |
200
201
  | `docs` | `boolean \| SwaggerConfig` | `{ enabled: false, path: '/docs' }` | Interactive OpenAPI / Swagger UI documentation generation. |
201
202
 
@@ -39,6 +39,8 @@ import type {
39
39
  TexFileOptions,
40
40
  TexPasswordOptions,
41
41
  TexObjectOptions,
42
+ TexUrlOptions,
43
+ SafeParseResult,
42
44
  ValidationErrorDescriptor,
43
45
  PaginationMeta,
44
46
  PaginatedResult,
@@ -93,6 +95,8 @@ The `tex.coerce` namespace provides explicit coercion primitives for query param
93
95
 
94
96
  Validates an object against a structured field schema.
95
97
 
98
+ Options: `strict` (reject keys not in the schema), and `optional`, `nullable`, `nullish` for an object used as a field (the same as calling `.optional()`, `.nullable()` or `.nullish()`). Any other option throws, so a misspelled option in plain JavaScript is not silently ignored.
99
+
96
100
  ```typescript
97
101
  const UserSchema = tex.object({
98
102
  id: tex.string(),
@@ -0,0 +1,16 @@
1
+ export { loadConfig } from './config/config';
2
+ export { loadEnv, parseEnv } from './config/env';
3
+ export { App, setActiveAppInstance } from './server/app';
4
+ export { RouteScanner, routeParadigm, mixedParadigmMessage, } from './router/route-scanner';
5
+ export { describeAccess } from './router/authorize';
6
+ export { formatCliError, formatDevError } from './error/overlay';
7
+ export { registerPathAliasLoader, resolvePathAliases, } from './lib/resolve-aliases';
8
+ export { getFormattedTime } from './utils/time';
9
+ export { startBuiltServer, type StartOptions } from './lib/start-command';
10
+ /** The production server entry (`exisjs/start`) */
11
+ export declare const START_SERVER_PATH: string;
12
+ /** The `node:test` reporter used by `exisjs test` */
13
+ export declare const TEST_REPORTER_PATH: string;
14
+ /** The installed runtime version, which the CLI must match */
15
+ export declare const RUNTIME_VERSION: string;
16
+ //# sourceMappingURL=internal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,EAAE,GAAG,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,EACL,YAAY,EACZ,aAAa,EACb,oBAAoB,GACrB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAChE,OAAO,EACL,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,gBAAgB,EAAE,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAEzE,mDAAmD;AACnD,eAAO,MAAM,iBAAiB,QAAiD,CAAA;AAE/E,qDAAqD;AACrD,eAAO,MAAM,kBAAkB,QAI9B,CAAA;AAED,8DAA8D;AAE9D,eAAO,MAAM,eAAe,EAAE,MAA2C,CAAA"}
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.RUNTIME_VERSION = exports.TEST_REPORTER_PATH = exports.START_SERVER_PATH = exports.startBuiltServer = exports.getFormattedTime = exports.resolvePathAliases = exports.registerPathAliasLoader = exports.formatDevError = exports.formatCliError = exports.describeAccess = exports.mixedParadigmMessage = exports.routeParadigm = exports.RouteScanner = exports.setActiveAppInstance = exports.App = exports.parseEnv = exports.loadEnv = exports.loadConfig = void 0;
7
+ /**
8
+ * Runtime pieces used by `@exisjs/cli` (`exisjs/internal`).
9
+ *
10
+ * Not part of the public API: names and signatures may change in any
11
+ * release. The CLI is versioned together with this package.
12
+ */
13
+ const node_path_1 = __importDefault(require("node:path"));
14
+ var config_1 = require("./config/config");
15
+ Object.defineProperty(exports, "loadConfig", { enumerable: true, get: function () { return config_1.loadConfig; } });
16
+ var env_1 = require("./config/env");
17
+ Object.defineProperty(exports, "loadEnv", { enumerable: true, get: function () { return env_1.loadEnv; } });
18
+ Object.defineProperty(exports, "parseEnv", { enumerable: true, get: function () { return env_1.parseEnv; } });
19
+ var app_1 = require("./server/app");
20
+ Object.defineProperty(exports, "App", { enumerable: true, get: function () { return app_1.App; } });
21
+ Object.defineProperty(exports, "setActiveAppInstance", { enumerable: true, get: function () { return app_1.setActiveAppInstance; } });
22
+ var route_scanner_1 = require("./router/route-scanner");
23
+ Object.defineProperty(exports, "RouteScanner", { enumerable: true, get: function () { return route_scanner_1.RouteScanner; } });
24
+ Object.defineProperty(exports, "routeParadigm", { enumerable: true, get: function () { return route_scanner_1.routeParadigm; } });
25
+ Object.defineProperty(exports, "mixedParadigmMessage", { enumerable: true, get: function () { return route_scanner_1.mixedParadigmMessage; } });
26
+ var authorize_1 = require("./router/authorize");
27
+ Object.defineProperty(exports, "describeAccess", { enumerable: true, get: function () { return authorize_1.describeAccess; } });
28
+ var overlay_1 = require("./error/overlay");
29
+ Object.defineProperty(exports, "formatCliError", { enumerable: true, get: function () { return overlay_1.formatCliError; } });
30
+ Object.defineProperty(exports, "formatDevError", { enumerable: true, get: function () { return overlay_1.formatDevError; } });
31
+ var resolve_aliases_1 = require("./lib/resolve-aliases");
32
+ Object.defineProperty(exports, "registerPathAliasLoader", { enumerable: true, get: function () { return resolve_aliases_1.registerPathAliasLoader; } });
33
+ Object.defineProperty(exports, "resolvePathAliases", { enumerable: true, get: function () { return resolve_aliases_1.resolvePathAliases; } });
34
+ var time_1 = require("./utils/time");
35
+ Object.defineProperty(exports, "getFormattedTime", { enumerable: true, get: function () { return time_1.getFormattedTime; } });
36
+ var start_command_1 = require("./lib/start-command");
37
+ Object.defineProperty(exports, "startBuiltServer", { enumerable: true, get: function () { return start_command_1.startBuiltServer; } });
38
+ /** The production server entry (`exisjs/start`) */
39
+ exports.START_SERVER_PATH = node_path_1.default.join(__dirname, 'lib', 'start-server.js');
40
+ /** The `node:test` reporter used by `exisjs test` */
41
+ exports.TEST_REPORTER_PATH = node_path_1.default.join(__dirname, 'testing', 'reporter.mjs');
42
+ /** The installed runtime version, which the CLI must match */
43
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
44
+ exports.RUNTIME_VERSION = require('../package.json').version;
45
+ //# sourceMappingURL=internal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal.js","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":";;;;;;AAAA;;;;;GAKG;AACH,0DAA4B;AAE5B,0CAA4C;AAAnC,oGAAA,UAAU,OAAA;AACnB,oCAAgD;AAAvC,8FAAA,OAAO,OAAA;AAAE,+FAAA,QAAQ,OAAA;AAC1B,oCAAwD;AAA/C,0FAAA,GAAG,OAAA;AAAE,2GAAA,oBAAoB,OAAA;AAClC,wDAI+B;AAH7B,6GAAA,YAAY,OAAA;AACZ,8GAAA,aAAa,OAAA;AACb,qHAAA,oBAAoB,OAAA;AAEtB,gDAAmD;AAA1C,2GAAA,cAAc,OAAA;AACvB,2CAAgE;AAAvD,yGAAA,cAAc,OAAA;AAAE,yGAAA,cAAc,OAAA;AACvC,yDAG8B;AAF5B,0HAAA,uBAAuB,OAAA;AACvB,qHAAA,kBAAkB,OAAA;AAEpB,qCAA+C;AAAtC,wGAAA,gBAAgB,OAAA;AACzB,qDAAyE;AAAhE,iHAAA,gBAAgB,OAAA;AAEzB,mDAAmD;AACtC,QAAA,iBAAiB,GAAG,mBAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,iBAAiB,CAAC,CAAA;AAE/E,qDAAqD;AACxC,QAAA,kBAAkB,GAAG,mBAAI,CAAC,IAAI,CACzC,SAAS,EACT,SAAS,EACT,cAAc,CACf,CAAA;AAED,8DAA8D;AAC9D,iEAAiE;AACpD,QAAA,eAAe,GAAW,OAAO,CAAC,iBAAiB,CAAC,CAAC,OAAO,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-aliases.d.ts","sourceRoot":"","sources":["../../src/cli/resolve-aliases.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAA;IACd,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,EAAE,CAyDxD;AAMD,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CA+BzD;AAiKD;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CA8CjB"}
1
+ {"version":3,"file":"resolve-aliases.d.ts","sourceRoot":"","sources":["../../src/lib/resolve-aliases.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAA;IACd,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,EAAE,CAyDxD;AAMD,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CA+BzD;AAiKD;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CA8CjB"}