@kindgi/env-schema 0.0.0-bootstrap.0 → 0.1.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/dist/schema.js ADDED
@@ -0,0 +1,465 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+ // ---------------------------------------------------------------------
4
+ // Group ordering — output convention for `.env.example`.
5
+ // ---------------------------------------------------------------------
6
+ export const ENV_GROUPS = {
7
+ core: 'Core server config',
8
+ secrets: 'Secrets backend selection',
9
+ gcp: 'GCP vendor config (postgres + gcp KMS)',
10
+ 'pack-service': 'Pack service (runs the pack code: tools and guardrail checks)',
11
+ 'image-registry': "Image registry (where deployments' images are read from)",
12
+ dev: 'Development (`kindgi dev`; each needs `KINDGI_DEV=true`)',
13
+ };
14
+ // ---------------------------------------------------------------------
15
+ // The registry.
16
+ // ---------------------------------------------------------------------
17
+ /** The server's own vars: every target but the pack service's. */
18
+ const appliesToServer = (t) => t.component !== 'pack-service';
19
+ const appliesToPostgresBackend = (t) => appliesToServer(t) && t.secretsBackend === 'postgres';
20
+ const appliesToDotenvBackend = (t) => appliesToServer(t) && t.secretsBackend === 'dotenv';
21
+ const appliesToPostgresGcp = (t) => appliesToPostgresBackend(t) && t.secretsBackendKms === 'gcp';
22
+ const appliesToPackService = (t) => t.component === 'pack-service';
23
+ /** The server, calling a pack service over HTTP. */
24
+ const appliesToServerHttpPackTransport = (t) => appliesToServer(t) && t.packTransport === 'http';
25
+ /**
26
+ * Every operator-facing env var Kindgi understands, keyed by name.
27
+ * Declarative source of truth. Consumers filter this via
28
+ * `envVarsForTarget` / `validateEnvForTarget`.
29
+ */
30
+ export const KINDGI_ENV_SCHEMA = [
31
+ // ---- core server ------------------------------------------------
32
+ {
33
+ name: 'KINDGI_API_PORT',
34
+ description: 'HTTP port the Kindgi API server listens on. Default 4000.',
35
+ example: '4000',
36
+ required: false,
37
+ appliesTo: appliesToServer,
38
+ group: 'core',
39
+ },
40
+ {
41
+ name: 'KINDGI_API_HOST',
42
+ description: 'Address the API server binds. Default: all interfaces (what a container platform such as Cloud Run needs). `127.0.0.1` keeps it off the network; `kindgi dev` sets that on Linux, where the runtime container shares the host network.',
43
+ example: '127.0.0.1',
44
+ required: false,
45
+ appliesTo: appliesToServer,
46
+ group: 'core',
47
+ },
48
+ {
49
+ name: 'KINDGI_DATABASE_URL',
50
+ description: 'Postgres connection string. Default `postgres://localhost:5432/kindgi` (dev only).',
51
+ example: 'postgres://user:pass@postgres.internal:5432/kindgi',
52
+ required: false,
53
+ appliesTo: appliesToServer,
54
+ group: 'core',
55
+ },
56
+ {
57
+ name: 'KINDGI_OPENFGA_API_URL',
58
+ description: 'OpenFGA HTTP API URL. Set → per-tenant FGA stores are bootstrapped and authorization is enforced; unset → routes mount without enforcement (dev only; production MUST set it).',
59
+ example: 'http://openfga.internal:8080',
60
+ required: false,
61
+ appliesTo: appliesToServer,
62
+ group: 'core',
63
+ },
64
+ {
65
+ name: 'KINDGI_TENANT_ID',
66
+ description: 'Tenant UUID to seed / reuse. Default: fresh UUID printed at boot.',
67
+ example: '00000000-0000-4000-8000-000000000001',
68
+ required: false,
69
+ appliesTo: appliesToServer,
70
+ group: 'core',
71
+ },
72
+ {
73
+ name: 'KINDGI_API_TOKEN',
74
+ description: 'Bearer token to seed / reuse. Default: fresh `kgi_bt_...` token per boot.',
75
+ example: 'kgi_bt_my_stable_local_token',
76
+ required: false,
77
+ appliesTo: appliesToServer,
78
+ group: 'core',
79
+ },
80
+ {
81
+ name: 'KINDGI_SEED_USER_ID',
82
+ description: 'Seed user UUID. Pinning this across restarts keeps the FGA admin@tenant tuple stable.',
83
+ example: '00000000-0000-4000-8000-000000000002',
84
+ required: false,
85
+ appliesTo: appliesToServer,
86
+ group: 'core',
87
+ },
88
+ {
89
+ name: 'KINDGI_DOCS',
90
+ description: 'Mount `/docs` (Scalar API reference). `true` (default) | `false`.',
91
+ example: 'true',
92
+ required: false,
93
+ appliesTo: appliesToServer,
94
+ group: 'core',
95
+ allowedValues: ['true', 'false', '1', '0'],
96
+ },
97
+ {
98
+ name: 'KINDGI_DEV',
99
+ description: 'Development mode: `true` enables development-only settings (the `dotenv` secrets backend, `KINDGI_PACK_DIR`, `KINDGI_DEV_CONSOLE_LOGIN`, `KINDGI_DEV_HOST_ALIAS`). The server refuses those settings when this is off. Never set it in production.',
100
+ example: 'false',
101
+ required: false,
102
+ appliesTo: appliesToServer,
103
+ group: 'core',
104
+ allowedValues: ['true', 'false', '1', '0'],
105
+ },
106
+ {
107
+ name: 'KINDGI_TENANT_HOST_ACCESS',
108
+ description: "How far what tenants register may reach into the server's own host. `deployed` refuses a `stdio` MCP endpoint (a command the server would run in its container, as its user) at registration (`403 host-access-denied`) and at connect; run MCP servers over HTTP instead. It also refuses the server's connections to the cloud metadata endpoints (link-local addresses) and to its own host (loopback) when a tenant chose the host: an MCP endpoint, a model provider's base URL, an HTTP tool, an image reference. Private networks stay reachable. `local` allows all of it: only for a machine where every token holder may run commands. Unset: `local` with `KINDGI_DEV`, `deployed` otherwise; a value set here always wins.",
109
+ example: 'deployed',
110
+ required: false,
111
+ appliesTo: appliesToServer,
112
+ group: 'core',
113
+ allowedValues: ['local', 'deployed'],
114
+ },
115
+ {
116
+ name: 'KINDGI_LICENSE_KEY',
117
+ description: 'The commercial license key (`kgi_lk_...`) Kindgi issues: signed, checked offline at startup, with no call to Kindgi. Required outside development mode: without a valid key the server refuses to start, naming this variable. `KINDGI_DEV=true` needs none. A production key comes with a commercial license; a free non-production key covers staging and CI. A secret: give it from your secrets store.',
118
+ example: '',
119
+ required: false,
120
+ appliesTo: appliesToServer,
121
+ group: 'core',
122
+ },
123
+ {
124
+ name: 'KINDGI_ENV',
125
+ description: 'The env this runtime serves. Secrets a tool declares by name (`needsSpec.secrets`) resolve under this env name. Unset: `local` in development mode (the `.env` and `.env.local` files); otherwise a tool that declares secrets fails its calls, naming this variable.',
126
+ example: 'production',
127
+ required: false,
128
+ appliesTo: appliesToServer,
129
+ group: 'core',
130
+ },
131
+ {
132
+ name: 'KINDGI_PUBLIC_TOKEN_SIGNING_KEY_PATH',
133
+ description: 'Absolute path to the Ed25519 private key (PKCS#8 PEM, mode 0600) that signs public run tokens (`kgi_pt_…`): the short-lived, read-only tokens a browser uses to follow a run. Use a key for this alone (`openssl genpkey -algorithm ed25519`). Unset: in development mode the server signs with a key generated at startup (tokens end at restart); otherwise public run tokens are off.',
134
+ example: '/etc/kindgi/public-token-signing.pem',
135
+ required: false,
136
+ appliesTo: appliesToServer,
137
+ group: 'core',
138
+ },
139
+ {
140
+ name: 'KINDGI_PUBLIC_TOKEN_SIGNING_KEY',
141
+ description: "The same key's PEM file, base64 (`base64 < key.pem`): for platforms that give secrets as environment variables (Cloud Run with Secret Manager), where a key file's mode can't be 0600. Set this or `KINDGI_PUBLIC_TOKEN_SIGNING_KEY_PATH`, not both.",
142
+ example: '',
143
+ required: false,
144
+ appliesTo: appliesToServer,
145
+ group: 'core',
146
+ },
147
+ {
148
+ name: 'KINDGI_CORS_ORIGINS',
149
+ description: 'Comma-separated browser origins allowed to call, cross-origin, the routes a public run token can use (`GET /v1/runs/{runId}/progress` and its stream). Exact origins, no wildcards. Unset: no CORS headers on any route.',
150
+ example: 'https://app.example.com',
151
+ required: false,
152
+ appliesTo: appliesToServer,
153
+ group: 'core',
154
+ },
155
+ // ---- secrets backend --------------------------------------------
156
+ {
157
+ name: 'KINDGI_SECRETS_BACKEND',
158
+ description: 'Where secret bytes live. `none` (default; /v1/secrets/* unmounted) | `postgres` (envelope-encrypted, needs KMS) | `dotenv` (`.env` files in a directory; development only, needs `KINDGI_DEV=true`) | `secret-manager` (reserved; not supported through this variable).',
159
+ example: 'postgres',
160
+ required: false,
161
+ appliesTo: appliesToServer,
162
+ group: 'secrets',
163
+ allowedValues: ['none', 'postgres', 'dotenv', 'secret-manager'],
164
+ },
165
+ {
166
+ name: 'KINDGI_SECRETS_DOTENV_DIR',
167
+ description: 'Absolute path of the directory whose `.env` files hold secrets (`dotenv` backend). Mount the project directory here; secrets written through the API land in its files.',
168
+ example: '/pack',
169
+ required: true,
170
+ appliesTo: appliesToDotenvBackend,
171
+ group: 'secrets',
172
+ },
173
+ {
174
+ name: 'KINDGI_SECRETS_DOTENV_FILES',
175
+ description: 'Comma-separated `.env` files read for secrets (`dotenv` backend), relative to `KINDGI_SECRETS_DOTENV_DIR`, lowest precedence first. Default `.env,.env.local`.',
176
+ example: '.env,.env.local',
177
+ required: false,
178
+ appliesTo: appliesToDotenvBackend,
179
+ group: 'secrets',
180
+ },
181
+ {
182
+ name: 'KINDGI_SECRETS_BACKEND_KMS',
183
+ description: 'Which KMS vendor wraps DEKs (postgres backend only). Currently supported: `gcp`. Reserved: `aws`, `libsodium`.',
184
+ example: 'gcp',
185
+ required: true,
186
+ appliesTo: appliesToPostgresBackend,
187
+ group: 'secrets',
188
+ allowedValues: ['gcp', 'aws', 'libsodium'],
189
+ },
190
+ {
191
+ name: 'KINDGI_SECRETS_AAD_KEY_PATH',
192
+ description: 'Absolute path to a 32-byte AAD/HMAC key file (mode 0600). Same key across every replica; protects AEAD associated data over every secret row. The postgres backend needs this or `KINDGI_SECRETS_AAD_KEY`, not both.',
193
+ example: '/etc/kindgi/secrets-aad.key',
194
+ required: false,
195
+ appliesTo: appliesToPostgresBackend,
196
+ group: 'secrets',
197
+ },
198
+ {
199
+ name: 'KINDGI_SECRETS_AAD_KEY',
200
+ description: "The 32-byte AAD/HMAC key itself, base64: for platforms that give secrets as environment variables (Cloud Run with Secret Manager), where a key file's mode can't be 0600. The postgres backend needs this or `KINDGI_SECRETS_AAD_KEY_PATH`, not both.",
201
+ example: '',
202
+ required: false,
203
+ appliesTo: appliesToPostgresBackend,
204
+ group: 'secrets',
205
+ },
206
+ // ---- GCP vendor -------------------------------------------------
207
+ {
208
+ name: 'KINDGI_SECRETS_GCP_PROJECT_ID',
209
+ description: 'GCP project id owning the KMS keyring + key.',
210
+ example: 'my-proj',
211
+ required: true,
212
+ appliesTo: appliesToPostgresGcp,
213
+ group: 'gcp',
214
+ },
215
+ {
216
+ name: 'KINDGI_SECRETS_GCP_LOCATION_ID',
217
+ description: 'KMS location, e.g. `us-central1`, `europe-west1`, `global`.',
218
+ example: 'us-central1',
219
+ required: true,
220
+ appliesTo: appliesToPostgresGcp,
221
+ group: 'gcp',
222
+ },
223
+ {
224
+ name: 'KINDGI_SECRETS_GCP_KEY_RING_ID',
225
+ description: 'KMS keyring id within the location.',
226
+ example: 'kindgi',
227
+ required: true,
228
+ appliesTo: appliesToPostgresGcp,
229
+ group: 'gcp',
230
+ },
231
+ {
232
+ name: 'KINDGI_SECRETS_GCP_KEY_ID',
233
+ description: 'CryptoKey id within the keyring (symmetric GOOGLE_SYMMETRIC_ENCRYPTION).',
234
+ example: 'secrets-kek',
235
+ required: true,
236
+ appliesTo: appliesToPostgresGcp,
237
+ group: 'gcp',
238
+ },
239
+ // ---- pack service -----------------------------------------------
240
+ // The server's side: where the pack service is, and how long a call
241
+ // may take.
242
+ {
243
+ name: 'KINDGI_PACK_SERVICE_URL',
244
+ description: 'Base URL of the pack service, the separate process that runs the pack code (its tools and guardrail checks), e.g. `http://pack-service:8080` or its internal Cloud Run URL. Set: the server calls it over HTTP for every pack tool and check, and needs `KINDGI_PACK_SERVICE_TOKEN`. Unset: no pack code runs, and a pack tool fails saying no pack service is wired. `kindgi dev` runs its own.',
245
+ example: 'http://pack-service:8080',
246
+ required: false,
247
+ appliesTo: appliesToServer,
248
+ group: 'pack-service',
249
+ },
250
+ {
251
+ name: 'KINDGI_PACK_CALL_TIMEOUT_MS',
252
+ description: 'How long one pack call (a tool or a guardrail check) may take, in milliseconds. Default 120000. The deadline travels with the call, and the pack service aborts the handler when it passes.',
253
+ example: '120000',
254
+ required: false,
255
+ appliesTo: appliesToServerHttpPackTransport,
256
+ group: 'pack-service',
257
+ },
258
+ {
259
+ name: 'KINDGI_PACK_SERVICE_AUTH',
260
+ description: "How the server proves itself to the pack service besides the pack token. `token` (default): the pack token alone. `google-id-token`: also a Google ID token for the pack service URL, from the server's own identity, for a pack service on Cloud Run behind IAM (`--no-allow-unauthenticated`); the URL must be https. The identity is a service account: on Cloud Run the server's own; elsewhere, impersonate one (a person's own credentials can't mint an ID token for a service).",
261
+ example: 'token',
262
+ required: false,
263
+ appliesTo: appliesToServerHttpPackTransport,
264
+ group: 'pack-service',
265
+ allowedValues: ['token', 'google-id-token'],
266
+ },
267
+ // Both sides: the shared token.
268
+ {
269
+ name: 'KINDGI_PACK_SERVICE_TOKEN',
270
+ description: 'Shared secret between the server and the pack service. The pack service refuses any call without it, and the server sends it with every call. Required by the pack service, and by the server when `KINDGI_PACK_SERVICE_URL` is set. Use a long random value (`openssl rand -base64 32`). The pack service removes it from its environment before it loads the pack code.',
271
+ example: '',
272
+ required: true,
273
+ appliesTo: (t) => appliesToPackService(t) || appliesToServerHttpPackTransport(t),
274
+ group: 'pack-service',
275
+ },
276
+ // The pack service's side. It also listens on `PORT` (default 8080),
277
+ // the platform convention, which is not a Kindgi variable.
278
+ {
279
+ name: 'KINDGI_PACK_INDEX',
280
+ description: "Path of the pack's `index.json` in the pack service's image. Default `/app/index.json`, where `kindgi build` puts it; the `--index` flag overrides it.",
281
+ example: '/app/index.json',
282
+ required: false,
283
+ appliesTo: appliesToPackService,
284
+ group: 'pack-service',
285
+ },
286
+ {
287
+ name: 'KINDGI_PACK_SERVICE_MAX_CONCURRENCY',
288
+ description: "How many calls the pack service runs at once. Past it, calls get 503 (`overloaded`), which the server retries. Default 32. On Cloud Run, set the service's concurrency to the same number.",
289
+ example: '32',
290
+ required: false,
291
+ appliesTo: appliesToPackService,
292
+ group: 'pack-service',
293
+ },
294
+ {
295
+ name: 'KINDGI_PACK_ENV_CHECK',
296
+ description: "What the pack service does when a name the pack's `env.required` declares is unset or empty in its environment. `strict` (default): it isn't ready, and `/readyz` and every call answer 503 naming the missing names. `warn`: it serves, and names them in its log and `/v1/info`. `kindgi dev` uses `warn`.",
297
+ example: 'strict',
298
+ required: false,
299
+ appliesTo: appliesToPackService,
300
+ group: 'pack-service',
301
+ allowedValues: ['strict', 'warn'],
302
+ },
303
+ // ---- image registry ---------------------------------------------
304
+ // How the server reads a deployment's image to verify it (`POST
305
+ // /v1/deployments`): anonymous unless credentials are set.
306
+ {
307
+ name: 'KINDGI_IMAGE_REGISTRY_HOST',
308
+ description: 'The registry host the credentials below are for, with its port when it has one (e.g. `registry.example`, `ghcr.io`). Other registries are read anonymously.',
309
+ example: 'registry.example',
310
+ required: false,
311
+ appliesTo: appliesToServer,
312
+ group: 'image-registry',
313
+ },
314
+ {
315
+ name: 'KINDGI_IMAGE_REGISTRY_USERNAME',
316
+ description: "Username for `KINDGI_IMAGE_REGISTRY_HOST`. Used for the registry's token flow, or as basic auth.",
317
+ example: 'kindgi-reader',
318
+ required: false,
319
+ appliesTo: appliesToServer,
320
+ group: 'image-registry',
321
+ },
322
+ {
323
+ name: 'KINDGI_IMAGE_REGISTRY_PASSWORD',
324
+ description: 'Password or access token for `KINDGI_IMAGE_REGISTRY_HOST`. Read-only (pull) access is enough.',
325
+ example: '',
326
+ required: false,
327
+ appliesTo: appliesToServer,
328
+ group: 'image-registry',
329
+ },
330
+ {
331
+ name: 'KINDGI_IMAGE_REGISTRY_INSECURE_HOSTS',
332
+ description: 'Comma-separated registry hosts reached over plain HTTP instead of HTTPS, e.g. a local `registry:2`. Loopback hosts (`localhost`, `127.0.0.1`) always are.',
333
+ example: 'registry.internal:5000',
334
+ required: false,
335
+ appliesTo: appliesToServer,
336
+ group: 'image-registry',
337
+ },
338
+ {
339
+ name: 'KINDGI_IMAGE_REGISTRY_AUTH',
340
+ description: "How the server signs in to `KINDGI_IMAGE_REGISTRY_HOST`. `static` (default): `KINDGI_IMAGE_REGISTRY_USERNAME` and `_PASSWORD`. `google`: the server's own Google identity (Application Default Credentials: the service's identity on Cloud Run), for Artifact Registry; no username or password is set, and Kindgi keeps no key file.",
341
+ example: 'static',
342
+ required: false,
343
+ appliesTo: appliesToServer,
344
+ group: 'image-registry',
345
+ allowedValues: ['static', 'google'],
346
+ },
347
+ // ---- development (`kindgi dev`) ---------------------------------
348
+ {
349
+ name: 'KINDGI_PACK_DIR',
350
+ description: "Development only: the pack directory `kindgi dev` runs. The server reads the pack's tools, guardrails, agents and flows from the index `kindgi dev` writes there (`.kindgi/dev/index.json`), on every change, instead of from Postgres; signed deployments are off. Mount the directory, not the file: the index is replaced by rename.",
351
+ example: '/pack',
352
+ required: false,
353
+ appliesTo: appliesToServer,
354
+ group: 'dev',
355
+ },
356
+ {
357
+ name: 'KINDGI_DEV_CONSOLE_LOGIN',
358
+ description: 'Development only: `true` lets the console log in by itself. `GET /__dev/bearer` hands it the API token, answering only requests addressed to a loopback host (`localhost`, `127.0.0.1`, `[::1]`). Needs the console.',
359
+ example: 'true',
360
+ required: false,
361
+ appliesTo: appliesToServer,
362
+ group: 'dev',
363
+ allowedValues: ['true', 'false', '1', '0'],
364
+ },
365
+ {
366
+ name: 'KINDGI_DEV_HOST_ALIAS',
367
+ description: "Development only: where the server's outbound calls to a loopback address (`localhost`, `127.0.0.1`, `[::1]`) connect instead. This covers webhooks to the app, HTTP MCP endpoints, model providers and the pack service. Inside a container, loopback is the container itself; `kindgi dev` sets `host.docker.internal` on Docker Desktop. The URL, the `Host` header and the TLS server name stay as written; only the connection goes to the alias.",
368
+ example: 'host.docker.internal',
369
+ required: false,
370
+ appliesTo: appliesToServer,
371
+ group: 'dev',
372
+ },
373
+ ];
374
+ // ---------------------------------------------------------------------
375
+ // Helper API — the three consumer entry points.
376
+ // ---------------------------------------------------------------------
377
+ /**
378
+ * Filter the schema down to just vars that apply to the caller's
379
+ * target. Preserves declaration order (which drives `.env.example`
380
+ * ordering).
381
+ */
382
+ export function envVarsForTarget(target, schema = KINDGI_ENV_SCHEMA) {
383
+ return schema.filter((v) => v.appliesTo(target));
384
+ }
385
+ /**
386
+ * Render vars as a `.env.example` file body. Each group listed in
387
+ * `ENV_GROUPS` gets a section-header comment; groups appear in order of
388
+ * first appearance, ungrouped vars last. Each var gets a description
389
+ * comment, its allowed-values enum (when set), and the example
390
+ * assignment. Optional vars are prefixed with `# ` so operators
391
+ * explicitly opt in.
392
+ */
393
+ export function renderEnvExample(vars) {
394
+ const groups = new Map();
395
+ const ungrouped = [];
396
+ for (const v of vars) {
397
+ if (v.group === undefined) {
398
+ ungrouped.push(v);
399
+ continue;
400
+ }
401
+ const list = groups.get(v.group);
402
+ if (list !== undefined) {
403
+ list.push(v);
404
+ }
405
+ else {
406
+ groups.set(v.group, [v]);
407
+ }
408
+ }
409
+ const lines = [
410
+ '# Generated by `kindgi env init` — Kindgi deployment env vars.',
411
+ '# See @kindgi/env-schema for the source of truth.',
412
+ '',
413
+ ];
414
+ const emitGroup = (group, entries) => {
415
+ if (entries.length === 0)
416
+ return;
417
+ const header = group !== undefined && ENV_GROUPS[group];
418
+ if (typeof header === 'string') {
419
+ lines.push(`# ---- ${header} ----`);
420
+ lines.push('');
421
+ }
422
+ for (const v of entries) {
423
+ lines.push(`# ${v.description}`);
424
+ if (v.allowedValues !== undefined) {
425
+ lines.push(`# Allowed values: ${v.allowedValues.join(' | ')}`);
426
+ }
427
+ const prefix = v.required ? '' : '# ';
428
+ lines.push(`${prefix}${v.name}=${v.example}`);
429
+ lines.push('');
430
+ }
431
+ };
432
+ for (const [group, entries] of groups) {
433
+ emitGroup(group, entries);
434
+ }
435
+ emitGroup(undefined, ungrouped);
436
+ return lines.join('\n');
437
+ }
438
+ /**
439
+ * Check whether every required var for the target is set in `env`.
440
+ * Returns `{ ok: true }` on success, `{ ok: false, missing }` with a
441
+ * complete list of missing var names on failure. Callers can render
442
+ * this into an operator-actionable error message.
443
+ *
444
+ * Only checks REQUIRED vars — optional vars that are unset are fine
445
+ * (defaults apply, or the var is passthrough).
446
+ *
447
+ * Does not enforce `allowedValues` — that's a declarative hint for
448
+ * tooling; code that reads a var validates its value.
449
+ */
450
+ export function validateEnvForTarget(env, target, schema = KINDGI_ENV_SCHEMA) {
451
+ const applicable = envVarsForTarget(target, schema);
452
+ const missing = [];
453
+ for (const v of applicable) {
454
+ if (!v.required)
455
+ continue;
456
+ const value = env[v.name];
457
+ if (value === undefined || value === '') {
458
+ missing.push(v.name);
459
+ }
460
+ }
461
+ if (missing.length === 0)
462
+ return { ok: true };
463
+ return { ok: false, missing };
464
+ }
465
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Value checks for variables whose shape the schema can't express.
3
+ * Shared by the server, which reads them at startup, and the CLI, which
4
+ * checks them before it starts anything: both refuse the same values
5
+ * with the same message.
6
+ */
7
+ /** The Ed25519 private key file that signs public run tokens. */
8
+ export declare const PUBLIC_TOKEN_KEY_PATH_VAR = "KINDGI_PUBLIC_TOKEN_SIGNING_KEY_PATH";
9
+ /** The same key's PEM file, base64: the alternative to the path. */
10
+ export declare const PUBLIC_TOKEN_KEY_VAR = "KINDGI_PUBLIC_TOKEN_SIGNING_KEY";
11
+ /** The license key the server checks at startup outside development mode. */
12
+ export declare const LICENSE_KEY_VAR = "KINDGI_LICENSE_KEY";
13
+ /** The browser origins allowed on the routes a public run token opens. */
14
+ export declare const CORS_ORIGINS_VAR = "KINDGI_CORS_ORIGINS";
15
+ /**
16
+ * Parse `KINDGI_CORS_ORIGINS`: comma-separated exact origins
17
+ * (`https://app.example.com`, `http://localhost:3000`): a scheme, a host
18
+ * and an optional port; no path, no trailing slash, no wildcard. Unset or
19
+ * empty: none. Throws on anything else, so a typo fails at startup rather
20
+ * than as a browser's CORS error.
21
+ */
22
+ export declare function parseCorsOrigins(raw: string | undefined): readonly string[];
23
+ //# sourceMappingURL=values.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"values.d.ts","sourceRoot":"","sources":["../src/values.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AAEH,iEAAiE;AACjE,eAAO,MAAM,yBAAyB,yCAAyC,CAAC;AAEhF,oEAAoE;AACpE,eAAO,MAAM,oBAAoB,oCAAoC,CAAC;AAEtE,6EAA6E;AAC7E,eAAO,MAAM,eAAe,uBAAuB,CAAC;AAEpD,0EAA0E;AAC1E,eAAO,MAAM,gBAAgB,wBAAwB,CAAC;AAEtD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,MAAM,EAAE,CAc3E"}
package/dist/values.js ADDED
@@ -0,0 +1,51 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+ /**
4
+ * Value checks for variables whose shape the schema can't express.
5
+ * Shared by the server, which reads them at startup, and the CLI, which
6
+ * checks them before it starts anything: both refuse the same values
7
+ * with the same message.
8
+ */
9
+ /** The Ed25519 private key file that signs public run tokens. */
10
+ export const PUBLIC_TOKEN_KEY_PATH_VAR = 'KINDGI_PUBLIC_TOKEN_SIGNING_KEY_PATH';
11
+ /** The same key's PEM file, base64: the alternative to the path. */
12
+ export const PUBLIC_TOKEN_KEY_VAR = 'KINDGI_PUBLIC_TOKEN_SIGNING_KEY';
13
+ /** The license key the server checks at startup outside development mode. */
14
+ export const LICENSE_KEY_VAR = 'KINDGI_LICENSE_KEY';
15
+ /** The browser origins allowed on the routes a public run token opens. */
16
+ export const CORS_ORIGINS_VAR = 'KINDGI_CORS_ORIGINS';
17
+ /**
18
+ * Parse `KINDGI_CORS_ORIGINS`: comma-separated exact origins
19
+ * (`https://app.example.com`, `http://localhost:3000`): a scheme, a host
20
+ * and an optional port; no path, no trailing slash, no wildcard. Unset or
21
+ * empty: none. Throws on anything else, so a typo fails at startup rather
22
+ * than as a browser's CORS error.
23
+ */
24
+ export function parseCorsOrigins(raw) {
25
+ if (raw === undefined || raw.trim() === '')
26
+ return [];
27
+ const origins = raw
28
+ .split(',')
29
+ .map((entry) => entry.trim())
30
+ .filter((entry) => entry !== '');
31
+ const invalid = origins.filter((origin) => !isExactOrigin(origin));
32
+ if (invalid.length > 0) {
33
+ throw new Error(`${CORS_ORIGINS_VAR} entries must be exact origins like https://app.example.com ` +
34
+ `(scheme, host, optional port; no path or wildcard). Got: ${invalid.join(', ')}.`);
35
+ }
36
+ return [...new Set(origins)];
37
+ }
38
+ function isExactOrigin(value) {
39
+ let url;
40
+ try {
41
+ url = new URL(value);
42
+ }
43
+ catch {
44
+ return false;
45
+ }
46
+ // `https://*.example.com` parses (as a literal `*` host): refuse it.
47
+ return ((url.protocol === 'https:' || url.protocol === 'http:') &&
48
+ url.origin === value &&
49
+ !value.includes('*'));
50
+ }
51
+ //# sourceMappingURL=values.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"values.js","sourceRoot":"","sources":["../src/values.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iCAAiC;AAEjC;;;;;GAKG;AAEH,iEAAiE;AACjE,MAAM,CAAC,MAAM,yBAAyB,GAAG,sCAAsC,CAAC;AAEhF,oEAAoE;AACpE,MAAM,CAAC,MAAM,oBAAoB,GAAG,iCAAiC,CAAC;AAEtE,6EAA6E;AAC7E,MAAM,CAAC,MAAM,eAAe,GAAG,oBAAoB,CAAC;AAEpD,0EAA0E;AAC1E,MAAM,CAAC,MAAM,gBAAgB,GAAG,qBAAqB,CAAC;AAEtD;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAuB;IACtD,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,EAAE,CAAC;IACtD,MAAM,OAAO,GAAG,GAAG;SAChB,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;SAC5B,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;IACnE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,GAAG,gBAAgB,8DAA8D;YAC/E,4DAA4D,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACpF,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;AAC/B,CAAC;AAED,SAAS,aAAa,CAAC,KAAa;IAClC,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IACD,qEAAqE;IACrE,OAAO,CACL,CAAC,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,CAAC;QACvD,GAAG,CAAC,MAAM,KAAK,KAAK;QACpB,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CACrB,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,47 @@
1
1
  {
2
2
  "name": "@kindgi/env-schema",
3
- "version": "0.0.0-bootstrap.0",
4
- "description": "Placeholder so a trusted publisher can be attached. Releases are published from https://github.com/kindgi/kindgi-sdk with provenance; use 0.1.0 or later.",
3
+ "version": "0.1.0",
4
+ "description": "Machine-readable registry of the Kindgi runtime's operator-facing env vars. Single source of truth for boot-time validation (validateEnvForTarget), .env.example scaffolding (renderEnvExample), and tools or coding agents introspecting deployment config. Adding a new env var means adding one entry here — no drift between validation, docs, and .env.example generation.",
5
5
  "license": "Apache-2.0",
6
- "repository": { "type": "git", "url": "git+https://github.com/kindgi/kindgi-sdk.git" }
7
- }
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/kindgi/kindgi-sdk.git",
9
+ "directory": "packages/env-schema"
10
+ },
11
+ "homepage": "https://github.com/kindgi/kindgi-sdk/tree/main/packages/env-schema#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/kindgi/kindgi-sdk/issues"
14
+ },
15
+ "type": "module",
16
+ "main": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js"
22
+ }
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "src",
27
+ "README.md"
28
+ ],
29
+ "devDependencies": {
30
+ "@types/node": "^22.10.5",
31
+ "typescript": "^5.7.3",
32
+ "vitest": "^2.1.8"
33
+ },
34
+ "engines": {
35
+ "node": ">=22.0.0"
36
+ },
37
+ "publishConfig": {
38
+ "access": "public",
39
+ "provenance": true
40
+ },
41
+ "scripts": {
42
+ "build": "tsc -p tsconfig.build.json",
43
+ "typecheck": "tsc --noEmit",
44
+ "test": "vitest run",
45
+ "clean": "rm -rf dist *.tsbuildinfo"
46
+ }
47
+ }
package/src/index.ts ADDED
@@ -0,0 +1,19 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+
4
+ export {
5
+ ENV_GROUPS,
6
+ type EnvTarget,
7
+ type EnvVarSpec,
8
+ KINDGI_ENV_SCHEMA,
9
+ envVarsForTarget,
10
+ renderEnvExample,
11
+ validateEnvForTarget,
12
+ } from './schema.js';
13
+ export {
14
+ CORS_ORIGINS_VAR,
15
+ LICENSE_KEY_VAR,
16
+ PUBLIC_TOKEN_KEY_PATH_VAR,
17
+ PUBLIC_TOKEN_KEY_VAR,
18
+ parseCorsOrigins,
19
+ } from './values.js';