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,559 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Routing"
|
|
3
|
+
description: "File-tree stamps for HTTP paths, Flow names, and client units from on(http.*, flow) under src/flows."
|
|
4
|
+
icon: "GitFork"
|
|
5
|
+
source: "docs/spec/unified-theory.md"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
HTTP routes are inferred from where a Flow file lives. Put `http.get()` in
|
|
9
|
+
`src/flows/notes/[id]/get.ts` and the compiler stamps `GET /notes/:id`, names the
|
|
10
|
+
Flow `notes.get`, and the client calls `api.notes.get({ id })`.
|
|
11
|
+
|
|
12
|
+
<Callout title="The one rule">
|
|
13
|
+
On a tree file, omit path and name: `on(http.get(), flow({ do }))`. The file
|
|
14
|
+
tree stamps both. Pass either only for control — barrels, a URL that must not
|
|
15
|
+
follow the folder, or a stable name for `fx.call`. Explicit always wins.
|
|
16
|
+
</Callout>
|
|
17
|
+
|
|
18
|
+
## When to omit · when to pass
|
|
19
|
+
|
|
20
|
+
| | Omit (default) | Pass explicitly |
|
|
21
|
+
| ------------- | -------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
22
|
+
| **HTTP path** | Tree file under `src/flows/<unit>/` — `http.get()`, `http.post()`, … | Barrel `index.ts`; a public URL that must not match the folder; `http.resource(path, ops)`; custom live SSE path |
|
|
23
|
+
| **Flow name** | Same tree file — `flow({ do })` stamps `unit.export` | Barrel (optional — export still stamps); stable name across moves; call-only Flow you `fx.call` by name |
|
|
24
|
+
|
|
25
|
+
**Consequence:** most app code looks like the create-oke template —
|
|
26
|
+
`http.get().public()` + `flow({ … })` — with no string path and no string name.
|
|
27
|
+
|
|
28
|
+
## Smallest Example
|
|
29
|
+
|
|
30
|
+
<Steps>
|
|
31
|
+
|
|
32
|
+
<Step>
|
|
33
|
+
### Place the file in the tree
|
|
34
|
+
|
|
35
|
+
`oke dev` / `oke build` regenerate `src/flows/generated.ts`. Import it before
|
|
36
|
+
`oke()` so pathless triggers receive their stamp:
|
|
37
|
+
|
|
38
|
+
```typescript title="src/app.ts"
|
|
39
|
+
import "@/flows/generated";
|
|
40
|
+
import { oke } from "okengine";
|
|
41
|
+
|
|
42
|
+
export const app = oke({ name: "notes" });
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
</Step>
|
|
46
|
+
|
|
47
|
+
<Step>
|
|
48
|
+
### Use pathless `http.get()`
|
|
49
|
+
|
|
50
|
+
The tree stamps `GET /notes/:id`. `:id` merges into `in`. The export name is the
|
|
51
|
+
client method (`api.notes.get`):
|
|
52
|
+
|
|
53
|
+
```typescript title="src/flows/notes/[id]/get.ts"
|
|
54
|
+
import { on, flow, http } from "okengine";
|
|
55
|
+
import { z } from "zod";
|
|
56
|
+
|
|
57
|
+
export const get = on(
|
|
58
|
+
http.get({
|
|
59
|
+
in: z.object({ id: z.string() }),
|
|
60
|
+
out: z.object({ id: z.string() }),
|
|
61
|
+
}),
|
|
62
|
+
flow({
|
|
63
|
+
do: async ({ id }) => ({ id }),
|
|
64
|
+
}),
|
|
65
|
+
);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
</Step>
|
|
69
|
+
|
|
70
|
+
<Step>
|
|
71
|
+
### Call the endpoint
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
curl -X GET http://localhost:6530/notes/n_1 -H "accept: application/json"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Response:
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"data": { "id": "n_1" },
|
|
82
|
+
"error": null
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
</Step>
|
|
87
|
+
|
|
88
|
+
</Steps>
|
|
89
|
+
|
|
90
|
+
<Callout title="Method is not the filename">
|
|
91
|
+
`list.ts` does not become `GET` by itself. Reserved leaves only omit a URL segment. Bind
|
|
92
|
+
`http.get()`, `http.post()`, `http.patch()`, or `http.delete()` yourself — see [Reserved
|
|
93
|
+
Leaves](#reserved-leaves).
|
|
94
|
+
</Callout>
|
|
95
|
+
|
|
96
|
+
## Progressive Patterns
|
|
97
|
+
|
|
98
|
+
From a pathless tree file to an explicit barrel, an action leaf, and a catch-all:
|
|
99
|
+
|
|
100
|
+
<Tabs items={["Tree", "Barrel", "Action", "Catch-all"]}>
|
|
101
|
+
|
|
102
|
+
<Tab value="Tree">
|
|
103
|
+
|
|
104
|
+
One file per route. Skip the path argument. The generated barrel calls
|
|
105
|
+
`stampHttpPath` / `stampFlowName` after import:
|
|
106
|
+
|
|
107
|
+
```typescript title="src/flows/notes/list.ts"
|
|
108
|
+
import { on, flow, http } from "okengine";
|
|
109
|
+
|
|
110
|
+
export const list = on(
|
|
111
|
+
http.get(),
|
|
112
|
+
flow({
|
|
113
|
+
do: () => [],
|
|
114
|
+
}),
|
|
115
|
+
);
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Stamped to `GET /notes`, Flow `notes.list`, client `api.notes.list()`.
|
|
119
|
+
|
|
120
|
+
</Tab>
|
|
121
|
+
|
|
122
|
+
<Tab value="Barrel">
|
|
123
|
+
|
|
124
|
+
A unit that is **only** `index.ts` (plus skip-list files) is a barrel. The
|
|
125
|
+
generated file re-exports it **without** stamping — pass explicit paths:
|
|
126
|
+
|
|
127
|
+
```typescript title="src/flows/notes/index.ts"
|
|
128
|
+
import { on, flow, http } from "okengine";
|
|
129
|
+
import { z } from "zod";
|
|
130
|
+
|
|
131
|
+
export const list = on(
|
|
132
|
+
http.get("/notes").public(),
|
|
133
|
+
flow("notes.list", {
|
|
134
|
+
do: () => [],
|
|
135
|
+
}),
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
export const create = on(
|
|
139
|
+
http.post("/notes", { in: z.object({ title: z.string().min(1) }) }),
|
|
140
|
+
flow("notes.create", {
|
|
141
|
+
do: async ({ title }, fx) => ({ id: fx.id(), title }),
|
|
142
|
+
}),
|
|
143
|
+
);
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Pathless `http.get()` inside a barrel stays unresolved and fails boot
|
|
147
|
+
(**OKE1040**).
|
|
148
|
+
|
|
149
|
+
</Tab>
|
|
150
|
+
|
|
151
|
+
<Tab value="Action">
|
|
152
|
+
|
|
153
|
+
A leaf that is not reserved **adds** a segment. `archive.ts` is
|
|
154
|
+
`POST /notes/:id/archive`, not `POST /notes/:id`:
|
|
155
|
+
|
|
156
|
+
```typescript title="src/flows/notes/[id]/archive.ts"
|
|
157
|
+
import { on, flow, http } from "okengine";
|
|
158
|
+
import { z } from "zod";
|
|
159
|
+
|
|
160
|
+
export const archive = on(
|
|
161
|
+
http.post({ in: z.object({ id: z.string() }) }),
|
|
162
|
+
flow({
|
|
163
|
+
do: async ({ id }) => ({ id, archived: true }),
|
|
164
|
+
}),
|
|
165
|
+
);
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
</Tab>
|
|
169
|
+
|
|
170
|
+
<Tab value="Catch-all">
|
|
171
|
+
|
|
172
|
+
`[...slug]` becomes `*` on the URL. The request param is always `"*"`, never
|
|
173
|
+
`slug`:
|
|
174
|
+
|
|
175
|
+
```typescript title="src/flows/docs/[...slug]/get.ts"
|
|
176
|
+
import { on, flow, http } from "okengine";
|
|
177
|
+
import { z } from "zod";
|
|
178
|
+
|
|
179
|
+
export const get = on(
|
|
180
|
+
http.get({ in: z.object({ "*": z.string() }) }).public(),
|
|
181
|
+
flow({
|
|
182
|
+
do: async (input) => ({ path: input["*"] }),
|
|
183
|
+
}),
|
|
184
|
+
);
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
curl -X GET http://localhost:6530/docs/getting-started/install \
|
|
189
|
+
-H "accept: application/json"
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
`do` receives `{ "*": "getting-started/install" }`. Call
|
|
193
|
+
`api.docs.get({ "*": "a/b/c" })` — not `{ slug }`.
|
|
194
|
+
|
|
195
|
+
</Tab>
|
|
196
|
+
|
|
197
|
+
</Tabs>
|
|
198
|
+
|
|
199
|
+
## Convention Reference
|
|
200
|
+
|
|
201
|
+
| Convention | File | Stamped route | Client |
|
|
202
|
+
| ------------- | --------------------------------------- | ------------------------- | ------------------------------ |
|
|
203
|
+
| Dynamic param | `notes/[id]/get.ts` + `http.get()` | `GET /notes/:id` | `api.notes.get({ id })` |
|
|
204
|
+
| Reserved leaf | `notes/list.ts` + `http.get()` | `GET /notes` | `api.notes.list()` |
|
|
205
|
+
| Action leaf | `notes/[id]/archive.ts` + `http.post()` | `POST /notes/:id/archive` | `api.notes.archive({ id })` |
|
|
206
|
+
| Catch-all | `docs/[...slug]/get.ts` + `http.get()` | `GET /docs/*` | `api.docs.get({ "*": "a/b" })` |
|
|
207
|
+
| Route group | `notes/(ops)/archive.ts` | `/notes/archive` | `api.notes.archive` |
|
|
208
|
+
| Root unit | `main/health.ts` + `http.get()` | `GET /health` | `api.main.health()` |
|
|
209
|
+
| Folder root | `main/route.ts` + `http.get()` | `GET /` | `api.main.root()` |
|
|
210
|
+
|
|
211
|
+
## Units
|
|
212
|
+
|
|
213
|
+
The first folder under `src/flows/` is the **client unit**. Nested folders and
|
|
214
|
+
the leaf file build the URL. The `export const` name is the method on that unit.
|
|
215
|
+
|
|
216
|
+
```text
|
|
217
|
+
src/flows/
|
|
218
|
+
├── notes/ # Unit: notes → api.notes.*
|
|
219
|
+
│ ├── list.ts # GET /notes (reserved leaf)
|
|
220
|
+
│ ├── create.ts # POST /notes (reserved leaf)
|
|
221
|
+
│ ├── shapes.ts # skipped (not a route)
|
|
222
|
+
│ └── [id]/
|
|
223
|
+
│ ├── get.ts # GET /notes/:id
|
|
224
|
+
│ └── archive.ts # POST /notes/:id/archive
|
|
225
|
+
├── billing/
|
|
226
|
+
│ └── (checkout)/ # omitted from the URL
|
|
227
|
+
│ └── charge.ts # POST /billing/charge (if http.post())
|
|
228
|
+
└── main/ # Unit: main — prefix omitted from the URL
|
|
229
|
+
├── health.ts # GET /health
|
|
230
|
+
└── route.ts # GET /
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
A file sitting directly in `src/flows/` (no unit folder) is not a route.
|
|
234
|
+
|
|
235
|
+
Unit folder names must be valid JS identifiers (`notes`, `main`, `_` allowed
|
|
236
|
+
inside; `my-notes` is skipped). Folders starting with `_`, `[`, or `(` are not
|
|
237
|
+
units.
|
|
238
|
+
|
|
239
|
+
**Consequence:** `export const getNote` from `get.ts` is `api.notes.getNote`, not
|
|
240
|
+
`api.notes.get`. Match the export to the name you want on the client.
|
|
241
|
+
|
|
242
|
+
## Path Conventions
|
|
243
|
+
|
|
244
|
+
**Default — pathless.** Omit the path so `generated.ts` stamps the URL from disk:
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
http.get(); // pending until stampHttpPath runs
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**Control — explicit path.** Pass the URL template when the folder should not
|
|
251
|
+
own the route (barrel, public API shape, resource mount). The tree never
|
|
252
|
+
overwrites an explicit path:
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
http.get("/organizations/:orgId/members/:memberId");
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Path params, query string, and JSON body still merge into one object checked by
|
|
259
|
+
`in` — same order as [HTTP · Request Parsing](/docs/elements/flow/http#request-parsing).
|
|
260
|
+
|
|
261
|
+
### Dynamic parameters
|
|
262
|
+
|
|
263
|
+
`[id]` → `:id`. The folder name is the param key. Declare the same key on `in`:
|
|
264
|
+
|
|
265
|
+
```typescript title="src/flows/orgs/[orgId]/members/[memberId]/get.ts"
|
|
266
|
+
import { on, flow, http } from "okengine";
|
|
267
|
+
import { z } from "zod";
|
|
268
|
+
|
|
269
|
+
export const get = on(
|
|
270
|
+
http.get({ in: z.object({ orgId: z.string(), memberId: z.string() }) }),
|
|
271
|
+
flow({
|
|
272
|
+
do: async ({ orgId, memberId }) => ({ orgId, memberId }),
|
|
273
|
+
}),
|
|
274
|
+
);
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Stamped to `GET /orgs/:orgId/members/:memberId`.
|
|
278
|
+
|
|
279
|
+
### Catch-alls
|
|
280
|
+
|
|
281
|
+
`[...slug]` → `*` (greedy rest). Optional `[[...slug]]` is **not** supported —
|
|
282
|
+
generate fails with `Optional catch-all "[[...slug]]" is not supported — use [...slug] (param is "*").`
|
|
283
|
+
|
|
284
|
+
A route that includes `*` selects the Trie matcher automatically (the compiled
|
|
285
|
+
RegExp matcher cannot express wildcards).
|
|
286
|
+
|
|
287
|
+
### Route groups
|
|
288
|
+
|
|
289
|
+
A folder `(ops)` is omitted from the URL. Use it to group files without adding a
|
|
290
|
+
segment:
|
|
291
|
+
|
|
292
|
+
```text
|
|
293
|
+
src/flows/notes/(ops)/archive.ts → /notes/archive
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
`(ops)` never enters the Flow name either (`notes.archive`).
|
|
297
|
+
|
|
298
|
+
### The `main` unit
|
|
299
|
+
|
|
300
|
+
`main` is omitted from the URL prefix. Flow names still use `main.`:
|
|
301
|
+
|
|
302
|
+
| File | URL | Flow name |
|
|
303
|
+
| ---------------- | ------------- | -------------------------------------- |
|
|
304
|
+
| `main/health.ts` | `/health` | `main.health` |
|
|
305
|
+
| `main/route.ts` | `/` | `main.root` (from `export const root`) |
|
|
306
|
+
| `main/index.ts` | `/` (extract) | barrel — pass `http.get("/")` |
|
|
307
|
+
|
|
308
|
+
### Skip list
|
|
309
|
+
|
|
310
|
+
These files are never routes (walk skips them; path inference returns nothing):
|
|
311
|
+
|
|
312
|
+
| Pattern | Why |
|
|
313
|
+
| --------------------------- | ------------------------------------------------ |
|
|
314
|
+
| `generated.ts` | Adopt barrel (`oke dev` / `oke build` writes it) |
|
|
315
|
+
| `shapes.ts` | Shared Zod / contracts |
|
|
316
|
+
| `signals.ts` | Signal declarations |
|
|
317
|
+
| `*.test.ts` / `*.test.tsx` | Tests |
|
|
318
|
+
| `_` prefix (file or folder) | Private helpers (`notes/_lib/util.ts`) |
|
|
319
|
+
|
|
320
|
+
Skip-list files may sit next to tree routes. They do **not** turn a tree into a
|
|
321
|
+
barrel.
|
|
322
|
+
|
|
323
|
+
## Reserved Leaves
|
|
324
|
+
|
|
325
|
+
To avoid `/notes/get` and `/orders/list`, these filenames add **no** URL
|
|
326
|
+
segment — the same five CRUD names as `http.resource`, plus folder roots:
|
|
327
|
+
|
|
328
|
+
| Leaf | Typical trigger | Example file | Stamped path |
|
|
329
|
+
| -------- | --------------- | ----------------------------------- | --------------- |
|
|
330
|
+
| `list` | `http.get()` | `notes/list.ts` | `/notes` |
|
|
331
|
+
| `create` | `http.post()` | `notes/create.ts` | `/notes` |
|
|
332
|
+
| `get` | `http.get()` | `notes/[id]/get.ts` | `/notes/:id` |
|
|
333
|
+
| `update` | `http.patch()` | `notes/[id]/update.ts` | `/notes/:id` |
|
|
334
|
+
| `remove` | `http.delete()` | `notes/[id]/remove.ts` | `/notes/:id` |
|
|
335
|
+
| `index` | _(barrel only)_ | `notes/index.ts` | `/notes` |
|
|
336
|
+
| `route` | any | `notes/route.ts` or `main/route.ts` | `/notes` or `/` |
|
|
337
|
+
|
|
338
|
+
Any other leaf **is** a segment: `query.ts` → `/notes/query`.
|
|
339
|
+
|
|
340
|
+
In a tree unit, do **not** add `index.ts` beside other route files — that is a
|
|
341
|
+
generate error. Use `route.ts` (or `list.ts` / `create.ts`) for the collection
|
|
342
|
+
root.
|
|
343
|
+
|
|
344
|
+
## Barrel vs Tree
|
|
345
|
+
|
|
346
|
+
`oke dev` / `oke build` scans each `src/flows/<unit>/` folder and writes
|
|
347
|
+
`generated.ts`. Two shapes, never mixed:
|
|
348
|
+
|
|
349
|
+
<Tabs items={["Tree", "Barrel", "App entry"]}>
|
|
350
|
+
|
|
351
|
+
<Tab value="Tree">
|
|
352
|
+
|
|
353
|
+
`[param]` folders, `(group)` folders, or extra route files. The barrel imports
|
|
354
|
+
each file and stamps path + name:
|
|
355
|
+
|
|
356
|
+
```typescript
|
|
357
|
+
const notes = {
|
|
358
|
+
get: stampHttpPath(stampFlowName(notes_$id$_get.get, "notes.get"), "/notes/:id"),
|
|
359
|
+
list: stampHttpPath(stampFlowName(notes_list.list, "notes.list"), "/notes"),
|
|
360
|
+
};
|
|
361
|
+
export { notes };
|
|
362
|
+
registerFlowUnits({ notes });
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
`oke()` drains `registerFlowUnits` into `$routes`. `.adopt({ notes })` is
|
|
366
|
+
optional and additive.
|
|
367
|
+
|
|
368
|
+
</Tab>
|
|
369
|
+
|
|
370
|
+
<Tab value="Barrel">
|
|
371
|
+
|
|
372
|
+
Only `index.ts` (+ skip-list). Re-export, no stamp:
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
import * as notes from "./notes/index.ts";
|
|
376
|
+
export { notes };
|
|
377
|
+
registerFlowUnits({ notes });
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
Declare `http.get("/notes")` and `flow("notes.list", {…})` (or rely on adopt to
|
|
381
|
+
stamp the name from the export). Pathless HTTP fails **OKE1040**.
|
|
382
|
+
|
|
383
|
+
</Tab>
|
|
384
|
+
|
|
385
|
+
<Tab value="App entry">
|
|
386
|
+
|
|
387
|
+
```typescript title="src/app.ts"
|
|
388
|
+
import "@/flows/generated";
|
|
389
|
+
import { oke } from "okengine";
|
|
390
|
+
|
|
391
|
+
export const app = oke({ name: "notes" });
|
|
392
|
+
export type App = typeof app;
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
Do not edit `generated.ts` by hand. Adding a unit folder without regenerating
|
|
396
|
+
leaves a stale barrel — **OKE1030** in prod / `oke dev` with Compose.
|
|
397
|
+
|
|
398
|
+
</Tab>
|
|
399
|
+
|
|
400
|
+
</Tabs>
|
|
401
|
+
|
|
402
|
+
<Accordions>
|
|
403
|
+
|
|
404
|
+
<Accordion title="Mixed barrel + tree">
|
|
405
|
+
`index.ts` plus `[id]/get.ts` (or any other route file) throws at generate:
|
|
406
|
+
|
|
407
|
+
```text
|
|
408
|
+
Unit "notes" mixes a barrel index.ts with tree route files. Use only index.ts (barrel), or move the collection path to route.ts and keep [id]/ beside it.
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
Fix: delete `index.ts` and use `list.ts` / `route.ts`, or fold every route into
|
|
412
|
+
`index.ts` with explicit paths.
|
|
413
|
+
|
|
414
|
+
</Accordion>
|
|
415
|
+
|
|
416
|
+
<Accordion title="Export collisions">
|
|
417
|
+
Two files in the same unit cannot share an `export const` name:
|
|
418
|
+
|
|
419
|
+
```text
|
|
420
|
+
Unit "notes" exports "get" from both list.ts and route.ts.
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
Rename one export. The client method is the export name, not the filename.
|
|
424
|
+
|
|
425
|
+
</Accordion>
|
|
426
|
+
|
|
427
|
+
<Accordion title="Unit-prefix drift">
|
|
428
|
+
`flow("tasks.get", {…})` living under `src/flows/notes/` throws:
|
|
429
|
+
|
|
430
|
+
```text
|
|
431
|
+
flow("tasks.…") in notes/get.ts does not match the folder "notes".
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
Use `flow("notes.get", {…})`, a nameless `flow({ do })` (stamped `notes.get`
|
|
435
|
+
from the export), or move the file.
|
|
436
|
+
|
|
437
|
+
</Accordion>
|
|
438
|
+
|
|
439
|
+
</Accordions>
|
|
440
|
+
|
|
441
|
+
## Names
|
|
442
|
+
|
|
443
|
+
Three names, one file:
|
|
444
|
+
|
|
445
|
+
| Surface | Source | Example |
|
|
446
|
+
| --------- | ------------------------------------------------------------------- | ----------------------- |
|
|
447
|
+
| HTTP path | File tree (default) or explicit `http.get("/x")` | `/notes/:id` |
|
|
448
|
+
| Flow name | `unit.export` from `flow({ do })` (default), or `flow("notes.get")` | `notes.get` |
|
|
449
|
+
| Client | Unit folder + `export const` | `api.notes.get({ id })` |
|
|
450
|
+
|
|
451
|
+
Nameless `flow({ do })` is the tree default — same rule as pathless HTTP. Pass
|
|
452
|
+
`flow("notes.get")` only for control (stable name, barrel, or matching unit
|
|
453
|
+
prefix). Wrong-unit prefixes fail generate.
|
|
454
|
+
|
|
455
|
+
Non-HTTP files still join the unit. A signal consumer in `notes/on-created.ts`
|
|
456
|
+
is `api.notes.onCreated` over RPC (`POST /_oke/notes/onCreated`), not HTTP.
|
|
457
|
+
|
|
458
|
+
HTTP flows that remain nameless after adopt fail **OKE1045**.
|
|
459
|
+
|
|
460
|
+
## Runtime Matching
|
|
461
|
+
|
|
462
|
+
All adopted HTTP bindings go into one matcher. Wrong method on a known path is
|
|
463
|
+
**405** with `Allow`. No match is a bare **404** `Not Found`.
|
|
464
|
+
|
|
465
|
+
| `oke({ router })` | Default | What it does |
|
|
466
|
+
| ----------------- | ------- | ----------------------------------------------------------------------------------------------------------- |
|
|
467
|
+
| `"default"` | yes | Compiled RegExp (O(1) static map + per-bucket regex for `:id`). Falls back to Trie when a path includes `*` |
|
|
468
|
+
| `"edge"` | | Linear scan, then Trie. No RegExp compile — cold-start / isolates |
|
|
469
|
+
|
|
470
|
+
p99 match stays under **1 ms** on the compiled matcher. You do not pick buckets
|
|
471
|
+
by hand — a catch-all in the table selects Trie for the whole app.
|
|
472
|
+
|
|
473
|
+
Duplicate `METHOD + path` fails boot (**OKE1041**), including a resource mount
|
|
474
|
+
plus a handwritten `http.get("/notes")`.
|
|
475
|
+
|
|
476
|
+
## Troubleshooting
|
|
477
|
+
|
|
478
|
+
<Accordions>
|
|
479
|
+
|
|
480
|
+
<Accordion title="404 Not Found — route missing">
|
|
481
|
+
No Flow is bound to that method + path. Check the explicit path, or for pathless routes the
|
|
482
|
+
file-tree stamp (`notes/[id]/get.ts` → `GET /notes/:id`). A bare `404` with body `Not Found` means
|
|
483
|
+
the router found no match.
|
|
484
|
+
</Accordion>
|
|
485
|
+
|
|
486
|
+
<Accordion title="405 Method Not Allowed on valid route">
|
|
487
|
+
The path exists but has not been bound to the requested verb. `Allow` lists the methods that are.
|
|
488
|
+
`list.ts` with `http.get()` is GET-only — POST that URL is 405, not a missing file.
|
|
489
|
+
</Accordion>
|
|
490
|
+
|
|
491
|
+
<Accordion title="OKE1040 — pathless trigger never stamped">
|
|
492
|
+
Cause: `Flow "{flow}" bound {method} with no path — the file-tree stamp never ran.` Import
|
|
493
|
+
`@/flows/generated`, run `oke dev` / `oke build`, or pass `http.get("/…")`. Barrels do not stamp —
|
|
494
|
+
they need the explicit path.
|
|
495
|
+
</Accordion>
|
|
496
|
+
|
|
497
|
+
<Accordion title="OKE1030 — adopt barrel stale">
|
|
498
|
+
Cause: `src/flows/{unit} exists on disk but adopted no flows — the .adopt() barrel is stale.` Run
|
|
499
|
+
`oke dev` or `oke build` after adding a unit folder. Prod and Compose `oke dev` refuse to boot
|
|
500
|
+
this way.
|
|
501
|
+
</Accordion>
|
|
502
|
+
|
|
503
|
+
<Accordion title="OKE1041 — method + path bound twice">
|
|
504
|
+
Cause: `{method} {path} is bound twice (flow "{flow}").` Two tree files stamped the same verb +
|
|
505
|
+
path (`list.ts` and `route.ts` both `http.get()`), or a resource mount plus a handwritten route.
|
|
506
|
+
Drop one binding.
|
|
507
|
+
</Accordion>
|
|
508
|
+
|
|
509
|
+
<Accordion title="OKE1045 — HTTP flow unnamed">
|
|
510
|
+
Cause: `An HTTP flow on {method} {path} has no name.`
|
|
511
|
+
Use `flow("unit.export", {…})` or `export const` from a `src/flows/<unit>/`
|
|
512
|
+
file so the tree can stamp `unit.export`. `export default` is not picked up.
|
|
513
|
+
</Accordion>
|
|
514
|
+
|
|
515
|
+
<Accordion title="422 — path param missing from in">
|
|
516
|
+
`[id]` stamps `:id`. `in` must declare `id` (same key). A schema that expects `userId` while the
|
|
517
|
+
path is `:id` fails validation before `do`.
|
|
518
|
+
</Accordion>
|
|
519
|
+
|
|
520
|
+
<Accordion title="Catch-all input is empty / wrong key">
|
|
521
|
+
`[...slug]` does not bind `slug`. The router param is `"*"`. Declare
|
|
522
|
+
`in: z.object({ "*": z.string() })` and read `input["*"]`. Optional
|
|
523
|
+
`[[...slug]]` is rejected at generate.
|
|
524
|
+
</Accordion>
|
|
525
|
+
|
|
526
|
+
<Accordion title="Unit mixes index.ts with tree files">
|
|
527
|
+
Generate: `Unit "…" mixes a barrel index.ts with tree route files.` Use only `index.ts` (explicit
|
|
528
|
+
paths), or move the collection path to `route.ts` and keep `[id]/` beside it.
|
|
529
|
+
</Accordion>
|
|
530
|
+
|
|
531
|
+
</Accordions>
|
|
532
|
+
|
|
533
|
+
## Learn more
|
|
534
|
+
|
|
535
|
+
- [HTTP](/docs/elements/flow/http) — verbs, envelopes, `http.resource`, live SSE
|
|
536
|
+
- [Client](/docs/client/calling) — `api.notes.get`, REST vs RPC, `$routes`
|
|
537
|
+
- [Errors](/docs/reference/errors) — OKE1040 · OKE1030 · OKE1041 · OKE1045
|
|
538
|
+
- [The Model](/docs/understand/the-model) — derived routes, no hand-written table
|
|
539
|
+
- [Gate](/docs/elements/gate) — `.gate(...)` / `.public()` on the same trigger
|
|
540
|
+
|
|
541
|
+
## Next
|
|
542
|
+
|
|
543
|
+
<Cards>
|
|
544
|
+
<Card
|
|
545
|
+
title="HTTP"
|
|
546
|
+
description="REST verbs, RFC 10008 QUERY, CRUD mounts, and live SSE on Flow."
|
|
547
|
+
href="/docs/elements/flow/http"
|
|
548
|
+
/>
|
|
549
|
+
<Card
|
|
550
|
+
title="Client"
|
|
551
|
+
description="Typed caller — createClient, envelopes, REST from $routes."
|
|
552
|
+
href="/docs/client/calling"
|
|
553
|
+
/>
|
|
554
|
+
<Card
|
|
555
|
+
title="Consumers"
|
|
556
|
+
description="Signal workers, named Clock jobs, and SQL CDC — one Flow species."
|
|
557
|
+
href="/docs/elements/flow/consumers"
|
|
558
|
+
/>
|
|
559
|
+
</Cards>
|