okengine 0.10.3 → 0.11.1

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 (323) 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/config.ts +13 -3
  204. package/src/elements/gate/constants.ts +18 -0
  205. package/src/elements/gate/declare.ts +1 -1
  206. package/src/elements/gate/strategies.ts +2 -12
  207. package/src/elements/gate.test.ts +1 -1
  208. package/src/elements/gate.ts +2 -2
  209. package/src/elements/store/domain-ddl.test.ts +5 -12
  210. package/src/elements/store/emit-drizzle.ts +44 -19
  211. package/src/elements/store/index-boot.test.ts +15 -116
  212. package/src/elements/store/load-plugin-tables.ts +1 -1
  213. package/src/elements/store/resource-list-docs.fixture.ts +12 -6
  214. package/src/elements/store/resource-list-docs.test.ts +64 -44
  215. package/src/elements/store/resource.test.ts +17 -10
  216. package/src/elements/store/runtime.ts +9 -12
  217. package/src/elements/store/schema-decl.test.ts +16 -32
  218. package/src/elements/store/seed.test.ts +1 -2
  219. package/src/elements/store/seed.ts +7 -8
  220. package/src/elements/store/sql-condition.test.ts +2 -2
  221. package/src/elements/store/sql-session.test.ts +8 -10
  222. package/src/elements/store/sql-session.ts +10 -2
  223. package/src/elements/store.test.ts +13 -13
  224. package/src/elements/vault/audit.ts +233 -0
  225. package/src/elements/vault/boot-chain.test.ts +78 -0
  226. package/src/elements/vault/boot-chain.ts +43 -39
  227. package/src/elements/vault/builtin-adapter.test.ts +479 -0
  228. package/src/elements/vault/builtin-adapter.ts +1184 -0
  229. package/src/elements/vault/crypto.test.ts +237 -0
  230. package/src/elements/vault/crypto.ts +431 -0
  231. package/src/elements/vault/declare.ts +164 -3
  232. package/src/elements/vault/errors.ts +56 -0
  233. package/src/elements/vault/kms-unseal.test.ts +76 -0
  234. package/src/elements/vault/kms-unseal.ts +181 -0
  235. package/src/elements/vault/path.ts +90 -0
  236. package/src/elements/vault/resilience.test.ts +102 -0
  237. package/src/elements/vault/resilience.ts +107 -0
  238. package/src/elements/vault/runtime.ts +36 -4
  239. package/src/elements/vault/security-checklist.test.ts +130 -0
  240. package/src/elements/vault/storage.ts +448 -0
  241. package/src/elements/vault/types.ts +288 -0
  242. package/src/elements/vault/unseal.ts +150 -0
  243. package/src/elements/vault.test.ts +72 -4
  244. package/src/elements/vault.ts +91 -2
  245. package/src/full.ts +248 -0
  246. package/src/http.ts +41 -0
  247. package/src/i18n/interpolate-simple.ts +37 -0
  248. package/src/i18n/messages.ts +51 -4
  249. package/src/i18n-entry.ts +7 -0
  250. package/src/index.ts +35 -145
  251. package/src/journal-entry.ts +20 -0
  252. package/src/kernel/adopt-barrel-fresh.test.ts +25 -10
  253. package/src/kernel/app-auth.ts +98 -0
  254. package/src/kernel/app.ts +77 -110
  255. package/src/kernel/auto-registry.test.ts +2 -2
  256. package/src/kernel/boot-bind/ai.test.ts +5 -5
  257. package/src/kernel/boot-bind/ai.ts +2 -1
  258. package/src/kernel/boot-bind/channel.test.ts +6 -6
  259. package/src/kernel/boot-bind/channel.ts +3 -10
  260. package/src/kernel/boot-bind/clock.ts +2 -2
  261. package/src/kernel/boot-bind/gate.ts +5 -9
  262. package/src/kernel/boot-bind/honor-config.test.ts +42 -42
  263. package/src/kernel/boot-bind/journal.ts +2 -2
  264. package/src/kernel/boot-bind/store.test.ts +43 -44
  265. package/src/kernel/boot-bind/store.ts +16 -41
  266. package/src/kernel/boot-bind/vault.ts +16 -1
  267. package/src/kernel/boot.test.ts +13 -19
  268. package/src/kernel/boot.ts +31 -19
  269. package/src/kernel/budget-entry.ts +1 -1
  270. package/src/kernel/compensate.test.ts +288 -1
  271. package/src/kernel/compensate.ts +126 -0
  272. package/src/kernel/concurrency.test.ts +10 -9
  273. package/src/kernel/effects-stamping.test.ts +27 -2
  274. package/src/kernel/element-registries.ts +5 -3
  275. package/src/kernel/flow.ts +4 -2
  276. package/src/kernel/fx.test.ts +119 -3
  277. package/src/kernel/fx.ts +215 -40
  278. package/src/kernel/index.ts +14 -0
  279. package/src/kernel/journal.ts +130 -7
  280. package/src/kernel/pipeline.test.ts +20 -6
  281. package/src/kernel/redacted.test.ts +35 -0
  282. package/src/kernel/redacted.ts +24 -2
  283. package/src/kernel/router/create-default.ts +16 -0
  284. package/src/kernel/router/create-edge.ts +18 -0
  285. package/src/kernel/router/create.ts +23 -0
  286. package/src/kernel/router/index.ts +23 -0
  287. package/src/kernel/router/linear.ts +88 -0
  288. package/src/kernel/router/regexp.ts +188 -0
  289. package/src/kernel/router/smart.ts +120 -0
  290. package/src/kernel/router/trie.ts +108 -0
  291. package/src/kernel/router/types.ts +56 -0
  292. package/src/kernel/router.ts +18 -532
  293. package/src/kernel-entry.ts +43 -0
  294. package/src/manifest/fixtures/skyport.excerpt.json +1 -1
  295. package/src/manifest/fixtures/skyport.manifest.json +1 -1
  296. package/src/plugins/config-source.test.ts +7 -7
  297. package/src/release/build-lib.ts +61 -0
  298. package/src/release/exports.test.ts +4 -2
  299. package/src/release/exports.ts +30 -4
  300. package/src/release/measure.ts +101 -22
  301. package/src/runs/duckdb.ts +7 -2
  302. package/src/shared/lazy-src.ts +79 -0
  303. package/src/shared/optional-peer.ts +41 -0
  304. package/src/term.test.ts +3 -44
  305. package/src/test/create-test-app.ts +12 -0
  306. package/src/test/provisions.integration.test.ts +1 -1
  307. package/src/test/reset-element-registries.ts +2 -0
  308. package/src/upgrade/codemods.test.ts +7 -20
  309. package/src/upgrade/codemods.ts +93 -60
  310. package/site/content/docs/recipes/openbao.mdx +0 -141
  311. package/src/cli/ask-dev-mode.ts +0 -40
  312. package/src/cli/dev-mode.test.ts +0 -45
  313. package/src/cli/dev-mode.ts +0 -78
  314. package/src/cli/openbao-bootstrap.test.ts +0 -150
  315. package/src/cli/openbao-bootstrap.ts +0 -321
  316. package/src/cli/openbao-restart.integration.test.ts +0 -145
  317. package/src/console/ui/dist/assets/panel-vault-Za1GyJfM.js +0 -1
  318. package/src/console/ui/dist/assets/style-C8MxEWPd.css +0 -3
  319. package/src/docker/recipes/openbao.ts +0 -47
  320. package/src/drivers/libsql.ts +0 -179
  321. package/src/drivers/sqlite.ts +0 -44
  322. package/src/drivers/vault-openbao.test.ts +0 -97
  323. package/src/drivers/vault-openbao.ts +0 -143
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Unit tests for hidden / stdin master-key helpers.
3
+ */
4
+
5
+ import { describe, expect, test } from "bun:test";
6
+ import { EventEmitter } from "node:events";
7
+ import { promptHidden, readStdinSecure } from "./vault-secure-input.ts";
8
+
9
+ describe("readStdinSecure", () => {
10
+ test("trims a full stdin payload", async () => {
11
+ const stdin = new EventEmitter() as EventEmitter & {
12
+ setEncoding?: (encoding: BufferEncoding) => void;
13
+ };
14
+ stdin.setEncoding = () => undefined;
15
+ const pending = readStdinSecure(stdin);
16
+ stdin.emit("data", " abc123\n");
17
+ stdin.emit("end");
18
+ expect(await pending).toBe("abc123");
19
+ });
20
+ });
21
+
22
+ describe("promptHidden", () => {
23
+ test("masks characters and resolves on Enter", async () => {
24
+ const stdin = new EventEmitter() as EventEmitter & {
25
+ setRawMode?: (mode: boolean) => void;
26
+ off?: (event: string, listener: (...args: unknown[]) => void) => void;
27
+ };
28
+ let raw = false;
29
+ stdin.setRawMode = (mode) => {
30
+ raw = mode;
31
+ };
32
+ stdin.off = (event: string | symbol, listener: (...args: unknown[]) => void) => {
33
+ stdin.removeListener(event, listener);
34
+ return stdin;
35
+ };
36
+ let written = "";
37
+ const pending = promptHidden("key: ", {
38
+ stdin,
39
+ write: (t) => {
40
+ written += t;
41
+ },
42
+ exit: () => {
43
+ throw new Error("exit should not run");
44
+ },
45
+ });
46
+ // Allow the listener to attach.
47
+ await Promise.resolve();
48
+ stdin.emit("data", "ab");
49
+ stdin.emit("data", "\r");
50
+ expect(await pending).toBe("ab");
51
+ expect(written).toContain("key: ");
52
+ expect(written).toContain("**");
53
+ expect(written).not.toContain("ab");
54
+ expect(raw).toBe(false);
55
+ });
56
+ });
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Secure master-key input for `oke vault` — avoid shell history.
3
+ *
4
+ * Prefer `--key -` (stdin) or an interactive hidden prompt over putting
5
+ * base64 keys on the argv in shared environments.
6
+ */
7
+
8
+ /** Minimal readable stream used by {@link readStdinSecure}. */
9
+ export interface SecureStdin {
10
+ setEncoding?(encoding: BufferEncoding): void;
11
+ on(event: "data", listener: (chunk: string | Buffer) => void): unknown;
12
+ on(event: "end", listener: () => void): unknown;
13
+ on(event: "error", listener: (error: Error) => void): unknown;
14
+ }
15
+
16
+ /** Minimal TTY-ish stdin used by {@link promptHidden}. */
17
+ export interface SecurePromptStdin {
18
+ setRawMode?(mode: boolean): void;
19
+ on(event: "data", listener: (chunk: string | Buffer) => void): unknown;
20
+ removeListener?(event: "data", listener: (chunk: string | Buffer) => void): unknown;
21
+ off?(event: "data", listener: (chunk: string | Buffer) => void): unknown;
22
+ }
23
+
24
+ /** IO sinks for {@link promptHidden}. */
25
+ export interface PromptHiddenOptions {
26
+ /** Prompt destination. Defaults to `process.stdout.write`. */
27
+ readonly write?: (text: string) => void;
28
+ /** Character stream (TTY). Defaults to `process.stdin`. */
29
+ readonly stdin?: SecurePromptStdin;
30
+ /** Exit handler for Ctrl+C. Defaults to `process.exit`. */
31
+ readonly exit?: (code: number) => void;
32
+ }
33
+
34
+ /**
35
+ * Read a trimmed secret from stdin (for `--key -` / `--new-key -`).
36
+ *
37
+ * @param stdin - Readable stream; defaults to `process.stdin`
38
+ */
39
+ export async function readStdinSecure(stdin: SecureStdin = process.stdin): Promise<string> {
40
+ stdin.setEncoding?.("utf8");
41
+ return new Promise((resolve, reject) => {
42
+ let data = "";
43
+ stdin.on("data", (chunk) => {
44
+ data += typeof chunk === "string" ? chunk : chunk.toString("utf8");
45
+ });
46
+ stdin.on("end", () => resolve(data.trim()));
47
+ stdin.on("error", reject);
48
+ });
49
+ }
50
+
51
+ /**
52
+ * Prompt for a secret on a TTY without echoing the cleartext.
53
+ *
54
+ * Characters are masked with `*`. Backspace edits; Enter submits; Ctrl+C
55
+ * exits the process (or the injected `exit` handler).
56
+ *
57
+ * @param question - Prompt text written before input
58
+ * @param options - Injectable IO for tests
59
+ */
60
+ export async function promptHidden(
61
+ question: string,
62
+ options: PromptHiddenOptions = {},
63
+ ): Promise<string> {
64
+ const write = options.write ?? ((t: string) => process.stdout.write(t));
65
+ const stdin = options.stdin ?? process.stdin;
66
+ const exit = options.exit ?? ((code: number) => process.exit(code));
67
+
68
+ write(question);
69
+ stdin.setRawMode?.(true);
70
+
71
+ return new Promise((resolve) => {
72
+ let input = "";
73
+ const onData = (char: string | Buffer): void => {
74
+ const text = typeof char === "string" ? char : char.toString("utf8");
75
+ for (const ch of text) {
76
+ if (ch === "\n" || ch === "\r" || ch === "\u0004") {
77
+ stdin.setRawMode?.(false);
78
+ write("\n");
79
+ removeDataListener(stdin, onData);
80
+ resolve(input);
81
+ return;
82
+ }
83
+ if (ch === "\u0003") {
84
+ stdin.setRawMode?.(false);
85
+ write("\n");
86
+ removeDataListener(stdin, onData);
87
+ exit(1);
88
+ return;
89
+ }
90
+ if (ch === "\u007f" || ch === "\b") {
91
+ if (input.length > 0) {
92
+ input = input.slice(0, -1);
93
+ write("\b \b");
94
+ }
95
+ continue;
96
+ }
97
+ // Ignore other control characters.
98
+ if (ch < " ") continue;
99
+ input += ch;
100
+ write("*");
101
+ }
102
+ };
103
+ stdin.on("data", onData);
104
+ });
105
+ }
106
+
107
+ /**
108
+ * Detach the raw-mode data listener when the host supports it.
109
+ *
110
+ * @param stdin - Prompt stdin
111
+ * @param listener - Handler to remove
112
+ */
113
+ function removeDataListener(
114
+ stdin: SecurePromptStdin,
115
+ listener: (chunk: string | Buffer) => void,
116
+ ): void {
117
+ if (typeof stdin.off === "function") {
118
+ stdin.off("data", listener);
119
+ return;
120
+ }
121
+ if (typeof stdin.removeListener === "function") {
122
+ stdin.removeListener("data", listener);
123
+ }
124
+ }
@@ -120,6 +120,9 @@ const WRITE_METHODS = new Set([
120
120
  "putImage",
121
121
  ]);
122
122
 
123
+ /** `fx.vault.*` methods whose first argument is a secret path. */
124
+ const VAULT_PATH_METHODS = new Set(["get", "set", "rotate", "delete"]);
125
+
123
126
  /** Methods whose first argument is a table / collection identifier. */
124
127
  const TABLE_ARG_METHODS = new Set([
125
128
  "insert",
@@ -189,6 +192,10 @@ export function inferEffects(options: InferEffectsOptions): InferredEffects {
189
192
  }
190
193
 
191
194
  if (chain.rootMethod === "vault" && call === chain.rootCall) {
195
+ // `fx.vault.list()` / `fx.vault.status()` take no path — nothing to
196
+ // declare. Every other method's first argument is the secret.
197
+ const method = chain.methods[1] ?? "get";
198
+ if (!VAULT_PATH_METHODS.has(method)) continue;
192
199
  const ref = resolveNamed(call.arguments[0], options.bindings, "secret");
193
200
  if (ref) secrets.add(ref);
194
201
  continue;
@@ -2,15 +2,15 @@ import { defineConfig } from "okengine/config";
2
2
 
3
3
  export default defineConfig({
4
4
  drivers: {
5
- prod: ["postgres", "redis", "s3", "smtp", "openbao", "anthropic", "pgvector"],
5
+ prod: ["postgres", "redis", "s3", "smtp", "vault", "anthropic", "pgvector"],
6
6
  store: {
7
- sql: { local: "sqlite", prod: { driver: "postgres" } },
7
+ sql: { dev: { driver: "postgres" }, test: "pglite", prod: { driver: "postgres" } },
8
8
  kv: { prod: "redis" },
9
9
  files: { prod: "s3" },
10
10
  index: { prod: "pgvector" },
11
11
  },
12
12
  signal: { prod: "redis" },
13
- vault: { prod: "openbao" },
13
+ vault: { prod: "vault" },
14
14
  channel: { email: { prod: "smtp" } },
15
15
  ai: { prod: { driver: "anthropic" } },
16
16
  },
@@ -7,7 +7,7 @@ export const chargeBooking = flow("payments.chargeBooking", {
7
7
  // Journal only serializable step values — a Redacted is not journaled.
8
8
  const intent = await fx.step("create-intent", async () => ({
9
9
  id: `pi_${orderId}`,
10
- key: fx.vault(stripeKey).reveal(),
10
+ key: (await fx.vault.get(stripeKey)).reveal(),
11
11
  }));
12
12
  await fx.clock.sleep("verify-window", "2m");
13
13
  return fx.step("confirm", () => intent);
@@ -162,7 +162,7 @@
162
162
  }
163
163
  },
164
164
  "drivers": {
165
- "prod": ["postgres", "redis", "s3", "smtp", "openbao", "anthropic", "pgvector"]
165
+ "prod": ["postgres", "redis", "s3", "smtp", "vault", "anthropic", "pgvector"]
166
166
  },
167
167
  "tenancy": {
168
168
  "isolation": "row"
@@ -0,0 +1,7 @@
1
+ /**
2
+ * `okengine/compiler` — AoT / dynamic route compile + Manifest extract.
3
+ *
4
+ * @module
5
+ */
6
+
7
+ export * from "./compiler/index.ts";
@@ -1,82 +1,146 @@
1
1
  /**
2
- * `defineConfig` fills missing `docker` pins from `prod` and normalizes legacy keys.
2
+ * `defineConfig` fills missing `dev` pins from `prod` and normalizes legacy keys.
3
3
  */
4
4
 
5
5
  import { describe, expect, test } from "bun:test";
6
- import { defineConfig, fillDockerFromProd, normalizeEnvDriverMap } from "./index.ts";
6
+ import { defineConfig, fillDevFromProd, normalizeEnvDriverMap } from "./index.ts";
7
7
 
8
- describe("fillDockerFromProd / defineConfig", () => {
9
- test("copies prod onto docker when docker is omitted", () => {
10
- const filled = fillDockerFromProd({
11
- local: "sqlite",
8
+ describe("fillDevFromProd / defineConfig", () => {
9
+ test("copies prod onto dev when dev is omitted", () => {
10
+ const filled = fillDevFromProd({
11
+ test: "pglite",
12
12
  prod: "postgres",
13
13
  });
14
- expect(filled?.docker).toBe("postgres");
15
- expect(filled?.local).toBe("sqlite");
14
+ expect(filled?.dev).toBe("postgres");
15
+ expect(filled?.test).toBe("pglite");
16
16
  });
17
17
 
18
- test("does not overwrite an explicit docker pin", () => {
18
+ test("does not overwrite an explicit dev pin", () => {
19
19
  expect(
20
- fillDockerFromProd({
21
- local: "sqlite",
22
- docker: "memory",
20
+ fillDevFromProd({
21
+ dev: "memory",
23
22
  prod: "postgres",
24
- })?.docker,
23
+ })?.dev,
25
24
  ).toBe("memory");
26
25
  });
27
26
 
28
- test("vault prod → docker copies the prod driver", () => {
29
- expect(fillDockerFromProd({ local: "env", prod: "openbao" })?.docker).toBe("openbao");
27
+ test("vault prod → dev copies the prod driver", () => {
28
+ expect(fillDevFromProd({ prod: "vault" })?.dev).toBe("vault");
30
29
  });
31
30
 
32
31
  test("defineConfig fills every element from prod", () => {
33
32
  const cfg = defineConfig({
34
33
  drivers: {
35
34
  store: {
36
- sql: { local: "sqlite", prod: "postgres" },
37
- kv: { local: "memory", prod: "redis" },
38
- files: { local: "fs", prod: "s3" },
35
+ sql: { test: "pglite", prod: "postgres" },
36
+ kv: { test: "memory", prod: "redis" },
37
+ files: { test: "memory", prod: "s3" },
39
38
  },
40
- signal: { local: "memory", prod: "redis" },
41
- clock: { local: "memory", prod: "file" },
42
- vault: { local: "env", prod: "openbao" },
39
+ signal: { test: "memory", prod: "redis" },
40
+ clock: { test: "frozen", prod: "file" },
41
+ vault: { test: "memory", prod: "vault" },
43
42
  channel: {
44
- email: { local: "console", prod: "smtp" },
43
+ email: { test: "console", prod: "smtp" },
45
44
  },
46
- ai: { local: "mock", prod: "anthropic" },
45
+ ai: { test: "mock", prod: "anthropic" },
47
46
  },
48
47
  });
49
- expect(cfg.drivers?.store?.sql?.docker).toBe("postgres");
50
- expect(cfg.drivers?.store?.kv?.docker).toBe("redis");
51
- expect(cfg.drivers?.store?.files?.docker).toBe("s3");
52
- expect(cfg.drivers?.signal?.docker).toBe("redis");
53
- expect(cfg.drivers?.clock?.docker).toBe("file");
54
- expect(cfg.drivers?.vault?.docker).toBe("openbao");
55
- expect(cfg.drivers?.channel?.email?.docker).toBe("smtp");
56
- expect(cfg.drivers?.ai?.docker).toBe("anthropic");
48
+ expect(cfg.drivers?.store?.sql).toMatchObject({
49
+ dev: "postgres",
50
+ test: "pglite",
51
+ prod: "postgres",
52
+ });
53
+ expect(cfg.drivers?.store?.kv).toMatchObject({
54
+ dev: "redis",
55
+ test: "memory",
56
+ prod: "redis",
57
+ });
58
+ expect(cfg.drivers?.store?.files).toMatchObject({
59
+ dev: "s3",
60
+ test: "memory",
61
+ prod: "s3",
62
+ });
63
+ expect(cfg.drivers?.signal).toMatchObject({
64
+ dev: "redis",
65
+ test: "memory",
66
+ prod: "redis",
67
+ });
68
+ expect(cfg.drivers?.clock).toMatchObject({
69
+ dev: "file",
70
+ test: "frozen",
71
+ prod: "file",
72
+ });
73
+ expect(cfg.drivers?.vault).toMatchObject({
74
+ dev: "vault",
75
+ test: "memory",
76
+ prod: "vault",
77
+ });
78
+ expect(cfg.drivers?.channel?.email).toMatchObject({
79
+ dev: "smtp",
80
+ test: "console",
81
+ prod: "smtp",
82
+ });
83
+ expect(cfg.drivers?.ai).toMatchObject({
84
+ dev: "anthropic",
85
+ test: "mock",
86
+ prod: "anthropic",
87
+ });
88
+ });
89
+
90
+ test("normalizeEnvDriverMap expands a bare string to all envs", () => {
91
+ expect(normalizeEnvDriverMap("redis")).toEqual({
92
+ dev: "redis",
93
+ test: "redis",
94
+ prod: "redis",
95
+ });
57
96
  });
58
97
 
59
- test("normalizeEnvDriverMap maps legacy keys", () => {
98
+ test("normalizeEnvDriverMap keeps only dev/test/prod keys", () => {
60
99
  const normalized = normalizeEnvDriverMap({
61
- dev: "sqlite",
62
- stack: "postgres",
100
+ dev: "postgres",
101
+ test: "pglite",
102
+ prod: "postgres",
103
+ });
104
+ expect(normalized).toEqual({
105
+ dev: "postgres",
106
+ test: "pglite",
63
107
  prod: "postgres",
64
108
  });
65
- expect(normalized?.local).toBe("sqlite");
66
- expect(normalized?.docker).toBe("postgres");
67
- expect((normalized as { dev?: string } | undefined)?.dev).toBeUndefined();
68
- expect((normalized as { stack?: string } | undefined)?.stack).toBeUndefined();
69
109
  });
70
110
 
71
- test("defineConfig accepts legacy driver-map keys", () => {
72
- const cfg = defineConfig({
73
- drivers: {
74
- store: {
75
- sql: { dev: "sqlite", stack: "postgres", prod: "postgres" } as never,
111
+ test("defineConfig rejects sqlite", () => {
112
+ expect(() =>
113
+ defineConfig({
114
+ drivers: {
115
+ store: {
116
+ sql: { dev: "sqlite", test: "pglite", prod: "postgres" },
117
+ },
76
118
  },
77
- },
78
- });
79
- expect(cfg.drivers?.store?.sql?.local).toBe("sqlite");
80
- expect(cfg.drivers?.store?.sql?.docker).toBe("postgres");
119
+ }),
120
+ ).toThrow(/sqlite/);
121
+ });
122
+
123
+ test("defineConfig rejects libsql", () => {
124
+ expect(() =>
125
+ defineConfig({
126
+ drivers: {
127
+ store: {
128
+ sql: { dev: "libsql", test: "pglite", prod: "postgres" },
129
+ },
130
+ },
131
+ }),
132
+ ).toThrow(/libsql/);
133
+ });
134
+
135
+ test("defineConfig rejects non-pglite test SQL", () => {
136
+ expect(() =>
137
+ defineConfig({
138
+ drivers: {
139
+ store: {
140
+ sql: { dev: "postgres", test: "memory", prod: "postgres" },
141
+ },
142
+ },
143
+ }),
144
+ ).toThrow(/pglite/);
81
145
  });
82
146
  });
@@ -20,11 +20,10 @@ import {
20
20
 
21
21
  describe("mergeEnvDriverMap", () => {
22
22
  test("an unset key keeps the real default, not a sibling key's value", () => {
23
- const merged = mergeEnvDriverMap({ local: "pglite" }, STORE_SQL_DEFAULTS);
23
+ const merged = mergeEnvDriverMap({ test: "pglite" }, STORE_SQL_DEFAULTS);
24
24
  expect(merged).toEqual({
25
- local: "pglite",
26
- docker: "postgres",
27
- test: "memory",
25
+ dev: "postgres",
26
+ test: "pglite",
28
27
  prod: "postgres",
29
28
  });
30
29
  });
@@ -34,28 +33,27 @@ describe("mergeEnvDriverMap", () => {
34
33
  });
35
34
 
36
35
  test("a fully-specified override wins on every key", () => {
37
- const override = { local: "a", docker: "b", test: "c", prod: "d" };
36
+ const override = { dev: "a", test: "b", prod: "c" };
38
37
  expect(mergeEnvDriverMap(override, STORE_SQL_DEFAULTS)).toEqual(override);
39
38
  });
40
39
  });
41
40
 
42
- describe("resolveEffectiveDrivers — the drivers.store.sql.local discussion scenario", () => {
43
- test("`{ store: { sql: { local: 'pglite' } } }` resolves sql to the real map, pglite only on local", () => {
41
+ describe("resolveEffectiveDrivers", () => {
42
+ test("`{ store: { sql: { test: 'pglite' } } }` keeps postgres on dev/prod", () => {
44
43
  const effective = resolveEffectiveDrivers({
45
- store: { sql: { local: "pglite" } },
44
+ store: { sql: { test: "pglite" } },
46
45
  });
47
46
 
48
47
  expect(effective.store.sql).toEqual({
49
- local: "pglite",
50
- docker: "postgres",
51
- test: "memory",
48
+ dev: "postgres",
49
+ test: "pglite",
52
50
  prod: "postgres",
53
51
  });
54
52
  });
55
53
 
56
54
  test("every other driver stays at its full, real, untouched default map", () => {
57
55
  const effective = resolveEffectiveDrivers({
58
- store: { sql: { local: "pglite" } },
56
+ store: { sql: { test: "pglite" } },
59
57
  });
60
58
 
61
59
  expect(effective.store.kv).toEqual(STORE_KV_DEFAULTS);
@@ -70,34 +68,29 @@ describe("resolveEffectiveDrivers — the drivers.store.sql.local discussion sce
70
68
 
71
69
  test("overriding one driver's map has zero effect on a sibling driver's defaults", () => {
72
70
  const effective = resolveEffectiveDrivers({
73
- store: { kv: { local: "redis" } },
71
+ store: { kv: { dev: "redis" } },
74
72
  });
75
73
 
76
- // The overridden driver (kv) reflects the override on its one set key.
77
74
  expect(effective.store.kv).toEqual({
78
- local: "redis",
79
- docker: "redis",
75
+ dev: "redis",
80
76
  test: "memory",
81
77
  prod: "redis",
82
78
  });
83
- // sql / files (same element, different facet) stay fully at real defaults.
84
79
  expect(effective.store.sql).toEqual(STORE_SQL_DEFAULTS);
85
80
  expect(effective.store.files).toEqual(STORE_FILES_DEFAULTS);
86
- // Unrelated elements stay fully at real defaults too.
87
81
  expect(effective.signal).toEqual(SIGNAL_DEFAULTS);
88
82
  expect(effective.vault).toEqual(VAULT_DEFAULTS);
89
83
  });
90
84
 
91
- test("overriding one env key leaves the other three at real defaults for that driver", () => {
85
+ test("overriding one env key leaves the other two at real defaults for that driver", () => {
92
86
  const effective = resolveEffectiveDrivers({
93
- vault: { local: "keychain" },
87
+ vault: { dev: "keychain" },
94
88
  });
95
89
 
96
90
  expect(effective.vault).toEqual({
97
- local: "keychain",
98
- docker: "env",
91
+ dev: "keychain",
99
92
  test: "memory",
100
- prod: "env",
93
+ prod: "vault",
101
94
  });
102
95
  });
103
96