okengine 0.10.3 → 0.11.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/package.json +76 -10
- package/site/content/docs/deployment/docker-swarm.mdx +48 -111
- package/site/content/docs/deployment/docker.mdx +43 -36
- package/site/content/docs/deployment/index.mdx +9 -9
- package/site/content/docs/deployment/kubernetes.mdx +4 -4
- package/site/content/docs/elements/ai.mdx +7 -7
- package/site/content/docs/elements/channel.mdx +9 -7
- package/site/content/docs/elements/clock.mdx +8 -8
- package/site/content/docs/elements/flow.mdx +46 -47
- package/site/content/docs/elements/gate.mdx +6 -5
- package/site/content/docs/elements/signal.mdx +2 -2
- package/site/content/docs/elements/store.mdx +71 -78
- package/site/content/docs/elements/vault.mdx +89 -70
- package/site/content/docs/get-started/basic-usage.mdx +8 -8
- package/site/content/docs/get-started/installation.mdx +36 -36
- package/site/content/docs/get-started/introduction.mdx +11 -0
- package/site/content/docs/get-started/why.mdx +2 -2
- package/site/content/docs/plugins/anonymous.mdx +1 -1
- package/site/content/docs/plugins/magic-link.mdx +11 -11
- package/site/content/docs/plugins/otp.mdx +2 -2
- package/site/content/docs/plugins/passkey.mdx +1 -1
- package/site/content/docs/plugins/two-factor.mdx +1 -1
- package/site/content/docs/plugins/username.mdx +1 -1
- package/site/content/docs/recipes/caddy.mdx +1 -1
- package/site/content/docs/recipes/cockroachdb.mdx +2 -2
- package/site/content/docs/recipes/dragonfly.mdx +1 -1
- package/site/content/docs/recipes/index.mdx +1 -2
- package/site/content/docs/recipes/llama-cpp.mdx +21 -23
- package/site/content/docs/recipes/mailpit.mdx +11 -11
- package/site/content/docs/recipes/meilisearch.mdx +10 -10
- package/site/content/docs/recipes/meta.json +0 -1
- package/site/content/docs/recipes/ollama.mdx +1 -1
- package/site/content/docs/recipes/pgdog.mdx +12 -9
- package/site/content/docs/recipes/postgres.mdx +3 -3
- package/site/content/docs/recipes/redis.mdx +2 -2
- package/site/content/docs/recipes/rustfs.mdx +10 -7
- package/site/content/docs/recipes/sglang.mdx +1 -1
- package/site/content/docs/recipes/supabase-docker.mdx +1 -1
- package/site/content/docs/recipes/timescale.mdx +2 -2
- package/site/content/docs/recipes/valkey.mdx +1 -1
- package/site/content/docs/recipes/vllm.mdx +1 -1
- package/site/content/docs/recipes/yugabytedb.mdx +2 -2
- package/site/content/docs/reference/cli.md +61 -38
- package/site/content/docs/reference/configuration.mdx +145 -70
- package/site/content/docs/reference/environment-variables.mdx +36 -28
- package/site/content/docs/reference/errors.mdx +28 -29
- package/site/content/docs/reference/fx.mdx +11 -4
- package/site/content/docs/reference/i18n.mdx +17 -6
- package/site/content/docs/reference/index.mdx +5 -0
- package/site/content/docs/reference/meta.json +1 -0
- package/site/content/docs/reference/migrating-environments.mdx +158 -0
- package/site/content/docs/reference/plugins.mdx +2 -2
- package/src/auth/gate-auth.test.ts +12 -10
- package/src/cli/ai-setup/ai-setup.test.ts +27 -15
- package/src/cli/ai-setup/apply.ts +111 -15
- package/src/cli/ai-setup/catalog.ts +3 -3
- package/src/cli/ai-setup/index.ts +1 -1
- package/src/cli/ai-setup/prompts.ts +1 -1
- package/src/cli/ai-setup/recommend.test.ts +1 -1
- package/src/cli/ask-seed.test.ts +3 -3
- package/src/cli/build.ts +1 -1
- package/src/cli/db-auto-push.test.ts +6 -3
- package/src/cli/db-auto-push.ts +7 -5
- package/src/cli/db-seed.ts +7 -8
- package/src/cli/db.test.ts +70 -71
- package/src/cli/db.ts +86 -12
- package/src/cli/dev-controller.test.ts +35 -0
- package/src/cli/dev-controller.ts +298 -0
- package/src/cli/dev-controls.ts +11 -65
- package/src/cli/dev-db-push.test.ts +47 -15
- package/src/cli/dev-schema-sync.test.ts +11 -11
- package/src/cli/dev-schema-sync.ts +10 -10
- package/src/cli/dev-session-lock.test.ts +106 -0
- package/src/cli/dev-session-lock.ts +209 -0
- package/src/cli/dev.test.ts +166 -121
- package/src/cli/dev.ts +138 -192
- package/src/cli/doc-staleness.test.ts +3 -6
- package/src/cli/docker-clean.test.ts +33 -1
- package/src/cli/docker-clean.ts +28 -33
- package/src/cli/docker-cli.test.ts +12 -11
- package/src/cli/docker.ts +95 -20
- package/src/cli/doctor.test.ts +40 -0
- package/src/cli/doctor.ts +55 -15
- package/src/cli/drizzle-env.test.ts +11 -13
- package/src/cli/drizzle-env.ts +18 -11
- package/src/cli/ensure-drizzle-config.ts +11 -14
- package/src/cli/hero-meta.test.ts +15 -15
- package/src/cli/hero-meta.ts +10 -9
- package/src/cli/index.ts +36 -6
- package/src/cli/load-config.images.test.ts +16 -12
- package/src/cli/load-config.source.test.ts +50 -0
- package/src/cli/load-config.ts +34 -28
- package/src/cli/meilisearch-local.ts +1 -2
- package/src/cli/mode.ts +7 -58
- package/src/cli/registry.ts +175 -19
- package/src/cli/resolve-dev-sql-env.test.ts +8 -16
- package/src/cli/resolve-dev-sql-env.ts +13 -15
- package/src/cli/safe-defaults.test.ts +28 -10
- package/src/cli/schema.ts +65 -16
- package/src/cli/test.ts +58 -0
- package/src/cli/tui/App.tsx +252 -0
- package/src/cli/tui/DevLive.tsx +116 -0
- package/src/cli/tui/components/ConfirmDialog.tsx +48 -0
- package/src/cli/tui/components/HeaderBar.tsx +67 -0
- package/src/cli/tui/components/LogStream.tsx +47 -0
- package/src/cli/tui/components/PanelCard.tsx +39 -0
- package/src/cli/tui/components/SelectRow.tsx +37 -0
- package/src/cli/tui/components/SlashPalette.tsx +172 -0
- package/src/cli/tui/components/Spinner.tsx +32 -0
- package/src/cli/tui/components/StatusBar.tsx +51 -0
- package/src/cli/tui/components/StatusDot.tsx +37 -0
- package/src/cli/tui/components/TabBar.tsx +49 -0
- package/src/cli/tui/components/Wordmark.tsx +43 -0
- package/src/cli/tui/format.ts +38 -0
- package/src/cli/tui/keys.test.ts +18 -0
- package/src/cli/tui/keys.ts +26 -0
- package/src/cli/tui/launch.test.ts +18 -0
- package/src/cli/tui/launch.ts +57 -0
- package/src/cli/tui/panels/Dashboard.tsx +201 -0
- package/src/cli/tui/panels/Database.tsx +198 -0
- package/src/cli/tui/panels/Dev.tsx +257 -0
- package/src/cli/tui/panels/Docker.tsx +357 -0
- package/src/cli/tui/panels/Navigator.test.ts +22 -0
- package/src/cli/tui/panels/Navigator.tsx +213 -0
- package/src/cli/tui/slash-catalog.test.ts +31 -0
- package/src/cli/tui/slash-catalog.ts +184 -0
- package/src/cli/tui/slash-run.ts +54 -0
- package/src/cli/tui/state/ports.ts +95 -0
- package/src/cli/tui/theme.ts +24 -0
- package/src/cli/vault-cmd.test.ts +402 -0
- package/src/cli/vault-cmd.ts +727 -69
- package/src/cli/vault-secure-input.test.ts +56 -0
- package/src/cli/vault-secure-input.ts +124 -0
- package/src/compiler/effects-infer.ts +7 -0
- package/src/compiler/fixtures/skyport/oke.config.ts +3 -3
- package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +1 -1
- package/src/compiler/fixtures/skyport.expected.json +1 -1
- package/src/compiler-entry.ts +7 -0
- package/src/config/define-config.test.ts +111 -47
- package/src/config/driver-defaults.test.ts +16 -23
- package/src/config/driver-defaults.ts +33 -63
- package/src/config/index.ts +169 -144
- package/src/config/resolve-driver.test.ts +14 -19
- package/src/console/server/app.ts +4 -2
- package/src/console/server/console.test.ts +58 -1
- package/src/console/server/flows.ts +22 -2
- package/src/console/server/index.ts +3 -0
- package/src/console/server/operator-db.test.ts +55 -13
- package/src/console/server/operator-db.ts +305 -263
- package/src/console/server/serve.ts +16 -7
- package/src/console/server/state.ts +31 -9
- package/src/console/server/vault.test.ts +120 -5
- package/src/console/server/vault.ts +208 -12
- package/src/console/ui/dist/assets/{index-D-9KFce5.js → index--Y0Uaz-m.js} +2 -2
- package/src/console/ui/dist/assets/panel-vault-BkZdJPX8.js +1 -0
- package/src/console/ui/dist/assets/style-C3L349iZ.css +3 -0
- package/src/console/ui/dist/index.html +2 -2
- package/src/console/ui/shell/client.ts +16 -0
- package/src/console/ui/shell/panels/vault/VaultPanel.tsx +54 -1
- package/src/console/ui/vault/VaultA11yView.tsx +33 -1
- package/src/console/ui/vault/backend.test.ts +75 -0
- package/src/console/ui/vault/backend.ts +117 -0
- package/src/console/ui/vault/fixture.ts +21 -2
- package/src/console/ui/vault/index.ts +11 -1
- package/src/console/ui/vault/types.ts +26 -0
- package/src/docker/compose.ts +164 -61
- package/src/docker/derive.ts +106 -12
- package/src/docker/docker.test.ts +156 -110
- package/src/docker/helpers.ts +98 -0
- package/src/docker/images-config.test.ts +3 -8
- package/src/docker/index.ts +30 -5
- package/src/docker/recipes/index.ts +0 -3
- package/src/docker/recipes/llama-cpp.ts +4 -4
- package/src/docker/recipes/pgdog.ts +9 -2
- package/src/docker/resources.test.ts +71 -0
- package/src/docker/resources.ts +176 -0
- package/src/docker/stack-id.test.ts +11 -4
- package/src/docker/stack-id.ts +42 -32
- package/src/docker/stack.integration.test.ts +4 -15
- package/src/docker/types.ts +35 -3
- package/src/drivers/ai-ollama.integration.test.ts +2 -2
- package/src/drivers/conformance.test.ts +11 -12
- package/src/drivers/drizzle-dialect.test.ts +0 -4
- package/src/drivers/drizzle-dialect.ts +7 -13
- package/src/drivers/index.ts +24 -7
- package/src/drivers/journal-postgres.test.ts +3 -1
- package/src/drivers/journal-postgres.ts +4 -2
- package/src/drivers/meilisearch.ts +1 -1
- package/src/drivers/pglite.ts +28 -5
- package/src/drivers/types.ts +9 -11
- package/src/drivers/vault-aws-secrets-manager.test.ts +159 -0
- package/src/drivers/vault-aws-secrets-manager.ts +333 -0
- package/src/drivers/vault-builtin.test.ts +110 -0
- package/src/drivers/vault-builtin.ts +184 -0
- package/src/drivers/vault-driver-removal.test.ts +13 -0
- package/src/drivers/vault-managed.test.ts +95 -0
- package/src/drivers/vault-managed.ts +101 -25
- package/src/drivers/vault-types.ts +25 -5
- package/src/elements/ai/runtime.ts +1 -1
- package/src/elements/clock/chaos.test.ts +4 -1
- package/src/elements/clock/durable.ts +57 -4
- package/src/elements/clock.test.ts +13 -14
- package/src/elements/gate/constants.ts +18 -0
- package/src/elements/gate.test.ts +1 -1
- package/src/elements/gate.ts +2 -2
- package/src/elements/store/domain-ddl.test.ts +5 -12
- package/src/elements/store/emit-drizzle.ts +44 -19
- package/src/elements/store/index-boot.test.ts +15 -116
- package/src/elements/store/load-plugin-tables.ts +1 -1
- package/src/elements/store/resource-list-docs.fixture.ts +12 -6
- package/src/elements/store/resource-list-docs.test.ts +64 -44
- package/src/elements/store/resource.test.ts +17 -10
- package/src/elements/store/runtime.ts +9 -12
- package/src/elements/store/schema-decl.test.ts +16 -32
- package/src/elements/store/seed.test.ts +1 -2
- package/src/elements/store/seed.ts +7 -8
- package/src/elements/store/sql-condition.test.ts +2 -2
- package/src/elements/store/sql-session.test.ts +8 -10
- package/src/elements/store/sql-session.ts +10 -2
- package/src/elements/store.test.ts +13 -13
- package/src/elements/vault/audit.ts +233 -0
- package/src/elements/vault/boot-chain.test.ts +78 -0
- package/src/elements/vault/boot-chain.ts +43 -39
- package/src/elements/vault/builtin-adapter.test.ts +479 -0
- package/src/elements/vault/builtin-adapter.ts +1184 -0
- package/src/elements/vault/crypto.test.ts +237 -0
- package/src/elements/vault/crypto.ts +431 -0
- package/src/elements/vault/declare.ts +164 -3
- package/src/elements/vault/errors.ts +56 -0
- package/src/elements/vault/kms-unseal.test.ts +76 -0
- package/src/elements/vault/kms-unseal.ts +181 -0
- package/src/elements/vault/path.ts +90 -0
- package/src/elements/vault/resilience.test.ts +102 -0
- package/src/elements/vault/resilience.ts +107 -0
- package/src/elements/vault/runtime.ts +36 -4
- package/src/elements/vault/security-checklist.test.ts +130 -0
- package/src/elements/vault/storage.ts +448 -0
- package/src/elements/vault/types.ts +288 -0
- package/src/elements/vault/unseal.ts +150 -0
- package/src/elements/vault.test.ts +72 -4
- package/src/elements/vault.ts +91 -2
- package/src/full.ts +248 -0
- package/src/http.ts +41 -0
- package/src/i18n/interpolate-simple.ts +37 -0
- package/src/i18n/messages.ts +51 -4
- package/src/i18n-entry.ts +7 -0
- package/src/index.ts +35 -145
- package/src/journal-entry.ts +20 -0
- package/src/kernel/adopt-barrel-fresh.test.ts +25 -10
- package/src/kernel/app.ts +40 -42
- package/src/kernel/auto-registry.test.ts +2 -2
- package/src/kernel/boot-bind/ai.test.ts +5 -5
- package/src/kernel/boot-bind/ai.ts +2 -1
- package/src/kernel/boot-bind/channel.test.ts +6 -6
- package/src/kernel/boot-bind/channel.ts +3 -10
- package/src/kernel/boot-bind/clock.ts +2 -2
- package/src/kernel/boot-bind/gate.ts +5 -9
- package/src/kernel/boot-bind/honor-config.test.ts +42 -42
- package/src/kernel/boot-bind/journal.ts +2 -2
- package/src/kernel/boot-bind/store.test.ts +43 -44
- package/src/kernel/boot-bind/store.ts +16 -41
- package/src/kernel/boot-bind/vault.ts +16 -1
- package/src/kernel/boot.test.ts +12 -4
- package/src/kernel/boot.ts +31 -19
- package/src/kernel/budget-entry.ts +1 -1
- package/src/kernel/compensate.test.ts +288 -1
- package/src/kernel/compensate.ts +126 -0
- package/src/kernel/concurrency.test.ts +10 -9
- package/src/kernel/effects-stamping.test.ts +27 -2
- package/src/kernel/element-registries.ts +5 -3
- package/src/kernel/flow.ts +4 -2
- package/src/kernel/fx.test.ts +119 -3
- package/src/kernel/fx.ts +215 -40
- package/src/kernel/index.ts +14 -0
- package/src/kernel/journal.ts +130 -7
- package/src/kernel/pipeline.test.ts +20 -6
- package/src/kernel/redacted.test.ts +35 -0
- package/src/kernel/redacted.ts +24 -2
- package/src/kernel/router/create-default.ts +16 -0
- package/src/kernel/router/create-edge.ts +18 -0
- package/src/kernel/router/create.ts +23 -0
- package/src/kernel/router/index.ts +23 -0
- package/src/kernel/router/linear.ts +88 -0
- package/src/kernel/router/regexp.ts +188 -0
- package/src/kernel/router/smart.ts +120 -0
- package/src/kernel/router/trie.ts +108 -0
- package/src/kernel/router/types.ts +56 -0
- package/src/kernel/router.ts +18 -532
- package/src/kernel-entry.ts +43 -0
- package/src/manifest/fixtures/skyport.excerpt.json +1 -1
- package/src/manifest/fixtures/skyport.manifest.json +1 -1
- package/src/plugins/config-source.test.ts +7 -7
- package/src/release/build-lib.ts +58 -0
- package/src/release/exports.test.ts +4 -2
- package/src/release/exports.ts +30 -4
- package/src/release/measure.ts +101 -22
- package/src/runs/duckdb.ts +7 -2
- package/src/shared/optional-peer.ts +41 -0
- package/src/term.test.ts +3 -44
- package/src/test/create-test-app.ts +12 -0
- package/src/test/provisions.integration.test.ts +1 -1
- package/src/test/reset-element-registries.ts +2 -0
- package/src/upgrade/codemods.test.ts +7 -20
- package/src/upgrade/codemods.ts +93 -60
- package/site/content/docs/recipes/openbao.mdx +0 -141
- package/src/cli/ask-dev-mode.ts +0 -40
- package/src/cli/dev-mode.test.ts +0 -45
- package/src/cli/dev-mode.ts +0 -78
- package/src/cli/openbao-bootstrap.test.ts +0 -150
- package/src/cli/openbao-bootstrap.ts +0 -321
- package/src/cli/openbao-restart.integration.test.ts +0 -145
- package/src/console/ui/dist/assets/panel-vault-Za1GyJfM.js +0 -1
- package/src/console/ui/dist/assets/style-C8MxEWPd.css +0 -3
- package/src/docker/recipes/openbao.ts +0 -47
- package/src/drivers/libsql.ts +0 -179
- package/src/drivers/sqlite.ts +0 -44
- package/src/drivers/vault-openbao.test.ts +0 -97
- package/src/drivers/vault-openbao.ts +0 -143
|
@@ -186,7 +186,7 @@ await fx.store(db).delete(notes).where(lt(notes.createdAt, cutoff));
|
|
|
186
186
|
|
|
187
187
|
### Schema — declare once, generate per dialect
|
|
188
188
|
|
|
189
|
-
The recommended path: declare tables ORM-agnostically, then let `oke db` emit real Drizzle
|
|
189
|
+
The recommended path: declare tables ORM-agnostically, then let `oke db` emit real Drizzle (`pgTable` for Postgres / PGLite) into `src/db/schema.drizzle.ts`.
|
|
190
190
|
|
|
191
191
|
| Field API | Meaning |
|
|
192
192
|
| -------------------------------------------- | ----------------------------------------------- |
|
|
@@ -232,28 +232,28 @@ export const relations = store.schema.relations({ links, daily }, (r) => ({
|
|
|
232
232
|
| `oke db generate` | Write versioned SQL under `drizzle/` for review |
|
|
233
233
|
| `oke db migrate` | Apply those files — human or CI, **never** at boot |
|
|
234
234
|
|
|
235
|
-
`oke dev`
|
|
235
|
+
`oke dev` auto-pushes when you save a schema _input_ (`schema.decl.ts`,
|
|
236
236
|
hand-written `schema.ts`, `app.ts` for plugin tables, or `drizzle.config.ts`) —
|
|
237
|
-
not when emit rewrites `schema.
|
|
237
|
+
not when emit rewrites `schema.drizzle.ts`.
|
|
238
238
|
|
|
239
|
-
Opt out with `--no-db-push` or `db: { autoPush: false }`.
|
|
240
|
-
auto-
|
|
239
|
+
Opt out with `--no-db-push` or `db: { autoPush: false }`. `prod` **never**
|
|
240
|
+
auto-applies DDL; a missing table fails as **OKE1101** (`oke db migrate`).
|
|
241
241
|
|
|
242
242
|
#### Multiple environments
|
|
243
243
|
|
|
244
|
-
|
|
244
|
+
`dev` can `oke db push` freely — safe to wipe and regenerate.
|
|
245
245
|
|
|
246
246
|
Staging/prod accumulate versioned SQL under `drizzle/` (`oke db generate`).
|
|
247
247
|
`oke db migrate` applies only unrecorded files in order — behind DBs catch up.
|
|
248
248
|
|
|
249
249
|
| Environment | Sync |
|
|
250
250
|
| -------------- | -------------------------------------------------------------- |
|
|
251
|
-
|
|
|
251
|
+
| `dev` | `oke db push` (or auto-push from `oke dev`) |
|
|
252
252
|
| Staging / prod | `oke db generate` → review files → `oke db migrate` on that DB |
|
|
253
253
|
|
|
254
254
|
<Callout title="Connection pooling is infrastructure, not app code" type="info">
|
|
255
255
|
Bun.SQL defaults to **10** connections per process — fine per instance. Scale out and `N × pool`
|
|
256
|
-
can exceed Postgres `max_connections`.
|
|
256
|
+
can exceed Postgres `max_connections`. `dev`/`prod` put **PgDog** in front; `DATABASE_URL` → port
|
|
257
257
|
`6432`. No app code changes.
|
|
258
258
|
</Callout>
|
|
259
259
|
|
|
@@ -272,15 +272,13 @@ Seed proves existence (bootstrap rows); it does not correct schema-adjacent data
|
|
|
272
272
|
|
|
273
273
|
<StoreSeeding />
|
|
274
274
|
|
|
275
|
-
| env
|
|
276
|
-
|
|
|
277
|
-
| `
|
|
278
|
-
| `
|
|
279
|
-
| `
|
|
280
|
-
| `prod` | yes | no | yes |
|
|
275
|
+
| env | `essential` | `dev` | `prod` |
|
|
276
|
+
| ------ | ----------- | ----- | ------ |
|
|
277
|
+
| `dev` | yes | yes | no |
|
|
278
|
+
| `test` | yes | no | no |
|
|
279
|
+
| `prod` | yes | no | yes |
|
|
281
280
|
|
|
282
|
-
`
|
|
283
|
-
Outside `test`, exactly one of `dev` / `prod` runs with `essential`.
|
|
281
|
+
Outside `test`, exactly one of seed-category `dev` / `prod` runs with `essential`.
|
|
284
282
|
|
|
285
283
|
**Simple form** — everything inline:
|
|
286
284
|
|
|
@@ -367,14 +365,14 @@ await fx.store(db).upsert(
|
|
|
367
365
|
is for seed-owned rows you intentionally overwrite. Schema-wide data fixes still belong in
|
|
368
366
|
migrations, not seed.
|
|
369
367
|
|
|
370
|
-
| Env
|
|
371
|
-
|
|
|
372
|
-
| `
|
|
373
|
-
| `
|
|
368
|
+
| Env | Confirm |
|
|
369
|
+
| -------------- | ----------------------------------------------------- |
|
|
370
|
+
| `test` | none |
|
|
371
|
+
| `dev` / `prod` | print DB target; type the env name (`--force` for CI) |
|
|
374
372
|
|
|
375
373
|
```bash
|
|
376
|
-
oke db seed # resolve env like other oke db commands
|
|
377
|
-
oke db seed --env
|
|
374
|
+
oke db seed # resolve env like other oke db commands
|
|
375
|
+
oke db seed --env dev # explicit override
|
|
378
376
|
oke db seed --env prod --force
|
|
379
377
|
```
|
|
380
378
|
|
|
@@ -394,27 +392,25 @@ oke db seed --env prod --force
|
|
|
394
392
|
|
|
395
393
|
Same flow code, different backends — configured once in `oke.config.ts`:
|
|
396
394
|
|
|
397
|
-
| Facet |
|
|
398
|
-
| ----- |
|
|
399
|
-
| `sql` | `
|
|
395
|
+
| Facet | `dev` / `prod` | `test` | Runs as |
|
|
396
|
+
| ----- | -------------- | -------- | --------------------------------------------- |
|
|
397
|
+
| `sql` | `postgres` | `pglite` | Compose / deploy Postgres → in-process PGLite |
|
|
400
398
|
|
|
401
|
-
Defaults: `
|
|
399
|
+
Defaults: `postgres` for `dev`/`prod`, `pglite` for `test`. SQLite-family drivers (`sqlite`, `libsql`) are removed. Container images come from the `images` map — change the vendor by changing the pin, never the driver id.
|
|
402
400
|
|
|
403
401
|
#### Opt-in SQL drivers
|
|
404
402
|
|
|
405
|
-
|
|
403
|
+
| Driver | Install | Wire dialect | Choose for |
|
|
404
|
+
| -------- | -------------------------------------------------------- | ------------ | --------------------------------------------------------- |
|
|
405
|
+
| `pglite` | `@electric-sql/pglite` + `@electric-sql/pglite-pgvector` | postgresql | **required** for `store.sql.test`; also usable in-process |
|
|
406
406
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
<Callout title="PGlite is not a latency play">
|
|
413
|
-
PGlite pays a one-time ~1 s WASM init, and warm CRUD is roughly 15× slower than `bun:sqlite`.
|
|
414
|
-
Choose it for dialect/pgvector parity with prod — never as a faster local default.
|
|
407
|
+
<Callout title="PGlite is the test SQL driver">
|
|
408
|
+
`defineConfig` requires `drivers.store.sql.test` to be `pglite` when set. Use `oke test` (sets
|
|
409
|
+
`OKE_PGLITE_URL=memory://`). Choose PGLite for Postgres correctness in tests — not as a Compose
|
|
410
|
+
substitute for `oke dev`.
|
|
415
411
|
</Callout>
|
|
416
412
|
|
|
417
|
-
SQL-backed index
|
|
413
|
+
SQL-backed index driver `pgvector` shares this facet's connection — see [Advanced — composing facets together](#advanced--composing-facets-together).
|
|
418
414
|
|
|
419
415
|
## KV
|
|
420
416
|
|
|
@@ -470,8 +466,8 @@ Optional third argument on `set` is a duration string: `(\d+)(ms|s|m|h|d)` — e
|
|
|
470
466
|
|
|
471
467
|
<StoreKvTtl />
|
|
472
468
|
|
|
473
|
-
**Consequence:** a TTL you rely on in prod does nothing under the
|
|
474
|
-
against `redis`
|
|
469
|
+
**Consequence:** a TTL you rely on in prod does nothing under the `test` `memory` driver. Exercise
|
|
470
|
+
expiry against `redis` under `oke dev` when lifetime matters.
|
|
475
471
|
|
|
476
472
|
### Examples — what follows from each choice
|
|
477
473
|
|
|
@@ -498,25 +494,25 @@ your Flows and operator tools stay readable.
|
|
|
498
494
|
```typescript title="oke.config.ts"
|
|
499
495
|
drivers: {
|
|
500
496
|
store: {
|
|
501
|
-
kv: {
|
|
497
|
+
kv: { dev: "redis", test: "memory", prod: "redis" },
|
|
502
498
|
},
|
|
503
499
|
},
|
|
504
500
|
images: {
|
|
505
|
-
|
|
501
|
+
store: { kv: "redis:8-alpine" },
|
|
506
502
|
// or: "valkey/valkey:8-alpine"
|
|
507
503
|
// or: "docker.dragonflydb.io/dragonflydb/dragonfly"
|
|
508
504
|
},
|
|
509
505
|
```
|
|
510
506
|
|
|
511
|
-
| Facet |
|
|
512
|
-
| ----- |
|
|
513
|
-
| `kv` | `
|
|
507
|
+
| Facet | `dev` / `prod` | `test` | Runs as |
|
|
508
|
+
| ----- | -------------- | -------- | ---------------------- |
|
|
509
|
+
| `kv` | `redis` | `memory` | container → in-process |
|
|
514
510
|
|
|
515
511
|
| Variable | When |
|
|
516
512
|
| ------------------ | -------------------------------- |
|
|
517
513
|
| `REDIS_URL` | Required for the `redis` driver |
|
|
518
514
|
| `OKE_STORE_KV_URL` | Override if `REDIS_URL` is unset |
|
|
519
|
-
| `OKE_KV_DRIVER` | Force a driver id
|
|
515
|
+
| `OKE_KV_DRIVER` | Force a driver id |
|
|
520
516
|
|
|
521
517
|
Missing Redis URL fails boot loudly: `oke boot: redis driver needs REDIS_URL`.
|
|
522
518
|
|
|
@@ -613,28 +609,28 @@ Keys are opaque strings the driver stores as-is. Prefer path-like prefixes (`pho
|
|
|
613
609
|
```typescript title="oke.config.ts"
|
|
614
610
|
drivers: {
|
|
615
611
|
store: {
|
|
616
|
-
files: {
|
|
612
|
+
files: { dev: "s3", test: "memory", prod: "s3" },
|
|
617
613
|
},
|
|
618
614
|
},
|
|
619
615
|
images: {
|
|
620
|
-
|
|
616
|
+
store: { files: "rustfs/rustfs:1.0.0-beta.11" },
|
|
621
617
|
},
|
|
622
618
|
```
|
|
623
619
|
|
|
624
|
-
| Facet |
|
|
625
|
-
| ------- |
|
|
626
|
-
| `files` | `
|
|
620
|
+
| Facet | `dev` / `prod` | `test` | Runs as |
|
|
621
|
+
| ------- | -------------- | -------- | ------------------------ |
|
|
622
|
+
| `files` | `s3` | `memory` | RustFS / S3 → in-process |
|
|
627
623
|
|
|
628
624
|
| Variable | When |
|
|
629
625
|
| ----------------------------- | -------------------------------------- |
|
|
630
626
|
| `S3_BUCKET` | Required bucket for the `s3` driver |
|
|
631
627
|
| `OKE_STORE_FILES_DB` | Override bucket name |
|
|
632
628
|
| `S3_ENDPOINT` · keys · region | S3-compatible endpoint and credentials |
|
|
633
|
-
| `OKE_FILES_DRIVER` | Force a driver id
|
|
629
|
+
| `OKE_FILES_DRIVER` | Force a driver id |
|
|
634
630
|
|
|
635
631
|
`memory` is the test default. Local `fs` writes under a temp root when no binding `root` is set.
|
|
636
632
|
|
|
637
|
-
**Known limit:** `fs` is single-host. Under horizontal scale each replica sees its own filesystem (silently inconsistent object views). Boot prints a one-shot warning when `drivers.store.files` is `fs`. Use `s3` for
|
|
633
|
+
**Known limit:** `fs` is single-host. Under horizontal scale each replica sees its own filesystem (silently inconsistent object views). Boot prints a one-shot warning when `drivers.store.files` is `fs`. Use `s3` for `dev`/`prod` (create-oke templates already do).
|
|
638
634
|
|
|
639
635
|
<Callout title="Operator tools can browse, not edit bytes">
|
|
640
636
|
Operator tools can list keys and delete them. Direct edit is **KV + SQL only** — blob bodies are
|
|
@@ -747,11 +743,10 @@ runtime.
|
|
|
747
743
|
|
|
748
744
|
### Vector ANN
|
|
749
745
|
|
|
750
|
-
| `store.index` id | Shares connection from | Real ANN via
|
|
751
|
-
| ---------------- | -------------------------- |
|
|
752
|
-
| `memory` | — (in-process, default) | Full scan cosine
|
|
753
|
-
| `pgvector` | `postgres` or `pglite` sql | HNSW + `cosineDistance`
|
|
754
|
-
| `libsql` | `libsql` sql | `libsql_vector_idx` + `vector_top_k` |
|
|
746
|
+
| `store.index` id | Shares connection from | Real ANN via |
|
|
747
|
+
| ---------------- | -------------------------- | ----------------------- |
|
|
748
|
+
| `memory` | — (in-process, default) | Full scan cosine |
|
|
749
|
+
| `pgvector` | `postgres` or `pglite` sql | HNSW + `cosineDistance` |
|
|
755
750
|
|
|
756
751
|
**Consequence:** a configured SQL-backed index that cannot reach its engine — missing peer, missing
|
|
757
752
|
`vector` extension, wrong sql driver — fails loudly at first use. It never silently falls back to
|
|
@@ -788,29 +783,27 @@ do: async ({ id, doc, q }, fx) => {
|
|
|
788
783
|
```typescript title="oke.config.ts"
|
|
789
784
|
drivers: {
|
|
790
785
|
store: {
|
|
791
|
-
index: {
|
|
786
|
+
index: { dev: "meilisearch", test: "memory", prod: "meilisearch" },
|
|
792
787
|
},
|
|
793
788
|
},
|
|
794
789
|
images: {
|
|
795
|
-
|
|
790
|
+
store: { index: "getmeili/meilisearch:v1.37" },
|
|
796
791
|
},
|
|
797
792
|
```
|
|
798
793
|
|
|
799
|
-
-
|
|
800
|
-
- **Docker / prod** uses the image recipe; the app gets `OKE_STORE_INDEX_URL` + `OKE_STORE_INDEX_KEY` from Compose — a standalone HTTP service, never the shared `sqlUrl`.
|
|
794
|
+
- **`oke dev` / prod** use the image recipe; the app gets `OKE_STORE_INDEX_URL` + `OKE_STORE_INDEX_KEY` from Compose — a standalone HTTP service, never the shared `sqlUrl`.
|
|
801
795
|
- **Fail-loud:** a configured meilisearch that is unreachable or unhealthy throws `MeilisearchUnavailableError` — never a silent memory fallback.
|
|
802
796
|
- **Not for vectors:** `ai.embed` / `fx.search` stay vector-only; pointing an embed `into` a meilisearch index fails loud (embeddings don't apply).
|
|
803
|
-
- **Alpine caveat:** the raw glibc binary fails on Alpine/musl _hosts_; the official image is musl-clean. Install the binary for your platform (e.g. Homebrew / install script), or use `--docker`.
|
|
804
797
|
|
|
805
798
|
### Per-environment Index drivers
|
|
806
799
|
|
|
807
|
-
Unlike KV/Files, an unset `drivers.store.index` map stays **`memory` in every environment** — there is no
|
|
800
|
+
Unlike KV/Files, an unset `drivers.store.index` map stays **`memory` in every environment** — there is no automatic fallback to `pgvector`. Opt in explicitly:
|
|
808
801
|
|
|
809
802
|
```typescript title="oke.config.ts"
|
|
810
803
|
drivers: {
|
|
811
804
|
store: {
|
|
812
|
-
sql: {
|
|
813
|
-
index: {
|
|
805
|
+
sql: { dev: "postgres", test: "pglite", prod: "postgres" },
|
|
806
|
+
index: { dev: "pgvector", test: "memory", prod: "pgvector" },
|
|
814
807
|
},
|
|
815
808
|
},
|
|
816
809
|
```
|
|
@@ -831,25 +824,25 @@ target meilisearch.
|
|
|
831
824
|
|
|
832
825
|
Facets are independent declarations. A Flow may touch several in one `do` — for example store a files key on a SQL row, or `upsert` into an index after a SQL write. There is no special sync API: `store.resource` `search:` is SQL substring match, not meilisearch.
|
|
833
826
|
|
|
834
|
-
One real coupling:
|
|
827
|
+
One real coupling: `pgvector` shares the sql facet's already-open connection, so configure the pair together:
|
|
835
828
|
|
|
836
829
|
```typescript title="oke.config.ts"
|
|
837
830
|
drivers: {
|
|
838
831
|
store: {
|
|
839
|
-
sql: {
|
|
840
|
-
index: {
|
|
832
|
+
sql: { dev: "postgres", test: "pglite", prod: "postgres" },
|
|
833
|
+
index: { dev: "pgvector", test: "memory", prod: "pgvector" },
|
|
841
834
|
},
|
|
842
835
|
},
|
|
843
836
|
```
|
|
844
837
|
|
|
845
|
-
|
|
838
|
+
The full per-environment map looks like this:
|
|
846
839
|
|
|
847
840
|
```typescript title="oke.config.ts"
|
|
848
841
|
drivers: {
|
|
849
842
|
store: {
|
|
850
|
-
sql: {
|
|
851
|
-
kv: {
|
|
852
|
-
files: {
|
|
843
|
+
sql: { dev: "postgres", test: "pglite", prod: "postgres" },
|
|
844
|
+
kv: { dev: "redis", test: "memory", prod: "redis" },
|
|
845
|
+
files: { dev: "s3", test: "memory", prod: "s3" },
|
|
853
846
|
},
|
|
854
847
|
},
|
|
855
848
|
```
|
|
@@ -867,9 +860,9 @@ same PII masking — see the Callout under [Querying by hand](#querying-by-hand)
|
|
|
867
860
|
## Troubleshooting
|
|
868
861
|
|
|
869
862
|
<Accordions>
|
|
870
|
-
<Accordion title="OKE1101 — missing table in
|
|
863
|
+
<Accordion title="OKE1101 — missing table in prod">
|
|
871
864
|
|
|
872
|
-
Schema DDL never runs automatically
|
|
865
|
+
Schema DDL never runs automatically in `prod`. Under `oke dev`, `db.autoPush` (default `true`) runs `oke db push`. For production use `oke db generate` + `oke db migrate`.
|
|
873
866
|
|
|
874
867
|
</Accordion>
|
|
875
868
|
<Accordion title="I need a join — with: is not supported">
|
|
@@ -887,14 +880,14 @@ You are on offset paging. Switch `list` to keyset by setting `cursor` columns wi
|
|
|
887
880
|
`count: "exact"` runs `COUNT(*)` per page. Set `count: "none"` in the `list` options to skip it, or use keyset mode where totals are rarely needed.
|
|
888
881
|
|
|
889
882
|
</Accordion>
|
|
890
|
-
<Accordion title="KV TTL never expires
|
|
883
|
+
<Accordion title="KV TTL never expires in tests">
|
|
891
884
|
|
|
892
|
-
The
|
|
885
|
+
The `test` default is `memory`, which ignores TTL on `set`. Under `oke dev`, KV is `redis` by default — use that when you need real expiry.
|
|
893
886
|
|
|
894
887
|
</Accordion>
|
|
895
888
|
<Accordion title="oke boot: redis / meilisearch / S3 URL missing">
|
|
896
889
|
|
|
897
|
-
Driver-backed facets fail boot when their URL is absent — Redis needs `REDIS_URL`, meilisearch needs `OKE_STORE_INDEX_URL`, S3 needs `S3_BUCKET`.
|
|
890
|
+
Driver-backed facets fail boot when their URL is absent — Redis needs `REDIS_URL`, meilisearch needs `OKE_STORE_INDEX_URL`, S3 needs `S3_BUCKET`. `oke dev` writes these into the Compose env.
|
|
898
891
|
|
|
899
892
|
</Accordion>
|
|
900
893
|
<Accordion title="vector dims X !== index dims Y">
|
|
@@ -902,9 +895,9 @@ Driver-backed facets fail boot when their URL is absent — Redis needs `REDIS_U
|
|
|
902
895
|
The vector length must match `store.index(…, { dims })` (runtime default `3` if unset). Align `dims` with your embedder, or fix the vector you pass to `upsert` / `search`.
|
|
903
896
|
|
|
904
897
|
</Accordion>
|
|
905
|
-
<Accordion title="Index stays on memory
|
|
898
|
+
<Accordion title="Index stays on memory under oke dev">
|
|
906
899
|
|
|
907
|
-
Unlike KV/Files, unset `drivers.store.index` does **not** promote to `pgvector` in
|
|
900
|
+
Unlike KV/Files, unset `drivers.store.index` does **not** promote to `pgvector` in `dev` — it stays `memory`. Set the map explicitly (and pair SQL for `pgvector`).
|
|
908
901
|
|
|
909
902
|
</Accordion>
|
|
910
903
|
</Accordions>
|
|
@@ -55,7 +55,7 @@ oke vault set STRIPE_KEY sk_test_your_key_here
|
|
|
55
55
|
<Step>
|
|
56
56
|
### Read it in a Flow
|
|
57
57
|
|
|
58
|
-
Flows read secrets through `fx.vault` — never through `process.env`.
|
|
58
|
+
Flows read secrets through `fx.vault.get` — never through `process.env`. It resolves to a
|
|
59
59
|
`Redacted<string>`: printing, logging, or serializing it yields a placeholder, never the value.
|
|
60
60
|
Call `.reveal()` once at the boundary that needs the real credential:
|
|
61
61
|
|
|
@@ -66,7 +66,7 @@ export const charge = on(
|
|
|
66
66
|
in: ChargeInput,
|
|
67
67
|
out: z.object({ id: z.string() }),
|
|
68
68
|
do: async (input, fx) => {
|
|
69
|
-
const key = fx.vault(stripeKey); // Redacted — safe to pass to fx.log
|
|
69
|
+
const key = await fx.vault.get(stripeKey); // Redacted — safe to pass to fx.log
|
|
70
70
|
const intent = await stripe(key.reveal()).create(input);
|
|
71
71
|
return { id: intent.id };
|
|
72
72
|
},
|
|
@@ -87,9 +87,9 @@ That's the whole loop: declare → set → read. Everything below is what OKE gu
|
|
|
87
87
|
|
|
88
88
|
<VaultRedacted />
|
|
89
89
|
|
|
90
|
-
Pass the wrapper freely — `fx.log`, `String()`,
|
|
91
|
-
`
|
|
92
|
-
credential.
|
|
90
|
+
Pass the wrapper freely — `fx.log`, `String()`, `JSON.stringify`, and
|
|
91
|
+
`console.log` / `util.inspect` all yield `[redacted]` (or a `Redacted<…>` label).
|
|
92
|
+
Call `.reveal()` once at the provider boundary that needs the credential.
|
|
93
93
|
|
|
94
94
|
## Two kinds of contracts
|
|
95
95
|
|
|
@@ -100,6 +100,20 @@ credential.
|
|
|
100
100
|
|
|
101
101
|
`vault(name, …)` is shorthand for `vault.secret(name, …)`.
|
|
102
102
|
|
|
103
|
+
### Plain environment variables
|
|
104
|
+
|
|
105
|
+
`vault.env` reads `process.env` synchronously for values that need no contract — a port, a feature flag, a log level. It never joins the resolution chain, never gets a fingerprint, and never gets redacted.
|
|
106
|
+
|
|
107
|
+
| Call | Returns | On a missing value |
|
|
108
|
+
| -------------------------------- | --------------------- | -------------------------------------- |
|
|
109
|
+
| `vault.env("LOG_LEVEL")` | `string \| undefined` | `undefined` (empty counts as missing) |
|
|
110
|
+
| `vault.env.required("REGION")` | `string` | Throws, and boot lists it as a gap |
|
|
111
|
+
| `vault.env.int("PORT", 3000)` | `number` | The default; throws when none is given |
|
|
112
|
+
| `vault.env.bool("DEBUG", false)` | `boolean` | The default; throws when none is given |
|
|
113
|
+
| `vault.env.json("FLAGS")` | `T \| undefined` | `undefined`; throws on malformed JSON |
|
|
114
|
+
|
|
115
|
+
Every name passed to `vault.env.required` is registered, so boot reports missing variables in the same `VaultBootError` as missing secrets — before it opens a database connection.
|
|
116
|
+
|
|
103
117
|
### Contract options
|
|
104
118
|
|
|
105
119
|
| Option | Type | Meaning |
|
|
@@ -110,9 +124,9 @@ credential.
|
|
|
110
124
|
| `dev` | string | Local-only fallback when no source provides a value (never used in prod) |
|
|
111
125
|
| `sensitive` | boolean | Override the default (`true` for secrets, `false` for config) |
|
|
112
126
|
|
|
113
|
-
### Zero-setup
|
|
127
|
+
### Zero-setup Compose fallback
|
|
114
128
|
|
|
115
|
-
`dev: vault.fromDocker("store.sql")` resolves the connection URL that `oke dev
|
|
129
|
+
`dev: vault.fromDocker("store.sql")` resolves the connection URL that `oke dev` generated for that role — no manual copying of Postgres URLs:
|
|
116
130
|
|
|
117
131
|
```typescript
|
|
118
132
|
export const dbUrl = vault.secret("DATABASE_URL", {
|
|
@@ -140,85 +154,82 @@ VaultBootError: 1 secret(s) missing:
|
|
|
140
154
|
|
|
141
155
|
## Setting and rotating values
|
|
142
156
|
|
|
143
|
-
| Command
|
|
144
|
-
|
|
|
145
|
-
| `oke vault set NAME value`
|
|
146
|
-
| `oke vault list`
|
|
147
|
-
| `oke vault import <file>`
|
|
157
|
+
| Command | What it does |
|
|
158
|
+
| -------------------------------------------------- | -------------------------------------------------------------------- |
|
|
159
|
+
| `oke vault set NAME value` | Write a value to the env file (`.env.local` by default) |
|
|
160
|
+
| `oke vault list` | List names present in the active store |
|
|
161
|
+
| `oke vault import <file>` | Bulk-import names from a dotenv file |
|
|
162
|
+
| `oke vault init` | Initialize the built-in encrypted store (prints the master key once) |
|
|
163
|
+
| `oke vault status` / `seal` / `unseal` | Built-in seal lifecycle |
|
|
164
|
+
| `oke vault rotate <path>` / `rotate-master` | Re-encrypt a secret, or rewrap every DEK under a new master |
|
|
165
|
+
| `oke vault audit` / `audit verify` / `audit purge` | Hash-chained audit (no secret values) |
|
|
166
|
+
| `oke vault purge-expired [--dry-run] [--before]` | Hard-delete secret rows past `expires_at` (operator cleanup) |
|
|
167
|
+
| `oke vault backup` / `restore` | Encrypted backup under a separate backup KEK |
|
|
148
168
|
|
|
149
|
-
|
|
169
|
+
Flows can write too, through the same capability gate as reads: `fx.vault.set(path, value, { ttlMs?, metadata? })`, `fx.vault.rotate(path, value)`, `fx.vault.delete(path)`, plus `fx.vault.list(prefix?)` and `fx.vault.status()`. These need the encrypted-at-rest backend (`drivers.vault = "vault"`) and throw without it; `fx.vault.get` works on every app.
|
|
150
170
|
|
|
151
171
|
The **Console** (`:6533`) can also set and rotate values, but it is **write-only**: it shows a salted fingerprint (`sha256:…`) per secret, never the cleartext. When you rotate a key there, the panel shows the **blast radius** — which in-flight durable runs will wake up with the new value.
|
|
152
172
|
|
|
173
|
+
<Callout title="Builtin master keys and expired rows">
|
|
174
|
+
Resolve the master key with `--key -` (stdin), `OKE_VAULT_MASTER_KEY`, or a hidden TTY prompt —
|
|
175
|
+
never put keys on argv in shared shells (history risk). Expired rows stay until `oke vault
|
|
176
|
+
purge-expired` (use `--dry-run` first, or schedule via cron).
|
|
177
|
+
</Callout>
|
|
178
|
+
|
|
153
179
|
<Callout title="Secrets never reach logs">
|
|
154
|
-
`fx.vault` returns `Redacted` — `fx.log` shows `[redacted]`. A revealed string that still
|
|
155
|
-
a log is scrubbed by the boot redactor to `[redacted:secret]`. Traces and the Console get
|
|
180
|
+
`fx.vault.get` returns `Redacted` — `fx.log` shows `[redacted]`. A revealed string that still
|
|
181
|
+
reaches a log is scrubbed by the boot redactor to `[redacted:secret]`. Traces and the Console get
|
|
156
182
|
fingerprints, never cleartext.
|
|
157
183
|
</Callout>
|
|
158
184
|
|
|
159
185
|
## Per-environment drivers
|
|
160
186
|
|
|
161
|
-
Which backend holds your values depends on the
|
|
187
|
+
Which backend holds your values depends on the environment — configured once in `oke.config.ts`.
|
|
162
188
|
App boot and the Console share the same resolution-chain builder (`env` layers → backend):
|
|
163
189
|
|
|
164
190
|
```typescript title="oke.config.ts"
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
191
|
+
drivers: {
|
|
192
|
+
vault: {
|
|
193
|
+
dev: "env", // process env / .env.local
|
|
194
|
+
test: "memory",
|
|
195
|
+
prod: "vault", // built-in encrypted store (Postgres you already run)
|
|
196
|
+
},
|
|
170
197
|
},
|
|
171
198
|
```
|
|
172
199
|
|
|
173
|
-
|
|
174
|
-
| --------- | --------------- | ------------------------------------------ |
|
|
175
|
-
| `env` | `.env.local` | Local loop — no infra at all |
|
|
176
|
-
| `openbao` | OpenBao (KV v2) | Docker + prod — durable, access-controlled |
|
|
177
|
-
| `memory` | in-process map | Tests |
|
|
178
|
-
|
|
179
|
-
Other drivers (`managed`) implement the same `VaultDriver` interface — adding one is a driver exercise, not an architecture change.
|
|
180
|
-
|
|
181
|
-
## OpenBao in docker and prod
|
|
200
|
+
Defaults are `env` / `memory` / `vault`. create-oke templates pin the built-in store for prod.
|
|
182
201
|
|
|
183
|
-
|
|
202
|
+
| Driver | Backend | Best for |
|
|
203
|
+
| --------- | ------------------------------------------------------------------- | ---------------------------------- |
|
|
204
|
+
| `env` | process env | Local pins — no encryption at rest |
|
|
205
|
+
| `vault` | Postgres/PGlite envelope (AES-256-GCM) | Default prod — no extra container |
|
|
206
|
+
| `managed` | AWS Secrets Manager (`OKE_VAULT_PROVIDER`) or platform-injected env | Cloud SM / Fly / Railway / K8s |
|
|
207
|
+
| `memory` | in-process map | Tests |
|
|
184
208
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
<Step>
|
|
188
|
-
### First boot is automatic
|
|
209
|
+
### Threat model (honest)
|
|
189
210
|
|
|
190
|
-
|
|
211
|
+
Built-in Vault protects a **database dump** (ciphertext + wrapped DEKs). It does **not** equal a separate process-isolated vault:
|
|
191
212
|
|
|
192
|
-
|
|
213
|
+
| Threat | Built-in `vault` | Managed AWS SM / remote vault |
|
|
214
|
+
| --------------------------------------------- | ---------------------------------- | ----------------------------- |
|
|
215
|
+
| Postgres dump / backup leak | Protected (need master/KEK) | Protected |
|
|
216
|
+
| App RCE / memory dump | Game over (same process) | Better if vault is isolated |
|
|
217
|
+
| Master key only in `.env` next to app secrets | Weak — use KMS auto-unseal in prod | Prefer non-exportable KEK |
|
|
218
|
+
| JS `Buffer.fill(0)` vs remote `mlock` | Hygiene only — not claimed | Stronger outside the app |
|
|
193
219
|
|
|
194
|
-
|
|
195
|
-
### Keys stay on the host
|
|
220
|
+
For production built-in stores, set `vault.encryption.masterKey` to a KMS source (optional peer `@aws-sdk/client-kms`) or use `managed` + AWS Secrets Manager. `oke doctor` warns when prod would take the master key from the environment.
|
|
196
221
|
|
|
197
|
-
|
|
222
|
+
## Managed providers (official)
|
|
198
223
|
|
|
199
|
-
|
|
224
|
+
Official managed provider: **AWS Secrets Manager** — set `drivers.vault` to `"managed"` and
|
|
225
|
+
`OKE_VAULT_PROVIDER=aws-secrets-manager` (optional peer `@aws-sdk/client-secrets-manager`).
|
|
226
|
+
Omit the provider when the platform already injects secrets as env vars.
|
|
200
227
|
|
|
201
|
-
|
|
202
|
-
### Restarts just work
|
|
228
|
+
## Community / plugin
|
|
203
229
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
</Steps>
|
|
209
|
-
|
|
210
|
-
| File | Holds | Used by |
|
|
211
|
-
| ------------------------- | ------------------------- | -------------------------------- |
|
|
212
|
-
| `.oke/openbao/unseal.key` | The single unseal share | `oke` (every start) |
|
|
213
|
-
| `.oke/openbao/root.token` | Root token | `oke` (policy sync / token mint) |
|
|
214
|
-
| `.oke/openbao/app.token` | Least-privilege app token | the app + Console |
|
|
215
|
-
|
|
216
|
-
<Callout title="Single point of failure — read this once" type="warn">
|
|
217
|
-
Back up `.oke/openbao/unseal.key` to a separate safe location. Losing it means losing every secret
|
|
218
|
-
permanently, with no recovery.
|
|
219
|
-
</Callout>
|
|
220
|
-
|
|
221
|
-
This is by design: self-hosted single-node, Shamir 1-of-1, no cloud KMS. If OpenBao is initialized but the key is gone, boot fails with an explicit permanent-loss error — it never silently starts empty.
|
|
230
|
+
OpenBao, HashiCorp Vault, Azure Key Vault, GCP Secret Manager, Doppler, and 1Password are not
|
|
231
|
+
shipped in core. Implement a community adapter for the `managed` driver surface, or keep using
|
|
232
|
+
built-in `vault` / `env`.
|
|
222
233
|
|
|
223
234
|
## Troubleshooting
|
|
224
235
|
|
|
@@ -228,30 +239,38 @@ This is by design: self-hosted single-node, Shamir 1-of-1, no cloud KMS. If Open
|
|
|
228
239
|
A contract has no value in any layer of the chain. Fix by providing it in exactly one place:
|
|
229
240
|
|
|
230
241
|
- locally: add `NAME=value` to `.env.local` (or run `oke vault set NAME value`)
|
|
231
|
-
-
|
|
232
|
-
- CI / hosting: set a real environment variable
|
|
242
|
+
- built-in store: `oke vault init` then unseal, or set via Console (write-only)
|
|
243
|
+
- CI / hosting: set a real environment variable (or AWS SM when `managed`)
|
|
233
244
|
|
|
234
245
|
</Accordion>
|
|
235
|
-
<Accordion title="
|
|
246
|
+
<Accordion title="How do I rotate a key safely?">
|
|
236
247
|
|
|
237
|
-
|
|
248
|
+
Set the new value (`oke vault set` or the Console). The Console's rotation view shows the blast radius — in-flight durable runs that will resume with the new value — before you commit. The `rotate: "90d"` hint on the contract drives the rotation-due signal.
|
|
238
249
|
|
|
239
250
|
</Accordion>
|
|
240
|
-
<Accordion title="
|
|
251
|
+
<Accordion title="How do I pass the builtin master key without shell history?">
|
|
241
252
|
|
|
242
|
-
|
|
253
|
+
Prefer `oke vault unseal --key -` and pipe the key on stdin, or omit `--key` on a
|
|
254
|
+
TTY and type it at the hidden prompt. Avoid `--key <base64>` on shared hosts.
|
|
243
255
|
|
|
244
256
|
</Accordion>
|
|
245
|
-
<Accordion title="
|
|
257
|
+
<Accordion title="Expired secrets still take space in Postgres">
|
|
246
258
|
|
|
247
|
-
|
|
259
|
+
`expires_at` fails closed on read, but rows stay until you hard-delete them:
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
oke vault purge-expired --dry-run
|
|
263
|
+
oke vault purge-expired
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Schedule the live command with cron when you want automatic cleanup.
|
|
248
267
|
|
|
249
268
|
</Accordion>
|
|
250
269
|
</Accordions>
|
|
251
270
|
|
|
252
271
|
## Learn more
|
|
253
272
|
|
|
254
|
-
- [Flow](/docs/elements/flow) — how `fx.vault` reads secrets inside `do`
|
|
273
|
+
- [Flow](/docs/elements/flow) — how `fx.vault.get` reads secrets inside `do`
|
|
255
274
|
- [CLI Reference](/docs/reference/cli) — `oke vault set` · `list` · `import`
|
|
256
275
|
|
|
257
276
|
## Next
|
|
@@ -39,7 +39,7 @@ digest Clock, and an AI summarize stub.
|
|
|
39
39
|
The standard starter already exports a named health Flow:
|
|
40
40
|
|
|
41
41
|
```typescript title="flows/main"
|
|
42
|
-
import { on, flow, http, gate } from "okengine";
|
|
42
|
+
import { on, flow, http, gate } from "okengine/http";
|
|
43
43
|
import { z } from "zod";
|
|
44
44
|
|
|
45
45
|
export const health = on(
|
|
@@ -63,17 +63,17 @@ same Manifest.
|
|
|
63
63
|
Adopted modules become namespaces on the client:
|
|
64
64
|
|
|
65
65
|
```typescript title="app"
|
|
66
|
-
import
|
|
67
|
-
import * as main from "./flows/main";
|
|
68
|
-
import * as notes from "./flows/notes";
|
|
69
|
-
import { db } from "./core";
|
|
66
|
+
import "@/core";
|
|
70
67
|
|
|
71
|
-
|
|
68
|
+
import { oke } from "okengine/http";
|
|
69
|
+
import * as routes from "@/flows/generated";
|
|
70
|
+
|
|
71
|
+
export const app = oke({ name: "notes" }).adopt(routes);
|
|
72
72
|
export type App = typeof app;
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
`import "@/core"` loads stores, secrets, channels, and message catalogs
|
|
76
|
+
(via `locales/index.ts`) so they auto-register before `oke()`.
|
|
77
77
|
|
|
78
78
|
```typescript title="client"
|
|
79
79
|
import { createClient } from "okengine/client";
|