okengine 0.18.4 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +18 -10
- package/README.md +2 -2
- package/package.json +51 -50
- package/site/content/docs/ai/index.mdx +25 -6
- package/site/content/docs/ai/llms-txt.mdx +1 -1
- package/site/content/docs/ai/meta.json +1 -1
- package/site/content/docs/ai/skills.mdx +4 -1
- package/site/content/docs/ai/try-it.mdx +58 -0
- package/site/content/docs/client/auth.mdx +208 -0
- package/site/content/docs/client/calling.mdx +451 -0
- package/site/content/docs/client/index.mdx +209 -0
- package/site/content/docs/client/live.mdx +234 -0
- package/site/content/docs/client/meta.json +5 -0
- package/site/content/docs/client/react.mdx +249 -0
- package/site/content/docs/elements/ai/agents.mdx +232 -0
- package/site/content/docs/elements/ai/index.mdx +341 -0
- package/site/content/docs/elements/ai/mcp.mdx +275 -0
- package/site/content/docs/elements/ai/meta.json +5 -0
- package/site/content/docs/elements/ai/models.mdx +283 -0
- package/site/content/docs/elements/ai/prompts.mdx +256 -0
- package/site/content/docs/elements/channel/email.mdx +266 -0
- package/site/content/docs/elements/channel/index.mdx +344 -0
- package/site/content/docs/elements/channel/meta.json +5 -0
- package/site/content/docs/elements/channel/push.mdx +218 -0
- package/site/content/docs/elements/channel/receipts.mdx +206 -0
- package/site/content/docs/elements/channel/sms.mdx +264 -0
- package/site/content/docs/elements/channel/whatsapp.mdx +220 -0
- package/site/content/docs/elements/clock/index.mdx +300 -0
- package/site/content/docs/elements/clock/meta.json +5 -0
- package/site/content/docs/elements/clock/schedules.mdx +508 -0
- package/site/content/docs/elements/clock/sleep.mdx +445 -0
- package/site/content/docs/elements/flow/consumers.mdx +707 -0
- package/site/content/docs/elements/flow/http.mdx +1080 -0
- package/site/content/docs/elements/flow/index.mdx +618 -0
- package/site/content/docs/elements/flow/meta.json +5 -0
- package/site/content/docs/elements/flow/routing.mdx +559 -0
- package/site/content/docs/elements/flow/workflows.mdx +640 -0
- package/site/content/docs/elements/gate/auth.mdx +371 -0
- package/site/content/docs/elements/gate/authorization.mdx +298 -0
- package/site/content/docs/elements/gate/index.mdx +418 -0
- package/site/content/docs/elements/gate/meta.json +5 -0
- package/site/content/docs/elements/gate/rate-limits.mdx +365 -0
- package/site/content/docs/elements/gate/rls.mdx +303 -0
- package/site/content/docs/elements/gate/tenancy.mdx +372 -0
- package/site/content/docs/elements/index.mdx +52 -11
- package/site/content/docs/elements/signal/broadcast.mdx +517 -0
- package/site/content/docs/elements/signal/index.mdx +352 -0
- package/site/content/docs/elements/signal/live.mdx +590 -0
- package/site/content/docs/elements/signal/meta.json +5 -0
- package/site/content/docs/elements/signal/once.mdx +596 -0
- package/site/content/docs/elements/store/files.mdx +659 -0
- package/site/content/docs/elements/store/index.mdx +310 -0
- package/site/content/docs/elements/store/kv.mdx +629 -0
- package/site/content/docs/elements/store/meta.json +5 -0
- package/site/content/docs/elements/store/search.mdx +946 -0
- package/site/content/docs/elements/store/sql.mdx +937 -0
- package/site/content/docs/elements/vault/config.mdx +256 -0
- package/site/content/docs/elements/vault/index.mdx +356 -0
- package/site/content/docs/elements/vault/meta.json +5 -0
- package/site/content/docs/elements/vault/rotation.mdx +273 -0
- package/site/content/docs/elements/vault/secrets.mdx +285 -0
- package/site/content/docs/index.mdx +78 -30
- package/site/content/docs/meta.json +11 -8
- package/site/content/docs/plugins/cors.mdx +2 -1
- package/site/content/docs/plugins/csrf.mdx +4 -1
- package/site/content/docs/plugins/headers.mdx +2 -1
- package/site/content/docs/plugins/ip-allowlist.mdx +2 -1
- package/site/content/docs/plugins/magic-link.mdx +6 -0
- package/site/content/docs/plugins/maintenance-mode.mdx +2 -1
- package/site/content/docs/plugins/oauth.mdx +1 -1
- package/site/content/docs/plugins/otp.mdx +12 -1
- package/site/content/docs/plugins/passkey.mdx +39 -15
- package/site/content/docs/plugins/two-factor.mdx +91 -34
- package/site/content/docs/plugins/username.mdx +1 -1
- package/site/content/docs/recipes/caddy.mdx +3 -3
- package/site/content/docs/recipes/index.mdx +18 -28
- package/site/content/docs/recipes/mailpit.mdx +1 -1
- package/site/content/docs/recipes/meilisearch.mdx +3 -3
- package/site/content/docs/recipes/meta.json +1 -4
- package/site/content/docs/recipes/nginx.mdx +2 -2
- package/site/content/docs/recipes/openrouter.mdx +283 -0
- package/site/content/docs/recipes/pgdog.mdx +3 -3
- package/site/content/docs/recipes/postgres.mdx +1 -2
- package/site/content/docs/recipes/rustfs.mdx +2 -2
- package/site/content/docs/recipes/traefik.mdx +3 -3
- package/site/content/docs/reference/cli.mdx +231 -0
- package/site/content/docs/reference/configuration.mdx +30 -10
- package/site/content/docs/reference/environment-variables.mdx +93 -20
- package/site/content/docs/reference/errors.mdx +132 -29
- package/site/content/docs/reference/fx.mdx +137 -73
- package/site/content/docs/reference/index.mdx +13 -21
- package/site/content/docs/reference/meta.json +4 -5
- package/site/content/docs/reference/okid.mdx +42 -17
- package/site/content/docs/reference/plugins.mdx +4 -3
- package/site/content/docs/reference/security.mdx +197 -0
- package/site/content/docs/understand/meta.json +5 -0
- package/site/content/docs/understand/the-anatomy.mdx +132 -0
- package/site/content/docs/understand/the-model.mdx +32 -0
- package/site/content/docs/understand/the-problem.mdx +74 -0
- package/site/content/docs/understand/the-vocabulary.mdx +26 -0
- package/src/auth/api-keys.ts +2 -1
- package/src/auth/bindings.ts +64 -16
- package/src/auth/gate-auth.test.ts +6 -1
- package/src/auth/identity.ts +152 -5
- package/src/auth/index.ts +29 -0
- package/src/auth/invites.ts +2 -1
- package/src/auth/method-context.ts +41 -0
- package/src/auth/oauth-as/crypto.ts +2 -1
- package/src/auth/oauth-as/stores.ts +2 -1
- package/src/auth/operator.ts +2 -1
- package/src/auth/sessions-jwt.test.ts +77 -0
- package/src/auth/sessions.ts +20 -4
- package/src/auth/tenants.ts +3 -2
- package/src/auth/two-factor-challenge.test.ts +61 -0
- package/src/auth/two-factor-challenge.ts +284 -0
- package/src/auth/verification.ts +5 -0
- package/src/bench/REPORT.md +49 -0
- package/src/bench/g03-signal-once.bench.ts +1 -1
- package/src/bench/g10-observability-contention.bench.ts +1 -1
- package/src/bench/g17-hybrid-search.bench.ts +572 -0
- package/src/bench/load-app.ts +2 -10
- package/src/cli/ai-setup/ai-setup.test.ts +331 -42
- package/src/cli/ai-setup/apply.ts +294 -52
- package/src/cli/ai-setup/catalog.ts +238 -1342
- package/src/cli/ai-setup/index.ts +14 -99
- package/src/cli/ai-setup/prompts.ts +60 -443
- package/src/cli/ask-seed.test.ts +96 -0
- package/src/cli/ask-seed.ts +82 -0
- package/src/cli/ask-vault-gaps.test.ts +84 -0
- package/src/cli/ask-vault-gaps.ts +146 -0
- package/src/cli/build.ts +2 -2
- package/src/cli/client-add.test.ts +26 -1
- package/src/cli/client-add.ts +106 -27
- package/src/cli/competitor-mention-removal.test.ts +1 -1
- package/src/cli/db-seed.ts +2 -0
- package/src/cli/db.ts +150 -11
- package/src/cli/dev.ts +119 -211
- package/src/cli/docker-clean.ts +2 -2
- package/src/cli/docker-cli.test.ts +1 -1
- package/src/cli/doctor-diff.ts +4 -2
- package/src/cli/doctor-pii.test.ts +1 -1
- package/src/cli/doctor.ts +14 -1
- package/src/cli/hero-meta.test.ts +4 -2
- package/src/cli/load-config.images.test.ts +8 -10
- package/src/cli/load-config.ts +1 -1
- package/src/cli/registry.ts +22 -10
- package/src/cli/replay.ts +3 -1
- package/src/cli/start.ts +1 -1
- package/src/cli/tui/keys.ts +2 -3
- package/src/client/auth/cookies.ts +74 -0
- package/src/client/auth/create-auth-client.ts +636 -0
- package/src/client/auth/denials.ts +99 -0
- package/src/client/auth/session.ts +283 -0
- package/src/client/auth.test.ts +251 -0
- package/src/client/auth.ts +39 -114
- package/src/client/create-with-session.ts +245 -0
- package/src/client/create.ts +51 -5
- package/src/client/index.ts +11 -1
- package/src/client/live.ts +11 -79
- package/src/client/notes-contract.test.ts +5 -10
- package/src/client/sse.ts +137 -0
- package/src/client/stream.ts +147 -0
- package/src/client/transport.test.ts +32 -0
- package/src/client/transport.ts +123 -26
- package/src/client/types.ts +118 -14
- package/src/client-react/index.ts +185 -24
- package/src/client-react/use-live-query.ts +13 -3
- package/src/compiler/aot.test.ts +7 -4
- package/src/compiler/effects-embed.test.ts +56 -0
- package/src/compiler/effects-fetch.test.ts +43 -0
- package/src/compiler/effects-infer.ts +58 -2
- package/src/compiler/extract.test.ts +258 -44
- package/src/compiler/extract.ts +566 -48
- package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +7 -4
- package/src/compiler/fixtures/skyport/src/flows/bookings/signals.ts +2 -8
- package/src/compiler/fixtures/skyport.expected.json +4 -4
- package/src/compiler/fixtures/triggers/five-triggers.ts +14 -10
- package/src/compiler/response.ts +2 -2
- package/src/compiler/search-writer-isolation.test.ts +40 -0
- package/src/config/index.ts +11 -0
- package/src/console/server/app.ts +17 -23
- package/src/console/server/bind.ts +4 -0
- package/src/console/server/console.test.ts +2 -2
- package/src/console/server/flows-invoke.test.ts +50 -34
- package/src/console/server/flows.ts +436 -255
- package/src/console/server/runs-ingest.test.ts +6 -3
- package/src/console/server/serve.ts +1 -1
- package/src/console/server/signals.test.ts +1 -5
- package/src/console/server/signals.ts +8 -6
- package/src/console/server/state.ts +6 -1
- package/src/console/server/store.ts +1 -1
- package/src/console/ui-next/dist/assets/FileExportIcon-Ck-5od4R.js +1 -0
- package/src/console/ui-next/dist/assets/MoreHorizontalCircle01Icon-gMNGsE37.js +1 -0
- package/src/console/ui-next/dist/assets/PlusSignIcon-CwG3nxfu.js +1 -0
- package/src/console/ui-next/dist/assets/UnavailableIcon-D9cvHVPr.js +1 -0
- package/src/console/ui-next/dist/assets/UserIcon-DaE2PB5_.js +1 -0
- package/src/console/ui-next/dist/assets/access-page-DFeymU07.js +4 -0
- package/src/console/ui-next/dist/assets/agent-disclosure-U1rdfblp.js +1 -0
- package/src/console/ui-next/dist/assets/cache-glyph-BeFJeqBG.js +1 -0
- package/src/console/ui-next/dist/assets/call-pii-button-CVAONPii.js +1 -0
- package/src/console/ui-next/dist/assets/collapsible-D2A6NJ-3.js +1 -0
- package/src/console/ui-next/dist/assets/copy-inline-button-CAYD18cr.js +1 -0
- package/src/console/ui-next/dist/assets/dagre.esm-B1_XeuLP.js +1 -0
- package/src/console/ui-next/dist/assets/detail-header-DVWNjWjg.js +1 -0
- package/src/console/ui-next/dist/assets/dropdown-menu-4h2LOVXM.js +1 -0
- package/src/console/ui-next/dist/assets/duration-tone-Cgk_h5ja.js +9 -0
- package/src/console/ui-next/dist/assets/element-icons-BI8cJgdh.js +1 -0
- package/src/console/ui-next/dist/assets/explorer-empty-CJs5A-wm.js +1 -0
- package/src/console/ui-next/dist/assets/flows-page-Dss7941e.js +1 -0
- package/src/console/ui-next/dist/assets/highlighted-json-MYZQtRnw.js +154 -0
- package/src/console/ui-next/dist/assets/http-method-Jrh39p7A.js +1 -0
- package/src/console/ui-next/dist/assets/index-D0zS5rKO.css +2 -0
- package/src/console/ui-next/dist/assets/index-DXP2dBIF.js +63 -0
- package/src/console/ui-next/dist/assets/observability-page-HvolXxTI.js +4 -0
- package/src/console/ui-next/dist/assets/react-dom-Ddte4I-Q.js +9 -0
- package/src/console/ui-next/dist/assets/replica-lag-CSh2dzrb.js +18 -0
- package/src/console/ui-next/dist/assets/request-meta-BatF8KrK.js +1 -0
- package/src/console/ui-next/dist/assets/shortcut-keys-3ILd8oGn.js +1 -0
- package/src/console/ui-next/dist/assets/{sql-BskegiFM.js → sql-BsFa4tDR.js} +1 -1
- package/src/console/ui-next/dist/assets/store-page-eiKiHnNe.js +41 -0
- package/src/console/ui-next/dist/assets/trace-detail-sheet-CZkMeKS-.js +2 -0
- package/src/console/ui-next/dist/assets/tree-expand-toggle-CW8y5A2h.js +55 -0
- package/src/console/ui-next/dist/assets/units-page-B_RWJrEO.js +1 -0
- package/src/console/ui-next/dist/assets/{use-vault-list-uk4WVboC.js → use-vault-list-CT4-gajj.js} +1 -1
- package/src/console/ui-next/dist/assets/vault-page-CWrg-A68.js +2 -0
- package/src/console/ui-next/dist/assets/xyflow-CSyC6ryz.css +1 -0
- package/src/console/ui-next/dist/assets/xyflow-yApv7D4e.js +7 -0
- package/src/console/ui-next/dist/index.html +6 -13
- package/src/console/ui-next/seed-invoke-host.ts +21 -18
- package/src/console/ui-next/src/client.ts +7 -2
- package/src/console/ui-next/src/features/flows/graph/element-map.ts +2 -0
- package/src/console/ui-next/src/features/flows/traces/effect-kind.ts +12 -2
- package/src/console/ui-next/src/features/flows/traces/effect-summary.ts +4 -0
- package/src/console/ui-next/src/features/flows/traces/trace-detail-sheet.tsx +8 -0
- package/src/console/ui-next/src/features/flows/traces/waterfall-bars.ts +4 -0
- package/src/console/ui-next/src/features/flows/traces/waterfall-tooltip.ts +9 -3
- package/src/console/ui-next/src/features/store/detail/reveal-cell.tsx +7 -11
- package/src/console/ui-next/src/features/store/detail/store-row-detail-sheet.tsx +2 -2
- package/src/console/ui-next/src/features/store/lib/fields-from-table.ts +2 -0
- package/src/console/ui-next/src/features/store/lib/grid-model.test.ts +25 -1
- package/src/console/ui-next/src/features/store/lib/grid-model.ts +36 -1
- package/src/console/ui-next/src/features/store/query/query-results.tsx +3 -3
- package/src/console/ui-next/src/features/units/detail/effects-summary.tsx +2 -0
- package/src/console/ui-next/src/features/units/lib/call-read-safe.ts +3 -1
- package/src/console/ui-next/src/features/units/lib/fields-from-schema.ts +6 -0
- package/src/docker/ai-model-status.test.ts +1 -12
- package/src/docker/ai-model-status.ts +10 -38
- package/src/docker/compose-up.test.ts +100 -0
- package/src/docker/compose-up.ts +292 -0
- package/src/docker/compose.ts +4 -14
- package/src/docker/derive.ts +9 -34
- package/src/docker/docker.test.ts +16 -261
- package/src/docker/images-config.test.ts +13 -25
- package/src/docker/index.ts +1 -24
- package/src/docker/recipes/index.ts +0 -23
- package/src/docker/recipes/pgdog.ts +6 -4
- package/src/docker/stack-id.test.ts +2 -2
- package/src/docker/stack-id.ts +0 -1
- package/src/docker/types.ts +2 -2
- package/src/drivers/ai-anthropic.ts +10 -0
- package/src/drivers/ai-openai-compatible.ts +34 -7
- package/src/drivers/ai-providers.test.ts +0 -107
- package/src/drivers/ai-stream.test.ts +0 -34
- package/src/drivers/ai-types.ts +17 -8
- package/src/drivers/channel-fcm.ts +6 -1
- package/src/drivers/channel-msegat.ts +6 -1
- package/src/drivers/channel-resend.ts +5 -1
- package/src/drivers/channel-smtp.ts +5 -1
- package/src/drivers/channel-sndr.ts +10 -1
- package/src/drivers/channel-taqnyat-mail.ts +5 -1
- package/src/drivers/channel-taqnyat-whatsapp.ts +6 -1
- package/src/drivers/channel-taqnyat.ts +6 -1
- package/src/drivers/channel-types.ts +10 -0
- package/src/drivers/channel-unifonic.ts +6 -1
- package/src/drivers/channel-wa-cloud.ts +6 -1
- package/src/drivers/channel-webpush.ts +6 -1
- package/src/drivers/external.ts +33 -0
- package/src/drivers/index.ts +0 -10
- package/src/drivers/meilisearch.ts +6 -0
- package/src/drivers/oauth-types.ts +4 -0
- package/src/drivers/postgres.test.ts +74 -3
- package/src/drivers/postgres.ts +175 -6
- package/src/drivers/signal-types.ts +5 -5
- package/src/drivers/types.ts +7 -0
- package/src/drivers/vault-types.ts +5 -0
- package/src/elements/ai/declare.ts +17 -4
- package/src/elements/ai/eval.ts +1 -1
- package/src/elements/ai/mcp-http.ts +1 -1
- package/src/elements/ai/pii.ts +1 -1
- package/src/elements/ai/providers.test.ts +289 -0
- package/src/elements/ai/providers.ts +169 -0
- package/src/elements/ai/runtime.ts +68 -5
- package/src/elements/ai/schema.ts +2 -2
- package/src/elements/ai.test.ts +7 -7
- package/src/elements/ai.ts +17 -1
- package/src/elements/channel/runtime.ts +105 -12
- package/src/elements/clock/cron-fields.test.ts +144 -0
- package/src/elements/clock/cron-fields.ts +185 -0
- package/src/elements/clock/declare.ts +247 -3
- package/src/elements/clock.ts +21 -1
- package/src/elements/index.ts +15 -0
- package/src/elements/signal/chaos-child.ts +1 -2
- package/src/elements/signal/declare.ts +65 -37
- package/src/elements/signal/delivery-modes.test.ts +11 -31
- package/src/elements/signal/dry-run-replay.test.ts +1 -7
- package/src/elements/signal/dry-run-write-isolation.test.ts +1 -7
- package/src/elements/signal/key-ordering.test.ts +6 -26
- package/src/elements/signal/lease-reclaim.test.ts +2 -6
- package/src/elements/signal/optional-emit.test.ts +6 -9
- package/src/elements/signal/order-lifecycle.test.ts +4 -17
- package/src/elements/signal/orphan-messages.test.ts +4 -15
- package/src/elements/signal/reconcile.test.ts +2 -2
- package/src/elements/signal/runtime.ts +1 -1
- package/src/elements/signal/schema-emit.test.ts +4 -8
- package/src/elements/signal.test.ts +24 -49
- package/src/elements/signal.ts +9 -2
- package/src/elements/store/domain-ddl.test.ts +1 -1
- package/src/elements/store/live-http.test.ts +9 -4
- package/src/elements/store/prepare-row.test.ts +123 -0
- package/src/elements/store/resource.ts +43 -12
- package/src/elements/store/schema-decl.ts +117 -0
- package/src/elements/store/search-backfill.ts +205 -0
- package/src/elements/store/search-bind.ts +66 -0
- package/src/elements/store/search-bm25.ts +78 -0
- package/src/elements/store/search-ddl.ts +156 -0
- package/src/elements/store/search-embed-flow.ts +141 -0
- package/src/elements/store/search-errors.ts +34 -0
- package/src/elements/store/search-fusion.ts +112 -0
- package/src/elements/store/search-lsh.ts +179 -0
- package/src/elements/store/search-runtime.ts +300 -0
- package/src/elements/store/search.test.ts +144 -0
- package/src/elements/store/sql-session.test.ts +1 -0
- package/src/elements/store/sql-session.ts +83 -3
- package/src/elements/store/table.ts +23 -2
- package/src/elements/store/upsert-app.test.ts +1 -3
- package/src/elements/store.ts +50 -0
- package/src/full.ts +4 -2
- package/src/http.ts +4 -1
- package/src/i18n/catalogs/ar.ts +14 -6
- package/src/i18n/catalogs/en.ts +14 -6
- package/src/index.ts +6 -1
- package/src/kernel/adopt-barrel-fresh.test.ts +7 -7
- package/src/kernel/adopt-routes.ts +9 -1
- package/src/kernel/app-auth.ts +5 -0
- package/src/kernel/app.ts +102 -9
- package/src/kernel/auto-cache.test.ts +6 -12
- package/src/kernel/auto-registry.test.ts +3 -3
- package/src/kernel/boot-bind/ai.test.ts +22 -19
- package/src/kernel/boot-bind/ai.ts +5 -43
- package/src/kernel/boot-bind/clock.ts +23 -5
- package/src/kernel/boot-bind/honor-config.test.ts +4 -4
- package/src/kernel/boot.test.ts +11 -6
- package/src/kernel/boot.ts +66 -16
- package/src/kernel/boundary-contract.ts +93 -0
- package/src/kernel/budget.test.ts +1 -1
- package/src/kernel/call.ts +89 -0
- package/src/kernel/capability.ts +6 -0
- package/src/kernel/client-descriptor.ts +123 -0
- package/src/kernel/clock-timezone.test.ts +80 -0
- package/src/kernel/correlation.test.ts +1 -1
- package/src/kernel/dry-run.ts +11 -8
- package/src/kernel/effects-stamping.test.ts +42 -9
- package/src/kernel/effects.test.ts +4 -2
- package/src/kernel/effects.ts +51 -9
- package/src/kernel/errors-channel.ts +17 -0
- package/src/kernel/errors-live-resume.ts +3 -2
- package/src/kernel/errors-tenant.ts +7 -4
- package/src/kernel/errors.registry-helpers.ts +96 -0
- package/src/kernel/errors.registry.test.ts +139 -25
- package/src/kernel/errors.ts +102 -23
- package/src/kernel/external-effects.test.ts +196 -0
- package/src/kernel/flow.test.ts +13 -4
- package/src/kernel/flow.ts +69 -71
- package/src/kernel/fx-ask-telemetry.test.ts +2 -2
- package/src/kernel/fx-dead-letters.test.ts +3 -3
- package/src/kernel/fx-fetch.ts +55 -0
- package/src/kernel/fx-live-stream.ts +2 -2
- package/src/kernel/fx-live.test.ts +8 -8
- package/src/kernel/fx.test.ts +17 -11
- package/src/kernel/fx.ts +180 -57
- package/src/kernel/horizontal-child.ts +1 -1
- package/src/kernel/http-query.test.ts +3 -6
- package/src/kernel/index.ts +13 -3
- package/src/kernel/instance-id.ts +1 -1
- package/src/kernel/instances.test.ts +40 -0
- package/src/kernel/instances.ts +47 -9
- package/src/kernel/live-http.test.ts +6 -7
- package/src/kernel/live-http.ts +6 -2
- package/src/kernel/live-resume.test.ts +1 -1
- package/src/kernel/mcp-tool.test.ts +3 -3
- package/src/kernel/on.ts +98 -4
- package/src/kernel/pipeline.test.ts +12 -15
- package/src/kernel/plugin-elements.test.ts +1 -1
- package/src/kernel/stamp-http.test.ts +3 -3
- package/src/kernel/triggers.ts +210 -95
- package/src/kernel-entry.ts +0 -1
- package/src/manifest/diff.ts +11 -1
- package/src/manifest/fixtures/skyport.excerpt.json +1 -1
- package/src/manifest/types.ts +46 -2
- package/src/mcp/docs-index.ts +3 -3
- package/src/mcp/docs-mcp.test.ts +2 -2
- package/src/mcp/docs-tools.ts +1 -1
- package/src/okid.test.ts +56 -0
- package/src/okid.ts +55 -11
- package/src/plugins/anonymous.ts +8 -4
- package/src/plugins/auth/shared.ts +27 -3
- package/src/plugins/auth-delivery.mailpit.integration.test.ts +1 -1
- package/src/plugins/auth-methods.security.test.ts +561 -23
- package/src/plugins/config-source.ts +1 -1
- package/src/plugins/csrf.test.ts +65 -0
- package/src/plugins/index.ts +2 -0
- package/src/plugins/magic-link.ts +36 -16
- package/src/plugins/oauth/shared.ts +3 -1
- package/src/plugins/oauth.ts +22 -14
- package/src/plugins/otp.ts +37 -21
- package/src/plugins/passkey-webauthn.ts +9 -6
- package/src/plugins/passkey.ts +98 -26
- package/src/plugins/pre-account-hijack.test.ts +223 -0
- package/src/plugins/two-factor.ts +466 -37
- package/src/plugins/username.ts +19 -7
- package/src/release/build-lib.ts +1 -0
- package/src/release/limits.ts +2 -2
- package/src/release/measure.ts +1 -1
- package/src/runs/collect.test.ts +0 -2
- package/src/runtime/json-code-block.test.ts +250 -20
- package/src/runtime/json-code-block.ts +1261 -41
- package/src/term.test.ts +1 -1
- package/src/test/create-test-app.test.ts +12 -12
- package/src/test/live-signals.test.ts +6 -6
- package/src/test/provisions.integration.test.ts +10 -14
- package/src/test/reset-element-registries.ts +1 -1
- package/src/test/tenant-isolation.test.ts +12 -6
- package/site/content/docs/deployment/docker-swarm.mdx +0 -164
- package/site/content/docs/deployment/docker.mdx +0 -227
- package/site/content/docs/deployment/index.mdx +0 -83
- package/site/content/docs/deployment/kubernetes.mdx +0 -176
- package/site/content/docs/deployment/meta.json +0 -5
- package/site/content/docs/deployment/reverse-proxy.mdx +0 -234
- package/site/content/docs/elements/ai.mdx +0 -385
- package/site/content/docs/elements/channel.mdx +0 -346
- package/site/content/docs/elements/clock.mdx +0 -244
- package/site/content/docs/elements/flow.mdx +0 -420
- package/site/content/docs/elements/gate.mdx +0 -436
- package/site/content/docs/elements/signal.mdx +0 -380
- package/site/content/docs/elements/store.mdx +0 -1099
- package/site/content/docs/elements/vault.mdx +0 -405
- package/site/content/docs/get-started/basic-usage.mdx +0 -173
- package/site/content/docs/get-started/index.mdx +0 -43
- package/site/content/docs/get-started/installation.mdx +0 -220
- package/site/content/docs/get-started/introduction.mdx +0 -132
- package/site/content/docs/get-started/meta.json +0 -13
- package/site/content/docs/get-started/project-structure.mdx +0 -925
- package/site/content/docs/get-started/testing.mdx +0 -328
- package/site/content/docs/get-started/why.mdx +0 -162
- package/site/content/docs/recipes/llama-cpp.mdx +0 -151
- package/site/content/docs/recipes/ollama.mdx +0 -142
- package/site/content/docs/recipes/sglang.mdx +0 -105
- package/site/content/docs/recipes/vllm.mdx +0 -106
- package/site/content/docs/reference/cli.md +0 -232
- package/site/content/docs/reference/client.mdx +0 -469
- package/site/content/docs/reference/security.md +0 -74
- package/src/cli/ai-setup/detect-ollama.ts +0 -213
- package/src/cli/ai-setup/recommend.test.ts +0 -225
- package/src/cli/ai-setup/recommend.ts +0 -225
- package/src/cli/dev-controls.test.ts +0 -122
- package/src/cli/dev-controls.ts +0 -164
- package/src/cli/tui/DevLive.tsx +0 -126
- package/src/console/ui-next/dist/assets/access-page-De7Lc2JC.js +0 -4
- package/src/console/ui-next/dist/assets/agent-disclosure-BP0Y0Sux.js +0 -1
- package/src/console/ui-next/dist/assets/cache-glyph-B5X-NM0-.js +0 -1
- package/src/console/ui-next/dist/assets/call-pii-button-ChAUiLo9.js +0 -1
- package/src/console/ui-next/dist/assets/collapsible-DGnOM2ph.js +0 -1
- package/src/console/ui-next/dist/assets/copy-inline-button-DBHhgHKP.js +0 -1
- package/src/console/ui-next/dist/assets/dagre.esm-ZwcdTuZZ.js +0 -1
- package/src/console/ui-next/dist/assets/detail-header-DhHM1iaZ.js +0 -1
- package/src/console/ui-next/dist/assets/dropdown-menu-_NjTEo5_.js +0 -1
- package/src/console/ui-next/dist/assets/duration-tone-sC3lGABz.js +0 -9
- package/src/console/ui-next/dist/assets/element-icons-BVXtRyd3.js +0 -1
- package/src/console/ui-next/dist/assets/explorer-empty-2uIhBu0_.js +0 -1
- package/src/console/ui-next/dist/assets/flows-page-RGy7VEA_.js +0 -1
- package/src/console/ui-next/dist/assets/highlighted-json-Awq7gYdu.js +0 -154
- package/src/console/ui-next/dist/assets/http-method-_UHM2ODJ.js +0 -1
- package/src/console/ui-next/dist/assets/index-Ck88Jmv8.css +0 -2
- package/src/console/ui-next/dist/assets/index-_rgpdVzo.js +0 -66
- package/src/console/ui-next/dist/assets/link-BX6Vqztd.js +0 -1
- package/src/console/ui-next/dist/assets/observability-page-Ds6pcnh-.js +0 -4
- package/src/console/ui-next/dist/assets/preload-helper-oH4irX4C.js +0 -1
- package/src/console/ui-next/dist/assets/react-D8E3mtu1.js +0 -1
- package/src/console/ui-next/dist/assets/react-dom-Bph1y7z7.js +0 -9
- package/src/console/ui-next/dist/assets/replica-lag-DKRrbvdo.js +0 -18
- package/src/console/ui-next/dist/assets/request-meta-DV0ywz7t.js +0 -1
- package/src/console/ui-next/dist/assets/shortcut-JQIZlWfm.js +0 -1
- package/src/console/ui-next/dist/assets/shortcut-keys-DKxNTe_m.js +0 -1
- package/src/console/ui-next/dist/assets/skeleton-D-czQJT6.js +0 -1
- package/src/console/ui-next/dist/assets/store-page-02xOiqIK.js +0 -41
- package/src/console/ui-next/dist/assets/trace-detail-sheet-B09O8rA6.js +0 -2
- package/src/console/ui-next/dist/assets/tree-expand-toggle-BtyhmWb4.js +0 -55
- package/src/console/ui-next/dist/assets/units-page-4rHOePuE.js +0 -1
- package/src/console/ui-next/dist/assets/useMutation-B8EO02Ej.js +0 -1
- package/src/console/ui-next/dist/assets/useRender-BE2A9BWC.js +0 -1
- package/src/console/ui-next/dist/assets/vault-page-DISPgxLM.js +0 -2
- package/src/console/ui-next/dist/assets/xyflow-D7n4g6go.js +0 -7
- package/src/console/ui-next/dist/assets/xyflow-DZ0Ws1xk.css +0 -1
- package/src/docker/ollama-pull.ts +0 -232
- package/src/docker/recipes/llama-cpp.ts +0 -298
- package/src/docker/recipes/ollama.ts +0 -44
- package/src/docker/recipes/sglang.ts +0 -55
- package/src/docker/recipes/vllm.ts +0 -44
- package/src/drivers/ai-ollama-tools.integration.test.ts +0 -109
- package/src/drivers/ai-ollama.integration.test.ts +0 -184
- package/src/drivers/ai-ollama.ts +0 -389
- package/src/drivers/ollama.ts +0 -14
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `openai-compatible` AI driver — thin HTTP client for OpenAI-shaped APIs.
|
|
3
3
|
*
|
|
4
|
-
* One protocol driver for OpenAI, Groq, Together, OpenRouter,
|
|
5
|
-
*
|
|
6
|
-
* `
|
|
7
|
-
* on the separate `ollama` driver. Injectable `fetch` for tests. Never a
|
|
4
|
+
* One protocol driver for OpenAI, Groq, Together, OpenRouter, LM Studio, and
|
|
5
|
+
* other chat/completions `/v1` endpoints. Configure via `baseUrl` + `apiKey` +
|
|
6
|
+
* `model` (+ optional `headers`). Injectable `fetch` for tests. Never a
|
|
8
7
|
* production default — prod must declare.
|
|
9
8
|
*/
|
|
10
9
|
|
|
@@ -19,6 +18,8 @@ import type {
|
|
|
19
18
|
AiStreamChunk,
|
|
20
19
|
AiToolCall,
|
|
21
20
|
} from "./ai-types.ts";
|
|
21
|
+
import type { DriverExternal } from "./external.ts";
|
|
22
|
+
import { hostFromUrl } from "./external.ts";
|
|
22
23
|
|
|
23
24
|
/** Default OpenAI cloud base — apiKey is required for this origin. */
|
|
24
25
|
export const OPENAI_COMPAT_DEFAULT_BASE = "https://api.openai.com/v1";
|
|
@@ -90,6 +91,7 @@ export async function openOpenaiCompatible(options: AiOpenOptions = {}): Promise
|
|
|
90
91
|
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
91
92
|
const extraHeaders = options.headers;
|
|
92
93
|
preconnectFetch(fetchFn, baseUrl);
|
|
94
|
+
const externalBase = resolveOpenaiCompatibleExternal(baseUrl, options);
|
|
93
95
|
|
|
94
96
|
return {
|
|
95
97
|
driverId: "openai-compatible",
|
|
@@ -140,6 +142,7 @@ export async function openOpenaiCompatible(options: AiOpenOptions = {}): Promise
|
|
|
140
142
|
inputTokens: raw.usage?.prompt_tokens,
|
|
141
143
|
outputTokens: raw.usage?.completion_tokens,
|
|
142
144
|
},
|
|
145
|
+
...(externalBase !== undefined ? { external: externalBase } : {}),
|
|
143
146
|
};
|
|
144
147
|
},
|
|
145
148
|
async *stream(opts: AiCompleteOptions): AsyncIterable<AiStreamChunk> {
|
|
@@ -186,11 +189,35 @@ export async function openOpenaiCompatible(options: AiOpenOptions = {}): Promise
|
|
|
186
189
|
vectors,
|
|
187
190
|
model: raw.model ?? resolvedModel,
|
|
188
191
|
driverId: "openai-compatible",
|
|
192
|
+
...(externalBase !== undefined ? { external: externalBase } : {}),
|
|
189
193
|
};
|
|
190
194
|
},
|
|
191
195
|
};
|
|
192
196
|
}
|
|
193
197
|
|
|
198
|
+
/**
|
|
199
|
+
* Build egress metadata from open options + the real request base URL.
|
|
200
|
+
*
|
|
201
|
+
* Kind comes from declare-time {@link AiOpenOptions.external} (or defaults to
|
|
202
|
+
* third-party for the OpenAI cloud base). Host is always the real request host.
|
|
203
|
+
*
|
|
204
|
+
* @param baseUrl - Normalized chat/embeddings base
|
|
205
|
+
* @param options - Open options
|
|
206
|
+
*/
|
|
207
|
+
function resolveOpenaiCompatibleExternal(
|
|
208
|
+
baseUrl: string,
|
|
209
|
+
options: AiOpenOptions,
|
|
210
|
+
): DriverExternal | undefined {
|
|
211
|
+
const host = hostFromUrl(baseUrl);
|
|
212
|
+
if (!host) return undefined;
|
|
213
|
+
const kind = options.external?.kind ?? "third-party";
|
|
214
|
+
return {
|
|
215
|
+
host,
|
|
216
|
+
kind,
|
|
217
|
+
...(options.external?.provider !== undefined ? { provider: options.external.provider } : {}),
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
194
221
|
/** Protocol-named openai-compatible driver. */
|
|
195
222
|
export const openaiCompatibleAiDriver: AiDriver = {
|
|
196
223
|
id: "openai-compatible",
|
|
@@ -198,8 +225,8 @@ export const openaiCompatibleAiDriver: AiDriver = {
|
|
|
198
225
|
};
|
|
199
226
|
|
|
200
227
|
/**
|
|
201
|
-
*
|
|
202
|
-
* the ask-time schema instruction is the portable contract.
|
|
228
|
+
* Some openai-compatible servers empty `content` on `json_schema`;
|
|
229
|
+
* `json_object` plus the ask-time schema instruction is the portable contract.
|
|
203
230
|
*
|
|
204
231
|
* @param responseFormat - Runtime format (may be json_schema)
|
|
205
232
|
*/
|
|
@@ -309,7 +336,7 @@ async function* readOpenaiSse(res: Response, signal?: AbortSignal): AsyncGenerat
|
|
|
309
336
|
function responseTextStream(res: Response): AsyncIterable<string> {
|
|
310
337
|
const stream = (res as Response & { textStream?: () => AsyncIterable<string> }).textStream;
|
|
311
338
|
if (typeof stream !== "function") {
|
|
312
|
-
throw new Error("openai-compatible: Response.textStream is required (Bun >= 1.4.
|
|
339
|
+
throw new Error("openai-compatible: Response.textStream is required (Bun >= 1.4.2)");
|
|
313
340
|
}
|
|
314
341
|
return stream.call(res);
|
|
315
342
|
}
|
|
@@ -5,14 +5,6 @@
|
|
|
5
5
|
import { describe, expect, test } from "bun:test";
|
|
6
6
|
import { anthropicAiDriver, openAnthropic } from "./ai-anthropic.ts";
|
|
7
7
|
import { mockAiDriver } from "./ai-mock.ts";
|
|
8
|
-
import {
|
|
9
|
-
normalizeOllamaBaseUrl,
|
|
10
|
-
ollamaAiDriver,
|
|
11
|
-
OLLAMA_DEFAULT_MODEL,
|
|
12
|
-
openOllama,
|
|
13
|
-
OllamaUnavailableError,
|
|
14
|
-
resolveOllamaModel,
|
|
15
|
-
} from "./ai-ollama.ts";
|
|
16
8
|
import { openaiCompatibleAiDriver, openOpenaiCompatible } from "./ai-openai-compatible.ts";
|
|
17
9
|
|
|
18
10
|
describe("anthropic driver", () => {
|
|
@@ -266,102 +258,3 @@ describe("openai-compatible driver", () => {
|
|
|
266
258
|
);
|
|
267
259
|
});
|
|
268
260
|
});
|
|
269
|
-
|
|
270
|
-
describe("ollama driver", () => {
|
|
271
|
-
test("id is ollama; documented default model is qwen3.5:9b (overridable)", () => {
|
|
272
|
-
expect(ollamaAiDriver.id).toBe("ollama");
|
|
273
|
-
expect(OLLAMA_DEFAULT_MODEL).toBe("qwen3.5:9b");
|
|
274
|
-
expect(resolveOllamaModel({ model: "llama3.2:1b" })).toBe("llama3.2:1b");
|
|
275
|
-
expect(normalizeOllamaBaseUrl("localhost:11434")).toBe("http://localhost:11434");
|
|
276
|
-
expect(normalizeOllamaBaseUrl("http://127.0.0.1:11434/v1")).toBe("http://127.0.0.1:11434");
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
test("complete via injectable fetch — native /api/chat, any model name", async () => {
|
|
280
|
-
const calls: Array<{ url: string; body: Record<string, unknown> }> = [];
|
|
281
|
-
const fetchFn: typeof fetch = Object.assign(
|
|
282
|
-
async (input: string | URL | Request, init?: RequestInit) => {
|
|
283
|
-
const url = String(input);
|
|
284
|
-
if (url.endsWith("/api/tags")) {
|
|
285
|
-
return new Response(JSON.stringify({ models: [] }), { status: 200 });
|
|
286
|
-
}
|
|
287
|
-
const body = JSON.parse(String(init?.body)) as Record<string, unknown>;
|
|
288
|
-
calls.push({ url, body });
|
|
289
|
-
return new Response(
|
|
290
|
-
JSON.stringify({
|
|
291
|
-
model: "llama3.2:1b",
|
|
292
|
-
message: { role: "assistant", content: "pong" },
|
|
293
|
-
prompt_eval_count: 4,
|
|
294
|
-
eval_count: 1,
|
|
295
|
-
}),
|
|
296
|
-
{ status: 200 },
|
|
297
|
-
);
|
|
298
|
-
},
|
|
299
|
-
{ preconnect: () => {} },
|
|
300
|
-
) as typeof fetch;
|
|
301
|
-
|
|
302
|
-
const client = await openOllama({
|
|
303
|
-
model: "llama3.2:1b",
|
|
304
|
-
baseUrl: "http://ollama.test:11434",
|
|
305
|
-
fetch: fetchFn,
|
|
306
|
-
});
|
|
307
|
-
const result = await client.complete({
|
|
308
|
-
messages: [{ role: "user", content: "ping" }],
|
|
309
|
-
temperature: 0,
|
|
310
|
-
maxTokens: 16,
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
expect(result.driverId).toBe("ollama");
|
|
314
|
-
expect(result.text).toBe("pong");
|
|
315
|
-
expect(result.usage?.inputTokens).toBe(4);
|
|
316
|
-
expect(calls).toHaveLength(1);
|
|
317
|
-
expect(calls[0]!.url).toBe("http://ollama.test:11434/api/chat");
|
|
318
|
-
expect(calls[0]!.body.model).toBe("llama3.2:1b");
|
|
319
|
-
expect(calls[0]!.body.stream).toBe(false);
|
|
320
|
-
expect(calls[0]!.body.think).toBe(false);
|
|
321
|
-
expect(calls[0]!.body.options).toEqual({ temperature: 0, num_predict: 16 });
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
test("embed via injectable fetch — native /api/embeddings", async () => {
|
|
325
|
-
const paths: string[] = [];
|
|
326
|
-
const fetchFn: typeof fetch = Object.assign(
|
|
327
|
-
async (input: string | URL | Request) => {
|
|
328
|
-
const url = String(input);
|
|
329
|
-
paths.push(url);
|
|
330
|
-
if (url.endsWith("/api/tags")) {
|
|
331
|
-
return new Response(JSON.stringify({ models: [] }), { status: 200 });
|
|
332
|
-
}
|
|
333
|
-
if (url.endsWith("/api/embeddings")) {
|
|
334
|
-
return new Response(JSON.stringify({ embedding: [0.1, 0.2, 0.3] }), {
|
|
335
|
-
status: 200,
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
return new Response(JSON.stringify({ error: "unexpected" }), { status: 500 });
|
|
339
|
-
},
|
|
340
|
-
{ preconnect: () => {} },
|
|
341
|
-
) as typeof fetch;
|
|
342
|
-
|
|
343
|
-
const client = await openOllama({
|
|
344
|
-
model: "nomic-embed-text",
|
|
345
|
-
baseUrl: "http://ollama.test:11434",
|
|
346
|
-
fetch: fetchFn,
|
|
347
|
-
});
|
|
348
|
-
const emb = await client.embed!({ input: ["a", "b"] });
|
|
349
|
-
expect(emb.driverId).toBe("ollama");
|
|
350
|
-
expect(emb.vectors).toHaveLength(2);
|
|
351
|
-
expect(emb.vectors[0]).toEqual([0.1, 0.2, 0.3]);
|
|
352
|
-
expect(paths.filter((p) => p.endsWith("/api/embeddings"))).toHaveLength(2);
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
test("unreachable server throws OllamaUnavailableError (no silent fallback)", async () => {
|
|
356
|
-
const fetchFn: typeof fetch = Object.assign(
|
|
357
|
-
async () => {
|
|
358
|
-
throw new TypeError("connection refused");
|
|
359
|
-
},
|
|
360
|
-
{ preconnect: () => {} },
|
|
361
|
-
) as typeof fetch;
|
|
362
|
-
|
|
363
|
-
await expect(
|
|
364
|
-
openOllama({ baseUrl: "http://127.0.0.1:9", fetch: fetchFn }),
|
|
365
|
-
).rejects.toBeInstanceOf(OllamaUnavailableError);
|
|
366
|
-
});
|
|
367
|
-
});
|
|
@@ -7,7 +7,6 @@ import { withAbortSignal } from "../kernel/abort-scope.ts";
|
|
|
7
7
|
import { createFx, createFxContext } from "../kernel/fx.ts";
|
|
8
8
|
import { ai, createAiRuntime } from "../elements/ai.ts";
|
|
9
9
|
import { openOpenaiCompatible } from "./ai-openai-compatible.ts";
|
|
10
|
-
import { openOllama } from "./ai-ollama.ts";
|
|
11
10
|
import { mockAiDriver } from "./ai-mock.ts";
|
|
12
11
|
|
|
13
12
|
describe("openai-compatible SSE stream", () => {
|
|
@@ -59,39 +58,6 @@ describe("openai-compatible SSE stream", () => {
|
|
|
59
58
|
});
|
|
60
59
|
});
|
|
61
60
|
|
|
62
|
-
describe("ollama NDJSON stream", () => {
|
|
63
|
-
test("yields message.content deltas", async () => {
|
|
64
|
-
const ndjson =
|
|
65
|
-
JSON.stringify({ message: { content: "A" }, done: false }) +
|
|
66
|
-
"\n" +
|
|
67
|
-
JSON.stringify({ message: { content: "B" }, done: true }) +
|
|
68
|
-
"\n";
|
|
69
|
-
const fetchFn: typeof fetch = Object.assign(
|
|
70
|
-
async (input: string | URL | Request) => {
|
|
71
|
-
const url = String(input);
|
|
72
|
-
if (url.endsWith("/api/tags")) {
|
|
73
|
-
return new Response(JSON.stringify({ models: [] }), { status: 200 });
|
|
74
|
-
}
|
|
75
|
-
return new Response(ndjson, { status: 200 });
|
|
76
|
-
},
|
|
77
|
-
{ preconnect: () => {} },
|
|
78
|
-
) as typeof fetch;
|
|
79
|
-
|
|
80
|
-
const client = await openOllama({
|
|
81
|
-
model: "llama3.2:1b",
|
|
82
|
-
baseUrl: "http://ollama.test:11434",
|
|
83
|
-
fetch: fetchFn,
|
|
84
|
-
});
|
|
85
|
-
const parts: string[] = [];
|
|
86
|
-
for await (const chunk of client.stream!({
|
|
87
|
-
messages: [{ role: "user", content: "x" }],
|
|
88
|
-
})) {
|
|
89
|
-
if (chunk.text) parts.push(chunk.text);
|
|
90
|
-
}
|
|
91
|
-
expect(parts.join("")).toBe("AB");
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
|
|
95
61
|
describe("fx.stream uses ambient AbortSignal", () => {
|
|
96
62
|
test("race abort cancels in-flight stream fetch", async () => {
|
|
97
63
|
let sawAbort = false;
|
package/src/drivers/ai-types.ts
CHANGED
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Protocol-named AI model driver contracts.
|
|
3
3
|
*
|
|
4
|
-
* Driver ids: `mock` · `anthropic` · `openai-compatible` · `bedrock` · `vertex
|
|
4
|
+
* Driver ids: `mock` · `anthropic` · `openai-compatible` · `bedrock` · `vertex`.
|
|
5
5
|
* Dev default is `mock`. There is **no** production default — prod must declare.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import type { DriverExternal } from "./external.ts";
|
|
9
|
+
|
|
8
10
|
/** Protocol ids for AI model drivers. */
|
|
9
|
-
export type AiDriverId =
|
|
10
|
-
| "mock"
|
|
11
|
-
| "anthropic"
|
|
12
|
-
| "openai-compatible"
|
|
13
|
-
| "bedrock"
|
|
14
|
-
| "vertex"
|
|
15
|
-
| "ollama";
|
|
11
|
+
export type AiDriverId = "mock" | "anthropic" | "openai-compatible" | "bedrock" | "vertex";
|
|
16
12
|
|
|
17
13
|
/** Tool definition offered to a model (Flow-backed at the fx layer). */
|
|
18
14
|
export interface AiToolDef {
|
|
@@ -66,6 +62,8 @@ export interface AiCompleteResult {
|
|
|
66
62
|
readonly outputTokens?: number;
|
|
67
63
|
readonly cost?: number;
|
|
68
64
|
};
|
|
65
|
+
/** Egress identity when the completion left the process. */
|
|
66
|
+
readonly external?: DriverExternal;
|
|
69
67
|
}
|
|
70
68
|
|
|
71
69
|
/** One streamed token / delta from a model. */
|
|
@@ -85,6 +83,8 @@ export interface AiEmbedResult {
|
|
|
85
83
|
readonly vectors: readonly (readonly number[])[];
|
|
86
84
|
readonly model: string;
|
|
87
85
|
readonly driverId: AiDriverId;
|
|
86
|
+
/** Egress identity when the embed left the process. */
|
|
87
|
+
readonly external?: DriverExternal;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
/** Opened model client. */
|
|
@@ -115,6 +115,15 @@ export interface AiOpenOptions {
|
|
|
115
115
|
/** Mock canned responses keyed by prompt name or substring. */
|
|
116
116
|
readonly mockResponses?: Readonly<Record<string, unknown>>;
|
|
117
117
|
readonly fetch?: typeof globalThis.fetch;
|
|
118
|
+
/**
|
|
119
|
+
* Driver-reported egress classification for ledger entries.
|
|
120
|
+
* Set by the AI element from declare-time provider identity — never guessed
|
|
121
|
+
* by hostname regex inside the driver.
|
|
122
|
+
*/
|
|
123
|
+
readonly external?: {
|
|
124
|
+
readonly kind: "third-party" | "infrastructure";
|
|
125
|
+
readonly provider?: string;
|
|
126
|
+
};
|
|
118
127
|
}
|
|
119
128
|
|
|
120
129
|
/** AI model driver factory. */
|
|
@@ -72,7 +72,12 @@ export function openFcmChannel(options: ChannelOpenOptions = {}): ChannelDriver
|
|
|
72
72
|
verify: () => transport.verify(),
|
|
73
73
|
};
|
|
74
74
|
|
|
75
|
-
return {
|
|
75
|
+
return {
|
|
76
|
+
id: "fcm",
|
|
77
|
+
channel,
|
|
78
|
+
pushTransport: transport,
|
|
79
|
+
external: { host: "fcm.googleapis.com", provider: "fcm", kind: "third-party" },
|
|
80
|
+
};
|
|
76
81
|
}
|
|
77
82
|
|
|
78
83
|
/** FCM driver factory. */
|
|
@@ -51,7 +51,12 @@ export function openMsegatChannel(options: ChannelOpenOptions = {}): ChannelDriv
|
|
|
51
51
|
verify: () => transport.verify(),
|
|
52
52
|
};
|
|
53
53
|
|
|
54
|
-
return {
|
|
54
|
+
return {
|
|
55
|
+
id: "msegat",
|
|
56
|
+
channel,
|
|
57
|
+
smsTransport: transport,
|
|
58
|
+
external: { host: "www.msegat.com", provider: "msegat", kind: "third-party" },
|
|
59
|
+
};
|
|
55
60
|
}
|
|
56
61
|
|
|
57
62
|
/** Msegat driver factory. */
|
|
@@ -15,7 +15,11 @@ export function openResendChannel(options: ChannelOpenOptions = {}): ChannelDriv
|
|
|
15
15
|
throw new Error("resend channel: apiKey is required");
|
|
16
16
|
}
|
|
17
17
|
const transport = new ResendTransport({ apiKey: options.apiKey });
|
|
18
|
-
return {
|
|
18
|
+
return {
|
|
19
|
+
id: "resend",
|
|
20
|
+
transport,
|
|
21
|
+
external: { host: "api.resend.com", provider: "resend", kind: "third-party" },
|
|
22
|
+
};
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
/** Resend driver factory. */
|
|
@@ -25,7 +25,11 @@ export function openSmtpChannel(options: ChannelOpenOptions = {}): ChannelDriver
|
|
|
25
25
|
adapter: new BunAdapter({ secure }),
|
|
26
26
|
...(options.user && options.pass ? { auth: { user: options.user, pass: options.pass } } : {}),
|
|
27
27
|
});
|
|
28
|
-
return {
|
|
28
|
+
return {
|
|
29
|
+
id: "smtp",
|
|
30
|
+
transport,
|
|
31
|
+
external: { host: options.host, provider: "smtp", kind: "infrastructure" },
|
|
32
|
+
};
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
/** SMTP driver factory. */
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { SndrTransport } from "sently/transports/sndr";
|
|
6
6
|
import type { ChannelDriver, ChannelOpenOptions } from "./channel-types.ts";
|
|
7
|
+
import { hostFromUrl } from "./external.ts";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Open an SNDR channel driver.
|
|
@@ -18,7 +19,15 @@ export function openSndrChannel(options: ChannelOpenOptions = {}): ChannelDriver
|
|
|
18
19
|
apiKey: options.apiKey,
|
|
19
20
|
...(options.url ? { baseUrl: options.url } : {}),
|
|
20
21
|
});
|
|
21
|
-
return {
|
|
22
|
+
return {
|
|
23
|
+
id: "sndr",
|
|
24
|
+
transport,
|
|
25
|
+
external: {
|
|
26
|
+
host: (options.url ? hostFromUrl(options.url) : undefined) ?? "api.sndr.email",
|
|
27
|
+
provider: "sndr",
|
|
28
|
+
kind: "third-party",
|
|
29
|
+
},
|
|
30
|
+
};
|
|
22
31
|
}
|
|
23
32
|
|
|
24
33
|
/** SNDR driver factory. */
|
|
@@ -24,7 +24,11 @@ export function openTaqnyatMailChannel(options: ChannelOpenOptions = {}): Channe
|
|
|
24
24
|
throw new Error("taqnyat-mail channel: campaignName is required");
|
|
25
25
|
}
|
|
26
26
|
const transport = new TaqnyatMailTransport({ bearerToken, campaignName });
|
|
27
|
-
return {
|
|
27
|
+
return {
|
|
28
|
+
id: "taqnyat-mail",
|
|
29
|
+
transport,
|
|
30
|
+
external: { host: "api.taqnyat.sa", provider: "taqnyat-mail", kind: "third-party" },
|
|
31
|
+
};
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
/** Taqnyat Email driver factory. */
|
|
@@ -84,7 +84,12 @@ export function openTaqnyatWhatsAppChannel(options: ChannelOpenOptions = {}): Ch
|
|
|
84
84
|
verify: () => transport.verify(),
|
|
85
85
|
};
|
|
86
86
|
|
|
87
|
-
return {
|
|
87
|
+
return {
|
|
88
|
+
id: "taqnyat-whatsapp",
|
|
89
|
+
channel,
|
|
90
|
+
whatsappTransport: transport,
|
|
91
|
+
external: { host: "api.taqnyat.sa", provider: "taqnyat-whatsapp", kind: "third-party" },
|
|
92
|
+
};
|
|
88
93
|
}
|
|
89
94
|
|
|
90
95
|
/** Taqnyat WhatsApp driver factory. */
|
|
@@ -47,7 +47,12 @@ export function openTaqnyatChannel(options: ChannelOpenOptions = {}): ChannelDri
|
|
|
47
47
|
verify: () => transport.verify(),
|
|
48
48
|
};
|
|
49
49
|
|
|
50
|
-
return {
|
|
50
|
+
return {
|
|
51
|
+
id: "taqnyat",
|
|
52
|
+
channel,
|
|
53
|
+
smsTransport: transport,
|
|
54
|
+
external: { host: "api.taqnyat.sa", provider: "taqnyat", kind: "third-party" },
|
|
55
|
+
};
|
|
51
56
|
}
|
|
52
57
|
|
|
53
58
|
/** Taqnyat driver factory. */
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { MailOptions, SendResult, Transport, VerifyResult } from "sently";
|
|
10
|
+
import type { DriverExternal } from "./external.ts";
|
|
10
11
|
|
|
11
12
|
export type {
|
|
12
13
|
Address,
|
|
@@ -185,6 +186,8 @@ export interface ChannelAttempt {
|
|
|
185
186
|
readonly error?: string;
|
|
186
187
|
readonly at: number;
|
|
187
188
|
readonly messageId?: string;
|
|
189
|
+
/** Egress identity for this attempt when the call left the process. */
|
|
190
|
+
readonly external?: DriverExternal;
|
|
188
191
|
}
|
|
189
192
|
|
|
190
193
|
/** Result of a channel send including chain history. */
|
|
@@ -195,6 +198,8 @@ export interface ChannelSendResult {
|
|
|
195
198
|
readonly attempts: readonly ChannelAttempt[];
|
|
196
199
|
/** Present when an email transport returned a sently {@link SendResult}. */
|
|
197
200
|
readonly mail?: SendResult;
|
|
201
|
+
/** Egress identity for the winning (or last) attempt. */
|
|
202
|
+
readonly external?: DriverExternal;
|
|
198
203
|
}
|
|
199
204
|
|
|
200
205
|
/** Medium-agnostic transport (sms / whatsapp / push / console). */
|
|
@@ -223,6 +228,11 @@ export interface ChannelDriver {
|
|
|
223
228
|
readonly pushTransport?: PushTransport;
|
|
224
229
|
/** Medium-agnostic transport. */
|
|
225
230
|
readonly channel?: ChannelTransport;
|
|
231
|
+
/**
|
|
232
|
+
* Driver-reported egress identity for sends through this binding.
|
|
233
|
+
* Omitted for in-process console / local sinks.
|
|
234
|
+
*/
|
|
235
|
+
readonly external?: DriverExternal;
|
|
226
236
|
}
|
|
227
237
|
|
|
228
238
|
/** Open options shared by channel drivers. */
|
|
@@ -48,7 +48,12 @@ export function openUnifonicChannel(options: ChannelOpenOptions = {}): ChannelDr
|
|
|
48
48
|
verify: () => transport.verify(),
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
-
return {
|
|
51
|
+
return {
|
|
52
|
+
id: "unifonic",
|
|
53
|
+
channel,
|
|
54
|
+
smsTransport: transport,
|
|
55
|
+
external: { host: "el.cloud.unifonic.com", provider: "unifonic", kind: "third-party" },
|
|
56
|
+
};
|
|
52
57
|
}
|
|
53
58
|
|
|
54
59
|
/** Unifonic driver factory. */
|
|
@@ -56,7 +56,12 @@ export function openWaCloudChannel(options: ChannelOpenOptions = {}): ChannelDri
|
|
|
56
56
|
verify: () => transport.verify(),
|
|
57
57
|
};
|
|
58
58
|
|
|
59
|
-
return {
|
|
59
|
+
return {
|
|
60
|
+
id: "wa-cloud",
|
|
61
|
+
channel,
|
|
62
|
+
whatsappTransport: transport,
|
|
63
|
+
external: { host: "graph.facebook.com", provider: "wa-cloud", kind: "third-party" },
|
|
64
|
+
};
|
|
60
65
|
}
|
|
61
66
|
|
|
62
67
|
/** WhatsApp Cloud driver factory. */
|
|
@@ -68,7 +68,12 @@ export function openWebPushChannel(options: ChannelOpenOptions = {}): ChannelDri
|
|
|
68
68
|
close: () => sender.close(),
|
|
69
69
|
};
|
|
70
70
|
|
|
71
|
-
return {
|
|
71
|
+
return {
|
|
72
|
+
id: "webpush",
|
|
73
|
+
channel,
|
|
74
|
+
pushTransport: transport,
|
|
75
|
+
external: { host: "webpush", provider: "webpush", kind: "third-party" },
|
|
76
|
+
};
|
|
72
77
|
}
|
|
73
78
|
|
|
74
79
|
/** Web Push driver factory. */
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared egress identity for driver call results and {@link EffectEntry.external}.
|
|
3
|
+
*
|
|
4
|
+
* Drivers report this on real call results — never inferred by hostname regex
|
|
5
|
+
* at the ledger layer. Only `host` is required when present.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** Egress peer for an effect that left the process. */
|
|
9
|
+
export interface DriverExternal {
|
|
10
|
+
/** Peer hostname (or equivalent) the call reached. */
|
|
11
|
+
readonly host: string;
|
|
12
|
+
/** Vendor / transport / registry label when known. */
|
|
13
|
+
readonly provider?: string;
|
|
14
|
+
/**
|
|
15
|
+
* `"third-party"` — vendor business API.
|
|
16
|
+
* `"infrastructure"` — developer-owned egress.
|
|
17
|
+
*/
|
|
18
|
+
readonly kind?: "third-party" | "infrastructure";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Hostname from an absolute URL or base URL string.
|
|
23
|
+
*
|
|
24
|
+
* @param url - Absolute URL
|
|
25
|
+
*/
|
|
26
|
+
export function hostFromUrl(url: string): string | undefined {
|
|
27
|
+
try {
|
|
28
|
+
const host = new URL(url).hostname;
|
|
29
|
+
return host || undefined;
|
|
30
|
+
} catch {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
package/src/drivers/index.ts
CHANGED
|
@@ -245,13 +245,3 @@ export {
|
|
|
245
245
|
isOpenaiCloudBase,
|
|
246
246
|
openaiCompatibleHeaders,
|
|
247
247
|
} from "./ai-openai-compatible.ts";
|
|
248
|
-
export {
|
|
249
|
-
ollamaAiDriver,
|
|
250
|
-
openOllama,
|
|
251
|
-
OllamaUnavailableError,
|
|
252
|
-
OLLAMA_DEFAULT_MODEL,
|
|
253
|
-
OLLAMA_DEFAULT_BASE_URL,
|
|
254
|
-
normalizeOllamaBaseUrl,
|
|
255
|
-
resolveOllamaBaseUrl,
|
|
256
|
-
resolveOllamaModel,
|
|
257
|
-
} from "./ai-ollama.ts";
|
|
@@ -21,6 +21,7 @@ import type {
|
|
|
21
21
|
TextIndexSearchResult,
|
|
22
22
|
TextIndexStore,
|
|
23
23
|
} from "./types.ts";
|
|
24
|
+
import { hostFromUrl } from "./external.ts";
|
|
24
25
|
|
|
25
26
|
/** Error thrown when the remote Meilisearch is unreachable / unhealthy / errors. */
|
|
26
27
|
export class MeilisearchUnavailableError extends Error {
|
|
@@ -195,6 +196,11 @@ export async function openMeilisearchIndex(
|
|
|
195
196
|
|
|
196
197
|
return {
|
|
197
198
|
driverId: "meilisearch",
|
|
199
|
+
external: {
|
|
200
|
+
host: hostFromUrl(url) ?? "meilisearch",
|
|
201
|
+
provider: "meilisearch",
|
|
202
|
+
kind: "infrastructure",
|
|
203
|
+
},
|
|
198
204
|
async upsert(id, document) {
|
|
199
205
|
const body = [{ ...document, id }];
|
|
200
206
|
const task = await enqueue(`/indexes/${uid}/documents`, {
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
* grants are never implemented.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
+
import type { DriverExternal } from "./external.ts";
|
|
15
|
+
|
|
14
16
|
/** Supported social providers. */
|
|
15
17
|
export type OAuthDriverId =
|
|
16
18
|
| "apple"
|
|
@@ -80,6 +82,8 @@ export interface OAuthExchangeInput {
|
|
|
80
82
|
/** Result of {@link OAuthDriver.exchangeCode}. */
|
|
81
83
|
export interface OAuthExchangeResult {
|
|
82
84
|
readonly tokens: OAuthTokenSet;
|
|
85
|
+
/** Egress identity for the token endpoint call. */
|
|
86
|
+
readonly external?: DriverExternal;
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
/** Input to {@link OAuthDriver.resolveAssertion}. */
|