okengine 0.18.5 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +18 -10
- package/README.md +2 -2
- package/package.json +51 -50
- 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 +20 -10
- 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 +63 -36
- package/site/content/docs/meta.json +8 -7
- 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/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 +257 -43
- 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 -144
- 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 -114
- 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-3-EFj-2G.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-cVFnA4HH.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-CMIgUbD0.js +0 -66
- package/src/console/ui-next/dist/assets/index-Ck88Jmv8.css +0 -2
- package/src/console/ui-next/dist/assets/link-BX6Vqztd.js +0 -1
- package/src/console/ui-next/dist/assets/observability-page-CQ3p34ip.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-l8FeKfnP.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-CL-d_mLE.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,256 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Prompts"
|
|
3
|
+
description: "Versioned prompt artifacts on ai.model — out schemas, via recovery, budgets, timeouts, and fx.ask."
|
|
4
|
+
icon: "FileCode"
|
|
5
|
+
source: "docs/spec/unified-theory.md"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
A prompt is a **versioned artifact** minted on a model binding (`smart.prompt(...)`). It names
|
|
9
|
+
the ask, optional `in` / `out` shapes, a recovery chain, and a cost cap — then Flows call it
|
|
10
|
+
with `fx.ask`.
|
|
11
|
+
|
|
12
|
+
For developers who need typed triage JSON and a fallback model — declare once, ask everywhere.
|
|
13
|
+
|
|
14
|
+
<Callout title="The one rule">
|
|
15
|
+
Mint prompts with `model.prompt(name, options)` — there is no top-level `ai.prompt`. Input is
|
|
16
|
+
JSON-serialized (no `template` / `{{var}}` API). When `out` is set, the reply must match or
|
|
17
|
+
the ask throws.
|
|
18
|
+
</Callout>
|
|
19
|
+
|
|
20
|
+
## Smallest Example
|
|
21
|
+
|
|
22
|
+
<Steps>
|
|
23
|
+
|
|
24
|
+
<Step>
|
|
25
|
+
### Mint a prompt on a model
|
|
26
|
+
|
|
27
|
+
```typescript title="src/core/ai.ts"
|
|
28
|
+
import { ai } from "okengine";
|
|
29
|
+
import { z } from "zod";
|
|
30
|
+
|
|
31
|
+
export const smart = ai.model("smart", {
|
|
32
|
+
provider: "openrouter",
|
|
33
|
+
model: "openrouter/free",
|
|
34
|
+
apiKey: process.env.OPENROUTER_API_KEY,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
export const classifyTicket = smart.prompt("support.classify", {
|
|
38
|
+
version: 1,
|
|
39
|
+
budget: { maxCostPerCall: 0.01 },
|
|
40
|
+
in: z.object({ message: z.string() }),
|
|
41
|
+
out: z.object({
|
|
42
|
+
category: z.enum(["billing", "technical", "feature_request"]),
|
|
43
|
+
urgency: z.enum(["low", "medium", "high"]),
|
|
44
|
+
}),
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
</Step>
|
|
49
|
+
|
|
50
|
+
<Step>
|
|
51
|
+
### Ask from a Flow
|
|
52
|
+
|
|
53
|
+
```typescript title="src/flows/support/classify.ts"
|
|
54
|
+
import { on, flow, http } from "okengine";
|
|
55
|
+
import { z } from "zod";
|
|
56
|
+
import { classifyTicket } from "@/core/ai";
|
|
57
|
+
|
|
58
|
+
export const classify = on(
|
|
59
|
+
http.post(),
|
|
60
|
+
flow({
|
|
61
|
+
in: z.object({ message: z.string().min(1) }),
|
|
62
|
+
do: async ({ message }, fx) => {
|
|
63
|
+
return await fx.ask(classifyTicket, { message });
|
|
64
|
+
},
|
|
65
|
+
}),
|
|
66
|
+
);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Manifest lists `asks: ["support.classify"]`. Pin a version at call time with
|
|
70
|
+
`fx.ask("support.classify@1", input)`.
|
|
71
|
+
|
|
72
|
+
</Step>
|
|
73
|
+
|
|
74
|
+
<Step>
|
|
75
|
+
### See structured output
|
|
76
|
+
|
|
77
|
+
With `out` set, the runtime appends a schema instruction and validates the JSON reply. Invalid
|
|
78
|
+
shape → `AiSchemaValidationError` (`code: "AiSchemaInvalid"`) — **no** automatic correction
|
|
79
|
+
retry.
|
|
80
|
+
|
|
81
|
+
</Step>
|
|
82
|
+
|
|
83
|
+
</Steps>
|
|
84
|
+
|
|
85
|
+
## Progressive Patterns
|
|
86
|
+
|
|
87
|
+
<Tabs items={["Minimal", "via", "Budget", "Tools"]}>
|
|
88
|
+
|
|
89
|
+
<Tab value="Minimal">
|
|
90
|
+
|
|
91
|
+
Name + optional version — model is the parent binding:
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
export const summarize = smart.prompt("docs.summarize", { version: 1 });
|
|
95
|
+
|
|
96
|
+
await fx.ask(summarize, { text: "…" });
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
</Tab>
|
|
100
|
+
|
|
101
|
+
<Tab value="via">
|
|
102
|
+
|
|
103
|
+
Ordered logical model names for recovery. Resolution:
|
|
104
|
+
`ask.via ?? prompt.via ?? [prompt.model]`:
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
export const triage = smart.prompt("ticket-triage", {
|
|
108
|
+
version: 1,
|
|
109
|
+
via: ["smart", "local"],
|
|
110
|
+
out: z.object({ category: z.string() }),
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
await fx.ask(triage, input, { via: ["local"] }); // call override
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Consequence:** each via step uses that binding’s own `apiKey` / `baseUrl`.
|
|
117
|
+
|
|
118
|
+
</Tab>
|
|
119
|
+
|
|
120
|
+
<Tab value="Budget">
|
|
121
|
+
|
|
122
|
+
Per-call cost cap — exceeded throws `AiBudgetExceededError`:
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
smart.prompt("ticket-triage", {
|
|
126
|
+
budget: { maxCostPerCall: 0.02 },
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`maxCostPerRun` on a prompt budget is reserved for multi-step asks; agents use
|
|
131
|
+
`budget.maxCostPerRun` on `ai.agent`.
|
|
132
|
+
|
|
133
|
+
</Tab>
|
|
134
|
+
|
|
135
|
+
<Tab value="Tools">
|
|
136
|
+
|
|
137
|
+
Offer Flows for one ask without declaring an agent:
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
await fx.ask(
|
|
141
|
+
triage,
|
|
142
|
+
{ message },
|
|
143
|
+
{
|
|
144
|
+
tools: ["docs.search", "tickets.create"],
|
|
145
|
+
maxSteps: 4,
|
|
146
|
+
},
|
|
147
|
+
);
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Default `maxSteps` is `6`. Tool names also stamp `effects.calls`.
|
|
151
|
+
|
|
152
|
+
</Tab>
|
|
153
|
+
|
|
154
|
+
</Tabs>
|
|
155
|
+
|
|
156
|
+
## Options
|
|
157
|
+
|
|
158
|
+
| Option | Type | Default | Meaning |
|
|
159
|
+
| --------- | ------------------------------------- | ---------------- | --------------------------------------------------------------- |
|
|
160
|
+
| `version` | `number` | — | Pin with `fx.ask("name@N")` |
|
|
161
|
+
| `evals` | `string` | — | Path for `oke eval` JSONL |
|
|
162
|
+
| `budget` | `{ maxCostPerCall?, maxCostPerRun? }` | — | Cost contracts |
|
|
163
|
+
| `via` | `string[]` | `[parent model]` | Recovery chain of logical names |
|
|
164
|
+
| `timeout` | `"30s"` \| ms | — | Ask deadline (not a cost budget) |
|
|
165
|
+
| `in` | Schema | — | Declared / Manifest / doctor — **not** runtime-validated on ask |
|
|
166
|
+
| `out` | Schema | — | Runtime-validated (Zod / JSON Schema / field shorthand) |
|
|
167
|
+
|
|
168
|
+
## How input reaches the model
|
|
169
|
+
|
|
170
|
+
There is **no** template string API. The runtime JSON-stringifies the ask input (redacting
|
|
171
|
+
secrets), and when `out` is set appends:
|
|
172
|
+
|
|
173
|
+
```text
|
|
174
|
+
Reply with JSON only matching this schema: …
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Pass the fields you need as the second argument to `fx.ask` — do not invent `template` /
|
|
178
|
+
`{{message}}` options.
|
|
179
|
+
|
|
180
|
+
## `fx.ask` options
|
|
181
|
+
|
|
182
|
+
| Option | Type | Default | Meaning |
|
|
183
|
+
| ---------- | --------- | ---------------- | ------------------------------- |
|
|
184
|
+
| `via` | refs | prompt chain | Override recovery for this call |
|
|
185
|
+
| `timeout` | duration | prompt `timeout` | Per-call deadline |
|
|
186
|
+
| `tools` | Flow refs | — | Tool loop via `fx.call` |
|
|
187
|
+
| `maxSteps` | `number` | `6` | Cap on tool rounds |
|
|
188
|
+
|
|
189
|
+
## Embeds (related)
|
|
190
|
+
|
|
191
|
+
`ai.embed` is a separate declaration for vector pipelines into `store.index`:
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
export const kb = ai.embed("kb", {
|
|
195
|
+
model: "smart",
|
|
196
|
+
into: "knowledge",
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
const vector = await fx.embed(smart, "install guide");
|
|
200
|
+
const hits = await fx.search(kb, "how to install", { topK: 5 });
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
`fx.embed` records `embeds` (not `asks`). Missing `into` or a non-vector index fails at
|
|
204
|
+
runtime with `ai: embed "…" has no into` / vector-index errors.
|
|
205
|
+
|
|
206
|
+
## Troubleshooting
|
|
207
|
+
|
|
208
|
+
<Accordions>
|
|
209
|
+
|
|
210
|
+
<Accordion title='ai: unknown prompt "…"'>
|
|
211
|
+
The name was never registered with `model.prompt`, or the AI module was not imported before boot.
|
|
212
|
+
</Accordion>
|
|
213
|
+
|
|
214
|
+
<Accordion title="OKE1005 — UNDECLARED_ASK">
|
|
215
|
+
Cause: `Flow "{flow}" asks "{resource}" without declaring it.` Use the prompt handle in `do`
|
|
216
|
+
or list `effects: { asks: ["support.classify"] }`.
|
|
217
|
+
</Accordion>
|
|
218
|
+
|
|
219
|
+
<Accordion title='ai: schema validation failed for prompt "…"@N'>
|
|
220
|
+
`AiSchemaValidationError` — the model reply failed `out`. Message includes missing / extra / type
|
|
221
|
+
issues. There is no retry-with-corrections loop.
|
|
222
|
+
</Accordion>
|
|
223
|
+
|
|
224
|
+
<Accordion title='ai: prompt "…" exceeded maxCostPerCall'>
|
|
225
|
+
`AiBudgetExceededError` — raise `budget.maxCostPerCall` or reduce tokens / tool rounds.
|
|
226
|
+
</Accordion>
|
|
227
|
+
|
|
228
|
+
<Accordion title='ai: all models failed for prompt "…"'>
|
|
229
|
+
Every entry in the `via` chain failed (network, auth, or provider error). Check each binding’s
|
|
230
|
+
`apiKey` / `baseUrl` and driver health.
|
|
231
|
+
</Accordion>
|
|
232
|
+
|
|
233
|
+
</Accordions>
|
|
234
|
+
|
|
235
|
+
## Learn more
|
|
236
|
+
|
|
237
|
+
- [Models](/docs/elements/ai/models) — bindings and providers
|
|
238
|
+
- [Agents](/docs/elements/ai/agents) — multi-step `fx.run`
|
|
239
|
+
- [AI](/docs/elements/ai) — guardrails and PII egress
|
|
240
|
+
- [OpenRouter](/docs/recipes/openrouter) — cloud ask recipe
|
|
241
|
+
|
|
242
|
+
## Next
|
|
243
|
+
|
|
244
|
+
<Cards>
|
|
245
|
+
<Card
|
|
246
|
+
title="Agents"
|
|
247
|
+
description="Bounded agents whose tools are Flows."
|
|
248
|
+
href="/docs/elements/ai/agents"
|
|
249
|
+
/>
|
|
250
|
+
<Card
|
|
251
|
+
title="Models"
|
|
252
|
+
description="Provider registry and drivers."
|
|
253
|
+
href="/docs/elements/ai/models"
|
|
254
|
+
/>
|
|
255
|
+
<Card title="AI" description="Element overview." href="/docs/elements/ai" />
|
|
256
|
+
</Cards>
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Email"
|
|
3
|
+
description: "Transactional email — channel.email templates, {{field}} catalogs, SMTP/Mailpit, Resend, SNDR, and Taqnyat Mail."
|
|
4
|
+
icon: "Mail"
|
|
5
|
+
source: "docs/spec/unified-theory.md"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Email (`channel.email`) is the default Channel medium. Declare a binder with a From address,
|
|
9
|
+
register templates, put bodies in the catalog, and send with `fx.send`.
|
|
10
|
+
|
|
11
|
+
For developers who need local catchers and production HTTP MTAs — same `fx.send` path, swap the
|
|
12
|
+
driver.
|
|
13
|
+
|
|
14
|
+
<Callout title="The one rule">
|
|
15
|
+
Use `channel.email({ from }).template(name, { schema, locales })` — never
|
|
16
|
+
`channel.email("name", { subject, body })`. Subject and body live in the catalog.
|
|
17
|
+
</Callout>
|
|
18
|
+
|
|
19
|
+
## Smallest Example
|
|
20
|
+
|
|
21
|
+
<Steps>
|
|
22
|
+
|
|
23
|
+
<Step>
|
|
24
|
+
### Declare binder + template
|
|
25
|
+
|
|
26
|
+
```typescript title="src/core/channel.ts"
|
|
27
|
+
import { channel } from "okengine";
|
|
28
|
+
import { z } from "zod";
|
|
29
|
+
|
|
30
|
+
const mail = channel.email({ from: "App <noreply@example.com>" });
|
|
31
|
+
|
|
32
|
+
export const passwordReset = mail.template("auth.resetPassword", {
|
|
33
|
+
description: "Password reset link",
|
|
34
|
+
locales: ["en"],
|
|
35
|
+
schema: z.object({ resetLink: z.string().url() }),
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
</Step>
|
|
40
|
+
|
|
41
|
+
<Step>
|
|
42
|
+
### Catalog + send
|
|
43
|
+
|
|
44
|
+
```typescript title="src/app.ts"
|
|
45
|
+
import { oke } from "okengine";
|
|
46
|
+
|
|
47
|
+
oke({
|
|
48
|
+
name: "app",
|
|
49
|
+
channel: {
|
|
50
|
+
catalog: {
|
|
51
|
+
"auth.resetPassword": {
|
|
52
|
+
en: {
|
|
53
|
+
subject: "Reset your password",
|
|
54
|
+
text: "Open {{resetLink}} to choose a new password.",
|
|
55
|
+
html: '<p><a href="{{resetLink}}">Reset your password</a></p>',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
```typescript title="src/flows/auth/reset.ts"
|
|
64
|
+
import { on, flow, http } from "okengine";
|
|
65
|
+
import { z } from "zod";
|
|
66
|
+
import { passwordReset } from "@/core/channel";
|
|
67
|
+
|
|
68
|
+
export const reset = on(
|
|
69
|
+
http.post().public(),
|
|
70
|
+
flow({
|
|
71
|
+
in: z.object({ email: z.string().email() }),
|
|
72
|
+
do: async ({ email }, fx) => {
|
|
73
|
+
await fx.send(passwordReset, {
|
|
74
|
+
to: email,
|
|
75
|
+
data: { resetLink: `https://example.com/reset?t=${fx.id()}` },
|
|
76
|
+
});
|
|
77
|
+
return { ok: true };
|
|
78
|
+
},
|
|
79
|
+
}),
|
|
80
|
+
);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
</Step>
|
|
84
|
+
|
|
85
|
+
<Step>
|
|
86
|
+
### Inspect locally
|
|
87
|
+
|
|
88
|
+
With Mailpit (`images.channel.email` + `SMTP_URL`), open `MAILPIT_UI_URL`. Manifest lists
|
|
89
|
+
`sends: ["auth.resetPassword"]` on the Flow.
|
|
90
|
+
|
|
91
|
+
</Step>
|
|
92
|
+
|
|
93
|
+
</Steps>
|
|
94
|
+
|
|
95
|
+
## Progressive Patterns
|
|
96
|
+
|
|
97
|
+
<Tabs items={["Minimal", "Catalog", "Failover", "Plugin catalog"]}>
|
|
98
|
+
|
|
99
|
+
<Tab value="Minimal">
|
|
100
|
+
|
|
101
|
+
No catalog — runtime uses `subject: templateName` and `text: JSON.stringify(data)`:
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
await fx.send(passwordReset, {
|
|
105
|
+
to: "alice@example.com",
|
|
106
|
+
data: { resetLink: "https://example.com/r/1" },
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
</Tab>
|
|
111
|
+
|
|
112
|
+
<Tab value="Catalog">
|
|
113
|
+
|
|
114
|
+
Per-locale `subject` / `text` / `html` with `{{field}}` interpolation from `data`:
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
catalog: {
|
|
118
|
+
"auth.resetPassword": {
|
|
119
|
+
en: { subject: "Reset", text: "{{resetLink}}", html: "<a href=\"{{resetLink}}\">Reset</a>" },
|
|
120
|
+
ar: { subject: "إعادة التعيين", text: "{{resetLink}}" },
|
|
121
|
+
},
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
</Tab>
|
|
126
|
+
|
|
127
|
+
<Tab value="Failover">
|
|
128
|
+
|
|
129
|
+
Pin multiple email drivers in `oke({ channel: { drivers } })` or rely on the boot chain, then
|
|
130
|
+
order them per send:
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
await fx.send(passwordReset, {
|
|
134
|
+
to: "alice@example.com",
|
|
135
|
+
data: { resetLink: "…" },
|
|
136
|
+
via: ["smtp", "resend"],
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Receipt status `fallback` means an earlier attempt failed and a later one succeeded.
|
|
141
|
+
|
|
142
|
+
</Tab>
|
|
143
|
+
|
|
144
|
+
<Tab value="Plugin catalog">
|
|
145
|
+
|
|
146
|
+
Official plugins contribute catalogs with `.channelCatalog(…)` (e.g. OTP, magic link). App
|
|
147
|
+
`channel.catalog` merges with plugin contributions at boot.
|
|
148
|
+
|
|
149
|
+
</Tab>
|
|
150
|
+
|
|
151
|
+
</Tabs>
|
|
152
|
+
|
|
153
|
+
## Options Reference
|
|
154
|
+
|
|
155
|
+
### `channel.email(options?)`
|
|
156
|
+
|
|
157
|
+
| Option | Type | Meaning |
|
|
158
|
+
| -------- | -------- | --------------------- |
|
|
159
|
+
| `from` | `string` | Default From / sender |
|
|
160
|
+
| `sender` | `string` | Alias for `from` |
|
|
161
|
+
|
|
162
|
+
### `.template(name, options?)`
|
|
163
|
+
|
|
164
|
+
| Option | Type | Meaning |
|
|
165
|
+
| ------------- | ---------- | --------------------------- |
|
|
166
|
+
| `description` | `string` | Console label |
|
|
167
|
+
| `locales` | `string[]` | Declared locales |
|
|
168
|
+
| `schema` | Schema | Payload contract for `data` |
|
|
169
|
+
|
|
170
|
+
Default From when neither binder nor template sets one: `"oke@localhost.test"`.
|
|
171
|
+
|
|
172
|
+
## Drivers
|
|
173
|
+
|
|
174
|
+
| Driver id | Opens at boot | Env / keys |
|
|
175
|
+
| -------------- | ------------- | ----------------------------------------------------------------------------- |
|
|
176
|
+
| `smtp` | yes (default) | `SMTP_URL` or `OKE_CHANNEL_EMAIL_URL`; optional `SMTP_USER` / `SMTP_PASSWORD` |
|
|
177
|
+
| `console` | yes (test) | In-process inbox — no network |
|
|
178
|
+
| `resend` | yes | `RESEND_API_KEY` |
|
|
179
|
+
| `sndr` | yes | `SNDR_API_KEY`; optional `SNDR_BASE_URL` |
|
|
180
|
+
| `taqnyat-mail` | yes | `TAQNYAT_MAIL_TOKEN` + `TAQNYAT_CAMPAIGN` |
|
|
181
|
+
|
|
182
|
+
```typescript title="oke.config.ts"
|
|
183
|
+
drivers: {
|
|
184
|
+
channel: {
|
|
185
|
+
email: { dev: "smtp", test: "console", prod: "resend" },
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
images: {
|
|
189
|
+
channel: { email: "axllent/mailpit:v1.31.1" },
|
|
190
|
+
},
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Consequence:** `dev` and `prod` both speak SMTP protocol by default — Mailpit locally, your
|
|
194
|
+
relay in production. Swap `prod` to `resend` / `sndr` / `taqnyat-mail` when you want HTTP APIs.
|
|
195
|
+
|
|
196
|
+
Unknown id → `oke boot: unknown email channel driver "…"`. Missing SMTP URL →
|
|
197
|
+
`oke boot: smtp driver needs SMTP_URL`.
|
|
198
|
+
|
|
199
|
+
## Locale & consent
|
|
200
|
+
|
|
201
|
+
Locale chain and suppression run before the driver (see [Overview](/docs/elements/channel) and
|
|
202
|
+
[Receipts](/docs/elements/channel/receipts)). Opted-out or prior hard-bounce addresses never
|
|
203
|
+
reach SMTP / Resend.
|
|
204
|
+
|
|
205
|
+
Channel catalogs are **not** ICU — do not use `fx.t` for email bodies ([i18n](/docs/reference/i18n)).
|
|
206
|
+
|
|
207
|
+
## Troubleshooting
|
|
208
|
+
|
|
209
|
+
<Accordions>
|
|
210
|
+
|
|
211
|
+
<Accordion title="oke boot: smtp driver needs SMTP_URL">
|
|
212
|
+
Pin Mailpit / set `SMTP_URL=smtp://…`. URL must use the `smtp://` scheme (`oke boot: SMTP_URL must
|
|
213
|
+
use smtp://`).
|
|
214
|
+
</Accordion>
|
|
215
|
+
|
|
216
|
+
<Accordion title="oke boot: resend channel needs RESEND_API_KEY">
|
|
217
|
+
Email driver is `resend` but the key is missing. Export `RESEND_API_KEY` for that env.
|
|
218
|
+
</Accordion>
|
|
219
|
+
|
|
220
|
+
<Accordion title="oke boot: sndr channel needs SNDR_API_KEY">
|
|
221
|
+
Same pattern for `sndr` — set `SNDR_API_KEY` (and `SNDR_BASE_URL` if non-default).
|
|
222
|
+
</Accordion>
|
|
223
|
+
|
|
224
|
+
<Accordion title="oke boot: taqnyat-mail channel needs TAQNYAT_MAIL_TOKEN / TAQNYAT_CAMPAIGN">
|
|
225
|
+
Taqnyat Email requires both the mail token and a campaign name.
|
|
226
|
+
</Accordion>
|
|
227
|
+
|
|
228
|
+
<Accordion title="Message in Mailpit has JSON body / template name as subject">
|
|
229
|
+
No catalog entry for that template + locale. Add `channel.catalog` (or a plugin catalog) with
|
|
230
|
+
`subject` / `text` / `html`.
|
|
231
|
+
</Accordion>
|
|
232
|
+
|
|
233
|
+
<Accordion title="suppressed/opted-out or prior-bounce — no provider call">
|
|
234
|
+
Consent or hard-bounce suppression blocked the send. Check the receipt ledger; see
|
|
235
|
+
[Receipts](/docs/elements/channel/receipts).
|
|
236
|
+
</Accordion>
|
|
237
|
+
|
|
238
|
+
</Accordions>
|
|
239
|
+
|
|
240
|
+
## Learn more
|
|
241
|
+
|
|
242
|
+
- [Channel overview](/docs/elements/channel) — declare → send → drivers
|
|
243
|
+
- [Mailpit](/docs/recipes/mailpit) — local SMTP catcher
|
|
244
|
+
- [Receipts](/docs/elements/channel/receipts) — delivery ledger
|
|
245
|
+
- [Environment variables](/docs/reference/environment-variables) — email boot binder
|
|
246
|
+
- [OTP plugin](/docs/plugins/otp) — `auth-otp-email` catalog
|
|
247
|
+
|
|
248
|
+
## Next
|
|
249
|
+
|
|
250
|
+
<Cards>
|
|
251
|
+
<Card
|
|
252
|
+
title="SMS"
|
|
253
|
+
description="SMS templates and provider OTP."
|
|
254
|
+
href="/docs/elements/channel/sms"
|
|
255
|
+
/>
|
|
256
|
+
<Card
|
|
257
|
+
title="Receipts"
|
|
258
|
+
description="Ledger, outcomes, and suppression."
|
|
259
|
+
href="/docs/elements/channel/receipts"
|
|
260
|
+
/>
|
|
261
|
+
<Card
|
|
262
|
+
title="Channel Overview"
|
|
263
|
+
description="Physics, fx surface, and driver table."
|
|
264
|
+
href="/docs/elements/channel"
|
|
265
|
+
/>
|
|
266
|
+
</Cards>
|