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
|
@@ -3,9 +3,18 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Named clocks are reconciled into the Store at boot; the scheduler reads
|
|
5
5
|
* the effective state from the Store (console §5), never the code directly.
|
|
6
|
+
*
|
|
7
|
+
* Helpers (`clock.daily` · `cron` · `every` · …) compile to the same
|
|
8
|
+
* {@link ClockDecl} shape as `clock(name, { cron })`.
|
|
6
9
|
*/
|
|
7
10
|
|
|
8
11
|
import { clockRegistry } from "../../kernel/element-registries.ts";
|
|
12
|
+
import {
|
|
13
|
+
assertValidCronExpression,
|
|
14
|
+
buildCronExpression,
|
|
15
|
+
type CronField,
|
|
16
|
+
type CronFields,
|
|
17
|
+
} from "./cron-fields.ts";
|
|
9
18
|
|
|
10
19
|
/** Options for {@link clock}. */
|
|
11
20
|
export interface ClockOptions {
|
|
@@ -29,6 +38,51 @@ export interface ClockOptions {
|
|
|
29
38
|
readonly perTenant?: boolean;
|
|
30
39
|
}
|
|
31
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Shared options for convenience helpers (no `cron` / `every` — those are
|
|
43
|
+
* supplied by the helper).
|
|
44
|
+
*/
|
|
45
|
+
export type ClockHelperOptions = Omit<ClockOptions, "cron" | "every">;
|
|
46
|
+
|
|
47
|
+
/** Options for {@link clock.daily}. */
|
|
48
|
+
export type ClockDailyOptions = ClockHelperOptions & {
|
|
49
|
+
/** Wall-clock time (`"06:00"`). Default midnight. */
|
|
50
|
+
readonly at?: string;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/** Options for {@link clock.hourly}. */
|
|
54
|
+
export type ClockHourlyOptions = ClockHelperOptions & {
|
|
55
|
+
/** Minute of each hour (default `0`). */
|
|
56
|
+
readonly minute?: number;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/** Day-of-week token for {@link clock.weekly}. */
|
|
60
|
+
export type ClockWeekday = CronField;
|
|
61
|
+
|
|
62
|
+
/** Options for {@link clock.weekly}. */
|
|
63
|
+
export type ClockWeeklyOptions = ClockHelperOptions & {
|
|
64
|
+
/** Day(s) of week (`"mon"` · `1` · `["mon", "fri"]` · `"1-5"`). */
|
|
65
|
+
readonly on: ClockWeekday;
|
|
66
|
+
/** Wall-clock time (default `"00:00"`). */
|
|
67
|
+
readonly at?: string;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/** Options for {@link clock.monthly}. */
|
|
71
|
+
export type ClockMonthlyOptions = ClockHelperOptions & {
|
|
72
|
+
/** Day(s) of month (`1` · `[1, 15]`). */
|
|
73
|
+
readonly on: CronField;
|
|
74
|
+
/** Wall-clock time (default `"00:00"`). */
|
|
75
|
+
readonly at?: string;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Structured cron bag + shared helper options for {@link clock.cron}.
|
|
80
|
+
*
|
|
81
|
+
* Schedule keys (`minute` · `hour` · … · `at`) build the expression;
|
|
82
|
+
* remaining keys are {@link ClockHelperOptions}.
|
|
83
|
+
*/
|
|
84
|
+
export type ClockCronFieldsOptions = CronFields & ClockHelperOptions;
|
|
85
|
+
|
|
32
86
|
/**
|
|
33
87
|
* Declared clock handle — reconciled into `oke_crons` at boot.
|
|
34
88
|
*/
|
|
@@ -41,6 +95,13 @@ export interface ClockDecl {
|
|
|
41
95
|
readonly every?: string;
|
|
42
96
|
/** IANA timezone. */
|
|
43
97
|
readonly timezone: string;
|
|
98
|
+
/**
|
|
99
|
+
* When true, `timezone` was omitted at declare and may be replaced by
|
|
100
|
+
* `oke({ clock: { timezone } })` / `defineConfig({ clock: { timezone } })`.
|
|
101
|
+
*
|
|
102
|
+
* @internal
|
|
103
|
+
*/
|
|
104
|
+
readonly timezoneDefaulted?: boolean;
|
|
44
105
|
/** Whether Console override is allowed. */
|
|
45
106
|
readonly overridable: boolean;
|
|
46
107
|
/** Optional human description. */
|
|
@@ -80,11 +141,16 @@ function declareClock(name: string, options: ClockOptions = {}): ClockDecl {
|
|
|
80
141
|
if (!options.cron && !options.every) {
|
|
81
142
|
throw new TypeError(`clock("${name}"): require cron or every`);
|
|
82
143
|
}
|
|
144
|
+
if (options.cron) {
|
|
145
|
+
assertValidCronExpression(options.cron, `clock("${name}")`);
|
|
146
|
+
}
|
|
147
|
+
const timezoneDefaulted = options.timezone === undefined;
|
|
83
148
|
const decl: ClockDecl = {
|
|
84
149
|
name,
|
|
85
150
|
cron: options.cron,
|
|
86
151
|
every: options.every,
|
|
87
152
|
timezone: options.timezone ?? "UTC",
|
|
153
|
+
...(timezoneDefaulted ? { timezoneDefaulted: true } : {}),
|
|
88
154
|
overridable: options.overridable ?? false,
|
|
89
155
|
...(options.description !== undefined ? { description: options.description } : {}),
|
|
90
156
|
...(options.perTenant === true ? { perTenant: true } : {}),
|
|
@@ -93,6 +159,35 @@ function declareClock(name: string, options: ClockOptions = {}): ClockDecl {
|
|
|
93
159
|
return decl;
|
|
94
160
|
}
|
|
95
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Apply an app-wide default timezone to clocks that omitted `timezone`.
|
|
164
|
+
*
|
|
165
|
+
* Explicit `timezone: "…"` on a declaration always wins. When `defaultTimezone`
|
|
166
|
+
* is omitted / empty, defaulted clocks stay on `"UTC"`.
|
|
167
|
+
*
|
|
168
|
+
* @param decls - Declared clocks
|
|
169
|
+
* @param defaultTimezone - IANA zone from `oke({ clock })` / config
|
|
170
|
+
*/
|
|
171
|
+
export function applyClockTimezoneDefaults(
|
|
172
|
+
decls: readonly ClockDecl[],
|
|
173
|
+
defaultTimezone: string | undefined,
|
|
174
|
+
): ClockDecl[] {
|
|
175
|
+
const zone = defaultTimezone?.trim();
|
|
176
|
+
if (!zone) return decls.slice();
|
|
177
|
+
return decls.map((d) => {
|
|
178
|
+
if (!d.timezoneDefaulted) return d;
|
|
179
|
+
return {
|
|
180
|
+
name: d.name,
|
|
181
|
+
...(d.cron !== undefined ? { cron: d.cron } : {}),
|
|
182
|
+
...(d.every !== undefined ? { every: d.every } : {}),
|
|
183
|
+
timezone: zone,
|
|
184
|
+
overridable: d.overridable,
|
|
185
|
+
...(d.description !== undefined ? { description: d.description } : {}),
|
|
186
|
+
...(d.perTenant === true ? { perTenant: true } : {}),
|
|
187
|
+
};
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
96
191
|
/**
|
|
97
192
|
* Per-tenant schedule template — one `oke_crons` row per tenant.
|
|
98
193
|
*
|
|
@@ -103,6 +198,134 @@ function declarePerTenantClock(name: string, options: ClockOptions = {}): ClockD
|
|
|
103
198
|
return declareClock(name, { ...options, perTenant: true });
|
|
104
199
|
}
|
|
105
200
|
|
|
201
|
+
/**
|
|
202
|
+
* Interval helper — `clock.every("health.ping", "30s")`.
|
|
203
|
+
*
|
|
204
|
+
* @param name - Schedule name
|
|
205
|
+
* @param duration - Interval (`"30s"`, `"1h"`, …)
|
|
206
|
+
* @param options - Timezone / overridable / description / perTenant
|
|
207
|
+
*/
|
|
208
|
+
function declareEveryClock(
|
|
209
|
+
name: string,
|
|
210
|
+
duration: string,
|
|
211
|
+
options: ClockHelperOptions = {},
|
|
212
|
+
): ClockDecl {
|
|
213
|
+
return declareClock(name, { ...options, every: duration });
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Split structured cron fields from shared helper options.
|
|
218
|
+
*
|
|
219
|
+
* @param bag - Mixed `CronFields` + `ClockHelperOptions`
|
|
220
|
+
*/
|
|
221
|
+
function splitCronBag(bag: ClockCronFieldsOptions): {
|
|
222
|
+
readonly fields: CronFields;
|
|
223
|
+
readonly opts: ClockHelperOptions;
|
|
224
|
+
} {
|
|
225
|
+
const {
|
|
226
|
+
minute,
|
|
227
|
+
hour,
|
|
228
|
+
dayOfMonth,
|
|
229
|
+
month,
|
|
230
|
+
dayOfWeek,
|
|
231
|
+
at,
|
|
232
|
+
timezone,
|
|
233
|
+
overridable,
|
|
234
|
+
description,
|
|
235
|
+
perTenant,
|
|
236
|
+
} = bag;
|
|
237
|
+
return {
|
|
238
|
+
fields: {
|
|
239
|
+
...(minute !== undefined ? { minute } : {}),
|
|
240
|
+
...(hour !== undefined ? { hour } : {}),
|
|
241
|
+
...(dayOfMonth !== undefined ? { dayOfMonth } : {}),
|
|
242
|
+
...(month !== undefined ? { month } : {}),
|
|
243
|
+
...(dayOfWeek !== undefined ? { dayOfWeek } : {}),
|
|
244
|
+
...(at !== undefined ? { at } : {}),
|
|
245
|
+
},
|
|
246
|
+
opts: {
|
|
247
|
+
...(timezone !== undefined ? { timezone } : {}),
|
|
248
|
+
...(overridable !== undefined ? { overridable } : {}),
|
|
249
|
+
...(description !== undefined ? { description } : {}),
|
|
250
|
+
...(perTenant !== undefined ? { perTenant } : {}),
|
|
251
|
+
},
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Cron helper — string expression or structured fields.
|
|
257
|
+
*
|
|
258
|
+
* @param name - Schedule name
|
|
259
|
+
* @param expressionOrFields - Five-field / nickname string, or field bag
|
|
260
|
+
* @param options - Shared options when the second arg is a string
|
|
261
|
+
*/
|
|
262
|
+
function declareCronClock(
|
|
263
|
+
name: string,
|
|
264
|
+
expressionOrFields: string | ClockCronFieldsOptions,
|
|
265
|
+
options: ClockHelperOptions = {},
|
|
266
|
+
): ClockDecl {
|
|
267
|
+
if (typeof expressionOrFields === "string") {
|
|
268
|
+
return declareClock(name, { ...options, cron: expressionOrFields });
|
|
269
|
+
}
|
|
270
|
+
const { fields, opts } = splitCronBag(expressionOrFields);
|
|
271
|
+
const cron = buildCronExpression(fields);
|
|
272
|
+
return declareClock(name, { ...opts, cron });
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Daily preset — midnight unless `at` is set.
|
|
277
|
+
*
|
|
278
|
+
* @param name - Schedule name
|
|
279
|
+
* @param options - `at` + shared options
|
|
280
|
+
*/
|
|
281
|
+
function declareDailyClock(name: string, options: ClockDailyOptions = {}): ClockDecl {
|
|
282
|
+
const { at, ...opts } = options;
|
|
283
|
+
const cron = buildCronExpression({ at: at ?? "00:00" });
|
|
284
|
+
return declareClock(name, { ...opts, cron });
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Hourly preset — top of the hour unless `minute` is set.
|
|
289
|
+
*
|
|
290
|
+
* @param name - Schedule name
|
|
291
|
+
* @param options - `minute` + shared options
|
|
292
|
+
*/
|
|
293
|
+
function declareHourlyClock(name: string, options: ClockHourlyOptions = {}): ClockDecl {
|
|
294
|
+
const { minute, ...opts } = options;
|
|
295
|
+
const cron = buildCronExpression({ minute: minute ?? 0 });
|
|
296
|
+
return declareClock(name, { ...opts, cron });
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Weekly / multi-weekday preset.
|
|
301
|
+
*
|
|
302
|
+
* @param name - Schedule name
|
|
303
|
+
* @param options - `on` (required) + optional `at`
|
|
304
|
+
*/
|
|
305
|
+
function declareWeeklyClock(name: string, options: ClockWeeklyOptions): ClockDecl {
|
|
306
|
+
const { on, at, ...opts } = options;
|
|
307
|
+
const cron = buildCronExpression({
|
|
308
|
+
at: at ?? "00:00",
|
|
309
|
+
dayOfWeek: on,
|
|
310
|
+
});
|
|
311
|
+
return declareClock(name, { ...opts, cron });
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Monthly / multi-DOM preset.
|
|
316
|
+
*
|
|
317
|
+
* @param name - Schedule name
|
|
318
|
+
* @param options - `on` (required) + optional `at`
|
|
319
|
+
*/
|
|
320
|
+
function declareMonthlyClock(name: string, options: ClockMonthlyOptions): ClockDecl {
|
|
321
|
+
const { on, at, ...opts } = options;
|
|
322
|
+
const cron = buildCronExpression({
|
|
323
|
+
at: at ?? "00:00",
|
|
324
|
+
dayOfMonth: on,
|
|
325
|
+
});
|
|
326
|
+
return declareClock(name, { ...opts, cron });
|
|
327
|
+
}
|
|
328
|
+
|
|
106
329
|
/**
|
|
107
330
|
* Separator between a per-tenant template name and the tenant id.
|
|
108
331
|
*/
|
|
@@ -137,12 +360,33 @@ export function parsePerTenantCronName(
|
|
|
137
360
|
return { template, tenantId };
|
|
138
361
|
}
|
|
139
362
|
|
|
363
|
+
/** Public Clock declaration namespace — callable + convenience helpers. */
|
|
364
|
+
export interface ClockNamespace {
|
|
365
|
+
(name: string, options?: ClockOptions): ClockDecl;
|
|
366
|
+
readonly perTenant: typeof declarePerTenantClock;
|
|
367
|
+
readonly every: typeof declareEveryClock;
|
|
368
|
+
readonly cron: typeof declareCronClock;
|
|
369
|
+
readonly daily: typeof declareDailyClock;
|
|
370
|
+
readonly hourly: typeof declareHourlyClock;
|
|
371
|
+
readonly weekly: typeof declareWeeklyClock;
|
|
372
|
+
readonly monthly: typeof declareMonthlyClock;
|
|
373
|
+
}
|
|
374
|
+
|
|
140
375
|
/**
|
|
141
376
|
* Declare a named clock / cron schedule.
|
|
142
377
|
*
|
|
378
|
+
* Helpers: `clock.every` · `clock.cron` · `clock.daily` · `clock.hourly` ·
|
|
379
|
+
* `clock.weekly` · `clock.monthly` · `clock.perTenant`.
|
|
380
|
+
*
|
|
143
381
|
* @param name - Schedule name
|
|
144
382
|
* @param options - `cron` and/or `every`, timezone, overridable
|
|
145
383
|
*/
|
|
146
|
-
export const clock: (
|
|
147
|
-
|
|
148
|
-
|
|
384
|
+
export const clock: ClockNamespace = Object.assign(declareClock, {
|
|
385
|
+
perTenant: declarePerTenantClock,
|
|
386
|
+
every: declareEveryClock,
|
|
387
|
+
cron: declareCronClock,
|
|
388
|
+
daily: declareDailyClock,
|
|
389
|
+
hourly: declareHourlyClock,
|
|
390
|
+
weekly: declareWeeklyClock,
|
|
391
|
+
monthly: declareMonthlyClock,
|
|
392
|
+
});
|
package/src/elements/clock.ts
CHANGED
|
@@ -14,9 +14,29 @@ export {
|
|
|
14
14
|
clock,
|
|
15
15
|
perTenantCronName,
|
|
16
16
|
parsePerTenantCronName,
|
|
17
|
+
applyClockTimezoneDefaults,
|
|
17
18
|
PER_TENANT_CRON_SEP,
|
|
18
19
|
} from "./clock/declare.ts";
|
|
19
|
-
export type {
|
|
20
|
+
export type {
|
|
21
|
+
ClockDecl,
|
|
22
|
+
ClockOptions,
|
|
23
|
+
ClockHelperOptions,
|
|
24
|
+
ClockDailyOptions,
|
|
25
|
+
ClockHourlyOptions,
|
|
26
|
+
ClockWeeklyOptions,
|
|
27
|
+
ClockMonthlyOptions,
|
|
28
|
+
ClockCronFieldsOptions,
|
|
29
|
+
ClockWeekday,
|
|
30
|
+
ClockNamespace,
|
|
31
|
+
} from "./clock/declare.ts";
|
|
32
|
+
|
|
33
|
+
export {
|
|
34
|
+
buildCronExpression,
|
|
35
|
+
parseAtTime,
|
|
36
|
+
serializeCronField,
|
|
37
|
+
assertValidCronExpression,
|
|
38
|
+
} from "./clock/cron-fields.ts";
|
|
39
|
+
export type { CronField, CronFields } from "./clock/cron-fields.ts";
|
|
20
40
|
|
|
21
41
|
export { parseDurationMs } from "./clock/duration.ts";
|
|
22
42
|
|
package/src/elements/index.ts
CHANGED
|
@@ -43,7 +43,11 @@ export type {
|
|
|
43
43
|
export { signal, createSignalRuntime } from "./signal.ts";
|
|
44
44
|
export type {
|
|
45
45
|
SignalDecl,
|
|
46
|
+
SignalLiveOptions,
|
|
47
|
+
SignalNamespace,
|
|
46
48
|
SignalOptions,
|
|
49
|
+
SignalRetention,
|
|
50
|
+
SignalSharedOptions,
|
|
47
51
|
SignalRuntime,
|
|
48
52
|
CreateSignalRuntimeOptions,
|
|
49
53
|
} from "./signal.ts";
|
|
@@ -59,6 +63,17 @@ export {
|
|
|
59
63
|
parseDurationMs,
|
|
60
64
|
} from "./clock.ts";
|
|
61
65
|
export type { ClockDecl, ClockOptions, ClockRuntime, TimeTravel, DurableResult } from "./clock.ts";
|
|
66
|
+
export type {
|
|
67
|
+
ClockHelperOptions,
|
|
68
|
+
ClockDailyOptions,
|
|
69
|
+
ClockHourlyOptions,
|
|
70
|
+
ClockWeeklyOptions,
|
|
71
|
+
ClockMonthlyOptions,
|
|
72
|
+
ClockCronFieldsOptions,
|
|
73
|
+
ClockNamespace,
|
|
74
|
+
CronField,
|
|
75
|
+
CronFields,
|
|
76
|
+
} from "./clock.ts";
|
|
62
77
|
|
|
63
78
|
export {
|
|
64
79
|
gate,
|
|
@@ -26,8 +26,7 @@ if (!durablePath) {
|
|
|
26
26
|
process.exit(2);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
const orderPlaced = signal("order-placed", {
|
|
30
|
-
delivery: "once",
|
|
29
|
+
const orderPlaced = signal.once("order-placed", {
|
|
31
30
|
retries: 3,
|
|
32
31
|
deadLetter: true,
|
|
33
32
|
// Producer-only / cross-process consumer: no local subscriber at emit time.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Signal declaration — data in motion.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Delivery physics are chosen by helper name (`signal.once` / `broadcast` /
|
|
5
|
+
* `live`), matching `http.get` / `http.post` — no default, no options bag for mode.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { SignalDelivery } from "../../manifest/types.ts";
|
|
@@ -17,8 +17,8 @@ export interface SignalRetention {
|
|
|
17
17
|
readonly maxCount?: number;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
/** Shared options for every {@link signal} delivery
|
|
21
|
-
interface
|
|
20
|
+
/** Shared options for every {@link signal} delivery helper. */
|
|
21
|
+
export interface SignalSharedOptions {
|
|
22
22
|
/** Optional human description for Console / docs (falls back to the signal name). */
|
|
23
23
|
readonly description?: string;
|
|
24
24
|
/** Max delivery attempts before dead-letter (once). */
|
|
@@ -34,20 +34,16 @@ interface SignalOptionsBase {
|
|
|
34
34
|
readonly optional?: boolean;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
/** Options for {@link signal.live} — shared fields plus optional tape retention. */
|
|
38
|
+
export type SignalLiveOptions = SignalSharedOptions & {
|
|
39
|
+
readonly retention?: SignalRetention;
|
|
40
|
+
};
|
|
41
|
+
|
|
37
42
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* `retention` is live-only — a type error on `once` / `broadcast`.
|
|
43
|
+
* @deprecated Prefer {@link SignalSharedOptions} / {@link SignalLiveOptions}.
|
|
44
|
+
* Alias kept for type-only imports that still name `SignalOptions`.
|
|
41
45
|
*/
|
|
42
|
-
export type SignalOptions =
|
|
43
|
-
| (SignalOptionsBase & {
|
|
44
|
-
readonly delivery: "once" | "broadcast";
|
|
45
|
-
readonly retention?: never;
|
|
46
|
-
})
|
|
47
|
-
| (SignalOptionsBase & {
|
|
48
|
-
readonly delivery: "live";
|
|
49
|
-
readonly retention?: SignalRetention;
|
|
50
|
-
});
|
|
46
|
+
export type SignalOptions = SignalSharedOptions | SignalLiveOptions;
|
|
51
47
|
|
|
52
48
|
/**
|
|
53
49
|
* Declared signal handle — usable as `on(signal, flow)`, `fx.emit(signal, …)`,
|
|
@@ -74,8 +70,33 @@ export interface SignalDecl<T = unknown> {
|
|
|
74
70
|
readonly _payload?: T;
|
|
75
71
|
}
|
|
76
72
|
|
|
73
|
+
/** Public Signal declaration namespace — `signal.once` / `broadcast` / `live`. */
|
|
74
|
+
export interface SignalNamespace {
|
|
75
|
+
/**
|
|
76
|
+
* Competing queue — exactly one subscriber claims each message.
|
|
77
|
+
*
|
|
78
|
+
* @param name - Signal name
|
|
79
|
+
* @param options - Retry / DLQ / schema policy
|
|
80
|
+
*/
|
|
81
|
+
once<T = unknown>(name: string, options?: SignalSharedOptions): SignalDecl<T>;
|
|
82
|
+
/**
|
|
83
|
+
* Pub/sub fan-out — every subscriber receives each message.
|
|
84
|
+
*
|
|
85
|
+
* @param name - Signal name
|
|
86
|
+
* @param options - Schema / optional policy
|
|
87
|
+
*/
|
|
88
|
+
broadcast<T = unknown>(name: string, options?: SignalSharedOptions): SignalDecl<T>;
|
|
89
|
+
/**
|
|
90
|
+
* Live SSE tape — retained stream for `http.live` / `.live(signal)`.
|
|
91
|
+
*
|
|
92
|
+
* @param name - Signal name
|
|
93
|
+
* @param options - Retention / schema / optional policy
|
|
94
|
+
*/
|
|
95
|
+
live<T = unknown>(name: string, options?: SignalLiveOptions): SignalDecl<T>;
|
|
96
|
+
}
|
|
97
|
+
|
|
77
98
|
/**
|
|
78
|
-
* `signal
|
|
99
|
+
* `signal.*` pushes into the shared {@link signalRegistry}
|
|
79
100
|
* (`src/kernel/element-registries.ts`) so {@link oke} can auto-populate
|
|
80
101
|
* `signals` with zero explicit array — mirrors the {@link on} trigger-drain
|
|
81
102
|
* registry (`src/kernel/on.ts`).
|
|
@@ -95,45 +116,52 @@ export function resetSignals(): void {
|
|
|
95
116
|
signalRegistry.length = 0;
|
|
96
117
|
}
|
|
97
118
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
*/
|
|
104
|
-
export function signal<T = unknown>(name: string, options: SignalOptions): SignalDecl<T> {
|
|
105
|
-
if (
|
|
106
|
-
options.delivery !== "once" &&
|
|
107
|
-
options.delivery !== "broadcast" &&
|
|
108
|
-
options.delivery !== "live"
|
|
109
|
-
) {
|
|
110
|
-
throw new TypeError(`signal("${name}"): delivery is mandatory (once | broadcast | live)`);
|
|
111
|
-
}
|
|
119
|
+
function declareSignal<T = unknown>(
|
|
120
|
+
name: string,
|
|
121
|
+
delivery: SignalDelivery,
|
|
122
|
+
options: SignalSharedOptions | SignalLiveOptions = {},
|
|
123
|
+
): SignalDecl<T> {
|
|
112
124
|
const retention = "retention" in options ? options.retention : undefined;
|
|
113
|
-
if (retention !== undefined &&
|
|
114
|
-
throw new TypeError(`signal("${name}"): retention is only valid with
|
|
125
|
+
if (retention !== undefined && delivery !== "live") {
|
|
126
|
+
throw new TypeError(`signal.${delivery}("${name}"): retention is only valid with signal.live`);
|
|
115
127
|
}
|
|
116
128
|
if (retention?.maxAge !== undefined && parseDurationMs(retention.maxAge) <= 0) {
|
|
117
129
|
throw new TypeError(
|
|
118
|
-
`signal("${name}"): retention.maxAge must be a duration like "24h" or "30s"`,
|
|
130
|
+
`signal.live("${name}"): retention.maxAge must be a duration like "24h" or "30s"`,
|
|
119
131
|
);
|
|
120
132
|
}
|
|
121
133
|
if (
|
|
122
134
|
retention?.maxCount !== undefined &&
|
|
123
135
|
(!Number.isInteger(retention.maxCount) || retention.maxCount < 1)
|
|
124
136
|
) {
|
|
125
|
-
throw new TypeError(`signal("${name}"): retention.maxCount must be an integer ≥ 1`);
|
|
137
|
+
throw new TypeError(`signal.live("${name}"): retention.maxCount must be an integer ≥ 1`);
|
|
126
138
|
}
|
|
127
139
|
const decl: SignalDecl<T> = {
|
|
128
140
|
name,
|
|
129
|
-
delivery
|
|
141
|
+
delivery,
|
|
130
142
|
...(options.description !== undefined ? { description: options.description } : {}),
|
|
131
143
|
retries: options.retries ?? 3,
|
|
132
144
|
deadLetter: options.deadLetter ?? true,
|
|
133
145
|
schema: options.schema,
|
|
134
146
|
optional: options.optional ?? false,
|
|
135
|
-
...(
|
|
147
|
+
...(delivery === "live" && retention !== undefined ? { retention } : {}),
|
|
136
148
|
};
|
|
137
149
|
signalRegistry.push(decl as SignalDecl);
|
|
138
150
|
return decl;
|
|
139
151
|
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Declare a signal. Delivery physics are chosen by helper name —
|
|
155
|
+
* `signal.once` · `signal.broadcast` · `signal.live`.
|
|
156
|
+
*/
|
|
157
|
+
export const signal: SignalNamespace = {
|
|
158
|
+
once<T = unknown>(name: string, options?: SignalSharedOptions): SignalDecl<T> {
|
|
159
|
+
return declareSignal(name, "once", options);
|
|
160
|
+
},
|
|
161
|
+
broadcast<T = unknown>(name: string, options?: SignalSharedOptions): SignalDecl<T> {
|
|
162
|
+
return declareSignal(name, "broadcast", options);
|
|
163
|
+
},
|
|
164
|
+
live<T = unknown>(name: string, options?: SignalLiveOptions): SignalDecl<T> {
|
|
165
|
+
return declareSignal(name, "live", options);
|
|
166
|
+
},
|
|
167
|
+
};
|
|
@@ -90,11 +90,7 @@ for (const { label, driver, setup } of drivers) {
|
|
|
90
90
|
describe(`signal delivery modes · ${label}`, () => {
|
|
91
91
|
test("once: one message reaches exactly one of two competing consumers", async () => {
|
|
92
92
|
// Shape matches Linkly linkClicked / Provisions order-placed.
|
|
93
|
-
const once = signal("link-clicked", {
|
|
94
|
-
delivery: "once",
|
|
95
|
-
retries: 3,
|
|
96
|
-
deadLetter: true,
|
|
97
|
-
});
|
|
93
|
+
const once = signal.once("link-clicked", { retries: 3, deadLetter: true });
|
|
98
94
|
const bus = await openBus(driver, [once], setup?.() ?? {});
|
|
99
95
|
const got: string[] = [];
|
|
100
96
|
|
|
@@ -113,11 +109,7 @@ for (const { label, driver, setup } of drivers) {
|
|
|
113
109
|
});
|
|
114
110
|
|
|
115
111
|
test("once: retries+1 attempts then dead-letter when deadLetter: true", async () => {
|
|
116
|
-
const once = signal("flaky", {
|
|
117
|
-
delivery: "once",
|
|
118
|
-
retries: 2,
|
|
119
|
-
deadLetter: true,
|
|
120
|
-
});
|
|
112
|
+
const once = signal.once("flaky", { retries: 2, deadLetter: true });
|
|
121
113
|
const bus = await openBus(driver, [once], setup?.() ?? {});
|
|
122
114
|
let attempts = 0;
|
|
123
115
|
await bus.subscribe("flaky", "c1", async () => {
|
|
@@ -136,11 +128,7 @@ for (const { label, driver, setup } of drivers) {
|
|
|
136
128
|
});
|
|
137
129
|
|
|
138
130
|
test("once: deadLetter: false marks delivered after exhausting retries", async () => {
|
|
139
|
-
const once = signal("flaky-drop", {
|
|
140
|
-
delivery: "once",
|
|
141
|
-
retries: 1,
|
|
142
|
-
deadLetter: false,
|
|
143
|
-
});
|
|
131
|
+
const once = signal.once("flaky-drop", { retries: 1, deadLetter: false });
|
|
144
132
|
const bus = await openBus(driver, [once], setup?.() ?? {});
|
|
145
133
|
let attempts = 0;
|
|
146
134
|
await bus.subscribe("flaky-drop", "c1", async () => {
|
|
@@ -159,7 +147,7 @@ for (const { label, driver, setup } of drivers) {
|
|
|
159
147
|
});
|
|
160
148
|
|
|
161
149
|
test("broadcast: every subscriber receives its own copy", async () => {
|
|
162
|
-
const bcast = signal("news"
|
|
150
|
+
const bcast = signal.broadcast("news");
|
|
163
151
|
const bus = await openBus(driver, [bcast], setup?.() ?? {});
|
|
164
152
|
const a: unknown[] = [];
|
|
165
153
|
const b: unknown[] = [];
|
|
@@ -179,7 +167,7 @@ for (const { label, driver, setup } of drivers) {
|
|
|
179
167
|
|
|
180
168
|
test("live: late subscriber replays full retained history (unbounded)", async () => {
|
|
181
169
|
// Shape matches Skyport seat-feed.
|
|
182
|
-
const live = signal("seat-feed", {
|
|
170
|
+
const live = signal.live("seat-feed", { optional: true });
|
|
183
171
|
const bus = await openBus(driver, [live], setup?.() ?? {});
|
|
184
172
|
|
|
185
173
|
await bus.emit("seat-feed", { seat: "12A" });
|
|
@@ -194,11 +182,7 @@ for (const { label, driver, setup } of drivers) {
|
|
|
194
182
|
});
|
|
195
183
|
|
|
196
184
|
test("live: maxCount keeps the newest N", async () => {
|
|
197
|
-
const live = signal("seat-feed", {
|
|
198
|
-
delivery: "live",
|
|
199
|
-
optional: true,
|
|
200
|
-
retention: { maxCount: 2 },
|
|
201
|
-
});
|
|
185
|
+
const live = signal.live("seat-feed", { optional: true, retention: { maxCount: 2 } });
|
|
202
186
|
const bus = await openBus(driver, [live], setup?.() ?? {});
|
|
203
187
|
|
|
204
188
|
for (const seat of ["12A", "12B", "12C", "12D", "12E"]) {
|
|
@@ -212,11 +196,7 @@ for (const { label, driver, setup } of drivers) {
|
|
|
212
196
|
|
|
213
197
|
test("live: maxAge prunes on emit and on live() open", async () => {
|
|
214
198
|
let t = 1_000;
|
|
215
|
-
const live = signal("seat-feed", {
|
|
216
|
-
delivery: "live",
|
|
217
|
-
optional: true,
|
|
218
|
-
retention: { maxAge: "1s" },
|
|
219
|
-
});
|
|
199
|
+
const live = signal.live("seat-feed", { optional: true, retention: { maxAge: "1s" } });
|
|
220
200
|
const bus = await openBus(driver, [live], { now: () => t, ...(setup?.() ?? {}) });
|
|
221
201
|
|
|
222
202
|
await bus.emit("seat-feed", { seat: "old" });
|
|
@@ -230,7 +210,7 @@ for (const { label, driver, setup } of drivers) {
|
|
|
230
210
|
});
|
|
231
211
|
|
|
232
212
|
test("live: afterId skips already-delivered events", async () => {
|
|
233
|
-
const live = signal("seat-feed", {
|
|
213
|
+
const live = signal.live("seat-feed", { optional: true });
|
|
234
214
|
const bus = await openBus(driver, [live], setup?.() ?? {});
|
|
235
215
|
|
|
236
216
|
await bus.emit("seat-feed", { seat: "12A" });
|
|
@@ -248,15 +228,15 @@ for (const { label, driver, setup } of drivers) {
|
|
|
248
228
|
expect(rest.map((e) => e.payload)).toEqual([{ seat: "12B" }, { seat: "12C" }]);
|
|
249
229
|
});
|
|
250
230
|
|
|
251
|
-
test("live: unknown afterId throws
|
|
252
|
-
const live = signal("seat-feed", {
|
|
231
|
+
test("live: unknown afterId throws OKE1210", async () => {
|
|
232
|
+
const live = signal.live("seat-feed", { optional: true });
|
|
253
233
|
const bus = await openBus(driver, [live], setup?.() ?? {});
|
|
254
234
|
await bus.emit("seat-feed", { seat: "12A" });
|
|
255
235
|
await bus.drain();
|
|
256
236
|
|
|
257
237
|
const it = bus.live("seat-feed", { afterId: "missing" })[Symbol.asyncIterator]();
|
|
258
238
|
try {
|
|
259
|
-
await expect(it.next()).rejects.toMatchObject({ code:
|
|
239
|
+
await expect(it.next()).rejects.toMatchObject({ code: 1210 });
|
|
260
240
|
} finally {
|
|
261
241
|
await it.return?.();
|
|
262
242
|
}
|
|
@@ -23,13 +23,7 @@ describe("signal dry-run replay — external effects stubbed", () => {
|
|
|
23
23
|
} as unknown as ChannelRuntime;
|
|
24
24
|
|
|
25
25
|
const runtime = createSignalRuntime({ driver: memorySignalDriver });
|
|
26
|
-
runtime.register(
|
|
27
|
-
signal("order-placed", {
|
|
28
|
-
delivery: "once",
|
|
29
|
-
retries: 0,
|
|
30
|
-
deadLetter: true,
|
|
31
|
-
}),
|
|
32
|
-
);
|
|
26
|
+
runtime.register(signal.once("order-placed", { retries: 0, deadLetter: true }));
|
|
33
27
|
const bus = await runtime.start();
|
|
34
28
|
|
|
35
29
|
// Seed DLQ with a failing consumer, then replace with a send consumer.
|
|
@@ -18,13 +18,7 @@ describe("signal dry-run replay — write isolation", () => {
|
|
|
18
18
|
const before = structuredClone(stockRow);
|
|
19
19
|
|
|
20
20
|
const runtime = createSignalRuntime({ driver: memorySignalDriver });
|
|
21
|
-
runtime.register(
|
|
22
|
-
signal("order-placed", {
|
|
23
|
-
delivery: "once",
|
|
24
|
-
retries: 0,
|
|
25
|
-
deadLetter: true,
|
|
26
|
-
}),
|
|
27
|
-
);
|
|
21
|
+
runtime.register(signal.once("order-placed", { retries: 0, deadLetter: true }));
|
|
28
22
|
const bus = await runtime.start();
|
|
29
23
|
|
|
30
24
|
const unsubFail = await bus.subscribe("order-placed", "flaky", async () => {
|