okengine 0.18.5 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +18 -10
- package/README.md +2 -2
- package/package.json +51 -50
- package/site/content/docs/ai/llms-txt.mdx +1 -1
- package/site/content/docs/ai/meta.json +1 -1
- package/site/content/docs/ai/skills.mdx +4 -1
- package/site/content/docs/ai/try-it.mdx +58 -0
- package/site/content/docs/client/auth.mdx +208 -0
- package/site/content/docs/client/calling.mdx +451 -0
- package/site/content/docs/client/index.mdx +209 -0
- package/site/content/docs/client/live.mdx +234 -0
- package/site/content/docs/client/meta.json +5 -0
- package/site/content/docs/client/react.mdx +249 -0
- package/site/content/docs/elements/ai/agents.mdx +232 -0
- package/site/content/docs/elements/ai/index.mdx +341 -0
- package/site/content/docs/elements/ai/mcp.mdx +275 -0
- package/site/content/docs/elements/ai/meta.json +5 -0
- package/site/content/docs/elements/ai/models.mdx +283 -0
- package/site/content/docs/elements/ai/prompts.mdx +256 -0
- package/site/content/docs/elements/channel/email.mdx +266 -0
- package/site/content/docs/elements/channel/index.mdx +344 -0
- package/site/content/docs/elements/channel/meta.json +5 -0
- package/site/content/docs/elements/channel/push.mdx +218 -0
- package/site/content/docs/elements/channel/receipts.mdx +206 -0
- package/site/content/docs/elements/channel/sms.mdx +264 -0
- package/site/content/docs/elements/channel/whatsapp.mdx +220 -0
- package/site/content/docs/elements/clock/index.mdx +300 -0
- package/site/content/docs/elements/clock/meta.json +5 -0
- package/site/content/docs/elements/clock/schedules.mdx +508 -0
- package/site/content/docs/elements/clock/sleep.mdx +445 -0
- package/site/content/docs/elements/flow/consumers.mdx +707 -0
- package/site/content/docs/elements/flow/http.mdx +1080 -0
- package/site/content/docs/elements/flow/index.mdx +618 -0
- package/site/content/docs/elements/flow/meta.json +5 -0
- package/site/content/docs/elements/flow/routing.mdx +559 -0
- package/site/content/docs/elements/flow/workflows.mdx +640 -0
- package/site/content/docs/elements/gate/auth.mdx +371 -0
- package/site/content/docs/elements/gate/authorization.mdx +298 -0
- package/site/content/docs/elements/gate/index.mdx +418 -0
- package/site/content/docs/elements/gate/meta.json +5 -0
- package/site/content/docs/elements/gate/rate-limits.mdx +365 -0
- package/site/content/docs/elements/gate/rls.mdx +303 -0
- package/site/content/docs/elements/gate/tenancy.mdx +372 -0
- package/site/content/docs/elements/index.mdx +20 -10
- package/site/content/docs/elements/signal/broadcast.mdx +517 -0
- package/site/content/docs/elements/signal/index.mdx +352 -0
- package/site/content/docs/elements/signal/live.mdx +590 -0
- package/site/content/docs/elements/signal/meta.json +5 -0
- package/site/content/docs/elements/signal/once.mdx +596 -0
- package/site/content/docs/elements/store/files.mdx +659 -0
- package/site/content/docs/elements/store/index.mdx +310 -0
- package/site/content/docs/elements/store/kv.mdx +629 -0
- package/site/content/docs/elements/store/meta.json +5 -0
- package/site/content/docs/elements/store/search.mdx +946 -0
- package/site/content/docs/elements/store/sql.mdx +937 -0
- package/site/content/docs/elements/vault/config.mdx +256 -0
- package/site/content/docs/elements/vault/index.mdx +356 -0
- package/site/content/docs/elements/vault/meta.json +5 -0
- package/site/content/docs/elements/vault/rotation.mdx +273 -0
- package/site/content/docs/elements/vault/secrets.mdx +285 -0
- package/site/content/docs/index.mdx +63 -36
- package/site/content/docs/meta.json +8 -7
- package/site/content/docs/plugins/cors.mdx +2 -1
- package/site/content/docs/plugins/csrf.mdx +4 -1
- package/site/content/docs/plugins/headers.mdx +2 -1
- package/site/content/docs/plugins/ip-allowlist.mdx +2 -1
- package/site/content/docs/plugins/magic-link.mdx +6 -0
- package/site/content/docs/plugins/maintenance-mode.mdx +2 -1
- package/site/content/docs/plugins/oauth.mdx +1 -1
- package/site/content/docs/plugins/otp.mdx +12 -1
- package/site/content/docs/plugins/passkey.mdx +39 -15
- package/site/content/docs/plugins/two-factor.mdx +91 -34
- package/site/content/docs/plugins/username.mdx +1 -1
- package/site/content/docs/recipes/caddy.mdx +3 -3
- package/site/content/docs/recipes/index.mdx +18 -28
- package/site/content/docs/recipes/mailpit.mdx +1 -1
- package/site/content/docs/recipes/meilisearch.mdx +3 -3
- package/site/content/docs/recipes/meta.json +1 -4
- package/site/content/docs/recipes/nginx.mdx +2 -2
- package/site/content/docs/recipes/openrouter.mdx +283 -0
- package/site/content/docs/recipes/pgdog.mdx +3 -3
- package/site/content/docs/recipes/postgres.mdx +1 -2
- package/site/content/docs/recipes/rustfs.mdx +2 -2
- package/site/content/docs/recipes/traefik.mdx +3 -3
- package/site/content/docs/reference/cli.mdx +231 -0
- package/site/content/docs/reference/configuration.mdx +30 -10
- package/site/content/docs/reference/environment-variables.mdx +93 -20
- package/site/content/docs/reference/errors.mdx +132 -29
- package/site/content/docs/reference/fx.mdx +137 -73
- package/site/content/docs/reference/index.mdx +13 -21
- package/site/content/docs/reference/meta.json +4 -5
- package/site/content/docs/reference/okid.mdx +42 -17
- package/site/content/docs/reference/plugins.mdx +4 -3
- package/site/content/docs/reference/security.mdx +197 -0
- package/site/content/docs/understand/meta.json +5 -0
- package/site/content/docs/understand/the-anatomy.mdx +132 -0
- package/site/content/docs/understand/the-model.mdx +32 -0
- package/site/content/docs/understand/the-problem.mdx +74 -0
- package/site/content/docs/understand/the-vocabulary.mdx +26 -0
- package/src/auth/api-keys.ts +2 -1
- package/src/auth/bindings.ts +64 -16
- package/src/auth/gate-auth.test.ts +6 -1
- package/src/auth/identity.ts +152 -5
- package/src/auth/index.ts +29 -0
- package/src/auth/invites.ts +2 -1
- package/src/auth/method-context.ts +41 -0
- package/src/auth/oauth-as/crypto.ts +2 -1
- package/src/auth/oauth-as/stores.ts +2 -1
- package/src/auth/operator.ts +2 -1
- package/src/auth/sessions-jwt.test.ts +77 -0
- package/src/auth/sessions.ts +20 -4
- package/src/auth/tenants.ts +3 -2
- package/src/auth/two-factor-challenge.test.ts +61 -0
- package/src/auth/two-factor-challenge.ts +284 -0
- package/src/auth/verification.ts +5 -0
- package/src/bench/REPORT.md +49 -0
- package/src/bench/g03-signal-once.bench.ts +1 -1
- package/src/bench/g10-observability-contention.bench.ts +1 -1
- package/src/bench/g17-hybrid-search.bench.ts +572 -0
- package/src/bench/load-app.ts +2 -10
- package/src/cli/ai-setup/ai-setup.test.ts +331 -42
- package/src/cli/ai-setup/apply.ts +294 -52
- package/src/cli/ai-setup/catalog.ts +238 -1342
- package/src/cli/ai-setup/index.ts +14 -99
- package/src/cli/ai-setup/prompts.ts +60 -443
- package/src/cli/ask-seed.test.ts +96 -0
- package/src/cli/ask-seed.ts +82 -0
- package/src/cli/ask-vault-gaps.test.ts +84 -0
- package/src/cli/ask-vault-gaps.ts +146 -0
- package/src/cli/build.ts +2 -2
- package/src/cli/client-add.test.ts +26 -1
- package/src/cli/client-add.ts +106 -27
- package/src/cli/db-seed.ts +2 -0
- package/src/cli/db.ts +150 -11
- package/src/cli/dev.ts +119 -211
- package/src/cli/docker-clean.ts +2 -2
- package/src/cli/docker-cli.test.ts +1 -1
- package/src/cli/doctor-diff.ts +4 -2
- package/src/cli/doctor-pii.test.ts +1 -1
- package/src/cli/doctor.ts +14 -1
- package/src/cli/hero-meta.test.ts +4 -2
- package/src/cli/load-config.images.test.ts +8 -10
- package/src/cli/load-config.ts +1 -1
- package/src/cli/registry.ts +22 -10
- package/src/cli/replay.ts +3 -1
- package/src/cli/start.ts +1 -1
- package/src/cli/tui/keys.ts +2 -3
- package/src/client/auth/cookies.ts +74 -0
- package/src/client/auth/create-auth-client.ts +636 -0
- package/src/client/auth/denials.ts +99 -0
- package/src/client/auth/session.ts +283 -0
- package/src/client/auth.test.ts +251 -0
- package/src/client/auth.ts +39 -114
- package/src/client/create-with-session.ts +245 -0
- package/src/client/create.ts +51 -5
- package/src/client/index.ts +11 -1
- package/src/client/live.ts +11 -79
- package/src/client/notes-contract.test.ts +5 -10
- package/src/client/sse.ts +137 -0
- package/src/client/stream.ts +147 -0
- package/src/client/transport.test.ts +32 -0
- package/src/client/transport.ts +123 -26
- package/src/client/types.ts +118 -14
- package/src/client-react/index.ts +185 -24
- package/src/client-react/use-live-query.ts +13 -3
- package/src/compiler/aot.test.ts +7 -4
- package/src/compiler/effects-embed.test.ts +56 -0
- package/src/compiler/effects-fetch.test.ts +43 -0
- package/src/compiler/effects-infer.ts +58 -2
- package/src/compiler/extract.test.ts +257 -43
- package/src/compiler/extract.ts +566 -48
- package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +7 -4
- package/src/compiler/fixtures/skyport/src/flows/bookings/signals.ts +2 -8
- package/src/compiler/fixtures/skyport.expected.json +4 -4
- package/src/compiler/fixtures/triggers/five-triggers.ts +14 -10
- package/src/compiler/response.ts +2 -2
- package/src/compiler/search-writer-isolation.test.ts +40 -0
- package/src/config/index.ts +11 -0
- package/src/console/server/app.ts +17 -23
- package/src/console/server/bind.ts +4 -0
- package/src/console/server/console.test.ts +2 -2
- package/src/console/server/flows-invoke.test.ts +50 -34
- package/src/console/server/flows.ts +436 -255
- package/src/console/server/runs-ingest.test.ts +6 -3
- package/src/console/server/serve.ts +1 -1
- package/src/console/server/signals.test.ts +1 -5
- package/src/console/server/signals.ts +8 -6
- package/src/console/server/state.ts +6 -1
- package/src/console/server/store.ts +1 -1
- package/src/console/ui-next/dist/assets/FileExportIcon-Ck-5od4R.js +1 -0
- package/src/console/ui-next/dist/assets/MoreHorizontalCircle01Icon-gMNGsE37.js +1 -0
- package/src/console/ui-next/dist/assets/PlusSignIcon-CwG3nxfu.js +1 -0
- package/src/console/ui-next/dist/assets/UnavailableIcon-D9cvHVPr.js +1 -0
- package/src/console/ui-next/dist/assets/UserIcon-DaE2PB5_.js +1 -0
- package/src/console/ui-next/dist/assets/access-page-DFeymU07.js +4 -0
- package/src/console/ui-next/dist/assets/agent-disclosure-U1rdfblp.js +1 -0
- package/src/console/ui-next/dist/assets/cache-glyph-BeFJeqBG.js +1 -0
- package/src/console/ui-next/dist/assets/call-pii-button-CVAONPii.js +1 -0
- package/src/console/ui-next/dist/assets/collapsible-D2A6NJ-3.js +1 -0
- package/src/console/ui-next/dist/assets/copy-inline-button-CAYD18cr.js +1 -0
- package/src/console/ui-next/dist/assets/dagre.esm-B1_XeuLP.js +1 -0
- package/src/console/ui-next/dist/assets/detail-header-DVWNjWjg.js +1 -0
- package/src/console/ui-next/dist/assets/dropdown-menu-4h2LOVXM.js +1 -0
- package/src/console/ui-next/dist/assets/duration-tone-Cgk_h5ja.js +9 -0
- package/src/console/ui-next/dist/assets/element-icons-BI8cJgdh.js +1 -0
- package/src/console/ui-next/dist/assets/explorer-empty-CJs5A-wm.js +1 -0
- package/src/console/ui-next/dist/assets/flows-page-Dss7941e.js +1 -0
- package/src/console/ui-next/dist/assets/highlighted-json-MYZQtRnw.js +154 -0
- package/src/console/ui-next/dist/assets/http-method-Jrh39p7A.js +1 -0
- package/src/console/ui-next/dist/assets/index-D0zS5rKO.css +2 -0
- package/src/console/ui-next/dist/assets/index-DXP2dBIF.js +63 -0
- package/src/console/ui-next/dist/assets/observability-page-HvolXxTI.js +4 -0
- package/src/console/ui-next/dist/assets/react-dom-Ddte4I-Q.js +9 -0
- package/src/console/ui-next/dist/assets/replica-lag-CSh2dzrb.js +18 -0
- package/src/console/ui-next/dist/assets/request-meta-BatF8KrK.js +1 -0
- package/src/console/ui-next/dist/assets/shortcut-keys-3ILd8oGn.js +1 -0
- package/src/console/ui-next/dist/assets/{sql-BskegiFM.js → sql-BsFa4tDR.js} +1 -1
- package/src/console/ui-next/dist/assets/store-page-eiKiHnNe.js +41 -0
- package/src/console/ui-next/dist/assets/trace-detail-sheet-CZkMeKS-.js +2 -0
- package/src/console/ui-next/dist/assets/tree-expand-toggle-CW8y5A2h.js +55 -0
- package/src/console/ui-next/dist/assets/units-page-B_RWJrEO.js +1 -0
- package/src/console/ui-next/dist/assets/{use-vault-list-uk4WVboC.js → use-vault-list-CT4-gajj.js} +1 -1
- package/src/console/ui-next/dist/assets/vault-page-CWrg-A68.js +2 -0
- package/src/console/ui-next/dist/assets/xyflow-CSyC6ryz.css +1 -0
- package/src/console/ui-next/dist/assets/xyflow-yApv7D4e.js +7 -0
- package/src/console/ui-next/dist/index.html +6 -13
- package/src/console/ui-next/seed-invoke-host.ts +21 -18
- package/src/console/ui-next/src/client.ts +7 -2
- package/src/console/ui-next/src/features/flows/graph/element-map.ts +2 -0
- package/src/console/ui-next/src/features/flows/traces/effect-kind.ts +12 -2
- package/src/console/ui-next/src/features/flows/traces/effect-summary.ts +4 -0
- package/src/console/ui-next/src/features/flows/traces/trace-detail-sheet.tsx +8 -0
- package/src/console/ui-next/src/features/flows/traces/waterfall-bars.ts +4 -0
- package/src/console/ui-next/src/features/flows/traces/waterfall-tooltip.ts +9 -3
- package/src/console/ui-next/src/features/store/detail/reveal-cell.tsx +7 -11
- package/src/console/ui-next/src/features/store/detail/store-row-detail-sheet.tsx +2 -2
- package/src/console/ui-next/src/features/store/lib/fields-from-table.ts +2 -0
- package/src/console/ui-next/src/features/store/lib/grid-model.test.ts +25 -1
- package/src/console/ui-next/src/features/store/lib/grid-model.ts +36 -1
- package/src/console/ui-next/src/features/store/query/query-results.tsx +3 -3
- package/src/console/ui-next/src/features/units/detail/effects-summary.tsx +2 -0
- package/src/console/ui-next/src/features/units/lib/call-read-safe.ts +3 -1
- package/src/console/ui-next/src/features/units/lib/fields-from-schema.ts +6 -0
- package/src/docker/ai-model-status.test.ts +1 -12
- package/src/docker/ai-model-status.ts +10 -38
- package/src/docker/compose-up.test.ts +100 -0
- package/src/docker/compose-up.ts +292 -0
- package/src/docker/compose.ts +4 -14
- package/src/docker/derive.ts +9 -34
- package/src/docker/docker.test.ts +16 -261
- package/src/docker/images-config.test.ts +13 -25
- package/src/docker/index.ts +1 -24
- package/src/docker/recipes/index.ts +0 -23
- package/src/docker/recipes/pgdog.ts +6 -4
- package/src/docker/stack-id.test.ts +2 -2
- package/src/docker/stack-id.ts +0 -1
- package/src/docker/types.ts +2 -2
- package/src/drivers/ai-anthropic.ts +10 -0
- package/src/drivers/ai-openai-compatible.ts +34 -7
- package/src/drivers/ai-providers.test.ts +0 -107
- package/src/drivers/ai-stream.test.ts +0 -34
- package/src/drivers/ai-types.ts +17 -8
- package/src/drivers/channel-fcm.ts +6 -1
- package/src/drivers/channel-msegat.ts +6 -1
- package/src/drivers/channel-resend.ts +5 -1
- package/src/drivers/channel-smtp.ts +5 -1
- package/src/drivers/channel-sndr.ts +10 -1
- package/src/drivers/channel-taqnyat-mail.ts +5 -1
- package/src/drivers/channel-taqnyat-whatsapp.ts +6 -1
- package/src/drivers/channel-taqnyat.ts +6 -1
- package/src/drivers/channel-types.ts +10 -0
- package/src/drivers/channel-unifonic.ts +6 -1
- package/src/drivers/channel-wa-cloud.ts +6 -1
- package/src/drivers/channel-webpush.ts +6 -1
- package/src/drivers/external.ts +33 -0
- package/src/drivers/index.ts +0 -10
- package/src/drivers/meilisearch.ts +6 -0
- package/src/drivers/oauth-types.ts +4 -0
- package/src/drivers/postgres.test.ts +74 -3
- package/src/drivers/postgres.ts +175 -6
- package/src/drivers/signal-types.ts +5 -5
- package/src/drivers/types.ts +7 -0
- package/src/drivers/vault-types.ts +5 -0
- package/src/elements/ai/declare.ts +17 -4
- package/src/elements/ai/eval.ts +1 -1
- package/src/elements/ai/mcp-http.ts +1 -1
- package/src/elements/ai/pii.ts +1 -1
- package/src/elements/ai/providers.test.ts +289 -0
- package/src/elements/ai/providers.ts +169 -0
- package/src/elements/ai/runtime.ts +68 -5
- package/src/elements/ai/schema.ts +2 -2
- package/src/elements/ai.test.ts +7 -7
- package/src/elements/ai.ts +17 -1
- package/src/elements/channel/runtime.ts +105 -12
- package/src/elements/clock/cron-fields.test.ts +144 -0
- package/src/elements/clock/cron-fields.ts +185 -0
- package/src/elements/clock/declare.ts +247 -3
- package/src/elements/clock.ts +21 -1
- package/src/elements/index.ts +15 -0
- package/src/elements/signal/chaos-child.ts +1 -2
- package/src/elements/signal/declare.ts +65 -37
- package/src/elements/signal/delivery-modes.test.ts +11 -31
- package/src/elements/signal/dry-run-replay.test.ts +1 -7
- package/src/elements/signal/dry-run-write-isolation.test.ts +1 -7
- package/src/elements/signal/key-ordering.test.ts +6 -26
- package/src/elements/signal/lease-reclaim.test.ts +2 -6
- package/src/elements/signal/optional-emit.test.ts +6 -9
- package/src/elements/signal/order-lifecycle.test.ts +4 -17
- package/src/elements/signal/orphan-messages.test.ts +4 -15
- package/src/elements/signal/reconcile.test.ts +2 -2
- package/src/elements/signal/runtime.ts +1 -1
- package/src/elements/signal/schema-emit.test.ts +4 -8
- package/src/elements/signal.test.ts +24 -49
- package/src/elements/signal.ts +9 -2
- package/src/elements/store/domain-ddl.test.ts +1 -1
- package/src/elements/store/live-http.test.ts +9 -4
- package/src/elements/store/prepare-row.test.ts +123 -0
- package/src/elements/store/resource.ts +43 -12
- package/src/elements/store/schema-decl.ts +117 -0
- package/src/elements/store/search-backfill.ts +205 -0
- package/src/elements/store/search-bind.ts +66 -0
- package/src/elements/store/search-bm25.ts +78 -0
- package/src/elements/store/search-ddl.ts +156 -0
- package/src/elements/store/search-embed-flow.ts +141 -0
- package/src/elements/store/search-errors.ts +34 -0
- package/src/elements/store/search-fusion.ts +112 -0
- package/src/elements/store/search-lsh.ts +179 -0
- package/src/elements/store/search-runtime.ts +300 -0
- package/src/elements/store/search.test.ts +144 -0
- package/src/elements/store/sql-session.test.ts +1 -0
- package/src/elements/store/sql-session.ts +83 -3
- package/src/elements/store/table.ts +23 -2
- package/src/elements/store/upsert-app.test.ts +1 -3
- package/src/elements/store.ts +50 -0
- package/src/full.ts +4 -2
- package/src/http.ts +4 -1
- package/src/i18n/catalogs/ar.ts +14 -6
- package/src/i18n/catalogs/en.ts +14 -6
- package/src/index.ts +6 -1
- package/src/kernel/adopt-barrel-fresh.test.ts +7 -7
- package/src/kernel/adopt-routes.ts +9 -1
- package/src/kernel/app-auth.ts +5 -0
- package/src/kernel/app.ts +102 -9
- package/src/kernel/auto-cache.test.ts +6 -12
- package/src/kernel/auto-registry.test.ts +3 -3
- package/src/kernel/boot-bind/ai.test.ts +22 -19
- package/src/kernel/boot-bind/ai.ts +5 -43
- package/src/kernel/boot-bind/clock.ts +23 -5
- package/src/kernel/boot-bind/honor-config.test.ts +4 -4
- package/src/kernel/boot.test.ts +11 -6
- package/src/kernel/boot.ts +66 -16
- package/src/kernel/boundary-contract.ts +93 -0
- package/src/kernel/budget.test.ts +1 -1
- package/src/kernel/call.ts +89 -0
- package/src/kernel/capability.ts +6 -0
- package/src/kernel/client-descriptor.ts +123 -0
- package/src/kernel/clock-timezone.test.ts +80 -0
- package/src/kernel/correlation.test.ts +1 -1
- package/src/kernel/dry-run.ts +11 -8
- package/src/kernel/effects-stamping.test.ts +42 -9
- package/src/kernel/effects.test.ts +4 -2
- package/src/kernel/effects.ts +51 -9
- package/src/kernel/errors-channel.ts +17 -0
- package/src/kernel/errors-live-resume.ts +3 -2
- package/src/kernel/errors-tenant.ts +7 -4
- package/src/kernel/errors.registry-helpers.ts +96 -0
- package/src/kernel/errors.registry.test.ts +139 -25
- package/src/kernel/errors.ts +102 -23
- package/src/kernel/external-effects.test.ts +196 -0
- package/src/kernel/flow.test.ts +13 -4
- package/src/kernel/flow.ts +69 -71
- package/src/kernel/fx-ask-telemetry.test.ts +2 -2
- package/src/kernel/fx-dead-letters.test.ts +3 -3
- package/src/kernel/fx-fetch.ts +55 -0
- package/src/kernel/fx-live-stream.ts +2 -2
- package/src/kernel/fx-live.test.ts +8 -8
- package/src/kernel/fx.test.ts +17 -11
- package/src/kernel/fx.ts +180 -57
- package/src/kernel/horizontal-child.ts +1 -1
- package/src/kernel/http-query.test.ts +3 -6
- package/src/kernel/index.ts +13 -3
- package/src/kernel/instance-id.ts +1 -1
- package/src/kernel/instances.test.ts +40 -0
- package/src/kernel/instances.ts +47 -9
- package/src/kernel/live-http.test.ts +6 -7
- package/src/kernel/live-http.ts +6 -2
- package/src/kernel/live-resume.test.ts +1 -1
- package/src/kernel/mcp-tool.test.ts +3 -3
- package/src/kernel/on.ts +98 -4
- package/src/kernel/pipeline.test.ts +12 -15
- package/src/kernel/plugin-elements.test.ts +1 -1
- package/src/kernel/stamp-http.test.ts +3 -3
- package/src/kernel/triggers.ts +210 -95
- package/src/kernel-entry.ts +0 -1
- package/src/manifest/diff.ts +11 -1
- package/src/manifest/fixtures/skyport.excerpt.json +1 -1
- package/src/manifest/types.ts +46 -2
- package/src/mcp/docs-index.ts +3 -3
- package/src/mcp/docs-mcp.test.ts +2 -2
- package/src/mcp/docs-tools.ts +1 -1
- package/src/okid.test.ts +56 -0
- package/src/okid.ts +55 -11
- package/src/plugins/anonymous.ts +8 -4
- package/src/plugins/auth/shared.ts +27 -3
- package/src/plugins/auth-delivery.mailpit.integration.test.ts +1 -1
- package/src/plugins/auth-methods.security.test.ts +561 -23
- package/src/plugins/config-source.ts +1 -1
- package/src/plugins/csrf.test.ts +65 -0
- package/src/plugins/index.ts +2 -0
- package/src/plugins/magic-link.ts +36 -16
- package/src/plugins/oauth/shared.ts +3 -1
- package/src/plugins/oauth.ts +22 -14
- package/src/plugins/otp.ts +37 -21
- package/src/plugins/passkey-webauthn.ts +9 -6
- package/src/plugins/passkey.ts +98 -26
- package/src/plugins/pre-account-hijack.test.ts +223 -0
- package/src/plugins/two-factor.ts +466 -37
- package/src/plugins/username.ts +19 -7
- package/src/release/build-lib.ts +1 -0
- package/src/release/limits.ts +2 -2
- package/src/release/measure.ts +1 -1
- package/src/runs/collect.test.ts +0 -2
- package/src/runtime/json-code-block.test.ts +250 -20
- package/src/runtime/json-code-block.ts +1261 -41
- package/src/term.test.ts +1 -1
- package/src/test/create-test-app.test.ts +12 -12
- package/src/test/live-signals.test.ts +6 -6
- package/src/test/provisions.integration.test.ts +10 -14
- package/src/test/reset-element-registries.ts +1 -1
- package/src/test/tenant-isolation.test.ts +12 -6
- package/site/content/docs/deployment/docker-swarm.mdx +0 -164
- package/site/content/docs/deployment/docker.mdx +0 -227
- package/site/content/docs/deployment/index.mdx +0 -83
- package/site/content/docs/deployment/kubernetes.mdx +0 -176
- package/site/content/docs/deployment/meta.json +0 -5
- package/site/content/docs/deployment/reverse-proxy.mdx +0 -234
- package/site/content/docs/elements/ai.mdx +0 -385
- package/site/content/docs/elements/channel.mdx +0 -346
- package/site/content/docs/elements/clock.mdx +0 -244
- package/site/content/docs/elements/flow.mdx +0 -420
- package/site/content/docs/elements/gate.mdx +0 -436
- package/site/content/docs/elements/signal.mdx +0 -380
- package/site/content/docs/elements/store.mdx +0 -1099
- package/site/content/docs/elements/vault.mdx +0 -405
- package/site/content/docs/get-started/basic-usage.mdx +0 -173
- package/site/content/docs/get-started/index.mdx +0 -43
- package/site/content/docs/get-started/installation.mdx +0 -220
- package/site/content/docs/get-started/introduction.mdx +0 -144
- package/site/content/docs/get-started/meta.json +0 -13
- package/site/content/docs/get-started/project-structure.mdx +0 -925
- package/site/content/docs/get-started/testing.mdx +0 -328
- package/site/content/docs/get-started/why.mdx +0 -114
- package/site/content/docs/recipes/llama-cpp.mdx +0 -151
- package/site/content/docs/recipes/ollama.mdx +0 -142
- package/site/content/docs/recipes/sglang.mdx +0 -105
- package/site/content/docs/recipes/vllm.mdx +0 -106
- package/site/content/docs/reference/cli.md +0 -232
- package/site/content/docs/reference/client.mdx +0 -469
- package/site/content/docs/reference/security.md +0 -74
- package/src/cli/ai-setup/detect-ollama.ts +0 -213
- package/src/cli/ai-setup/recommend.test.ts +0 -225
- package/src/cli/ai-setup/recommend.ts +0 -225
- package/src/cli/dev-controls.test.ts +0 -122
- package/src/cli/dev-controls.ts +0 -164
- package/src/cli/tui/DevLive.tsx +0 -126
- package/src/console/ui-next/dist/assets/access-page-3-EFj-2G.js +0 -4
- package/src/console/ui-next/dist/assets/agent-disclosure-BP0Y0Sux.js +0 -1
- package/src/console/ui-next/dist/assets/cache-glyph-B5X-NM0-.js +0 -1
- package/src/console/ui-next/dist/assets/call-pii-button-ChAUiLo9.js +0 -1
- package/src/console/ui-next/dist/assets/collapsible-DGnOM2ph.js +0 -1
- package/src/console/ui-next/dist/assets/copy-inline-button-DBHhgHKP.js +0 -1
- package/src/console/ui-next/dist/assets/dagre.esm-ZwcdTuZZ.js +0 -1
- package/src/console/ui-next/dist/assets/detail-header-DhHM1iaZ.js +0 -1
- package/src/console/ui-next/dist/assets/dropdown-menu-_NjTEo5_.js +0 -1
- package/src/console/ui-next/dist/assets/duration-tone-sC3lGABz.js +0 -9
- package/src/console/ui-next/dist/assets/element-icons-BVXtRyd3.js +0 -1
- package/src/console/ui-next/dist/assets/explorer-empty-2uIhBu0_.js +0 -1
- package/src/console/ui-next/dist/assets/flows-page-cVFnA4HH.js +0 -1
- package/src/console/ui-next/dist/assets/highlighted-json-Awq7gYdu.js +0 -154
- package/src/console/ui-next/dist/assets/http-method-_UHM2ODJ.js +0 -1
- package/src/console/ui-next/dist/assets/index-CMIgUbD0.js +0 -66
- package/src/console/ui-next/dist/assets/index-Ck88Jmv8.css +0 -2
- package/src/console/ui-next/dist/assets/link-BX6Vqztd.js +0 -1
- package/src/console/ui-next/dist/assets/observability-page-CQ3p34ip.js +0 -4
- package/src/console/ui-next/dist/assets/preload-helper-oH4irX4C.js +0 -1
- package/src/console/ui-next/dist/assets/react-D8E3mtu1.js +0 -1
- package/src/console/ui-next/dist/assets/react-dom-Bph1y7z7.js +0 -9
- package/src/console/ui-next/dist/assets/replica-lag-DKRrbvdo.js +0 -18
- package/src/console/ui-next/dist/assets/request-meta-DV0ywz7t.js +0 -1
- package/src/console/ui-next/dist/assets/shortcut-JQIZlWfm.js +0 -1
- package/src/console/ui-next/dist/assets/shortcut-keys-DKxNTe_m.js +0 -1
- package/src/console/ui-next/dist/assets/skeleton-D-czQJT6.js +0 -1
- package/src/console/ui-next/dist/assets/store-page-02xOiqIK.js +0 -41
- package/src/console/ui-next/dist/assets/trace-detail-sheet-B09O8rA6.js +0 -2
- package/src/console/ui-next/dist/assets/tree-expand-toggle-BtyhmWb4.js +0 -55
- package/src/console/ui-next/dist/assets/units-page-l8FeKfnP.js +0 -1
- package/src/console/ui-next/dist/assets/useMutation-B8EO02Ej.js +0 -1
- package/src/console/ui-next/dist/assets/useRender-BE2A9BWC.js +0 -1
- package/src/console/ui-next/dist/assets/vault-page-CL-d_mLE.js +0 -2
- package/src/console/ui-next/dist/assets/xyflow-D7n4g6go.js +0 -7
- package/src/console/ui-next/dist/assets/xyflow-DZ0Ws1xk.css +0 -1
- package/src/docker/ollama-pull.ts +0 -232
- package/src/docker/recipes/llama-cpp.ts +0 -298
- package/src/docker/recipes/ollama.ts +0 -44
- package/src/docker/recipes/sglang.ts +0 -55
- package/src/docker/recipes/vllm.ts +0 -44
- package/src/drivers/ai-ollama-tools.integration.test.ts +0 -109
- package/src/drivers/ai-ollama.integration.test.ts +0 -184
- package/src/drivers/ai-ollama.ts +0 -389
- package/src/drivers/ollama.ts +0 -14
|
@@ -10,6 +10,8 @@ import type {
|
|
|
10
10
|
AuthApiKeysResourceRef,
|
|
11
11
|
AuthTenantsResourceRef,
|
|
12
12
|
Effects,
|
|
13
|
+
EmbedRef,
|
|
14
|
+
FetchHostRef,
|
|
13
15
|
PromptRef,
|
|
14
16
|
ResourceRef,
|
|
15
17
|
SecretRef,
|
|
@@ -53,6 +55,7 @@ export interface InferBinding {
|
|
|
53
55
|
readonly kind:
|
|
54
56
|
| "store"
|
|
55
57
|
| "signal"
|
|
58
|
+
| "clock"
|
|
56
59
|
| "prompt"
|
|
57
60
|
| "secret"
|
|
58
61
|
| "template"
|
|
@@ -96,7 +99,7 @@ export interface InferredEffects {
|
|
|
96
99
|
* the flow must opt out of auto-caching.
|
|
97
100
|
*/
|
|
98
101
|
readonly cacheIneligible: boolean;
|
|
99
|
-
/** True when any `fx.ask` was seen (implies nondeterministic). */
|
|
102
|
+
/** True when any `fx.ask` or `fx.embed` was seen (implies nondeterministic). */
|
|
100
103
|
readonly nondeterministic: boolean;
|
|
101
104
|
/** True when the body references `fx.auth.userId`. */
|
|
102
105
|
readonly readsUserId: boolean;
|
|
@@ -112,6 +115,10 @@ const READ_METHODS = new Set([
|
|
|
112
115
|
"find",
|
|
113
116
|
"list",
|
|
114
117
|
"ttlMs",
|
|
118
|
+
"count",
|
|
119
|
+
"page",
|
|
120
|
+
"search",
|
|
121
|
+
"raw",
|
|
115
122
|
]);
|
|
116
123
|
|
|
117
124
|
const WRITE_METHODS = new Set([
|
|
@@ -139,6 +146,9 @@ const TABLE_ARG_METHODS = new Set([
|
|
|
139
146
|
"upsert",
|
|
140
147
|
"increment",
|
|
141
148
|
"delete",
|
|
149
|
+
"count",
|
|
150
|
+
"page",
|
|
151
|
+
"search",
|
|
142
152
|
]);
|
|
143
153
|
|
|
144
154
|
/**
|
|
@@ -154,8 +164,10 @@ export function inferEffects(options: InferEffectsOptions): InferredEffects {
|
|
|
154
164
|
const emits = new Set<SignalRef>();
|
|
155
165
|
const sends = new Set<TemplateRef>();
|
|
156
166
|
const asks = new Set<PromptRef>();
|
|
167
|
+
const embeds = new Set<EmbedRef>();
|
|
157
168
|
const secrets = new Set<SecretRef>();
|
|
158
169
|
const calls = new Set<FlowRef>();
|
|
170
|
+
const fetches = new Set<FetchHostRef>();
|
|
159
171
|
const steps: string[] = [];
|
|
160
172
|
let usesRaw = false;
|
|
161
173
|
|
|
@@ -211,6 +223,34 @@ export function inferEffects(options: InferEffectsOptions): InferredEffects {
|
|
|
211
223
|
continue;
|
|
212
224
|
}
|
|
213
225
|
|
|
226
|
+
if (chain.rootMethod === "embed" && call === chain.rootCall) {
|
|
227
|
+
// fx.embed(model, text) — distinct from fx.ask; never classified as asks.
|
|
228
|
+
// Prefer model binding; also accept embed-pipeline and string literals.
|
|
229
|
+
const lit = stringArg(call.arguments[0]);
|
|
230
|
+
if (lit) {
|
|
231
|
+
embeds.add(lit);
|
|
232
|
+
} else {
|
|
233
|
+
const binding = resolveBinding(call.arguments[0], options.bindings);
|
|
234
|
+
if (binding && (binding.kind === "embed" || binding.kind === "unknown")) {
|
|
235
|
+
embeds.add(binding.ref);
|
|
236
|
+
} else {
|
|
237
|
+
const name = identifierName(call.arguments[0]);
|
|
238
|
+
if (name) embeds.add(name);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (chain.rootMethod === "fetch" && call === chain.rootCall) {
|
|
245
|
+
// fx.fetch(url) — host becomes effects.fetches entry.
|
|
246
|
+
const lit = stringArg(call.arguments[0]);
|
|
247
|
+
if (lit) {
|
|
248
|
+
const host = hostFromUrlLiteral(lit);
|
|
249
|
+
if (host) fetches.add(host);
|
|
250
|
+
}
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
|
|
214
254
|
if (chain.rootMethod === "vault" && call === chain.rootCall) {
|
|
215
255
|
// `fx.vault.list()` / `fx.vault.status()` take no path — nothing to
|
|
216
256
|
// declare. Every other method's first argument is the secret.
|
|
@@ -289,15 +329,17 @@ export function inferEffects(options: InferEffectsOptions): InferredEffects {
|
|
|
289
329
|
if (emits.size > 0) effects.emits = sortUnique([...emits]);
|
|
290
330
|
if (sends.size > 0) effects.sends = sortUnique([...sends]);
|
|
291
331
|
if (asks.size > 0) effects.asks = sortUnique([...asks]);
|
|
332
|
+
if (embeds.size > 0) effects.embeds = sortUnique([...embeds]);
|
|
292
333
|
if (secrets.size > 0) effects.secrets = sortUnique([...secrets]);
|
|
293
334
|
if (calls.size > 0) effects.calls = sortUnique([...calls]);
|
|
335
|
+
if (fetches.size > 0) effects.fetches = sortUnique([...fetches]);
|
|
294
336
|
|
|
295
337
|
return {
|
|
296
338
|
effects,
|
|
297
339
|
steps,
|
|
298
340
|
usesRaw,
|
|
299
341
|
cacheIneligible: usesRaw && !options.hasExplicitEffects,
|
|
300
|
-
nondeterministic: asks.size > 0,
|
|
342
|
+
nondeterministic: asks.size > 0 || embeds.size > 0,
|
|
301
343
|
readsUserId: containsAuthUserId(options.doNode),
|
|
302
344
|
};
|
|
303
345
|
}
|
|
@@ -658,6 +700,20 @@ export function stringArg(node: AstNode | undefined): string | undefined {
|
|
|
658
700
|
return undefined;
|
|
659
701
|
}
|
|
660
702
|
|
|
703
|
+
/**
|
|
704
|
+
* Hostname from a URL string literal for `fx.fetch` inference.
|
|
705
|
+
*
|
|
706
|
+
* @param url - Absolute or protocol-relative URL string
|
|
707
|
+
*/
|
|
708
|
+
export function hostFromUrlLiteral(url: string): string | undefined {
|
|
709
|
+
try {
|
|
710
|
+
const parsed = new URL(url);
|
|
711
|
+
return parsed.hostname || undefined;
|
|
712
|
+
} catch {
|
|
713
|
+
return undefined;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
|
|
661
717
|
/**
|
|
662
718
|
* Identifier name.
|
|
663
719
|
*
|
|
@@ -246,6 +246,133 @@ export const db = store.sql("app", { schema: { notes } });
|
|
|
246
246
|
});
|
|
247
247
|
});
|
|
248
248
|
|
|
249
|
+
test("extracts searchable / embed column meta and table.search engines", async () => {
|
|
250
|
+
const source = `
|
|
251
|
+
import { store, field, ai } from "okengine";
|
|
252
|
+
|
|
253
|
+
export const embedder = ai.model("embedder", { provider: "openai-compatible", model: "nomic-embed-text" });
|
|
254
|
+
|
|
255
|
+
export const articles = store.schema.table("articles", {
|
|
256
|
+
id: field.text().primaryKey(),
|
|
257
|
+
title: field.text().searchable({ weight: 2 }).notNull(),
|
|
258
|
+
body: field.text().searchable().embed({ dims: 8, model: embedder }),
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
export const db = store.sql("app", { schema: { articles } });
|
|
262
|
+
`;
|
|
263
|
+
const manifest = await extractFromSources({
|
|
264
|
+
"src/schema.decl.ts": source,
|
|
265
|
+
});
|
|
266
|
+
const table = manifest.stores?.app?.tables?.articles;
|
|
267
|
+
expect(table?.columns?.title).toMatchObject({
|
|
268
|
+
searchable: { weight: 2 },
|
|
269
|
+
});
|
|
270
|
+
expect(table?.columns?.body).toMatchObject({
|
|
271
|
+
searchable: { weight: 1 },
|
|
272
|
+
embed: { dims: 8, model: "embedder" },
|
|
273
|
+
});
|
|
274
|
+
expect(table?.search?.engines).toEqual(["bm25", "lsh"]);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
test("embed without ai element fails SearchConfigError", async () => {
|
|
278
|
+
const source = `
|
|
279
|
+
import { store, field } from "okengine";
|
|
280
|
+
|
|
281
|
+
export const articles = store.schema.table("articles", {
|
|
282
|
+
id: field.text().primaryKey(),
|
|
283
|
+
body: field.text().searchable().embed({ dims: 8, model: "embedder" }),
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
export const db = store.sql("app", { schema: { articles } });
|
|
287
|
+
`;
|
|
288
|
+
await expect(extractFromSources({ "src/schema.decl.ts": source })).rejects.toThrow(
|
|
289
|
+
/SearchConfigError|ai element/,
|
|
290
|
+
);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
test("project search.embed default stamps bare .embed()", async () => {
|
|
294
|
+
const source = `
|
|
295
|
+
import { store, field, ai, oke } from "okengine";
|
|
296
|
+
|
|
297
|
+
export const embedder = ai.model("embedder", { provider: "openai-compatible", model: "nomic-embed-text" });
|
|
298
|
+
|
|
299
|
+
oke({
|
|
300
|
+
store: {
|
|
301
|
+
search: {
|
|
302
|
+
embed: { model: embedder, dims: 768 },
|
|
303
|
+
},
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
export const articles = store.schema.table("articles", {
|
|
308
|
+
id: field.text().primaryKey(),
|
|
309
|
+
body: field.text().searchable().embed(),
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
export const db = store.sql("app", { schema: { articles } });
|
|
313
|
+
`;
|
|
314
|
+
const manifest = await extractFromSources({
|
|
315
|
+
"src/schema.decl.ts": source,
|
|
316
|
+
});
|
|
317
|
+
expect(manifest.store?.search?.embed).toEqual({ model: "embedder", dims: 768 });
|
|
318
|
+
expect(manifest.stores?.app?.tables?.articles?.columns?.body).toMatchObject({
|
|
319
|
+
searchable: { weight: 1 },
|
|
320
|
+
embed: { model: "embedder", dims: 768 },
|
|
321
|
+
});
|
|
322
|
+
expect(manifest.stores?.app?.tables?.articles?.search?.engines).toEqual(["bm25", "lsh"]);
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
test("field .embed() override wins over project search.embed default", async () => {
|
|
326
|
+
const source = `
|
|
327
|
+
import { store, field, ai, oke } from "okengine";
|
|
328
|
+
|
|
329
|
+
export const embedder = ai.model("embedder", { provider: "openai-compatible", model: "nomic-embed-text" });
|
|
330
|
+
export const other = ai.model("other", { provider: "openai-compatible", model: "nomic-embed-text" });
|
|
331
|
+
|
|
332
|
+
oke({
|
|
333
|
+
store: {
|
|
334
|
+
search: {
|
|
335
|
+
embed: { model: embedder, dims: 768 },
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
export const articles = store.schema.table("articles", {
|
|
341
|
+
id: field.text().primaryKey(),
|
|
342
|
+
body: field.text().searchable().embed(),
|
|
343
|
+
caption: field.text().searchable().embed({ model: other }),
|
|
344
|
+
alt: field.text().searchable().embed({ model: other, dims: 384 }),
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
export const db = store.sql("app", { schema: { articles } });
|
|
348
|
+
`;
|
|
349
|
+
const manifest = await extractFromSources({
|
|
350
|
+
"src/schema.decl.ts": source,
|
|
351
|
+
});
|
|
352
|
+
const cols = manifest.stores?.app?.tables?.articles?.columns;
|
|
353
|
+
expect(cols?.body).toMatchObject({ embed: { model: "embedder", dims: 768 } });
|
|
354
|
+
expect(cols?.caption).toMatchObject({ embed: { model: "other", dims: 768 } });
|
|
355
|
+
expect(cols?.alt).toMatchObject({ embed: { model: "other", dims: 384 } });
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
test("bare .embed() without project default fails SearchConfigError", async () => {
|
|
359
|
+
const source = `
|
|
360
|
+
import { store, field, ai } from "okengine";
|
|
361
|
+
|
|
362
|
+
export const embedder = ai.model("embedder", { provider: "openai-compatible", model: "nomic-embed-text" });
|
|
363
|
+
|
|
364
|
+
export const articles = store.schema.table("articles", {
|
|
365
|
+
id: field.text().primaryKey(),
|
|
366
|
+
body: field.text().searchable().embed(),
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
export const db = store.sql("app", { schema: { articles } });
|
|
370
|
+
`;
|
|
371
|
+
await expect(extractFromSources({ "src/schema.decl.ts": source })).rejects.toThrow(
|
|
372
|
+
/SearchConfigError|model and dims|store: \{ search: \{ embed/,
|
|
373
|
+
);
|
|
374
|
+
});
|
|
375
|
+
|
|
249
376
|
test("extracts RLS helpers onto store.tables", async () => {
|
|
250
377
|
const source = `
|
|
251
378
|
import { store, field } from "okengine";
|
|
@@ -349,6 +476,69 @@ export const db = store.sql("app", { schema: { assets } });
|
|
|
349
476
|
expect(cols?.createdAt).toMatchObject({ type: "integer", nullable: false, default: null });
|
|
350
477
|
});
|
|
351
478
|
|
|
479
|
+
test("field.id() / field.okid() heads extract as text PK with dynamic default", async () => {
|
|
480
|
+
const source = `
|
|
481
|
+
import { store, field } from "okengine";
|
|
482
|
+
|
|
483
|
+
export const tasks = store.schema.table("tasks", {
|
|
484
|
+
id: field.id().primaryKey(),
|
|
485
|
+
title: field.text().notNull(),
|
|
486
|
+
updatedAt: field.timestamp().notNull().now(),
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
export const assets = store.schema.table("assets", {
|
|
490
|
+
id: field.okid().primaryKey(),
|
|
491
|
+
name: field.text().notNull(),
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
export const db = store.sql("app", { schema: { tasks, assets } });
|
|
495
|
+
`;
|
|
496
|
+
const manifest = await extractFromSources({
|
|
497
|
+
"src/schema.decl.ts": source,
|
|
498
|
+
});
|
|
499
|
+
expect(manifest.stores?.app?.tables?.tasks?.columns?.id).toMatchObject({
|
|
500
|
+
type: "text",
|
|
501
|
+
primaryKey: true,
|
|
502
|
+
default: null,
|
|
503
|
+
sqlName: "id",
|
|
504
|
+
});
|
|
505
|
+
expect(manifest.stores?.app?.tables?.assets?.columns?.id).toMatchObject({
|
|
506
|
+
type: "text",
|
|
507
|
+
primaryKey: true,
|
|
508
|
+
default: null,
|
|
509
|
+
});
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
test("live(.live(table)) accepts field.id().primaryKey() tables", async () => {
|
|
513
|
+
const source = `
|
|
514
|
+
import { on, flow, http, gate, store, field } from "okengine";
|
|
515
|
+
|
|
516
|
+
export const tasks = store.schema.table("tasks", {
|
|
517
|
+
id: field.id().primaryKey(),
|
|
518
|
+
status: field.text().notNull(),
|
|
519
|
+
updatedAt: field.timestamp().notNull().now(),
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
export const db = store.sql("app", { schema: { tasks } });
|
|
523
|
+
export const member = gate.policy("member", { require: ["member"] });
|
|
524
|
+
|
|
525
|
+
export const live = on(
|
|
526
|
+
http.get("/tasks/live").gate(member).live(tasks),
|
|
527
|
+
flow("tasks.live", {
|
|
528
|
+
do: async () => ({ ok: true }),
|
|
529
|
+
}),
|
|
530
|
+
);
|
|
531
|
+
`;
|
|
532
|
+
const manifest = await extractFromSources({
|
|
533
|
+
"src/schema.decl.ts": source,
|
|
534
|
+
"src/flows/live.ts": source,
|
|
535
|
+
});
|
|
536
|
+
expect(manifest.flows?.["tasks.live"]).toBeDefined();
|
|
537
|
+
expect(manifest.stores?.app?.tables?.tasks?.columns?.id).toMatchObject({
|
|
538
|
+
primaryKey: true,
|
|
539
|
+
});
|
|
540
|
+
});
|
|
541
|
+
|
|
352
542
|
test("decimal head collapses to numeric in the manifest", async () => {
|
|
353
543
|
const source = `
|
|
354
544
|
import { store, field } from "okengine";
|
|
@@ -389,10 +579,7 @@ export const embeddings = store.index("embeddings", {
|
|
|
389
579
|
|
|
390
580
|
export const sessions = store.kv("sessions", { description: "Session cache" });
|
|
391
581
|
|
|
392
|
-
export const orderPlaced = signal("order-placed", {
|
|
393
|
-
delivery: "once",
|
|
394
|
-
description: "Order placed event",
|
|
395
|
-
});
|
|
582
|
+
export const orderPlaced = signal.once("order-placed", { description: "Order placed event" });
|
|
396
583
|
|
|
397
584
|
export const bookingConfirmed = channel.template("booking-confirmed", {
|
|
398
585
|
medium: "email",
|
|
@@ -438,11 +625,8 @@ export const stripeKey = vault.secret("STRIPE_KEY", {
|
|
|
438
625
|
const manifest = await extractFromSources({
|
|
439
626
|
"src/signals.ts": `
|
|
440
627
|
import { signal } from "okengine";
|
|
441
|
-
export const orderStatus = signal("order-status", {
|
|
442
|
-
|
|
443
|
-
optional: true,
|
|
444
|
-
retention: { maxAge: "24h", maxCount: 500 },
|
|
445
|
-
});
|
|
628
|
+
export const orderStatus = signal.live("order-status", { optional: true,
|
|
629
|
+
retention: { maxAge: "24h", maxCount: 500 } });
|
|
446
630
|
`,
|
|
447
631
|
});
|
|
448
632
|
expect(manifest.signals?.["order-status"]?.retention).toEqual({
|
|
@@ -802,9 +986,8 @@ export const tasksTable = store.schema.table(
|
|
|
802
986
|
);
|
|
803
987
|
|
|
804
988
|
export const tasksLive = on(
|
|
805
|
-
http.get("/tasks/live").gate(member).live(tasksTable),
|
|
989
|
+
http.get("/tasks/live", { in: { unknown: true } }).gate(member).live(tasksTable),
|
|
806
990
|
flow("tasks.live", {
|
|
807
|
-
in: { unknown: true },
|
|
808
991
|
do: async (_input, fx) => liveQuery(fx, tasksTable, _input),
|
|
809
992
|
}),
|
|
810
993
|
);
|
|
@@ -948,12 +1131,13 @@ export const attach = on(
|
|
|
948
1131
|
|
|
949
1132
|
test("fx.store(files).list(...) infers a read, unannotated", async () => {
|
|
950
1133
|
const source = `
|
|
951
|
-
import { on, flow,
|
|
1134
|
+
import { on, flow, clock, store } from "okengine";
|
|
952
1135
|
|
|
953
1136
|
export const files = store.files("uploads");
|
|
1137
|
+
export const sweepClock = clock("notes.sweep", { every: "1d" });
|
|
954
1138
|
|
|
955
1139
|
export const sweep = on(
|
|
956
|
-
|
|
1140
|
+
sweepClock,
|
|
957
1141
|
flow("notes.sweep", {
|
|
958
1142
|
do: async (_input, fx) => {
|
|
959
1143
|
const keys = await fx.store(files).list();
|
|
@@ -968,16 +1152,49 @@ export const sweep = on(
|
|
|
968
1152
|
});
|
|
969
1153
|
});
|
|
970
1154
|
|
|
1155
|
+
describe("extractManifest — clock convenience helpers", () => {
|
|
1156
|
+
test("daily / cron fields / every compile into clocks", async () => {
|
|
1157
|
+
const source = `
|
|
1158
|
+
import { clock } from "okengine";
|
|
1159
|
+
|
|
1160
|
+
export const daily = clock.daily("reports.daily", { at: "06:00", description: "Morning" });
|
|
1161
|
+
export const sweep = clock.cron("ops.sweep", {
|
|
1162
|
+
minute: "*/15",
|
|
1163
|
+
hour: [9, 12, 17],
|
|
1164
|
+
dayOfWeek: "1-5",
|
|
1165
|
+
overridable: true,
|
|
1166
|
+
});
|
|
1167
|
+
export const ping = clock.every("health.ping", "30s");
|
|
1168
|
+
export const nick = clock.cron("metrics.hourly", "@hourly");
|
|
1169
|
+
export const weekly = clock.weekly("digest", { on: ["mon", "fri"], at: "09:00" });
|
|
1170
|
+
`;
|
|
1171
|
+
const manifest = await extractFromSources({ "src/clocks.ts": source });
|
|
1172
|
+
|
|
1173
|
+
expect(manifest.clocks?.["reports.daily"]).toMatchObject({
|
|
1174
|
+
cron: "0 6 * * *",
|
|
1175
|
+
description: "Morning",
|
|
1176
|
+
});
|
|
1177
|
+
expect(manifest.clocks?.["ops.sweep"]).toMatchObject({
|
|
1178
|
+
cron: "*/15 9,12,17 * * 1-5",
|
|
1179
|
+
overridable: true,
|
|
1180
|
+
});
|
|
1181
|
+
expect(manifest.clocks?.["health.ping"]).toMatchObject({ every: "30s" });
|
|
1182
|
+
expect(manifest.clocks?.["metrics.hourly"]).toMatchObject({ cron: "@hourly" });
|
|
1183
|
+
expect(manifest.clocks?.digest).toMatchObject({ cron: "0 9 * * 1,5" });
|
|
1184
|
+
});
|
|
1185
|
+
});
|
|
1186
|
+
|
|
971
1187
|
describe("extractManifest — kv key methods", () => {
|
|
972
1188
|
test("fx.store(kv).delete(key) writes kv:<namespace>, not kv:<identifier>", async () => {
|
|
973
1189
|
const source = `
|
|
974
|
-
import { on, flow,
|
|
1190
|
+
import { on, flow, clock, store, signal } from "okengine";
|
|
975
1191
|
|
|
976
1192
|
export const draftsKv = store.kv("drafts");
|
|
977
|
-
export const draftExpired = signal("draft-expired", {
|
|
1193
|
+
export const draftExpired = signal.broadcast("draft-expired", { retries: 0, deadLetter: false });
|
|
1194
|
+
export const expireClock = clock("drafts.expire", { every: "10m" });
|
|
978
1195
|
|
|
979
1196
|
export const expire = on(
|
|
980
|
-
|
|
1197
|
+
expireClock,
|
|
981
1198
|
flow("drafts.expire", {
|
|
982
1199
|
do: async (_input, fx) => {
|
|
983
1200
|
const keys = await fx.store(draftsKv).list();
|
|
@@ -1005,7 +1222,7 @@ describe("extractManifest — fx.deadLetters", () => {
|
|
|
1005
1222
|
const source = `
|
|
1006
1223
|
import { on, flow, http, signal } from "okengine";
|
|
1007
1224
|
|
|
1008
|
-
export const notify = signal("notify"
|
|
1225
|
+
export const notify = signal.once("notify");
|
|
1009
1226
|
|
|
1010
1227
|
export const failed = on(
|
|
1011
1228
|
http.get("/notifications/failed").public(),
|
|
@@ -1026,9 +1243,7 @@ import { on, http, gate, signal } from "okengine";
|
|
|
1026
1243
|
import { z } from "zod";
|
|
1027
1244
|
|
|
1028
1245
|
export const member = gate.policy("member", ({ auth }) => !!auth.verified);
|
|
1029
|
-
export const orderStatus = signal("order-status", {
|
|
1030
|
-
delivery: "live",
|
|
1031
|
-
optional: true,
|
|
1246
|
+
export const orderStatus = signal.live("order-status", { optional: true,
|
|
1032
1247
|
schema: z.object({ orderId: z.string(), status: z.string() }),
|
|
1033
1248
|
});
|
|
1034
1249
|
|
|
@@ -1049,7 +1264,7 @@ export const events = on(http.get("/orders/:orderId/events").gate(member).live(o
|
|
|
1049
1264
|
import { on, http, gate, signal } from "okengine";
|
|
1050
1265
|
|
|
1051
1266
|
export const member = gate.policy("member", ({ auth }) => !!auth.verified);
|
|
1052
|
-
export const orderStatus = signal("order-status", {
|
|
1267
|
+
export const orderStatus = signal.live("order-status", { optional: true });
|
|
1053
1268
|
|
|
1054
1269
|
export const firehose = on(http.live(orderStatus).gate(member));
|
|
1055
1270
|
`;
|
|
@@ -1065,7 +1280,7 @@ export const firehose = on(http.live(orderStatus).gate(member));
|
|
|
1065
1280
|
const source = `
|
|
1066
1281
|
import { on, flow, http, signal } from "okengine";
|
|
1067
1282
|
|
|
1068
|
-
export const orderStatus = signal("order-status", {
|
|
1283
|
+
export const orderStatus = signal.live("order-status", { optional: true });
|
|
1069
1284
|
|
|
1070
1285
|
export const events = on(
|
|
1071
1286
|
http.get("/feed").public().live(orderStatus),
|
|
@@ -1130,12 +1345,12 @@ export const send = on(
|
|
|
1130
1345
|
});
|
|
1131
1346
|
});
|
|
1132
1347
|
|
|
1133
|
-
describe("extractManifest —
|
|
1134
|
-
test("bare
|
|
1348
|
+
describe("extractManifest — call(name, options) invoke contract", () => {
|
|
1349
|
+
test("bare call(name, {...}) extracts name, in, out, effects", async () => {
|
|
1135
1350
|
const source = `
|
|
1136
|
-
import {
|
|
1351
|
+
import { call } from "okengine";
|
|
1137
1352
|
|
|
1138
|
-
export const chargeOrder =
|
|
1353
|
+
export const chargeOrder = call("checkout.chargeOrder", {
|
|
1139
1354
|
in: ChargeIn,
|
|
1140
1355
|
out: ChargeOut,
|
|
1141
1356
|
effects: { reads: ["sql:orders"], writes: ["sql:orders"] },
|
|
@@ -1153,14 +1368,13 @@ export const chargeOrder = flow("checkout.chargeOrder", {
|
|
|
1153
1368
|
expect(manifest.flows?.["checkout.chargeOrder"]?.effects?.writes).toEqual(["sql:orders"]);
|
|
1154
1369
|
});
|
|
1155
1370
|
|
|
1156
|
-
test("on(trigger, flow(name, {...})) extracts
|
|
1371
|
+
test("on(trigger, flow(name, {...})) extracts HTTP contract from the trigger", async () => {
|
|
1157
1372
|
const source = `
|
|
1158
1373
|
import { on, http, flow } from "okengine";
|
|
1159
1374
|
|
|
1160
1375
|
export const getOrder = on(
|
|
1161
|
-
http.get("/orders/:id"),
|
|
1376
|
+
http.get("/orders/:id", { out: OrderOut }),
|
|
1162
1377
|
flow("checkout.getOrder", {
|
|
1163
|
-
out: OrderOut,
|
|
1164
1378
|
effects: { reads: ["sql:orders"] },
|
|
1165
1379
|
do: async (input, fx) => {
|
|
1166
1380
|
return { id: input.id };
|
|
@@ -1338,7 +1552,7 @@ export const ping = flow({ do: () => ({ ok: true }) });
|
|
|
1338
1552
|
import { on, flow, http, store, signal } from "okengine";
|
|
1339
1553
|
export const db = store.sql("db");
|
|
1340
1554
|
export const notes = { name: "notes" };
|
|
1341
|
-
export const noteCreated = signal("note-created");
|
|
1555
|
+
export const noteCreated = signal.once("note-created");
|
|
1342
1556
|
export const get = on(
|
|
1343
1557
|
http.get("/notes/:id").public(),
|
|
1344
1558
|
flow("notes.get", {
|
|
@@ -1350,7 +1564,7 @@ export const get = on(
|
|
|
1350
1564
|
import { on, flow, http, store, signal } from "okengine";
|
|
1351
1565
|
export const db = store.sql("db");
|
|
1352
1566
|
export const notes = { name: "notes" };
|
|
1353
|
-
export const noteCreated = signal("note-created");
|
|
1567
|
+
export const noteCreated = signal.once("note-created");
|
|
1354
1568
|
export const get = on(
|
|
1355
1569
|
http.get().public(),
|
|
1356
1570
|
flow({
|
|
@@ -1372,10 +1586,10 @@ export const get = on(
|
|
|
1372
1586
|
});
|
|
1373
1587
|
});
|
|
1374
1588
|
|
|
1375
|
-
describe("extractManifest —
|
|
1589
|
+
describe("extractManifest — invoke contract schema expansion", () => {
|
|
1376
1590
|
test("expands z.object identifiers into JSON Schema fields", async () => {
|
|
1377
1591
|
const source = `
|
|
1378
|
-
import {
|
|
1592
|
+
import { call } from "okengine";
|
|
1379
1593
|
import { z } from "zod";
|
|
1380
1594
|
|
|
1381
1595
|
export const TaskCreateIn = z.object({
|
|
@@ -1389,7 +1603,7 @@ export const TaskCreateOut = z.object({
|
|
|
1389
1603
|
identifier: z.string(),
|
|
1390
1604
|
});
|
|
1391
1605
|
|
|
1392
|
-
export const create =
|
|
1606
|
+
export const create = call("tasks.create", {
|
|
1393
1607
|
in: TaskCreateIn,
|
|
1394
1608
|
out: TaskCreateOut,
|
|
1395
1609
|
do: async () => ({ id: "1", identifier: "ENG-1" }),
|
|
@@ -1428,7 +1642,7 @@ export const users = store.schema.table("users", {
|
|
|
1428
1642
|
});
|
|
1429
1643
|
`;
|
|
1430
1644
|
const flows = `
|
|
1431
|
-
import {
|
|
1645
|
+
import { call } from "okengine";
|
|
1432
1646
|
import { createInsertSchema, createSelectSchema, createUpdateSchema } from "drizzle-orm/zod";
|
|
1433
1647
|
import { users } from "../schema.decl.ts";
|
|
1434
1648
|
|
|
@@ -1436,13 +1650,13 @@ export const userSelect = createSelectSchema(users);
|
|
|
1436
1650
|
export const userInsert = createInsertSchema(users);
|
|
1437
1651
|
export const userUpdate = createUpdateSchema(users);
|
|
1438
1652
|
|
|
1439
|
-
export const create =
|
|
1653
|
+
export const create = call("users.create", {
|
|
1440
1654
|
in: userInsert,
|
|
1441
1655
|
out: userSelect,
|
|
1442
1656
|
do: async () => ({}),
|
|
1443
1657
|
});
|
|
1444
1658
|
|
|
1445
|
-
export const patch =
|
|
1659
|
+
export const patch = call("users.patch", {
|
|
1446
1660
|
in: userUpdate,
|
|
1447
1661
|
do: async () => ({}),
|
|
1448
1662
|
});
|
|
@@ -1503,8 +1717,8 @@ export function tableZod(table) {
|
|
|
1503
1717
|
export const spacesZod = tableZod(spaces);
|
|
1504
1718
|
`;
|
|
1505
1719
|
const flows = `
|
|
1506
|
-
import {
|
|
1507
|
-
export const create =
|
|
1720
|
+
import { call } from "okengine";
|
|
1721
|
+
export const create = call("spaces.create", {
|
|
1508
1722
|
in: spacesZod.insert,
|
|
1509
1723
|
out: spacesZod.select.pick({ id: true, key: true }),
|
|
1510
1724
|
do: async () => ({}),
|
|
@@ -1580,19 +1794,19 @@ export const { list, create, get, update, remove } = bindCrud({
|
|
|
1580
1794
|
|
|
1581
1795
|
test("same-named createIn stays file-local (does not leak across units)", async () => {
|
|
1582
1796
|
const spaces = `
|
|
1583
|
-
import {
|
|
1797
|
+
import { call } from "okengine";
|
|
1584
1798
|
import { z } from "zod";
|
|
1585
1799
|
const createIn = z.object({ key: z.string(), name: z.string() });
|
|
1586
|
-
export const create =
|
|
1800
|
+
export const create = call("spaces.create", {
|
|
1587
1801
|
in: createIn,
|
|
1588
1802
|
do: async () => ({}),
|
|
1589
1803
|
});
|
|
1590
1804
|
`;
|
|
1591
1805
|
const views = `
|
|
1592
|
-
import {
|
|
1806
|
+
import { call } from "okengine";
|
|
1593
1807
|
import { z } from "zod";
|
|
1594
1808
|
const createIn = z.object({ kind: z.enum(["list", "board"]) });
|
|
1595
|
-
export const create =
|
|
1809
|
+
export const create = call("views.create", {
|
|
1596
1810
|
in: createIn,
|
|
1597
1811
|
do: async () => ({}),
|
|
1598
1812
|
});
|