okengine 0.18.4 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +18 -10
- package/README.md +2 -2
- package/package.json +51 -50
- package/site/content/docs/ai/index.mdx +25 -6
- package/site/content/docs/ai/llms-txt.mdx +1 -1
- package/site/content/docs/ai/meta.json +1 -1
- package/site/content/docs/ai/skills.mdx +4 -1
- package/site/content/docs/ai/try-it.mdx +58 -0
- package/site/content/docs/client/auth.mdx +208 -0
- package/site/content/docs/client/calling.mdx +451 -0
- package/site/content/docs/client/index.mdx +209 -0
- package/site/content/docs/client/live.mdx +234 -0
- package/site/content/docs/client/meta.json +5 -0
- package/site/content/docs/client/react.mdx +249 -0
- package/site/content/docs/elements/ai/agents.mdx +232 -0
- package/site/content/docs/elements/ai/index.mdx +341 -0
- package/site/content/docs/elements/ai/mcp.mdx +275 -0
- package/site/content/docs/elements/ai/meta.json +5 -0
- package/site/content/docs/elements/ai/models.mdx +283 -0
- package/site/content/docs/elements/ai/prompts.mdx +256 -0
- package/site/content/docs/elements/channel/email.mdx +266 -0
- package/site/content/docs/elements/channel/index.mdx +344 -0
- package/site/content/docs/elements/channel/meta.json +5 -0
- package/site/content/docs/elements/channel/push.mdx +218 -0
- package/site/content/docs/elements/channel/receipts.mdx +206 -0
- package/site/content/docs/elements/channel/sms.mdx +264 -0
- package/site/content/docs/elements/channel/whatsapp.mdx +220 -0
- package/site/content/docs/elements/clock/index.mdx +300 -0
- package/site/content/docs/elements/clock/meta.json +5 -0
- package/site/content/docs/elements/clock/schedules.mdx +508 -0
- package/site/content/docs/elements/clock/sleep.mdx +445 -0
- package/site/content/docs/elements/flow/consumers.mdx +707 -0
- package/site/content/docs/elements/flow/http.mdx +1080 -0
- package/site/content/docs/elements/flow/index.mdx +618 -0
- package/site/content/docs/elements/flow/meta.json +5 -0
- package/site/content/docs/elements/flow/routing.mdx +559 -0
- package/site/content/docs/elements/flow/workflows.mdx +640 -0
- package/site/content/docs/elements/gate/auth.mdx +371 -0
- package/site/content/docs/elements/gate/authorization.mdx +298 -0
- package/site/content/docs/elements/gate/index.mdx +418 -0
- package/site/content/docs/elements/gate/meta.json +5 -0
- package/site/content/docs/elements/gate/rate-limits.mdx +365 -0
- package/site/content/docs/elements/gate/rls.mdx +303 -0
- package/site/content/docs/elements/gate/tenancy.mdx +372 -0
- package/site/content/docs/elements/index.mdx +52 -11
- package/site/content/docs/elements/signal/broadcast.mdx +517 -0
- package/site/content/docs/elements/signal/index.mdx +352 -0
- package/site/content/docs/elements/signal/live.mdx +590 -0
- package/site/content/docs/elements/signal/meta.json +5 -0
- package/site/content/docs/elements/signal/once.mdx +596 -0
- package/site/content/docs/elements/store/files.mdx +659 -0
- package/site/content/docs/elements/store/index.mdx +310 -0
- package/site/content/docs/elements/store/kv.mdx +629 -0
- package/site/content/docs/elements/store/meta.json +5 -0
- package/site/content/docs/elements/store/search.mdx +946 -0
- package/site/content/docs/elements/store/sql.mdx +937 -0
- package/site/content/docs/elements/vault/config.mdx +256 -0
- package/site/content/docs/elements/vault/index.mdx +356 -0
- package/site/content/docs/elements/vault/meta.json +5 -0
- package/site/content/docs/elements/vault/rotation.mdx +273 -0
- package/site/content/docs/elements/vault/secrets.mdx +285 -0
- package/site/content/docs/index.mdx +78 -30
- package/site/content/docs/meta.json +11 -8
- package/site/content/docs/plugins/cors.mdx +2 -1
- package/site/content/docs/plugins/csrf.mdx +4 -1
- package/site/content/docs/plugins/headers.mdx +2 -1
- package/site/content/docs/plugins/ip-allowlist.mdx +2 -1
- package/site/content/docs/plugins/magic-link.mdx +6 -0
- package/site/content/docs/plugins/maintenance-mode.mdx +2 -1
- package/site/content/docs/plugins/oauth.mdx +1 -1
- package/site/content/docs/plugins/otp.mdx +12 -1
- package/site/content/docs/plugins/passkey.mdx +39 -15
- package/site/content/docs/plugins/two-factor.mdx +91 -34
- package/site/content/docs/plugins/username.mdx +1 -1
- package/site/content/docs/recipes/caddy.mdx +3 -3
- package/site/content/docs/recipes/index.mdx +18 -28
- package/site/content/docs/recipes/mailpit.mdx +1 -1
- package/site/content/docs/recipes/meilisearch.mdx +3 -3
- package/site/content/docs/recipes/meta.json +1 -4
- package/site/content/docs/recipes/nginx.mdx +2 -2
- package/site/content/docs/recipes/openrouter.mdx +283 -0
- package/site/content/docs/recipes/pgdog.mdx +3 -3
- package/site/content/docs/recipes/postgres.mdx +1 -2
- package/site/content/docs/recipes/rustfs.mdx +2 -2
- package/site/content/docs/recipes/traefik.mdx +3 -3
- package/site/content/docs/reference/cli.mdx +231 -0
- package/site/content/docs/reference/configuration.mdx +30 -10
- package/site/content/docs/reference/environment-variables.mdx +93 -20
- package/site/content/docs/reference/errors.mdx +132 -29
- package/site/content/docs/reference/fx.mdx +137 -73
- package/site/content/docs/reference/index.mdx +13 -21
- package/site/content/docs/reference/meta.json +4 -5
- package/site/content/docs/reference/okid.mdx +42 -17
- package/site/content/docs/reference/plugins.mdx +4 -3
- package/site/content/docs/reference/security.mdx +197 -0
- package/site/content/docs/understand/meta.json +5 -0
- package/site/content/docs/understand/the-anatomy.mdx +132 -0
- package/site/content/docs/understand/the-model.mdx +32 -0
- package/site/content/docs/understand/the-problem.mdx +74 -0
- package/site/content/docs/understand/the-vocabulary.mdx +26 -0
- package/src/auth/api-keys.ts +2 -1
- package/src/auth/bindings.ts +64 -16
- package/src/auth/gate-auth.test.ts +6 -1
- package/src/auth/identity.ts +152 -5
- package/src/auth/index.ts +29 -0
- package/src/auth/invites.ts +2 -1
- package/src/auth/method-context.ts +41 -0
- package/src/auth/oauth-as/crypto.ts +2 -1
- package/src/auth/oauth-as/stores.ts +2 -1
- package/src/auth/operator.ts +2 -1
- package/src/auth/sessions-jwt.test.ts +77 -0
- package/src/auth/sessions.ts +20 -4
- package/src/auth/tenants.ts +3 -2
- package/src/auth/two-factor-challenge.test.ts +61 -0
- package/src/auth/two-factor-challenge.ts +284 -0
- package/src/auth/verification.ts +5 -0
- package/src/bench/REPORT.md +49 -0
- package/src/bench/g03-signal-once.bench.ts +1 -1
- package/src/bench/g10-observability-contention.bench.ts +1 -1
- package/src/bench/g17-hybrid-search.bench.ts +572 -0
- package/src/bench/load-app.ts +2 -10
- package/src/cli/ai-setup/ai-setup.test.ts +331 -42
- package/src/cli/ai-setup/apply.ts +294 -52
- package/src/cli/ai-setup/catalog.ts +238 -1342
- package/src/cli/ai-setup/index.ts +14 -99
- package/src/cli/ai-setup/prompts.ts +60 -443
- package/src/cli/ask-seed.test.ts +96 -0
- package/src/cli/ask-seed.ts +82 -0
- package/src/cli/ask-vault-gaps.test.ts +84 -0
- package/src/cli/ask-vault-gaps.ts +146 -0
- package/src/cli/build.ts +2 -2
- package/src/cli/client-add.test.ts +26 -1
- package/src/cli/client-add.ts +106 -27
- package/src/cli/competitor-mention-removal.test.ts +1 -1
- package/src/cli/db-seed.ts +2 -0
- package/src/cli/db.ts +150 -11
- package/src/cli/dev.ts +119 -211
- package/src/cli/docker-clean.ts +2 -2
- package/src/cli/docker-cli.test.ts +1 -1
- package/src/cli/doctor-diff.ts +4 -2
- package/src/cli/doctor-pii.test.ts +1 -1
- package/src/cli/doctor.ts +14 -1
- package/src/cli/hero-meta.test.ts +4 -2
- package/src/cli/load-config.images.test.ts +8 -10
- package/src/cli/load-config.ts +1 -1
- package/src/cli/registry.ts +22 -10
- package/src/cli/replay.ts +3 -1
- package/src/cli/start.ts +1 -1
- package/src/cli/tui/keys.ts +2 -3
- package/src/client/auth/cookies.ts +74 -0
- package/src/client/auth/create-auth-client.ts +636 -0
- package/src/client/auth/denials.ts +99 -0
- package/src/client/auth/session.ts +283 -0
- package/src/client/auth.test.ts +251 -0
- package/src/client/auth.ts +39 -114
- package/src/client/create-with-session.ts +245 -0
- package/src/client/create.ts +51 -5
- package/src/client/index.ts +11 -1
- package/src/client/live.ts +11 -79
- package/src/client/notes-contract.test.ts +5 -10
- package/src/client/sse.ts +137 -0
- package/src/client/stream.ts +147 -0
- package/src/client/transport.test.ts +32 -0
- package/src/client/transport.ts +123 -26
- package/src/client/types.ts +118 -14
- package/src/client-react/index.ts +185 -24
- package/src/client-react/use-live-query.ts +13 -3
- package/src/compiler/aot.test.ts +7 -4
- package/src/compiler/effects-embed.test.ts +56 -0
- package/src/compiler/effects-fetch.test.ts +43 -0
- package/src/compiler/effects-infer.ts +58 -2
- package/src/compiler/extract.test.ts +258 -44
- package/src/compiler/extract.ts +566 -48
- package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +7 -4
- package/src/compiler/fixtures/skyport/src/flows/bookings/signals.ts +2 -8
- package/src/compiler/fixtures/skyport.expected.json +4 -4
- package/src/compiler/fixtures/triggers/five-triggers.ts +14 -10
- package/src/compiler/response.ts +2 -2
- package/src/compiler/search-writer-isolation.test.ts +40 -0
- package/src/config/index.ts +11 -0
- package/src/console/server/app.ts +17 -23
- package/src/console/server/bind.ts +4 -0
- package/src/console/server/console.test.ts +2 -2
- package/src/console/server/flows-invoke.test.ts +50 -34
- package/src/console/server/flows.ts +436 -255
- package/src/console/server/runs-ingest.test.ts +6 -3
- package/src/console/server/serve.ts +1 -1
- package/src/console/server/signals.test.ts +1 -5
- package/src/console/server/signals.ts +8 -6
- package/src/console/server/state.ts +6 -1
- package/src/console/server/store.ts +1 -1
- package/src/console/ui-next/dist/assets/FileExportIcon-Ck-5od4R.js +1 -0
- package/src/console/ui-next/dist/assets/MoreHorizontalCircle01Icon-gMNGsE37.js +1 -0
- package/src/console/ui-next/dist/assets/PlusSignIcon-CwG3nxfu.js +1 -0
- package/src/console/ui-next/dist/assets/UnavailableIcon-D9cvHVPr.js +1 -0
- package/src/console/ui-next/dist/assets/UserIcon-DaE2PB5_.js +1 -0
- package/src/console/ui-next/dist/assets/access-page-DFeymU07.js +4 -0
- package/src/console/ui-next/dist/assets/agent-disclosure-U1rdfblp.js +1 -0
- package/src/console/ui-next/dist/assets/cache-glyph-BeFJeqBG.js +1 -0
- package/src/console/ui-next/dist/assets/call-pii-button-CVAONPii.js +1 -0
- package/src/console/ui-next/dist/assets/collapsible-D2A6NJ-3.js +1 -0
- package/src/console/ui-next/dist/assets/copy-inline-button-CAYD18cr.js +1 -0
- package/src/console/ui-next/dist/assets/dagre.esm-B1_XeuLP.js +1 -0
- package/src/console/ui-next/dist/assets/detail-header-DVWNjWjg.js +1 -0
- package/src/console/ui-next/dist/assets/dropdown-menu-4h2LOVXM.js +1 -0
- package/src/console/ui-next/dist/assets/duration-tone-Cgk_h5ja.js +9 -0
- package/src/console/ui-next/dist/assets/element-icons-BI8cJgdh.js +1 -0
- package/src/console/ui-next/dist/assets/explorer-empty-CJs5A-wm.js +1 -0
- package/src/console/ui-next/dist/assets/flows-page-Dss7941e.js +1 -0
- package/src/console/ui-next/dist/assets/highlighted-json-MYZQtRnw.js +154 -0
- package/src/console/ui-next/dist/assets/http-method-Jrh39p7A.js +1 -0
- package/src/console/ui-next/dist/assets/index-D0zS5rKO.css +2 -0
- package/src/console/ui-next/dist/assets/index-DXP2dBIF.js +63 -0
- package/src/console/ui-next/dist/assets/observability-page-HvolXxTI.js +4 -0
- package/src/console/ui-next/dist/assets/react-dom-Ddte4I-Q.js +9 -0
- package/src/console/ui-next/dist/assets/replica-lag-CSh2dzrb.js +18 -0
- package/src/console/ui-next/dist/assets/request-meta-BatF8KrK.js +1 -0
- package/src/console/ui-next/dist/assets/shortcut-keys-3ILd8oGn.js +1 -0
- package/src/console/ui-next/dist/assets/{sql-BskegiFM.js → sql-BsFa4tDR.js} +1 -1
- package/src/console/ui-next/dist/assets/store-page-eiKiHnNe.js +41 -0
- package/src/console/ui-next/dist/assets/trace-detail-sheet-CZkMeKS-.js +2 -0
- package/src/console/ui-next/dist/assets/tree-expand-toggle-CW8y5A2h.js +55 -0
- package/src/console/ui-next/dist/assets/units-page-B_RWJrEO.js +1 -0
- package/src/console/ui-next/dist/assets/{use-vault-list-uk4WVboC.js → use-vault-list-CT4-gajj.js} +1 -1
- package/src/console/ui-next/dist/assets/vault-page-CWrg-A68.js +2 -0
- package/src/console/ui-next/dist/assets/xyflow-CSyC6ryz.css +1 -0
- package/src/console/ui-next/dist/assets/xyflow-yApv7D4e.js +7 -0
- package/src/console/ui-next/dist/index.html +6 -13
- package/src/console/ui-next/seed-invoke-host.ts +21 -18
- package/src/console/ui-next/src/client.ts +7 -2
- package/src/console/ui-next/src/features/flows/graph/element-map.ts +2 -0
- package/src/console/ui-next/src/features/flows/traces/effect-kind.ts +12 -2
- package/src/console/ui-next/src/features/flows/traces/effect-summary.ts +4 -0
- package/src/console/ui-next/src/features/flows/traces/trace-detail-sheet.tsx +8 -0
- package/src/console/ui-next/src/features/flows/traces/waterfall-bars.ts +4 -0
- package/src/console/ui-next/src/features/flows/traces/waterfall-tooltip.ts +9 -3
- package/src/console/ui-next/src/features/store/detail/reveal-cell.tsx +7 -11
- package/src/console/ui-next/src/features/store/detail/store-row-detail-sheet.tsx +2 -2
- package/src/console/ui-next/src/features/store/lib/fields-from-table.ts +2 -0
- package/src/console/ui-next/src/features/store/lib/grid-model.test.ts +25 -1
- package/src/console/ui-next/src/features/store/lib/grid-model.ts +36 -1
- package/src/console/ui-next/src/features/store/query/query-results.tsx +3 -3
- package/src/console/ui-next/src/features/units/detail/effects-summary.tsx +2 -0
- package/src/console/ui-next/src/features/units/lib/call-read-safe.ts +3 -1
- package/src/console/ui-next/src/features/units/lib/fields-from-schema.ts +6 -0
- package/src/docker/ai-model-status.test.ts +1 -12
- package/src/docker/ai-model-status.ts +10 -38
- package/src/docker/compose-up.test.ts +100 -0
- package/src/docker/compose-up.ts +292 -0
- package/src/docker/compose.ts +4 -14
- package/src/docker/derive.ts +9 -34
- package/src/docker/docker.test.ts +16 -261
- package/src/docker/images-config.test.ts +13 -25
- package/src/docker/index.ts +1 -24
- package/src/docker/recipes/index.ts +0 -23
- package/src/docker/recipes/pgdog.ts +6 -4
- package/src/docker/stack-id.test.ts +2 -2
- package/src/docker/stack-id.ts +0 -1
- package/src/docker/types.ts +2 -2
- package/src/drivers/ai-anthropic.ts +10 -0
- package/src/drivers/ai-openai-compatible.ts +34 -7
- package/src/drivers/ai-providers.test.ts +0 -107
- package/src/drivers/ai-stream.test.ts +0 -34
- package/src/drivers/ai-types.ts +17 -8
- package/src/drivers/channel-fcm.ts +6 -1
- package/src/drivers/channel-msegat.ts +6 -1
- package/src/drivers/channel-resend.ts +5 -1
- package/src/drivers/channel-smtp.ts +5 -1
- package/src/drivers/channel-sndr.ts +10 -1
- package/src/drivers/channel-taqnyat-mail.ts +5 -1
- package/src/drivers/channel-taqnyat-whatsapp.ts +6 -1
- package/src/drivers/channel-taqnyat.ts +6 -1
- package/src/drivers/channel-types.ts +10 -0
- package/src/drivers/channel-unifonic.ts +6 -1
- package/src/drivers/channel-wa-cloud.ts +6 -1
- package/src/drivers/channel-webpush.ts +6 -1
- package/src/drivers/external.ts +33 -0
- package/src/drivers/index.ts +0 -10
- package/src/drivers/meilisearch.ts +6 -0
- package/src/drivers/oauth-types.ts +4 -0
- package/src/drivers/postgres.test.ts +74 -3
- package/src/drivers/postgres.ts +175 -6
- package/src/drivers/signal-types.ts +5 -5
- package/src/drivers/types.ts +7 -0
- package/src/drivers/vault-types.ts +5 -0
- package/src/elements/ai/declare.ts +17 -4
- package/src/elements/ai/eval.ts +1 -1
- package/src/elements/ai/mcp-http.ts +1 -1
- package/src/elements/ai/pii.ts +1 -1
- package/src/elements/ai/providers.test.ts +289 -0
- package/src/elements/ai/providers.ts +169 -0
- package/src/elements/ai/runtime.ts +68 -5
- package/src/elements/ai/schema.ts +2 -2
- package/src/elements/ai.test.ts +7 -7
- package/src/elements/ai.ts +17 -1
- package/src/elements/channel/runtime.ts +105 -12
- package/src/elements/clock/cron-fields.test.ts +144 -0
- package/src/elements/clock/cron-fields.ts +185 -0
- package/src/elements/clock/declare.ts +247 -3
- package/src/elements/clock.ts +21 -1
- package/src/elements/index.ts +15 -0
- package/src/elements/signal/chaos-child.ts +1 -2
- package/src/elements/signal/declare.ts +65 -37
- package/src/elements/signal/delivery-modes.test.ts +11 -31
- package/src/elements/signal/dry-run-replay.test.ts +1 -7
- package/src/elements/signal/dry-run-write-isolation.test.ts +1 -7
- package/src/elements/signal/key-ordering.test.ts +6 -26
- package/src/elements/signal/lease-reclaim.test.ts +2 -6
- package/src/elements/signal/optional-emit.test.ts +6 -9
- package/src/elements/signal/order-lifecycle.test.ts +4 -17
- package/src/elements/signal/orphan-messages.test.ts +4 -15
- package/src/elements/signal/reconcile.test.ts +2 -2
- package/src/elements/signal/runtime.ts +1 -1
- package/src/elements/signal/schema-emit.test.ts +4 -8
- package/src/elements/signal.test.ts +24 -49
- package/src/elements/signal.ts +9 -2
- package/src/elements/store/domain-ddl.test.ts +1 -1
- package/src/elements/store/live-http.test.ts +9 -4
- package/src/elements/store/prepare-row.test.ts +123 -0
- package/src/elements/store/resource.ts +43 -12
- package/src/elements/store/schema-decl.ts +117 -0
- package/src/elements/store/search-backfill.ts +205 -0
- package/src/elements/store/search-bind.ts +66 -0
- package/src/elements/store/search-bm25.ts +78 -0
- package/src/elements/store/search-ddl.ts +156 -0
- package/src/elements/store/search-embed-flow.ts +141 -0
- package/src/elements/store/search-errors.ts +34 -0
- package/src/elements/store/search-fusion.ts +112 -0
- package/src/elements/store/search-lsh.ts +179 -0
- package/src/elements/store/search-runtime.ts +300 -0
- package/src/elements/store/search.test.ts +144 -0
- package/src/elements/store/sql-session.test.ts +1 -0
- package/src/elements/store/sql-session.ts +83 -3
- package/src/elements/store/table.ts +23 -2
- package/src/elements/store/upsert-app.test.ts +1 -3
- package/src/elements/store.ts +50 -0
- package/src/full.ts +4 -2
- package/src/http.ts +4 -1
- package/src/i18n/catalogs/ar.ts +14 -6
- package/src/i18n/catalogs/en.ts +14 -6
- package/src/index.ts +6 -1
- package/src/kernel/adopt-barrel-fresh.test.ts +7 -7
- package/src/kernel/adopt-routes.ts +9 -1
- package/src/kernel/app-auth.ts +5 -0
- package/src/kernel/app.ts +102 -9
- package/src/kernel/auto-cache.test.ts +6 -12
- package/src/kernel/auto-registry.test.ts +3 -3
- package/src/kernel/boot-bind/ai.test.ts +22 -19
- package/src/kernel/boot-bind/ai.ts +5 -43
- package/src/kernel/boot-bind/clock.ts +23 -5
- package/src/kernel/boot-bind/honor-config.test.ts +4 -4
- package/src/kernel/boot.test.ts +11 -6
- package/src/kernel/boot.ts +66 -16
- package/src/kernel/boundary-contract.ts +93 -0
- package/src/kernel/budget.test.ts +1 -1
- package/src/kernel/call.ts +89 -0
- package/src/kernel/capability.ts +6 -0
- package/src/kernel/client-descriptor.ts +123 -0
- package/src/kernel/clock-timezone.test.ts +80 -0
- package/src/kernel/correlation.test.ts +1 -1
- package/src/kernel/dry-run.ts +11 -8
- package/src/kernel/effects-stamping.test.ts +42 -9
- package/src/kernel/effects.test.ts +4 -2
- package/src/kernel/effects.ts +51 -9
- package/src/kernel/errors-channel.ts +17 -0
- package/src/kernel/errors-live-resume.ts +3 -2
- package/src/kernel/errors-tenant.ts +7 -4
- package/src/kernel/errors.registry-helpers.ts +96 -0
- package/src/kernel/errors.registry.test.ts +139 -25
- package/src/kernel/errors.ts +102 -23
- package/src/kernel/external-effects.test.ts +196 -0
- package/src/kernel/flow.test.ts +13 -4
- package/src/kernel/flow.ts +69 -71
- package/src/kernel/fx-ask-telemetry.test.ts +2 -2
- package/src/kernel/fx-dead-letters.test.ts +3 -3
- package/src/kernel/fx-fetch.ts +55 -0
- package/src/kernel/fx-live-stream.ts +2 -2
- package/src/kernel/fx-live.test.ts +8 -8
- package/src/kernel/fx.test.ts +17 -11
- package/src/kernel/fx.ts +180 -57
- package/src/kernel/horizontal-child.ts +1 -1
- package/src/kernel/http-query.test.ts +3 -6
- package/src/kernel/index.ts +13 -3
- package/src/kernel/instance-id.ts +1 -1
- package/src/kernel/instances.test.ts +40 -0
- package/src/kernel/instances.ts +47 -9
- package/src/kernel/live-http.test.ts +6 -7
- package/src/kernel/live-http.ts +6 -2
- package/src/kernel/live-resume.test.ts +1 -1
- package/src/kernel/mcp-tool.test.ts +3 -3
- package/src/kernel/on.ts +98 -4
- package/src/kernel/pipeline.test.ts +12 -15
- package/src/kernel/plugin-elements.test.ts +1 -1
- package/src/kernel/stamp-http.test.ts +3 -3
- package/src/kernel/triggers.ts +210 -95
- package/src/kernel-entry.ts +0 -1
- package/src/manifest/diff.ts +11 -1
- package/src/manifest/fixtures/skyport.excerpt.json +1 -1
- package/src/manifest/types.ts +46 -2
- package/src/mcp/docs-index.ts +3 -3
- package/src/mcp/docs-mcp.test.ts +2 -2
- package/src/mcp/docs-tools.ts +1 -1
- package/src/okid.test.ts +56 -0
- package/src/okid.ts +55 -11
- package/src/plugins/anonymous.ts +8 -4
- package/src/plugins/auth/shared.ts +27 -3
- package/src/plugins/auth-delivery.mailpit.integration.test.ts +1 -1
- package/src/plugins/auth-methods.security.test.ts +561 -23
- package/src/plugins/config-source.ts +1 -1
- package/src/plugins/csrf.test.ts +65 -0
- package/src/plugins/index.ts +2 -0
- package/src/plugins/magic-link.ts +36 -16
- package/src/plugins/oauth/shared.ts +3 -1
- package/src/plugins/oauth.ts +22 -14
- package/src/plugins/otp.ts +37 -21
- package/src/plugins/passkey-webauthn.ts +9 -6
- package/src/plugins/passkey.ts +98 -26
- package/src/plugins/pre-account-hijack.test.ts +223 -0
- package/src/plugins/two-factor.ts +466 -37
- package/src/plugins/username.ts +19 -7
- package/src/release/build-lib.ts +1 -0
- package/src/release/limits.ts +2 -2
- package/src/release/measure.ts +1 -1
- package/src/runs/collect.test.ts +0 -2
- package/src/runtime/json-code-block.test.ts +250 -20
- package/src/runtime/json-code-block.ts +1261 -41
- package/src/term.test.ts +1 -1
- package/src/test/create-test-app.test.ts +12 -12
- package/src/test/live-signals.test.ts +6 -6
- package/src/test/provisions.integration.test.ts +10 -14
- package/src/test/reset-element-registries.ts +1 -1
- package/src/test/tenant-isolation.test.ts +12 -6
- package/site/content/docs/deployment/docker-swarm.mdx +0 -164
- package/site/content/docs/deployment/docker.mdx +0 -227
- package/site/content/docs/deployment/index.mdx +0 -83
- package/site/content/docs/deployment/kubernetes.mdx +0 -176
- package/site/content/docs/deployment/meta.json +0 -5
- package/site/content/docs/deployment/reverse-proxy.mdx +0 -234
- package/site/content/docs/elements/ai.mdx +0 -385
- package/site/content/docs/elements/channel.mdx +0 -346
- package/site/content/docs/elements/clock.mdx +0 -244
- package/site/content/docs/elements/flow.mdx +0 -420
- package/site/content/docs/elements/gate.mdx +0 -436
- package/site/content/docs/elements/signal.mdx +0 -380
- package/site/content/docs/elements/store.mdx +0 -1099
- package/site/content/docs/elements/vault.mdx +0 -405
- package/site/content/docs/get-started/basic-usage.mdx +0 -173
- package/site/content/docs/get-started/index.mdx +0 -43
- package/site/content/docs/get-started/installation.mdx +0 -220
- package/site/content/docs/get-started/introduction.mdx +0 -132
- package/site/content/docs/get-started/meta.json +0 -13
- package/site/content/docs/get-started/project-structure.mdx +0 -925
- package/site/content/docs/get-started/testing.mdx +0 -328
- package/site/content/docs/get-started/why.mdx +0 -162
- package/site/content/docs/recipes/llama-cpp.mdx +0 -151
- package/site/content/docs/recipes/ollama.mdx +0 -142
- package/site/content/docs/recipes/sglang.mdx +0 -105
- package/site/content/docs/recipes/vllm.mdx +0 -106
- package/site/content/docs/reference/cli.md +0 -232
- package/site/content/docs/reference/client.mdx +0 -469
- package/site/content/docs/reference/security.md +0 -74
- package/src/cli/ai-setup/detect-ollama.ts +0 -213
- package/src/cli/ai-setup/recommend.test.ts +0 -225
- package/src/cli/ai-setup/recommend.ts +0 -225
- package/src/cli/dev-controls.test.ts +0 -122
- package/src/cli/dev-controls.ts +0 -164
- package/src/cli/tui/DevLive.tsx +0 -126
- package/src/console/ui-next/dist/assets/access-page-De7Lc2JC.js +0 -4
- package/src/console/ui-next/dist/assets/agent-disclosure-BP0Y0Sux.js +0 -1
- package/src/console/ui-next/dist/assets/cache-glyph-B5X-NM0-.js +0 -1
- package/src/console/ui-next/dist/assets/call-pii-button-ChAUiLo9.js +0 -1
- package/src/console/ui-next/dist/assets/collapsible-DGnOM2ph.js +0 -1
- package/src/console/ui-next/dist/assets/copy-inline-button-DBHhgHKP.js +0 -1
- package/src/console/ui-next/dist/assets/dagre.esm-ZwcdTuZZ.js +0 -1
- package/src/console/ui-next/dist/assets/detail-header-DhHM1iaZ.js +0 -1
- package/src/console/ui-next/dist/assets/dropdown-menu-_NjTEo5_.js +0 -1
- package/src/console/ui-next/dist/assets/duration-tone-sC3lGABz.js +0 -9
- package/src/console/ui-next/dist/assets/element-icons-BVXtRyd3.js +0 -1
- package/src/console/ui-next/dist/assets/explorer-empty-2uIhBu0_.js +0 -1
- package/src/console/ui-next/dist/assets/flows-page-RGy7VEA_.js +0 -1
- package/src/console/ui-next/dist/assets/highlighted-json-Awq7gYdu.js +0 -154
- package/src/console/ui-next/dist/assets/http-method-_UHM2ODJ.js +0 -1
- package/src/console/ui-next/dist/assets/index-Ck88Jmv8.css +0 -2
- package/src/console/ui-next/dist/assets/index-_rgpdVzo.js +0 -66
- package/src/console/ui-next/dist/assets/link-BX6Vqztd.js +0 -1
- package/src/console/ui-next/dist/assets/observability-page-Ds6pcnh-.js +0 -4
- package/src/console/ui-next/dist/assets/preload-helper-oH4irX4C.js +0 -1
- package/src/console/ui-next/dist/assets/react-D8E3mtu1.js +0 -1
- package/src/console/ui-next/dist/assets/react-dom-Bph1y7z7.js +0 -9
- package/src/console/ui-next/dist/assets/replica-lag-DKRrbvdo.js +0 -18
- package/src/console/ui-next/dist/assets/request-meta-DV0ywz7t.js +0 -1
- package/src/console/ui-next/dist/assets/shortcut-JQIZlWfm.js +0 -1
- package/src/console/ui-next/dist/assets/shortcut-keys-DKxNTe_m.js +0 -1
- package/src/console/ui-next/dist/assets/skeleton-D-czQJT6.js +0 -1
- package/src/console/ui-next/dist/assets/store-page-02xOiqIK.js +0 -41
- package/src/console/ui-next/dist/assets/trace-detail-sheet-B09O8rA6.js +0 -2
- package/src/console/ui-next/dist/assets/tree-expand-toggle-BtyhmWb4.js +0 -55
- package/src/console/ui-next/dist/assets/units-page-4rHOePuE.js +0 -1
- package/src/console/ui-next/dist/assets/useMutation-B8EO02Ej.js +0 -1
- package/src/console/ui-next/dist/assets/useRender-BE2A9BWC.js +0 -1
- package/src/console/ui-next/dist/assets/vault-page-DISPgxLM.js +0 -2
- package/src/console/ui-next/dist/assets/xyflow-D7n4g6go.js +0 -7
- package/src/console/ui-next/dist/assets/xyflow-DZ0Ws1xk.css +0 -1
- package/src/docker/ollama-pull.ts +0 -232
- package/src/docker/recipes/llama-cpp.ts +0 -298
- package/src/docker/recipes/ollama.ts +0 -44
- package/src/docker/recipes/sglang.ts +0 -55
- package/src/docker/recipes/vllm.ts +0 -44
- package/src/drivers/ai-ollama-tools.integration.test.ts +0 -109
- package/src/drivers/ai-ollama.integration.test.ts +0 -184
- package/src/drivers/ai-ollama.ts +0 -389
- package/src/drivers/ollama.ts +0 -14
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Durable Sleep"
|
|
3
|
+
description: "Journaled pauses that resume across restarts — fx.clock.sleep(label, duration) on durable Flows."
|
|
4
|
+
icon: "Moon"
|
|
5
|
+
source: "docs/spec/unified-theory.md"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Durable sleep suspends a Flow until a future instant without holding a worker thread.
|
|
9
|
+
Call `await fx.clock.sleep(label, duration)` inside a `durable: true` Flow — the journal
|
|
10
|
+
stores `wakeAt`, releases the run lease, and any instance may resume when due.
|
|
11
|
+
|
|
12
|
+
For developers building trial reminders, delayed digests, and multi-day provisions on okengine.
|
|
13
|
+
|
|
14
|
+
<Callout title="The one rule">
|
|
15
|
+
Signature is `fx.clock.sleep(label, duration)` — two arguments. A single duration string is
|
|
16
|
+
treated as the **label**, not the wait. Sleep only parks when the Flow is durable.
|
|
17
|
+
</Callout>
|
|
18
|
+
|
|
19
|
+
<ClockSleep />
|
|
20
|
+
|
|
21
|
+
## Smallest Example
|
|
22
|
+
|
|
23
|
+
<Steps>
|
|
24
|
+
|
|
25
|
+
<Step>
|
|
26
|
+
### Sleep inside a durable Flow
|
|
27
|
+
|
|
28
|
+
```typescript title="src/flows/trials/start.ts"
|
|
29
|
+
import { on, flow, http } from "okengine";
|
|
30
|
+
import { z } from "zod";
|
|
31
|
+
|
|
32
|
+
export const start = on(
|
|
33
|
+
http.post(),
|
|
34
|
+
flow({
|
|
35
|
+
durable: true,
|
|
36
|
+
in: z.object({ email: z.string().email() }),
|
|
37
|
+
do: async ({ email }, fx) => {
|
|
38
|
+
await fx.step("mark-trial", async () => {
|
|
39
|
+
await fx.call(startTrial, { email });
|
|
40
|
+
});
|
|
41
|
+
await fx.clock.sleep("expiry-window", "3d");
|
|
42
|
+
await fx.step("notify", async () => {
|
|
43
|
+
await fx.send(trialExpiringEmail, { to: email });
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
}),
|
|
47
|
+
);
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
</Step>
|
|
51
|
+
|
|
52
|
+
<Step>
|
|
53
|
+
### Call the endpoint
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
curl -X POST http://localhost:6530/trials/start \
|
|
57
|
+
-H "content-type: application/json" \
|
|
58
|
+
-d '{"email":"ada@example.com"}'
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Response: **`204 No Content`** (empty body). The HTTP client is done — wake continues on a
|
|
62
|
+
worker three days later. Wrap side effects in `fx.step` so replay does not re-send mail.
|
|
63
|
+
|
|
64
|
+
</Step>
|
|
65
|
+
|
|
66
|
+
</Steps>
|
|
67
|
+
|
|
68
|
+
<Callout title="Detailed section">
|
|
69
|
+
If you only need a pause, the example above is enough. Below: park physics, wake-early,
|
|
70
|
+
nested-call limits, non-durable no-ops, and how sleep fits with steps / compensation.
|
|
71
|
+
</Callout>
|
|
72
|
+
|
|
73
|
+
## Progressive Patterns
|
|
74
|
+
|
|
75
|
+
From a labelled pause to HTTP parking, nested-call limits, and non-durable behavior:
|
|
76
|
+
|
|
77
|
+
<Tabs items={["Label + duration", "HTTP park", "After a step", "Non-durable"]}>
|
|
78
|
+
|
|
79
|
+
<Tab value="Label + duration">
|
|
80
|
+
|
|
81
|
+
Durations: `"200ms"` · `"30s"` · `"2m"` · `"1h"` · `"7d"`. Labels show up in the journal
|
|
82
|
+
and Console:
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
await fx.clock.sleep("morning-window", "8h");
|
|
86
|
+
await fx.clock.sleep("verify-window", "2m");
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Wrong:** `fx.clock.sleep("8h")` — `"8h"` is the label; duration is missing → immediate
|
|
90
|
+
resolve / unexpected behavior.
|
|
91
|
+
|
|
92
|
+
</Tab>
|
|
93
|
+
|
|
94
|
+
<Tab value="HTTP park">
|
|
95
|
+
|
|
96
|
+
Sleep on an HTTP-triggered durable Flow returns success with an empty body (`204`). Return
|
|
97
|
+
a body **before** sleep if the caller must see an id:
|
|
98
|
+
|
|
99
|
+
```typescript title="src/flows/workspaces/create.ts"
|
|
100
|
+
import { on, flow, http } from "okengine";
|
|
101
|
+
import { z } from "zod";
|
|
102
|
+
|
|
103
|
+
export const create = on(
|
|
104
|
+
http.post(),
|
|
105
|
+
flow({
|
|
106
|
+
durable: true,
|
|
107
|
+
in: z.object({ email: z.string().email() }),
|
|
108
|
+
do: async ({ email }, fx) => {
|
|
109
|
+
await fx.step("create", async () => {
|
|
110
|
+
await fx.call(createWorkspace, { email });
|
|
111
|
+
});
|
|
112
|
+
await fx.emit(workspaceProvisioned, { email });
|
|
113
|
+
await fx.clock.sleep("welcome-delay", "8h");
|
|
114
|
+
await fx.step("notify", async () => {
|
|
115
|
+
await fx.send(welcomeEmail, { to: email });
|
|
116
|
+
});
|
|
117
|
+
},
|
|
118
|
+
}),
|
|
119
|
+
);
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
After sleep the HTTP client is already done (`204`). Need a JSON body? Return from a
|
|
123
|
+
Flow that does **not** sleep, and park on a Signal consumer instead. See
|
|
124
|
+
[Workflows · Durable Sleep](/docs/elements/flow/workflows#durable-sleep).
|
|
125
|
+
|
|
126
|
+
</Tab>
|
|
127
|
+
|
|
128
|
+
<Tab value="After a step">
|
|
129
|
+
|
|
130
|
+
Checkpoint work **before** the pause so a crash mid-provision does not re-run after wake:
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
await fx.step("provision", async () => {
|
|
134
|
+
await fx.call(createWorkspace, { email });
|
|
135
|
+
});
|
|
136
|
+
await fx.clock.sleep("morning-window", "8h");
|
|
137
|
+
await fx.step("notify", async () => {
|
|
138
|
+
await fx.send(welcomeEmail, { to: email });
|
|
139
|
+
});
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Do not hold `fx.using` resources across sleep — acquire again after wake.
|
|
143
|
+
|
|
144
|
+
</Tab>
|
|
145
|
+
|
|
146
|
+
<Tab value="Non-durable">
|
|
147
|
+
|
|
148
|
+
Without a journal, `fx.clock.sleep` resolves **immediately**. There is no thread sleep and
|
|
149
|
+
no `setTimeout`. Use durable Flows for real delays; use frozen clock + advance in tests.
|
|
150
|
+
|
|
151
|
+
</Tab>
|
|
152
|
+
|
|
153
|
+
</Tabs>
|
|
154
|
+
|
|
155
|
+
## Sleep Reference
|
|
156
|
+
|
|
157
|
+
| Call / option | Type | Default | Meaning |
|
|
158
|
+
| --------------------------------- | ----------- | ------- | -------------------------------------------------- |
|
|
159
|
+
| `durable: true` | Flow option | `false` | Journals steps and sleep; required to park |
|
|
160
|
+
| `fx.clock.sleep(label, duration)` | park | — | Writes `wakeAt`, status `sleeping`, releases lease |
|
|
161
|
+
| `label` | `string` | — | Journal / Console step name |
|
|
162
|
+
| `duration` | `string` | — | `"200ms"` · `"30s"` · `"2m"` · `"1h"` · `"7d"` |
|
|
163
|
+
|
|
164
|
+
Outcomes of a durable attempt that hits sleep: status `"sleeping"` with `wakeAt` and
|
|
165
|
+
`label`. After wake, prior `fx.step` bodies replay from the journal and do not re-execute.
|
|
166
|
+
|
|
167
|
+
### Duration units
|
|
168
|
+
|
|
169
|
+
Same grammar as `fx.clock.ago` / `fromNow` / `clock.every`:
|
|
170
|
+
|
|
171
|
+
| Unit | Example | Milliseconds |
|
|
172
|
+
| ---- | --------- | ------------ |
|
|
173
|
+
| `ms` | `"200ms"` | 200 |
|
|
174
|
+
| `s` | `"30s"` | 30_000 |
|
|
175
|
+
| `m` | `"2m"` | 120_000 |
|
|
176
|
+
| `h` | `"1h"` | 3_600_000 |
|
|
177
|
+
| `d` | `"7d"` | 604_800_000 |
|
|
178
|
+
|
|
179
|
+
Integer + unit only — no weeks. `"d"` is exactly 86_400_000 ms, not a calendar day across
|
|
180
|
+
DST. Unknown strings parse as `0` ms (wake immediately).
|
|
181
|
+
|
|
182
|
+
## Park Physics
|
|
183
|
+
|
|
184
|
+
<Callout title="Detailed section">
|
|
185
|
+
If you only need `await fx.clock.sleep("label", "8h")`, jump past this section. The park writes a
|
|
186
|
+
journal entry, sets status `sleeping`, and **releases the run lease** so a parked flow does not
|
|
187
|
+
hold a 30s lock for days.
|
|
188
|
+
</Callout>
|
|
189
|
+
|
|
190
|
+
```text
|
|
191
|
+
fx.clock.sleep(label, duration)
|
|
192
|
+
→ journal entry { kind: "sleep", label, duration, wakeAt }
|
|
193
|
+
→ status = sleeping, lease released
|
|
194
|
+
→ HTTP / caller sees success (often 204)
|
|
195
|
+
→ later: claim due sleep → resume → replay steps → continue after sleep
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Any instance may claim the row when `wakeAt` is due (shared journal + lease). Resume replays
|
|
199
|
+
completed `fx.step` values from the journal, then continues past the sleep entry.
|
|
200
|
+
|
|
201
|
+
| Phase | Status | Lease | What happens |
|
|
202
|
+
| -------------- | ---------------------- | ------------ | --------------------------------------------- |
|
|
203
|
+
| Before sleep | `running` | Held | Steps append; side effects execute once |
|
|
204
|
+
| At sleep | `sleeping` | **Released** | `wakeAt` stored; worker free |
|
|
205
|
+
| After `wakeAt` | claim → `running` | Re-acquired | Replay steps; sleep entry is a no-op past due |
|
|
206
|
+
| Done | `completed` / `failed` | Released | Terminal — resume refused |
|
|
207
|
+
|
|
208
|
+
**Consequence:** multi-day sleeps are safe across deploys — the journal row is the schedule,
|
|
209
|
+
not an in-memory timer.
|
|
210
|
+
|
|
211
|
+
## With Steps
|
|
212
|
+
|
|
213
|
+
Each verb of durable work binds the same way — checkpoint, park, then more checkpoints:
|
|
214
|
+
|
|
215
|
+
<Tabs items={["Checkpoint sandwich", "HTTP body + sleep", "Signal consumer"]}>
|
|
216
|
+
|
|
217
|
+
<Tab value="Checkpoint sandwich">
|
|
218
|
+
|
|
219
|
+
Wrap every side effect in a uniquely named `fx.step`. Sleep sits **between** steps:
|
|
220
|
+
|
|
221
|
+
```typescript title="src/flows/onboarding/welcome.ts"
|
|
222
|
+
import { on, flow } from "okengine";
|
|
223
|
+
import { userSignedUp } from "@/signals";
|
|
224
|
+
import { welcomeEmail } from "@/channels/welcome";
|
|
225
|
+
|
|
226
|
+
export const sendWelcome = on(
|
|
227
|
+
userSignedUp,
|
|
228
|
+
flow("onboarding.welcome", {
|
|
229
|
+
durable: true,
|
|
230
|
+
do: async ({ email }, fx) => {
|
|
231
|
+
await fx.step("provision", async () => {
|
|
232
|
+
await fx.call(createWorkspace, { email });
|
|
233
|
+
});
|
|
234
|
+
await fx.clock.sleep("morning-window", "8h");
|
|
235
|
+
await fx.step("notify", async () => {
|
|
236
|
+
await fx.send(welcomeEmail, { to: email });
|
|
237
|
+
});
|
|
238
|
+
},
|
|
239
|
+
}),
|
|
240
|
+
);
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Consequence:** after wake, `provision` returns the journaled value and never re-runs;
|
|
244
|
+
`notify` runs for the first time.
|
|
245
|
+
|
|
246
|
+
</Tab>
|
|
247
|
+
|
|
248
|
+
<Tab value="HTTP body + sleep">
|
|
249
|
+
|
|
250
|
+
Parking an HTTP Flow always answers **`204`** (suspend returns `undefined`). When the
|
|
251
|
+
caller must see an id, **do not sleep on that route** — return the body, emit, and park
|
|
252
|
+
on a consumer:
|
|
253
|
+
|
|
254
|
+
```typescript title="src/flows/trials/create.ts"
|
|
255
|
+
import { on, flow, http } from "okengine";
|
|
256
|
+
import { z } from "zod";
|
|
257
|
+
|
|
258
|
+
export const create = on(
|
|
259
|
+
http.post(),
|
|
260
|
+
flow({
|
|
261
|
+
durable: true,
|
|
262
|
+
in: z.object({ email: z.string().email() }),
|
|
263
|
+
out: z.object({ trialId: z.string() }),
|
|
264
|
+
do: async ({ email }, fx) => {
|
|
265
|
+
const trialId = await fx.step("create", async () => {
|
|
266
|
+
return await fx.call(createTrial, { email });
|
|
267
|
+
});
|
|
268
|
+
await fx.emit(trialStarted, { trialId, email });
|
|
269
|
+
return { trialId };
|
|
270
|
+
},
|
|
271
|
+
}),
|
|
272
|
+
);
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
</Tab>
|
|
276
|
+
|
|
277
|
+
<Tab value="Signal consumer">
|
|
278
|
+
|
|
279
|
+
The consumer owns the multi-day wait (paired with the HTTP Flow above):
|
|
280
|
+
|
|
281
|
+
```typescript title="src/flows/trials/remind.ts"
|
|
282
|
+
import { on, flow } from "okengine";
|
|
283
|
+
import { trialStarted } from "@/signals";
|
|
284
|
+
import { trialExpiringEmail } from "@/channels/trials";
|
|
285
|
+
|
|
286
|
+
export const remind = on(
|
|
287
|
+
trialStarted,
|
|
288
|
+
flow("trials.remind", {
|
|
289
|
+
durable: true,
|
|
290
|
+
do: async ({ trialId, email }, fx) => {
|
|
291
|
+
await fx.clock.sleep("expiry-window", "3d");
|
|
292
|
+
await fx.step("notify", async () => {
|
|
293
|
+
await fx.send(trialExpiringEmail, { to: email, trialId });
|
|
294
|
+
});
|
|
295
|
+
},
|
|
296
|
+
}),
|
|
297
|
+
);
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
</Tab>
|
|
301
|
+
|
|
302
|
+
</Tabs>
|
|
303
|
+
|
|
304
|
+
## Nested Calls
|
|
305
|
+
|
|
306
|
+
<Callout title="Detailed section">
|
|
307
|
+
If you sleep only on the root durable Flow, skip this section. `fx.call` waits for the callee to
|
|
308
|
+
return — a sleeping callee does not keep the caller parked.
|
|
309
|
+
</Callout>
|
|
310
|
+
|
|
311
|
+
`fx.call` of a durable sleeper: the caller receives `undefined` and continues; the child
|
|
312
|
+
wakes later as its own run.
|
|
313
|
+
|
|
314
|
+
| Pattern | Safe? | Why |
|
|
315
|
+
| --------------------------------------------- | ----- | ------------------------------------------ |
|
|
316
|
+
| Sleep on the root durable Flow | Yes | One journal row, clear park |
|
|
317
|
+
| `fx.emit` → durable consumer that sleeps | Yes | Separate run owns the wait |
|
|
318
|
+
| `fx.call(sleeperFlow, …)` then use the result | No | Caller gets `undefined`; child parks alone |
|
|
319
|
+
|
|
320
|
+
**Consequence:** sleep on the **root** durable Flow, or split with `fx.emit` to a consumer —
|
|
321
|
+
do not nest sleep behind `fx.call`.
|
|
322
|
+
|
|
323
|
+
## Wake Early
|
|
324
|
+
|
|
325
|
+
Operators can advance `wakeAt` to **now** from Console (waiting-on / wake-early). With a
|
|
326
|
+
flow resolver, the run resumes immediately; without it, only the wake time moves forward.
|
|
327
|
+
|
|
328
|
+
| Outcome | Meaning |
|
|
329
|
+
| ---------------------------- | ---------------------------------------------------------------- |
|
|
330
|
+
| Resumed | `wakeAt` set to now and `runDurable` continued past the sleep |
|
|
331
|
+
| Wake time only | `wakeAt` advanced; scheduler / next claim picks it up |
|
|
332
|
+
| `ClockResourceNotFoundError` | `run "{id}" not found` — missing id, or status is not `sleeping` |
|
|
333
|
+
|
|
334
|
+
Missing or non-sleeping run id → `ClockResourceNotFoundError` — `run "{id}" not found`.
|
|
335
|
+
|
|
336
|
+
## Non-durable & Tests
|
|
337
|
+
|
|
338
|
+
Without a journal session, `fx.clock.sleep` resolves immediately (tests and sync Flows).
|
|
339
|
+
There is no thread sleep and no `setTimeout`.
|
|
340
|
+
|
|
341
|
+
For deterministic waits in tests, use a frozen clock and advance:
|
|
342
|
+
|
|
343
|
+
```typescript
|
|
344
|
+
import { createTimeTravel } from "okengine";
|
|
345
|
+
|
|
346
|
+
const t = createTimeTravel(0);
|
|
347
|
+
// Park a durable run with now: () => t.now()
|
|
348
|
+
t.advance("7d");
|
|
349
|
+
// Resume — sleep entry is past due and continues
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Pin journal for the env you need:
|
|
353
|
+
|
|
354
|
+
| Driver | Default env | Best for |
|
|
355
|
+
| ---------- | -------------- | ---------------------------------------------------- |
|
|
356
|
+
| `postgres` | `dev`, `prod` | Shared durable runs across replicas (`DATABASE_URL`) |
|
|
357
|
+
| `memory` | `test` | Process-local; lost on exit |
|
|
358
|
+
| `file` | pin explicitly | One machine — `.oke/journal.json` |
|
|
359
|
+
|
|
360
|
+
Unknown ids throw `oke boot: unknown journal driver "…" (expected memory · file · postgres)`.
|
|
361
|
+
Postgres without a URL throws `oke boot: journal driver "postgres" needs DATABASE_URL`.
|
|
362
|
+
|
|
363
|
+
Full lease / orphan / status tables live on [Workflows · Journal](/docs/elements/flow/workflows#journal).
|
|
364
|
+
|
|
365
|
+
## Troubleshooting
|
|
366
|
+
|
|
367
|
+
<Accordions>
|
|
368
|
+
|
|
369
|
+
<Accordion title="Sleep returns immediately / work runs twice after wait">
|
|
370
|
+
Missing `durable: true`, or `fx.clock.sleep("8h")` with one argument. Use `fx.clock.sleep("label",
|
|
371
|
+
"8h")`. Non-durable sleep is a no-op.
|
|
372
|
+
</Accordion>
|
|
373
|
+
|
|
374
|
+
<Accordion title="HTTP 204 with empty body after POST">
|
|
375
|
+
The Flow parked on `fx.clock.sleep` — success, not a missing handler. The original client is done;
|
|
376
|
+
wake continues on a worker. Return a body before sleep if needed, or emit to a Signal consumer for
|
|
377
|
+
the long wait.
|
|
378
|
+
</Accordion>
|
|
379
|
+
|
|
380
|
+
<Accordion title="Mail / charge ran again after resume">
|
|
381
|
+
The side effect was outside `fx.step`. Wrap provider calls in uniquely named steps so replay
|
|
382
|
+
returns the journaled value.
|
|
383
|
+
</Accordion>
|
|
384
|
+
|
|
385
|
+
<Accordion title="Connection held across sleep">
|
|
386
|
+
`fx.using` is same-attempt cleanup — do not hold handles across `fx.clock.sleep`. Acquire again
|
|
387
|
+
after wake.
|
|
388
|
+
</Accordion>
|
|
389
|
+
|
|
390
|
+
<Accordion title="ClockResourceNotFoundError on wake">
|
|
391
|
+
Cause: `run "{id}" not found`. The wake-early target is missing or not `sleeping` — check the run
|
|
392
|
+
id from Console / durable result.
|
|
393
|
+
</Accordion>
|
|
394
|
+
|
|
395
|
+
<Accordion title="fx.call of a durable sleeper returned undefined">
|
|
396
|
+
The callee parked. Sleep on the root Flow, or emit to a durable consumer instead of calling a
|
|
397
|
+
sleeper inline.
|
|
398
|
+
</Accordion>
|
|
399
|
+
|
|
400
|
+
<Accordion title="Unknown duration wakes immediately">
|
|
401
|
+
Strings that do not match `integer + ms|s|m|h|d` parse as `0` ms. Use `"8h"`, not `"8 hours"` or
|
|
402
|
+
`"1w"`.
|
|
403
|
+
</Accordion>
|
|
404
|
+
|
|
405
|
+
<Accordion title='journal: run "…" is leased by another instance'>
|
|
406
|
+
Resume lost the lease race (`JournalLeaseBusy`). The other holder continues; this instance skips.
|
|
407
|
+
Shared `postgres` journal + default **30s** lease — same physics as Signal claims.
|
|
408
|
+
</Accordion>
|
|
409
|
+
|
|
410
|
+
<Accordion title="GET /_/ready is 503 reason orphan_scan">
|
|
411
|
+
Boot is still reclaiming `running` / `sleeping` / `compensating` rows with no live lease. Wait for
|
|
412
|
+
the orphan scan; future sleeps stay scheduled until `wakeAt`.
|
|
413
|
+
</Accordion>
|
|
414
|
+
|
|
415
|
+
</Accordions>
|
|
416
|
+
|
|
417
|
+
## Learn more
|
|
418
|
+
|
|
419
|
+
- [Workflows](/docs/elements/flow/workflows) — `durable`, `fx.step`, compensate, full sleep section
|
|
420
|
+
- [HTTP](/docs/elements/flow/http) — request envelope; `204` from park / `undefined`
|
|
421
|
+
- [Clock overview](/docs/elements/clock) — schedules and `fx.clock` helpers
|
|
422
|
+
- [Schedules](/docs/elements/clock/schedules) — cron / every (calendar time, not durable pause)
|
|
423
|
+
- [fx](/docs/reference/fx) — `fx.clock.sleep`, `fx.step`, `fx.using`
|
|
424
|
+
- [Configuration](/docs/reference/configuration) — `drivers.journal`
|
|
425
|
+
- [Errors](/docs/reference/errors) — `ClockResourceNotFoundError`
|
|
426
|
+
|
|
427
|
+
## Next
|
|
428
|
+
|
|
429
|
+
<Cards>
|
|
430
|
+
<Card
|
|
431
|
+
title="Durable Workflows"
|
|
432
|
+
description="Step journaling, undo, and multi-day runs."
|
|
433
|
+
href="/docs/elements/flow/workflows"
|
|
434
|
+
/>
|
|
435
|
+
<Card
|
|
436
|
+
title="Schedules"
|
|
437
|
+
description="Cron helpers, intervals, and IANA timezones."
|
|
438
|
+
href="/docs/elements/clock/schedules"
|
|
439
|
+
/>
|
|
440
|
+
<Card
|
|
441
|
+
title="Clock Overview"
|
|
442
|
+
description="Return to the Clock element overview."
|
|
443
|
+
href="/docs/elements/clock"
|
|
444
|
+
/>
|
|
445
|
+
</Cards>
|