okengine 0.10.2 → 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 (343) hide show
  1. package/package.json +76 -10
  2. package/site/content/docs/ai/mcp.mdx +0 -1
  3. package/site/content/docs/deployment/docker-swarm.mdx +48 -111
  4. package/site/content/docs/deployment/docker.mdx +43 -36
  5. package/site/content/docs/deployment/index.mdx +9 -9
  6. package/site/content/docs/deployment/kubernetes.mdx +4 -4
  7. package/site/content/docs/elements/ai.mdx +7 -13
  8. package/site/content/docs/elements/channel.mdx +9 -13
  9. package/site/content/docs/elements/clock.mdx +8 -14
  10. package/site/content/docs/elements/flow.mdx +46 -54
  11. package/site/content/docs/elements/gate.mdx +6 -11
  12. package/site/content/docs/elements/signal.mdx +2 -8
  13. package/site/content/docs/elements/store.mdx +79 -93
  14. package/site/content/docs/elements/vault.mdx +89 -76
  15. package/site/content/docs/get-started/basic-usage.mdx +8 -14
  16. package/site/content/docs/get-started/installation.mdx +36 -36
  17. package/site/content/docs/get-started/introduction.mdx +11 -0
  18. package/site/content/docs/get-started/why.mdx +3 -4
  19. package/site/content/docs/index.mdx +0 -1
  20. package/site/content/docs/meta.json +0 -1
  21. package/site/content/docs/plugins/anonymous.mdx +1 -1
  22. package/site/content/docs/plugins/magic-link.mdx +11 -11
  23. package/site/content/docs/plugins/otp.mdx +2 -2
  24. package/site/content/docs/plugins/passkey.mdx +1 -1
  25. package/site/content/docs/plugins/two-factor.mdx +1 -1
  26. package/site/content/docs/plugins/username.mdx +1 -1
  27. package/site/content/docs/recipes/caddy.mdx +1 -1
  28. package/site/content/docs/recipes/cockroachdb.mdx +2 -2
  29. package/site/content/docs/recipes/dragonfly.mdx +1 -1
  30. package/site/content/docs/recipes/index.mdx +1 -2
  31. package/site/content/docs/recipes/llama-cpp.mdx +21 -23
  32. package/site/content/docs/recipes/mailpit.mdx +11 -11
  33. package/site/content/docs/recipes/meilisearch.mdx +10 -10
  34. package/site/content/docs/recipes/meta.json +0 -1
  35. package/site/content/docs/recipes/ollama.mdx +1 -1
  36. package/site/content/docs/recipes/pgdog.mdx +12 -9
  37. package/site/content/docs/recipes/postgres.mdx +3 -3
  38. package/site/content/docs/recipes/redis.mdx +2 -2
  39. package/site/content/docs/recipes/rustfs.mdx +10 -7
  40. package/site/content/docs/recipes/sglang.mdx +1 -1
  41. package/site/content/docs/recipes/supabase-docker.mdx +1 -1
  42. package/site/content/docs/recipes/timescale.mdx +2 -2
  43. package/site/content/docs/recipes/valkey.mdx +1 -1
  44. package/site/content/docs/recipes/vllm.mdx +1 -1
  45. package/site/content/docs/recipes/yugabytedb.mdx +2 -2
  46. package/site/content/docs/reference/cli.md +61 -38
  47. package/site/content/docs/reference/configuration.mdx +145 -70
  48. package/site/content/docs/reference/environment-variables.mdx +36 -28
  49. package/site/content/docs/reference/errors.mdx +28 -29
  50. package/site/content/docs/reference/fx.mdx +14 -7
  51. package/site/content/docs/reference/i18n.mdx +17 -6
  52. package/site/content/docs/reference/index.mdx +5 -0
  53. package/site/content/docs/reference/meta.json +1 -0
  54. package/site/content/docs/reference/migrating-environments.mdx +158 -0
  55. package/site/content/docs/reference/plugins.mdx +2 -2
  56. package/src/auth/gate-auth.test.ts +12 -10
  57. package/src/cli/ai-setup/ai-setup.test.ts +30 -16
  58. package/src/cli/ai-setup/apply.ts +111 -15
  59. package/src/cli/ai-setup/catalog.ts +3 -3
  60. package/src/cli/ai-setup/index.ts +1 -1
  61. package/src/cli/ai-setup/prompts.ts +1 -1
  62. package/src/cli/ai-setup/recommend.test.ts +1 -1
  63. package/src/cli/ask-seed.test.ts +3 -3
  64. package/src/cli/build.ts +8 -9
  65. package/src/cli/db-auto-push.test.ts +6 -3
  66. package/src/cli/db-auto-push.ts +7 -5
  67. package/src/cli/db-seed.ts +7 -8
  68. package/src/cli/db.test.ts +70 -71
  69. package/src/cli/db.ts +86 -12
  70. package/src/cli/dev-controller.test.ts +35 -0
  71. package/src/cli/dev-controller.ts +298 -0
  72. package/src/cli/dev-controls.ts +11 -65
  73. package/src/cli/dev-db-push.test.ts +47 -15
  74. package/src/cli/dev-schema-sync.test.ts +11 -11
  75. package/src/cli/dev-schema-sync.ts +10 -10
  76. package/src/cli/dev-session-lock.test.ts +106 -0
  77. package/src/cli/dev-session-lock.ts +209 -0
  78. package/src/cli/dev.test.ts +246 -114
  79. package/src/cli/dev.ts +153 -205
  80. package/src/cli/doc-staleness.test.ts +3 -6
  81. package/src/cli/docker-clean.test.ts +33 -1
  82. package/src/cli/docker-clean.ts +28 -33
  83. package/src/cli/docker-cli.test.ts +12 -11
  84. package/src/cli/docker.ts +95 -20
  85. package/src/cli/doctor.test.ts +40 -0
  86. package/src/cli/doctor.ts +142 -9
  87. package/src/cli/drizzle-env.test.ts +11 -13
  88. package/src/cli/drizzle-env.ts +18 -11
  89. package/src/cli/ensure-drizzle-config.ts +11 -14
  90. package/src/cli/hero-meta.test.ts +15 -15
  91. package/src/cli/hero-meta.ts +10 -9
  92. package/src/cli/index.ts +36 -6
  93. package/src/cli/load-config.images.test.ts +44 -10
  94. package/src/cli/load-config.source.test.ts +50 -0
  95. package/src/cli/load-config.ts +35 -29
  96. package/src/cli/meilisearch-local.ts +1 -2
  97. package/src/cli/mode.ts +7 -58
  98. package/src/cli/registry.ts +175 -19
  99. package/src/cli/resolve-dev-sql-env.test.ts +8 -16
  100. package/src/cli/resolve-dev-sql-env.ts +13 -15
  101. package/src/cli/safe-defaults.test.ts +29 -11
  102. package/src/cli/schema.ts +65 -16
  103. package/src/cli/test.ts +58 -0
  104. package/src/cli/tui/App.tsx +252 -0
  105. package/src/cli/tui/DevLive.tsx +116 -0
  106. package/src/cli/tui/components/ConfirmDialog.tsx +48 -0
  107. package/src/cli/tui/components/HeaderBar.tsx +67 -0
  108. package/src/cli/tui/components/LogStream.tsx +47 -0
  109. package/src/cli/tui/components/PanelCard.tsx +39 -0
  110. package/src/cli/tui/components/SelectRow.tsx +37 -0
  111. package/src/cli/tui/components/SlashPalette.tsx +172 -0
  112. package/src/cli/tui/components/Spinner.tsx +32 -0
  113. package/src/cli/tui/components/StatusBar.tsx +51 -0
  114. package/src/cli/tui/components/StatusDot.tsx +37 -0
  115. package/src/cli/tui/components/TabBar.tsx +49 -0
  116. package/src/cli/tui/components/Wordmark.tsx +43 -0
  117. package/src/cli/tui/format.ts +38 -0
  118. package/src/cli/tui/keys.test.ts +18 -0
  119. package/src/cli/tui/keys.ts +26 -0
  120. package/src/cli/tui/launch.test.ts +18 -0
  121. package/src/cli/tui/launch.ts +57 -0
  122. package/src/cli/tui/panels/Dashboard.tsx +201 -0
  123. package/src/cli/tui/panels/Database.tsx +198 -0
  124. package/src/cli/tui/panels/Dev.tsx +257 -0
  125. package/src/cli/tui/panels/Docker.tsx +357 -0
  126. package/src/cli/tui/panels/Navigator.test.ts +22 -0
  127. package/src/cli/tui/panels/Navigator.tsx +213 -0
  128. package/src/cli/tui/slash-catalog.test.ts +31 -0
  129. package/src/cli/tui/slash-catalog.ts +184 -0
  130. package/src/cli/tui/slash-run.ts +54 -0
  131. package/src/cli/tui/state/ports.ts +95 -0
  132. package/src/cli/tui/theme.ts +24 -0
  133. package/src/cli/vault-cmd.test.ts +402 -0
  134. package/src/cli/vault-cmd.ts +727 -69
  135. package/src/cli/vault-secure-input.test.ts +56 -0
  136. package/src/cli/vault-secure-input.ts +124 -0
  137. package/src/compiler/effects-infer.ts +7 -0
  138. package/src/compiler/extract.ts +12 -0
  139. package/src/compiler/fixtures/skyport/oke.config.ts +7 -5
  140. package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +1 -1
  141. package/src/compiler/fixtures/skyport.expected.json +1 -1
  142. package/src/compiler/generate-adopt.ts +27 -1
  143. package/src/compiler-entry.ts +7 -0
  144. package/src/config/define-config.test.ts +111 -47
  145. package/src/config/driver-defaults.test.ts +115 -0
  146. package/src/config/driver-defaults.ts +156 -0
  147. package/src/config/index.ts +246 -131
  148. package/src/config/resolve-driver.test.ts +14 -19
  149. package/src/console/server/app.ts +4 -2
  150. package/src/console/server/console.test.ts +58 -1
  151. package/src/console/server/flows.ts +22 -2
  152. package/src/console/server/index.ts +3 -0
  153. package/src/console/server/operator-db.test.ts +55 -13
  154. package/src/console/server/operator-db.ts +305 -263
  155. package/src/console/server/serve.ts +16 -7
  156. package/src/console/server/state.ts +31 -9
  157. package/src/console/server/vault.test.ts +120 -5
  158. package/src/console/server/vault.ts +208 -12
  159. package/src/console/ui/dist/assets/{index-D-9KFce5.js → index--Y0Uaz-m.js} +2 -2
  160. package/src/console/ui/dist/assets/panel-vault-BkZdJPX8.js +1 -0
  161. package/src/console/ui/dist/assets/style-C3L349iZ.css +3 -0
  162. package/src/console/ui/dist/index.html +2 -2
  163. package/src/console/ui/shell/client.ts +16 -0
  164. package/src/console/ui/shell/panels/vault/VaultPanel.tsx +54 -1
  165. package/src/console/ui/vault/VaultA11yView.tsx +33 -1
  166. package/src/console/ui/vault/backend.test.ts +75 -0
  167. package/src/console/ui/vault/backend.ts +117 -0
  168. package/src/console/ui/vault/fixture.ts +21 -2
  169. package/src/console/ui/vault/index.ts +11 -1
  170. package/src/console/ui/vault/types.ts +26 -0
  171. package/src/docker/compose.ts +164 -61
  172. package/src/docker/derive.ts +106 -12
  173. package/src/docker/docker.test.ts +156 -110
  174. package/src/docker/helpers.ts +98 -0
  175. package/src/docker/images-config.test.ts +163 -0
  176. package/src/docker/index.ts +30 -5
  177. package/src/docker/recipes/index.ts +0 -3
  178. package/src/docker/recipes/llama-cpp.ts +4 -4
  179. package/src/docker/recipes/pgdog.ts +9 -2
  180. package/src/docker/resources.test.ts +71 -0
  181. package/src/docker/resources.ts +176 -0
  182. package/src/docker/stack-id.test.ts +11 -4
  183. package/src/docker/stack-id.ts +42 -32
  184. package/src/docker/stack.integration.test.ts +4 -15
  185. package/src/docker/types.ts +35 -3
  186. package/src/drivers/ai-ollama.integration.test.ts +2 -2
  187. package/src/drivers/conformance.test.ts +11 -12
  188. package/src/drivers/drizzle-dialect.test.ts +0 -4
  189. package/src/drivers/drizzle-dialect.ts +7 -13
  190. package/src/drivers/index.ts +24 -7
  191. package/src/drivers/journal-postgres.test.ts +3 -1
  192. package/src/drivers/journal-postgres.ts +4 -2
  193. package/src/drivers/meilisearch.ts +1 -1
  194. package/src/drivers/pglite.ts +28 -5
  195. package/src/drivers/types.ts +9 -11
  196. package/src/drivers/vault-aws-secrets-manager.test.ts +159 -0
  197. package/src/drivers/vault-aws-secrets-manager.ts +333 -0
  198. package/src/drivers/vault-builtin.test.ts +110 -0
  199. package/src/drivers/vault-builtin.ts +184 -0
  200. package/src/drivers/vault-driver-removal.test.ts +13 -0
  201. package/src/drivers/vault-managed.test.ts +95 -0
  202. package/src/drivers/vault-managed.ts +101 -25
  203. package/src/drivers/vault-types.ts +25 -5
  204. package/src/elements/ai/runtime.ts +1 -1
  205. package/src/elements/clock/chaos.test.ts +4 -1
  206. package/src/elements/clock/durable.ts +57 -4
  207. package/src/elements/clock.test.ts +13 -14
  208. package/src/elements/gate/constants.ts +18 -0
  209. package/src/elements/gate.test.ts +1 -1
  210. package/src/elements/gate.ts +2 -2
  211. package/src/elements/store/domain-ddl.test.ts +5 -12
  212. package/src/elements/store/emit-drizzle.ts +44 -19
  213. package/src/elements/store/index-boot.test.ts +15 -116
  214. package/src/elements/store/load-plugin-tables.ts +1 -1
  215. package/src/elements/store/resource-list-docs.fixture.ts +12 -6
  216. package/src/elements/store/resource-list-docs.test.ts +64 -44
  217. package/src/elements/store/resource.test.ts +17 -10
  218. package/src/elements/store/runtime.ts +9 -12
  219. package/src/elements/store/schema-decl.test.ts +16 -32
  220. package/src/elements/store/seed.test.ts +1 -2
  221. package/src/elements/store/seed.ts +7 -8
  222. package/src/elements/store/sql-condition.test.ts +2 -2
  223. package/src/elements/store/sql-session.test.ts +8 -10
  224. package/src/elements/store/sql-session.ts +10 -2
  225. package/src/elements/store.test.ts +13 -13
  226. package/src/elements/vault/audit.ts +233 -0
  227. package/src/elements/vault/boot-chain.test.ts +78 -0
  228. package/src/elements/vault/boot-chain.ts +43 -39
  229. package/src/elements/vault/builtin-adapter.test.ts +479 -0
  230. package/src/elements/vault/builtin-adapter.ts +1184 -0
  231. package/src/elements/vault/crypto.test.ts +237 -0
  232. package/src/elements/vault/crypto.ts +431 -0
  233. package/src/elements/vault/declare.ts +164 -3
  234. package/src/elements/vault/errors.ts +56 -0
  235. package/src/elements/vault/kms-unseal.test.ts +76 -0
  236. package/src/elements/vault/kms-unseal.ts +181 -0
  237. package/src/elements/vault/path.ts +90 -0
  238. package/src/elements/vault/resilience.test.ts +102 -0
  239. package/src/elements/vault/resilience.ts +107 -0
  240. package/src/elements/vault/runtime.ts +36 -4
  241. package/src/elements/vault/security-checklist.test.ts +130 -0
  242. package/src/elements/vault/storage.ts +448 -0
  243. package/src/elements/vault/types.ts +288 -0
  244. package/src/elements/vault/unseal.ts +150 -0
  245. package/src/elements/vault.test.ts +72 -4
  246. package/src/elements/vault.ts +91 -2
  247. package/src/full.ts +248 -0
  248. package/src/http.ts +41 -0
  249. package/src/i18n/interpolate-simple.ts +37 -0
  250. package/src/i18n/messages.ts +51 -4
  251. package/src/i18n-entry.ts +7 -0
  252. package/src/index.ts +35 -145
  253. package/src/journal-entry.ts +20 -0
  254. package/src/kernel/adopt-barrel-fresh.test.ts +25 -10
  255. package/src/kernel/app.ts +40 -42
  256. package/src/kernel/auto-registry.test.ts +2 -2
  257. package/src/kernel/boot-bind/ai.test.ts +5 -5
  258. package/src/kernel/boot-bind/ai.ts +2 -1
  259. package/src/kernel/boot-bind/channel.test.ts +6 -6
  260. package/src/kernel/boot-bind/channel.ts +5 -4
  261. package/src/kernel/boot-bind/clock.ts +5 -5
  262. package/src/kernel/boot-bind/gate.ts +6 -7
  263. package/src/kernel/boot-bind/honor-config.test.ts +42 -42
  264. package/src/kernel/boot-bind/journal.ts +5 -5
  265. package/src/kernel/boot-bind/signal.ts +3 -1
  266. package/src/kernel/boot-bind/store.test.ts +55 -37
  267. package/src/kernel/boot-bind/store.ts +24 -34
  268. package/src/kernel/boot-bind/vault.ts +19 -4
  269. package/src/kernel/boot.test.ts +12 -4
  270. package/src/kernel/boot.ts +31 -19
  271. package/src/kernel/budget-entry.ts +1 -1
  272. package/src/kernel/compensate.test.ts +288 -1
  273. package/src/kernel/compensate.ts +126 -0
  274. package/src/kernel/concurrency.test.ts +10 -9
  275. package/src/kernel/effects-stamping.test.ts +27 -2
  276. package/src/kernel/element-registries.ts +5 -3
  277. package/src/kernel/flow.ts +4 -2
  278. package/src/kernel/fx.test.ts +119 -3
  279. package/src/kernel/fx.ts +215 -40
  280. package/src/kernel/index.ts +14 -0
  281. package/src/kernel/journal.ts +130 -7
  282. package/src/kernel/pipeline.test.ts +20 -6
  283. package/src/kernel/redacted.test.ts +35 -0
  284. package/src/kernel/redacted.ts +24 -2
  285. package/src/kernel/router/create-default.ts +16 -0
  286. package/src/kernel/router/create-edge.ts +18 -0
  287. package/src/kernel/router/create.ts +23 -0
  288. package/src/kernel/router/index.ts +23 -0
  289. package/src/kernel/router/linear.ts +88 -0
  290. package/src/kernel/router/regexp.ts +188 -0
  291. package/src/kernel/router/smart.ts +120 -0
  292. package/src/kernel/router/trie.ts +108 -0
  293. package/src/kernel/router/types.ts +56 -0
  294. package/src/kernel/router.ts +18 -532
  295. package/src/kernel-entry.ts +43 -0
  296. package/src/manifest/fixtures/skyport.excerpt.json +1 -1
  297. package/src/manifest/fixtures/skyport.manifest.json +1 -1
  298. package/src/plugins/config-source.test.ts +7 -7
  299. package/src/release/build-lib.ts +58 -0
  300. package/src/release/exports.test.ts +4 -2
  301. package/src/release/exports.ts +30 -4
  302. package/src/release/measure.ts +101 -22
  303. package/src/runs/duckdb.ts +7 -2
  304. package/src/shared/optional-peer.ts +41 -0
  305. package/src/term.test.ts +3 -44
  306. package/src/test/create-test-app.ts +12 -0
  307. package/src/test/provisions.integration.test.ts +1 -1
  308. package/src/test/reset-element-registries.ts +2 -0
  309. package/src/upgrade/codemods.test.ts +7 -20
  310. package/src/upgrade/codemods.ts +93 -60
  311. package/site/content/docs/console/access.mdx +0 -29
  312. package/site/content/docs/console/ai.mdx +0 -35
  313. package/site/content/docs/console/architecture.mdx +0 -35
  314. package/site/content/docs/console/channels.mdx +0 -37
  315. package/site/content/docs/console/clock.mdx +0 -51
  316. package/site/content/docs/console/flows.mdx +0 -31
  317. package/site/content/docs/console/gates.mdx +0 -73
  318. package/site/content/docs/console/index.mdx +0 -54
  319. package/site/content/docs/console/manifest-diff.mdx +0 -34
  320. package/site/content/docs/console/meta.json +0 -24
  321. package/site/content/docs/console/overview.mdx +0 -40
  322. package/site/content/docs/console/plugins.mdx +0 -41
  323. package/site/content/docs/console/privacy.mdx +0 -32
  324. package/site/content/docs/console/runs.mdx +0 -50
  325. package/site/content/docs/console/signals.mdx +0 -40
  326. package/site/content/docs/console/store.mdx +0 -32
  327. package/site/content/docs/console/tenancy.mdx +0 -32
  328. package/site/content/docs/console/traces.mdx +0 -38
  329. package/site/content/docs/console/vault.mdx +0 -41
  330. package/site/content/docs/recipes/openbao.mdx +0 -141
  331. package/src/cli/ask-dev-mode.ts +0 -40
  332. package/src/cli/dev-mode.test.ts +0 -45
  333. package/src/cli/dev-mode.ts +0 -78
  334. package/src/cli/openbao-bootstrap.test.ts +0 -150
  335. package/src/cli/openbao-bootstrap.ts +0 -321
  336. package/src/cli/openbao-restart.integration.test.ts +0 -145
  337. package/src/console/ui/dist/assets/panel-vault-Za1GyJfM.js +0 -1
  338. package/src/console/ui/dist/assets/style-C8MxEWPd.css +0 -3
  339. package/src/docker/recipes/openbao.ts +0 -47
  340. package/src/drivers/libsql.ts +0 -179
  341. package/src/drivers/sqlite.ts +0 -44
  342. package/src/drivers/vault-openbao.test.ts +0 -97
  343. package/src/drivers/vault-openbao.ts +0 -143
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Prebuild tree-shaken ESM library entries into `dist/` for non-Bun consumers.
4
+ *
5
+ * Bun itself resolves the `"bun"` export condition to TypeScript sources under
6
+ * `src/`. This build is what `"import"` / `"default"` conditions point at.
7
+ */
8
+
9
+ import { mkdir, rm } from "node:fs/promises";
10
+ import { dirname, join, relative, resolve } from "node:path";
11
+ import { EXPORT_BUILD_EXTERNALS } from "./measure.ts";
12
+
13
+ const ROOT = resolve(import.meta.dir, "../..");
14
+ const DIST = join(ROOT, "dist");
15
+
16
+ /** Library entry points mirrored into `dist/`. */
17
+ const ENTRIES: readonly { readonly src: string; readonly out: string }[] = [
18
+ { src: "src/index.ts", out: "dist/index.js" },
19
+ { src: "src/http.ts", out: "dist/http.js" },
20
+ { src: "src/kernel-entry.ts", out: "dist/kernel-entry.js" },
21
+ { src: "src/full.ts", out: "dist/full.js" },
22
+ { src: "src/i18n-entry.ts", out: "dist/i18n-entry.js" },
23
+ { src: "src/compiler-entry.ts", out: "dist/compiler-entry.js" },
24
+ { src: "src/journal-entry.ts", out: "dist/journal-entry.js" },
25
+ ];
26
+
27
+ /**
28
+ * Build every library entry into `dist/`.
29
+ */
30
+ export async function buildLib(): Promise<void> {
31
+ await rm(DIST, { recursive: true, force: true });
32
+ await mkdir(DIST, { recursive: true });
33
+
34
+ for (const entry of ENTRIES) {
35
+ const absIn = join(ROOT, entry.src);
36
+ const absOut = join(ROOT, entry.out);
37
+ await mkdir(dirname(absOut), { recursive: true });
38
+ const result = await Bun.build({
39
+ entrypoints: [absIn],
40
+ outdir: dirname(absOut),
41
+ naming: relative(DIST, absOut).replace(/\\/g, "/"),
42
+ target: "bun",
43
+ format: "esm",
44
+ minify: false,
45
+ sourcemap: "external",
46
+ external: [...EXPORT_BUILD_EXTERNALS],
47
+ splitting: false,
48
+ });
49
+ if (!result.success) {
50
+ throw new Error(`build:lib failed for ${entry.src}:\n${result.logs.map(String).join("\n")}`);
51
+ }
52
+ }
53
+ }
54
+
55
+ if (import.meta.main) {
56
+ await buildLib();
57
+ console.log(`build:lib wrote ${ENTRIES.length} entries under dist/`);
58
+ }
@@ -59,13 +59,15 @@ describe("export budget targets", () => {
59
59
 
60
60
  test("every non-glob package export and every driver module is covered", async () => {
61
61
  const pkg = (await Bun.file(join(ROOT, "package.json")).json()) as {
62
- exports: Record<string, string>;
62
+ exports: Record<string, import("./exports.ts").PackageExportTarget>;
63
63
  };
64
+ const { resolveExportSourcePath } = await import("./exports.ts");
64
65
  const targets = await resolveExportBudgetTargets();
65
66
  const bySubpath = new Map(targets.map((t) => [t.subpath, t]));
66
67
 
67
- for (const [subpath, entryRel] of Object.entries(pkg.exports)) {
68
+ for (const [subpath, entryTarget] of Object.entries(pkg.exports)) {
68
69
  if (subpath.endsWith("/*")) continue;
70
+ const entryRel = resolveExportSourcePath(entryTarget);
69
71
  const target = bySubpath.get(subpath);
70
72
  expect(target).toBeDefined();
71
73
  expect(target!.id).toBe(`export:${subpath}`);
@@ -77,8 +77,29 @@ export function exportBudgetGroup(subpath: string): BudgetGroup {
77
77
  return "exports";
78
78
  }
79
79
 
80
+ /** One package.json exports target (string path or conditional map). */
81
+ export type PackageExportTarget =
82
+ | string
83
+ | Readonly<Partial<Record<"types" | "bun" | "import" | "default" | "require", string>>>;
84
+
80
85
  interface PackageExports {
81
- readonly exports?: Readonly<Record<string, string>>;
86
+ readonly exports?: Readonly<Record<string, PackageExportTarget>>;
87
+ }
88
+
89
+ /**
90
+ * Resolve a package export target to the TypeScript source path used for budgets.
91
+ *
92
+ * Prefers `bun` / `types` (src) over compiled `import`/`default` (dist).
93
+ *
94
+ * @param target - Export target from package.json
95
+ */
96
+ export function resolveExportSourcePath(target: PackageExportTarget): string {
97
+ if (typeof target === "string") return target;
98
+ const path = target.bun ?? target.types ?? target.import ?? target.default;
99
+ if (!path || typeof path !== "string") {
100
+ throw new Error("export target has no resolvable string path");
101
+ }
102
+ return path;
82
103
  }
83
104
 
84
105
  /**
@@ -150,7 +171,7 @@ export async function resolveExportBudgetTargets(options?: {
150
171
 
151
172
  const targets: ExportBudgetTarget[] = [];
152
173
 
153
- for (const [subpath, entryRel] of Object.entries(exportsMap)) {
174
+ for (const [subpath, entryTarget] of Object.entries(exportsMap)) {
154
175
  if (subpath.endsWith("/*")) {
155
176
  if (subpath !== "./drivers/*") {
156
177
  throw new Error(`unsupported export glob ${subpath}: only ./drivers/* is expanded`);
@@ -164,8 +185,13 @@ export async function resolveExportBudgetTargets(options?: {
164
185
  continue;
165
186
  }
166
187
 
167
- if (typeof entryRel !== "string") {
168
- throw new Error(`export ${subpath} must map to a string path`);
188
+ let entryRel: string;
189
+ try {
190
+ entryRel = resolveExportSourcePath(entryTarget);
191
+ } catch {
192
+ throw new Error(
193
+ `export ${subpath} must map to a string path or conditional bun/types target`,
194
+ );
169
195
  }
170
196
 
171
197
  targets.push(targetFor(subpath, resolve(root, entryRel)));
@@ -39,7 +39,7 @@ const BUILD_EXTERNALS = [
39
39
  ] as const;
40
40
 
41
41
  /** Heavy optional / peer packages — not counted in export:* gzip samples. */
42
- const EXPORT_BUILD_EXTERNALS = [
42
+ export const EXPORT_BUILD_EXTERNALS = [
43
43
  ...BUILD_EXTERNALS,
44
44
  "sently",
45
45
  "sently/*",
@@ -48,8 +48,6 @@ const EXPORT_BUILD_EXTERNALS = [
48
48
  "ajv-formats",
49
49
  "oxc-parser",
50
50
  "zod",
51
- "@libsql/client",
52
- "@libsql/*",
53
51
  "@electric-sql/pglite",
54
52
  "@electric-sql/*",
55
53
  ] as const;
@@ -152,6 +150,80 @@ export async function measureEntryGzipBytes(
152
150
  return gzipBuildOutputs(result, label);
153
151
  }
154
152
 
153
+ /**
154
+ * Raw (uncompressed) minified JS bytes for one entry.
155
+ *
156
+ * @param entry - Absolute path to the TypeScript entry
157
+ * @param label - Error context
158
+ * @param external - Packages left external (not inlined)
159
+ */
160
+ export async function measureEntryRawBytes(
161
+ entry: string,
162
+ label = entry,
163
+ external: readonly string[] = BUILD_EXTERNALS,
164
+ ): Promise<number> {
165
+ const result = await Bun.build({
166
+ entrypoints: [entry],
167
+ minify: true,
168
+ target: "bun",
169
+ format: "esm",
170
+ external: [...external],
171
+ });
172
+ if (!result.success) {
173
+ throw new Error(`${label} build failed:\n${result.logs.map(String).join("\n")}`);
174
+ }
175
+ let total = 0;
176
+ for (const artifact of result.outputs) {
177
+ const path = artifact.path;
178
+ if (path && !/\.(m?js|cjs)$/.test(path) && artifact.kind === "asset") continue;
179
+ const raw = await artifact.arrayBuffer();
180
+ total += raw.byteLength;
181
+ }
182
+ if (total <= 0) throw new Error(`${label} build produced no JS output`);
183
+ return total;
184
+ }
185
+
186
+ /** HTTP-ping app budget sample (raw + gzip, with/without export externals). */
187
+ export interface HttpPingBudgetSample {
188
+ readonly gzipWithExternals: number;
189
+ readonly rawWithExternals: number;
190
+ readonly gzipWithoutExternals: number;
191
+ readonly rawWithoutExternals: number;
192
+ }
193
+
194
+ /**
195
+ * Measure a minimal HTTP ping app via `okengine/http`.
196
+ */
197
+ export async function measureHttpPingAppBytes(): Promise<HttpPingBudgetSample> {
198
+ const dir = await mkdtemp(join(tmpdir(), "oke-http-ping-budget-"));
199
+ const anchor = join(dir, "anchor.ts");
200
+ const httpEntry = resolve(ROOT, "src/http.ts");
201
+ await Bun.write(
202
+ anchor,
203
+ `import { on, flow, http, gate, oke, createBunRuntime } from ${JSON.stringify(httpEntry)};\n` +
204
+ `on(http.get("/").gate(gate.public), flow("ping", { do: () => "Hi" }));\n` +
205
+ `export const app = oke({ name: "ping" });\n` +
206
+ `export const rt = createBunRuntime;\n`,
207
+ );
208
+ try {
209
+ const [gzipWithExternals, rawWithExternals, gzipWithoutExternals, rawWithoutExternals] =
210
+ await Promise.all([
211
+ measureEntryGzipBytes(anchor, "http-ping", EXPORT_BUILD_EXTERNALS),
212
+ measureEntryRawBytes(anchor, "http-ping", EXPORT_BUILD_EXTERNALS),
213
+ measureEntryGzipBytes(anchor, "http-ping-deps", BUILD_EXTERNALS),
214
+ measureEntryRawBytes(anchor, "http-ping-deps", BUILD_EXTERNALS),
215
+ ]);
216
+ return {
217
+ gzipWithExternals,
218
+ rawWithExternals,
219
+ gzipWithoutExternals,
220
+ rawWithoutExternals,
221
+ };
222
+ } finally {
223
+ await rm(dir, { recursive: true, force: true });
224
+ }
225
+ }
226
+
155
227
  /**
156
228
  * Gzip size of the kernel edge profile bundle.
157
229
  */
@@ -287,22 +359,13 @@ export async function measureConsoleBundleBreakdown(
287
359
  * (FS / module-cache warmup), median of the remaining six.
288
360
  */
289
361
  async function measureColdStartMedianMsOnce(): Promise<number> {
290
- const paths = {
291
- bun: `${import.meta.dir}/../runtime/bun.ts`,
292
- app: `${import.meta.dir}/../kernel/app.ts`,
293
- flow: `${import.meta.dir}/../kernel/flow.ts`,
294
- on: `${import.meta.dir}/../kernel/on.ts`,
295
- http: `${import.meta.dir}/../kernel/triggers.ts`,
296
- };
362
+ const httpEntry = `${import.meta.dir}/../http.ts`;
297
363
  const probe = `
298
364
  const t0 = performance.now();
299
- const { createBunRuntime } = await import(${JSON.stringify(paths.bun)});
300
- const { oke } = await import(${JSON.stringify(paths.app)});
301
- const { flow } = await import(${JSON.stringify(paths.flow)});
302
- const { on, resetBindings } = await import(${JSON.stringify(paths.on)});
303
- const { http } = await import(${JSON.stringify(paths.http)});
365
+ const { createBunRuntime, oke, on, flow, http, gate } = await import(${JSON.stringify(httpEntry)});
366
+ const { resetBindings } = await import(${JSON.stringify(`${import.meta.dir}/../kernel/on.ts`)});
304
367
  resetBindings();
305
- on(http.get("/ping"), flow("ping", { do: () => ({ ok: true }) }));
368
+ on(http.get("/ping").gate(gate.public), flow("ping", { do: () => ({ ok: true }) }));
306
369
  const app = oke({ name: "cold-start" });
307
370
  const rt = createBunRuntime();
308
371
  const server = rt.serve(app, { port: 0, hostname: "127.0.0.1" });
@@ -429,11 +492,13 @@ export async function measureAllBudgets(): Promise<BudgetsSnapshot> {
429
492
  // Cold start alone first — parallel gzip work contends for CPU on CI and
430
493
  // falsely inflates the wall-clock probe.
431
494
  const coldStartMedianMs = await measureColdStartMedianMs();
432
- const [kernelEdgeGzipBytes, clientGzipBytes, consoleInitialGzipBytes] = await Promise.all([
433
- measureKernelEdgeGzipBytes(),
434
- measureClientGzipBytes(),
435
- measureConsoleInitialGzipBytes(),
436
- ]);
495
+ const [kernelEdgeGzipBytes, clientGzipBytes, consoleInitialGzipBytes, httpPing] =
496
+ await Promise.all([
497
+ measureKernelEdgeGzipBytes(),
498
+ measureClientGzipBytes(),
499
+ measureConsoleInitialGzipBytes(),
500
+ measureHttpPingAppBytes(),
501
+ ]);
437
502
  const routingP99Ms = measureRoutingP99Ms();
438
503
 
439
504
  const budgets: BudgetSample[] = [
@@ -482,6 +547,20 @@ export async function measureAllBudgets(): Promise<BudgetsSnapshot> {
482
547
  "absolute",
483
548
  "core",
484
549
  ),
550
+ regressionSample(
551
+ "httpPingGzipBytes",
552
+ "HTTP ping app (gzip, externals)",
553
+ "core",
554
+ httpPing.gzipWithExternals,
555
+ previous,
556
+ ),
557
+ regressionSample(
558
+ "httpPingRawBytes",
559
+ "HTTP ping app (raw, externals)",
560
+ "core",
561
+ httpPing.rawWithExternals,
562
+ previous,
563
+ ),
485
564
  ];
486
565
 
487
566
  const exportTargets = await resolveExportBudgetTargets();
@@ -561,7 +640,7 @@ export function formatBudgetsMarkdown(snapshot: BudgetsSnapshot): string {
561
640
  "",
562
641
  `_okengine v${snapshot.version} · measured ${snapshot.measuredAt}_`,
563
642
  "",
564
- "Core rows are absolute AGENTS caps. Exports, Plugins, and Drivers fail on regression vs the prior [`budgets.json`](budgets.json) (max +256 B or +2%). Export gzip excludes peers/optionals (`zod`, `sently`, `oxc-parser`, `ajv`).",
643
+ "Core rows are absolute AGENTS caps (plus HTTP-ping regression samples). Exports, Plugins, and Drivers fail on regression vs the prior [`budgets.json`](budgets.json) (max +256 B or +2%). Export gzip excludes peers/optionals (`zod`, `sently`, `oxc-parser`, `ajv`, DuckDB, FormatJS). The `okengine` export row is the **thin root** (gzip); use `okengine/full` for the legacy mega-barrel and `okengine/http` for HTTP-only apps.",
565
644
  ];
566
645
  const order: readonly BudgetGroup[] = ["core", "exports", "plugins", "drivers"];
567
646
  for (const group of order) {
@@ -2,8 +2,9 @@
2
2
  * Thin DuckDB adapter — adopted via `@duckdb/node-api`, not reinvented.
3
3
  */
4
4
 
5
- import { DuckDBInstance, type DuckDBConnection } from "@duckdb/node-api";
5
+ import type { DuckDBConnection, DuckDBInstance } from "@duckdb/node-api";
6
6
 
7
+ import { importOptionalPeer } from "../shared/optional-peer.ts";
7
8
  import type { RunsRow } from "./types.ts";
8
9
 
9
10
  /** DuckDB session — instance kept alive with the connection. */
@@ -18,7 +19,11 @@ export interface DuckSession {
18
19
 
19
20
  /** Open an in-memory DuckDB session. */
20
21
  export async function openDuckDB(): Promise<DuckSession> {
21
- const instance = await DuckDBInstance.create(":memory:");
22
+ const mod = await importOptionalPeer<typeof import("@duckdb/node-api")>(
23
+ "@duckdb/node-api",
24
+ "Runs DuckDB / Parquet queries",
25
+ );
26
+ const instance = await mod.DuckDBInstance.create(":memory:");
22
27
  const conn = await instance.connect();
23
28
  return {
24
29
  instance,
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Resolve optional peer dependencies with a clear install hint.
3
+ */
4
+
5
+ import { createRequire } from "node:module";
6
+
7
+ const require = createRequire(import.meta.url);
8
+
9
+ /**
10
+ * Dynamically import an optional peer, or throw an actionable error.
11
+ *
12
+ * @param spec - Package name
13
+ * @param feature - Human feature label for the error
14
+ */
15
+ export async function importOptionalPeer<T>(spec: string, feature: string): Promise<T> {
16
+ try {
17
+ return (await import(spec)) as T;
18
+ } catch (err) {
19
+ const detail = err instanceof Error ? err.message : String(err);
20
+ throw new Error(
21
+ `${feature} requires optional peer \`${spec}\`. Install it with \`bun add ${spec}\`. (${detail})`,
22
+ );
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Synchronously require an optional peer, or throw an actionable error.
28
+ *
29
+ * @param spec - Package name
30
+ * @param feature - Human feature label
31
+ */
32
+ export function requireOptionalPeer<T>(spec: string, feature: string): T {
33
+ try {
34
+ return require(spec) as T;
35
+ } catch (err) {
36
+ const detail = err instanceof Error ? err.message : String(err);
37
+ throw new Error(
38
+ `${feature} requires optional peer \`${spec}\`. Install it with \`bun add ${spec}\`. (${detail})`,
39
+ );
40
+ }
41
+ }
package/src/term.test.ts CHANGED
@@ -16,9 +16,6 @@ import {
16
16
  formatRequestLine,
17
17
  formatStackSummary,
18
18
  countTermLines,
19
- createAnchoredBoard,
20
- createBootProgress,
21
- createRewritableBlock,
22
19
  formatStatusDot,
23
20
  formatStatusLine,
24
21
  termStyle,
@@ -48,7 +45,7 @@ describe("term", () => {
48
45
  { element: "flow", detail: "", status: "ready" },
49
46
  { element: "store", detail: "sql postgres · kv redis", status: "ready" },
50
47
  { element: "signal", detail: "memory", status: "ready" },
51
- { element: "ai", detail: "openai-compatible · smollm2", status: "pending" },
48
+ { element: "ai", detail: "openai-compatible · granite3.3:2b", status: "pending" },
52
49
  ],
53
50
  });
54
51
  expect(out).toContain("oke dev v0.2.4");
@@ -77,47 +74,9 @@ describe("term", () => {
77
74
  expect(formatStatusDot("ready", false)).toBe("●");
78
75
  });
79
76
 
80
- test("createRewritableBlock appends when disabled", () => {
81
- let out = "";
82
- const block = createRewritableBlock((t) => {
83
- out += t;
84
- }, false);
85
- block.paint("a\nb\n");
86
- block.paint("c\n");
87
- expect(out).toBe("a\nb\nc\n");
77
+ test("countTermLines counts rows", () => {
88
78
  expect(countTermLines("a\nb\n")).toBe(2);
89
- });
90
-
91
- test("createBootProgress replaces keyed rows then clears", () => {
92
- let out = "";
93
- const progress = createBootProgress((t) => {
94
- out += t;
95
- }, false);
96
- progress.set("compose", "compose…\n");
97
- progress.set("compose", "compose ok\n");
98
- progress.set("vault", "vault ok\n");
99
- // Non-TTY appends each set (including replacements).
100
- expect(out).toContain("compose ok\n");
101
- expect(out).toContain("vault ok\n");
102
- progress.clear();
103
- // clear is a no-op on the stream when rewrite is disabled
104
- expect(out).toContain("vault ok\n");
105
- });
106
-
107
- test("createAnchoredBoard wrapWrite tracks below output", () => {
108
- let out = "";
109
- const board = createAnchoredBoard((t) => {
110
- out += t;
111
- }, false);
112
- board.paint("board\n");
113
- const w = board.wrapWrite((t) => {
114
- out += t;
115
- });
116
- w("below\n");
117
- board.paint("board2\n"); // non-TTY: no rewrite append
118
- expect(out).toContain("board\n");
119
- expect(out).toContain("below\n");
120
- board.stop();
79
+ expect(countTermLines("")).toBe(0);
121
80
  });
122
81
 
123
82
  test("formatServiceLine / formatAppReadyLine include URL", () => {
@@ -14,6 +14,9 @@
14
14
  * ```
15
15
  */
16
16
 
17
+ import { mkdtemp, rm } from "node:fs/promises";
18
+ import { tmpdir } from "node:os";
19
+ import { join } from "node:path";
17
20
  import {
18
21
  createMockAiDriver,
19
22
  createChannelInbox,
@@ -212,6 +215,12 @@ export async function createTestApp<App extends OkeApp>(
212
215
  return out;
213
216
  };
214
217
 
218
+ // Unique on-disk PGLite datadir per harness — `memory://` is not reliably
219
+ // isolated across boots in one worker (IF NOT EXISTS / row leaks).
220
+ const prevPgliteUrl = process.env.OKE_PGLITE_URL;
221
+ const pgliteDir = await mkdtemp(join(tmpdir(), "oke-pglite-"));
222
+ process.env.OKE_PGLITE_URL = pgliteDir;
223
+
215
224
  await app.boot({
216
225
  ...(options.boot ?? {}),
217
226
  env: "test",
@@ -322,6 +331,9 @@ export async function createTestApp<App extends OkeApp>(
322
331
  },
323
332
  async close() {
324
333
  await app.bootResult?.close();
334
+ if (prevPgliteUrl === undefined) delete process.env.OKE_PGLITE_URL;
335
+ else process.env.OKE_PGLITE_URL = prevPgliteUrl;
336
+ await rm(pgliteDir, { recursive: true, force: true }).catch(() => undefined);
325
337
  },
326
338
  };
327
339
 
@@ -54,7 +54,7 @@ describe("Provisions integration", () => {
54
54
  out: z.boolean(),
55
55
  effects: { secrets: ["STRIPE_KEY"], emits: ["order-news"] },
56
56
  do: async ({ orderId }, fx) => {
57
- const key = fx.vault(stripeKey);
57
+ const key = await fx.vault.get(stripeKey);
58
58
  expect(key.reveal().startsWith("sk_")).toBe(true);
59
59
 
60
60
  await fx.step("create-intent", async () => ({ id: `pi_${orderId}` }));
@@ -18,6 +18,7 @@
18
18
  import { afterEach } from "bun:test";
19
19
  import {
20
20
  channelTemplateRegistry,
21
+ requiredEnvRegistry,
21
22
  secretRegistry,
22
23
  signalRegistry,
23
24
  storeRegistry,
@@ -26,6 +27,7 @@ import {
26
27
  afterEach(() => {
27
28
  storeRegistry.length = 0;
28
29
  secretRegistry.length = 0;
30
+ requiredEnvRegistry.length = 0;
29
31
  signalRegistry.length = 0;
30
32
  channelTemplateRegistry.length = 0;
31
33
  });
@@ -5,8 +5,7 @@
5
5
  import { describe, expect, test } from "bun:test";
6
6
  import {
7
7
  CODEMODS,
8
- rewriteConfigEnvKeys,
9
- rewriteFromStackMarkers,
8
+ rewriteThinRootImports,
10
9
  runCodemods,
11
10
  validateCodemodRegistry,
12
11
  type Codemod,
@@ -54,24 +53,12 @@ describe("codemod registry", () => {
54
53
  expect(changes).toEqual([{ path: "src/x.ts", before: "old", after: "new" }]);
55
54
  });
56
55
 
57
- test("rewriteConfigEnvKeys renames driver-map keys", () => {
58
- const after = rewriteConfigEnvKeys(`sql: {
59
- dev: "sqlite",
60
- stack: "postgres",
61
- prod: "postgres",
62
- }`);
63
- expect(after).toContain('local: "sqlite"');
64
- expect(after).toContain('docker: "postgres"');
65
- expect(after).not.toMatch(/(^|[^\w.])dev\s*:/);
66
- expect(after).not.toMatch(/(^|[^\w.])stack\s*:/);
67
- });
68
-
69
- test("rewriteFromStackMarkers renames vault helpers", () => {
70
- const after = rewriteFromStackMarkers(
71
- `dev: vault.fromStack("store.sql") // __oke_from_stack__`,
56
+ test("rewriteThinRootImports moves deep imports to subpaths", () => {
57
+ const after = rewriteThinRootImports(
58
+ `import { createFx, on } from "okengine";\nimport { flow } from "okengine";\n`,
72
59
  );
73
- expect(after).toContain("fromDocker");
74
- expect(after).toContain("__oke_from_docker__");
75
- expect(after).not.toContain("fromStack");
60
+ expect(after).toContain('from "okengine/full"');
61
+ expect(after).toContain("createFx");
62
+ expect(after).toMatch(/from ["']okengine["']/);
76
63
  });
77
64
  });