okengine 0.18.4 → 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 (512) 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/index.mdx +25 -6
  5. package/site/content/docs/ai/llms-txt.mdx +1 -1
  6. package/site/content/docs/ai/meta.json +1 -1
  7. package/site/content/docs/ai/skills.mdx +4 -1
  8. package/site/content/docs/ai/try-it.mdx +58 -0
  9. package/site/content/docs/client/auth.mdx +208 -0
  10. package/site/content/docs/client/calling.mdx +451 -0
  11. package/site/content/docs/client/index.mdx +209 -0
  12. package/site/content/docs/client/live.mdx +234 -0
  13. package/site/content/docs/client/meta.json +5 -0
  14. package/site/content/docs/client/react.mdx +249 -0
  15. package/site/content/docs/elements/ai/agents.mdx +232 -0
  16. package/site/content/docs/elements/ai/index.mdx +341 -0
  17. package/site/content/docs/elements/ai/mcp.mdx +275 -0
  18. package/site/content/docs/elements/ai/meta.json +5 -0
  19. package/site/content/docs/elements/ai/models.mdx +283 -0
  20. package/site/content/docs/elements/ai/prompts.mdx +256 -0
  21. package/site/content/docs/elements/channel/email.mdx +266 -0
  22. package/site/content/docs/elements/channel/index.mdx +344 -0
  23. package/site/content/docs/elements/channel/meta.json +5 -0
  24. package/site/content/docs/elements/channel/push.mdx +218 -0
  25. package/site/content/docs/elements/channel/receipts.mdx +206 -0
  26. package/site/content/docs/elements/channel/sms.mdx +264 -0
  27. package/site/content/docs/elements/channel/whatsapp.mdx +220 -0
  28. package/site/content/docs/elements/clock/index.mdx +300 -0
  29. package/site/content/docs/elements/clock/meta.json +5 -0
  30. package/site/content/docs/elements/clock/schedules.mdx +508 -0
  31. package/site/content/docs/elements/clock/sleep.mdx +445 -0
  32. package/site/content/docs/elements/flow/consumers.mdx +707 -0
  33. package/site/content/docs/elements/flow/http.mdx +1080 -0
  34. package/site/content/docs/elements/flow/index.mdx +618 -0
  35. package/site/content/docs/elements/flow/meta.json +5 -0
  36. package/site/content/docs/elements/flow/routing.mdx +559 -0
  37. package/site/content/docs/elements/flow/workflows.mdx +640 -0
  38. package/site/content/docs/elements/gate/auth.mdx +371 -0
  39. package/site/content/docs/elements/gate/authorization.mdx +298 -0
  40. package/site/content/docs/elements/gate/index.mdx +418 -0
  41. package/site/content/docs/elements/gate/meta.json +5 -0
  42. package/site/content/docs/elements/gate/rate-limits.mdx +365 -0
  43. package/site/content/docs/elements/gate/rls.mdx +303 -0
  44. package/site/content/docs/elements/gate/tenancy.mdx +372 -0
  45. package/site/content/docs/elements/index.mdx +52 -11
  46. package/site/content/docs/elements/signal/broadcast.mdx +517 -0
  47. package/site/content/docs/elements/signal/index.mdx +352 -0
  48. package/site/content/docs/elements/signal/live.mdx +590 -0
  49. package/site/content/docs/elements/signal/meta.json +5 -0
  50. package/site/content/docs/elements/signal/once.mdx +596 -0
  51. package/site/content/docs/elements/store/files.mdx +659 -0
  52. package/site/content/docs/elements/store/index.mdx +310 -0
  53. package/site/content/docs/elements/store/kv.mdx +629 -0
  54. package/site/content/docs/elements/store/meta.json +5 -0
  55. package/site/content/docs/elements/store/search.mdx +946 -0
  56. package/site/content/docs/elements/store/sql.mdx +937 -0
  57. package/site/content/docs/elements/vault/config.mdx +256 -0
  58. package/site/content/docs/elements/vault/index.mdx +356 -0
  59. package/site/content/docs/elements/vault/meta.json +5 -0
  60. package/site/content/docs/elements/vault/rotation.mdx +273 -0
  61. package/site/content/docs/elements/vault/secrets.mdx +285 -0
  62. package/site/content/docs/index.mdx +78 -30
  63. package/site/content/docs/meta.json +11 -8
  64. package/site/content/docs/plugins/cors.mdx +2 -1
  65. package/site/content/docs/plugins/csrf.mdx +4 -1
  66. package/site/content/docs/plugins/headers.mdx +2 -1
  67. package/site/content/docs/plugins/ip-allowlist.mdx +2 -1
  68. package/site/content/docs/plugins/magic-link.mdx +6 -0
  69. package/site/content/docs/plugins/maintenance-mode.mdx +2 -1
  70. package/site/content/docs/plugins/oauth.mdx +1 -1
  71. package/site/content/docs/plugins/otp.mdx +12 -1
  72. package/site/content/docs/plugins/passkey.mdx +39 -15
  73. package/site/content/docs/plugins/two-factor.mdx +91 -34
  74. package/site/content/docs/plugins/username.mdx +1 -1
  75. package/site/content/docs/recipes/caddy.mdx +3 -3
  76. package/site/content/docs/recipes/index.mdx +18 -28
  77. package/site/content/docs/recipes/mailpit.mdx +1 -1
  78. package/site/content/docs/recipes/meilisearch.mdx +3 -3
  79. package/site/content/docs/recipes/meta.json +1 -4
  80. package/site/content/docs/recipes/nginx.mdx +2 -2
  81. package/site/content/docs/recipes/openrouter.mdx +283 -0
  82. package/site/content/docs/recipes/pgdog.mdx +3 -3
  83. package/site/content/docs/recipes/postgres.mdx +1 -2
  84. package/site/content/docs/recipes/rustfs.mdx +2 -2
  85. package/site/content/docs/recipes/traefik.mdx +3 -3
  86. package/site/content/docs/reference/cli.mdx +231 -0
  87. package/site/content/docs/reference/configuration.mdx +30 -10
  88. package/site/content/docs/reference/environment-variables.mdx +93 -20
  89. package/site/content/docs/reference/errors.mdx +132 -29
  90. package/site/content/docs/reference/fx.mdx +137 -73
  91. package/site/content/docs/reference/index.mdx +13 -21
  92. package/site/content/docs/reference/meta.json +4 -5
  93. package/site/content/docs/reference/okid.mdx +42 -17
  94. package/site/content/docs/reference/plugins.mdx +4 -3
  95. package/site/content/docs/reference/security.mdx +197 -0
  96. package/site/content/docs/understand/meta.json +5 -0
  97. package/site/content/docs/understand/the-anatomy.mdx +132 -0
  98. package/site/content/docs/understand/the-model.mdx +32 -0
  99. package/site/content/docs/understand/the-problem.mdx +74 -0
  100. package/site/content/docs/understand/the-vocabulary.mdx +26 -0
  101. package/src/auth/api-keys.ts +2 -1
  102. package/src/auth/bindings.ts +64 -16
  103. package/src/auth/gate-auth.test.ts +6 -1
  104. package/src/auth/identity.ts +152 -5
  105. package/src/auth/index.ts +29 -0
  106. package/src/auth/invites.ts +2 -1
  107. package/src/auth/method-context.ts +41 -0
  108. package/src/auth/oauth-as/crypto.ts +2 -1
  109. package/src/auth/oauth-as/stores.ts +2 -1
  110. package/src/auth/operator.ts +2 -1
  111. package/src/auth/sessions-jwt.test.ts +77 -0
  112. package/src/auth/sessions.ts +20 -4
  113. package/src/auth/tenants.ts +3 -2
  114. package/src/auth/two-factor-challenge.test.ts +61 -0
  115. package/src/auth/two-factor-challenge.ts +284 -0
  116. package/src/auth/verification.ts +5 -0
  117. package/src/bench/REPORT.md +49 -0
  118. package/src/bench/g03-signal-once.bench.ts +1 -1
  119. package/src/bench/g10-observability-contention.bench.ts +1 -1
  120. package/src/bench/g17-hybrid-search.bench.ts +572 -0
  121. package/src/bench/load-app.ts +2 -10
  122. package/src/cli/ai-setup/ai-setup.test.ts +331 -42
  123. package/src/cli/ai-setup/apply.ts +294 -52
  124. package/src/cli/ai-setup/catalog.ts +238 -1342
  125. package/src/cli/ai-setup/index.ts +14 -99
  126. package/src/cli/ai-setup/prompts.ts +60 -443
  127. package/src/cli/ask-seed.test.ts +96 -0
  128. package/src/cli/ask-seed.ts +82 -0
  129. package/src/cli/ask-vault-gaps.test.ts +84 -0
  130. package/src/cli/ask-vault-gaps.ts +146 -0
  131. package/src/cli/build.ts +2 -2
  132. package/src/cli/client-add.test.ts +26 -1
  133. package/src/cli/client-add.ts +106 -27
  134. package/src/cli/competitor-mention-removal.test.ts +1 -1
  135. package/src/cli/db-seed.ts +2 -0
  136. package/src/cli/db.ts +150 -11
  137. package/src/cli/dev.ts +119 -211
  138. package/src/cli/docker-clean.ts +2 -2
  139. package/src/cli/docker-cli.test.ts +1 -1
  140. package/src/cli/doctor-diff.ts +4 -2
  141. package/src/cli/doctor-pii.test.ts +1 -1
  142. package/src/cli/doctor.ts +14 -1
  143. package/src/cli/hero-meta.test.ts +4 -2
  144. package/src/cli/load-config.images.test.ts +8 -10
  145. package/src/cli/load-config.ts +1 -1
  146. package/src/cli/registry.ts +22 -10
  147. package/src/cli/replay.ts +3 -1
  148. package/src/cli/start.ts +1 -1
  149. package/src/cli/tui/keys.ts +2 -3
  150. package/src/client/auth/cookies.ts +74 -0
  151. package/src/client/auth/create-auth-client.ts +636 -0
  152. package/src/client/auth/denials.ts +99 -0
  153. package/src/client/auth/session.ts +283 -0
  154. package/src/client/auth.test.ts +251 -0
  155. package/src/client/auth.ts +39 -114
  156. package/src/client/create-with-session.ts +245 -0
  157. package/src/client/create.ts +51 -5
  158. package/src/client/index.ts +11 -1
  159. package/src/client/live.ts +11 -79
  160. package/src/client/notes-contract.test.ts +5 -10
  161. package/src/client/sse.ts +137 -0
  162. package/src/client/stream.ts +147 -0
  163. package/src/client/transport.test.ts +32 -0
  164. package/src/client/transport.ts +123 -26
  165. package/src/client/types.ts +118 -14
  166. package/src/client-react/index.ts +185 -24
  167. package/src/client-react/use-live-query.ts +13 -3
  168. package/src/compiler/aot.test.ts +7 -4
  169. package/src/compiler/effects-embed.test.ts +56 -0
  170. package/src/compiler/effects-fetch.test.ts +43 -0
  171. package/src/compiler/effects-infer.ts +58 -2
  172. package/src/compiler/extract.test.ts +258 -44
  173. package/src/compiler/extract.ts +566 -48
  174. package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +7 -4
  175. package/src/compiler/fixtures/skyport/src/flows/bookings/signals.ts +2 -8
  176. package/src/compiler/fixtures/skyport.expected.json +4 -4
  177. package/src/compiler/fixtures/triggers/five-triggers.ts +14 -10
  178. package/src/compiler/response.ts +2 -2
  179. package/src/compiler/search-writer-isolation.test.ts +40 -0
  180. package/src/config/index.ts +11 -0
  181. package/src/console/server/app.ts +17 -23
  182. package/src/console/server/bind.ts +4 -0
  183. package/src/console/server/console.test.ts +2 -2
  184. package/src/console/server/flows-invoke.test.ts +50 -34
  185. package/src/console/server/flows.ts +436 -255
  186. package/src/console/server/runs-ingest.test.ts +6 -3
  187. package/src/console/server/serve.ts +1 -1
  188. package/src/console/server/signals.test.ts +1 -5
  189. package/src/console/server/signals.ts +8 -6
  190. package/src/console/server/state.ts +6 -1
  191. package/src/console/server/store.ts +1 -1
  192. package/src/console/ui-next/dist/assets/FileExportIcon-Ck-5od4R.js +1 -0
  193. package/src/console/ui-next/dist/assets/MoreHorizontalCircle01Icon-gMNGsE37.js +1 -0
  194. package/src/console/ui-next/dist/assets/PlusSignIcon-CwG3nxfu.js +1 -0
  195. package/src/console/ui-next/dist/assets/UnavailableIcon-D9cvHVPr.js +1 -0
  196. package/src/console/ui-next/dist/assets/UserIcon-DaE2PB5_.js +1 -0
  197. package/src/console/ui-next/dist/assets/access-page-DFeymU07.js +4 -0
  198. package/src/console/ui-next/dist/assets/agent-disclosure-U1rdfblp.js +1 -0
  199. package/src/console/ui-next/dist/assets/cache-glyph-BeFJeqBG.js +1 -0
  200. package/src/console/ui-next/dist/assets/call-pii-button-CVAONPii.js +1 -0
  201. package/src/console/ui-next/dist/assets/collapsible-D2A6NJ-3.js +1 -0
  202. package/src/console/ui-next/dist/assets/copy-inline-button-CAYD18cr.js +1 -0
  203. package/src/console/ui-next/dist/assets/dagre.esm-B1_XeuLP.js +1 -0
  204. package/src/console/ui-next/dist/assets/detail-header-DVWNjWjg.js +1 -0
  205. package/src/console/ui-next/dist/assets/dropdown-menu-4h2LOVXM.js +1 -0
  206. package/src/console/ui-next/dist/assets/duration-tone-Cgk_h5ja.js +9 -0
  207. package/src/console/ui-next/dist/assets/element-icons-BI8cJgdh.js +1 -0
  208. package/src/console/ui-next/dist/assets/explorer-empty-CJs5A-wm.js +1 -0
  209. package/src/console/ui-next/dist/assets/flows-page-Dss7941e.js +1 -0
  210. package/src/console/ui-next/dist/assets/highlighted-json-MYZQtRnw.js +154 -0
  211. package/src/console/ui-next/dist/assets/http-method-Jrh39p7A.js +1 -0
  212. package/src/console/ui-next/dist/assets/index-D0zS5rKO.css +2 -0
  213. package/src/console/ui-next/dist/assets/index-DXP2dBIF.js +63 -0
  214. package/src/console/ui-next/dist/assets/observability-page-HvolXxTI.js +4 -0
  215. package/src/console/ui-next/dist/assets/react-dom-Ddte4I-Q.js +9 -0
  216. package/src/console/ui-next/dist/assets/replica-lag-CSh2dzrb.js +18 -0
  217. package/src/console/ui-next/dist/assets/request-meta-BatF8KrK.js +1 -0
  218. package/src/console/ui-next/dist/assets/shortcut-keys-3ILd8oGn.js +1 -0
  219. package/src/console/ui-next/dist/assets/{sql-BskegiFM.js → sql-BsFa4tDR.js} +1 -1
  220. package/src/console/ui-next/dist/assets/store-page-eiKiHnNe.js +41 -0
  221. package/src/console/ui-next/dist/assets/trace-detail-sheet-CZkMeKS-.js +2 -0
  222. package/src/console/ui-next/dist/assets/tree-expand-toggle-CW8y5A2h.js +55 -0
  223. package/src/console/ui-next/dist/assets/units-page-B_RWJrEO.js +1 -0
  224. package/src/console/ui-next/dist/assets/{use-vault-list-uk4WVboC.js → use-vault-list-CT4-gajj.js} +1 -1
  225. package/src/console/ui-next/dist/assets/vault-page-CWrg-A68.js +2 -0
  226. package/src/console/ui-next/dist/assets/xyflow-CSyC6ryz.css +1 -0
  227. package/src/console/ui-next/dist/assets/xyflow-yApv7D4e.js +7 -0
  228. package/src/console/ui-next/dist/index.html +6 -13
  229. package/src/console/ui-next/seed-invoke-host.ts +21 -18
  230. package/src/console/ui-next/src/client.ts +7 -2
  231. package/src/console/ui-next/src/features/flows/graph/element-map.ts +2 -0
  232. package/src/console/ui-next/src/features/flows/traces/effect-kind.ts +12 -2
  233. package/src/console/ui-next/src/features/flows/traces/effect-summary.ts +4 -0
  234. package/src/console/ui-next/src/features/flows/traces/trace-detail-sheet.tsx +8 -0
  235. package/src/console/ui-next/src/features/flows/traces/waterfall-bars.ts +4 -0
  236. package/src/console/ui-next/src/features/flows/traces/waterfall-tooltip.ts +9 -3
  237. package/src/console/ui-next/src/features/store/detail/reveal-cell.tsx +7 -11
  238. package/src/console/ui-next/src/features/store/detail/store-row-detail-sheet.tsx +2 -2
  239. package/src/console/ui-next/src/features/store/lib/fields-from-table.ts +2 -0
  240. package/src/console/ui-next/src/features/store/lib/grid-model.test.ts +25 -1
  241. package/src/console/ui-next/src/features/store/lib/grid-model.ts +36 -1
  242. package/src/console/ui-next/src/features/store/query/query-results.tsx +3 -3
  243. package/src/console/ui-next/src/features/units/detail/effects-summary.tsx +2 -0
  244. package/src/console/ui-next/src/features/units/lib/call-read-safe.ts +3 -1
  245. package/src/console/ui-next/src/features/units/lib/fields-from-schema.ts +6 -0
  246. package/src/docker/ai-model-status.test.ts +1 -12
  247. package/src/docker/ai-model-status.ts +10 -38
  248. package/src/docker/compose-up.test.ts +100 -0
  249. package/src/docker/compose-up.ts +292 -0
  250. package/src/docker/compose.ts +4 -14
  251. package/src/docker/derive.ts +9 -34
  252. package/src/docker/docker.test.ts +16 -261
  253. package/src/docker/images-config.test.ts +13 -25
  254. package/src/docker/index.ts +1 -24
  255. package/src/docker/recipes/index.ts +0 -23
  256. package/src/docker/recipes/pgdog.ts +6 -4
  257. package/src/docker/stack-id.test.ts +2 -2
  258. package/src/docker/stack-id.ts +0 -1
  259. package/src/docker/types.ts +2 -2
  260. package/src/drivers/ai-anthropic.ts +10 -0
  261. package/src/drivers/ai-openai-compatible.ts +34 -7
  262. package/src/drivers/ai-providers.test.ts +0 -107
  263. package/src/drivers/ai-stream.test.ts +0 -34
  264. package/src/drivers/ai-types.ts +17 -8
  265. package/src/drivers/channel-fcm.ts +6 -1
  266. package/src/drivers/channel-msegat.ts +6 -1
  267. package/src/drivers/channel-resend.ts +5 -1
  268. package/src/drivers/channel-smtp.ts +5 -1
  269. package/src/drivers/channel-sndr.ts +10 -1
  270. package/src/drivers/channel-taqnyat-mail.ts +5 -1
  271. package/src/drivers/channel-taqnyat-whatsapp.ts +6 -1
  272. package/src/drivers/channel-taqnyat.ts +6 -1
  273. package/src/drivers/channel-types.ts +10 -0
  274. package/src/drivers/channel-unifonic.ts +6 -1
  275. package/src/drivers/channel-wa-cloud.ts +6 -1
  276. package/src/drivers/channel-webpush.ts +6 -1
  277. package/src/drivers/external.ts +33 -0
  278. package/src/drivers/index.ts +0 -10
  279. package/src/drivers/meilisearch.ts +6 -0
  280. package/src/drivers/oauth-types.ts +4 -0
  281. package/src/drivers/postgres.test.ts +74 -3
  282. package/src/drivers/postgres.ts +175 -6
  283. package/src/drivers/signal-types.ts +5 -5
  284. package/src/drivers/types.ts +7 -0
  285. package/src/drivers/vault-types.ts +5 -0
  286. package/src/elements/ai/declare.ts +17 -4
  287. package/src/elements/ai/eval.ts +1 -1
  288. package/src/elements/ai/mcp-http.ts +1 -1
  289. package/src/elements/ai/pii.ts +1 -1
  290. package/src/elements/ai/providers.test.ts +289 -0
  291. package/src/elements/ai/providers.ts +169 -0
  292. package/src/elements/ai/runtime.ts +68 -5
  293. package/src/elements/ai/schema.ts +2 -2
  294. package/src/elements/ai.test.ts +7 -7
  295. package/src/elements/ai.ts +17 -1
  296. package/src/elements/channel/runtime.ts +105 -12
  297. package/src/elements/clock/cron-fields.test.ts +144 -0
  298. package/src/elements/clock/cron-fields.ts +185 -0
  299. package/src/elements/clock/declare.ts +247 -3
  300. package/src/elements/clock.ts +21 -1
  301. package/src/elements/index.ts +15 -0
  302. package/src/elements/signal/chaos-child.ts +1 -2
  303. package/src/elements/signal/declare.ts +65 -37
  304. package/src/elements/signal/delivery-modes.test.ts +11 -31
  305. package/src/elements/signal/dry-run-replay.test.ts +1 -7
  306. package/src/elements/signal/dry-run-write-isolation.test.ts +1 -7
  307. package/src/elements/signal/key-ordering.test.ts +6 -26
  308. package/src/elements/signal/lease-reclaim.test.ts +2 -6
  309. package/src/elements/signal/optional-emit.test.ts +6 -9
  310. package/src/elements/signal/order-lifecycle.test.ts +4 -17
  311. package/src/elements/signal/orphan-messages.test.ts +4 -15
  312. package/src/elements/signal/reconcile.test.ts +2 -2
  313. package/src/elements/signal/runtime.ts +1 -1
  314. package/src/elements/signal/schema-emit.test.ts +4 -8
  315. package/src/elements/signal.test.ts +24 -49
  316. package/src/elements/signal.ts +9 -2
  317. package/src/elements/store/domain-ddl.test.ts +1 -1
  318. package/src/elements/store/live-http.test.ts +9 -4
  319. package/src/elements/store/prepare-row.test.ts +123 -0
  320. package/src/elements/store/resource.ts +43 -12
  321. package/src/elements/store/schema-decl.ts +117 -0
  322. package/src/elements/store/search-backfill.ts +205 -0
  323. package/src/elements/store/search-bind.ts +66 -0
  324. package/src/elements/store/search-bm25.ts +78 -0
  325. package/src/elements/store/search-ddl.ts +156 -0
  326. package/src/elements/store/search-embed-flow.ts +141 -0
  327. package/src/elements/store/search-errors.ts +34 -0
  328. package/src/elements/store/search-fusion.ts +112 -0
  329. package/src/elements/store/search-lsh.ts +179 -0
  330. package/src/elements/store/search-runtime.ts +300 -0
  331. package/src/elements/store/search.test.ts +144 -0
  332. package/src/elements/store/sql-session.test.ts +1 -0
  333. package/src/elements/store/sql-session.ts +83 -3
  334. package/src/elements/store/table.ts +23 -2
  335. package/src/elements/store/upsert-app.test.ts +1 -3
  336. package/src/elements/store.ts +50 -0
  337. package/src/full.ts +4 -2
  338. package/src/http.ts +4 -1
  339. package/src/i18n/catalogs/ar.ts +14 -6
  340. package/src/i18n/catalogs/en.ts +14 -6
  341. package/src/index.ts +6 -1
  342. package/src/kernel/adopt-barrel-fresh.test.ts +7 -7
  343. package/src/kernel/adopt-routes.ts +9 -1
  344. package/src/kernel/app-auth.ts +5 -0
  345. package/src/kernel/app.ts +102 -9
  346. package/src/kernel/auto-cache.test.ts +6 -12
  347. package/src/kernel/auto-registry.test.ts +3 -3
  348. package/src/kernel/boot-bind/ai.test.ts +22 -19
  349. package/src/kernel/boot-bind/ai.ts +5 -43
  350. package/src/kernel/boot-bind/clock.ts +23 -5
  351. package/src/kernel/boot-bind/honor-config.test.ts +4 -4
  352. package/src/kernel/boot.test.ts +11 -6
  353. package/src/kernel/boot.ts +66 -16
  354. package/src/kernel/boundary-contract.ts +93 -0
  355. package/src/kernel/budget.test.ts +1 -1
  356. package/src/kernel/call.ts +89 -0
  357. package/src/kernel/capability.ts +6 -0
  358. package/src/kernel/client-descriptor.ts +123 -0
  359. package/src/kernel/clock-timezone.test.ts +80 -0
  360. package/src/kernel/correlation.test.ts +1 -1
  361. package/src/kernel/dry-run.ts +11 -8
  362. package/src/kernel/effects-stamping.test.ts +42 -9
  363. package/src/kernel/effects.test.ts +4 -2
  364. package/src/kernel/effects.ts +51 -9
  365. package/src/kernel/errors-channel.ts +17 -0
  366. package/src/kernel/errors-live-resume.ts +3 -2
  367. package/src/kernel/errors-tenant.ts +7 -4
  368. package/src/kernel/errors.registry-helpers.ts +96 -0
  369. package/src/kernel/errors.registry.test.ts +139 -25
  370. package/src/kernel/errors.ts +102 -23
  371. package/src/kernel/external-effects.test.ts +196 -0
  372. package/src/kernel/flow.test.ts +13 -4
  373. package/src/kernel/flow.ts +69 -71
  374. package/src/kernel/fx-ask-telemetry.test.ts +2 -2
  375. package/src/kernel/fx-dead-letters.test.ts +3 -3
  376. package/src/kernel/fx-fetch.ts +55 -0
  377. package/src/kernel/fx-live-stream.ts +2 -2
  378. package/src/kernel/fx-live.test.ts +8 -8
  379. package/src/kernel/fx.test.ts +17 -11
  380. package/src/kernel/fx.ts +180 -57
  381. package/src/kernel/horizontal-child.ts +1 -1
  382. package/src/kernel/http-query.test.ts +3 -6
  383. package/src/kernel/index.ts +13 -3
  384. package/src/kernel/instance-id.ts +1 -1
  385. package/src/kernel/instances.test.ts +40 -0
  386. package/src/kernel/instances.ts +47 -9
  387. package/src/kernel/live-http.test.ts +6 -7
  388. package/src/kernel/live-http.ts +6 -2
  389. package/src/kernel/live-resume.test.ts +1 -1
  390. package/src/kernel/mcp-tool.test.ts +3 -3
  391. package/src/kernel/on.ts +98 -4
  392. package/src/kernel/pipeline.test.ts +12 -15
  393. package/src/kernel/plugin-elements.test.ts +1 -1
  394. package/src/kernel/stamp-http.test.ts +3 -3
  395. package/src/kernel/triggers.ts +210 -95
  396. package/src/kernel-entry.ts +0 -1
  397. package/src/manifest/diff.ts +11 -1
  398. package/src/manifest/fixtures/skyport.excerpt.json +1 -1
  399. package/src/manifest/types.ts +46 -2
  400. package/src/mcp/docs-index.ts +3 -3
  401. package/src/mcp/docs-mcp.test.ts +2 -2
  402. package/src/mcp/docs-tools.ts +1 -1
  403. package/src/okid.test.ts +56 -0
  404. package/src/okid.ts +55 -11
  405. package/src/plugins/anonymous.ts +8 -4
  406. package/src/plugins/auth/shared.ts +27 -3
  407. package/src/plugins/auth-delivery.mailpit.integration.test.ts +1 -1
  408. package/src/plugins/auth-methods.security.test.ts +561 -23
  409. package/src/plugins/config-source.ts +1 -1
  410. package/src/plugins/csrf.test.ts +65 -0
  411. package/src/plugins/index.ts +2 -0
  412. package/src/plugins/magic-link.ts +36 -16
  413. package/src/plugins/oauth/shared.ts +3 -1
  414. package/src/plugins/oauth.ts +22 -14
  415. package/src/plugins/otp.ts +37 -21
  416. package/src/plugins/passkey-webauthn.ts +9 -6
  417. package/src/plugins/passkey.ts +98 -26
  418. package/src/plugins/pre-account-hijack.test.ts +223 -0
  419. package/src/plugins/two-factor.ts +466 -37
  420. package/src/plugins/username.ts +19 -7
  421. package/src/release/build-lib.ts +1 -0
  422. package/src/release/limits.ts +2 -2
  423. package/src/release/measure.ts +1 -1
  424. package/src/runs/collect.test.ts +0 -2
  425. package/src/runtime/json-code-block.test.ts +250 -20
  426. package/src/runtime/json-code-block.ts +1261 -41
  427. package/src/term.test.ts +1 -1
  428. package/src/test/create-test-app.test.ts +12 -12
  429. package/src/test/live-signals.test.ts +6 -6
  430. package/src/test/provisions.integration.test.ts +10 -14
  431. package/src/test/reset-element-registries.ts +1 -1
  432. package/src/test/tenant-isolation.test.ts +12 -6
  433. package/site/content/docs/deployment/docker-swarm.mdx +0 -164
  434. package/site/content/docs/deployment/docker.mdx +0 -227
  435. package/site/content/docs/deployment/index.mdx +0 -83
  436. package/site/content/docs/deployment/kubernetes.mdx +0 -176
  437. package/site/content/docs/deployment/meta.json +0 -5
  438. package/site/content/docs/deployment/reverse-proxy.mdx +0 -234
  439. package/site/content/docs/elements/ai.mdx +0 -385
  440. package/site/content/docs/elements/channel.mdx +0 -346
  441. package/site/content/docs/elements/clock.mdx +0 -244
  442. package/site/content/docs/elements/flow.mdx +0 -420
  443. package/site/content/docs/elements/gate.mdx +0 -436
  444. package/site/content/docs/elements/signal.mdx +0 -380
  445. package/site/content/docs/elements/store.mdx +0 -1099
  446. package/site/content/docs/elements/vault.mdx +0 -405
  447. package/site/content/docs/get-started/basic-usage.mdx +0 -173
  448. package/site/content/docs/get-started/index.mdx +0 -43
  449. package/site/content/docs/get-started/installation.mdx +0 -220
  450. package/site/content/docs/get-started/introduction.mdx +0 -132
  451. package/site/content/docs/get-started/meta.json +0 -13
  452. package/site/content/docs/get-started/project-structure.mdx +0 -925
  453. package/site/content/docs/get-started/testing.mdx +0 -328
  454. package/site/content/docs/get-started/why.mdx +0 -162
  455. package/site/content/docs/recipes/llama-cpp.mdx +0 -151
  456. package/site/content/docs/recipes/ollama.mdx +0 -142
  457. package/site/content/docs/recipes/sglang.mdx +0 -105
  458. package/site/content/docs/recipes/vllm.mdx +0 -106
  459. package/site/content/docs/reference/cli.md +0 -232
  460. package/site/content/docs/reference/client.mdx +0 -469
  461. package/site/content/docs/reference/security.md +0 -74
  462. package/src/cli/ai-setup/detect-ollama.ts +0 -213
  463. package/src/cli/ai-setup/recommend.test.ts +0 -225
  464. package/src/cli/ai-setup/recommend.ts +0 -225
  465. package/src/cli/dev-controls.test.ts +0 -122
  466. package/src/cli/dev-controls.ts +0 -164
  467. package/src/cli/tui/DevLive.tsx +0 -126
  468. package/src/console/ui-next/dist/assets/access-page-De7Lc2JC.js +0 -4
  469. package/src/console/ui-next/dist/assets/agent-disclosure-BP0Y0Sux.js +0 -1
  470. package/src/console/ui-next/dist/assets/cache-glyph-B5X-NM0-.js +0 -1
  471. package/src/console/ui-next/dist/assets/call-pii-button-ChAUiLo9.js +0 -1
  472. package/src/console/ui-next/dist/assets/collapsible-DGnOM2ph.js +0 -1
  473. package/src/console/ui-next/dist/assets/copy-inline-button-DBHhgHKP.js +0 -1
  474. package/src/console/ui-next/dist/assets/dagre.esm-ZwcdTuZZ.js +0 -1
  475. package/src/console/ui-next/dist/assets/detail-header-DhHM1iaZ.js +0 -1
  476. package/src/console/ui-next/dist/assets/dropdown-menu-_NjTEo5_.js +0 -1
  477. package/src/console/ui-next/dist/assets/duration-tone-sC3lGABz.js +0 -9
  478. package/src/console/ui-next/dist/assets/element-icons-BVXtRyd3.js +0 -1
  479. package/src/console/ui-next/dist/assets/explorer-empty-2uIhBu0_.js +0 -1
  480. package/src/console/ui-next/dist/assets/flows-page-RGy7VEA_.js +0 -1
  481. package/src/console/ui-next/dist/assets/highlighted-json-Awq7gYdu.js +0 -154
  482. package/src/console/ui-next/dist/assets/http-method-_UHM2ODJ.js +0 -1
  483. package/src/console/ui-next/dist/assets/index-Ck88Jmv8.css +0 -2
  484. package/src/console/ui-next/dist/assets/index-_rgpdVzo.js +0 -66
  485. package/src/console/ui-next/dist/assets/link-BX6Vqztd.js +0 -1
  486. package/src/console/ui-next/dist/assets/observability-page-Ds6pcnh-.js +0 -4
  487. package/src/console/ui-next/dist/assets/preload-helper-oH4irX4C.js +0 -1
  488. package/src/console/ui-next/dist/assets/react-D8E3mtu1.js +0 -1
  489. package/src/console/ui-next/dist/assets/react-dom-Bph1y7z7.js +0 -9
  490. package/src/console/ui-next/dist/assets/replica-lag-DKRrbvdo.js +0 -18
  491. package/src/console/ui-next/dist/assets/request-meta-DV0ywz7t.js +0 -1
  492. package/src/console/ui-next/dist/assets/shortcut-JQIZlWfm.js +0 -1
  493. package/src/console/ui-next/dist/assets/shortcut-keys-DKxNTe_m.js +0 -1
  494. package/src/console/ui-next/dist/assets/skeleton-D-czQJT6.js +0 -1
  495. package/src/console/ui-next/dist/assets/store-page-02xOiqIK.js +0 -41
  496. package/src/console/ui-next/dist/assets/trace-detail-sheet-B09O8rA6.js +0 -2
  497. package/src/console/ui-next/dist/assets/tree-expand-toggle-BtyhmWb4.js +0 -55
  498. package/src/console/ui-next/dist/assets/units-page-4rHOePuE.js +0 -1
  499. package/src/console/ui-next/dist/assets/useMutation-B8EO02Ej.js +0 -1
  500. package/src/console/ui-next/dist/assets/useRender-BE2A9BWC.js +0 -1
  501. package/src/console/ui-next/dist/assets/vault-page-DISPgxLM.js +0 -2
  502. package/src/console/ui-next/dist/assets/xyflow-D7n4g6go.js +0 -7
  503. package/src/console/ui-next/dist/assets/xyflow-DZ0Ws1xk.css +0 -1
  504. package/src/docker/ollama-pull.ts +0 -232
  505. package/src/docker/recipes/llama-cpp.ts +0 -298
  506. package/src/docker/recipes/ollama.ts +0 -44
  507. package/src/docker/recipes/sglang.ts +0 -55
  508. package/src/docker/recipes/vllm.ts +0 -44
  509. package/src/drivers/ai-ollama-tools.integration.test.ts +0 -109
  510. package/src/drivers/ai-ollama.integration.test.ts +0 -184
  511. package/src/drivers/ai-ollama.ts +0 -389
  512. package/src/drivers/ollama.ts +0 -14
@@ -0,0 +1,559 @@
1
+ ---
2
+ title: "Routing"
3
+ description: "File-tree stamps for HTTP paths, Flow names, and client units from on(http.*, flow) under src/flows."
4
+ icon: "GitFork"
5
+ source: "docs/spec/unified-theory.md"
6
+ ---
7
+
8
+ HTTP routes are inferred from where a Flow file lives. Put `http.get()` in
9
+ `src/flows/notes/[id]/get.ts` and the compiler stamps `GET /notes/:id`, names the
10
+ Flow `notes.get`, and the client calls `api.notes.get({ id })`.
11
+
12
+ <Callout title="The one rule">
13
+ On a tree file, omit path and name: `on(http.get(), flow({ do }))`. The file
14
+ tree stamps both. Pass either only for control — barrels, a URL that must not
15
+ follow the folder, or a stable name for `fx.call`. Explicit always wins.
16
+ </Callout>
17
+
18
+ ## When to omit · when to pass
19
+
20
+ | | Omit (default) | Pass explicitly |
21
+ | ------------- | -------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
22
+ | **HTTP path** | Tree file under `src/flows/<unit>/` — `http.get()`, `http.post()`, … | Barrel `index.ts`; a public URL that must not match the folder; `http.resource(path, ops)`; custom live SSE path |
23
+ | **Flow name** | Same tree file — `flow({ do })` stamps `unit.export` | Barrel (optional — export still stamps); stable name across moves; call-only Flow you `fx.call` by name |
24
+
25
+ **Consequence:** most app code looks like the create-oke template —
26
+ `http.get().public()` + `flow({ … })` — with no string path and no string name.
27
+
28
+ ## Smallest Example
29
+
30
+ <Steps>
31
+
32
+ <Step>
33
+ ### Place the file in the tree
34
+
35
+ `oke dev` / `oke build` regenerate `src/flows/generated.ts`. Import it before
36
+ `oke()` so pathless triggers receive their stamp:
37
+
38
+ ```typescript title="src/app.ts"
39
+ import "@/flows/generated";
40
+ import { oke } from "okengine";
41
+
42
+ export const app = oke({ name: "notes" });
43
+ ```
44
+
45
+ </Step>
46
+
47
+ <Step>
48
+ ### Use pathless `http.get()`
49
+
50
+ The tree stamps `GET /notes/:id`. `:id` merges into `in`. The export name is the
51
+ client method (`api.notes.get`):
52
+
53
+ ```typescript title="src/flows/notes/[id]/get.ts"
54
+ import { on, flow, http } from "okengine";
55
+ import { z } from "zod";
56
+
57
+ export const get = on(
58
+ http.get({
59
+ in: z.object({ id: z.string() }),
60
+ out: z.object({ id: z.string() }),
61
+ }),
62
+ flow({
63
+ do: async ({ id }) => ({ id }),
64
+ }),
65
+ );
66
+ ```
67
+
68
+ </Step>
69
+
70
+ <Step>
71
+ ### Call the endpoint
72
+
73
+ ```bash
74
+ curl -X GET http://localhost:6530/notes/n_1 -H "accept: application/json"
75
+ ```
76
+
77
+ Response:
78
+
79
+ ```json
80
+ {
81
+ "data": { "id": "n_1" },
82
+ "error": null
83
+ }
84
+ ```
85
+
86
+ </Step>
87
+
88
+ </Steps>
89
+
90
+ <Callout title="Method is not the filename">
91
+ `list.ts` does not become `GET` by itself. Reserved leaves only omit a URL segment. Bind
92
+ `http.get()`, `http.post()`, `http.patch()`, or `http.delete()` yourself — see [Reserved
93
+ Leaves](#reserved-leaves).
94
+ </Callout>
95
+
96
+ ## Progressive Patterns
97
+
98
+ From a pathless tree file to an explicit barrel, an action leaf, and a catch-all:
99
+
100
+ <Tabs items={["Tree", "Barrel", "Action", "Catch-all"]}>
101
+
102
+ <Tab value="Tree">
103
+
104
+ One file per route. Skip the path argument. The generated barrel calls
105
+ `stampHttpPath` / `stampFlowName` after import:
106
+
107
+ ```typescript title="src/flows/notes/list.ts"
108
+ import { on, flow, http } from "okengine";
109
+
110
+ export const list = on(
111
+ http.get(),
112
+ flow({
113
+ do: () => [],
114
+ }),
115
+ );
116
+ ```
117
+
118
+ Stamped to `GET /notes`, Flow `notes.list`, client `api.notes.list()`.
119
+
120
+ </Tab>
121
+
122
+ <Tab value="Barrel">
123
+
124
+ A unit that is **only** `index.ts` (plus skip-list files) is a barrel. The
125
+ generated file re-exports it **without** stamping — pass explicit paths:
126
+
127
+ ```typescript title="src/flows/notes/index.ts"
128
+ import { on, flow, http } from "okengine";
129
+ import { z } from "zod";
130
+
131
+ export const list = on(
132
+ http.get("/notes").public(),
133
+ flow("notes.list", {
134
+ do: () => [],
135
+ }),
136
+ );
137
+
138
+ export const create = on(
139
+ http.post("/notes", { in: z.object({ title: z.string().min(1) }) }),
140
+ flow("notes.create", {
141
+ do: async ({ title }, fx) => ({ id: fx.id(), title }),
142
+ }),
143
+ );
144
+ ```
145
+
146
+ Pathless `http.get()` inside a barrel stays unresolved and fails boot
147
+ (**OKE1040**).
148
+
149
+ </Tab>
150
+
151
+ <Tab value="Action">
152
+
153
+ A leaf that is not reserved **adds** a segment. `archive.ts` is
154
+ `POST /notes/:id/archive`, not `POST /notes/:id`:
155
+
156
+ ```typescript title="src/flows/notes/[id]/archive.ts"
157
+ import { on, flow, http } from "okengine";
158
+ import { z } from "zod";
159
+
160
+ export const archive = on(
161
+ http.post({ in: z.object({ id: z.string() }) }),
162
+ flow({
163
+ do: async ({ id }) => ({ id, archived: true }),
164
+ }),
165
+ );
166
+ ```
167
+
168
+ </Tab>
169
+
170
+ <Tab value="Catch-all">
171
+
172
+ `[...slug]` becomes `*` on the URL. The request param is always `"*"`, never
173
+ `slug`:
174
+
175
+ ```typescript title="src/flows/docs/[...slug]/get.ts"
176
+ import { on, flow, http } from "okengine";
177
+ import { z } from "zod";
178
+
179
+ export const get = on(
180
+ http.get({ in: z.object({ "*": z.string() }) }).public(),
181
+ flow({
182
+ do: async (input) => ({ path: input["*"] }),
183
+ }),
184
+ );
185
+ ```
186
+
187
+ ```bash
188
+ curl -X GET http://localhost:6530/docs/getting-started/install \
189
+ -H "accept: application/json"
190
+ ```
191
+
192
+ `do` receives `{ "*": "getting-started/install" }`. Call
193
+ `api.docs.get({ "*": "a/b/c" })` — not `{ slug }`.
194
+
195
+ </Tab>
196
+
197
+ </Tabs>
198
+
199
+ ## Convention Reference
200
+
201
+ | Convention | File | Stamped route | Client |
202
+ | ------------- | --------------------------------------- | ------------------------- | ------------------------------ |
203
+ | Dynamic param | `notes/[id]/get.ts` + `http.get()` | `GET /notes/:id` | `api.notes.get({ id })` |
204
+ | Reserved leaf | `notes/list.ts` + `http.get()` | `GET /notes` | `api.notes.list()` |
205
+ | Action leaf | `notes/[id]/archive.ts` + `http.post()` | `POST /notes/:id/archive` | `api.notes.archive({ id })` |
206
+ | Catch-all | `docs/[...slug]/get.ts` + `http.get()` | `GET /docs/*` | `api.docs.get({ "*": "a/b" })` |
207
+ | Route group | `notes/(ops)/archive.ts` | `/notes/archive` | `api.notes.archive` |
208
+ | Root unit | `main/health.ts` + `http.get()` | `GET /health` | `api.main.health()` |
209
+ | Folder root | `main/route.ts` + `http.get()` | `GET /` | `api.main.root()` |
210
+
211
+ ## Units
212
+
213
+ The first folder under `src/flows/` is the **client unit**. Nested folders and
214
+ the leaf file build the URL. The `export const` name is the method on that unit.
215
+
216
+ ```text
217
+ src/flows/
218
+ ├── notes/ # Unit: notes → api.notes.*
219
+ │ ├── list.ts # GET /notes (reserved leaf)
220
+ │ ├── create.ts # POST /notes (reserved leaf)
221
+ │ ├── shapes.ts # skipped (not a route)
222
+ │ └── [id]/
223
+ │ ├── get.ts # GET /notes/:id
224
+ │ └── archive.ts # POST /notes/:id/archive
225
+ ├── billing/
226
+ │ └── (checkout)/ # omitted from the URL
227
+ │ └── charge.ts # POST /billing/charge (if http.post())
228
+ └── main/ # Unit: main — prefix omitted from the URL
229
+ ├── health.ts # GET /health
230
+ └── route.ts # GET /
231
+ ```
232
+
233
+ A file sitting directly in `src/flows/` (no unit folder) is not a route.
234
+
235
+ Unit folder names must be valid JS identifiers (`notes`, `main`, `_` allowed
236
+ inside; `my-notes` is skipped). Folders starting with `_`, `[`, or `(` are not
237
+ units.
238
+
239
+ **Consequence:** `export const getNote` from `get.ts` is `api.notes.getNote`, not
240
+ `api.notes.get`. Match the export to the name you want on the client.
241
+
242
+ ## Path Conventions
243
+
244
+ **Default — pathless.** Omit the path so `generated.ts` stamps the URL from disk:
245
+
246
+ ```typescript
247
+ http.get(); // pending until stampHttpPath runs
248
+ ```
249
+
250
+ **Control — explicit path.** Pass the URL template when the folder should not
251
+ own the route (barrel, public API shape, resource mount). The tree never
252
+ overwrites an explicit path:
253
+
254
+ ```typescript
255
+ http.get("/organizations/:orgId/members/:memberId");
256
+ ```
257
+
258
+ Path params, query string, and JSON body still merge into one object checked by
259
+ `in` — same order as [HTTP · Request Parsing](/docs/elements/flow/http#request-parsing).
260
+
261
+ ### Dynamic parameters
262
+
263
+ `[id]` → `:id`. The folder name is the param key. Declare the same key on `in`:
264
+
265
+ ```typescript title="src/flows/orgs/[orgId]/members/[memberId]/get.ts"
266
+ import { on, flow, http } from "okengine";
267
+ import { z } from "zod";
268
+
269
+ export const get = on(
270
+ http.get({ in: z.object({ orgId: z.string(), memberId: z.string() }) }),
271
+ flow({
272
+ do: async ({ orgId, memberId }) => ({ orgId, memberId }),
273
+ }),
274
+ );
275
+ ```
276
+
277
+ Stamped to `GET /orgs/:orgId/members/:memberId`.
278
+
279
+ ### Catch-alls
280
+
281
+ `[...slug]` → `*` (greedy rest). Optional `[[...slug]]` is **not** supported —
282
+ generate fails with `Optional catch-all "[[...slug]]" is not supported — use [...slug] (param is "*").`
283
+
284
+ A route that includes `*` selects the Trie matcher automatically (the compiled
285
+ RegExp matcher cannot express wildcards).
286
+
287
+ ### Route groups
288
+
289
+ A folder `(ops)` is omitted from the URL. Use it to group files without adding a
290
+ segment:
291
+
292
+ ```text
293
+ src/flows/notes/(ops)/archive.ts → /notes/archive
294
+ ```
295
+
296
+ `(ops)` never enters the Flow name either (`notes.archive`).
297
+
298
+ ### The `main` unit
299
+
300
+ `main` is omitted from the URL prefix. Flow names still use `main.`:
301
+
302
+ | File | URL | Flow name |
303
+ | ---------------- | ------------- | -------------------------------------- |
304
+ | `main/health.ts` | `/health` | `main.health` |
305
+ | `main/route.ts` | `/` | `main.root` (from `export const root`) |
306
+ | `main/index.ts` | `/` (extract) | barrel — pass `http.get("/")` |
307
+
308
+ ### Skip list
309
+
310
+ These files are never routes (walk skips them; path inference returns nothing):
311
+
312
+ | Pattern | Why |
313
+ | --------------------------- | ------------------------------------------------ |
314
+ | `generated.ts` | Adopt barrel (`oke dev` / `oke build` writes it) |
315
+ | `shapes.ts` | Shared Zod / contracts |
316
+ | `signals.ts` | Signal declarations |
317
+ | `*.test.ts` / `*.test.tsx` | Tests |
318
+ | `_` prefix (file or folder) | Private helpers (`notes/_lib/util.ts`) |
319
+
320
+ Skip-list files may sit next to tree routes. They do **not** turn a tree into a
321
+ barrel.
322
+
323
+ ## Reserved Leaves
324
+
325
+ To avoid `/notes/get` and `/orders/list`, these filenames add **no** URL
326
+ segment — the same five CRUD names as `http.resource`, plus folder roots:
327
+
328
+ | Leaf | Typical trigger | Example file | Stamped path |
329
+ | -------- | --------------- | ----------------------------------- | --------------- |
330
+ | `list` | `http.get()` | `notes/list.ts` | `/notes` |
331
+ | `create` | `http.post()` | `notes/create.ts` | `/notes` |
332
+ | `get` | `http.get()` | `notes/[id]/get.ts` | `/notes/:id` |
333
+ | `update` | `http.patch()` | `notes/[id]/update.ts` | `/notes/:id` |
334
+ | `remove` | `http.delete()` | `notes/[id]/remove.ts` | `/notes/:id` |
335
+ | `index` | _(barrel only)_ | `notes/index.ts` | `/notes` |
336
+ | `route` | any | `notes/route.ts` or `main/route.ts` | `/notes` or `/` |
337
+
338
+ Any other leaf **is** a segment: `query.ts` → `/notes/query`.
339
+
340
+ In a tree unit, do **not** add `index.ts` beside other route files — that is a
341
+ generate error. Use `route.ts` (or `list.ts` / `create.ts`) for the collection
342
+ root.
343
+
344
+ ## Barrel vs Tree
345
+
346
+ `oke dev` / `oke build` scans each `src/flows/<unit>/` folder and writes
347
+ `generated.ts`. Two shapes, never mixed:
348
+
349
+ <Tabs items={["Tree", "Barrel", "App entry"]}>
350
+
351
+ <Tab value="Tree">
352
+
353
+ `[param]` folders, `(group)` folders, or extra route files. The barrel imports
354
+ each file and stamps path + name:
355
+
356
+ ```typescript
357
+ const notes = {
358
+ get: stampHttpPath(stampFlowName(notes_$id$_get.get, "notes.get"), "/notes/:id"),
359
+ list: stampHttpPath(stampFlowName(notes_list.list, "notes.list"), "/notes"),
360
+ };
361
+ export { notes };
362
+ registerFlowUnits({ notes });
363
+ ```
364
+
365
+ `oke()` drains `registerFlowUnits` into `$routes`. `.adopt({ notes })` is
366
+ optional and additive.
367
+
368
+ </Tab>
369
+
370
+ <Tab value="Barrel">
371
+
372
+ Only `index.ts` (+ skip-list). Re-export, no stamp:
373
+
374
+ ```typescript
375
+ import * as notes from "./notes/index.ts";
376
+ export { notes };
377
+ registerFlowUnits({ notes });
378
+ ```
379
+
380
+ Declare `http.get("/notes")` and `flow("notes.list", {…})` (or rely on adopt to
381
+ stamp the name from the export). Pathless HTTP fails **OKE1040**.
382
+
383
+ </Tab>
384
+
385
+ <Tab value="App entry">
386
+
387
+ ```typescript title="src/app.ts"
388
+ import "@/flows/generated";
389
+ import { oke } from "okengine";
390
+
391
+ export const app = oke({ name: "notes" });
392
+ export type App = typeof app;
393
+ ```
394
+
395
+ Do not edit `generated.ts` by hand. Adding a unit folder without regenerating
396
+ leaves a stale barrel — **OKE1030** in prod / `oke dev` with Compose.
397
+
398
+ </Tab>
399
+
400
+ </Tabs>
401
+
402
+ <Accordions>
403
+
404
+ <Accordion title="Mixed barrel + tree">
405
+ `index.ts` plus `[id]/get.ts` (or any other route file) throws at generate:
406
+
407
+ ```text
408
+ Unit "notes" mixes a barrel index.ts with tree route files. Use only index.ts (barrel), or move the collection path to route.ts and keep [id]/ beside it.
409
+ ```
410
+
411
+ Fix: delete `index.ts` and use `list.ts` / `route.ts`, or fold every route into
412
+ `index.ts` with explicit paths.
413
+
414
+ </Accordion>
415
+
416
+ <Accordion title="Export collisions">
417
+ Two files in the same unit cannot share an `export const` name:
418
+
419
+ ```text
420
+ Unit "notes" exports "get" from both list.ts and route.ts.
421
+ ```
422
+
423
+ Rename one export. The client method is the export name, not the filename.
424
+
425
+ </Accordion>
426
+
427
+ <Accordion title="Unit-prefix drift">
428
+ `flow("tasks.get", {…})` living under `src/flows/notes/` throws:
429
+
430
+ ```text
431
+ flow("tasks.…") in notes/get.ts does not match the folder "notes".
432
+ ```
433
+
434
+ Use `flow("notes.get", {…})`, a nameless `flow({ do })` (stamped `notes.get`
435
+ from the export), or move the file.
436
+
437
+ </Accordion>
438
+
439
+ </Accordions>
440
+
441
+ ## Names
442
+
443
+ Three names, one file:
444
+
445
+ | Surface | Source | Example |
446
+ | --------- | ------------------------------------------------------------------- | ----------------------- |
447
+ | HTTP path | File tree (default) or explicit `http.get("/x")` | `/notes/:id` |
448
+ | Flow name | `unit.export` from `flow({ do })` (default), or `flow("notes.get")` | `notes.get` |
449
+ | Client | Unit folder + `export const` | `api.notes.get({ id })` |
450
+
451
+ Nameless `flow({ do })` is the tree default — same rule as pathless HTTP. Pass
452
+ `flow("notes.get")` only for control (stable name, barrel, or matching unit
453
+ prefix). Wrong-unit prefixes fail generate.
454
+
455
+ Non-HTTP files still join the unit. A signal consumer in `notes/on-created.ts`
456
+ is `api.notes.onCreated` over RPC (`POST /_oke/notes/onCreated`), not HTTP.
457
+
458
+ HTTP flows that remain nameless after adopt fail **OKE1045**.
459
+
460
+ ## Runtime Matching
461
+
462
+ All adopted HTTP bindings go into one matcher. Wrong method on a known path is
463
+ **405** with `Allow`. No match is a bare **404** `Not Found`.
464
+
465
+ | `oke({ router })` | Default | What it does |
466
+ | ----------------- | ------- | ----------------------------------------------------------------------------------------------------------- |
467
+ | `"default"` | yes | Compiled RegExp (O(1) static map + per-bucket regex for `:id`). Falls back to Trie when a path includes `*` |
468
+ | `"edge"` | | Linear scan, then Trie. No RegExp compile — cold-start / isolates |
469
+
470
+ p99 match stays under **1 ms** on the compiled matcher. You do not pick buckets
471
+ by hand — a catch-all in the table selects Trie for the whole app.
472
+
473
+ Duplicate `METHOD + path` fails boot (**OKE1041**), including a resource mount
474
+ plus a handwritten `http.get("/notes")`.
475
+
476
+ ## Troubleshooting
477
+
478
+ <Accordions>
479
+
480
+ <Accordion title="404 Not Found — route missing">
481
+ No Flow is bound to that method + path. Check the explicit path, or for pathless routes the
482
+ file-tree stamp (`notes/[id]/get.ts` → `GET /notes/:id`). A bare `404` with body `Not Found` means
483
+ the router found no match.
484
+ </Accordion>
485
+
486
+ <Accordion title="405 Method Not Allowed on valid route">
487
+ The path exists but has not been bound to the requested verb. `Allow` lists the methods that are.
488
+ `list.ts` with `http.get()` is GET-only — POST that URL is 405, not a missing file.
489
+ </Accordion>
490
+
491
+ <Accordion title="OKE1040 — pathless trigger never stamped">
492
+ Cause: `Flow "{flow}" bound {method} with no path — the file-tree stamp never ran.` Import
493
+ `@/flows/generated`, run `oke dev` / `oke build`, or pass `http.get("/…")`. Barrels do not stamp —
494
+ they need the explicit path.
495
+ </Accordion>
496
+
497
+ <Accordion title="OKE1030 — adopt barrel stale">
498
+ Cause: `src/flows/{unit} exists on disk but adopted no flows — the .adopt() barrel is stale.` Run
499
+ `oke dev` or `oke build` after adding a unit folder. Prod and Compose `oke dev` refuse to boot
500
+ this way.
501
+ </Accordion>
502
+
503
+ <Accordion title="OKE1041 — method + path bound twice">
504
+ Cause: `{method} {path} is bound twice (flow "{flow}").` Two tree files stamped the same verb +
505
+ path (`list.ts` and `route.ts` both `http.get()`), or a resource mount plus a handwritten route.
506
+ Drop one binding.
507
+ </Accordion>
508
+
509
+ <Accordion title="OKE1045 — HTTP flow unnamed">
510
+ Cause: `An HTTP flow on {method} {path} has no name.`
511
+ Use `flow("unit.export", {…})` or `export const` from a `src/flows/<unit>/`
512
+ file so the tree can stamp `unit.export`. `export default` is not picked up.
513
+ </Accordion>
514
+
515
+ <Accordion title="422 — path param missing from in">
516
+ `[id]` stamps `:id`. `in` must declare `id` (same key). A schema that expects `userId` while the
517
+ path is `:id` fails validation before `do`.
518
+ </Accordion>
519
+
520
+ <Accordion title="Catch-all input is empty / wrong key">
521
+ `[...slug]` does not bind `slug`. The router param is `"*"`. Declare
522
+ `in: z.object({ "*": z.string() })` and read `input["*"]`. Optional
523
+ `[[...slug]]` is rejected at generate.
524
+ </Accordion>
525
+
526
+ <Accordion title="Unit mixes index.ts with tree files">
527
+ Generate: `Unit "…" mixes a barrel index.ts with tree route files.` Use only `index.ts` (explicit
528
+ paths), or move the collection path to `route.ts` and keep `[id]/` beside it.
529
+ </Accordion>
530
+
531
+ </Accordions>
532
+
533
+ ## Learn more
534
+
535
+ - [HTTP](/docs/elements/flow/http) — verbs, envelopes, `http.resource`, live SSE
536
+ - [Client](/docs/client/calling) — `api.notes.get`, REST vs RPC, `$routes`
537
+ - [Errors](/docs/reference/errors) — OKE1040 · OKE1030 · OKE1041 · OKE1045
538
+ - [The Model](/docs/understand/the-model) — derived routes, no hand-written table
539
+ - [Gate](/docs/elements/gate) — `.gate(...)` / `.public()` on the same trigger
540
+
541
+ ## Next
542
+
543
+ <Cards>
544
+ <Card
545
+ title="HTTP"
546
+ description="REST verbs, RFC 10008 QUERY, CRUD mounts, and live SSE on Flow."
547
+ href="/docs/elements/flow/http"
548
+ />
549
+ <Card
550
+ title="Client"
551
+ description="Typed caller — createClient, envelopes, REST from $routes."
552
+ href="/docs/client/calling"
553
+ />
554
+ <Card
555
+ title="Consumers"
556
+ description="Signal workers, named Clock jobs, and SQL CDC — one Flow species."
557
+ href="/docs/elements/flow/consumers"
558
+ />
559
+ </Cards>