okengine 0.18.5 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +18 -10
- package/README.md +2 -2
- package/package.json +51 -50
- package/site/content/docs/ai/llms-txt.mdx +1 -1
- package/site/content/docs/ai/meta.json +1 -1
- package/site/content/docs/ai/skills.mdx +4 -1
- package/site/content/docs/ai/try-it.mdx +58 -0
- package/site/content/docs/client/auth.mdx +208 -0
- package/site/content/docs/client/calling.mdx +451 -0
- package/site/content/docs/client/index.mdx +209 -0
- package/site/content/docs/client/live.mdx +234 -0
- package/site/content/docs/client/meta.json +5 -0
- package/site/content/docs/client/react.mdx +249 -0
- package/site/content/docs/elements/ai/agents.mdx +232 -0
- package/site/content/docs/elements/ai/index.mdx +341 -0
- package/site/content/docs/elements/ai/mcp.mdx +275 -0
- package/site/content/docs/elements/ai/meta.json +5 -0
- package/site/content/docs/elements/ai/models.mdx +283 -0
- package/site/content/docs/elements/ai/prompts.mdx +256 -0
- package/site/content/docs/elements/channel/email.mdx +266 -0
- package/site/content/docs/elements/channel/index.mdx +344 -0
- package/site/content/docs/elements/channel/meta.json +5 -0
- package/site/content/docs/elements/channel/push.mdx +218 -0
- package/site/content/docs/elements/channel/receipts.mdx +206 -0
- package/site/content/docs/elements/channel/sms.mdx +264 -0
- package/site/content/docs/elements/channel/whatsapp.mdx +220 -0
- package/site/content/docs/elements/clock/index.mdx +300 -0
- package/site/content/docs/elements/clock/meta.json +5 -0
- package/site/content/docs/elements/clock/schedules.mdx +508 -0
- package/site/content/docs/elements/clock/sleep.mdx +445 -0
- package/site/content/docs/elements/flow/consumers.mdx +707 -0
- package/site/content/docs/elements/flow/http.mdx +1080 -0
- package/site/content/docs/elements/flow/index.mdx +618 -0
- package/site/content/docs/elements/flow/meta.json +5 -0
- package/site/content/docs/elements/flow/routing.mdx +559 -0
- package/site/content/docs/elements/flow/workflows.mdx +640 -0
- package/site/content/docs/elements/gate/auth.mdx +371 -0
- package/site/content/docs/elements/gate/authorization.mdx +298 -0
- package/site/content/docs/elements/gate/index.mdx +418 -0
- package/site/content/docs/elements/gate/meta.json +5 -0
- package/site/content/docs/elements/gate/rate-limits.mdx +365 -0
- package/site/content/docs/elements/gate/rls.mdx +303 -0
- package/site/content/docs/elements/gate/tenancy.mdx +372 -0
- package/site/content/docs/elements/index.mdx +20 -10
- package/site/content/docs/elements/signal/broadcast.mdx +517 -0
- package/site/content/docs/elements/signal/index.mdx +352 -0
- package/site/content/docs/elements/signal/live.mdx +590 -0
- package/site/content/docs/elements/signal/meta.json +5 -0
- package/site/content/docs/elements/signal/once.mdx +596 -0
- package/site/content/docs/elements/store/files.mdx +659 -0
- package/site/content/docs/elements/store/index.mdx +310 -0
- package/site/content/docs/elements/store/kv.mdx +629 -0
- package/site/content/docs/elements/store/meta.json +5 -0
- package/site/content/docs/elements/store/search.mdx +946 -0
- package/site/content/docs/elements/store/sql.mdx +937 -0
- package/site/content/docs/elements/vault/config.mdx +256 -0
- package/site/content/docs/elements/vault/index.mdx +356 -0
- package/site/content/docs/elements/vault/meta.json +5 -0
- package/site/content/docs/elements/vault/rotation.mdx +273 -0
- package/site/content/docs/elements/vault/secrets.mdx +285 -0
- package/site/content/docs/index.mdx +63 -36
- package/site/content/docs/meta.json +8 -7
- package/site/content/docs/plugins/cors.mdx +2 -1
- package/site/content/docs/plugins/csrf.mdx +4 -1
- package/site/content/docs/plugins/headers.mdx +2 -1
- package/site/content/docs/plugins/ip-allowlist.mdx +2 -1
- package/site/content/docs/plugins/magic-link.mdx +6 -0
- package/site/content/docs/plugins/maintenance-mode.mdx +2 -1
- package/site/content/docs/plugins/oauth.mdx +1 -1
- package/site/content/docs/plugins/otp.mdx +12 -1
- package/site/content/docs/plugins/passkey.mdx +39 -15
- package/site/content/docs/plugins/two-factor.mdx +91 -34
- package/site/content/docs/plugins/username.mdx +1 -1
- package/site/content/docs/recipes/caddy.mdx +3 -3
- package/site/content/docs/recipes/index.mdx +18 -28
- package/site/content/docs/recipes/mailpit.mdx +1 -1
- package/site/content/docs/recipes/meilisearch.mdx +3 -3
- package/site/content/docs/recipes/meta.json +1 -4
- package/site/content/docs/recipes/nginx.mdx +2 -2
- package/site/content/docs/recipes/openrouter.mdx +283 -0
- package/site/content/docs/recipes/pgdog.mdx +3 -3
- package/site/content/docs/recipes/postgres.mdx +1 -2
- package/site/content/docs/recipes/rustfs.mdx +2 -2
- package/site/content/docs/recipes/traefik.mdx +3 -3
- package/site/content/docs/reference/cli.mdx +231 -0
- package/site/content/docs/reference/configuration.mdx +30 -10
- package/site/content/docs/reference/environment-variables.mdx +93 -20
- package/site/content/docs/reference/errors.mdx +132 -29
- package/site/content/docs/reference/fx.mdx +137 -73
- package/site/content/docs/reference/index.mdx +13 -21
- package/site/content/docs/reference/meta.json +4 -5
- package/site/content/docs/reference/okid.mdx +42 -17
- package/site/content/docs/reference/plugins.mdx +4 -3
- package/site/content/docs/reference/security.mdx +197 -0
- package/site/content/docs/understand/meta.json +5 -0
- package/site/content/docs/understand/the-anatomy.mdx +132 -0
- package/site/content/docs/understand/the-model.mdx +32 -0
- package/site/content/docs/understand/the-problem.mdx +74 -0
- package/site/content/docs/understand/the-vocabulary.mdx +26 -0
- package/src/auth/api-keys.ts +2 -1
- package/src/auth/bindings.ts +64 -16
- package/src/auth/gate-auth.test.ts +6 -1
- package/src/auth/identity.ts +152 -5
- package/src/auth/index.ts +29 -0
- package/src/auth/invites.ts +2 -1
- package/src/auth/method-context.ts +41 -0
- package/src/auth/oauth-as/crypto.ts +2 -1
- package/src/auth/oauth-as/stores.ts +2 -1
- package/src/auth/operator.ts +2 -1
- package/src/auth/sessions-jwt.test.ts +77 -0
- package/src/auth/sessions.ts +20 -4
- package/src/auth/tenants.ts +3 -2
- package/src/auth/two-factor-challenge.test.ts +61 -0
- package/src/auth/two-factor-challenge.ts +284 -0
- package/src/auth/verification.ts +5 -0
- package/src/bench/REPORT.md +49 -0
- package/src/bench/g03-signal-once.bench.ts +1 -1
- package/src/bench/g10-observability-contention.bench.ts +1 -1
- package/src/bench/g17-hybrid-search.bench.ts +572 -0
- package/src/bench/load-app.ts +2 -10
- package/src/cli/ai-setup/ai-setup.test.ts +331 -42
- package/src/cli/ai-setup/apply.ts +294 -52
- package/src/cli/ai-setup/catalog.ts +238 -1342
- package/src/cli/ai-setup/index.ts +14 -99
- package/src/cli/ai-setup/prompts.ts +60 -443
- package/src/cli/ask-seed.test.ts +96 -0
- package/src/cli/ask-seed.ts +82 -0
- package/src/cli/ask-vault-gaps.test.ts +84 -0
- package/src/cli/ask-vault-gaps.ts +146 -0
- package/src/cli/build.ts +2 -2
- package/src/cli/client-add.test.ts +26 -1
- package/src/cli/client-add.ts +106 -27
- package/src/cli/db-seed.ts +2 -0
- package/src/cli/db.ts +150 -11
- package/src/cli/dev.ts +119 -211
- package/src/cli/docker-clean.ts +2 -2
- package/src/cli/docker-cli.test.ts +1 -1
- package/src/cli/doctor-diff.ts +4 -2
- package/src/cli/doctor-pii.test.ts +1 -1
- package/src/cli/doctor.ts +14 -1
- package/src/cli/hero-meta.test.ts +4 -2
- package/src/cli/load-config.images.test.ts +8 -10
- package/src/cli/load-config.ts +1 -1
- package/src/cli/registry.ts +22 -10
- package/src/cli/replay.ts +3 -1
- package/src/cli/start.ts +1 -1
- package/src/cli/tui/keys.ts +2 -3
- package/src/client/auth/cookies.ts +74 -0
- package/src/client/auth/create-auth-client.ts +636 -0
- package/src/client/auth/denials.ts +99 -0
- package/src/client/auth/session.ts +283 -0
- package/src/client/auth.test.ts +251 -0
- package/src/client/auth.ts +39 -114
- package/src/client/create-with-session.ts +245 -0
- package/src/client/create.ts +51 -5
- package/src/client/index.ts +11 -1
- package/src/client/live.ts +11 -79
- package/src/client/notes-contract.test.ts +5 -10
- package/src/client/sse.ts +137 -0
- package/src/client/stream.ts +147 -0
- package/src/client/transport.test.ts +32 -0
- package/src/client/transport.ts +123 -26
- package/src/client/types.ts +118 -14
- package/src/client-react/index.ts +185 -24
- package/src/client-react/use-live-query.ts +13 -3
- package/src/compiler/aot.test.ts +7 -4
- package/src/compiler/effects-embed.test.ts +56 -0
- package/src/compiler/effects-fetch.test.ts +43 -0
- package/src/compiler/effects-infer.ts +58 -2
- package/src/compiler/extract.test.ts +257 -43
- package/src/compiler/extract.ts +566 -48
- package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +7 -4
- package/src/compiler/fixtures/skyport/src/flows/bookings/signals.ts +2 -8
- package/src/compiler/fixtures/skyport.expected.json +4 -4
- package/src/compiler/fixtures/triggers/five-triggers.ts +14 -10
- package/src/compiler/response.ts +2 -2
- package/src/compiler/search-writer-isolation.test.ts +40 -0
- package/src/config/index.ts +11 -0
- package/src/console/server/app.ts +17 -23
- package/src/console/server/bind.ts +4 -0
- package/src/console/server/console.test.ts +2 -2
- package/src/console/server/flows-invoke.test.ts +50 -34
- package/src/console/server/flows.ts +436 -255
- package/src/console/server/runs-ingest.test.ts +6 -3
- package/src/console/server/serve.ts +1 -1
- package/src/console/server/signals.test.ts +1 -5
- package/src/console/server/signals.ts +8 -6
- package/src/console/server/state.ts +6 -1
- package/src/console/server/store.ts +1 -1
- package/src/console/ui-next/dist/assets/FileExportIcon-Ck-5od4R.js +1 -0
- package/src/console/ui-next/dist/assets/MoreHorizontalCircle01Icon-gMNGsE37.js +1 -0
- package/src/console/ui-next/dist/assets/PlusSignIcon-CwG3nxfu.js +1 -0
- package/src/console/ui-next/dist/assets/UnavailableIcon-D9cvHVPr.js +1 -0
- package/src/console/ui-next/dist/assets/UserIcon-DaE2PB5_.js +1 -0
- package/src/console/ui-next/dist/assets/access-page-DFeymU07.js +4 -0
- package/src/console/ui-next/dist/assets/agent-disclosure-U1rdfblp.js +1 -0
- package/src/console/ui-next/dist/assets/cache-glyph-BeFJeqBG.js +1 -0
- package/src/console/ui-next/dist/assets/call-pii-button-CVAONPii.js +1 -0
- package/src/console/ui-next/dist/assets/collapsible-D2A6NJ-3.js +1 -0
- package/src/console/ui-next/dist/assets/copy-inline-button-CAYD18cr.js +1 -0
- package/src/console/ui-next/dist/assets/dagre.esm-B1_XeuLP.js +1 -0
- package/src/console/ui-next/dist/assets/detail-header-DVWNjWjg.js +1 -0
- package/src/console/ui-next/dist/assets/dropdown-menu-4h2LOVXM.js +1 -0
- package/src/console/ui-next/dist/assets/duration-tone-Cgk_h5ja.js +9 -0
- package/src/console/ui-next/dist/assets/element-icons-BI8cJgdh.js +1 -0
- package/src/console/ui-next/dist/assets/explorer-empty-CJs5A-wm.js +1 -0
- package/src/console/ui-next/dist/assets/flows-page-Dss7941e.js +1 -0
- package/src/console/ui-next/dist/assets/highlighted-json-MYZQtRnw.js +154 -0
- package/src/console/ui-next/dist/assets/http-method-Jrh39p7A.js +1 -0
- package/src/console/ui-next/dist/assets/index-D0zS5rKO.css +2 -0
- package/src/console/ui-next/dist/assets/index-DXP2dBIF.js +63 -0
- package/src/console/ui-next/dist/assets/observability-page-HvolXxTI.js +4 -0
- package/src/console/ui-next/dist/assets/react-dom-Ddte4I-Q.js +9 -0
- package/src/console/ui-next/dist/assets/replica-lag-CSh2dzrb.js +18 -0
- package/src/console/ui-next/dist/assets/request-meta-BatF8KrK.js +1 -0
- package/src/console/ui-next/dist/assets/shortcut-keys-3ILd8oGn.js +1 -0
- package/src/console/ui-next/dist/assets/{sql-BskegiFM.js → sql-BsFa4tDR.js} +1 -1
- package/src/console/ui-next/dist/assets/store-page-eiKiHnNe.js +41 -0
- package/src/console/ui-next/dist/assets/trace-detail-sheet-CZkMeKS-.js +2 -0
- package/src/console/ui-next/dist/assets/tree-expand-toggle-CW8y5A2h.js +55 -0
- package/src/console/ui-next/dist/assets/units-page-B_RWJrEO.js +1 -0
- package/src/console/ui-next/dist/assets/{use-vault-list-uk4WVboC.js → use-vault-list-CT4-gajj.js} +1 -1
- package/src/console/ui-next/dist/assets/vault-page-CWrg-A68.js +2 -0
- package/src/console/ui-next/dist/assets/xyflow-CSyC6ryz.css +1 -0
- package/src/console/ui-next/dist/assets/xyflow-yApv7D4e.js +7 -0
- package/src/console/ui-next/dist/index.html +6 -13
- package/src/console/ui-next/seed-invoke-host.ts +21 -18
- package/src/console/ui-next/src/client.ts +7 -2
- package/src/console/ui-next/src/features/flows/graph/element-map.ts +2 -0
- package/src/console/ui-next/src/features/flows/traces/effect-kind.ts +12 -2
- package/src/console/ui-next/src/features/flows/traces/effect-summary.ts +4 -0
- package/src/console/ui-next/src/features/flows/traces/trace-detail-sheet.tsx +8 -0
- package/src/console/ui-next/src/features/flows/traces/waterfall-bars.ts +4 -0
- package/src/console/ui-next/src/features/flows/traces/waterfall-tooltip.ts +9 -3
- package/src/console/ui-next/src/features/store/detail/reveal-cell.tsx +7 -11
- package/src/console/ui-next/src/features/store/detail/store-row-detail-sheet.tsx +2 -2
- package/src/console/ui-next/src/features/store/lib/fields-from-table.ts +2 -0
- package/src/console/ui-next/src/features/store/lib/grid-model.test.ts +25 -1
- package/src/console/ui-next/src/features/store/lib/grid-model.ts +36 -1
- package/src/console/ui-next/src/features/store/query/query-results.tsx +3 -3
- package/src/console/ui-next/src/features/units/detail/effects-summary.tsx +2 -0
- package/src/console/ui-next/src/features/units/lib/call-read-safe.ts +3 -1
- package/src/console/ui-next/src/features/units/lib/fields-from-schema.ts +6 -0
- package/src/docker/ai-model-status.test.ts +1 -12
- package/src/docker/ai-model-status.ts +10 -38
- package/src/docker/compose-up.test.ts +100 -0
- package/src/docker/compose-up.ts +292 -0
- package/src/docker/compose.ts +4 -14
- package/src/docker/derive.ts +9 -34
- package/src/docker/docker.test.ts +16 -261
- package/src/docker/images-config.test.ts +13 -25
- package/src/docker/index.ts +1 -24
- package/src/docker/recipes/index.ts +0 -23
- package/src/docker/recipes/pgdog.ts +6 -4
- package/src/docker/stack-id.test.ts +2 -2
- package/src/docker/stack-id.ts +0 -1
- package/src/docker/types.ts +2 -2
- package/src/drivers/ai-anthropic.ts +10 -0
- package/src/drivers/ai-openai-compatible.ts +34 -7
- package/src/drivers/ai-providers.test.ts +0 -107
- package/src/drivers/ai-stream.test.ts +0 -34
- package/src/drivers/ai-types.ts +17 -8
- package/src/drivers/channel-fcm.ts +6 -1
- package/src/drivers/channel-msegat.ts +6 -1
- package/src/drivers/channel-resend.ts +5 -1
- package/src/drivers/channel-smtp.ts +5 -1
- package/src/drivers/channel-sndr.ts +10 -1
- package/src/drivers/channel-taqnyat-mail.ts +5 -1
- package/src/drivers/channel-taqnyat-whatsapp.ts +6 -1
- package/src/drivers/channel-taqnyat.ts +6 -1
- package/src/drivers/channel-types.ts +10 -0
- package/src/drivers/channel-unifonic.ts +6 -1
- package/src/drivers/channel-wa-cloud.ts +6 -1
- package/src/drivers/channel-webpush.ts +6 -1
- package/src/drivers/external.ts +33 -0
- package/src/drivers/index.ts +0 -10
- package/src/drivers/meilisearch.ts +6 -0
- package/src/drivers/oauth-types.ts +4 -0
- package/src/drivers/postgres.test.ts +74 -3
- package/src/drivers/postgres.ts +175 -6
- package/src/drivers/signal-types.ts +5 -5
- package/src/drivers/types.ts +7 -0
- package/src/drivers/vault-types.ts +5 -0
- package/src/elements/ai/declare.ts +17 -4
- package/src/elements/ai/eval.ts +1 -1
- package/src/elements/ai/mcp-http.ts +1 -1
- package/src/elements/ai/pii.ts +1 -1
- package/src/elements/ai/providers.test.ts +289 -0
- package/src/elements/ai/providers.ts +169 -0
- package/src/elements/ai/runtime.ts +68 -5
- package/src/elements/ai/schema.ts +2 -2
- package/src/elements/ai.test.ts +7 -7
- package/src/elements/ai.ts +17 -1
- package/src/elements/channel/runtime.ts +105 -12
- package/src/elements/clock/cron-fields.test.ts +144 -0
- package/src/elements/clock/cron-fields.ts +185 -0
- package/src/elements/clock/declare.ts +247 -3
- package/src/elements/clock.ts +21 -1
- package/src/elements/index.ts +15 -0
- package/src/elements/signal/chaos-child.ts +1 -2
- package/src/elements/signal/declare.ts +65 -37
- package/src/elements/signal/delivery-modes.test.ts +11 -31
- package/src/elements/signal/dry-run-replay.test.ts +1 -7
- package/src/elements/signal/dry-run-write-isolation.test.ts +1 -7
- package/src/elements/signal/key-ordering.test.ts +6 -26
- package/src/elements/signal/lease-reclaim.test.ts +2 -6
- package/src/elements/signal/optional-emit.test.ts +6 -9
- package/src/elements/signal/order-lifecycle.test.ts +4 -17
- package/src/elements/signal/orphan-messages.test.ts +4 -15
- package/src/elements/signal/reconcile.test.ts +2 -2
- package/src/elements/signal/runtime.ts +1 -1
- package/src/elements/signal/schema-emit.test.ts +4 -8
- package/src/elements/signal.test.ts +24 -49
- package/src/elements/signal.ts +9 -2
- package/src/elements/store/domain-ddl.test.ts +1 -1
- package/src/elements/store/live-http.test.ts +9 -4
- package/src/elements/store/prepare-row.test.ts +123 -0
- package/src/elements/store/resource.ts +43 -12
- package/src/elements/store/schema-decl.ts +117 -0
- package/src/elements/store/search-backfill.ts +205 -0
- package/src/elements/store/search-bind.ts +66 -0
- package/src/elements/store/search-bm25.ts +78 -0
- package/src/elements/store/search-ddl.ts +156 -0
- package/src/elements/store/search-embed-flow.ts +141 -0
- package/src/elements/store/search-errors.ts +34 -0
- package/src/elements/store/search-fusion.ts +112 -0
- package/src/elements/store/search-lsh.ts +179 -0
- package/src/elements/store/search-runtime.ts +300 -0
- package/src/elements/store/search.test.ts +144 -0
- package/src/elements/store/sql-session.test.ts +1 -0
- package/src/elements/store/sql-session.ts +83 -3
- package/src/elements/store/table.ts +23 -2
- package/src/elements/store/upsert-app.test.ts +1 -3
- package/src/elements/store.ts +50 -0
- package/src/full.ts +4 -2
- package/src/http.ts +4 -1
- package/src/i18n/catalogs/ar.ts +14 -6
- package/src/i18n/catalogs/en.ts +14 -6
- package/src/index.ts +6 -1
- package/src/kernel/adopt-barrel-fresh.test.ts +7 -7
- package/src/kernel/adopt-routes.ts +9 -1
- package/src/kernel/app-auth.ts +5 -0
- package/src/kernel/app.ts +102 -9
- package/src/kernel/auto-cache.test.ts +6 -12
- package/src/kernel/auto-registry.test.ts +3 -3
- package/src/kernel/boot-bind/ai.test.ts +22 -19
- package/src/kernel/boot-bind/ai.ts +5 -43
- package/src/kernel/boot-bind/clock.ts +23 -5
- package/src/kernel/boot-bind/honor-config.test.ts +4 -4
- package/src/kernel/boot.test.ts +11 -6
- package/src/kernel/boot.ts +66 -16
- package/src/kernel/boundary-contract.ts +93 -0
- package/src/kernel/budget.test.ts +1 -1
- package/src/kernel/call.ts +89 -0
- package/src/kernel/capability.ts +6 -0
- package/src/kernel/client-descriptor.ts +123 -0
- package/src/kernel/clock-timezone.test.ts +80 -0
- package/src/kernel/correlation.test.ts +1 -1
- package/src/kernel/dry-run.ts +11 -8
- package/src/kernel/effects-stamping.test.ts +42 -9
- package/src/kernel/effects.test.ts +4 -2
- package/src/kernel/effects.ts +51 -9
- package/src/kernel/errors-channel.ts +17 -0
- package/src/kernel/errors-live-resume.ts +3 -2
- package/src/kernel/errors-tenant.ts +7 -4
- package/src/kernel/errors.registry-helpers.ts +96 -0
- package/src/kernel/errors.registry.test.ts +139 -25
- package/src/kernel/errors.ts +102 -23
- package/src/kernel/external-effects.test.ts +196 -0
- package/src/kernel/flow.test.ts +13 -4
- package/src/kernel/flow.ts +69 -71
- package/src/kernel/fx-ask-telemetry.test.ts +2 -2
- package/src/kernel/fx-dead-letters.test.ts +3 -3
- package/src/kernel/fx-fetch.ts +55 -0
- package/src/kernel/fx-live-stream.ts +2 -2
- package/src/kernel/fx-live.test.ts +8 -8
- package/src/kernel/fx.test.ts +17 -11
- package/src/kernel/fx.ts +180 -57
- package/src/kernel/horizontal-child.ts +1 -1
- package/src/kernel/http-query.test.ts +3 -6
- package/src/kernel/index.ts +13 -3
- package/src/kernel/instance-id.ts +1 -1
- package/src/kernel/instances.test.ts +40 -0
- package/src/kernel/instances.ts +47 -9
- package/src/kernel/live-http.test.ts +6 -7
- package/src/kernel/live-http.ts +6 -2
- package/src/kernel/live-resume.test.ts +1 -1
- package/src/kernel/mcp-tool.test.ts +3 -3
- package/src/kernel/on.ts +98 -4
- package/src/kernel/pipeline.test.ts +12 -15
- package/src/kernel/plugin-elements.test.ts +1 -1
- package/src/kernel/stamp-http.test.ts +3 -3
- package/src/kernel/triggers.ts +210 -95
- package/src/kernel-entry.ts +0 -1
- package/src/manifest/diff.ts +11 -1
- package/src/manifest/fixtures/skyport.excerpt.json +1 -1
- package/src/manifest/types.ts +46 -2
- package/src/mcp/docs-index.ts +3 -3
- package/src/mcp/docs-mcp.test.ts +2 -2
- package/src/mcp/docs-tools.ts +1 -1
- package/src/okid.test.ts +56 -0
- package/src/okid.ts +55 -11
- package/src/plugins/anonymous.ts +8 -4
- package/src/plugins/auth/shared.ts +27 -3
- package/src/plugins/auth-delivery.mailpit.integration.test.ts +1 -1
- package/src/plugins/auth-methods.security.test.ts +561 -23
- package/src/plugins/config-source.ts +1 -1
- package/src/plugins/csrf.test.ts +65 -0
- package/src/plugins/index.ts +2 -0
- package/src/plugins/magic-link.ts +36 -16
- package/src/plugins/oauth/shared.ts +3 -1
- package/src/plugins/oauth.ts +22 -14
- package/src/plugins/otp.ts +37 -21
- package/src/plugins/passkey-webauthn.ts +9 -6
- package/src/plugins/passkey.ts +98 -26
- package/src/plugins/pre-account-hijack.test.ts +223 -0
- package/src/plugins/two-factor.ts +466 -37
- package/src/plugins/username.ts +19 -7
- package/src/release/build-lib.ts +1 -0
- package/src/release/limits.ts +2 -2
- package/src/release/measure.ts +1 -1
- package/src/runs/collect.test.ts +0 -2
- package/src/runtime/json-code-block.test.ts +250 -20
- package/src/runtime/json-code-block.ts +1261 -41
- package/src/term.test.ts +1 -1
- package/src/test/create-test-app.test.ts +12 -12
- package/src/test/live-signals.test.ts +6 -6
- package/src/test/provisions.integration.test.ts +10 -14
- package/src/test/reset-element-registries.ts +1 -1
- package/src/test/tenant-isolation.test.ts +12 -6
- package/site/content/docs/deployment/docker-swarm.mdx +0 -164
- package/site/content/docs/deployment/docker.mdx +0 -227
- package/site/content/docs/deployment/index.mdx +0 -83
- package/site/content/docs/deployment/kubernetes.mdx +0 -176
- package/site/content/docs/deployment/meta.json +0 -5
- package/site/content/docs/deployment/reverse-proxy.mdx +0 -234
- package/site/content/docs/elements/ai.mdx +0 -385
- package/site/content/docs/elements/channel.mdx +0 -346
- package/site/content/docs/elements/clock.mdx +0 -244
- package/site/content/docs/elements/flow.mdx +0 -420
- package/site/content/docs/elements/gate.mdx +0 -436
- package/site/content/docs/elements/signal.mdx +0 -380
- package/site/content/docs/elements/store.mdx +0 -1099
- package/site/content/docs/elements/vault.mdx +0 -405
- package/site/content/docs/get-started/basic-usage.mdx +0 -173
- package/site/content/docs/get-started/index.mdx +0 -43
- package/site/content/docs/get-started/installation.mdx +0 -220
- package/site/content/docs/get-started/introduction.mdx +0 -144
- package/site/content/docs/get-started/meta.json +0 -13
- package/site/content/docs/get-started/project-structure.mdx +0 -925
- package/site/content/docs/get-started/testing.mdx +0 -328
- package/site/content/docs/get-started/why.mdx +0 -114
- package/site/content/docs/recipes/llama-cpp.mdx +0 -151
- package/site/content/docs/recipes/ollama.mdx +0 -142
- package/site/content/docs/recipes/sglang.mdx +0 -105
- package/site/content/docs/recipes/vllm.mdx +0 -106
- package/site/content/docs/reference/cli.md +0 -232
- package/site/content/docs/reference/client.mdx +0 -469
- package/site/content/docs/reference/security.md +0 -74
- package/src/cli/ai-setup/detect-ollama.ts +0 -213
- package/src/cli/ai-setup/recommend.test.ts +0 -225
- package/src/cli/ai-setup/recommend.ts +0 -225
- package/src/cli/dev-controls.test.ts +0 -122
- package/src/cli/dev-controls.ts +0 -164
- package/src/cli/tui/DevLive.tsx +0 -126
- package/src/console/ui-next/dist/assets/access-page-3-EFj-2G.js +0 -4
- package/src/console/ui-next/dist/assets/agent-disclosure-BP0Y0Sux.js +0 -1
- package/src/console/ui-next/dist/assets/cache-glyph-B5X-NM0-.js +0 -1
- package/src/console/ui-next/dist/assets/call-pii-button-ChAUiLo9.js +0 -1
- package/src/console/ui-next/dist/assets/collapsible-DGnOM2ph.js +0 -1
- package/src/console/ui-next/dist/assets/copy-inline-button-DBHhgHKP.js +0 -1
- package/src/console/ui-next/dist/assets/dagre.esm-ZwcdTuZZ.js +0 -1
- package/src/console/ui-next/dist/assets/detail-header-DhHM1iaZ.js +0 -1
- package/src/console/ui-next/dist/assets/dropdown-menu-_NjTEo5_.js +0 -1
- package/src/console/ui-next/dist/assets/duration-tone-sC3lGABz.js +0 -9
- package/src/console/ui-next/dist/assets/element-icons-BVXtRyd3.js +0 -1
- package/src/console/ui-next/dist/assets/explorer-empty-2uIhBu0_.js +0 -1
- package/src/console/ui-next/dist/assets/flows-page-cVFnA4HH.js +0 -1
- package/src/console/ui-next/dist/assets/highlighted-json-Awq7gYdu.js +0 -154
- package/src/console/ui-next/dist/assets/http-method-_UHM2ODJ.js +0 -1
- package/src/console/ui-next/dist/assets/index-CMIgUbD0.js +0 -66
- package/src/console/ui-next/dist/assets/index-Ck88Jmv8.css +0 -2
- package/src/console/ui-next/dist/assets/link-BX6Vqztd.js +0 -1
- package/src/console/ui-next/dist/assets/observability-page-CQ3p34ip.js +0 -4
- package/src/console/ui-next/dist/assets/preload-helper-oH4irX4C.js +0 -1
- package/src/console/ui-next/dist/assets/react-D8E3mtu1.js +0 -1
- package/src/console/ui-next/dist/assets/react-dom-Bph1y7z7.js +0 -9
- package/src/console/ui-next/dist/assets/replica-lag-DKRrbvdo.js +0 -18
- package/src/console/ui-next/dist/assets/request-meta-DV0ywz7t.js +0 -1
- package/src/console/ui-next/dist/assets/shortcut-JQIZlWfm.js +0 -1
- package/src/console/ui-next/dist/assets/shortcut-keys-DKxNTe_m.js +0 -1
- package/src/console/ui-next/dist/assets/skeleton-D-czQJT6.js +0 -1
- package/src/console/ui-next/dist/assets/store-page-02xOiqIK.js +0 -41
- package/src/console/ui-next/dist/assets/trace-detail-sheet-B09O8rA6.js +0 -2
- package/src/console/ui-next/dist/assets/tree-expand-toggle-BtyhmWb4.js +0 -55
- package/src/console/ui-next/dist/assets/units-page-l8FeKfnP.js +0 -1
- package/src/console/ui-next/dist/assets/useMutation-B8EO02Ej.js +0 -1
- package/src/console/ui-next/dist/assets/useRender-BE2A9BWC.js +0 -1
- package/src/console/ui-next/dist/assets/vault-page-CL-d_mLE.js +0 -2
- package/src/console/ui-next/dist/assets/xyflow-D7n4g6go.js +0 -7
- package/src/console/ui-next/dist/assets/xyflow-DZ0Ws1xk.css +0 -1
- package/src/docker/ollama-pull.ts +0 -232
- package/src/docker/recipes/llama-cpp.ts +0 -298
- package/src/docker/recipes/ollama.ts +0 -44
- package/src/docker/recipes/sglang.ts +0 -55
- package/src/docker/recipes/vllm.ts +0 -44
- package/src/drivers/ai-ollama-tools.integration.test.ts +0 -109
- package/src/drivers/ai-ollama.integration.test.ts +0 -184
- package/src/drivers/ai-ollama.ts +0 -389
- package/src/drivers/ollama.ts +0 -14
|
@@ -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,114 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Why OKE
|
|
3
|
-
description: The problem of seams across independent backend tools, the insight, and the smaller model.
|
|
4
|
-
source: docs/spec/unified-theory.md
|
|
5
|
-
icon: Compass
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## The Problem: The Seams You Own
|
|
9
|
-
|
|
10
|
-
Modern backends accumulate many independently adopted systems: router, queue, cron, websockets, cache, secrets, mailer, AI wrappers, and observability.
|
|
11
|
-
|
|
12
|
-
<Callout title="A note on the count">
|
|
13
|
-
'Forty' is a representative illustration of the number of backend concerns developers commonly
|
|
14
|
-
assemble across modern stacks, not a literal census.
|
|
15
|
-
</Callout>
|
|
16
|
-
|
|
17
|
-
```text
|
|
18
|
-
many systems → many seams → many contracts → many mental models
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
Every TypeScript backend works on day one. The bill arrives later in the seams:
|
|
22
|
-
|
|
23
|
-
- **Cache that lies:** You update a writer, but forget the cache key in checkout.
|
|
24
|
-
- **Secret that fails at 2am:** Deploy boots fine; the first charge fails because the env var was missed.
|
|
25
|
-
- **Permission checks in the wrong place:** Auth logic scattered across handlers instead of verified at the trigger.
|
|
26
|
-
- **The dashboard that doesn't know you:** Observability tools learn routes from traffic samples instead of the compiled model.
|
|
27
|
-
|
|
28
|
-
## The Insight: One Programming Model
|
|
29
|
-
|
|
30
|
-
These concerns do not need to become separate programming concepts. They collapse into one closed set:
|
|
31
|
-
|
|
32
|
-
```text
|
|
33
|
-
Many backend concerns → One programming model
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
> **One law. Eight elements. One contract.**
|
|
37
|
-
|
|
38
|
-
## Wrong vs. Right Mental Model
|
|
39
|
-
|
|
40
|
-
Understanding OKE begins by rejecting the conventional feature-pile model:
|
|
41
|
-
|
|
42
|
-
| ❌ Wrong Mental Model (Feature Bundle) | ✅ OKEngine Model (Unified Primitives) |
|
|
43
|
-
| -------------------------------------- | -------------------------------------- |
|
|
44
|
-
| Router + Queue + Cron + Auth + ORM | `on(Trigger) → Flow` (One species) |
|
|
45
|
-
| Separate mental model per tool | Eight closed semantic elements |
|
|
46
|
-
| Ad-hoc side effects everywhere | Single door to the world: `fx` |
|
|
47
|
-
| Hand-maintained glue & OpenAPI | Compiled Manifest contract |
|
|
48
|
-
| Unchecked runtime drift | Derived, inspectable surfaces |
|
|
49
|
-
|
|
50
|
-
The difference is not how many features OKE has. It is how few concepts you need to understand.
|
|
51
|
-
|
|
52
|
-
## The Law and the `fx` Rule
|
|
53
|
-
|
|
54
|
-
Every backend behavior is a Flow:
|
|
55
|
-
|
|
56
|
-
```typescript
|
|
57
|
-
import { on, flow, http } from "okengine/http";
|
|
58
|
-
|
|
59
|
-
export const health = on(http.get().public(), flow({ do: () => ({ ok: true }) }));
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
**All world access goes through `fx`.** A Flow that calls `fetch` directly, imports `node:fs`, or uses `Date.now()` is a defect.
|
|
63
|
-
|
|
64
|
-
```text
|
|
65
|
-
Flow → fx → observable Effects → Compiler → Manifest → Surfaces
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
Because all effects pass through `fx`, the compiler infers cache keys, capability matrices, and trace trees without manual annotations.
|
|
69
|
-
|
|
70
|
-
## One Contract, Many Surfaces
|
|
71
|
-
|
|
72
|
-
The source of truth is the backend model expressed in code. The **Manifest** is the compiled, versioned contract representing that model.
|
|
73
|
-
|
|
74
|
-
| Surface | Port | You Maintain? |
|
|
75
|
-
| --------------------------------- | ------------------ | ----------------------------- |
|
|
76
|
-
| Typed client (`okengine/client`) | your app code | No — derived from Manifest |
|
|
77
|
-
| Console panels, traces, explorers | `:6533` | No — reads the Manifest |
|
|
78
|
-
| MCP for agents | `:6535` | No — reads the Manifest |
|
|
79
|
-
| Architecture diagram | Console | No — it _is_ the effect graph |
|
|
80
|
-
| Capability matrix + cache keys | compiler / runtime | No — inferred from `fx` |
|
|
81
|
-
|
|
82
|
-
Operational surfaces are derived, not separately maintained.
|
|
83
|
-
|
|
84
|
-
## See the Model Compose
|
|
85
|
-
|
|
86
|
-
OKE does not add new subsystems when new architectural requirements emerge. The eight closed primitives compose naturally:
|
|
87
|
-
|
|
88
|
-
- **Realtime:** `Store + Gate + Signal + Flow → Live Query` (Global CDC + RLS re-check + SSE).
|
|
89
|
-
- **Security:** `Gate + Store/RLS + Tenant + fx → Secure execution` (Unified user, operator, and agent boundaries).
|
|
90
|
-
- **Agents:** `MCP + Gate + OAuth + Flow → Agent-accessible backend` (Exposing Flows as MCP tools).
|
|
91
|
-
- **Operations:** `Manifest + Effects + Runs → Inspectable backend` (Wide-event telemetry and live graphs).
|
|
92
|
-
|
|
93
|
-
> **None of these required a ninth primitive.**
|
|
94
|
-
|
|
95
|
-
## Core Philosophy
|
|
96
|
-
|
|
97
|
-
> **Keep the model small. Let the backend grow without growing the mental model.**
|
|
98
|
-
|
|
99
|
-
Your backend is not just executable. It is inspectable.
|
|
100
|
-
|
|
101
|
-
## Next Steps
|
|
102
|
-
|
|
103
|
-
<Cards>
|
|
104
|
-
<Card
|
|
105
|
-
title="Introduction"
|
|
106
|
-
description="The Law, Flow anatomy, and the eight elements."
|
|
107
|
-
href="/docs/get-started/introduction"
|
|
108
|
-
/>
|
|
109
|
-
<Card
|
|
110
|
-
title="Installation"
|
|
111
|
-
description="Scaffold your first project with create-oke."
|
|
112
|
-
href="/docs/get-started/installation"
|
|
113
|
-
/>
|
|
114
|
-
</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>
|