okengine 0.18.4 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +18 -10
- package/README.md +2 -2
- package/package.json +51 -50
- package/site/content/docs/ai/index.mdx +25 -6
- package/site/content/docs/ai/llms-txt.mdx +1 -1
- package/site/content/docs/ai/meta.json +1 -1
- package/site/content/docs/ai/skills.mdx +4 -1
- package/site/content/docs/ai/try-it.mdx +58 -0
- package/site/content/docs/client/auth.mdx +208 -0
- package/site/content/docs/client/calling.mdx +451 -0
- package/site/content/docs/client/index.mdx +209 -0
- package/site/content/docs/client/live.mdx +234 -0
- package/site/content/docs/client/meta.json +5 -0
- package/site/content/docs/client/react.mdx +249 -0
- package/site/content/docs/elements/ai/agents.mdx +232 -0
- package/site/content/docs/elements/ai/index.mdx +341 -0
- package/site/content/docs/elements/ai/mcp.mdx +275 -0
- package/site/content/docs/elements/ai/meta.json +5 -0
- package/site/content/docs/elements/ai/models.mdx +283 -0
- package/site/content/docs/elements/ai/prompts.mdx +256 -0
- package/site/content/docs/elements/channel/email.mdx +266 -0
- package/site/content/docs/elements/channel/index.mdx +344 -0
- package/site/content/docs/elements/channel/meta.json +5 -0
- package/site/content/docs/elements/channel/push.mdx +218 -0
- package/site/content/docs/elements/channel/receipts.mdx +206 -0
- package/site/content/docs/elements/channel/sms.mdx +264 -0
- package/site/content/docs/elements/channel/whatsapp.mdx +220 -0
- package/site/content/docs/elements/clock/index.mdx +300 -0
- package/site/content/docs/elements/clock/meta.json +5 -0
- package/site/content/docs/elements/clock/schedules.mdx +508 -0
- package/site/content/docs/elements/clock/sleep.mdx +445 -0
- package/site/content/docs/elements/flow/consumers.mdx +707 -0
- package/site/content/docs/elements/flow/http.mdx +1080 -0
- package/site/content/docs/elements/flow/index.mdx +618 -0
- package/site/content/docs/elements/flow/meta.json +5 -0
- package/site/content/docs/elements/flow/routing.mdx +559 -0
- package/site/content/docs/elements/flow/workflows.mdx +640 -0
- package/site/content/docs/elements/gate/auth.mdx +371 -0
- package/site/content/docs/elements/gate/authorization.mdx +298 -0
- package/site/content/docs/elements/gate/index.mdx +418 -0
- package/site/content/docs/elements/gate/meta.json +5 -0
- package/site/content/docs/elements/gate/rate-limits.mdx +365 -0
- package/site/content/docs/elements/gate/rls.mdx +303 -0
- package/site/content/docs/elements/gate/tenancy.mdx +372 -0
- package/site/content/docs/elements/index.mdx +52 -11
- package/site/content/docs/elements/signal/broadcast.mdx +517 -0
- package/site/content/docs/elements/signal/index.mdx +352 -0
- package/site/content/docs/elements/signal/live.mdx +590 -0
- package/site/content/docs/elements/signal/meta.json +5 -0
- package/site/content/docs/elements/signal/once.mdx +596 -0
- package/site/content/docs/elements/store/files.mdx +659 -0
- package/site/content/docs/elements/store/index.mdx +310 -0
- package/site/content/docs/elements/store/kv.mdx +629 -0
- package/site/content/docs/elements/store/meta.json +5 -0
- package/site/content/docs/elements/store/search.mdx +946 -0
- package/site/content/docs/elements/store/sql.mdx +937 -0
- package/site/content/docs/elements/vault/config.mdx +256 -0
- package/site/content/docs/elements/vault/index.mdx +356 -0
- package/site/content/docs/elements/vault/meta.json +5 -0
- package/site/content/docs/elements/vault/rotation.mdx +273 -0
- package/site/content/docs/elements/vault/secrets.mdx +285 -0
- package/site/content/docs/index.mdx +78 -30
- package/site/content/docs/meta.json +11 -8
- package/site/content/docs/plugins/cors.mdx +2 -1
- package/site/content/docs/plugins/csrf.mdx +4 -1
- package/site/content/docs/plugins/headers.mdx +2 -1
- package/site/content/docs/plugins/ip-allowlist.mdx +2 -1
- package/site/content/docs/plugins/magic-link.mdx +6 -0
- package/site/content/docs/plugins/maintenance-mode.mdx +2 -1
- package/site/content/docs/plugins/oauth.mdx +1 -1
- package/site/content/docs/plugins/otp.mdx +12 -1
- package/site/content/docs/plugins/passkey.mdx +39 -15
- package/site/content/docs/plugins/two-factor.mdx +91 -34
- package/site/content/docs/plugins/username.mdx +1 -1
- package/site/content/docs/recipes/caddy.mdx +3 -3
- package/site/content/docs/recipes/index.mdx +18 -28
- package/site/content/docs/recipes/mailpit.mdx +1 -1
- package/site/content/docs/recipes/meilisearch.mdx +3 -3
- package/site/content/docs/recipes/meta.json +1 -4
- package/site/content/docs/recipes/nginx.mdx +2 -2
- package/site/content/docs/recipes/openrouter.mdx +283 -0
- package/site/content/docs/recipes/pgdog.mdx +3 -3
- package/site/content/docs/recipes/postgres.mdx +1 -2
- package/site/content/docs/recipes/rustfs.mdx +2 -2
- package/site/content/docs/recipes/traefik.mdx +3 -3
- package/site/content/docs/reference/cli.mdx +231 -0
- package/site/content/docs/reference/configuration.mdx +30 -10
- package/site/content/docs/reference/environment-variables.mdx +93 -20
- package/site/content/docs/reference/errors.mdx +132 -29
- package/site/content/docs/reference/fx.mdx +137 -73
- package/site/content/docs/reference/index.mdx +13 -21
- package/site/content/docs/reference/meta.json +4 -5
- package/site/content/docs/reference/okid.mdx +42 -17
- package/site/content/docs/reference/plugins.mdx +4 -3
- package/site/content/docs/reference/security.mdx +197 -0
- package/site/content/docs/understand/meta.json +5 -0
- package/site/content/docs/understand/the-anatomy.mdx +132 -0
- package/site/content/docs/understand/the-model.mdx +32 -0
- package/site/content/docs/understand/the-problem.mdx +74 -0
- package/site/content/docs/understand/the-vocabulary.mdx +26 -0
- package/src/auth/api-keys.ts +2 -1
- package/src/auth/bindings.ts +64 -16
- package/src/auth/gate-auth.test.ts +6 -1
- package/src/auth/identity.ts +152 -5
- package/src/auth/index.ts +29 -0
- package/src/auth/invites.ts +2 -1
- package/src/auth/method-context.ts +41 -0
- package/src/auth/oauth-as/crypto.ts +2 -1
- package/src/auth/oauth-as/stores.ts +2 -1
- package/src/auth/operator.ts +2 -1
- package/src/auth/sessions-jwt.test.ts +77 -0
- package/src/auth/sessions.ts +20 -4
- package/src/auth/tenants.ts +3 -2
- package/src/auth/two-factor-challenge.test.ts +61 -0
- package/src/auth/two-factor-challenge.ts +284 -0
- package/src/auth/verification.ts +5 -0
- package/src/bench/REPORT.md +49 -0
- package/src/bench/g03-signal-once.bench.ts +1 -1
- package/src/bench/g10-observability-contention.bench.ts +1 -1
- package/src/bench/g17-hybrid-search.bench.ts +572 -0
- package/src/bench/load-app.ts +2 -10
- package/src/cli/ai-setup/ai-setup.test.ts +331 -42
- package/src/cli/ai-setup/apply.ts +294 -52
- package/src/cli/ai-setup/catalog.ts +238 -1342
- package/src/cli/ai-setup/index.ts +14 -99
- package/src/cli/ai-setup/prompts.ts +60 -443
- package/src/cli/ask-seed.test.ts +96 -0
- package/src/cli/ask-seed.ts +82 -0
- package/src/cli/ask-vault-gaps.test.ts +84 -0
- package/src/cli/ask-vault-gaps.ts +146 -0
- package/src/cli/build.ts +2 -2
- package/src/cli/client-add.test.ts +26 -1
- package/src/cli/client-add.ts +106 -27
- package/src/cli/competitor-mention-removal.test.ts +1 -1
- package/src/cli/db-seed.ts +2 -0
- package/src/cli/db.ts +150 -11
- package/src/cli/dev.ts +119 -211
- package/src/cli/docker-clean.ts +2 -2
- package/src/cli/docker-cli.test.ts +1 -1
- package/src/cli/doctor-diff.ts +4 -2
- package/src/cli/doctor-pii.test.ts +1 -1
- package/src/cli/doctor.ts +14 -1
- package/src/cli/hero-meta.test.ts +4 -2
- package/src/cli/load-config.images.test.ts +8 -10
- package/src/cli/load-config.ts +1 -1
- package/src/cli/registry.ts +22 -10
- package/src/cli/replay.ts +3 -1
- package/src/cli/start.ts +1 -1
- package/src/cli/tui/keys.ts +2 -3
- package/src/client/auth/cookies.ts +74 -0
- package/src/client/auth/create-auth-client.ts +636 -0
- package/src/client/auth/denials.ts +99 -0
- package/src/client/auth/session.ts +283 -0
- package/src/client/auth.test.ts +251 -0
- package/src/client/auth.ts +39 -114
- package/src/client/create-with-session.ts +245 -0
- package/src/client/create.ts +51 -5
- package/src/client/index.ts +11 -1
- package/src/client/live.ts +11 -79
- package/src/client/notes-contract.test.ts +5 -10
- package/src/client/sse.ts +137 -0
- package/src/client/stream.ts +147 -0
- package/src/client/transport.test.ts +32 -0
- package/src/client/transport.ts +123 -26
- package/src/client/types.ts +118 -14
- package/src/client-react/index.ts +185 -24
- package/src/client-react/use-live-query.ts +13 -3
- package/src/compiler/aot.test.ts +7 -4
- package/src/compiler/effects-embed.test.ts +56 -0
- package/src/compiler/effects-fetch.test.ts +43 -0
- package/src/compiler/effects-infer.ts +58 -2
- package/src/compiler/extract.test.ts +258 -44
- package/src/compiler/extract.ts +566 -48
- package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +7 -4
- package/src/compiler/fixtures/skyport/src/flows/bookings/signals.ts +2 -8
- package/src/compiler/fixtures/skyport.expected.json +4 -4
- package/src/compiler/fixtures/triggers/five-triggers.ts +14 -10
- package/src/compiler/response.ts +2 -2
- package/src/compiler/search-writer-isolation.test.ts +40 -0
- package/src/config/index.ts +11 -0
- package/src/console/server/app.ts +17 -23
- package/src/console/server/bind.ts +4 -0
- package/src/console/server/console.test.ts +2 -2
- package/src/console/server/flows-invoke.test.ts +50 -34
- package/src/console/server/flows.ts +436 -255
- package/src/console/server/runs-ingest.test.ts +6 -3
- package/src/console/server/serve.ts +1 -1
- package/src/console/server/signals.test.ts +1 -5
- package/src/console/server/signals.ts +8 -6
- package/src/console/server/state.ts +6 -1
- package/src/console/server/store.ts +1 -1
- package/src/console/ui-next/dist/assets/FileExportIcon-Ck-5od4R.js +1 -0
- package/src/console/ui-next/dist/assets/MoreHorizontalCircle01Icon-gMNGsE37.js +1 -0
- package/src/console/ui-next/dist/assets/PlusSignIcon-CwG3nxfu.js +1 -0
- package/src/console/ui-next/dist/assets/UnavailableIcon-D9cvHVPr.js +1 -0
- package/src/console/ui-next/dist/assets/UserIcon-DaE2PB5_.js +1 -0
- package/src/console/ui-next/dist/assets/access-page-DFeymU07.js +4 -0
- package/src/console/ui-next/dist/assets/agent-disclosure-U1rdfblp.js +1 -0
- package/src/console/ui-next/dist/assets/cache-glyph-BeFJeqBG.js +1 -0
- package/src/console/ui-next/dist/assets/call-pii-button-CVAONPii.js +1 -0
- package/src/console/ui-next/dist/assets/collapsible-D2A6NJ-3.js +1 -0
- package/src/console/ui-next/dist/assets/copy-inline-button-CAYD18cr.js +1 -0
- package/src/console/ui-next/dist/assets/dagre.esm-B1_XeuLP.js +1 -0
- package/src/console/ui-next/dist/assets/detail-header-DVWNjWjg.js +1 -0
- package/src/console/ui-next/dist/assets/dropdown-menu-4h2LOVXM.js +1 -0
- package/src/console/ui-next/dist/assets/duration-tone-Cgk_h5ja.js +9 -0
- package/src/console/ui-next/dist/assets/element-icons-BI8cJgdh.js +1 -0
- package/src/console/ui-next/dist/assets/explorer-empty-CJs5A-wm.js +1 -0
- package/src/console/ui-next/dist/assets/flows-page-Dss7941e.js +1 -0
- package/src/console/ui-next/dist/assets/highlighted-json-MYZQtRnw.js +154 -0
- package/src/console/ui-next/dist/assets/http-method-Jrh39p7A.js +1 -0
- package/src/console/ui-next/dist/assets/index-D0zS5rKO.css +2 -0
- package/src/console/ui-next/dist/assets/index-DXP2dBIF.js +63 -0
- package/src/console/ui-next/dist/assets/observability-page-HvolXxTI.js +4 -0
- package/src/console/ui-next/dist/assets/react-dom-Ddte4I-Q.js +9 -0
- package/src/console/ui-next/dist/assets/replica-lag-CSh2dzrb.js +18 -0
- package/src/console/ui-next/dist/assets/request-meta-BatF8KrK.js +1 -0
- package/src/console/ui-next/dist/assets/shortcut-keys-3ILd8oGn.js +1 -0
- package/src/console/ui-next/dist/assets/{sql-BskegiFM.js → sql-BsFa4tDR.js} +1 -1
- package/src/console/ui-next/dist/assets/store-page-eiKiHnNe.js +41 -0
- package/src/console/ui-next/dist/assets/trace-detail-sheet-CZkMeKS-.js +2 -0
- package/src/console/ui-next/dist/assets/tree-expand-toggle-CW8y5A2h.js +55 -0
- package/src/console/ui-next/dist/assets/units-page-B_RWJrEO.js +1 -0
- package/src/console/ui-next/dist/assets/{use-vault-list-uk4WVboC.js → use-vault-list-CT4-gajj.js} +1 -1
- package/src/console/ui-next/dist/assets/vault-page-CWrg-A68.js +2 -0
- package/src/console/ui-next/dist/assets/xyflow-CSyC6ryz.css +1 -0
- package/src/console/ui-next/dist/assets/xyflow-yApv7D4e.js +7 -0
- package/src/console/ui-next/dist/index.html +6 -13
- package/src/console/ui-next/seed-invoke-host.ts +21 -18
- package/src/console/ui-next/src/client.ts +7 -2
- package/src/console/ui-next/src/features/flows/graph/element-map.ts +2 -0
- package/src/console/ui-next/src/features/flows/traces/effect-kind.ts +12 -2
- package/src/console/ui-next/src/features/flows/traces/effect-summary.ts +4 -0
- package/src/console/ui-next/src/features/flows/traces/trace-detail-sheet.tsx +8 -0
- package/src/console/ui-next/src/features/flows/traces/waterfall-bars.ts +4 -0
- package/src/console/ui-next/src/features/flows/traces/waterfall-tooltip.ts +9 -3
- package/src/console/ui-next/src/features/store/detail/reveal-cell.tsx +7 -11
- package/src/console/ui-next/src/features/store/detail/store-row-detail-sheet.tsx +2 -2
- package/src/console/ui-next/src/features/store/lib/fields-from-table.ts +2 -0
- package/src/console/ui-next/src/features/store/lib/grid-model.test.ts +25 -1
- package/src/console/ui-next/src/features/store/lib/grid-model.ts +36 -1
- package/src/console/ui-next/src/features/store/query/query-results.tsx +3 -3
- package/src/console/ui-next/src/features/units/detail/effects-summary.tsx +2 -0
- package/src/console/ui-next/src/features/units/lib/call-read-safe.ts +3 -1
- package/src/console/ui-next/src/features/units/lib/fields-from-schema.ts +6 -0
- package/src/docker/ai-model-status.test.ts +1 -12
- package/src/docker/ai-model-status.ts +10 -38
- package/src/docker/compose-up.test.ts +100 -0
- package/src/docker/compose-up.ts +292 -0
- package/src/docker/compose.ts +4 -14
- package/src/docker/derive.ts +9 -34
- package/src/docker/docker.test.ts +16 -261
- package/src/docker/images-config.test.ts +13 -25
- package/src/docker/index.ts +1 -24
- package/src/docker/recipes/index.ts +0 -23
- package/src/docker/recipes/pgdog.ts +6 -4
- package/src/docker/stack-id.test.ts +2 -2
- package/src/docker/stack-id.ts +0 -1
- package/src/docker/types.ts +2 -2
- package/src/drivers/ai-anthropic.ts +10 -0
- package/src/drivers/ai-openai-compatible.ts +34 -7
- package/src/drivers/ai-providers.test.ts +0 -107
- package/src/drivers/ai-stream.test.ts +0 -34
- package/src/drivers/ai-types.ts +17 -8
- package/src/drivers/channel-fcm.ts +6 -1
- package/src/drivers/channel-msegat.ts +6 -1
- package/src/drivers/channel-resend.ts +5 -1
- package/src/drivers/channel-smtp.ts +5 -1
- package/src/drivers/channel-sndr.ts +10 -1
- package/src/drivers/channel-taqnyat-mail.ts +5 -1
- package/src/drivers/channel-taqnyat-whatsapp.ts +6 -1
- package/src/drivers/channel-taqnyat.ts +6 -1
- package/src/drivers/channel-types.ts +10 -0
- package/src/drivers/channel-unifonic.ts +6 -1
- package/src/drivers/channel-wa-cloud.ts +6 -1
- package/src/drivers/channel-webpush.ts +6 -1
- package/src/drivers/external.ts +33 -0
- package/src/drivers/index.ts +0 -10
- package/src/drivers/meilisearch.ts +6 -0
- package/src/drivers/oauth-types.ts +4 -0
- package/src/drivers/postgres.test.ts +74 -3
- package/src/drivers/postgres.ts +175 -6
- package/src/drivers/signal-types.ts +5 -5
- package/src/drivers/types.ts +7 -0
- package/src/drivers/vault-types.ts +5 -0
- package/src/elements/ai/declare.ts +17 -4
- package/src/elements/ai/eval.ts +1 -1
- package/src/elements/ai/mcp-http.ts +1 -1
- package/src/elements/ai/pii.ts +1 -1
- package/src/elements/ai/providers.test.ts +289 -0
- package/src/elements/ai/providers.ts +169 -0
- package/src/elements/ai/runtime.ts +68 -5
- package/src/elements/ai/schema.ts +2 -2
- package/src/elements/ai.test.ts +7 -7
- package/src/elements/ai.ts +17 -1
- package/src/elements/channel/runtime.ts +105 -12
- package/src/elements/clock/cron-fields.test.ts +144 -0
- package/src/elements/clock/cron-fields.ts +185 -0
- package/src/elements/clock/declare.ts +247 -3
- package/src/elements/clock.ts +21 -1
- package/src/elements/index.ts +15 -0
- package/src/elements/signal/chaos-child.ts +1 -2
- package/src/elements/signal/declare.ts +65 -37
- package/src/elements/signal/delivery-modes.test.ts +11 -31
- package/src/elements/signal/dry-run-replay.test.ts +1 -7
- package/src/elements/signal/dry-run-write-isolation.test.ts +1 -7
- package/src/elements/signal/key-ordering.test.ts +6 -26
- package/src/elements/signal/lease-reclaim.test.ts +2 -6
- package/src/elements/signal/optional-emit.test.ts +6 -9
- package/src/elements/signal/order-lifecycle.test.ts +4 -17
- package/src/elements/signal/orphan-messages.test.ts +4 -15
- package/src/elements/signal/reconcile.test.ts +2 -2
- package/src/elements/signal/runtime.ts +1 -1
- package/src/elements/signal/schema-emit.test.ts +4 -8
- package/src/elements/signal.test.ts +24 -49
- package/src/elements/signal.ts +9 -2
- package/src/elements/store/domain-ddl.test.ts +1 -1
- package/src/elements/store/live-http.test.ts +9 -4
- package/src/elements/store/prepare-row.test.ts +123 -0
- package/src/elements/store/resource.ts +43 -12
- package/src/elements/store/schema-decl.ts +117 -0
- package/src/elements/store/search-backfill.ts +205 -0
- package/src/elements/store/search-bind.ts +66 -0
- package/src/elements/store/search-bm25.ts +78 -0
- package/src/elements/store/search-ddl.ts +156 -0
- package/src/elements/store/search-embed-flow.ts +141 -0
- package/src/elements/store/search-errors.ts +34 -0
- package/src/elements/store/search-fusion.ts +112 -0
- package/src/elements/store/search-lsh.ts +179 -0
- package/src/elements/store/search-runtime.ts +300 -0
- package/src/elements/store/search.test.ts +144 -0
- package/src/elements/store/sql-session.test.ts +1 -0
- package/src/elements/store/sql-session.ts +83 -3
- package/src/elements/store/table.ts +23 -2
- package/src/elements/store/upsert-app.test.ts +1 -3
- package/src/elements/store.ts +50 -0
- package/src/full.ts +4 -2
- package/src/http.ts +4 -1
- package/src/i18n/catalogs/ar.ts +14 -6
- package/src/i18n/catalogs/en.ts +14 -6
- package/src/index.ts +6 -1
- package/src/kernel/adopt-barrel-fresh.test.ts +7 -7
- package/src/kernel/adopt-routes.ts +9 -1
- package/src/kernel/app-auth.ts +5 -0
- package/src/kernel/app.ts +102 -9
- package/src/kernel/auto-cache.test.ts +6 -12
- package/src/kernel/auto-registry.test.ts +3 -3
- package/src/kernel/boot-bind/ai.test.ts +22 -19
- package/src/kernel/boot-bind/ai.ts +5 -43
- package/src/kernel/boot-bind/clock.ts +23 -5
- package/src/kernel/boot-bind/honor-config.test.ts +4 -4
- package/src/kernel/boot.test.ts +11 -6
- package/src/kernel/boot.ts +66 -16
- package/src/kernel/boundary-contract.ts +93 -0
- package/src/kernel/budget.test.ts +1 -1
- package/src/kernel/call.ts +89 -0
- package/src/kernel/capability.ts +6 -0
- package/src/kernel/client-descriptor.ts +123 -0
- package/src/kernel/clock-timezone.test.ts +80 -0
- package/src/kernel/correlation.test.ts +1 -1
- package/src/kernel/dry-run.ts +11 -8
- package/src/kernel/effects-stamping.test.ts +42 -9
- package/src/kernel/effects.test.ts +4 -2
- package/src/kernel/effects.ts +51 -9
- package/src/kernel/errors-channel.ts +17 -0
- package/src/kernel/errors-live-resume.ts +3 -2
- package/src/kernel/errors-tenant.ts +7 -4
- package/src/kernel/errors.registry-helpers.ts +96 -0
- package/src/kernel/errors.registry.test.ts +139 -25
- package/src/kernel/errors.ts +102 -23
- package/src/kernel/external-effects.test.ts +196 -0
- package/src/kernel/flow.test.ts +13 -4
- package/src/kernel/flow.ts +69 -71
- package/src/kernel/fx-ask-telemetry.test.ts +2 -2
- package/src/kernel/fx-dead-letters.test.ts +3 -3
- package/src/kernel/fx-fetch.ts +55 -0
- package/src/kernel/fx-live-stream.ts +2 -2
- package/src/kernel/fx-live.test.ts +8 -8
- package/src/kernel/fx.test.ts +17 -11
- package/src/kernel/fx.ts +180 -57
- package/src/kernel/horizontal-child.ts +1 -1
- package/src/kernel/http-query.test.ts +3 -6
- package/src/kernel/index.ts +13 -3
- package/src/kernel/instance-id.ts +1 -1
- package/src/kernel/instances.test.ts +40 -0
- package/src/kernel/instances.ts +47 -9
- package/src/kernel/live-http.test.ts +6 -7
- package/src/kernel/live-http.ts +6 -2
- package/src/kernel/live-resume.test.ts +1 -1
- package/src/kernel/mcp-tool.test.ts +3 -3
- package/src/kernel/on.ts +98 -4
- package/src/kernel/pipeline.test.ts +12 -15
- package/src/kernel/plugin-elements.test.ts +1 -1
- package/src/kernel/stamp-http.test.ts +3 -3
- package/src/kernel/triggers.ts +210 -95
- package/src/kernel-entry.ts +0 -1
- package/src/manifest/diff.ts +11 -1
- package/src/manifest/fixtures/skyport.excerpt.json +1 -1
- package/src/manifest/types.ts +46 -2
- package/src/mcp/docs-index.ts +3 -3
- package/src/mcp/docs-mcp.test.ts +2 -2
- package/src/mcp/docs-tools.ts +1 -1
- package/src/okid.test.ts +56 -0
- package/src/okid.ts +55 -11
- package/src/plugins/anonymous.ts +8 -4
- package/src/plugins/auth/shared.ts +27 -3
- package/src/plugins/auth-delivery.mailpit.integration.test.ts +1 -1
- package/src/plugins/auth-methods.security.test.ts +561 -23
- package/src/plugins/config-source.ts +1 -1
- package/src/plugins/csrf.test.ts +65 -0
- package/src/plugins/index.ts +2 -0
- package/src/plugins/magic-link.ts +36 -16
- package/src/plugins/oauth/shared.ts +3 -1
- package/src/plugins/oauth.ts +22 -14
- package/src/plugins/otp.ts +37 -21
- package/src/plugins/passkey-webauthn.ts +9 -6
- package/src/plugins/passkey.ts +98 -26
- package/src/plugins/pre-account-hijack.test.ts +223 -0
- package/src/plugins/two-factor.ts +466 -37
- package/src/plugins/username.ts +19 -7
- package/src/release/build-lib.ts +1 -0
- package/src/release/limits.ts +2 -2
- package/src/release/measure.ts +1 -1
- package/src/runs/collect.test.ts +0 -2
- package/src/runtime/json-code-block.test.ts +250 -20
- package/src/runtime/json-code-block.ts +1261 -41
- package/src/term.test.ts +1 -1
- package/src/test/create-test-app.test.ts +12 -12
- package/src/test/live-signals.test.ts +6 -6
- package/src/test/provisions.integration.test.ts +10 -14
- package/src/test/reset-element-registries.ts +1 -1
- package/src/test/tenant-isolation.test.ts +12 -6
- package/site/content/docs/deployment/docker-swarm.mdx +0 -164
- package/site/content/docs/deployment/docker.mdx +0 -227
- package/site/content/docs/deployment/index.mdx +0 -83
- package/site/content/docs/deployment/kubernetes.mdx +0 -176
- package/site/content/docs/deployment/meta.json +0 -5
- package/site/content/docs/deployment/reverse-proxy.mdx +0 -234
- package/site/content/docs/elements/ai.mdx +0 -385
- package/site/content/docs/elements/channel.mdx +0 -346
- package/site/content/docs/elements/clock.mdx +0 -244
- package/site/content/docs/elements/flow.mdx +0 -420
- package/site/content/docs/elements/gate.mdx +0 -436
- package/site/content/docs/elements/signal.mdx +0 -380
- package/site/content/docs/elements/store.mdx +0 -1099
- package/site/content/docs/elements/vault.mdx +0 -405
- package/site/content/docs/get-started/basic-usage.mdx +0 -173
- package/site/content/docs/get-started/index.mdx +0 -43
- package/site/content/docs/get-started/installation.mdx +0 -220
- package/site/content/docs/get-started/introduction.mdx +0 -132
- package/site/content/docs/get-started/meta.json +0 -13
- package/site/content/docs/get-started/project-structure.mdx +0 -925
- package/site/content/docs/get-started/testing.mdx +0 -328
- package/site/content/docs/get-started/why.mdx +0 -162
- package/site/content/docs/recipes/llama-cpp.mdx +0 -151
- package/site/content/docs/recipes/ollama.mdx +0 -142
- package/site/content/docs/recipes/sglang.mdx +0 -105
- package/site/content/docs/recipes/vllm.mdx +0 -106
- package/site/content/docs/reference/cli.md +0 -232
- package/site/content/docs/reference/client.mdx +0 -469
- package/site/content/docs/reference/security.md +0 -74
- package/src/cli/ai-setup/detect-ollama.ts +0 -213
- package/src/cli/ai-setup/recommend.test.ts +0 -225
- package/src/cli/ai-setup/recommend.ts +0 -225
- package/src/cli/dev-controls.test.ts +0 -122
- package/src/cli/dev-controls.ts +0 -164
- package/src/cli/tui/DevLive.tsx +0 -126
- package/src/console/ui-next/dist/assets/access-page-De7Lc2JC.js +0 -4
- package/src/console/ui-next/dist/assets/agent-disclosure-BP0Y0Sux.js +0 -1
- package/src/console/ui-next/dist/assets/cache-glyph-B5X-NM0-.js +0 -1
- package/src/console/ui-next/dist/assets/call-pii-button-ChAUiLo9.js +0 -1
- package/src/console/ui-next/dist/assets/collapsible-DGnOM2ph.js +0 -1
- package/src/console/ui-next/dist/assets/copy-inline-button-DBHhgHKP.js +0 -1
- package/src/console/ui-next/dist/assets/dagre.esm-ZwcdTuZZ.js +0 -1
- package/src/console/ui-next/dist/assets/detail-header-DhHM1iaZ.js +0 -1
- package/src/console/ui-next/dist/assets/dropdown-menu-_NjTEo5_.js +0 -1
- package/src/console/ui-next/dist/assets/duration-tone-sC3lGABz.js +0 -9
- package/src/console/ui-next/dist/assets/element-icons-BVXtRyd3.js +0 -1
- package/src/console/ui-next/dist/assets/explorer-empty-2uIhBu0_.js +0 -1
- package/src/console/ui-next/dist/assets/flows-page-RGy7VEA_.js +0 -1
- package/src/console/ui-next/dist/assets/highlighted-json-Awq7gYdu.js +0 -154
- package/src/console/ui-next/dist/assets/http-method-_UHM2ODJ.js +0 -1
- package/src/console/ui-next/dist/assets/index-Ck88Jmv8.css +0 -2
- package/src/console/ui-next/dist/assets/index-_rgpdVzo.js +0 -66
- package/src/console/ui-next/dist/assets/link-BX6Vqztd.js +0 -1
- package/src/console/ui-next/dist/assets/observability-page-Ds6pcnh-.js +0 -4
- package/src/console/ui-next/dist/assets/preload-helper-oH4irX4C.js +0 -1
- package/src/console/ui-next/dist/assets/react-D8E3mtu1.js +0 -1
- package/src/console/ui-next/dist/assets/react-dom-Bph1y7z7.js +0 -9
- package/src/console/ui-next/dist/assets/replica-lag-DKRrbvdo.js +0 -18
- package/src/console/ui-next/dist/assets/request-meta-DV0ywz7t.js +0 -1
- package/src/console/ui-next/dist/assets/shortcut-JQIZlWfm.js +0 -1
- package/src/console/ui-next/dist/assets/shortcut-keys-DKxNTe_m.js +0 -1
- package/src/console/ui-next/dist/assets/skeleton-D-czQJT6.js +0 -1
- package/src/console/ui-next/dist/assets/store-page-02xOiqIK.js +0 -41
- package/src/console/ui-next/dist/assets/trace-detail-sheet-B09O8rA6.js +0 -2
- package/src/console/ui-next/dist/assets/tree-expand-toggle-BtyhmWb4.js +0 -55
- package/src/console/ui-next/dist/assets/units-page-4rHOePuE.js +0 -1
- package/src/console/ui-next/dist/assets/useMutation-B8EO02Ej.js +0 -1
- package/src/console/ui-next/dist/assets/useRender-BE2A9BWC.js +0 -1
- package/src/console/ui-next/dist/assets/vault-page-DISPgxLM.js +0 -2
- package/src/console/ui-next/dist/assets/xyflow-D7n4g6go.js +0 -7
- package/src/console/ui-next/dist/assets/xyflow-DZ0Ws1xk.css +0 -1
- package/src/docker/ollama-pull.ts +0 -232
- package/src/docker/recipes/llama-cpp.ts +0 -298
- package/src/docker/recipes/ollama.ts +0 -44
- package/src/docker/recipes/sglang.ts +0 -55
- package/src/docker/recipes/vllm.ts +0 -44
- package/src/drivers/ai-ollama-tools.integration.test.ts +0 -109
- package/src/drivers/ai-ollama.integration.test.ts +0 -184
- package/src/drivers/ai-ollama.ts +0 -389
- package/src/drivers/ollama.ts +0 -14
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Calling"
|
|
3
|
+
description: "createClient forms, REST vs RPC, options, result envelopes, store resources, and remote types."
|
|
4
|
+
icon: "Braces"
|
|
5
|
+
source: "docs/spec/unified-theory.md"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
`createClient` builds a typed proxy over your adopted Flows. HTTP triggers go out as REST from
|
|
9
|
+
`$routes`; untriggered Flows fall back to RPC. Every call returns `{ data, error }` — never a
|
|
10
|
+
thrown domain failure.
|
|
11
|
+
|
|
12
|
+
For developers wiring a storefront, mobile app, or partner service to an okengine backend (port
|
|
13
|
+
**6530**).
|
|
14
|
+
|
|
15
|
+
<Callout title="The one rule">
|
|
16
|
+
Treat every call as a result envelope: `{ data, error }`. Switch on `error.code`. Only transport
|
|
17
|
+
/ protocol problems use `code: "TransportError"`.
|
|
18
|
+
</Callout>
|
|
19
|
+
|
|
20
|
+
## Smallest Example
|
|
21
|
+
|
|
22
|
+
<Steps>
|
|
23
|
+
|
|
24
|
+
<Step>
|
|
25
|
+
### Create the client from the app
|
|
26
|
+
|
|
27
|
+
```typescript title="web/src/api.ts"
|
|
28
|
+
import { createClient } from "okengine/client";
|
|
29
|
+
import { vault } from "okengine/vault";
|
|
30
|
+
import { app } from "../../src/app";
|
|
31
|
+
|
|
32
|
+
export const api = createClient(app, vault.env("PUBLIC_API_URL") ?? "");
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
</Step>
|
|
36
|
+
|
|
37
|
+
<Step>
|
|
38
|
+
### Confirm a booking and narrow the result
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
const { data, error } = await api.bookings.get({ id: "bkg_7f3a" });
|
|
42
|
+
|
|
43
|
+
if (error) {
|
|
44
|
+
// show “booking not found” or a network banner
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
renderConfirmation(data.confirmationCode, data.seats);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Envelope:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"data": {
|
|
56
|
+
"id": "bkg_7f3a",
|
|
57
|
+
"confirmationCode": "SK-4812",
|
|
58
|
+
"seats": 2,
|
|
59
|
+
"status": "confirmed"
|
|
60
|
+
},
|
|
61
|
+
"error": null
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
</Step>
|
|
66
|
+
|
|
67
|
+
</Steps>
|
|
68
|
+
|
|
69
|
+
## Base URL (Vault + env)
|
|
70
|
+
|
|
71
|
+
Do not paste origins into source. Declare the public API origin as Vault config, then read it from
|
|
72
|
+
env in each runtime:
|
|
73
|
+
|
|
74
|
+
```typescript title="src/core/vault.ts"
|
|
75
|
+
import { vault } from "okengine/vault";
|
|
76
|
+
import { z } from "zod";
|
|
77
|
+
|
|
78
|
+
export const publicApiUrl = vault.config("PUBLIC_API_URL", {
|
|
79
|
+
description: "Browser-facing API origin",
|
|
80
|
+
schema: z.string().url(),
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
| Runtime | Base URL for `createClient` |
|
|
85
|
+
| ------------------------------------------ | --------------------------------------------------------------- |
|
|
86
|
+
| Browser / Bun (create-oke web) | `vault.env("PUBLIC_API_URL") ?? ""` — empty = same-origin proxy |
|
|
87
|
+
| Node / worker / CLI | `vault.env.required("PUBLIC_API_URL")` |
|
|
88
|
+
| Separate storefront after `oke client add` | Same `vault.env("PUBLIC_API_URL") ?? ""` |
|
|
89
|
+
|
|
90
|
+
Set `PUBLIC_API_URL` via environment or `oke vault set`. Prefer `vault.env` over raw
|
|
91
|
+
`process.env` — same helpers as the rest of the measure. See
|
|
92
|
+
[Vault · Config](/docs/elements/vault/config).
|
|
93
|
+
|
|
94
|
+
## Progressive Patterns
|
|
95
|
+
|
|
96
|
+
From a simple read to typed domain failures and transport errors:
|
|
97
|
+
|
|
98
|
+
<Tabs items={["Minimal", "Narrow", "Failures", "Transport", "Binary"]}>
|
|
99
|
+
|
|
100
|
+
<Tab value="Minimal">
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
const { data, error } = await api.bookings.get({ id: "bkg_7f3a" });
|
|
104
|
+
if (error) return;
|
|
105
|
+
showSeatMap(data.seats);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
</Tab>
|
|
109
|
+
|
|
110
|
+
<Tab value="Narrow">
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
import { isOk } from "okengine/client";
|
|
114
|
+
|
|
115
|
+
const result = await api.orders.get({ id: "ord_9c2e" });
|
|
116
|
+
|
|
117
|
+
if (isOk(result)) {
|
|
118
|
+
result.data.trackingNumber;
|
|
119
|
+
result.data.eta;
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
</Tab>
|
|
124
|
+
|
|
125
|
+
<Tab value="Failures">
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { isOk, isErrorCode } from "okengine/client";
|
|
129
|
+
|
|
130
|
+
const result = await api.bookings.create({
|
|
131
|
+
flightId: "SK481",
|
|
132
|
+
seats: 2,
|
|
133
|
+
cabin: "economy",
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
if (isOk(result)) {
|
|
137
|
+
result.data.confirmationCode;
|
|
138
|
+
} else if (result.error.code === "FlightFull") {
|
|
139
|
+
offerWaitlist(result.error.data.seatsLeft);
|
|
140
|
+
} else if (isErrorCode(result.error, "NotFound")) {
|
|
141
|
+
// shared helper narrowing
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Prefer `error?.code === "FlightFull"` for inference; use `isErrorCode` in shared helpers.
|
|
146
|
+
|
|
147
|
+
</Tab>
|
|
148
|
+
|
|
149
|
+
<Tab value="Transport">
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
import { isTransportError } from "okengine/client";
|
|
153
|
+
|
|
154
|
+
const result = await api.orders.list({ limit: 20, status: "shipped" });
|
|
155
|
+
|
|
156
|
+
if (result.error && isTransportError(result.error)) {
|
|
157
|
+
showOfflineBanner(result.error.data.message);
|
|
158
|
+
// optional: result.error.data.status
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Network failure, abort (`timeout`), non-JSON body, or HTTP status without a `{ data, error }`
|
|
163
|
+
envelope — never a declared Flow code.
|
|
164
|
+
|
|
165
|
+
</Tab>
|
|
166
|
+
|
|
167
|
+
<Tab value="Binary">
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
const { data, error } = await api.files.download({ id: "file_1" }, { response: "blob" });
|
|
171
|
+
if (error || !data) return;
|
|
172
|
+
a.href = URL.createObjectURL(data);
|
|
173
|
+
a.download = "report.pdf";
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Same `{ data, error }` envelope; `{ response: "arrayBuffer" }` for raw bytes. Default remains
|
|
177
|
+
JSON envelopes.
|
|
178
|
+
|
|
179
|
+
</Tab>
|
|
180
|
+
|
|
181
|
+
</Tabs>
|
|
182
|
+
|
|
183
|
+
## `createClient` forms
|
|
184
|
+
|
|
185
|
+
| Form | Types from | Wire |
|
|
186
|
+
| ------------------------------- | -------------------------------------- | ------------------------------------------------ |
|
|
187
|
+
| `createClient(app, url, opts?)` | `typeof app` | REST from `app.$routes`; untriggered flows → RPC |
|
|
188
|
+
| `createClient<App>(url, opts?)` | Explicit `App` type | RPC unless `opts.$routes` or `opts.routes` |
|
|
189
|
+
| `createClient(url, opts?)` | Ambient `Register` (`oke-client.d.ts`) | Same — pass routes for REST |
|
|
190
|
+
|
|
191
|
+
`url` is the app origin from `vault.env("PUBLIC_API_URL")` — empty string means same-origin.
|
|
192
|
+
See [Base URL](#base-url-vault--env).
|
|
193
|
+
|
|
194
|
+
**Consequence:** `createClient<App>(url)` alone types the proxy but still posts
|
|
195
|
+
`POST /_oke/{unit}/{flow}` until you pass the app value, `$routes`, or `routes`.
|
|
196
|
+
|
|
197
|
+
## REST vs RPC
|
|
198
|
+
|
|
199
|
+
| Situation | Request |
|
|
200
|
+
| ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
201
|
+
| HTTP trigger with method + path on `$routes` | That method and path (`:id` filled from input; leftover fields → query on GET/HEAD, JSON body otherwise). QUERY always sends JSON (`{}` when only path params) |
|
|
202
|
+
| Adopted flow with no HTTP trigger | `POST {base}/_oke/{unit}/{flow}` with JSON body |
|
|
203
|
+
| Incomplete proxy path (`api.bookings()` with no flow) | Result error: `Incomplete path: api.bookings(…)` |
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
// REST — method/path from the bound HTTP trigger (file tree or explicit)
|
|
207
|
+
await api.bookings.get({ id: "bkg_7f3a" }); // GET /bookings/bkg_7f3a
|
|
208
|
+
|
|
209
|
+
// RPC — untriggered flow named bookings.manifest (internal tally)
|
|
210
|
+
await api.bookings.manifest({ flightId: "SK481" }); // POST /_oke/bookings/manifest
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Full file-tree rules: [Routing](/docs/elements/flow/routing).
|
|
214
|
+
|
|
215
|
+
## How input becomes a request
|
|
216
|
+
|
|
217
|
+
Before the wire call, the client maps `input` onto the REST template or the RPC body:
|
|
218
|
+
|
|
219
|
+
1. **Path params** — `:id` (and friends) filled from matching input keys.
|
|
220
|
+
2. **Leftover fields** — query string on GET/HEAD; JSON body otherwise.
|
|
221
|
+
3. **QUERY** — always JSON (`{}` when only path params remain).
|
|
222
|
+
4. **RPC** — whole input as JSON on `POST /_oke/{unit}/{flow}`.
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
await api.orders.get({ id: "ord_9c2e" });
|
|
226
|
+
// GET /orders/ord_9c2e
|
|
227
|
+
|
|
228
|
+
await api.orders.list({ limit: 20, q: "stockholm" });
|
|
229
|
+
// GET /orders?limit=20&q=stockholm (when list is GET on $routes)
|
|
230
|
+
|
|
231
|
+
await api.bookings.create({ flightId: "SK481", seats: 2 });
|
|
232
|
+
// POST /bookings with JSON body
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Call shapes
|
|
236
|
+
|
|
237
|
+
<Tabs items={["unit.flow", "List pager", "for await", "Empty 204"]}>
|
|
238
|
+
|
|
239
|
+
<Tab value="unit.flow">
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
const { data, error } = await api.orders.get({ id: "ord_9c2e" });
|
|
243
|
+
if (error) return;
|
|
244
|
+
data.trackingNumber;
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
</Tab>
|
|
248
|
+
|
|
249
|
+
<Tab value="List pager">
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
const page = await api.orders.list({ limit: 20, status: "open" });
|
|
253
|
+
const more = await page.next();
|
|
254
|
+
|
|
255
|
+
// meta.next / meta.prev are { cursor } bags — spread them, or use page.next()
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
TanStack `useInfiniteQuery` takes the bag, not the methods:
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
useInfiniteQuery({
|
|
262
|
+
queryKey: ["orders", status],
|
|
263
|
+
queryFn: ({ pageParam }) => api.orders.list({ limit: 20, status, ...pageParam }),
|
|
264
|
+
initialPageParam: {} as { cursor?: string },
|
|
265
|
+
getNextPageParam: (last) => last.meta.next ?? undefined,
|
|
266
|
+
getPreviousPageParam: (last) => last.meta.prev ?? undefined,
|
|
267
|
+
});
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
</Tab>
|
|
271
|
+
|
|
272
|
+
<Tab value="for await">
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
for await (const page of api.orders.list({ limit: 20, status: "shipped" })) {
|
|
276
|
+
for (const order of page.data) renderRow(order);
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
</Tab>
|
|
281
|
+
|
|
282
|
+
<Tab value="Empty 204">
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
await api.orders.remove({ id: "ord_9c2e" }); // DELETE → 204, data undefined
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
</Tab>
|
|
289
|
+
|
|
290
|
+
</Tabs>
|
|
291
|
+
|
|
292
|
+
## Resources
|
|
293
|
+
|
|
294
|
+
Mount a resource, adopt the returned ops, then call the five Flows like any other:
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
const ordersR = store.resource(db, orders, {/* in, out, list */});
|
|
298
|
+
const mounted = on(http.resource("/orders", ordersR.all()).gate(member));
|
|
299
|
+
// .adopt({ orders: mounted }) →
|
|
300
|
+
const page = await api.orders.list({ limit: 20, status: "open" });
|
|
301
|
+
await api.orders.get({ id: "ord_9c2e" }); // GET /orders/:id — NotFound when missing
|
|
302
|
+
await api.orders.remove({ id: "ord_9c2e" }); // DELETE → 204
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
See [Store](/docs/elements/store) for the list query language. Handwritten lists use
|
|
306
|
+
`fx.json.withQuery(rows, input)` for the same envelope. Auth posture:
|
|
307
|
+
[Gate](/docs/elements/gate). Live mounts: [Live](/docs/client/live).
|
|
308
|
+
|
|
309
|
+
## Options
|
|
310
|
+
|
|
311
|
+
| Option | Type | Default | Meaning |
|
|
312
|
+
| --------------- | ---------------------------------------------- | ------------------ | -------------------------------------------------------------- |
|
|
313
|
+
| `fetch` | `(input, init?) => Promise<Response>` | `globalThis.fetch` | Inject a fetch implementation |
|
|
314
|
+
| `headers` | `Record<string, string>` \| pairs \| `() => …` | — | Static headers, or a getter per request |
|
|
315
|
+
| `timeout` | `number` (ms) | — | Abort after this many milliseconds |
|
|
316
|
+
| `retry.retries` | `number` | `0` | Extra attempts after the first (network / 5xx) |
|
|
317
|
+
| `retry.delay` | `number` (ms) | `50` | Initial backoff delay |
|
|
318
|
+
| `retry.backoff` | `number` | `2` | Multiplier after each retry |
|
|
319
|
+
| `auth.getToken` | `() => string \| null \| …` | — | Bearer access token (or null) — see [Auth](/docs/client/auth) |
|
|
320
|
+
| `auth.refresh` | `() => Promise<string \| null \| …>` | — | Runs once on HTTP 401, then the request retries |
|
|
321
|
+
| `$routes` | `ClientRouteMap` | — | Runtime map from `app.$routes` (REST when method+path present) |
|
|
322
|
+
| `routes` | `Record<"unit.flow", { method, path }>` | — | Flat REST table; wins over flattening `$routes` |
|
|
323
|
+
|
|
324
|
+
## Result envelopes
|
|
325
|
+
|
|
326
|
+
Success may include optional top-level `meta` (for example pagination). Declared flow errors and
|
|
327
|
+
transport failures share the failure arm:
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
import { isOk, isFail, isErrorCode, isTransportError } from "okengine/client";
|
|
331
|
+
|
|
332
|
+
const result = await api.bookings.create({ flightId: "SK481", seats: 2 });
|
|
333
|
+
|
|
334
|
+
if (isOk(result)) {
|
|
335
|
+
result.data.confirmationCode;
|
|
336
|
+
} else if (result.error.code === "FlightFull") {
|
|
337
|
+
result.error.data.seatsLeft;
|
|
338
|
+
} else if (isTransportError(result.error)) {
|
|
339
|
+
result.error.data.message;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
isFail(result); // true when error !== null
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
## Remote types
|
|
346
|
+
|
|
347
|
+
`oke dev` regenerates `oke-client.d.ts` from `GET /_oke/client.json`. A separate storefront repo —
|
|
348
|
+
pass the origin from Vault / env (never a hardcoded host in source):
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
oke client add "$PUBLIC_API_URL"
|
|
352
|
+
oke client add "$PUBLIC_API_URL" --out ./types/oke-client.d.ts
|
|
353
|
+
# also writes oke-client.routes.ts (or types/oke-client.routes.ts)
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
```typescript
|
|
357
|
+
import { createClient } from "okengine/client";
|
|
358
|
+
import { routes } from "./oke-client.routes.ts";
|
|
359
|
+
|
|
360
|
+
const api = createClient(import.meta.env.PUBLIC_API_URL ?? "", { $routes: routes });
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Ambient `.d.ts` types `in` / `out` / live / stream stamps. The routes module supplies wire REST.
|
|
364
|
+
|
|
365
|
+
create-oke starters ship `web/`: Vite proxies Flow paths plus `/auth` and `/_oke` to the app.
|
|
366
|
+
Leave `PUBLIC_API_URL` unset in local web so `createClient("")` stays same-origin.
|
|
367
|
+
|
|
368
|
+
CLI details: [CLI Reference](/docs/reference/cli).
|
|
369
|
+
|
|
370
|
+
## Exports
|
|
371
|
+
|
|
372
|
+
| Export | Kind | Role |
|
|
373
|
+
| ----------------------------------------- | --------- | --------------------------------------------------- |
|
|
374
|
+
| `createClient` | function | Typed proxy `api.unit.flow(input?)` plus `api.live` |
|
|
375
|
+
| `flattenRoutes` | function | `$routes` → flat `unit.flow` REST table |
|
|
376
|
+
| `createTransport` | function | Low-level HTTP transport (timeout / retry / auth) |
|
|
377
|
+
| `isOk` / `isFail` | function | Envelope predicates |
|
|
378
|
+
| `isErrorCode` / `isTransportError` | function | Error narrowing |
|
|
379
|
+
| `Client`, `ClientCall`, `ClientResult`, … | types | Contracts, `page.next()` / `for await` of `list()` |
|
|
380
|
+
| `Register` | interface | Module-augmentation slot for ambient App types |
|
|
381
|
+
| `AppOf` | type | Brand a bare route map as an App |
|
|
382
|
+
|
|
383
|
+
Budget: the `./client` export stays under the measured client-runtime cap (hard gate in CI).
|
|
384
|
+
|
|
385
|
+
## Troubleshooting
|
|
386
|
+
|
|
387
|
+
<Accordions>
|
|
388
|
+
|
|
389
|
+
<Accordion title="api.bookings.get is not a function / type error">
|
|
390
|
+
Confirm the Flow is `export`ed from a generated unit (`import "@/flows/generated"` then
|
|
391
|
+
`oke({ name })`), or from a module you still `.adopt({ bookings })`.
|
|
392
|
+
|
|
393
|
+
Type `createClient` with that `App` (or ambient `Register` after `oke-client.d.ts` regenerates).
|
|
394
|
+
Restart `oke dev` after renaming exports.
|
|
395
|
+
|
|
396
|
+
</Accordion>
|
|
397
|
+
|
|
398
|
+
<Accordion title="Calls hit /_oke/… instead of my HTTP path">
|
|
399
|
+
Types alone do not choose REST. Pass `createClient(app, url)`, or
|
|
400
|
+
`createClient(url, { $routes: app.$routes })`, or an explicit `routes` map.
|
|
401
|
+
</Accordion>
|
|
402
|
+
|
|
403
|
+
<Accordion title='error.code is "TransportError"'>
|
|
404
|
+
Network failure, abort (`timeout`), non-JSON body, empty error response, or HTTP status without a
|
|
405
|
+
`{ data, error }` envelope. Declared flow codes (`NotFound`, `FlightFull`, …) never use this code.
|
|
406
|
+
Message text lives in `error.data.message`; HTTP status may appear as `error.data.status`.
|
|
407
|
+
</Accordion>
|
|
408
|
+
|
|
409
|
+
<Accordion title="Failed to fetch …/_oke/client.json">
|
|
410
|
+
`oke client add` needs a running app that serves the descriptor. Start the app (`oke dev` /
|
|
411
|
+
`oke start`), check the URL, then retry. Usage when the URL is missing:
|
|
412
|
+
`Usage: oke client add <url> [--out oke-client.d.ts]`.
|
|
413
|
+
</Accordion>
|
|
414
|
+
|
|
415
|
+
<Accordion title="Incomplete path: api.bookings(…)">
|
|
416
|
+
The proxy path stopped at a unit. Call a Flow: `api.bookings.get({id})`, not `api.bookings()`.
|
|
417
|
+
</Accordion>
|
|
418
|
+
|
|
419
|
+
</Accordions>
|
|
420
|
+
|
|
421
|
+
## Learn more
|
|
422
|
+
|
|
423
|
+
- [Overview](/docs/client) — ClientLoop, Flows only
|
|
424
|
+
- [Auth](/docs/client/auth) — Bearer, refresh, denials
|
|
425
|
+
- [Live](/docs/client/live) — `api.live` and live queries
|
|
426
|
+
- [React](/docs/client/react) — hooks package
|
|
427
|
+
- [Vault · Config](/docs/elements/vault/config) — `PUBLIC_API_URL`, `vault.env`
|
|
428
|
+
- [Routing](/docs/elements/flow/routing) — `$routes` stamps
|
|
429
|
+
- [HTTP](/docs/elements/flow/http) — verbs and envelopes on the server
|
|
430
|
+
- [Errors](/docs/reference/errors) — framework codes vs failure values
|
|
431
|
+
- [CLI](/docs/reference/cli) — `oke client add`, `oke dev`
|
|
432
|
+
|
|
433
|
+
## Next
|
|
434
|
+
|
|
435
|
+
<Cards>
|
|
436
|
+
<Card
|
|
437
|
+
title="Auth"
|
|
438
|
+
description="Sessions and gate denials on the client."
|
|
439
|
+
href="/docs/client/auth"
|
|
440
|
+
/>
|
|
441
|
+
<Card
|
|
442
|
+
title="Live"
|
|
443
|
+
description="SSE subscribe and live resource queries."
|
|
444
|
+
href="/docs/client/live"
|
|
445
|
+
/>
|
|
446
|
+
<Card
|
|
447
|
+
title="Routing"
|
|
448
|
+
description="Folders stamp HTTP paths and client units."
|
|
449
|
+
href="/docs/elements/flow/routing"
|
|
450
|
+
/>
|
|
451
|
+
</Cards>
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Overview"
|
|
3
|
+
description: "Typed caller for your Flows — createClient from okengine/client, zero codegen, errors as values."
|
|
4
|
+
icon: "Cable"
|
|
5
|
+
source: "docs/spec/unified-theory.md"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
`okengine/client` is how a browser, CLI, or another service calls your app's Flows. Import the
|
|
9
|
+
generated barrel, take `typeof app`, and `api.bookings.get({ id })` is fully typed — same contracts
|
|
10
|
+
the server already has, no separate schema project.
|
|
11
|
+
|
|
12
|
+
For developers consuming an okengine app from the outside — create the client, call a Flow, narrow
|
|
13
|
+
the envelope.
|
|
14
|
+
|
|
15
|
+
<Callout title="The one rule">
|
|
16
|
+
Treat every call as a result envelope: `{ data, error }`. Flow failures are values you switch on
|
|
17
|
+
(`error.code`); they are never thrown. Only transport / protocol problems use
|
|
18
|
+
`code: "TransportError"`.
|
|
19
|
+
</Callout>
|
|
20
|
+
|
|
21
|
+
## Smallest Example
|
|
22
|
+
|
|
23
|
+
<Steps>
|
|
24
|
+
|
|
25
|
+
<Step>
|
|
26
|
+
### Export `App` from the server
|
|
27
|
+
|
|
28
|
+
```typescript title="src/app.ts"
|
|
29
|
+
import "@/core";
|
|
30
|
+
import "@/flows/generated";
|
|
31
|
+
import { oke } from "okengine/http";
|
|
32
|
+
|
|
33
|
+
export const app = oke({ name: "commerce" });
|
|
34
|
+
export type App = typeof app;
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`.adopt({ bookings })` is optional and additive when a unit is not already in the generated barrel.
|
|
38
|
+
|
|
39
|
+
</Step>
|
|
40
|
+
|
|
41
|
+
<Step>
|
|
42
|
+
### Load a booking from the client
|
|
43
|
+
|
|
44
|
+
```typescript title="web/src/api.ts"
|
|
45
|
+
import { createClient } from "okengine/client";
|
|
46
|
+
import { vault } from "okengine/vault";
|
|
47
|
+
import { app } from "../../src/app";
|
|
48
|
+
|
|
49
|
+
// Base URL via vault.env (empty = same-origin proxy in create-oke web)
|
|
50
|
+
const api = createClient(app, vault.env("PUBLIC_API_URL") ?? "");
|
|
51
|
+
const { data, error } = await api.bookings.get({ id: "bkg_7f3a" });
|
|
52
|
+
|
|
53
|
+
if (error) {
|
|
54
|
+
// TransportError or a declared flow code (NotFound, …)
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
console.log(data.confirmationCode, data.seats);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
With `$routes` wired that is `GET /bookings/bkg_7f3a` on the backend (port **6530**):
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"data": {
|
|
66
|
+
"id": "bkg_7f3a",
|
|
67
|
+
"confirmationCode": "SK-4812",
|
|
68
|
+
"seats": 2,
|
|
69
|
+
"status": "confirmed"
|
|
70
|
+
},
|
|
71
|
+
"error": null
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
</Step>
|
|
76
|
+
|
|
77
|
+
</Steps>
|
|
78
|
+
|
|
79
|
+
## Progressive Patterns
|
|
80
|
+
|
|
81
|
+
Same typed proxy from same-repo REST to a separate frontend repo:
|
|
82
|
+
|
|
83
|
+
<Tabs items={["Same-repo", "Type-only", "Ambient Register"]}>
|
|
84
|
+
|
|
85
|
+
<Tab value="Same-repo">
|
|
86
|
+
|
|
87
|
+
Pass the app value so HTTP triggers hit REST (method + path from `$routes`):
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { createClient } from "okengine/client";
|
|
91
|
+
import { vault } from "okengine/vault";
|
|
92
|
+
import { app } from "./app";
|
|
93
|
+
|
|
94
|
+
const api = createClient(app, vault.env("PUBLIC_API_URL") ?? "");
|
|
95
|
+
await api.bookings.get({ id: "bkg_7f3a" }); // GET /bookings/bkg_7f3a
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
</Tab>
|
|
99
|
+
|
|
100
|
+
<Tab value="Type-only">
|
|
101
|
+
|
|
102
|
+
Types from an explicit `App` — still RPC until you pass routes:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { createClient } from "okengine/client";
|
|
106
|
+
import { vault } from "okengine/vault";
|
|
107
|
+
import type { App } from "./app";
|
|
108
|
+
import { app } from "./app";
|
|
109
|
+
|
|
110
|
+
const api = createClient<App>(vault.env("PUBLIC_API_URL") ?? "", {
|
|
111
|
+
$routes: app.$routes,
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
</Tab>
|
|
116
|
+
|
|
117
|
+
<Tab value="Ambient Register">
|
|
118
|
+
|
|
119
|
+
`oke dev` regenerates `oke-client.d.ts` from `GET /_oke/client.json`. A separate storefront repo
|
|
120
|
+
runs `oke client add` against your public API origin (from Vault / env):
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
import { createClient } from "okengine/client";
|
|
124
|
+
import { vault } from "okengine/vault";
|
|
125
|
+
|
|
126
|
+
const api = createClient(vault.env("PUBLIC_API_URL") ?? "");
|
|
127
|
+
// types from ambient Register in oke-client.d.ts
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Declare the origin on the server with [Vault · Config](/docs/elements/vault/config)
|
|
131
|
+
(`PUBLIC_API_URL`), then set it via env or `oke vault set`. Leave it unset in local web
|
|
132
|
+
dev so `createClient("")` stays same-origin behind the Vite proxy.
|
|
133
|
+
|
|
134
|
+
</Tab>
|
|
135
|
+
|
|
136
|
+
</Tabs>
|
|
137
|
+
|
|
138
|
+
<ClientLoop />
|
|
139
|
+
|
|
140
|
+
## Flows only
|
|
141
|
+
|
|
142
|
+
<Callout title="Flows only">
|
|
143
|
+
The client calls **Flows**. Every other element runs on the server through `fx`. You reach its
|
|
144
|
+
outcome by calling a Flow that uses it — or by handling a gate denial on that call.
|
|
145
|
+
</Callout>
|
|
146
|
+
|
|
147
|
+
| Element | On the client | How |
|
|
148
|
+
| --------------------------------- | ------------- | ------------------------------------------------------------------------------------------ |
|
|
149
|
+
| [Flow](/docs/elements/flow) | Direct | `api.unit.flow(input)` — the only public surface |
|
|
150
|
+
| [Gate](/docs/elements/gate) | Indirect | Bearer via `auth`; denials as `Unauthorized` / `Forbidden` / `RateLimited` |
|
|
151
|
+
| [Store](/docs/elements/store) | Via Flows | `fx.store` inside Flows; `store.resource` + `on(http.resource…)` → five Flows on `$routes` |
|
|
152
|
+
| [Signal](/docs/elements/signal) | Live SSE | `api.live(signal, input?, { onEvent })` — HTTP GET, callback + unsubscribe |
|
|
153
|
+
| [Clock](/docs/elements/clock) | Via Flows | Schedules fire on the server — the client never ticks a clock |
|
|
154
|
+
| [Vault](/docs/elements/vault) | Via Flows | Secrets stay server-side; never ship them to the browser package |
|
|
155
|
+
| [Channel](/docs/elements/channel) | Via Flows | `fx.send` in a Flow — the client does not send email/SMS/push |
|
|
156
|
+
| [AI](/docs/elements/ai) | Via Flows | `fx.ask` / `fx.run` inside a Flow; the client gets that Flow’s `out` |
|
|
157
|
+
|
|
158
|
+
## Pages
|
|
159
|
+
|
|
160
|
+
<Cards>
|
|
161
|
+
<Card
|
|
162
|
+
title="Calling"
|
|
163
|
+
description="createClient forms, REST vs RPC, options, envelopes, resources, remote types."
|
|
164
|
+
href="/docs/client/calling"
|
|
165
|
+
/>
|
|
166
|
+
<Card
|
|
167
|
+
title="Auth"
|
|
168
|
+
description="memorySession, Bearer refresh, and gate denials as values."
|
|
169
|
+
href="/docs/client/auth"
|
|
170
|
+
/>
|
|
171
|
+
<Card
|
|
172
|
+
title="Live"
|
|
173
|
+
description="api.live SSE, resume gaps, and live resource queries."
|
|
174
|
+
href="/docs/client/live"
|
|
175
|
+
/>
|
|
176
|
+
<Card
|
|
177
|
+
title="React"
|
|
178
|
+
description="useSession, useLive, useLiveQuery from okengine/client-react."
|
|
179
|
+
href="/docs/client/react"
|
|
180
|
+
/>
|
|
181
|
+
</Cards>
|
|
182
|
+
|
|
183
|
+
## Learn more
|
|
184
|
+
|
|
185
|
+
- [Routing](/docs/elements/flow/routing) — folders are the URL; `$routes` without `.adopt()`
|
|
186
|
+
- [HTTP](/docs/elements/flow/http) — verbs, `http.resource`, live SSE
|
|
187
|
+
- [The Anatomy](/docs/understand/the-anatomy) — generated barrel → client → test loop
|
|
188
|
+
- [The Model](/docs/understand/the-model) — same contract for Client, Console, MCP
|
|
189
|
+
- [Errors](/docs/reference/errors) — framework codes vs failure values
|
|
190
|
+
|
|
191
|
+
## Next
|
|
192
|
+
|
|
193
|
+
<Cards>
|
|
194
|
+
<Card
|
|
195
|
+
title="Calling"
|
|
196
|
+
description="REST vs RPC, options, helpers, and remote types."
|
|
197
|
+
href="/docs/client/calling"
|
|
198
|
+
/>
|
|
199
|
+
<Card
|
|
200
|
+
title="Auth"
|
|
201
|
+
description="Sessions and gate denials on the client."
|
|
202
|
+
href="/docs/client/auth"
|
|
203
|
+
/>
|
|
204
|
+
<Card
|
|
205
|
+
title="Live"
|
|
206
|
+
description="SSE subscribe and live resource queries."
|
|
207
|
+
href="/docs/client/live"
|
|
208
|
+
/>
|
|
209
|
+
</Cards>
|