@znight/cli 0.6.2 → 0.6.3

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/README.md CHANGED
@@ -63,26 +63,30 @@ writes its committed `openapi.json` with `znight openapi` and checks it with `--
63
63
  ```sh
64
64
  znight new my-service # asks the questions below
65
65
  znight new my-service --yes # defaults, no question
66
- znight new my-service --pm pnpm --adapter fastify --features config,observability,messaging
67
- znight new my-worker --yes --features config,schedule,openapi
66
+ znight new my-service --pm pnpm --adapter hono --features config,observability,messaging
67
+ znight new my-api --yes --features config,observability,openapi,graphql,websocket --openapi-ui swagger
68
+ znight new my-worker --yes --features config,schedule,openapi --no-docker
68
69
  znight new . --yes --no-install # in the current (empty) directory
69
70
  ```
70
71
 
71
- In a terminal, the CLI asks for the name, the package manager, the HTTP adapter, the features,
72
- and whether to install the dependencies and initialise git. Flags answer the questions up front; with
73
- `--yes` (or without a terminal, e.g. in CI) the defaults are used.
74
-
75
- | Option | Default | Description |
76
- | ------------------------------------------ | --------------------------------------------- | -------------------------------------------------------------------------------- |
77
- | `[name]` | (asked) | npm package name (`my-service`, `@acme/api`), or `.` |
78
- | `-y, --yes` | `false` | Do not ask questions |
79
- | `--pm <bun\|npm\|pnpm\|yarn>` | the one running the CLI, else bun on Bun, npm | Package manager |
80
- | `--adapter <node\|fastify\|express\|hono>` | `node` | HTTP adapter (`node`: the built-in `node:http` server) |
81
- | `--features <list>` | `config,observability` | `config`, `observability`, `messaging`, `schedule`, `openapi`, or `all` / `none` |
82
- | `--no-install` | install | Do not install the dependencies |
83
- | `--no-git` | init | Do not run `git init` (skipped anyway inside a git repository) |
84
- | `--dir <path>` | `./<name>` (unscoped) | Target directory |
85
- | `--force` | `false` | Write into a non-empty directory (existing files are overwritten) |
72
+ In a terminal, the CLI asks for the name, the package manager, the HTTP adapter (Fastify first, and
73
+ the default), the features, the OpenAPI reference UI (when `openapi` is selected), whether to add a
74
+ Dockerfile, and whether to install the dependencies and initialise git. Flags answer the questions up
75
+ front; with `--yes` (or without a terminal, e.g. in CI) the defaults are used.
76
+
77
+ | Option | Default | Description |
78
+ | ------------------------------------------ | --------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
79
+ | `[name]` | (asked) | npm package name (`my-service`, `@acme/api`), or `.` |
80
+ | `-y, --yes` | `false` | Do not ask questions |
81
+ | `--pm <bun\|npm\|pnpm\|yarn>` | the one running the CLI, else bun on Bun, npm | Package manager |
82
+ | `--adapter <fastify\|node\|express\|hono>` | `fastify` | HTTP adapter (`node`: the built-in `node:http` server) |
83
+ | `--features <list>` | `config,observability` | `config`, `observability`, `messaging`, `schedule`, `openapi`, `graphql`, `websocket`, or `all` / `none` |
84
+ | `--openapi-ui <scalar\|swagger>` | `scalar` | API reference UI served at `/docs` by the `openapi` feature (Scalar or Swagger UI) |
85
+ | `--no-docker` | Dockerfile | Do not generate the `Dockerfile` and `.dockerignore` |
86
+ | `--no-install` | install | Do not install the dependencies |
87
+ | `--no-git` | init | Do not run `git init` (skipped anyway inside a git repository) |
88
+ | `--dir <path>` | `./<name>` (unscoped) | Target directory |
89
+ | `--force` | `false` | Write into a non-empty directory (existing files are overwritten) |
86
90
 
87
91
  The package manager defaults to the one that launched the CLI (`npx`, `pnpm dlx`, `yarn dlx`,
88
92
  `bunx`). The target directory must be empty (`.git`, `.DS_Store` and editor folders are fine).
@@ -100,17 +104,23 @@ my-service/
100
104
  │ ├─ greeting.service.ts # @Injectable, uses AppConfig and Logger
101
105
  │ ├─ greeting.controller.ts # GET /greetings/:name?excited, POST /greetings (validated body)
102
106
  │ ├─ greeting.consumer.ts # @Consumer('greetings'), POST /greetings/async (messaging)
107
+ │ ├─ greeting.gateway.ts # @Gateway('/ws'): a "greet" WebSocket event (websocket)
108
+ │ ├─ greeting.resolver.ts # @Resolver: query { greeting(name) } (graphql)
103
109
  │ ├─ health.controller.ts # GET /health
104
110
  │ └─ heartbeat.jobs.ts # @Cron('* * * * *'): a job every minute (schedule)
105
111
  ├─ test/
106
112
  │ ├─ greeting.service.test.ts # TestBed: real factory, auto-mocked dependencies
107
113
  │ ├─ greeting.controller.test.ts # TestApp: in-memory HTTP requests
114
+ │ ├─ greeting.gateway.test.ts # TestApp.connect(): in-memory WebSocket (websocket)
115
+ │ ├─ greeting.resolver.test.ts # executeOperation(): GraphQL over HTTP (graphql)
108
116
  │ └─ heartbeat.jobs.test.ts # TestApp + createTestClock(): virtual time (schedule)
109
117
  ├─ vite.config.ts # plugins: [znight(options)]
110
118
  ├─ znight.config.ts # compiler options, shared by znight(), the Bun preload and znight generate
111
119
  ├─ tsconfig.json # strict, experimentalDecorators, moduleResolution bundler, noEmit
112
120
  ├─ bunfig.toml # bun only: preloads @znight/compiler/bun before the tests
113
121
  ├─ package.json # type module; scripts dev, build, start, generate, typecheck, test
122
+ ├─ Dockerfile # multi-stage production image (docker)
123
+ ├─ .dockerignore
114
124
  └─ .gitignore # node_modules, dist, .znight
115
125
  ```
116
126
 
@@ -127,12 +137,32 @@ my-service/
127
137
  - `schedule` adds `@znight/schedule`, `SchedulePlugin.configure()` **before** `HttpPlugin` (plugins
128
138
  stop in reverse order: HTTP stops taking requests first, then running jobs drain), a sample job
129
139
  and its test on a virtual clock (`createTestClock()` of `@znight/schedule/testing`).
130
- - `openapi` adds `@znight/openapi`, `OpenApiPlugin.configure()` after `HttpPlugin` (`/openapi.json`
131
- and the API reference at `/docs`), `src/api.ts` (`@OpenApiDocument`) and the `openapi` /
132
- `openapi:check` scripts (commit `openapi.json`, check it in CI).
133
- - The `TestApp` test configures `ObservabilityPlugin` with `metrics: { server: false }`: with
134
- `prom-client` installed, the metrics server (`:9464`) would collide with `znight dev` or with other
135
- test files running in parallel.
140
+ - `observability` adds `@znight/observability` and `ObservabilityPlugin.configure()` first, its
141
+ logger named after the project (`logging: { name: '<name>' }`), with the `metrics` and `tracing`
142
+ options as commented-out placeholders.
143
+ - `openapi` adds `@znight/openapi`, `OpenApiPlugin.configure({ ui })` after `HttpPlugin`
144
+ (`/openapi.json` and the API reference at `/docs`, `ui: 'scalar'` or `'swagger'` from
145
+ `--openapi-ui`), `src/api.ts` (`@OpenApiDocument`) and the `openapi` / `openapi:check` scripts
146
+ (commit `openapi.json`, check it in CI).
147
+ - `graphql` adds `@znight/graphql` and `graphql`, `GraphQLPlugin.configure()` after `HttpPlugin`
148
+ (`POST /graphql`, GraphiQL on `GET /graphql` in development), a code-first resolver
149
+ (`src/app/greeting.resolver.ts`: the schema is derived from its types) and its test
150
+ (`executeOperation()` of `@znight/graphql/testing`).
151
+ - `websocket` adds `@znight/websocket` and `ws` (the transport of the `node:http` based servers; Bun
152
+ provides its own), `WebSocketPlugin.configure()` after `HttpPlugin`, a gateway on `/ws`
153
+ (`src/app/greeting.gateway.ts`, a validated `greet` event with a reply) and its test
154
+ (`TestApp.connect()`).
155
+ - The `TestApp` tests configure `ObservabilityPlugin` with `metrics: false`: with `prom-client`
156
+ installed, the metrics server (`:9464`) would collide with `znight dev` or with other test files
157
+ running in parallel, and any metrics option object requires `prom-client`.
158
+ - The `Dockerfile` (unless `--no-docker`) is multi-stage: a `deps` stage installs the production
159
+ dependencies only from the lockfile, a `build` stage installs everything and runs the build (the
160
+ compiler runs there), and the runtime stage (`node:24-slim`, or `oven/bun:1-slim` for Bun projects)
161
+ copies `dist/` and the production `node_modules`, sets `NODE_ENV=production`, runs as the image's
162
+ non-root user, exposes port 3000, probes `GET /health` in its `HEALTHCHECK` and starts the bundle in
163
+ exec form (`node --enable-source-maps dist/main.js`, `bun --no-env-file dist/main.js`). Installs are
164
+ frozen, so the lockfile must exist (install the dependencies first); pnpm and yarn come from
165
+ Corepack. `.dockerignore` leaves out `node_modules`, `dist`, `.znight`, `.env` files and `.git`.
136
166
 
137
167
  ## `znight generate`
138
168
 
@@ -283,7 +313,8 @@ restart is fast and always consistent.
283
313
  5. `Ctrl+C` (or `SIGTERM`, `SIGHUP` when the terminal is closed, `Ctrl+\` / `SIGQUIT`) → the
284
314
  watcher closes and the application stops gracefully (`SIGINT` after `Ctrl+C`, `SIGTERM` otherwise);
285
315
  a second signal kills it. The application runs in its own session and process group, so it
286
- receives exactly one signal, and never the terminal's.
316
+ receives exactly one signal, and never the terminal's. On Windows it shares the console, which
317
+ delivers `Ctrl+C` to it: the CLI waits for it to stop (`SIGKILL` after `--kill-timeout`).
287
318
  6. The CLI dies without stopping it (`kill -9`, the OOM killer) → the application stops by itself
288
319
  (`SIGTERM`, then `SIGKILL` after `--kill-timeout`) within half a second instead of keeping its
289
320
  port: the CLI preloads a small guard into it (`--import` on Node.js, `--preload` on Bun) that
@@ -370,7 +401,9 @@ Runs the production build with `NODE_ENV=production` (unless set). On Linux and
370
401
  **replaces itself** with the runtime (`execve`): same PID, signals and exit code go straight to the
371
402
  application, which makes `znight start` a good container entry point. Elsewhere the application runs
372
403
  as a child process: `SIGINT`, `SIGTERM` and `SIGHUP` are forwarded and its exit code is returned
373
- (`128 + n` when it is killed by a signal).
404
+ (`128 + n` when it is killed by a signal). On Windows, `Ctrl+C` and the console closing are not
405
+ forwarded: the application shares the console and receives them itself, while forwarding would
406
+ terminate it at once (Windows has no graceful `kill()`).
374
407
 
375
408
  | Option | Default | Description |
376
409
  | ----------------------------- | ------------------------------- | ----------------------------------------------- |
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { n as main } from "./main-DUyElIVZ.mjs";
2
+ import { n as main } from "./main-CLoS12u4.mjs";
3
3
  // src/cli.ts
4
4
  /**
5
5
  * The `znight` binary. Everything lives in `main()`; this file only wires the process: arguments,
package/dist/index.d.mts CHANGED
@@ -510,8 +510,9 @@ export declare class AppSupervisor {
510
510
  /** Restarts after `debounceMs`; calls in between postpone it. */
511
511
  scheduleRestart(): void;
512
512
  /**
513
- * Cancels a restart scheduled by {@link scheduleRestart} and not started yet (the output it would
514
- * run turned out to be broken, e.g. a failed compilation). Returns whether one was pending.
513
+ * Cancels the restarts that did not start their process yet (the output they would run turned out
514
+ * to be broken, e.g. a failed compilation): scheduled, queued, or stopping the previous process
515
+ * (which still stops). Returns whether one was pending.
515
516
  */
516
517
  cancelRestart(): boolean;
517
518
  /**
@@ -519,8 +520,12 @@ export declare class AppSupervisor {
519
520
  * requested while another one is waiting to run is merged with it.
520
521
  */
521
522
  restart(): Promise<void>;
522
- /** Stops the current process with `signal` (SIGKILL after the timeout) and refuses new starts. */
523
- stop(signal?: NodeJS.Signals): Promise<void>;
523
+ /**
524
+ * Stops the current process with `signal` (SIGKILL after the timeout) and refuses new starts.
525
+ * `null`: the process already received the signal (a console Ctrl+C on Windows, where `kill()` is
526
+ * a forced termination): it is only waited for, then SIGKILLed after the timeout.
527
+ */
528
+ stop(signal?: NodeJS.Signals | null): Promise<void>;
524
529
  /** Immediately SIGKILLs every process (a second Ctrl+C). */
525
530
  kill(): void;
526
531
  }
@@ -530,10 +535,12 @@ type PackageManager = "bun" | "npm" | "pnpm" | "yarn";
530
535
  /** HTTP adapters of `@znight/http`. */
531
536
  type HttpAdapterName = "node" | "fastify" | "express" | "hono";
532
537
  /** Optional features of a new project. */
533
- type Feature = "config" | "observability" | "messaging" | "schedule" | "openapi";
538
+ type Feature = "config" | "observability" | "messaging" | "schedule" | "openapi" | "graphql" | "websocket";
539
+ /** API reference UIs of `@znight/openapi` (its `ui` option). */
540
+ type OpenApiUiName = "scalar" | "swagger";
534
541
  /** Every package manager, in display order. */
535
542
  export declare const PACKAGE_MANAGERS: readonly PackageManager[];
536
- /** Every HTTP adapter, in display order. */
543
+ /** Every HTTP adapter, in display order (the default first). */
537
544
  export declare const HTTP_ADAPTERS: readonly HttpAdapterName[];
538
545
  /** Every feature, in display (and canonical) order. */
539
546
  export declare const FEATURES: readonly Feature[];
@@ -547,6 +554,10 @@ interface ProjectOptions {
547
554
  readonly adapter: HttpAdapterName;
548
555
  /** Selected features, in canonical order. */
549
556
  readonly features: readonly Feature[];
557
+ /** API reference UI served at `/docs` with the `openapi` feature. Default: `'scalar'`. */
558
+ readonly openapiUi?: OpenApiUiName;
559
+ /** Generate a multi-stage `Dockerfile` and a `.dockerignore`. Default: `true`. */
560
+ readonly docker?: boolean;
550
561
  /** Version range base of the `@znight/*` packages (the CLI version). */
551
562
  readonly znightVersion: string;
552
563
  }
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- export { d as AppSupervisor, t as COMMANDS, _ as CancelledError, v as CliError, s as DEFAULT_FEATURES, y as ExitCode, c as FEATURES, l as HTTP_ADAPTERS, u as PACKAGE_MANAGERS, r as SCHEMATICS, b as UsageError, m as adaptCompilerModule, p as cliVersion, f as createContext, g as defineCommand, i as findSchematic, h as loadCompiler, n as main, a as planSchematic, o as renderProject } from "./main-DUyElIVZ.mjs";
1
+ export { d as AppSupervisor, t as COMMANDS, _ as CancelledError, v as CliError, s as DEFAULT_FEATURES, y as ExitCode, c as FEATURES, l as HTTP_ADAPTERS, u as PACKAGE_MANAGERS, r as SCHEMATICS, b as UsageError, m as adaptCompilerModule, p as cliVersion, f as createContext, g as defineCommand, i as findSchematic, h as loadCompiler, n as main, a as planSchematic, o as renderProject } from "./main-CLoS12u4.mjs";