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
package/src/kernel/fx.test.ts
CHANGED
|
@@ -129,7 +129,7 @@ describe("fx — capability enforcement", () => {
|
|
|
129
129
|
err = e;
|
|
130
130
|
}
|
|
131
131
|
expect(err).toBeInstanceOf(OkeError);
|
|
132
|
-
expect((err as OkeError).code).toBe(
|
|
132
|
+
expect((err as OkeError).code).toBe(1810);
|
|
133
133
|
});
|
|
134
134
|
|
|
135
135
|
test("index driverId is meilisearch before first I/O (not a function, not memory)", async () => {
|
|
@@ -485,9 +485,15 @@ describe("fx — wholesale swap", () => {
|
|
|
485
485
|
async ask() {
|
|
486
486
|
return {};
|
|
487
487
|
},
|
|
488
|
+
async embed() {
|
|
489
|
+
return [];
|
|
490
|
+
},
|
|
488
491
|
async search() {
|
|
489
492
|
return [];
|
|
490
493
|
},
|
|
494
|
+
async fetch() {
|
|
495
|
+
return new Response(null, { status: 204 });
|
|
496
|
+
},
|
|
491
497
|
async run() {
|
|
492
498
|
return {};
|
|
493
499
|
},
|
|
@@ -679,31 +685,31 @@ describe("fx.json", () => {
|
|
|
679
685
|
});
|
|
680
686
|
|
|
681
687
|
describe("errors — registry", () => {
|
|
682
|
-
test("
|
|
688
|
+
test("OKE1240 is reserved with the §21 shape", () => {
|
|
683
689
|
const def = OKE_ERRORS.ORPHAN_EMIT;
|
|
684
|
-
expect(def.code).toBe(
|
|
685
|
-
expect(lookupOkeError(
|
|
690
|
+
expect(def.code).toBe(1240);
|
|
691
|
+
expect(lookupOkeError(1240)).toEqual(def);
|
|
686
692
|
const err = new OkeError(def, {
|
|
687
693
|
flow: "bookings.create",
|
|
688
694
|
resource: "order-placed",
|
|
689
695
|
});
|
|
690
|
-
expect(err.message).toContain("
|
|
696
|
+
expect(err.message).toContain("OKE1240");
|
|
691
697
|
expect(err.message).toContain("no subscriber");
|
|
692
|
-
expect(err.message).toContain("https://oke.omqkhafi.dev/e/
|
|
698
|
+
expect(err.message).toContain("https://oke.omqkhafi.dev/e/1240");
|
|
693
699
|
expect(err.message).toContain("→");
|
|
694
700
|
});
|
|
695
701
|
|
|
696
|
-
test("
|
|
702
|
+
test("OKE1250 is reserved for signal schema emit failures", () => {
|
|
697
703
|
const def = OKE_ERRORS.SIGNAL_SCHEMA;
|
|
698
|
-
expect(def.code).toBe(
|
|
699
|
-
expect(lookupOkeError(
|
|
704
|
+
expect(def.code).toBe(1250);
|
|
705
|
+
expect(lookupOkeError(1250)).toEqual(def);
|
|
700
706
|
const err = new OkeError(def, {
|
|
701
707
|
resource: "order-placed",
|
|
702
708
|
detail: "total: Expected number, received string",
|
|
703
709
|
});
|
|
704
|
-
expect(err.message).toContain("
|
|
710
|
+
expect(err.message).toContain("OKE1250");
|
|
705
711
|
expect(err.message).toContain("order-placed");
|
|
706
|
-
expect(err.message).toContain("https://oke.omqkhafi.dev/e/
|
|
712
|
+
expect(err.message).toContain("https://oke.omqkhafi.dev/e/1250");
|
|
707
713
|
});
|
|
708
714
|
|
|
709
715
|
test("fx.fail returns a value, not an exception", () => {
|
package/src/kernel/fx.ts
CHANGED
|
@@ -44,7 +44,13 @@ import type { TenantStore } from "../auth/tenants.ts";
|
|
|
44
44
|
import type { SessionCrypto, SessionStore } from "../auth/sessions.ts";
|
|
45
45
|
import type { Manifest } from "../manifest/types.ts";
|
|
46
46
|
import { createCapabilityToken, type CapabilityToken } from "./capability.ts";
|
|
47
|
-
import {
|
|
47
|
+
import {
|
|
48
|
+
createEffectLedger,
|
|
49
|
+
recordEffect,
|
|
50
|
+
reversibilityOf,
|
|
51
|
+
type EffectExternal,
|
|
52
|
+
type EffectLedger,
|
|
53
|
+
} from "./effects.ts";
|
|
48
54
|
import { resolveDurationMs } from "./elapsed.ts";
|
|
49
55
|
import {
|
|
50
56
|
DryRunWriteIsolationError,
|
|
@@ -90,6 +96,11 @@ function loadFxLiveStream(): typeof import("./fx-live-stream.ts") {
|
|
|
90
96
|
return lazyRequire(import.meta.dir, ["fx", "live", "stream"].join("-"));
|
|
91
97
|
}
|
|
92
98
|
|
|
99
|
+
/** `fx.fetch` — keep host parsing + dry-run stub off cold edge / Store-only graphs. */
|
|
100
|
+
function loadFxFetch(): typeof import("./fx-fetch.ts") {
|
|
101
|
+
return lazyRequire(import.meta.dir, ["fx", "fetch"].join("-"));
|
|
102
|
+
}
|
|
103
|
+
|
|
93
104
|
/** Resource ref Flows declare to read the Runs store via {@link Fx.runs}. */
|
|
94
105
|
export const RUNS_RESOURCE = "runs";
|
|
95
106
|
|
|
@@ -386,7 +397,7 @@ export interface JsonStreamResult {
|
|
|
386
397
|
readonly kind: "stream";
|
|
387
398
|
readonly status: 200;
|
|
388
399
|
readonly chunks: AsyncIterable<unknown>;
|
|
389
|
-
/** Awaited before the 200 SSE body; throws
|
|
400
|
+
/** Awaited before the 200 SSE body; throws OKE1210 on a missing resume cursor. */
|
|
390
401
|
ready?: () => Promise<void>;
|
|
391
402
|
/** Set by the kernel to commit journal / Runs after the stream settles. */
|
|
392
403
|
finalize?: () => Promise<void>;
|
|
@@ -693,7 +704,7 @@ export interface Fx {
|
|
|
693
704
|
* Stream a `delivery: "live"` signal as SSE (records `read` on `signal:<name>`).
|
|
694
705
|
*
|
|
695
706
|
* HTTP `Last-Event-ID` is applied when `opts.afterId` is omitted. A missing
|
|
696
|
-
* cursor throws
|
|
707
|
+
* cursor throws OKE1210; `JsonStreamResult.ready` turns that into HTTP 410.
|
|
697
708
|
*
|
|
698
709
|
* @param signal - Signal name or handle
|
|
699
710
|
* @param opts - Payload filter and optional resume cursor
|
|
@@ -773,6 +784,14 @@ export interface Fx {
|
|
|
773
784
|
* @param opts - Model routing opts
|
|
774
785
|
*/
|
|
775
786
|
ask(prompt: NamedRef, input?: unknown, opts?: FxAskOptions): Promise<Record<string, unknown>>;
|
|
787
|
+
/**
|
|
788
|
+
* Embed text via a named model (records `embed` — distinct from `ask`).
|
|
789
|
+
* Returns the vector; does not write an index.
|
|
790
|
+
*
|
|
791
|
+
* @param model - Model name or handle
|
|
792
|
+
* @param text - Text to embed
|
|
793
|
+
*/
|
|
794
|
+
embed(model: NamedRef, text: string): Promise<readonly number[]>;
|
|
776
795
|
/**
|
|
777
796
|
* Similarity search over an index/embed (records `read` on the embed ref).
|
|
778
797
|
*
|
|
@@ -781,6 +800,17 @@ export interface Fx {
|
|
|
781
800
|
* @param opts - Search options
|
|
782
801
|
*/
|
|
783
802
|
search(embed: NamedRef, query: unknown, opts?: FxSearchOptions): Promise<unknown[]>;
|
|
803
|
+
/**
|
|
804
|
+
* Outbound HTTP to an arbitrary URL (records `fetch` on the hostname).
|
|
805
|
+
*
|
|
806
|
+
* Unconditionally external (`kind: "third-party"`). Declare the hostname in
|
|
807
|
+
* `effects.fetches`. Prefer wrapping inside {@link Fx.step}; use
|
|
808
|
+
* {@link Fx.retry} only when the remote API is safe to repeat.
|
|
809
|
+
*
|
|
810
|
+
* @param url - Absolute URL (string or URL)
|
|
811
|
+
* @param init - Standard `RequestInit`
|
|
812
|
+
*/
|
|
813
|
+
fetch(url: string | URL, init?: RequestInit): Promise<Response>;
|
|
784
814
|
/**
|
|
785
815
|
* Run a bounded AI agent (records `ask`).
|
|
786
816
|
*
|
|
@@ -1077,6 +1107,15 @@ function stampAskTelemetry(
|
|
|
1077
1107
|
if (outputTokens > 0) telemetry.outputTokens += outputTokens;
|
|
1078
1108
|
}
|
|
1079
1109
|
|
|
1110
|
+
/**
|
|
1111
|
+
* Hostname for `fx.fetch` capability / ledger resource.
|
|
1112
|
+
*
|
|
1113
|
+
* @param href - Absolute URL string
|
|
1114
|
+
*/
|
|
1115
|
+
export function hostFromFetchUrl(href: string): string {
|
|
1116
|
+
return loadFxFetch().hostFromFetchUrl(href);
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1080
1119
|
/**
|
|
1081
1120
|
* Create an in-memory `fx` context (v1 stubs, full surface).
|
|
1082
1121
|
*
|
|
@@ -1162,9 +1201,12 @@ export function createFxContext(options: CreateFxOptions): FxContext {
|
|
|
1162
1201
|
kind: Parameters<CapabilityToken["assert"]>[0],
|
|
1163
1202
|
resource: string,
|
|
1164
1203
|
body: () => T | Promise<T>,
|
|
1204
|
+
externalOf?:
|
|
1205
|
+
| EffectExternal
|
|
1206
|
+
| ((result: T | undefined, error: unknown) => EffectExternal | undefined),
|
|
1165
1207
|
): Promise<T> {
|
|
1166
1208
|
capability.assert(kind, resource);
|
|
1167
|
-
const execute = () => recordEffect(ledger, kind, resource, now, body);
|
|
1209
|
+
const execute = () => recordEffect(ledger, kind, resource, now, body, externalOf);
|
|
1168
1210
|
if (journal) {
|
|
1169
1211
|
return journal.effect(kind, resource, execute);
|
|
1170
1212
|
}
|
|
@@ -1265,14 +1307,15 @@ export function createFxContext(options: CreateFxOptions): FxContext {
|
|
|
1265
1307
|
table: unknown,
|
|
1266
1308
|
body: () => T | Promise<T>,
|
|
1267
1309
|
): Promise<T> => {
|
|
1310
|
+
const externalOf = (): EffectExternal | undefined => cached?.external;
|
|
1268
1311
|
const name = schemaTableName(table);
|
|
1269
1312
|
if (name !== undefined) {
|
|
1270
1313
|
const perTable = sqlTableRef(name);
|
|
1271
1314
|
if (perTable !== ref && capability.allows(kind, perTable)) {
|
|
1272
|
-
return gated(kind, perTable, body);
|
|
1315
|
+
return gated(kind, perTable, body, externalOf);
|
|
1273
1316
|
}
|
|
1274
1317
|
}
|
|
1275
|
-
return gated(kind, ref, body);
|
|
1318
|
+
return gated(kind, ref, body, externalOf);
|
|
1276
1319
|
};
|
|
1277
1320
|
|
|
1278
1321
|
return {
|
|
@@ -1443,6 +1486,42 @@ export function createFxContext(options: CreateFxOptions): FxContext {
|
|
|
1443
1486
|
return h.page(table, pageOptions);
|
|
1444
1487
|
});
|
|
1445
1488
|
},
|
|
1489
|
+
search(table, searchOptions) {
|
|
1490
|
+
return gatedTable("read", table, async () => {
|
|
1491
|
+
const h = await ensure();
|
|
1492
|
+
const result = await h.search(table, searchOptions);
|
|
1493
|
+
// Optional rerank via fx.ask — only when explicitly requested.
|
|
1494
|
+
if (
|
|
1495
|
+
searchOptions.rerank &&
|
|
1496
|
+
typeof searchOptions.rerank === "object" &&
|
|
1497
|
+
searchOptions.rerank.model
|
|
1498
|
+
) {
|
|
1499
|
+
const model = searchOptions.rerank.model;
|
|
1500
|
+
const pk = "id";
|
|
1501
|
+
const docs = result.data.map((row) => ({
|
|
1502
|
+
id: String(row[pk] ?? ""),
|
|
1503
|
+
text: Object.values(row)
|
|
1504
|
+
.filter((v) => typeof v === "string")
|
|
1505
|
+
.join("\n"),
|
|
1506
|
+
score: 0,
|
|
1507
|
+
}));
|
|
1508
|
+
const out = (await fx.ask(model, {
|
|
1509
|
+
query: searchOptions.query,
|
|
1510
|
+
docs,
|
|
1511
|
+
})) as { rankedIds?: string[] };
|
|
1512
|
+
if (out.rankedIds && out.rankedIds.length > 0) {
|
|
1513
|
+
const byId = new Map(result.data.map((r) => [String(r[pk] ?? ""), r]));
|
|
1514
|
+
return {
|
|
1515
|
+
...result,
|
|
1516
|
+
data: out.rankedIds
|
|
1517
|
+
.map((id) => byId.get(id))
|
|
1518
|
+
.filter((r): r is NonNullable<typeof r> => r !== undefined),
|
|
1519
|
+
};
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
return result;
|
|
1523
|
+
});
|
|
1524
|
+
},
|
|
1446
1525
|
ensureTable(table) {
|
|
1447
1526
|
return gatedTable("write", table, async () => {
|
|
1448
1527
|
refuseDryRunWrite();
|
|
@@ -1555,17 +1634,28 @@ export function createFxContext(options: CreateFxOptions): FxContext {
|
|
|
1555
1634
|
}
|
|
1556
1635
|
const isRead = prop === "get" || prop === "search" || prop === "list" || prop === "ttlMs";
|
|
1557
1636
|
return (...args: unknown[]) =>
|
|
1558
|
-
gated(
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
)
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1637
|
+
gated(
|
|
1638
|
+
isRead ? "read" : "write",
|
|
1639
|
+
baseRef,
|
|
1640
|
+
async () => {
|
|
1641
|
+
if (!isRead && isDryRun()) {
|
|
1642
|
+
throw new DryRunWriteIsolationError(
|
|
1643
|
+
`Driver-backed store "${baseRef}" cannot isolate writes during dry-run; dry-run refused rather than risk a double-write.`,
|
|
1644
|
+
);
|
|
1645
|
+
}
|
|
1646
|
+
const h = await open();
|
|
1647
|
+
const fn = (h as unknown as Record<string | symbol, unknown>)[prop];
|
|
1648
|
+
if (typeof fn !== "function") return undefined;
|
|
1649
|
+
return (fn as (...a: unknown[]) => unknown).apply(h, args);
|
|
1650
|
+
},
|
|
1651
|
+
() => {
|
|
1652
|
+
const opened = cache.handle;
|
|
1653
|
+
if (opened && typeof opened === "object" && "external" in opened) {
|
|
1654
|
+
return (opened as { external?: EffectExternal }).external;
|
|
1655
|
+
}
|
|
1656
|
+
return undefined;
|
|
1657
|
+
},
|
|
1658
|
+
);
|
|
1569
1659
|
},
|
|
1570
1660
|
});
|
|
1571
1661
|
}
|
|
@@ -1893,26 +1983,33 @@ export function createFxContext(options: CreateFxOptions): FxContext {
|
|
|
1893
1983
|
cache,
|
|
1894
1984
|
send(template, opts) {
|
|
1895
1985
|
const name = resolveName(template);
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1986
|
+
let sendExternal: EffectExternal | undefined;
|
|
1987
|
+
return gated(
|
|
1988
|
+
"send",
|
|
1989
|
+
name,
|
|
1990
|
+
async () => {
|
|
1991
|
+
// Dry-run: record "would have fired" — never contact a real channel
|
|
1992
|
+
// (console §9.1 · §9.3 · §9.4).
|
|
1993
|
+
if (isDryRun()) {
|
|
1994
|
+
recordWouldHaveFired("send", name);
|
|
1995
|
+
return { ok: true as const };
|
|
1996
|
+
}
|
|
1997
|
+
if (options.channelRuntime) {
|
|
1998
|
+
const result = await options.channelRuntime.send(name, {
|
|
1999
|
+
to: opts?.to ?? "",
|
|
2000
|
+
data: opts?.data,
|
|
2001
|
+
via: opts?.via?.map(resolveName),
|
|
2002
|
+
locale: opts?.locale ?? locale,
|
|
2003
|
+
profileLocale: opts?.profileLocale,
|
|
2004
|
+
acceptLanguage: opts?.acceptLanguage,
|
|
2005
|
+
});
|
|
2006
|
+
sendExternal = result.external;
|
|
2007
|
+
return { ok: result.ok as true };
|
|
2008
|
+
}
|
|
1901
2009
|
return { ok: true as const };
|
|
1902
|
-
}
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
to: opts?.to ?? "",
|
|
1906
|
-
data: opts?.data,
|
|
1907
|
-
via: opts?.via?.map(resolveName),
|
|
1908
|
-
locale: opts?.locale ?? locale,
|
|
1909
|
-
profileLocale: opts?.profileLocale,
|
|
1910
|
-
acceptLanguage: opts?.acceptLanguage,
|
|
1911
|
-
});
|
|
1912
|
-
return { ok: result.ok as true };
|
|
1913
|
-
}
|
|
1914
|
-
return { ok: true as const };
|
|
1915
|
-
});
|
|
2010
|
+
},
|
|
2011
|
+
() => sendExternal,
|
|
2012
|
+
);
|
|
1916
2013
|
},
|
|
1917
2014
|
sendOtp(opts) {
|
|
1918
2015
|
return gated("send", "sms-otp", async () => {
|
|
@@ -1982,28 +2079,51 @@ export function createFxContext(options: CreateFxOptions): FxContext {
|
|
|
1982
2079
|
},
|
|
1983
2080
|
ask(prompt, input, opts) {
|
|
1984
2081
|
const name = resolveName(prompt);
|
|
1985
|
-
return gated(
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
return await options.aiRuntime.ask(name, input, {
|
|
1994
|
-
via: opts?.via?.map(resolveName),
|
|
1995
|
-
...(opts?.timeout !== undefined ? { timeout: opts.timeout } : {}),
|
|
1996
|
-
tools: opts?.tools?.map(resolveName),
|
|
1997
|
-
maxSteps: opts?.maxSteps,
|
|
1998
|
-
// Host fx.call — same capability / ledger / Runs path as any call.
|
|
1999
|
-
callTool: (tool, toolInput) => fx.call(tool, toolInput),
|
|
2000
|
-
});
|
|
2001
|
-
} finally {
|
|
2002
|
-
stampAskTelemetry(telemetry, options.aiRuntime, name);
|
|
2082
|
+
return gated(
|
|
2083
|
+
"ask",
|
|
2084
|
+
name,
|
|
2085
|
+
async () => {
|
|
2086
|
+
// Dry-run: stub the model call the same way as send.
|
|
2087
|
+
if (isDryRun()) {
|
|
2088
|
+
recordWouldHaveFired("ask", name);
|
|
2089
|
+
return {};
|
|
2003
2090
|
}
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2091
|
+
if (options.aiRuntime) {
|
|
2092
|
+
try {
|
|
2093
|
+
return await options.aiRuntime.ask(name, input, {
|
|
2094
|
+
via: opts?.via?.map(resolveName),
|
|
2095
|
+
...(opts?.timeout !== undefined ? { timeout: opts.timeout } : {}),
|
|
2096
|
+
tools: opts?.tools?.map(resolveName),
|
|
2097
|
+
maxSteps: opts?.maxSteps,
|
|
2098
|
+
// Host fx.call — same capability / ledger / Runs path as any call.
|
|
2099
|
+
callTool: (tool, toolInput) => fx.call(tool, toolInput),
|
|
2100
|
+
});
|
|
2101
|
+
} finally {
|
|
2102
|
+
stampAskTelemetry(telemetry, options.aiRuntime, name);
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
throw new Error(`fx.ask: AI runtime is not configured for prompt "${name}"`);
|
|
2106
|
+
},
|
|
2107
|
+
() => options.aiRuntime?.lastExternal,
|
|
2108
|
+
);
|
|
2109
|
+
},
|
|
2110
|
+
embed(model, text) {
|
|
2111
|
+
const name = resolveName(model);
|
|
2112
|
+
return gated(
|
|
2113
|
+
"embed",
|
|
2114
|
+
name,
|
|
2115
|
+
async () => {
|
|
2116
|
+
if (isDryRun()) {
|
|
2117
|
+
recordWouldHaveFired("embed", name);
|
|
2118
|
+
return [];
|
|
2119
|
+
}
|
|
2120
|
+
if (options.aiRuntime && typeof options.aiRuntime.embedVector === "function") {
|
|
2121
|
+
return options.aiRuntime.embedVector(name, text);
|
|
2122
|
+
}
|
|
2123
|
+
throw new Error(`fx.embed: AI runtime is not configured for model "${name}"`);
|
|
2124
|
+
},
|
|
2125
|
+
() => options.aiRuntime?.lastExternal,
|
|
2126
|
+
);
|
|
2007
2127
|
},
|
|
2008
2128
|
search(embed, query, opts) {
|
|
2009
2129
|
const name = resolveName(embed);
|
|
@@ -2029,6 +2149,9 @@ export function createFxContext(options: CreateFxOptions): FxContext {
|
|
|
2029
2149
|
return [];
|
|
2030
2150
|
});
|
|
2031
2151
|
},
|
|
2152
|
+
fetch(url, init) {
|
|
2153
|
+
return loadFxFetch().runFxFetch(gated, url, init);
|
|
2154
|
+
},
|
|
2032
2155
|
run(agent, input) {
|
|
2033
2156
|
const name = resolveName(agent);
|
|
2034
2157
|
return gated("ask", name, async () => {
|
|
@@ -104,7 +104,7 @@ const signalRt = createSignalRuntime({
|
|
|
104
104
|
durablePath: signalPath,
|
|
105
105
|
leaseMs: Number.isFinite(leaseMs) ? leaseMs : 300,
|
|
106
106
|
});
|
|
107
|
-
const job = signal(SIG, {
|
|
107
|
+
const job = signal.once(SIG, { retries: 3, deadLetter: true, optional: true });
|
|
108
108
|
signalRt.register(job);
|
|
109
109
|
const bus = await signalRt.start();
|
|
110
110
|
await bus.subscribe(SIG, `consumer-${instanceId}`, async (msg) => {
|
|
@@ -19,16 +19,14 @@ describe("http.query — RFC 10008", () => {
|
|
|
19
19
|
test("a QUERY flow receives the JSON body exactly as POST does", async () => {
|
|
20
20
|
const schema = z.object({ n: z.number() });
|
|
21
21
|
on(
|
|
22
|
-
http.query("/q"),
|
|
22
|
+
http.query("/q", { in: schema }),
|
|
23
23
|
flow("q.run", {
|
|
24
|
-
in: schema,
|
|
25
24
|
do: (input: { n: number }) => input,
|
|
26
25
|
}),
|
|
27
26
|
);
|
|
28
27
|
on(
|
|
29
|
-
http.post("/p"),
|
|
28
|
+
http.post("/p", { in: schema }),
|
|
30
29
|
flow("p.run", {
|
|
31
|
-
in: schema,
|
|
32
30
|
do: (input: { n: number }) => input,
|
|
33
31
|
}),
|
|
34
32
|
);
|
|
@@ -70,9 +68,8 @@ describe("http.query — RFC 10008", () => {
|
|
|
70
68
|
describe("http.query — RFC 10008 media type", () => {
|
|
71
69
|
function queryApp(aot = true) {
|
|
72
70
|
on(
|
|
73
|
-
http.query("/q"),
|
|
71
|
+
http.query("/q", { in: z.object({ n: z.number() }) }),
|
|
74
72
|
flow("q.run", {
|
|
75
|
-
in: z.object({ n: z.number() }),
|
|
76
73
|
do: (input: { n: number }) => input,
|
|
77
74
|
}),
|
|
78
75
|
);
|
package/src/kernel/index.ts
CHANGED
|
@@ -91,6 +91,7 @@ export {
|
|
|
91
91
|
recordEffect,
|
|
92
92
|
reversibilityOf,
|
|
93
93
|
type EffectEntry,
|
|
94
|
+
type EffectExternal,
|
|
94
95
|
type EffectKind,
|
|
95
96
|
type EffectLedger,
|
|
96
97
|
type ReversibilityTier,
|
|
@@ -107,6 +108,7 @@ export {
|
|
|
107
108
|
fail,
|
|
108
109
|
formatOkeMessage,
|
|
109
110
|
lookupOkeError,
|
|
111
|
+
OKE_ERROR_RANGES,
|
|
110
112
|
OKE_ERRORS,
|
|
111
113
|
OkeError,
|
|
112
114
|
throwOke,
|
|
@@ -115,6 +117,7 @@ export {
|
|
|
115
117
|
type FlowFailure,
|
|
116
118
|
type OkeErrorCode,
|
|
117
119
|
type OkeErrorDefinition,
|
|
120
|
+
type OkeErrorDomain,
|
|
118
121
|
type OkeErrorParams,
|
|
119
122
|
} from "./errors.ts";
|
|
120
123
|
|
|
@@ -133,6 +136,14 @@ export {
|
|
|
133
136
|
type StandardSchemaV1,
|
|
134
137
|
} from "./flow.ts";
|
|
135
138
|
|
|
139
|
+
export { call } from "./call.ts";
|
|
140
|
+
export type {
|
|
141
|
+
BoundaryContract,
|
|
142
|
+
InferBoundaryErrors,
|
|
143
|
+
InferBoundaryIn,
|
|
144
|
+
InferBoundaryOut,
|
|
145
|
+
} from "./boundary-contract.ts";
|
|
146
|
+
|
|
136
147
|
export {
|
|
137
148
|
createFx,
|
|
138
149
|
createFxContext,
|
|
@@ -346,15 +357,15 @@ export {
|
|
|
346
357
|
|
|
347
358
|
export {
|
|
348
359
|
asSignalTrigger,
|
|
349
|
-
every,
|
|
350
360
|
http,
|
|
351
361
|
internal,
|
|
362
|
+
isClockDecl,
|
|
352
363
|
isResourceMount,
|
|
353
364
|
isSignalTriggerSource,
|
|
354
365
|
normalizeTrigger,
|
|
355
|
-
table,
|
|
356
366
|
type BoundTriggerOf,
|
|
357
367
|
type CdcTrigger,
|
|
368
|
+
type ClockTrigger,
|
|
358
369
|
type EveryTrigger,
|
|
359
370
|
type GateRef,
|
|
360
371
|
type HttpMethod,
|
|
@@ -365,7 +376,6 @@ export {
|
|
|
365
376
|
type ResourceMount,
|
|
366
377
|
type SignalAsTrigger,
|
|
367
378
|
type SignalSource,
|
|
368
|
-
type TableHandle,
|
|
369
379
|
type Trigger,
|
|
370
380
|
type TriggerKind,
|
|
371
381
|
} from "./triggers.ts";
|
|
@@ -11,7 +11,9 @@ import { INSTANCE_ID_PREFIX } from "./instance-id.ts";
|
|
|
11
11
|
import {
|
|
12
12
|
createInstanceRuntime,
|
|
13
13
|
createMemoryInstanceStore,
|
|
14
|
+
isBenignSqlDisconnect,
|
|
14
15
|
projectInstancesList,
|
|
16
|
+
type InstanceStore,
|
|
15
17
|
} from "./instances.ts";
|
|
16
18
|
|
|
17
19
|
describe("projectInstancesList", () => {
|
|
@@ -64,6 +66,44 @@ describe("instance heartbeat", () => {
|
|
|
64
66
|
expect(second?.heartbeatAt).toBe(1_100);
|
|
65
67
|
expect(second?.startedAt).toBe(first?.startedAt);
|
|
66
68
|
});
|
|
69
|
+
|
|
70
|
+
test("heartbeat swallows paused / connection-closed SQL errors", async () => {
|
|
71
|
+
const store: InstanceStore = {
|
|
72
|
+
kind: "memory",
|
|
73
|
+
async upsert() {
|
|
74
|
+
const err = new Error("shared Postgres pools are paused (compose stopped)");
|
|
75
|
+
(err as { code?: string; name?: string }).code = "ERR_OKE_POSTGRES_PAUSED";
|
|
76
|
+
(err as { name?: string }).name = "SharedPostgresPausedError";
|
|
77
|
+
throw err;
|
|
78
|
+
},
|
|
79
|
+
async get() {
|
|
80
|
+
return undefined;
|
|
81
|
+
},
|
|
82
|
+
async list() {
|
|
83
|
+
return [];
|
|
84
|
+
},
|
|
85
|
+
async listAlive() {
|
|
86
|
+
return [];
|
|
87
|
+
},
|
|
88
|
+
async remove() {},
|
|
89
|
+
};
|
|
90
|
+
const rt = createInstanceRuntime({
|
|
91
|
+
instanceId: "inst-pause",
|
|
92
|
+
store,
|
|
93
|
+
env: "dev",
|
|
94
|
+
heartbeatMs: 1,
|
|
95
|
+
leaseMs: 300,
|
|
96
|
+
});
|
|
97
|
+
await expect(rt.heartbeat()).resolves.toBeUndefined();
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe("isBenignSqlDisconnect", () => {
|
|
102
|
+
test("matches pause and Bun connection codes", () => {
|
|
103
|
+
expect(isBenignSqlDisconnect({ code: "ERR_OKE_POSTGRES_PAUSED" })).toBe(true);
|
|
104
|
+
expect(isBenignSqlDisconnect({ code: "ERR_POSTGRES_CONNECTION_CLOSED" })).toBe(true);
|
|
105
|
+
expect(isBenignSqlDisconnect(new Error("relation missing"))).toBe(false);
|
|
106
|
+
});
|
|
67
107
|
});
|
|
68
108
|
|
|
69
109
|
describe("boot instanceId unification", () => {
|
package/src/kernel/instances.ts
CHANGED
|
@@ -188,6 +188,38 @@ export interface InstanceRuntime {
|
|
|
188
188
|
close(): Promise<void>;
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
/**
|
|
192
|
+
* SQL failures that are expected while `oke dev` pauses shared Postgres for
|
|
193
|
+
* compose stop (or the server is already gone). Scheduler ticks must not dump
|
|
194
|
+
* these as unhandled rejections.
|
|
195
|
+
*
|
|
196
|
+
* @param err - Rejection / throw
|
|
197
|
+
*/
|
|
198
|
+
export function isBenignSqlDisconnect(err: unknown): boolean {
|
|
199
|
+
if (!err || typeof err !== "object") return false;
|
|
200
|
+
const code = (err as { code?: unknown }).code;
|
|
201
|
+
if (typeof code === "string") {
|
|
202
|
+
if (
|
|
203
|
+
code === "ERR_OKE_POSTGRES_PAUSED" ||
|
|
204
|
+
code === "ERR_POSTGRES_CONNECTION_CLOSED" ||
|
|
205
|
+
code === "ERR_POSTGRES_CONNECTION_REFUSED" ||
|
|
206
|
+
code === "ERR_POSTGRES_CONNECTION_TIMEOUT"
|
|
207
|
+
) {
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const name = (err as { name?: unknown }).name;
|
|
212
|
+
if (name === "SharedPostgresPausedError") return true;
|
|
213
|
+
const message = (err as { message?: unknown }).message;
|
|
214
|
+
if (typeof message !== "string") return false;
|
|
215
|
+
return (
|
|
216
|
+
message === "Connection closed" ||
|
|
217
|
+
/shared Postgres pools are paused/i.test(message) ||
|
|
218
|
+
/Failed to connect/i.test(message) ||
|
|
219
|
+
/ECONNREFUSED/i.test(message)
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
191
223
|
/**
|
|
192
224
|
* Create a heartbeat runtime for one process.
|
|
193
225
|
*
|
|
@@ -214,15 +246,21 @@ export function createInstanceRuntime(options: CreateInstanceRuntimeOptions): In
|
|
|
214
246
|
},
|
|
215
247
|
async heartbeat(at) {
|
|
216
248
|
const t = at ?? now();
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
249
|
+
try {
|
|
250
|
+
await options.store.upsert({
|
|
251
|
+
id: options.instanceId,
|
|
252
|
+
startedAt,
|
|
253
|
+
heartbeatAt: t,
|
|
254
|
+
leaseExpiresAt: t + leaseMs,
|
|
255
|
+
env: options.env,
|
|
256
|
+
pid,
|
|
257
|
+
});
|
|
258
|
+
lastHeartbeatAt = t;
|
|
259
|
+
} catch (err) {
|
|
260
|
+
// Compose-stop pause / torn-down Postgres — skip until pools resume.
|
|
261
|
+
if (isBenignSqlDisconnect(err)) return;
|
|
262
|
+
throw err;
|
|
263
|
+
}
|
|
226
264
|
},
|
|
227
265
|
async release() {
|
|
228
266
|
await options.store.remove(options.instanceId);
|