@kitsy/cnos-docs 1.6.0 → 1.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/docs/api/browser.mdx +29 -0
- package/docs/api/create-cnos.mdx +41 -0
- package/docs/api/runtime.mdx +44 -0
- package/docs/cli/build.mdx +1 -0
- package/docs/cli/cache.mdx +28 -0
- package/docs/cli/inspect.mdx +28 -0
- package/docs/cli/value.mdx +17 -0
- package/docs/guides/backend.mdx +25 -0
- package/docs/guides/ci-cd.mdx +18 -2
- package/docs/guides/containers-and-actions.mdx +136 -0
- package/docs/guides/derived-values.mdx +130 -0
- package/docs/guides/frontend-vite.mdx +52 -0
- package/docs/guides/generated-env-files.mdx +2 -0
- package/docs/guides/remote-roots.mdx +86 -0
- package/docs/guides/workspaces.mdx +7 -0
- package/docs/reference/namespaces.mdx +34 -0
- package/manifest.yml +9 -1
- package/package.json +1 -1
package/docs/api/browser.mdx
CHANGED
|
@@ -16,3 +16,32 @@ Only promoted browser-safe values are available here.
|
|
|
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
17
|
|
|
18
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.
|
|
19
|
+
|
|
20
|
+
## Cross-App Browser Config
|
|
21
|
+
|
|
22
|
+
Use the same runtime for shared browser-safe values such as sibling app origins, CDN roots, public feature flags, or analytics ids.
|
|
23
|
+
|
|
24
|
+
```yaml
|
|
25
|
+
public:
|
|
26
|
+
promote:
|
|
27
|
+
- value.apps.docs.origin
|
|
28
|
+
- value.apps.console.origin
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import cnos from '@kitsy/cnos/browser';
|
|
33
|
+
|
|
34
|
+
const docsOrigin = cnos('public.apps.docs.origin');
|
|
35
|
+
const consoleOrigin = cnos('public.apps.console.origin');
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
This is intentionally simple:
|
|
39
|
+
|
|
40
|
+
1. define the values in CNOS
|
|
41
|
+
2. promote them to `public.*`
|
|
42
|
+
3. install the framework integration
|
|
43
|
+
4. read them in browser code with `@kitsy/cnos/browser`
|
|
44
|
+
|
|
45
|
+
You should not need a second app-specific browser config mechanism on top of CNOS.
|
|
46
|
+
|
|
47
|
+
Derived public values are supported too, but only when CNOS can resolve them safely at build time. If a promoted key depends on a server-only runtime namespace such as `process.*` or `request.*`, the browser/public build fails instead of emitting unstable data.
|
package/docs/api/create-cnos.mdx
CHANGED
|
@@ -13,3 +13,44 @@ const runtime = await createCnos({
|
|
|
13
13
|
profile: 'stage',
|
|
14
14
|
});
|
|
15
15
|
```
|
|
16
|
+
|
|
17
|
+
Common options:
|
|
18
|
+
|
|
19
|
+
- `cwd`
|
|
20
|
+
- `root`
|
|
21
|
+
- `workspace`
|
|
22
|
+
- `profile`
|
|
23
|
+
- `globalRoot`
|
|
24
|
+
- `cacheMode`
|
|
25
|
+
- `cacheTtlSeconds`
|
|
26
|
+
- `processEnv`
|
|
27
|
+
|
|
28
|
+
`root` can be a local path or a remote git root URI:
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
const runtime = await createCnos({
|
|
32
|
+
root: 'git+https://github.com/org/config.git#v2.1.0',
|
|
33
|
+
workspace: 'travel',
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Derived values and runtime namespaces work through the explicit runtime too:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { createCnos } from '@kitsy/cnos/configure';
|
|
41
|
+
|
|
42
|
+
const runtime = await createCnos({
|
|
43
|
+
cwd: process.cwd(),
|
|
44
|
+
profile: 'prod',
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
runtime.registerRuntimeProvider('request', (key) => {
|
|
48
|
+
if (key === 'headers.host') {
|
|
49
|
+
return currentRequest?.headers.host;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return undefined;
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const origin = runtime.value('app.origin');
|
|
56
|
+
```
|
package/docs/api/runtime.mdx
CHANGED
|
@@ -36,6 +36,7 @@ The runtime currently exposes:
|
|
|
36
36
|
- `cnos.format(message)`
|
|
37
37
|
- `cnos.log(message)`
|
|
38
38
|
- `cnos.loadProjection(path)`
|
|
39
|
+
- `cnos.registerRuntimeProvider(namespace, provider)`
|
|
39
40
|
- `cnos.refreshSecrets()`
|
|
40
41
|
- `cnos.refreshSecret(key)`
|
|
41
42
|
|
|
@@ -67,6 +68,49 @@ await cnos.loadProjection('./.cnos-server.json');
|
|
|
67
68
|
await cnos.ready();
|
|
68
69
|
```
|
|
69
70
|
|
|
71
|
+
## Derived Values
|
|
72
|
+
|
|
73
|
+
Derived values resolve transparently through the same read APIs.
|
|
74
|
+
|
|
75
|
+
```yaml
|
|
76
|
+
app:
|
|
77
|
+
origin:
|
|
78
|
+
$derive: "${value.app.protocol}://${value.app.host}:${value.app.port}"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
const origin = cnos.value('app.origin');
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Config-only derivations are cached for the active runtime. Runtime-dependent derivations stay live:
|
|
86
|
+
|
|
87
|
+
```yaml
|
|
88
|
+
server:
|
|
89
|
+
effective_port:
|
|
90
|
+
$derive:
|
|
91
|
+
expr: "coalesce(process.env.PORT, value.server.default_port, '3000')"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
const port = cnos.value('server.effective_port');
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Runtime Providers
|
|
99
|
+
|
|
100
|
+
Declare custom runtime namespaces in the manifest, then register a provider at runtime.
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
cnos.registerRuntimeProvider('request', (key) => {
|
|
104
|
+
if (key === 'headers.host') {
|
|
105
|
+
return currentRequest?.headers.host;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return undefined;
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
That lets server-side derived values depend on live request, session, or app-framework context without adding a second config layer.
|
|
113
|
+
|
|
70
114
|
## Typed values
|
|
71
115
|
|
|
72
116
|
CNOS values are not limited to strings. If the underlying config stores numbers, booleans, arrays, or objects, runtime reads return those values as-is.
|
package/docs/cli/build.mdx
CHANGED
|
@@ -13,6 +13,7 @@ cnos build browser --to .cnos-browser.json
|
|
|
13
13
|
cnos build env --profile local --to .env.local
|
|
14
14
|
cnos build env --profile stage --to .env.stage
|
|
15
15
|
cnos build public --framework vite --to .env.production
|
|
16
|
+
cnos build env --profile local-domain --format docker-env --to .env.local-domain
|
|
16
17
|
```
|
|
17
18
|
|
|
18
19
|
Targets:
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: cnos cache
|
|
3
|
+
description: Inspect and manage cached remote CNOS roots.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# cnos cache
|
|
7
|
+
|
|
8
|
+
Use `cache` when a package anchor points at a remote root such as a git-backed config repo.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
cnos cache list
|
|
12
|
+
cnos cache clear
|
|
13
|
+
cnos cache clear git+https://github.com/org/config.git#v2.1.0
|
|
14
|
+
cnos cache refresh
|
|
15
|
+
cnos cache refresh git+ssh://git@github.com/org/config.git#main
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Subcommands:
|
|
19
|
+
|
|
20
|
+
- `cache list` shows cached remote roots, resolved commits, immutability, and size
|
|
21
|
+
- `cache clear` removes all cached roots or one specific cached root
|
|
22
|
+
- `cache refresh` forces a re-fetch for the current remote root or a specific git root URI
|
|
23
|
+
|
|
24
|
+
Notes:
|
|
25
|
+
|
|
26
|
+
- immutable refs such as semantic-version tags and commit SHAs stay cached permanently
|
|
27
|
+
- mutable refs such as branches are refreshed based on CNOS cache policy
|
|
28
|
+
- remote roots are read-only when consumed through CNOS
|
package/docs/cli/inspect.mdx
CHANGED
|
@@ -9,3 +9,31 @@ description: Inspect resolved values, provenance, and overrides.
|
|
|
9
9
|
cnos inspect value.app.name
|
|
10
10
|
cnos inspect secret.app.token --reveal
|
|
11
11
|
```
|
|
12
|
+
|
|
13
|
+
`cnos inspect` also shows derived metadata.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
cnos inspect value.app.origin
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Typical output includes:
|
|
20
|
+
|
|
21
|
+
- resolved value
|
|
22
|
+
- expression or template source
|
|
23
|
+
- dependency keys
|
|
24
|
+
- whether the value is runtime-dependent
|
|
25
|
+
- which runtime namespaces it depends on
|
|
26
|
+
|
|
27
|
+
Example:
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
key: value.app.origin
|
|
31
|
+
value: https://api.kitsy.ai:443
|
|
32
|
+
derivedType: template
|
|
33
|
+
derivedExpression: ${value.app.protocol}://${value.app.host}:${value.app.port}
|
|
34
|
+
runtimeDependent: false
|
|
35
|
+
dependencies:
|
|
36
|
+
- value.app.host
|
|
37
|
+
- value.app.port
|
|
38
|
+
- value.app.protocol
|
|
39
|
+
```
|
package/docs/cli/value.mdx
CHANGED
|
@@ -12,6 +12,22 @@ cnos value list --prefix app.
|
|
|
12
12
|
cnos value delete app.name
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
## Derived values
|
|
16
|
+
|
|
17
|
+
Use `--derive` for template shorthand:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
cnos value set app.origin --derive '${value.app.protocol}://${value.app.host}'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Use `--derive --expr` for expression form:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
cnos value set app.effective_port --derive --expr "coalesce(process.env.PORT, value.app.default_port, '3000')"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
CNOS stores these as first-class derived values, not as opaque strings.
|
|
30
|
+
|
|
15
31
|
## Typed input
|
|
16
32
|
|
|
17
33
|
`cnos value set` parses the input as YAML before writing it. That means you can store more than strings.
|
|
@@ -46,3 +62,4 @@ cnos read value.app.name
|
|
|
46
62
|
- Values are private by default.
|
|
47
63
|
- To expose a value to browser/public surfaces, use `cnos promote`.
|
|
48
64
|
- To expose a value as shell env, map it through `envMapping.explicit` or `cnos promote --to env`.
|
|
65
|
+
- Derived values can be authored only under writable data namespaces such as `value.*` and custom writable data namespaces.
|
package/docs/guides/backend.mdx
CHANGED
|
@@ -30,6 +30,31 @@ const port = cnos.value('server.port');
|
|
|
30
30
|
const token = cnos.secret('app.token');
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
+
Derived server config stays inside CNOS too:
|
|
34
|
+
|
|
35
|
+
```yaml
|
|
36
|
+
server:
|
|
37
|
+
effective_port:
|
|
38
|
+
$derive:
|
|
39
|
+
expr: "coalesce(process.env.PORT, value.server.default_port, '3000')"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
const port = cnos.value('server.effective_port');
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
If you need live request or session context, declare a runtime namespace and register a provider:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
cnos.registerRuntimeProvider('request', (key) => {
|
|
50
|
+
if (key === 'headers.host') {
|
|
51
|
+
return currentRequest?.headers.host;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return undefined;
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
33
58
|
Env export bridge:
|
|
34
59
|
|
|
35
60
|
```bash
|
package/docs/guides/ci-cd.mdx
CHANGED
|
@@ -8,9 +8,10 @@ description: Use CNOS in build and deploy pipelines without committing generated
|
|
|
8
8
|
Common patterns:
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
|
-
cnos
|
|
12
|
-
cnos
|
|
11
|
+
cnos build env --profile stage --to .env.stage
|
|
12
|
+
cnos build public --framework vite --profile stage --to .env.stage
|
|
13
13
|
cnos run --profile stage -- pnpm build
|
|
14
|
+
cnos build server --profile prod --to dist/.cnos-server.json
|
|
14
15
|
```
|
|
15
16
|
|
|
16
17
|
For CI-backed vaults:
|
|
@@ -19,3 +20,18 @@ For CI-backed vaults:
|
|
|
19
20
|
cnos vault create github-ci --provider github-secrets --no-passphrase
|
|
20
21
|
cnos secret set app.token APP_TOKEN --vault github-ci
|
|
21
22
|
```
|
|
23
|
+
|
|
24
|
+
GitHub Actions example:
|
|
25
|
+
|
|
26
|
+
```yaml
|
|
27
|
+
- name: Install deps
|
|
28
|
+
run: pnpm install --frozen-lockfile
|
|
29
|
+
|
|
30
|
+
- name: Build CNOS env
|
|
31
|
+
run: cnos build env --profile stage --to .env.stage
|
|
32
|
+
|
|
33
|
+
- name: Build app
|
|
34
|
+
run: pnpm build
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Use `cnos run` when you do not need an intermediate env file. Use `cnos build env` or `cnos build public` when the build tool or deploy step expects a file artifact.
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Containers, Kubernetes, and GitHub Actions
|
|
3
|
+
description: Use CNOS-generated artifacts in Docker, Docker Compose, Kubernetes, and GitHub Actions without making .env files the source of truth.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Containers, Kubernetes, and GitHub Actions
|
|
7
|
+
|
|
8
|
+
CNOS should stay the source of truth. Containers and pipelines should consume derived artifacts.
|
|
9
|
+
|
|
10
|
+
Use these patterns:
|
|
11
|
+
|
|
12
|
+
- `cnos build env` when the runtime expects flat env vars
|
|
13
|
+
- `cnos build server` when a server runtime should consume a CNOS projection artifact
|
|
14
|
+
- `cnos run` when a child process should get CNOS directly at launch time
|
|
15
|
+
|
|
16
|
+
## Docker
|
|
17
|
+
|
|
18
|
+
Generate a Docker-friendly env file:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
cnos build env --profile local-domain --format docker-env --to .docker/runtime/current.env
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
That file is a derived artifact. Keep it gitignored.
|
|
25
|
+
|
|
26
|
+
For a production-style local preview flow:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pnpm build:local-domain:all
|
|
30
|
+
cnos build env --profile local-domain --format docker-env --to .docker/runtime/current.env
|
|
31
|
+
docker compose up --build
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Use this when:
|
|
35
|
+
- your image or emulator runtime expects env vars
|
|
36
|
+
- you want one fixed runtime env file per profile
|
|
37
|
+
- the build already consumed the same CNOS profile
|
|
38
|
+
|
|
39
|
+
## Docker Compose
|
|
40
|
+
|
|
41
|
+
Recommended compose pattern:
|
|
42
|
+
|
|
43
|
+
```yaml
|
|
44
|
+
services:
|
|
45
|
+
app:
|
|
46
|
+
env_file:
|
|
47
|
+
- ./.docker/runtime/current.env
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
This keeps runtime env injection explicit and lets the same CNOS profile drive:
|
|
51
|
+
- the build step
|
|
52
|
+
- the container runtime
|
|
53
|
+
- local emulators
|
|
54
|
+
|
|
55
|
+
For browser builds behind nginx or another proxy:
|
|
56
|
+
- build the app first with `cnos run --profile <name> -- pnpm build`
|
|
57
|
+
- then feed compose/runtime with `cnos build env --format docker-env`
|
|
58
|
+
|
|
59
|
+
## Kubernetes
|
|
60
|
+
|
|
61
|
+
Use CNOS to render the env payload before applying manifests:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
cnos build env --profile stage --format yaml --to k8s/generated/app-config.yaml
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Or generate a flat env file and convert it into a ConfigMap or Secret with your existing tooling:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
cnos build env --profile stage --format dotenv --to .artifacts/stage.env
|
|
71
|
+
kubectl create configmap app-config --from-env-file=.artifacts/stage.env --dry-run=client -o yaml
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Rules:
|
|
75
|
+
- do not make Kubernetes manifests the source of truth for application config
|
|
76
|
+
- do not embed decrypted CNOS secret values into build artifacts by default
|
|
77
|
+
- prefer runtime secret providers or platform-native secrets for secret plaintext
|
|
78
|
+
|
|
79
|
+
## GitHub Actions
|
|
80
|
+
|
|
81
|
+
Two good patterns exist.
|
|
82
|
+
|
|
83
|
+
### 1. Build with direct CNOS injection
|
|
84
|
+
|
|
85
|
+
```yaml
|
|
86
|
+
- name: Install deps
|
|
87
|
+
run: pnpm install --frozen-lockfile
|
|
88
|
+
|
|
89
|
+
- name: Build with CNOS
|
|
90
|
+
run: cnos run --profile stage -- pnpm build
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 2. Materialize an env artifact first
|
|
94
|
+
|
|
95
|
+
```yaml
|
|
96
|
+
- name: Build CNOS env file
|
|
97
|
+
run: cnos build env --profile stage --to .env.stage
|
|
98
|
+
|
|
99
|
+
- name: Build app
|
|
100
|
+
run: pnpm build
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
For browser-only frameworks:
|
|
104
|
+
|
|
105
|
+
```yaml
|
|
106
|
+
- name: Build public env for Vite
|
|
107
|
+
run: cnos build public --framework vite --profile stage --to .env.stage
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
For Next:
|
|
111
|
+
|
|
112
|
+
```yaml
|
|
113
|
+
- name: Build public env for Next
|
|
114
|
+
run: cnos build public --framework next --profile prod --to .env.production
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
For server packaging:
|
|
118
|
+
|
|
119
|
+
```yaml
|
|
120
|
+
- name: Build server projection
|
|
121
|
+
run: cnos build server --profile prod --to dist/.cnos-server.json
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Secret handling
|
|
125
|
+
|
|
126
|
+
Keep this split clear:
|
|
127
|
+
|
|
128
|
+
- non-secret config can become a build or runtime artifact
|
|
129
|
+
- decrypted secret plaintext should not become a build artifact by default
|
|
130
|
+
|
|
131
|
+
Use:
|
|
132
|
+
- CNOS vault refs
|
|
133
|
+
- platform env injection
|
|
134
|
+
- runtime secret hydration
|
|
135
|
+
|
|
136
|
+
Do not rely on generated env files for secret rotation-sensitive server secrets unless you deliberately accept that tradeoff.
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Derived Values
|
|
3
|
+
description: Compute config from other CNOS keys and live runtime namespaces.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Derived Values
|
|
7
|
+
|
|
8
|
+
Derived values let you keep config composition inside CNOS instead of re-implementing it in app code.
|
|
9
|
+
|
|
10
|
+
Template shorthand:
|
|
11
|
+
|
|
12
|
+
```yaml
|
|
13
|
+
app:
|
|
14
|
+
origin:
|
|
15
|
+
$derive: "${value.app.protocol}://${value.app.host}:${value.app.port}"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Expression form:
|
|
19
|
+
|
|
20
|
+
```yaml
|
|
21
|
+
app:
|
|
22
|
+
effective_port:
|
|
23
|
+
$derive:
|
|
24
|
+
expr: "coalesce(process.env.PORT, value.app.default_port, '3000')"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Write from the CLI
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
cnos value set app.origin --derive '${value.app.protocol}://${value.app.host}'
|
|
31
|
+
cnos value set app.effective_port --derive --expr "coalesce(process.env.PORT, value.app.default_port, '3000')"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Built-ins
|
|
35
|
+
|
|
36
|
+
Supported functions:
|
|
37
|
+
|
|
38
|
+
- `concat(...)`
|
|
39
|
+
- `coalesce(...)`
|
|
40
|
+
- `when(condition, thenValue, elseValue)`
|
|
41
|
+
- `exists(ref)`
|
|
42
|
+
- `eq(a, b)`
|
|
43
|
+
- `ne(a, b)`
|
|
44
|
+
|
|
45
|
+
The language is intentionally small and safe. There is no arbitrary JavaScript execution.
|
|
46
|
+
|
|
47
|
+
## Runtime Namespaces
|
|
48
|
+
|
|
49
|
+
`process.*` is the built-in runtime namespace. It stays live between reads.
|
|
50
|
+
|
|
51
|
+
```yaml
|
|
52
|
+
app:
|
|
53
|
+
effective_port:
|
|
54
|
+
$derive:
|
|
55
|
+
expr: "coalesce(process.env.PORT, value.app.default_port, '3000')"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Custom runtime namespaces are declared in the manifest and populated by the host app:
|
|
59
|
+
|
|
60
|
+
```yaml
|
|
61
|
+
namespaces:
|
|
62
|
+
runtime:
|
|
63
|
+
request:
|
|
64
|
+
description: HTTP request context
|
|
65
|
+
server_only: true
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import cnos from '@kitsy/cnos';
|
|
70
|
+
|
|
71
|
+
await cnos.ready();
|
|
72
|
+
|
|
73
|
+
cnos.registerRuntimeProvider('request', (key) => {
|
|
74
|
+
if (key === 'headers.host') {
|
|
75
|
+
return currentRequest?.headers.host;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return undefined;
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Caching Rules
|
|
83
|
+
|
|
84
|
+
- config-only derivations are cached once per resolution pass
|
|
85
|
+
- runtime-dependent derivations are never cached
|
|
86
|
+
|
|
87
|
+
That means `value.app.origin` is stable until the next `createCnos()` or `cnos.ready()`, while `value.app.effective_port` can change between reads when `process.env.PORT` changes.
|
|
88
|
+
|
|
89
|
+
## Browser and Server Behavior
|
|
90
|
+
|
|
91
|
+
Browser/public outputs always need concrete values.
|
|
92
|
+
|
|
93
|
+
- config-only derived values can be promoted and embedded normally
|
|
94
|
+
- runtime-dependent derived values that rely on server-only namespaces are rejected for browser/public builds
|
|
95
|
+
|
|
96
|
+
Server projections split the result:
|
|
97
|
+
|
|
98
|
+
- `values` contains concrete non-secret values, including config-only derivations
|
|
99
|
+
- `derived` contains live runtime-dependent formulas
|
|
100
|
+
- `runtimeNamespaces` lists which runtime providers the server runtime needs
|
|
101
|
+
|
|
102
|
+
## Use Cases
|
|
103
|
+
|
|
104
|
+
Cross-app browser links:
|
|
105
|
+
|
|
106
|
+
```yaml
|
|
107
|
+
apps:
|
|
108
|
+
cnos:
|
|
109
|
+
origin:
|
|
110
|
+
$derive: "${value.platform.protocol}://${value.apps.cnos.host}"
|
|
111
|
+
|
|
112
|
+
public:
|
|
113
|
+
promote:
|
|
114
|
+
- value.apps.cnos.origin
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import cnos from '@kitsy/cnos/browser';
|
|
119
|
+
|
|
120
|
+
const cnosOrigin = cnos('public.apps.cnos.origin');
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Server fallback port:
|
|
124
|
+
|
|
125
|
+
```yaml
|
|
126
|
+
server:
|
|
127
|
+
port:
|
|
128
|
+
$derive:
|
|
129
|
+
expr: "coalesce(process.env.PORT, value.server.default_port, '3000')"
|
|
130
|
+
```
|
|
@@ -40,6 +40,58 @@ console.log(cnos('public.app.apiBaseUrl'));
|
|
|
40
40
|
console.log(import.meta.env.VITE_APP_API_BASE_URL);
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
+
Cross-app browser links work the same way. Put the browser-safe origins in CNOS, promote them, and let the Vite plugin handle the embedding:
|
|
44
|
+
|
|
45
|
+
```yaml
|
|
46
|
+
public:
|
|
47
|
+
promote:
|
|
48
|
+
- value.apps.main.origin
|
|
49
|
+
- value.apps.cnos.origin
|
|
50
|
+
- value.apps.coop.origin
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```yaml
|
|
54
|
+
apps:
|
|
55
|
+
main:
|
|
56
|
+
origin: https://kitsy.ai
|
|
57
|
+
cnos:
|
|
58
|
+
origin: https://cnos.kitsy.ai
|
|
59
|
+
coop:
|
|
60
|
+
origin: https://coop.kitsy.ai
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Then in UI code:
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import cnos from '@kitsy/cnos/browser';
|
|
67
|
+
|
|
68
|
+
const cnosOrigin = cnos('public.apps.cnos.origin');
|
|
69
|
+
const coopOrigin = cnos('public.apps.coop.origin');
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
That is the point of the integration. You promote once, keep using the same logical reads in UI code, and `@kitsy/cnos-vite` makes sure the values are already present in the browser bundle.
|
|
73
|
+
|
|
74
|
+
Derived public values work the same way as long as they are build-safe:
|
|
75
|
+
|
|
76
|
+
```yaml
|
|
77
|
+
apps:
|
|
78
|
+
cnos:
|
|
79
|
+
origin:
|
|
80
|
+
$derive: "${value.platform.protocol}://${value.apps.cnos.host}"
|
|
81
|
+
|
|
82
|
+
public:
|
|
83
|
+
promote:
|
|
84
|
+
- value.apps.cnos.origin
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import cnos from '@kitsy/cnos/browser';
|
|
89
|
+
|
|
90
|
+
const cnosOrigin = cnos('public.apps.cnos.origin');
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
If a promoted derived value depends on a server-only runtime namespace such as `process.*` or a custom `request.*`, CNOS rejects the browser/public build instead of leaking an unstable value.
|
|
94
|
+
|
|
43
95
|
Migration path:
|
|
44
96
|
|
|
45
97
|
1. keep `VITE_*` working through generated env files
|
|
@@ -15,6 +15,7 @@ Use generated env files as a **bridge**, not as the source of truth.
|
|
|
15
15
|
cnos build env --profile local --to .env.local
|
|
16
16
|
cnos build env --profile stage --to .env.stage
|
|
17
17
|
cnos build env --profile prod --to .env.prod
|
|
18
|
+
cnos build env --profile local-domain --format docker-env --to .docker/runtime/current.env
|
|
18
19
|
```
|
|
19
20
|
|
|
20
21
|
## Watched dev loop
|
|
@@ -36,3 +37,4 @@ cnos build env --public --framework next --profile prod --to .env.production
|
|
|
36
37
|
- keep generated `.env.*` files gitignored
|
|
37
38
|
- migrate app code toward direct CNOS reads over time
|
|
38
39
|
- keep secrets on runtime/vault flows instead of materializing them into env files by default
|
|
40
|
+
- use `docker-env` when Docker or Docker Compose expects a runtime env file
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Remote Roots
|
|
3
|
+
description: Point .cnosrc.yml at a remote git-backed CNOS root and consume it through the local cache.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Remote Roots
|
|
7
|
+
|
|
8
|
+
`.cnosrc.yml` can point at either a local `.cnos` directory or a remote git-backed root.
|
|
9
|
+
|
|
10
|
+
Local:
|
|
11
|
+
|
|
12
|
+
```yaml
|
|
13
|
+
root: ./.cnos
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Remote:
|
|
17
|
+
|
|
18
|
+
```yaml
|
|
19
|
+
root: git+https://github.com/org/config.git#v2.1.0
|
|
20
|
+
workspace: travel
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Remote roots are resolved into the CNOS cache, then loaded exactly like a local manifest root.
|
|
24
|
+
|
|
25
|
+
## Supported URIs
|
|
26
|
+
|
|
27
|
+
Recommended production form:
|
|
28
|
+
|
|
29
|
+
```yaml
|
|
30
|
+
root: git+https://github.com/org/config.git#v2.1.0
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Private repo over SSH:
|
|
34
|
+
|
|
35
|
+
```yaml
|
|
36
|
+
root: git+ssh://git@github.com/org/private-config.git#main
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Subpath inside the repo:
|
|
40
|
+
|
|
41
|
+
```yaml
|
|
42
|
+
root: git+https://github.com/org/monorepo.git#v2.1.0:config/.cnos
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Cache Behavior
|
|
46
|
+
|
|
47
|
+
- semantic-version tags and commit SHAs are treated as immutable
|
|
48
|
+
- branch refs are treated as mutable
|
|
49
|
+
- runtime reads use a cache TTL
|
|
50
|
+
- `cnos build` refreshes mutable refs before building artifacts
|
|
51
|
+
- `cnos cache refresh` forces a re-fetch when needed
|
|
52
|
+
|
|
53
|
+
Inspect the cache:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
cnos cache list
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Override TTL for one command when needed:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
cnos read value.app.name --cache-ttl 0
|
|
63
|
+
cnos watch --cache-ttl 15 -- node server.js
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Read-Only Model
|
|
67
|
+
|
|
68
|
+
Remote roots are consumed as read-only config.
|
|
69
|
+
|
|
70
|
+
These work:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
cnos read value.app.name
|
|
74
|
+
cnos build env --to .env.stage
|
|
75
|
+
cnos run -- node server.js
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
These are blocked:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
cnos value set app.name demo
|
|
82
|
+
cnos promote value.app.name --to public
|
|
83
|
+
cnos vault create default
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The right workflow is to edit the source config repo and then let consumers refresh the cached root.
|
|
@@ -22,6 +22,13 @@ root: ../../.cnos
|
|
|
22
22
|
workspace: travel
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
Child app from a remote config repo:
|
|
26
|
+
|
|
27
|
+
```yaml
|
|
28
|
+
root: git+https://github.com/org/config.git#v2.1.0
|
|
29
|
+
workspace: travel
|
|
30
|
+
```
|
|
31
|
+
|
|
25
32
|
`.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
33
|
|
|
27
34
|
Typical manifest shape:
|
|
@@ -12,6 +12,7 @@ Primary namespaces:
|
|
|
12
12
|
- `meta.*`
|
|
13
13
|
- `process.*` for server-only ambient runtime state
|
|
14
14
|
- custom data namespaces such as `flags.*` or `config.*` when declared in `.cnos/cnos.yml`
|
|
15
|
+
- custom runtime namespaces declared under `namespaces.runtime`
|
|
15
16
|
|
|
16
17
|
Derived surfaces:
|
|
17
18
|
|
|
@@ -35,3 +36,36 @@ Custom data namespaces can be:
|
|
|
35
36
|
- `process.env.PATH`
|
|
36
37
|
|
|
37
38
|
`process.*` cannot be promoted or exported.
|
|
39
|
+
|
|
40
|
+
## Runtime Namespaces
|
|
41
|
+
|
|
42
|
+
Runtime namespaces are not populated from config files. They are declared in the manifest and populated by the host runtime.
|
|
43
|
+
|
|
44
|
+
```yaml
|
|
45
|
+
namespaces:
|
|
46
|
+
runtime:
|
|
47
|
+
request:
|
|
48
|
+
description: HTTP request context
|
|
49
|
+
server_only: true
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Use them from derived values:
|
|
53
|
+
|
|
54
|
+
```yaml
|
|
55
|
+
app:
|
|
56
|
+
current_host:
|
|
57
|
+
$derive:
|
|
58
|
+
expr: "coalesce(request.headers.host, value.app.default_host)"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
And register providers in server code:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
cnos.registerRuntimeProvider('request', (key) => {
|
|
65
|
+
if (key === 'headers.host') {
|
|
66
|
+
return currentRequest?.headers.host;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return undefined;
|
|
70
|
+
});
|
|
71
|
+
```
|
package/manifest.yml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
product: cnos
|
|
2
2
|
title: CNOS Documentation
|
|
3
3
|
tagline: Configuration orchestration for apps, monorepos, and deployment pipelines
|
|
4
|
-
version: "1.
|
|
4
|
+
version: "1.7"
|
|
5
5
|
|
|
6
6
|
sidebar:
|
|
7
7
|
- group: Getting Started
|
|
@@ -29,10 +29,16 @@ sidebar:
|
|
|
29
29
|
label: SSR Projects
|
|
30
30
|
- path: guides/ci-cd
|
|
31
31
|
label: CI/CD Pipelines
|
|
32
|
+
- path: guides/containers-and-actions
|
|
33
|
+
label: Containers and Actions
|
|
32
34
|
- path: guides/workspaces
|
|
33
35
|
label: Workspaces and Monorepos
|
|
36
|
+
- path: guides/remote-roots
|
|
37
|
+
label: Remote Roots
|
|
34
38
|
- path: guides/profiles
|
|
35
39
|
label: Profiles and Environments
|
|
40
|
+
- path: guides/derived-values
|
|
41
|
+
label: Derived Values
|
|
36
42
|
- path: guides/secrets
|
|
37
43
|
label: Secrets and Vaults
|
|
38
44
|
- path: guides/migration
|
|
@@ -61,6 +67,8 @@ sidebar:
|
|
|
61
67
|
label: cnos export
|
|
62
68
|
- path: cli/build
|
|
63
69
|
label: cnos build env
|
|
70
|
+
- path: cli/cache
|
|
71
|
+
label: cnos cache
|
|
64
72
|
- path: cli/dev
|
|
65
73
|
label: cnos dev env
|
|
66
74
|
- path: cli/run
|