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
@@ -37,11 +37,11 @@ describe("boot binders honour drivers.* config", () => {
37
37
  process.env.APP_NAME = "honor-config";
38
38
  try {
39
39
  const result = await bootApplication({
40
- env: "local",
40
+ env: "test",
41
41
  secrets: [vault.config("APP_NAME", { description: "app" })],
42
42
  config: {
43
43
  drivers: {
44
- vault: { local: "env", docker: "openbao", test: "memory", prod: "openbao" },
44
+ vault: { test: "env" },
45
45
  },
46
46
  },
47
47
  });
@@ -58,21 +58,17 @@ describe("boot binders honour drivers.* config", () => {
58
58
  }
59
59
  });
60
60
 
61
- test("vault: drivers.vault openbao with credentials selects openbao layer", () => {
62
- process.env.OKE_VAULT_URL = "http://127.0.0.1:8200";
63
- process.env.OKE_VAULT_TOKEN = "test-token";
61
+ test("vault: drivers.vault vault selects built-in layer behind env", () => {
64
62
  const chain = buildVaultBootChain({
65
- driverId: "openbao",
66
- env: "local",
67
- missingOpenbao: "throw",
63
+ driverId: "vault",
64
+ env: "test",
68
65
  });
69
- expect(chain.map((l) => l.driver.id)).toContain("openbao");
66
+ expect(chain.map((l) => l.driver.id)).toContain("vault");
70
67
  expect(chain.map((l) => l.driver.id)).toContain("env");
71
68
  });
72
69
 
73
- test("vault: openbao without credentials fails loud in prod", async () => {
74
- delete process.env.OKE_VAULT_URL;
75
- delete process.env.OKE_VAULT_TOKEN;
70
+ test("vault: unknown driver id fails loud at boot", async () => {
71
+ const removed = ["open", "bao"].join("");
76
72
  await expect(
77
73
  bootApplication({
78
74
  env: "prod",
@@ -80,21 +76,23 @@ describe("boot binders honour drivers.* config", () => {
80
76
  vault: { allowDevFallbacks: true },
81
77
  config: {
82
78
  drivers: {
83
- vault: { prod: "openbao" },
79
+ vault: { prod: removed },
84
80
  },
85
81
  },
86
82
  }),
87
- ).rejects.toThrow(/openbao.*OKE_VAULT_URL/);
83
+ ).rejects.toThrow(/unknown vault driver/);
88
84
  });
89
85
 
90
86
  test("clock: drivers.clock memory binds memory CronStore", async () => {
87
+ // `test` env always forces frozen — pin under `dev` to honour memory.
91
88
  const result = await bootApplication({
92
- env: "local",
89
+ env: "dev",
93
90
  startScheduler: false,
94
91
  clocks: [clock("tick", { every: "1h" })],
95
92
  config: {
96
93
  drivers: {
97
- clock: { local: "memory", docker: "file", test: "frozen", prod: "file" },
94
+ clock: { dev: "memory" },
95
+ store: { sql: { dev: "memory" }, kv: { dev: "memory" } },
98
96
  },
99
97
  },
100
98
  });
@@ -110,12 +108,13 @@ describe("boot binders honour drivers.* config", () => {
110
108
  tmp = await mkdtemp(join(tmpdir(), "oke-clock-file-"));
111
109
  process.chdir(tmp);
112
110
  const result = await bootApplication({
113
- env: "local",
111
+ env: "dev",
114
112
  startScheduler: false,
115
113
  clocks: [clock("tick", { every: "1h" })],
116
114
  config: {
117
115
  drivers: {
118
- clock: { local: "file", docker: "file", test: "frozen", prod: "file" },
116
+ clock: { dev: "file" },
117
+ store: { sql: { dev: "memory" }, kv: { dev: "memory" } },
119
118
  },
120
119
  },
121
120
  });
@@ -135,12 +134,13 @@ describe("boot binders honour drivers.* config", () => {
135
134
  try {
136
135
  await expect(
137
136
  bootApplication({
138
- env: "local",
137
+ env: "dev",
139
138
  startScheduler: false,
140
139
  clocks: [clock("tick", { every: "1h" })],
141
140
  config: {
142
141
  drivers: {
143
- clock: { local: "postgres" },
142
+ clock: { dev: "postgres" },
143
+ store: { sql: { dev: "memory" }, kv: { dev: "memory" } },
144
144
  },
145
145
  },
146
146
  }),
@@ -155,7 +155,7 @@ describe("boot binders honour drivers.* config", () => {
155
155
 
156
156
  test("journal: durable flow binds memory journal by default", async () => {
157
157
  const result = await bootApplication({
158
- env: "local",
158
+ env: "test",
159
159
  startScheduler: false,
160
160
  flows: [flow("charge", { durable: true, do: () => ({ ok: true }) })],
161
161
  });
@@ -170,7 +170,7 @@ describe("boot binders honour drivers.* config", () => {
170
170
 
171
171
  test("journal: no durable flow → no journal runtime", async () => {
172
172
  const result = await bootApplication({
173
- env: "local",
173
+ env: "test",
174
174
  startScheduler: false,
175
175
  flows: [flow("plain", { do: () => ({ ok: true }) })],
176
176
  });
@@ -185,12 +185,12 @@ describe("boot binders honour drivers.* config", () => {
185
185
  tmp = await mkdtemp(join(tmpdir(), "oke-journal-file-"));
186
186
  process.chdir(tmp);
187
187
  const result = await bootApplication({
188
- env: "local",
188
+ env: "test",
189
189
  startScheduler: false,
190
190
  flows: [flow("charge", { durable: true, do: () => ({ ok: true }) })],
191
191
  config: {
192
192
  drivers: {
193
- journal: { local: "file", docker: "postgres", test: "memory", prod: "postgres" },
193
+ journal: { test: "file" },
194
194
  },
195
195
  },
196
196
  });
@@ -209,12 +209,12 @@ describe("boot binders honour drivers.* config", () => {
209
209
  try {
210
210
  await expect(
211
211
  bootApplication({
212
- env: "local",
212
+ env: "test",
213
213
  startScheduler: false,
214
214
  flows: [flow("charge", { durable: true, do: () => ({ ok: true }) })],
215
215
  config: {
216
216
  drivers: {
217
- journal: { local: "postgres" },
217
+ journal: { test: "postgres" },
218
218
  },
219
219
  },
220
220
  }),
@@ -230,12 +230,12 @@ describe("boot binders honour drivers.* config", () => {
230
230
  test("journal: unknown driver fails loud", async () => {
231
231
  await expect(
232
232
  bootApplication({
233
- env: "local",
233
+ env: "test",
234
234
  startScheduler: false,
235
235
  flows: [flow("charge", { durable: true, do: () => ({ ok: true }) })],
236
236
  config: {
237
237
  drivers: {
238
- journal: { local: "neon" },
238
+ journal: { test: "neon" },
239
239
  },
240
240
  },
241
241
  }),
@@ -245,13 +245,13 @@ describe("boot binders honour drivers.* config", () => {
245
245
  test("gate: drivers.store.kv redis opens redis-backed oke:gates", async () => {
246
246
  const fake = createRedisFakeClient();
247
247
  const result = await bootApplication({
248
- env: "local",
248
+ env: "test",
249
249
  gates: [gate.rate({ max: 10, per: "1m" })],
250
250
  clients: { kv: fake },
251
251
  config: {
252
252
  drivers: {
253
253
  store: {
254
- kv: { local: "redis", docker: "redis", prod: "redis" },
254
+ kv: { test: "redis", dev: "redis", prod: "redis" },
255
255
  },
256
256
  },
257
257
  },
@@ -268,12 +268,12 @@ describe("boot binders honour drivers.* config", () => {
268
268
  delete process.env.OKE_STORE_KV_URL;
269
269
  await expect(
270
270
  bootApplication({
271
- env: "local",
271
+ env: "test",
272
272
  gates: [gate.rate({ max: 10, per: "1m" })],
273
273
  config: {
274
274
  drivers: {
275
275
  store: {
276
- kv: { local: "redis", docker: "redis", prod: "redis" },
276
+ kv: { test: "redis", dev: "redis", prod: "redis" },
277
277
  },
278
278
  },
279
279
  },
@@ -283,12 +283,12 @@ describe("boot binders honour drivers.* config", () => {
283
283
 
284
284
  test("gate: drivers.store.kv memory keeps memory oke:gates", async () => {
285
285
  const result = await bootApplication({
286
- env: "local",
286
+ env: "test",
287
287
  gates: [gate.rate({ max: 10, per: "1m" })],
288
288
  config: {
289
289
  drivers: {
290
290
  store: {
291
- kv: { local: "memory", docker: "redis", prod: "redis" },
291
+ kv: { dev: "redis", test: "memory", prod: "redis" },
292
292
  },
293
293
  },
294
294
  },
@@ -302,11 +302,11 @@ describe("boot binders honour drivers.* config", () => {
302
302
 
303
303
  test("signal: drivers.signal memory binds memory", async () => {
304
304
  const result = await bootApplication({
305
- env: "local",
305
+ env: "test",
306
306
  signals: [signal("ping", { delivery: "once" })],
307
307
  config: {
308
308
  drivers: {
309
- signal: { local: "memory", docker: "redis", prod: "redis" },
309
+ signal: { dev: "redis", test: "memory", prod: "redis" },
310
310
  },
311
311
  },
312
312
  });
@@ -320,12 +320,12 @@ describe("boot binders honour drivers.* config", () => {
320
320
  test("signal: drivers.signal redis binds redis", async () => {
321
321
  const fake = createSignalRedisFake();
322
322
  const result = await bootApplication({
323
- env: "local",
323
+ env: "test",
324
324
  signals: [signal("ping", { delivery: "once" })],
325
325
  clients: { signalRedis: fake },
326
326
  config: {
327
327
  drivers: {
328
- signal: { local: "redis", docker: "redis", prod: "redis" },
328
+ signal: { test: "redis", dev: "redis", prod: "redis" },
329
329
  },
330
330
  },
331
331
  });
@@ -339,11 +339,11 @@ describe("boot binders honour drivers.* config", () => {
339
339
  test("signal: drivers.signal postgres fails loud (never silent memory)", async () => {
340
340
  await expect(
341
341
  bootApplication({
342
- env: "local",
342
+ env: "test",
343
343
  signals: [signal("ping", { delivery: "once" })],
344
344
  config: {
345
345
  drivers: {
346
- signal: { local: "postgres" },
346
+ signal: { test: "postgres" },
347
347
  },
348
348
  },
349
349
  }),
@@ -353,11 +353,11 @@ describe("boot binders honour drivers.* config", () => {
353
353
  test("signal: drivers.signal nats fails loud", async () => {
354
354
  await expect(
355
355
  bootApplication({
356
- env: "local",
356
+ env: "test",
357
357
  signals: [signal("ping", { delivery: "once" })],
358
358
  config: {
359
359
  drivers: {
360
- signal: { local: "nats" },
360
+ signal: { test: "nats" },
361
361
  },
362
362
  },
363
363
  }),
@@ -66,8 +66,8 @@ export async function bindJournal(
66
66
  const url = process.env.DATABASE_URL ?? process.env.OKE_STORE_SQL_URL ?? undefined;
67
67
  if (!url) {
68
68
  throw new Error(
69
- env === "docker"
70
- ? 'oke boot: journal driver "postgres" needs DATABASE_URL (did `oke dev -d` write docker/.env.docker?)'
69
+ env === "dev"
70
+ ? 'oke boot: journal driver "postgres" needs DATABASE_URL (did `oke dev` write docker/.env.docker?)'
71
71
  : 'oke boot: journal driver "postgres" needs DATABASE_URL',
72
72
  );
73
73
  }
@@ -36,66 +36,65 @@ describe("bindStore driver resolution", () => {
36
36
  else process.env.OKE_INDEX_DRIVER = prev.index;
37
37
  });
38
38
 
39
- test("local env keeps sqlite / memory from config", () => {
39
+ test("test env keeps pglite / memory / fs from config", () => {
40
40
  const options = {
41
41
  config: {
42
42
  drivers: {
43
43
  store: {
44
- sql: { local: "sqlite", docker: "postgres", prod: "postgres" },
45
- kv: { local: "memory", docker: "redis", prod: "redis" },
46
- files: { local: "fs", docker: "s3", prod: "s3" },
44
+ sql: { dev: "postgres", test: "pglite", prod: "postgres" },
45
+ kv: { dev: "redis", test: "memory", prod: "redis" },
46
+ files: { dev: "s3", test: "fs", prod: "s3" },
47
47
  },
48
48
  },
49
49
  },
50
50
  };
51
- expect(resolveSqlDriverId(options, "local", false)).toBe("sqlite");
52
- expect(resolveKvDriverId(options, "local", false)).toBe("memory");
53
- expect(resolveFilesDriverId(options, "local", false)).toBe("fs");
51
+ expect(resolveSqlDriverId(options, "test", false)).toBe("pglite");
52
+ expect(resolveKvDriverId(options, "test", false)).toBe("memory");
53
+ expect(resolveFilesDriverId(options, "test", false)).toBe("fs");
54
54
  });
55
55
 
56
- test("docker env uses docker profile (falls back to prod)", () => {
56
+ test("dev env uses compose profile (falls back to prod)", () => {
57
57
  const options = {
58
58
  config: {
59
59
  drivers: {
60
60
  store: {
61
- sql: { local: "sqlite", docker: "postgres", prod: "postgres" },
62
- kv: { local: "memory", prod: "redis" },
63
- files: { local: "fs", prod: "s3" },
61
+ sql: { dev: "postgres", test: "pglite", prod: "postgres" },
62
+ kv: { dev: "redis", test: "memory", prod: "redis" },
63
+ files: { dev: "s3", test: "fs", prod: "s3" },
64
64
  },
65
65
  },
66
66
  },
67
67
  };
68
- expect(resolveSqlDriverId(options, "docker", true)).toBe("postgres");
69
- expect(resolveKvDriverId(options, "docker", true)).toBe("redis");
70
- expect(resolveFilesDriverId(options, "docker", true)).toBe("s3");
68
+ expect(resolveSqlDriverId(options, "dev", true)).toBe("postgres");
69
+ expect(resolveKvDriverId(options, "dev", true)).toBe("redis");
70
+ expect(resolveFilesDriverId(options, "dev", true)).toBe("s3");
71
71
  });
72
72
 
73
73
  test("docker mode honours OKE_*_DRIVER overrides", () => {
74
74
  process.env.OKE_SQL_DRIVER = "postgres";
75
75
  process.env.OKE_KV_DRIVER = "redis";
76
76
  process.env.OKE_FILES_DRIVER = "s3";
77
- expect(resolveSqlDriverId({}, "docker", true)).toBe("postgres");
78
- expect(resolveKvDriverId({}, "docker", true)).toBe("redis");
79
- expect(resolveFilesDriverId({}, "docker", true)).toBe("s3");
77
+ expect(resolveSqlDriverId({}, "dev", true)).toBe("postgres");
78
+ expect(resolveKvDriverId({}, "dev", true)).toBe("redis");
79
+ expect(resolveFilesDriverId({}, "dev", true)).toBe("s3");
80
80
  });
81
81
 
82
- test("pinning only `local` never leaks into docker/test/prod — each keeps its real default", () => {
82
+ test("pinning only `test` never leaks into dev/prod — each keeps its real default", () => {
83
83
  const options = {
84
84
  config: {
85
85
  drivers: {
86
86
  store: {
87
- sql: { local: "pglite" },
87
+ sql: { test: "pglite" },
88
88
  },
89
89
  },
90
90
  },
91
91
  };
92
- expect(resolveSqlDriverId(options, "local", false)).toBe("pglite");
93
- expect(resolveSqlDriverId(options, "docker", true)).toBe("postgres");
94
- expect(resolveSqlDriverId(options, "test", false)).toBe("memory");
92
+ expect(resolveSqlDriverId(options, "test", false)).toBe("pglite");
93
+ expect(resolveSqlDriverId(options, "dev", true)).toBe("postgres");
95
94
  expect(resolveSqlDriverId(options, "prod", true)).toBe("postgres");
96
95
  // kv / files are untouched by the sql-only override.
97
- expect(resolveKvDriverId(options, "local", false)).toBe("memory");
98
- expect(resolveKvDriverId(options, "docker", true)).toBe("redis");
96
+ expect(resolveKvDriverId(options, "test", false)).toBe("memory");
97
+ expect(resolveKvDriverId(options, "dev", true)).toBe("redis");
99
98
  });
100
99
  });
101
100
 
@@ -118,12 +117,12 @@ describe("bindStore files fs multi-instance warn", () => {
118
117
  config: {
119
118
  drivers: {
120
119
  store: {
121
- files: { local: "fs", docker: "s3", prod: "s3" },
120
+ files: { dev: "s3", test: "fs", prod: "s3" },
122
121
  },
123
122
  },
124
123
  },
125
124
  },
126
- "local",
125
+ "test",
127
126
  () => Date.now(),
128
127
  false,
129
128
  );
@@ -133,12 +132,12 @@ describe("bindStore files fs multi-instance warn", () => {
133
132
  config: {
134
133
  drivers: {
135
134
  store: {
136
- files: { local: "fs", docker: "s3", prod: "s3" },
135
+ files: { dev: "s3", test: "fs", prod: "s3" },
137
136
  },
138
137
  },
139
138
  },
140
139
  },
141
- "local",
140
+ "test",
142
141
  () => Date.now(),
143
142
  false,
144
143
  );
@@ -162,12 +161,12 @@ describe("bindStore files fs multi-instance warn", () => {
162
161
  config: {
163
162
  drivers: {
164
163
  store: {
165
- files: { local: "memory", docker: "s3", prod: "s3" },
164
+ files: { dev: "s3", test: "memory", prod: "s3" },
166
165
  },
167
166
  },
168
167
  },
169
168
  },
170
- "local",
169
+ "test",
171
170
  () => Date.now(),
172
171
  false,
173
172
  );
@@ -187,8 +186,8 @@ describe("bindStore index driver resolution", () => {
187
186
  });
188
187
 
189
188
  test("defaults to memory when no index driver is configured", () => {
190
- expect(resolveIndexDriverId({}, "local", false)).toBe("memory");
191
- expect(resolveIndexDriverId({}, "docker", true)).toBe("memory");
189
+ expect(resolveIndexDriverId({}, "test", false)).toBe("memory");
190
+ expect(resolveIndexDriverId({}, "dev", true)).toBe("memory");
192
191
  expect(indexDriverFor("memory").id).toBe("memory");
193
192
  });
194
193
 
@@ -197,37 +196,37 @@ describe("bindStore index driver resolution", () => {
197
196
  config: {
198
197
  drivers: {
199
198
  store: {
200
- index: { local: "memory", docker: "pgvector", prod: "pgvector" },
199
+ index: { dev: "pgvector", test: "memory", prod: "pgvector" },
201
200
  },
202
201
  },
203
202
  },
204
203
  };
205
- expect(resolveIndexDriverId(options, "local", false)).toBe("memory");
206
- expect(resolveIndexDriverId(options, "docker", true)).toBe("pgvector");
204
+ expect(resolveIndexDriverId(options, "test", false)).toBe("memory");
205
+ expect(resolveIndexDriverId(options, "dev", true)).toBe("pgvector");
207
206
  expect(resolveIndexDriverId(options, "prod", false)).toBe("pgvector");
208
207
  });
209
208
 
210
- test("libsql resolves from config", () => {
209
+ test("pgvector resolves from config", () => {
211
210
  const options = {
212
- config: { drivers: { store: { index: { local: "libsql" } } } },
211
+ config: { drivers: { store: { index: { test: "pgvector" } } } },
213
212
  };
214
- expect(resolveIndexDriverId(options, "local", false)).toBe("libsql");
215
- expect(indexDriverFor("libsql").id).toBe("libsql");
213
+ expect(resolveIndexDriverId(options, "test", false)).toBe("pgvector");
214
+ expect(indexDriverFor("pgvector").id).toBe("pgvector");
216
215
  });
217
216
 
218
217
  test("meilisearch resolves from config as a fourth id", () => {
219
218
  const options = {
220
- config: { drivers: { store: { index: { local: "meilisearch", docker: "meilisearch" } } } },
219
+ config: { drivers: { store: { index: { dev: "meilisearch", test: "meilisearch" } } } },
221
220
  };
222
- expect(resolveIndexDriverId(options, "local", false)).toBe("meilisearch");
223
- expect(resolveIndexDriverId(options, "docker", true)).toBe("meilisearch");
221
+ expect(resolveIndexDriverId(options, "test", false)).toBe("meilisearch");
222
+ expect(resolveIndexDriverId(options, "dev", true)).toBe("meilisearch");
224
223
  expect(indexDriverFor("meilisearch").id).toBe("meilisearch");
225
224
  });
226
225
 
227
226
  test("docker mode honours OKE_INDEX_DRIVER override", () => {
228
227
  process.env.OKE_INDEX_DRIVER = "pgvector";
229
- expect(resolveIndexDriverId({}, "docker", true)).toBe("pgvector");
230
- expect(resolveIndexDriverId({}, "local", false)).toBe("memory");
228
+ expect(resolveIndexDriverId({}, "dev", true)).toBe("pgvector");
229
+ expect(resolveIndexDriverId({}, "test", false)).toBe("memory");
231
230
  });
232
231
 
233
232
  test("indexDriverFor returns the configured driver and throws on unknown ids", () => {
@@ -4,13 +4,11 @@
4
4
 
5
5
  import { resolveDomainDdlMode, resolveDriverId, type ConfigEnv } from "../../config/index.ts";
6
6
  import {
7
- dockerFlagDefaults,
8
7
  STORE_FILES_DEFAULTS,
9
8
  STORE_KV_DEFAULTS,
10
9
  STORE_SQL_DEFAULTS,
11
10
  } from "../../config/driver-defaults.ts";
12
11
  import { fsDriver } from "../../drivers/fs.ts";
13
- import { libsqlDriver, libsqlIndexDriver } from "../../drivers/libsql.ts";
14
12
  import { meilisearchDriver } from "../../drivers/meilisearch.ts";
15
13
  import { memoryDrivers } from "../../drivers/memory.ts";
16
14
  import { pgliteDriver } from "../../drivers/pglite.ts";
@@ -18,7 +16,6 @@ import { pgvectorDriver } from "../../drivers/pgvector.ts";
18
16
  import { postgresDriver } from "../../drivers/postgres.ts";
19
17
  import { redisDriver } from "../../drivers/redis.ts";
20
18
  import { s3Driver } from "../../drivers/s3.ts";
21
- import { sqliteDriver } from "../../drivers/sqlite.ts";
22
19
  import type { FilesDriver, IndexDriver, KvDriver, SqlDriver } from "../../drivers/types.ts";
23
20
  import { createStoreRuntime, type StoreRuntime } from "../../elements/store.ts";
24
21
  import type { StoreDecl } from "../../elements/store/declare.ts";
@@ -28,8 +25,8 @@ import type { BootOptions } from "../boot.ts"; // type-only — no cycle at runt
28
25
  /**
29
26
  * Construct a Store runtime and register facet declarations.
30
27
  *
31
- * In docker mode (`env === "docker"` / `OKE_DOCKER=1`), SQL/KV resolve from the
32
- * `docker` driver map (falling back to `prod`) and URLs from `docker/.env.docker`.
28
+ * With compose infra (`OKE_DOCKER=1` / `oke dev`), SQL/KV URLs come from
29
+ * `docker/.env.docker`. `env: "test"` uses PGLite (`memory://` by default).
33
30
  *
34
31
  * @param options - Boot options
35
32
  * @param env - Active environment
@@ -68,7 +65,7 @@ export function bindStore(
68
65
  const filesId = resolveFilesDriverId(options, env, docker);
69
66
  const indexId = resolveIndexDriverId(options, env, docker);
70
67
  if (filesId === "fs") warnFilesFsMultiInstance();
71
- const sqlUrl = sqlUrlFor(sqlId, docker);
68
+ const sqlUrl = sqlUrlFor(sqlId, docker, env);
72
69
  const kvUrl = kvUrlFor(kvId, docker);
73
70
  const filesRoot = filesRootFor(filesId);
74
71
 
@@ -145,11 +142,7 @@ export function resolveSqlDriverId(options: BootOptions, env: ConfigEnv, docker:
145
142
  const fromEnv = process.env.OKE_SQL_DRIVER?.trim();
146
143
  if (docker && fromEnv) return fromEnv;
147
144
  // Defaults cover every ConfigEnv key, so this is never undefined.
148
- return resolveDriverId(
149
- options.config?.drivers?.store?.sql,
150
- env,
151
- dockerFlagDefaults(STORE_SQL_DEFAULTS, docker),
152
- )!;
145
+ return resolveDriverId(options.config?.drivers?.store?.sql, env, STORE_SQL_DEFAULTS)!;
153
146
  }
154
147
 
155
148
  /**
@@ -161,11 +154,7 @@ export function resolveKvDriverId(options: BootOptions, env: ConfigEnv, docker:
161
154
  const fromEnv = process.env.OKE_KV_DRIVER?.trim();
162
155
  if (docker && fromEnv) return fromEnv;
163
156
  // Defaults cover every ConfigEnv key, so this is never undefined.
164
- return resolveDriverId(
165
- options.config?.drivers?.store?.kv,
166
- env,
167
- dockerFlagDefaults(STORE_KV_DEFAULTS, docker),
168
- )!;
157
+ return resolveDriverId(options.config?.drivers?.store?.kv, env, STORE_KV_DEFAULTS)!;
169
158
  }
170
159
 
171
160
  /**
@@ -181,17 +170,13 @@ export function resolveFilesDriverId(
181
170
  const fromEnv = process.env.OKE_FILES_DRIVER?.trim();
182
171
  if (docker && fromEnv) return fromEnv;
183
172
  // Defaults cover every ConfigEnv key, so this is never undefined.
184
- return resolveDriverId(
185
- options.config?.drivers?.store?.files,
186
- env,
187
- dockerFlagDefaults(STORE_FILES_DEFAULTS, docker),
188
- )!;
173
+ return resolveDriverId(options.config?.drivers?.store?.files, env, STORE_FILES_DEFAULTS)!;
189
174
  }
190
175
 
191
176
  /**
192
177
  * Index driver — same resolution chain as sql/kv/files. Defaults to `memory`;
193
- * a configured `pgvector` / `libsql` is honoured at real boot (and fails loud
194
- * if its SQL engine or peer is missing — never silently back to memory).
178
+ * a configured `pgvector` is honoured at real boot (and fails loud if its
179
+ * SQL engine or peer is missing — never silently back to memory).
195
180
  *
196
181
  * @param options - Boot options
197
182
  * @param env - Active env
@@ -213,10 +198,6 @@ function sqlDriverFor(id: string): SqlDriver {
213
198
  switch (id) {
214
199
  case "postgres":
215
200
  return postgresDriver;
216
- case "sqlite":
217
- return sqliteDriver;
218
- case "libsql":
219
- return libsqlDriver;
220
201
  case "pglite":
221
202
  return pgliteDriver;
222
203
  case "memory":
@@ -260,8 +241,6 @@ export function indexDriverFor(id: string): IndexDriver {
260
241
  return memoryDrivers.index;
261
242
  case "pgvector":
262
243
  return pgvectorDriver;
263
- case "libsql":
264
- return libsqlIndexDriver;
265
244
  case "meilisearch":
266
245
  return meilisearchDriver;
267
246
  default:
@@ -269,28 +248,24 @@ export function indexDriverFor(id: string): IndexDriver {
269
248
  }
270
249
  }
271
250
 
272
- function sqlUrlFor(sqlId: string, docker: boolean): string {
251
+ function sqlUrlFor(sqlId: string, docker: boolean, env: ConfigEnv): string {
273
252
  if (sqlId === "postgres") {
274
253
  const url = process.env.DATABASE_URL ?? process.env.OKE_STORE_SQL_URL ?? undefined;
275
254
  if (!url) {
276
255
  throw new Error(
277
256
  docker
278
- ? "oke boot: postgres driver needs DATABASE_URL (did `oke dev -d` write docker/.env.docker?)"
257
+ ? "oke boot: postgres driver needs DATABASE_URL (did `oke dev` write docker/.env.docker?)"
279
258
  : "oke boot: postgres driver needs DATABASE_URL",
280
259
  );
281
260
  }
282
261
  return url;
283
262
  }
284
- if (sqlId === "sqlite") {
285
- return process.env.OKE_SQLITE_URL ?? ".oke/app.sqlite";
286
- }
287
- if (sqlId === "libsql") {
288
- return process.env.OKE_LIBSQL_URL ?? ".oke/app.libsql";
289
- }
290
263
  if (sqlId === "pglite") {
291
- return process.env.OKE_PGLITE_URL ?? ".oke/pgdata";
264
+ return process.env.OKE_PGLITE_URL ?? (env === "test" ? "memory://" : ".oke/pgdata");
292
265
  }
293
- return ":memory:";
266
+ // In-process `memory` SQL driver ignores URL; keep a non-path token so a
267
+ // mis-wired pglite connect never creates a literal `./:memory:` datadir.
268
+ return "memory://";
294
269
  }
295
270
 
296
271
  function kvUrlFor(kvId: string, docker: boolean): string | undefined {
@@ -299,7 +274,7 @@ function kvUrlFor(kvId: string, docker: boolean): string | undefined {
299
274
  if (!url) {
300
275
  throw new Error(
301
276
  docker
302
- ? "oke boot: redis driver needs REDIS_URL (did `oke dev -d` write docker/.env.docker?)"
277
+ ? "oke boot: redis driver needs REDIS_URL (did `oke dev` write docker/.env.docker?)"
303
278
  : "oke boot: redis driver needs REDIS_URL",
304
279
  );
305
280
  }
@@ -317,7 +292,7 @@ function indexUrlFor(docker: boolean): string {
317
292
  if (!url) {
318
293
  throw new Error(
319
294
  docker
320
- ? "oke boot: meilisearch index needs OKE_STORE_INDEX_URL (did `oke dev -d` write docker/.env.docker?)"
295
+ ? "oke boot: meilisearch index needs OKE_STORE_INDEX_URL (did `oke dev` write docker/.env.docker?)"
321
296
  : "oke boot: meilisearch index needs OKE_STORE_INDEX_URL",
322
297
  );
323
298
  }
@@ -4,7 +4,13 @@
4
4
 
5
5
  import { resolveDriverId, type ConfigEnv } from "../../config/index.ts";
6
6
  import { VAULT_DEFAULTS } from "../../config/driver-defaults.ts";
7
- import { createVaultRuntime, type VaultRuntime } from "../../elements/vault.ts";
7
+ import {
8
+ createVaultRuntime,
9
+ listRequiredEnvNames,
10
+ requiredEnvGaps,
11
+ VaultBootError,
12
+ type VaultRuntime,
13
+ } from "../../elements/vault.ts";
8
14
  import { buildVaultBootChain, normalizeVaultDriverId } from "../../elements/vault/boot-chain.ts";
9
15
  import type { BootOptions } from "../boot.ts";
10
16
 
@@ -30,6 +36,14 @@ export function resolveVaultDriverId(options: BootOptions, env: ConfigEnv): stri
30
36
  */
31
37
  export async function bindVault(options: BootOptions, env: ConfigEnv): Promise<VaultRuntime> {
32
38
  const vaultSecrets = options.vault?.secrets ?? options.secrets ?? [];
39
+ const requiredEnv = options.vault?.requiredEnv ?? listRequiredEnvNames();
40
+ // Fail before the chain is built: the builtin `vault` driver opens SQL at
41
+ // `open()`, and a boot that is already doomed by a missing env var should
42
+ // never pay for (or leak) a database connection first.
43
+ const envGaps = requiredEnvGaps(requiredEnv, new Set(vaultSecrets.map((s) => s.name)));
44
+ if (envGaps.length > 0) {
45
+ throw new VaultBootError(envGaps);
46
+ }
33
47
  const chain =
34
48
  options.vault?.chain ??
35
49
  buildVaultBootChain({
@@ -40,6 +54,7 @@ export async function bindVault(options: BootOptions, env: ConfigEnv): Promise<V
40
54
  });
41
55
  const vault = createVaultRuntime({
42
56
  secrets: vaultSecrets,
57
+ requiredEnv,
43
58
  chain,
44
59
  allowDevFallbacks: options.vault?.allowDevFallbacks ?? env !== "prod",
45
60
  now: options.vault?.now,