@kitsy/cnos-docs 1.5.0 → 1.6.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.
@@ -14,3 +14,5 @@ console.log(cnos('public.app.apiBaseUrl'));
14
14
  Only promoted browser-safe values are available here.
15
15
 
16
16
  Framework integrations such as `@kitsy/cnos-vite`, `@kitsy/cnos-next`, and `@kitsy/cnos-webpack` are responsible for embedding that browser payload during the build.
17
+
18
+ The browser runtime does not fetch config over the network. It reads from data already embedded into the bundle/runtime globals by the framework integration, so it follows the same bundle and service-worker caching behavior as the rest of your frontend assets.
@@ -32,6 +32,12 @@ The runtime currently exposes:
32
32
  - `cnos.toNamespace(namespace)`
33
33
  - `cnos.toEnv()`
34
34
  - `cnos.toPublicEnv()`
35
+ - `cnos.toServerProjection()`
36
+ - `cnos.format(message)`
37
+ - `cnos.log(message)`
38
+ - `cnos.loadProjection(path)`
39
+ - `cnos.refreshSecrets()`
40
+ - `cnos.refreshSecret(key)`
35
41
 
36
42
  Example:
37
43
 
@@ -45,6 +51,20 @@ const dbPassword = cnos.secret('db.password');
45
51
  const profile = cnos.meta('profile');
46
52
  const port = cnos.readOr('value.server.port', 3000);
47
53
  const flags = cnos.toNamespace('flags');
54
+ const line = cnos.format('Starting server at ${value.server.port}');
55
+
56
+ cnos.log('Starting server at ${value.server.port}');
57
+ ```
58
+
59
+ `cnos.format(...)` and `cnos.log(...)` interpolate `${logical.key}` placeholders through the active runtime. Missing keys are left unchanged.
60
+
61
+ For server packaging, the runtime can also bootstrap from a projection artifact:
62
+
63
+ ```ts
64
+ import cnos from '@kitsy/cnos';
65
+
66
+ await cnos.loadProjection('./.cnos-server.json');
67
+ await cnos.ready();
48
68
  ```
49
69
 
50
70
  ## Typed values
@@ -1,23 +1,25 @@
1
1
  ---
2
- title: cnos build env
3
- description: Build flat env-file artifacts from CNOS.
2
+ title: cnos build
3
+ description: Build derived CNOS projection artifacts for server, browser, env, and public surfaces.
4
4
  ---
5
5
 
6
- # cnos build env
6
+ # cnos build
7
7
 
8
- Use `build env` when a repo still expects `.env.*` files but CNOS is the source of truth.
8
+ Use `build` when a repo needs a deterministic artifact derived from CNOS.
9
9
 
10
10
  ```bash
11
+ cnos build server --to .cnos-server.json
12
+ cnos build browser --to .cnos-browser.json
11
13
  cnos build env --profile local --to .env.local
12
14
  cnos build env --profile stage --to .env.stage
13
- cnos build env --public --framework vite --to .env.production
15
+ cnos build public --framework vite --to .env.production
14
16
  ```
15
17
 
16
- `build env`:
18
+ Targets:
17
19
 
18
- - resolves the selected CNOS workspace/profile
19
- - renders a deterministic flat `KEY=VALUE` file
20
- - writes the target path
21
- - does not start a child process
20
+ - `build server` writes a server runtime projection with resolved values plus secret refs
21
+ - `build browser` writes a public-only browser projection
22
+ - `build env` writes explicit env mappings in formats like `dotenv`, `shell`, `json`, `yaml`, `docker-env`, or `toml`
23
+ - `build public` writes promoted public env with optional framework prefixes like Vite and Next
22
24
 
23
- This is the preferred bridge for build systems and CI pipelines that still consume env files.
25
+ All build artifacts are derived output. `.cnos` remains the source of truth.
@@ -45,3 +45,10 @@ For frontend builds:
45
45
  - Vite: `@kitsy/cnos-vite`
46
46
  - Webpack/static bundles: `@kitsy/cnos-webpack`
47
47
  - Next.js: `@kitsy/cnos-next`
48
+
49
+ For webpack/static bundles, build-time settings can come from CNOS too:
50
+
51
+ ```bash
52
+ cnos set value dev.server.port 8800
53
+ npm run dev
54
+ ```
@@ -10,6 +10,15 @@ Backend projects usually use one of two patterns:
10
10
  - `cnos run -- <command>` for zero-code-change adoption
11
11
  - `import cnos from '@kitsy/cnos'` for direct runtime reads
12
12
 
13
+ For an existing Express or Node service that already uses `.env`, start with the env bridge:
14
+
15
+ ```bash
16
+ cnos build env --profile local --to .env.local
17
+ cnos build env --profile stage --to .env.stage
18
+ ```
19
+
20
+ Then keep your current `dotenv` setup while moving runtime reads to CNOS.
21
+
13
22
  Example:
14
23
 
15
24
  ```ts
@@ -24,6 +33,12 @@ const token = cnos.secret('app.token');
24
33
  Env export bridge:
25
34
 
26
35
  ```bash
27
- cnos export env --to .env.local
28
- cnos export env --profile stage --to .env.stage
36
+ cnos build env --to .env.local
37
+ cnos build env --profile stage --to .env.stage
38
+ ```
39
+
40
+ Projection-first packaging:
41
+
42
+ ```bash
43
+ cnos build server --profile prod --to .cnos-server.json
29
44
  ```
@@ -5,6 +5,12 @@ description: Use CNOS public projection with Next.js builds and browser-safe run
5
5
 
6
6
  # Frontend with Next.js
7
7
 
8
+ If the app already depends on `NEXT_PUBLIC_*`, keep that contract while CNOS becomes the source of truth:
9
+
10
+ ```bash
11
+ cnos build public --framework next --profile prod --to .env.production
12
+ ```
13
+
8
14
  ```ts
9
15
  import { withCnosNext } from '@kitsy/cnos-next';
10
16
 
@@ -12,3 +18,10 @@ export default withCnosNext({});
12
18
  ```
13
19
 
14
20
  Browser-safe values remain under `public.promote` and are exposed as `NEXT_PUBLIC_*` plus browser-runtime data for `@kitsy/cnos/browser`.
21
+
22
+ Migration path:
23
+
24
+ 1. keep `NEXT_PUBLIC_*` via generated env or Next env injection
25
+ 2. add `withCnosNext()`
26
+ 3. move browser-safe reads to `@kitsy/cnos/browser`
27
+ 4. move server-only reads to `@kitsy/cnos` or `@kitsy/cnos/configure`
@@ -5,6 +5,13 @@ description: Project browser-safe CNOS values into Vite and use the browser runt
5
5
 
6
6
  # Frontend with Vite
7
7
 
8
+ If your app already uses `VITE_*`, keep that shape first and let CNOS generate it.
9
+
10
+ ```bash
11
+ cnos build public --framework vite --profile local --to .env.local
12
+ cnos dev env --public --framework vite --profile local --to .env.local -- pnpm dev
13
+ ```
14
+
8
15
  Promote browser-safe values:
9
16
 
10
17
  ```yaml
@@ -32,3 +39,10 @@ import cnos from '@kitsy/cnos/browser';
32
39
  console.log(cnos('public.app.apiBaseUrl'));
33
40
  console.log(import.meta.env.VITE_APP_API_BASE_URL);
34
41
  ```
42
+
43
+ Migration path:
44
+
45
+ 1. keep `VITE_*` working through generated env files
46
+ 2. add `createCnosVitePlugin()`
47
+ 3. move browser reads to `@kitsy/cnos/browser`
48
+ 4. stop treating handwritten `.env.local` as the source of truth
@@ -7,6 +7,26 @@ description: Use CNOS public projection with webpack builds, webpack-dev-server,
7
7
 
8
8
  CNOS integrates with webpack through `@kitsy/cnos-webpack`. This covers the common static-bundle case where webpack produces a browser build that is then deployed as static assets.
9
9
 
10
+ ## Highlight: change webpack dev-server config from CNOS
11
+
12
+ Once webpack reads build-time config through `createCnos()`, changing a setting such as the dev-server port is just a config write:
13
+
14
+ ```powershell
15
+ cnos set value dev.server.port 8800
16
+ npm run dev
17
+ ```
18
+
19
+ Typical result:
20
+
21
+ ```text
22
+ set value.dev.server.port in .cnos\values\dev.yml
23
+ Cnos value.dev.server.port: 8800
24
+ [webpack-dev-server] Project is running at:
25
+ [webpack-dev-server] Loopback: http://localhost:8800/
26
+ ```
27
+
28
+ This is the main benefit of the CNOS webpack path: you change config in `.cnos`, not scattered build scripts or ad hoc env files.
29
+
10
30
  Promote browser-safe values:
11
31
 
12
32
  ```yaml
@@ -16,7 +36,7 @@ public:
16
36
  - flags.upi_enabled
17
37
  ```
18
38
 
19
- Use an async webpack config:
39
+ Use an async webpack config. If your repo already uses ESM webpack config, this is the cleanest shape:
20
40
 
21
41
  ```ts
22
42
  import { createCnos } from '@kitsy/cnos/configure';
@@ -40,6 +60,38 @@ export default async () => {
40
60
  };
41
61
  ```
42
62
 
63
+ If your project uses CommonJS-style webpack config, keep `module.exports = async () => ...` and load CNOS with dynamic `import()` inside the async factory:
64
+
65
+ ```js
66
+ const ESLintPlugin = require('eslint-webpack-plugin');
67
+ const MiniCssExtractPlugin = require('mini-css-extract-plugin');
68
+ const HtmlWebpackPlugin = require('html-webpack-plugin');
69
+
70
+ module.exports = async () => {
71
+ const { createCnos } = await import('@kitsy/cnos/configure');
72
+ const { CnosWebpackPlugin } = await import('@kitsy/cnos-webpack');
73
+
74
+ const profile = process.env.NODE_ENV === 'production' ? 'prod' : 'local';
75
+ const cnos = await createCnos({ profile });
76
+
77
+ return {
78
+ devServer: {
79
+ port: Number(cnos.readOr('value.devServer.port', 3000)),
80
+ },
81
+ plugins: [
82
+ new CnosWebpackPlugin({ profile }),
83
+ new HtmlWebpackPlugin({
84
+ templateParameters: {
85
+ appName: cnos.read('public.app.name'),
86
+ },
87
+ }),
88
+ new MiniCssExtractPlugin(),
89
+ new ESLintPlugin(),
90
+ ],
91
+ };
92
+ };
93
+ ```
94
+
43
95
  Read in browser code:
44
96
 
45
97
  ```ts
@@ -54,5 +106,47 @@ The webpack plugin:
54
106
  - injects `process.env.*` define replacements for promoted public values
55
107
  - embeds `globalThis.__CNOS_BROWSER_DATA__` for `@kitsy/cnos/browser`
56
108
  - keeps server-only `value.*` and `secret.*` out of the browser bundle
109
+ - uses no prefix by default for webpack public env unless you configure `public.frameworks.webpack` or pass `prefix`
110
+
111
+ ## Bundle and cache behavior
112
+
113
+ CNOS does not add a runtime fetch layer to the browser bundle.
114
+
115
+ - `@kitsy/cnos-webpack` resolves public config at build time
116
+ - browser-safe values are embedded into the existing webpack bundle through `DefinePlugin` and `globalThis.__CNOS_BROWSER_DATA__`
117
+ - `@kitsy/cnos/browser` is a small reader over that embedded payload
118
+ - if your app does not import `@kitsy/cnos/browser`, webpack can leave it out of the browser bundle
119
+ - if your app does import `@kitsy/cnos/browser`, it is bundled like any other app dependency and follows your existing webpack and service-worker caching strategy
120
+
121
+ So if your site already uses `sw.js` for offline behavior, CNOS does not disable or bypass that. CNOS becomes part of the same built assets your service worker already caches.
57
122
 
58
123
  If you need build-time server config such as `devServer.port`, read it in the webpack config through `createCnos()` so dev and production builds use the same CNOS source of truth.
124
+
125
+ ## Plugin order
126
+
127
+ Recommended order:
128
+
129
+ ```ts
130
+ plugins: [
131
+ new CnosWebpackPlugin({ profile }),
132
+ new HtmlWebpackPlugin(...),
133
+ new MiniCssExtractPlugin(...),
134
+ new CopyPlugin(...),
135
+ new ESLintPlugin(...),
136
+ ]
137
+ ```
138
+
139
+ Guidance:
140
+ - Put `CnosWebpackPlugin` early in the plugin list.
141
+ - `HtmlWebpackPlugin`, `MiniCssExtractPlugin`, `CopyPlugin`, and `ESLintPlugin` can follow it.
142
+ - If you need CNOS values in HTML templates, read them with `createCnos()` in the webpack config and pass them through `templateParameters`. `DefinePlugin` replacements do not automatically populate HTML templates.
143
+
144
+ ## Why `require is not defined` happens
145
+
146
+ If webpack-cli logs a path like `file:///.../webpack.config.js`, it loaded your config as ESM. In that mode, `require(...)` is not available.
147
+
148
+ Choose one style and stay consistent:
149
+ - ESM: `webpack.config.mjs` or a package with `"type": "module"` and `import ...`
150
+ - CommonJS: `webpack.config.cjs` or CommonJS `module.exports = async () => ...`, using dynamic `import()` for CNOS ESM packages
151
+
152
+ Do not mix top-level `await` plus `require(...)` in a config file that webpack treats as ESM.
@@ -5,7 +5,16 @@ description: Move existing env-based projects onto CNOS without losing current w
5
5
 
6
6
  # Migrating from .env
7
7
 
8
- Use the migration assistant:
8
+ CNOS migration works best as a bridge, not a flag day.
9
+
10
+ The pattern is:
11
+
12
+ 1. Keep `.cnos` as the new source of truth.
13
+ 2. Keep your current app/build/runtime working.
14
+ 3. Generate whatever bridge artifact the existing stack needs.
15
+ 4. Migrate direct env reads to CNOS app by app.
16
+
17
+ Use the migration assistant when you want help mapping existing env usage:
9
18
 
10
19
  ```bash
11
20
  cnos migrate --scan src --dry-run
@@ -13,20 +22,112 @@ cnos migrate --apply
13
22
  cnos migrate --apply --rewrite
14
23
  ```
15
24
 
16
- Bridge to existing tooling:
25
+ ## Plain Node or Express with `.env`
26
+
27
+ If your service currently starts with `dotenv`, keep that flow first.
17
28
 
18
29
  ```bash
19
- cnos build env --to .env.local
30
+ cnos build env --profile local --to .env.local
20
31
  cnos build env --profile stage --to .env.stage
21
- cnos dev env --profile local --to .env.local -- pnpm dev
22
32
  ```
23
33
 
24
- For webpack or other static bundles, pair this with `@kitsy/cnos-webpack` or `@kitsy/cnos/build` so browser-safe `public.*` values are injected at build time without keeping handwritten `.env` files as the source of truth.
34
+ Then your existing `dotenv` bootstrap keeps working.
35
+
36
+ Move server code gradually:
37
+
38
+ ```ts
39
+ import cnos from '@kitsy/cnos';
40
+
41
+ await cnos.ready();
42
+
43
+ const port = cnos.readOr('value.server.port', 3000);
44
+ const token = cnos.secret('app.token');
45
+ ```
46
+
47
+ For runtime packaging instead of env files:
48
+
49
+ ```bash
50
+ cnos build server --profile prod --to .cnos-server.json
51
+ ```
52
+
53
+ ## Vite Frontend
54
+
55
+ If you already use `VITE_*` env variables, keep that contract first.
56
+
57
+ ```bash
58
+ cnos build public --framework vite --profile local --to .env.local
59
+ cnos dev env --public --framework vite --profile local --to .env.local -- pnpm dev
60
+ ```
61
+
62
+ Then add `@kitsy/cnos-vite` and migrate browser reads to:
63
+
64
+ ```ts
65
+ import cnos from '@kitsy/cnos/browser';
66
+
67
+ cnos('public.app.apiBaseUrl');
68
+ ```
69
+
70
+ ## Next.js
71
+
72
+ If you already use `NEXT_PUBLIC_*`, keep that contract while adopting CNOS.
73
+
74
+ ```bash
75
+ cnos build public --framework next --profile prod --to .env.production
76
+ ```
77
+
78
+ Then wire `@kitsy/cnos-next` so Next gets public data from CNOS directly and browser code can read `public.*` through `@kitsy/cnos/browser`.
79
+
80
+ ## Webpack Static Frontend
81
+
82
+ If you already have a `webpack.config.js`, you do not need to invent a new runtime.
83
+
84
+ - read build-time settings such as dev-server port through `createCnos()`
85
+ - inject browser-safe config through `@kitsy/cnos-webpack`
86
+ - keep generated `.env.*` files only if your repo still expects them
87
+
88
+ Example bridge:
89
+
90
+ ```bash
91
+ cnos build public --profile local --to .env.local
92
+ ```
93
+
94
+ Longer-term path:
95
+
96
+ - `CnosWebpackPlugin` for browser-safe values
97
+ - `createCnos()` inside webpack config for build-time settings
98
+
99
+ ## pnpm Monorepo
100
+
101
+ For monorepos, do not copy `.cnos` into every package.
102
+
103
+ - keep one repo-root `.cnos/`
104
+ - add `.cnosrc.yml` to each consuming app/package
105
+ - optionally add a repo-root `.cnosrc.yml` if the root also consumes CNOS
106
+
107
+ Example:
108
+
109
+ ```yaml
110
+ # apps/travel/.cnosrc.yml
111
+ root: ../../.cnos
112
+ workspace: travel
113
+ ```
114
+
115
+ Server-side packages can use projections:
116
+
117
+ ```bash
118
+ cnos build server --workspace travel --profile prod --to apps/travel/.cnos-server.json
119
+ ```
120
+
121
+ Legacy env-based packages can still use:
122
+
123
+ ```bash
124
+ cnos build env --workspace travel --profile local --to apps/travel/.env.local
125
+ ```
25
126
 
26
127
  Recommended migration sequence:
27
128
 
28
129
  1. Keep `.cnos` as the source of truth.
29
- 2. Generate `.env.*` artifacts for legacy tools.
130
+ 2. Generate `.env.*`, browser, or server projection artifacts for legacy tools.
30
131
  3. Migrate server code to `@kitsy/cnos`.
31
132
  4. Migrate browser code to `@kitsy/cnos/browser`.
32
- 5. Remove env-file dependencies app by app.
133
+ 5. Remove handwritten env-file dependencies app by app.
@@ -5,18 +5,88 @@ description: Use CNOS workspaces to model multiple apps inside one repo.
5
5
 
6
6
  # Workspaces and Monorepos
7
7
 
8
- In single-project mode, CNOS stays simple.
8
+ For monorepos, keep one authoritative `.cnos/` tree at the repo root and put a `.cnosrc.yml` anchor in each consuming app or package.
9
9
 
10
- For monorepos:
10
+ Repo root as both author and consumer:
11
11
 
12
- ```bash
13
- cnos init --workspace api
14
- cnos use --workspace api
15
- cnos list values
12
+ ```yaml
13
+ # .cnosrc.yml
14
+ root: ./.cnos
15
+ ```
16
+
17
+ Child app:
18
+
19
+ ```yaml
20
+ # apps/travel/.cnosrc.yml
21
+ root: ../../.cnos
22
+ workspace: travel
23
+ ```
24
+
25
+ `.cnosrc.yml` is the only discovery anchor. CNOS does not walk upward looking for `.cnos` directories. It looks for `.cnosrc.yml` within a bounded package-root search window, then resolves the real `.cnos` root from there.
26
+
27
+ Typical manifest shape:
28
+
29
+ ```yaml
30
+ workspaces:
31
+ default: root
32
+ items:
33
+ root: {}
34
+ travel:
35
+ extends: [root]
36
+ food:
37
+ extends: [root]
38
+ ```
39
+
40
+ This lets you keep shared values in `root` and override only what each app needs in `travel`, `food`, or other child workspaces.
41
+
42
+ Read from an app package without passing a root manually:
43
+
44
+ ```ts
45
+ import cnos from '@kitsy/cnos';
46
+
47
+ await cnos.ready();
48
+ console.log(cnos('value.app.name'));
16
49
  ```
17
50
 
18
51
  Override per command when needed:
19
52
 
20
53
  ```bash
21
- cnos list values --workspace webapp
54
+ cnos list values --workspace travel
55
+ cnos build server --workspace travel --profile prod --to apps/travel/.cnos-server.json
22
56
  ```
57
+
58
+ ## Runtime Projection
59
+
60
+ The authoring tree stays at repo root. Runtime consumers do not need the full `.cnos/` layout.
61
+
62
+ For server packaging:
63
+
64
+ ```bash
65
+ cnos build server --workspace api-gateway --profile prod --to apps/api-gateway/.cnos-server.json
66
+ ```
67
+
68
+ `@kitsy/cnos` then auto-loads in this order:
69
+
70
+ 1. `__CNOS_PROJECTION__`
71
+ 2. `.cnos-server.json`
72
+ 3. full authoring resolution through `.cnosrc.yml`
73
+
74
+ Browser packages keep using public projection through Vite, Next, webpack, or `@kitsy/cnos/build`.
75
+
76
+ ## Detach and Reattach
77
+
78
+ Detach a child package into a standalone CNOS root:
79
+
80
+ ```bash
81
+ cnos workspace detach --package-root apps/travel
82
+ ```
83
+
84
+ This materializes the effective config into `apps/travel/.cnos`, rewrites `apps/travel/.cnosrc.yml` to point to that local root, and stops inheriting from the parent repo.
85
+
86
+ Reattach it later:
87
+
88
+ ```bash
89
+ cnos workspace attach --package-root apps/travel
90
+ ```
91
+
92
+ This imports the standalone child config back into the parent workspace model, archives the detached `.cnos`, and restores the package anchor.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitsy/cnos-docs",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "Source-of-truth CNOS documentation content for Astro Starlight and other static docs consumers.",
5
5
  "type": "module",
6
6
  "exports": {