@konfig.ts/env 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +60 -72
  2. package/package.json +8 -8
package/README.md CHANGED
@@ -1,100 +1,88 @@
1
1
  # @konfig.ts/env
2
2
 
3
- Yieldable environment entries the shared definition layer between
4
- konfig manifest emission and the pod's runtime Effect application.
3
+ One declaration for a pod's environment, shared by both sides of the wire: the
4
+ Kubernetes manifest that injects the env vars, and the app code that decodes
5
+ them at startup. Name `DATABASE_URL` once — rename it in one place and the
6
+ typechecker flags every consumer.
5
7
 
6
- ## Why
8
+ ## Install
7
9
 
8
- A pod's environment variables live in two places today:
10
+ ```bash
11
+ bun add @konfig.ts/env
12
+ ```
9
13
 
10
- - The konfig manifest (`secretEnv({ name: "DATABASE_URL", ... })`,
11
- `valueEnv`, `configMapEnv`).
12
- - The pod's runtime code (`Config.redacted("DATABASE_URL")`).
14
+ ## Usage
13
15
 
14
- The env-var name `"DATABASE_URL"` is duplicated. This package collapses
15
- both ends into one declaration:
16
+ Declare the contract once, in a module both sides import:
16
17
 
17
18
  ```ts
18
- // shared/secrets.ts imported by both sides
19
- import { defineEnvironment, defineLiteral, defineSecret } from "@konfig.ts/env"
19
+ import { Downward, Environment, Literal, Secret } from "@konfig.ts/env"
20
20
 
21
- export const dbCreds = defineSecret({
21
+ export const dbCreds = Secret.define({
22
22
  name: "db-creds",
23
23
  namespace: "prod",
24
- env: {
25
- url: "DATABASE_URL",
26
- password: "DATABASE_PASSWORD"
27
- }
24
+ env: { url: "DATABASE_URL", password: "DATABASE_PASSWORD" }
28
25
  })
29
26
 
30
- export const port = defineLiteral({ envName: "PORT", value: 8080 })
31
-
32
- export const apiEnv = defineEnvironment({ db: dbCreds, port })
27
+ export const apiEnv = Environment.define({
28
+ db: dbCreds,
29
+ http: Environment.define({
30
+ port: Literal.define({ envName: "HTTP_PORT", value: 8080 }),
31
+ logLevel: Literal.define({ envName: "LOG_LEVEL", value: "info" })
32
+ }),
33
+ runtime: Environment.define({
34
+ nodeEnv: Literal.define({ envName: "NODE_ENV", value: "production" }),
35
+ podName: Downward.define({ envName: "POD_NAME", fieldPath: "metadata.name" })
36
+ })
37
+ })
33
38
  ```
34
39
 
35
- ## Entries and environments
36
-
37
- Every `defineSecret` / `defineLiteral` / `defineDownward` call returns
38
- an **entry** — a yieldable Effect `Config<...>` intersected with the
39
- pure binding metadata (`name`, `namespace`, `env`/`envName`). Each
40
- entry is its own state-management-style atom: pull it standalone, or
41
- group it.
42
-
43
- `defineEnvironment({...})` is a **bundle** — also a yieldable Config,
44
- with `.members` re-exposing each named entry.
40
+ Then use the same `apiEnv` from both sides. `bind` (manifest) and `runtime`
41
+ (process) both live in `@konfig.ts/k8s`:
45
42
 
46
43
  ```ts
47
- // runtime pod code
48
- import { Effect, Redacted } from "effect"
49
- import { apiEnv, dbCreds } from "./secrets"
50
-
51
- const program = Effect.gen(function*() {
52
- const env = yield* apiEnv // { db: { url: Redacted, password: Redacted }, port: number }
53
- const db = yield* dbCreds // { url: Redacted, password: Redacted }
54
- const url = yield* dbCreds.fields.url // Redacted<string>
55
- })
44
+ // infra module — emit the Deployment env block + the secret backend's CRs
45
+ import { Environment } from "@konfig.ts/k8s"
46
+ const bound = Environment.bind({ env: apiEnv, namespace: "prod", secrets: { db: { backend } } })
47
+ // bound.envVars → container env; bound.manifests → the CRs
48
+
49
+ // app process decode the same vars at startup, into a typed record
50
+ import { Environment } from "@konfig.ts/k8s"
51
+ import { Effect } from "effect"
52
+ const config = await Effect.runPromise(Environment.runtime(apiEnv))
53
+ console.log(`listening on :${config.http.port}`)
56
54
  ```
57
55
 
58
- ## Bound on the konfig side
56
+ ## Atoms
59
57
 
60
- `@konfig.ts/k8s` provides `Secret.bind({secret})` and
61
- `Environment.bind({env})` for the manifest-side wiring. They consume
62
- the same shared entries and produce ready-to-spread `envVars` for the
63
- container:
58
+ | Constructor | Produces |
59
+ | -------------------- | ---------------------------------------------------------------------------------- |
60
+ | `Secret.define` | a secret contract (`{ name, namespace, env }`), bound to a backend at compose time |
61
+ | `Literal.define` | a constant (`{ envName, value, schema? }`) baked into the manifest |
62
+ | `Downward.define` | a Kubernetes downward-API field (`{ envName, fieldPath }`) |
63
+ | `Environment.define` | a bundle of the above — nestable; the single source of truth for both sides |
64
+ | `SecretSource` | plaintext sources for backends: `.fromConfig`, `.literal`, `.fromCommand` |
64
65
 
65
- ```ts
66
- // konfig-side infra code
67
- import { Environment, Secret, Workload } from "@konfig.ts/k8s"
68
-
69
- const apiEnvK8s = Environment.bind({ env: apiEnv })
70
-
71
- Workload.web({
72
- /* ... */
73
- deployment: {
74
- containers: [{ name: "api", image: "...", env: apiEnvK8s.envVars }]
75
- }
76
- })
77
- ```
66
+ Two members claiming the same `envName` is a compile-time error
67
+ (`EnvNameCollision`) caught before it can silently shadow another.
78
68
 
79
- ## Status
69
+ ## Internals
80
70
 
81
- Phase 1 of the secret refactor see `.docs/secret-refactoring/plan.md`.
82
- Entries, bundles, env-var wiring only. Backends (ExternalSecrets,
83
- SealedSecrets, Sops) and the `source` / `values` accessors land in
84
- later phases.
71
+ An atom is a yieldable Effect `Config` intersected with its binding metadata; a
72
+ bundle is a `Config` over the whole tree. See the `Environment` section of
73
+ [`.docs/architecture.md`](../../.docs/architecture.md).
85
74
 
86
75
  ## Requirements
87
76
 
88
- konfig.ts builds on [Effect](https://effect.website/), which is still in
89
- beta. Until Effect ships a stable 4.x, you must install the exact beta
90
- konfig is developed against:
77
+ konfig.ts is built on [Effect](https://effect.website/), currently in beta.
78
+ Until Effect ships a stable 4.x, install the exact beta konfig.ts is built
79
+ against:
91
80
 
92
- - **`effect@4.0.0-beta.70`** — required.
93
- - **`@effect/platform-node@4.0.0-beta.70`** — required only for `render()`
94
- (the Node filesystem/subprocess entrypoint); manifest-only consumers can
95
- omit it.
81
+ - **`effect@4.0.0-beta.70`** — required by every package.
82
+ - **`@effect/platform-node@4.0.0-beta.70`** — required only when you call
83
+ `render()` (the Node filesystem/subprocess entrypoint); manifest-only
84
+ consumers can omit it (it is declared as an optional peer).
96
85
 
97
- The peer dependency is pinned to the exact version on purpose: Effect's beta
98
- line makes breaking changes between builds, so a looser range would surface
99
- as `ERESOLVE` install conflicts rather than a working install. This pin will
100
- relax to a caret range once Effect reaches a stable 4.x.
86
+ The pin is exact on purpose: Effect's beta line makes breaking changes between
87
+ builds, so a looser range surfaces as `ERESOLVE` install conflicts. It relaxes
88
+ to a caret range once Effect reaches a stable 4.x.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@konfig.ts/env",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "Yieldable environment atoms (defineSecret, defineLiteral, defineDownward, defineEnvironment) shared between konfig manifest emission and the runtime pod application.",
5
5
  "license": "MIT",
6
6
  "author": "David Stahl-Gruber",
@@ -51,17 +51,17 @@
51
51
  "postpack": "node ../../scripts/prepack-exports.mjs restore"
52
52
  },
53
53
  "dependencies": {
54
- "@konfig.ts/core": "0.0.1"
54
+ "@konfig.ts/core": "0.0.3"
55
55
  },
56
56
  "peerDependencies": {
57
57
  "effect": "4.0.0-beta.70"
58
58
  },
59
59
  "devDependencies": {
60
- "@effect/vitest": "catalog:",
61
- "@types/bun": "catalog:",
62
- "effect": "catalog:",
63
- "fast-check": "catalog:",
64
- "typescript": "catalog:",
65
- "vitest": "catalog:"
60
+ "@effect/vitest": "4.0.0-beta.70",
61
+ "@types/bun": "^1.3.6",
62
+ "effect": "4.0.0-beta.70",
63
+ "fast-check": "^4.7.0",
64
+ "typescript": "^5.8.3",
65
+ "vitest": "^4.0.18"
66
66
  }
67
67
  }