okengine 0.18.5 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (510) hide show
  1. package/AGENTS.md +18 -10
  2. package/README.md +2 -2
  3. package/package.json +51 -50
  4. package/site/content/docs/ai/llms-txt.mdx +1 -1
  5. package/site/content/docs/ai/meta.json +1 -1
  6. package/site/content/docs/ai/skills.mdx +4 -1
  7. package/site/content/docs/ai/try-it.mdx +58 -0
  8. package/site/content/docs/client/auth.mdx +208 -0
  9. package/site/content/docs/client/calling.mdx +451 -0
  10. package/site/content/docs/client/index.mdx +209 -0
  11. package/site/content/docs/client/live.mdx +234 -0
  12. package/site/content/docs/client/meta.json +5 -0
  13. package/site/content/docs/client/react.mdx +249 -0
  14. package/site/content/docs/elements/ai/agents.mdx +232 -0
  15. package/site/content/docs/elements/ai/index.mdx +341 -0
  16. package/site/content/docs/elements/ai/mcp.mdx +275 -0
  17. package/site/content/docs/elements/ai/meta.json +5 -0
  18. package/site/content/docs/elements/ai/models.mdx +283 -0
  19. package/site/content/docs/elements/ai/prompts.mdx +256 -0
  20. package/site/content/docs/elements/channel/email.mdx +266 -0
  21. package/site/content/docs/elements/channel/index.mdx +344 -0
  22. package/site/content/docs/elements/channel/meta.json +5 -0
  23. package/site/content/docs/elements/channel/push.mdx +218 -0
  24. package/site/content/docs/elements/channel/receipts.mdx +206 -0
  25. package/site/content/docs/elements/channel/sms.mdx +264 -0
  26. package/site/content/docs/elements/channel/whatsapp.mdx +220 -0
  27. package/site/content/docs/elements/clock/index.mdx +300 -0
  28. package/site/content/docs/elements/clock/meta.json +5 -0
  29. package/site/content/docs/elements/clock/schedules.mdx +508 -0
  30. package/site/content/docs/elements/clock/sleep.mdx +445 -0
  31. package/site/content/docs/elements/flow/consumers.mdx +707 -0
  32. package/site/content/docs/elements/flow/http.mdx +1080 -0
  33. package/site/content/docs/elements/flow/index.mdx +618 -0
  34. package/site/content/docs/elements/flow/meta.json +5 -0
  35. package/site/content/docs/elements/flow/routing.mdx +559 -0
  36. package/site/content/docs/elements/flow/workflows.mdx +640 -0
  37. package/site/content/docs/elements/gate/auth.mdx +371 -0
  38. package/site/content/docs/elements/gate/authorization.mdx +298 -0
  39. package/site/content/docs/elements/gate/index.mdx +418 -0
  40. package/site/content/docs/elements/gate/meta.json +5 -0
  41. package/site/content/docs/elements/gate/rate-limits.mdx +365 -0
  42. package/site/content/docs/elements/gate/rls.mdx +303 -0
  43. package/site/content/docs/elements/gate/tenancy.mdx +372 -0
  44. package/site/content/docs/elements/index.mdx +20 -10
  45. package/site/content/docs/elements/signal/broadcast.mdx +517 -0
  46. package/site/content/docs/elements/signal/index.mdx +352 -0
  47. package/site/content/docs/elements/signal/live.mdx +590 -0
  48. package/site/content/docs/elements/signal/meta.json +5 -0
  49. package/site/content/docs/elements/signal/once.mdx +596 -0
  50. package/site/content/docs/elements/store/files.mdx +659 -0
  51. package/site/content/docs/elements/store/index.mdx +310 -0
  52. package/site/content/docs/elements/store/kv.mdx +629 -0
  53. package/site/content/docs/elements/store/meta.json +5 -0
  54. package/site/content/docs/elements/store/search.mdx +946 -0
  55. package/site/content/docs/elements/store/sql.mdx +937 -0
  56. package/site/content/docs/elements/vault/config.mdx +256 -0
  57. package/site/content/docs/elements/vault/index.mdx +356 -0
  58. package/site/content/docs/elements/vault/meta.json +5 -0
  59. package/site/content/docs/elements/vault/rotation.mdx +273 -0
  60. package/site/content/docs/elements/vault/secrets.mdx +285 -0
  61. package/site/content/docs/index.mdx +63 -36
  62. package/site/content/docs/meta.json +8 -7
  63. package/site/content/docs/plugins/cors.mdx +2 -1
  64. package/site/content/docs/plugins/csrf.mdx +4 -1
  65. package/site/content/docs/plugins/headers.mdx +2 -1
  66. package/site/content/docs/plugins/ip-allowlist.mdx +2 -1
  67. package/site/content/docs/plugins/magic-link.mdx +6 -0
  68. package/site/content/docs/plugins/maintenance-mode.mdx +2 -1
  69. package/site/content/docs/plugins/oauth.mdx +1 -1
  70. package/site/content/docs/plugins/otp.mdx +12 -1
  71. package/site/content/docs/plugins/passkey.mdx +39 -15
  72. package/site/content/docs/plugins/two-factor.mdx +91 -34
  73. package/site/content/docs/plugins/username.mdx +1 -1
  74. package/site/content/docs/recipes/caddy.mdx +3 -3
  75. package/site/content/docs/recipes/index.mdx +18 -28
  76. package/site/content/docs/recipes/mailpit.mdx +1 -1
  77. package/site/content/docs/recipes/meilisearch.mdx +3 -3
  78. package/site/content/docs/recipes/meta.json +1 -4
  79. package/site/content/docs/recipes/nginx.mdx +2 -2
  80. package/site/content/docs/recipes/openrouter.mdx +283 -0
  81. package/site/content/docs/recipes/pgdog.mdx +3 -3
  82. package/site/content/docs/recipes/postgres.mdx +1 -2
  83. package/site/content/docs/recipes/rustfs.mdx +2 -2
  84. package/site/content/docs/recipes/traefik.mdx +3 -3
  85. package/site/content/docs/reference/cli.mdx +231 -0
  86. package/site/content/docs/reference/configuration.mdx +30 -10
  87. package/site/content/docs/reference/environment-variables.mdx +93 -20
  88. package/site/content/docs/reference/errors.mdx +132 -29
  89. package/site/content/docs/reference/fx.mdx +137 -73
  90. package/site/content/docs/reference/index.mdx +13 -21
  91. package/site/content/docs/reference/meta.json +4 -5
  92. package/site/content/docs/reference/okid.mdx +42 -17
  93. package/site/content/docs/reference/plugins.mdx +4 -3
  94. package/site/content/docs/reference/security.mdx +197 -0
  95. package/site/content/docs/understand/meta.json +5 -0
  96. package/site/content/docs/understand/the-anatomy.mdx +132 -0
  97. package/site/content/docs/understand/the-model.mdx +32 -0
  98. package/site/content/docs/understand/the-problem.mdx +74 -0
  99. package/site/content/docs/understand/the-vocabulary.mdx +26 -0
  100. package/src/auth/api-keys.ts +2 -1
  101. package/src/auth/bindings.ts +64 -16
  102. package/src/auth/gate-auth.test.ts +6 -1
  103. package/src/auth/identity.ts +152 -5
  104. package/src/auth/index.ts +29 -0
  105. package/src/auth/invites.ts +2 -1
  106. package/src/auth/method-context.ts +41 -0
  107. package/src/auth/oauth-as/crypto.ts +2 -1
  108. package/src/auth/oauth-as/stores.ts +2 -1
  109. package/src/auth/operator.ts +2 -1
  110. package/src/auth/sessions-jwt.test.ts +77 -0
  111. package/src/auth/sessions.ts +20 -4
  112. package/src/auth/tenants.ts +3 -2
  113. package/src/auth/two-factor-challenge.test.ts +61 -0
  114. package/src/auth/two-factor-challenge.ts +284 -0
  115. package/src/auth/verification.ts +5 -0
  116. package/src/bench/REPORT.md +49 -0
  117. package/src/bench/g03-signal-once.bench.ts +1 -1
  118. package/src/bench/g10-observability-contention.bench.ts +1 -1
  119. package/src/bench/g17-hybrid-search.bench.ts +572 -0
  120. package/src/bench/load-app.ts +2 -10
  121. package/src/cli/ai-setup/ai-setup.test.ts +331 -42
  122. package/src/cli/ai-setup/apply.ts +294 -52
  123. package/src/cli/ai-setup/catalog.ts +238 -1342
  124. package/src/cli/ai-setup/index.ts +14 -99
  125. package/src/cli/ai-setup/prompts.ts +60 -443
  126. package/src/cli/ask-seed.test.ts +96 -0
  127. package/src/cli/ask-seed.ts +82 -0
  128. package/src/cli/ask-vault-gaps.test.ts +84 -0
  129. package/src/cli/ask-vault-gaps.ts +146 -0
  130. package/src/cli/build.ts +2 -2
  131. package/src/cli/client-add.test.ts +26 -1
  132. package/src/cli/client-add.ts +106 -27
  133. package/src/cli/db-seed.ts +2 -0
  134. package/src/cli/db.ts +150 -11
  135. package/src/cli/dev.ts +119 -211
  136. package/src/cli/docker-clean.ts +2 -2
  137. package/src/cli/docker-cli.test.ts +1 -1
  138. package/src/cli/doctor-diff.ts +4 -2
  139. package/src/cli/doctor-pii.test.ts +1 -1
  140. package/src/cli/doctor.ts +14 -1
  141. package/src/cli/hero-meta.test.ts +4 -2
  142. package/src/cli/load-config.images.test.ts +8 -10
  143. package/src/cli/load-config.ts +1 -1
  144. package/src/cli/registry.ts +22 -10
  145. package/src/cli/replay.ts +3 -1
  146. package/src/cli/start.ts +1 -1
  147. package/src/cli/tui/keys.ts +2 -3
  148. package/src/client/auth/cookies.ts +74 -0
  149. package/src/client/auth/create-auth-client.ts +636 -0
  150. package/src/client/auth/denials.ts +99 -0
  151. package/src/client/auth/session.ts +283 -0
  152. package/src/client/auth.test.ts +251 -0
  153. package/src/client/auth.ts +39 -114
  154. package/src/client/create-with-session.ts +245 -0
  155. package/src/client/create.ts +51 -5
  156. package/src/client/index.ts +11 -1
  157. package/src/client/live.ts +11 -79
  158. package/src/client/notes-contract.test.ts +5 -10
  159. package/src/client/sse.ts +137 -0
  160. package/src/client/stream.ts +147 -0
  161. package/src/client/transport.test.ts +32 -0
  162. package/src/client/transport.ts +123 -26
  163. package/src/client/types.ts +118 -14
  164. package/src/client-react/index.ts +185 -24
  165. package/src/client-react/use-live-query.ts +13 -3
  166. package/src/compiler/aot.test.ts +7 -4
  167. package/src/compiler/effects-embed.test.ts +56 -0
  168. package/src/compiler/effects-fetch.test.ts +43 -0
  169. package/src/compiler/effects-infer.ts +58 -2
  170. package/src/compiler/extract.test.ts +257 -43
  171. package/src/compiler/extract.ts +566 -48
  172. package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +7 -4
  173. package/src/compiler/fixtures/skyport/src/flows/bookings/signals.ts +2 -8
  174. package/src/compiler/fixtures/skyport.expected.json +4 -4
  175. package/src/compiler/fixtures/triggers/five-triggers.ts +14 -10
  176. package/src/compiler/response.ts +2 -2
  177. package/src/compiler/search-writer-isolation.test.ts +40 -0
  178. package/src/config/index.ts +11 -0
  179. package/src/console/server/app.ts +17 -23
  180. package/src/console/server/bind.ts +4 -0
  181. package/src/console/server/console.test.ts +2 -2
  182. package/src/console/server/flows-invoke.test.ts +50 -34
  183. package/src/console/server/flows.ts +436 -255
  184. package/src/console/server/runs-ingest.test.ts +6 -3
  185. package/src/console/server/serve.ts +1 -1
  186. package/src/console/server/signals.test.ts +1 -5
  187. package/src/console/server/signals.ts +8 -6
  188. package/src/console/server/state.ts +6 -1
  189. package/src/console/server/store.ts +1 -1
  190. package/src/console/ui-next/dist/assets/FileExportIcon-Ck-5od4R.js +1 -0
  191. package/src/console/ui-next/dist/assets/MoreHorizontalCircle01Icon-gMNGsE37.js +1 -0
  192. package/src/console/ui-next/dist/assets/PlusSignIcon-CwG3nxfu.js +1 -0
  193. package/src/console/ui-next/dist/assets/UnavailableIcon-D9cvHVPr.js +1 -0
  194. package/src/console/ui-next/dist/assets/UserIcon-DaE2PB5_.js +1 -0
  195. package/src/console/ui-next/dist/assets/access-page-DFeymU07.js +4 -0
  196. package/src/console/ui-next/dist/assets/agent-disclosure-U1rdfblp.js +1 -0
  197. package/src/console/ui-next/dist/assets/cache-glyph-BeFJeqBG.js +1 -0
  198. package/src/console/ui-next/dist/assets/call-pii-button-CVAONPii.js +1 -0
  199. package/src/console/ui-next/dist/assets/collapsible-D2A6NJ-3.js +1 -0
  200. package/src/console/ui-next/dist/assets/copy-inline-button-CAYD18cr.js +1 -0
  201. package/src/console/ui-next/dist/assets/dagre.esm-B1_XeuLP.js +1 -0
  202. package/src/console/ui-next/dist/assets/detail-header-DVWNjWjg.js +1 -0
  203. package/src/console/ui-next/dist/assets/dropdown-menu-4h2LOVXM.js +1 -0
  204. package/src/console/ui-next/dist/assets/duration-tone-Cgk_h5ja.js +9 -0
  205. package/src/console/ui-next/dist/assets/element-icons-BI8cJgdh.js +1 -0
  206. package/src/console/ui-next/dist/assets/explorer-empty-CJs5A-wm.js +1 -0
  207. package/src/console/ui-next/dist/assets/flows-page-Dss7941e.js +1 -0
  208. package/src/console/ui-next/dist/assets/highlighted-json-MYZQtRnw.js +154 -0
  209. package/src/console/ui-next/dist/assets/http-method-Jrh39p7A.js +1 -0
  210. package/src/console/ui-next/dist/assets/index-D0zS5rKO.css +2 -0
  211. package/src/console/ui-next/dist/assets/index-DXP2dBIF.js +63 -0
  212. package/src/console/ui-next/dist/assets/observability-page-HvolXxTI.js +4 -0
  213. package/src/console/ui-next/dist/assets/react-dom-Ddte4I-Q.js +9 -0
  214. package/src/console/ui-next/dist/assets/replica-lag-CSh2dzrb.js +18 -0
  215. package/src/console/ui-next/dist/assets/request-meta-BatF8KrK.js +1 -0
  216. package/src/console/ui-next/dist/assets/shortcut-keys-3ILd8oGn.js +1 -0
  217. package/src/console/ui-next/dist/assets/{sql-BskegiFM.js → sql-BsFa4tDR.js} +1 -1
  218. package/src/console/ui-next/dist/assets/store-page-eiKiHnNe.js +41 -0
  219. package/src/console/ui-next/dist/assets/trace-detail-sheet-CZkMeKS-.js +2 -0
  220. package/src/console/ui-next/dist/assets/tree-expand-toggle-CW8y5A2h.js +55 -0
  221. package/src/console/ui-next/dist/assets/units-page-B_RWJrEO.js +1 -0
  222. package/src/console/ui-next/dist/assets/{use-vault-list-uk4WVboC.js → use-vault-list-CT4-gajj.js} +1 -1
  223. package/src/console/ui-next/dist/assets/vault-page-CWrg-A68.js +2 -0
  224. package/src/console/ui-next/dist/assets/xyflow-CSyC6ryz.css +1 -0
  225. package/src/console/ui-next/dist/assets/xyflow-yApv7D4e.js +7 -0
  226. package/src/console/ui-next/dist/index.html +6 -13
  227. package/src/console/ui-next/seed-invoke-host.ts +21 -18
  228. package/src/console/ui-next/src/client.ts +7 -2
  229. package/src/console/ui-next/src/features/flows/graph/element-map.ts +2 -0
  230. package/src/console/ui-next/src/features/flows/traces/effect-kind.ts +12 -2
  231. package/src/console/ui-next/src/features/flows/traces/effect-summary.ts +4 -0
  232. package/src/console/ui-next/src/features/flows/traces/trace-detail-sheet.tsx +8 -0
  233. package/src/console/ui-next/src/features/flows/traces/waterfall-bars.ts +4 -0
  234. package/src/console/ui-next/src/features/flows/traces/waterfall-tooltip.ts +9 -3
  235. package/src/console/ui-next/src/features/store/detail/reveal-cell.tsx +7 -11
  236. package/src/console/ui-next/src/features/store/detail/store-row-detail-sheet.tsx +2 -2
  237. package/src/console/ui-next/src/features/store/lib/fields-from-table.ts +2 -0
  238. package/src/console/ui-next/src/features/store/lib/grid-model.test.ts +25 -1
  239. package/src/console/ui-next/src/features/store/lib/grid-model.ts +36 -1
  240. package/src/console/ui-next/src/features/store/query/query-results.tsx +3 -3
  241. package/src/console/ui-next/src/features/units/detail/effects-summary.tsx +2 -0
  242. package/src/console/ui-next/src/features/units/lib/call-read-safe.ts +3 -1
  243. package/src/console/ui-next/src/features/units/lib/fields-from-schema.ts +6 -0
  244. package/src/docker/ai-model-status.test.ts +1 -12
  245. package/src/docker/ai-model-status.ts +10 -38
  246. package/src/docker/compose-up.test.ts +100 -0
  247. package/src/docker/compose-up.ts +292 -0
  248. package/src/docker/compose.ts +4 -14
  249. package/src/docker/derive.ts +9 -34
  250. package/src/docker/docker.test.ts +16 -261
  251. package/src/docker/images-config.test.ts +13 -25
  252. package/src/docker/index.ts +1 -24
  253. package/src/docker/recipes/index.ts +0 -23
  254. package/src/docker/recipes/pgdog.ts +6 -4
  255. package/src/docker/stack-id.test.ts +2 -2
  256. package/src/docker/stack-id.ts +0 -1
  257. package/src/docker/types.ts +2 -2
  258. package/src/drivers/ai-anthropic.ts +10 -0
  259. package/src/drivers/ai-openai-compatible.ts +34 -7
  260. package/src/drivers/ai-providers.test.ts +0 -107
  261. package/src/drivers/ai-stream.test.ts +0 -34
  262. package/src/drivers/ai-types.ts +17 -8
  263. package/src/drivers/channel-fcm.ts +6 -1
  264. package/src/drivers/channel-msegat.ts +6 -1
  265. package/src/drivers/channel-resend.ts +5 -1
  266. package/src/drivers/channel-smtp.ts +5 -1
  267. package/src/drivers/channel-sndr.ts +10 -1
  268. package/src/drivers/channel-taqnyat-mail.ts +5 -1
  269. package/src/drivers/channel-taqnyat-whatsapp.ts +6 -1
  270. package/src/drivers/channel-taqnyat.ts +6 -1
  271. package/src/drivers/channel-types.ts +10 -0
  272. package/src/drivers/channel-unifonic.ts +6 -1
  273. package/src/drivers/channel-wa-cloud.ts +6 -1
  274. package/src/drivers/channel-webpush.ts +6 -1
  275. package/src/drivers/external.ts +33 -0
  276. package/src/drivers/index.ts +0 -10
  277. package/src/drivers/meilisearch.ts +6 -0
  278. package/src/drivers/oauth-types.ts +4 -0
  279. package/src/drivers/postgres.test.ts +74 -3
  280. package/src/drivers/postgres.ts +175 -6
  281. package/src/drivers/signal-types.ts +5 -5
  282. package/src/drivers/types.ts +7 -0
  283. package/src/drivers/vault-types.ts +5 -0
  284. package/src/elements/ai/declare.ts +17 -4
  285. package/src/elements/ai/eval.ts +1 -1
  286. package/src/elements/ai/mcp-http.ts +1 -1
  287. package/src/elements/ai/pii.ts +1 -1
  288. package/src/elements/ai/providers.test.ts +289 -0
  289. package/src/elements/ai/providers.ts +169 -0
  290. package/src/elements/ai/runtime.ts +68 -5
  291. package/src/elements/ai/schema.ts +2 -2
  292. package/src/elements/ai.test.ts +7 -7
  293. package/src/elements/ai.ts +17 -1
  294. package/src/elements/channel/runtime.ts +105 -12
  295. package/src/elements/clock/cron-fields.test.ts +144 -0
  296. package/src/elements/clock/cron-fields.ts +185 -0
  297. package/src/elements/clock/declare.ts +247 -3
  298. package/src/elements/clock.ts +21 -1
  299. package/src/elements/index.ts +15 -0
  300. package/src/elements/signal/chaos-child.ts +1 -2
  301. package/src/elements/signal/declare.ts +65 -37
  302. package/src/elements/signal/delivery-modes.test.ts +11 -31
  303. package/src/elements/signal/dry-run-replay.test.ts +1 -7
  304. package/src/elements/signal/dry-run-write-isolation.test.ts +1 -7
  305. package/src/elements/signal/key-ordering.test.ts +6 -26
  306. package/src/elements/signal/lease-reclaim.test.ts +2 -6
  307. package/src/elements/signal/optional-emit.test.ts +6 -9
  308. package/src/elements/signal/order-lifecycle.test.ts +4 -17
  309. package/src/elements/signal/orphan-messages.test.ts +4 -15
  310. package/src/elements/signal/reconcile.test.ts +2 -2
  311. package/src/elements/signal/runtime.ts +1 -1
  312. package/src/elements/signal/schema-emit.test.ts +4 -8
  313. package/src/elements/signal.test.ts +24 -49
  314. package/src/elements/signal.ts +9 -2
  315. package/src/elements/store/domain-ddl.test.ts +1 -1
  316. package/src/elements/store/live-http.test.ts +9 -4
  317. package/src/elements/store/prepare-row.test.ts +123 -0
  318. package/src/elements/store/resource.ts +43 -12
  319. package/src/elements/store/schema-decl.ts +117 -0
  320. package/src/elements/store/search-backfill.ts +205 -0
  321. package/src/elements/store/search-bind.ts +66 -0
  322. package/src/elements/store/search-bm25.ts +78 -0
  323. package/src/elements/store/search-ddl.ts +156 -0
  324. package/src/elements/store/search-embed-flow.ts +141 -0
  325. package/src/elements/store/search-errors.ts +34 -0
  326. package/src/elements/store/search-fusion.ts +112 -0
  327. package/src/elements/store/search-lsh.ts +179 -0
  328. package/src/elements/store/search-runtime.ts +300 -0
  329. package/src/elements/store/search.test.ts +144 -0
  330. package/src/elements/store/sql-session.test.ts +1 -0
  331. package/src/elements/store/sql-session.ts +83 -3
  332. package/src/elements/store/table.ts +23 -2
  333. package/src/elements/store/upsert-app.test.ts +1 -3
  334. package/src/elements/store.ts +50 -0
  335. package/src/full.ts +4 -2
  336. package/src/http.ts +4 -1
  337. package/src/i18n/catalogs/ar.ts +14 -6
  338. package/src/i18n/catalogs/en.ts +14 -6
  339. package/src/index.ts +6 -1
  340. package/src/kernel/adopt-barrel-fresh.test.ts +7 -7
  341. package/src/kernel/adopt-routes.ts +9 -1
  342. package/src/kernel/app-auth.ts +5 -0
  343. package/src/kernel/app.ts +102 -9
  344. package/src/kernel/auto-cache.test.ts +6 -12
  345. package/src/kernel/auto-registry.test.ts +3 -3
  346. package/src/kernel/boot-bind/ai.test.ts +22 -19
  347. package/src/kernel/boot-bind/ai.ts +5 -43
  348. package/src/kernel/boot-bind/clock.ts +23 -5
  349. package/src/kernel/boot-bind/honor-config.test.ts +4 -4
  350. package/src/kernel/boot.test.ts +11 -6
  351. package/src/kernel/boot.ts +66 -16
  352. package/src/kernel/boundary-contract.ts +93 -0
  353. package/src/kernel/budget.test.ts +1 -1
  354. package/src/kernel/call.ts +89 -0
  355. package/src/kernel/capability.ts +6 -0
  356. package/src/kernel/client-descriptor.ts +123 -0
  357. package/src/kernel/clock-timezone.test.ts +80 -0
  358. package/src/kernel/correlation.test.ts +1 -1
  359. package/src/kernel/dry-run.ts +11 -8
  360. package/src/kernel/effects-stamping.test.ts +42 -9
  361. package/src/kernel/effects.test.ts +4 -2
  362. package/src/kernel/effects.ts +51 -9
  363. package/src/kernel/errors-channel.ts +17 -0
  364. package/src/kernel/errors-live-resume.ts +3 -2
  365. package/src/kernel/errors-tenant.ts +7 -4
  366. package/src/kernel/errors.registry-helpers.ts +96 -0
  367. package/src/kernel/errors.registry.test.ts +139 -25
  368. package/src/kernel/errors.ts +102 -23
  369. package/src/kernel/external-effects.test.ts +196 -0
  370. package/src/kernel/flow.test.ts +13 -4
  371. package/src/kernel/flow.ts +69 -71
  372. package/src/kernel/fx-ask-telemetry.test.ts +2 -2
  373. package/src/kernel/fx-dead-letters.test.ts +3 -3
  374. package/src/kernel/fx-fetch.ts +55 -0
  375. package/src/kernel/fx-live-stream.ts +2 -2
  376. package/src/kernel/fx-live.test.ts +8 -8
  377. package/src/kernel/fx.test.ts +17 -11
  378. package/src/kernel/fx.ts +180 -57
  379. package/src/kernel/horizontal-child.ts +1 -1
  380. package/src/kernel/http-query.test.ts +3 -6
  381. package/src/kernel/index.ts +13 -3
  382. package/src/kernel/instance-id.ts +1 -1
  383. package/src/kernel/instances.test.ts +40 -0
  384. package/src/kernel/instances.ts +47 -9
  385. package/src/kernel/live-http.test.ts +6 -7
  386. package/src/kernel/live-http.ts +6 -2
  387. package/src/kernel/live-resume.test.ts +1 -1
  388. package/src/kernel/mcp-tool.test.ts +3 -3
  389. package/src/kernel/on.ts +98 -4
  390. package/src/kernel/pipeline.test.ts +12 -15
  391. package/src/kernel/plugin-elements.test.ts +1 -1
  392. package/src/kernel/stamp-http.test.ts +3 -3
  393. package/src/kernel/triggers.ts +210 -95
  394. package/src/kernel-entry.ts +0 -1
  395. package/src/manifest/diff.ts +11 -1
  396. package/src/manifest/fixtures/skyport.excerpt.json +1 -1
  397. package/src/manifest/types.ts +46 -2
  398. package/src/mcp/docs-index.ts +3 -3
  399. package/src/mcp/docs-mcp.test.ts +2 -2
  400. package/src/mcp/docs-tools.ts +1 -1
  401. package/src/okid.test.ts +56 -0
  402. package/src/okid.ts +55 -11
  403. package/src/plugins/anonymous.ts +8 -4
  404. package/src/plugins/auth/shared.ts +27 -3
  405. package/src/plugins/auth-delivery.mailpit.integration.test.ts +1 -1
  406. package/src/plugins/auth-methods.security.test.ts +561 -23
  407. package/src/plugins/config-source.ts +1 -1
  408. package/src/plugins/csrf.test.ts +65 -0
  409. package/src/plugins/index.ts +2 -0
  410. package/src/plugins/magic-link.ts +36 -16
  411. package/src/plugins/oauth/shared.ts +3 -1
  412. package/src/plugins/oauth.ts +22 -14
  413. package/src/plugins/otp.ts +37 -21
  414. package/src/plugins/passkey-webauthn.ts +9 -6
  415. package/src/plugins/passkey.ts +98 -26
  416. package/src/plugins/pre-account-hijack.test.ts +223 -0
  417. package/src/plugins/two-factor.ts +466 -37
  418. package/src/plugins/username.ts +19 -7
  419. package/src/release/build-lib.ts +1 -0
  420. package/src/release/limits.ts +2 -2
  421. package/src/release/measure.ts +1 -1
  422. package/src/runs/collect.test.ts +0 -2
  423. package/src/runtime/json-code-block.test.ts +250 -20
  424. package/src/runtime/json-code-block.ts +1261 -41
  425. package/src/term.test.ts +1 -1
  426. package/src/test/create-test-app.test.ts +12 -12
  427. package/src/test/live-signals.test.ts +6 -6
  428. package/src/test/provisions.integration.test.ts +10 -14
  429. package/src/test/reset-element-registries.ts +1 -1
  430. package/src/test/tenant-isolation.test.ts +12 -6
  431. package/site/content/docs/deployment/docker-swarm.mdx +0 -164
  432. package/site/content/docs/deployment/docker.mdx +0 -227
  433. package/site/content/docs/deployment/index.mdx +0 -83
  434. package/site/content/docs/deployment/kubernetes.mdx +0 -176
  435. package/site/content/docs/deployment/meta.json +0 -5
  436. package/site/content/docs/deployment/reverse-proxy.mdx +0 -234
  437. package/site/content/docs/elements/ai.mdx +0 -385
  438. package/site/content/docs/elements/channel.mdx +0 -346
  439. package/site/content/docs/elements/clock.mdx +0 -244
  440. package/site/content/docs/elements/flow.mdx +0 -420
  441. package/site/content/docs/elements/gate.mdx +0 -436
  442. package/site/content/docs/elements/signal.mdx +0 -380
  443. package/site/content/docs/elements/store.mdx +0 -1099
  444. package/site/content/docs/elements/vault.mdx +0 -405
  445. package/site/content/docs/get-started/basic-usage.mdx +0 -173
  446. package/site/content/docs/get-started/index.mdx +0 -43
  447. package/site/content/docs/get-started/installation.mdx +0 -220
  448. package/site/content/docs/get-started/introduction.mdx +0 -144
  449. package/site/content/docs/get-started/meta.json +0 -13
  450. package/site/content/docs/get-started/project-structure.mdx +0 -925
  451. package/site/content/docs/get-started/testing.mdx +0 -328
  452. package/site/content/docs/get-started/why.mdx +0 -114
  453. package/site/content/docs/recipes/llama-cpp.mdx +0 -151
  454. package/site/content/docs/recipes/ollama.mdx +0 -142
  455. package/site/content/docs/recipes/sglang.mdx +0 -105
  456. package/site/content/docs/recipes/vllm.mdx +0 -106
  457. package/site/content/docs/reference/cli.md +0 -232
  458. package/site/content/docs/reference/client.mdx +0 -469
  459. package/site/content/docs/reference/security.md +0 -74
  460. package/src/cli/ai-setup/detect-ollama.ts +0 -213
  461. package/src/cli/ai-setup/recommend.test.ts +0 -225
  462. package/src/cli/ai-setup/recommend.ts +0 -225
  463. package/src/cli/dev-controls.test.ts +0 -122
  464. package/src/cli/dev-controls.ts +0 -164
  465. package/src/cli/tui/DevLive.tsx +0 -126
  466. package/src/console/ui-next/dist/assets/access-page-3-EFj-2G.js +0 -4
  467. package/src/console/ui-next/dist/assets/agent-disclosure-BP0Y0Sux.js +0 -1
  468. package/src/console/ui-next/dist/assets/cache-glyph-B5X-NM0-.js +0 -1
  469. package/src/console/ui-next/dist/assets/call-pii-button-ChAUiLo9.js +0 -1
  470. package/src/console/ui-next/dist/assets/collapsible-DGnOM2ph.js +0 -1
  471. package/src/console/ui-next/dist/assets/copy-inline-button-DBHhgHKP.js +0 -1
  472. package/src/console/ui-next/dist/assets/dagre.esm-ZwcdTuZZ.js +0 -1
  473. package/src/console/ui-next/dist/assets/detail-header-DhHM1iaZ.js +0 -1
  474. package/src/console/ui-next/dist/assets/dropdown-menu-_NjTEo5_.js +0 -1
  475. package/src/console/ui-next/dist/assets/duration-tone-sC3lGABz.js +0 -9
  476. package/src/console/ui-next/dist/assets/element-icons-BVXtRyd3.js +0 -1
  477. package/src/console/ui-next/dist/assets/explorer-empty-2uIhBu0_.js +0 -1
  478. package/src/console/ui-next/dist/assets/flows-page-cVFnA4HH.js +0 -1
  479. package/src/console/ui-next/dist/assets/highlighted-json-Awq7gYdu.js +0 -154
  480. package/src/console/ui-next/dist/assets/http-method-_UHM2ODJ.js +0 -1
  481. package/src/console/ui-next/dist/assets/index-CMIgUbD0.js +0 -66
  482. package/src/console/ui-next/dist/assets/index-Ck88Jmv8.css +0 -2
  483. package/src/console/ui-next/dist/assets/link-BX6Vqztd.js +0 -1
  484. package/src/console/ui-next/dist/assets/observability-page-CQ3p34ip.js +0 -4
  485. package/src/console/ui-next/dist/assets/preload-helper-oH4irX4C.js +0 -1
  486. package/src/console/ui-next/dist/assets/react-D8E3mtu1.js +0 -1
  487. package/src/console/ui-next/dist/assets/react-dom-Bph1y7z7.js +0 -9
  488. package/src/console/ui-next/dist/assets/replica-lag-DKRrbvdo.js +0 -18
  489. package/src/console/ui-next/dist/assets/request-meta-DV0ywz7t.js +0 -1
  490. package/src/console/ui-next/dist/assets/shortcut-JQIZlWfm.js +0 -1
  491. package/src/console/ui-next/dist/assets/shortcut-keys-DKxNTe_m.js +0 -1
  492. package/src/console/ui-next/dist/assets/skeleton-D-czQJT6.js +0 -1
  493. package/src/console/ui-next/dist/assets/store-page-02xOiqIK.js +0 -41
  494. package/src/console/ui-next/dist/assets/trace-detail-sheet-B09O8rA6.js +0 -2
  495. package/src/console/ui-next/dist/assets/tree-expand-toggle-BtyhmWb4.js +0 -55
  496. package/src/console/ui-next/dist/assets/units-page-l8FeKfnP.js +0 -1
  497. package/src/console/ui-next/dist/assets/useMutation-B8EO02Ej.js +0 -1
  498. package/src/console/ui-next/dist/assets/useRender-BE2A9BWC.js +0 -1
  499. package/src/console/ui-next/dist/assets/vault-page-CL-d_mLE.js +0 -2
  500. package/src/console/ui-next/dist/assets/xyflow-D7n4g6go.js +0 -7
  501. package/src/console/ui-next/dist/assets/xyflow-DZ0Ws1xk.css +0 -1
  502. package/src/docker/ollama-pull.ts +0 -232
  503. package/src/docker/recipes/llama-cpp.ts +0 -298
  504. package/src/docker/recipes/ollama.ts +0 -44
  505. package/src/docker/recipes/sglang.ts +0 -55
  506. package/src/docker/recipes/vllm.ts +0 -44
  507. package/src/drivers/ai-ollama-tools.integration.test.ts +0 -109
  508. package/src/drivers/ai-ollama.integration.test.ts +0 -184
  509. package/src/drivers/ai-ollama.ts +0 -389
  510. package/src/drivers/ollama.ts +0 -14
@@ -1,380 +0,0 @@
1
- ---
2
- title: "Signal"
3
- description: "Data in motion — queues, pub/sub, and streams as one declaration whose delivery physics you choose explicitly."
4
- icon: "Radio"
5
- source: "docs/spec/unified-theory.md"
6
- ---
7
-
8
- Signal is how your app moves data between flows and to clients: background jobs, events, fan-out notifications, live feeds. What other stacks split into a queue library, a pub/sub client, and a streaming platform is **one declaration** here — you pick the delivery physics, and the driver underneath is swappable per environment.
9
-
10
- <Callout title="The one rule">
11
- `delivery` is **mandatory with no default**. Delivery physics is a semantic decision about your
12
- data — guessing it produces silent, expensive bugs, so omitting it is a type error.
13
- </Callout>
14
-
15
- ## Quick start
16
-
17
- <Steps>
18
-
19
- <Step>
20
- ### Declare the signal
21
-
22
- A signal is a named, typed channel. The schema describes the payload; `delivery` describes its physics:
23
-
24
- ```typescript title="src/signals.ts"
25
- import { signal } from "okengine";
26
- import { z } from "zod";
27
-
28
- export const orderPlaced = signal("order-placed", {
29
- schema: z.object({ orderId: z.string(), total: z.number() }),
30
- delivery: "once", // queue physics: one consumer, retries, DLQ
31
- retries: 3,
32
- deadLetter: true,
33
- });
34
- ```
35
-
36
- </Step>
37
-
38
- <Step>
39
- ### Emit it from a Flow
40
-
41
- Producers never touch a broker client — they call `fx.emit`:
42
-
43
- ```typescript title="src/flows/orders/place.ts"
44
- do: async (input, fx) => {
45
- await fx.store(db).insert(orders).values({ id: input.id /* … */ });
46
- await fx.emit(orderPlaced, { orderId: input.id, total: input.total }, { key: input.id });
47
- // optional `key` keeps same-order events serialized under `once`
48
- };
49
- ```
50
-
51
- </Step>
52
-
53
- <Step>
54
- ### Consume it with a Flow
55
-
56
- A signal is a trigger like any other — the consumer is an ordinary Flow:
57
-
58
- ```typescript title="src/flows/orders/send-confirmation.ts"
59
- export const sendConfirmation = on(
60
- orderPlaced,
61
- flow("orders.sendConfirmation", {
62
- in: z.object({ orderId: z.string(), total: z.number() }),
63
- do: async (input, fx) => {
64
- await fx.send(orderConfirmed, { to: "user-1", data: input });
65
- },
66
- }),
67
- );
68
- ```
69
-
70
- </Step>
71
-
72
- </Steps>
73
-
74
- That's the loop for `once` and `broadcast`: declare → `fx.emit` → `on(signal, flow)`.
75
- `live` keeps the same emit; expose it over HTTP with `.live(signal)` and subscribe from `api.live`.
76
-
77
- ## The three delivery physics
78
-
79
- <SignalDelivery />
80
-
81
- The declaration is identical in shape for all three — switching physics later is a one-word change, not a migration to another library.
82
-
83
- ### Options
84
-
85
- | Option | Type | Default | Meaning |
86
- | ------------- | --------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------- |
87
- | `delivery` | `"once" \| "broadcast" \| "live"` | — (**required**) | Delivery physics |
88
- | `description` | string | — | Human title in the Console (falls back to the signal name) |
89
- | `schema` | zod / Standard Schema | — | Payload contract — validated at emit (**OKE1043** on failure); Manifest docs |
90
- | `retries` | number | `3` | Retry budget for `once` — dead-letter when `attempts > retries` (`retries + 1` total invocations) |
91
- | `deadLetter` | boolean | `true` | Preserve exhausted messages in the DLQ (`once`) |
92
- | `optional` | boolean | `false` | Allow emitting while nobody subscribes (skip the orphan check) |
93
- | `retention` | `{ maxAge?, maxCount? }` | unbounded | Live tape cap (`delivery: "live"` only). Both limits AND-combine when set |
94
-
95
- ## One order, three modes
96
-
97
- One placed order can need all three physics at once — pick a signal per job, not one signal stretched across modes:
98
-
99
- | Signal | Mode | Job |
100
- | --------------- | ----------- | ----------------------------------------------------------- |
101
- | `order-placed` | `once` | One job — competing workers, retries, DLQ |
102
- | `order-changed` | `broadcast` | Fan-out — cache invalidation **and** customer notification |
103
- | `order-status` | `live` | Status feed — retained history a late subscriber can replay |
104
-
105
- ```typescript title="src/signals.ts"
106
- import { signal } from "okengine";
107
- import { z } from "zod";
108
-
109
- export const orderPlaced = signal("order-placed", {
110
- schema: z.object({ orderId: z.string(), total: z.number() }),
111
- delivery: "once",
112
- retries: 3,
113
- deadLetter: true,
114
- });
115
-
116
- export const orderChanged = signal("order-changed", {
117
- schema: z.object({ orderId: z.string(), kind: z.literal("placed") }),
118
- delivery: "broadcast",
119
- });
120
-
121
- export const orderStatus = signal("order-status", {
122
- schema: z.object({
123
- orderId: z.string(),
124
- status: z.enum(["placed", "fulfilling", "shipped"]),
125
- }),
126
- delivery: "live",
127
- optional: true, // clients may not be connected yet
128
- retention: { maxAge: "24h", maxCount: 500 },
129
- });
130
- ```
131
-
132
- A Flow **writes** all three tapes. `once` / `broadcast` **listen** with `on(signal, flow)`. `live` does not.
133
-
134
- ```typescript title="src/flows/orders/place.ts"
135
- export const placeOrder = on(
136
- http.post("/orders").public(),
137
- flow("orders.place", {
138
- in: z.object({ id: z.string(), total: z.number() }),
139
- do: async (input, fx) => {
140
- await fx.emit(orderPlaced, { orderId: input.id, total: input.total });
141
- await fx.emit(orderChanged, { orderId: input.id, kind: "placed" });
142
- await fx.emit(orderStatus, { orderId: input.id, status: "placed" });
143
- await fx.emit(orderStatus, { orderId: input.id, status: "fulfilling" });
144
- await fx.emit(orderStatus, { orderId: input.id, status: "shipped" });
145
- },
146
- }),
147
- );
148
- ```
149
-
150
- Stacked status emits are so replay is visible in one request. A real app emits as the order moves.
151
-
152
- `once` — the listener is `on(orderPlaced, flow)`. Two workers compete; **exactly one** claims each message (at-least-once; make the handler idempotent):
153
-
154
- ```typescript title="src/flows/orders/send-confirmation.ts"
155
- export const sendConfirmation = on(
156
- orderPlaced,
157
- flow("orders.sendConfirmation", {
158
- do: async (input, fx) => {
159
- await fx.send(orderConfirmed, { to: "user-1", data: input });
160
- },
161
- }),
162
- );
163
- ```
164
-
165
- `broadcast` — every `on(orderChanged, flow)` gets its own copy. Neither Flow knows the other exists:
166
-
167
- ```typescript title="src/flows/orders/side-effects.ts"
168
- export const invalidateCache = on(
169
- orderChanged,
170
- flow("cache.onOrderChanged", {
171
- do: async ({ orderId }, fx) => {
172
- /* invalidate order:{orderId} */
173
- },
174
- }),
175
- );
176
-
177
- export const notifyCustomer = on(
178
- orderChanged,
179
- flow("notify.onOrderChanged", {
180
- do: async ({ orderId }, fx) => {
181
- await fx.send(orderConfirmed, { to: "user-1", data: { orderId } });
182
- },
183
- }),
184
- );
185
- ```
186
-
187
- `live` — retain the tape. A late subscriber replays history (`placed → fulfilling → shipped`), then keeps going. Omit `retention` and that history is **unbounded** — declare `maxAge` / `maxCount` in production.
188
-
189
- The listener is **not** `on(orderStatus, flow)` — that trigger does not replay retained payloads. Expose GET SSE with `.live(signal)`, then subscribe from the typed client. `optional: true` is required so emits succeed before anyone is connected.
190
-
191
- ```typescript
192
- export const events = on(http.get("/orders/:orderId/events").gate(member).live(orderStatus));
193
-
194
- export const adminFeed = on(http.get("/admin/order-status").gate(admin).live(orderStatus));
195
-
196
- const stop = api.live(
197
- orderStatus,
198
- { orderId: "ord_1" },
199
- {
200
- onEvent: (event) => {
201
- /* placed → fulfilling → shipped */
202
- },
203
- },
204
- );
205
- stop();
206
- ```
207
-
208
- Same signal, two audiences: member filter on `:orderId`, admin firehose. Duplicate `(signal, gates, match)` is **OKE1013**. Same HTTP path is still **OKE1011**. Firehose default: `on(http.live(orderStatus).gate(member))` → `GET /_oke/live/order-status`.
209
-
210
- Server-side `fx.live` **is** the SSE carrier (`JsonStreamResult`). Custom `do` is allowed; authors do not wrap `fx.json.stream`. Reconnects send `Last-Event-ID`; a missing cursor is **OKE1014** / HTTP 410, not a silent full replay. `autoResubscribe: true` backs off 500ms…30s and, after a 410, replays the remaining tape.
211
-
212
- **Why separate signals:** delivery is fixed per declaration. Competing work stays on `once`; fan-out stays on `broadcast`; the timeline stays on `live`. Switching a word later is cheap; mixing physics on one name is not.
213
-
214
- ## When delivery fails
215
-
216
- `once` signals retry automatically. Every attempt keeps a **typed failure reason**, and the full attempt history survives into the DLQ — so when a message lands there you see _why_ each attempt failed, not just that it did.
217
-
218
- Query that queue from a Flow with `fx.deadLetters(signal)` — same handle as `fx.emit`. The compiler stamps `reads: ["signal:<name>"]`; another signal throws **OKE1001**.
219
-
220
- The **Console** (`:6533` → `/overview`) shows emit and consume on the graph, and delivery attempts in Traces — no separate broker UI to run.
221
-
222
- ```typescript
223
- on(
224
- http.get("/notifications/failed"),
225
- flow("notifications.failed", {
226
- do: async (input, fx) => fx.json.withQuery(await fx.deadLetters(orderPlaced), input),
227
- }),
228
- );
229
- ```
230
-
231
- <Callout title="Orphan emits and schema fail loudly">
232
- Zero subscribers throws **OKE1042** unless `optional: true`. A payload that fails the signal's
233
- Standard Schema throws **OKE1043** before the message is staged — same `validate()` path as Flow
234
- `in`.
235
- </Callout>
236
-
237
- ## Per-key ordering (`once`)
238
-
239
- `fx.emit(signal, payload, { key })` is optional and additive. When `key` is set, no two messages
240
- sharing the same `(signal, key)` are claimed concurrently — a per-key serialization lock, not a
241
- partitioned log.
242
-
243
- The lock **is** the in-flight message's visibility lease: while that row is `inflight` with an
244
- unexpired `leaseExpiresAt`, same-key siblings stay unclaimable. Crash → lease expiry → reclaim
245
- (same clock as unkeyed `once`). Omit `key` for pure competing-consumer behavior.
246
-
247
- ```typescript
248
- await fx.emit(orderPlaced, { orderId, total }, { key: orderId });
249
- await fx.emit(orderPlaced, { orderId, total: total + fee }, { key: orderId });
250
- // Same key → never concurrent; complete in emission order across competing workers.
251
- ```
252
-
253
- ## Durability and leases (`once`)
254
-
255
- <SignalOnceLease />
256
-
257
- Committed `once` messages survive process death. A claim sets `lockedBy` and a visibility lease (`leaseExpiresAt`, default **30s**). There is no background sweeper: the next consumer reclaim query takes `pending` rows **or** `inflight` rows whose lease has expired. Per-key locks reuse this same lease — no second timeout.
258
-
259
- <Callout title="At-least-once, not exactly-once">
260
- Delivery is **at-least-once** — finish side effects then die before ack, and the message may run
261
- again; make consumers idempotent. Handlers must finish within `leaseMs` (default 30s): a healthy
262
- but slower handler can be reclaimed while still running. Lease heartbeat is not offered yet.
263
- </Callout>
264
-
265
- ## Live replay
266
-
267
- <SignalLiveReplay />
268
-
269
- `live` retains delivered messages and replays them to a late subscriber. Omit `retention` for an unbounded tape (a production hazard). `maxAge` (clock duration) and `maxCount` AND-combine when both are set. Drivers prune on write and when `live()` opens — no background sweeper.
270
-
271
- Reconnects send SSE `Last-Event-ID`. If that id was pruned or never existed, the server returns **410** `{ error: { code: "LiveResumeGap" } }` (**OKE1014**) before opening the stream. The client clears the cursor; `autoResubscribe` then replays whatever remains.
272
-
273
- The Console payload monitor still shows only the newest 50 for display — that cap is not the retained tape.
274
-
275
- <Callout title="HTTP live is GET SSE">
276
- Expose with `http.get(path).live(signal)` or `http.live(signal)`. Subscribe with `api.live(signal,
277
- input?, {onEvent})` — callback + unsubscribe, not `for await`. See
278
- [Client](/docs/reference/client#live-signals).
279
- </Callout>
280
-
281
- ## Orphaned signal config
282
-
283
- When a signal disappears from code, reconciliation marks its config row `orphaned` — it is never deleted. Pending and DLQ messages for that name stay in storage. Drain and replay require an active declaration again: restore the `signal(…)` (and a consumer), then replay from the Console or bus.
284
-
285
- ## Per-environment drivers
286
-
287
- ```typescript title="oke.config.ts"
288
- drivers: {
289
- signal: { dev: "redis", test: "memory", prod: "redis" },
290
- },
291
- ```
292
-
293
- | Driver | Runs as | Boot today |
294
- | ---------- | ------------------------------------ | --------------------------------------------------------------------------- |
295
- | `memory` | in-process | Tests — zero infrastructure |
296
- | `redis` | Redis / Valkey / Dragonfly image pin | Boot-bound — **emit relay** via Streams / pub/sub; consume is process-local |
297
- | `postgres` | Postgres | Driver exists; boot **fails loud** until a LISTEN/NOTIFY SQL client binds |
298
- | `nats` | NATS | Driver exists; boot **fails loud** until a production NATS client binds |
299
-
300
- **Known limit:** `redis` relays emits to Redis, but `once` / `broadcast` / `live` **consume, `live` replay, and `drain` still use a process-local outbox** today. Competing consumers across replicas do not share that outbox until Redis Streams consume ships. Boot prints a one-shot warning when `drivers.signal` is `redis`. Prefer a single consumer instance (or a shared durable outbox path in tests) for multi-process `once` until then.
301
-
302
- Pairing an arbitrary Store insert with emit inside **one** shared SQL transaction is not what `fx.emit` does — keep consumers idempotent (at-least-once).
303
-
304
- ## Troubleshooting
305
-
306
- <Accordions>
307
- <Accordion title="Emit fails with OKE1042 (no subscriber)">
308
-
309
- You emitted a signal that nobody currently subscribes to. For `once` and `broadcast`, wire
310
- `on(signal, flow)` before emit.
311
-
312
- `live` listeners are HTTP SSE (`api.live` / `fx.live`), not a Flow — set `optional: true` when they may connect later.
313
-
314
- </Accordion>
315
- <Accordion title="Emit fails with OKE1043 (schema)">
316
-
317
- The payload failed the signal's Standard Schema at emit time — nothing was staged. Fix the payload shape, or remove `schema` if the contract was intentional.
318
-
319
- </Accordion>
320
- <Accordion title="A message keeps retrying and then disappears">
321
-
322
- When `attempts > retries` the message moves to the DLQ (if `deadLetter: true`) — it is not lost. List it from a Flow with `fx.deadLetters(signal)`, or open Console → Flows, inspect the typed failure, fix the consumer, then replay.
323
-
324
- </Accordion>
325
- <Accordion title="fx.deadLetters throws OKE1001">
326
-
327
- The flow read a signal it did not declare. The compiler infers `reads: ["signal:<name>"]` from `fx.deadLetters(signal)` and `fx.live(signal)`. A different handle needs its own read.
328
-
329
- </Accordion>
330
- <Accordion title="Boot fails with OKE1013 (live exposure duplicate)">
331
-
332
- Two GET routes expose the same live signal with the same gates and match.
333
- Change the gate or path-param filter, or drop the extra route (same path is **OKE1011**).
334
-
335
- </Accordion>
336
- <Accordion title="Subscribe gets HTTP 410 LiveResumeGap (OKE1014)">
337
-
338
- The `Last-Event-ID` cursor is not on the retained tape (pruned, never existed, or the memory bus restarted). The gap is visible in `onError`. With `autoResubscribe: true` the next request omits the header and replays what remains.
339
-
340
- </Accordion>
341
- <Accordion title="on(liveSignal, flow) never replays history">
342
-
343
- `on(signal, flow)` listens for `once` and `broadcast`. `live` replay is HTTP SSE (`api.live` /
344
- `fx.live`) — a Flow trigger does not replay retained payloads.
345
-
346
- </Accordion>
347
- <Accordion title="once vs broadcast vs live — how do I choose?">
348
-
349
- Ask: _how many consumers should process each message?_ One → `once`. All of them → `broadcast`. Clients over time, with full retained replay → `live`. Retries and a DLQ are `once` only.
350
-
351
- </Accordion>
352
- <Accordion title="My emit happened but the row didn't (or vice versa)">
353
-
354
- `fx.emit` commits the signal outbox when it resolves; it does not wrap your Store insert. Treat delivery as at-least-once and make the consumer idempotent (or check the row before acting). Remember: `redis` today is an emit relay with a process-local consume outbox — not multi-instance competing consumers yet.
355
-
356
- </Accordion>
357
- <Accordion title="The same once message ran twice">
358
-
359
- At-least-once: crash-after-claim reclaims when the lease expires, and a handler slower than `leaseMs` can be reclaimed while still running. Idempotent consumers are required; there is no lease heartbeat yet.
360
-
361
- </Accordion>
362
- </Accordions>
363
-
364
- ## Learn more
365
-
366
- - [Project structure](/docs/get-started/project-structure) — signal files get a name, never a URL; `http.get("/…")` still wins
367
- - [Flow](/docs/elements/flow) — `on(trigger, flow)` and `fx.emit`
368
- - [fx](/docs/reference/fx) — `fx.emit` and `fx.deadLetters`
369
- - [Clock](/docs/elements/clock) — scheduled and delayed work
370
-
371
- ## Next
372
-
373
- <Cards>
374
- <Card title="Store" description="Continue to Store." href="/docs/elements/store" />
375
- <Card
376
- title="Introduction"
377
- description="Eight elements overview."
378
- href="/docs/get-started/introduction"
379
- />
380
- </Cards>