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,344 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Overview"
|
|
3
|
+
description: "Reaching humans — declare email, SMS, WhatsApp, and push templates, send through fx.send, track receipts and consent."
|
|
4
|
+
icon: "Mail"
|
|
5
|
+
source: "docs/spec/unified-theory.md"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Channel is how your backend **reaches a person** — the order-confirmation email, the SMS
|
|
9
|
+
sign-in code, a WhatsApp notice, or a device push. You declare a template on a medium, fill a
|
|
10
|
+
`{{field}}` body catalog, and send from a Flow with `fx.send`.
|
|
11
|
+
|
|
12
|
+
For developers wiring Mailpit locally and Resend / Taqnyat / FCM in production — templates and
|
|
13
|
+
drivers first, never vendor SDKs inside `do`.
|
|
14
|
+
|
|
15
|
+
<Callout title="The one rule">
|
|
16
|
+
Declare a template (`channel.email(…).template(…)`), then `fx.send(template, { to, data })`.
|
|
17
|
+
Bodies live in the catalog (`subject` / `text` / `html`), not on the declare call. Consent and
|
|
18
|
+
prior bounces suppress before any driver runs.
|
|
19
|
+
</Callout>
|
|
20
|
+
|
|
21
|
+
<ChannelPhysics />
|
|
22
|
+
|
|
23
|
+
## Smallest Example
|
|
24
|
+
|
|
25
|
+
<Steps>
|
|
26
|
+
|
|
27
|
+
<Step>
|
|
28
|
+
### Declare an email template
|
|
29
|
+
|
|
30
|
+
```typescript title="src/core/channel.ts"
|
|
31
|
+
import { channel } from "okengine";
|
|
32
|
+
import { z } from "zod";
|
|
33
|
+
|
|
34
|
+
const mail = channel.email({ from: "Notes <notes@localhost>" });
|
|
35
|
+
|
|
36
|
+
export const noteCreatedMail = mail.template("note-created", {
|
|
37
|
+
locales: ["en"],
|
|
38
|
+
schema: z.object({
|
|
39
|
+
id: z.string(),
|
|
40
|
+
title: z.string(),
|
|
41
|
+
}),
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Import this module before `oke()` so auto-registry adopts the template (or pass it in
|
|
46
|
+
`oke({ channel: { templates: […] } })`).
|
|
47
|
+
|
|
48
|
+
</Step>
|
|
49
|
+
|
|
50
|
+
<Step>
|
|
51
|
+
### Send from a Flow
|
|
52
|
+
|
|
53
|
+
```typescript title="src/flows/notes/on-created.ts"
|
|
54
|
+
import { on, flow } from "okengine";
|
|
55
|
+
import { noteCreatedMail } from "@/core/channel";
|
|
56
|
+
import { noteCreated } from "./signals";
|
|
57
|
+
|
|
58
|
+
export const onCreated = on(
|
|
59
|
+
noteCreated,
|
|
60
|
+
flow({
|
|
61
|
+
do: async (payload, fx) => {
|
|
62
|
+
await fx.send(noteCreatedMail, {
|
|
63
|
+
to: "you@localhost",
|
|
64
|
+
data: { id: payload.id, title: payload.title },
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
}),
|
|
68
|
+
);
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The compiler stamps `sends: ["note-created"]` on the Flow’s effects (template name — not
|
|
72
|
+
`email:note-created`).
|
|
73
|
+
|
|
74
|
+
</Step>
|
|
75
|
+
|
|
76
|
+
<Step>
|
|
77
|
+
### See it locally
|
|
78
|
+
|
|
79
|
+
With `drivers.channel.email.dev: "smtp"` and Mailpit pinned, open the Mailpit UI
|
|
80
|
+
(`MAILPIT_UI_URL`). Missing catalog bodies fall back to `subject: note-created` and
|
|
81
|
+
`text: JSON.stringify(data)`.
|
|
82
|
+
|
|
83
|
+
</Step>
|
|
84
|
+
|
|
85
|
+
</Steps>
|
|
86
|
+
|
|
87
|
+
## Progressive Patterns
|
|
88
|
+
|
|
89
|
+
From a bare send to catalog bodies, locale, and same-medium failover:
|
|
90
|
+
|
|
91
|
+
<Tabs items={["Minimal", "Catalog", "Locale", "via"]}>
|
|
92
|
+
|
|
93
|
+
<Tab value="Minimal">
|
|
94
|
+
|
|
95
|
+
Template handle + recipient — catalog optional for local smoke tests:
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
await fx.send(noteCreatedMail, {
|
|
99
|
+
to: "alice@example.com",
|
|
100
|
+
data: { id: "n1", title: "Hello" },
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
</Tab>
|
|
105
|
+
|
|
106
|
+
<Tab value="Catalog">
|
|
107
|
+
|
|
108
|
+
Bodies are `{{field}}` strings per locale — not ICU, not React. Pass them on boot or via a
|
|
109
|
+
plugin `.channelCatalog(…)`:
|
|
110
|
+
|
|
111
|
+
```typescript title="src/app.ts"
|
|
112
|
+
import { oke } from "okengine";
|
|
113
|
+
|
|
114
|
+
export const app = oke({
|
|
115
|
+
name: "notes",
|
|
116
|
+
channel: {
|
|
117
|
+
catalog: {
|
|
118
|
+
"note-created": {
|
|
119
|
+
en: {
|
|
120
|
+
subject: "Note created",
|
|
121
|
+
text: "Your note {{title}} ({{id}}) is ready.",
|
|
122
|
+
html: "<p>Your note <strong>{{title}}</strong> is ready.</p>",
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
</Tab>
|
|
131
|
+
|
|
132
|
+
<Tab value="Locale">
|
|
133
|
+
|
|
134
|
+
Precedence: explicit `locale` → `profileLocale` → `Accept-Language` →
|
|
135
|
+
`channel.defaultLocale` / `i18n.default` (`"en"`). Omit send locale opts and the send uses
|
|
136
|
+
`fx.locale`.
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
await fx.send(noteCreatedMail, {
|
|
140
|
+
to: "alice@example.com",
|
|
141
|
+
data: { id: "n1", title: "مرحبا" },
|
|
142
|
+
locale: "ar",
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Missing exact locale falls back to default / `en` in the catalog. Chain steps are recorded on
|
|
147
|
+
the receipt (`profile:…` · `accept-language:…` · `default:…`).
|
|
148
|
+
|
|
149
|
+
</Tab>
|
|
150
|
+
|
|
151
|
+
<Tab value="via">
|
|
152
|
+
|
|
153
|
+
Order same-medium drivers for failover. Provider / 5xx errors advance; permanent client errors
|
|
154
|
+
(400, invalid address) do **not**:
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
await fx.send(noteCreatedMail, {
|
|
158
|
+
to: "alice@example.com",
|
|
159
|
+
data: { id: "n1", title: "Hello" },
|
|
160
|
+
via: ["smtp", "resend"],
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**Consequence:** receipt status is `fallback` when an earlier attempt failed and a later one
|
|
165
|
+
succeeded — every attempt is kept on the receipt.
|
|
166
|
+
|
|
167
|
+
</Tab>
|
|
168
|
+
|
|
169
|
+
</Tabs>
|
|
170
|
+
|
|
171
|
+
## Declaration Reference
|
|
172
|
+
|
|
173
|
+
| Declaration | Signature | Purpose |
|
|
174
|
+
| ------------------ | ---------------------------------- | ----------------------------------------- |
|
|
175
|
+
| `channel.email` | `channel.email(options?)` | Email medium binder |
|
|
176
|
+
| `channel.sms` | `channel.sms(options?)` | SMS medium binder |
|
|
177
|
+
| `channel.whatsapp` | `channel.whatsapp(options?)` | WhatsApp medium binder |
|
|
178
|
+
| `channel.push` | `channel.push(options?)` | Push medium binder |
|
|
179
|
+
| `binder.template` | `binder.template(name, options?)` | Auto-registered template |
|
|
180
|
+
| `channel.template` | `channel.template(name, options?)` | Medium-agnostic — **not** auto-registered |
|
|
181
|
+
|
|
182
|
+
### Medium options
|
|
183
|
+
|
|
184
|
+
| Option | Type | Default | Meaning |
|
|
185
|
+
| -------- | -------- | ------- | ------------------------------------------- |
|
|
186
|
+
| `from` | `string` | — | Default sender (email From / SMS sender id) |
|
|
187
|
+
| `sender` | `string` | — | Alias stored as `from` |
|
|
188
|
+
|
|
189
|
+
### Template options
|
|
190
|
+
|
|
191
|
+
| Option | Type | Default | Meaning |
|
|
192
|
+
| ------------- | ---------- | --------- | --------------------------------------------------- |
|
|
193
|
+
| `description` | `string` | name | Console / docs label |
|
|
194
|
+
| `locales` | `string[]` | — | Declared locale tags for the template |
|
|
195
|
+
| `schema` | Schema | — | Payload shape (Zod / Standard Schema) |
|
|
196
|
+
| `from` | `string` | binder’s | Override sender on agnostic `channel.template` only |
|
|
197
|
+
| `medium` | medium | `"email"` | Only on `channel.template()` |
|
|
198
|
+
|
|
199
|
+
Empty name throws `TypeError: channel.template: name is required`.
|
|
200
|
+
|
|
201
|
+
There is **no** `subject` / `body` / `html` on declare — those belong in the catalog.
|
|
202
|
+
|
|
203
|
+
## `fx` surface
|
|
204
|
+
|
|
205
|
+
| Method | Capability / `sends` | Meaning |
|
|
206
|
+
| -------------------------- | -------------------- | ------------------------------------------- |
|
|
207
|
+
| `fx.send(template, opts?)` | template name | Deliver through the medium’s driver chain |
|
|
208
|
+
| `fx.sendOtp(opts)` | `"sms-otp"` | Provider-managed SMS OTP (Taqnyat Verify) |
|
|
209
|
+
| `fx.verifyOtp(opts)` | `"sms-otp"` | Check a provider OTP code |
|
|
210
|
+
| `fx.deliverOtp(opts)` | `"auth-otp"` | App-owned OTP across email / SMS / WhatsApp |
|
|
211
|
+
|
|
212
|
+
### `fx.send` options
|
|
213
|
+
|
|
214
|
+
| Option | Type | Meaning |
|
|
215
|
+
| ---------------- | -------- | -------------------------------------------- |
|
|
216
|
+
| `to` | `string` | Recipient (email / E.164 / FCM token / …) |
|
|
217
|
+
| `data` | object | Interpolated into `{{field}}` catalog bodies |
|
|
218
|
+
| `via` | refs | Same-medium driver order for failover |
|
|
219
|
+
| `locale` | `string` | Explicit locale (wins) |
|
|
220
|
+
| `profileLocale` | `string` | Profile locale step |
|
|
221
|
+
| `acceptLanguage` | `string` | Raw `Accept-Language` header |
|
|
222
|
+
|
|
223
|
+
Dry-run records _would have fired_ and never contacts a provider. Undeclared send → **OKE1004**
|
|
224
|
+
`UNDECLARED_SEND`.
|
|
225
|
+
|
|
226
|
+
## Per-environment drivers
|
|
227
|
+
|
|
228
|
+
Email defaults from `DRIVER_DEFAULTS.channel.email`. SMS / WhatsApp / push are **opt-in**:
|
|
229
|
+
|
|
230
|
+
```typescript title="oke.config.ts"
|
|
231
|
+
import { defineConfig } from "okengine/config";
|
|
232
|
+
|
|
233
|
+
export default defineConfig({
|
|
234
|
+
drivers: {
|
|
235
|
+
channel: {
|
|
236
|
+
email: { dev: "smtp", test: "console", prod: "smtp" },
|
|
237
|
+
// sms: { prod: "taqnyat" },
|
|
238
|
+
// whatsapp: { prod: "wa-cloud" },
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
images: {
|
|
242
|
+
channel: { email: "axllent/mailpit:v1.31.1" },
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
| Key | Default (dev / test / prod) | Driver ids |
|
|
248
|
+
| ------------------ | --------------------------- | ---------------------------------------------------------------- |
|
|
249
|
+
| `channel.email` | `smtp` / `console` / `smtp` | `console` · `smtp` · `resend` · `sndr` · `taqnyat-mail` |
|
|
250
|
+
| `channel.sms` | none | `taqnyat` · `msegat` · `unifonic` (`console` opens nothing) |
|
|
251
|
+
| `channel.whatsapp` | none | `wa-cloud` · `taqnyat-whatsapp` |
|
|
252
|
+
| `channel.push` | none — **not auto-bound** | Pass `oke({ channel: { drivers: […] } })` with `webpush` / `fcm` |
|
|
253
|
+
|
|
254
|
+
Env knobs: [Environment variables](/docs/reference/environment-variables). Local SMTP catcher:
|
|
255
|
+
[Mailpit](/docs/recipes/mailpit).
|
|
256
|
+
|
|
257
|
+
## The Capabilities of Channel
|
|
258
|
+
|
|
259
|
+
<Cards>
|
|
260
|
+
<Card
|
|
261
|
+
title="Email"
|
|
262
|
+
description="SMTP / Mailpit, Resend, SNDR, Taqnyat Mail — templates and catalogs."
|
|
263
|
+
href="/docs/elements/channel/email"
|
|
264
|
+
/>
|
|
265
|
+
<Card
|
|
266
|
+
title="SMS"
|
|
267
|
+
description="Transactional SMS and provider-managed OTP (Taqnyat Verify)."
|
|
268
|
+
href="/docs/elements/channel/sms"
|
|
269
|
+
/>
|
|
270
|
+
<Card
|
|
271
|
+
title="WhatsApp"
|
|
272
|
+
description="wa-cloud and Taqnyat WhatsApp medium binders."
|
|
273
|
+
href="/docs/elements/channel/whatsapp"
|
|
274
|
+
/>
|
|
275
|
+
<Card
|
|
276
|
+
title="Push"
|
|
277
|
+
description="FCM device tokens and Web Push (VAPID) driver binding."
|
|
278
|
+
href="/docs/elements/channel/push"
|
|
279
|
+
/>
|
|
280
|
+
<Card
|
|
281
|
+
title="Receipts"
|
|
282
|
+
description="In-memory ledger, outcomes taxonomy, consent and bounce suppression."
|
|
283
|
+
href="/docs/elements/channel/receipts"
|
|
284
|
+
/>
|
|
285
|
+
</Cards>
|
|
286
|
+
|
|
287
|
+
## Troubleshooting
|
|
288
|
+
|
|
289
|
+
<Accordions>
|
|
290
|
+
|
|
291
|
+
<Accordion title='channel: unknown template "…"'>
|
|
292
|
+
`fx.send` named a template that was never declared or not adopted at boot. Import the medium
|
|
293
|
+
binder module before `oke()`, or pass `channel.templates` explicitly.
|
|
294
|
+
</Accordion>
|
|
295
|
+
|
|
296
|
+
<Accordion title="OKE1004 — UNDECLARED_SEND">
|
|
297
|
+
Cause: `Flow "{flow}" sends "{resource}" without declaring it.` Touch the template handle
|
|
298
|
+
inside `do` (inference) or list `effects: { sends: ["note-created"] }`.
|
|
299
|
+
</Accordion>
|
|
300
|
+
|
|
301
|
+
<Accordion title="channel: no email transport in driver chain">
|
|
302
|
+
No email-capable driver is bound (or `via` filtered them all out). Check `drivers.channel.email`
|
|
303
|
+
and `SMTP_URL` / provider API keys for the active env.
|
|
304
|
+
</Accordion>
|
|
305
|
+
|
|
306
|
+
<Accordion title="oke boot: smtp driver needs SMTP_URL">
|
|
307
|
+
Email is pinned to `smtp` but neither `SMTP_URL` nor `OKE_CHANNEL_EMAIL_URL` is set. For local
|
|
308
|
+
Docker, run the Mailpit stack so compose writes the URL.
|
|
309
|
+
</Accordion>
|
|
310
|
+
|
|
311
|
+
<Accordion title="Process-local suppression / receipts warning">
|
|
312
|
+
Boot warns: `Channel suppression/consent/receipts default to process-local memory…` Opt-out on one
|
|
313
|
+
instance is invisible to others until you inject shared stores or run a single Channel consumer.
|
|
314
|
+
See [Receipts](/docs/elements/channel/receipts).
|
|
315
|
+
</Accordion>
|
|
316
|
+
|
|
317
|
+
</Accordions>
|
|
318
|
+
|
|
319
|
+
## Learn more
|
|
320
|
+
|
|
321
|
+
- [Email](/docs/elements/channel/email) — drivers, catalog, Mailpit
|
|
322
|
+
- [SMS](/docs/elements/channel/sms) — `fx.sendOtp` / `fx.verifyOtp`
|
|
323
|
+
- [WhatsApp](/docs/elements/channel/whatsapp) — `channel.whatsapp` + boot drivers
|
|
324
|
+
- [Push](/docs/elements/channel/push) — FCM / Web Push binding
|
|
325
|
+
- [Receipts](/docs/elements/channel/receipts) — ledger, outcomes, suppression
|
|
326
|
+
- [OTP plugin](/docs/plugins/otp) — `/auth/otp/*` over Channel
|
|
327
|
+
- [fx](/docs/reference/fx) — `fx.send` options
|
|
328
|
+
- [i18n](/docs/reference/i18n) — Channel catalogs vs `fx.t`
|
|
329
|
+
|
|
330
|
+
## Next
|
|
331
|
+
|
|
332
|
+
<Cards>
|
|
333
|
+
<Card
|
|
334
|
+
title="Email"
|
|
335
|
+
description="Declare email templates and pin SMTP / Resend drivers."
|
|
336
|
+
href="/docs/elements/channel/email"
|
|
337
|
+
/>
|
|
338
|
+
<Card title="AI Element" description="Models, prompts, and agents." href="/docs/elements/ai" />
|
|
339
|
+
<Card
|
|
340
|
+
title="The Model"
|
|
341
|
+
description="Eight elements overview."
|
|
342
|
+
href="/docs/understand/the-model"
|
|
343
|
+
/>
|
|
344
|
+
</Cards>
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Push"
|
|
3
|
+
description: "Mobile and web push — channel.push templates, FCM device tokens, and Web Push (VAPID) drivers bound on boot."
|
|
4
|
+
icon: "Bell"
|
|
5
|
+
source: "docs/spec/unified-theory.md"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Push (`channel.push`) delivers device notifications. Unlike email / SMS / WhatsApp, push
|
|
9
|
+
drivers are **not** opened by the default boot binder — pass `webpush` / `fcm` drivers on
|
|
10
|
+
`oke({ channel: { drivers } })`.
|
|
11
|
+
|
|
12
|
+
For developers notifying installed apps — FCM uses the device token as `to`; Web Push needs
|
|
13
|
+
VAPID keys on the driver.
|
|
14
|
+
|
|
15
|
+
<Callout title="The one rule">
|
|
16
|
+
Declare with `channel.push().template(…)`. Bind push drivers yourself — `drivers.channel.push` in
|
|
17
|
+
config is not auto-opened today. WhatsApp is a different medium
|
|
18
|
+
([WhatsApp](/docs/elements/channel/whatsapp)).
|
|
19
|
+
</Callout>
|
|
20
|
+
|
|
21
|
+
## Smallest Example
|
|
22
|
+
|
|
23
|
+
<Steps>
|
|
24
|
+
|
|
25
|
+
<Step>
|
|
26
|
+
### Declare a push template
|
|
27
|
+
|
|
28
|
+
```typescript title="src/core/channel.ts"
|
|
29
|
+
import { channel } from "okengine";
|
|
30
|
+
import { z } from "zod";
|
|
31
|
+
|
|
32
|
+
const push = channel.push();
|
|
33
|
+
|
|
34
|
+
export const orderPush = push.template("order.status", {
|
|
35
|
+
locales: ["en"],
|
|
36
|
+
schema: z.object({
|
|
37
|
+
title: z.string(),
|
|
38
|
+
body: z.string(),
|
|
39
|
+
}),
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
</Step>
|
|
44
|
+
|
|
45
|
+
<Step>
|
|
46
|
+
### Bind an FCM driver
|
|
47
|
+
|
|
48
|
+
```typescript title="src/app.ts"
|
|
49
|
+
import { oke } from "okengine";
|
|
50
|
+
import { openFcmChannel } from "okengine/drivers";
|
|
51
|
+
|
|
52
|
+
export const app = oke({
|
|
53
|
+
name: "shop",
|
|
54
|
+
channel: {
|
|
55
|
+
drivers: [
|
|
56
|
+
openFcmChannel({
|
|
57
|
+
projectId: process.env.FCM_PROJECT_ID,
|
|
58
|
+
clientEmail: process.env.FCM_CLIENT_EMAIL,
|
|
59
|
+
privateKey: process.env.FCM_PRIVATE_KEY,
|
|
60
|
+
}),
|
|
61
|
+
],
|
|
62
|
+
catalog: {
|
|
63
|
+
"order.status": {
|
|
64
|
+
en: { subject: "{{title}}", text: "{{body}}" },
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
FCM maps catalog `subject` → notification title, `text` → body; `to` is the device token.
|
|
72
|
+
|
|
73
|
+
</Step>
|
|
74
|
+
|
|
75
|
+
<Step>
|
|
76
|
+
### Send
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
await fx.send(orderPush, {
|
|
80
|
+
to: deviceToken,
|
|
81
|
+
data: { title: "Shipped", body: "Your order is on the way." },
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
</Step>
|
|
86
|
+
|
|
87
|
+
</Steps>
|
|
88
|
+
|
|
89
|
+
## Progressive Patterns
|
|
90
|
+
|
|
91
|
+
<Tabs items={["FCM", "Web Push", "Catalog"]}>
|
|
92
|
+
|
|
93
|
+
<Tab value="FCM">
|
|
94
|
+
|
|
95
|
+
`openFcmChannel` requires `projectId` (or `from`) plus either service-account
|
|
96
|
+
`clientEmail` + `privateKey` or a pre-fetched access `token` / `apiKey`.
|
|
97
|
+
|
|
98
|
+
```text
|
|
99
|
+
fcm channel: projectId (or from) is required
|
|
100
|
+
fcm channel: clientEmail+privateKey (service account) or token (access token) required
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
</Tab>
|
|
104
|
+
|
|
105
|
+
<Tab value="Web Push">
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
import { openWebPushChannel } from "okengine/drivers";
|
|
109
|
+
|
|
110
|
+
openWebPushChannel({
|
|
111
|
+
vapidPublicKey: process.env.VAPID_PUBLIC_KEY,
|
|
112
|
+
vapidPrivateKey: process.env.VAPID_PRIVATE_KEY,
|
|
113
|
+
vapidSubject: "mailto:ops@example.com",
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
```text
|
|
118
|
+
webpush: vapidPublicKey and vapidPrivateKey are required
|
|
119
|
+
webpush: pushSubscription with endpoint + keys is required
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Web Push needs `pushSubscription` (`endpoint` + `p256dh` / `auth`) on the runtime send
|
|
123
|
+
options — `fx.send` does not forward it. Prefer FCM for token-based `fx.send`, or bind
|
|
124
|
+
Web Push where the subscription is supplied on the runtime path.
|
|
125
|
+
|
|
126
|
+
</Tab>
|
|
127
|
+
|
|
128
|
+
<Tab value="Catalog">
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
"order.status": {
|
|
132
|
+
en: { subject: "{{title}}", text: "{{body}}" },
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`subject` becomes the notification title on FCM; `text` is the body. Extra `data` fields pass
|
|
137
|
+
through as FCM data payload when present.
|
|
138
|
+
|
|
139
|
+
</Tab>
|
|
140
|
+
|
|
141
|
+
</Tabs>
|
|
142
|
+
|
|
143
|
+
## Drivers
|
|
144
|
+
|
|
145
|
+
| Driver id | How it binds | Role |
|
|
146
|
+
| --------- | ---------------------------------------- | -------------------------------- |
|
|
147
|
+
| `fcm` | `openFcmChannel(…)` in `channel.drivers` | Firebase Cloud Messaging HTTP v1 |
|
|
148
|
+
| `webpush` | `openWebPushChannel(…)` | RFC 8030 + VAPID |
|
|
149
|
+
| `console` | `openConsoleChannel()` | Dev inbox (all mediums) |
|
|
150
|
+
|
|
151
|
+
Config key `drivers.channel.push` exists for Manifest / tooling ids (`console` · `webpush` ·
|
|
152
|
+
`fcm`) but the boot binder does **not** open push from that map yet — pass drivers on
|
|
153
|
+
`CreateChannelRuntimeOptions.drivers`.
|
|
154
|
+
|
|
155
|
+
## Options Reference
|
|
156
|
+
|
|
157
|
+
### `channel.push(options?)`
|
|
158
|
+
|
|
159
|
+
| Option | Type | Meaning |
|
|
160
|
+
| -------- | -------- | ---------------- |
|
|
161
|
+
| `from` | `string` | Optional default |
|
|
162
|
+
| `sender` | `string` | Alias for `from` |
|
|
163
|
+
|
|
164
|
+
### `.template(name, options?)`
|
|
165
|
+
|
|
166
|
+
`description` · `locales` · `schema` — same as other mediums.
|
|
167
|
+
|
|
168
|
+
## Troubleshooting
|
|
169
|
+
|
|
170
|
+
<Accordions>
|
|
171
|
+
|
|
172
|
+
<Accordion title="Push template sends but nothing is delivered">
|
|
173
|
+
No push driver in `channel.drivers`. Email/SMS/WhatsApp boot chain does not include FCM or Web
|
|
174
|
+
Push — add `openFcmChannel` / `openWebPushChannel`.
|
|
175
|
+
</Accordion>
|
|
176
|
+
|
|
177
|
+
<Accordion title="fcm channel: projectId / credentials required">
|
|
178
|
+
Open options missing project id or service-account pair / access token. See Progressive Patterns →
|
|
179
|
+
FCM.
|
|
180
|
+
</Accordion>
|
|
181
|
+
|
|
182
|
+
<Accordion title="webpush: pushSubscription with endpoint + keys is required">
|
|
183
|
+
Web Push driver received a message without subscription keys. Supply `pushSubscription` on the
|
|
184
|
+
runtime send path; token-only `to` is not enough for Web Push.
|
|
185
|
+
</Accordion>
|
|
186
|
+
|
|
187
|
+
<Accordion title="channel: unknown template">
|
|
188
|
+
Import the push binder module before `oke()`, or list the template under `channel.templates`.
|
|
189
|
+
</Accordion>
|
|
190
|
+
|
|
191
|
+
</Accordions>
|
|
192
|
+
|
|
193
|
+
## Learn more
|
|
194
|
+
|
|
195
|
+
- [WhatsApp](/docs/elements/channel/whatsapp) — separate medium for chat
|
|
196
|
+
- [Channel overview](/docs/elements/channel) — `fx.send` and catalogs
|
|
197
|
+
- [Receipts](/docs/elements/channel/receipts) — delivery ledger
|
|
198
|
+
- [Configuration](/docs/reference/configuration) — driver id tables
|
|
199
|
+
|
|
200
|
+
## Next
|
|
201
|
+
|
|
202
|
+
<Cards>
|
|
203
|
+
<Card
|
|
204
|
+
title="Receipts"
|
|
205
|
+
description="Ledger, outcomes, and suppression."
|
|
206
|
+
href="/docs/elements/channel/receipts"
|
|
207
|
+
/>
|
|
208
|
+
<Card
|
|
209
|
+
title="WhatsApp"
|
|
210
|
+
description="wa-cloud and Taqnyat WhatsApp."
|
|
211
|
+
href="/docs/elements/channel/whatsapp"
|
|
212
|
+
/>
|
|
213
|
+
<Card
|
|
214
|
+
title="Channel Overview"
|
|
215
|
+
description="Declare, send, and drivers."
|
|
216
|
+
href="/docs/elements/channel"
|
|
217
|
+
/>
|
|
218
|
+
</Cards>
|