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.
Files changed (318) hide show
  1. package/package.json +76 -10
  2. package/site/content/docs/deployment/docker-swarm.mdx +48 -111
  3. package/site/content/docs/deployment/docker.mdx +43 -36
  4. package/site/content/docs/deployment/index.mdx +9 -9
  5. package/site/content/docs/deployment/kubernetes.mdx +4 -4
  6. package/site/content/docs/elements/ai.mdx +7 -7
  7. package/site/content/docs/elements/channel.mdx +9 -7
  8. package/site/content/docs/elements/clock.mdx +8 -8
  9. package/site/content/docs/elements/flow.mdx +46 -47
  10. package/site/content/docs/elements/gate.mdx +6 -5
  11. package/site/content/docs/elements/signal.mdx +2 -2
  12. package/site/content/docs/elements/store.mdx +71 -78
  13. package/site/content/docs/elements/vault.mdx +89 -70
  14. package/site/content/docs/get-started/basic-usage.mdx +8 -8
  15. package/site/content/docs/get-started/installation.mdx +36 -36
  16. package/site/content/docs/get-started/introduction.mdx +11 -0
  17. package/site/content/docs/get-started/why.mdx +2 -2
  18. package/site/content/docs/plugins/anonymous.mdx +1 -1
  19. package/site/content/docs/plugins/magic-link.mdx +11 -11
  20. package/site/content/docs/plugins/otp.mdx +2 -2
  21. package/site/content/docs/plugins/passkey.mdx +1 -1
  22. package/site/content/docs/plugins/two-factor.mdx +1 -1
  23. package/site/content/docs/plugins/username.mdx +1 -1
  24. package/site/content/docs/recipes/caddy.mdx +1 -1
  25. package/site/content/docs/recipes/cockroachdb.mdx +2 -2
  26. package/site/content/docs/recipes/dragonfly.mdx +1 -1
  27. package/site/content/docs/recipes/index.mdx +1 -2
  28. package/site/content/docs/recipes/llama-cpp.mdx +21 -23
  29. package/site/content/docs/recipes/mailpit.mdx +11 -11
  30. package/site/content/docs/recipes/meilisearch.mdx +10 -10
  31. package/site/content/docs/recipes/meta.json +0 -1
  32. package/site/content/docs/recipes/ollama.mdx +1 -1
  33. package/site/content/docs/recipes/pgdog.mdx +12 -9
  34. package/site/content/docs/recipes/postgres.mdx +3 -3
  35. package/site/content/docs/recipes/redis.mdx +2 -2
  36. package/site/content/docs/recipes/rustfs.mdx +10 -7
  37. package/site/content/docs/recipes/sglang.mdx +1 -1
  38. package/site/content/docs/recipes/supabase-docker.mdx +1 -1
  39. package/site/content/docs/recipes/timescale.mdx +2 -2
  40. package/site/content/docs/recipes/valkey.mdx +1 -1
  41. package/site/content/docs/recipes/vllm.mdx +1 -1
  42. package/site/content/docs/recipes/yugabytedb.mdx +2 -2
  43. package/site/content/docs/reference/cli.md +61 -38
  44. package/site/content/docs/reference/configuration.mdx +145 -70
  45. package/site/content/docs/reference/environment-variables.mdx +36 -28
  46. package/site/content/docs/reference/errors.mdx +28 -29
  47. package/site/content/docs/reference/fx.mdx +11 -4
  48. package/site/content/docs/reference/i18n.mdx +17 -6
  49. package/site/content/docs/reference/index.mdx +5 -0
  50. package/site/content/docs/reference/meta.json +1 -0
  51. package/site/content/docs/reference/migrating-environments.mdx +158 -0
  52. package/site/content/docs/reference/plugins.mdx +2 -2
  53. package/src/auth/gate-auth.test.ts +12 -10
  54. package/src/cli/ai-setup/ai-setup.test.ts +27 -15
  55. package/src/cli/ai-setup/apply.ts +111 -15
  56. package/src/cli/ai-setup/catalog.ts +3 -3
  57. package/src/cli/ai-setup/index.ts +1 -1
  58. package/src/cli/ai-setup/prompts.ts +1 -1
  59. package/src/cli/ai-setup/recommend.test.ts +1 -1
  60. package/src/cli/ask-seed.test.ts +3 -3
  61. package/src/cli/build.ts +1 -1
  62. package/src/cli/db-auto-push.test.ts +6 -3
  63. package/src/cli/db-auto-push.ts +7 -5
  64. package/src/cli/db-seed.ts +7 -8
  65. package/src/cli/db.test.ts +70 -71
  66. package/src/cli/db.ts +86 -12
  67. package/src/cli/dev-controller.test.ts +35 -0
  68. package/src/cli/dev-controller.ts +298 -0
  69. package/src/cli/dev-controls.ts +11 -65
  70. package/src/cli/dev-db-push.test.ts +47 -15
  71. package/src/cli/dev-schema-sync.test.ts +11 -11
  72. package/src/cli/dev-schema-sync.ts +10 -10
  73. package/src/cli/dev-session-lock.test.ts +106 -0
  74. package/src/cli/dev-session-lock.ts +209 -0
  75. package/src/cli/dev.test.ts +166 -121
  76. package/src/cli/dev.ts +138 -192
  77. package/src/cli/doc-staleness.test.ts +3 -6
  78. package/src/cli/docker-clean.test.ts +33 -1
  79. package/src/cli/docker-clean.ts +28 -33
  80. package/src/cli/docker-cli.test.ts +12 -11
  81. package/src/cli/docker.ts +95 -20
  82. package/src/cli/doctor.test.ts +40 -0
  83. package/src/cli/doctor.ts +55 -15
  84. package/src/cli/drizzle-env.test.ts +11 -13
  85. package/src/cli/drizzle-env.ts +18 -11
  86. package/src/cli/ensure-drizzle-config.ts +11 -14
  87. package/src/cli/hero-meta.test.ts +15 -15
  88. package/src/cli/hero-meta.ts +10 -9
  89. package/src/cli/index.ts +36 -6
  90. package/src/cli/load-config.images.test.ts +16 -12
  91. package/src/cli/load-config.source.test.ts +50 -0
  92. package/src/cli/load-config.ts +34 -28
  93. package/src/cli/meilisearch-local.ts +1 -2
  94. package/src/cli/mode.ts +7 -58
  95. package/src/cli/registry.ts +175 -19
  96. package/src/cli/resolve-dev-sql-env.test.ts +8 -16
  97. package/src/cli/resolve-dev-sql-env.ts +13 -15
  98. package/src/cli/safe-defaults.test.ts +28 -10
  99. package/src/cli/schema.ts +65 -16
  100. package/src/cli/test.ts +58 -0
  101. package/src/cli/tui/App.tsx +252 -0
  102. package/src/cli/tui/DevLive.tsx +116 -0
  103. package/src/cli/tui/components/ConfirmDialog.tsx +48 -0
  104. package/src/cli/tui/components/HeaderBar.tsx +67 -0
  105. package/src/cli/tui/components/LogStream.tsx +47 -0
  106. package/src/cli/tui/components/PanelCard.tsx +39 -0
  107. package/src/cli/tui/components/SelectRow.tsx +37 -0
  108. package/src/cli/tui/components/SlashPalette.tsx +172 -0
  109. package/src/cli/tui/components/Spinner.tsx +32 -0
  110. package/src/cli/tui/components/StatusBar.tsx +51 -0
  111. package/src/cli/tui/components/StatusDot.tsx +37 -0
  112. package/src/cli/tui/components/TabBar.tsx +49 -0
  113. package/src/cli/tui/components/Wordmark.tsx +43 -0
  114. package/src/cli/tui/format.ts +38 -0
  115. package/src/cli/tui/keys.test.ts +18 -0
  116. package/src/cli/tui/keys.ts +26 -0
  117. package/src/cli/tui/launch.test.ts +18 -0
  118. package/src/cli/tui/launch.ts +57 -0
  119. package/src/cli/tui/panels/Dashboard.tsx +201 -0
  120. package/src/cli/tui/panels/Database.tsx +198 -0
  121. package/src/cli/tui/panels/Dev.tsx +257 -0
  122. package/src/cli/tui/panels/Docker.tsx +357 -0
  123. package/src/cli/tui/panels/Navigator.test.ts +22 -0
  124. package/src/cli/tui/panels/Navigator.tsx +213 -0
  125. package/src/cli/tui/slash-catalog.test.ts +31 -0
  126. package/src/cli/tui/slash-catalog.ts +184 -0
  127. package/src/cli/tui/slash-run.ts +54 -0
  128. package/src/cli/tui/state/ports.ts +95 -0
  129. package/src/cli/tui/theme.ts +24 -0
  130. package/src/cli/vault-cmd.test.ts +402 -0
  131. package/src/cli/vault-cmd.ts +727 -69
  132. package/src/cli/vault-secure-input.test.ts +56 -0
  133. package/src/cli/vault-secure-input.ts +124 -0
  134. package/src/compiler/effects-infer.ts +7 -0
  135. package/src/compiler/fixtures/skyport/oke.config.ts +3 -3
  136. package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +1 -1
  137. package/src/compiler/fixtures/skyport.expected.json +1 -1
  138. package/src/compiler-entry.ts +7 -0
  139. package/src/config/define-config.test.ts +111 -47
  140. package/src/config/driver-defaults.test.ts +16 -23
  141. package/src/config/driver-defaults.ts +33 -63
  142. package/src/config/index.ts +169 -144
  143. package/src/config/resolve-driver.test.ts +14 -19
  144. package/src/console/server/app.ts +4 -2
  145. package/src/console/server/console.test.ts +58 -1
  146. package/src/console/server/flows.ts +22 -2
  147. package/src/console/server/index.ts +3 -0
  148. package/src/console/server/operator-db.test.ts +55 -13
  149. package/src/console/server/operator-db.ts +305 -263
  150. package/src/console/server/serve.ts +16 -7
  151. package/src/console/server/state.ts +31 -9
  152. package/src/console/server/vault.test.ts +120 -5
  153. package/src/console/server/vault.ts +208 -12
  154. package/src/console/ui/dist/assets/{index-D-9KFce5.js → index--Y0Uaz-m.js} +2 -2
  155. package/src/console/ui/dist/assets/panel-vault-BkZdJPX8.js +1 -0
  156. package/src/console/ui/dist/assets/style-C3L349iZ.css +3 -0
  157. package/src/console/ui/dist/index.html +2 -2
  158. package/src/console/ui/shell/client.ts +16 -0
  159. package/src/console/ui/shell/panels/vault/VaultPanel.tsx +54 -1
  160. package/src/console/ui/vault/VaultA11yView.tsx +33 -1
  161. package/src/console/ui/vault/backend.test.ts +75 -0
  162. package/src/console/ui/vault/backend.ts +117 -0
  163. package/src/console/ui/vault/fixture.ts +21 -2
  164. package/src/console/ui/vault/index.ts +11 -1
  165. package/src/console/ui/vault/types.ts +26 -0
  166. package/src/docker/compose.ts +164 -61
  167. package/src/docker/derive.ts +106 -12
  168. package/src/docker/docker.test.ts +156 -110
  169. package/src/docker/helpers.ts +98 -0
  170. package/src/docker/images-config.test.ts +3 -8
  171. package/src/docker/index.ts +30 -5
  172. package/src/docker/recipes/index.ts +0 -3
  173. package/src/docker/recipes/llama-cpp.ts +4 -4
  174. package/src/docker/recipes/pgdog.ts +9 -2
  175. package/src/docker/resources.test.ts +71 -0
  176. package/src/docker/resources.ts +176 -0
  177. package/src/docker/stack-id.test.ts +11 -4
  178. package/src/docker/stack-id.ts +42 -32
  179. package/src/docker/stack.integration.test.ts +4 -15
  180. package/src/docker/types.ts +35 -3
  181. package/src/drivers/ai-ollama.integration.test.ts +2 -2
  182. package/src/drivers/conformance.test.ts +11 -12
  183. package/src/drivers/drizzle-dialect.test.ts +0 -4
  184. package/src/drivers/drizzle-dialect.ts +7 -13
  185. package/src/drivers/index.ts +24 -7
  186. package/src/drivers/journal-postgres.test.ts +3 -1
  187. package/src/drivers/journal-postgres.ts +4 -2
  188. package/src/drivers/meilisearch.ts +1 -1
  189. package/src/drivers/pglite.ts +28 -5
  190. package/src/drivers/types.ts +9 -11
  191. package/src/drivers/vault-aws-secrets-manager.test.ts +159 -0
  192. package/src/drivers/vault-aws-secrets-manager.ts +333 -0
  193. package/src/drivers/vault-builtin.test.ts +110 -0
  194. package/src/drivers/vault-builtin.ts +184 -0
  195. package/src/drivers/vault-driver-removal.test.ts +13 -0
  196. package/src/drivers/vault-managed.test.ts +95 -0
  197. package/src/drivers/vault-managed.ts +101 -25
  198. package/src/drivers/vault-types.ts +25 -5
  199. package/src/elements/ai/runtime.ts +1 -1
  200. package/src/elements/clock/chaos.test.ts +4 -1
  201. package/src/elements/clock/durable.ts +57 -4
  202. package/src/elements/clock.test.ts +13 -14
  203. package/src/elements/gate/constants.ts +18 -0
  204. package/src/elements/gate.test.ts +1 -1
  205. package/src/elements/gate.ts +2 -2
  206. package/src/elements/store/domain-ddl.test.ts +5 -12
  207. package/src/elements/store/emit-drizzle.ts +44 -19
  208. package/src/elements/store/index-boot.test.ts +15 -116
  209. package/src/elements/store/load-plugin-tables.ts +1 -1
  210. package/src/elements/store/resource-list-docs.fixture.ts +12 -6
  211. package/src/elements/store/resource-list-docs.test.ts +64 -44
  212. package/src/elements/store/resource.test.ts +17 -10
  213. package/src/elements/store/runtime.ts +9 -12
  214. package/src/elements/store/schema-decl.test.ts +16 -32
  215. package/src/elements/store/seed.test.ts +1 -2
  216. package/src/elements/store/seed.ts +7 -8
  217. package/src/elements/store/sql-condition.test.ts +2 -2
  218. package/src/elements/store/sql-session.test.ts +8 -10
  219. package/src/elements/store/sql-session.ts +10 -2
  220. package/src/elements/store.test.ts +13 -13
  221. package/src/elements/vault/audit.ts +233 -0
  222. package/src/elements/vault/boot-chain.test.ts +78 -0
  223. package/src/elements/vault/boot-chain.ts +43 -39
  224. package/src/elements/vault/builtin-adapter.test.ts +479 -0
  225. package/src/elements/vault/builtin-adapter.ts +1184 -0
  226. package/src/elements/vault/crypto.test.ts +237 -0
  227. package/src/elements/vault/crypto.ts +431 -0
  228. package/src/elements/vault/declare.ts +164 -3
  229. package/src/elements/vault/errors.ts +56 -0
  230. package/src/elements/vault/kms-unseal.test.ts +76 -0
  231. package/src/elements/vault/kms-unseal.ts +181 -0
  232. package/src/elements/vault/path.ts +90 -0
  233. package/src/elements/vault/resilience.test.ts +102 -0
  234. package/src/elements/vault/resilience.ts +107 -0
  235. package/src/elements/vault/runtime.ts +36 -4
  236. package/src/elements/vault/security-checklist.test.ts +130 -0
  237. package/src/elements/vault/storage.ts +448 -0
  238. package/src/elements/vault/types.ts +288 -0
  239. package/src/elements/vault/unseal.ts +150 -0
  240. package/src/elements/vault.test.ts +72 -4
  241. package/src/elements/vault.ts +91 -2
  242. package/src/full.ts +248 -0
  243. package/src/http.ts +41 -0
  244. package/src/i18n/interpolate-simple.ts +37 -0
  245. package/src/i18n/messages.ts +51 -4
  246. package/src/i18n-entry.ts +7 -0
  247. package/src/index.ts +35 -145
  248. package/src/journal-entry.ts +20 -0
  249. package/src/kernel/adopt-barrel-fresh.test.ts +25 -10
  250. package/src/kernel/app.ts +40 -42
  251. package/src/kernel/auto-registry.test.ts +2 -2
  252. package/src/kernel/boot-bind/ai.test.ts +5 -5
  253. package/src/kernel/boot-bind/ai.ts +2 -1
  254. package/src/kernel/boot-bind/channel.test.ts +6 -6
  255. package/src/kernel/boot-bind/channel.ts +3 -10
  256. package/src/kernel/boot-bind/clock.ts +2 -2
  257. package/src/kernel/boot-bind/gate.ts +5 -9
  258. package/src/kernel/boot-bind/honor-config.test.ts +42 -42
  259. package/src/kernel/boot-bind/journal.ts +2 -2
  260. package/src/kernel/boot-bind/store.test.ts +43 -44
  261. package/src/kernel/boot-bind/store.ts +16 -41
  262. package/src/kernel/boot-bind/vault.ts +16 -1
  263. package/src/kernel/boot.test.ts +12 -4
  264. package/src/kernel/boot.ts +31 -19
  265. package/src/kernel/budget-entry.ts +1 -1
  266. package/src/kernel/compensate.test.ts +288 -1
  267. package/src/kernel/compensate.ts +126 -0
  268. package/src/kernel/concurrency.test.ts +10 -9
  269. package/src/kernel/effects-stamping.test.ts +27 -2
  270. package/src/kernel/element-registries.ts +5 -3
  271. package/src/kernel/flow.ts +4 -2
  272. package/src/kernel/fx.test.ts +119 -3
  273. package/src/kernel/fx.ts +215 -40
  274. package/src/kernel/index.ts +14 -0
  275. package/src/kernel/journal.ts +130 -7
  276. package/src/kernel/pipeline.test.ts +20 -6
  277. package/src/kernel/redacted.test.ts +35 -0
  278. package/src/kernel/redacted.ts +24 -2
  279. package/src/kernel/router/create-default.ts +16 -0
  280. package/src/kernel/router/create-edge.ts +18 -0
  281. package/src/kernel/router/create.ts +23 -0
  282. package/src/kernel/router/index.ts +23 -0
  283. package/src/kernel/router/linear.ts +88 -0
  284. package/src/kernel/router/regexp.ts +188 -0
  285. package/src/kernel/router/smart.ts +120 -0
  286. package/src/kernel/router/trie.ts +108 -0
  287. package/src/kernel/router/types.ts +56 -0
  288. package/src/kernel/router.ts +18 -532
  289. package/src/kernel-entry.ts +43 -0
  290. package/src/manifest/fixtures/skyport.excerpt.json +1 -1
  291. package/src/manifest/fixtures/skyport.manifest.json +1 -1
  292. package/src/plugins/config-source.test.ts +7 -7
  293. package/src/release/build-lib.ts +58 -0
  294. package/src/release/exports.test.ts +4 -2
  295. package/src/release/exports.ts +30 -4
  296. package/src/release/measure.ts +101 -22
  297. package/src/runs/duckdb.ts +7 -2
  298. package/src/shared/optional-peer.ts +41 -0
  299. package/src/term.test.ts +3 -44
  300. package/src/test/create-test-app.ts +12 -0
  301. package/src/test/provisions.integration.test.ts +1 -1
  302. package/src/test/reset-element-registries.ts +2 -0
  303. package/src/upgrade/codemods.test.ts +7 -20
  304. package/src/upgrade/codemods.ts +93 -60
  305. package/site/content/docs/recipes/openbao.mdx +0 -141
  306. package/src/cli/ask-dev-mode.ts +0 -40
  307. package/src/cli/dev-mode.test.ts +0 -45
  308. package/src/cli/dev-mode.ts +0 -78
  309. package/src/cli/openbao-bootstrap.test.ts +0 -150
  310. package/src/cli/openbao-bootstrap.ts +0 -321
  311. package/src/cli/openbao-restart.integration.test.ts +0 -145
  312. package/src/console/ui/dist/assets/panel-vault-Za1GyJfM.js +0 -1
  313. package/src/console/ui/dist/assets/style-C8MxEWPd.css +0 -3
  314. package/src/docker/recipes/openbao.ts +0 -47
  315. package/src/drivers/libsql.ts +0 -179
  316. package/src/drivers/sqlite.ts +0 -44
  317. package/src/drivers/vault-openbao.test.ts +0 -97
  318. package/src/drivers/vault-openbao.ts +0 -143
@@ -2,17 +2,13 @@
2
2
  * Real, already-established default driver ids per {@link ConfigEnv} —
3
3
  * one source of truth for every driver map that has a single default table.
4
4
  *
5
- * These mirror the literal fallbacks that used to live inline in each
6
- * `src/kernel/boot-bind/*.ts` resolver (`docker ? "postgres" : "memory"`,
7
- * `env === "test" ? "frozen" : "memory"`, …). Kept here so
8
- * {@link mergeEnvDriverMap} has one real map to merge a developer's partial
9
- * override onto, instead of every resolver re-deriving its own default.
5
+ * Philosophy: we test on what we deploy. `dev`/`prod` share production
6
+ * protocols (Postgres, Redis, …); `test` uses PGLite for SQL and memory
7
+ * drivers where the protocol is simple.
10
8
  *
11
9
  * `store.index`, `channel.whatsapp` / `push`, and `ai` are intentionally
12
- * absent — they don't have one established default across all four envs
13
- * (index/whatsapp/push default to nothing until configured; ai has no prod
14
- * default at all and must be declared) and keep using
15
- * {@link resolveDriverId}'s legacy cascade.
10
+ * absent — they don't have one established default across all three envs
11
+ * and keep using {@link resolveDriverId}'s legacy cascade.
16
12
  * @module
17
13
  */
18
14
 
@@ -21,69 +17,64 @@ import {
21
17
  normalizeEnvDriverMap,
22
18
  type DriversConfig,
23
19
  type EnvDriverMap,
24
- type RawEnvDriverMap,
20
+ type EnvDriverInput,
25
21
  } from "./index.ts";
26
22
 
27
- /** `drivers.store.sql` — Postgres for docker/prod, in-memory otherwise. */
23
+ /** `drivers.store.sql` — Postgres for dev/prod, PGLite for test. */
28
24
  export const STORE_SQL_DEFAULTS: EnvDriverMap = {
29
- local: "memory",
30
- docker: "postgres",
31
- test: "memory",
25
+ dev: "postgres",
26
+ test: "pglite",
32
27
  prod: "postgres",
33
28
  };
34
29
 
35
- /** `drivers.store.kv` — Redis for docker/prod, in-memory otherwise. */
30
+ /** `drivers.store.kv` — Redis for dev/prod, in-memory for test. */
36
31
  export const STORE_KV_DEFAULTS: EnvDriverMap = {
37
- local: "memory",
38
- docker: "redis",
32
+ dev: "redis",
39
33
  test: "memory",
40
34
  prod: "redis",
41
35
  };
42
36
 
43
- /** `drivers.store.files` — S3 for docker/prod, in-memory otherwise. */
37
+ /** `drivers.store.files` — S3 for dev/prod, in-memory for test. */
44
38
  export const STORE_FILES_DEFAULTS: EnvDriverMap = {
45
- local: "memory",
46
- docker: "s3",
39
+ dev: "s3",
47
40
  test: "memory",
48
41
  prod: "s3",
49
42
  };
50
43
 
51
- /** `drivers.signal` — in-memory bus everywhere. */
44
+ /** `drivers.signal` — Redis for dev/prod, in-memory for test. */
52
45
  export const SIGNAL_DEFAULTS: EnvDriverMap = {
53
- local: "memory",
54
- docker: "memory",
46
+ dev: "redis",
55
47
  test: "memory",
56
- prod: "memory",
48
+ prod: "redis",
57
49
  };
58
50
 
59
- /** `drivers.clock` — frozen test clock in `test`, in-memory cron elsewhere. */
51
+ /** `drivers.clock` — Postgres cron for dev/prod, frozen clock in test. */
60
52
  export const CLOCK_DEFAULTS: EnvDriverMap = {
61
- local: "memory",
62
- docker: "memory",
53
+ dev: "postgres",
63
54
  test: "frozen",
64
- prod: "memory",
55
+ prod: "postgres",
65
56
  };
66
57
 
67
- /** `drivers.journal` — in-memory durable-run store everywhere. */
58
+ /** `drivers.journal` — Postgres for dev/prod, in-memory for test. */
68
59
  export const JOURNAL_DEFAULTS: EnvDriverMap = {
69
- local: "memory",
70
- docker: "memory",
60
+ dev: "postgres",
71
61
  test: "memory",
72
- prod: "memory",
62
+ prod: "postgres",
73
63
  };
74
64
 
75
- /** `drivers.vault` — OS env vars everywhere except `test` (in-memory). */
65
+ /**
66
+ * `drivers.vault` — OS env vars in dev, in-memory for test, and the built-in
67
+ * encrypted-at-rest store in prod (env layers still resolve first).
68
+ */
76
69
  export const VAULT_DEFAULTS: EnvDriverMap = {
77
- local: "env",
78
- docker: "env",
70
+ dev: "env",
79
71
  test: "memory",
80
- prod: "env",
72
+ prod: "vault",
81
73
  };
82
74
 
83
- /** `drivers.channel.email` — SMTP for docker/prod, console inbox otherwise. */
75
+ /** `drivers.channel.email` — SMTP for dev/prod, console inbox for test. */
84
76
  export const CHANNEL_EMAIL_DEFAULTS: EnvDriverMap = {
85
- local: "console",
86
- docker: "smtp",
77
+ dev: "smtp",
87
78
  test: "console",
88
79
  prod: "smtp",
89
80
  };
@@ -94,27 +85,6 @@ export const CHANNEL_EMAIL_DEFAULTS: EnvDriverMap = {
94
85
  */
95
86
  export const CHANNEL_SMS_DEFAULTS: EnvDriverMap = {};
96
87
 
97
- /**
98
- * Effective default map for a driver whose real default also depends on the
99
- * boot-time `docker` flag (real docker-compose infra available), not just
100
- * the active {@link ConfigEnv} key — `store.sql` / `store.kv` /
101
- * `store.files` / `channel.email` / the Gate KV facet. Real usage always
102
- * pairs `docker: true` with `env: "docker"` / `"prod"`, so the static table
103
- * (`docker`/`prod` → real infra id) applies as-is; with the flag `false`
104
- * (`oke dev -l`, `test`, or a boot that deliberately decouples `env` from
105
- * infra availability) every key falls back to the same safe, no-external-
106
- * deps id the real table already uses for `test`.
107
- *
108
- * @param defaults - Real per-env default table (its `docker`/`prod` slots
109
- * assume real infra is actually up)
110
- * @param docker - Boot-time docker/compose-infra flag
111
- */
112
- export function dockerFlagDefaults(defaults: EnvDriverMap, docker: boolean): EnvDriverMap {
113
- if (docker) return defaults;
114
- const safe = defaults.test;
115
- return { local: safe, docker: safe, test: safe, prod: safe };
116
- }
117
-
118
88
  /** Every driver map with one established default table, grouped by element. */
119
89
  export const DRIVER_DEFAULTS = {
120
90
  store: {
@@ -135,7 +105,7 @@ export const DRIVER_DEFAULTS = {
135
105
  /**
136
106
  * Every driver map from {@link DRIVER_DEFAULTS}, fully resolved — the
137
107
  * developer's `oke.config.ts` override merged onto the real default,
138
- * per-key, for all four {@link ConfigEnv} slots at once. This is the "full
108
+ * per-key, for all three {@link ConfigEnv} slots at once. This is the "full
139
109
  * picture" `oke doctor` prints: what boot actually uses for every env, even
140
110
  * when the config on disk only pins one key.
141
111
  */
@@ -166,8 +136,8 @@ export interface EffectiveDriversConfig {
166
136
  export function resolveEffectiveDrivers(
167
137
  drivers: DriversConfig | undefined,
168
138
  ): EffectiveDriversConfig {
169
- const merge = (map: EnvDriverMap | undefined, defaults: EnvDriverMap) =>
170
- mergeEnvDriverMap(normalizeEnvDriverMap(map as RawEnvDriverMap), defaults);
139
+ const merge = (map: EnvDriverInput | undefined, defaults: EnvDriverMap) =>
140
+ mergeEnvDriverMap(normalizeEnvDriverMap(map), defaults);
171
141
  return {
172
142
  store: {
173
143
  sql: merge(drivers?.store?.sql, STORE_SQL_DEFAULTS),
@@ -2,21 +2,22 @@
2
2
  * `oke.config.ts` surface. Subpath: `okengine/config`.
3
3
  *
4
4
  * Driver maps are protocol-named; vendor/image choice lives in `images`.
5
+ * Three environment targets: `dev` (Docker Compose), `test` (PGLite), `prod`.
5
6
  * @module
6
7
  */
7
8
 
8
9
  /**
9
10
  * Environment role keys used in driver maps.
10
11
  *
11
- * - `local` — laptop defaults (`oke dev` / `oke dev -l`)
12
- * - `docker` — compose infra + host Bun (`oke dev -d`)
13
- * - `test` — automated tests
12
+ * - `dev` — local development via Docker Compose (`oke dev`)
13
+ * - `test` — automated tests (`oke test` / PGLite)
14
14
  * - `prod` — production deploy
15
15
  */
16
- export type ConfigEnv = "local" | "docker" | "test" | "prod";
16
+ import type { VaultElementConfig } from "../elements/vault/types.ts";
17
17
 
18
- /** Legacy driver-map keys accepted during soft-compat migration. */
19
- type LegacyConfigEnv = "dev" | "stack";
18
+ export type { VaultElementConfig };
19
+
20
+ export type ConfigEnv = "dev" | "test" | "prod";
20
21
 
21
22
  /** Pool options for SQL drivers. */
22
23
  export interface DriverPoolOptions {
@@ -38,29 +39,26 @@ export type DriverRef =
38
39
  readonly key?: unknown;
39
40
  };
40
41
 
41
- /** Map of env → driver ref. */
42
+ /** Map of env → driver ref (canonical three-key shape). */
42
43
  export type EnvDriverMap = Partial<Record<ConfigEnv, DriverRef>>;
43
44
 
44
- /**
45
- * Raw map that may still use deprecated `dev` / `stack` keys.
46
- * Normalized by {@link normalizeEnvDriverMap}.
47
- */
48
- export type RawEnvDriverMap = Partial<Record<ConfigEnv | LegacyConfigEnv, DriverRef>>;
45
+ /** Driver pin: bare ref (all envs) or per-env map (`dev` / `test` / `prod`). */
46
+ export type EnvDriverInput = DriverRef | EnvDriverMap;
49
47
 
50
48
  /** Store facet driver maps. */
51
49
  export interface StoreDriversConfig {
52
- readonly sql?: EnvDriverMap;
53
- readonly kv?: EnvDriverMap;
54
- readonly files?: EnvDriverMap;
55
- readonly index?: EnvDriverMap;
50
+ readonly sql?: EnvDriverInput;
51
+ readonly kv?: EnvDriverInput;
52
+ readonly files?: EnvDriverInput;
53
+ readonly index?: EnvDriverInput;
56
54
  }
57
55
 
58
56
  /** Channel medium → env driver map. */
59
57
  export interface ChannelDriversConfig {
60
- readonly email?: EnvDriverMap;
61
- readonly sms?: EnvDriverMap;
62
- readonly whatsapp?: EnvDriverMap;
63
- readonly push?: EnvDriverMap;
58
+ readonly email?: EnvDriverInput;
59
+ readonly sms?: EnvDriverInput;
60
+ readonly whatsapp?: EnvDriverInput;
61
+ readonly push?: EnvDriverInput;
64
62
  }
65
63
 
66
64
  /** Top-level drivers block in {@link OkeConfig}. */
@@ -71,14 +69,14 @@ export interface DriversConfig {
71
69
  */
72
70
  readonly prod?: readonly string[];
73
71
  readonly store?: StoreDriversConfig;
74
- readonly signal?: EnvDriverMap;
75
- readonly clock?: EnvDriverMap;
72
+ readonly signal?: EnvDriverInput;
73
+ readonly clock?: EnvDriverInput;
76
74
  /** Durable-run journal: `memory` · `file` · `postgres`. */
77
- readonly journal?: EnvDriverMap;
78
- readonly vault?: EnvDriverMap;
75
+ readonly journal?: EnvDriverInput;
76
+ readonly vault?: EnvDriverInput;
79
77
  readonly channel?: ChannelDriversConfig;
80
- readonly ai?: EnvDriverMap;
81
- readonly runs?: EnvDriverMap;
78
+ readonly ai?: EnvDriverInput;
79
+ readonly runs?: EnvDriverInput;
82
80
  }
83
81
 
84
82
  /**
@@ -189,9 +187,9 @@ export type PrivacyConfig = Readonly<Record<string, unknown>>;
189
187
  */
190
188
  export interface DbConfig {
191
189
  /**
192
- * Auto-run `oke db push` when domain schema files change under `oke dev`
193
- * (local mode only). Default `true`. Set `false` to opt out explicitly.
194
- * Forced off for `docker` / `prod`.
190
+ * Auto-run `oke db push` when domain schema files change under `oke dev`.
191
+ * Default `true`. Set `false` to opt out explicitly.
192
+ * Forced off for `prod`.
195
193
  */
196
194
  readonly autoPush?: boolean;
197
195
  /**
@@ -207,7 +205,8 @@ export interface DbConfig {
207
205
  readonly declare?: string;
208
206
  /**
209
207
  * Generated Drizzle schema path written from abstract decls.
210
- * Default `"src/db/schema.generated.ts"` (legacy `"src/schema.generated.ts"`).
208
+ * Default `"src/db/schema.drizzle.ts"` (prior `"src/db/schema.generated.ts"`;
209
+ * legacy `"src/schema.generated.ts"`).
211
210
  * Point `drizzle.config.ts` `schema` at this file when using the abstract path.
212
211
  */
213
212
  readonly generated?: string;
@@ -240,6 +239,11 @@ export interface OkeConfig {
240
239
  * Domain Drizzle schema sync (`oke db …`). Not related to `oke schema`.
241
240
  */
242
241
  readonly db?: DbConfig;
242
+ /**
243
+ * Encrypted-at-rest Vault settings (algorithm, master key, audit, seal).
244
+ * Contracts stay in code — this block only configures the backend.
245
+ */
246
+ readonly vault?: VaultElementConfig;
243
247
  readonly topology?: "monolith" | "services";
244
248
  readonly ports?: PortsConfig;
245
249
  readonly console?: ConsoleConfig;
@@ -248,8 +252,8 @@ export interface OkeConfig {
248
252
  /**
249
253
  * Whether domain auto-DDL (`ensureFromMeta`) should run for this env.
250
254
  *
251
- * - `ensure` — `CREATE TABLE IF NOT EXISTS` on first touch (test / local opt-out)
252
- * - `off` — migrations / `oke db push` own DDL (docker, prod, local+autoPush)
255
+ * - `ensure` — `CREATE TABLE IF NOT EXISTS` on first touch (test / dev opt-out)
256
+ * - `off` — migrations / `oke db push` own DDL (dev+autoPush, prod)
253
257
  */
254
258
  export type DomainDdlMode = "ensure" | "off";
255
259
 
@@ -261,95 +265,115 @@ export type DomainDdlMode = "ensure" | "off";
261
265
  */
262
266
  export function resolveDomainDdlMode(env: ConfigEnv, autoPush = true): DomainDdlMode {
263
267
  if (env === "test") return "ensure";
264
- if (env === "docker" || env === "prod") return "off";
268
+ if (env === "prod") return "off";
265
269
  return autoPush ? "off" : "ensure";
266
270
  }
267
271
 
268
- /** Whether a legacy-key deprecation warning was already emitted this process. */
269
- let legacyKeyWarned = false;
272
+ /**
273
+ * Extract the protocol id from a {@link DriverRef}.
274
+ *
275
+ * @param ref - Driver ref
276
+ */
277
+ export function driverRefId(ref: DriverRef | undefined): string | undefined {
278
+ if (ref === undefined) return undefined;
279
+ return typeof ref === "string" ? ref : ref.driver;
280
+ }
270
281
 
271
282
  /**
272
- * Normalize deprecated `dev`/`stack` driver-map keys to `local`/`docker`.
283
+ * True when `value` is a bare driver pin (string or `{ driver, … }`), not an env map.
273
284
  *
274
- * Emits a one-time stderr warning when legacy keys are present.
285
+ * @param value - Unknown driver input
286
+ */
287
+ function isBareDriverRef(value: unknown): value is DriverRef {
288
+ if (typeof value === "string") return true;
289
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
290
+ const obj = value as Record<string, unknown>;
291
+ return typeof obj.driver === "string";
292
+ }
293
+
294
+ /**
295
+ * Expand a bare {@link DriverRef} to all three env keys.
275
296
  *
276
- * @param raw - Env driver map (possibly legacy keys)
297
+ * @param ref - Driver ref applied to every env
277
298
  */
278
- export function normalizeEnvDriverMap(
279
- raw: RawEnvDriverMap | EnvDriverMap | undefined,
280
- ): EnvDriverMap | undefined {
281
- if (!raw) return undefined;
282
- const hasLegacy =
283
- (raw as RawEnvDriverMap).dev !== undefined || (raw as RawEnvDriverMap).stack !== undefined;
284
- if (hasLegacy && !legacyKeyWarned) {
285
- legacyKeyWarned = true;
286
- console.warn(
287
- "oke: driver map keys `dev`/`stack` are deprecated use `local`/`docker` (run `oke upgrade`)",
288
- );
289
- }
290
- const out: EnvDriverMap = { ...(raw as EnvDriverMap) };
291
- const legacy = raw as RawEnvDriverMap;
292
- if (legacy.local === undefined && legacy.dev !== undefined) {
293
- out.local = legacy.dev;
294
- }
295
- if (legacy.docker === undefined && legacy.stack !== undefined) {
296
- out.docker = legacy.stack;
297
- }
298
- delete (out as RawEnvDriverMap).dev;
299
- delete (out as RawEnvDriverMap).stack;
299
+ export function expandDriverRefToMap(ref: DriverRef): EnvDriverMap {
300
+ return { dev: ref, test: ref, prod: ref };
301
+ }
302
+
303
+ /**
304
+ * Expand a bare driver pin to `{ dev, test, prod }`, or pass through a map.
305
+ *
306
+ * @param raw - Env → driver map, bare ref, or undefined
307
+ */
308
+ export function normalizeEnvDriverMap(raw: EnvDriverInput | undefined): EnvDriverMap | undefined {
309
+ if (raw === undefined) return undefined;
310
+ if (isBareDriverRef(raw)) return expandDriverRefToMap(raw);
311
+ const record = raw as EnvDriverMap;
312
+ const out: EnvDriverMap = {};
313
+ if (record.dev !== undefined) out.dev = record.dev;
314
+ if (record.test !== undefined) out.test = record.test;
315
+ if (record.prod !== undefined) out.prod = record.prod;
300
316
  return out;
301
317
  }
302
318
 
303
319
  /**
304
- * Normalize every env map under a drivers block.
320
+ * Apply `fn` to every env-driver slot under a drivers block.
305
321
  *
306
322
  * @param drivers - Drivers block
323
+ * @param fn - Per-slot transform
307
324
  */
308
- export function normalizeDriversConfig(
309
- drivers: DriversConfig | undefined,
310
- ): DriversConfig | undefined {
311
- if (!drivers) return undefined;
325
+ function mapDriversSlots(
326
+ drivers: DriversConfig,
327
+ fn: (input: EnvDriverInput | undefined) => EnvDriverInput | undefined,
328
+ ): DriversConfig {
312
329
  const store = drivers.store
313
330
  ? {
314
331
  ...drivers.store,
315
- sql: normalizeEnvDriverMap(drivers.store.sql as RawEnvDriverMap),
316
- kv: normalizeEnvDriverMap(drivers.store.kv as RawEnvDriverMap),
317
- files: normalizeEnvDriverMap(drivers.store.files as RawEnvDriverMap),
318
- index: normalizeEnvDriverMap(drivers.store.index as RawEnvDriverMap),
332
+ sql: fn(drivers.store.sql),
333
+ kv: fn(drivers.store.kv),
334
+ files: fn(drivers.store.files),
335
+ index: fn(drivers.store.index),
319
336
  }
320
337
  : undefined;
321
338
  const channel = drivers.channel
322
339
  ? {
323
340
  ...drivers.channel,
324
- email: normalizeEnvDriverMap(drivers.channel.email as RawEnvDriverMap),
325
- sms: normalizeEnvDriverMap(drivers.channel.sms as RawEnvDriverMap),
326
- whatsapp: normalizeEnvDriverMap(drivers.channel.whatsapp as RawEnvDriverMap),
327
- push: normalizeEnvDriverMap(drivers.channel.push as RawEnvDriverMap),
341
+ email: fn(drivers.channel.email),
342
+ sms: fn(drivers.channel.sms),
343
+ whatsapp: fn(drivers.channel.whatsapp),
344
+ push: fn(drivers.channel.push),
328
345
  }
329
346
  : undefined;
330
347
  return {
331
348
  ...drivers,
332
349
  ...(store !== undefined ? { store } : {}),
333
- signal: normalizeEnvDriverMap(drivers.signal as RawEnvDriverMap),
334
- clock: normalizeEnvDriverMap(drivers.clock as RawEnvDriverMap),
335
- journal: normalizeEnvDriverMap(drivers.journal as RawEnvDriverMap),
336
- vault: normalizeEnvDriverMap(drivers.vault as RawEnvDriverMap),
350
+ signal: fn(drivers.signal),
351
+ clock: fn(drivers.clock),
352
+ journal: fn(drivers.journal),
353
+ vault: fn(drivers.vault),
337
354
  ...(channel !== undefined ? { channel } : {}),
338
- ai: normalizeEnvDriverMap(drivers.ai as RawEnvDriverMap),
339
- runs: normalizeEnvDriverMap(drivers.runs as RawEnvDriverMap),
355
+ ai: fn(drivers.ai),
356
+ runs: fn(drivers.runs),
340
357
  };
341
358
  }
342
359
 
360
+ /**
361
+ * Normalize every env map under a drivers block (expand shorthand + rewrite keys).
362
+ *
363
+ * @param drivers - Drivers block
364
+ */
365
+ export function normalizeDriversConfig(
366
+ drivers: DriversConfig | undefined,
367
+ ): DriversConfig | undefined {
368
+ if (!drivers) return undefined;
369
+ return mapDriversSlots(drivers, normalizeEnvDriverMap);
370
+ }
371
+
343
372
  /**
344
373
  * Merge a developer's partial {@link EnvDriverMap} onto the real default map
345
374
  * for one specific driver — per environment key, never a whole-object
346
375
  * replace. An unset key keeps that driver's own real default; it never
347
- * inherits a sibling key's value (the old `docker → prod → local → test`
348
- * cascade in {@link resolveDriverId} did that, which is exactly the bug this
349
- * fixes — `{ local: "pglite" }` no longer leaks `pglite` into `docker`).
350
- *
351
- * Scoped strictly to the `{ local?, docker?, test?, prod? }` shape — not a
352
- * generic deep merge, and never applied to a whole config object.
376
+ * inherits a sibling key's value.
353
377
  *
354
378
  * @param override - Developer-supplied partial map (may be `undefined`)
355
379
  * @param defaults - Real, already-established default map for this driver
@@ -359,79 +383,91 @@ export function mergeEnvDriverMap(
359
383
  defaults: EnvDriverMap,
360
384
  ): EnvDriverMap {
361
385
  return {
362
- local: override?.local ?? defaults.local,
363
- docker: override?.docker ?? defaults.docker,
386
+ dev: override?.dev ?? defaults.dev,
364
387
  test: override?.test ?? defaults.test,
365
388
  prod: override?.prod ?? defaults.prod,
366
389
  };
367
390
  }
368
391
 
369
392
  /**
370
- * Fill missing `docker` pins from `prod` (compose infra ≈ production protocols).
393
+ * Fill missing `dev` pins from `prod` (compose laptop ≈ production protocols).
371
394
  *
372
395
  * @param map - Env → driver map
373
396
  */
374
- export function fillDockerFromProd(map: EnvDriverMap | undefined): EnvDriverMap | undefined {
397
+ export function fillDevFromProd(map: EnvDriverMap | undefined): EnvDriverMap | undefined {
375
398
  if (!map) return undefined;
376
- if (map.docker !== undefined || map.prod === undefined) return map;
377
- return { ...map, docker: map.prod };
399
+ if (map.dev !== undefined || map.prod === undefined) return map;
400
+ return { ...map, dev: map.prod };
378
401
  }
379
402
 
380
403
  /**
381
- * Copy production driver pins onto `docker` wherever `docker` is omitted.
404
+ * Copy production driver pins onto `dev` wherever `dev` is omitted.
382
405
  *
383
406
  * @param drivers - Drivers block
384
407
  */
385
- export function fillDriversDockerFromProd(
408
+ export function fillDriversDevFromProd(
386
409
  drivers: DriversConfig | undefined,
387
410
  ): DriversConfig | undefined {
388
411
  if (!drivers) return undefined;
389
- const store = drivers.store
390
- ? {
391
- ...drivers.store,
392
- sql: fillDockerFromProd(drivers.store.sql),
393
- kv: fillDockerFromProd(drivers.store.kv),
394
- files: fillDockerFromProd(drivers.store.files),
395
- index: fillDockerFromProd(drivers.store.index),
396
- }
397
- : undefined;
398
- const channel = drivers.channel
399
- ? {
400
- ...drivers.channel,
401
- email: fillDockerFromProd(drivers.channel.email),
402
- sms: fillDockerFromProd(drivers.channel.sms),
403
- whatsapp: fillDockerFromProd(drivers.channel.whatsapp),
404
- push: fillDockerFromProd(drivers.channel.push),
412
+ return mapDriversSlots(drivers, (input) => fillDevFromProd(input as EnvDriverMap | undefined));
413
+ }
414
+
415
+ /**
416
+ * Walk every driver pin and throw if `sqlite` appears or test SQL is not `pglite`.
417
+ *
418
+ * @param drivers - Normalized drivers block
419
+ */
420
+ export function assertDriverSafety(drivers: DriversConfig | undefined): void {
421
+ if (!drivers) return;
422
+ const maps: readonly (EnvDriverMap | undefined)[] = [
423
+ drivers.store?.sql as EnvDriverMap | undefined,
424
+ drivers.store?.kv as EnvDriverMap | undefined,
425
+ drivers.store?.files as EnvDriverMap | undefined,
426
+ drivers.store?.index as EnvDriverMap | undefined,
427
+ drivers.signal as EnvDriverMap | undefined,
428
+ drivers.clock as EnvDriverMap | undefined,
429
+ drivers.journal as EnvDriverMap | undefined,
430
+ drivers.vault as EnvDriverMap | undefined,
431
+ drivers.channel?.email as EnvDriverMap | undefined,
432
+ drivers.channel?.sms as EnvDriverMap | undefined,
433
+ drivers.channel?.whatsapp as EnvDriverMap | undefined,
434
+ drivers.channel?.push as EnvDriverMap | undefined,
435
+ drivers.ai as EnvDriverMap | undefined,
436
+ drivers.runs as EnvDriverMap | undefined,
437
+ ];
438
+ for (const map of maps) {
439
+ if (!map) continue;
440
+ for (const env of ["dev", "test", "prod"] as const) {
441
+ const id = driverRefId(map[env]);
442
+ if (id === "sqlite" || id === "libsql") {
443
+ throw new Error(
444
+ `oke.config: "${id}" was removed — use postgres (dev/prod) or pglite (test); index → pgvector/memory`,
445
+ );
405
446
  }
406
- : undefined;
407
- return {
408
- ...drivers,
409
- ...(store !== undefined ? { store } : {}),
410
- signal: fillDockerFromProd(drivers.signal),
411
- clock: fillDockerFromProd(drivers.clock),
412
- journal: fillDockerFromProd(drivers.journal),
413
- vault: fillDockerFromProd(drivers.vault),
414
- ...(channel !== undefined ? { channel } : {}),
415
- ai: fillDockerFromProd(drivers.ai),
416
- runs: fillDockerFromProd(drivers.runs),
417
- };
447
+ }
448
+ }
449
+ const sqlTest = driverRefId((drivers.store?.sql as EnvDriverMap | undefined)?.test);
450
+ if (sqlTest !== undefined && sqlTest !== "pglite") {
451
+ throw new Error(`oke.config: drivers.store.sql.test must be "pglite" (got "${sqlTest}")`);
452
+ }
418
453
  }
419
454
 
420
455
  /**
421
456
  * Define an `oke.config.ts` document.
422
457
  *
423
- * Missing `docker` driver pins are filled from `prod` so `oke dev -d` uses the
424
- * same server protocols as production (vault `env` for `docker/.env.docker`).
425
- * Legacy `dev`/`stack` keys are normalized to `local`/`docker`.
458
+ * Bare string pins expand to all three envs. Missing `dev` pins fill from
459
+ * `prod`. Rejects `sqlite` / `libsql` and non-`pglite` test SQL.
426
460
  *
427
461
  * @param config - Driver / tenancy / i18n / topology
428
462
  */
429
463
  export function defineConfig(config: OkeConfig): OkeConfig {
430
464
  if (!config.drivers) return config;
431
465
  const normalized = normalizeDriversConfig(config.drivers);
466
+ const filled = fillDriversDevFromProd(normalized);
467
+ assertDriverSafety(filled);
432
468
  return {
433
469
  ...config,
434
- drivers: fillDriversDockerFromProd(normalized),
470
+ drivers: filled,
435
471
  };
436
472
  }
437
473
 
@@ -441,36 +477,25 @@ export function defineConfig(config: OkeConfig): OkeConfig {
441
477
  * With `defaults` given, the developer's map is merged onto it per-key via
442
478
  * {@link mergeEnvDriverMap} and the active env's slot is read directly — a
443
479
  * key the developer never set keeps that driver's real default, full stop.
444
- * This is the path every driver map with an established default should use.
445
480
  *
446
481
  * Without `defaults` (legacy path — `store.index`, `channel.whatsapp` /
447
- * `push`, `ai`, which have no single established default table): `docker`
448
- * falls back to `prod` then `local` then `test` so existing configs keep
449
- * working until an explicit `docker:` pin is added. Legacy `dev`/`stack`
450
- * keys are normalized first either way.
482
+ * `push`, `ai`): cascade is `env dev prod → test`.
451
483
  *
452
- * @param map - Env → driver map
484
+ * @param map - Env → driver map (or bare ref)
453
485
  * @param env - Active environment
454
486
  * @param defaults - Real default map for this specific driver (per-key merge)
455
487
  */
456
488
  export function resolveDriverId(
457
- map: EnvDriverMap | RawEnvDriverMap | undefined,
489
+ map: EnvDriverInput | undefined,
458
490
  env: ConfigEnv,
459
491
  defaults?: EnvDriverMap,
460
492
  ): string | undefined {
461
- const normalized = normalizeEnvDriverMap(map as RawEnvDriverMap);
493
+ const normalized = normalizeEnvDriverMap(map);
462
494
  if (defaults) {
463
495
  const merged = mergeEnvDriverMap(normalized, defaults);
464
- const ref = merged[env];
465
- if (ref === undefined) return undefined;
466
- return typeof ref === "string" ? ref : ref.driver;
496
+ return driverRefId(merged[env]);
467
497
  }
468
- if (!map) return undefined;
469
- const resolved = normalized ?? map;
470
- const ref =
471
- env === "docker"
472
- ? (resolved.docker ?? resolved.prod ?? resolved.local ?? resolved.test)
473
- : (resolved[env] ?? resolved.local ?? resolved.test);
474
- if (ref === undefined) return undefined;
475
- return typeof ref === "string" ? ref : ref.driver;
498
+ if (!normalized) return undefined;
499
+ const ref = normalized[env] ?? normalized.dev ?? normalized.prod ?? normalized.test;
500
+ return driverRefId(ref);
476
501
  }