@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 +58 -25
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +17 -6
- package/dist/index.mjs +1 -1
- package/dist/{main-DUyElIVZ.mjs → main-CLoS12u4.mjs} +452 -75
- package/dist/main-CLoS12u4.mjs.map +1 -0
- package/package.json +7 -7
- package/src/commands/dev.ts +23 -6
- package/src/commands/generate.ts +36 -27
- package/src/commands/new.ts +41 -8
- package/src/commands/start.ts +7 -2
- package/src/dev/supervisor.ts +38 -14
- package/src/scaffold/options.ts +37 -5
- package/src/scaffold/templates.ts +379 -24
- package/src/scaffold/versions.ts +2 -0
- package/dist/main-DUyElIVZ.mjs.map +0 -1
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
|
|
67
|
-
znight new my-
|
|
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
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
|
77
|
-
|
|
|
78
|
-
|
|
|
79
|
-
|
|
|
80
|
-
| `--
|
|
81
|
-
| `--
|
|
82
|
-
| `--
|
|
83
|
-
| `--
|
|
84
|
-
| `--
|
|
85
|
-
| `--
|
|
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
|
-
- `
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
-
|
|
134
|
-
`
|
|
135
|
-
|
|
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
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
|
|
514
|
-
*
|
|
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
|
-
/**
|
|
523
|
-
|
|
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-
|
|
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";
|