@konfig.ts/k8s 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 +72 -130
  2. package/package.json +10 -10
package/README.md CHANGED
@@ -1,154 +1,96 @@
1
1
  # @konfig.ts/k8s
2
2
 
3
- Kubernetes resource constructors with branded references on top of
4
- `@konfig.ts/core`'s `Manifest<A>` carrier. The brands are where the
5
- package earns its keep: cross-resource invariants (env-var Secret,
6
- volume ConfigMap, Ingress TLS Secret) are checked at the type level,
7
- and the `Dep.*` tracking propagates needs/provides through Effect
8
- `Layer`s.
3
+ Kubernetes resource builders with branded references. Cross-resource links — an
4
+ env var to a Secret, a volume to a ConfigMap, Ingress TLS to a Secret — are
5
+ checked at the type level, so a workload pointing at a Secret nobody creates is
6
+ a compile error, not a failed `argocd sync`.
9
7
 
10
- ## Branded references
8
+ ## Install
11
9
 
12
- ```ts
13
- import { ConfigMapRef, SecretRef, ServiceAccountRef } from "@konfig.ts/k8s"
14
-
15
- const apiCreds = SecretRef.of("api-creds") // SecretRef<"api-creds">
16
- const cfg = ConfigMapRef.of("oauth-templates") // ConfigMapRef<"oauth-templates">
17
- const sa = ServiceAccountRef.of("api") // ServiceAccountRef<"api">
10
+ ```bash
11
+ bun add @konfig.ts/k8s
18
12
  ```
19
13
 
20
- Each ref carries the resource _name_ in its type parameter. The
21
- enforcement points (env var `secretKeyRef` / `configMapKeyRef`, volume
22
- secret, volume configMap, `imagePullSecret`, Ingress TLS) all accept the
23
- branded type and reject raw strings.
24
-
25
- ## Identity constructors expose `.ref`
26
-
27
- ```ts
28
- const apiSecret = Secret.make({ name: "api-creds", namespace: "prod", stringData: {...} });
29
- // apiSecret.ref is a SecretRef<"api-creds">
30
- ```
14
+ ## Usage
31
15
 
32
- The `.ref` accessor means consumers wire the brand through without
33
- restating the name:
16
+ Compose a container and a web workload (Deployment + Service, plus an Ingress
17
+ if you add one):
34
18
 
35
19
  ```ts
36
- const env = secretEnv("DATABASE_URL", { ref: apiSecret.ref, key: "url" })
20
+ import { Container, EnvVar, Port, Secret, Workload } from "@konfig.ts/k8s"
21
+
22
+ const apiCreds = Secret.make({
23
+ name: "api-creds",
24
+ namespace: "prod",
25
+ stringData: { url: "postgres://…" }
26
+ }) // apiCreds.ref is a SecretRef<"api-creds">
27
+
28
+ const api = Container.define({
29
+ name: "api",
30
+ image: "ghcr.io/example/api:1.0.0",
31
+ ports: [Port.make({ name: "http", containerPort: 8080 })],
32
+ env: [
33
+ // ref is branded — a raw string, or a Secret in the wrong namespace, won't compile
34
+ EnvVar.fromSecretForPod({ name: "DATABASE_URL", ref: apiCreds.ref, key: "url", podNamespace: "prod" }),
35
+ EnvVar.value({ name: "LOG_LEVEL", value: "info" })
36
+ ],
37
+ readinessProbe: { httpGet: { path: "/healthz", port: Port.ref("http") } }
38
+ })
39
+
40
+ const workload = Workload.web({
41
+ name: "api",
42
+ namespace: "prod",
43
+ deployment: { replicas: 2, containers: [api] },
44
+ service: { ports: [{ port: 80, targetPort: Port.ref("http") }] }
45
+ })
37
46
  ```
38
47
 
39
- ## Env-var helpers
40
-
41
- | Helper | Rejects raw string for |
42
- | ------------------------------------------- | ---------------------- |
43
- | `valueEnv(name, value)` | n/a |
44
- | `secretEnv(name, {ref, key, optional?})` | `ref` |
45
- | `configMapEnv(name, {ref, key, optional?})` | `ref` |
46
- | `rawEnv({name, value?, valueFrom?})` | n/a (escape hatch) |
47
-
48
- ## Volume helpers
49
-
50
- | Helper |
51
- | ----------------------------------- |
52
- | `volumeFromSecret(name, ref)` |
53
- | `volumeFromConfigMap(name, ref)` |
54
- | `emptyDirVolume(name, opts?)` |
55
- | `pvcVolume(name, claimName, opts?)` |
56
-
57
- ## Constructors
58
-
59
- Workload-tier (`Deployment.make`, `StatefulSet.make`, `Job.make`,
60
- `CronJob.make`) accept typed containers, `Volume`s,
61
- `imagePullSecrets: { name: SecretRef<N> }[]`, and
62
- `serviceAccountName: ServiceAccountRef | string`.
48
+ ## What's inside
63
49
 
64
- Network-tier (`Service.make`, `Ingress.make`). Ingress TLS uses the
65
- `ingressTLS(secretName, hosts?)` helper for branded refs.
50
+ **Branded refs** — `SecretRef`, `ConfigMapRef`, `ServiceAccountRef`, `PvcRef`.
51
+ Identity constructors (`Secret.make`, `ConfigMap.make`, …) expose a typed
52
+ `.ref`; the enforcement points (env `secretKeyRef`, volumes, `imagePullSecrets`,
53
+ Ingress TLS) take the brand and reject raw strings.
66
54
 
67
- Identity-tier (`Namespace.make`, `ServiceAccount.make`, `ConfigMap.make`,
68
- `Secret.make`) return constructors whose returned record carries the
69
- typed `.ref`.
55
+ **Env vars** — `EnvVar.value`, `EnvVar.fromSecretForPod`, `EnvVar.fromConfigMap`.
56
+ Duplicate names in one container's `env` are caught at compile time.
70
57
 
71
- Policy-tier (`PersistentVolume.make`, `PersistentVolumeClaim.make`,
72
- `NetworkPolicy.make`, `ClusterRole.make`, `ClusterRoleBinding.make`,
73
- `Role.make`, `RoleBinding.make`) — simple constructors with no extra
74
- dependencies.
58
+ **Ports** `Port.make({ name, containerPort })` and `Port.ref(name)` brand the
59
+ port-name union, so a probe or Service targeting a typo'd port won't compile.
75
60
 
76
- ## Higher-level: `Workload.web` and `Workload.cron`
61
+ **Workloads** `Workload.web` (Deployment + Service + optional Ingress) and
62
+ `Workload.cron` (CronJob + private ServiceAccount) cover the common shapes. The
63
+ lower-level `Deployment` / `StatefulSet` / `Job` / `CronJob` / `Service` /
64
+ `Ingress` and the identity / RBAC / policy constructors are there for bespoke
65
+ resources.
77
66
 
78
- Built for the workload shapes consumers need today not speculative.
67
+ **Env contracts & secrets** `Environment.bind` and `Secret.bind` turn a
68
+ [`@konfig.ts/env`](../env) contract into the Deployment env block plus a secret
69
+ backend's CRs ([sops](../sops), [sealed-secrets](../sealed-secrets),
70
+ [external-secrets](../external-secrets), or the built-in `NativeSecret`).
79
71
 
80
- `Workload.web(...)` composes Deployment + Service + (optional) Ingress
81
- with derived labels (`app: <name>`). `Workload.cron(...)` composes
82
- CronJob + ServiceAccount (the SA is private to the cron).
72
+ **Secret rotation** — `Workload.web({ reloader: "stakater" })` annotates for
73
+ [Stakater Reloader](https://github.com/stakater/Reloader) (rolls on in-cluster
74
+ change); `hashSecretValues` stamps a pod-spec hash that rolls on re-render.
83
75
 
84
- ## Secret rotation — build-time hash vs runtime Reloader
76
+ ## Internals
85
77
 
86
- konfig provides two complementary stories for restarting pods when a
87
- Secret or ConfigMap they consume changes:
88
-
89
- - **Build time** (`hashSecretValues` / `pod-hash` annotation). A SHA of
90
- the secret material lives on the pod spec; re-rendering after a
91
- rotation produces a new hash, so the Deployment's pod template
92
- changes and Kubernetes rolls. Fast feedback, deterministic — but only
93
- fires when konfig re-renders.
94
-
95
- - **Runtime** (`Workload.web({ reloader: "stakater" })`). Emits
96
- `reloader.stakater.com/auto: "true"` on the Deployment so
97
- [Stakater Reloader](https://github.com/stakater/Reloader) watches
98
- every referenced Secret/ConfigMap and patches the workload when the
99
- in-cluster object changes. Pair with `ExternalSecrets` or a
100
- controller that updates Secrets out-of-band.
101
-
102
- Pick build-time hashes for stateless render → apply pipelines; pick
103
- Reloader when secrets rotate independently of CI. They compose — a
104
- config-managed Secret with `reloader: "stakater"` rolls on both
105
- re-render and on out-of-band updates.
106
-
107
- ## Secret backends — `SecretBackend<N, K>`
108
-
109
- `SecretBackend` is the contract Sops / SealedSecrets / ExternalSecrets
110
- implement. `Secret.bind({ secret, backend, source? })` ties an env-bundle
111
- secret to a backend emission. `backend.requiresSource` is `true` for
112
- Sops and SealedSecrets (they need plaintext at render time) and `false`
113
- for ExternalSecrets (it just emits an `ExternalSecret` CR pointing at a
114
- remote store).
115
-
116
- ## k8s 1.30 types
117
-
118
- Re-exported from `kubernetes-types@1.30.0` under
119
- `src/.generated/k8s-types/`. We pin to the cluster minor and ship the
120
- re-export rather than rolling our own OpenAPI codegen.
121
-
122
- ## Layout
123
-
124
- ```
125
- src/
126
- ├── index.ts barrel
127
- ├── .generated/k8s-types/ thin re-export from kubernetes-types
128
- ├── refs.ts SecretRef, ConfigMapRef, ServiceAccountRef
129
- ├── env.ts secretEnv, configMapEnv, valueEnv, rawEnv
130
- ├── volume.ts volumeFromSecret, volumeFromConfigMap, ...
131
- ├── container.ts ContainerInput, PodSpecInput, imagePullSecret
132
- ├── identity.ts Namespace, ServiceAccount, ConfigMap, Secret
133
- ├── workload.ts Deployment, StatefulSet, Job, CronJob
134
- ├── network.ts Service, Ingress, ingressTLS
135
- ├── policy.ts PV, PVC, NetworkPolicy, RBAC
136
- ├── workloadHelpers.ts Workload.web, Workload.cron
137
- └── backend.ts SecretBackend contract + Secret.bind
138
- ```
78
+ Built on `@konfig.ts/core`'s `Manifest<A>` carrier; refs and `Dep.*` needs
79
+ propagate through Effect `Layer`s. Raw Kubernetes types are re-exported as the
80
+ `K8s` namespace (pinned `kubernetes-types@1.30.0`). See
81
+ [`.docs/architecture.md`](../../.docs/architecture.md).
139
82
 
140
83
  ## Requirements
141
84
 
142
- konfig.ts builds on [Effect](https://effect.website/), which is still in
143
- beta. Until Effect ships a stable 4.x, you must install the exact beta
144
- konfig is developed against:
85
+ konfig.ts is built on [Effect](https://effect.website/), currently in beta.
86
+ Until Effect ships a stable 4.x, install the exact beta konfig.ts is built
87
+ against:
145
88
 
146
- - **`effect@4.0.0-beta.70`** — required.
147
- - **`@effect/platform-node@4.0.0-beta.70`** — required only for `render()`
148
- (the Node filesystem/subprocess entrypoint); manifest-only consumers can
149
- omit it.
89
+ - **`effect@4.0.0-beta.70`** — required by every package.
90
+ - **`@effect/platform-node@4.0.0-beta.70`** — required only when you call
91
+ `render()` (the Node filesystem/subprocess entrypoint); manifest-only
92
+ consumers can omit it (it is declared as an optional peer).
150
93
 
151
- The peer dependency is pinned to the exact version on purpose: Effect's beta
152
- line makes breaking changes between builds, so a looser range would surface
153
- as `ERESOLVE` install conflicts rather than a working install. This pin will
154
- relax to a caret range once Effect reaches a stable 4.x.
94
+ The pin is exact on purpose: Effect's beta line makes breaking changes between
95
+ builds, so a looser range surfaces as `ERESOLVE` install conflicts. It relaxes
96
+ 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/k8s",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "Kubernetes resource builders (workloads, network, identity, policy, volume, env) for konfig.ts.",
5
5
  "license": "MIT",
6
6
  "author": "David Stahl-Gruber",
@@ -50,20 +50,20 @@
50
50
  "postpack": "node ../../scripts/prepack-exports.mjs restore"
51
51
  },
52
52
  "dependencies": {
53
- "@konfig.ts/core": "0.0.1",
54
- "@konfig.ts/env": "0.0.1",
53
+ "@konfig.ts/core": "0.0.3",
54
+ "@konfig.ts/env": "0.0.3",
55
55
  "kubernetes-types": "~1.30.0"
56
56
  },
57
57
  "peerDependencies": {
58
58
  "effect": "4.0.0-beta.70"
59
59
  },
60
60
  "devDependencies": {
61
- "@effect/platform-node": "catalog:",
62
- "@effect/vitest": "catalog:",
63
- "@types/bun": "catalog:",
64
- "effect": "catalog:",
65
- "fast-check": "catalog:",
66
- "typescript": "catalog:",
67
- "vitest": "catalog:"
61
+ "@effect/platform-node": "4.0.0-beta.70",
62
+ "@effect/vitest": "4.0.0-beta.70",
63
+ "@types/bun": "^1.3.6",
64
+ "effect": "4.0.0-beta.70",
65
+ "fast-check": "^4.7.0",
66
+ "typescript": "^5.8.3",
67
+ "vitest": "^4.0.18"
68
68
  }
69
69
  }