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
|
@@ -1,436 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "Gate"
|
|
3
|
-
description: "Permission to act — policies, rate limits, and built-in auth on the HTTP trigger, evaluated before any effect runs."
|
|
4
|
-
icon: "ShieldCheck"
|
|
5
|
-
source: "docs/spec/unified-theory.md"
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
Gate answers **"may this happen?"** before it happens: is this a verified member? has this IP
|
|
9
|
-
burned its minute quota? Attach gates to the HTTP trigger — the pipeline checks them before a
|
|
10
|
-
store write, emit, or channel send runs.
|
|
11
|
-
|
|
12
|
-
> **Same Semantics Across Planes:** OKE does not create separate security models for users, operators, and agents. They enter the same execution model through different triggers and planes: users via sessions, operators via Console policies, and agents via `mcp.tool()` + OAuth 2.1 AS.
|
|
13
|
-
|
|
14
|
-
<Callout title="The one rule">
|
|
15
|
-
Every HTTP trigger declares posture: attach a real gate, or attach `.public()`. Omitting both
|
|
16
|
-
fails boot. Denial is a typed error value — never a thrown exception mid-`do`.
|
|
17
|
-
</Callout>
|
|
18
|
-
|
|
19
|
-
## Quick start
|
|
20
|
-
|
|
21
|
-
<Steps>
|
|
22
|
-
|
|
23
|
-
<Step>
|
|
24
|
-
### Declare policies
|
|
25
|
-
|
|
26
|
-
Policies are named predicates; rate limits are declarative budgets. Import the module before
|
|
27
|
-
`oke()` — they auto-register. `oke({ gate: { policies } })` is still valid and additive.
|
|
28
|
-
|
|
29
|
-
```typescript title="src/gates.ts"
|
|
30
|
-
import { gate } from "okengine";
|
|
31
|
-
|
|
32
|
-
export const member = gate.policy("member", ({ auth }) => !!auth.verified);
|
|
33
|
-
|
|
34
|
-
export const canBook = gate.scope("booking:create");
|
|
35
|
-
|
|
36
|
-
export const fair = gate.rate({
|
|
37
|
-
max: 60,
|
|
38
|
-
per: "1m",
|
|
39
|
-
keyBy: "ip",
|
|
40
|
-
});
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
`gate.scope(name)` is sugar for
|
|
44
|
-
`gate.policy(name, ({ auth }) => auth.scopes.has(name))` — one string is both the policy id and
|
|
45
|
-
the scope checked.
|
|
46
|
-
|
|
47
|
-
```typescript title="src/app.ts"
|
|
48
|
-
import "./gates";
|
|
49
|
-
import { oke } from "okengine";
|
|
50
|
-
|
|
51
|
-
export const app = oke({ name: "shop", env: "dev" });
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
</Step>
|
|
55
|
-
|
|
56
|
-
<Step>
|
|
57
|
-
### Attach them to triggers
|
|
58
|
-
|
|
59
|
-
`.gate(...)` composes left to right — first denial wins. Public routes must say so explicitly. Path and name can come from the file tree — see [Project structure](/docs/get-started/project-structure).
|
|
60
|
-
|
|
61
|
-
```typescript title="src/flows/links/shorten.ts"
|
|
62
|
-
import { on, flow, http, gate } from "okengine";
|
|
63
|
-
import { member, canBook, fair } from "../../gates";
|
|
64
|
-
|
|
65
|
-
export const health = on(
|
|
66
|
-
http.get("/health").public(),
|
|
67
|
-
flow("health.check", {
|
|
68
|
-
do: () => ({ ok: true }),
|
|
69
|
-
}),
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
export const write = gate.all(member, canBook, fair);
|
|
73
|
-
|
|
74
|
-
export const shorten = on(
|
|
75
|
-
http.post("/links").gate(write),
|
|
76
|
-
flow("links.shorten", {
|
|
77
|
-
in: NewLink,
|
|
78
|
-
out: LinkCode,
|
|
79
|
-
errors: { Taken },
|
|
80
|
-
do: async ({ url, code }, fx) => {
|
|
81
|
-
/* runs only if every gate passed */
|
|
82
|
-
},
|
|
83
|
-
}),
|
|
84
|
-
);
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
A single gate stays `.gate(member)`. Reuse two or more with `gate.all` — `.gate(write)`
|
|
88
|
-
flattens. `http.resource(path, ops).gate(...)` stamps every verb. Public routes use
|
|
89
|
-
`.public()` — do **not** put `gate.public` in `gate.policies`.
|
|
90
|
-
|
|
91
|
-
</Step>
|
|
92
|
-
|
|
93
|
-
<Step>
|
|
94
|
-
### See typed denials
|
|
95
|
-
|
|
96
|
-
A denied request never reaches `do`. It returns one of three typed failures:
|
|
97
|
-
|
|
98
|
-
| Gate result | Typed failure |
|
|
99
|
-
| -------------------------------- | ------------------------------------- |
|
|
100
|
-
| Policy denied, not authenticated | `Unauthorized` |
|
|
101
|
-
| Policy denied, authenticated | `Forbidden` (with gate name + reason) |
|
|
102
|
-
| Rate limit exceeded | `RateLimited` (with `retryAfterMs`) |
|
|
103
|
-
|
|
104
|
-
</Step>
|
|
105
|
-
|
|
106
|
-
</Steps>
|
|
107
|
-
|
|
108
|
-
## First denial wins
|
|
109
|
-
|
|
110
|
-
<GatePipeline />
|
|
111
|
-
|
|
112
|
-
`.gate(member, canBook, fair)` and `.gate(write)` (from `gate.all`) evaluate left
|
|
113
|
-
to right — first denial wins (`Unauthorized` · `Forbidden` · `RateLimited`); later
|
|
114
|
-
gates are skipped. `do` runs only when every gate passed.
|
|
115
|
-
|
|
116
|
-
## `oke({ gate })` bag
|
|
117
|
-
|
|
118
|
-
| Option | Type | Default | Meaning |
|
|
119
|
-
| --------------- | ----------------------- | -------- | --------------------------------------------------------------- |
|
|
120
|
-
| `policies` | `GateDecl[]` | `[]` | Policy / rate decls — `gate.all` handles flatten to members |
|
|
121
|
-
| `auth` | `GateAuthOptions` | — | Builtin hybrid sessions + `/auth/*` Flows (see below) |
|
|
122
|
-
| `rateLimit` | `{ enabled?: boolean }` | see note | When auth is on, defaults `true` — stricter rates on auth paths |
|
|
123
|
-
| `unguardedHttp` | `"deny"` \| `"allow"` | `"deny"` | `"allow"` skips posture audit **only** when `env === "test"` |
|
|
124
|
-
|
|
125
|
-
## Declarations
|
|
126
|
-
|
|
127
|
-
| Declaration | Question it answers | Evaluated against |
|
|
128
|
-
| ------------------------------------- | ------------------------------------------- | ---------------------------------- |
|
|
129
|
-
| `gate.policy(name, check \| options)` | Is this principal allowed? (ABAC) | auth / operator / request metadata |
|
|
130
|
-
| `gate.scope(name)` | Does `auth.scopes` contain this exact name? | `auth.scopes` |
|
|
131
|
-
| `gate.public` / `.public()` | Intentionally unauthenticated surface | always allows |
|
|
132
|
-
| `gate.rate(options)` | Is there budget left for this subject? | an atomic counter on the kv driver |
|
|
133
|
-
| `gate.all(...members)` | Reuse this chain on many triggers | flattens; each member is evaluated |
|
|
134
|
-
|
|
135
|
-
Pass `{ check, description }` on `gate.policy` when you want a human title in the Console (falls
|
|
136
|
-
back to the policy name). The name `"public"` is reserved — mark the trigger with
|
|
137
|
-
`.public()`, not `gate.policy("public", …)`.
|
|
138
|
-
|
|
139
|
-
`gate.all()` with no members throws. Nested `all` handles flatten.
|
|
140
|
-
Members auto-register when declared; `oke({ gate: { policies: [write] } })` is additive.
|
|
141
|
-
|
|
142
|
-
### Policy context
|
|
143
|
-
|
|
144
|
-
| Field | Contents |
|
|
145
|
-
| ---------- | -------------------------------------------------------- |
|
|
146
|
-
| `auth` | User principal: `userId`, `scopes` (a `Set`), `verified` |
|
|
147
|
-
| `operator` | Operator principal (Console plane): `id` |
|
|
148
|
-
| `meta` | Request metadata for keying: `ip`, `userId`, … |
|
|
149
|
-
|
|
150
|
-
A policy name containing `:` is also a `Module:Action` permission for Console role reviews.
|
|
151
|
-
Fine-grained authorization (`gate.scope`, roles) stays opt-in — attach it only where you need it.
|
|
152
|
-
|
|
153
|
-
### Rate options
|
|
154
|
-
|
|
155
|
-
| Option | Type | Default | Meaning |
|
|
156
|
-
| ------------- | ------------ | -------------------------- | -------------------------------------------------------- |
|
|
157
|
-
| `max` | number | — (**required**) | Takes allowed within `per` |
|
|
158
|
-
| `per` | string | — (**required**) | Window / refill period (`"1m"`, `"60s"`, …) |
|
|
159
|
-
| `keyBy` | string | — | Subject dimension (`"ip"`, `"user"`, …) |
|
|
160
|
-
| `strategy` | RateStrategy | `"sliding-window-counter"` | Algorithm (below) |
|
|
161
|
-
| `overridable` | boolean | `false` | Catalog flag in Console (rate edit UI not shipped) |
|
|
162
|
-
| `description` | string | — | Human title in the Console (falls back to the rate name) |
|
|
163
|
-
|
|
164
|
-
| Strategy | Behavior |
|
|
165
|
-
| ------------------------ | ------------------------------------------------------ |
|
|
166
|
-
| `sliding-window-counter` | Near-exact, two keys, no boundary bursts — the default |
|
|
167
|
-
| `fixed-window` | Cheapest; allows bursts at window boundaries |
|
|
168
|
-
| `sliding-log` | Exact; stores one timestamp per take |
|
|
169
|
-
| `token-bucket` | Steady refill; permits saved-up bursts |
|
|
170
|
-
| `leaky-bucket` | Smooths output to a constant rate |
|
|
171
|
-
|
|
172
|
-
All five run as atomic Lua on the kv driver — correct under concurrency, identical on the memory
|
|
173
|
-
driver in tests. Boot opens a dedicated `oke:gates` namespace on **`drivers.store.kv`**
|
|
174
|
-
(`memory` in test · `redis` in `dev`/`prod`) so multi-instance rate limits share counters.
|
|
175
|
-
|
|
176
|
-
## Auth posture at boot
|
|
177
|
-
|
|
178
|
-
Every HTTP trigger must carry a gate or `.public()`. Omitting both fails boot with
|
|
179
|
-
`GateBootError` — message starts with `gate boot failed —` and lists every gap.
|
|
180
|
-
|
|
181
|
-
```typescript
|
|
182
|
-
on(http.get("/health").public(), flow("health.check", {/* … */}));
|
|
183
|
-
on(http.post("/bookings").gate(member, canBook), flow("bookings.create", {/* … */}));
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
**Consequence:** first `fetch` / `execute` auto-boots (`autoBoot` defaults to `true`).
|
|
187
|
-
`oke({ autoBoot: false })` is a unit-test escape hatch only. A rate-only chain is declared
|
|
188
|
-
posture but does **not** authenticate.
|
|
189
|
-
|
|
190
|
-
`gate: { unguardedHttp: "allow" }` skips the audit **only** when `env === "test"`.
|
|
191
|
-
In `dev` / `prod` migrate with per-trigger `.public()`.
|
|
192
|
-
|
|
193
|
-
## Built-in auth (`gate.auth`)
|
|
194
|
-
|
|
195
|
-
Enable hybrid sessions (Bearer access + revocable refresh). Auth HTTP surfaces are ordinary
|
|
196
|
-
Bindings under `/auth` — same posture audit and pipeline as your app Flows:
|
|
197
|
-
|
|
198
|
-
```typescript title="src/app.ts"
|
|
199
|
-
import { oke } from "okengine";
|
|
200
|
-
import { member, canBook } from "./gates";
|
|
201
|
-
|
|
202
|
-
export const app = oke({
|
|
203
|
-
name: "shop",
|
|
204
|
-
env: "dev",
|
|
205
|
-
gate: {
|
|
206
|
-
auth: {
|
|
207
|
-
emailAndPassword: { enabled: true },
|
|
208
|
-
session: { freshAgeMs: 24 * 60 * 60_000 },
|
|
209
|
-
},
|
|
210
|
-
policies: [member, canBook],
|
|
211
|
-
},
|
|
212
|
-
});
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
| Surface | When |
|
|
216
|
-
| -------------------------- | -------------------------------------- |
|
|
217
|
-
| `POST /auth/sign-up/email` | `emailAndPassword.enabled` |
|
|
218
|
-
| `POST /auth/sign-in/email` | `emailAndPassword.enabled` |
|
|
219
|
-
| `POST /auth/refresh` | when `gate.auth` is set |
|
|
220
|
-
| `POST /auth/revoke` | when `gate.auth` is set |
|
|
221
|
-
| `GET /auth/me` | Bearer session (`auth.session` policy) |
|
|
222
|
-
|
|
223
|
-
| Auth option | Default | Meaning |
|
|
224
|
-
| ------------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------- |
|
|
225
|
-
| `secret` | minted\* | HMAC for access tokens (\*`prod` requires you set it) |
|
|
226
|
-
| `basePath` | `"/auth"` | HTTP prefix for auth Flows |
|
|
227
|
-
| `http` | `true` | `false` = secret/tables only (no `/auth/*` Bindings) |
|
|
228
|
-
| `audience` | `oke-app` | Audience stamped on access tokens |
|
|
229
|
-
| `emailAndPassword.enabled` | `false` | Sign-up / sign-in email Flows |
|
|
230
|
-
| `emailAndPassword.requireEmailVerification` | `false` | Block sign-in until email is verified |
|
|
231
|
-
| `passwordPolicy` | secure\* | `\*` minLength 8, letter + number + upper + lower + special (`requireSpecial`); sign-up → `AuthFailed` / `password_policy` |
|
|
232
|
-
| `breachCheck` | unset | `(password) => Promise<boolean>` — `true` rejects as `password_breached` |
|
|
233
|
-
| `session.freshAgeMs` | 24h | Window for step-up `auth.fresh` policy |
|
|
234
|
-
| `session.accessTtlMs` / `refreshTtlMs` | 14m / 30d | Access / refresh lifetimes |
|
|
235
|
-
| `session.idleTtlMs` | unset | Opt-in: reject refresh when idle too long |
|
|
236
|
-
| `session.absoluteTtlMs` | unset | Opt-in: hard cap from session creation |
|
|
237
|
-
| `session.singleSessionPerUser` | `false` | Opt-in: issuing a session revokes other families for that user |
|
|
238
|
-
| `cookies.enabled` | `false` | Opt-in HttpOnly cookie mirror (Bearer stays default) |
|
|
239
|
-
| `secondaryStorage.enabled` | `false` | Hot auth data in `store.kv` when configured |
|
|
240
|
-
| `tenant` | unset | Opt-in identity dimension — `true` or `{ required, source, header, resolve, authoritative }` |
|
|
241
|
-
| `user` / `session` / … | defaults | `modelName` / `fields` / `additionalFields` |
|
|
242
|
-
|
|
243
|
-
HIBP via `createHibpBreachCheck` from `okengine/auth` (k-anonymity range API; requires
|
|
244
|
-
`userAgent`; `onError` defaults to `"reject"` — fail closed while the check is enabled):
|
|
245
|
-
|
|
246
|
-
```typescript
|
|
247
|
-
import { createHibpBreachCheck } from "okengine/auth";
|
|
248
|
-
|
|
249
|
-
gate: {
|
|
250
|
-
auth: {
|
|
251
|
-
emailAndPassword: { enabled: true },
|
|
252
|
-
breachCheck: createHibpBreachCheck({ userAgent: "shop/1.0" }),
|
|
253
|
-
},
|
|
254
|
-
}
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
Customize tables, then `oke schema generate` (`.oke/schema/oke.ts`; `--check` in CI). Extra
|
|
258
|
-
sign-in shapes: [Plugins](/docs/plugins). Call auth from
|
|
259
|
-
[createClient](/docs/reference/client) — helpers in `okengine/client/auth`.
|
|
260
|
-
|
|
261
|
-
## Tenants (identity dimension)
|
|
262
|
-
|
|
263
|
-
`gate.auth.tenant: true` (or an options bag) is **not** a second authorization system and not an
|
|
264
|
-
organizations product. Tenant is a dimension of identity, like `fx.auth` / `fx.operator`.
|
|
265
|
-
|
|
266
|
-
```typescript
|
|
267
|
-
export const app = oke({
|
|
268
|
-
name: "shop",
|
|
269
|
-
gate: { auth: { tenant: true } },
|
|
270
|
-
});
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
| Option | Default | Meaning |
|
|
274
|
-
| --------------- | -------------- | ------------------------------------------------------------------------------------------------ |
|
|
275
|
-
| `required` | `false` | Pure B2B: authenticated user-plane requests without a tenant are `Forbidden` / `tenant_required` |
|
|
276
|
-
| `source` | `"claim"` | `"claim"` · `"header"` · `"subdomain"` · `"resolve"` |
|
|
277
|
-
| `header` | `x-oke-tenant` | Header name when `source` is `"header"` |
|
|
278
|
-
| `resolve` | unset | Callback that returns an id; membership is still checked unless `authoritative` |
|
|
279
|
-
| `authoritative` | `false` | Trust `resolve` without a membership query |
|
|
280
|
-
|
|
281
|
-
Three tiers, fail-safe:
|
|
282
|
-
|
|
283
|
-
1. **Claim** — signed JWT `tid` or API-key `tenantId`. The id is trusted; no membership query.
|
|
284
|
-
2. **Header / subdomain** — never trust a client-supplied id without membership.
|
|
285
|
-
3. **`resolve`** — still membership-checked unless `authoritative: true`.
|
|
286
|
-
|
|
287
|
-
`required: false` (default) is B2C+B2B: `fx.tenant.id` may be `null`. Internal / cron / `fx.call`
|
|
288
|
-
have no HTTP request — header and subdomain sources keep the stamped claim.
|
|
289
|
-
|
|
290
|
-
`fx.auth.switchTenant(id)` issues a **new** access+refresh pair and a **new** family (so tab A
|
|
291
|
-
rotation cannot reuse-detect tab B). It never Set-Cookies.
|
|
292
|
-
|
|
293
|
-
Refresh copies that row's `tid`; tenant-role scopes never melt into the JWT.
|
|
294
|
-
|
|
295
|
-
`fx.auth.listTenants` / `createTenant` / `addMember` / `upsertTenantRole` are session-only
|
|
296
|
-
(`auth:tenants`). Tenant roles may grant application scopes only — `console:*` fails like an
|
|
297
|
-
unknown name.
|
|
298
|
-
|
|
299
|
-
Live `fx.auth.scopes` unions those grants only when `fx.tenant.id` is set, the flow is
|
|
300
|
-
tenant-scoped (default on; `flow({ tenantScoped: false })` opts out), and user-plane.
|
|
301
|
-
`gate.scope()` still reads `auth.scopes.has(name)`.
|
|
302
|
-
|
|
303
|
-
SQL stamps `oke.tenant()` when tenancy is on — [Store](/docs/elements/store) and
|
|
304
|
-
built-in [Vault](/docs/elements/vault#tenant-isolation-built-in-store) ciphertext.
|
|
305
|
-
|
|
306
|
-
## API keys
|
|
307
|
-
|
|
308
|
-
A key is the **issuer with fewer gates** — not a second permission system.
|
|
309
|
-
Bearer secrets authenticate as the creator; `fx.auth.scopes` shrink to the key.
|
|
310
|
-
|
|
311
|
-
| Field | Session | API key |
|
|
312
|
-
| ----------------------------------- | -------------- | ----------------------- |
|
|
313
|
-
| `fx.auth.userId` / `fx.operator.id` | subject | creator (`creatorId`) |
|
|
314
|
-
| `fx.auth.scopes` | session scopes | key scopes (attenuated) |
|
|
315
|
-
| `fx.auth.apiKeyId` | `null` | key id |
|
|
316
|
-
| WideEvent `principal` | subject | issuer |
|
|
317
|
-
| `dimensions.api_key` | absent | key id |
|
|
318
|
-
|
|
319
|
-
`gate.auth` always creates a shared key store (HMAC-SHA-256 with `gate.auth.secret`).
|
|
320
|
-
Do not pass `apiKeyStore` unless you are injecting a test Map.
|
|
321
|
-
|
|
322
|
-
<Callout title="Keys live on the app database">
|
|
323
|
-
With `store.sql()`, boot hydrates public `oke_api_keys` on that connection (`DATABASE_URL`) and
|
|
324
|
-
write-through persists create / rotate / revoke. Console **Access** attaches this host store — it
|
|
325
|
-
does not keep a second key database.
|
|
326
|
-
</Callout>
|
|
327
|
-
|
|
328
|
-
Session Flows manage keys via [fx](/docs/reference/fx) (`createApiKey`, `listApiKeys`,
|
|
329
|
-
`revokeApiKey`, `rotateApiKey`, `updateApiKey`). A key-authenticated caller cannot.
|
|
330
|
-
|
|
331
|
-
Declare `effects.reads: ["auth:api-keys"]` / `effects.writes: ["auth:api-keys"]` — never
|
|
332
|
-
`sql:oke_api_keys`. Console **Access** (`:6533` → `/access`) mints operator keys as the
|
|
333
|
-
operator, and user-plane keys only as a picked issuer (`creatorUserId`).
|
|
334
|
-
|
|
335
|
-
Verify rejects expired, revoked, allowlist-miss, and over-rate secrets with `401`
|
|
336
|
-
and no `api_key` dimension.
|
|
337
|
-
|
|
338
|
-
## Identity and decisions
|
|
339
|
-
|
|
340
|
-
Gates decide on principals that already exist. `gate.auth` issues hybrid sessions onto
|
|
341
|
-
`fx.auth` (Console: `fx.operator`). Audit across `fx.call` uses read-only `fx.principal`
|
|
342
|
-
(see [fx](/docs/reference/fx)).
|
|
343
|
-
|
|
344
|
-
Pass **and** deny land on the run's `gates` dimension. Console (`:6533` → `/flows`) shows the
|
|
345
|
-
chain on the flow contract. Rate `overridable` is a catalog flag only — Clock schedules are what the Console can
|
|
346
|
-
edit live today.
|
|
347
|
-
|
|
348
|
-
<Callout title="RLS reads the stamped principal">
|
|
349
|
-
After HTTP Gate passes, user-plane `fx.store` stamps `oke.gate()`, `oke.user()`, and
|
|
350
|
-
`oke.has_scope()`. With `gate.auth.tenant` on, a fourth GUC `oke.tenant()` is set. Rate, cron,
|
|
351
|
-
CDC, and signal stay unstamped. Helpers: [Store](/docs/elements/store).
|
|
352
|
-
</Callout>
|
|
353
|
-
|
|
354
|
-
## Troubleshooting
|
|
355
|
-
|
|
356
|
-
<Accordions>
|
|
357
|
-
<Accordion title="Boot: gate boot failed — N HTTP trigger(s) missing auth posture">
|
|
358
|
-
|
|
359
|
-
Empty `.gate(...)` chain. Attach a policy/rate gate, or `.public()`. First `fetch`
|
|
360
|
-
auto-boots — do not rely on `gate.unguardedHttp: "allow"` outside `env: "test"`.
|
|
361
|
-
|
|
362
|
-
</Accordion>
|
|
363
|
-
<Accordion title="Can a policy read the request body?">
|
|
364
|
-
|
|
365
|
-
No. Gates run before the flow, so they see only `auth`, `operator`, and `meta`. Body-dependent
|
|
366
|
-
decisions belong inside `do` as typed `errors`.
|
|
367
|
-
|
|
368
|
-
</Accordion>
|
|
369
|
-
<Accordion title="Logged-in users still get Forbidden">
|
|
370
|
-
|
|
371
|
-
`Forbidden` means authenticated but a policy said no. Check `verified` or a missing scope —
|
|
372
|
-
the failure includes the gate name and reason.
|
|
373
|
-
|
|
374
|
-
</Accordion>
|
|
375
|
-
<Accordion title="Forbidden tenant_required / not_member">
|
|
376
|
-
|
|
377
|
-
`required: true` and no resolved tenant → `tenant_required`. Header/subdomain id that is not a
|
|
378
|
-
membership → `not_member`. Call `fx.auth.switchTenant(id)` or send a signed `tid`.
|
|
379
|
-
|
|
380
|
-
</Accordion>
|
|
381
|
-
<Accordion title="Prod boot: gate.auth: secret is required">
|
|
382
|
-
|
|
383
|
-
Set `gate.auth.secret` (or provide it before boot). Non-prod may mint a development secret.
|
|
384
|
-
|
|
385
|
-
</Accordion>
|
|
386
|
-
<Accordion title="Sign-up returns AuthFailed password_policy">
|
|
387
|
-
|
|
388
|
-
Default policy: length ≥ 8 plus upper, lower, number, and special (`"123"` is rejected).
|
|
389
|
-
Tighten via `gate.auth.passwordPolicy`. Console claim uses min length 12 with the same
|
|
390
|
-
character classes.
|
|
391
|
-
|
|
392
|
-
</Accordion>
|
|
393
|
-
<Accordion title="Which keyBy should I use?">
|
|
394
|
-
|
|
395
|
-
`"ip"` for public surfaces (sign-up, password reset), `"user"` for authenticated quotas.
|
|
396
|
-
Keying an authenticated endpoint by IP punishes shared NAT.
|
|
397
|
-
|
|
398
|
-
</Accordion>
|
|
399
|
-
<Accordion title="API key Bearer returns 401">
|
|
400
|
-
|
|
401
|
-
Expired, revoked, allowlist miss, or over `rateLimit`. `ipAllowlist` uses the
|
|
402
|
-
same X-Forwarded-For hop as `ip-allowlist` (IP or hostname; lookup failure is closed).
|
|
403
|
-
Rotate if the secret was shown once and then lost.
|
|
404
|
-
|
|
405
|
-
</Accordion>
|
|
406
|
-
<Accordion title="Keys vanish after an app restart">
|
|
407
|
-
|
|
408
|
-
No SQL store, or a new `gate.auth.secret`. Declare `store.sql()`, keep
|
|
409
|
-
`DATABASE_URL` (or the same PGlite datadir) and the auth secret stable.
|
|
410
|
-
Console does not persist keys in `oke_console`.
|
|
411
|
-
|
|
412
|
-
</Accordion>
|
|
413
|
-
<Accordion title="Key can call a route the issuer cannot">
|
|
414
|
-
|
|
415
|
-
That is a bug in the mint. `createApiKey` / `fx.auth.createApiKey` re-run
|
|
416
|
-
`assertAttenuated` against the issuer's live scopes. Custom `gate.policy`
|
|
417
|
-
predicates that ignore scopes still see `verified: true`.
|
|
418
|
-
|
|
419
|
-
</Accordion>
|
|
420
|
-
</Accordions>
|
|
421
|
-
|
|
422
|
-
## Learn more
|
|
423
|
-
|
|
424
|
-
- [Project structure](/docs/get-started/project-structure) — `http.get()` and `flow({…})` fill path and name from the file tree
|
|
425
|
-
- [Flow](/docs/elements/flow) — the trigger pipeline gates plug into
|
|
426
|
-
- [fx](/docs/reference/fx) — `fx.auth`, `fx.operator`, `fx.principal`, `fx.tenant`
|
|
427
|
-
- [Client](/docs/reference/client) — Bearer `createClient` + `okengine/client/auth`
|
|
428
|
-
- [Plugins](/docs/plugins) — username, magic link, OTP, TOTP, passkeys
|
|
429
|
-
- [Vault](/docs/elements/vault) — credentials your policies protect
|
|
430
|
-
|
|
431
|
-
## Next
|
|
432
|
-
|
|
433
|
-
<Cards>
|
|
434
|
-
<Card title="Vault" description="Continue to Vault." href="/docs/elements/vault" />
|
|
435
|
-
<Card title="Plugins" description="Sign-in method plugins under /auth." href="/docs/plugins" />
|
|
436
|
-
</Cards>
|