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
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* EffectKind presentation for the trace detail Sheet.
|
|
3
3
|
*
|
|
4
4
|
* Kernel {@link EffectKind} values (singular): read · write · emit · send ·
|
|
5
|
-
* ask · secret · call. Graph edge strokes use the plural Manifest keys
|
|
6
|
-
* (reads/writes/emits/calls/asks) — map through {@link effectBarColor}.
|
|
5
|
+
* ask · embed · secret · call. Graph edge strokes use the plural Manifest keys
|
|
6
|
+
* (reads/writes/emits/calls/asks/embeds) — map through {@link effectBarColor}.
|
|
7
7
|
* Icons reuse the same eight-element HugeIcons vocabulary as Flow graph
|
|
8
8
|
* nodes (store / signal / flow / ai / channel / vault).
|
|
9
9
|
*/
|
|
@@ -23,8 +23,10 @@ export const EFFECT_KIND_LABEL: Readonly<Record<RunEffectKind, string>> = {
|
|
|
23
23
|
emit: "Emit",
|
|
24
24
|
send: "Send",
|
|
25
25
|
ask: "Ask",
|
|
26
|
+
embed: "Embed",
|
|
26
27
|
secret: "Secret",
|
|
27
28
|
call: "Call",
|
|
29
|
+
fetch: "Fetch",
|
|
28
30
|
};
|
|
29
31
|
|
|
30
32
|
/**
|
|
@@ -40,8 +42,10 @@ export function effectKindSummaryLabel(kind: RunEffectKind, count: number): stri
|
|
|
40
42
|
emit: "emit",
|
|
41
43
|
send: "send",
|
|
42
44
|
ask: "ask",
|
|
45
|
+
embed: "embed",
|
|
43
46
|
secret: "secret",
|
|
44
47
|
call: "call",
|
|
48
|
+
fetch: "fetch",
|
|
45
49
|
};
|
|
46
50
|
const plural: Record<RunEffectKind, string> = {
|
|
47
51
|
read: "reads",
|
|
@@ -49,8 +53,10 @@ export function effectKindSummaryLabel(kind: RunEffectKind, count: number): stri
|
|
|
49
53
|
emit: "emits",
|
|
50
54
|
send: "sends",
|
|
51
55
|
ask: "asks",
|
|
56
|
+
embed: "embeds",
|
|
52
57
|
secret: "secrets",
|
|
53
58
|
call: "calls",
|
|
59
|
+
fetch: "fetches",
|
|
54
60
|
};
|
|
55
61
|
return `${count} ${count === 1 ? singular[kind] : plural[kind]}`;
|
|
56
62
|
}
|
|
@@ -73,8 +79,10 @@ export function effectBarColor(kind: RunEffectKind): string {
|
|
|
73
79
|
case "call":
|
|
74
80
|
return EDGE_STROKE.calls;
|
|
75
81
|
case "ask":
|
|
82
|
+
case "embed":
|
|
76
83
|
return EDGE_STROKE.asks;
|
|
77
84
|
case "send":
|
|
85
|
+
case "fetch":
|
|
78
86
|
return EDGE_STROKE.sends;
|
|
79
87
|
case "secret":
|
|
80
88
|
return EDGE_STROKE.secrets;
|
|
@@ -99,8 +107,10 @@ export function effectKindIcon(kind: RunEffectKind, resource?: string): ElementH
|
|
|
99
107
|
case "call":
|
|
100
108
|
return ELEMENT_ICONS.flow.icon;
|
|
101
109
|
case "ask":
|
|
110
|
+
case "embed":
|
|
102
111
|
return ELEMENT_ICONS.ai.icon;
|
|
103
112
|
case "send":
|
|
113
|
+
case "fetch":
|
|
104
114
|
return ELEMENT_ICONS.channel.icon;
|
|
105
115
|
case "secret":
|
|
106
116
|
return ELEMENT_ICONS.vault.icon;
|
|
@@ -43,7 +43,9 @@ const KIND_ORDER: readonly RunEffectKind[] = [
|
|
|
43
43
|
"emit",
|
|
44
44
|
"call",
|
|
45
45
|
"ask",
|
|
46
|
+
"embed",
|
|
46
47
|
"send",
|
|
48
|
+
"fetch",
|
|
47
49
|
"secret",
|
|
48
50
|
];
|
|
49
51
|
|
|
@@ -201,8 +203,10 @@ export function effectEventLabel(effect: Pick<RunEffect, "kind" | "resource">):
|
|
|
201
203
|
emit: "Emit",
|
|
202
204
|
send: "Send",
|
|
203
205
|
ask: "Ask",
|
|
206
|
+
embed: "Embed",
|
|
204
207
|
secret: "Secret",
|
|
205
208
|
call: "Call",
|
|
209
|
+
fetch: "Fetch",
|
|
206
210
|
};
|
|
207
211
|
return labels[effect.kind];
|
|
208
212
|
}
|
|
@@ -484,6 +484,7 @@ export function TraceDetailSheet({
|
|
|
484
484
|
data-slot="trace-event-row"
|
|
485
485
|
data-index={index}
|
|
486
486
|
data-focused={focused ? "true" : "false"}
|
|
487
|
+
data-external={effect.external ? "true" : undefined}
|
|
487
488
|
className={cn(
|
|
488
489
|
EXPLORER_ROW_CLASS,
|
|
489
490
|
"cursor-pointer flex-col items-stretch gap-1 text-[11px]",
|
|
@@ -510,6 +511,9 @@ export function TraceDetailSheet({
|
|
|
510
511
|
</span>
|
|
511
512
|
<span className="min-w-0 flex-1 truncate font-mono text-muted-foreground">
|
|
512
513
|
{effect.resource}
|
|
514
|
+
{effect.external
|
|
515
|
+
? ` · ↗ ${effect.external.host}${effect.external.kind ? ` (${effect.external.kind})` : ""}`
|
|
516
|
+
: ""}
|
|
513
517
|
</span>
|
|
514
518
|
<span className="shrink-0 tabular-nums text-muted-foreground">
|
|
515
519
|
{formatDuration(effect.duration)}
|
|
@@ -815,6 +819,7 @@ function OverviewTrack({
|
|
|
815
819
|
"absolute inset-y-0.5 cursor-pointer rounded-full transition-opacity",
|
|
816
820
|
hoverIndex !== null && hoverIndex !== bar.index && !focused && "opacity-35",
|
|
817
821
|
focused && "ring-1 ring-foreground/40",
|
|
822
|
+
bar.external && "outline outline-1 outline-dashed outline-foreground/50",
|
|
818
823
|
)}
|
|
819
824
|
style={{
|
|
820
825
|
left: `${mapped.left * 100}%`,
|
|
@@ -822,6 +827,7 @@ function OverviewTrack({
|
|
|
822
827
|
backgroundColor: effectBarColor(bar.kind),
|
|
823
828
|
}}
|
|
824
829
|
data-slot="trace-waterfall-overview-bar"
|
|
830
|
+
data-external={bar.external ? "true" : undefined}
|
|
825
831
|
onClick={(event) => {
|
|
826
832
|
event.stopPropagation();
|
|
827
833
|
onSelect?.(bar.index);
|
|
@@ -995,6 +1001,7 @@ function PlaybackBarFill({
|
|
|
995
1001
|
"absolute inset-y-0 rounded-full transition-opacity",
|
|
996
1002
|
!animated && dimmed && !focused && "opacity-35",
|
|
997
1003
|
focused && "ring-1 ring-foreground/40",
|
|
1004
|
+
bar.external && "outline outline-1 outline-dashed outline-foreground/50",
|
|
998
1005
|
)}
|
|
999
1006
|
style={{
|
|
1000
1007
|
left: `${left * 100}%`,
|
|
@@ -1004,6 +1011,7 @@ function PlaybackBarFill({
|
|
|
1004
1011
|
...(animated ? { scaleX, opacity } : {}),
|
|
1005
1012
|
}}
|
|
1006
1013
|
data-slot={slot}
|
|
1014
|
+
data-external={bar.external ? "true" : undefined}
|
|
1007
1015
|
/>
|
|
1008
1016
|
);
|
|
1009
1017
|
}
|
|
@@ -30,6 +30,8 @@ export type WaterfallBar = {
|
|
|
30
30
|
* `offsetRatio + widthRatio === 1`.
|
|
31
31
|
*/
|
|
32
32
|
readonly widthRatio: number;
|
|
33
|
+
/** Egress identity when the effect left the process. */
|
|
34
|
+
readonly external?: RunEffect["external"];
|
|
33
35
|
};
|
|
34
36
|
|
|
35
37
|
/**
|
|
@@ -58,6 +60,7 @@ export function waterfallBars(
|
|
|
58
60
|
durationMs: 0,
|
|
59
61
|
offsetRatio: 0,
|
|
60
62
|
widthRatio: 0,
|
|
63
|
+
...(effect.external !== undefined ? { external: effect.external } : {}),
|
|
61
64
|
}));
|
|
62
65
|
}
|
|
63
66
|
|
|
@@ -75,6 +78,7 @@ export function waterfallBars(
|
|
|
75
78
|
durationMs: clampedDuration,
|
|
76
79
|
offsetRatio: startOffsetMs / durationMs,
|
|
77
80
|
widthRatio: clampedDuration / durationMs,
|
|
81
|
+
...(effect.external !== undefined ? { external: effect.external } : {}),
|
|
78
82
|
};
|
|
79
83
|
});
|
|
80
84
|
}
|
|
@@ -9,12 +9,18 @@ import type { WaterfallBar } from "./waterfall-bars.ts";
|
|
|
9
9
|
/**
|
|
10
10
|
* Build the shadcn Tooltip content for one waterfall bar.
|
|
11
11
|
*
|
|
12
|
-
* Format: `{kind label} · {resource} · {duration} · +{start offset}
|
|
12
|
+
* Format: `{kind label} · {resource} · {duration} · +{start offset}`
|
|
13
|
+
* plus optional egress (`host` / provider / kind) when `external` is set.
|
|
13
14
|
*
|
|
14
15
|
* @param bar - Positioned bar (layout + effect identity)
|
|
15
16
|
*/
|
|
16
17
|
export function waterfallBarTooltip(
|
|
17
|
-
bar: Pick<WaterfallBar, "kind" | "resource" | "durationMs" | "startOffsetMs">,
|
|
18
|
+
bar: Pick<WaterfallBar, "kind" | "resource" | "durationMs" | "startOffsetMs" | "external">,
|
|
18
19
|
): string {
|
|
19
|
-
|
|
20
|
+
const base = `${effectEventLabel(bar)} · ${bar.resource} · ${formatDuration(bar.durationMs)} · +${formatDuration(bar.startOffsetMs)}`;
|
|
21
|
+
if (!bar.external) return base;
|
|
22
|
+
const parts = [bar.external.host];
|
|
23
|
+
if (bar.external.provider) parts.push(bar.external.provider);
|
|
24
|
+
if (bar.external.kind) parts.push(bar.external.kind);
|
|
25
|
+
return `${base} · ↗ ${parts.join(" · ")}`;
|
|
20
26
|
}
|
|
@@ -7,6 +7,7 @@ import { ViewIcon, ViewOffSlashIcon } from "@hugeicons/core-free-icons";
|
|
|
7
7
|
import { HugeiconsIcon } from "@hugeicons/react";
|
|
8
8
|
import { Button } from "@/components/ui/button";
|
|
9
9
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
|
10
|
+
import { formatTemporalCell, formatGridCell } from "../lib/grid-model.ts";
|
|
10
11
|
import { useStoreReveal } from "../data/use-store-reveal.ts";
|
|
11
12
|
|
|
12
13
|
/** Props for {@link RevealCell}. */
|
|
@@ -38,7 +39,9 @@ export function RevealCell({
|
|
|
38
39
|
if (clear !== null) {
|
|
39
40
|
return (
|
|
40
41
|
<span className="inline-flex max-w-full items-center gap-1" data-slot="reveal-cell">
|
|
41
|
-
<span className="min-w-0 truncate font-mono text-[11px]">
|
|
42
|
+
<span className="min-w-0 truncate font-mono text-[11px]">
|
|
43
|
+
{formatRevealCell(column, clear.value)}
|
|
44
|
+
</span>
|
|
42
45
|
<Tooltip>
|
|
43
46
|
<TooltipTrigger
|
|
44
47
|
render={(props) => (
|
|
@@ -120,18 +123,11 @@ export function RevealCell({
|
|
|
120
123
|
{reveal.error.message}
|
|
121
124
|
</span>
|
|
122
125
|
) : null}
|
|
123
|
-
<span className="sr-only">{
|
|
126
|
+
<span className="sr-only">{formatRevealCell(column, maskedValue)}</span>
|
|
124
127
|
</span>
|
|
125
128
|
);
|
|
126
129
|
}
|
|
127
130
|
|
|
128
|
-
function
|
|
129
|
-
|
|
130
|
-
if (typeof value === "string") return value;
|
|
131
|
-
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
132
|
-
try {
|
|
133
|
-
return JSON.stringify(value);
|
|
134
|
-
} catch {
|
|
135
|
-
return "[unserializable]";
|
|
136
|
-
}
|
|
131
|
+
function formatRevealCell(column: string, value: unknown): string {
|
|
132
|
+
return formatTemporalCell(column, value) ?? formatGridCell(value);
|
|
137
133
|
}
|
|
@@ -25,7 +25,7 @@ import { cn } from "@/lib/utils";
|
|
|
25
25
|
import { useStoreEdit } from "../data/use-store-edit.ts";
|
|
26
26
|
import { RevealCell } from "./reveal-cell.tsx";
|
|
27
27
|
import {
|
|
28
|
-
|
|
28
|
+
formatStoreCell,
|
|
29
29
|
type StoreGridColumn,
|
|
30
30
|
type StoreGridModel,
|
|
31
31
|
type StoreGridRow,
|
|
@@ -236,7 +236,7 @@ export function StoreRowDetailSheet({
|
|
|
236
236
|
className="min-w-0 flex-1 font-mono text-[11px] break-words"
|
|
237
237
|
dir={isRtlText(value) ? "rtl" : "ltr"}
|
|
238
238
|
>
|
|
239
|
-
{
|
|
239
|
+
{formatStoreCell(col, value)}
|
|
240
240
|
</span>
|
|
241
241
|
)}
|
|
242
242
|
</li>
|
|
@@ -66,6 +66,8 @@ function fieldFromColumn(
|
|
|
66
66
|
...(description !== undefined ? { description } : {}),
|
|
67
67
|
...(col.pii === true ? { pii: true } : {}),
|
|
68
68
|
...(col.sensitive === true ? { sensitive: true } : {}),
|
|
69
|
+
...(declared?.searchable ? { searchable: true, searchWeight: declared.searchable.weight } : {}),
|
|
70
|
+
...(declared?.embed ? { embed: true, embedDims: declared.embed.dims } : {}),
|
|
69
71
|
...(declared?.primaryKey === true ? { primaryKey: true } : {}),
|
|
70
72
|
...(declared?.unique === true && declared.primaryKey !== true ? { unique: true } : {}),
|
|
71
73
|
...(declared?.references?.table
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
buildStoreGridModel,
|
|
4
|
+
formatStoreCell,
|
|
5
|
+
formatTemporalCell,
|
|
6
|
+
isTemporalColumnKey,
|
|
7
|
+
sqlRowId,
|
|
8
|
+
} from "./grid-model.ts";
|
|
3
9
|
|
|
4
10
|
describe("buildStoreGridModel", () => {
|
|
5
11
|
test("sql rows map to editable typed columns with pii flags", () => {
|
|
@@ -125,3 +131,21 @@ describe("sqlRowId", () => {
|
|
|
125
131
|
expect(sqlRowId({})).toBe("");
|
|
126
132
|
});
|
|
127
133
|
});
|
|
134
|
+
|
|
135
|
+
describe("formatTemporalCell / formatStoreCell", () => {
|
|
136
|
+
test("formats epoch-ms *_at columns as ISO", () => {
|
|
137
|
+
expect(isTemporalColumnKey("created_at")).toBe(true);
|
|
138
|
+
expect(isTemporalColumnKey("createdAt")).toBe(true);
|
|
139
|
+
expect(isTemporalColumnKey("seats")).toBe(false);
|
|
140
|
+
expect(formatTemporalCell("created_at", 1_723_622_400_000)).toBe("2024-08-14T08:00:00.000Z");
|
|
141
|
+
expect(
|
|
142
|
+
formatStoreCell(
|
|
143
|
+
{ key: "created_at", type: "integer", editable: false, pii: false },
|
|
144
|
+
1_723_622_400_000,
|
|
145
|
+
),
|
|
146
|
+
).toBe("2024-08-14T08:00:00.000Z");
|
|
147
|
+
expect(formatStoreCell({ key: "seats", type: "integer", editable: true, pii: false }, 2)).toBe(
|
|
148
|
+
"2",
|
|
149
|
+
);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
@@ -197,6 +197,7 @@ export function sqlRowId(row: Readonly<Record<string, unknown>>): string {
|
|
|
197
197
|
/** Format a cell value for display. */
|
|
198
198
|
export function formatGridCell(value: unknown): string {
|
|
199
199
|
if (value === null || value === undefined) return "—";
|
|
200
|
+
if (value instanceof Date) return value.toISOString();
|
|
200
201
|
if (typeof value === "string") return value;
|
|
201
202
|
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
202
203
|
try {
|
|
@@ -207,7 +208,39 @@ export function formatGridCell(value: unknown): string {
|
|
|
207
208
|
}
|
|
208
209
|
|
|
209
210
|
/**
|
|
210
|
-
*
|
|
211
|
+
* True when a SQL column name looks like an instant (`created_at`, `expiresAt`, …).
|
|
212
|
+
*
|
|
213
|
+
* @param key - Column key (camelCase or snake_case)
|
|
214
|
+
*/
|
|
215
|
+
export function isTemporalColumnKey(key: string): boolean {
|
|
216
|
+
return /(?:^|_)(at|time|timestamp)$/i.test(key) || /(?:At|Time|Timestamp)$/.test(key);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Format epoch-ms / `Date` / ISO for a temporal column. Returns `null` when the
|
|
221
|
+
* value should keep the default grid formatter (non-temporal or non-instant).
|
|
222
|
+
*
|
|
223
|
+
* @param key - Column key
|
|
224
|
+
* @param value - Raw cell
|
|
225
|
+
*/
|
|
226
|
+
export function formatTemporalCell(key: string, value: unknown): string | null {
|
|
227
|
+
if (value === null || value === undefined) return null;
|
|
228
|
+
if (value instanceof Date) return value.toISOString();
|
|
229
|
+
if (typeof value === "string") {
|
|
230
|
+
if (!isTemporalColumnKey(key)) return null;
|
|
231
|
+
const ms = Date.parse(value);
|
|
232
|
+
return Number.isNaN(ms) ? null : new Date(ms).toISOString();
|
|
233
|
+
}
|
|
234
|
+
if (typeof value === "number" && Number.isFinite(value) && isTemporalColumnKey(key)) {
|
|
235
|
+
// Auth / clock system tables store epoch-ms; reject tiny integers (counts).
|
|
236
|
+
if (value < 1_000_000_000_000 || value > 10_000_000_000_000) return null;
|
|
237
|
+
return new Date(value).toISOString();
|
|
238
|
+
}
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Format a cell using the column's display hint (TTL / bytes / temporal) when set.
|
|
211
244
|
*
|
|
212
245
|
* @param col - Column descriptor
|
|
213
246
|
* @param value - Raw cell
|
|
@@ -215,5 +248,7 @@ export function formatGridCell(value: unknown): string {
|
|
|
215
248
|
export function formatStoreCell(col: StoreGridColumn, value: unknown): string {
|
|
216
249
|
if (col.format === "ttl") return formatKvTtl(value);
|
|
217
250
|
if (col.format === "bytes") return formatByteSize(value);
|
|
251
|
+
const temporal = formatTemporalCell(col.key, value);
|
|
252
|
+
if (temporal !== null) return temporal;
|
|
218
253
|
return formatGridCell(value);
|
|
219
254
|
}
|
|
@@ -36,7 +36,7 @@ import { cn } from "@/lib/utils.ts";
|
|
|
36
36
|
import { JsonValueSheet } from "../detail/json-value-sheet.tsx";
|
|
37
37
|
import { ToolbarTip } from "@/components/ui/toolbar-tip.tsx";
|
|
38
38
|
import { cellExportText, rowsToCsv } from "../lib/grid-transfer.ts";
|
|
39
|
-
import { formatGridCell } from "../lib/grid-model.ts";
|
|
39
|
+
import { formatGridCell, formatTemporalCell } from "../lib/grid-model.ts";
|
|
40
40
|
import { asInspectableJson } from "../lib/json-value.ts";
|
|
41
41
|
import type { QueryHighlightLanguage } from "../lib/query-highlight.ts";
|
|
42
42
|
import { QueryHighlightView } from "./query-highlight-view.tsx";
|
|
@@ -310,10 +310,10 @@ export function QueryResults({
|
|
|
310
310
|
setInspect({ rowId: String(i), column: col, value })
|
|
311
311
|
}
|
|
312
312
|
>
|
|
313
|
-
{formatGridCell(value)}
|
|
313
|
+
{formatTemporalCell(col, value) ?? formatGridCell(value)}
|
|
314
314
|
</button>
|
|
315
315
|
) : (
|
|
316
|
-
formatGridCell(value)
|
|
316
|
+
(formatTemporalCell(col, value) ?? formatGridCell(value))
|
|
317
317
|
)}
|
|
318
318
|
</td>
|
|
319
319
|
);
|
|
@@ -82,7 +82,9 @@ function flattenEffects(effects: Effects | undefined): EffectChip[] {
|
|
|
82
82
|
push("emit", effects.emits);
|
|
83
83
|
push("send", effects.sends);
|
|
84
84
|
push("ask", effects.asks);
|
|
85
|
+
push("embed", effects.embeds);
|
|
85
86
|
push("secret", effects.secrets);
|
|
86
87
|
push("call", effects.calls);
|
|
88
|
+
push("fetch", effects.fetches);
|
|
87
89
|
return out;
|
|
88
90
|
}
|
|
@@ -16,7 +16,9 @@ export function isReadSafeCall(row: UnitFlowRow): boolean {
|
|
|
16
16
|
(effects.writes?.length ?? 0) === 0 &&
|
|
17
17
|
(effects.emits?.length ?? 0) === 0 &&
|
|
18
18
|
(effects.sends?.length ?? 0) === 0 &&
|
|
19
|
-
(effects.asks?.length ?? 0) === 0
|
|
19
|
+
(effects.asks?.length ?? 0) === 0 &&
|
|
20
|
+
(effects.embeds?.length ?? 0) === 0 &&
|
|
21
|
+
(effects.fetches?.length ?? 0) === 0
|
|
20
22
|
);
|
|
21
23
|
}
|
|
22
24
|
|
|
@@ -25,6 +25,12 @@ export interface FormField {
|
|
|
25
25
|
readonly pii?: boolean;
|
|
26
26
|
/** When true, column is sensitive-classified (Store schema pills). */
|
|
27
27
|
readonly sensitive?: boolean;
|
|
28
|
+
/** Built-in hybrid search — BM25 via `.searchable()`. */
|
|
29
|
+
readonly searchable?: boolean;
|
|
30
|
+
readonly searchWeight?: number;
|
|
31
|
+
/** Async LSH embed via `.embed()`. */
|
|
32
|
+
readonly embed?: boolean;
|
|
33
|
+
readonly embedDims?: number;
|
|
28
34
|
/** When true, column is a primary key (Store schema pills). */
|
|
29
35
|
readonly primaryKey?: boolean;
|
|
30
36
|
/** When true, column is a foreign key (declared or inferred). */
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
normalizeAiProbeUrl,
|
|
6
6
|
probeAiModelStatus,
|
|
7
7
|
startAiModelWatch,
|
|
8
|
-
statusFromOllamaTags,
|
|
9
8
|
statusFromOpenAiModels,
|
|
10
9
|
} from "./ai-model-status.ts";
|
|
11
10
|
|
|
@@ -17,12 +16,9 @@ describe("ai-model-status", () => {
|
|
|
17
16
|
expect(normalizeAiProbeUrl("http://127.0.0.1:8080/v1/", "openai-compatible")).toBe(
|
|
18
17
|
"http://127.0.0.1:8080/v1",
|
|
19
18
|
);
|
|
20
|
-
expect(normalizeAiProbeUrl("http://127.0.0.1:11434/v1", "ollama")).toBe(
|
|
21
|
-
"http://127.0.0.1:11434",
|
|
22
|
-
);
|
|
23
19
|
});
|
|
24
20
|
|
|
25
|
-
test("aiModelIdsMatch tolerates
|
|
21
|
+
test("aiModelIdsMatch tolerates quant aliasing", () => {
|
|
26
22
|
expect(aiModelIdsMatch("gemma4:e4b-q4_K_M", "gemma4:Q4_K_M")).toBe(true);
|
|
27
23
|
expect(aiModelIdsMatch("smollm2", "smollm2")).toBe(true);
|
|
28
24
|
expect(aiModelIdsMatch("gemma4:e4b-q4_K_M", "qwen3:8b")).toBe(false);
|
|
@@ -45,13 +41,6 @@ describe("ai-model-status", () => {
|
|
|
45
41
|
expect(statusFromOpenAiModels("smollm2", { data: [] }).phase).toBe("starting");
|
|
46
42
|
});
|
|
47
43
|
|
|
48
|
-
test("statusFromOllamaTags ready when present", () => {
|
|
49
|
-
expect(statusFromOllamaTags("qwen3.5:9b", { models: [{ name: "qwen3.5:9b" }] }).phase).toBe(
|
|
50
|
-
"ready",
|
|
51
|
-
);
|
|
52
|
-
expect(statusFromOllamaTags("qwen3.5:9b", { models: [] }).phase).toBe("loading");
|
|
53
|
-
});
|
|
54
|
-
|
|
55
44
|
test("probeAiModelStatus uses injectable fetch", async () => {
|
|
56
45
|
const status = await probeAiModelStatus({
|
|
57
46
|
url: "http://127.0.0.1:9/v1",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Probe
|
|
3
|
-
*
|
|
2
|
+
* Probe OpenAI-compatible AI servers for configured-model readiness
|
|
3
|
+
* (BYO `OKE_AI_URL`). Used by `oke dev` to show model id + phase without
|
|
4
4
|
* blocking boot.
|
|
5
5
|
*/
|
|
6
6
|
|
|
@@ -19,14 +19,14 @@ export type AiModelStatus = {
|
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
/** Which HTTP surface to probe. */
|
|
22
|
-
export type AiModelProbeKind = "openai-compatible"
|
|
22
|
+
export type AiModelProbeKind = "openai-compatible";
|
|
23
23
|
|
|
24
24
|
/** Fetch contract (injectable for tests). */
|
|
25
25
|
export type AiModelFetch = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
26
26
|
|
|
27
27
|
/** Options for {@link probeAiModelStatus}. */
|
|
28
28
|
export type ProbeAiModelStatusOptions = {
|
|
29
|
-
/** Base URL — with or without trailing `/v1
|
|
29
|
+
/** Base URL — with or without trailing `/v1`. */
|
|
30
30
|
readonly url: string;
|
|
31
31
|
readonly model: string;
|
|
32
32
|
readonly kind: AiModelProbeKind;
|
|
@@ -34,17 +34,15 @@ export type ProbeAiModelStatusOptions = {
|
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
* Strip trailing slashes;
|
|
37
|
+
* Strip trailing slashes; keep a single `/v1` suffix for OpenAI-compatible.
|
|
38
38
|
*
|
|
39
39
|
* @param url - Raw base URL
|
|
40
40
|
* @param kind - Probe kind
|
|
41
41
|
*/
|
|
42
42
|
export function normalizeAiProbeUrl(url: string, kind: AiModelProbeKind): string {
|
|
43
43
|
let base = url.trim().replace(/\/+$/, "");
|
|
44
|
-
if (kind === "openai-compatible") {
|
|
45
|
-
|
|
46
|
-
} else if (base.endsWith("/v1")) {
|
|
47
|
-
base = base.slice(0, -3);
|
|
44
|
+
if (kind === "openai-compatible" && !base.endsWith("/v1")) {
|
|
45
|
+
base = `${base}/v1`;
|
|
48
46
|
}
|
|
49
47
|
return base;
|
|
50
48
|
}
|
|
@@ -52,7 +50,7 @@ export function normalizeAiProbeUrl(url: string, kind: AiModelProbeKind): string
|
|
|
52
50
|
/**
|
|
53
51
|
* Whether a reported model id covers the requested `OKE_AI_MODEL`.
|
|
54
52
|
*
|
|
55
|
-
* Tolerates
|
|
53
|
+
* Tolerates quant / alias normalization (`gemma4:e4b-q4_K_M` ↔ `gemma4:Q4_K_M`).
|
|
56
54
|
*
|
|
57
55
|
* @param want - Requested id
|
|
58
56
|
* @param reported - Server id
|
|
@@ -123,30 +121,6 @@ export function statusFromOpenAiModels(model: string, json: unknown): AiModelSta
|
|
|
123
121
|
};
|
|
124
122
|
}
|
|
125
123
|
|
|
126
|
-
/**
|
|
127
|
-
* Parse Ollama `GET /api/tags` into a status for `model`.
|
|
128
|
-
*
|
|
129
|
-
* @param model - Requested id
|
|
130
|
-
* @param json - Parsed JSON
|
|
131
|
-
*/
|
|
132
|
-
export function statusFromOllamaTags(model: string, json: unknown): AiModelStatus {
|
|
133
|
-
if (!json || typeof json !== "object") {
|
|
134
|
-
return { model, phase: "starting", detail: "invalid /api/tags body" };
|
|
135
|
-
}
|
|
136
|
-
const models = (json as { models?: unknown }).models;
|
|
137
|
-
if (!Array.isArray(models)) {
|
|
138
|
-
return { model, phase: "starting" };
|
|
139
|
-
}
|
|
140
|
-
for (const row of models) {
|
|
141
|
-
if (!row || typeof row !== "object") continue;
|
|
142
|
-
const name = (row as { name?: unknown }).name;
|
|
143
|
-
if (typeof name === "string" && aiModelIdsMatch(model, name)) {
|
|
144
|
-
return { model, phase: "ready", reportedId: name };
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
return { model, phase: "loading", detail: "not in /api/tags yet" };
|
|
148
|
-
}
|
|
149
|
-
|
|
150
124
|
/**
|
|
151
125
|
* Map a server-native status string to {@link AiModelPhase}.
|
|
152
126
|
*
|
|
@@ -173,7 +147,7 @@ export async function probeAiModelStatus(opts: ProbeAiModelStatusOptions): Promi
|
|
|
173
147
|
if (!model) return { model: "", phase: "error", detail: "OKE_AI_MODEL is empty" };
|
|
174
148
|
const fetchFn = opts.fetch ?? globalThis.fetch;
|
|
175
149
|
const base = normalizeAiProbeUrl(opts.url, opts.kind);
|
|
176
|
-
const path =
|
|
150
|
+
const path = `${base}/models`;
|
|
177
151
|
try {
|
|
178
152
|
const res = await fetchFn(path, { method: "GET" });
|
|
179
153
|
if (!res.ok) {
|
|
@@ -184,9 +158,7 @@ export async function probeAiModelStatus(opts: ProbeAiModelStatusOptions): Promi
|
|
|
184
158
|
};
|
|
185
159
|
}
|
|
186
160
|
const json: unknown = await res.json().catch(() => null);
|
|
187
|
-
return
|
|
188
|
-
? statusFromOllamaTags(model, json)
|
|
189
|
-
: statusFromOpenAiModels(model, json);
|
|
161
|
+
return statusFromOpenAiModels(model, json);
|
|
190
162
|
} catch (err) {
|
|
191
163
|
const msg = err instanceof Error ? err.message : String(err);
|
|
192
164
|
return { model, phase: "unreachable", detail: msg };
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for compose-up progress parsing / labels.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, expect, test } from "bun:test";
|
|
6
|
+
import {
|
|
7
|
+
composeUpPhaseLabel,
|
|
8
|
+
composeUpPhaseStatus,
|
|
9
|
+
formatComposeUpEventMessage,
|
|
10
|
+
parseComposeProgressLine,
|
|
11
|
+
shortenComposeTarget,
|
|
12
|
+
stripAnsi,
|
|
13
|
+
} from "./compose-up.ts";
|
|
14
|
+
|
|
15
|
+
describe("parseComposeProgressLine", () => {
|
|
16
|
+
test("parses Image / Container lifecycle lines", () => {
|
|
17
|
+
expect(parseComposeProgressLine(" Image postgres:16-alpine Pulling ")).toEqual({
|
|
18
|
+
raw: "Image postgres:16-alpine Pulling",
|
|
19
|
+
target: "postgres:16-alpine",
|
|
20
|
+
kind: "image",
|
|
21
|
+
phase: "pulling",
|
|
22
|
+
});
|
|
23
|
+
expect(parseComposeProgressLine("Container oke-oke-2-postgres-1 Started")).toEqual({
|
|
24
|
+
raw: "Container oke-oke-2-postgres-1 Started",
|
|
25
|
+
target: "oke-oke-2-postgres-1",
|
|
26
|
+
kind: "container",
|
|
27
|
+
phase: "started",
|
|
28
|
+
});
|
|
29
|
+
expect(parseComposeProgressLine("Network oke-oke-2_default Creating")).toEqual({
|
|
30
|
+
raw: "Network oke-oke-2_default Creating",
|
|
31
|
+
target: "oke-oke-2_default",
|
|
32
|
+
kind: "network",
|
|
33
|
+
phase: "creating",
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("parses bare service Pulling / Pulled", () => {
|
|
38
|
+
expect(parseComposeProgressLine("postgres Pulling")).toEqual({
|
|
39
|
+
raw: "postgres Pulling",
|
|
40
|
+
target: "postgres",
|
|
41
|
+
phase: "pulling",
|
|
42
|
+
});
|
|
43
|
+
expect(parseComposeProgressLine("redis Pulled")).toEqual({
|
|
44
|
+
raw: "redis Pulled",
|
|
45
|
+
target: "redis",
|
|
46
|
+
phase: "pulled",
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("parses download / extract / error chatter", () => {
|
|
51
|
+
expect(parseComposeProgressLine("1f2544649a1a Downloading [====>] 5MB/12MB")?.phase).toBe(
|
|
52
|
+
"downloading",
|
|
53
|
+
);
|
|
54
|
+
expect(parseComposeProgressLine("1f2544649a1a Extracting [========>]")?.phase).toBe(
|
|
55
|
+
"extracting",
|
|
56
|
+
);
|
|
57
|
+
expect(parseComposeProgressLine("Error response from daemon: boom")?.phase).toBe("error");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("keeps unknown lines as activity", () => {
|
|
61
|
+
expect(parseComposeProgressLine("some compose note")).toEqual({
|
|
62
|
+
raw: "some compose note",
|
|
63
|
+
phase: "other",
|
|
64
|
+
detail: "some compose note",
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("skips empty / spinner-only", () => {
|
|
69
|
+
expect(parseComposeProgressLine(" ")).toBeNull();
|
|
70
|
+
expect(parseComposeProgressLine("…")).toBeNull();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("strips ANSI before parse", () => {
|
|
74
|
+
const line = "\x1b[32mContainer oke-x-redis-1 Started\x1b[0m";
|
|
75
|
+
expect(parseComposeProgressLine(line)?.phase).toBe("started");
|
|
76
|
+
expect(stripAnsi(line)).toBe("Container oke-x-redis-1 Started");
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe("shortenComposeTarget / labels", () => {
|
|
81
|
+
test("shortens oke container and image refs", () => {
|
|
82
|
+
expect(shortenComposeTarget("oke-oke-2-postgres-1")).toBe("postgres");
|
|
83
|
+
expect(shortenComposeTarget("postgres:16-alpine")).toBe("postgres");
|
|
84
|
+
expect(shortenComposeTarget("ghcr.io/org/mailpit:latest")).toBe("mailpit");
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("formats event messages and status dots", () => {
|
|
88
|
+
expect(
|
|
89
|
+
formatComposeUpEventMessage({
|
|
90
|
+
raw: "Image postgres:16 Pulling",
|
|
91
|
+
target: "postgres:16",
|
|
92
|
+
phase: "pulling",
|
|
93
|
+
}),
|
|
94
|
+
).toBe("postgres pulling…");
|
|
95
|
+
expect(composeUpPhaseLabel("started")).toBe("started");
|
|
96
|
+
expect(composeUpPhaseStatus("pulling")).toBe("pending");
|
|
97
|
+
expect(composeUpPhaseStatus("started")).toBe("ready");
|
|
98
|
+
expect(composeUpPhaseStatus("error")).toBe("error");
|
|
99
|
+
});
|
|
100
|
+
});
|