okengine 0.18.5 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (510) hide show
  1. package/AGENTS.md +18 -10
  2. package/README.md +2 -2
  3. package/package.json +51 -50
  4. package/site/content/docs/ai/llms-txt.mdx +1 -1
  5. package/site/content/docs/ai/meta.json +1 -1
  6. package/site/content/docs/ai/skills.mdx +4 -1
  7. package/site/content/docs/ai/try-it.mdx +58 -0
  8. package/site/content/docs/client/auth.mdx +208 -0
  9. package/site/content/docs/client/calling.mdx +451 -0
  10. package/site/content/docs/client/index.mdx +209 -0
  11. package/site/content/docs/client/live.mdx +234 -0
  12. package/site/content/docs/client/meta.json +5 -0
  13. package/site/content/docs/client/react.mdx +249 -0
  14. package/site/content/docs/elements/ai/agents.mdx +232 -0
  15. package/site/content/docs/elements/ai/index.mdx +341 -0
  16. package/site/content/docs/elements/ai/mcp.mdx +275 -0
  17. package/site/content/docs/elements/ai/meta.json +5 -0
  18. package/site/content/docs/elements/ai/models.mdx +283 -0
  19. package/site/content/docs/elements/ai/prompts.mdx +256 -0
  20. package/site/content/docs/elements/channel/email.mdx +266 -0
  21. package/site/content/docs/elements/channel/index.mdx +344 -0
  22. package/site/content/docs/elements/channel/meta.json +5 -0
  23. package/site/content/docs/elements/channel/push.mdx +218 -0
  24. package/site/content/docs/elements/channel/receipts.mdx +206 -0
  25. package/site/content/docs/elements/channel/sms.mdx +264 -0
  26. package/site/content/docs/elements/channel/whatsapp.mdx +220 -0
  27. package/site/content/docs/elements/clock/index.mdx +300 -0
  28. package/site/content/docs/elements/clock/meta.json +5 -0
  29. package/site/content/docs/elements/clock/schedules.mdx +508 -0
  30. package/site/content/docs/elements/clock/sleep.mdx +445 -0
  31. package/site/content/docs/elements/flow/consumers.mdx +707 -0
  32. package/site/content/docs/elements/flow/http.mdx +1080 -0
  33. package/site/content/docs/elements/flow/index.mdx +618 -0
  34. package/site/content/docs/elements/flow/meta.json +5 -0
  35. package/site/content/docs/elements/flow/routing.mdx +559 -0
  36. package/site/content/docs/elements/flow/workflows.mdx +640 -0
  37. package/site/content/docs/elements/gate/auth.mdx +371 -0
  38. package/site/content/docs/elements/gate/authorization.mdx +298 -0
  39. package/site/content/docs/elements/gate/index.mdx +418 -0
  40. package/site/content/docs/elements/gate/meta.json +5 -0
  41. package/site/content/docs/elements/gate/rate-limits.mdx +365 -0
  42. package/site/content/docs/elements/gate/rls.mdx +303 -0
  43. package/site/content/docs/elements/gate/tenancy.mdx +372 -0
  44. package/site/content/docs/elements/index.mdx +20 -10
  45. package/site/content/docs/elements/signal/broadcast.mdx +517 -0
  46. package/site/content/docs/elements/signal/index.mdx +352 -0
  47. package/site/content/docs/elements/signal/live.mdx +590 -0
  48. package/site/content/docs/elements/signal/meta.json +5 -0
  49. package/site/content/docs/elements/signal/once.mdx +596 -0
  50. package/site/content/docs/elements/store/files.mdx +659 -0
  51. package/site/content/docs/elements/store/index.mdx +310 -0
  52. package/site/content/docs/elements/store/kv.mdx +629 -0
  53. package/site/content/docs/elements/store/meta.json +5 -0
  54. package/site/content/docs/elements/store/search.mdx +946 -0
  55. package/site/content/docs/elements/store/sql.mdx +937 -0
  56. package/site/content/docs/elements/vault/config.mdx +256 -0
  57. package/site/content/docs/elements/vault/index.mdx +356 -0
  58. package/site/content/docs/elements/vault/meta.json +5 -0
  59. package/site/content/docs/elements/vault/rotation.mdx +273 -0
  60. package/site/content/docs/elements/vault/secrets.mdx +285 -0
  61. package/site/content/docs/index.mdx +63 -36
  62. package/site/content/docs/meta.json +8 -7
  63. package/site/content/docs/plugins/cors.mdx +2 -1
  64. package/site/content/docs/plugins/csrf.mdx +4 -1
  65. package/site/content/docs/plugins/headers.mdx +2 -1
  66. package/site/content/docs/plugins/ip-allowlist.mdx +2 -1
  67. package/site/content/docs/plugins/magic-link.mdx +6 -0
  68. package/site/content/docs/plugins/maintenance-mode.mdx +2 -1
  69. package/site/content/docs/plugins/oauth.mdx +1 -1
  70. package/site/content/docs/plugins/otp.mdx +12 -1
  71. package/site/content/docs/plugins/passkey.mdx +39 -15
  72. package/site/content/docs/plugins/two-factor.mdx +91 -34
  73. package/site/content/docs/plugins/username.mdx +1 -1
  74. package/site/content/docs/recipes/caddy.mdx +3 -3
  75. package/site/content/docs/recipes/index.mdx +18 -28
  76. package/site/content/docs/recipes/mailpit.mdx +1 -1
  77. package/site/content/docs/recipes/meilisearch.mdx +3 -3
  78. package/site/content/docs/recipes/meta.json +1 -4
  79. package/site/content/docs/recipes/nginx.mdx +2 -2
  80. package/site/content/docs/recipes/openrouter.mdx +283 -0
  81. package/site/content/docs/recipes/pgdog.mdx +3 -3
  82. package/site/content/docs/recipes/postgres.mdx +1 -2
  83. package/site/content/docs/recipes/rustfs.mdx +2 -2
  84. package/site/content/docs/recipes/traefik.mdx +3 -3
  85. package/site/content/docs/reference/cli.mdx +231 -0
  86. package/site/content/docs/reference/configuration.mdx +30 -10
  87. package/site/content/docs/reference/environment-variables.mdx +93 -20
  88. package/site/content/docs/reference/errors.mdx +132 -29
  89. package/site/content/docs/reference/fx.mdx +137 -73
  90. package/site/content/docs/reference/index.mdx +13 -21
  91. package/site/content/docs/reference/meta.json +4 -5
  92. package/site/content/docs/reference/okid.mdx +42 -17
  93. package/site/content/docs/reference/plugins.mdx +4 -3
  94. package/site/content/docs/reference/security.mdx +197 -0
  95. package/site/content/docs/understand/meta.json +5 -0
  96. package/site/content/docs/understand/the-anatomy.mdx +132 -0
  97. package/site/content/docs/understand/the-model.mdx +32 -0
  98. package/site/content/docs/understand/the-problem.mdx +74 -0
  99. package/site/content/docs/understand/the-vocabulary.mdx +26 -0
  100. package/src/auth/api-keys.ts +2 -1
  101. package/src/auth/bindings.ts +64 -16
  102. package/src/auth/gate-auth.test.ts +6 -1
  103. package/src/auth/identity.ts +152 -5
  104. package/src/auth/index.ts +29 -0
  105. package/src/auth/invites.ts +2 -1
  106. package/src/auth/method-context.ts +41 -0
  107. package/src/auth/oauth-as/crypto.ts +2 -1
  108. package/src/auth/oauth-as/stores.ts +2 -1
  109. package/src/auth/operator.ts +2 -1
  110. package/src/auth/sessions-jwt.test.ts +77 -0
  111. package/src/auth/sessions.ts +20 -4
  112. package/src/auth/tenants.ts +3 -2
  113. package/src/auth/two-factor-challenge.test.ts +61 -0
  114. package/src/auth/two-factor-challenge.ts +284 -0
  115. package/src/auth/verification.ts +5 -0
  116. package/src/bench/REPORT.md +49 -0
  117. package/src/bench/g03-signal-once.bench.ts +1 -1
  118. package/src/bench/g10-observability-contention.bench.ts +1 -1
  119. package/src/bench/g17-hybrid-search.bench.ts +572 -0
  120. package/src/bench/load-app.ts +2 -10
  121. package/src/cli/ai-setup/ai-setup.test.ts +331 -42
  122. package/src/cli/ai-setup/apply.ts +294 -52
  123. package/src/cli/ai-setup/catalog.ts +238 -1342
  124. package/src/cli/ai-setup/index.ts +14 -99
  125. package/src/cli/ai-setup/prompts.ts +60 -443
  126. package/src/cli/ask-seed.test.ts +96 -0
  127. package/src/cli/ask-seed.ts +82 -0
  128. package/src/cli/ask-vault-gaps.test.ts +84 -0
  129. package/src/cli/ask-vault-gaps.ts +146 -0
  130. package/src/cli/build.ts +2 -2
  131. package/src/cli/client-add.test.ts +26 -1
  132. package/src/cli/client-add.ts +106 -27
  133. package/src/cli/db-seed.ts +2 -0
  134. package/src/cli/db.ts +150 -11
  135. package/src/cli/dev.ts +119 -211
  136. package/src/cli/docker-clean.ts +2 -2
  137. package/src/cli/docker-cli.test.ts +1 -1
  138. package/src/cli/doctor-diff.ts +4 -2
  139. package/src/cli/doctor-pii.test.ts +1 -1
  140. package/src/cli/doctor.ts +14 -1
  141. package/src/cli/hero-meta.test.ts +4 -2
  142. package/src/cli/load-config.images.test.ts +8 -10
  143. package/src/cli/load-config.ts +1 -1
  144. package/src/cli/registry.ts +22 -10
  145. package/src/cli/replay.ts +3 -1
  146. package/src/cli/start.ts +1 -1
  147. package/src/cli/tui/keys.ts +2 -3
  148. package/src/client/auth/cookies.ts +74 -0
  149. package/src/client/auth/create-auth-client.ts +636 -0
  150. package/src/client/auth/denials.ts +99 -0
  151. package/src/client/auth/session.ts +283 -0
  152. package/src/client/auth.test.ts +251 -0
  153. package/src/client/auth.ts +39 -114
  154. package/src/client/create-with-session.ts +245 -0
  155. package/src/client/create.ts +51 -5
  156. package/src/client/index.ts +11 -1
  157. package/src/client/live.ts +11 -79
  158. package/src/client/notes-contract.test.ts +5 -10
  159. package/src/client/sse.ts +137 -0
  160. package/src/client/stream.ts +147 -0
  161. package/src/client/transport.test.ts +32 -0
  162. package/src/client/transport.ts +123 -26
  163. package/src/client/types.ts +118 -14
  164. package/src/client-react/index.ts +185 -24
  165. package/src/client-react/use-live-query.ts +13 -3
  166. package/src/compiler/aot.test.ts +7 -4
  167. package/src/compiler/effects-embed.test.ts +56 -0
  168. package/src/compiler/effects-fetch.test.ts +43 -0
  169. package/src/compiler/effects-infer.ts +58 -2
  170. package/src/compiler/extract.test.ts +257 -43
  171. package/src/compiler/extract.ts +566 -48
  172. package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +7 -4
  173. package/src/compiler/fixtures/skyport/src/flows/bookings/signals.ts +2 -8
  174. package/src/compiler/fixtures/skyport.expected.json +4 -4
  175. package/src/compiler/fixtures/triggers/five-triggers.ts +14 -10
  176. package/src/compiler/response.ts +2 -2
  177. package/src/compiler/search-writer-isolation.test.ts +40 -0
  178. package/src/config/index.ts +11 -0
  179. package/src/console/server/app.ts +17 -23
  180. package/src/console/server/bind.ts +4 -0
  181. package/src/console/server/console.test.ts +2 -2
  182. package/src/console/server/flows-invoke.test.ts +50 -34
  183. package/src/console/server/flows.ts +436 -255
  184. package/src/console/server/runs-ingest.test.ts +6 -3
  185. package/src/console/server/serve.ts +1 -1
  186. package/src/console/server/signals.test.ts +1 -5
  187. package/src/console/server/signals.ts +8 -6
  188. package/src/console/server/state.ts +6 -1
  189. package/src/console/server/store.ts +1 -1
  190. package/src/console/ui-next/dist/assets/FileExportIcon-Ck-5od4R.js +1 -0
  191. package/src/console/ui-next/dist/assets/MoreHorizontalCircle01Icon-gMNGsE37.js +1 -0
  192. package/src/console/ui-next/dist/assets/PlusSignIcon-CwG3nxfu.js +1 -0
  193. package/src/console/ui-next/dist/assets/UnavailableIcon-D9cvHVPr.js +1 -0
  194. package/src/console/ui-next/dist/assets/UserIcon-DaE2PB5_.js +1 -0
  195. package/src/console/ui-next/dist/assets/access-page-DFeymU07.js +4 -0
  196. package/src/console/ui-next/dist/assets/agent-disclosure-U1rdfblp.js +1 -0
  197. package/src/console/ui-next/dist/assets/cache-glyph-BeFJeqBG.js +1 -0
  198. package/src/console/ui-next/dist/assets/call-pii-button-CVAONPii.js +1 -0
  199. package/src/console/ui-next/dist/assets/collapsible-D2A6NJ-3.js +1 -0
  200. package/src/console/ui-next/dist/assets/copy-inline-button-CAYD18cr.js +1 -0
  201. package/src/console/ui-next/dist/assets/dagre.esm-B1_XeuLP.js +1 -0
  202. package/src/console/ui-next/dist/assets/detail-header-DVWNjWjg.js +1 -0
  203. package/src/console/ui-next/dist/assets/dropdown-menu-4h2LOVXM.js +1 -0
  204. package/src/console/ui-next/dist/assets/duration-tone-Cgk_h5ja.js +9 -0
  205. package/src/console/ui-next/dist/assets/element-icons-BI8cJgdh.js +1 -0
  206. package/src/console/ui-next/dist/assets/explorer-empty-CJs5A-wm.js +1 -0
  207. package/src/console/ui-next/dist/assets/flows-page-Dss7941e.js +1 -0
  208. package/src/console/ui-next/dist/assets/highlighted-json-MYZQtRnw.js +154 -0
  209. package/src/console/ui-next/dist/assets/http-method-Jrh39p7A.js +1 -0
  210. package/src/console/ui-next/dist/assets/index-D0zS5rKO.css +2 -0
  211. package/src/console/ui-next/dist/assets/index-DXP2dBIF.js +63 -0
  212. package/src/console/ui-next/dist/assets/observability-page-HvolXxTI.js +4 -0
  213. package/src/console/ui-next/dist/assets/react-dom-Ddte4I-Q.js +9 -0
  214. package/src/console/ui-next/dist/assets/replica-lag-CSh2dzrb.js +18 -0
  215. package/src/console/ui-next/dist/assets/request-meta-BatF8KrK.js +1 -0
  216. package/src/console/ui-next/dist/assets/shortcut-keys-3ILd8oGn.js +1 -0
  217. package/src/console/ui-next/dist/assets/{sql-BskegiFM.js → sql-BsFa4tDR.js} +1 -1
  218. package/src/console/ui-next/dist/assets/store-page-eiKiHnNe.js +41 -0
  219. package/src/console/ui-next/dist/assets/trace-detail-sheet-CZkMeKS-.js +2 -0
  220. package/src/console/ui-next/dist/assets/tree-expand-toggle-CW8y5A2h.js +55 -0
  221. package/src/console/ui-next/dist/assets/units-page-B_RWJrEO.js +1 -0
  222. package/src/console/ui-next/dist/assets/{use-vault-list-uk4WVboC.js → use-vault-list-CT4-gajj.js} +1 -1
  223. package/src/console/ui-next/dist/assets/vault-page-CWrg-A68.js +2 -0
  224. package/src/console/ui-next/dist/assets/xyflow-CSyC6ryz.css +1 -0
  225. package/src/console/ui-next/dist/assets/xyflow-yApv7D4e.js +7 -0
  226. package/src/console/ui-next/dist/index.html +6 -13
  227. package/src/console/ui-next/seed-invoke-host.ts +21 -18
  228. package/src/console/ui-next/src/client.ts +7 -2
  229. package/src/console/ui-next/src/features/flows/graph/element-map.ts +2 -0
  230. package/src/console/ui-next/src/features/flows/traces/effect-kind.ts +12 -2
  231. package/src/console/ui-next/src/features/flows/traces/effect-summary.ts +4 -0
  232. package/src/console/ui-next/src/features/flows/traces/trace-detail-sheet.tsx +8 -0
  233. package/src/console/ui-next/src/features/flows/traces/waterfall-bars.ts +4 -0
  234. package/src/console/ui-next/src/features/flows/traces/waterfall-tooltip.ts +9 -3
  235. package/src/console/ui-next/src/features/store/detail/reveal-cell.tsx +7 -11
  236. package/src/console/ui-next/src/features/store/detail/store-row-detail-sheet.tsx +2 -2
  237. package/src/console/ui-next/src/features/store/lib/fields-from-table.ts +2 -0
  238. package/src/console/ui-next/src/features/store/lib/grid-model.test.ts +25 -1
  239. package/src/console/ui-next/src/features/store/lib/grid-model.ts +36 -1
  240. package/src/console/ui-next/src/features/store/query/query-results.tsx +3 -3
  241. package/src/console/ui-next/src/features/units/detail/effects-summary.tsx +2 -0
  242. package/src/console/ui-next/src/features/units/lib/call-read-safe.ts +3 -1
  243. package/src/console/ui-next/src/features/units/lib/fields-from-schema.ts +6 -0
  244. package/src/docker/ai-model-status.test.ts +1 -12
  245. package/src/docker/ai-model-status.ts +10 -38
  246. package/src/docker/compose-up.test.ts +100 -0
  247. package/src/docker/compose-up.ts +292 -0
  248. package/src/docker/compose.ts +4 -14
  249. package/src/docker/derive.ts +9 -34
  250. package/src/docker/docker.test.ts +16 -261
  251. package/src/docker/images-config.test.ts +13 -25
  252. package/src/docker/index.ts +1 -24
  253. package/src/docker/recipes/index.ts +0 -23
  254. package/src/docker/recipes/pgdog.ts +6 -4
  255. package/src/docker/stack-id.test.ts +2 -2
  256. package/src/docker/stack-id.ts +0 -1
  257. package/src/docker/types.ts +2 -2
  258. package/src/drivers/ai-anthropic.ts +10 -0
  259. package/src/drivers/ai-openai-compatible.ts +34 -7
  260. package/src/drivers/ai-providers.test.ts +0 -107
  261. package/src/drivers/ai-stream.test.ts +0 -34
  262. package/src/drivers/ai-types.ts +17 -8
  263. package/src/drivers/channel-fcm.ts +6 -1
  264. package/src/drivers/channel-msegat.ts +6 -1
  265. package/src/drivers/channel-resend.ts +5 -1
  266. package/src/drivers/channel-smtp.ts +5 -1
  267. package/src/drivers/channel-sndr.ts +10 -1
  268. package/src/drivers/channel-taqnyat-mail.ts +5 -1
  269. package/src/drivers/channel-taqnyat-whatsapp.ts +6 -1
  270. package/src/drivers/channel-taqnyat.ts +6 -1
  271. package/src/drivers/channel-types.ts +10 -0
  272. package/src/drivers/channel-unifonic.ts +6 -1
  273. package/src/drivers/channel-wa-cloud.ts +6 -1
  274. package/src/drivers/channel-webpush.ts +6 -1
  275. package/src/drivers/external.ts +33 -0
  276. package/src/drivers/index.ts +0 -10
  277. package/src/drivers/meilisearch.ts +6 -0
  278. package/src/drivers/oauth-types.ts +4 -0
  279. package/src/drivers/postgres.test.ts +74 -3
  280. package/src/drivers/postgres.ts +175 -6
  281. package/src/drivers/signal-types.ts +5 -5
  282. package/src/drivers/types.ts +7 -0
  283. package/src/drivers/vault-types.ts +5 -0
  284. package/src/elements/ai/declare.ts +17 -4
  285. package/src/elements/ai/eval.ts +1 -1
  286. package/src/elements/ai/mcp-http.ts +1 -1
  287. package/src/elements/ai/pii.ts +1 -1
  288. package/src/elements/ai/providers.test.ts +289 -0
  289. package/src/elements/ai/providers.ts +169 -0
  290. package/src/elements/ai/runtime.ts +68 -5
  291. package/src/elements/ai/schema.ts +2 -2
  292. package/src/elements/ai.test.ts +7 -7
  293. package/src/elements/ai.ts +17 -1
  294. package/src/elements/channel/runtime.ts +105 -12
  295. package/src/elements/clock/cron-fields.test.ts +144 -0
  296. package/src/elements/clock/cron-fields.ts +185 -0
  297. package/src/elements/clock/declare.ts +247 -3
  298. package/src/elements/clock.ts +21 -1
  299. package/src/elements/index.ts +15 -0
  300. package/src/elements/signal/chaos-child.ts +1 -2
  301. package/src/elements/signal/declare.ts +65 -37
  302. package/src/elements/signal/delivery-modes.test.ts +11 -31
  303. package/src/elements/signal/dry-run-replay.test.ts +1 -7
  304. package/src/elements/signal/dry-run-write-isolation.test.ts +1 -7
  305. package/src/elements/signal/key-ordering.test.ts +6 -26
  306. package/src/elements/signal/lease-reclaim.test.ts +2 -6
  307. package/src/elements/signal/optional-emit.test.ts +6 -9
  308. package/src/elements/signal/order-lifecycle.test.ts +4 -17
  309. package/src/elements/signal/orphan-messages.test.ts +4 -15
  310. package/src/elements/signal/reconcile.test.ts +2 -2
  311. package/src/elements/signal/runtime.ts +1 -1
  312. package/src/elements/signal/schema-emit.test.ts +4 -8
  313. package/src/elements/signal.test.ts +24 -49
  314. package/src/elements/signal.ts +9 -2
  315. package/src/elements/store/domain-ddl.test.ts +1 -1
  316. package/src/elements/store/live-http.test.ts +9 -4
  317. package/src/elements/store/prepare-row.test.ts +123 -0
  318. package/src/elements/store/resource.ts +43 -12
  319. package/src/elements/store/schema-decl.ts +117 -0
  320. package/src/elements/store/search-backfill.ts +205 -0
  321. package/src/elements/store/search-bind.ts +66 -0
  322. package/src/elements/store/search-bm25.ts +78 -0
  323. package/src/elements/store/search-ddl.ts +156 -0
  324. package/src/elements/store/search-embed-flow.ts +141 -0
  325. package/src/elements/store/search-errors.ts +34 -0
  326. package/src/elements/store/search-fusion.ts +112 -0
  327. package/src/elements/store/search-lsh.ts +179 -0
  328. package/src/elements/store/search-runtime.ts +300 -0
  329. package/src/elements/store/search.test.ts +144 -0
  330. package/src/elements/store/sql-session.test.ts +1 -0
  331. package/src/elements/store/sql-session.ts +83 -3
  332. package/src/elements/store/table.ts +23 -2
  333. package/src/elements/store/upsert-app.test.ts +1 -3
  334. package/src/elements/store.ts +50 -0
  335. package/src/full.ts +4 -2
  336. package/src/http.ts +4 -1
  337. package/src/i18n/catalogs/ar.ts +14 -6
  338. package/src/i18n/catalogs/en.ts +14 -6
  339. package/src/index.ts +6 -1
  340. package/src/kernel/adopt-barrel-fresh.test.ts +7 -7
  341. package/src/kernel/adopt-routes.ts +9 -1
  342. package/src/kernel/app-auth.ts +5 -0
  343. package/src/kernel/app.ts +102 -9
  344. package/src/kernel/auto-cache.test.ts +6 -12
  345. package/src/kernel/auto-registry.test.ts +3 -3
  346. package/src/kernel/boot-bind/ai.test.ts +22 -19
  347. package/src/kernel/boot-bind/ai.ts +5 -43
  348. package/src/kernel/boot-bind/clock.ts +23 -5
  349. package/src/kernel/boot-bind/honor-config.test.ts +4 -4
  350. package/src/kernel/boot.test.ts +11 -6
  351. package/src/kernel/boot.ts +66 -16
  352. package/src/kernel/boundary-contract.ts +93 -0
  353. package/src/kernel/budget.test.ts +1 -1
  354. package/src/kernel/call.ts +89 -0
  355. package/src/kernel/capability.ts +6 -0
  356. package/src/kernel/client-descriptor.ts +123 -0
  357. package/src/kernel/clock-timezone.test.ts +80 -0
  358. package/src/kernel/correlation.test.ts +1 -1
  359. package/src/kernel/dry-run.ts +11 -8
  360. package/src/kernel/effects-stamping.test.ts +42 -9
  361. package/src/kernel/effects.test.ts +4 -2
  362. package/src/kernel/effects.ts +51 -9
  363. package/src/kernel/errors-channel.ts +17 -0
  364. package/src/kernel/errors-live-resume.ts +3 -2
  365. package/src/kernel/errors-tenant.ts +7 -4
  366. package/src/kernel/errors.registry-helpers.ts +96 -0
  367. package/src/kernel/errors.registry.test.ts +139 -25
  368. package/src/kernel/errors.ts +102 -23
  369. package/src/kernel/external-effects.test.ts +196 -0
  370. package/src/kernel/flow.test.ts +13 -4
  371. package/src/kernel/flow.ts +69 -71
  372. package/src/kernel/fx-ask-telemetry.test.ts +2 -2
  373. package/src/kernel/fx-dead-letters.test.ts +3 -3
  374. package/src/kernel/fx-fetch.ts +55 -0
  375. package/src/kernel/fx-live-stream.ts +2 -2
  376. package/src/kernel/fx-live.test.ts +8 -8
  377. package/src/kernel/fx.test.ts +17 -11
  378. package/src/kernel/fx.ts +180 -57
  379. package/src/kernel/horizontal-child.ts +1 -1
  380. package/src/kernel/http-query.test.ts +3 -6
  381. package/src/kernel/index.ts +13 -3
  382. package/src/kernel/instance-id.ts +1 -1
  383. package/src/kernel/instances.test.ts +40 -0
  384. package/src/kernel/instances.ts +47 -9
  385. package/src/kernel/live-http.test.ts +6 -7
  386. package/src/kernel/live-http.ts +6 -2
  387. package/src/kernel/live-resume.test.ts +1 -1
  388. package/src/kernel/mcp-tool.test.ts +3 -3
  389. package/src/kernel/on.ts +98 -4
  390. package/src/kernel/pipeline.test.ts +12 -15
  391. package/src/kernel/plugin-elements.test.ts +1 -1
  392. package/src/kernel/stamp-http.test.ts +3 -3
  393. package/src/kernel/triggers.ts +210 -95
  394. package/src/kernel-entry.ts +0 -1
  395. package/src/manifest/diff.ts +11 -1
  396. package/src/manifest/fixtures/skyport.excerpt.json +1 -1
  397. package/src/manifest/types.ts +46 -2
  398. package/src/mcp/docs-index.ts +3 -3
  399. package/src/mcp/docs-mcp.test.ts +2 -2
  400. package/src/mcp/docs-tools.ts +1 -1
  401. package/src/okid.test.ts +56 -0
  402. package/src/okid.ts +55 -11
  403. package/src/plugins/anonymous.ts +8 -4
  404. package/src/plugins/auth/shared.ts +27 -3
  405. package/src/plugins/auth-delivery.mailpit.integration.test.ts +1 -1
  406. package/src/plugins/auth-methods.security.test.ts +561 -23
  407. package/src/plugins/config-source.ts +1 -1
  408. package/src/plugins/csrf.test.ts +65 -0
  409. package/src/plugins/index.ts +2 -0
  410. package/src/plugins/magic-link.ts +36 -16
  411. package/src/plugins/oauth/shared.ts +3 -1
  412. package/src/plugins/oauth.ts +22 -14
  413. package/src/plugins/otp.ts +37 -21
  414. package/src/plugins/passkey-webauthn.ts +9 -6
  415. package/src/plugins/passkey.ts +98 -26
  416. package/src/plugins/pre-account-hijack.test.ts +223 -0
  417. package/src/plugins/two-factor.ts +466 -37
  418. package/src/plugins/username.ts +19 -7
  419. package/src/release/build-lib.ts +1 -0
  420. package/src/release/limits.ts +2 -2
  421. package/src/release/measure.ts +1 -1
  422. package/src/runs/collect.test.ts +0 -2
  423. package/src/runtime/json-code-block.test.ts +250 -20
  424. package/src/runtime/json-code-block.ts +1261 -41
  425. package/src/term.test.ts +1 -1
  426. package/src/test/create-test-app.test.ts +12 -12
  427. package/src/test/live-signals.test.ts +6 -6
  428. package/src/test/provisions.integration.test.ts +10 -14
  429. package/src/test/reset-element-registries.ts +1 -1
  430. package/src/test/tenant-isolation.test.ts +12 -6
  431. package/site/content/docs/deployment/docker-swarm.mdx +0 -164
  432. package/site/content/docs/deployment/docker.mdx +0 -227
  433. package/site/content/docs/deployment/index.mdx +0 -83
  434. package/site/content/docs/deployment/kubernetes.mdx +0 -176
  435. package/site/content/docs/deployment/meta.json +0 -5
  436. package/site/content/docs/deployment/reverse-proxy.mdx +0 -234
  437. package/site/content/docs/elements/ai.mdx +0 -385
  438. package/site/content/docs/elements/channel.mdx +0 -346
  439. package/site/content/docs/elements/clock.mdx +0 -244
  440. package/site/content/docs/elements/flow.mdx +0 -420
  441. package/site/content/docs/elements/gate.mdx +0 -436
  442. package/site/content/docs/elements/signal.mdx +0 -380
  443. package/site/content/docs/elements/store.mdx +0 -1099
  444. package/site/content/docs/elements/vault.mdx +0 -405
  445. package/site/content/docs/get-started/basic-usage.mdx +0 -173
  446. package/site/content/docs/get-started/index.mdx +0 -43
  447. package/site/content/docs/get-started/installation.mdx +0 -220
  448. package/site/content/docs/get-started/introduction.mdx +0 -144
  449. package/site/content/docs/get-started/meta.json +0 -13
  450. package/site/content/docs/get-started/project-structure.mdx +0 -925
  451. package/site/content/docs/get-started/testing.mdx +0 -328
  452. package/site/content/docs/get-started/why.mdx +0 -114
  453. package/site/content/docs/recipes/llama-cpp.mdx +0 -151
  454. package/site/content/docs/recipes/ollama.mdx +0 -142
  455. package/site/content/docs/recipes/sglang.mdx +0 -105
  456. package/site/content/docs/recipes/vllm.mdx +0 -106
  457. package/site/content/docs/reference/cli.md +0 -232
  458. package/site/content/docs/reference/client.mdx +0 -469
  459. package/site/content/docs/reference/security.md +0 -74
  460. package/src/cli/ai-setup/detect-ollama.ts +0 -213
  461. package/src/cli/ai-setup/recommend.test.ts +0 -225
  462. package/src/cli/ai-setup/recommend.ts +0 -225
  463. package/src/cli/dev-controls.test.ts +0 -122
  464. package/src/cli/dev-controls.ts +0 -164
  465. package/src/cli/tui/DevLive.tsx +0 -126
  466. package/src/console/ui-next/dist/assets/access-page-3-EFj-2G.js +0 -4
  467. package/src/console/ui-next/dist/assets/agent-disclosure-BP0Y0Sux.js +0 -1
  468. package/src/console/ui-next/dist/assets/cache-glyph-B5X-NM0-.js +0 -1
  469. package/src/console/ui-next/dist/assets/call-pii-button-ChAUiLo9.js +0 -1
  470. package/src/console/ui-next/dist/assets/collapsible-DGnOM2ph.js +0 -1
  471. package/src/console/ui-next/dist/assets/copy-inline-button-DBHhgHKP.js +0 -1
  472. package/src/console/ui-next/dist/assets/dagre.esm-ZwcdTuZZ.js +0 -1
  473. package/src/console/ui-next/dist/assets/detail-header-DhHM1iaZ.js +0 -1
  474. package/src/console/ui-next/dist/assets/dropdown-menu-_NjTEo5_.js +0 -1
  475. package/src/console/ui-next/dist/assets/duration-tone-sC3lGABz.js +0 -9
  476. package/src/console/ui-next/dist/assets/element-icons-BVXtRyd3.js +0 -1
  477. package/src/console/ui-next/dist/assets/explorer-empty-2uIhBu0_.js +0 -1
  478. package/src/console/ui-next/dist/assets/flows-page-cVFnA4HH.js +0 -1
  479. package/src/console/ui-next/dist/assets/highlighted-json-Awq7gYdu.js +0 -154
  480. package/src/console/ui-next/dist/assets/http-method-_UHM2ODJ.js +0 -1
  481. package/src/console/ui-next/dist/assets/index-CMIgUbD0.js +0 -66
  482. package/src/console/ui-next/dist/assets/index-Ck88Jmv8.css +0 -2
  483. package/src/console/ui-next/dist/assets/link-BX6Vqztd.js +0 -1
  484. package/src/console/ui-next/dist/assets/observability-page-CQ3p34ip.js +0 -4
  485. package/src/console/ui-next/dist/assets/preload-helper-oH4irX4C.js +0 -1
  486. package/src/console/ui-next/dist/assets/react-D8E3mtu1.js +0 -1
  487. package/src/console/ui-next/dist/assets/react-dom-Bph1y7z7.js +0 -9
  488. package/src/console/ui-next/dist/assets/replica-lag-DKRrbvdo.js +0 -18
  489. package/src/console/ui-next/dist/assets/request-meta-DV0ywz7t.js +0 -1
  490. package/src/console/ui-next/dist/assets/shortcut-JQIZlWfm.js +0 -1
  491. package/src/console/ui-next/dist/assets/shortcut-keys-DKxNTe_m.js +0 -1
  492. package/src/console/ui-next/dist/assets/skeleton-D-czQJT6.js +0 -1
  493. package/src/console/ui-next/dist/assets/store-page-02xOiqIK.js +0 -41
  494. package/src/console/ui-next/dist/assets/trace-detail-sheet-B09O8rA6.js +0 -2
  495. package/src/console/ui-next/dist/assets/tree-expand-toggle-BtyhmWb4.js +0 -55
  496. package/src/console/ui-next/dist/assets/units-page-l8FeKfnP.js +0 -1
  497. package/src/console/ui-next/dist/assets/useMutation-B8EO02Ej.js +0 -1
  498. package/src/console/ui-next/dist/assets/useRender-BE2A9BWC.js +0 -1
  499. package/src/console/ui-next/dist/assets/vault-page-CL-d_mLE.js +0 -2
  500. package/src/console/ui-next/dist/assets/xyflow-D7n4g6go.js +0 -7
  501. package/src/console/ui-next/dist/assets/xyflow-DZ0Ws1xk.css +0 -1
  502. package/src/docker/ollama-pull.ts +0 -232
  503. package/src/docker/recipes/llama-cpp.ts +0 -298
  504. package/src/docker/recipes/ollama.ts +0 -44
  505. package/src/docker/recipes/sglang.ts +0 -55
  506. package/src/docker/recipes/vllm.ts +0 -44
  507. package/src/drivers/ai-ollama-tools.integration.test.ts +0 -109
  508. package/src/drivers/ai-ollama.integration.test.ts +0 -184
  509. package/src/drivers/ai-ollama.ts +0 -389
  510. package/src/drivers/ollama.ts +0 -14
@@ -0,0 +1,618 @@
1
+ ---
2
+ title: "Overview"
3
+ description: "One Flow species for HTTP, Signal, Clock, CDC, and call-only work — contracts, fx, and options in one place."
4
+ icon: "Workflow"
5
+ source: "docs/spec/unified-theory.md"
6
+ ---
7
+
8
+ Flow is the element for **behavior**. An HTTP endpoint, a Signal worker, a named Clock tick, a SQL change handler, and a multi-step checkout are the same shape: `on(trigger, flow)`. Only the trigger changes.
9
+
10
+ For developers writing backend work on okengine — put the invoke contract on the exposure
11
+ (`http.*` / `call` / `mcp.tool`), keep `do` on `fx`.
12
+
13
+ <Callout title="The one rule">
14
+ All world access goes through `fx`. A direct `fetch`, `Date.now()`, or `node:` import inside `do`
15
+ is a defect. Effects are inferred from what the Flow touches through `fx` — that inference powers
16
+ the Manifest, Console, cache, and durability.
17
+ </Callout>
18
+
19
+ <FlowShape />
20
+
21
+ ## Smallest Example
22
+
23
+ <Steps>
24
+
25
+ <Step>
26
+ ### Define a Flow
27
+
28
+ ```typescript title="src/flows/main/health.ts"
29
+ import { on, flow, http } from "okengine";
30
+
31
+ export const health = on(
32
+ http.get().public(),
33
+ flow({
34
+ do: () => ({ ok: true }),
35
+ }),
36
+ );
37
+ ```
38
+
39
+ </Step>
40
+
41
+ <Step>
42
+ ### Call it
43
+
44
+ ```bash
45
+ curl -X GET http://localhost:6530/health -H "accept: application/json"
46
+ ```
47
+
48
+ Response:
49
+
50
+ ```json
51
+ {
52
+ "data": { "ok": true },
53
+ "error": null
54
+ }
55
+ ```
56
+
57
+ </Step>
58
+
59
+ </Steps>
60
+
61
+ <Callout title="Omit path and name">
62
+ Tree default: `http.get()` + `flow({ do })` — no path or name strings. Pass
63
+ either only for
64
+ [control](/docs/elements/flow/routing#when-to-omit--when-to-pass).
65
+ </Callout>
66
+
67
+ <Callout title="Call-only Flows">
68
+ Use `call("payments.charge", { in, out, do, … })` for internal callees — same species as
69
+ `flow`, with the invoke contract on the bag. Nothing outside your code can start it unless you
70
+ also bind a trigger. Other Flows invoke it with `fx.call(flowRef, input)`.
71
+ </Callout>
72
+ ## Progressive Patterns
73
+
74
+ Same `on` + `flow` + `do` from a ping to a typed failure to a private callee:
75
+
76
+ <Tabs items={["Minimal", "Validated", "Failures", "Call-only"]}>
77
+
78
+ <Tab value="Minimal">
79
+
80
+ Return a value. HTTP wraps it as `{ data, error: null }`:
81
+
82
+ ```typescript title="src/flows/main/ping.ts"
83
+ import { on, flow, http } from "okengine";
84
+
85
+ export const ping = on(
86
+ http.get().public(),
87
+ flow({
88
+ do: () => ({ status: "ok" }),
89
+ }),
90
+ );
91
+ ```
92
+
93
+ </Tab>
94
+
95
+ <Tab value="Validated">
96
+
97
+ `in` / `out` live on the HTTP bag. Invalid input never enters `do`:
98
+
99
+ ```typescript title="src/flows/notes/create.ts"
100
+ import { on, flow, http } from "okengine";
101
+ import { z } from "zod";
102
+
103
+ export const create = on(
104
+ http.post({
105
+ in: z.object({ title: z.string().min(1) }),
106
+ out: z.object({ id: z.string(), title: z.string() }),
107
+ }),
108
+ flow({
109
+ do: async ({ title }, fx) => {
110
+ const id = fx.id();
111
+ return { id, title };
112
+ },
113
+ }),
114
+ );
115
+ ```
116
+
117
+ </Tab>
118
+
119
+ <Tab value="Failures">
120
+
121
+ Declare domain errors on the exposure bag and return `fx.fail` — do not throw for expected failures:
122
+
123
+ ```typescript title="src/flows/orders/[id]/get.ts"
124
+ import { on, flow, http } from "okengine";
125
+ import { z } from "zod";
126
+ import { eq } from "drizzle-orm";
127
+ import { db, orders } from "@/schema";
128
+
129
+ export const get = on(
130
+ http.get({
131
+ in: z.object({ id: z.string() }),
132
+ out: z.object({ id: z.string(), sku: z.string(), qty: z.number() }),
133
+ errors: { NotFound: z.object({ id: z.string() }) },
134
+ }),
135
+ flow({
136
+ do: async ({ id }, fx) => {
137
+ const [order] = await fx.store(db).select().from(orders).where(eq(orders.id, id));
138
+ if (!order) return fx.fail("NotFound", { id });
139
+ return order;
140
+ },
141
+ }),
142
+ );
143
+ ```
144
+
145
+ </Tab>
146
+
147
+ <Tab value="Call-only">
148
+
149
+ Use `call(name, { … })` — contract and `do` on one bag. The parent records `calls: ["payments.charge"]`.
150
+ `fx.call` waits for the callee:
151
+
152
+ ```typescript title="src/flows/payments/charge.ts"
153
+ import { call } from "okengine";
154
+ import { z } from "zod";
155
+ import { db, charges } from "@/schema";
156
+
157
+ export const chargeCard = call("payments.charge", {
158
+ in: z.object({ amount: z.number() }),
159
+ out: z.object({ chargeId: z.string() }),
160
+ do: async ({ amount }, fx) => {
161
+ const chargeId = fx.id();
162
+ await fx.store(db).insert(charges).values({ id: chargeId, amount });
163
+ return { chargeId };
164
+ },
165
+ });
166
+ ```
167
+
168
+ ```typescript
169
+ const { chargeId } = await fx.call(chargeCard, { amount: 50 });
170
+ ```
171
+
172
+ </Tab>
173
+
174
+ </Tabs>
175
+
176
+ ## Trigger Reference
177
+
178
+ `flow`, `do`, and `fx` never change. Bind a different trigger:
179
+
180
+ <FlowTriggers />
181
+
182
+ | Trigger | Bind | Starts when | `do` input |
183
+ | --------- | ---------------------------------------------- | ------------------- | -------------------------- |
184
+ | HTTP | `on(http.get(), flow)` | A request | Merged path / query / body |
185
+ | Signal | `on(signalHandle, flow)` | `fx.emit` | Payload (`schema`) |
186
+ | Clock | `on(clockDecl, flow)` | Scheduler tick | none (`_`) |
187
+ | CDC | `on(db.table(t).changed(), flow)` | Committed SQL write | `{ before, after }` |
188
+ | Call-only | `call("name", { in, out, do, … })` | `fx.call` | Callee `in` |
189
+ | MCP | `on(mcp.tool("x", { in, out }).gate(…), flow)` | MCP `tools/call` | Tool args |
190
+
191
+ `signal.live` is an HTTP SSE tape — bind it with [`http.live`](/docs/elements/flow/http#live-streams), not as a worker.
192
+
193
+ ## The Capabilities of Flow
194
+
195
+ <Cards>
196
+ <Card
197
+ title="HTTP"
198
+ description="REST verbs, RFC 10008 QUERY, CRUD mounts, and live SSE."
199
+ href="/docs/elements/flow/http"
200
+ />
201
+ <Card
202
+ title="Routing"
203
+ description="File-tree stamps for HTTP paths, Flow names, and client units."
204
+ href="/docs/elements/flow/routing"
205
+ />
206
+ <Card
207
+ title="Consumers"
208
+ description="Signal workers, named Clock jobs, and SQL CDC — one species."
209
+ href="/docs/elements/flow/consumers"
210
+ />
211
+ <Card
212
+ title="Durable Workflows"
213
+ description="fx.step replay, LIFO undo, durable sleep, and crash resume."
214
+ href="/docs/elements/flow/workflows"
215
+ />
216
+ </Cards>
217
+
218
+ ## Options Reference
219
+
220
+ Second argument to `flow(name, options)` — or the only argument to a nameless `flow({ do })`.
221
+ Invoke contracts (`in` / `out` / `errors` / `breaking`) belong on the exposure — see
222
+ [Contracts](#contracts) below.
223
+
224
+ | Option | Type | Default | Meaning |
225
+ | -------------- | -------------------------------------- | ------------------------- | ------------------------------------------------------------------------------- |
226
+ | `do` | `(input, fx) => output \| FlowFailure` | _(required)_ | Handler. Missing `do` throws `flow() expected an options bag with a do handler` |
227
+ | `durable` | `boolean` | `false` | Journal `fx.step` / sleep / gated `fx` calls |
228
+ | `retry` | `FxRetryOptions` | omitted | Whole-`do` retry on throw (same journal when durable) |
229
+ | `cache` | `boolean \| string` | omitted (auto) | Read-only Flows cache automatically; `false` opts out; `"30s"` adds TTL |
230
+ | `compensate` | `(ctx, fx) => unknown` | omitted | After LIFO `{ undo }`, before the run commits `failed` |
231
+ | `plane` | `"user" \| "operator"` | `"user"` | Operator bypasses RLS; user must not `fx.call` operator |
232
+ | `effects` | `Effects` | inferred | Capability token — write this only when inference cannot see the body |
233
+ | `slo` | `{ availability?, latency? }` | omitted | Manifest metadata (Console / docs) |
234
+ | `tenantScoped` | `boolean` | `true` when tenancy is on | `false` skips tenant-role scope union |
235
+
236
+ **Consequence:** `durable: true` disables automatic read-cache for that Flow.
237
+
238
+ ## Contracts
239
+
240
+ <Callout title="Detailed section">
241
+ Invoke contracts live on the **exposure** — `http.post({ in, out, errors })`, `call("name", {
242
+ in, out, do })`, or `mcp.tool("x", { in, out })`. The Manifest still shows flat
243
+ `flows.*.{in,out,errors,breaking}` as a projection from that exposure. `in` runs before `do`;
244
+ `out` runs after a successful return. `fx.fail` skips `out`. Signal / Channel `schema` is a
245
+ separate **emit** contract (validated at `fx.emit` / `fx.send`).
246
+ </Callout>
247
+
248
+ <Tabs items={["Standard Schema", "Failures", "Envelope"]}>
249
+
250
+ <Tab value="Standard Schema">
251
+
252
+ Any library with `~standard` (Standard Schema V1) works. Zod is the usual choice:
253
+
254
+ ```typescript
255
+ import { on, flow, http } from "okengine";
256
+ import { z } from "zod";
257
+
258
+ on(
259
+ http.post({
260
+ in: z.object({ sku: z.string(), qty: z.number().int().min(1) }),
261
+ out: z.object({ id: z.string() }),
262
+ }),
263
+ flow({
264
+ do: async (input, fx) => ({ id: fx.id() }),
265
+ }),
266
+ );
267
+ ```
268
+
269
+ Valibot (`v.object`) and ArkType (`type({…})`) bind the same way. Shared DTOs belong in
270
+ `shapes.ts` next to the unit — that filename is never a route.
271
+
272
+ </Tab>
273
+
274
+ <Tab value="Failures">
275
+
276
+ Errors at the Flow boundary are **values**. Throw only for bugs. Declare `errors` on the
277
+ exposure and return from `do`:
278
+
279
+ ```typescript
280
+ call("orders.create", {
281
+ in: z.object({ sku: z.string(), qty: z.number().int().min(1) }),
282
+ out: z.object({ id: z.string() }),
283
+ errors: {
284
+ OutOfStock: z.object({ available: z.number() }),
285
+ },
286
+ do: async (input, fx) => {
287
+ const [row] = await fx.store(db).select().from(stock).where(eq(stock.sku, input.sku));
288
+ if (!row || row.available < input.qty) {
289
+ return fx.fail("OutOfStock", { available: row?.available ?? 0 });
290
+ }
291
+ return { id: fx.id() };
292
+ },
293
+ });
294
+ ```
295
+
296
+ `fx.fail(code, data, { message? })` builds `{ data: null, error: { code, data, message? } }`.
297
+ The typed client narrows on `res.error.code`.
298
+
299
+ </Tab>
300
+
301
+ <Tab value="Envelope">
302
+
303
+ HTTP success from a returned value is `200` + `{ data, error: null }`. `undefined` is
304
+ `204` with an empty body. Typed failures use `{ data: null, error }`:
305
+
306
+ ```json
307
+ {
308
+ "data": null,
309
+ "error": {
310
+ "code": "OutOfStock",
311
+ "data": { "available": 0 }
312
+ }
313
+ }
314
+ ```
315
+
316
+ Status for `error.code`:
317
+
318
+ | Code | Status |
319
+ | ----------------------------------------------------- | ------ |
320
+ | `ValidationError` | `422` |
321
+ | `Unauthorized` | `401` |
322
+ | `Forbidden` | `403` |
323
+ | `RateLimited` | `429` |
324
+ | Any other declared code (`NotFound`, `OutOfStock`, …) | `400` |
325
+
326
+ A bare `404` with body `Not Found` means **no route matched** — not `fx.fail("NotFound")`.
327
+
328
+ </Tab>
329
+
330
+ </Tabs>
331
+
332
+ <Accordions>
333
+
334
+ <Accordion title="store.resource schemas">
335
+ `store.resource(db, table, { in, out })` requires `in` (create body) and `out` (item
336
+ shape). List / get / update / remove Flows are built for you — contracts are stamped
337
+ from the resource factory. Handwritten invoke contracts go on `http.*` / `call` /
338
+ `mcp.tool` — see [HTTP · Resources](/docs/elements/flow/http#resources).
339
+ </Accordion>
340
+
341
+ <Accordion title="ValidationError payload">
342
+ Failed `in` (or `out`) is `ValidationError` with `error.data.issues` — each issue has `message`
343
+ and `path`. HTTP status is **422**. The handler never ran.
344
+ </Accordion>
345
+
346
+ <Accordion title="Name stamping">
347
+ Prefer nameless `flow({ do })` on tree files — the file stamps `unit.export`.
348
+ Pass `flow("notes.create", { … })` only for control. Nameless HTTP after adopt
349
+ fails **OKE1045** — see [Routing](/docs/elements/flow/routing#when-to-omit--when-to-pass).
350
+ </Accordion>
351
+
352
+ </Accordions>
353
+
354
+ ## The fx door
355
+
356
+ <Callout title="Detailed section">
357
+ If you only need store / emit, jump to the table. `fx` is the only I/O surface inside `do`. The
358
+ compiler records what you touch as `effects` on the Manifest.
359
+ </Callout>
360
+
361
+ | Call | Records | Use |
362
+ | -------------------------- | -------------------------- | --------------------------------------------- |
363
+ | `fx.store(db)` | `reads` / `writes` `sql:…` | SQL (and other Store facets) |
364
+ | `fx.emit(signal, payload)` | `emits` | Signal outbox |
365
+ | `fx.send(template, opts)` | `sends` | Channel template |
366
+ | `fx.ask(prompt, opts)` | `asks` | AI prompt |
367
+ | `fx.vault.get(secret)` | `secrets` | Declared secret (never a raw value in source) |
368
+ | `fx.call(flow, input?)` | `calls` | Another Flow — waits for return |
369
+ | `fx.id()` | — | UUID |
370
+ | `fx.clock.now()` | — | Deterministic time |
371
+ | `fx.fail(code, data)` | — | Typed failure value |
372
+ | `fx.step(name, fn)` | journal | Durable checkpoint |
373
+
374
+ <Accordions>
375
+
376
+ <Accordion title="Side channels">
377
+ `Date.now()`, `new Date()`, `setTimeout`, global `fetch`, and `node:fs` skip the ledger.
378
+ Tests cannot time-travel; durable replay cannot skip the work; cache cannot see the read.
379
+
380
+ **Fix:** `fx.clock.now()`, `fx.store`, `fx.send`, or wrap a provider in `fx.step`.
381
+
382
+ </Accordion>
383
+
384
+ <Accordion title="fx.call identity">
385
+ `fx.call` starts the callee with an **empty** `fx.auth` (fail-closed). `fx.tenant.id` propagates.
386
+ For audit only, read `fx.principal` — gates never consult it. See [fx](/docs/reference/fx).
387
+ </Accordion>
388
+
389
+ <Accordion title="Undeclared effects (OKE1001–1007)">
390
+ Explicit `effects` that drift from the body throw at runtime (`Flow "{flow}" writes "{resource}"
391
+ without declaring it.`). Most apps never write `effects` — inference covers them. **OKE1020** is
392
+ deploy-shaped boot with neither inference nor a block.
393
+ </Accordion>
394
+
395
+ </Accordions>
396
+
397
+ ## Call-only
398
+
399
+ <Callout title="Detailed section">
400
+ Prefer `call("name", { in, out, do, … })`. `internal` exists so call-only is a trigger
401
+ *value* — `on(internal, flow)` — when you need all kinds addressable the same way.
402
+ </Callout>
403
+
404
+ ```typescript title="src/flows/orders/checkout.ts"
405
+ import { on, flow, http } from "okengine";
406
+ import { z } from "zod";
407
+ import { chargeCard } from "@/flows/payments/charge";
408
+
409
+ export const checkout = on(
410
+ http.post({ in: z.object({ sku: z.string() }) }),
411
+ flow({
412
+ do: async ({ sku }, fx) => {
413
+ const { chargeId } = await fx.call(chargeCard, { amount: 50 });
414
+ return { sku, chargeId };
415
+ },
416
+ }),
417
+ );
418
+ ```
419
+
420
+ Do **not** `fx.call` a Flow that parks on `fx.clock.sleep` — the caller receives
421
+ `undefined` and continues; the child wakes later as its own run. Sleep on the root
422
+ durable Flow, or split with `fx.emit`. See [Workflows](/docs/elements/flow/workflows).
423
+
424
+ ## Cache, retry, and plane
425
+
426
+ <Tabs items={["Cache", "Retry", "Plane"]}>
427
+
428
+ <Tab value="Cache">
429
+
430
+ Read-only Flows (Store `reads`, no `writes`, no `asks`, not durable) cache automatically.
431
+ No `cache:` option required. Mutations and `durable: true` stay uncached:
432
+
433
+ ```typescript
434
+ flow("catalog.get", {
435
+ cache: "30s",
436
+ do: async ({ id }, fx) => {
437
+ const [row] = await fx.store(db).select().from(products).where(eq(products.id, id));
438
+ return row;
439
+ },
440
+ });
441
+ ```
442
+
443
+ `cache: false` opts out. A duration string adds TTL on top of write invalidation.
444
+
445
+ </Tab>
446
+
447
+ <Tab value="Retry">
448
+
449
+ `flow({ retry })` re-enters the whole `do`. `retries` is extra attempts after the first.
450
+ Prefer `fx.retry` **inside** `fx.step` so a completed charge never re-runs:
451
+
452
+ ```typescript
453
+ flow({
454
+ retry: { retries: 3, delay: "200ms", backoff: 2 },
455
+ do: async (input, fx) => {
456
+ return await fx.ask(flakyModel, { prompt: input.text });
457
+ },
458
+ });
459
+ ```
460
+
461
+ | `retry` option | Default | Meaning |
462
+ | -------------- | ------------- | ---------------------------------- |
463
+ | `retries` | `0` | Extra attempts after the first |
464
+ | `delay` | `50` (ms) | Initial wait (`"200ms"` allowed) |
465
+ | `backoff` | `2` | Multiplier after each retry |
466
+ | `jitter` | `true` | Full jitter |
467
+ | `when` | thrown errors | Skips abort and durable-sleep park |
468
+
469
+ </Tab>
470
+
471
+ <Tab value="Plane">
472
+
473
+ `"user"` is the application default. `"operator"` is Console — RLS is bypassed,
474
+ `fx.operator` is the principal, `fx.auth` must not appear in that body:
475
+
476
+ ```typescript
477
+ flow("ops.allOrders", {
478
+ plane: "operator",
479
+ do: async (_, fx) => {
480
+ return await fx.store(db).select().from(orders);
481
+ },
482
+ });
483
+ ```
484
+
485
+ A user-plane Flow that `fx.call`s an operator Flow fails compile:
486
+ `cross-plane call: user flow "…" calls operator flow "…"`.
487
+
488
+ </Tab>
489
+
490
+ </Tabs>
491
+
492
+ <Accordions>
493
+
494
+ <Accordion title="compensate context">
495
+ Durable-only. Runs after reverse `{ undo }`, never on success, retry attempts, or sleep
496
+ park. Context: `{ input, error, completedSteps }` — forward step names only. Full
497
+ physics: [Workflows · Compensation](/docs/elements/flow/workflows#compensation).
498
+ </Accordion>
499
+
500
+ <Accordion title="breaking and tenantScoped">
501
+ `breaking: true` on the exposure bag lets `oke doctor --diff` accept that Flow's contract
502
+ break. It does not cover a different Flow.
503
+
504
+ `tenantScoped: false` skips tenant-role scope union even when `fx.tenant.id` is set.
505
+ Default is `true` once `gate.auth.tenant` is on.
506
+
507
+ </Accordion>
508
+
509
+ <Accordion title="Hooks and plugins">
510
+ `flowDef.hook(stage, fn)` registers a per-Flow hook (`onRequest` · `onParse` · `onAuth` ·
511
+ `beforeHandle` · `afterHandle` · `onError` · `onResponse`). `flowDef.plug(plugin)` scopes a plugin
512
+ to that Flow — see [Plugins](/docs/reference/plugins).
513
+ </Accordion>
514
+
515
+ </Accordions>
516
+
517
+ ## Troubleshooting
518
+
519
+ <Accordions>
520
+
521
+ <Accordion title='TypeError: flow() expected an options bag with a do handler'>
522
+ `flow()` requires `{ do }`. `flow("name")` with no options, or a bag without `do`,
523
+ throws at declaration — before `on()`.
524
+ </Accordion>
525
+
526
+ <Accordion title="TypeError: on() expected a trigger or signal handle">
527
+ First argument must be an HTTP trigger, Signal handle, Clock handle,
528
+ `db.table(…).changed()`, `internal`, or `mcp.tool(…)`. A bare interval string is not
529
+ a trigger — wrap it in `clock("name", { every: "1h" })`.
530
+ </Accordion>
531
+
532
+ <Accordion title="TypeError: on() expected a flow() definition as the second argument">
533
+ Second argument must be the object `flow()` returned. Passing a plain function or
534
+ forgetting `flow({ do })` fails here. Resource mounts take **no** second argument —
535
+ see [HTTP · Resources](/docs/elements/flow/http#resources).
536
+ </Accordion>
537
+
538
+ <Accordion title="Direct Date.now, fetch, or node: import inside do">
539
+ Side channels skip effect tracking and durable replay.
540
+
541
+ **Fix:** `fx.clock.now()`, `fx.store`, `fx.send`, or `fx.step` around the provider.
542
+
543
+ </Accordion>
544
+
545
+ <Accordion title="Thrown Error becomes a mystery 500 instead of a typed envelope">
546
+ Uncaught exceptions are defects. Declare the code in `errors` on the exposure and `return
547
+ fx.fail("OutOfStock", payload)` from `do`.
548
+ </Accordion>
549
+
550
+ <Accordion title="422 ValidationError — path param missing from in">
551
+ `http.get("/users/:id")` merges `{id}`. A schema that expects `userId` fails before `do`. Align
552
+ path keys with `in` object keys. See [HTTP · Request
553
+ Parsing](/docs/elements/flow/http#request-parsing).
554
+ </Accordion>
555
+
556
+ <Accordion title="fx.fail('NotFound') is 400, not 404">
557
+ Custom domain codes map to **400**. A bare `404` `Not Found` means the router found no method +
558
+ path. Use `fx.fail` for domain misses; fix the route for missing bindings.
559
+ </Accordion>
560
+
561
+ <Accordion title="Read-only Flow never cache-hits">
562
+ Auto-cache needs Store `reads`, no `writes`, no `asks`, and `durable` off. Empty effect sets stay
563
+ uncached. Opt in with a duration (`cache: "30s"`) only after a real read is inferred — or pass
564
+ `cache: false` to disable.
565
+ </Accordion>
566
+
567
+ <Accordion title='cross-plane call: user flow "…" calls operator flow "…"'>
568
+ User-plane Flows cannot `fx.call` operator Flows. Keep operator work on `plane: "operator"` and
569
+ invoke it from Console, or split a user-safe callee.
570
+ </Accordion>
571
+
572
+ <Accordion title="OKE1020 — no declared effects">
573
+ Cause: `Flow "{flow}" has no declared effects and no Manifest to derive them from.` Boot with `oke
574
+ build` / `oke dev` so extract can infer. Framework / plugin Flows outside the app tree get an
575
+ empty least-privilege stamp automatically when a Manifest is present — do not hand-write `effects:{" "}
576
+ {}`. Real `fx` usage still needs inference (app source) or an explicit non-empty `effects` block
577
+ when extract cannot see the body. If extract failed (`Manifest extract failed`), install
578
+ `oxc-parser` and retry.
579
+ </Accordion>
580
+
581
+ </Accordions>
582
+
583
+ ## Learn more
584
+
585
+ - [The Anatomy](/docs/understand/the-anatomy) — `on`, trigger, `flow`, `do`, `fx`
586
+ - [HTTP](/docs/elements/flow/http) — verbs, envelopes, resources, live SSE
587
+ - [Routing](/docs/elements/flow/routing) — file-tree stamps, barrels, OKE1030 · OKE1040–1045
588
+ - [Consumers](/docs/elements/flow/consumers) — Signal / Clock / CDC
589
+ - [Workflows](/docs/elements/flow/workflows) — `durable: true` + `fx.step`
590
+ - [fx](/docs/reference/fx) — every method inside `do`
591
+ - [Gate](/docs/elements/gate) — `.gate(...)` / `.public()` on the trigger
592
+ - [Errors](/docs/reference/errors) — OKE1001–1009 · OKE1020 · ValidationError · denials
593
+ - [MCP](/docs/elements/ai/mcp) — `mcp.tool` exposure
594
+
595
+ ## Next
596
+
597
+ <Cards>
598
+ <Card
599
+ title="HTTP"
600
+ description="Synchronous REST, QUERY, resources, and live SSE."
601
+ href="/docs/elements/flow/http"
602
+ />
603
+ <Card
604
+ title="Consumers"
605
+ description="Signal workers, named Clock jobs, and SQL CDC — one Flow species."
606
+ href="/docs/elements/flow/consumers"
607
+ />
608
+ <Card
609
+ title="Durable Workflows"
610
+ description="Step journaling and multi-step distributed execution."
611
+ href="/docs/elements/flow/workflows"
612
+ />
613
+ <Card
614
+ title="The Anatomy"
615
+ description="Five pieces behind on(trigger, flow)."
616
+ href="/docs/understand/the-anatomy"
617
+ />
618
+ </Cards>
@@ -0,0 +1,5 @@
1
+ {
2
+ "title": "Flow",
3
+ "icon": "Workflow",
4
+ "pages": ["index", "http", "routing", "consumers", "workflows"]
5
+ }