okengine 0.18.4 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (512) hide show
  1. package/AGENTS.md +18 -10
  2. package/README.md +2 -2
  3. package/package.json +51 -50
  4. package/site/content/docs/ai/index.mdx +25 -6
  5. package/site/content/docs/ai/llms-txt.mdx +1 -1
  6. package/site/content/docs/ai/meta.json +1 -1
  7. package/site/content/docs/ai/skills.mdx +4 -1
  8. package/site/content/docs/ai/try-it.mdx +58 -0
  9. package/site/content/docs/client/auth.mdx +208 -0
  10. package/site/content/docs/client/calling.mdx +451 -0
  11. package/site/content/docs/client/index.mdx +209 -0
  12. package/site/content/docs/client/live.mdx +234 -0
  13. package/site/content/docs/client/meta.json +5 -0
  14. package/site/content/docs/client/react.mdx +249 -0
  15. package/site/content/docs/elements/ai/agents.mdx +232 -0
  16. package/site/content/docs/elements/ai/index.mdx +341 -0
  17. package/site/content/docs/elements/ai/mcp.mdx +275 -0
  18. package/site/content/docs/elements/ai/meta.json +5 -0
  19. package/site/content/docs/elements/ai/models.mdx +283 -0
  20. package/site/content/docs/elements/ai/prompts.mdx +256 -0
  21. package/site/content/docs/elements/channel/email.mdx +266 -0
  22. package/site/content/docs/elements/channel/index.mdx +344 -0
  23. package/site/content/docs/elements/channel/meta.json +5 -0
  24. package/site/content/docs/elements/channel/push.mdx +218 -0
  25. package/site/content/docs/elements/channel/receipts.mdx +206 -0
  26. package/site/content/docs/elements/channel/sms.mdx +264 -0
  27. package/site/content/docs/elements/channel/whatsapp.mdx +220 -0
  28. package/site/content/docs/elements/clock/index.mdx +300 -0
  29. package/site/content/docs/elements/clock/meta.json +5 -0
  30. package/site/content/docs/elements/clock/schedules.mdx +508 -0
  31. package/site/content/docs/elements/clock/sleep.mdx +445 -0
  32. package/site/content/docs/elements/flow/consumers.mdx +707 -0
  33. package/site/content/docs/elements/flow/http.mdx +1080 -0
  34. package/site/content/docs/elements/flow/index.mdx +618 -0
  35. package/site/content/docs/elements/flow/meta.json +5 -0
  36. package/site/content/docs/elements/flow/routing.mdx +559 -0
  37. package/site/content/docs/elements/flow/workflows.mdx +640 -0
  38. package/site/content/docs/elements/gate/auth.mdx +371 -0
  39. package/site/content/docs/elements/gate/authorization.mdx +298 -0
  40. package/site/content/docs/elements/gate/index.mdx +418 -0
  41. package/site/content/docs/elements/gate/meta.json +5 -0
  42. package/site/content/docs/elements/gate/rate-limits.mdx +365 -0
  43. package/site/content/docs/elements/gate/rls.mdx +303 -0
  44. package/site/content/docs/elements/gate/tenancy.mdx +372 -0
  45. package/site/content/docs/elements/index.mdx +52 -11
  46. package/site/content/docs/elements/signal/broadcast.mdx +517 -0
  47. package/site/content/docs/elements/signal/index.mdx +352 -0
  48. package/site/content/docs/elements/signal/live.mdx +590 -0
  49. package/site/content/docs/elements/signal/meta.json +5 -0
  50. package/site/content/docs/elements/signal/once.mdx +596 -0
  51. package/site/content/docs/elements/store/files.mdx +659 -0
  52. package/site/content/docs/elements/store/index.mdx +310 -0
  53. package/site/content/docs/elements/store/kv.mdx +629 -0
  54. package/site/content/docs/elements/store/meta.json +5 -0
  55. package/site/content/docs/elements/store/search.mdx +946 -0
  56. package/site/content/docs/elements/store/sql.mdx +937 -0
  57. package/site/content/docs/elements/vault/config.mdx +256 -0
  58. package/site/content/docs/elements/vault/index.mdx +356 -0
  59. package/site/content/docs/elements/vault/meta.json +5 -0
  60. package/site/content/docs/elements/vault/rotation.mdx +273 -0
  61. package/site/content/docs/elements/vault/secrets.mdx +285 -0
  62. package/site/content/docs/index.mdx +78 -30
  63. package/site/content/docs/meta.json +11 -8
  64. package/site/content/docs/plugins/cors.mdx +2 -1
  65. package/site/content/docs/plugins/csrf.mdx +4 -1
  66. package/site/content/docs/plugins/headers.mdx +2 -1
  67. package/site/content/docs/plugins/ip-allowlist.mdx +2 -1
  68. package/site/content/docs/plugins/magic-link.mdx +6 -0
  69. package/site/content/docs/plugins/maintenance-mode.mdx +2 -1
  70. package/site/content/docs/plugins/oauth.mdx +1 -1
  71. package/site/content/docs/plugins/otp.mdx +12 -1
  72. package/site/content/docs/plugins/passkey.mdx +39 -15
  73. package/site/content/docs/plugins/two-factor.mdx +91 -34
  74. package/site/content/docs/plugins/username.mdx +1 -1
  75. package/site/content/docs/recipes/caddy.mdx +3 -3
  76. package/site/content/docs/recipes/index.mdx +18 -28
  77. package/site/content/docs/recipes/mailpit.mdx +1 -1
  78. package/site/content/docs/recipes/meilisearch.mdx +3 -3
  79. package/site/content/docs/recipes/meta.json +1 -4
  80. package/site/content/docs/recipes/nginx.mdx +2 -2
  81. package/site/content/docs/recipes/openrouter.mdx +283 -0
  82. package/site/content/docs/recipes/pgdog.mdx +3 -3
  83. package/site/content/docs/recipes/postgres.mdx +1 -2
  84. package/site/content/docs/recipes/rustfs.mdx +2 -2
  85. package/site/content/docs/recipes/traefik.mdx +3 -3
  86. package/site/content/docs/reference/cli.mdx +231 -0
  87. package/site/content/docs/reference/configuration.mdx +30 -10
  88. package/site/content/docs/reference/environment-variables.mdx +93 -20
  89. package/site/content/docs/reference/errors.mdx +132 -29
  90. package/site/content/docs/reference/fx.mdx +137 -73
  91. package/site/content/docs/reference/index.mdx +13 -21
  92. package/site/content/docs/reference/meta.json +4 -5
  93. package/site/content/docs/reference/okid.mdx +42 -17
  94. package/site/content/docs/reference/plugins.mdx +4 -3
  95. package/site/content/docs/reference/security.mdx +197 -0
  96. package/site/content/docs/understand/meta.json +5 -0
  97. package/site/content/docs/understand/the-anatomy.mdx +132 -0
  98. package/site/content/docs/understand/the-model.mdx +32 -0
  99. package/site/content/docs/understand/the-problem.mdx +74 -0
  100. package/site/content/docs/understand/the-vocabulary.mdx +26 -0
  101. package/src/auth/api-keys.ts +2 -1
  102. package/src/auth/bindings.ts +64 -16
  103. package/src/auth/gate-auth.test.ts +6 -1
  104. package/src/auth/identity.ts +152 -5
  105. package/src/auth/index.ts +29 -0
  106. package/src/auth/invites.ts +2 -1
  107. package/src/auth/method-context.ts +41 -0
  108. package/src/auth/oauth-as/crypto.ts +2 -1
  109. package/src/auth/oauth-as/stores.ts +2 -1
  110. package/src/auth/operator.ts +2 -1
  111. package/src/auth/sessions-jwt.test.ts +77 -0
  112. package/src/auth/sessions.ts +20 -4
  113. package/src/auth/tenants.ts +3 -2
  114. package/src/auth/two-factor-challenge.test.ts +61 -0
  115. package/src/auth/two-factor-challenge.ts +284 -0
  116. package/src/auth/verification.ts +5 -0
  117. package/src/bench/REPORT.md +49 -0
  118. package/src/bench/g03-signal-once.bench.ts +1 -1
  119. package/src/bench/g10-observability-contention.bench.ts +1 -1
  120. package/src/bench/g17-hybrid-search.bench.ts +572 -0
  121. package/src/bench/load-app.ts +2 -10
  122. package/src/cli/ai-setup/ai-setup.test.ts +331 -42
  123. package/src/cli/ai-setup/apply.ts +294 -52
  124. package/src/cli/ai-setup/catalog.ts +238 -1342
  125. package/src/cli/ai-setup/index.ts +14 -99
  126. package/src/cli/ai-setup/prompts.ts +60 -443
  127. package/src/cli/ask-seed.test.ts +96 -0
  128. package/src/cli/ask-seed.ts +82 -0
  129. package/src/cli/ask-vault-gaps.test.ts +84 -0
  130. package/src/cli/ask-vault-gaps.ts +146 -0
  131. package/src/cli/build.ts +2 -2
  132. package/src/cli/client-add.test.ts +26 -1
  133. package/src/cli/client-add.ts +106 -27
  134. package/src/cli/competitor-mention-removal.test.ts +1 -1
  135. package/src/cli/db-seed.ts +2 -0
  136. package/src/cli/db.ts +150 -11
  137. package/src/cli/dev.ts +119 -211
  138. package/src/cli/docker-clean.ts +2 -2
  139. package/src/cli/docker-cli.test.ts +1 -1
  140. package/src/cli/doctor-diff.ts +4 -2
  141. package/src/cli/doctor-pii.test.ts +1 -1
  142. package/src/cli/doctor.ts +14 -1
  143. package/src/cli/hero-meta.test.ts +4 -2
  144. package/src/cli/load-config.images.test.ts +8 -10
  145. package/src/cli/load-config.ts +1 -1
  146. package/src/cli/registry.ts +22 -10
  147. package/src/cli/replay.ts +3 -1
  148. package/src/cli/start.ts +1 -1
  149. package/src/cli/tui/keys.ts +2 -3
  150. package/src/client/auth/cookies.ts +74 -0
  151. package/src/client/auth/create-auth-client.ts +636 -0
  152. package/src/client/auth/denials.ts +99 -0
  153. package/src/client/auth/session.ts +283 -0
  154. package/src/client/auth.test.ts +251 -0
  155. package/src/client/auth.ts +39 -114
  156. package/src/client/create-with-session.ts +245 -0
  157. package/src/client/create.ts +51 -5
  158. package/src/client/index.ts +11 -1
  159. package/src/client/live.ts +11 -79
  160. package/src/client/notes-contract.test.ts +5 -10
  161. package/src/client/sse.ts +137 -0
  162. package/src/client/stream.ts +147 -0
  163. package/src/client/transport.test.ts +32 -0
  164. package/src/client/transport.ts +123 -26
  165. package/src/client/types.ts +118 -14
  166. package/src/client-react/index.ts +185 -24
  167. package/src/client-react/use-live-query.ts +13 -3
  168. package/src/compiler/aot.test.ts +7 -4
  169. package/src/compiler/effects-embed.test.ts +56 -0
  170. package/src/compiler/effects-fetch.test.ts +43 -0
  171. package/src/compiler/effects-infer.ts +58 -2
  172. package/src/compiler/extract.test.ts +258 -44
  173. package/src/compiler/extract.ts +566 -48
  174. package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +7 -4
  175. package/src/compiler/fixtures/skyport/src/flows/bookings/signals.ts +2 -8
  176. package/src/compiler/fixtures/skyport.expected.json +4 -4
  177. package/src/compiler/fixtures/triggers/five-triggers.ts +14 -10
  178. package/src/compiler/response.ts +2 -2
  179. package/src/compiler/search-writer-isolation.test.ts +40 -0
  180. package/src/config/index.ts +11 -0
  181. package/src/console/server/app.ts +17 -23
  182. package/src/console/server/bind.ts +4 -0
  183. package/src/console/server/console.test.ts +2 -2
  184. package/src/console/server/flows-invoke.test.ts +50 -34
  185. package/src/console/server/flows.ts +436 -255
  186. package/src/console/server/runs-ingest.test.ts +6 -3
  187. package/src/console/server/serve.ts +1 -1
  188. package/src/console/server/signals.test.ts +1 -5
  189. package/src/console/server/signals.ts +8 -6
  190. package/src/console/server/state.ts +6 -1
  191. package/src/console/server/store.ts +1 -1
  192. package/src/console/ui-next/dist/assets/FileExportIcon-Ck-5od4R.js +1 -0
  193. package/src/console/ui-next/dist/assets/MoreHorizontalCircle01Icon-gMNGsE37.js +1 -0
  194. package/src/console/ui-next/dist/assets/PlusSignIcon-CwG3nxfu.js +1 -0
  195. package/src/console/ui-next/dist/assets/UnavailableIcon-D9cvHVPr.js +1 -0
  196. package/src/console/ui-next/dist/assets/UserIcon-DaE2PB5_.js +1 -0
  197. package/src/console/ui-next/dist/assets/access-page-DFeymU07.js +4 -0
  198. package/src/console/ui-next/dist/assets/agent-disclosure-U1rdfblp.js +1 -0
  199. package/src/console/ui-next/dist/assets/cache-glyph-BeFJeqBG.js +1 -0
  200. package/src/console/ui-next/dist/assets/call-pii-button-CVAONPii.js +1 -0
  201. package/src/console/ui-next/dist/assets/collapsible-D2A6NJ-3.js +1 -0
  202. package/src/console/ui-next/dist/assets/copy-inline-button-CAYD18cr.js +1 -0
  203. package/src/console/ui-next/dist/assets/dagre.esm-B1_XeuLP.js +1 -0
  204. package/src/console/ui-next/dist/assets/detail-header-DVWNjWjg.js +1 -0
  205. package/src/console/ui-next/dist/assets/dropdown-menu-4h2LOVXM.js +1 -0
  206. package/src/console/ui-next/dist/assets/duration-tone-Cgk_h5ja.js +9 -0
  207. package/src/console/ui-next/dist/assets/element-icons-BI8cJgdh.js +1 -0
  208. package/src/console/ui-next/dist/assets/explorer-empty-CJs5A-wm.js +1 -0
  209. package/src/console/ui-next/dist/assets/flows-page-Dss7941e.js +1 -0
  210. package/src/console/ui-next/dist/assets/highlighted-json-MYZQtRnw.js +154 -0
  211. package/src/console/ui-next/dist/assets/http-method-Jrh39p7A.js +1 -0
  212. package/src/console/ui-next/dist/assets/index-D0zS5rKO.css +2 -0
  213. package/src/console/ui-next/dist/assets/index-DXP2dBIF.js +63 -0
  214. package/src/console/ui-next/dist/assets/observability-page-HvolXxTI.js +4 -0
  215. package/src/console/ui-next/dist/assets/react-dom-Ddte4I-Q.js +9 -0
  216. package/src/console/ui-next/dist/assets/replica-lag-CSh2dzrb.js +18 -0
  217. package/src/console/ui-next/dist/assets/request-meta-BatF8KrK.js +1 -0
  218. package/src/console/ui-next/dist/assets/shortcut-keys-3ILd8oGn.js +1 -0
  219. package/src/console/ui-next/dist/assets/{sql-BskegiFM.js → sql-BsFa4tDR.js} +1 -1
  220. package/src/console/ui-next/dist/assets/store-page-eiKiHnNe.js +41 -0
  221. package/src/console/ui-next/dist/assets/trace-detail-sheet-CZkMeKS-.js +2 -0
  222. package/src/console/ui-next/dist/assets/tree-expand-toggle-CW8y5A2h.js +55 -0
  223. package/src/console/ui-next/dist/assets/units-page-B_RWJrEO.js +1 -0
  224. package/src/console/ui-next/dist/assets/{use-vault-list-uk4WVboC.js → use-vault-list-CT4-gajj.js} +1 -1
  225. package/src/console/ui-next/dist/assets/vault-page-CWrg-A68.js +2 -0
  226. package/src/console/ui-next/dist/assets/xyflow-CSyC6ryz.css +1 -0
  227. package/src/console/ui-next/dist/assets/xyflow-yApv7D4e.js +7 -0
  228. package/src/console/ui-next/dist/index.html +6 -13
  229. package/src/console/ui-next/seed-invoke-host.ts +21 -18
  230. package/src/console/ui-next/src/client.ts +7 -2
  231. package/src/console/ui-next/src/features/flows/graph/element-map.ts +2 -0
  232. package/src/console/ui-next/src/features/flows/traces/effect-kind.ts +12 -2
  233. package/src/console/ui-next/src/features/flows/traces/effect-summary.ts +4 -0
  234. package/src/console/ui-next/src/features/flows/traces/trace-detail-sheet.tsx +8 -0
  235. package/src/console/ui-next/src/features/flows/traces/waterfall-bars.ts +4 -0
  236. package/src/console/ui-next/src/features/flows/traces/waterfall-tooltip.ts +9 -3
  237. package/src/console/ui-next/src/features/store/detail/reveal-cell.tsx +7 -11
  238. package/src/console/ui-next/src/features/store/detail/store-row-detail-sheet.tsx +2 -2
  239. package/src/console/ui-next/src/features/store/lib/fields-from-table.ts +2 -0
  240. package/src/console/ui-next/src/features/store/lib/grid-model.test.ts +25 -1
  241. package/src/console/ui-next/src/features/store/lib/grid-model.ts +36 -1
  242. package/src/console/ui-next/src/features/store/query/query-results.tsx +3 -3
  243. package/src/console/ui-next/src/features/units/detail/effects-summary.tsx +2 -0
  244. package/src/console/ui-next/src/features/units/lib/call-read-safe.ts +3 -1
  245. package/src/console/ui-next/src/features/units/lib/fields-from-schema.ts +6 -0
  246. package/src/docker/ai-model-status.test.ts +1 -12
  247. package/src/docker/ai-model-status.ts +10 -38
  248. package/src/docker/compose-up.test.ts +100 -0
  249. package/src/docker/compose-up.ts +292 -0
  250. package/src/docker/compose.ts +4 -14
  251. package/src/docker/derive.ts +9 -34
  252. package/src/docker/docker.test.ts +16 -261
  253. package/src/docker/images-config.test.ts +13 -25
  254. package/src/docker/index.ts +1 -24
  255. package/src/docker/recipes/index.ts +0 -23
  256. package/src/docker/recipes/pgdog.ts +6 -4
  257. package/src/docker/stack-id.test.ts +2 -2
  258. package/src/docker/stack-id.ts +0 -1
  259. package/src/docker/types.ts +2 -2
  260. package/src/drivers/ai-anthropic.ts +10 -0
  261. package/src/drivers/ai-openai-compatible.ts +34 -7
  262. package/src/drivers/ai-providers.test.ts +0 -107
  263. package/src/drivers/ai-stream.test.ts +0 -34
  264. package/src/drivers/ai-types.ts +17 -8
  265. package/src/drivers/channel-fcm.ts +6 -1
  266. package/src/drivers/channel-msegat.ts +6 -1
  267. package/src/drivers/channel-resend.ts +5 -1
  268. package/src/drivers/channel-smtp.ts +5 -1
  269. package/src/drivers/channel-sndr.ts +10 -1
  270. package/src/drivers/channel-taqnyat-mail.ts +5 -1
  271. package/src/drivers/channel-taqnyat-whatsapp.ts +6 -1
  272. package/src/drivers/channel-taqnyat.ts +6 -1
  273. package/src/drivers/channel-types.ts +10 -0
  274. package/src/drivers/channel-unifonic.ts +6 -1
  275. package/src/drivers/channel-wa-cloud.ts +6 -1
  276. package/src/drivers/channel-webpush.ts +6 -1
  277. package/src/drivers/external.ts +33 -0
  278. package/src/drivers/index.ts +0 -10
  279. package/src/drivers/meilisearch.ts +6 -0
  280. package/src/drivers/oauth-types.ts +4 -0
  281. package/src/drivers/postgres.test.ts +74 -3
  282. package/src/drivers/postgres.ts +175 -6
  283. package/src/drivers/signal-types.ts +5 -5
  284. package/src/drivers/types.ts +7 -0
  285. package/src/drivers/vault-types.ts +5 -0
  286. package/src/elements/ai/declare.ts +17 -4
  287. package/src/elements/ai/eval.ts +1 -1
  288. package/src/elements/ai/mcp-http.ts +1 -1
  289. package/src/elements/ai/pii.ts +1 -1
  290. package/src/elements/ai/providers.test.ts +289 -0
  291. package/src/elements/ai/providers.ts +169 -0
  292. package/src/elements/ai/runtime.ts +68 -5
  293. package/src/elements/ai/schema.ts +2 -2
  294. package/src/elements/ai.test.ts +7 -7
  295. package/src/elements/ai.ts +17 -1
  296. package/src/elements/channel/runtime.ts +105 -12
  297. package/src/elements/clock/cron-fields.test.ts +144 -0
  298. package/src/elements/clock/cron-fields.ts +185 -0
  299. package/src/elements/clock/declare.ts +247 -3
  300. package/src/elements/clock.ts +21 -1
  301. package/src/elements/index.ts +15 -0
  302. package/src/elements/signal/chaos-child.ts +1 -2
  303. package/src/elements/signal/declare.ts +65 -37
  304. package/src/elements/signal/delivery-modes.test.ts +11 -31
  305. package/src/elements/signal/dry-run-replay.test.ts +1 -7
  306. package/src/elements/signal/dry-run-write-isolation.test.ts +1 -7
  307. package/src/elements/signal/key-ordering.test.ts +6 -26
  308. package/src/elements/signal/lease-reclaim.test.ts +2 -6
  309. package/src/elements/signal/optional-emit.test.ts +6 -9
  310. package/src/elements/signal/order-lifecycle.test.ts +4 -17
  311. package/src/elements/signal/orphan-messages.test.ts +4 -15
  312. package/src/elements/signal/reconcile.test.ts +2 -2
  313. package/src/elements/signal/runtime.ts +1 -1
  314. package/src/elements/signal/schema-emit.test.ts +4 -8
  315. package/src/elements/signal.test.ts +24 -49
  316. package/src/elements/signal.ts +9 -2
  317. package/src/elements/store/domain-ddl.test.ts +1 -1
  318. package/src/elements/store/live-http.test.ts +9 -4
  319. package/src/elements/store/prepare-row.test.ts +123 -0
  320. package/src/elements/store/resource.ts +43 -12
  321. package/src/elements/store/schema-decl.ts +117 -0
  322. package/src/elements/store/search-backfill.ts +205 -0
  323. package/src/elements/store/search-bind.ts +66 -0
  324. package/src/elements/store/search-bm25.ts +78 -0
  325. package/src/elements/store/search-ddl.ts +156 -0
  326. package/src/elements/store/search-embed-flow.ts +141 -0
  327. package/src/elements/store/search-errors.ts +34 -0
  328. package/src/elements/store/search-fusion.ts +112 -0
  329. package/src/elements/store/search-lsh.ts +179 -0
  330. package/src/elements/store/search-runtime.ts +300 -0
  331. package/src/elements/store/search.test.ts +144 -0
  332. package/src/elements/store/sql-session.test.ts +1 -0
  333. package/src/elements/store/sql-session.ts +83 -3
  334. package/src/elements/store/table.ts +23 -2
  335. package/src/elements/store/upsert-app.test.ts +1 -3
  336. package/src/elements/store.ts +50 -0
  337. package/src/full.ts +4 -2
  338. package/src/http.ts +4 -1
  339. package/src/i18n/catalogs/ar.ts +14 -6
  340. package/src/i18n/catalogs/en.ts +14 -6
  341. package/src/index.ts +6 -1
  342. package/src/kernel/adopt-barrel-fresh.test.ts +7 -7
  343. package/src/kernel/adopt-routes.ts +9 -1
  344. package/src/kernel/app-auth.ts +5 -0
  345. package/src/kernel/app.ts +102 -9
  346. package/src/kernel/auto-cache.test.ts +6 -12
  347. package/src/kernel/auto-registry.test.ts +3 -3
  348. package/src/kernel/boot-bind/ai.test.ts +22 -19
  349. package/src/kernel/boot-bind/ai.ts +5 -43
  350. package/src/kernel/boot-bind/clock.ts +23 -5
  351. package/src/kernel/boot-bind/honor-config.test.ts +4 -4
  352. package/src/kernel/boot.test.ts +11 -6
  353. package/src/kernel/boot.ts +66 -16
  354. package/src/kernel/boundary-contract.ts +93 -0
  355. package/src/kernel/budget.test.ts +1 -1
  356. package/src/kernel/call.ts +89 -0
  357. package/src/kernel/capability.ts +6 -0
  358. package/src/kernel/client-descriptor.ts +123 -0
  359. package/src/kernel/clock-timezone.test.ts +80 -0
  360. package/src/kernel/correlation.test.ts +1 -1
  361. package/src/kernel/dry-run.ts +11 -8
  362. package/src/kernel/effects-stamping.test.ts +42 -9
  363. package/src/kernel/effects.test.ts +4 -2
  364. package/src/kernel/effects.ts +51 -9
  365. package/src/kernel/errors-channel.ts +17 -0
  366. package/src/kernel/errors-live-resume.ts +3 -2
  367. package/src/kernel/errors-tenant.ts +7 -4
  368. package/src/kernel/errors.registry-helpers.ts +96 -0
  369. package/src/kernel/errors.registry.test.ts +139 -25
  370. package/src/kernel/errors.ts +102 -23
  371. package/src/kernel/external-effects.test.ts +196 -0
  372. package/src/kernel/flow.test.ts +13 -4
  373. package/src/kernel/flow.ts +69 -71
  374. package/src/kernel/fx-ask-telemetry.test.ts +2 -2
  375. package/src/kernel/fx-dead-letters.test.ts +3 -3
  376. package/src/kernel/fx-fetch.ts +55 -0
  377. package/src/kernel/fx-live-stream.ts +2 -2
  378. package/src/kernel/fx-live.test.ts +8 -8
  379. package/src/kernel/fx.test.ts +17 -11
  380. package/src/kernel/fx.ts +180 -57
  381. package/src/kernel/horizontal-child.ts +1 -1
  382. package/src/kernel/http-query.test.ts +3 -6
  383. package/src/kernel/index.ts +13 -3
  384. package/src/kernel/instance-id.ts +1 -1
  385. package/src/kernel/instances.test.ts +40 -0
  386. package/src/kernel/instances.ts +47 -9
  387. package/src/kernel/live-http.test.ts +6 -7
  388. package/src/kernel/live-http.ts +6 -2
  389. package/src/kernel/live-resume.test.ts +1 -1
  390. package/src/kernel/mcp-tool.test.ts +3 -3
  391. package/src/kernel/on.ts +98 -4
  392. package/src/kernel/pipeline.test.ts +12 -15
  393. package/src/kernel/plugin-elements.test.ts +1 -1
  394. package/src/kernel/stamp-http.test.ts +3 -3
  395. package/src/kernel/triggers.ts +210 -95
  396. package/src/kernel-entry.ts +0 -1
  397. package/src/manifest/diff.ts +11 -1
  398. package/src/manifest/fixtures/skyport.excerpt.json +1 -1
  399. package/src/manifest/types.ts +46 -2
  400. package/src/mcp/docs-index.ts +3 -3
  401. package/src/mcp/docs-mcp.test.ts +2 -2
  402. package/src/mcp/docs-tools.ts +1 -1
  403. package/src/okid.test.ts +56 -0
  404. package/src/okid.ts +55 -11
  405. package/src/plugins/anonymous.ts +8 -4
  406. package/src/plugins/auth/shared.ts +27 -3
  407. package/src/plugins/auth-delivery.mailpit.integration.test.ts +1 -1
  408. package/src/plugins/auth-methods.security.test.ts +561 -23
  409. package/src/plugins/config-source.ts +1 -1
  410. package/src/plugins/csrf.test.ts +65 -0
  411. package/src/plugins/index.ts +2 -0
  412. package/src/plugins/magic-link.ts +36 -16
  413. package/src/plugins/oauth/shared.ts +3 -1
  414. package/src/plugins/oauth.ts +22 -14
  415. package/src/plugins/otp.ts +37 -21
  416. package/src/plugins/passkey-webauthn.ts +9 -6
  417. package/src/plugins/passkey.ts +98 -26
  418. package/src/plugins/pre-account-hijack.test.ts +223 -0
  419. package/src/plugins/two-factor.ts +466 -37
  420. package/src/plugins/username.ts +19 -7
  421. package/src/release/build-lib.ts +1 -0
  422. package/src/release/limits.ts +2 -2
  423. package/src/release/measure.ts +1 -1
  424. package/src/runs/collect.test.ts +0 -2
  425. package/src/runtime/json-code-block.test.ts +250 -20
  426. package/src/runtime/json-code-block.ts +1261 -41
  427. package/src/term.test.ts +1 -1
  428. package/src/test/create-test-app.test.ts +12 -12
  429. package/src/test/live-signals.test.ts +6 -6
  430. package/src/test/provisions.integration.test.ts +10 -14
  431. package/src/test/reset-element-registries.ts +1 -1
  432. package/src/test/tenant-isolation.test.ts +12 -6
  433. package/site/content/docs/deployment/docker-swarm.mdx +0 -164
  434. package/site/content/docs/deployment/docker.mdx +0 -227
  435. package/site/content/docs/deployment/index.mdx +0 -83
  436. package/site/content/docs/deployment/kubernetes.mdx +0 -176
  437. package/site/content/docs/deployment/meta.json +0 -5
  438. package/site/content/docs/deployment/reverse-proxy.mdx +0 -234
  439. package/site/content/docs/elements/ai.mdx +0 -385
  440. package/site/content/docs/elements/channel.mdx +0 -346
  441. package/site/content/docs/elements/clock.mdx +0 -244
  442. package/site/content/docs/elements/flow.mdx +0 -420
  443. package/site/content/docs/elements/gate.mdx +0 -436
  444. package/site/content/docs/elements/signal.mdx +0 -380
  445. package/site/content/docs/elements/store.mdx +0 -1099
  446. package/site/content/docs/elements/vault.mdx +0 -405
  447. package/site/content/docs/get-started/basic-usage.mdx +0 -173
  448. package/site/content/docs/get-started/index.mdx +0 -43
  449. package/site/content/docs/get-started/installation.mdx +0 -220
  450. package/site/content/docs/get-started/introduction.mdx +0 -132
  451. package/site/content/docs/get-started/meta.json +0 -13
  452. package/site/content/docs/get-started/project-structure.mdx +0 -925
  453. package/site/content/docs/get-started/testing.mdx +0 -328
  454. package/site/content/docs/get-started/why.mdx +0 -162
  455. package/site/content/docs/recipes/llama-cpp.mdx +0 -151
  456. package/site/content/docs/recipes/ollama.mdx +0 -142
  457. package/site/content/docs/recipes/sglang.mdx +0 -105
  458. package/site/content/docs/recipes/vllm.mdx +0 -106
  459. package/site/content/docs/reference/cli.md +0 -232
  460. package/site/content/docs/reference/client.mdx +0 -469
  461. package/site/content/docs/reference/security.md +0 -74
  462. package/src/cli/ai-setup/detect-ollama.ts +0 -213
  463. package/src/cli/ai-setup/recommend.test.ts +0 -225
  464. package/src/cli/ai-setup/recommend.ts +0 -225
  465. package/src/cli/dev-controls.test.ts +0 -122
  466. package/src/cli/dev-controls.ts +0 -164
  467. package/src/cli/tui/DevLive.tsx +0 -126
  468. package/src/console/ui-next/dist/assets/access-page-De7Lc2JC.js +0 -4
  469. package/src/console/ui-next/dist/assets/agent-disclosure-BP0Y0Sux.js +0 -1
  470. package/src/console/ui-next/dist/assets/cache-glyph-B5X-NM0-.js +0 -1
  471. package/src/console/ui-next/dist/assets/call-pii-button-ChAUiLo9.js +0 -1
  472. package/src/console/ui-next/dist/assets/collapsible-DGnOM2ph.js +0 -1
  473. package/src/console/ui-next/dist/assets/copy-inline-button-DBHhgHKP.js +0 -1
  474. package/src/console/ui-next/dist/assets/dagre.esm-ZwcdTuZZ.js +0 -1
  475. package/src/console/ui-next/dist/assets/detail-header-DhHM1iaZ.js +0 -1
  476. package/src/console/ui-next/dist/assets/dropdown-menu-_NjTEo5_.js +0 -1
  477. package/src/console/ui-next/dist/assets/duration-tone-sC3lGABz.js +0 -9
  478. package/src/console/ui-next/dist/assets/element-icons-BVXtRyd3.js +0 -1
  479. package/src/console/ui-next/dist/assets/explorer-empty-2uIhBu0_.js +0 -1
  480. package/src/console/ui-next/dist/assets/flows-page-RGy7VEA_.js +0 -1
  481. package/src/console/ui-next/dist/assets/highlighted-json-Awq7gYdu.js +0 -154
  482. package/src/console/ui-next/dist/assets/http-method-_UHM2ODJ.js +0 -1
  483. package/src/console/ui-next/dist/assets/index-Ck88Jmv8.css +0 -2
  484. package/src/console/ui-next/dist/assets/index-_rgpdVzo.js +0 -66
  485. package/src/console/ui-next/dist/assets/link-BX6Vqztd.js +0 -1
  486. package/src/console/ui-next/dist/assets/observability-page-Ds6pcnh-.js +0 -4
  487. package/src/console/ui-next/dist/assets/preload-helper-oH4irX4C.js +0 -1
  488. package/src/console/ui-next/dist/assets/react-D8E3mtu1.js +0 -1
  489. package/src/console/ui-next/dist/assets/react-dom-Bph1y7z7.js +0 -9
  490. package/src/console/ui-next/dist/assets/replica-lag-DKRrbvdo.js +0 -18
  491. package/src/console/ui-next/dist/assets/request-meta-DV0ywz7t.js +0 -1
  492. package/src/console/ui-next/dist/assets/shortcut-JQIZlWfm.js +0 -1
  493. package/src/console/ui-next/dist/assets/shortcut-keys-DKxNTe_m.js +0 -1
  494. package/src/console/ui-next/dist/assets/skeleton-D-czQJT6.js +0 -1
  495. package/src/console/ui-next/dist/assets/store-page-02xOiqIK.js +0 -41
  496. package/src/console/ui-next/dist/assets/trace-detail-sheet-B09O8rA6.js +0 -2
  497. package/src/console/ui-next/dist/assets/tree-expand-toggle-BtyhmWb4.js +0 -55
  498. package/src/console/ui-next/dist/assets/units-page-4rHOePuE.js +0 -1
  499. package/src/console/ui-next/dist/assets/useMutation-B8EO02Ej.js +0 -1
  500. package/src/console/ui-next/dist/assets/useRender-BE2A9BWC.js +0 -1
  501. package/src/console/ui-next/dist/assets/vault-page-DISPgxLM.js +0 -2
  502. package/src/console/ui-next/dist/assets/xyflow-D7n4g6go.js +0 -7
  503. package/src/console/ui-next/dist/assets/xyflow-DZ0Ws1xk.css +0 -1
  504. package/src/docker/ollama-pull.ts +0 -232
  505. package/src/docker/recipes/llama-cpp.ts +0 -298
  506. package/src/docker/recipes/ollama.ts +0 -44
  507. package/src/docker/recipes/sglang.ts +0 -55
  508. package/src/docker/recipes/vllm.ts +0 -44
  509. package/src/drivers/ai-ollama-tools.integration.test.ts +0 -109
  510. package/src/drivers/ai-ollama.integration.test.ts +0 -184
  511. package/src/drivers/ai-ollama.ts +0 -389
  512. package/src/drivers/ollama.ts +0 -14
@@ -0,0 +1,344 @@
1
+ ---
2
+ title: "Overview"
3
+ description: "Reaching humans — declare email, SMS, WhatsApp, and push templates, send through fx.send, track receipts and consent."
4
+ icon: "Mail"
5
+ source: "docs/spec/unified-theory.md"
6
+ ---
7
+
8
+ Channel is how your backend **reaches a person** — the order-confirmation email, the SMS
9
+ sign-in code, a WhatsApp notice, or a device push. You declare a template on a medium, fill a
10
+ `{{field}}` body catalog, and send from a Flow with `fx.send`.
11
+
12
+ For developers wiring Mailpit locally and Resend / Taqnyat / FCM in production — templates and
13
+ drivers first, never vendor SDKs inside `do`.
14
+
15
+ <Callout title="The one rule">
16
+ Declare a template (`channel.email(…).template(…)`), then `fx.send(template, { to, data })`.
17
+ Bodies live in the catalog (`subject` / `text` / `html`), not on the declare call. Consent and
18
+ prior bounces suppress before any driver runs.
19
+ </Callout>
20
+
21
+ <ChannelPhysics />
22
+
23
+ ## Smallest Example
24
+
25
+ <Steps>
26
+
27
+ <Step>
28
+ ### Declare an email template
29
+
30
+ ```typescript title="src/core/channel.ts"
31
+ import { channel } from "okengine";
32
+ import { z } from "zod";
33
+
34
+ const mail = channel.email({ from: "Notes <notes@localhost>" });
35
+
36
+ export const noteCreatedMail = mail.template("note-created", {
37
+ locales: ["en"],
38
+ schema: z.object({
39
+ id: z.string(),
40
+ title: z.string(),
41
+ }),
42
+ });
43
+ ```
44
+
45
+ Import this module before `oke()` so auto-registry adopts the template (or pass it in
46
+ `oke({ channel: { templates: […] } })`).
47
+
48
+ </Step>
49
+
50
+ <Step>
51
+ ### Send from a Flow
52
+
53
+ ```typescript title="src/flows/notes/on-created.ts"
54
+ import { on, flow } from "okengine";
55
+ import { noteCreatedMail } from "@/core/channel";
56
+ import { noteCreated } from "./signals";
57
+
58
+ export const onCreated = on(
59
+ noteCreated,
60
+ flow({
61
+ do: async (payload, fx) => {
62
+ await fx.send(noteCreatedMail, {
63
+ to: "you@localhost",
64
+ data: { id: payload.id, title: payload.title },
65
+ });
66
+ },
67
+ }),
68
+ );
69
+ ```
70
+
71
+ The compiler stamps `sends: ["note-created"]` on the Flow’s effects (template name — not
72
+ `email:note-created`).
73
+
74
+ </Step>
75
+
76
+ <Step>
77
+ ### See it locally
78
+
79
+ With `drivers.channel.email.dev: "smtp"` and Mailpit pinned, open the Mailpit UI
80
+ (`MAILPIT_UI_URL`). Missing catalog bodies fall back to `subject: note-created` and
81
+ `text: JSON.stringify(data)`.
82
+
83
+ </Step>
84
+
85
+ </Steps>
86
+
87
+ ## Progressive Patterns
88
+
89
+ From a bare send to catalog bodies, locale, and same-medium failover:
90
+
91
+ <Tabs items={["Minimal", "Catalog", "Locale", "via"]}>
92
+
93
+ <Tab value="Minimal">
94
+
95
+ Template handle + recipient — catalog optional for local smoke tests:
96
+
97
+ ```typescript
98
+ await fx.send(noteCreatedMail, {
99
+ to: "alice@example.com",
100
+ data: { id: "n1", title: "Hello" },
101
+ });
102
+ ```
103
+
104
+ </Tab>
105
+
106
+ <Tab value="Catalog">
107
+
108
+ Bodies are `{{field}}` strings per locale — not ICU, not React. Pass them on boot or via a
109
+ plugin `.channelCatalog(…)`:
110
+
111
+ ```typescript title="src/app.ts"
112
+ import { oke } from "okengine";
113
+
114
+ export const app = oke({
115
+ name: "notes",
116
+ channel: {
117
+ catalog: {
118
+ "note-created": {
119
+ en: {
120
+ subject: "Note created",
121
+ text: "Your note {{title}} ({{id}}) is ready.",
122
+ html: "<p>Your note <strong>{{title}}</strong> is ready.</p>",
123
+ },
124
+ },
125
+ },
126
+ },
127
+ });
128
+ ```
129
+
130
+ </Tab>
131
+
132
+ <Tab value="Locale">
133
+
134
+ Precedence: explicit `locale` → `profileLocale` → `Accept-Language` →
135
+ `channel.defaultLocale` / `i18n.default` (`"en"`). Omit send locale opts and the send uses
136
+ `fx.locale`.
137
+
138
+ ```typescript
139
+ await fx.send(noteCreatedMail, {
140
+ to: "alice@example.com",
141
+ data: { id: "n1", title: "مرحبا" },
142
+ locale: "ar",
143
+ });
144
+ ```
145
+
146
+ Missing exact locale falls back to default / `en` in the catalog. Chain steps are recorded on
147
+ the receipt (`profile:…` · `accept-language:…` · `default:…`).
148
+
149
+ </Tab>
150
+
151
+ <Tab value="via">
152
+
153
+ Order same-medium drivers for failover. Provider / 5xx errors advance; permanent client errors
154
+ (400, invalid address) do **not**:
155
+
156
+ ```typescript
157
+ await fx.send(noteCreatedMail, {
158
+ to: "alice@example.com",
159
+ data: { id: "n1", title: "Hello" },
160
+ via: ["smtp", "resend"],
161
+ });
162
+ ```
163
+
164
+ **Consequence:** receipt status is `fallback` when an earlier attempt failed and a later one
165
+ succeeded — every attempt is kept on the receipt.
166
+
167
+ </Tab>
168
+
169
+ </Tabs>
170
+
171
+ ## Declaration Reference
172
+
173
+ | Declaration | Signature | Purpose |
174
+ | ------------------ | ---------------------------------- | ----------------------------------------- |
175
+ | `channel.email` | `channel.email(options?)` | Email medium binder |
176
+ | `channel.sms` | `channel.sms(options?)` | SMS medium binder |
177
+ | `channel.whatsapp` | `channel.whatsapp(options?)` | WhatsApp medium binder |
178
+ | `channel.push` | `channel.push(options?)` | Push medium binder |
179
+ | `binder.template` | `binder.template(name, options?)` | Auto-registered template |
180
+ | `channel.template` | `channel.template(name, options?)` | Medium-agnostic — **not** auto-registered |
181
+
182
+ ### Medium options
183
+
184
+ | Option | Type | Default | Meaning |
185
+ | -------- | -------- | ------- | ------------------------------------------- |
186
+ | `from` | `string` | — | Default sender (email From / SMS sender id) |
187
+ | `sender` | `string` | — | Alias stored as `from` |
188
+
189
+ ### Template options
190
+
191
+ | Option | Type | Default | Meaning |
192
+ | ------------- | ---------- | --------- | --------------------------------------------------- |
193
+ | `description` | `string` | name | Console / docs label |
194
+ | `locales` | `string[]` | — | Declared locale tags for the template |
195
+ | `schema` | Schema | — | Payload shape (Zod / Standard Schema) |
196
+ | `from` | `string` | binder’s | Override sender on agnostic `channel.template` only |
197
+ | `medium` | medium | `"email"` | Only on `channel.template()` |
198
+
199
+ Empty name throws `TypeError: channel.template: name is required`.
200
+
201
+ There is **no** `subject` / `body` / `html` on declare — those belong in the catalog.
202
+
203
+ ## `fx` surface
204
+
205
+ | Method | Capability / `sends` | Meaning |
206
+ | -------------------------- | -------------------- | ------------------------------------------- |
207
+ | `fx.send(template, opts?)` | template name | Deliver through the medium’s driver chain |
208
+ | `fx.sendOtp(opts)` | `"sms-otp"` | Provider-managed SMS OTP (Taqnyat Verify) |
209
+ | `fx.verifyOtp(opts)` | `"sms-otp"` | Check a provider OTP code |
210
+ | `fx.deliverOtp(opts)` | `"auth-otp"` | App-owned OTP across email / SMS / WhatsApp |
211
+
212
+ ### `fx.send` options
213
+
214
+ | Option | Type | Meaning |
215
+ | ---------------- | -------- | -------------------------------------------- |
216
+ | `to` | `string` | Recipient (email / E.164 / FCM token / …) |
217
+ | `data` | object | Interpolated into `{{field}}` catalog bodies |
218
+ | `via` | refs | Same-medium driver order for failover |
219
+ | `locale` | `string` | Explicit locale (wins) |
220
+ | `profileLocale` | `string` | Profile locale step |
221
+ | `acceptLanguage` | `string` | Raw `Accept-Language` header |
222
+
223
+ Dry-run records _would have fired_ and never contacts a provider. Undeclared send → **OKE1004**
224
+ `UNDECLARED_SEND`.
225
+
226
+ ## Per-environment drivers
227
+
228
+ Email defaults from `DRIVER_DEFAULTS.channel.email`. SMS / WhatsApp / push are **opt-in**:
229
+
230
+ ```typescript title="oke.config.ts"
231
+ import { defineConfig } from "okengine/config";
232
+
233
+ export default defineConfig({
234
+ drivers: {
235
+ channel: {
236
+ email: { dev: "smtp", test: "console", prod: "smtp" },
237
+ // sms: { prod: "taqnyat" },
238
+ // whatsapp: { prod: "wa-cloud" },
239
+ },
240
+ },
241
+ images: {
242
+ channel: { email: "axllent/mailpit:v1.31.1" },
243
+ },
244
+ });
245
+ ```
246
+
247
+ | Key | Default (dev / test / prod) | Driver ids |
248
+ | ------------------ | --------------------------- | ---------------------------------------------------------------- |
249
+ | `channel.email` | `smtp` / `console` / `smtp` | `console` · `smtp` · `resend` · `sndr` · `taqnyat-mail` |
250
+ | `channel.sms` | none | `taqnyat` · `msegat` · `unifonic` (`console` opens nothing) |
251
+ | `channel.whatsapp` | none | `wa-cloud` · `taqnyat-whatsapp` |
252
+ | `channel.push` | none — **not auto-bound** | Pass `oke({ channel: { drivers: […] } })` with `webpush` / `fcm` |
253
+
254
+ Env knobs: [Environment variables](/docs/reference/environment-variables). Local SMTP catcher:
255
+ [Mailpit](/docs/recipes/mailpit).
256
+
257
+ ## The Capabilities of Channel
258
+
259
+ <Cards>
260
+ <Card
261
+ title="Email"
262
+ description="SMTP / Mailpit, Resend, SNDR, Taqnyat Mail — templates and catalogs."
263
+ href="/docs/elements/channel/email"
264
+ />
265
+ <Card
266
+ title="SMS"
267
+ description="Transactional SMS and provider-managed OTP (Taqnyat Verify)."
268
+ href="/docs/elements/channel/sms"
269
+ />
270
+ <Card
271
+ title="WhatsApp"
272
+ description="wa-cloud and Taqnyat WhatsApp medium binders."
273
+ href="/docs/elements/channel/whatsapp"
274
+ />
275
+ <Card
276
+ title="Push"
277
+ description="FCM device tokens and Web Push (VAPID) driver binding."
278
+ href="/docs/elements/channel/push"
279
+ />
280
+ <Card
281
+ title="Receipts"
282
+ description="In-memory ledger, outcomes taxonomy, consent and bounce suppression."
283
+ href="/docs/elements/channel/receipts"
284
+ />
285
+ </Cards>
286
+
287
+ ## Troubleshooting
288
+
289
+ <Accordions>
290
+
291
+ <Accordion title='channel: unknown template "…"'>
292
+ `fx.send` named a template that was never declared or not adopted at boot. Import the medium
293
+ binder module before `oke()`, or pass `channel.templates` explicitly.
294
+ </Accordion>
295
+
296
+ <Accordion title="OKE1004 — UNDECLARED_SEND">
297
+ Cause: `Flow "{flow}" sends "{resource}" without declaring it.` Touch the template handle
298
+ inside `do` (inference) or list `effects: { sends: ["note-created"] }`.
299
+ </Accordion>
300
+
301
+ <Accordion title="channel: no email transport in driver chain">
302
+ No email-capable driver is bound (or `via` filtered them all out). Check `drivers.channel.email`
303
+ and `SMTP_URL` / provider API keys for the active env.
304
+ </Accordion>
305
+
306
+ <Accordion title="oke boot: smtp driver needs SMTP_URL">
307
+ Email is pinned to `smtp` but neither `SMTP_URL` nor `OKE_CHANNEL_EMAIL_URL` is set. For local
308
+ Docker, run the Mailpit stack so compose writes the URL.
309
+ </Accordion>
310
+
311
+ <Accordion title="Process-local suppression / receipts warning">
312
+ Boot warns: `Channel suppression/consent/receipts default to process-local memory…` Opt-out on one
313
+ instance is invisible to others until you inject shared stores or run a single Channel consumer.
314
+ See [Receipts](/docs/elements/channel/receipts).
315
+ </Accordion>
316
+
317
+ </Accordions>
318
+
319
+ ## Learn more
320
+
321
+ - [Email](/docs/elements/channel/email) — drivers, catalog, Mailpit
322
+ - [SMS](/docs/elements/channel/sms) — `fx.sendOtp` / `fx.verifyOtp`
323
+ - [WhatsApp](/docs/elements/channel/whatsapp) — `channel.whatsapp` + boot drivers
324
+ - [Push](/docs/elements/channel/push) — FCM / Web Push binding
325
+ - [Receipts](/docs/elements/channel/receipts) — ledger, outcomes, suppression
326
+ - [OTP plugin](/docs/plugins/otp) — `/auth/otp/*` over Channel
327
+ - [fx](/docs/reference/fx) — `fx.send` options
328
+ - [i18n](/docs/reference/i18n) — Channel catalogs vs `fx.t`
329
+
330
+ ## Next
331
+
332
+ <Cards>
333
+ <Card
334
+ title="Email"
335
+ description="Declare email templates and pin SMTP / Resend drivers."
336
+ href="/docs/elements/channel/email"
337
+ />
338
+ <Card title="AI Element" description="Models, prompts, and agents." href="/docs/elements/ai" />
339
+ <Card
340
+ title="The Model"
341
+ description="Eight elements overview."
342
+ href="/docs/understand/the-model"
343
+ />
344
+ </Cards>
@@ -0,0 +1,5 @@
1
+ {
2
+ "title": "Channel",
3
+ "icon": "Mail",
4
+ "pages": ["index", "email", "sms", "whatsapp", "push", "receipts"]
5
+ }
@@ -0,0 +1,218 @@
1
+ ---
2
+ title: "Push"
3
+ description: "Mobile and web push — channel.push templates, FCM device tokens, and Web Push (VAPID) drivers bound on boot."
4
+ icon: "Bell"
5
+ source: "docs/spec/unified-theory.md"
6
+ ---
7
+
8
+ Push (`channel.push`) delivers device notifications. Unlike email / SMS / WhatsApp, push
9
+ drivers are **not** opened by the default boot binder — pass `webpush` / `fcm` drivers on
10
+ `oke({ channel: { drivers } })`.
11
+
12
+ For developers notifying installed apps — FCM uses the device token as `to`; Web Push needs
13
+ VAPID keys on the driver.
14
+
15
+ <Callout title="The one rule">
16
+ Declare with `channel.push().template(…)`. Bind push drivers yourself — `drivers.channel.push` in
17
+ config is not auto-opened today. WhatsApp is a different medium
18
+ ([WhatsApp](/docs/elements/channel/whatsapp)).
19
+ </Callout>
20
+
21
+ ## Smallest Example
22
+
23
+ <Steps>
24
+
25
+ <Step>
26
+ ### Declare a push template
27
+
28
+ ```typescript title="src/core/channel.ts"
29
+ import { channel } from "okengine";
30
+ import { z } from "zod";
31
+
32
+ const push = channel.push();
33
+
34
+ export const orderPush = push.template("order.status", {
35
+ locales: ["en"],
36
+ schema: z.object({
37
+ title: z.string(),
38
+ body: z.string(),
39
+ }),
40
+ });
41
+ ```
42
+
43
+ </Step>
44
+
45
+ <Step>
46
+ ### Bind an FCM driver
47
+
48
+ ```typescript title="src/app.ts"
49
+ import { oke } from "okengine";
50
+ import { openFcmChannel } from "okengine/drivers";
51
+
52
+ export const app = oke({
53
+ name: "shop",
54
+ channel: {
55
+ drivers: [
56
+ openFcmChannel({
57
+ projectId: process.env.FCM_PROJECT_ID,
58
+ clientEmail: process.env.FCM_CLIENT_EMAIL,
59
+ privateKey: process.env.FCM_PRIVATE_KEY,
60
+ }),
61
+ ],
62
+ catalog: {
63
+ "order.status": {
64
+ en: { subject: "{{title}}", text: "{{body}}" },
65
+ },
66
+ },
67
+ },
68
+ });
69
+ ```
70
+
71
+ FCM maps catalog `subject` → notification title, `text` → body; `to` is the device token.
72
+
73
+ </Step>
74
+
75
+ <Step>
76
+ ### Send
77
+
78
+ ```typescript
79
+ await fx.send(orderPush, {
80
+ to: deviceToken,
81
+ data: { title: "Shipped", body: "Your order is on the way." },
82
+ });
83
+ ```
84
+
85
+ </Step>
86
+
87
+ </Steps>
88
+
89
+ ## Progressive Patterns
90
+
91
+ <Tabs items={["FCM", "Web Push", "Catalog"]}>
92
+
93
+ <Tab value="FCM">
94
+
95
+ `openFcmChannel` requires `projectId` (or `from`) plus either service-account
96
+ `clientEmail` + `privateKey` or a pre-fetched access `token` / `apiKey`.
97
+
98
+ ```text
99
+ fcm channel: projectId (or from) is required
100
+ fcm channel: clientEmail+privateKey (service account) or token (access token) required
101
+ ```
102
+
103
+ </Tab>
104
+
105
+ <Tab value="Web Push">
106
+
107
+ ```typescript
108
+ import { openWebPushChannel } from "okengine/drivers";
109
+
110
+ openWebPushChannel({
111
+ vapidPublicKey: process.env.VAPID_PUBLIC_KEY,
112
+ vapidPrivateKey: process.env.VAPID_PRIVATE_KEY,
113
+ vapidSubject: "mailto:ops@example.com",
114
+ });
115
+ ```
116
+
117
+ ```text
118
+ webpush: vapidPublicKey and vapidPrivateKey are required
119
+ webpush: pushSubscription with endpoint + keys is required
120
+ ```
121
+
122
+ Web Push needs `pushSubscription` (`endpoint` + `p256dh` / `auth`) on the runtime send
123
+ options — `fx.send` does not forward it. Prefer FCM for token-based `fx.send`, or bind
124
+ Web Push where the subscription is supplied on the runtime path.
125
+
126
+ </Tab>
127
+
128
+ <Tab value="Catalog">
129
+
130
+ ```typescript
131
+ "order.status": {
132
+ en: { subject: "{{title}}", text: "{{body}}" },
133
+ }
134
+ ```
135
+
136
+ `subject` becomes the notification title on FCM; `text` is the body. Extra `data` fields pass
137
+ through as FCM data payload when present.
138
+
139
+ </Tab>
140
+
141
+ </Tabs>
142
+
143
+ ## Drivers
144
+
145
+ | Driver id | How it binds | Role |
146
+ | --------- | ---------------------------------------- | -------------------------------- |
147
+ | `fcm` | `openFcmChannel(…)` in `channel.drivers` | Firebase Cloud Messaging HTTP v1 |
148
+ | `webpush` | `openWebPushChannel(…)` | RFC 8030 + VAPID |
149
+ | `console` | `openConsoleChannel()` | Dev inbox (all mediums) |
150
+
151
+ Config key `drivers.channel.push` exists for Manifest / tooling ids (`console` · `webpush` ·
152
+ `fcm`) but the boot binder does **not** open push from that map yet — pass drivers on
153
+ `CreateChannelRuntimeOptions.drivers`.
154
+
155
+ ## Options Reference
156
+
157
+ ### `channel.push(options?)`
158
+
159
+ | Option | Type | Meaning |
160
+ | -------- | -------- | ---------------- |
161
+ | `from` | `string` | Optional default |
162
+ | `sender` | `string` | Alias for `from` |
163
+
164
+ ### `.template(name, options?)`
165
+
166
+ `description` · `locales` · `schema` — same as other mediums.
167
+
168
+ ## Troubleshooting
169
+
170
+ <Accordions>
171
+
172
+ <Accordion title="Push template sends but nothing is delivered">
173
+ No push driver in `channel.drivers`. Email/SMS/WhatsApp boot chain does not include FCM or Web
174
+ Push — add `openFcmChannel` / `openWebPushChannel`.
175
+ </Accordion>
176
+
177
+ <Accordion title="fcm channel: projectId / credentials required">
178
+ Open options missing project id or service-account pair / access token. See Progressive Patterns →
179
+ FCM.
180
+ </Accordion>
181
+
182
+ <Accordion title="webpush: pushSubscription with endpoint + keys is required">
183
+ Web Push driver received a message without subscription keys. Supply `pushSubscription` on the
184
+ runtime send path; token-only `to` is not enough for Web Push.
185
+ </Accordion>
186
+
187
+ <Accordion title="channel: unknown template">
188
+ Import the push binder module before `oke()`, or list the template under `channel.templates`.
189
+ </Accordion>
190
+
191
+ </Accordions>
192
+
193
+ ## Learn more
194
+
195
+ - [WhatsApp](/docs/elements/channel/whatsapp) — separate medium for chat
196
+ - [Channel overview](/docs/elements/channel) — `fx.send` and catalogs
197
+ - [Receipts](/docs/elements/channel/receipts) — delivery ledger
198
+ - [Configuration](/docs/reference/configuration) — driver id tables
199
+
200
+ ## Next
201
+
202
+ <Cards>
203
+ <Card
204
+ title="Receipts"
205
+ description="Ledger, outcomes, and suppression."
206
+ href="/docs/elements/channel/receipts"
207
+ />
208
+ <Card
209
+ title="WhatsApp"
210
+ description="wa-cloud and Taqnyat WhatsApp."
211
+ href="/docs/elements/channel/whatsapp"
212
+ />
213
+ <Card
214
+ title="Channel Overview"
215
+ description="Declare, send, and drivers."
216
+ href="/docs/elements/channel"
217
+ />
218
+ </Cards>