@znight/cli 0.6.5 → 0.7.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/README.md CHANGED
@@ -70,8 +70,9 @@ znight new . --yes --no-install # in the current (empty) directory
70
70
  ```
71
71
 
72
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
73
+ the default), the features (`config` and `observability` preselected), the OpenAPI reference UI
74
+ (Scalar, Swagger UI or no UI, when `openapi` is selected), whether to add a Dockerfile, and whether
75
+ to install the dependencies and initialise git. Flags answer the questions up
75
76
  front; with `--yes` (or without a terminal, e.g. in CI) the defaults are used.
76
77
 
77
78
  | Option | Default | Description |
@@ -81,7 +82,7 @@ front; with `--yes` (or without a terminal, e.g. in CI) the defaults are used.
81
82
  | `--pm <bun\|npm\|pnpm\|yarn>` | the one running the CLI, else bun on Bun, npm | Package manager |
82
83
  | `--adapter <fastify\|node\|express\|hono>` | `fastify` | HTTP adapter (`node`: the built-in `node:http` server) |
83
84
  | `--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
+ | `--openapi-ui <scalar\|swagger\|none>` | `scalar` | API reference UI served at `/docs` by the `openapi` feature (Scalar, Swagger UI, or `none`) |
85
86
  | `--no-docker` | Dockerfile | Do not generate the `Dockerfile` and `.dockerignore` |
86
87
  | `--no-install` | install | Do not install the dependencies |
87
88
  | `--no-git` | init | Do not run `git init` (skipped anyway inside a git repository) |
@@ -97,9 +98,9 @@ The package manager defaults to the one that launched the CLI (`npx`, `pnpm dlx`
97
98
  my-service/
98
99
  ├─ src/
99
100
  │ ├─ main.ts # Application.create() with the plugins, then start()
100
- │ ├─ api.ts # @OpenApiDocument: title, tags of openapi.json (openapi)
101
+ │ ├─ openapi.ts # @OpenApiDocument: info of openapi.json (openapi)
101
102
  │ └─ app/
102
- │ ├─ app.config.ts # @Config('app'): PORT, APP_GREETING (config)
103
+ │ ├─ app.config.ts # @Config('app'): PORT, APP_GREETING, NODE_ENV (config)
103
104
  │ ├─ greeting.schemas.ts # Zod schema of the request body
104
105
  │ ├─ greeting.service.ts # @Injectable, uses AppConfig and Logger
105
106
  │ ├─ greeting.controller.ts # GET /greetings/:name?excited, POST /greetings (validated body)
@@ -137,13 +138,33 @@ my-service/
137
138
  - `schedule` adds `@znight/schedule`, `SchedulePlugin.configure()` **before** `HttpPlugin` (plugins
138
139
  stop in reverse order: HTTP stops taking requests first, then running jobs drain), a sample job
139
140
  and its test on a virtual clock (`createTestClock()` of `@znight/schedule/testing`).
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.
141
+ - `observability` adds `@znight/observability`, `pino-pretty` as a dev dependency (it is loaded only
142
+ in development, so the production image does not ship it) and `ObservabilityPlugin.configure()`
143
+ first: its logger is named after the project and pretty-printed in development only, JSON
144
+ otherwise, `metrics: false` and `tracing: false`. With `config`, `AppConfig` gets an `environment`
145
+ property read from `NODE_ENV` and the options are a function of the container:
146
+
147
+ ```ts
148
+ ObservabilityPlugin.configure(container => ({
149
+ logging: {
150
+ name: 'my-service',
151
+ // human-readable logs in development (`znight dev`), JSON logs in production
152
+ pretty: container.get(AppConfig).environment === 'development',
153
+ },
154
+ metrics: false,
155
+ tracing: false,
156
+ }))
157
+ ```
158
+
159
+ Without `config`, the options are an object with `pretty: process.env['NODE_ENV'] ===
160
+ 'development'`. `znight dev` runs the application with `NODE_ENV=development`, `znight start` and
161
+ the `Dockerfile` with `NODE_ENV=production`.
143
162
  - `openapi` adds `@znight/openapi`, `OpenApiPlugin.configure({ ui })` after `HttpPlugin`
144
163
  (`/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).
164
+ `--openapi-ui`; `OpenApiPlugin.configure()` and no `/docs` with `--openapi-ui none`),
165
+ `src/openapi.ts` (`@OpenApiDocument({ info: { title, description, version } })`, the title being
166
+ the project name) and the `openapi` / `openapi:check` scripts (commit `openapi.json`, check it in
167
+ CI).
147
168
  - `graphql` adds `@znight/graphql` and `graphql`, `GraphQLPlugin.configure()` after `HttpPlugin`
148
169
  (`POST /graphql`, GraphiQL on `GET /graphql` in development), a code-first resolver
149
170
  (`src/app/greeting.resolver.ts`: the schema is derived from its types) and its test
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { n as main } from "./main-CLoS12u4.mjs";
2
+ import { n as main } from "./main-D_BXiYBu.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
@@ -1,3 +1,9 @@
1
+ /**
2
+ * `@znight/cli`: the `znight` command (`znight new`, `generate`, `g`, `dev`, `build`, `start`).
3
+ *
4
+ * The programmatic API runs the CLI in-process (`main(['build'])`) and exposes the pure building
5
+ * blocks: project templates, schematics and the restart supervisor of `znight dev`.
6
+ */
1
7
  import { ArgsDef, ParsedArgs } from "citty";
2
8
  import picocolors from "picocolors";
3
9
  import { InlineConfig, Plugin } from "vite";
@@ -536,8 +542,11 @@ type PackageManager = "bun" | "npm" | "pnpm" | "yarn";
536
542
  type HttpAdapterName = "node" | "fastify" | "express" | "hono";
537
543
  /** Optional features of a new project. */
538
544
  type Feature = "config" | "observability" | "messaging" | "schedule" | "openapi" | "graphql" | "websocket";
539
- /** API reference UIs of `@znight/openapi` (its `ui` option). */
540
- type OpenApiUiName = "scalar" | "swagger";
545
+ /**
546
+ * API reference UI of the `openapi` feature: `'scalar'` or `'swagger'` (the `ui` option of
547
+ * `OpenApiPlugin`), or `'none'` (no `ui` option: `/openapi.json` only).
548
+ */
549
+ type OpenApiUiName = "scalar" | "swagger" | "none";
541
550
  /** Every package manager, in display order. */
542
551
  export declare const PACKAGE_MANAGERS: readonly PackageManager[];
543
552
  /** Every HTTP adapter, in display order (the default first). */
@@ -554,7 +563,7 @@ interface ProjectOptions {
554
563
  readonly adapter: HttpAdapterName;
555
564
  /** Selected features, in canonical order. */
556
565
  readonly features: readonly Feature[];
557
- /** API reference UI served at `/docs` with the `openapi` feature. Default: `'scalar'`. */
566
+ /** API reference UI served at `/docs` with the `openapi` feature (`'none'`: no UI). Default: `'scalar'`. */
558
567
  readonly openapiUi?: OpenApiUiName;
559
568
  /** Generate a multi-stage `Dockerfile` and a `.dockerignore`. Default: `true`. */
560
569
  readonly docker?: boolean;
@@ -694,5 +703,4 @@ export declare function main(argv: readonly string[], options?: CliContextOption
694
703
  * Projects created by `znight new` depend on `@znight/*` packages at `^<version>`.
695
704
  */
696
705
  export declare function cliVersion(): string;
697
- export type { AppSupervisorOptions, CheckResultLike, ChildHandle, CliContext, CliContextOptions, CliServices, Command, CommandDefinition, CommandMeta, CommandRunContext, CompileResultLike, CompilerApi, CompilerChanges, CompilerModule, Diagnostic, DiagnosticLocation, ExecveFunction, ExitStatus, Feature, FileWatcher, FormatDiagnosticsOptions, GenerateResultLike, HostRuntime, HttpAdapterName, IncrementalCompiler, OpenApiEmitApi, OpenApiEmitOptionsLike, OpenApiEmitResultLike, OpenApiViteApi, OpenApiVitePluginOptionsLike, OpenApiWarningLike, OutputStream, PackageManager, PlanSchematicOptions, ProcessService, ProjectFile, ProjectOptions, PromptChoice, Prompts, Reporter, RunOptions, RunResult, RuntimeName, RuntimeOption, Schematic, SchematicContext, SchematicName, SchematicNames, SchematicPlan, SignalSource, SpawnOptions, SupervisorEvents, WatchFactory, WatchTarget, ZnightConfigLike, ZnightOptions };
698
- //# sourceMappingURL=index.d.mts.map
706
+ export type { AppSupervisorOptions, CheckResultLike, ChildHandle, CliContext, CliContextOptions, CliServices, Command, CommandDefinition, CommandMeta, CommandRunContext, CompileResultLike, CompilerApi, CompilerChanges, CompilerModule, Diagnostic, DiagnosticLocation, ExecveFunction, ExitStatus, Feature, FileWatcher, FormatDiagnosticsOptions, GenerateResultLike, HostRuntime, HttpAdapterName, IncrementalCompiler, OpenApiEmitApi, OpenApiEmitOptionsLike, OpenApiEmitResultLike, OpenApiViteApi, OpenApiVitePluginOptionsLike, OpenApiWarningLike, OutputStream, PackageManager, PlanSchematicOptions, ProcessService, ProjectFile, ProjectOptions, PromptChoice, Prompts, Reporter, RunOptions, RunResult, RuntimeName, RuntimeOption, Schematic, SchematicContext, SchematicName, SchematicNames, SchematicPlan, SignalSource, SpawnOptions, SupervisorEvents, WatchFactory, WatchTarget, ZnightConfigLike, ZnightOptions };
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-CLoS12u4.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-D_BXiYBu.mjs";
@@ -3,7 +3,7 @@ import { createRequire } from "node:module";
3
3
  import { parseArgs } from "citty";
4
4
  import { stripVTControlCharacters } from "node:util";
5
5
  import picocolors from "picocolors";
6
- import { accessSync, constants, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, statSync, watch, writeFileSync } from "node:fs";
6
+ import { accessSync, constants, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, statSync, watch as watch$1, writeFileSync } from "node:fs";
7
7
  import { basename, delimiter, dirname, isAbsolute, join, normalize, posix, relative, resolve, sep } from "node:path";
8
8
  import { pathToFileURL } from "node:url";
9
9
  import { spawn } from "node:child_process";
@@ -1049,7 +1049,7 @@ const watchFiles = (targets, onChange) => {
1049
1049
  if (!existsSync(target.path)) continue;
1050
1050
  let watcher;
1051
1051
  try {
1052
- watcher = watch(target.path, { recursive: target.recursive }, (_event, filename) => {
1052
+ watcher = watch$1(target.path, { recursive: target.recursive }, (_event, filename) => {
1053
1053
  if (filename === null) {
1054
1054
  onChange(target.path);
1055
1055
  return;
@@ -1928,7 +1928,7 @@ const generateCommand = defineCommand({
1928
1928
  const configLoader = args["config-loader"];
1929
1929
  const options = await compilerOptions(cli, compiler, root, args.config, configLoader);
1930
1930
  if (args.check === true) return check(cli, compiler, options);
1931
- if (args.watch === true) return watch$1(cli, compiler, options);
1931
+ if (args.watch === true) return watch(cli, compiler, options);
1932
1932
  return hasErrors((await generateOnce(cli, compiler, options)).diagnostics) ? 1 : 0;
1933
1933
  }
1934
1934
  });
@@ -2059,7 +2059,7 @@ async function check(cli, compiler, options) {
2059
2059
  cli.reporter.success(`${cli.colors.bold(file)} is up to date ${cli.colors.dim(`(${statsOf(result, performance.now() - started)})`)}`);
2060
2060
  return 0;
2061
2061
  }
2062
- async function watch$1(cli, compiler, options) {
2062
+ async function watch(cli, compiler, options) {
2063
2063
  const root = options.root ?? cli.cwd;
2064
2064
  const realRoot = realPath(root);
2065
2065
  const incremental = compiler.createIncremental(options);
@@ -2151,7 +2151,11 @@ const FEATURES = [
2151
2151
  "websocket"
2152
2152
  ];
2153
2153
  /** Every OpenAPI reference UI, in display order (the default first). */
2154
- const OPENAPI_UIS = ["scalar", "swagger"];
2154
+ const OPENAPI_UIS = [
2155
+ "scalar",
2156
+ "swagger",
2157
+ "none"
2158
+ ];
2155
2159
  /** Features selected when none are given. */
2156
2160
  const DEFAULT_FEATURES = ["config", "observability"];
2157
2161
  /** Labels shown by the prompts and the help. */
@@ -2167,14 +2171,15 @@ const FEATURE_LABELS = {
2167
2171
  observability: "Observability: structured logs, metrics, tracing (@znight/observability)",
2168
2172
  messaging: "Messaging: message consumers and publishing (@znight/messaging)",
2169
2173
  schedule: "Schedule: cron, interval and timeout jobs (@znight/schedule)",
2170
- openapi: "OpenAPI: openapi.json and an API reference at /docs (@znight/openapi)",
2174
+ openapi: "OpenAPI: openapi.json and an optional API reference at /docs (@znight/openapi)",
2171
2175
  graphql: "GraphQL: code-first schema derived from the TypeScript types (@znight/graphql)",
2172
2176
  websocket: "WebSocket: gateways served on the HTTP port (@znight/websocket)"
2173
2177
  };
2174
2178
  /** Labels shown by the prompts. */
2175
2179
  const OPENAPI_UI_LABELS = {
2176
2180
  scalar: "Scalar",
2177
- swagger: "Swagger UI"
2181
+ swagger: "Swagger UI",
2182
+ none: "No UI (openapi.json only)"
2178
2183
  };
2179
2184
  /**
2180
2185
  * Parses `--features` (`config,observability`, `none`, `all`). Returns the features in canonical
@@ -2279,6 +2284,7 @@ const DEPENDENCY_VERSIONS = {
2279
2284
  graphql: "^17.0.2",
2280
2285
  hono: "^4.13.14",
2281
2286
  "light-my-request": "^6.8.0",
2287
+ "pino-pretty": "^13.2.0",
2282
2288
  typescript: "^7.0.0",
2283
2289
  vite: "^8.0.0",
2284
2290
  vitest: "^4.1.0",
@@ -2386,8 +2392,8 @@ function renderProject(options) {
2386
2392
  });
2387
2393
  }
2388
2394
  if (flags.openapi) files.push({
2389
- path: "src/api.ts",
2390
- content: apiDocument(options)
2395
+ path: "src/openapi.ts",
2396
+ content: openApiDocument(flags)
2391
2397
  });
2392
2398
  if (flags.graphql) {
2393
2399
  files.push({
@@ -2468,6 +2474,7 @@ function packageJson(options, flags) {
2468
2474
  };
2469
2475
  if (flags.bun) devDependencies["@types/bun"] = versionOf("@types/bun");
2470
2476
  else devDependencies["vitest"] = versionOf("vitest");
2477
+ if (flags.observability) devDependencies["pino-pretty"] = versionOf("pino-pretty");
2471
2478
  if (flags.adapter === "express") devDependencies["@types/express"] = versionOf("@types/express");
2472
2479
  if (flags.adapter === "node" || flags.adapter === "express") devDependencies["light-my-request"] = versionOf("light-my-request");
2473
2480
  const manifest = {
@@ -2689,7 +2696,26 @@ function mainTs(flags) {
2689
2696
  ].filter((line) => line !== void 0);
2690
2697
  const localImports = ["import { __ZNIGHT_METADATA__ } from './.znight/container.generated.js'", flags.config ? "import { AppConfig } from './app/app.config.js'" : void 0].filter((line) => line !== void 0);
2691
2698
  const plugins = [];
2692
- if (flags.observability) plugins.push(" // first, so that its hooks wrap everything: request logs, metrics (with prom-client), traces", " ObservabilityPlugin.configure({", " logging: {", ` name: ${quote(flags.name)},`, " },", " // metrics: {", " // // options of the metrics registry", " // },", " // tracing: {", " // // options of the tracer", " // },", " }),");
2699
+ if (flags.observability) {
2700
+ const logging = [
2701
+ " logging: {",
2702
+ ` name: ${quote(flags.name)},`,
2703
+ " // human-readable logs in development (`znight dev`), JSON logs in production",
2704
+ flags.config ? " pretty: container.get(AppConfig).environment === 'development'," : " pretty: process.env['NODE_ENV'] === 'development',",
2705
+ " },",
2706
+ " metrics: false,",
2707
+ " tracing: false,"
2708
+ ];
2709
+ plugins.push(" // first, so that its hooks wrap everything; metrics (with prom-client) and tracing are off", ...flags.config ? [
2710
+ " ObservabilityPlugin.configure(container => ({",
2711
+ ...logging,
2712
+ " })),"
2713
+ ] : [
2714
+ " ObservabilityPlugin.configure({",
2715
+ ...logging,
2716
+ " }),"
2717
+ ]);
2718
+ }
2693
2719
  if (flags.config) plugins.push(" // loads .env files and the environment, validates every @Config class before anything starts", " ConfigPlugin.configure(),");
2694
2720
  if (flags.messaging) plugins.push(" // in-memory broker for development: use rabbitmq(), sqs() or kafka() in production", " MessagingPlugin.configure({ driver: memory() }),");
2695
2721
  if (flags.schedule) plugins.push(" // before HttpPlugin: plugins stop in reverse order, so HTTP stops first, then running jobs drain", " SchedulePlugin.configure(),");
@@ -2699,7 +2725,7 @@ function mainTs(flags) {
2699
2725
  const port = "port: Number(process.env.PORT ?? 3000)";
2700
2726
  plugins.push(adapter === void 0 ? ` HttpPlugin.configure({ ${port} }),` : ` HttpPlugin.configure({ adapter: ${adapter}, ${port} }),`);
2701
2727
  }
2702
- if (flags.openapi) plugins.push(` // GET /openapi.json and the API reference at /docs, with ${OPENAPI_UI_LABELS[flags.openapiUi]} (document options: src/api.ts)`, ` OpenApiPlugin.configure({ ui: ${quote(flags.openapiUi)} }),`);
2728
+ if (flags.openapi) plugins.push(...flags.openapiUi === "none" ? [" // GET /openapi.json, no API reference UI (document options: src/openapi.ts)", " OpenApiPlugin.configure(),"] : [` // GET /openapi.json and the API reference at /docs, with ${OPENAPI_UI_LABELS[flags.openapiUi]} (document options: src/openapi.ts)`, ` OpenApiPlugin.configure({ ui: ${quote(flags.openapiUi)} }),`]);
2703
2729
  if (flags.graphql) plugins.push(" // POST /graphql, GET /graphql (GraphiQL in development): the schema is derived from the resolvers", " GraphQLPlugin.configure(),");
2704
2730
  if (flags.websocket) plugins.push(" // WebSocket gateways on the HTTP server's port (ws on Node.js, Bun's own WebSocket on Bun)", " WebSocketPlugin.configure(),");
2705
2731
  return `${imports.join("\n")}
@@ -2746,6 +2772,10 @@ export class AppConfig {
2746
2772
 
2747
2773
  /** Greeting used by GreetingService (APP_GREETING). */
2748
2774
  greeting = 'Hello'
2775
+
2776
+ /** Runtime environment (NODE_ENV): \`znight dev\` sets "development"; unset, the application runs as in production. */
2777
+ @Env('NODE_ENV')
2778
+ environment = 'production'
2749
2779
  }
2750
2780
  `;
2751
2781
  }
@@ -2890,17 +2920,17 @@ export class HeartbeatJobs {
2890
2920
  }
2891
2921
  `;
2892
2922
  }
2893
- function apiDocument(options) {
2923
+ function openApiDocument(flags) {
2894
2924
  return `import { OpenApiDocument } from '@znight/openapi'
2895
2925
 
2896
- /**
2897
- * ${options.name}
2898
- *
2899
- * The HTTP API of ${options.name}. Title and description of the OpenAPI document come from this
2900
- * comment, the version from package.json.
2901
- */
2926
+ // Options of the OpenAPI document (${flags.openapiUi === "none" ? "GET /openapi.json" : "GET /openapi.json, the API reference at /docs"}), read by the
2927
+ // compiler. The class is a marker: it is never instantiated.
2902
2928
  @OpenApiDocument({
2903
- tags: [{ name: 'Greeting', description: 'Greetings' }],
2929
+ info: {
2930
+ title: ${quote(flags.name)},
2931
+ description: ${quote(`The HTTP API of ${flags.name}.`)},
2932
+ version: '1.0.0',
2933
+ },
2904
2934
  })
2905
2935
  export class Api {}
2906
2936
  `;
@@ -3151,10 +3181,10 @@ function readme(options, flags) {
3151
3181
  const features = [
3152
3182
  `- **HTTP** with \`@znight/http\` (${flags.adapter === "node" ? "built-in node:http server" : `${flags.adapter} adapter`})`,
3153
3183
  flags.config ? "- **Configuration** with `@znight/config` (`src/app/app.config.ts`, `.env` files)" : void 0,
3154
- flags.observability ? "- **Observability** with `@znight/observability` (structured logs, metrics, traces)" : void 0,
3184
+ flags.observability ? "- **Observability** with `@znight/observability` (structured logs: pretty-printed by `pino-pretty` in development, JSON in production; metrics and tracing are off in `src/main.ts`)" : void 0,
3155
3185
  flags.messaging ? "- **Messaging** with `@znight/messaging` (in-memory broker in `src/main.ts`)" : void 0,
3156
3186
  flags.schedule ? "- **Scheduled jobs** with `@znight/schedule` (`src/app/heartbeat.jobs.ts`)" : void 0,
3157
- flags.openapi ? `- **OpenAPI** with \`@znight/openapi\` (\`/openapi.json\`, ${OPENAPI_UI_LABELS[flags.openapiUi]} API reference at \`/docs\`, options in \`src/api.ts\`)` : void 0,
3187
+ flags.openapi ? `- **OpenAPI** with \`@znight/openapi\` (\`/openapi.json\`, ${flags.openapiUi === "none" ? "" : `${OPENAPI_UI_LABELS[flags.openapiUi]} API reference at \`/docs\`, `}options in \`src/openapi.ts\`)` : void 0,
3158
3188
  flags.graphql ? "- **GraphQL** with `@znight/graphql` (code-first: the schema is derived from `src/app/greeting.resolver.ts`)" : void 0,
3159
3189
  flags.websocket ? "- **WebSocket** with `@znight/websocket` (`src/app/greeting.gateway.ts`, on the HTTP port at `/ws`)" : void 0
3160
3190
  ].filter((line) => line !== void 0);
@@ -3172,7 +3202,7 @@ function readme(options, flags) {
3172
3202
  const tree = [
3173
3203
  "src/",
3174
3204
  "├─ main.ts # Application.create() + plugins + start()",
3175
- flags.openapi ? "├─ api.ts # @OpenApiDocument: title, tags, security of openapi.json" : void 0,
3205
+ flags.openapi ? "├─ openapi.ts # @OpenApiDocument: title, description, version of openapi.json" : void 0,
3176
3206
  "├─ .znight/ # generated DI container (git-ignored)",
3177
3207
  "└─ app/",
3178
3208
  ...app.map((line, index) => ` ${index === app.length - 1 ? "└─" : "├─"} ${line}`),
@@ -3184,9 +3214,9 @@ function readme(options, flags) {
3184
3214
  const configNote = flags.config ? `
3185
3215
  ## Configuration
3186
3216
 
3187
- \`AppConfig\` (\`src/app/app.config.ts\`) reads \`PORT\` and \`APP_GREETING\` from the environment or from
3188
- \`.env\` / \`.env.local\` files. Missing or invalid values stop the application at boot with every
3189
- problem listed.${flags.bun ? `
3217
+ \`AppConfig\` (\`src/app/app.config.ts\`) reads \`PORT\`, \`APP_GREETING\` and \`NODE_ENV\` from the environment
3218
+ or from \`.env\` / \`.env.local\` files. Missing or invalid values stop the application at boot with
3219
+ every problem listed.${flags.bun ? `
3190
3220
 
3191
3221
  \`bunfig.toml\` turns Bun's own \`.env\` loading off (\`env = false\`): the files are read by
3192
3222
  \`@znight/config\`, the same way on Node.js and Bun.` : ""}
@@ -3230,7 +3260,7 @@ ${flags.openapi ? `| \`${run("openapi")}\` | Write \`openapi.json\` (commit it;
3230
3260
  ${run("dev")}
3231
3261
  curl localhost:3000/health
3232
3262
  curl localhost:3000/greetings/Ada?excited=true
3233
- curl -X POST localhost:3000/greetings -H 'content-type: application/json' -d '{"name":"Grace"}'${flags.openapi ? "\ncurl localhost:3000/openapi.json # the API reference is at http://localhost:3000/docs" : ""}${flags.graphql ? `\ncurl localhost:3000/graphql -H 'content-type: application/json' -d '{"query":"{ greeting(name: \\"Ada\\") { message } }"}'` : ""}
3263
+ curl -X POST localhost:3000/greetings -H 'content-type: application/json' -d '{"name":"Grace"}'${flags.openapi ? `\ncurl localhost:3000/openapi.json${flags.openapiUi === "none" ? "" : " # the API reference is at http://localhost:3000/docs"}` : ""}${flags.graphql ? `\ncurl localhost:3000/graphql -H 'content-type: application/json' -d '{"query":"{ greeting(name: \\"Ada\\") { message } }"}'` : ""}
3234
3264
  \`\`\`
3235
3265
 
3236
3266
  ## Project structure
@@ -3311,8 +3341,12 @@ const newCommand = defineCommand({
3311
3341
  },
3312
3342
  "openapi-ui": {
3313
3343
  type: "enum",
3314
- options: ["scalar", "swagger"],
3315
- description: "API reference UI of the openapi feature, served at /docs (default: scalar)"
3344
+ options: [
3345
+ "scalar",
3346
+ "swagger",
3347
+ "none"
3348
+ ],
3349
+ description: "API reference UI of the openapi feature, served at /docs, or none (default: scalar)"
3316
3350
  },
3317
3351
  docker: {
3318
3352
  type: "boolean",
@@ -4262,4 +4296,4 @@ function stackOf(error) {
4262
4296
  }
4263
4297
  export { CancelledError as _, planSchematic as a, UsageError as b, FEATURES as c, AppSupervisor as d, createContext as f, defineCommand as g, loadCompiler as h, findSchematic as i, HTTP_ADAPTERS as l, adaptCompilerModule as m, main as n, renderProject as o, cliVersion as p, SCHEMATICS as r, DEFAULT_FEATURES as s, COMMANDS as t, PACKAGE_MANAGERS as u, CliError as v, ExitCode as y };
4264
4298
 
4265
- //# sourceMappingURL=main-CLoS12u4.mjs.map
4299
+ //# sourceMappingURL=main-D_BXiYBu.mjs.map