okengine 0.2.6 → 0.3.2

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 (681) hide show
  1. package/AGENTS.md +33 -30
  2. package/README.md +74 -340
  3. package/{spec/manifest.v1.schema.json → manifest.v1.schema.json} +40 -9
  4. package/package.json +47 -44
  5. package/site/content/docs/ai/llms-txt.mdx +54 -0
  6. package/site/content/docs/ai/mcp.mdx +123 -0
  7. package/site/content/docs/ai/meta.json +5 -0
  8. package/site/content/docs/ai/skills.mdx +53 -0
  9. package/site/content/docs/console/access.mdx +29 -0
  10. package/site/content/docs/console/ai.mdx +35 -0
  11. package/site/content/docs/console/architecture.mdx +35 -0
  12. package/site/content/docs/console/channels.mdx +37 -0
  13. package/site/content/docs/console/clock.mdx +31 -0
  14. package/site/content/docs/console/flows.mdx +31 -0
  15. package/site/content/docs/console/gates.mdx +35 -0
  16. package/site/content/docs/console/manifest-diff.mdx +34 -0
  17. package/site/content/docs/console/meta.json +23 -0
  18. package/site/content/docs/console/overview.mdx +40 -0
  19. package/site/content/docs/console/plugins.mdx +41 -0
  20. package/site/content/docs/console/privacy.mdx +32 -0
  21. package/site/content/docs/console/runs.mdx +40 -0
  22. package/site/content/docs/console/signals.mdx +31 -0
  23. package/site/content/docs/console/store.mdx +32 -0
  24. package/site/content/docs/console/tenancy.mdx +32 -0
  25. package/site/content/docs/console/traces.mdx +34 -0
  26. package/site/content/docs/console/vault.mdx +37 -0
  27. package/site/content/docs/elements/ai.mdx +180 -0
  28. package/site/content/docs/elements/channel.mdx +167 -0
  29. package/site/content/docs/elements/clock.mdx +182 -0
  30. package/site/content/docs/elements/flow.mdx +288 -0
  31. package/site/content/docs/elements/gate.mdx +171 -0
  32. package/site/content/docs/elements/meta.json +5 -0
  33. package/site/content/docs/elements/signal.mdx +171 -0
  34. package/site/content/docs/elements/store.mdx +320 -0
  35. package/site/content/docs/elements/vault.mdx +263 -0
  36. package/site/content/docs/get-started/basic-usage.mdx +124 -0
  37. package/site/content/docs/get-started/comparison.mdx +65 -0
  38. package/site/content/docs/get-started/installation.mdx +113 -0
  39. package/site/content/docs/get-started/introduction.mdx +123 -0
  40. package/site/content/docs/get-started/meta.json +5 -0
  41. package/site/content/docs/index.mdx +63 -0
  42. package/site/content/docs/meta.json +5 -0
  43. package/site/content/docs/plugins/compression.mdx +60 -0
  44. package/site/content/docs/plugins/cors.mdx +92 -0
  45. package/site/content/docs/plugins/csrf.mdx +96 -0
  46. package/site/content/docs/plugins/ip-allowlist.mdx +92 -0
  47. package/site/content/docs/plugins/maintenance-mode.mdx +101 -0
  48. package/site/content/docs/plugins/meta.json +15 -0
  49. package/site/content/docs/plugins/security-headers.mdx +136 -0
  50. package/site/content/docs/reference/cli.md +101 -0
  51. package/site/content/docs/reference/configuration.mdx +159 -0
  52. package/site/content/docs/reference/environment-variables.mdx +87 -0
  53. package/site/content/docs/reference/errors.mdx +80 -0
  54. package/site/content/docs/reference/fx.mdx +117 -0
  55. package/site/content/docs/reference/meta.json +5 -0
  56. package/site/content/docs/reference/plugins.mdx +249 -0
  57. package/site/content/docs/reference/security.md +63 -0
  58. package/src/auth/api-keys.ts +2 -5
  59. package/src/auth/attenuation.ts +2 -6
  60. package/src/auth/auth.test.ts +56 -31
  61. package/src/auth/invoke-as.ts +1 -3
  62. package/src/auth/operator.ts +8 -26
  63. package/src/auth/planes.ts +2 -7
  64. package/src/auth/plugin.ts +4 -7
  65. package/src/auth/roles.ts +1 -5
  66. package/src/auth/sessions.ts +10 -39
  67. package/src/cli/args.ts +1 -5
  68. package/src/cli/ask-dev-mode.ts +40 -0
  69. package/src/cli/build.ts +1 -2
  70. package/src/cli/client-add.test.ts +8 -15
  71. package/src/cli/client-add.ts +5 -14
  72. package/src/cli/completion.test.ts +1 -5
  73. package/src/cli/completion.ts +4 -17
  74. package/src/cli/db-auto-push.test.ts +64 -0
  75. package/src/cli/db-auto-push.ts +72 -0
  76. package/src/cli/db.test.ts +189 -0
  77. package/src/cli/db.ts +456 -0
  78. package/src/cli/dev-app-runner.ts +2 -8
  79. package/src/cli/dev-db-push.test.ts +193 -0
  80. package/src/cli/dev-mode.test.ts +45 -0
  81. package/src/cli/dev-mode.ts +78 -0
  82. package/src/cli/dev-schema-sync.test.ts +66 -0
  83. package/src/cli/dev-schema-sync.ts +139 -0
  84. package/src/cli/dev.test.ts +264 -15
  85. package/src/cli/dev.ts +355 -139
  86. package/src/cli/doc-staleness.test.ts +69 -0
  87. package/src/cli/docker-cli.test.ts +27 -8
  88. package/src/cli/docker.ts +11 -3
  89. package/src/cli/doctor-diff.test.ts +1 -5
  90. package/src/cli/doctor-diff.ts +17 -46
  91. package/src/cli/doctor-pii.ts +2 -7
  92. package/src/cli/doctor.test.ts +26 -4
  93. package/src/cli/doctor.ts +35 -11
  94. package/src/cli/drizzle-env.test.ts +67 -0
  95. package/src/cli/drizzle-env.ts +78 -0
  96. package/src/cli/ensure-drizzle-config.ts +50 -0
  97. package/src/cli/eval.ts +4 -14
  98. package/src/cli/gates-list.ts +1 -4
  99. package/src/cli/hero-meta.test.ts +17 -19
  100. package/src/cli/hero-meta.ts +20 -30
  101. package/src/cli/images.ts +3 -8
  102. package/src/cli/index.ts +11 -2
  103. package/src/cli/load-config.images.test.ts +14 -14
  104. package/src/cli/load-config.ts +47 -47
  105. package/src/cli/mcp-from-console.ts +1 -4
  106. package/src/cli/mode.ts +65 -0
  107. package/src/cli/openbao-bootstrap.test.ts +147 -0
  108. package/src/cli/openbao-bootstrap.ts +280 -0
  109. package/src/cli/openbao-restart.integration.test.ts +136 -0
  110. package/src/cli/ports.test.ts +7 -14
  111. package/src/cli/ports.ts +7 -5
  112. package/src/cli/privacy-erase.ts +1 -3
  113. package/src/cli/registry.ts +75 -25
  114. package/src/cli/resolve-dev-sql-env.test.ts +48 -0
  115. package/src/cli/resolve-dev-sql-env.ts +42 -0
  116. package/src/cli/schema.ts +3 -10
  117. package/src/cli/stack.ts +8 -10
  118. package/src/cli/start.ts +4 -15
  119. package/src/cli/upgrade.ts +1 -4
  120. package/src/cli/vault-cmd.ts +63 -0
  121. package/src/client/budget-entry.ts +1 -6
  122. package/src/client/create.test.ts +6 -12
  123. package/src/client/create.ts +2 -8
  124. package/src/client/errors.ts +1 -4
  125. package/src/client/index.ts +1 -6
  126. package/src/client/notes-contract.test.ts +4 -13
  127. package/src/client/transport.ts +9 -30
  128. package/src/client/types.ts +15 -30
  129. package/src/compiler/aot.test.ts +2 -9
  130. package/src/compiler/aot.ts +1 -4
  131. package/src/compiler/differential.test.ts +3 -11
  132. package/src/compiler/dynamic.ts +1 -4
  133. package/src/compiler/effects-infer.ts +8 -34
  134. package/src/compiler/emit.ts +1 -3
  135. package/src/compiler/extract.test.ts +136 -30
  136. package/src/compiler/extract.ts +485 -157
  137. package/src/compiler/fixtures/skyport/oke.config.ts +3 -3
  138. package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +7 -3
  139. package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +1 -3
  140. package/src/compiler/fixtures/skyport/src/flows/support/index.ts +4 -1
  141. package/src/compiler/fixtures/skyport.expected.json +24 -83
  142. package/src/compiler/fixtures/triggers/five-triggers.ts +1 -2
  143. package/src/compiler/http-parse.ts +2 -9
  144. package/src/compiler/index.ts +1 -5
  145. package/src/compiler/response.ts +16 -7
  146. package/src/compiler/sucrose.ts +11 -31
  147. package/src/config/define-config.test.ts +55 -34
  148. package/src/config/index.ts +177 -46
  149. package/src/config/resolve-driver.test.ts +28 -17
  150. package/src/console/budget.test.ts +1 -4
  151. package/src/console/index.ts +1 -4
  152. package/src/console/server/access.test.ts +15 -43
  153. package/src/console/server/access.ts +19 -49
  154. package/src/console/server/ai.test.ts +3 -11
  155. package/src/console/server/ai.ts +23 -46
  156. package/src/console/server/app.ts +16 -45
  157. package/src/console/server/auth-rate.test.ts +4 -12
  158. package/src/console/server/bind.ts +1 -5
  159. package/src/console/server/channels.test.ts +2 -6
  160. package/src/console/server/channels.ts +10 -35
  161. package/src/console/server/claim.ts +2 -8
  162. package/src/console/server/clock.test.ts +2 -6
  163. package/src/console/server/clock.ts +8 -26
  164. package/src/console/server/console.test.ts +1 -3
  165. package/src/console/server/diff.test.ts +5 -17
  166. package/src/console/server/diff.ts +10 -31
  167. package/src/console/server/dry-run.audit.test.ts +2 -8
  168. package/src/console/server/flows.ts +64 -233
  169. package/src/console/server/gates.test.ts +14 -50
  170. package/src/console/server/gates.ts +13 -48
  171. package/src/console/server/index.ts +2 -9
  172. package/src/console/server/live.ts +3 -12
  173. package/src/console/server/operator-db.test.ts +4 -15
  174. package/src/console/server/operator-db.ts +13 -32
  175. package/src/console/server/plugin.ts +50 -53
  176. package/src/console/server/plugins.test.ts +2 -6
  177. package/src/console/server/plugins.ts +17 -56
  178. package/src/console/server/runs-pii.ts +2 -7
  179. package/src/console/server/security.gate.test.ts +18 -40
  180. package/src/console/server/serve.ts +10 -25
  181. package/src/console/server/signals.test.ts +1 -3
  182. package/src/console/server/signals.ts +17 -40
  183. package/src/console/server/state.ts +21 -59
  184. package/src/console/server/store.test.ts +20 -22
  185. package/src/console/server/store.ts +31 -76
  186. package/src/console/server/vault.test.ts +12 -29
  187. package/src/console/server/vault.ts +44 -66
  188. package/src/console/ui/access/AccessA11yView.tsx +6 -21
  189. package/src/console/ui/access/a11y.test.tsx +3 -12
  190. package/src/console/ui/access/acknowledgement.test.ts +1 -4
  191. package/src/console/ui/access/acknowledgement.ts +1 -3
  192. package/src/console/ui/access/blast-radius.ts +1 -3
  193. package/src/console/ui/access/confirmation.test.ts +1 -5
  194. package/src/console/ui/access/confirmation.ts +1 -4
  195. package/src/console/ui/access/fixture.ts +1 -5
  196. package/src/console/ui/access/grantable.test.ts +1 -3
  197. package/src/console/ui/access/grantable.ts +2 -7
  198. package/src/console/ui/access/index.ts +2 -9
  199. package/src/console/ui/access/provenance.test.ts +1 -3
  200. package/src/console/ui/access/provenance.ts +2 -6
  201. package/src/console/ui/access/search.test.ts +1 -5
  202. package/src/console/ui/access/search.ts +2 -6
  203. package/src/console/ui/ai/AiA11yView.tsx +6 -17
  204. package/src/console/ui/ai/a11y.test.tsx +2 -5
  205. package/src/console/ui/ai/fixture.ts +2 -7
  206. package/src/console/ui/ai/format.ts +1 -3
  207. package/src/console/ui/ai/group.test.ts +1 -3
  208. package/src/console/ui/ai/group.ts +4 -12
  209. package/src/console/ui/ai/index.ts +2 -9
  210. package/src/console/ui/ai/promotion.test.ts +2 -7
  211. package/src/console/ui/ai/promotion.ts +4 -13
  212. package/src/console/ui/ai/search.test.ts +2 -11
  213. package/src/console/ui/ai/search.ts +3 -13
  214. package/src/console/ui/ai/types.ts +1 -8
  215. package/src/console/ui/architecture/ArchitectureA11yView.tsx +8 -29
  216. package/src/console/ui/architecture/a11y.test.tsx +1 -2
  217. package/src/console/ui/architecture/declared.ts +1 -5
  218. package/src/console/ui/architecture/index.ts +7 -35
  219. package/src/console/ui/architecture/layout.ts +1 -3
  220. package/src/console/ui/architecture/pathologies.ts +10 -19
  221. package/src/console/ui/architecture/search.ts +6 -15
  222. package/src/console/ui/architecture/traffic.ts +4 -14
  223. package/src/console/ui/architecture/types.ts +2 -10
  224. package/src/console/ui/architecture/view.test.ts +7 -19
  225. package/src/console/ui/architecture/view.ts +9 -36
  226. package/src/console/ui/channels/ChannelsA11yView.tsx +4 -13
  227. package/src/console/ui/channels/a11y.test.tsx +1 -2
  228. package/src/console/ui/channels/confirmation.test.ts +1 -4
  229. package/src/console/ui/channels/confirmation.ts +1 -4
  230. package/src/console/ui/channels/findings.ts +1 -5
  231. package/src/console/ui/channels/index.ts +2 -8
  232. package/src/console/ui/channels/locale.test.ts +1 -3
  233. package/src/console/ui/channels/locale.ts +2 -8
  234. package/src/console/ui/channels/search.ts +4 -13
  235. package/src/console/ui/channels/taxonomy.ts +1 -3
  236. package/src/console/ui/clock/ClockA11yView.tsx +9 -26
  237. package/src/console/ui/clock/a11y.test.tsx +2 -5
  238. package/src/console/ui/clock/confirmation.test.ts +1 -3
  239. package/src/console/ui/clock/confirmation.ts +1 -4
  240. package/src/console/ui/clock/findings.ts +1 -4
  241. package/src/console/ui/clock/health.ts +2 -7
  242. package/src/console/ui/clock/index.ts +2 -10
  243. package/src/console/ui/clock/search.test.ts +1 -3
  244. package/src/console/ui/clock/search.ts +2 -6
  245. package/src/console/ui/clock/timeline.test.ts +1 -3
  246. package/src/console/ui/clock/waiting-on.test.ts +1 -5
  247. package/src/console/ui/clock/waiting-on.ts +2 -7
  248. package/src/console/ui/diff/DiffA11yView.tsx +8 -17
  249. package/src/console/ui/diff/a11y.test.tsx +2 -5
  250. package/src/console/ui/diff/group.test.ts +3 -13
  251. package/src/console/ui/diff/group.ts +2 -8
  252. package/src/console/ui/diff/index.ts +2 -8
  253. package/src/console/ui/diff/search.test.ts +1 -5
  254. package/src/console/ui/diff/search.ts +4 -16
  255. package/src/console/ui/diff/summary.ts +1 -2
  256. package/src/console/ui/dist/assets/{index-Dy4jht9P.js → index-BWo8R7NR.js} +2 -2
  257. package/src/console/ui/dist/assets/{panel-access-Dd37LU2c.js → panel-access-C0J2D-a2.js} +1 -1
  258. package/src/console/ui/dist/assets/{panel-ai-CC7LR6-J.js → panel-ai-D_m6WQI8.js} +1 -1
  259. package/src/console/ui/dist/assets/{panel-architecture-B5b3iKCz.js → panel-architecture-CKnXFyUx.js} +1 -1
  260. package/src/console/ui/dist/assets/{panel-channels-CeNjTKXp.js → panel-channels-BOmQ-onL.js} +1 -1
  261. package/src/console/ui/dist/assets/{panel-clock-DgFTLoHV.js → panel-clock-giAq0Ccv.js} +1 -1
  262. package/src/console/ui/dist/assets/{panel-diff-DxehccqB.js → panel-diff-cdonmH8c.js} +1 -1
  263. package/src/console/ui/dist/assets/{panel-flows-BtrVn-Eg.js → panel-flows-DlCU5zjA.js} +2 -2
  264. package/src/console/ui/dist/assets/{panel-gates-Z9MKRGdH.js → panel-gates-XclZxWD5.js} +1 -1
  265. package/src/console/ui/dist/assets/{panel-overview-Dt_AeXgd.js → panel-overview-BznEOTnb.js} +1 -1
  266. package/src/console/ui/dist/assets/{panel-plugins-DWd0TowH.js → panel-plugins-CcGM1g64.js} +1 -1
  267. package/src/console/ui/dist/assets/{panel-runs-DGstFHeq.js → panel-runs-CGWNHLR4.js} +1 -1
  268. package/src/console/ui/dist/assets/{panel-signals-DzEa2Fnt.js → panel-signals-CNywkdak.js} +1 -1
  269. package/src/console/ui/dist/assets/{panel-store-BJkbNgxx.js → panel-store-KmTbFHMH.js} +1 -1
  270. package/src/console/ui/dist/assets/{panel-traces-BaRVO3gM.js → panel-traces-DBLx2ilD.js} +1 -1
  271. package/src/console/ui/dist/assets/panel-vault-CEnFc0dk.js +1 -0
  272. package/src/console/ui/dist/index.html +1 -1
  273. package/src/console/ui/flows/FlowsA11yView.tsx +7 -22
  274. package/src/console/ui/flows/a11y.test.tsx +2 -8
  275. package/src/console/ui/flows/buffer.test.ts +3 -11
  276. package/src/console/ui/flows/buffer.ts +4 -11
  277. package/src/console/ui/flows/confirmation.ts +1 -3
  278. package/src/console/ui/flows/contract.test.ts +3 -7
  279. package/src/console/ui/flows/contract.ts +12 -36
  280. package/src/console/ui/flows/graph.test.ts +3 -11
  281. package/src/console/ui/flows/graph.ts +5 -15
  282. package/src/console/ui/flows/index.ts +1 -6
  283. package/src/console/ui/flows/save-as-test.ts +1 -3
  284. package/src/console/ui/flows/search.ts +8 -25
  285. package/src/console/ui/flows/tiers.ts +2 -9
  286. package/src/console/ui/gates/GatesA11yView.tsx +4 -13
  287. package/src/console/ui/gates/a11y.test.tsx +2 -5
  288. package/src/console/ui/gates/audit.ts +1 -3
  289. package/src/console/ui/gates/denial.test.ts +1 -3
  290. package/src/console/ui/gates/denial.ts +4 -12
  291. package/src/console/ui/gates/findings.ts +1 -3
  292. package/src/console/ui/gates/group.test.ts +3 -3
  293. package/src/console/ui/gates/group.ts +3 -11
  294. package/src/console/ui/gates/index.ts +2 -10
  295. package/src/console/ui/gates/search.ts +3 -10
  296. package/src/console/ui/overview/OverviewA11yView.tsx +9 -27
  297. package/src/console/ui/overview/a11y.test.tsx +1 -2
  298. package/src/console/ui/overview/busiest.ts +1 -3
  299. package/src/console/ui/overview/compose.ts +1 -13
  300. package/src/console/ui/overview/cost.ts +34 -38
  301. package/src/console/ui/overview/fixture.ts +21 -26
  302. package/src/console/ui/overview/golden.ts +4 -14
  303. package/src/console/ui/overview/index.ts +2 -9
  304. package/src/console/ui/overview/rank.test.ts +3 -10
  305. package/src/console/ui/overview/rank.ts +2 -7
  306. package/src/console/ui/overview/slo.test.ts +5 -9
  307. package/src/console/ui/overview/slo.ts +6 -23
  308. package/src/console/ui/overview/verdict.ts +3 -10
  309. package/src/console/ui/plugins/PluginsA11yView.tsx +8 -18
  310. package/src/console/ui/plugins/a11y.test.tsx +1 -2
  311. package/src/console/ui/plugins/fixture.ts +2 -4
  312. package/src/console/ui/plugins/group.test.ts +1 -3
  313. package/src/console/ui/plugins/group.ts +1 -6
  314. package/src/console/ui/plugins/index.ts +3 -13
  315. package/src/console/ui/plugins/search.ts +7 -19
  316. package/src/console/ui/runs/RunsA11yView.tsx +5 -20
  317. package/src/console/ui/runs/a11y.test.tsx +2 -5
  318. package/src/console/ui/runs/explain.ts +2 -6
  319. package/src/console/ui/runs/group.ts +3 -12
  320. package/src/console/ui/runs/histogram.test.ts +2 -11
  321. package/src/console/ui/runs/histogram.ts +1 -4
  322. package/src/console/ui/runs/index.ts +4 -18
  323. package/src/console/ui/runs/project.ts +2 -6
  324. package/src/console/ui/runs/query.test.ts +1 -3
  325. package/src/console/ui/runs/query.ts +12 -35
  326. package/src/console/ui/runs/search.ts +5 -19
  327. package/src/console/ui/runs/trace-link.test.ts +2 -6
  328. package/src/console/ui/runs/trace-link.ts +4 -16
  329. package/src/console/ui/runs/types.ts +1 -3
  330. package/src/console/ui/shell/App.tsx +2 -10
  331. package/src/console/ui/shell/client.ts +22 -115
  332. package/src/console/ui/shell/components/ui.tsx +1 -4
  333. package/src/console/ui/shell/layout/Shell.tsx +2 -4
  334. package/src/console/ui/shell/main.tsx +31 -96
  335. package/src/console/ui/shell/panels/access/AccessPanel.tsx +34 -98
  336. package/src/console/ui/shell/panels/ai/AiPanel.tsx +35 -106
  337. package/src/console/ui/shell/panels/architecture/ArchitecturePanel.tsx +18 -66
  338. package/src/console/ui/shell/panels/channels/ChannelsPanel.tsx +20 -57
  339. package/src/console/ui/shell/panels/clock/ClockPanel.tsx +22 -54
  340. package/src/console/ui/shell/panels/diff/DiffPanel.tsx +20 -61
  341. package/src/console/ui/shell/panels/flows/ContractEditor.tsx +6 -23
  342. package/src/console/ui/shell/panels/flows/FlowDrawer.tsx +13 -28
  343. package/src/console/ui/shell/panels/flows/FlowsPanel.tsx +9 -29
  344. package/src/console/ui/shell/panels/gates/GatesPanel.tsx +24 -80
  345. package/src/console/ui/shell/panels/overview/OverviewPanel.tsx +20 -58
  346. package/src/console/ui/shell/panels/plugins/PluginsPanel.tsx +16 -41
  347. package/src/console/ui/shell/panels/runs/RunsPanel.tsx +31 -99
  348. package/src/console/ui/shell/panels/signals/SignalsPanel.tsx +38 -101
  349. package/src/console/ui/shell/panels/store/StorePanel.tsx +27 -66
  350. package/src/console/ui/shell/panels/traces/TracesPanel.tsx +28 -89
  351. package/src/console/ui/shell/panels/vault/VaultPanel.tsx +22 -53
  352. package/src/console/ui/shell/setup/Wizard.tsx +3 -5
  353. package/src/console/ui/shell/styles.css +1 -2
  354. package/src/console/ui/signals/SignalsA11yView.tsx +9 -33
  355. package/src/console/ui/signals/a11y.test.tsx +2 -5
  356. package/src/console/ui/signals/confirmation.test.ts +1 -5
  357. package/src/console/ui/signals/confirmation.ts +2 -6
  358. package/src/console/ui/signals/dry-run.ts +1 -3
  359. package/src/console/ui/signals/durable.ts +1 -3
  360. package/src/console/ui/signals/findings.ts +1 -3
  361. package/src/console/ui/signals/group.test.ts +2 -8
  362. package/src/console/ui/signals/group.ts +2 -10
  363. package/src/console/ui/signals/index.ts +1 -4
  364. package/src/console/ui/signals/monitor.ts +2 -7
  365. package/src/console/ui/signals/schema-form.test.ts +3 -14
  366. package/src/console/ui/signals/schema-form.ts +1 -4
  367. package/src/console/ui/signals/search.ts +4 -13
  368. package/src/console/ui/store/StoreA11yView.tsx +3 -9
  369. package/src/console/ui/store/a11y.test.tsx +2 -5
  370. package/src/console/ui/store/confirmation.test.ts +1 -3
  371. package/src/console/ui/store/confirmation.ts +1 -4
  372. package/src/console/ui/store/dry-run.ts +2 -5
  373. package/src/console/ui/store/fixture.ts +1 -2
  374. package/src/console/ui/store/group.test.ts +1 -6
  375. package/src/console/ui/store/group.ts +1 -4
  376. package/src/console/ui/store/index.ts +1 -5
  377. package/src/console/ui/store/search.ts +2 -6
  378. package/src/console/ui/store/will-not-fire.ts +1 -2
  379. package/src/console/ui/traces/TracesA11yView.tsx +10 -29
  380. package/src/console/ui/traces/a11y.test.tsx +1 -2
  381. package/src/console/ui/traces/chain.test.ts +5 -19
  382. package/src/console/ui/traces/chain.ts +1 -3
  383. package/src/console/ui/traces/critical-path.test.ts +1 -3
  384. package/src/console/ui/traces/critical-path.ts +2 -6
  385. package/src/console/ui/traces/filter.test.ts +2 -6
  386. package/src/console/ui/traces/filter.ts +5 -13
  387. package/src/console/ui/traces/fold.test.ts +4 -12
  388. package/src/console/ui/traces/fold.ts +1 -3
  389. package/src/console/ui/traces/mini.ts +1 -3
  390. package/src/console/ui/traces/replay.test.ts +1 -3
  391. package/src/console/ui/traces/replay.ts +1 -3
  392. package/src/console/ui/traces/sampling.ts +1 -4
  393. package/src/console/ui/traces/search.ts +4 -17
  394. package/src/console/ui/traces/tier.ts +1 -3
  395. package/src/console/ui/vault/VaultA11yView.tsx +5 -17
  396. package/src/console/ui/vault/a11y.test.tsx +1 -2
  397. package/src/console/ui/vault/blast-radius.ts +1 -3
  398. package/src/console/ui/vault/confirmation.test.ts +1 -5
  399. package/src/console/ui/vault/confirmation.ts +1 -4
  400. package/src/console/ui/vault/dormant.test.ts +1 -4
  401. package/src/console/ui/vault/export-safe.test.ts +1 -5
  402. package/src/console/ui/vault/export-safe.ts +1 -4
  403. package/src/console/ui/vault/fixture.ts +3 -3
  404. package/src/console/ui/vault/group.ts +1 -2
  405. package/src/console/ui/vault/index.ts +2 -10
  406. package/src/console/ui/vault/search.ts +2 -6
  407. package/src/console/ui/vault/types.ts +1 -1
  408. package/src/console/xss.gate.test.ts +1 -3
  409. package/src/docker/compose.ts +215 -27
  410. package/src/docker/derive.ts +6 -14
  411. package/src/docker/docker.test.ts +118 -15
  412. package/src/docker/dockerfile.integration.test.ts +12 -21
  413. package/src/docker/helpers.ts +5 -4
  414. package/src/docker/index.ts +9 -6
  415. package/src/docker/pin.ts +1 -9
  416. package/src/docker/recipes/index.ts +6 -6
  417. package/src/docker/recipes/mailpit.ts +22 -0
  418. package/src/docker/recipes/openbao.ts +47 -0
  419. package/src/docker/recipes/postgres.ts +17 -6
  420. package/src/docker/recipes/redis.ts +11 -2
  421. package/src/docker/recipes/rustfs.ts +32 -0
  422. package/src/docker/stack-id.test.ts +73 -5
  423. package/src/docker/stack-id.ts +124 -33
  424. package/src/docker/stack.integration.test.ts +6 -21
  425. package/src/docker/stack.ts +36 -4
  426. package/src/docker/types.ts +16 -4
  427. package/src/docs-origin.ts +4 -4
  428. package/src/drivers/ai-anthropic.ts +5 -14
  429. package/src/drivers/ai-mock.ts +2 -5
  430. package/src/drivers/ai-openai-compatible.ts +4 -10
  431. package/src/drivers/ai-providers.test.ts +6 -13
  432. package/src/drivers/bun-native-completeness.test.ts +6 -15
  433. package/src/drivers/channel-console.ts +6 -7
  434. package/src/drivers/channel-fcm.ts +20 -30
  435. package/src/drivers/channel-resend.ts +1 -3
  436. package/src/drivers/channel-smtp.ts +2 -6
  437. package/src/drivers/channel-types.ts +2 -12
  438. package/src/drivers/channel-unifonic.ts +2 -6
  439. package/src/drivers/channel-wa-cloud.ts +2 -6
  440. package/src/drivers/channel-webpush.ts +21 -60
  441. package/src/drivers/conformance.test.ts +2 -10
  442. package/src/drivers/conformance.ts +8 -21
  443. package/src/drivers/drizzle-dialect.test.ts +20 -0
  444. package/src/drivers/drizzle-dialect.ts +37 -0
  445. package/src/drivers/fs.ts +2 -8
  446. package/src/drivers/index.ts +12 -57
  447. package/src/drivers/memory.ts +287 -75
  448. package/src/drivers/pgvector.ts +7 -11
  449. package/src/drivers/postgres.ts +7 -13
  450. package/src/drivers/redis.ts +13 -37
  451. package/src/drivers/s3.ts +15 -18
  452. package/src/drivers/signal-engine.ts +12 -49
  453. package/src/drivers/signal-memory.ts +2 -8
  454. package/src/drivers/signal-nats.ts +4 -9
  455. package/src/drivers/signal-postgres.ts +62 -129
  456. package/src/drivers/signal-redis.ts +7 -21
  457. package/src/drivers/signal-types.ts +1 -4
  458. package/src/drivers/sqlite.ts +3 -12
  459. package/src/drivers/types.ts +4 -23
  460. package/src/drivers/vault-driver-removal.test.ts +55 -0
  461. package/src/drivers/vault-env.ts +2 -6
  462. package/src/drivers/vault-infisical.ts +1 -5
  463. package/src/drivers/vault-managed.ts +1 -5
  464. package/src/drivers/vault-memory.ts +1 -5
  465. package/src/drivers/vault-openbao.test.ts +97 -0
  466. package/src/drivers/vault-openbao.ts +103 -40
  467. package/src/drivers/vault-types.ts +3 -16
  468. package/src/elements/ai/declare.ts +4 -14
  469. package/src/elements/ai/eval.ts +2 -6
  470. package/src/elements/ai/pii.ts +1 -3
  471. package/src/elements/ai/runtime.ts +12 -50
  472. package/src/elements/ai/schema.ts +4 -15
  473. package/src/elements/ai.test.ts +13 -24
  474. package/src/elements/ai.ts +1 -5
  475. package/src/elements/channel/consent.ts +3 -12
  476. package/src/elements/channel/costs.ts +4 -15
  477. package/src/elements/channel/declare.ts +1 -4
  478. package/src/elements/channel/email-auth.ts +1 -4
  479. package/src/elements/channel/locale.ts +2 -10
  480. package/src/elements/channel/mask.ts +1 -3
  481. package/src/elements/channel/mime.ts +2 -12
  482. package/src/elements/channel/outcomes.test.ts +1 -5
  483. package/src/elements/channel/outcomes.ts +5 -15
  484. package/src/elements/channel/receipts.ts +2 -7
  485. package/src/elements/channel/runtime.ts +28 -74
  486. package/src/elements/channel/suppression.ts +8 -14
  487. package/src/elements/channel.test.ts +8 -31
  488. package/src/elements/channel.ts +3 -14
  489. package/src/elements/clock/actions.ts +6 -18
  490. package/src/elements/clock/declare.ts +1 -3
  491. package/src/elements/clock/dst.ts +1 -5
  492. package/src/elements/clock/durable.ts +4 -16
  493. package/src/elements/clock/health.ts +2 -7
  494. package/src/elements/clock/leader.ts +2 -9
  495. package/src/elements/clock/reconcile.ts +4 -15
  496. package/src/elements/clock/runtime.ts +2 -5
  497. package/src/elements/clock/schedule.ts +4 -20
  498. package/src/elements/clock.test.ts +2 -7
  499. package/src/elements/clock.ts +5 -23
  500. package/src/elements/gate/permissions.ts +1 -4
  501. package/src/elements/gate/runtime.ts +7 -28
  502. package/src/elements/gate.ts +1 -5
  503. package/src/elements/index.ts +9 -7
  504. package/src/elements/signal/declare.ts +2 -7
  505. package/src/elements/signal/reconcile.test.ts +1 -4
  506. package/src/elements/signal/runtime.ts +1 -3
  507. package/src/elements/signal.test.ts +3 -15
  508. package/src/elements/signal.ts +2 -8
  509. package/src/elements/store/cache.test.ts +46 -0
  510. package/src/elements/store/cache.ts +3 -11
  511. package/src/elements/store/classify.ts +5 -22
  512. package/src/elements/store/declare.ts +11 -17
  513. package/src/elements/store/domain-ddl.test.ts +86 -0
  514. package/src/elements/store/emit-drizzle.ts +363 -0
  515. package/src/elements/store/files-policy.test.ts +1 -5
  516. package/src/elements/store/files-policy.ts +4 -12
  517. package/src/elements/store/load-plugin-tables.ts +103 -0
  518. package/src/elements/store/missing-relation.test.ts +83 -0
  519. package/src/elements/store/missing-relation.ts +38 -0
  520. package/src/elements/store/replica.ts +1 -4
  521. package/src/elements/store/resource-list-docs.fixture.ts +56 -0
  522. package/src/elements/store/resource-list-docs.test.ts +79 -0
  523. package/src/elements/store/resource.test.ts +253 -0
  524. package/src/elements/store/resource.ts +786 -0
  525. package/src/elements/store/runtime.ts +25 -28
  526. package/src/elements/store/schema-decl.test.ts +227 -0
  527. package/src/elements/store/schema-decl.ts +516 -0
  528. package/src/elements/store/sql-condition.test.ts +132 -0
  529. package/src/elements/store/sql-condition.ts +293 -65
  530. package/src/elements/store/sql-session.test.ts +135 -0
  531. package/src/elements/store/sql-session.ts +241 -84
  532. package/src/elements/store/table.ts +69 -23
  533. package/src/elements/store.test.ts +17 -39
  534. package/src/elements/store.ts +53 -31
  535. package/src/elements/vault/chain.ts +34 -0
  536. package/src/elements/vault/declare.ts +22 -32
  537. package/src/elements/vault/fingerprint.ts +2 -7
  538. package/src/elements/vault/redact.ts +2 -6
  539. package/src/elements/vault/runtime.ts +19 -33
  540. package/src/elements/vault.test.ts +12 -55
  541. package/src/elements/vault.ts +9 -13
  542. package/src/index.ts +5 -2
  543. package/src/kernel/adopt-routes.ts +15 -29
  544. package/src/kernel/app.ts +92 -118
  545. package/src/kernel/auth-resolve.ts +2 -9
  546. package/src/kernel/boot-bind/ai.ts +1 -4
  547. package/src/kernel/boot-bind/channel.test.ts +60 -0
  548. package/src/kernel/boot-bind/channel.ts +61 -5
  549. package/src/kernel/boot-bind/clock.ts +2 -6
  550. package/src/kernel/boot-bind/gate.ts +2 -8
  551. package/src/kernel/boot-bind/runs.ts +1 -3
  552. package/src/kernel/boot-bind/signal.ts +3 -10
  553. package/src/kernel/boot-bind/store.test.ts +27 -18
  554. package/src/kernel/boot-bind/store.ts +93 -52
  555. package/src/kernel/boot-bind/vault.ts +2 -8
  556. package/src/kernel/boot.test.ts +4 -10
  557. package/src/kernel/boot.ts +30 -77
  558. package/src/kernel/budget.test.ts +1 -3
  559. package/src/kernel/capability.ts +3 -10
  560. package/src/kernel/dry-run.test.ts +1 -4
  561. package/src/kernel/dry-run.ts +3 -11
  562. package/src/kernel/edge.test.ts +68 -0
  563. package/src/kernel/effects.test.ts +1 -5
  564. package/src/kernel/effects.ts +4 -11
  565. package/src/kernel/errors.registry.test.ts +2 -8
  566. package/src/kernel/errors.ts +23 -32
  567. package/src/kernel/flow.test.ts +12 -25
  568. package/src/kernel/flow.ts +13 -25
  569. package/src/kernel/fx.test.ts +31 -40
  570. package/src/kernel/fx.ts +135 -90
  571. package/src/kernel/hook-timing.test.ts +3 -6
  572. package/src/kernel/hook-timing.ts +5 -14
  573. package/src/kernel/hooks.test.ts +43 -10
  574. package/src/kernel/hooks.ts +25 -12
  575. package/src/kernel/index.ts +11 -17
  576. package/src/kernel/journal.ts +7 -31
  577. package/src/kernel/on.ts +45 -9
  578. package/src/kernel/pipeline.test.ts +10 -19
  579. package/src/kernel/pipeline.ts +5 -17
  580. package/src/kernel/plug.ts +4 -11
  581. package/src/kernel/plugin/conflicts.test.ts +13 -25
  582. package/src/kernel/plugin/decorate.test.ts +8 -13
  583. package/src/kernel/plugin/scoping.test.ts +4 -11
  584. package/src/kernel/plugin.ts +81 -27
  585. package/src/kernel/registry-isolation.test.ts +74 -0
  586. package/src/kernel/registry.ts +102 -30
  587. package/src/kernel/router.test.ts +15 -13
  588. package/src/kernel/router.ts +9 -29
  589. package/src/kernel/routing-budget.test.ts +1 -3
  590. package/src/kernel/run-telemetry.ts +1 -3
  591. package/src/kernel/triggers.ts +63 -21
  592. package/src/manifest/diff.test.ts +26 -91
  593. package/src/manifest/diff.ts +95 -225
  594. package/src/manifest/fixtures/skyport.excerpt.json +1 -1
  595. package/src/manifest/fixtures/skyport.manifest.json +1 -1
  596. package/src/manifest/index.ts +3 -10
  597. package/src/manifest/types.ts +30 -6
  598. package/src/manifest/undeclared.test.ts +4 -12
  599. package/src/manifest/undeclared.ts +1 -2
  600. package/src/manifest/validate.test.ts +2 -6
  601. package/src/manifest/validate.ts +5 -15
  602. package/src/mcp/authorization.ts +8 -27
  603. package/src/mcp/confirmation.ts +3 -10
  604. package/src/mcp/data.ts +2 -6
  605. package/src/mcp/docs-index.ts +4 -7
  606. package/src/mcp/docs-mcp.test.ts +3 -12
  607. package/src/mcp/docs-server.ts +7 -27
  608. package/src/mcp/docs-tools.ts +2 -6
  609. package/src/mcp/index.ts +1 -6
  610. package/src/mcp/injection.gate.test.ts +4 -18
  611. package/src/mcp/mcp.test.ts +18 -49
  612. package/src/mcp/protocol.ts +3 -10
  613. package/src/mcp/server.ts +11 -52
  614. package/src/mcp/session.ts +4 -14
  615. package/src/mcp/tools.ts +14 -50
  616. package/src/plugins/catalogue.test.ts +3 -7
  617. package/src/plugins/catalogue.ts +1 -3
  618. package/src/plugins/compression.test.ts +127 -0
  619. package/src/plugins/compression.ts +94 -0
  620. package/src/plugins/config-source.test.ts +204 -0
  621. package/src/plugins/config-source.ts +209 -0
  622. package/src/plugins/cors.test.ts +138 -0
  623. package/src/plugins/cors.ts +129 -0
  624. package/src/plugins/csrf.test.ts +102 -0
  625. package/src/plugins/csrf.ts +86 -0
  626. package/src/plugins/headers.ts +54 -0
  627. package/src/plugins/index.ts +26 -0
  628. package/src/plugins/ip-allowlist.test.ts +105 -0
  629. package/src/plugins/ip-allowlist.ts +76 -0
  630. package/src/plugins/maintenance-mode.test.ts +91 -0
  631. package/src/plugins/maintenance-mode.ts +85 -0
  632. package/src/plugins/node-import-scan.ts +2 -5
  633. package/src/plugins/security-headers.test.ts +243 -0
  634. package/src/plugins/security-headers.ts +255 -0
  635. package/src/plugins/supply-chain.ts +5 -17
  636. package/src/release/exports.ts +3 -8
  637. package/src/release/measure.exports.test.ts +1 -3
  638. package/src/release/measure.ts +16 -45
  639. package/src/runs/bench.test.ts +1 -3
  640. package/src/runs/collect.ts +8 -25
  641. package/src/runs/drivers/clickhouse.ts +2 -9
  642. package/src/runs/drivers/files.ts +9 -31
  643. package/src/runs/drivers/memory.ts +5 -22
  644. package/src/runs/drivers/postgres.ts +8 -20
  645. package/src/runs/duckdb.ts +2 -8
  646. package/src/runs/index.ts +3 -14
  647. package/src/runs/outlier.ts +3 -10
  648. package/src/runs/parquet.ts +8 -26
  649. package/src/runs/privacy.ts +2 -8
  650. package/src/runs/runs.test.ts +3 -9
  651. package/src/runs/runtime.ts +7 -32
  652. package/src/runs/shred.ts +10 -29
  653. package/src/runs/types.ts +1 -4
  654. package/src/runtime/bun.ts +4 -15
  655. package/src/runtime/cold-start.bench.ts +1 -3
  656. package/src/runtime/dev-request-log.test.ts +1 -4
  657. package/src/runtime/dev-request-log.ts +1 -4
  658. package/src/runtime/index.ts +1 -6
  659. package/src/runtime/primitives.ts +5 -4
  660. package/src/runtime/security.ts +3 -13
  661. package/src/runtime/serve.test.ts +4 -7
  662. package/src/runtime/types.ts +1 -4
  663. package/src/runtime/web-standard.ts +3 -15
  664. package/src/term.test.ts +4 -6
  665. package/src/term.ts +49 -98
  666. package/src/test/create-test-app.test.ts +4 -14
  667. package/src/test/create-test-app.ts +27 -33
  668. package/src/test/provisions.integration.test.ts +3 -11
  669. package/src/upgrade/codemods.test.ts +25 -6
  670. package/src/upgrade/codemods.ts +116 -3
  671. package/src/validation/standard-schema.test.ts +2 -5
  672. package/src/validation/standard-schema.ts +13 -33
  673. package/docs/spec/console.md +0 -739
  674. package/docs/spec/example.md +0 -1196
  675. package/docs/spec/four-applications.md +0 -1195
  676. package/docs/spec/unified-theory.md +0 -489
  677. package/src/cli/doc-drift.test.ts +0 -146
  678. package/src/cli/doc-drift.ts +0 -430
  679. package/src/cli/doctor-diff-examples.ts +0 -92
  680. package/src/console/ui/dist/assets/panel-vault-BbfWdox0.js +0 -1
  681. package/src/drivers/vault-sops.ts +0 -271
@@ -7,20 +7,14 @@
7
7
  */
8
8
 
9
9
  import type { Effects, FlowPlane, Slo } from "../manifest/types.ts";
10
- import type {
11
- InferSchemaOutput,
12
- SchemaInput,
13
- } from "../validation/standard-schema.ts";
10
+ import type { InferSchemaOutput, SchemaInput } from "../validation/standard-schema.ts";
14
11
  import type { FlowFailure } from "./errors.ts";
15
12
  import type { Fx } from "./fx.ts";
16
13
  import type { HookFn, HookStage } from "./hooks.ts";
17
14
  import type { PluginDef } from "./plugin.ts";
18
15
  import type { Trigger } from "./triggers.ts";
19
16
 
20
- export type {
21
- SchemaInput,
22
- StandardSchemaV1,
23
- } from "../validation/standard-schema.ts";
17
+ export type { SchemaInput, StandardSchemaV1 } from "../validation/standard-schema.ts";
24
18
 
25
19
  /** Result of a Standard Schema validate call (re-export shape). */
26
20
  export type StandardSchemaResult<Output> =
@@ -42,11 +36,7 @@ export type FlowHandler<I = unknown, O = unknown> = (
42
36
  ) => O | FlowFailure | Promise<O | FlowFailure>;
43
37
 
44
38
  /** Options for {@link flow}. */
45
- export interface FlowOptions<
46
- I = unknown,
47
- O = unknown,
48
- E extends FlowErrorMap = FlowErrorMap,
49
- > {
39
+ export interface FlowOptions<I = unknown, O = unknown, E extends FlowErrorMap = FlowErrorMap> {
50
40
  /** Optional stable name (used by `fx.call` and the Manifest). */
51
41
  readonly name?: string;
52
42
  /** Optional unit scope for unit-level hooks. */
@@ -72,6 +62,11 @@ export interface FlowOptions<
72
62
  * Cross-plane invocation is a compile error.
73
63
  */
74
64
  readonly plane?: FlowPlane;
65
+ /**
66
+ * Acknowledge intentional Manifest contract breaks for this flow
67
+ * (`oke doctor --diff` / CI gate).
68
+ */
69
+ readonly breaking?: boolean;
75
70
  /** The behavior. */
76
71
  readonly do: FlowHandler<I, O>;
77
72
  }
@@ -160,6 +155,8 @@ export interface FlowDef<
160
155
  readonly slo: Slo | undefined;
161
156
  /** Plane (user vs operator). */
162
157
  readonly plane: FlowPlane | undefined;
158
+ /** Intentional contract-break acknowledgement for Manifest Diff. */
159
+ readonly breaking: boolean;
163
160
  /** Handler body. */
164
161
  readonly do: FlowHandler<I, O>;
165
162
  /** Triggers bound via {@link on} (zero or more). */
@@ -192,13 +189,7 @@ export interface FlowDef<
192
189
  */
193
190
  plug<P extends PluginDef>(
194
191
  pluginDef: P,
195
- ): FlowDef<
196
- I,
197
- O,
198
- E,
199
- D & (P extends PluginDef<infer PD> ? PD : Record<string, never>),
200
- T
201
- >;
192
+ ): FlowDef<I, O, E, D & (P extends PluginDef<infer PD> ? PD : Record<string, never>), T>;
202
193
  }
203
194
 
204
195
  /** Unique brand symbol for {@link FlowDef}. */
@@ -222,11 +213,7 @@ export function flow<Opts extends FlowOptions<any, any, any>>(
222
213
  const hooks: Partial<Record<HookStage, HookFn[]>> = {};
223
214
  const pendingPlugins: PluginDef[] = [];
224
215
 
225
- const def: FlowDef<
226
- InferFlowIn<Opts>,
227
- InferFlowOut<Opts>,
228
- InferFlowErrors<Opts>
229
- > = {
216
+ const def: FlowDef<InferFlowIn<Opts>, InferFlowOut<Opts>, InferFlowErrors<Opts>> = {
230
217
  [flowBrand]: true,
231
218
  name,
232
219
  unit: options.unit,
@@ -239,6 +226,7 @@ export function flow<Opts extends FlowOptions<any, any, any>>(
239
226
  cache: options.cache,
240
227
  slo: options.slo,
241
228
  plane: options.plane,
229
+ breaking: options.breaking ?? false,
242
230
  do: options.do as FlowHandler<InferFlowIn<Opts>, InferFlowOut<Opts>>,
243
231
  triggers,
244
232
  $trigger: undefined,
@@ -1,16 +1,11 @@
1
1
  import { describe, expect, test } from "bun:test";
2
2
  import { createCapabilityToken } from "./capability.ts";
3
3
  import { createEffectLedger, reversibilityOf } from "./effects.ts";
4
- import {
5
- fail,
6
- formatOkeMessage,
7
- lookupOkeError,
8
- OKE_ERRORS,
9
- OkeError,
10
- } from "./errors.ts";
4
+ import { fail, formatOkeMessage, lookupOkeError, OKE_ERRORS, OkeError } from "./errors.ts";
11
5
  import {
12
6
  createFx,
13
7
  createFxContext,
8
+ jsonResultBrand,
14
9
  type Fx,
15
10
  type FxStubStoreHandle,
16
11
  } from "./fx.ts";
@@ -37,16 +32,10 @@ describe("fx — capability enforcement", () => {
37
32
  expect(err).toBeInstanceOf(OkeError);
38
33
  const oke = err as OkeError;
39
34
  expect(oke.code).toBe(1001);
40
- expect(oke.causeText).toBe(
41
- 'Flow "bookings.create" reads "sql:users" without declaring it.',
42
- );
43
- expect(oke.fix).toBe(
44
- 'Add "sql:users" to this flow\'s effects.reads.',
45
- );
46
- expect(oke.docsUrl).toBe("https://okengine.vercel.app/e/1001");
47
- expect(oke.message).toBe(
48
- formatOkeMessage(1001, oke.causeText, oke.fix, oke.docsUrl),
49
- );
35
+ expect(oke.causeText).toBe('Flow "bookings.create" reads "sql:users" without declaring it.');
36
+ expect(oke.fix).toBe('Add "sql:users" to this flow\'s effects.reads.');
37
+ expect(oke.docsUrl).toBe("https://oke.omqkhafi.dev/e/1001");
38
+ expect(oke.message).toBe(formatOkeMessage(1001, oke.causeText, oke.fix, oke.docsUrl));
50
39
  });
51
40
 
52
41
  test("declared store read succeeds", async () => {
@@ -79,21 +68,13 @@ describe("fx — effect ledger", () => {
79
68
  await fx.emit("order-placed", { orderId: "o1" });
80
69
 
81
70
  expect(ledger.entries).toHaveLength(3);
82
- expect(ledger.entries.map((e) => e.kind)).toEqual([
83
- "read",
84
- "write",
85
- "emit",
86
- ]);
71
+ expect(ledger.entries.map((e) => e.kind)).toEqual(["read", "write", "emit"]);
87
72
  expect(ledger.entries.map((e) => e.resource)).toEqual([
88
73
  "sql:bookings",
89
74
  "sql:bookings",
90
75
  "order-placed",
91
76
  ]);
92
- expect(ledger.entries.map((e) => e.reversibility)).toEqual([
93
- "none",
94
- "reversible",
95
- "deferred",
96
- ]);
77
+ expect(ledger.entries.map((e) => e.reversibility)).toEqual(["none", "reversible", "deferred"]);
97
78
  });
98
79
 
99
80
  test("all seven kinds receive the correct reversibility tier via fx", async () => {
@@ -123,15 +104,7 @@ describe("fx — effect ledger", () => {
123
104
 
124
105
  expect(ledger.entries).toHaveLength(7);
125
106
  const kinds = ledger.entries.map((e) => e.kind);
126
- expect(kinds).toEqual([
127
- "read",
128
- "write",
129
- "emit",
130
- "send",
131
- "ask",
132
- "secret",
133
- "call",
134
- ]);
107
+ expect(kinds).toEqual(["read", "write", "emit", "send", "ask", "secret", "call"]);
135
108
  for (const entry of ledger.entries) {
136
109
  expect(entry.reversibility).toBe(reversibilityOf(entry.kind));
137
110
  }
@@ -191,6 +164,20 @@ describe("fx — wholesale swap", () => {
191
164
  operator: { id: null },
192
165
  tenant: { id: "t1" },
193
166
  fail,
167
+ json: {
168
+ ok(value, opts) {
169
+ return { [jsonResultBrand]: true, status: 200, value, meta: opts?.meta };
170
+ },
171
+ create(value) {
172
+ return { [jsonResultBrand]: true, status: 201, value };
173
+ },
174
+ empty() {
175
+ return { [jsonResultBrand]: true, status: 204 };
176
+ },
177
+ with(data, meta) {
178
+ return { [jsonResultBrand]: true, status: 200, value: data, meta };
179
+ },
180
+ },
194
181
  async step(_name, fn) {
195
182
  return fn();
196
183
  },
@@ -218,15 +205,19 @@ describe("errors — registry", () => {
218
205
  });
219
206
  expect(err.message).toContain("OKE1042");
220
207
  expect(err.message).toContain("no subscriber");
221
- expect(err.message).toContain("https://okengine.vercel.app/e/1042");
208
+ expect(err.message).toContain("https://oke.omqkhafi.dev/e/1042");
222
209
  expect(err.message).toContain("→");
223
210
  });
224
211
 
225
212
  test("fx.fail returns a value, not an exception", () => {
226
213
  const fx = createFx({ flow: "x", effects: {} });
227
- const result = fx.fail("FlightFull", { seatsLeft: 0 }, {
228
- message: "full",
229
- });
214
+ const result = fx.fail(
215
+ "FlightFull",
216
+ { seatsLeft: 0 },
217
+ {
218
+ message: "full",
219
+ },
220
+ );
230
221
  expect(result).toEqual({
231
222
  data: null,
232
223
  error: { code: "FlightFull", data: { seatsLeft: 0 }, message: "full" },
package/src/kernel/fx.ts CHANGED
@@ -11,26 +11,20 @@
11
11
 
12
12
  import type { Effects, ResourceRef } from "../manifest/types.ts";
13
13
  import type {
14
+ SelectOrderBuilder,
14
15
  StoreDecl,
15
16
  StoreHandle,
16
17
  StoreRuntime,
17
18
  SqlStoreHandle,
18
19
  } from "../elements/store.ts";
20
+ import type { SqlRow } from "../drivers/types.ts";
19
21
  import type { SignalRuntime } from "../elements/signal.ts";
20
22
  import type { VaultRuntime } from "../elements/vault.ts";
21
23
  import type { ChannelRuntime } from "../elements/channel.ts";
22
24
  import type { AiRuntime } from "../elements/ai.ts";
23
25
  import { parseDurationMs } from "../elements/clock/duration.ts";
24
- import {
25
- createCapabilityToken,
26
- type CapabilityToken,
27
- } from "./capability.ts";
28
- import {
29
- createEffectLedger,
30
- recordEffect,
31
- reversibilityOf,
32
- type EffectLedger,
33
- } from "./effects.ts";
26
+ import { createCapabilityToken, type CapabilityToken } from "./capability.ts";
27
+ import { createEffectLedger, recordEffect, reversibilityOf, type EffectLedger } from "./effects.ts";
34
28
  import {
35
29
  DryRunWriteIsolationError,
36
30
  isDryRun,
@@ -196,23 +190,55 @@ export interface FxSearchOptions {
196
190
  readonly topK?: number;
197
191
  }
198
192
 
193
+ /** Brand for {@link JsonResult} (kept internal — flows never construct it). */
194
+ export const jsonResultBrand: unique symbol = Symbol.for("oke.json");
195
+
196
+ /** Carrier from {@link FxJson} — status + body read by the response encoder. */
197
+ export interface JsonResult<T = unknown> {
198
+ readonly [jsonResultBrand]: true;
199
+ readonly status: number;
200
+ readonly value?: T;
201
+ readonly meta?: Record<string, unknown>;
202
+ }
203
+
204
+ /** True when `value` is an {@link FxJson} carrier. */
205
+ export function isJsonResult(value: unknown): value is JsonResult {
206
+ return (
207
+ typeof value === "object" && value !== null && (value as JsonResult)[jsonResultBrand] === true
208
+ );
209
+ }
210
+
211
+ /**
212
+ * JSON response helpers. `fx.json.create` answers 201; `fx.json.ok` can carry
213
+ * a top-level `meta` (Stripe-style `{ data, meta?, error }`);
214
+ * `fx.json.empty` answers 204.
215
+ */
216
+ export interface FxJson {
217
+ /** 200 — body `{ data: value, meta?, error: null }`. */
218
+ ok<T>(value: T, opts?: { readonly meta?: Record<string, unknown> }): JsonResult<T>;
219
+ /** 201 — body `{ data: value, error: null }`. */
220
+ create<T>(value: T): JsonResult<T>;
221
+ /** 204 — no body. */
222
+ empty(): JsonResult<never>;
223
+ /** 200 — body `{ data, meta, error: null }` (paginated lists). */
224
+ with<T>(data: T, meta: Record<string, unknown>): JsonResult<T>;
225
+ }
226
+
199
227
  /**
200
228
  * The `fx` context object — v1 surface.
201
229
  *
202
230
  * Implementations must be plain objects so tests can replace `fx` wholesale.
203
231
  */
204
232
  export interface Fx {
205
- /**
206
- * Open a store handle for `ref` (capability checked on each op).
207
- *
208
- * When a {@link CreateFxOptions.storeRuntime} is bound and `ref` is a
209
- * registered store declaration, returns the driver-backed handle.
210
- *
211
- * @param ref - Store resource ref, named handle, or store declaration
212
- */
213
- store(
214
- ref: NamedRef | { readonly ref: ResourceRef } | StoreDecl,
215
- ): FxStoreHandle;
233
+ /**
234
+ * Open a store handle for `ref` (capability checked on each op).
235
+ *
236
+ * When a {@link CreateFxOptions.storeRuntime} is bound and `ref` is a
237
+ * registered store declaration, returns the driver-backed handle.
238
+ *
239
+ * @param ref - Store resource ref, named handle, or store declaration
240
+ */
241
+ store(ref: NamedRef | { readonly ref: ResourceRef } | StoreDecl): FxStoreHandle;
216
242
  /**
217
243
  * Emit a signal (records `emit`).
218
244
  *
@@ -251,11 +277,7 @@ export interface Fx {
251
277
  * @param input - Prompt input
252
278
  * @param opts - Model routing opts
253
279
  */
254
- ask(
255
- prompt: NamedRef,
256
- input?: unknown,
257
- opts?: FxAskOptions,
258
- ): Promise<Record<string, unknown>>;
280
+ ask(prompt: NamedRef, input?: unknown, opts?: FxAskOptions): Promise<Record<string, unknown>>;
259
281
  /**
260
282
  * Similarity search over an index/embed (records `read` on the embed ref).
261
283
  *
@@ -263,21 +285,14 @@ export interface Fx {
263
285
  * @param query - Query text or vector
264
286
  * @param opts - Search options
265
287
  */
266
- search(
267
- embed: NamedRef,
268
- query: unknown,
269
- opts?: FxSearchOptions,
270
- ): Promise<unknown[]>;
288
+ search(embed: NamedRef, query: unknown, opts?: FxSearchOptions): Promise<unknown[]>;
271
289
  /**
272
290
  * Run a bounded AI agent (records `ask`).
273
291
  *
274
292
  * @param agent - Agent name or handle
275
293
  * @param input - Agent input (`{ message }` or string)
276
294
  */
277
- run(
278
- agent: NamedRef,
279
- input?: unknown,
280
- ): Promise<unknown>;
295
+ run(agent: NamedRef, input?: unknown): Promise<unknown>;
281
296
  /**
282
297
  * Stream model tokens (records `ask`). Returns an async iterable of chunks.
283
298
  *
@@ -313,6 +328,8 @@ export interface Fx {
313
328
  * @param opts - Optional message
314
329
  */
315
330
  fail<E>(code: string, data: E, opts?: FailOptions): FlowFailure<E>;
331
+ /** JSON response helpers (status + Stripe-style envelope). */
332
+ readonly json: FxJson;
316
333
  /**
317
334
  * Named durable step — never re-runs on journal replay.
318
335
  *
@@ -326,10 +343,7 @@ export interface Fx {
326
343
  * Dispatch target for {@link Fx.call}. Wired by the app so untriggered
327
344
  * flows execute through the same pipeline as triggered ones.
328
345
  */
329
- export type FxCallHandler = (
330
- name: string,
331
- input: unknown,
332
- ) => Promise<unknown>;
346
+ export type FxCallHandler = (name: string, input: unknown) => Promise<unknown>;
333
347
 
334
348
  /** Options for {@link createFx}. */
335
349
  export interface CreateFxOptions {
@@ -352,9 +366,7 @@ export interface CreateFxOptions {
352
366
  /** Secret name → value map for `fx.vault`. */
353
367
  readonly secrets?: Readonly<Record<string, string>>;
354
368
  /** Seed data for in-memory stores: ref → key → value. */
355
- readonly storeData?: Readonly<
356
- Record<string, Readonly<Record<string, unknown>>>
357
- >;
369
+ readonly storeData?: Readonly<Record<string, Readonly<Record<string, unknown>>>>;
358
370
  /** Optional log sink (defaults to no-op). */
359
371
  readonly onLog?: (
360
372
  level: "debug" | "info" | "warn" | "error",
@@ -435,9 +447,7 @@ export function createFx(options: CreateFxOptions): Fx {
435
447
  */
436
448
  export function createFxContext(options: CreateFxOptions): FxContext {
437
449
  const ledger = options.ledger ?? createEffectLedger();
438
- const capability =
439
- options.capability ??
440
- createCapabilityToken(options.flow, options.effects);
450
+ const capability = options.capability ?? createCapabilityToken(options.flow, options.effects);
441
451
  const now = options.now ?? (() => Date.now());
442
452
  const secrets = options.secrets ?? {};
443
453
  const onLog = options.onLog;
@@ -499,15 +509,12 @@ export function createFxContext(options: CreateFxOptions): FxContext {
499
509
  select(): Promise<unknown[]> {
500
510
  return gated("read", ref, () => {
501
511
  const values = [...table().values()];
502
- return isDryRun()
503
- ? values.map((v) => structuredClone(v))
504
- : values;
512
+ return isDryRun() ? values.map((v) => structuredClone(v)) : values;
505
513
  });
506
514
  },
507
515
  insert(row: Record<string, unknown>): Promise<{ id: string }> {
508
516
  return gated("write", ref, () => {
509
- const id =
510
- typeof row.id === "string" ? row.id : crypto.randomUUID();
517
+ const id = typeof row.id === "string" ? row.id : crypto.randomUUID();
511
518
  table().set(id, { ...row, id });
512
519
  return { id };
513
520
  });
@@ -532,10 +539,7 @@ export function createFxContext(options: CreateFxOptions): FxContext {
532
539
  * @param decl - Store declaration
533
540
  * @param open - Opens (and caches) the runtime handle
534
541
  */
535
- function gatedSqlHandle(
536
- decl: StoreDecl,
537
- open: () => Promise<SqlStoreHandle>,
538
- ): SqlStoreHandle {
542
+ function gatedSqlHandle(decl: StoreDecl, open: () => Promise<SqlStoreHandle>): SqlStoreHandle {
539
543
  const ref = decl.ref as `sql:${string}`;
540
544
  let cached: SqlStoreHandle | undefined;
541
545
  const ensure = async (): Promise<SqlStoreHandle> => {
@@ -562,30 +566,53 @@ export function createFxContext(options: CreateFxOptions): FxContext {
562
566
  select(columns?) {
563
567
  return {
564
568
  from(table) {
565
- const all = gated("read", ref, async () => {
566
- const h = await ensure();
567
- return h.select(columns).from(table);
569
+ const run = (plan: {
570
+ where?: unknown;
571
+ orders?: readonly unknown[];
572
+ limit?: number;
573
+ offset?: number;
574
+ }): Promise<SqlRow[]> =>
575
+ gated("read", ref, async () => {
576
+ const h = await ensure();
577
+ const from = h.select(columns).from(table);
578
+ const filtered = plan.where === undefined ? from : from.where(plan.where);
579
+ const ordered =
580
+ plan.orders === undefined ? filtered : filtered.orderBy(...plan.orders);
581
+ if (plan.offset !== undefined) return ordered.offset(plan.offset);
582
+ return plan.limit === undefined ? ordered : ordered.limit(plan.limit);
583
+ });
584
+
585
+ const tail = (plan: {
586
+ where?: unknown;
587
+ orders?: readonly unknown[];
588
+ }): SelectOrderBuilder => ({
589
+ limit(n) {
590
+ return run({ ...plan, limit: n });
591
+ },
592
+ offset(n) {
593
+ return run({ ...plan, offset: n });
594
+ },
595
+ then(onfulfilled, onrejected) {
596
+ return run(plan).then(onfulfilled, onrejected);
597
+ },
568
598
  });
599
+
569
600
  return {
570
601
  where(where) {
571
- const filtered = gated("read", ref, async () => {
572
- const h = await ensure();
573
- return h.select(columns).from(table).where(where);
574
- });
575
602
  return {
576
- limit(n) {
577
- return gated("read", ref, async () => {
578
- const h = await ensure();
579
- return h.select(columns).from(table).where(where).limit(n);
580
- });
581
- },
582
- then(onfulfilled, onrejected) {
583
- return filtered.then(onfulfilled, onrejected);
584
- },
603
+ ...tail({ where }),
604
+ orderBy: (...orders: readonly unknown[]) => tail({ where, orders }),
585
605
  };
586
606
  },
607
+ orderBy: (...orders: readonly unknown[]) => tail({ orders }),
608
+ limit(n: number) {
609
+ return run({ limit: n });
610
+ },
611
+ offset(n: number) {
612
+ return run({ offset: n });
613
+ },
587
614
  then(onfulfilled, onrejected) {
588
- return all.then(onfulfilled, onrejected);
615
+ return run({}).then(onfulfilled, onrejected);
589
616
  },
590
617
  };
591
618
  },
@@ -674,6 +701,18 @@ export function createFxContext(options: CreateFxOptions): FxContext {
674
701
  return h.raw(sql, params);
675
702
  });
676
703
  },
704
+ count(table, where) {
705
+ return gated("read", ref, async () => {
706
+ const h = await ensure();
707
+ return h.count(table, where);
708
+ });
709
+ },
710
+ page(table, pageOptions) {
711
+ return gated("read", ref, async () => {
712
+ const h = await ensure();
713
+ return h.page(table, pageOptions);
714
+ });
715
+ },
677
716
  ensureTable(table) {
678
717
  return gated("write", ref, async () => {
679
718
  refuseDryRunWrite();
@@ -684,9 +723,7 @@ export function createFxContext(options: CreateFxOptions): FxContext {
684
723
  } as SqlStoreHandle;
685
724
  }
686
725
 
687
- function storeHandle(
688
- ref: NamedRef | { readonly ref: ResourceRef } | StoreDecl,
689
- ): FxStoreHandle {
726
+ function storeHandle(ref: NamedRef | { readonly ref: ResourceRef } | StoreDecl): FxStoreHandle {
690
727
  const runtime = options.storeRuntime;
691
728
  if (runtime && typeof ref === "object" && ref !== null && "facet" in ref) {
692
729
  const decl = ref;
@@ -714,8 +751,7 @@ export function createFxContext(options: CreateFxOptions): FxContext {
714
751
  get(_t, prop) {
715
752
  if (prop === "ref") return baseRef;
716
753
  if (prop === "then") return undefined;
717
- const isRead =
718
- prop === "get" || prop === "search" || prop === "list";
754
+ const isRead = prop === "get" || prop === "search" || prop === "list";
719
755
  return (...args: unknown[]) =>
720
756
  gated(isRead ? "read" : "write", baseRef, async () => {
721
757
  if (!isRead && isDryRun()) {
@@ -724,18 +760,14 @@ export function createFxContext(options: CreateFxOptions): FxContext {
724
760
  );
725
761
  }
726
762
  const h = await open();
727
- const fn = (h as unknown as Record<string | symbol, unknown>)[
728
- prop
729
- ];
763
+ const fn = (h as unknown as Record<string | symbol, unknown>)[prop];
730
764
  if (typeof fn !== "function") return undefined;
731
765
  return (fn as (...a: unknown[]) => unknown).apply(h, args);
732
766
  });
733
767
  },
734
768
  });
735
769
  }
736
- return stubStoreHandle(
737
- resolveStoreRef(ref as NamedRef | { readonly ref: ResourceRef }),
738
- );
770
+ return stubStoreHandle(resolveStoreRef(ref as NamedRef | { readonly ref: ResourceRef }));
739
771
  }
740
772
 
741
773
  const clock: FxClock = {
@@ -768,11 +800,7 @@ export function createFxContext(options: CreateFxOptions): FxContext {
768
800
  if (aiDisablesCache) return;
769
801
  cacheStore.set(key, value);
770
802
  },
771
- async getOrSet<T>(
772
- key: string,
773
- _ttl: string,
774
- produce: () => T | Promise<T>,
775
- ): Promise<T> {
803
+ async getOrSet<T>(key: string, _ttl: string, produce: () => T | Promise<T>): Promise<T> {
776
804
  if (aiDisablesCache) return await produce();
777
805
  if (cacheStore.has(key)) {
778
806
  if (telemetry) telemetry.cacheHits += 1;
@@ -792,9 +820,7 @@ export function createFxContext(options: CreateFxOptions): FxContext {
792
820
  const vault = options.vaultRuntime;
793
821
  if (!vault) return { message, data };
794
822
  const safeMessage = vault.redactString(message);
795
- const safeData = data
796
- ? (vault.redact(data) as Record<string, unknown>)
797
- : undefined;
823
+ const safeData = data ? (vault.redact(data) as Record<string, unknown>) : undefined;
798
824
  return { message: safeMessage, data: safeData };
799
825
  }
800
826
 
@@ -984,6 +1010,25 @@ export function createFxContext(options: CreateFxOptions): FxContext {
984
1010
  operator,
985
1011
  tenant,
986
1012
  fail,
1013
+ json: {
1014
+ ok<T>(value: T, opts?: { readonly meta?: Record<string, unknown> }): JsonResult<T> {
1015
+ return {
1016
+ [jsonResultBrand]: true,
1017
+ status: 200,
1018
+ value,
1019
+ ...(opts?.meta !== undefined ? { meta: opts.meta } : {}),
1020
+ } as JsonResult<T>;
1021
+ },
1022
+ create<T>(value: T): JsonResult<T> {
1023
+ return { [jsonResultBrand]: true, status: 201, value } as JsonResult<T>;
1024
+ },
1025
+ empty(): JsonResult<never> {
1026
+ return { [jsonResultBrand]: true, status: 204 } as JsonResult<never>;
1027
+ },
1028
+ with<T>(data: T, meta: Record<string, unknown>): JsonResult<T> {
1029
+ return { [jsonResultBrand]: true, status: 200, value: data, meta } as JsonResult<T>;
1030
+ },
1031
+ },
987
1032
  async step<T>(name: string, fn: () => T | Promise<T>): Promise<T> {
988
1033
  if (journal) {
989
1034
  return journal.step(name, fn);
@@ -49,12 +49,9 @@ describe("hook timing", () => {
49
49
 
50
50
  test("registry tags hooks at plug time", async () => {
51
51
  const registry = createPluginRegistry();
52
- const p = plugin("metered", { version: "1.0.0" }).hook(
53
- "onRequest",
54
- async () => {
55
- await Bun.sleep(1);
56
- },
57
- );
52
+ const p = plugin("metered", { version: "1.0.0" }).hook("onRequest", async () => {
53
+ await Bun.sleep(1);
54
+ });
58
55
  applyPlugin(registry, p, appPluginScope);
59
56
  const hooks = registry.hooksAt("app", undefined, "x");
60
57
  const ctx: InvocationContext = {
@@ -132,10 +132,7 @@ export function resetHookCosts(): void {
132
132
  filled = 0;
133
133
  }
134
134
 
135
- function summarize(
136
- pluginId: string,
137
- mine: readonly HookCostSample[],
138
- ): HookCostSummary {
135
+ function summarize(pluginId: string, mine: readonly HookCostSample[]): HookCostSummary {
139
136
  if (mine.length === 0) {
140
137
  return {
141
138
  pluginId,
@@ -149,18 +146,15 @@ function summarize(
149
146
  }
150
147
  const durations = mine.map((s) => s.durationMs).sort((a, b) => a - b);
151
148
  const sum = durations.reduce((a, b) => a + b, 0);
152
- const byStageAcc: Partial<
153
- Record<HookStage, { count: number; total: number }>
154
- > = {};
149
+ const byStageAcc: Partial<Record<HookStage, { count: number; total: number }>> = {};
155
150
  for (const s of mine) {
156
151
  const cur = byStageAcc[s.stage] ?? { count: 0, total: 0 };
157
152
  cur.count++;
158
153
  cur.total += s.durationMs;
159
154
  byStageAcc[s.stage] = cur;
160
155
  }
161
- const byStage: Partial<
162
- Record<HookStage, { readonly count: number; readonly meanMs: number }>
163
- > = {};
156
+ const byStage: Partial<Record<HookStage, { readonly count: number; readonly meanMs: number }>> =
157
+ {};
164
158
  for (const [stage, acc] of Object.entries(byStageAcc) as Array<
165
159
  [HookStage, { count: number; total: number }]
166
160
  >) {
@@ -182,9 +176,6 @@ function summarize(
182
176
 
183
177
  function percentile(sorted: readonly number[], p: number): number {
184
178
  if (sorted.length === 0) return 0;
185
- const idx = Math.min(
186
- sorted.length - 1,
187
- Math.max(0, Math.ceil(p * sorted.length) - 1),
188
- );
179
+ const idx = Math.min(sorted.length - 1, Math.max(0, Math.ceil(p * sorted.length) - 1));
189
180
  return sorted[idx]!;
190
181
  }