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
@@ -1,328 +0,0 @@
1
- ---
2
- title: Testing
3
- description: Write deterministic tests for your Flows with createTestApp — freeze the clock, mock AI, drain signals, and prove side effects.
4
- icon: FlaskConical
5
- ---
6
-
7
- `createTestApp` boots the **same app** you deploy, but with memory drivers and a
8
- frozen clock. You drive it through `t.api`, `t.auth`, `t.signals`, `t.clock`,
9
- and `t.channels` — every assertion is deterministic.
10
-
11
- <Callout title="The one rule">
12
- Boot the same `app` your server boots. Assert only through the harness surfaces (`t.api`,
13
- `t.auth`, `t.signals`, `t.clock`, `t.channels`, `t.ai`, `t.effects`) — never reach into internal
14
- runtimes.
15
- </Callout>
16
-
17
- ## Import
18
-
19
- The harness ships as a separate subpath so production bundles stay small:
20
-
21
- ```typescript title="tests/orders.test.ts"
22
- import { describe, expect, test } from "bun:test";
23
- import { createTestApp } from "okengine/testing"; // or "okengine/test"
24
- import { app } from "../src/app";
25
-
26
- test("orders flow", async () => {
27
- const t = await createTestApp(app);
28
- // ...
29
- await t.close();
30
- });
31
- ```
32
-
33
- Both `okengine/testing` and `okengine/test` are aliases. Use `okengine/testing`
34
- (→ `dist/testing.js`) for published packages and hoisted monorepos; `okengine/test`
35
- is the source-only path older starters use.
36
-
37
- ## Quick start
38
-
39
- <Steps>
40
-
41
- <Step>
42
- ### Adopt your Flows
43
-
44
- Every behavior on the app is reachable. No separate test database or server.
45
-
46
- ```typescript title="src/flows/orders/index.ts"
47
- import { on, flow, http } from "okengine";
48
- import { z } from "zod";
49
-
50
- export const create = on(
51
- http.post("/orders").gate(member),
52
- flow("orders.create", {
53
- in: z.object({ sku: z.string(), qty: z.number() }),
54
- out: z.object({ id: z.string() }),
55
- do: async (input, fx) => {
56
- const id = fx.id();
57
- await fx.emit(orderPlaced, { orderId: id, ...input });
58
- return { id };
59
- },
60
- }),
61
- );
62
- ```
63
-
64
- </Step>
65
-
66
- <Step>
67
- ### Boot the harness
68
-
69
- ```typescript title="tests/orders.test.ts"
70
- const t = await createTestApp(app, { gates: [member] });
71
- ```
72
-
73
- </Step>
74
-
75
- <Step>
76
- ### Login and call
77
-
78
- ```typescript
79
- const u = await t.auth.loginAs({ scopes: ["order:create"] });
80
- const { data, error } = await t.api.orders.create({ sku: "COFFEE", qty: 2 }, { as: u });
81
- expect(error).toBeNull();
82
- expect(data).toEqual({ id: expect.any(String) });
83
- ```
84
-
85
- </Step>
86
-
87
- <Step>
88
- ### Advance time and drain signals
89
-
90
- Signal handlers and Clocks are processed deterministically:
91
-
92
- ```typescript
93
- await t.signals.drain(); // run queued signal work
94
- await t.clock.advance("2m"); // tick scheduled Clocks forward
95
- expect(t.channels.sent()).toContainEqual(expect.objectContaining({ template: "order-confirmed" }));
96
- ```
97
-
98
- </Step>
99
-
100
- </Steps>
101
-
102
- ## Harness surface
103
-
104
- | Property | What it does |
105
- | ------------------------------------------- | -------------------------------------------------------------------------------------- |
106
- | `t.api.<unit>.<flow>(input, opts?)` | Invoke an adopted Flow directly with a `{ as }` principal and optional `{ tenant }` |
107
- | `t.auth.loginAs(options)` | Returns a verified `TestUser` with `id`, `scopes`, `verified`, and optional `tenantId` |
108
- | `t.clock.advance(by)` / `t.clock.now()` | Freeze and move the harness clock (used by durable sleeps and Clocks) |
109
- | `t.cron.run(name)` | Run a named Clock / `every()` interval now, still leader-elected |
110
- | `t.signals.drain()` | Drain the signal bus until idle (deterministic queued work) |
111
- | `t.signals.subscribeLive(signal, handlers)` | Subscribe to a `delivery: "live"` signal's event stream (deterministic) |
112
- | `t.signals.waitForLive(signal, predicate)` | Resolve once a live event matching `predicate` arrives |
113
- | `t.channels.sent()` | Receipts / inbox entries sent during the test |
114
- | `t.ai.mock(prompt, output)` | Register a canned mock response for a Prompt |
115
- | `t.ai.cost()` | Accumulated AI cost across `fx.ask` calls |
116
- | `t.effects.of(runId)` | Effect ledger for a recorded run (reads / writes / emits / sends) |
117
- | `t.runs()` | All wide events recorded during the test |
118
- | `t.close()` | Close booted element runtimes |
119
-
120
- ## Multi-tenancy & RLS
121
-
122
- With `gate.auth: { tenant: true }` you can test tenant isolation with real
123
- row-level security.
124
-
125
- ```typescript title="src/db/documents.ts"
126
- import { store, field } from "okengine";
127
-
128
- export const documents = store.schema.table(
129
- "documents",
130
- {
131
- id: field.text().primaryKey(),
132
- tenant_id: field.text().notNull(),
133
- title: field.text().notNull(),
134
- },
135
- [store.schema.policy.tenant("tenant_id", { for: "all" })],
136
- );
137
- ```
138
-
139
- Give each test user a tenant, and drive distinct tenants against the same
140
-
141
- Flow:
142
-
143
- ```typescript title="tests/tenant.test.ts"
144
- const t = await createTestApp(app, {
145
- gates: [member],
146
- boot: { config: { drivers: { store: { sql: { test: "pglite" } } } } },
147
- });
148
-
149
- const alice = await t.auth.loginAs({ id: "alice", tenantId: "acme" });
150
- const bob = await t.auth.loginAs({ id: "bob", tenantId: "globex" });
151
-
152
- await t.api.docs.create({ title: "Acme Roadmap" }, { as: alice });
153
- await t.api.docs.create({ title: "Globex Secrets" }, { as: bob });
154
-
155
- const acmeDocs = await t.api.docs.list(undefined, { as: alice });
156
- expect(acmeDocs.data).toHaveLength(1); // only Acme Roadmap
157
- ```
158
-
159
- Re-scope a single call to another tenant with `{ tenant }`, independent of the
160
- principal's own tenant:
161
-
162
- ```typescript
163
- const carol = await t.auth.loginAs({ id: "carol", tenantId: "acme" });
164
- const { data } = await t.api.docs.create(
165
- { title: "Globex Carol" },
166
- { as: carol, tenant: "globex" },
167
- );
168
- expect(data.tenantId).toBe("globex");
169
- ```
170
-
171
- RLS policies are row-level: tenant-scoped tables need `store.schema.policy.tenant`
172
- (or `store.schema.unscoped()` for genuinely global tables). Harness boots do not
173
- run migrations — in a real app `oke db push` installs those policies.
174
-
175
- ## Deterministic live signals
176
-
177
- Signals with `delivery: "live"` back client feeds and SSE streams. The harness
178
- exposes the retained event stream so you can assert both sides deterministically:
179
-
180
- ```typescript title="tests/live.test.ts"
181
- const orderStatus = signal("order-status", {
182
- delivery: "live",
183
- retention: { maxCount: 10 },
184
- });
185
-
186
- on(
187
- http.post("/orders/status").public(),
188
- flow("orders.updateStatus", {
189
- in: z.object({ orderId: z.string(), status: z.string() }),
190
- effects: { emits: ["order-status"] },
191
- do: async (input, fx) => {
192
- await fx.emit(orderStatus, input);
193
- return { ok: true };
194
- },
195
- }),
196
- );
197
- ```
198
-
199
- ```typescript
200
- const seen: Array<{ orderId: string; status: string }> = [];
201
-
202
- const unsubscribe = t.signals.subscribeLive(orderStatus, {
203
- onEvent: (event) => seen.push(event),
204
- });
205
-
206
- await t.api.orders.updateStatus({ orderId: "o1", status: "placed" });
207
- await t.signals.drain();
208
- expect(seen.map((e) => e.status)).toEqual(["placed"]);
209
-
210
- // Resolve a promise the moment a matching event arrives.
211
- const deliveredPromise = t.signals.waitForLive(
212
- orderStatus,
213
- (event) => event.status === "delivered",
214
- );
215
- await t.api.orders.updateStatus({ orderId: "o1", status: "delivered" });
216
- await t.signals.drain();
217
- const delivered = await deliveredPromise;
218
- expect(delivered.status).toBe("delivered");
219
-
220
- unsubscribe(); // no further events observed
221
- ```
222
-
223
- Call `t.signals.drain()` after each emit — live events are staged until the bus
224
- drains. `retention` caps the replayed tape (`maxCount` / `maxAge`); it is only
225
- valid on `delivery: "live"` signals.
226
-
227
- ## Time travel
228
-
229
- `t.clock` freezes time. `t.clock.advance("2m")` moves the clock forward and
230
- resumes any durable sleeps that become due. `t.cron.run("expire-stale")` runs a
231
- named Clock now:
232
-
233
- ```typescript
234
- await t.clock.advance("30s"); // durable sleeps resume
235
- await t.cron.run("expire-stale"); // named Clock fires
236
- expect(t.channels.sent()).toHaveLength(1); // side effect observed
237
- ```
238
-
239
- ## AI & channels
240
-
241
- `fx.ask` routes to a mock driver. Register canned outputs and read accumulated
242
- cost:
243
-
244
- ```typescript
245
- t.ai.mock(summarizePrompt, { title: "Mock summary" });
246
- const { data } = await t.api.posts.summarize({ postId: "p_1" }, { as: u });
247
- expect(data).toEqual({ title: "Mock summary" });
248
- expect(t.ai.cost()).toBe(0);
249
- ```
250
-
251
- Channels write to an inbox instead of a transport:
252
-
253
- ```typescript
254
- expect(t.channels.sent()).toContainEqual(
255
- expect.objectContaining({ template: "order-confirmed", to: u.id }),
256
- );
257
- ```
258
-
259
- ## Troubleshooting
260
-
261
- <Accordions>
262
-
263
- <Accordion title="createTestApp fails to boot — missing secrets or stores">
264
- The starter patches test drivers and fallback secrets on the app options. If
265
- your `oke({ ... })` references a Vault secret or Store that the template does
266
- not define, pass them explicitly:
267
-
268
- ```typescript
269
- await createTestApp(app, {
270
- secrets: [openAiKey],
271
- vaultSecrets: { OPENAI_KEY: "sk-test" },
272
- });
273
- ```
274
-
275
- </Accordion>
276
-
277
- <Accordion title="My live subscription never receives events">
278
- - Live events are staged until `t.signals.drain()` — await `drain()` after
279
- every emitting call.
280
- - Register `subscribeLive` / `waitForLive` **before** you emit.
281
- - A signal with a schema drops violating emits — assert `res.error`.
282
-
283
- </Accordion>
284
-
285
- <Accordion title="Cross-tenant reads return a stale cached row">
286
- Tier-1 read caching keys by flow, input, and user id — tenant is a row-level
287
- RLS scope, not a cache dimension. For reads under a `{ tenant }` override, use
288
- a distinct call principal (or write first) so the cache key differs.
289
-
290
- </Accordion>
291
-
292
- <Accordion title="PGlite RLS policies aren't applied in the harness">
293
- Test boots never run migrations — `oke db push` installs DDL and
294
- `store.schema.policy.tenant` policies in real apps.
295
-
296
- Assert real RLS by installing the policy + `oke.*` helpers on the booted
297
- primary connection (as the repo's `sql-rls-isolation.test.ts` does).
298
-
299
- </Accordion>
300
-
301
- </Accordions>
302
-
303
- ## Learn more
304
-
305
- - [Flow](/docs/elements/flow) — triggers, contracts, effects, and composition
306
- - [Store](/docs/elements/store) — SQL, KV, files, index, and RLS policies
307
- - [Signal](/docs/elements/signal) — delivery physics, retention, and live feeds
308
- - [Client](/docs/reference/client) — the typed client for real HTTP calls
309
-
310
- ## Next
311
-
312
- <Cards>
313
- <Card
314
- title="Project structure"
315
- description="Folders are the URL; unit plus export is the name."
316
- href="/docs/get-started/project-structure"
317
- />
318
- <Card
319
- title="Flow"
320
- description="Triggers, contracts, effects, and composition."
321
- href="/docs/elements/flow"
322
- />
323
- <Card
324
- title="Signal"
325
- description="Delivery physics, retention, and deterministic live feeds."
326
- href="/docs/elements/signal"
327
- />
328
- </Cards>
@@ -1,162 +0,0 @@
1
- ---
2
- title: Why OKE
3
- description: From forty tools to one species — the Manifest, the `fx` rule, and the eight closed elements.
4
- source: docs/spec/unified-theory.md
5
- icon: Compass
6
- ---
7
-
8
- ## From forty tools to one species
9
-
10
- A booking API, a nightly cleanup job, a receipt email, a row-change hook — in most stacks these are **four frameworks**. In OKE they are **one species** with one shape. Learn the shape once; only the trigger changes.
11
-
12
- > **The one rule**
13
- > Every backend behavior is a **Flow**: `on(Trigger) → Effects`. There are no separate species called endpoints, handlers, consumers, jobs, or workflows.
14
-
15
- <Callout title="A note on the count">
16
- 'Forty' is a representative illustration of the number of backend concerns developers commonly
17
- assemble across modern stacks, not a literal count of backend technologies.
18
- </Callout>
19
-
20
- ## The pain we solve
21
-
22
- Every TypeScript backend works on day one. The bill arrives later. None of these are router problems — they are **gaps** between what your code knows and what your tooling knows.
23
-
24
- ### Cache that lies
25
-
26
- You add a column to `orders` and update three writers. The cache key in `checkout` is not one of them. A customer finds it a week later.
27
-
28
- OKE derives: reads and writes are recorded through `fx`, so cache invalidation follows the Flow — there is no separate key to remember.
29
-
30
- ### Secret that fails at 2am
31
-
32
- `STRIPE_KEY` lives in your laptop's `.env`, a README, and a teammate's shell history. The deploy boots fine — the first charge request dies at 2am.
33
-
34
- OKE derives: [Vault](/docs/elements/vault) contracts declare the need in code; boot resolves every contract and **fails loud** with every gap listed — never halfway.
35
-
36
- ### The glue you rewrite
37
-
38
- CORS rules, security headers, CSRF tokens, compression — copied from the last repo, tweaked, and already drifting from whatever that repo does today.
39
-
40
- OKE derives: the official `okengine/plugins` set ships this glue once — shared lifecycle, optional live DB config, nothing to re-copy.
41
-
42
- ### The dashboard that doesn't know you
43
-
44
- Your observability stack learned your routes from sampled traffic. The Flow you deployed an hour ago is invisible until someone wires it by hand.
45
-
46
- OKE derives: its operator interface reads the Manifest — flows, effects, traces, architecture — current on every save, in dev and prod (`:6533`).
47
-
48
- ### Permission check in the wrong place
49
-
50
- `if (!user.isAdmin)` sits in handler forty-one of sixty. Which Flows touch `payments`? grep answers slowly; review answers never.
51
-
52
- OKE derives: declared effects produce a **least-privilege matrix** — widening access appears in Manifest Diff, not in a diff nobody reads.
53
-
54
- ### Local works, prod doesn't
55
-
56
- Local runs one vendor client, CI another, prod a third — three glue stories for the same database.
57
-
58
- OKE derives: drivers are named after protocols (`postgres`, `redis`, `s3`), the vendor lives in `images`, and `oke dev` runs the real stack locally.
59
-
60
- ---
61
-
62
- Every gap above is the same shape: knowledge the code already has, duplicated somewhere the compiler cannot check. **The tax is drift.** One change costs fifteen seams to update by hand; in OKE it always costs one.
63
-
64
- ## One Manifest feeds every surface
65
-
66
- At build time OKE extracts a **Manifest** — the compiled, versioned contract between your backend model and everything derived from it. The source of truth is your model expressed in code (`on(Trigger) → Flow → fx → Effects`); the Manifest freezes that model into a machine-readable, diffable contract. You do not write or hand-maintain the Manifest:
67
-
68
- | Surface | Port | You maintain? |
69
- | --------------------------------- | ------------------ | ----------------------------- |
70
- | Typed client (`okengine/client`) | your app code | No — derived from `Manifest` |
71
- | Console panels, traces, explorers | `:6533` | No — reads the Manifest |
72
- | MCP for agents | `:6535` | No — reads the Manifest |
73
- | Architecture diagram | Console | No — it _is_ the effect graph |
74
- | Capability matrix + cache keys | compiler / runtime | No — inferred from `fx` |
75
-
76
- Because every surface reads the same Manifest contract, they **cannot disagree** — there is only one source of truth.
77
-
78
- ## The `fx` rule — one door to the world
79
-
80
- **All world access goes through `fx`.** A Flow that imports `node:fs`, calls `fetch` directly, or uses `Date.now()` is a defect. Effects are **inferred from what a Flow touches through `fx`**, and that inference powers the Manifest, the Console, caching, and durability.
81
-
82
- <Callout title="What `fx` records">
83
- Every read, write, emit, send, ask, secret, and call is captured — so the Manifest knows exactly
84
- which flows touch `orders` or send PII to a model, without you declaring it.
85
- </Callout>
86
-
87
- | Inferred from `fx` | What it gives you |
88
- | ----------------------- | ------------------------------------ |
89
- | Cache invalidation keys | Automatic — follows the Flow |
90
- | Live queries | Built-in subscription model |
91
- | Least-privilege tokens | Capability matrix from effects |
92
- | Deterministic tests | Time, clock, and randomness injected |
93
- | Manifest Diff | Exact change surface on every save |
94
-
95
- ## Eight elements — a closed set
96
-
97
- Forty infrastructure concerns collapse into eight elements — each kept only because it has **irreducible physics**. New infrastructure becomes a **driver** for an existing element, never a ninth.
98
-
99
- | Element | Essence | Replaces the zoo |
100
- | ----------- | ----------------------------- | --------------------------------------------------------- |
101
- | **Flow** | Behavior | endpoint · handler · consumer · job · workflow · webhook |
102
- | **Signal** | Data in motion | queue · pub/sub · stream · websocket · SSE · event bus |
103
- | **Store** | Data at rest | database · cache · KV · file storage · search index |
104
- | **Clock** | Time | cron · delay · timeout · durable sleep · TTL |
105
- | **Gate** | Permission to act | auth · session · ABAC · rate limit · quota · feature flag |
106
- | **Vault** | Protected knowledge | secrets · config · environment |
107
- | **Channel** | Reaching humans | email · SMS · WhatsApp · push |
108
- | **AI** | Reaching machine intelligence | model calls · prompts · embeddings · agents · RAG |
109
-
110
- Drivers are named after **protocols** (`postgres`, `redis`, `s3`) — never vendors. The vendor lives in `images`, and `oke dev` runs the real stack locally.
111
-
112
- ## The shape of a Flow
113
-
114
- One pipeline. Only the trigger changes between an endpoint, a job, a consumer, and a row hook:
115
-
116
- ```ts
117
- import { on, flow, http } from "okengine/http";
118
-
119
- export const health = on(http.get().public(), flow({ do: () => ({ ok: true }) }));
120
- ```
121
-
122
- | Piece | Role |
123
- | ------------- | -------------------------------------------------------------- |
124
- | **Trigger** | How work starts — `http`, a signal, `every`, a row change |
125
- | **Contracts** | `in`, `out`, typed `errors` — validated before and after `do` |
126
- | **`do`** | The body — every read, write, emit, and call goes through `fx` |
127
- | **Effects** | Inferred from those `fx` calls — not hand-annotated |
128
-
129
- Consequence: **one documentation path, one trace shape, one Flow model, one thing for an AI agent to learn.**
130
-
131
- ## Ambition, stated plainly
132
-
133
- > **Ambition**: The default, most capable TypeScript backend — Bun-first, Web-Standards portable, contract-first
134
- > **Grounded in**: Eight elements, effect inference through `fx`, Gate and Vault, the official plugin set
135
- > **Maturity**: **pre-1.0** — published and usable; not independently battle-tested at scale yet
136
-
137
- ## Learn more
138
-
139
- - [Introduction](/docs/get-started/introduction) — the one law, eight elements, one contract
140
- - [Flow](/docs/elements/flow) — how effects are recorded and inferred
141
- - [Vault](/docs/elements/vault) — fail-loud secret contracts
142
- - [Plugins](/docs/reference/plugins) — the official HTTP glue set
143
-
144
- ## Next
145
-
146
- <Cards>
147
- <Card
148
- title="Installation"
149
- description="Scaffold with create-oke and open the Console."
150
- href="/docs/get-started/installation"
151
- />
152
- <Card
153
- title="Basic Usage"
154
- description="Health Flow, typed client, and bun:test."
155
- href="/docs/get-started/basic-usage"
156
- />
157
- <Card
158
- title="Introduction"
159
- description="The one law, eight elements, one contract."
160
- href="/docs/get-started/introduction"
161
- />
162
- </Cards>
@@ -1,151 +0,0 @@
1
- ---
2
- title: "llama.cpp"
3
- description: "Default local AI image — OpenAI-compatible llama-server, loopback-only publish, pinned build ≥ b8146."
4
- icon: "Bot"
5
- source: "docs/spec/unified-theory.md"
6
- ---
7
-
8
- llama.cpp is the default `images.ai` pin for local inference. It runs
9
- `llama-server` with an OpenAI-compatible `/v1` API — lightest resource footprint
10
- for single-user / dev. Driver id stays `openai-compatible`.
11
-
12
- <Callout title="The one rule">
13
- Pin a verified build ≥ `b8146`, publish only on loopback, and load models only from curated
14
- registries (Docker Hub `ai/`) — never arbitrary untrusted GGUF.
15
- </Callout>
16
-
17
- ## Quick start
18
-
19
- <Steps>
20
-
21
- <Step>
22
- ### Pin driver + image
23
-
24
- ```typescript title="oke.config.ts"
25
- drivers: {
26
- ai: { dev: "openai-compatible", test: "mock", prod: "openai-compatible" },
27
- },
28
- images: {
29
- ai: "ghcr.io/ggml-org/llama.cpp:server-b10450", // never :latest
30
- },
31
- ```
32
-
33
- Or `oke ai setup --provider llama-cpp` (TTY: banner → Ultra Fast / Fast /
34
- Balanced / Smart → up to 20 curated Docker Hub `ai/` picks per tier) / `--yes`
35
- for `granite3.3:2b`.
36
-
37
- </Step>
38
-
39
- <Step>
40
- ### Env written by the stack
41
-
42
- ```bash title=".env.local"
43
- OKE_AI_URL=http://127.0.0.1:8080/v1
44
- OKE_AI_MODEL=granite3.3:2b
45
- ```
46
-
47
- `OKE_AI_MODEL` is a Docker Hub `ai/<id>` model. The recipe writes
48
- `.oke/llama-entrypoint.py` (generated, gitignored), Hub-pulls into the cache
49
- volume, then starts `llama-server -m <gguf> --alias <id>` (single-model).
50
-
51
- Never set `LLAMA_ARG_MODELS_PRESET` / `LLAMA_ARG_DOCKER_REPO` — those hang on
52
- b10290+. `oke dev` shows the model id and polls `/v1/models` until `ready`
53
- (first boot may take minutes).
54
-
55
- </Step>
56
-
57
- <Step>
58
- ### Ask through the OpenAI-compatible driver
59
-
60
- ```typescript
61
- import { ai } from "okengine";
62
-
63
- export const smart = ai.model("smart", {
64
- provider: "openai-compatible",
65
- model: process.env.OKE_AI_MODEL ?? "granite3.3:2b",
66
- });
67
- ```
68
-
69
- </Step>
70
-
71
- </Steps>
72
-
73
- ## Security (hard requirements)
74
-
75
- | Control | Requirement |
76
- | -------------------- | ---------------------------------------------------------------------------- |
77
- | Host publish | `127.0.0.1:8080:8080` only — never `0.0.0.0` |
78
- | Image pin | Explicit build ≥ **b8146** (CVE-2026-27940 / CVE-2026-33298); never `latest` |
79
- | Model source | Docker Hub [`ai/`](https://hub.docker.com/u/ai) namespace (or known HF GGUF) |
80
- | Untrusted GGUF | **Forbidden** — crafted files can RCE the parser on unpatched builds |
81
- | RPC / extra backends | Not published — OpenAI HTTP only |
82
-
83
- Inside the container the server listens on `0.0.0.0` so the Compose network and
84
- loopback map work. The **host** bind is loopback — same isolation idea as
85
- Postgres/Redis, stricter on the published interface because of GGUF CVE risk.
86
-
87
- ## Required env
88
-
89
- | Variable | Required? | Meaning |
90
- | -------------- | ----------------- | --------------------------------------------- |
91
- | `OKE_AI_URL` | **Yes** in docker | Base URL including `/v1` |
92
- | `OKE_AI_MODEL` | Recommended | Docker Hub `ai/` id (default `granite3.3:2b`) |
93
-
94
- ## What the recipe configures
95
-
96
- | Field | Value |
97
- | -------------- | ------------------------------------------------------------ |
98
- | Container port | `8080` |
99
- | Host publish | `127.0.0.1:8080:8080` |
100
- | Healthcheck | `GET /health`, every 5s, 24 retries, 900s start |
101
- | Connection URL | `http://host:8080/v1` |
102
- | Model load | `.oke/llama-entrypoint.py` → Hub pull (incl. CNCF) then `-m` |
103
-
104
- ## When to choose something else
105
-
106
- | Workload | Prefer |
107
- | ------------------------------------------ | --------------------------------------- |
108
- | Single-user / dev, lightest footprint | **llama.cpp** (this recipe) |
109
- | Local DX with library pull UX | [Ollama](/docs/recipes/ollama) |
110
- | Multi-user / production concurrency on GPU | [vLLM](/docs/recipes/vllm) |
111
- | Structured / agent workloads on GPU | [SGLang](/docs/recipes/sglang) |
112
- | Managed cloud | Anthropic / OpenAI / … (no `images.ai`) |
113
-
114
- ## Troubleshooting
115
-
116
- <Accordions>
117
- <Accordion title="Connection refused on :8080">
118
-
119
- Confirm compose published `127.0.0.1:8080:8080` (not bare `8080:8080` on all
120
- interfaces). `OKE_AI_URL` must include `/v1`.
121
-
122
- </Accordion>
123
- <Accordion title="Model fails to load / slow first boot">
124
-
125
- First start Hub-pulls the curated `ai/` model into the named cache volume
126
- (see logs: `oke ai: ensuring…` / download %). Prefer `oke ai setup` tiers
127
- (Ultra Fast → `granite3.3:2b`) for smoke tests.
128
-
129
- Confirm `OKE_AI_MODEL` in `.env.local`. Watch `oke
130
- dev` until AI status is `ready`.
131
-
132
- If status stays `loading` on Compose that still uses `--models-preset`,
133
- regenerate `docker/` and recreate AI. Never mount random GGUF or set
134
- `LLAMA_ARG_MODELS_PRESET` / `LLAMA_ARG_DOCKER_REPO`.
135
-
136
- </Accordion>
137
- </Accordions>
138
-
139
- ## Learn more
140
-
141
- - [AI](/docs/elements/ai) — `fx.ask`, prompts, drivers
142
- - [Ollama](/docs/recipes/ollama) — fully supported alternative
143
- - [Environment variables](/docs/reference/environment-variables) — `OKE_AI_*`
144
-
145
- ## Next
146
-
147
- <Cards>
148
- <Card title="Ollama" description="Library UX alternative." href="/docs/recipes/ollama" />
149
- <Card title="vLLM" description="Production GPU serving." href="/docs/recipes/vllm" />
150
- <Card title="AI" description="Prompts, models, guardrails." href="/docs/elements/ai" />
151
- </Cards>