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,206 @@
1
+ ---
2
+ title: "Receipts"
3
+ description: "Delivery ledger, seven-state outcomes, consent opt-out, and hard-bounce suppression — process-local by default."
4
+ icon: "ReceiptText"
5
+ source: "docs/spec/unified-theory.md"
6
+ ---
7
+
8
+ Every Channel send records a **receipt** — success (`sent` / `fallback`), suppression, or a
9
+ classified failure. Provider bounces and complaints update that ledger through normalized
10
+ outcomes. There is no `oke_receipts` SQL table and no `fx.channel.getReceipt` helper.
11
+
12
+ For operators watching deliverability — Console projects the ledger; Flows only see send
13
+ results via `fx.send`’s `{ ok: true }` gate.
14
+
15
+ <Callout title="The one rule">
16
+ Consent and prior hard bounces suppress **before** any driver runs. Default suppression / consent
17
+ / receipts stores are **process-local memory** — inject shared stores for multi-instance, or run a
18
+ single Channel consumer, until a durable driver ships.
19
+ </Callout>
20
+
21
+ ## Smallest Example
22
+
23
+ <Steps>
24
+
25
+ <Step>
26
+ ### Send and accept the receipt
27
+
28
+ ```typescript
29
+ const result = await fx.send(noteCreatedMail, {
30
+ to: "alice@example.com",
31
+ data: { id: "n1", title: "Hi" },
32
+ });
33
+ // result.ok === true on the fx gate when the capability succeeds;
34
+ // the runtime ledger still stores status, attempts, and messageId.
35
+ ```
36
+
37
+ Dry-run never contacts a provider and still records _would have fired_.
38
+
39
+ </Step>
40
+
41
+ <Step>
42
+ ### Understand statuses
43
+
44
+ | Status | Meaning |
45
+ | ------------------------- | --------------------------------------------------------------- |
46
+ | `sent` | First (or only) attempt succeeded |
47
+ | `fallback` | An earlier attempt failed; a later same-medium driver succeeded |
48
+ | `suppressed/opted-out` | Consent store blocked the address |
49
+ | `suppressed/prior-bounce` | Prior hard bounce on the suppression list |
50
+ | `failed` / `opted-out` | Legacy aliases kept for older callers |
51
+
52
+ </Step>
53
+
54
+ <Step>
55
+ ### Watch the boot warning
56
+
57
+ ```text
58
+ oke boot: Channel suppression/consent/receipts default to process-local memory —
59
+ opt-out, bounce, and receipt state on one instance is invisible to others.
60
+ Inject shared stores for multi-instance, or run a single Channel consumer, until a
61
+ durable driver ships.
62
+ ```
63
+
64
+ </Step>
65
+
66
+ </Steps>
67
+
68
+ ## Progressive Patterns
69
+
70
+ <Tabs items={["Suppression", "Outcomes", "Inject stores"]}>
71
+
72
+ <Tab value="Suppression">
73
+
74
+ Opt-out or prior bounce never hits SMTP / SMS:
75
+
76
+ ```typescript
77
+ // Runtime path (not on fx): consent.optOut(subject, medium | "all")
78
+ // Next fx.send → receipt status suppressed/opted-out, driverId "suppression", ok: false
79
+ ```
80
+
81
+ Errors on the receipt: `"opted out"` or `"prior hard bounce"`.
82
+
83
+ </Tab>
84
+
85
+ <Tab value="Outcomes">
86
+
87
+ Post-send taxonomy (`DeliveryOutcomeState`):
88
+
89
+ | State | Verdict |
90
+ | --------------------------- | ---------- |
91
+ | `suppressed/opted-out` | `correct` |
92
+ | `suppressed/prior-bounce` | `correct` |
93
+ | `blocked/invalid-address` | `review` |
94
+ | `soft-bounce` | `retry` |
95
+ | `hard-bounce` | `suppress` |
96
+ | `provider-error` | `retry` |
97
+ | `delivered-then-complained` | `review` |
98
+
99
+ `ingestOutcome({ messageId, state })` updates the receipt. Hard bounce also adds the address
100
+ to suppression (`prior-bounce`). Invalid-address heuristics include patterns such as
101
+ `550 5.1.1` on attempt errors.
102
+
103
+ </Tab>
104
+
105
+ <Tab value="Inject stores">
106
+
107
+ Pass shared implementations on boot:
108
+
109
+ ```typescript
110
+ oke({
111
+ channel: {
112
+ suppression: mySuppressionStore,
113
+ consent: myConsentStore,
114
+ receipts: myReceiptLedger,
115
+ },
116
+ });
117
+ ```
118
+
119
+ Shapes: `SuppressionStore`, `ConsentStore`, `ReceiptLedger` from `okengine` — `record` /
120
+ `all` / `forTemplate` / `byMessageId` / `updateStatus` on the ledger.
121
+
122
+ </Tab>
123
+
124
+ </Tabs>
125
+
126
+ ## Receipt shape
127
+
128
+ | Field | Meaning |
129
+ | ------------------------ | ------------------------------------------- |
130
+ | `id` | Runtime receipt id |
131
+ | `template` | Template name |
132
+ | `to` | Recipient |
133
+ | `medium` | `email` · `sms` · `whatsapp` · `push` · … |
134
+ | `locale` / `localeChain` | Resolved locale + chain steps |
135
+ | `status` | Success, legacy, or outcome state |
136
+ | `messageId` | Provider / runtime message id |
137
+ | `driverId` | Winning driver (or `suppression`) |
138
+ | `attempts` | Every try (`driverId`, `ok`, `error`, `at`) |
139
+ | `at` | Epoch ms |
140
+ | `error` | Aggregated attempt errors when failed |
141
+
142
+ ## Consent & suppression
143
+
144
+ | Store | Role |
145
+ | ----------- | ---------------------------------------------------------------- |
146
+ | Consent | `isOptedOut` / `optOut` / `optIn` / `list` per subject + medium |
147
+ | Suppression | Reasons `"opted-out"` \| `"prior-bounce"`; checked on every send |
148
+
149
+ **Consequence:** suppression is not failure — verdict `correct` for opted-out and prior-bounce
150
+ rows. Complaints (`delivered-then-complained`) outrank many hard bounces in consequence weight.
151
+
152
+ There is no Flow helper to query receipts today — use Console projection or an injected ledger
153
+ from operator tooling.
154
+
155
+ ## Troubleshooting
156
+
157
+ <Accordions>
158
+
159
+ <Accordion title="Process-local memory boot warning">
160
+ Expected on single-node `oke dev`. For replicas, inject shared `suppression` / `consent` /
161
+ `receipts` or pin Channel work to one consumer.
162
+ </Accordion>
163
+
164
+ <Accordion title="Send returns ok but Mailpit / provider empty">
165
+ Check receipt status — `suppressed/*` never calls a driver. Opt-in the address or clear prior
166
+ bounce on the suppression store.
167
+ </Accordion>
168
+
169
+ <Accordion title="Status fallback with multiple attempts">
170
+ Same-medium `via` (or ordered driver chain) recovered after a provider error. Inspect `attempts[]`
171
+ for which driver failed and which succeeded.
172
+ </Accordion>
173
+
174
+ <Accordion title="No fx.channel.getReceipt">
175
+ That API does not exist. Use the runtime `receipts` store (injected or Console), not a Flow
176
+ method. `fx.send` only returns `{ ok: true }` after the capability gate.
177
+ </Accordion>
178
+
179
+ <Accordion title="Hard bounce still getting mail">
180
+ `ingestOutcome` with `hard-bounce` must run (webhook → normalized outcome). Without ingestion,
181
+ suppression never learns the bounce.
182
+ </Accordion>
183
+
184
+ </Accordions>
185
+
186
+ ## Learn more
187
+
188
+ - [Channel overview](/docs/elements/channel) — send path and `ChannelPhysics`
189
+ - [Email](/docs/elements/channel/email) — SMTP / provider drivers
190
+ - [fx](/docs/reference/fx) — dry-run send behavior
191
+
192
+ ## Next
193
+
194
+ <Cards>
195
+ <Card
196
+ title="Channel Overview"
197
+ description="Templates, fx.send, and drivers."
198
+ href="/docs/elements/channel"
199
+ />
200
+ <Card
201
+ title="Email"
202
+ description="Mailpit and production email drivers."
203
+ href="/docs/elements/channel/email"
204
+ />
205
+ <Card title="AI Element" description="Models, prompts, and agents." href="/docs/elements/ai" />
206
+ </Cards>
@@ -0,0 +1,264 @@
1
+ ---
2
+ title: "SMS"
3
+ description: "SMS templates via channel.sms, transactional fx.send, and provider-managed OTP with fx.sendOtp / fx.verifyOtp."
4
+ icon: "MessageSquare"
5
+ source: "docs/spec/unified-theory.md"
6
+ ---
7
+
8
+ SMS (`channel.sms`) delivers short text and provider-managed one-time codes. Pin an SMS driver
9
+ (no default in any env), declare templates for app-owned messages, or call `fx.sendOtp` when the
10
+ vendor owns the code.
11
+
12
+ For developers verifying phones — choose raw Channel OTP vs the [`otp`](/docs/plugins/otp) plugin.
13
+
14
+ <Callout title="The one rule">
15
+ SMS is opt-in: set `drivers.channel.sms` (e.g. `"taqnyat"`) or boot has no SMS transport. Provider
16
+ OTP needs a Verify-capable driver (`taqnyat`); app-owned codes use templates + `fx.deliverOtp` /
17
+ the OTP plugin.
18
+ </Callout>
19
+
20
+ ## Smallest Example
21
+
22
+ <Steps>
23
+
24
+ <Step>
25
+ ### Pin an SMS driver
26
+
27
+ ```typescript title="oke.config.ts"
28
+ import { defineConfig } from "okengine/config";
29
+
30
+ export default defineConfig({
31
+ drivers: {
32
+ channel: {
33
+ sms: { prod: "taqnyat" },
34
+ },
35
+ },
36
+ });
37
+ ```
38
+
39
+ Set `TAQNYAT_BEARER_TOKEN` (or `TAQNYAT_TOKEN`) and `TAQNYAT_SENDER`.
40
+
41
+ </Step>
42
+
43
+ <Step>
44
+ ### Declare a template and send
45
+
46
+ ```typescript title="src/core/channel.ts"
47
+ import { channel } from "okengine";
48
+ import { z } from "zod";
49
+
50
+ const sms = channel.sms({ sender: "ACME" });
51
+
52
+ export const orderShippedSms = sms.template("order.shipped", {
53
+ locales: ["en"],
54
+ schema: z.object({ tracking: z.string() }),
55
+ });
56
+ ```
57
+
58
+ ```typescript
59
+ await fx.send(orderShippedSms, {
60
+ to: "+15551234567",
61
+ data: { tracking: "1Z999" },
62
+ });
63
+ ```
64
+
65
+ Add a catalog body (`text: "Shipped — track {{tracking}}"`) or accept the JSON fallback.
66
+
67
+ </Step>
68
+
69
+ <Step>
70
+ ### Or send a provider OTP
71
+
72
+ ```typescript
73
+ await fx.sendOtp({
74
+ to: "+15551234567",
75
+ requestId: fx.id(),
76
+ lang: "en",
77
+ });
78
+
79
+ await fx.verifyOtp({
80
+ to: "+15551234567",
81
+ requestId, // same id
82
+ code: userEnteredCode,
83
+ });
84
+ ```
85
+
86
+ Effects record `sends: ["sms-otp"]`. Prefer [`otp({ mode: "provider" })`](/docs/plugins/otp) for
87
+ `/auth/otp/*` routes.
88
+
89
+ </Step>
90
+
91
+ </Steps>
92
+
93
+ ## Progressive Patterns
94
+
95
+ <Tabs items={["Template", "Provider OTP", "App OTP", "Plugin"]}>
96
+
97
+ <Tab value="Template">
98
+
99
+ Transactional SMS through the same `fx.send` path as email:
100
+
101
+ ```typescript
102
+ const sms = channel.sms({ from: "ACME" });
103
+ export const alertSms = sms.template("ops.alert", {
104
+ schema: z.object({ message: z.string() }),
105
+ });
106
+
107
+ await fx.send(alertSms, { to: phone, data: { message: "Disk 90%" } });
108
+ ```
109
+
110
+ </Tab>
111
+
112
+ <Tab value="Provider OTP">
113
+
114
+ Vendor owns the code (Taqnyat Verify). Options:
115
+
116
+ | Option | Type | Meaning |
117
+ | ----------- | ---------------- | ----------------------------------------- |
118
+ | `to` | `string` | E.164 recipient |
119
+ | `requestId` | `string` | Correlation id (required again on verify) |
120
+ | `lang` | `"en"` \| `"ar"` | Message language |
121
+ | `note` | `string` | Optional note appended to SMS |
122
+ | `from` | `string` | Sender override |
123
+
124
+ `verifyOtp` adds required `code`. Missing Channel →
125
+ `fx.sendOtp needs a bound Channel — declare channel and set drivers.channel.sms (e.g. taqnyat)`.
126
+
127
+ </Tab>
128
+
129
+ <Tab value="App OTP">
130
+
131
+ Your app generates the code; Channel fans out templates:
132
+
133
+ ```typescript
134
+ await fx.deliverOtp({
135
+ channels: ["sms", "whatsapp", "email"],
136
+ templates: {
137
+ sms: "auth-otp-sms",
138
+ whatsapp: "auth-otp-whatsapp",
139
+ email: "auth-otp-email",
140
+ },
141
+ phone: "+15551234567",
142
+ email: "alice@example.com",
143
+ data: { otp: "482910" },
144
+ locale: "en",
145
+ });
146
+ ```
147
+
148
+ Capability: `sends: ["auth-otp"]`. Pass `only: "sms"` for a single-channel resend (no
149
+ cross-medium failover).
150
+
151
+ </Tab>
152
+
153
+ <Tab value="Plugin">
154
+
155
+ ```typescript
156
+ .plug(otp({ mode: "provider" }))
157
+ // or
158
+ .plug(otp({ mode: "app", channels: ["sms", "email"], exposeDevOtp: true }))
159
+ ```
160
+
161
+ Full routes and modes: [OTP plugin](/docs/plugins/otp).
162
+
163
+ </Tab>
164
+
165
+ </Tabs>
166
+
167
+ ## Drivers
168
+
169
+ | Driver id | OTP Verify | Env |
170
+ | ---------- | ---------- | ----------------------------------------------------------- |
171
+ | `taqnyat` | yes | `TAQNYAT_BEARER_TOKEN` / `TAQNYAT_TOKEN` + `TAQNYAT_SENDER` |
172
+ | `msegat` | no | `MSEGAT_USERNAME` / `MSEGAT_API_KEY` / `MSEGAT_SENDER` |
173
+ | `unifonic` | no | `UNIFONIC_APPSID` |
174
+ | `console` | — | Config id that opens **no** SMS driver |
175
+
176
+ Boot errors (verbatim):
177
+
178
+ ```text
179
+ oke boot: taqnyat channel needs TAQNYAT_BEARER_TOKEN
180
+ oke boot: taqnyat channel needs TAQNYAT_SENDER
181
+ oke boot: msegat channel needs MSEGAT_USERNAME / MSEGAT_API_KEY / MSEGAT_SENDER
182
+ oke boot: unifonic channel needs UNIFONIC_APPSID
183
+ ```
184
+
185
+ Provider OTP without a Verify driver:
186
+
187
+ ```text
188
+ channel: SMS driver "…" does not support provider-managed OTP; use exposeDevOtp locally or set drivers.channel.sms to "taqnyat"
189
+ ```
190
+
191
+ No SMS bound:
192
+
193
+ ```text
194
+ channel: no SMS driver bound — bind drivers.channel.sms (e.g. taqnyat) to send provider OTP
195
+ ```
196
+
197
+ ## Options Reference
198
+
199
+ ### `channel.sms(options?)`
200
+
201
+ Same medium options as email: `from` / `sender`.
202
+
203
+ ### `.template(name, options?)`
204
+
205
+ `description` · `locales` · `schema` — bodies in the catalog (`text` is typical for SMS).
206
+
207
+ ## Troubleshooting
208
+
209
+ <Accordions>
210
+
211
+ <Accordion title="fx.sendOtp / verifyOtp needs a bound Channel">
212
+ No Channel runtime, or SMS not configured. Declare templates/drivers and set
213
+ `drivers.channel.sms`.
214
+ </Accordion>
215
+
216
+ <Accordion title="channel: no SMS driver bound">
217
+ Config has no SMS id for this env (`CHANNEL_SMS_DEFAULTS` is empty). Pin `taqnyat` / `msegat` /
218
+ `unifonic`.
219
+ </Accordion>
220
+
221
+ <Accordion title="SMS driver does not support provider-managed OTP">
222
+ Only Taqnyat exposes `sendOtp` / `verifyOtp`. Switch driver or use app-mode OTP
223
+ (`fx.deliverOtp` / `otp({ mode: "app" })`).
224
+ </Accordion>
225
+
226
+ <Accordion title="channel: otp delivery has no viable channel">
227
+ `fx.deliverOtp` had no matching address for a declared medium (need `phone` for SMS / WhatsApp,
228
+ `email` for email).
229
+ </Accordion>
230
+
231
+ <Accordion title="channel: otp delivery failed on all channels">
232
+ Every medium in the failover list failed. Check driver credentials, suppression, and template
233
+ catalog entries.
234
+ </Accordion>
235
+
236
+ </Accordions>
237
+
238
+ ## Learn more
239
+
240
+ - [OTP plugin](/docs/plugins/otp) — `/auth/otp/*`
241
+ - [WhatsApp](/docs/elements/channel/whatsapp) — medium for app-mode OTP failover
242
+ - [Email](/docs/elements/channel/email) — email leg of `deliverOtp`
243
+ - [Channel overview](/docs/elements/channel) — effects and drivers
244
+ - [Environment variables](/docs/reference/environment-variables) — SMS boot binder
245
+
246
+ ## Next
247
+
248
+ <Cards>
249
+ <Card
250
+ title="WhatsApp"
251
+ description="WhatsApp Cloud and Taqnyat WhatsApp drivers."
252
+ href="/docs/elements/channel/whatsapp"
253
+ />
254
+ <Card
255
+ title="OTP Plugin"
256
+ description="Auth routes over provider or app OTP."
257
+ href="/docs/plugins/otp"
258
+ />
259
+ <Card
260
+ title="Channel Overview"
261
+ description="fx.send, catalogs, and consent."
262
+ href="/docs/elements/channel"
263
+ />
264
+ </Cards>
@@ -0,0 +1,220 @@
1
+ ---
2
+ title: "WhatsApp"
3
+ description: "WhatsApp medium — channel.whatsapp templates, wa-cloud and taqnyat-whatsapp drivers, app-mode OTP delivery."
4
+ icon: "MessageCircle"
5
+ source: "docs/spec/unified-theory.md"
6
+ ---
7
+
8
+ WhatsApp (`channel.whatsapp`) is its own medium — not a Push subtype. Declare templates, pin a
9
+ WhatsApp driver (opt-in; no default), and send with `fx.send` or include WhatsApp in
10
+ `fx.deliverOtp` failover.
11
+
12
+ For developers reaching users on Meta Cloud or Taqnyat WhatsApp — same Channel physics as SMS.
13
+
14
+ <Callout title="The one rule">
15
+ Use `channel.whatsapp(…).template(…)` and set `drivers.channel.whatsapp` to `wa-cloud` or
16
+ `taqnyat-whatsapp`. Boot opens WhatsApp when configured; Push drivers are separate and not
17
+ auto-bound.
18
+ </Callout>
19
+
20
+ ## Smallest Example
21
+
22
+ <Steps>
23
+
24
+ <Step>
25
+ ### Pin a WhatsApp driver
26
+
27
+ ```typescript title="oke.config.ts"
28
+ import { defineConfig } from "okengine/config";
29
+
30
+ export default defineConfig({
31
+ drivers: {
32
+ channel: {
33
+ whatsapp: { prod: "wa-cloud" },
34
+ },
35
+ },
36
+ });
37
+ ```
38
+
39
+ `wa-cloud` needs `WHATSAPP_TOKEN` (or `WA_CLOUD_TOKEN`) and `WHATSAPP_PHONE_NUMBER_ID`
40
+ (or `WA_CLOUD_PHONE_NUMBER_ID`).
41
+
42
+ </Step>
43
+
44
+ <Step>
45
+ ### Declare and send
46
+
47
+ ```typescript title="src/core/channel.ts"
48
+ import { channel } from "okengine";
49
+ import { z } from "zod";
50
+
51
+ const wa = channel.whatsapp();
52
+
53
+ export const bookingReminder = wa.template("booking.reminder", {
54
+ locales: ["en", "ar"],
55
+ schema: z.object({ when: z.string(), place: z.string() }),
56
+ });
57
+ ```
58
+
59
+ ```typescript
60
+ await fx.send(bookingReminder, {
61
+ to: "+9665xxxxxxx",
62
+ data: { when: "Thu 15:00", place: "Clinic A" },
63
+ locale: "ar",
64
+ });
65
+ ```
66
+
67
+ </Step>
68
+
69
+ <Step>
70
+ ### Confirm the effect
71
+
72
+ Manifest / Console list `sends: ["booking.reminder"]`. Receipts follow the same ledger as email
73
+ and SMS.
74
+
75
+ </Step>
76
+
77
+ </Steps>
78
+
79
+ ## Progressive Patterns
80
+
81
+ <Tabs items={["Template", "Taqnyat", "App OTP"]}>
82
+
83
+ <Tab value="Template">
84
+
85
+ Catalog typically supplies `text` (and optional `subject` where the transport uses it):
86
+
87
+ ```typescript
88
+ oke({
89
+ channel: {
90
+ catalog: {
91
+ "booking.reminder": {
92
+ en: { text: "Reminder: {{when}} at {{place}}" },
93
+ ar: { text: "تذكير: {{when}} — {{place}}" },
94
+ },
95
+ },
96
+ },
97
+ });
98
+ ```
99
+
100
+ </Tab>
101
+
102
+ <Tab value="Taqnyat">
103
+
104
+ ```typescript
105
+ drivers: {
106
+ channel: {
107
+ whatsapp: { prod: "taqnyat-whatsapp" },
108
+ },
109
+ },
110
+ ```
111
+
112
+ Needs `TAQNYAT_WHATSAPP_TOKEN` (falls back to `TAQNYAT_BEARER_TOKEN`). Missing token:
113
+
114
+ ```text
115
+ oke boot: taqnyat-whatsapp channel needs TAQNYAT_WHATSAPP_TOKEN (or TAQNYAT_BEARER_TOKEN)
116
+ ```
117
+
118
+ </Tab>
119
+
120
+ <Tab value="App OTP">
121
+
122
+ Include WhatsApp in app-owned OTP delivery (plugin or raw):
123
+
124
+ ```typescript
125
+ await fx.deliverOtp({
126
+ channels: ["whatsapp", "sms", "email"],
127
+ templates: {
128
+ whatsapp: "auth-otp-whatsapp",
129
+ sms: "auth-otp-sms",
130
+ email: "auth-otp-email",
131
+ },
132
+ phone: "+15551234567",
133
+ data: { otp: "482910" },
134
+ });
135
+ ```
136
+
137
+ See [OTP plugin](/docs/plugins/otp) for `/auth/otp/*` and [SMS](/docs/elements/channel/sms) for
138
+ provider vs app mode.
139
+
140
+ </Tab>
141
+
142
+ </Tabs>
143
+
144
+ ## Drivers
145
+
146
+ | Driver id | Env |
147
+ | ------------------ | --------------------------------------------------------------------------------------------- |
148
+ | `wa-cloud` | `WHATSAPP_TOKEN` / `WA_CLOUD_TOKEN` + `WHATSAPP_PHONE_NUMBER_ID` / `WA_CLOUD_PHONE_NUMBER_ID` |
149
+ | `taqnyat-whatsapp` | `TAQNYAT_WHATSAPP_TOKEN` or `TAQNYAT_BEARER_TOKEN` |
150
+ | `console` | Config id — opens **no** WhatsApp driver |
151
+
152
+ ```text
153
+ oke boot: wa-cloud channel needs WHATSAPP_TOKEN and WHATSAPP_PHONE_NUMBER_ID
154
+ oke boot: unknown whatsapp channel driver "…"
155
+ ```
156
+
157
+ ## Options Reference
158
+
159
+ ### `channel.whatsapp(options?)`
160
+
161
+ | Option | Type | Meaning |
162
+ | -------- | -------- | ----------------- |
163
+ | `from` | `string` | Default sender id |
164
+ | `sender` | `string` | Alias for `from` |
165
+
166
+ ### `.template(name, options?)`
167
+
168
+ `description` · `locales` · `schema` — same as other mediums.
169
+
170
+ ## Troubleshooting
171
+
172
+ <Accordions>
173
+
174
+ <Accordion title="oke boot: wa-cloud channel needs WHATSAPP_TOKEN and WHATSAPP_PHONE_NUMBER_ID">
175
+ Both token and phone-number id are required for Meta Cloud. Check alias env names (`WA_CLOUD_*`)
176
+ if you use those.
177
+ </Accordion>
178
+
179
+ <Accordion title="oke boot: taqnyat-whatsapp channel needs TAQNYAT_WHATSAPP_TOKEN">
180
+ Set the WhatsApp-specific token or reuse `TAQNYAT_BEARER_TOKEN`.
181
+ </Accordion>
182
+
183
+ <Accordion title="fx.send succeeds nowhere — no WhatsApp in chain">
184
+ `drivers.channel.whatsapp` unset for this env, or id is `console`. Pin `wa-cloud` or
185
+ `taqnyat-whatsapp`.
186
+ </Accordion>
187
+
188
+ <Accordion title="channel: unknown template">
189
+ Template not auto-registered — import the `channel.whatsapp().template(…)` module before `oke()`,
190
+ or pass `channel.templates`.
191
+ </Accordion>
192
+
193
+ </Accordions>
194
+
195
+ ## Learn more
196
+
197
+ - [SMS](/docs/elements/channel/sms) — OTP modes and `fx.deliverOtp`
198
+ - [Push](/docs/elements/channel/push) — FCM / Web Push (separate medium)
199
+ - [Channel overview](/docs/elements/channel) — locale, via, effects
200
+ - [OTP plugin](/docs/plugins/otp) — multi-channel auth OTP
201
+
202
+ ## Next
203
+
204
+ <Cards>
205
+ <Card
206
+ title="Push"
207
+ description="FCM and Web Push driver binding."
208
+ href="/docs/elements/channel/push"
209
+ />
210
+ <Card
211
+ title="SMS"
212
+ description="SMS templates and provider OTP."
213
+ href="/docs/elements/channel/sms"
214
+ />
215
+ <Card
216
+ title="Channel Overview"
217
+ description="Declare, send, and drivers."
218
+ href="/docs/elements/channel"
219
+ />
220
+ </Cards>