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
@@ -26,11 +26,9 @@ describe("hooks — order and composition", () => {
26
26
 
27
27
  test("mergeHooks is app → unit → flow, registration order within", () => {
28
28
  const order: string[] = [];
29
- const mark =
30
- (label: string) =>
31
- () => {
32
- order.push(label);
33
- };
29
+ const mark = (label: string) => () => {
30
+ order.push(label);
31
+ };
34
32
 
35
33
  const merged = mergeHooks(
36
34
  { onRequest: [mark("app1"), mark("app2")] },
@@ -66,11 +64,13 @@ describe("hooks — order and composition", () => {
66
64
  order.push("handler");
67
65
  return { ok: true };
68
66
  },
69
- }).hook("beforeHandle", () => {
70
- order.push("flow:beforeHandle");
71
- }).hook("afterHandle", () => {
72
- order.push("flow:afterHandle");
73
- });
67
+ })
68
+ .hook("beforeHandle", () => {
69
+ order.push("flow:beforeHandle");
70
+ })
71
+ .hook("afterHandle", () => {
72
+ order.push("flow:afterHandle");
73
+ });
74
74
 
75
75
  on(http.get("/ordered"), f);
76
76
 
@@ -146,6 +146,39 @@ describe("hooks — order and composition", () => {
146
146
  expect(order).toEqual(["onAuth", "onResponse"]);
147
147
  });
148
148
 
149
+ test("onResponse sees the serialized data response and may replace it", async () => {
150
+ let seenAtHook: Response | undefined;
151
+
152
+ on(
153
+ http.get("/data"),
154
+ flow({
155
+ name: "data",
156
+ do: () => ({ ok: true }),
157
+ }),
158
+ );
159
+
160
+ const app = oke({ name: "data-res" }).hook("onResponse", (ctx) => {
161
+ seenAtHook = ctx.response;
162
+ if (!ctx.response) return;
163
+ const headers = new Headers(ctx.response.headers);
164
+ headers.set("x-stamped", "yes");
165
+ ctx.response = new Response(ctx.response.body, {
166
+ status: ctx.response.status,
167
+ headers,
168
+ });
169
+ });
170
+
171
+ const res = await app.fetch(new Request("http://localhost/data"));
172
+ expect(res.status).toBe(200);
173
+ expect(res.headers.get("x-stamped")).toBe("yes");
174
+ // The hook saw the real serialized response, not undefined.
175
+ expect(seenAtHook).toBeDefined();
176
+ expect(seenAtHook!.headers.get("content-type")).toContain("application/json");
177
+ // The body survived the rebuild untouched.
178
+ const body = (await res.json()) as { data?: { ok: boolean } };
179
+ expect(body.data?.ok).toBe(true);
180
+ });
181
+
149
182
  test("hook short-circuits with FlowFailure and runs onError", async () => {
150
183
  const order: string[] = [];
151
184
 
@@ -40,9 +40,7 @@ export const BEFORE_HANDLER_STAGES: readonly HookStage[] = [
40
40
  ] as const;
41
41
 
42
42
  /** Stages that run after a successful handler (before onResponse). */
43
- export const AFTER_HANDLER_STAGES: readonly HookStage[] = [
44
- "afterHandle",
45
- ] as const;
43
+ export const AFTER_HANDLER_STAGES: readonly HookStage[] = ["afterHandle"] as const;
46
44
 
47
45
  /** All user-registrable stages in pipeline order. */
48
46
  export const HOOK_STAGES: readonly HookStage[] = [
@@ -97,11 +95,7 @@ export type HookFn = (
97
95
  ctx: InvocationContext,
98
96
  fxOrErr: Fx | unknown,
99
97
  fx?: Fx,
100
- ) =>
101
- | void
102
- | Response
103
- | FlowFailure
104
- | Promise<void | Response | FlowFailure>;
98
+ ) => void | Response | FlowFailure | Promise<void | Response | FlowFailure>;
105
99
 
106
100
  /** Hook bag keyed by stage. */
107
101
  export type HookMap = Partial<Record<HookStage, HookFn[]>>;
@@ -156,19 +150,34 @@ export interface PipelineResult {
156
150
  readonly response: Response | undefined;
157
151
  }
158
152
 
153
+ /** Serialize a pipeline outcome into an HTTP response (app-layer encoder). */
154
+ export type PipelineEncoder = (result: {
155
+ readonly response?: Response | undefined;
156
+ readonly failure?: FlowFailure | undefined;
157
+ readonly output?: unknown;
158
+ readonly error?: unknown;
159
+ }) => Response;
160
+
159
161
  /**
160
162
  * Run the seven-stage pipeline around `handler`.
161
163
  *
164
+ * When `encode` is given (HTTP triggers), the outcome is serialized into
165
+ * `ctx.response` **before** `onResponse`, so the last stage sees — and may
166
+ * replace — the final response, as {@link InvocationContext.response}
167
+ * documents. Without `encode` (non-HTTP triggers) behavior is unchanged.
168
+ *
162
169
  * @param ctx - Invocation context
163
170
  * @param fx - Fx door
164
171
  * @param hooks - Merged hooks
165
172
  * @param handler - Flow body (the `handler` stage)
173
+ * @param encode - HTTP response encoder (e.g. `encodeExecuteResult`)
166
174
  */
167
175
  export async function runPipeline(
168
176
  ctx: InvocationContext,
169
177
  fx: Fx,
170
178
  hooks: HookMap,
171
179
  handler: () => unknown | Promise<unknown>,
180
+ encode?: PipelineEncoder,
172
181
  ): Promise<PipelineResult> {
173
182
  let shortCircuit: "response" | "error" | undefined;
174
183
 
@@ -221,6 +230,13 @@ export async function runPipeline(
221
230
  await runStage("onError", hooks, ctx, fx);
222
231
  }
223
232
 
233
+ // Serialize before the last stage so `onResponse` sees the final response
234
+ // (short-circuit wins; encoder input mirrors the app layer exactly).
235
+ if (encode !== undefined && ctx.response === undefined) {
236
+ const failure = isFlowFailure(ctx.error) ? ctx.error : undefined;
237
+ ctx.response = encode({ failure, output: ctx.result, error: ctx.error });
238
+ }
239
+
224
240
  await runStage("onResponse", hooks, ctx, fx);
225
241
 
226
242
  const failure = isFlowFailure(ctx.error) ? ctx.error : undefined;
@@ -247,10 +263,7 @@ async function runStage(
247
263
  const started = pluginId !== undefined ? performance.now() : 0;
248
264
  try {
249
265
  // Spec apps use `.hook("onError", (ctx, err, fx) => …)`.
250
- returned =
251
- stage === "onError"
252
- ? await fn(ctx, ctx.error, fx)
253
- : await fn(ctx, fx);
266
+ returned = stage === "onError" ? await fn(ctx, ctx.error, fx) : await fn(ctx, fx);
254
267
  } catch (err) {
255
268
  if (pluginId !== undefined) {
256
269
  recordHookCost(pluginId, stage, performance.now() - started);
@@ -50,11 +50,7 @@ export type {
50
50
  RoutesFromAdoptArgs,
51
51
  } from "./adopt-routes.ts";
52
52
 
53
- export {
54
- createCapabilityToken,
55
- effectsFieldOf,
56
- type CapabilityToken,
57
- } from "./capability.ts";
53
+ export { createCapabilityToken, effectsFieldOf, type CapabilityToken } from "./capability.ts";
58
54
 
59
55
  export {
60
56
  createEffectLedger,
@@ -107,6 +103,8 @@ export {
107
103
  export {
108
104
  createFx,
109
105
  createFxContext,
106
+ isJsonResult,
107
+ jsonResultBrand,
110
108
  resolveName,
111
109
  resolveStoreRef,
112
110
  type CreateFxOptions,
@@ -117,12 +115,14 @@ export {
117
115
  type FxCallHandler,
118
116
  type FxClock,
119
117
  type FxContext,
118
+ type FxJson,
120
119
  type FxLog,
121
120
  type FxOperator,
122
121
  type FxSearchOptions,
123
122
  type FxSendOptions,
124
123
  type FxStoreHandle,
125
124
  type FxTenant,
125
+ type JsonResult,
126
126
  type NamedRef,
127
127
  } from "./fx.ts";
128
128
 
@@ -181,12 +181,7 @@ export {
181
181
  type HookCostSummary,
182
182
  } from "./hook-timing.ts";
183
183
 
184
- export {
185
- listBindings,
186
- on,
187
- resetBindings,
188
- type Binding,
189
- } from "./on.ts";
184
+ export { listBindings, on, resetBindings, type Binding } from "./on.ts";
190
185
 
191
186
  export {
192
187
  isPlugin,
@@ -205,6 +200,7 @@ export {
205
200
  type PluginOptions,
206
201
  type PluginRegistration,
207
202
  type TableContribution,
203
+ type PluginTableOptions,
208
204
  } from "./plugin.ts";
209
205
 
210
206
  export {
@@ -244,6 +240,7 @@ export {
244
240
  every,
245
241
  http,
246
242
  internal,
243
+ isResourceMount,
247
244
  isSignalTriggerSource,
248
245
  normalizeTrigger,
249
246
  table,
@@ -254,6 +251,8 @@ export {
254
251
  type HttpMethod,
255
252
  type HttpTrigger,
256
253
  type InternalTrigger,
254
+ type ResourceFlowBag,
255
+ type ResourceMount,
257
256
  type SignalAsTrigger,
258
257
  type SignalSource,
259
258
  type TableHandle,
@@ -270,11 +269,6 @@ export {
270
269
  type JourneySlo,
271
270
  } from "./journey.ts";
272
271
 
273
- export {
274
- unit,
275
- consumeUnitPlugins,
276
- resetUnitPlugins,
277
- type UnitBag,
278
- } from "./unit.ts";
272
+ export { unit, consumeUnitPlugins, resetUnitPlugins, type UnitBag } from "./unit.ts";
279
273
 
280
274
  export { rateLimit, type RateLimitPluginOptions } from "./rate-limit.ts";
@@ -11,11 +11,7 @@ import { mkdir } from "node:fs/promises";
11
11
  import { dirname } from "node:path";
12
12
 
13
13
  /** Status of a durable run. */
14
- export type JournalRunStatus =
15
- | "running"
16
- | "sleeping"
17
- | "completed"
18
- | "failed";
14
+ export type JournalRunStatus = "running" | "sleeping" | "completed" | "failed";
19
15
 
20
16
  /** A completed named step. */
21
17
  export interface JournalStepEntry {
@@ -44,10 +40,7 @@ export interface JournalEffectEntry {
44
40
  }
45
41
 
46
42
  /** One journaled event in call order. */
47
- export type JournalEntry =
48
- | JournalStepEntry
49
- | JournalSleepEntry
50
- | JournalEffectEntry;
43
+ export type JournalEntry = JournalStepEntry | JournalSleepEntry | JournalEffectEntry;
51
44
 
52
45
  /** Persisted durable run. */
53
46
  export interface JournalRun {
@@ -103,9 +96,7 @@ export interface JournalStore {
103
96
  }
104
97
 
105
98
  /** In-memory journal store. */
106
- export function createMemoryJournalStore(
107
- seed?: readonly JournalRun[],
108
- ): JournalStore {
99
+ export function createMemoryJournalStore(seed?: readonly JournalRun[]): JournalStore {
109
100
  const runs = new Map<string, JournalRun>();
110
101
  for (const r of seed ?? []) {
111
102
  runs.set(r.id, cloneRun(r));
@@ -147,10 +138,7 @@ export function createFileJournalStore(path: string): JournalStore {
147
138
 
148
139
  async function flush(map: Map<string, JournalRun>): Promise<void> {
149
140
  await mkdir(dirname(path), { recursive: true });
150
- await Bun.write(
151
- path,
152
- JSON.stringify({ runs: [...map.values()] }, null, 2),
153
- );
141
+ await Bun.write(path, JSON.stringify({ runs: [...map.values()] }, null, 2));
154
142
  }
155
143
 
156
144
  return {
@@ -204,11 +192,7 @@ export interface JournalSession {
204
192
  * @param duration - Duration string (`7d`, `2m`, …)
205
193
  * @param parseMs - Duration → milliseconds
206
194
  */
207
- sleep(
208
- label: string,
209
- duration: string,
210
- parseMs: (duration: string) => number,
211
- ): Promise<void>;
195
+ sleep(label: string, duration: string, parseMs: (duration: string) => number): Promise<void>;
212
196
  /**
213
197
  * Journal an arbitrary fx effect (replay returns recorded value).
214
198
  *
@@ -216,11 +200,7 @@ export interface JournalSession {
216
200
  * @param resource - Resource ref
217
201
  * @param execute - Side-effecting body
218
202
  */
219
- effect<T>(
220
- effectKind: string,
221
- resource: string,
222
- execute: () => T | Promise<T>,
223
- ): Promise<T>;
203
+ effect<T>(effectKind: string, resource: string, execute: () => T | Promise<T>): Promise<T>;
224
204
  /** Persist current run status / output. */
225
205
  commit(
226
206
  status: JournalRunStatus,
@@ -327,11 +307,7 @@ export function createJournal(options: CreateJournalOptions): Journal {
327
307
  ): Promise<T> {
328
308
  for (let i = cursor; i < run.entries.length; i++) {
329
309
  const e = run.entries[i]!;
330
- if (
331
- e.kind === "effect" &&
332
- e.effectKind === effectKind &&
333
- e.resource === resource
334
- ) {
310
+ if (e.kind === "effect" && e.effectKind === effectKind && e.resource === resource) {
335
311
  cursor = i + 1;
336
312
  return e.value as T;
337
313
  }
package/src/kernel/on.ts CHANGED
@@ -6,15 +6,13 @@
6
6
  * The return type carries the bound trigger so `typeof app` can derive REST.
7
7
  */
8
8
 
9
+ import { isFlow, type AnyFlowDef, type FlowDef, type FlowErrorMap } from "./flow.ts";
9
10
  import {
10
- isFlow,
11
- type AnyFlowDef,
12
- type FlowDef,
13
- type FlowErrorMap,
14
- } from "./flow.ts";
15
- import {
11
+ isResourceMount,
16
12
  normalizeTrigger,
17
13
  type BoundTriggerOf,
14
+ type ResourceFlowBag,
15
+ type ResourceMount,
18
16
  type SignalSource,
19
17
  type Trigger,
20
18
  } from "./triggers.ts";
@@ -44,17 +42,55 @@ export function on<
44
42
  >(
45
43
  trigger: T,
46
44
  flowDef: FlowDef<I, O, E, D, Trigger | undefined>,
47
- ): FlowDef<I, O, E, D, BoundTriggerOf<T>> {
45
+ ): FlowDef<I, O, E, D, BoundTriggerOf<T>>;
46
+ /**
47
+ * Mount a CRUD resource (`http.resource(path, ops)`): registers the five
48
+ * verb bindings and returns the ops bag (unit keys `list` · `create` ·
49
+ * `get` · `update` · `remove`) for `.adopt({ notes })`.
50
+ *
51
+ * @param mount - Branded {@link ResourceMount}
52
+ */
53
+ export function on(mount: ResourceMount): ResourceFlowBag;
54
+ export function on(
55
+ triggerOrMount: Trigger | SignalSource | ResourceMount,
56
+ flowDef?: FlowDef<any, any, any, any, Trigger | undefined>,
57
+ ): unknown {
58
+ if (isResourceMount(triggerOrMount)) {
59
+ if (flowDef !== undefined) {
60
+ throw new TypeError("on(http.resource(...)) takes no second argument");
61
+ }
62
+ const byIdVerb: Partial<Record<string, "get" | "update" | "remove">> = {
63
+ GET: "get",
64
+ PATCH: "update",
65
+ DELETE: "remove",
66
+ };
67
+ const baseVerb: Partial<Record<string, "list" | "create">> = {
68
+ GET: "list",
69
+ POST: "create",
70
+ };
71
+ const ops: Record<string, unknown> = {};
72
+ for (const { trigger, flow } of triggerOrMount.mounts) {
73
+ const key = trigger.path.endsWith("/:id")
74
+ ? byIdVerb[trigger.method]
75
+ : baseVerb[trigger.method];
76
+ if (key === undefined || !isFlow(flow)) {
77
+ throw new TypeError("on(http.resource(...)) expects the five CRUD FlowDefs");
78
+ }
79
+ on(trigger, flow as FlowDef<any, any, any, any, Trigger | undefined>);
80
+ ops[key] = flow;
81
+ }
82
+ return ops as unknown as ResourceFlowBag;
83
+ }
48
84
  if (!isFlow(flowDef)) {
49
85
  throw new TypeError("on() expected a flow() definition as the second argument");
50
86
  }
51
- const normalized = normalizeTrigger(trigger);
87
+ const normalized = normalizeTrigger(triggerOrMount as Trigger | SignalSource);
52
88
  const list = flowDef.triggers as Trigger[];
53
89
  list.push(normalized);
54
90
  // Stamp runtime carrier for the first bound trigger (type follows BoundTriggerOf).
55
91
  (flowDef as { $trigger: Trigger }).$trigger = normalized;
56
92
  bindings.push({ trigger: normalized, flow: flowDef as AnyFlowDef });
57
- return flowDef as unknown as FlowDef<I, O, E, D, BoundTriggerOf<T>>;
93
+ return flowDef;
58
94
  }
59
95
 
60
96
  /**
@@ -9,10 +9,7 @@
9
9
 
10
10
  import { describe, expect, test } from "bun:test";
11
11
  import { z } from "zod";
12
- import {
13
- createSessionStore,
14
- issueSessionWithScopes,
15
- } from "../auth/sessions.ts";
12
+ import { createSessionStore, issueSessionWithScopes } from "../auth/sessions.ts";
16
13
  import { createClockRuntime } from "../elements/clock.ts";
17
14
  import { gate } from "../elements/gate.ts";
18
15
  import { createRunsRuntime, memoryRunsDriver } from "../runs/index.ts";
@@ -20,16 +17,11 @@ import { oke } from "./app.ts";
20
17
  import { flow, resetFlowSeq } from "./flow.ts";
21
18
  import { on, resetBindings } from "./on.ts";
22
19
  import { http } from "./triggers.ts";
23
- import {
24
- gateDenialFailure,
25
- recordGateEvaluations,
26
- } from "./pipeline.ts";
20
+ import { gateDenialFailure, recordGateEvaluations } from "./pipeline.ts";
27
21
  import { createRunTelemetry } from "./run-telemetry.ts";
28
22
 
29
23
  const member = gate.policy("member", ({ auth }) => !!auth.verified);
30
- const canOrder = gate.policy("order:create", ({ auth }) =>
31
- auth.scopes.has("order:create"),
32
- );
24
+ const canOrder = gate.policy("order:create", ({ auth }) => auth.scopes.has("order:create"));
33
25
 
34
26
  describe("gateDenialFailure", () => {
35
27
  test("anonymous → Unauthorized; authed → Forbidden; rate → RateLimited", () => {
@@ -217,18 +209,17 @@ describe("pipeline — Bearer cryptographic verification", () => {
217
209
  const app = oke({
218
210
  name: "auth-forge",
219
211
  gates: [member],
220
- env: "dev",
212
+ env: "local",
221
213
  auth: { secret: "hmac-secret-for-tests", sessions },
222
214
  startScheduler: false,
223
215
  });
224
- await app.boot({ env: "dev", gates: [member], startScheduler: false });
216
+ await app.boot({ env: "local", gates: [member], startScheduler: false });
225
217
 
226
218
  const res = await app.fetch(
227
219
  new Request("http://localhost/secure", {
228
220
  method: "GET",
229
221
  headers: {
230
- authorization:
231
- "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJoYWNrZXIifQ.forgedsignature",
222
+ authorization: "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJoYWNrZXIifQ.forgedsignature",
232
223
  },
233
224
  }),
234
225
  );
@@ -272,13 +263,13 @@ describe("pipeline — Bearer cryptographic verification", () => {
272
263
  const app = oke({
273
264
  name: "auth-expired",
274
265
  gates: [member],
275
- env: "dev",
266
+ env: "local",
276
267
  auth: { secret, sessions, now: () => nowMs },
277
268
  elements: { clock: clockRt },
278
269
  startScheduler: false,
279
270
  });
280
271
  await app.boot({
281
- env: "dev",
272
+ env: "local",
282
273
  gates: [member],
283
274
  startScheduler: false,
284
275
  elements: { clock: clockRt },
@@ -324,10 +315,10 @@ describe("pipeline — Bearer cryptographic verification", () => {
324
315
  const app = oke({
325
316
  name: "no-inject",
326
317
  gates: [member],
327
- env: "dev",
318
+ env: "local",
328
319
  startScheduler: false,
329
320
  });
330
- await app.boot({ env: "dev", gates: [member], startScheduler: false });
321
+ await app.boot({ env: "local", gates: [member], startScheduler: false });
331
322
 
332
323
  const result = await app.execute(
333
324
  app.flow("orders.inject")!,
@@ -74,18 +74,14 @@ export type GateDenialCode = "Unauthorized" | "Forbidden" | "RateLimited";
74
74
  * @param evaluation - First denying evaluation
75
75
  * @param ctx - Policy context at denial time
76
76
  */
77
- export function gateDenialFailure(
78
- evaluation: GateEvaluation,
79
- ctx: GatePolicyContext,
80
- ): FlowFailure {
77
+ export function gateDenialFailure(evaluation: GateEvaluation, ctx: GatePolicyContext): FlowFailure {
81
78
  if (evaluation.kind === "rate" || evaluation.reason === "rate limited") {
82
79
  return fail("RateLimited", {
83
80
  retryAfterMs: evaluation.retryAfterMs ?? 0,
84
81
  });
85
82
  }
86
83
 
87
- const authenticated =
88
- ctx.auth.userId !== null && ctx.auth.userId !== undefined;
84
+ const authenticated = ctx.auth.userId !== null && ctx.auth.userId !== undefined;
89
85
  if (!authenticated) {
90
86
  return fail("Unauthorized", {});
91
87
  }
@@ -102,9 +98,7 @@ export function gateDenialFailure(
102
98
  */
103
99
  export function gateNamesOf(trigger: Trigger): string[] {
104
100
  if (trigger.kind !== "http") return [];
105
- return (trigger as HttpTrigger).gates.map((g) =>
106
- typeof g === "string" ? g : g.name,
107
- );
101
+ return (trigger as HttpTrigger).gates.map((g) => (typeof g === "string" ? g : g.name));
108
102
  }
109
103
 
110
104
  /**
@@ -129,10 +123,7 @@ export function recordGateEvaluations(
129
123
  * @param bag - Mutable principal bag
130
124
  * @param resolved - Identity
131
125
  */
132
- export function applyPrincipal(
133
- bag: PrincipalBag,
134
- resolved: ResolvedPrincipal | undefined,
135
- ): void {
126
+ export function applyPrincipal(bag: PrincipalBag, resolved: ResolvedPrincipal | undefined): void {
136
127
  if (!resolved) return;
137
128
  if (resolved.plane === "operator" || resolved.operatorId !== undefined) {
138
129
  bag.operator.id = resolved.operatorId ?? null;
@@ -217,10 +208,7 @@ export function createElementPipelineHooks(deps: PipelineDeps): {
217
208
  * @param fx - Fx door
218
209
  * @param ctx - Invocation context (for IP / meta)
219
210
  */
220
- export function policyContextOf(
221
- fx: Fx,
222
- ctx: InvocationContext,
223
- ): GatePolicyContext {
211
+ export function policyContextOf(fx: Fx, ctx: InvocationContext): GatePolicyContext {
224
212
  const auth = fx.auth as FxAuth;
225
213
  const operator = fx.operator as FxOperator;
226
214
  const ip =
@@ -14,10 +14,7 @@
14
14
 
15
15
  import type { AnyFlowDef } from "./flow.ts";
16
16
  import { isPlugin, type DecorationsOf, type PluginDef } from "./plugin.ts";
17
- import {
18
- type PluginRegistry,
19
- type PluginScope,
20
- } from "./registry.ts";
17
+ import { type PluginRegistry, type PluginScope } from "./registry.ts";
21
18
 
22
19
  /**
23
20
  * Apply a plugin to a registry at the given scope.
@@ -43,10 +40,8 @@ export function applyPlugin(
43
40
  * @typeParam Base - Existing decorations
44
41
  * @typeParam P - Plugin being plugged
45
42
  */
46
- export type AccumulateDecorations<
47
- Base extends Record<string, unknown>,
48
- P,
49
- > = Base & DecorationsOf<P>;
43
+ export type AccumulateDecorations<Base extends Record<string, unknown>, P> = Base &
44
+ DecorationsOf<P>;
50
45
 
51
46
  /** Something that can receive `.plug()` with type accumulation. */
52
47
  export interface Pluggable<D extends Record<string, unknown> = {}> {
@@ -55,9 +50,7 @@ export interface Pluggable<D extends Record<string, unknown> = {}> {
55
50
  *
56
51
  * @param pluginDef - Plugin from {@link plugin}
57
52
  */
58
- plug<P extends PluginDef>(
59
- pluginDef: P,
60
- ): Pluggable<AccumulateDecorations<D, P>>;
53
+ plug<P extends PluginDef>(pluginDef: P): Pluggable<AccumulateDecorations<D, P>>;
61
54
  }
62
55
 
63
56
  /**
@@ -10,19 +10,11 @@ describe("plugin conflict detection", () => {
10
10
  test("table-name collision fails the boot with both plugin names", () => {
11
11
  const registry = createPluginRegistry();
12
12
 
13
- registry.plug(
14
- plugin("audit", { version: "1.0.0" }).table("events"),
15
- { kind: "app" },
16
- );
13
+ registry.plug(plugin("audit", { version: "1.0.0" }).table("events"), { kind: "app" });
17
14
 
18
15
  expect(() =>
19
- registry.plug(
20
- plugin("billing", { version: "1.0.0" }).table("events"),
21
- { kind: "app" },
22
- ),
23
- ).toThrow(
24
- 'Plugin conflict: table "events" claimed by "audit" and "billing"',
25
- );
16
+ registry.plug(plugin("billing", { version: "1.0.0" }).table("events"), { kind: "app" }),
17
+ ).toThrow('Plugin conflict: table "events" claimed by "audit" and "billing"');
26
18
  });
27
19
 
28
20
  test("panel-id collision names both sides", () => {
@@ -79,28 +71,24 @@ describe("plugin conflict detection", () => {
79
71
  config: { max: 30 },
80
72
  }).hook("onRequest", () => {});
81
73
 
82
- expect(
83
- registry.plug(p, { kind: "unit", name: "orders" }),
84
- ).toBeDefined();
85
- expect(
86
- registry.plug(p, { kind: "unit", name: "payments" }),
87
- ).toBeDefined();
74
+ expect(registry.plug(p, { kind: "unit", name: "orders" })).toBeDefined();
75
+ expect(registry.plug(p, { kind: "unit", name: "payments" })).toBeDefined();
88
76
  expect(registry.installed).toHaveLength(2);
89
77
  });
90
78
 
91
79
  test("same plugin twice with conflicting config is a boot error", () => {
92
80
  const registry = createPluginRegistry();
93
81
 
94
- registry.plug(
95
- plugin("rate-limit", { version: "1.0.0", config: { max: 30 } }),
96
- { kind: "unit", name: "orders" },
97
- );
82
+ registry.plug(plugin("rate-limit", { version: "1.0.0", config: { max: 30 } }), {
83
+ kind: "unit",
84
+ name: "orders",
85
+ });
98
86
 
99
87
  expect(() =>
100
- registry.plug(
101
- plugin("rate-limit", { version: "1.0.0", config: { max: 60 } }),
102
- { kind: "unit", name: "payments" },
103
- ),
88
+ registry.plug(plugin("rate-limit", { version: "1.0.0", config: { max: 60 } }), {
89
+ kind: "unit",
90
+ name: "payments",
91
+ }),
104
92
  ).toThrow(/conflicting config/);
105
93
  });
106
94
  });
@@ -15,8 +15,7 @@ beforeEach(() => {
15
15
  });
16
16
 
17
17
  /** Compile-time assert: `Actual` extends `Expected`. */
18
- type ExpectExtends<Actual, Expected> =
19
- Actual extends Expected ? true : false;
18
+ type ExpectExtends<Actual, Expected> = Actual extends Expected ? true : false;
20
19
 
21
20
  describe("plugin decorate — types and runtime", () => {
22
21
  test("decoration is visible in downstream handlers", async () => {
@@ -45,14 +44,12 @@ describe("plugin decorate — types and runtime", () => {
45
44
  });
46
45
 
47
46
  test("types accumulate through .plug()", () => {
48
- const withAudit = plugin("audit", { version: "1.0.0" }).decorate(
49
- "audit",
50
- { enabled: true as const },
51
- );
52
- const withBilling = plugin("billing", { version: "1.0.0" }).decorate(
53
- "billing",
54
- { currency: "SAR" as const },
55
- );
47
+ const withAudit = plugin("audit", { version: "1.0.0" }).decorate("audit", {
48
+ enabled: true as const,
49
+ });
50
+ const withBilling = plugin("billing", { version: "1.0.0" }).decorate("billing", {
51
+ currency: "SAR" as const,
52
+ });
56
53
 
57
54
  const app = oke({ name: "types" }).plug(withAudit).plug(withBilling);
58
55
 
@@ -98,9 +95,7 @@ describe("plugin decorate — types and runtime", () => {
98
95
  );
99
96
 
100
97
  const app = oke({ name: "deco-scope" });
101
- app.unit("orders").plug(
102
- plugin("flag", { version: "1.0.0" }).decorate("flag", "orders-only"),
103
- );
98
+ app.unit("orders").plug(plugin("flag", { version: "1.0.0" }).decorate("flag", "orders-only"));
104
99
 
105
100
  await app.fetch(new Request("http://localhost/orders"));
106
101
  await app.fetch(new Request("http://localhost/payments"));