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,328 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Testing
|
|
3
|
-
description: Write deterministic tests for your Flows with createTestApp — freeze the clock, mock AI, drain signals, and prove side effects.
|
|
4
|
-
icon: FlaskConical
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
`createTestApp` boots the **same app** you deploy, but with memory drivers and a
|
|
8
|
-
frozen clock. You drive it through `t.api`, `t.auth`, `t.signals`, `t.clock`,
|
|
9
|
-
and `t.channels` — every assertion is deterministic.
|
|
10
|
-
|
|
11
|
-
<Callout title="The one rule">
|
|
12
|
-
Boot the same `app` your server boots. Assert only through the harness surfaces (`t.api`,
|
|
13
|
-
`t.auth`, `t.signals`, `t.clock`, `t.channels`, `t.ai`, `t.effects`) — never reach into internal
|
|
14
|
-
runtimes.
|
|
15
|
-
</Callout>
|
|
16
|
-
|
|
17
|
-
## Import
|
|
18
|
-
|
|
19
|
-
The harness ships as a separate subpath so production bundles stay small:
|
|
20
|
-
|
|
21
|
-
```typescript title="tests/orders.test.ts"
|
|
22
|
-
import { describe, expect, test } from "bun:test";
|
|
23
|
-
import { createTestApp } from "okengine/testing"; // or "okengine/test"
|
|
24
|
-
import { app } from "../src/app";
|
|
25
|
-
|
|
26
|
-
test("orders flow", async () => {
|
|
27
|
-
const t = await createTestApp(app);
|
|
28
|
-
// ...
|
|
29
|
-
await t.close();
|
|
30
|
-
});
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Both `okengine/testing` and `okengine/test` are aliases. Use `okengine/testing`
|
|
34
|
-
(→ `dist/testing.js`) for published packages and hoisted monorepos; `okengine/test`
|
|
35
|
-
is the source-only path older starters use.
|
|
36
|
-
|
|
37
|
-
## Quick start
|
|
38
|
-
|
|
39
|
-
<Steps>
|
|
40
|
-
|
|
41
|
-
<Step>
|
|
42
|
-
### Adopt your Flows
|
|
43
|
-
|
|
44
|
-
Every behavior on the app is reachable. No separate test database or server.
|
|
45
|
-
|
|
46
|
-
```typescript title="src/flows/orders/index.ts"
|
|
47
|
-
import { on, flow, http } from "okengine";
|
|
48
|
-
import { z } from "zod";
|
|
49
|
-
|
|
50
|
-
export const create = on(
|
|
51
|
-
http.post("/orders").gate(member),
|
|
52
|
-
flow("orders.create", {
|
|
53
|
-
in: z.object({ sku: z.string(), qty: z.number() }),
|
|
54
|
-
out: z.object({ id: z.string() }),
|
|
55
|
-
do: async (input, fx) => {
|
|
56
|
-
const id = fx.id();
|
|
57
|
-
await fx.emit(orderPlaced, { orderId: id, ...input });
|
|
58
|
-
return { id };
|
|
59
|
-
},
|
|
60
|
-
}),
|
|
61
|
-
);
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
</Step>
|
|
65
|
-
|
|
66
|
-
<Step>
|
|
67
|
-
### Boot the harness
|
|
68
|
-
|
|
69
|
-
```typescript title="tests/orders.test.ts"
|
|
70
|
-
const t = await createTestApp(app, { gates: [member] });
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
</Step>
|
|
74
|
-
|
|
75
|
-
<Step>
|
|
76
|
-
### Login and call
|
|
77
|
-
|
|
78
|
-
```typescript
|
|
79
|
-
const u = await t.auth.loginAs({ scopes: ["order:create"] });
|
|
80
|
-
const { data, error } = await t.api.orders.create({ sku: "COFFEE", qty: 2 }, { as: u });
|
|
81
|
-
expect(error).toBeNull();
|
|
82
|
-
expect(data).toEqual({ id: expect.any(String) });
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
</Step>
|
|
86
|
-
|
|
87
|
-
<Step>
|
|
88
|
-
### Advance time and drain signals
|
|
89
|
-
|
|
90
|
-
Signal handlers and Clocks are processed deterministically:
|
|
91
|
-
|
|
92
|
-
```typescript
|
|
93
|
-
await t.signals.drain(); // run queued signal work
|
|
94
|
-
await t.clock.advance("2m"); // tick scheduled Clocks forward
|
|
95
|
-
expect(t.channels.sent()).toContainEqual(expect.objectContaining({ template: "order-confirmed" }));
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
</Step>
|
|
99
|
-
|
|
100
|
-
</Steps>
|
|
101
|
-
|
|
102
|
-
## Harness surface
|
|
103
|
-
|
|
104
|
-
| Property | What it does |
|
|
105
|
-
| ------------------------------------------- | -------------------------------------------------------------------------------------- |
|
|
106
|
-
| `t.api.<unit>.<flow>(input, opts?)` | Invoke an adopted Flow directly with a `{ as }` principal and optional `{ tenant }` |
|
|
107
|
-
| `t.auth.loginAs(options)` | Returns a verified `TestUser` with `id`, `scopes`, `verified`, and optional `tenantId` |
|
|
108
|
-
| `t.clock.advance(by)` / `t.clock.now()` | Freeze and move the harness clock (used by durable sleeps and Clocks) |
|
|
109
|
-
| `t.cron.run(name)` | Run a named Clock / `every()` interval now, still leader-elected |
|
|
110
|
-
| `t.signals.drain()` | Drain the signal bus until idle (deterministic queued work) |
|
|
111
|
-
| `t.signals.subscribeLive(signal, handlers)` | Subscribe to a `delivery: "live"` signal's event stream (deterministic) |
|
|
112
|
-
| `t.signals.waitForLive(signal, predicate)` | Resolve once a live event matching `predicate` arrives |
|
|
113
|
-
| `t.channels.sent()` | Receipts / inbox entries sent during the test |
|
|
114
|
-
| `t.ai.mock(prompt, output)` | Register a canned mock response for a Prompt |
|
|
115
|
-
| `t.ai.cost()` | Accumulated AI cost across `fx.ask` calls |
|
|
116
|
-
| `t.effects.of(runId)` | Effect ledger for a recorded run (reads / writes / emits / sends) |
|
|
117
|
-
| `t.runs()` | All wide events recorded during the test |
|
|
118
|
-
| `t.close()` | Close booted element runtimes |
|
|
119
|
-
|
|
120
|
-
## Multi-tenancy & RLS
|
|
121
|
-
|
|
122
|
-
With `gate.auth: { tenant: true }` you can test tenant isolation with real
|
|
123
|
-
row-level security.
|
|
124
|
-
|
|
125
|
-
```typescript title="src/db/documents.ts"
|
|
126
|
-
import { store, field } from "okengine";
|
|
127
|
-
|
|
128
|
-
export const documents = store.schema.table(
|
|
129
|
-
"documents",
|
|
130
|
-
{
|
|
131
|
-
id: field.text().primaryKey(),
|
|
132
|
-
tenant_id: field.text().notNull(),
|
|
133
|
-
title: field.text().notNull(),
|
|
134
|
-
},
|
|
135
|
-
[store.schema.policy.tenant("tenant_id", { for: "all" })],
|
|
136
|
-
);
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
Give each test user a tenant, and drive distinct tenants against the same
|
|
140
|
-
|
|
141
|
-
Flow:
|
|
142
|
-
|
|
143
|
-
```typescript title="tests/tenant.test.ts"
|
|
144
|
-
const t = await createTestApp(app, {
|
|
145
|
-
gates: [member],
|
|
146
|
-
boot: { config: { drivers: { store: { sql: { test: "pglite" } } } } },
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
const alice = await t.auth.loginAs({ id: "alice", tenantId: "acme" });
|
|
150
|
-
const bob = await t.auth.loginAs({ id: "bob", tenantId: "globex" });
|
|
151
|
-
|
|
152
|
-
await t.api.docs.create({ title: "Acme Roadmap" }, { as: alice });
|
|
153
|
-
await t.api.docs.create({ title: "Globex Secrets" }, { as: bob });
|
|
154
|
-
|
|
155
|
-
const acmeDocs = await t.api.docs.list(undefined, { as: alice });
|
|
156
|
-
expect(acmeDocs.data).toHaveLength(1); // only Acme Roadmap
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
Re-scope a single call to another tenant with `{ tenant }`, independent of the
|
|
160
|
-
principal's own tenant:
|
|
161
|
-
|
|
162
|
-
```typescript
|
|
163
|
-
const carol = await t.auth.loginAs({ id: "carol", tenantId: "acme" });
|
|
164
|
-
const { data } = await t.api.docs.create(
|
|
165
|
-
{ title: "Globex Carol" },
|
|
166
|
-
{ as: carol, tenant: "globex" },
|
|
167
|
-
);
|
|
168
|
-
expect(data.tenantId).toBe("globex");
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
RLS policies are row-level: tenant-scoped tables need `store.schema.policy.tenant`
|
|
172
|
-
(or `store.schema.unscoped()` for genuinely global tables). Harness boots do not
|
|
173
|
-
run migrations — in a real app `oke db push` installs those policies.
|
|
174
|
-
|
|
175
|
-
## Deterministic live signals
|
|
176
|
-
|
|
177
|
-
Signals with `delivery: "live"` back client feeds and SSE streams. The harness
|
|
178
|
-
exposes the retained event stream so you can assert both sides deterministically:
|
|
179
|
-
|
|
180
|
-
```typescript title="tests/live.test.ts"
|
|
181
|
-
const orderStatus = signal("order-status", {
|
|
182
|
-
delivery: "live",
|
|
183
|
-
retention: { maxCount: 10 },
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
on(
|
|
187
|
-
http.post("/orders/status").public(),
|
|
188
|
-
flow("orders.updateStatus", {
|
|
189
|
-
in: z.object({ orderId: z.string(), status: z.string() }),
|
|
190
|
-
effects: { emits: ["order-status"] },
|
|
191
|
-
do: async (input, fx) => {
|
|
192
|
-
await fx.emit(orderStatus, input);
|
|
193
|
-
return { ok: true };
|
|
194
|
-
},
|
|
195
|
-
}),
|
|
196
|
-
);
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
```typescript
|
|
200
|
-
const seen: Array<{ orderId: string; status: string }> = [];
|
|
201
|
-
|
|
202
|
-
const unsubscribe = t.signals.subscribeLive(orderStatus, {
|
|
203
|
-
onEvent: (event) => seen.push(event),
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
await t.api.orders.updateStatus({ orderId: "o1", status: "placed" });
|
|
207
|
-
await t.signals.drain();
|
|
208
|
-
expect(seen.map((e) => e.status)).toEqual(["placed"]);
|
|
209
|
-
|
|
210
|
-
// Resolve a promise the moment a matching event arrives.
|
|
211
|
-
const deliveredPromise = t.signals.waitForLive(
|
|
212
|
-
orderStatus,
|
|
213
|
-
(event) => event.status === "delivered",
|
|
214
|
-
);
|
|
215
|
-
await t.api.orders.updateStatus({ orderId: "o1", status: "delivered" });
|
|
216
|
-
await t.signals.drain();
|
|
217
|
-
const delivered = await deliveredPromise;
|
|
218
|
-
expect(delivered.status).toBe("delivered");
|
|
219
|
-
|
|
220
|
-
unsubscribe(); // no further events observed
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
Call `t.signals.drain()` after each emit — live events are staged until the bus
|
|
224
|
-
drains. `retention` caps the replayed tape (`maxCount` / `maxAge`); it is only
|
|
225
|
-
valid on `delivery: "live"` signals.
|
|
226
|
-
|
|
227
|
-
## Time travel
|
|
228
|
-
|
|
229
|
-
`t.clock` freezes time. `t.clock.advance("2m")` moves the clock forward and
|
|
230
|
-
resumes any durable sleeps that become due. `t.cron.run("expire-stale")` runs a
|
|
231
|
-
named Clock now:
|
|
232
|
-
|
|
233
|
-
```typescript
|
|
234
|
-
await t.clock.advance("30s"); // durable sleeps resume
|
|
235
|
-
await t.cron.run("expire-stale"); // named Clock fires
|
|
236
|
-
expect(t.channels.sent()).toHaveLength(1); // side effect observed
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
## AI & channels
|
|
240
|
-
|
|
241
|
-
`fx.ask` routes to a mock driver. Register canned outputs and read accumulated
|
|
242
|
-
cost:
|
|
243
|
-
|
|
244
|
-
```typescript
|
|
245
|
-
t.ai.mock(summarizePrompt, { title: "Mock summary" });
|
|
246
|
-
const { data } = await t.api.posts.summarize({ postId: "p_1" }, { as: u });
|
|
247
|
-
expect(data).toEqual({ title: "Mock summary" });
|
|
248
|
-
expect(t.ai.cost()).toBe(0);
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
Channels write to an inbox instead of a transport:
|
|
252
|
-
|
|
253
|
-
```typescript
|
|
254
|
-
expect(t.channels.sent()).toContainEqual(
|
|
255
|
-
expect.objectContaining({ template: "order-confirmed", to: u.id }),
|
|
256
|
-
);
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
## Troubleshooting
|
|
260
|
-
|
|
261
|
-
<Accordions>
|
|
262
|
-
|
|
263
|
-
<Accordion title="createTestApp fails to boot — missing secrets or stores">
|
|
264
|
-
The starter patches test drivers and fallback secrets on the app options. If
|
|
265
|
-
your `oke({ ... })` references a Vault secret or Store that the template does
|
|
266
|
-
not define, pass them explicitly:
|
|
267
|
-
|
|
268
|
-
```typescript
|
|
269
|
-
await createTestApp(app, {
|
|
270
|
-
secrets: [openAiKey],
|
|
271
|
-
vaultSecrets: { OPENAI_KEY: "sk-test" },
|
|
272
|
-
});
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
</Accordion>
|
|
276
|
-
|
|
277
|
-
<Accordion title="My live subscription never receives events">
|
|
278
|
-
- Live events are staged until `t.signals.drain()` — await `drain()` after
|
|
279
|
-
every emitting call.
|
|
280
|
-
- Register `subscribeLive` / `waitForLive` **before** you emit.
|
|
281
|
-
- A signal with a schema drops violating emits — assert `res.error`.
|
|
282
|
-
|
|
283
|
-
</Accordion>
|
|
284
|
-
|
|
285
|
-
<Accordion title="Cross-tenant reads return a stale cached row">
|
|
286
|
-
Tier-1 read caching keys by flow, input, and user id — tenant is a row-level
|
|
287
|
-
RLS scope, not a cache dimension. For reads under a `{ tenant }` override, use
|
|
288
|
-
a distinct call principal (or write first) so the cache key differs.
|
|
289
|
-
|
|
290
|
-
</Accordion>
|
|
291
|
-
|
|
292
|
-
<Accordion title="PGlite RLS policies aren't applied in the harness">
|
|
293
|
-
Test boots never run migrations — `oke db push` installs DDL and
|
|
294
|
-
`store.schema.policy.tenant` policies in real apps.
|
|
295
|
-
|
|
296
|
-
Assert real RLS by installing the policy + `oke.*` helpers on the booted
|
|
297
|
-
primary connection (as the repo's `sql-rls-isolation.test.ts` does).
|
|
298
|
-
|
|
299
|
-
</Accordion>
|
|
300
|
-
|
|
301
|
-
</Accordions>
|
|
302
|
-
|
|
303
|
-
## Learn more
|
|
304
|
-
|
|
305
|
-
- [Flow](/docs/elements/flow) — triggers, contracts, effects, and composition
|
|
306
|
-
- [Store](/docs/elements/store) — SQL, KV, files, index, and RLS policies
|
|
307
|
-
- [Signal](/docs/elements/signal) — delivery physics, retention, and live feeds
|
|
308
|
-
- [Client](/docs/reference/client) — the typed client for real HTTP calls
|
|
309
|
-
|
|
310
|
-
## Next
|
|
311
|
-
|
|
312
|
-
<Cards>
|
|
313
|
-
<Card
|
|
314
|
-
title="Project structure"
|
|
315
|
-
description="Folders are the URL; unit plus export is the name."
|
|
316
|
-
href="/docs/get-started/project-structure"
|
|
317
|
-
/>
|
|
318
|
-
<Card
|
|
319
|
-
title="Flow"
|
|
320
|
-
description="Triggers, contracts, effects, and composition."
|
|
321
|
-
href="/docs/elements/flow"
|
|
322
|
-
/>
|
|
323
|
-
<Card
|
|
324
|
-
title="Signal"
|
|
325
|
-
description="Delivery physics, retention, and deterministic live feeds."
|
|
326
|
-
href="/docs/elements/signal"
|
|
327
|
-
/>
|
|
328
|
-
</Cards>
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Why OKE
|
|
3
|
-
description: From forty tools to one species — the Manifest, the `fx` rule, and the eight closed elements.
|
|
4
|
-
source: docs/spec/unified-theory.md
|
|
5
|
-
icon: Compass
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## From forty tools to one species
|
|
9
|
-
|
|
10
|
-
A booking API, a nightly cleanup job, a receipt email, a row-change hook — in most stacks these are **four frameworks**. In OKE they are **one species** with one shape. Learn the shape once; only the trigger changes.
|
|
11
|
-
|
|
12
|
-
> **The one rule**
|
|
13
|
-
> Every backend behavior is a **Flow**: `on(Trigger) → Effects`. There are no separate species called endpoints, handlers, consumers, jobs, or workflows.
|
|
14
|
-
|
|
15
|
-
<Callout title="A note on the count">
|
|
16
|
-
'Forty' is a representative illustration of the number of backend concerns developers commonly
|
|
17
|
-
assemble across modern stacks, not a literal count of backend technologies.
|
|
18
|
-
</Callout>
|
|
19
|
-
|
|
20
|
-
## The pain we solve
|
|
21
|
-
|
|
22
|
-
Every TypeScript backend works on day one. The bill arrives later. None of these are router problems — they are **gaps** between what your code knows and what your tooling knows.
|
|
23
|
-
|
|
24
|
-
### Cache that lies
|
|
25
|
-
|
|
26
|
-
You add a column to `orders` and update three writers. The cache key in `checkout` is not one of them. A customer finds it a week later.
|
|
27
|
-
|
|
28
|
-
OKE derives: reads and writes are recorded through `fx`, so cache invalidation follows the Flow — there is no separate key to remember.
|
|
29
|
-
|
|
30
|
-
### Secret that fails at 2am
|
|
31
|
-
|
|
32
|
-
`STRIPE_KEY` lives in your laptop's `.env`, a README, and a teammate's shell history. The deploy boots fine — the first charge request dies at 2am.
|
|
33
|
-
|
|
34
|
-
OKE derives: [Vault](/docs/elements/vault) contracts declare the need in code; boot resolves every contract and **fails loud** with every gap listed — never halfway.
|
|
35
|
-
|
|
36
|
-
### The glue you rewrite
|
|
37
|
-
|
|
38
|
-
CORS rules, security headers, CSRF tokens, compression — copied from the last repo, tweaked, and already drifting from whatever that repo does today.
|
|
39
|
-
|
|
40
|
-
OKE derives: the official `okengine/plugins` set ships this glue once — shared lifecycle, optional live DB config, nothing to re-copy.
|
|
41
|
-
|
|
42
|
-
### The dashboard that doesn't know you
|
|
43
|
-
|
|
44
|
-
Your observability stack learned your routes from sampled traffic. The Flow you deployed an hour ago is invisible until someone wires it by hand.
|
|
45
|
-
|
|
46
|
-
OKE derives: its operator interface reads the Manifest — flows, effects, traces, architecture — current on every save, in dev and prod (`:6533`).
|
|
47
|
-
|
|
48
|
-
### Permission check in the wrong place
|
|
49
|
-
|
|
50
|
-
`if (!user.isAdmin)` sits in handler forty-one of sixty. Which Flows touch `payments`? grep answers slowly; review answers never.
|
|
51
|
-
|
|
52
|
-
OKE derives: declared effects produce a **least-privilege matrix** — widening access appears in Manifest Diff, not in a diff nobody reads.
|
|
53
|
-
|
|
54
|
-
### Local works, prod doesn't
|
|
55
|
-
|
|
56
|
-
Local runs one vendor client, CI another, prod a third — three glue stories for the same database.
|
|
57
|
-
|
|
58
|
-
OKE derives: drivers are named after protocols (`postgres`, `redis`, `s3`), the vendor lives in `images`, and `oke dev` runs the real stack locally.
|
|
59
|
-
|
|
60
|
-
---
|
|
61
|
-
|
|
62
|
-
Every gap above is the same shape: knowledge the code already has, duplicated somewhere the compiler cannot check. **The tax is drift.** One change costs fifteen seams to update by hand; in OKE it always costs one.
|
|
63
|
-
|
|
64
|
-
## One Manifest feeds every surface
|
|
65
|
-
|
|
66
|
-
At build time OKE extracts a **Manifest** — the compiled, versioned contract between your backend model and everything derived from it. The source of truth is your model expressed in code (`on(Trigger) → Flow → fx → Effects`); the Manifest freezes that model into a machine-readable, diffable contract. You do not write or hand-maintain the Manifest:
|
|
67
|
-
|
|
68
|
-
| Surface | Port | You maintain? |
|
|
69
|
-
| --------------------------------- | ------------------ | ----------------------------- |
|
|
70
|
-
| Typed client (`okengine/client`) | your app code | No — derived from `Manifest` |
|
|
71
|
-
| Console panels, traces, explorers | `:6533` | No — reads the Manifest |
|
|
72
|
-
| MCP for agents | `:6535` | No — reads the Manifest |
|
|
73
|
-
| Architecture diagram | Console | No — it _is_ the effect graph |
|
|
74
|
-
| Capability matrix + cache keys | compiler / runtime | No — inferred from `fx` |
|
|
75
|
-
|
|
76
|
-
Because every surface reads the same Manifest contract, they **cannot disagree** — there is only one source of truth.
|
|
77
|
-
|
|
78
|
-
## The `fx` rule — one door to the world
|
|
79
|
-
|
|
80
|
-
**All world access goes through `fx`.** A Flow that imports `node:fs`, calls `fetch` directly, or uses `Date.now()` is a defect. Effects are **inferred from what a Flow touches through `fx`**, and that inference powers the Manifest, the Console, caching, and durability.
|
|
81
|
-
|
|
82
|
-
<Callout title="What `fx` records">
|
|
83
|
-
Every read, write, emit, send, ask, secret, and call is captured — so the Manifest knows exactly
|
|
84
|
-
which flows touch `orders` or send PII to a model, without you declaring it.
|
|
85
|
-
</Callout>
|
|
86
|
-
|
|
87
|
-
| Inferred from `fx` | What it gives you |
|
|
88
|
-
| ----------------------- | ------------------------------------ |
|
|
89
|
-
| Cache invalidation keys | Automatic — follows the Flow |
|
|
90
|
-
| Live queries | Built-in subscription model |
|
|
91
|
-
| Least-privilege tokens | Capability matrix from effects |
|
|
92
|
-
| Deterministic tests | Time, clock, and randomness injected |
|
|
93
|
-
| Manifest Diff | Exact change surface on every save |
|
|
94
|
-
|
|
95
|
-
## Eight elements — a closed set
|
|
96
|
-
|
|
97
|
-
Forty infrastructure concerns collapse into eight elements — each kept only because it has **irreducible physics**. New infrastructure becomes a **driver** for an existing element, never a ninth.
|
|
98
|
-
|
|
99
|
-
| Element | Essence | Replaces the zoo |
|
|
100
|
-
| ----------- | ----------------------------- | --------------------------------------------------------- |
|
|
101
|
-
| **Flow** | Behavior | endpoint · handler · consumer · job · workflow · webhook |
|
|
102
|
-
| **Signal** | Data in motion | queue · pub/sub · stream · websocket · SSE · event bus |
|
|
103
|
-
| **Store** | Data at rest | database · cache · KV · file storage · search index |
|
|
104
|
-
| **Clock** | Time | cron · delay · timeout · durable sleep · TTL |
|
|
105
|
-
| **Gate** | Permission to act | auth · session · ABAC · rate limit · quota · feature flag |
|
|
106
|
-
| **Vault** | Protected knowledge | secrets · config · environment |
|
|
107
|
-
| **Channel** | Reaching humans | email · SMS · WhatsApp · push |
|
|
108
|
-
| **AI** | Reaching machine intelligence | model calls · prompts · embeddings · agents · RAG |
|
|
109
|
-
|
|
110
|
-
Drivers are named after **protocols** (`postgres`, `redis`, `s3`) — never vendors. The vendor lives in `images`, and `oke dev` runs the real stack locally.
|
|
111
|
-
|
|
112
|
-
## The shape of a Flow
|
|
113
|
-
|
|
114
|
-
One pipeline. Only the trigger changes between an endpoint, a job, a consumer, and a row hook:
|
|
115
|
-
|
|
116
|
-
```ts
|
|
117
|
-
import { on, flow, http } from "okengine/http";
|
|
118
|
-
|
|
119
|
-
export const health = on(http.get().public(), flow({ do: () => ({ ok: true }) }));
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
| Piece | Role |
|
|
123
|
-
| ------------- | -------------------------------------------------------------- |
|
|
124
|
-
| **Trigger** | How work starts — `http`, a signal, `every`, a row change |
|
|
125
|
-
| **Contracts** | `in`, `out`, typed `errors` — validated before and after `do` |
|
|
126
|
-
| **`do`** | The body — every read, write, emit, and call goes through `fx` |
|
|
127
|
-
| **Effects** | Inferred from those `fx` calls — not hand-annotated |
|
|
128
|
-
|
|
129
|
-
Consequence: **one documentation path, one trace shape, one Flow model, one thing for an AI agent to learn.**
|
|
130
|
-
|
|
131
|
-
## Ambition, stated plainly
|
|
132
|
-
|
|
133
|
-
> **Ambition**: The default, most capable TypeScript backend — Bun-first, Web-Standards portable, contract-first
|
|
134
|
-
> **Grounded in**: Eight elements, effect inference through `fx`, Gate and Vault, the official plugin set
|
|
135
|
-
> **Maturity**: **pre-1.0** — published and usable; not independently battle-tested at scale yet
|
|
136
|
-
|
|
137
|
-
## Learn more
|
|
138
|
-
|
|
139
|
-
- [Introduction](/docs/get-started/introduction) — the one law, eight elements, one contract
|
|
140
|
-
- [Flow](/docs/elements/flow) — how effects are recorded and inferred
|
|
141
|
-
- [Vault](/docs/elements/vault) — fail-loud secret contracts
|
|
142
|
-
- [Plugins](/docs/reference/plugins) — the official HTTP glue set
|
|
143
|
-
|
|
144
|
-
## Next
|
|
145
|
-
|
|
146
|
-
<Cards>
|
|
147
|
-
<Card
|
|
148
|
-
title="Installation"
|
|
149
|
-
description="Scaffold with create-oke and open the Console."
|
|
150
|
-
href="/docs/get-started/installation"
|
|
151
|
-
/>
|
|
152
|
-
<Card
|
|
153
|
-
title="Basic Usage"
|
|
154
|
-
description="Health Flow, typed client, and bun:test."
|
|
155
|
-
href="/docs/get-started/basic-usage"
|
|
156
|
-
/>
|
|
157
|
-
<Card
|
|
158
|
-
title="Introduction"
|
|
159
|
-
description="The one law, eight elements, one contract."
|
|
160
|
-
href="/docs/get-started/introduction"
|
|
161
|
-
/>
|
|
162
|
-
</Cards>
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "llama.cpp"
|
|
3
|
-
description: "Default local AI image — OpenAI-compatible llama-server, loopback-only publish, pinned build ≥ b8146."
|
|
4
|
-
icon: "Bot"
|
|
5
|
-
source: "docs/spec/unified-theory.md"
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
llama.cpp is the default `images.ai` pin for local inference. It runs
|
|
9
|
-
`llama-server` with an OpenAI-compatible `/v1` API — lightest resource footprint
|
|
10
|
-
for single-user / dev. Driver id stays `openai-compatible`.
|
|
11
|
-
|
|
12
|
-
<Callout title="The one rule">
|
|
13
|
-
Pin a verified build ≥ `b8146`, publish only on loopback, and load models only from curated
|
|
14
|
-
registries (Docker Hub `ai/`) — never arbitrary untrusted GGUF.
|
|
15
|
-
</Callout>
|
|
16
|
-
|
|
17
|
-
## Quick start
|
|
18
|
-
|
|
19
|
-
<Steps>
|
|
20
|
-
|
|
21
|
-
<Step>
|
|
22
|
-
### Pin driver + image
|
|
23
|
-
|
|
24
|
-
```typescript title="oke.config.ts"
|
|
25
|
-
drivers: {
|
|
26
|
-
ai: { dev: "openai-compatible", test: "mock", prod: "openai-compatible" },
|
|
27
|
-
},
|
|
28
|
-
images: {
|
|
29
|
-
ai: "ghcr.io/ggml-org/llama.cpp:server-b10450", // never :latest
|
|
30
|
-
},
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Or `oke ai setup --provider llama-cpp` (TTY: banner → Ultra Fast / Fast /
|
|
34
|
-
Balanced / Smart → up to 20 curated Docker Hub `ai/` picks per tier) / `--yes`
|
|
35
|
-
for `granite3.3:2b`.
|
|
36
|
-
|
|
37
|
-
</Step>
|
|
38
|
-
|
|
39
|
-
<Step>
|
|
40
|
-
### Env written by the stack
|
|
41
|
-
|
|
42
|
-
```bash title=".env.local"
|
|
43
|
-
OKE_AI_URL=http://127.0.0.1:8080/v1
|
|
44
|
-
OKE_AI_MODEL=granite3.3:2b
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
`OKE_AI_MODEL` is a Docker Hub `ai/<id>` model. The recipe writes
|
|
48
|
-
`.oke/llama-entrypoint.py` (generated, gitignored), Hub-pulls into the cache
|
|
49
|
-
volume, then starts `llama-server -m <gguf> --alias <id>` (single-model).
|
|
50
|
-
|
|
51
|
-
Never set `LLAMA_ARG_MODELS_PRESET` / `LLAMA_ARG_DOCKER_REPO` — those hang on
|
|
52
|
-
b10290+. `oke dev` shows the model id and polls `/v1/models` until `ready`
|
|
53
|
-
(first boot may take minutes).
|
|
54
|
-
|
|
55
|
-
</Step>
|
|
56
|
-
|
|
57
|
-
<Step>
|
|
58
|
-
### Ask through the OpenAI-compatible driver
|
|
59
|
-
|
|
60
|
-
```typescript
|
|
61
|
-
import { ai } from "okengine";
|
|
62
|
-
|
|
63
|
-
export const smart = ai.model("smart", {
|
|
64
|
-
provider: "openai-compatible",
|
|
65
|
-
model: process.env.OKE_AI_MODEL ?? "granite3.3:2b",
|
|
66
|
-
});
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
</Step>
|
|
70
|
-
|
|
71
|
-
</Steps>
|
|
72
|
-
|
|
73
|
-
## Security (hard requirements)
|
|
74
|
-
|
|
75
|
-
| Control | Requirement |
|
|
76
|
-
| -------------------- | ---------------------------------------------------------------------------- |
|
|
77
|
-
| Host publish | `127.0.0.1:8080:8080` only — never `0.0.0.0` |
|
|
78
|
-
| Image pin | Explicit build ≥ **b8146** (CVE-2026-27940 / CVE-2026-33298); never `latest` |
|
|
79
|
-
| Model source | Docker Hub [`ai/`](https://hub.docker.com/u/ai) namespace (or known HF GGUF) |
|
|
80
|
-
| Untrusted GGUF | **Forbidden** — crafted files can RCE the parser on unpatched builds |
|
|
81
|
-
| RPC / extra backends | Not published — OpenAI HTTP only |
|
|
82
|
-
|
|
83
|
-
Inside the container the server listens on `0.0.0.0` so the Compose network and
|
|
84
|
-
loopback map work. The **host** bind is loopback — same isolation idea as
|
|
85
|
-
Postgres/Redis, stricter on the published interface because of GGUF CVE risk.
|
|
86
|
-
|
|
87
|
-
## Required env
|
|
88
|
-
|
|
89
|
-
| Variable | Required? | Meaning |
|
|
90
|
-
| -------------- | ----------------- | --------------------------------------------- |
|
|
91
|
-
| `OKE_AI_URL` | **Yes** in docker | Base URL including `/v1` |
|
|
92
|
-
| `OKE_AI_MODEL` | Recommended | Docker Hub `ai/` id (default `granite3.3:2b`) |
|
|
93
|
-
|
|
94
|
-
## What the recipe configures
|
|
95
|
-
|
|
96
|
-
| Field | Value |
|
|
97
|
-
| -------------- | ------------------------------------------------------------ |
|
|
98
|
-
| Container port | `8080` |
|
|
99
|
-
| Host publish | `127.0.0.1:8080:8080` |
|
|
100
|
-
| Healthcheck | `GET /health`, every 5s, 24 retries, 900s start |
|
|
101
|
-
| Connection URL | `http://host:8080/v1` |
|
|
102
|
-
| Model load | `.oke/llama-entrypoint.py` → Hub pull (incl. CNCF) then `-m` |
|
|
103
|
-
|
|
104
|
-
## When to choose something else
|
|
105
|
-
|
|
106
|
-
| Workload | Prefer |
|
|
107
|
-
| ------------------------------------------ | --------------------------------------- |
|
|
108
|
-
| Single-user / dev, lightest footprint | **llama.cpp** (this recipe) |
|
|
109
|
-
| Local DX with library pull UX | [Ollama](/docs/recipes/ollama) |
|
|
110
|
-
| Multi-user / production concurrency on GPU | [vLLM](/docs/recipes/vllm) |
|
|
111
|
-
| Structured / agent workloads on GPU | [SGLang](/docs/recipes/sglang) |
|
|
112
|
-
| Managed cloud | Anthropic / OpenAI / … (no `images.ai`) |
|
|
113
|
-
|
|
114
|
-
## Troubleshooting
|
|
115
|
-
|
|
116
|
-
<Accordions>
|
|
117
|
-
<Accordion title="Connection refused on :8080">
|
|
118
|
-
|
|
119
|
-
Confirm compose published `127.0.0.1:8080:8080` (not bare `8080:8080` on all
|
|
120
|
-
interfaces). `OKE_AI_URL` must include `/v1`.
|
|
121
|
-
|
|
122
|
-
</Accordion>
|
|
123
|
-
<Accordion title="Model fails to load / slow first boot">
|
|
124
|
-
|
|
125
|
-
First start Hub-pulls the curated `ai/` model into the named cache volume
|
|
126
|
-
(see logs: `oke ai: ensuring…` / download %). Prefer `oke ai setup` tiers
|
|
127
|
-
(Ultra Fast → `granite3.3:2b`) for smoke tests.
|
|
128
|
-
|
|
129
|
-
Confirm `OKE_AI_MODEL` in `.env.local`. Watch `oke
|
|
130
|
-
dev` until AI status is `ready`.
|
|
131
|
-
|
|
132
|
-
If status stays `loading` on Compose that still uses `--models-preset`,
|
|
133
|
-
regenerate `docker/` and recreate AI. Never mount random GGUF or set
|
|
134
|
-
`LLAMA_ARG_MODELS_PRESET` / `LLAMA_ARG_DOCKER_REPO`.
|
|
135
|
-
|
|
136
|
-
</Accordion>
|
|
137
|
-
</Accordions>
|
|
138
|
-
|
|
139
|
-
## Learn more
|
|
140
|
-
|
|
141
|
-
- [AI](/docs/elements/ai) — `fx.ask`, prompts, drivers
|
|
142
|
-
- [Ollama](/docs/recipes/ollama) — fully supported alternative
|
|
143
|
-
- [Environment variables](/docs/reference/environment-variables) — `OKE_AI_*`
|
|
144
|
-
|
|
145
|
-
## Next
|
|
146
|
-
|
|
147
|
-
<Cards>
|
|
148
|
-
<Card title="Ollama" description="Library UX alternative." href="/docs/recipes/ollama" />
|
|
149
|
-
<Card title="vLLM" description="Production GPU serving." href="/docs/recipes/vllm" />
|
|
150
|
-
<Card title="AI" description="Prompts, models, guardrails." href="/docs/elements/ai" />
|
|
151
|
-
</Cards>
|