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.
- package/AGENTS.md +18 -10
- package/README.md +2 -2
- package/package.json +51 -50
- package/site/content/docs/ai/index.mdx +25 -6
- package/site/content/docs/ai/llms-txt.mdx +1 -1
- package/site/content/docs/ai/meta.json +1 -1
- package/site/content/docs/ai/skills.mdx +4 -1
- package/site/content/docs/ai/try-it.mdx +58 -0
- package/site/content/docs/client/auth.mdx +208 -0
- package/site/content/docs/client/calling.mdx +451 -0
- package/site/content/docs/client/index.mdx +209 -0
- package/site/content/docs/client/live.mdx +234 -0
- package/site/content/docs/client/meta.json +5 -0
- package/site/content/docs/client/react.mdx +249 -0
- package/site/content/docs/elements/ai/agents.mdx +232 -0
- package/site/content/docs/elements/ai/index.mdx +341 -0
- package/site/content/docs/elements/ai/mcp.mdx +275 -0
- package/site/content/docs/elements/ai/meta.json +5 -0
- package/site/content/docs/elements/ai/models.mdx +283 -0
- package/site/content/docs/elements/ai/prompts.mdx +256 -0
- package/site/content/docs/elements/channel/email.mdx +266 -0
- package/site/content/docs/elements/channel/index.mdx +344 -0
- package/site/content/docs/elements/channel/meta.json +5 -0
- package/site/content/docs/elements/channel/push.mdx +218 -0
- package/site/content/docs/elements/channel/receipts.mdx +206 -0
- package/site/content/docs/elements/channel/sms.mdx +264 -0
- package/site/content/docs/elements/channel/whatsapp.mdx +220 -0
- package/site/content/docs/elements/clock/index.mdx +300 -0
- package/site/content/docs/elements/clock/meta.json +5 -0
- package/site/content/docs/elements/clock/schedules.mdx +508 -0
- package/site/content/docs/elements/clock/sleep.mdx +445 -0
- package/site/content/docs/elements/flow/consumers.mdx +707 -0
- package/site/content/docs/elements/flow/http.mdx +1080 -0
- package/site/content/docs/elements/flow/index.mdx +618 -0
- package/site/content/docs/elements/flow/meta.json +5 -0
- package/site/content/docs/elements/flow/routing.mdx +559 -0
- package/site/content/docs/elements/flow/workflows.mdx +640 -0
- package/site/content/docs/elements/gate/auth.mdx +371 -0
- package/site/content/docs/elements/gate/authorization.mdx +298 -0
- package/site/content/docs/elements/gate/index.mdx +418 -0
- package/site/content/docs/elements/gate/meta.json +5 -0
- package/site/content/docs/elements/gate/rate-limits.mdx +365 -0
- package/site/content/docs/elements/gate/rls.mdx +303 -0
- package/site/content/docs/elements/gate/tenancy.mdx +372 -0
- package/site/content/docs/elements/index.mdx +52 -11
- package/site/content/docs/elements/signal/broadcast.mdx +517 -0
- package/site/content/docs/elements/signal/index.mdx +352 -0
- package/site/content/docs/elements/signal/live.mdx +590 -0
- package/site/content/docs/elements/signal/meta.json +5 -0
- package/site/content/docs/elements/signal/once.mdx +596 -0
- package/site/content/docs/elements/store/files.mdx +659 -0
- package/site/content/docs/elements/store/index.mdx +310 -0
- package/site/content/docs/elements/store/kv.mdx +629 -0
- package/site/content/docs/elements/store/meta.json +5 -0
- package/site/content/docs/elements/store/search.mdx +946 -0
- package/site/content/docs/elements/store/sql.mdx +937 -0
- package/site/content/docs/elements/vault/config.mdx +256 -0
- package/site/content/docs/elements/vault/index.mdx +356 -0
- package/site/content/docs/elements/vault/meta.json +5 -0
- package/site/content/docs/elements/vault/rotation.mdx +273 -0
- package/site/content/docs/elements/vault/secrets.mdx +285 -0
- package/site/content/docs/index.mdx +78 -30
- package/site/content/docs/meta.json +11 -8
- package/site/content/docs/plugins/cors.mdx +2 -1
- package/site/content/docs/plugins/csrf.mdx +4 -1
- package/site/content/docs/plugins/headers.mdx +2 -1
- package/site/content/docs/plugins/ip-allowlist.mdx +2 -1
- package/site/content/docs/plugins/magic-link.mdx +6 -0
- package/site/content/docs/plugins/maintenance-mode.mdx +2 -1
- package/site/content/docs/plugins/oauth.mdx +1 -1
- package/site/content/docs/plugins/otp.mdx +12 -1
- package/site/content/docs/plugins/passkey.mdx +39 -15
- package/site/content/docs/plugins/two-factor.mdx +91 -34
- package/site/content/docs/plugins/username.mdx +1 -1
- package/site/content/docs/recipes/caddy.mdx +3 -3
- package/site/content/docs/recipes/index.mdx +18 -28
- package/site/content/docs/recipes/mailpit.mdx +1 -1
- package/site/content/docs/recipes/meilisearch.mdx +3 -3
- package/site/content/docs/recipes/meta.json +1 -4
- package/site/content/docs/recipes/nginx.mdx +2 -2
- package/site/content/docs/recipes/openrouter.mdx +283 -0
- package/site/content/docs/recipes/pgdog.mdx +3 -3
- package/site/content/docs/recipes/postgres.mdx +1 -2
- package/site/content/docs/recipes/rustfs.mdx +2 -2
- package/site/content/docs/recipes/traefik.mdx +3 -3
- package/site/content/docs/reference/cli.mdx +231 -0
- package/site/content/docs/reference/configuration.mdx +30 -10
- package/site/content/docs/reference/environment-variables.mdx +93 -20
- package/site/content/docs/reference/errors.mdx +132 -29
- package/site/content/docs/reference/fx.mdx +137 -73
- package/site/content/docs/reference/index.mdx +13 -21
- package/site/content/docs/reference/meta.json +4 -5
- package/site/content/docs/reference/okid.mdx +42 -17
- package/site/content/docs/reference/plugins.mdx +4 -3
- package/site/content/docs/reference/security.mdx +197 -0
- package/site/content/docs/understand/meta.json +5 -0
- package/site/content/docs/understand/the-anatomy.mdx +132 -0
- package/site/content/docs/understand/the-model.mdx +32 -0
- package/site/content/docs/understand/the-problem.mdx +74 -0
- package/site/content/docs/understand/the-vocabulary.mdx +26 -0
- package/src/auth/api-keys.ts +2 -1
- package/src/auth/bindings.ts +64 -16
- package/src/auth/gate-auth.test.ts +6 -1
- package/src/auth/identity.ts +152 -5
- package/src/auth/index.ts +29 -0
- package/src/auth/invites.ts +2 -1
- package/src/auth/method-context.ts +41 -0
- package/src/auth/oauth-as/crypto.ts +2 -1
- package/src/auth/oauth-as/stores.ts +2 -1
- package/src/auth/operator.ts +2 -1
- package/src/auth/sessions-jwt.test.ts +77 -0
- package/src/auth/sessions.ts +20 -4
- package/src/auth/tenants.ts +3 -2
- package/src/auth/two-factor-challenge.test.ts +61 -0
- package/src/auth/two-factor-challenge.ts +284 -0
- package/src/auth/verification.ts +5 -0
- package/src/bench/REPORT.md +49 -0
- package/src/bench/g03-signal-once.bench.ts +1 -1
- package/src/bench/g10-observability-contention.bench.ts +1 -1
- package/src/bench/g17-hybrid-search.bench.ts +572 -0
- package/src/bench/load-app.ts +2 -10
- package/src/cli/ai-setup/ai-setup.test.ts +331 -42
- package/src/cli/ai-setup/apply.ts +294 -52
- package/src/cli/ai-setup/catalog.ts +238 -1342
- package/src/cli/ai-setup/index.ts +14 -99
- package/src/cli/ai-setup/prompts.ts +60 -443
- package/src/cli/ask-seed.test.ts +96 -0
- package/src/cli/ask-seed.ts +82 -0
- package/src/cli/ask-vault-gaps.test.ts +84 -0
- package/src/cli/ask-vault-gaps.ts +146 -0
- package/src/cli/build.ts +2 -2
- package/src/cli/client-add.test.ts +26 -1
- package/src/cli/client-add.ts +106 -27
- package/src/cli/competitor-mention-removal.test.ts +1 -1
- package/src/cli/db-seed.ts +2 -0
- package/src/cli/db.ts +150 -11
- package/src/cli/dev.ts +119 -211
- package/src/cli/docker-clean.ts +2 -2
- package/src/cli/docker-cli.test.ts +1 -1
- package/src/cli/doctor-diff.ts +4 -2
- package/src/cli/doctor-pii.test.ts +1 -1
- package/src/cli/doctor.ts +14 -1
- package/src/cli/hero-meta.test.ts +4 -2
- package/src/cli/load-config.images.test.ts +8 -10
- package/src/cli/load-config.ts +1 -1
- package/src/cli/registry.ts +22 -10
- package/src/cli/replay.ts +3 -1
- package/src/cli/start.ts +1 -1
- package/src/cli/tui/keys.ts +2 -3
- package/src/client/auth/cookies.ts +74 -0
- package/src/client/auth/create-auth-client.ts +636 -0
- package/src/client/auth/denials.ts +99 -0
- package/src/client/auth/session.ts +283 -0
- package/src/client/auth.test.ts +251 -0
- package/src/client/auth.ts +39 -114
- package/src/client/create-with-session.ts +245 -0
- package/src/client/create.ts +51 -5
- package/src/client/index.ts +11 -1
- package/src/client/live.ts +11 -79
- package/src/client/notes-contract.test.ts +5 -10
- package/src/client/sse.ts +137 -0
- package/src/client/stream.ts +147 -0
- package/src/client/transport.test.ts +32 -0
- package/src/client/transport.ts +123 -26
- package/src/client/types.ts +118 -14
- package/src/client-react/index.ts +185 -24
- package/src/client-react/use-live-query.ts +13 -3
- package/src/compiler/aot.test.ts +7 -4
- package/src/compiler/effects-embed.test.ts +56 -0
- package/src/compiler/effects-fetch.test.ts +43 -0
- package/src/compiler/effects-infer.ts +58 -2
- package/src/compiler/extract.test.ts +258 -44
- package/src/compiler/extract.ts +566 -48
- package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +7 -4
- package/src/compiler/fixtures/skyport/src/flows/bookings/signals.ts +2 -8
- package/src/compiler/fixtures/skyport.expected.json +4 -4
- package/src/compiler/fixtures/triggers/five-triggers.ts +14 -10
- package/src/compiler/response.ts +2 -2
- package/src/compiler/search-writer-isolation.test.ts +40 -0
- package/src/config/index.ts +11 -0
- package/src/console/server/app.ts +17 -23
- package/src/console/server/bind.ts +4 -0
- package/src/console/server/console.test.ts +2 -2
- package/src/console/server/flows-invoke.test.ts +50 -34
- package/src/console/server/flows.ts +436 -255
- package/src/console/server/runs-ingest.test.ts +6 -3
- package/src/console/server/serve.ts +1 -1
- package/src/console/server/signals.test.ts +1 -5
- package/src/console/server/signals.ts +8 -6
- package/src/console/server/state.ts +6 -1
- package/src/console/server/store.ts +1 -1
- package/src/console/ui-next/dist/assets/FileExportIcon-Ck-5od4R.js +1 -0
- package/src/console/ui-next/dist/assets/MoreHorizontalCircle01Icon-gMNGsE37.js +1 -0
- package/src/console/ui-next/dist/assets/PlusSignIcon-CwG3nxfu.js +1 -0
- package/src/console/ui-next/dist/assets/UnavailableIcon-D9cvHVPr.js +1 -0
- package/src/console/ui-next/dist/assets/UserIcon-DaE2PB5_.js +1 -0
- package/src/console/ui-next/dist/assets/access-page-DFeymU07.js +4 -0
- package/src/console/ui-next/dist/assets/agent-disclosure-U1rdfblp.js +1 -0
- package/src/console/ui-next/dist/assets/cache-glyph-BeFJeqBG.js +1 -0
- package/src/console/ui-next/dist/assets/call-pii-button-CVAONPii.js +1 -0
- package/src/console/ui-next/dist/assets/collapsible-D2A6NJ-3.js +1 -0
- package/src/console/ui-next/dist/assets/copy-inline-button-CAYD18cr.js +1 -0
- package/src/console/ui-next/dist/assets/dagre.esm-B1_XeuLP.js +1 -0
- package/src/console/ui-next/dist/assets/detail-header-DVWNjWjg.js +1 -0
- package/src/console/ui-next/dist/assets/dropdown-menu-4h2LOVXM.js +1 -0
- package/src/console/ui-next/dist/assets/duration-tone-Cgk_h5ja.js +9 -0
- package/src/console/ui-next/dist/assets/element-icons-BI8cJgdh.js +1 -0
- package/src/console/ui-next/dist/assets/explorer-empty-CJs5A-wm.js +1 -0
- package/src/console/ui-next/dist/assets/flows-page-Dss7941e.js +1 -0
- package/src/console/ui-next/dist/assets/highlighted-json-MYZQtRnw.js +154 -0
- package/src/console/ui-next/dist/assets/http-method-Jrh39p7A.js +1 -0
- package/src/console/ui-next/dist/assets/index-D0zS5rKO.css +2 -0
- package/src/console/ui-next/dist/assets/index-DXP2dBIF.js +63 -0
- package/src/console/ui-next/dist/assets/observability-page-HvolXxTI.js +4 -0
- package/src/console/ui-next/dist/assets/react-dom-Ddte4I-Q.js +9 -0
- package/src/console/ui-next/dist/assets/replica-lag-CSh2dzrb.js +18 -0
- package/src/console/ui-next/dist/assets/request-meta-BatF8KrK.js +1 -0
- package/src/console/ui-next/dist/assets/shortcut-keys-3ILd8oGn.js +1 -0
- package/src/console/ui-next/dist/assets/{sql-BskegiFM.js → sql-BsFa4tDR.js} +1 -1
- package/src/console/ui-next/dist/assets/store-page-eiKiHnNe.js +41 -0
- package/src/console/ui-next/dist/assets/trace-detail-sheet-CZkMeKS-.js +2 -0
- package/src/console/ui-next/dist/assets/tree-expand-toggle-CW8y5A2h.js +55 -0
- package/src/console/ui-next/dist/assets/units-page-B_RWJrEO.js +1 -0
- package/src/console/ui-next/dist/assets/{use-vault-list-uk4WVboC.js → use-vault-list-CT4-gajj.js} +1 -1
- package/src/console/ui-next/dist/assets/vault-page-CWrg-A68.js +2 -0
- package/src/console/ui-next/dist/assets/xyflow-CSyC6ryz.css +1 -0
- package/src/console/ui-next/dist/assets/xyflow-yApv7D4e.js +7 -0
- package/src/console/ui-next/dist/index.html +6 -13
- package/src/console/ui-next/seed-invoke-host.ts +21 -18
- package/src/console/ui-next/src/client.ts +7 -2
- package/src/console/ui-next/src/features/flows/graph/element-map.ts +2 -0
- package/src/console/ui-next/src/features/flows/traces/effect-kind.ts +12 -2
- package/src/console/ui-next/src/features/flows/traces/effect-summary.ts +4 -0
- package/src/console/ui-next/src/features/flows/traces/trace-detail-sheet.tsx +8 -0
- package/src/console/ui-next/src/features/flows/traces/waterfall-bars.ts +4 -0
- package/src/console/ui-next/src/features/flows/traces/waterfall-tooltip.ts +9 -3
- package/src/console/ui-next/src/features/store/detail/reveal-cell.tsx +7 -11
- package/src/console/ui-next/src/features/store/detail/store-row-detail-sheet.tsx +2 -2
- package/src/console/ui-next/src/features/store/lib/fields-from-table.ts +2 -0
- package/src/console/ui-next/src/features/store/lib/grid-model.test.ts +25 -1
- package/src/console/ui-next/src/features/store/lib/grid-model.ts +36 -1
- package/src/console/ui-next/src/features/store/query/query-results.tsx +3 -3
- package/src/console/ui-next/src/features/units/detail/effects-summary.tsx +2 -0
- package/src/console/ui-next/src/features/units/lib/call-read-safe.ts +3 -1
- package/src/console/ui-next/src/features/units/lib/fields-from-schema.ts +6 -0
- package/src/docker/ai-model-status.test.ts +1 -12
- package/src/docker/ai-model-status.ts +10 -38
- package/src/docker/compose-up.test.ts +100 -0
- package/src/docker/compose-up.ts +292 -0
- package/src/docker/compose.ts +4 -14
- package/src/docker/derive.ts +9 -34
- package/src/docker/docker.test.ts +16 -261
- package/src/docker/images-config.test.ts +13 -25
- package/src/docker/index.ts +1 -24
- package/src/docker/recipes/index.ts +0 -23
- package/src/docker/recipes/pgdog.ts +6 -4
- package/src/docker/stack-id.test.ts +2 -2
- package/src/docker/stack-id.ts +0 -1
- package/src/docker/types.ts +2 -2
- package/src/drivers/ai-anthropic.ts +10 -0
- package/src/drivers/ai-openai-compatible.ts +34 -7
- package/src/drivers/ai-providers.test.ts +0 -107
- package/src/drivers/ai-stream.test.ts +0 -34
- package/src/drivers/ai-types.ts +17 -8
- package/src/drivers/channel-fcm.ts +6 -1
- package/src/drivers/channel-msegat.ts +6 -1
- package/src/drivers/channel-resend.ts +5 -1
- package/src/drivers/channel-smtp.ts +5 -1
- package/src/drivers/channel-sndr.ts +10 -1
- package/src/drivers/channel-taqnyat-mail.ts +5 -1
- package/src/drivers/channel-taqnyat-whatsapp.ts +6 -1
- package/src/drivers/channel-taqnyat.ts +6 -1
- package/src/drivers/channel-types.ts +10 -0
- package/src/drivers/channel-unifonic.ts +6 -1
- package/src/drivers/channel-wa-cloud.ts +6 -1
- package/src/drivers/channel-webpush.ts +6 -1
- package/src/drivers/external.ts +33 -0
- package/src/drivers/index.ts +0 -10
- package/src/drivers/meilisearch.ts +6 -0
- package/src/drivers/oauth-types.ts +4 -0
- package/src/drivers/postgres.test.ts +74 -3
- package/src/drivers/postgres.ts +175 -6
- package/src/drivers/signal-types.ts +5 -5
- package/src/drivers/types.ts +7 -0
- package/src/drivers/vault-types.ts +5 -0
- package/src/elements/ai/declare.ts +17 -4
- package/src/elements/ai/eval.ts +1 -1
- package/src/elements/ai/mcp-http.ts +1 -1
- package/src/elements/ai/pii.ts +1 -1
- package/src/elements/ai/providers.test.ts +289 -0
- package/src/elements/ai/providers.ts +169 -0
- package/src/elements/ai/runtime.ts +68 -5
- package/src/elements/ai/schema.ts +2 -2
- package/src/elements/ai.test.ts +7 -7
- package/src/elements/ai.ts +17 -1
- package/src/elements/channel/runtime.ts +105 -12
- package/src/elements/clock/cron-fields.test.ts +144 -0
- package/src/elements/clock/cron-fields.ts +185 -0
- package/src/elements/clock/declare.ts +247 -3
- package/src/elements/clock.ts +21 -1
- package/src/elements/index.ts +15 -0
- package/src/elements/signal/chaos-child.ts +1 -2
- package/src/elements/signal/declare.ts +65 -37
- package/src/elements/signal/delivery-modes.test.ts +11 -31
- package/src/elements/signal/dry-run-replay.test.ts +1 -7
- package/src/elements/signal/dry-run-write-isolation.test.ts +1 -7
- package/src/elements/signal/key-ordering.test.ts +6 -26
- package/src/elements/signal/lease-reclaim.test.ts +2 -6
- package/src/elements/signal/optional-emit.test.ts +6 -9
- package/src/elements/signal/order-lifecycle.test.ts +4 -17
- package/src/elements/signal/orphan-messages.test.ts +4 -15
- package/src/elements/signal/reconcile.test.ts +2 -2
- package/src/elements/signal/runtime.ts +1 -1
- package/src/elements/signal/schema-emit.test.ts +4 -8
- package/src/elements/signal.test.ts +24 -49
- package/src/elements/signal.ts +9 -2
- package/src/elements/store/domain-ddl.test.ts +1 -1
- package/src/elements/store/live-http.test.ts +9 -4
- package/src/elements/store/prepare-row.test.ts +123 -0
- package/src/elements/store/resource.ts +43 -12
- package/src/elements/store/schema-decl.ts +117 -0
- package/src/elements/store/search-backfill.ts +205 -0
- package/src/elements/store/search-bind.ts +66 -0
- package/src/elements/store/search-bm25.ts +78 -0
- package/src/elements/store/search-ddl.ts +156 -0
- package/src/elements/store/search-embed-flow.ts +141 -0
- package/src/elements/store/search-errors.ts +34 -0
- package/src/elements/store/search-fusion.ts +112 -0
- package/src/elements/store/search-lsh.ts +179 -0
- package/src/elements/store/search-runtime.ts +300 -0
- package/src/elements/store/search.test.ts +144 -0
- package/src/elements/store/sql-session.test.ts +1 -0
- package/src/elements/store/sql-session.ts +83 -3
- package/src/elements/store/table.ts +23 -2
- package/src/elements/store/upsert-app.test.ts +1 -3
- package/src/elements/store.ts +50 -0
- package/src/full.ts +4 -2
- package/src/http.ts +4 -1
- package/src/i18n/catalogs/ar.ts +14 -6
- package/src/i18n/catalogs/en.ts +14 -6
- package/src/index.ts +6 -1
- package/src/kernel/adopt-barrel-fresh.test.ts +7 -7
- package/src/kernel/adopt-routes.ts +9 -1
- package/src/kernel/app-auth.ts +5 -0
- package/src/kernel/app.ts +102 -9
- package/src/kernel/auto-cache.test.ts +6 -12
- package/src/kernel/auto-registry.test.ts +3 -3
- package/src/kernel/boot-bind/ai.test.ts +22 -19
- package/src/kernel/boot-bind/ai.ts +5 -43
- package/src/kernel/boot-bind/clock.ts +23 -5
- package/src/kernel/boot-bind/honor-config.test.ts +4 -4
- package/src/kernel/boot.test.ts +11 -6
- package/src/kernel/boot.ts +66 -16
- package/src/kernel/boundary-contract.ts +93 -0
- package/src/kernel/budget.test.ts +1 -1
- package/src/kernel/call.ts +89 -0
- package/src/kernel/capability.ts +6 -0
- package/src/kernel/client-descriptor.ts +123 -0
- package/src/kernel/clock-timezone.test.ts +80 -0
- package/src/kernel/correlation.test.ts +1 -1
- package/src/kernel/dry-run.ts +11 -8
- package/src/kernel/effects-stamping.test.ts +42 -9
- package/src/kernel/effects.test.ts +4 -2
- package/src/kernel/effects.ts +51 -9
- package/src/kernel/errors-channel.ts +17 -0
- package/src/kernel/errors-live-resume.ts +3 -2
- package/src/kernel/errors-tenant.ts +7 -4
- package/src/kernel/errors.registry-helpers.ts +96 -0
- package/src/kernel/errors.registry.test.ts +139 -25
- package/src/kernel/errors.ts +102 -23
- package/src/kernel/external-effects.test.ts +196 -0
- package/src/kernel/flow.test.ts +13 -4
- package/src/kernel/flow.ts +69 -71
- package/src/kernel/fx-ask-telemetry.test.ts +2 -2
- package/src/kernel/fx-dead-letters.test.ts +3 -3
- package/src/kernel/fx-fetch.ts +55 -0
- package/src/kernel/fx-live-stream.ts +2 -2
- package/src/kernel/fx-live.test.ts +8 -8
- package/src/kernel/fx.test.ts +17 -11
- package/src/kernel/fx.ts +180 -57
- package/src/kernel/horizontal-child.ts +1 -1
- package/src/kernel/http-query.test.ts +3 -6
- package/src/kernel/index.ts +13 -3
- package/src/kernel/instance-id.ts +1 -1
- package/src/kernel/instances.test.ts +40 -0
- package/src/kernel/instances.ts +47 -9
- package/src/kernel/live-http.test.ts +6 -7
- package/src/kernel/live-http.ts +6 -2
- package/src/kernel/live-resume.test.ts +1 -1
- package/src/kernel/mcp-tool.test.ts +3 -3
- package/src/kernel/on.ts +98 -4
- package/src/kernel/pipeline.test.ts +12 -15
- package/src/kernel/plugin-elements.test.ts +1 -1
- package/src/kernel/stamp-http.test.ts +3 -3
- package/src/kernel/triggers.ts +210 -95
- package/src/kernel-entry.ts +0 -1
- package/src/manifest/diff.ts +11 -1
- package/src/manifest/fixtures/skyport.excerpt.json +1 -1
- package/src/manifest/types.ts +46 -2
- package/src/mcp/docs-index.ts +3 -3
- package/src/mcp/docs-mcp.test.ts +2 -2
- package/src/mcp/docs-tools.ts +1 -1
- package/src/okid.test.ts +56 -0
- package/src/okid.ts +55 -11
- package/src/plugins/anonymous.ts +8 -4
- package/src/plugins/auth/shared.ts +27 -3
- package/src/plugins/auth-delivery.mailpit.integration.test.ts +1 -1
- package/src/plugins/auth-methods.security.test.ts +561 -23
- package/src/plugins/config-source.ts +1 -1
- package/src/plugins/csrf.test.ts +65 -0
- package/src/plugins/index.ts +2 -0
- package/src/plugins/magic-link.ts +36 -16
- package/src/plugins/oauth/shared.ts +3 -1
- package/src/plugins/oauth.ts +22 -14
- package/src/plugins/otp.ts +37 -21
- package/src/plugins/passkey-webauthn.ts +9 -6
- package/src/plugins/passkey.ts +98 -26
- package/src/plugins/pre-account-hijack.test.ts +223 -0
- package/src/plugins/two-factor.ts +466 -37
- package/src/plugins/username.ts +19 -7
- package/src/release/build-lib.ts +1 -0
- package/src/release/limits.ts +2 -2
- package/src/release/measure.ts +1 -1
- package/src/runs/collect.test.ts +0 -2
- package/src/runtime/json-code-block.test.ts +250 -20
- package/src/runtime/json-code-block.ts +1261 -41
- package/src/term.test.ts +1 -1
- package/src/test/create-test-app.test.ts +12 -12
- package/src/test/live-signals.test.ts +6 -6
- package/src/test/provisions.integration.test.ts +10 -14
- package/src/test/reset-element-registries.ts +1 -1
- package/src/test/tenant-isolation.test.ts +12 -6
- package/site/content/docs/deployment/docker-swarm.mdx +0 -164
- package/site/content/docs/deployment/docker.mdx +0 -227
- package/site/content/docs/deployment/index.mdx +0 -83
- package/site/content/docs/deployment/kubernetes.mdx +0 -176
- package/site/content/docs/deployment/meta.json +0 -5
- package/site/content/docs/deployment/reverse-proxy.mdx +0 -234
- package/site/content/docs/elements/ai.mdx +0 -385
- package/site/content/docs/elements/channel.mdx +0 -346
- package/site/content/docs/elements/clock.mdx +0 -244
- package/site/content/docs/elements/flow.mdx +0 -420
- package/site/content/docs/elements/gate.mdx +0 -436
- package/site/content/docs/elements/signal.mdx +0 -380
- package/site/content/docs/elements/store.mdx +0 -1099
- package/site/content/docs/elements/vault.mdx +0 -405
- package/site/content/docs/get-started/basic-usage.mdx +0 -173
- package/site/content/docs/get-started/index.mdx +0 -43
- package/site/content/docs/get-started/installation.mdx +0 -220
- package/site/content/docs/get-started/introduction.mdx +0 -132
- package/site/content/docs/get-started/meta.json +0 -13
- package/site/content/docs/get-started/project-structure.mdx +0 -925
- package/site/content/docs/get-started/testing.mdx +0 -328
- package/site/content/docs/get-started/why.mdx +0 -162
- package/site/content/docs/recipes/llama-cpp.mdx +0 -151
- package/site/content/docs/recipes/ollama.mdx +0 -142
- package/site/content/docs/recipes/sglang.mdx +0 -105
- package/site/content/docs/recipes/vllm.mdx +0 -106
- package/site/content/docs/reference/cli.md +0 -232
- package/site/content/docs/reference/client.mdx +0 -469
- package/site/content/docs/reference/security.md +0 -74
- package/src/cli/ai-setup/detect-ollama.ts +0 -213
- package/src/cli/ai-setup/recommend.test.ts +0 -225
- package/src/cli/ai-setup/recommend.ts +0 -225
- package/src/cli/dev-controls.test.ts +0 -122
- package/src/cli/dev-controls.ts +0 -164
- package/src/cli/tui/DevLive.tsx +0 -126
- package/src/console/ui-next/dist/assets/access-page-De7Lc2JC.js +0 -4
- package/src/console/ui-next/dist/assets/agent-disclosure-BP0Y0Sux.js +0 -1
- package/src/console/ui-next/dist/assets/cache-glyph-B5X-NM0-.js +0 -1
- package/src/console/ui-next/dist/assets/call-pii-button-ChAUiLo9.js +0 -1
- package/src/console/ui-next/dist/assets/collapsible-DGnOM2ph.js +0 -1
- package/src/console/ui-next/dist/assets/copy-inline-button-DBHhgHKP.js +0 -1
- package/src/console/ui-next/dist/assets/dagre.esm-ZwcdTuZZ.js +0 -1
- package/src/console/ui-next/dist/assets/detail-header-DhHM1iaZ.js +0 -1
- package/src/console/ui-next/dist/assets/dropdown-menu-_NjTEo5_.js +0 -1
- package/src/console/ui-next/dist/assets/duration-tone-sC3lGABz.js +0 -9
- package/src/console/ui-next/dist/assets/element-icons-BVXtRyd3.js +0 -1
- package/src/console/ui-next/dist/assets/explorer-empty-2uIhBu0_.js +0 -1
- package/src/console/ui-next/dist/assets/flows-page-RGy7VEA_.js +0 -1
- package/src/console/ui-next/dist/assets/highlighted-json-Awq7gYdu.js +0 -154
- package/src/console/ui-next/dist/assets/http-method-_UHM2ODJ.js +0 -1
- package/src/console/ui-next/dist/assets/index-Ck88Jmv8.css +0 -2
- package/src/console/ui-next/dist/assets/index-_rgpdVzo.js +0 -66
- package/src/console/ui-next/dist/assets/link-BX6Vqztd.js +0 -1
- package/src/console/ui-next/dist/assets/observability-page-Ds6pcnh-.js +0 -4
- package/src/console/ui-next/dist/assets/preload-helper-oH4irX4C.js +0 -1
- package/src/console/ui-next/dist/assets/react-D8E3mtu1.js +0 -1
- package/src/console/ui-next/dist/assets/react-dom-Bph1y7z7.js +0 -9
- package/src/console/ui-next/dist/assets/replica-lag-DKRrbvdo.js +0 -18
- package/src/console/ui-next/dist/assets/request-meta-DV0ywz7t.js +0 -1
- package/src/console/ui-next/dist/assets/shortcut-JQIZlWfm.js +0 -1
- package/src/console/ui-next/dist/assets/shortcut-keys-DKxNTe_m.js +0 -1
- package/src/console/ui-next/dist/assets/skeleton-D-czQJT6.js +0 -1
- package/src/console/ui-next/dist/assets/store-page-02xOiqIK.js +0 -41
- package/src/console/ui-next/dist/assets/trace-detail-sheet-B09O8rA6.js +0 -2
- package/src/console/ui-next/dist/assets/tree-expand-toggle-BtyhmWb4.js +0 -55
- package/src/console/ui-next/dist/assets/units-page-4rHOePuE.js +0 -1
- package/src/console/ui-next/dist/assets/useMutation-B8EO02Ej.js +0 -1
- package/src/console/ui-next/dist/assets/useRender-BE2A9BWC.js +0 -1
- package/src/console/ui-next/dist/assets/vault-page-DISPgxLM.js +0 -2
- package/src/console/ui-next/dist/assets/xyflow-D7n4g6go.js +0 -7
- package/src/console/ui-next/dist/assets/xyflow-DZ0Ws1xk.css +0 -1
- package/src/docker/ollama-pull.ts +0 -232
- package/src/docker/recipes/llama-cpp.ts +0 -298
- package/src/docker/recipes/ollama.ts +0 -44
- package/src/docker/recipes/sglang.ts +0 -55
- package/src/docker/recipes/vllm.ts +0 -44
- package/src/drivers/ai-ollama-tools.integration.test.ts +0 -109
- package/src/drivers/ai-ollama.integration.test.ts +0 -184
- package/src/drivers/ai-ollama.ts +0 -389
- 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>
|