@kitsy/cnos-docs 1.6.1 → 1.8.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 +54 -0
- package/docs/api/runtime.mdx +44 -0
- package/docs/cli/build.mdx +1 -1
- package/docs/cli/cache.mdx +28 -0
- package/docs/cli/init.mdx +1 -1
- package/docs/cli/inspect.mdx +28 -0
- package/docs/cli/value.mdx +17 -0
- package/docs/cli/workspace.mdx +70 -0
- package/docs/getting-started/quick-start.mdx +8 -0
- package/docs/getting-started/your-first-project.mdx +7 -0
- package/docs/guides/backend.mdx +25 -0
- package/docs/guides/derived-values.mdx +130 -0
- package/docs/guides/frontend-vite.mdx +52 -0
- package/docs/guides/remote-roots.mdx +86 -0
- package/docs/guides/workspaces.mdx +44 -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,57 @@ 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
|
+
```
|
|
57
|
+
|
|
58
|
+
Workspace selection can come from three places:
|
|
59
|
+
|
|
60
|
+
1. explicit `workspace` in `createCnos({ ... })`
|
|
61
|
+
2. a package-local `.cnosrc.yml`
|
|
62
|
+
3. the manifest default workspace
|
|
63
|
+
|
|
64
|
+
Typical monorepo package anchor:
|
|
65
|
+
|
|
66
|
+
```yaml
|
|
67
|
+
root: ../../.cnos
|
|
68
|
+
workspace: api
|
|
69
|
+
```
|
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,7 +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 .
|
|
16
|
+
cnos build env --profile local-domain --format docker-env --to .env.local-domain
|
|
17
17
|
```
|
|
18
18
|
|
|
19
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/init.mdx
CHANGED
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.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: cnos workspace
|
|
3
|
+
description: Add, list, remove, scaffold, attach, and detach workspaces.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# cnos workspace
|
|
7
|
+
|
|
8
|
+
Use `cnos workspace` when a repo has more than one app or package consuming the same CNOS root.
|
|
9
|
+
|
|
10
|
+
## Add a workspace
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
cnos workspace add travel --package-root apps/travel --extends base
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
This updates `cnos.yml`, creates `.cnos/workspaces/travel`, and writes:
|
|
17
|
+
|
|
18
|
+
```yaml
|
|
19
|
+
# apps/travel/.cnosrc.yml
|
|
20
|
+
root: ../../.cnos
|
|
21
|
+
workspace: travel
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Onboard an older single-root project into workspace mode
|
|
25
|
+
|
|
26
|
+
If a repo already has a flat `.cnos/values`, `.cnos/secrets`, `.cnos/env`, and `.cnos/profiles` tree, migrate it like this:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
cnos workspace add main --onboard-current
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
CNOS will:
|
|
33
|
+
|
|
34
|
+
1. move the existing flat config folders into `.cnos/workspaces/main`
|
|
35
|
+
2. rewrite the root anchor to `workspace: main`
|
|
36
|
+
3. keep the repo in one authoritative `.cnos` root
|
|
37
|
+
|
|
38
|
+
## List workspaces
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
cnos workspace list
|
|
42
|
+
cnos workspace list --json
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Remove a workspace
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
cnos workspace remove gallery
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
CNOS removes the manifest entry and deletes `.cnos/workspaces/gallery`. It refuses to remove the current default workspace until you change `workspaces.default`.
|
|
52
|
+
|
|
53
|
+
## Scaffold wording
|
|
54
|
+
|
|
55
|
+
If your team prefers scaffold wording:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
cnos workspace scaffold insights --package-root apps/insights --extends base
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
This follows the same creation path as `workspace add`.
|
|
62
|
+
|
|
63
|
+
## Detach and attach
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
cnos workspace detach --package-root apps/travel
|
|
67
|
+
cnos workspace attach --package-root apps/travel
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Detach makes a child package independent. Attach imports it back into the parent workspace model.
|
|
@@ -34,6 +34,14 @@ console.log(runtime.value('app.name'));
|
|
|
34
34
|
console.log(runtime.read<string[]>('value.api.default_query_params'));
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
+
If your repo grows into multiple apps or packages, switch to workspace mode instead of duplicating `.cnos` trees:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
cnos workspace add main --package-root apps/main --extends base
|
|
41
|
+
cnos workspace add insights --package-root apps/insights --extends base
|
|
42
|
+
cnos workspace list
|
|
43
|
+
```
|
|
44
|
+
|
|
37
45
|
If your repo still expects env files, keep `.cnos` as the source of truth and generate them:
|
|
38
46
|
|
|
39
47
|
```bash
|
|
@@ -26,6 +26,13 @@ cnos profile create stage
|
|
|
26
26
|
cnos use --profile stage
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
+
If this later becomes a monorepo, do not create a second `.cnos`. Add workspaces instead:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
cnos workspace add api --package-root apps/api --extends base
|
|
33
|
+
cnos workspace add admin --package-root apps/admin --extends base
|
|
34
|
+
```
|
|
35
|
+
|
|
29
36
|
Create a local vault and authenticate it:
|
|
30
37
|
|
|
31
38
|
```bash
|
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
|
|
@@ -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
|
|
@@ -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:
|
|
@@ -39,6 +46,43 @@ workspaces:
|
|
|
39
46
|
|
|
40
47
|
This lets you keep shared values in `root` and override only what each app needs in `travel`, `food`, or other child workspaces.
|
|
41
48
|
|
|
49
|
+
## Day-to-day workspace management
|
|
50
|
+
|
|
51
|
+
Add a new app workspace:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
cnos workspace add insights --package-root apps/insights --extends root
|
|
55
|
+
cnos workspace add gallery --package-root apps/gallery --extends root
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
List what exists:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
cnos workspace list
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Remove one later:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
cnos workspace remove gallery
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Migrating an older single-root repo into workspace mode
|
|
71
|
+
|
|
72
|
+
If a repo was initialized earlier with:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
cnos init
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
and the current config still lives directly under `.cnos/values`, `.cnos/secrets`, `.cnos/env`, and `.cnos/profiles`, move that existing config into a real workspace with:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
cnos workspace add main --onboard-current
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
CNOS will move the physical folders into `.cnos/workspaces/main` and rewrite the local anchor so the repo now behaves as a workspace-aware project.
|
|
85
|
+
|
|
42
86
|
Read from an app package without passing a root manually:
|
|
43
87
|
|
|
44
88
|
```ts
|
|
@@ -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.8"
|
|
5
5
|
|
|
6
6
|
sidebar:
|
|
7
7
|
- group: Getting Started
|
|
@@ -33,8 +33,12 @@ sidebar:
|
|
|
33
33
|
label: Containers and Actions
|
|
34
34
|
- path: guides/workspaces
|
|
35
35
|
label: Workspaces and Monorepos
|
|
36
|
+
- path: guides/remote-roots
|
|
37
|
+
label: Remote Roots
|
|
36
38
|
- path: guides/profiles
|
|
37
39
|
label: Profiles and Environments
|
|
40
|
+
- path: guides/derived-values
|
|
41
|
+
label: Derived Values
|
|
38
42
|
- path: guides/secrets
|
|
39
43
|
label: Secrets and Vaults
|
|
40
44
|
- path: guides/migration
|
|
@@ -49,6 +53,8 @@ sidebar:
|
|
|
49
53
|
label: Overview
|
|
50
54
|
- path: cli/init
|
|
51
55
|
label: cnos init
|
|
56
|
+
- path: cli/workspace
|
|
57
|
+
label: cnos workspace
|
|
52
58
|
- path: cli/value
|
|
53
59
|
label: cnos value
|
|
54
60
|
- path: cli/secret
|
|
@@ -63,6 +69,8 @@ sidebar:
|
|
|
63
69
|
label: cnos export
|
|
64
70
|
- path: cli/build
|
|
65
71
|
label: cnos build env
|
|
72
|
+
- path: cli/cache
|
|
73
|
+
label: cnos cache
|
|
66
74
|
- path: cli/dev
|
|
67
75
|
label: cnos dev env
|
|
68
76
|
- path: cli/run
|