okengine 0.2.6 → 0.3.2
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 +33 -30
- package/README.md +74 -340
- package/{spec/manifest.v1.schema.json → manifest.v1.schema.json} +40 -9
- package/package.json +47 -44
- package/site/content/docs/ai/llms-txt.mdx +54 -0
- package/site/content/docs/ai/mcp.mdx +123 -0
- package/site/content/docs/ai/meta.json +5 -0
- package/site/content/docs/ai/skills.mdx +53 -0
- package/site/content/docs/console/access.mdx +29 -0
- package/site/content/docs/console/ai.mdx +35 -0
- package/site/content/docs/console/architecture.mdx +35 -0
- package/site/content/docs/console/channels.mdx +37 -0
- package/site/content/docs/console/clock.mdx +31 -0
- package/site/content/docs/console/flows.mdx +31 -0
- package/site/content/docs/console/gates.mdx +35 -0
- package/site/content/docs/console/manifest-diff.mdx +34 -0
- package/site/content/docs/console/meta.json +23 -0
- package/site/content/docs/console/overview.mdx +40 -0
- package/site/content/docs/console/plugins.mdx +41 -0
- package/site/content/docs/console/privacy.mdx +32 -0
- package/site/content/docs/console/runs.mdx +40 -0
- package/site/content/docs/console/signals.mdx +31 -0
- package/site/content/docs/console/store.mdx +32 -0
- package/site/content/docs/console/tenancy.mdx +32 -0
- package/site/content/docs/console/traces.mdx +34 -0
- package/site/content/docs/console/vault.mdx +37 -0
- package/site/content/docs/elements/ai.mdx +180 -0
- package/site/content/docs/elements/channel.mdx +167 -0
- package/site/content/docs/elements/clock.mdx +182 -0
- package/site/content/docs/elements/flow.mdx +288 -0
- package/site/content/docs/elements/gate.mdx +171 -0
- package/site/content/docs/elements/meta.json +5 -0
- package/site/content/docs/elements/signal.mdx +171 -0
- package/site/content/docs/elements/store.mdx +320 -0
- package/site/content/docs/elements/vault.mdx +263 -0
- package/site/content/docs/get-started/basic-usage.mdx +124 -0
- package/site/content/docs/get-started/comparison.mdx +65 -0
- package/site/content/docs/get-started/installation.mdx +113 -0
- package/site/content/docs/get-started/introduction.mdx +123 -0
- package/site/content/docs/get-started/meta.json +5 -0
- package/site/content/docs/index.mdx +63 -0
- package/site/content/docs/meta.json +5 -0
- package/site/content/docs/plugins/compression.mdx +60 -0
- package/site/content/docs/plugins/cors.mdx +92 -0
- package/site/content/docs/plugins/csrf.mdx +96 -0
- package/site/content/docs/plugins/ip-allowlist.mdx +92 -0
- package/site/content/docs/plugins/maintenance-mode.mdx +101 -0
- package/site/content/docs/plugins/meta.json +15 -0
- package/site/content/docs/plugins/security-headers.mdx +136 -0
- package/site/content/docs/reference/cli.md +101 -0
- package/site/content/docs/reference/configuration.mdx +159 -0
- package/site/content/docs/reference/environment-variables.mdx +87 -0
- package/site/content/docs/reference/errors.mdx +80 -0
- package/site/content/docs/reference/fx.mdx +117 -0
- package/site/content/docs/reference/meta.json +5 -0
- package/site/content/docs/reference/plugins.mdx +249 -0
- package/site/content/docs/reference/security.md +63 -0
- package/src/auth/api-keys.ts +2 -5
- package/src/auth/attenuation.ts +2 -6
- package/src/auth/auth.test.ts +56 -31
- package/src/auth/invoke-as.ts +1 -3
- package/src/auth/operator.ts +8 -26
- package/src/auth/planes.ts +2 -7
- package/src/auth/plugin.ts +4 -7
- package/src/auth/roles.ts +1 -5
- package/src/auth/sessions.ts +10 -39
- package/src/cli/args.ts +1 -5
- package/src/cli/ask-dev-mode.ts +40 -0
- package/src/cli/build.ts +1 -2
- package/src/cli/client-add.test.ts +8 -15
- package/src/cli/client-add.ts +5 -14
- package/src/cli/completion.test.ts +1 -5
- package/src/cli/completion.ts +4 -17
- package/src/cli/db-auto-push.test.ts +64 -0
- package/src/cli/db-auto-push.ts +72 -0
- package/src/cli/db.test.ts +189 -0
- package/src/cli/db.ts +456 -0
- package/src/cli/dev-app-runner.ts +2 -8
- package/src/cli/dev-db-push.test.ts +193 -0
- package/src/cli/dev-mode.test.ts +45 -0
- package/src/cli/dev-mode.ts +78 -0
- package/src/cli/dev-schema-sync.test.ts +66 -0
- package/src/cli/dev-schema-sync.ts +139 -0
- package/src/cli/dev.test.ts +264 -15
- package/src/cli/dev.ts +355 -139
- package/src/cli/doc-staleness.test.ts +69 -0
- package/src/cli/docker-cli.test.ts +27 -8
- package/src/cli/docker.ts +11 -3
- package/src/cli/doctor-diff.test.ts +1 -5
- package/src/cli/doctor-diff.ts +17 -46
- package/src/cli/doctor-pii.ts +2 -7
- package/src/cli/doctor.test.ts +26 -4
- package/src/cli/doctor.ts +35 -11
- package/src/cli/drizzle-env.test.ts +67 -0
- package/src/cli/drizzle-env.ts +78 -0
- package/src/cli/ensure-drizzle-config.ts +50 -0
- package/src/cli/eval.ts +4 -14
- package/src/cli/gates-list.ts +1 -4
- package/src/cli/hero-meta.test.ts +17 -19
- package/src/cli/hero-meta.ts +20 -30
- package/src/cli/images.ts +3 -8
- package/src/cli/index.ts +11 -2
- package/src/cli/load-config.images.test.ts +14 -14
- package/src/cli/load-config.ts +47 -47
- package/src/cli/mcp-from-console.ts +1 -4
- package/src/cli/mode.ts +65 -0
- package/src/cli/openbao-bootstrap.test.ts +147 -0
- package/src/cli/openbao-bootstrap.ts +280 -0
- package/src/cli/openbao-restart.integration.test.ts +136 -0
- package/src/cli/ports.test.ts +7 -14
- package/src/cli/ports.ts +7 -5
- package/src/cli/privacy-erase.ts +1 -3
- package/src/cli/registry.ts +75 -25
- package/src/cli/resolve-dev-sql-env.test.ts +48 -0
- package/src/cli/resolve-dev-sql-env.ts +42 -0
- package/src/cli/schema.ts +3 -10
- package/src/cli/stack.ts +8 -10
- package/src/cli/start.ts +4 -15
- package/src/cli/upgrade.ts +1 -4
- package/src/cli/vault-cmd.ts +63 -0
- package/src/client/budget-entry.ts +1 -6
- package/src/client/create.test.ts +6 -12
- package/src/client/create.ts +2 -8
- package/src/client/errors.ts +1 -4
- package/src/client/index.ts +1 -6
- package/src/client/notes-contract.test.ts +4 -13
- package/src/client/transport.ts +9 -30
- package/src/client/types.ts +15 -30
- package/src/compiler/aot.test.ts +2 -9
- package/src/compiler/aot.ts +1 -4
- package/src/compiler/differential.test.ts +3 -11
- package/src/compiler/dynamic.ts +1 -4
- package/src/compiler/effects-infer.ts +8 -34
- package/src/compiler/emit.ts +1 -3
- package/src/compiler/extract.test.ts +136 -30
- package/src/compiler/extract.ts +485 -157
- package/src/compiler/fixtures/skyport/oke.config.ts +3 -3
- package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +7 -3
- package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +1 -3
- package/src/compiler/fixtures/skyport/src/flows/support/index.ts +4 -1
- package/src/compiler/fixtures/skyport.expected.json +24 -83
- package/src/compiler/fixtures/triggers/five-triggers.ts +1 -2
- package/src/compiler/http-parse.ts +2 -9
- package/src/compiler/index.ts +1 -5
- package/src/compiler/response.ts +16 -7
- package/src/compiler/sucrose.ts +11 -31
- package/src/config/define-config.test.ts +55 -34
- package/src/config/index.ts +177 -46
- package/src/config/resolve-driver.test.ts +28 -17
- package/src/console/budget.test.ts +1 -4
- package/src/console/index.ts +1 -4
- package/src/console/server/access.test.ts +15 -43
- package/src/console/server/access.ts +19 -49
- package/src/console/server/ai.test.ts +3 -11
- package/src/console/server/ai.ts +23 -46
- package/src/console/server/app.ts +16 -45
- package/src/console/server/auth-rate.test.ts +4 -12
- package/src/console/server/bind.ts +1 -5
- package/src/console/server/channels.test.ts +2 -6
- package/src/console/server/channels.ts +10 -35
- package/src/console/server/claim.ts +2 -8
- package/src/console/server/clock.test.ts +2 -6
- package/src/console/server/clock.ts +8 -26
- package/src/console/server/console.test.ts +1 -3
- package/src/console/server/diff.test.ts +5 -17
- package/src/console/server/diff.ts +10 -31
- package/src/console/server/dry-run.audit.test.ts +2 -8
- package/src/console/server/flows.ts +64 -233
- package/src/console/server/gates.test.ts +14 -50
- package/src/console/server/gates.ts +13 -48
- package/src/console/server/index.ts +2 -9
- package/src/console/server/live.ts +3 -12
- package/src/console/server/operator-db.test.ts +4 -15
- package/src/console/server/operator-db.ts +13 -32
- package/src/console/server/plugin.ts +50 -53
- package/src/console/server/plugins.test.ts +2 -6
- package/src/console/server/plugins.ts +17 -56
- package/src/console/server/runs-pii.ts +2 -7
- package/src/console/server/security.gate.test.ts +18 -40
- package/src/console/server/serve.ts +10 -25
- package/src/console/server/signals.test.ts +1 -3
- package/src/console/server/signals.ts +17 -40
- package/src/console/server/state.ts +21 -59
- package/src/console/server/store.test.ts +20 -22
- package/src/console/server/store.ts +31 -76
- package/src/console/server/vault.test.ts +12 -29
- package/src/console/server/vault.ts +44 -66
- package/src/console/ui/access/AccessA11yView.tsx +6 -21
- package/src/console/ui/access/a11y.test.tsx +3 -12
- package/src/console/ui/access/acknowledgement.test.ts +1 -4
- package/src/console/ui/access/acknowledgement.ts +1 -3
- package/src/console/ui/access/blast-radius.ts +1 -3
- package/src/console/ui/access/confirmation.test.ts +1 -5
- package/src/console/ui/access/confirmation.ts +1 -4
- package/src/console/ui/access/fixture.ts +1 -5
- package/src/console/ui/access/grantable.test.ts +1 -3
- package/src/console/ui/access/grantable.ts +2 -7
- package/src/console/ui/access/index.ts +2 -9
- package/src/console/ui/access/provenance.test.ts +1 -3
- package/src/console/ui/access/provenance.ts +2 -6
- package/src/console/ui/access/search.test.ts +1 -5
- package/src/console/ui/access/search.ts +2 -6
- package/src/console/ui/ai/AiA11yView.tsx +6 -17
- package/src/console/ui/ai/a11y.test.tsx +2 -5
- package/src/console/ui/ai/fixture.ts +2 -7
- package/src/console/ui/ai/format.ts +1 -3
- package/src/console/ui/ai/group.test.ts +1 -3
- package/src/console/ui/ai/group.ts +4 -12
- package/src/console/ui/ai/index.ts +2 -9
- package/src/console/ui/ai/promotion.test.ts +2 -7
- package/src/console/ui/ai/promotion.ts +4 -13
- package/src/console/ui/ai/search.test.ts +2 -11
- package/src/console/ui/ai/search.ts +3 -13
- package/src/console/ui/ai/types.ts +1 -8
- package/src/console/ui/architecture/ArchitectureA11yView.tsx +8 -29
- package/src/console/ui/architecture/a11y.test.tsx +1 -2
- package/src/console/ui/architecture/declared.ts +1 -5
- package/src/console/ui/architecture/index.ts +7 -35
- package/src/console/ui/architecture/layout.ts +1 -3
- package/src/console/ui/architecture/pathologies.ts +10 -19
- package/src/console/ui/architecture/search.ts +6 -15
- package/src/console/ui/architecture/traffic.ts +4 -14
- package/src/console/ui/architecture/types.ts +2 -10
- package/src/console/ui/architecture/view.test.ts +7 -19
- package/src/console/ui/architecture/view.ts +9 -36
- package/src/console/ui/channels/ChannelsA11yView.tsx +4 -13
- package/src/console/ui/channels/a11y.test.tsx +1 -2
- package/src/console/ui/channels/confirmation.test.ts +1 -4
- package/src/console/ui/channels/confirmation.ts +1 -4
- package/src/console/ui/channels/findings.ts +1 -5
- package/src/console/ui/channels/index.ts +2 -8
- package/src/console/ui/channels/locale.test.ts +1 -3
- package/src/console/ui/channels/locale.ts +2 -8
- package/src/console/ui/channels/search.ts +4 -13
- package/src/console/ui/channels/taxonomy.ts +1 -3
- package/src/console/ui/clock/ClockA11yView.tsx +9 -26
- package/src/console/ui/clock/a11y.test.tsx +2 -5
- package/src/console/ui/clock/confirmation.test.ts +1 -3
- package/src/console/ui/clock/confirmation.ts +1 -4
- package/src/console/ui/clock/findings.ts +1 -4
- package/src/console/ui/clock/health.ts +2 -7
- package/src/console/ui/clock/index.ts +2 -10
- package/src/console/ui/clock/search.test.ts +1 -3
- package/src/console/ui/clock/search.ts +2 -6
- package/src/console/ui/clock/timeline.test.ts +1 -3
- package/src/console/ui/clock/waiting-on.test.ts +1 -5
- package/src/console/ui/clock/waiting-on.ts +2 -7
- package/src/console/ui/diff/DiffA11yView.tsx +8 -17
- package/src/console/ui/diff/a11y.test.tsx +2 -5
- package/src/console/ui/diff/group.test.ts +3 -13
- package/src/console/ui/diff/group.ts +2 -8
- package/src/console/ui/diff/index.ts +2 -8
- package/src/console/ui/diff/search.test.ts +1 -5
- package/src/console/ui/diff/search.ts +4 -16
- package/src/console/ui/diff/summary.ts +1 -2
- package/src/console/ui/dist/assets/{index-Dy4jht9P.js → index-BWo8R7NR.js} +2 -2
- package/src/console/ui/dist/assets/{panel-access-Dd37LU2c.js → panel-access-C0J2D-a2.js} +1 -1
- package/src/console/ui/dist/assets/{panel-ai-CC7LR6-J.js → panel-ai-D_m6WQI8.js} +1 -1
- package/src/console/ui/dist/assets/{panel-architecture-B5b3iKCz.js → panel-architecture-CKnXFyUx.js} +1 -1
- package/src/console/ui/dist/assets/{panel-channels-CeNjTKXp.js → panel-channels-BOmQ-onL.js} +1 -1
- package/src/console/ui/dist/assets/{panel-clock-DgFTLoHV.js → panel-clock-giAq0Ccv.js} +1 -1
- package/src/console/ui/dist/assets/{panel-diff-DxehccqB.js → panel-diff-cdonmH8c.js} +1 -1
- package/src/console/ui/dist/assets/{panel-flows-BtrVn-Eg.js → panel-flows-DlCU5zjA.js} +2 -2
- package/src/console/ui/dist/assets/{panel-gates-Z9MKRGdH.js → panel-gates-XclZxWD5.js} +1 -1
- package/src/console/ui/dist/assets/{panel-overview-Dt_AeXgd.js → panel-overview-BznEOTnb.js} +1 -1
- package/src/console/ui/dist/assets/{panel-plugins-DWd0TowH.js → panel-plugins-CcGM1g64.js} +1 -1
- package/src/console/ui/dist/assets/{panel-runs-DGstFHeq.js → panel-runs-CGWNHLR4.js} +1 -1
- package/src/console/ui/dist/assets/{panel-signals-DzEa2Fnt.js → panel-signals-CNywkdak.js} +1 -1
- package/src/console/ui/dist/assets/{panel-store-BJkbNgxx.js → panel-store-KmTbFHMH.js} +1 -1
- package/src/console/ui/dist/assets/{panel-traces-BaRVO3gM.js → panel-traces-DBLx2ilD.js} +1 -1
- package/src/console/ui/dist/assets/panel-vault-CEnFc0dk.js +1 -0
- package/src/console/ui/dist/index.html +1 -1
- package/src/console/ui/flows/FlowsA11yView.tsx +7 -22
- package/src/console/ui/flows/a11y.test.tsx +2 -8
- package/src/console/ui/flows/buffer.test.ts +3 -11
- package/src/console/ui/flows/buffer.ts +4 -11
- package/src/console/ui/flows/confirmation.ts +1 -3
- package/src/console/ui/flows/contract.test.ts +3 -7
- package/src/console/ui/flows/contract.ts +12 -36
- package/src/console/ui/flows/graph.test.ts +3 -11
- package/src/console/ui/flows/graph.ts +5 -15
- package/src/console/ui/flows/index.ts +1 -6
- package/src/console/ui/flows/save-as-test.ts +1 -3
- package/src/console/ui/flows/search.ts +8 -25
- package/src/console/ui/flows/tiers.ts +2 -9
- package/src/console/ui/gates/GatesA11yView.tsx +4 -13
- package/src/console/ui/gates/a11y.test.tsx +2 -5
- package/src/console/ui/gates/audit.ts +1 -3
- package/src/console/ui/gates/denial.test.ts +1 -3
- package/src/console/ui/gates/denial.ts +4 -12
- package/src/console/ui/gates/findings.ts +1 -3
- package/src/console/ui/gates/group.test.ts +3 -3
- package/src/console/ui/gates/group.ts +3 -11
- package/src/console/ui/gates/index.ts +2 -10
- package/src/console/ui/gates/search.ts +3 -10
- package/src/console/ui/overview/OverviewA11yView.tsx +9 -27
- package/src/console/ui/overview/a11y.test.tsx +1 -2
- package/src/console/ui/overview/busiest.ts +1 -3
- package/src/console/ui/overview/compose.ts +1 -13
- package/src/console/ui/overview/cost.ts +34 -38
- package/src/console/ui/overview/fixture.ts +21 -26
- package/src/console/ui/overview/golden.ts +4 -14
- package/src/console/ui/overview/index.ts +2 -9
- package/src/console/ui/overview/rank.test.ts +3 -10
- package/src/console/ui/overview/rank.ts +2 -7
- package/src/console/ui/overview/slo.test.ts +5 -9
- package/src/console/ui/overview/slo.ts +6 -23
- package/src/console/ui/overview/verdict.ts +3 -10
- package/src/console/ui/plugins/PluginsA11yView.tsx +8 -18
- package/src/console/ui/plugins/a11y.test.tsx +1 -2
- package/src/console/ui/plugins/fixture.ts +2 -4
- package/src/console/ui/plugins/group.test.ts +1 -3
- package/src/console/ui/plugins/group.ts +1 -6
- package/src/console/ui/plugins/index.ts +3 -13
- package/src/console/ui/plugins/search.ts +7 -19
- package/src/console/ui/runs/RunsA11yView.tsx +5 -20
- package/src/console/ui/runs/a11y.test.tsx +2 -5
- package/src/console/ui/runs/explain.ts +2 -6
- package/src/console/ui/runs/group.ts +3 -12
- package/src/console/ui/runs/histogram.test.ts +2 -11
- package/src/console/ui/runs/histogram.ts +1 -4
- package/src/console/ui/runs/index.ts +4 -18
- package/src/console/ui/runs/project.ts +2 -6
- package/src/console/ui/runs/query.test.ts +1 -3
- package/src/console/ui/runs/query.ts +12 -35
- package/src/console/ui/runs/search.ts +5 -19
- package/src/console/ui/runs/trace-link.test.ts +2 -6
- package/src/console/ui/runs/trace-link.ts +4 -16
- package/src/console/ui/runs/types.ts +1 -3
- package/src/console/ui/shell/App.tsx +2 -10
- package/src/console/ui/shell/client.ts +22 -115
- package/src/console/ui/shell/components/ui.tsx +1 -4
- package/src/console/ui/shell/layout/Shell.tsx +2 -4
- package/src/console/ui/shell/main.tsx +31 -96
- package/src/console/ui/shell/panels/access/AccessPanel.tsx +34 -98
- package/src/console/ui/shell/panels/ai/AiPanel.tsx +35 -106
- package/src/console/ui/shell/panels/architecture/ArchitecturePanel.tsx +18 -66
- package/src/console/ui/shell/panels/channels/ChannelsPanel.tsx +20 -57
- package/src/console/ui/shell/panels/clock/ClockPanel.tsx +22 -54
- package/src/console/ui/shell/panels/diff/DiffPanel.tsx +20 -61
- package/src/console/ui/shell/panels/flows/ContractEditor.tsx +6 -23
- package/src/console/ui/shell/panels/flows/FlowDrawer.tsx +13 -28
- package/src/console/ui/shell/panels/flows/FlowsPanel.tsx +9 -29
- package/src/console/ui/shell/panels/gates/GatesPanel.tsx +24 -80
- package/src/console/ui/shell/panels/overview/OverviewPanel.tsx +20 -58
- package/src/console/ui/shell/panels/plugins/PluginsPanel.tsx +16 -41
- package/src/console/ui/shell/panels/runs/RunsPanel.tsx +31 -99
- package/src/console/ui/shell/panels/signals/SignalsPanel.tsx +38 -101
- package/src/console/ui/shell/panels/store/StorePanel.tsx +27 -66
- package/src/console/ui/shell/panels/traces/TracesPanel.tsx +28 -89
- package/src/console/ui/shell/panels/vault/VaultPanel.tsx +22 -53
- package/src/console/ui/shell/setup/Wizard.tsx +3 -5
- package/src/console/ui/shell/styles.css +1 -2
- package/src/console/ui/signals/SignalsA11yView.tsx +9 -33
- package/src/console/ui/signals/a11y.test.tsx +2 -5
- package/src/console/ui/signals/confirmation.test.ts +1 -5
- package/src/console/ui/signals/confirmation.ts +2 -6
- package/src/console/ui/signals/dry-run.ts +1 -3
- package/src/console/ui/signals/durable.ts +1 -3
- package/src/console/ui/signals/findings.ts +1 -3
- package/src/console/ui/signals/group.test.ts +2 -8
- package/src/console/ui/signals/group.ts +2 -10
- package/src/console/ui/signals/index.ts +1 -4
- package/src/console/ui/signals/monitor.ts +2 -7
- package/src/console/ui/signals/schema-form.test.ts +3 -14
- package/src/console/ui/signals/schema-form.ts +1 -4
- package/src/console/ui/signals/search.ts +4 -13
- package/src/console/ui/store/StoreA11yView.tsx +3 -9
- package/src/console/ui/store/a11y.test.tsx +2 -5
- package/src/console/ui/store/confirmation.test.ts +1 -3
- package/src/console/ui/store/confirmation.ts +1 -4
- package/src/console/ui/store/dry-run.ts +2 -5
- package/src/console/ui/store/fixture.ts +1 -2
- package/src/console/ui/store/group.test.ts +1 -6
- package/src/console/ui/store/group.ts +1 -4
- package/src/console/ui/store/index.ts +1 -5
- package/src/console/ui/store/search.ts +2 -6
- package/src/console/ui/store/will-not-fire.ts +1 -2
- package/src/console/ui/traces/TracesA11yView.tsx +10 -29
- package/src/console/ui/traces/a11y.test.tsx +1 -2
- package/src/console/ui/traces/chain.test.ts +5 -19
- package/src/console/ui/traces/chain.ts +1 -3
- package/src/console/ui/traces/critical-path.test.ts +1 -3
- package/src/console/ui/traces/critical-path.ts +2 -6
- package/src/console/ui/traces/filter.test.ts +2 -6
- package/src/console/ui/traces/filter.ts +5 -13
- package/src/console/ui/traces/fold.test.ts +4 -12
- package/src/console/ui/traces/fold.ts +1 -3
- package/src/console/ui/traces/mini.ts +1 -3
- package/src/console/ui/traces/replay.test.ts +1 -3
- package/src/console/ui/traces/replay.ts +1 -3
- package/src/console/ui/traces/sampling.ts +1 -4
- package/src/console/ui/traces/search.ts +4 -17
- package/src/console/ui/traces/tier.ts +1 -3
- package/src/console/ui/vault/VaultA11yView.tsx +5 -17
- package/src/console/ui/vault/a11y.test.tsx +1 -2
- package/src/console/ui/vault/blast-radius.ts +1 -3
- package/src/console/ui/vault/confirmation.test.ts +1 -5
- package/src/console/ui/vault/confirmation.ts +1 -4
- package/src/console/ui/vault/dormant.test.ts +1 -4
- package/src/console/ui/vault/export-safe.test.ts +1 -5
- package/src/console/ui/vault/export-safe.ts +1 -4
- package/src/console/ui/vault/fixture.ts +3 -3
- package/src/console/ui/vault/group.ts +1 -2
- package/src/console/ui/vault/index.ts +2 -10
- package/src/console/ui/vault/search.ts +2 -6
- package/src/console/ui/vault/types.ts +1 -1
- package/src/console/xss.gate.test.ts +1 -3
- package/src/docker/compose.ts +215 -27
- package/src/docker/derive.ts +6 -14
- package/src/docker/docker.test.ts +118 -15
- package/src/docker/dockerfile.integration.test.ts +12 -21
- package/src/docker/helpers.ts +5 -4
- package/src/docker/index.ts +9 -6
- package/src/docker/pin.ts +1 -9
- package/src/docker/recipes/index.ts +6 -6
- package/src/docker/recipes/mailpit.ts +22 -0
- package/src/docker/recipes/openbao.ts +47 -0
- package/src/docker/recipes/postgres.ts +17 -6
- package/src/docker/recipes/redis.ts +11 -2
- package/src/docker/recipes/rustfs.ts +32 -0
- package/src/docker/stack-id.test.ts +73 -5
- package/src/docker/stack-id.ts +124 -33
- package/src/docker/stack.integration.test.ts +6 -21
- package/src/docker/stack.ts +36 -4
- package/src/docker/types.ts +16 -4
- package/src/docs-origin.ts +4 -4
- package/src/drivers/ai-anthropic.ts +5 -14
- package/src/drivers/ai-mock.ts +2 -5
- package/src/drivers/ai-openai-compatible.ts +4 -10
- package/src/drivers/ai-providers.test.ts +6 -13
- package/src/drivers/bun-native-completeness.test.ts +6 -15
- package/src/drivers/channel-console.ts +6 -7
- package/src/drivers/channel-fcm.ts +20 -30
- package/src/drivers/channel-resend.ts +1 -3
- package/src/drivers/channel-smtp.ts +2 -6
- package/src/drivers/channel-types.ts +2 -12
- package/src/drivers/channel-unifonic.ts +2 -6
- package/src/drivers/channel-wa-cloud.ts +2 -6
- package/src/drivers/channel-webpush.ts +21 -60
- package/src/drivers/conformance.test.ts +2 -10
- package/src/drivers/conformance.ts +8 -21
- package/src/drivers/drizzle-dialect.test.ts +20 -0
- package/src/drivers/drizzle-dialect.ts +37 -0
- package/src/drivers/fs.ts +2 -8
- package/src/drivers/index.ts +12 -57
- package/src/drivers/memory.ts +287 -75
- package/src/drivers/pgvector.ts +7 -11
- package/src/drivers/postgres.ts +7 -13
- package/src/drivers/redis.ts +13 -37
- package/src/drivers/s3.ts +15 -18
- package/src/drivers/signal-engine.ts +12 -49
- package/src/drivers/signal-memory.ts +2 -8
- package/src/drivers/signal-nats.ts +4 -9
- package/src/drivers/signal-postgres.ts +62 -129
- package/src/drivers/signal-redis.ts +7 -21
- package/src/drivers/signal-types.ts +1 -4
- package/src/drivers/sqlite.ts +3 -12
- package/src/drivers/types.ts +4 -23
- package/src/drivers/vault-driver-removal.test.ts +55 -0
- package/src/drivers/vault-env.ts +2 -6
- package/src/drivers/vault-infisical.ts +1 -5
- package/src/drivers/vault-managed.ts +1 -5
- package/src/drivers/vault-memory.ts +1 -5
- package/src/drivers/vault-openbao.test.ts +97 -0
- package/src/drivers/vault-openbao.ts +103 -40
- package/src/drivers/vault-types.ts +3 -16
- package/src/elements/ai/declare.ts +4 -14
- package/src/elements/ai/eval.ts +2 -6
- package/src/elements/ai/pii.ts +1 -3
- package/src/elements/ai/runtime.ts +12 -50
- package/src/elements/ai/schema.ts +4 -15
- package/src/elements/ai.test.ts +13 -24
- package/src/elements/ai.ts +1 -5
- package/src/elements/channel/consent.ts +3 -12
- package/src/elements/channel/costs.ts +4 -15
- package/src/elements/channel/declare.ts +1 -4
- package/src/elements/channel/email-auth.ts +1 -4
- package/src/elements/channel/locale.ts +2 -10
- package/src/elements/channel/mask.ts +1 -3
- package/src/elements/channel/mime.ts +2 -12
- package/src/elements/channel/outcomes.test.ts +1 -5
- package/src/elements/channel/outcomes.ts +5 -15
- package/src/elements/channel/receipts.ts +2 -7
- package/src/elements/channel/runtime.ts +28 -74
- package/src/elements/channel/suppression.ts +8 -14
- package/src/elements/channel.test.ts +8 -31
- package/src/elements/channel.ts +3 -14
- package/src/elements/clock/actions.ts +6 -18
- package/src/elements/clock/declare.ts +1 -3
- package/src/elements/clock/dst.ts +1 -5
- package/src/elements/clock/durable.ts +4 -16
- package/src/elements/clock/health.ts +2 -7
- package/src/elements/clock/leader.ts +2 -9
- package/src/elements/clock/reconcile.ts +4 -15
- package/src/elements/clock/runtime.ts +2 -5
- package/src/elements/clock/schedule.ts +4 -20
- package/src/elements/clock.test.ts +2 -7
- package/src/elements/clock.ts +5 -23
- package/src/elements/gate/permissions.ts +1 -4
- package/src/elements/gate/runtime.ts +7 -28
- package/src/elements/gate.ts +1 -5
- package/src/elements/index.ts +9 -7
- package/src/elements/signal/declare.ts +2 -7
- package/src/elements/signal/reconcile.test.ts +1 -4
- package/src/elements/signal/runtime.ts +1 -3
- package/src/elements/signal.test.ts +3 -15
- package/src/elements/signal.ts +2 -8
- package/src/elements/store/cache.test.ts +46 -0
- package/src/elements/store/cache.ts +3 -11
- package/src/elements/store/classify.ts +5 -22
- package/src/elements/store/declare.ts +11 -17
- package/src/elements/store/domain-ddl.test.ts +86 -0
- package/src/elements/store/emit-drizzle.ts +363 -0
- package/src/elements/store/files-policy.test.ts +1 -5
- package/src/elements/store/files-policy.ts +4 -12
- package/src/elements/store/load-plugin-tables.ts +103 -0
- package/src/elements/store/missing-relation.test.ts +83 -0
- package/src/elements/store/missing-relation.ts +38 -0
- package/src/elements/store/replica.ts +1 -4
- package/src/elements/store/resource-list-docs.fixture.ts +56 -0
- package/src/elements/store/resource-list-docs.test.ts +79 -0
- package/src/elements/store/resource.test.ts +253 -0
- package/src/elements/store/resource.ts +786 -0
- package/src/elements/store/runtime.ts +25 -28
- package/src/elements/store/schema-decl.test.ts +227 -0
- package/src/elements/store/schema-decl.ts +516 -0
- package/src/elements/store/sql-condition.test.ts +132 -0
- package/src/elements/store/sql-condition.ts +293 -65
- package/src/elements/store/sql-session.test.ts +135 -0
- package/src/elements/store/sql-session.ts +241 -84
- package/src/elements/store/table.ts +69 -23
- package/src/elements/store.test.ts +17 -39
- package/src/elements/store.ts +53 -31
- package/src/elements/vault/chain.ts +34 -0
- package/src/elements/vault/declare.ts +22 -32
- package/src/elements/vault/fingerprint.ts +2 -7
- package/src/elements/vault/redact.ts +2 -6
- package/src/elements/vault/runtime.ts +19 -33
- package/src/elements/vault.test.ts +12 -55
- package/src/elements/vault.ts +9 -13
- package/src/index.ts +5 -2
- package/src/kernel/adopt-routes.ts +15 -29
- package/src/kernel/app.ts +92 -118
- package/src/kernel/auth-resolve.ts +2 -9
- package/src/kernel/boot-bind/ai.ts +1 -4
- package/src/kernel/boot-bind/channel.test.ts +60 -0
- package/src/kernel/boot-bind/channel.ts +61 -5
- package/src/kernel/boot-bind/clock.ts +2 -6
- package/src/kernel/boot-bind/gate.ts +2 -8
- package/src/kernel/boot-bind/runs.ts +1 -3
- package/src/kernel/boot-bind/signal.ts +3 -10
- package/src/kernel/boot-bind/store.test.ts +27 -18
- package/src/kernel/boot-bind/store.ts +93 -52
- package/src/kernel/boot-bind/vault.ts +2 -8
- package/src/kernel/boot.test.ts +4 -10
- package/src/kernel/boot.ts +30 -77
- package/src/kernel/budget.test.ts +1 -3
- package/src/kernel/capability.ts +3 -10
- package/src/kernel/dry-run.test.ts +1 -4
- package/src/kernel/dry-run.ts +3 -11
- package/src/kernel/edge.test.ts +68 -0
- package/src/kernel/effects.test.ts +1 -5
- package/src/kernel/effects.ts +4 -11
- package/src/kernel/errors.registry.test.ts +2 -8
- package/src/kernel/errors.ts +23 -32
- package/src/kernel/flow.test.ts +12 -25
- package/src/kernel/flow.ts +13 -25
- package/src/kernel/fx.test.ts +31 -40
- package/src/kernel/fx.ts +135 -90
- package/src/kernel/hook-timing.test.ts +3 -6
- package/src/kernel/hook-timing.ts +5 -14
- package/src/kernel/hooks.test.ts +43 -10
- package/src/kernel/hooks.ts +25 -12
- package/src/kernel/index.ts +11 -17
- package/src/kernel/journal.ts +7 -31
- package/src/kernel/on.ts +45 -9
- package/src/kernel/pipeline.test.ts +10 -19
- package/src/kernel/pipeline.ts +5 -17
- package/src/kernel/plug.ts +4 -11
- package/src/kernel/plugin/conflicts.test.ts +13 -25
- package/src/kernel/plugin/decorate.test.ts +8 -13
- package/src/kernel/plugin/scoping.test.ts +4 -11
- package/src/kernel/plugin.ts +81 -27
- package/src/kernel/registry-isolation.test.ts +74 -0
- package/src/kernel/registry.ts +102 -30
- package/src/kernel/router.test.ts +15 -13
- package/src/kernel/router.ts +9 -29
- package/src/kernel/routing-budget.test.ts +1 -3
- package/src/kernel/run-telemetry.ts +1 -3
- package/src/kernel/triggers.ts +63 -21
- package/src/manifest/diff.test.ts +26 -91
- package/src/manifest/diff.ts +95 -225
- package/src/manifest/fixtures/skyport.excerpt.json +1 -1
- package/src/manifest/fixtures/skyport.manifest.json +1 -1
- package/src/manifest/index.ts +3 -10
- package/src/manifest/types.ts +30 -6
- package/src/manifest/undeclared.test.ts +4 -12
- package/src/manifest/undeclared.ts +1 -2
- package/src/manifest/validate.test.ts +2 -6
- package/src/manifest/validate.ts +5 -15
- package/src/mcp/authorization.ts +8 -27
- package/src/mcp/confirmation.ts +3 -10
- package/src/mcp/data.ts +2 -6
- package/src/mcp/docs-index.ts +4 -7
- package/src/mcp/docs-mcp.test.ts +3 -12
- package/src/mcp/docs-server.ts +7 -27
- package/src/mcp/docs-tools.ts +2 -6
- package/src/mcp/index.ts +1 -6
- package/src/mcp/injection.gate.test.ts +4 -18
- package/src/mcp/mcp.test.ts +18 -49
- package/src/mcp/protocol.ts +3 -10
- package/src/mcp/server.ts +11 -52
- package/src/mcp/session.ts +4 -14
- package/src/mcp/tools.ts +14 -50
- package/src/plugins/catalogue.test.ts +3 -7
- package/src/plugins/catalogue.ts +1 -3
- package/src/plugins/compression.test.ts +127 -0
- package/src/plugins/compression.ts +94 -0
- package/src/plugins/config-source.test.ts +204 -0
- package/src/plugins/config-source.ts +209 -0
- package/src/plugins/cors.test.ts +138 -0
- package/src/plugins/cors.ts +129 -0
- package/src/plugins/csrf.test.ts +102 -0
- package/src/plugins/csrf.ts +86 -0
- package/src/plugins/headers.ts +54 -0
- package/src/plugins/index.ts +26 -0
- package/src/plugins/ip-allowlist.test.ts +105 -0
- package/src/plugins/ip-allowlist.ts +76 -0
- package/src/plugins/maintenance-mode.test.ts +91 -0
- package/src/plugins/maintenance-mode.ts +85 -0
- package/src/plugins/node-import-scan.ts +2 -5
- package/src/plugins/security-headers.test.ts +243 -0
- package/src/plugins/security-headers.ts +255 -0
- package/src/plugins/supply-chain.ts +5 -17
- package/src/release/exports.ts +3 -8
- package/src/release/measure.exports.test.ts +1 -3
- package/src/release/measure.ts +16 -45
- package/src/runs/bench.test.ts +1 -3
- package/src/runs/collect.ts +8 -25
- package/src/runs/drivers/clickhouse.ts +2 -9
- package/src/runs/drivers/files.ts +9 -31
- package/src/runs/drivers/memory.ts +5 -22
- package/src/runs/drivers/postgres.ts +8 -20
- package/src/runs/duckdb.ts +2 -8
- package/src/runs/index.ts +3 -14
- package/src/runs/outlier.ts +3 -10
- package/src/runs/parquet.ts +8 -26
- package/src/runs/privacy.ts +2 -8
- package/src/runs/runs.test.ts +3 -9
- package/src/runs/runtime.ts +7 -32
- package/src/runs/shred.ts +10 -29
- package/src/runs/types.ts +1 -4
- package/src/runtime/bun.ts +4 -15
- package/src/runtime/cold-start.bench.ts +1 -3
- package/src/runtime/dev-request-log.test.ts +1 -4
- package/src/runtime/dev-request-log.ts +1 -4
- package/src/runtime/index.ts +1 -6
- package/src/runtime/primitives.ts +5 -4
- package/src/runtime/security.ts +3 -13
- package/src/runtime/serve.test.ts +4 -7
- package/src/runtime/types.ts +1 -4
- package/src/runtime/web-standard.ts +3 -15
- package/src/term.test.ts +4 -6
- package/src/term.ts +49 -98
- package/src/test/create-test-app.test.ts +4 -14
- package/src/test/create-test-app.ts +27 -33
- package/src/test/provisions.integration.test.ts +3 -11
- package/src/upgrade/codemods.test.ts +25 -6
- package/src/upgrade/codemods.ts +116 -3
- package/src/validation/standard-schema.test.ts +2 -5
- package/src/validation/standard-schema.ts +13 -33
- package/docs/spec/console.md +0 -739
- package/docs/spec/example.md +0 -1196
- package/docs/spec/four-applications.md +0 -1195
- package/docs/spec/unified-theory.md +0 -489
- package/src/cli/doc-drift.test.ts +0 -146
- package/src/cli/doc-drift.ts +0 -430
- package/src/cli/doctor-diff-examples.ts +0 -92
- package/src/console/ui/dist/assets/panel-vault-BbfWdox0.js +0 -1
- package/src/drivers/vault-sops.ts +0 -271
|
@@ -54,11 +54,7 @@ describe("plugin scoping — attachment point is the scope", () => {
|
|
|
54
54
|
await app.fetch(new Request("http://localhost/orders"));
|
|
55
55
|
await app.fetch(new Request("http://localhost/payments"));
|
|
56
56
|
|
|
57
|
-
expect(fired).toEqual([
|
|
58
|
-
"rate-limit",
|
|
59
|
-
"orders:handler",
|
|
60
|
-
"payments:handler",
|
|
61
|
-
]);
|
|
57
|
+
expect(fired).toEqual(["rate-limit", "orders:handler", "payments:handler"]);
|
|
62
58
|
});
|
|
63
59
|
|
|
64
60
|
test("app-scoped plugin hook fires for every unit", async () => {
|
|
@@ -87,12 +83,9 @@ describe("plugin scoping — attachment point is the scope", () => {
|
|
|
87
83
|
}),
|
|
88
84
|
);
|
|
89
85
|
|
|
90
|
-
const audit = plugin("audit", { version: "1.0.0" }).hook(
|
|
91
|
-
"
|
|
92
|
-
|
|
93
|
-
fired.push("audit");
|
|
94
|
-
},
|
|
95
|
-
);
|
|
86
|
+
const audit = plugin("audit", { version: "1.0.0" }).hook("afterHandle", () => {
|
|
87
|
+
fired.push("audit");
|
|
88
|
+
});
|
|
96
89
|
|
|
97
90
|
const app = oke({ name: "app-scope" }).plug(audit);
|
|
98
91
|
|
package/src/kernel/plugin.ts
CHANGED
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
* and records exactly what was requested (capability capture). We never
|
|
7
7
|
* statically analyse plugin source to guess intent.
|
|
8
8
|
*
|
|
9
|
-
* Contributions: flows · hooks ·
|
|
10
|
-
*
|
|
11
|
-
* commands · Console panels.
|
|
9
|
+
* Contributions: flows · hooks · edge handlers (unmatched requests) ·
|
|
10
|
+
* context decorations · elements · drivers · image recipes · DB schema ·
|
|
11
|
+
* typed errors · client extensions · CLI commands · Console panels.
|
|
12
12
|
*
|
|
13
13
|
* @see docs/spec/unified-theory.md §14
|
|
14
14
|
* @see docs/spec/console.md §9.15
|
|
@@ -87,14 +87,45 @@ export interface ImageRecipeContribution {
|
|
|
87
87
|
readonly recipe: string;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Edge handler — runs for HTTP requests that match **no** flow (the prime
|
|
92
|
+
* example: a CORS preflight `OPTIONS` for a path bound to another method).
|
|
93
|
+
* Handlers run in install order; the first to return a {@link Response}
|
|
94
|
+
* answers, `undefined` passes to the next handler, then the plain 404.
|
|
95
|
+
*/
|
|
96
|
+
export type EdgeHandler = (
|
|
97
|
+
request: Request,
|
|
98
|
+
info: { readonly method: string; readonly path: string },
|
|
99
|
+
) => undefined | Response | Promise<undefined | Response>;
|
|
100
|
+
|
|
90
101
|
/** Table / DB schema contribution. */
|
|
91
102
|
export interface TableContribution {
|
|
92
103
|
/** Table name — conflict namespace shared across plugins. */
|
|
93
104
|
readonly name: string;
|
|
94
|
-
/**
|
|
105
|
+
/**
|
|
106
|
+
* Abstract column map from `field.*` builders (merged into domain schema emit).
|
|
107
|
+
* Omit when the plugin only claims a name (DDL stays hand-written).
|
|
108
|
+
*/
|
|
109
|
+
readonly columns?: Readonly<Record<string, unknown>>;
|
|
110
|
+
/**
|
|
111
|
+
* Non-column metadata (e.g. data plane). Prefer this over stuffing `plane`
|
|
112
|
+
* into the column map.
|
|
113
|
+
*/
|
|
114
|
+
readonly options?: {
|
|
115
|
+
readonly plane?: "operator" | "user" | "shared" | string;
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Opaque schema descriptor (legacy). Prefer {@link columns} + {@link options}.
|
|
119
|
+
* Still set for plane-only contributions so older readers keep working.
|
|
120
|
+
*/
|
|
95
121
|
readonly schema?: unknown;
|
|
96
122
|
}
|
|
97
123
|
|
|
124
|
+
/** Options for {@link PluginApi.table} / {@link PluginDef.table}. */
|
|
125
|
+
export interface PluginTableOptions {
|
|
126
|
+
readonly plane?: "operator" | "user" | "shared" | string;
|
|
127
|
+
}
|
|
128
|
+
|
|
98
129
|
/** Driver contribution. */
|
|
99
130
|
export interface DriverContribution {
|
|
100
131
|
/** Driver id (protocol-named) — conflict namespace shared across plugins. */
|
|
@@ -115,6 +146,12 @@ export interface PluginApi {
|
|
|
115
146
|
* @param fn - Hook function
|
|
116
147
|
*/
|
|
117
148
|
hook(stage: HookStage, fn: HookFn): PluginApi;
|
|
149
|
+
/**
|
|
150
|
+
* Register an edge handler (intercept — requests that match no flow).
|
|
151
|
+
*
|
|
152
|
+
* @param fn - Edge handler
|
|
153
|
+
*/
|
|
154
|
+
edge(fn: EdgeHandler): PluginApi;
|
|
118
155
|
/**
|
|
119
156
|
* Decorate the invocation context (declare — once at boot).
|
|
120
157
|
*
|
|
@@ -152,10 +189,7 @@ export interface PluginApi {
|
|
|
152
189
|
* @param name - Command name
|
|
153
190
|
* @param handler - Command handler
|
|
154
191
|
*/
|
|
155
|
-
cli(
|
|
156
|
-
name: string,
|
|
157
|
-
handler: CliContribution["handler"],
|
|
158
|
-
): PluginApi;
|
|
192
|
+
cli(name: string, handler: CliContribution["handler"]): PluginApi;
|
|
159
193
|
/**
|
|
160
194
|
* Contribute a driver.
|
|
161
195
|
*
|
|
@@ -173,10 +207,19 @@ export interface PluginApi {
|
|
|
173
207
|
/**
|
|
174
208
|
* Contribute a DB table / schema fragment.
|
|
175
209
|
*
|
|
210
|
+
* Plugins may declare **whole tables** (with optional `field.*` columns)
|
|
211
|
+
* merged into the generated domain schema. Extending an existing app-owned
|
|
212
|
+
* table with plugin columns is not supported — contribute a separate table.
|
|
213
|
+
*
|
|
176
214
|
* @param name - Table name
|
|
177
|
-
* @param
|
|
215
|
+
* @param columns - Abstract column map, or legacy `{ plane }` options
|
|
216
|
+
* @param options - Plane / metadata (preferred over embedding `plane` in columns)
|
|
178
217
|
*/
|
|
179
|
-
table(
|
|
218
|
+
table(
|
|
219
|
+
name: string,
|
|
220
|
+
columns?: Readonly<Record<string, unknown>>,
|
|
221
|
+
options?: PluginTableOptions,
|
|
222
|
+
): PluginApi;
|
|
180
223
|
/**
|
|
181
224
|
* Contribute a flow.
|
|
182
225
|
*
|
|
@@ -216,6 +259,7 @@ export interface PluginCapabilities {
|
|
|
216
259
|
export interface PluginRegistration {
|
|
217
260
|
readonly capabilities: PluginCapabilities;
|
|
218
261
|
readonly hooks: Partial<Record<HookStage, HookFn[]>>;
|
|
262
|
+
readonly edges: readonly EdgeHandler[];
|
|
219
263
|
readonly decorations: Readonly<Record<string, unknown>>;
|
|
220
264
|
readonly elements: readonly PluginElement[];
|
|
221
265
|
readonly tables: readonly TableContribution[];
|
|
@@ -259,16 +303,19 @@ export interface PluginDef<D extends Record<string, unknown> = {}> {
|
|
|
259
303
|
* @param fn - Hook function
|
|
260
304
|
*/
|
|
261
305
|
hook(stage: HookStage, fn: HookFn): PluginDef<D>;
|
|
306
|
+
/**
|
|
307
|
+
* Queue an edge handler contribution (requests that match no flow).
|
|
308
|
+
*
|
|
309
|
+
* @param fn - Edge handler
|
|
310
|
+
*/
|
|
311
|
+
edge(fn: EdgeHandler): PluginDef<D>;
|
|
262
312
|
/**
|
|
263
313
|
* Queue a context decoration. Accumulates types for `.plug()`.
|
|
264
314
|
*
|
|
265
315
|
* @param key - Decoration key
|
|
266
316
|
* @param value - Value
|
|
267
317
|
*/
|
|
268
|
-
decorate<K extends string, V>(
|
|
269
|
-
key: K,
|
|
270
|
-
value: V,
|
|
271
|
-
): PluginDef<D & { [P in K]: V }>;
|
|
318
|
+
decorate<K extends string, V>(key: K, value: V): PluginDef<D & { [P in K]: V }>;
|
|
272
319
|
/**
|
|
273
320
|
* Queue an element contribution.
|
|
274
321
|
*
|
|
@@ -317,10 +364,17 @@ export interface PluginDef<D extends Record<string, unknown> = {}> {
|
|
|
317
364
|
/**
|
|
318
365
|
* Queue a table / schema contribution.
|
|
319
366
|
*
|
|
367
|
+
* Whole tables only — no column injection into app-owned tables (v1).
|
|
368
|
+
*
|
|
320
369
|
* @param name - Table name
|
|
321
|
-
* @param
|
|
370
|
+
* @param columns - Abstract column map, or legacy `{ plane }` options
|
|
371
|
+
* @param options - Plane / metadata
|
|
322
372
|
*/
|
|
323
|
-
table(
|
|
373
|
+
table(
|
|
374
|
+
name: string,
|
|
375
|
+
columns?: Readonly<Record<string, unknown>>,
|
|
376
|
+
options?: PluginTableOptions,
|
|
377
|
+
): PluginDef<D>;
|
|
324
378
|
/**
|
|
325
379
|
* Queue a flow contribution.
|
|
326
380
|
*
|
|
@@ -343,8 +397,7 @@ export interface PluginDef<D extends Record<string, unknown> = {}> {
|
|
|
343
397
|
}
|
|
344
398
|
|
|
345
399
|
/** Extract accumulated decoration types from a {@link PluginDef}. */
|
|
346
|
-
export type DecorationsOf<P> =
|
|
347
|
-
P extends PluginDef<infer D> ? D : Record<string, never>;
|
|
400
|
+
export type DecorationsOf<P> = P extends PluginDef<infer D> ? D : Record<string, never>;
|
|
348
401
|
|
|
349
402
|
/**
|
|
350
403
|
* Define a plugin. Fluent methods queue a registration plan; the registry
|
|
@@ -353,10 +406,7 @@ export type DecorationsOf<P> =
|
|
|
353
406
|
* @param name - Stable plugin id
|
|
354
407
|
* @param options - Version and optional config snapshot
|
|
355
408
|
*/
|
|
356
|
-
export function plugin(
|
|
357
|
-
name: string,
|
|
358
|
-
options: PluginOptions,
|
|
359
|
-
): PluginDef {
|
|
409
|
+
export function plugin(name: string, options: PluginOptions): PluginDef {
|
|
360
410
|
const steps: Array<(api: PluginApi) => void> = [];
|
|
361
411
|
|
|
362
412
|
const def: PluginDef = {
|
|
@@ -372,6 +422,12 @@ export function plugin(
|
|
|
372
422
|
});
|
|
373
423
|
return def;
|
|
374
424
|
},
|
|
425
|
+
edge(fn) {
|
|
426
|
+
steps.push((api) => {
|
|
427
|
+
api.edge(fn);
|
|
428
|
+
});
|
|
429
|
+
return def;
|
|
430
|
+
},
|
|
375
431
|
decorate(key, value) {
|
|
376
432
|
steps.push((api) => {
|
|
377
433
|
api.decorate(key, value);
|
|
@@ -390,9 +446,7 @@ export function plugin(
|
|
|
390
446
|
api.element(el);
|
|
391
447
|
} else if (typeof el.facet === "string" && typeof el.name === "string") {
|
|
392
448
|
api.element({
|
|
393
|
-
kind: el.facet.startsWith("store.")
|
|
394
|
-
? el.facet
|
|
395
|
-
: `store.${el.facet}`,
|
|
449
|
+
kind: el.facet.startsWith("store.") ? el.facet : `store.${el.facet}`,
|
|
396
450
|
name: el.name,
|
|
397
451
|
});
|
|
398
452
|
} else {
|
|
@@ -437,9 +491,9 @@ export function plugin(
|
|
|
437
491
|
});
|
|
438
492
|
return def;
|
|
439
493
|
},
|
|
440
|
-
table(tableName,
|
|
494
|
+
table(tableName, columns, options) {
|
|
441
495
|
steps.push((api) => {
|
|
442
|
-
api.table(tableName,
|
|
496
|
+
api.table(tableName, columns, options);
|
|
443
497
|
});
|
|
444
498
|
return def;
|
|
445
499
|
},
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry isolation — two `oke()` apps in one process must not share routes.
|
|
3
|
+
*
|
|
4
|
+
* This is the multi-app / future-`mount()` guarantee: constructing one app
|
|
5
|
+
* can never pull another app's flows through the process-global `on()`
|
|
6
|
+
* registry. Before the fix, `oke()` adopted the registry snapshot and left
|
|
7
|
+
* it intact, so App B below silently served App A's `/a` route (leakage).
|
|
8
|
+
* The default `registry: "consume"` mode drains the registry at construction.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { afterEach, describe, expect, test } from "bun:test";
|
|
12
|
+
import { oke } from "./app.ts";
|
|
13
|
+
import { flow, resetFlowSeq } from "./flow.ts";
|
|
14
|
+
import { listBindings, on, resetBindings, type Binding } from "./on.ts";
|
|
15
|
+
import { http } from "./triggers.ts";
|
|
16
|
+
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
resetBindings();
|
|
19
|
+
resetFlowSeq();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe("registry isolation", () => {
|
|
23
|
+
test("consume (default): App B does not serve App A routes", async () => {
|
|
24
|
+
on(http.get("/a"), flow({ name: "app-a.ping", do: () => "a" }));
|
|
25
|
+
const appA = oke({ name: "app-a" });
|
|
26
|
+
|
|
27
|
+
// No resetBindings() between the apps — the pre-fix leak scenario.
|
|
28
|
+
on(http.get("/b"), flow({ name: "app-b.ping", do: () => "b" }));
|
|
29
|
+
const appB = oke({ name: "app-b" });
|
|
30
|
+
|
|
31
|
+
// Pre-fix this was 200: App B adopted App A's leftover binding.
|
|
32
|
+
expect((await appB.fetch(new Request("http://localhost/a"))).status).toBe(404);
|
|
33
|
+
|
|
34
|
+
const own = await appB.fetch(new Request("http://localhost/b"));
|
|
35
|
+
expect(own.status).toBe(200);
|
|
36
|
+
expect(await own.json()).toEqual({ data: "b", error: null });
|
|
37
|
+
|
|
38
|
+
// App A still serves its own route after App B was constructed.
|
|
39
|
+
const stillA = await appA.fetch(new Request("http://localhost/a"));
|
|
40
|
+
expect(stillA.status).toBe(200);
|
|
41
|
+
expect(await stillA.json()).toEqual({ data: "a", error: null });
|
|
42
|
+
|
|
43
|
+
// Consume drained the registry — nothing left for a third app.
|
|
44
|
+
expect(listBindings()).toHaveLength(0);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("keep: today's behavior — registry survives construction", async () => {
|
|
48
|
+
on(http.get("/a"), flow({ name: "kept.ping", do: () => "a" }));
|
|
49
|
+
oke({ name: "app-a", registry: "keep" });
|
|
50
|
+
expect(listBindings()).toHaveLength(1);
|
|
51
|
+
|
|
52
|
+
const appB = oke({ name: "app-b", registry: "keep" });
|
|
53
|
+
expect((await appB.fetch(new Request("http://localhost/a"))).status).toBe(200);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("ignore: only options.bindings are served", async () => {
|
|
57
|
+
on(http.get("/stray"), flow({ name: "stray.ping", do: () => "stray" }));
|
|
58
|
+
|
|
59
|
+
const onlyB: Binding = {
|
|
60
|
+
trigger: http.get("/b"),
|
|
61
|
+
flow: flow({ name: "only-b.ping", do: () => "b" }),
|
|
62
|
+
};
|
|
63
|
+
const app = oke({ name: "app-b", registry: "ignore", bindings: [onlyB] });
|
|
64
|
+
|
|
65
|
+
expect((await app.fetch(new Request("http://localhost/stray"))).status).toBe(404);
|
|
66
|
+
|
|
67
|
+
const res = await app.fetch(new Request("http://localhost/b"));
|
|
68
|
+
expect(res.status).toBe(200);
|
|
69
|
+
expect(await res.json()).toEqual({ data: "b", error: null });
|
|
70
|
+
|
|
71
|
+
// Ignore never touches the registry.
|
|
72
|
+
expect(listBindings()).toHaveLength(1);
|
|
73
|
+
});
|
|
74
|
+
});
|
package/src/kernel/registry.ts
CHANGED
|
@@ -20,12 +20,14 @@ import type {
|
|
|
20
20
|
ClientExtensionContribution,
|
|
21
21
|
ConsolePanelContribution,
|
|
22
22
|
DriverContribution,
|
|
23
|
+
EdgeHandler,
|
|
23
24
|
ImageRecipeContribution,
|
|
24
25
|
PluginApi,
|
|
25
26
|
PluginCapabilities,
|
|
26
27
|
PluginDef,
|
|
27
28
|
PluginElement,
|
|
28
29
|
PluginRegistration,
|
|
30
|
+
PluginTableOptions,
|
|
29
31
|
TableContribution,
|
|
30
32
|
} from "./plugin.ts";
|
|
31
33
|
import type { SchemaInput } from "../validation/standard-schema.ts";
|
|
@@ -56,11 +58,12 @@ interface NameClaim {
|
|
|
56
58
|
*
|
|
57
59
|
* @param identity - Plugin name + version for the capability record
|
|
58
60
|
*/
|
|
59
|
-
export function createRecordingApi(identity: {
|
|
60
|
-
readonly
|
|
61
|
-
|
|
62
|
-
}
|
|
61
|
+
export function createRecordingApi(identity: { readonly name: string; readonly version: string }): {
|
|
62
|
+
readonly api: PluginApi;
|
|
63
|
+
snapshot(): PluginRegistration;
|
|
64
|
+
} {
|
|
63
65
|
const hooks: Partial<Record<HookStage, HookFn[]>> = {};
|
|
66
|
+
const edges: EdgeHandler[] = [];
|
|
64
67
|
const decorations: Record<string, unknown> = {};
|
|
65
68
|
const elements: PluginElement[] = [];
|
|
66
69
|
const tables: TableContribution[] = [];
|
|
@@ -80,7 +83,7 @@ export function createRecordingApi(identity: {
|
|
|
80
83
|
if (!declares.includes(cap)) declares.push(cap);
|
|
81
84
|
}
|
|
82
85
|
|
|
83
|
-
function pushIntercept(stage: HookStage): void {
|
|
86
|
+
function pushIntercept(stage: HookStage | "edge"): void {
|
|
84
87
|
if (!intercepts.includes(stage)) intercepts.push(stage);
|
|
85
88
|
}
|
|
86
89
|
|
|
@@ -92,6 +95,11 @@ export function createRecordingApi(identity: {
|
|
|
92
95
|
pushIntercept(stage);
|
|
93
96
|
return api;
|
|
94
97
|
},
|
|
98
|
+
edge(fn) {
|
|
99
|
+
edges.push(fn);
|
|
100
|
+
pushIntercept("edge");
|
|
101
|
+
return api;
|
|
102
|
+
},
|
|
95
103
|
decorate(key, value) {
|
|
96
104
|
decorations[key] = value;
|
|
97
105
|
pushDeclare(`decorate:${key}`);
|
|
@@ -133,8 +141,8 @@ export function createRecordingApi(identity: {
|
|
|
133
141
|
pushDeclare(`image:${role}`);
|
|
134
142
|
return api;
|
|
135
143
|
},
|
|
136
|
-
table(name,
|
|
137
|
-
tables.push(
|
|
144
|
+
table(name, columns, options) {
|
|
145
|
+
tables.push(normalizeTableContribution(name, columns, options));
|
|
138
146
|
pushDeclare(`table:${name}`);
|
|
139
147
|
return api;
|
|
140
148
|
},
|
|
@@ -167,6 +175,7 @@ export function createRecordingApi(identity: {
|
|
|
167
175
|
needs: needs.slice(),
|
|
168
176
|
},
|
|
169
177
|
hooks: { ...hooks },
|
|
178
|
+
edges: edges.slice(),
|
|
170
179
|
decorations: { ...decorations },
|
|
171
180
|
elements: elements.slice(),
|
|
172
181
|
tables: tables.slice(),
|
|
@@ -229,21 +238,25 @@ export interface PluginRegistry {
|
|
|
229
238
|
* @param unit - Flow's unit name (for `unit` kind)
|
|
230
239
|
* @param flowName - Flow name (for `flow` kind)
|
|
231
240
|
*/
|
|
232
|
-
hooksAt(
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
241
|
+
hooksAt(scopeKind: PluginScope["kind"], unit: string | undefined, flowName: string): HookMap;
|
|
242
|
+
/**
|
|
243
|
+
* Edge handlers in install order. They answer requests that match no
|
|
244
|
+
* flow, so there is no flow/unit scope to filter by — every installed
|
|
245
|
+
* handler runs.
|
|
246
|
+
*/
|
|
247
|
+
edgeHandlers(): readonly EdgeHandler[];
|
|
237
248
|
/**
|
|
238
249
|
* Merged decorations visible to a flow at the given unit.
|
|
239
250
|
*
|
|
240
251
|
* @param unit - Flow's unit name, if any
|
|
241
252
|
* @param flowName - Flow name
|
|
242
253
|
*/
|
|
243
|
-
decorationsFor(
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
254
|
+
decorationsFor(unit: string | undefined, flowName: string): Record<string, unknown>;
|
|
255
|
+
/**
|
|
256
|
+
* Unique table contributions from installed plugins (first install per
|
|
257
|
+
* plugin name). Used by `oke db` emit to merge plugin `field.*` tables.
|
|
258
|
+
*/
|
|
259
|
+
tableContributions(): readonly TableContribution[];
|
|
247
260
|
}
|
|
248
261
|
|
|
249
262
|
/**
|
|
@@ -276,10 +289,7 @@ export function createPluginRegistry(): PluginRegistry {
|
|
|
276
289
|
}
|
|
277
290
|
}
|
|
278
291
|
|
|
279
|
-
function assertNoConflicts(
|
|
280
|
-
pluginName: string,
|
|
281
|
-
registration: PluginRegistration,
|
|
282
|
-
): void {
|
|
292
|
+
function assertNoConflicts(pluginName: string, registration: PluginRegistration): void {
|
|
283
293
|
for (const t of registration.tables) {
|
|
284
294
|
claim(tableClaims, "table", t.name, pluginName);
|
|
285
295
|
}
|
|
@@ -301,12 +311,7 @@ export function createPluginRegistry(): PluginRegistry {
|
|
|
301
311
|
const scopeKey = nameScopeKey(pluginDef.name, scope);
|
|
302
312
|
const priorHere = byNameScope.get(scopeKey);
|
|
303
313
|
if (priorHere) {
|
|
304
|
-
if (
|
|
305
|
-
samePluginConfig(
|
|
306
|
-
priorHere.plugin.configSnapshot,
|
|
307
|
-
pluginDef.configSnapshot,
|
|
308
|
-
)
|
|
309
|
-
) {
|
|
314
|
+
if (samePluginConfig(priorHere.plugin.configSnapshot, pluginDef.configSnapshot)) {
|
|
310
315
|
return undefined; // identity dedup — no-op
|
|
311
316
|
}
|
|
312
317
|
throw new Error(
|
|
@@ -318,10 +323,7 @@ export function createPluginRegistry(): PluginRegistry {
|
|
|
318
323
|
const priorAnywhere = byName.get(pluginDef.name);
|
|
319
324
|
if (
|
|
320
325
|
priorAnywhere &&
|
|
321
|
-
!samePluginConfig(
|
|
322
|
-
priorAnywhere.plugin.configSnapshot,
|
|
323
|
-
pluginDef.configSnapshot,
|
|
324
|
-
)
|
|
326
|
+
!samePluginConfig(priorAnywhere.plugin.configSnapshot, pluginDef.configSnapshot)
|
|
325
327
|
) {
|
|
326
328
|
throw new Error(
|
|
327
329
|
`Plugin "${pluginDef.name}" registered twice with conflicting config ` +
|
|
@@ -392,7 +394,77 @@ export function createPluginRegistry(): PluginRegistry {
|
|
|
392
394
|
}
|
|
393
395
|
return out;
|
|
394
396
|
},
|
|
397
|
+
edgeHandlers() {
|
|
398
|
+
const out: EdgeHandler[] = [];
|
|
399
|
+
for (const entry of installed) {
|
|
400
|
+
out.push(...entry.registration.edges);
|
|
401
|
+
}
|
|
402
|
+
return out;
|
|
403
|
+
},
|
|
404
|
+
tableContributions() {
|
|
405
|
+
const seenPlugins = new Set<string>();
|
|
406
|
+
const out: TableContribution[] = [];
|
|
407
|
+
for (const entry of installed) {
|
|
408
|
+
if (seenPlugins.has(entry.plugin.name)) continue;
|
|
409
|
+
seenPlugins.add(entry.plugin.name);
|
|
410
|
+
out.push(...entry.registration.tables);
|
|
411
|
+
}
|
|
412
|
+
return out;
|
|
413
|
+
},
|
|
395
414
|
};
|
|
396
415
|
|
|
397
416
|
return registry;
|
|
398
417
|
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Normalize plugin `.table()` args — supports columns + options, and legacy
|
|
421
|
+
* `{ plane }` as the second argument.
|
|
422
|
+
*
|
|
423
|
+
* @param name - Table name
|
|
424
|
+
* @param columnsOrOptions - Column map or legacy options
|
|
425
|
+
* @param options - Explicit options (preferred)
|
|
426
|
+
*/
|
|
427
|
+
function normalizeTableContribution(
|
|
428
|
+
name: string,
|
|
429
|
+
columnsOrOptions?: Readonly<Record<string, unknown>>,
|
|
430
|
+
options?: PluginTableOptions,
|
|
431
|
+
): TableContribution {
|
|
432
|
+
if (options !== undefined) {
|
|
433
|
+
const columns =
|
|
434
|
+
columnsOrOptions && Object.keys(columnsOrOptions).length > 0 ? columnsOrOptions : undefined;
|
|
435
|
+
return {
|
|
436
|
+
name,
|
|
437
|
+
...(columns ? { columns } : {}),
|
|
438
|
+
options,
|
|
439
|
+
schema: options,
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
if (columnsOrOptions && isPlaneOnlyOptions(columnsOrOptions)) {
|
|
444
|
+
const planeOptions: PluginTableOptions = {
|
|
445
|
+
plane: columnsOrOptions.plane as string,
|
|
446
|
+
};
|
|
447
|
+
return {
|
|
448
|
+
name,
|
|
449
|
+
options: planeOptions,
|
|
450
|
+
schema: columnsOrOptions,
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if (columnsOrOptions && Object.keys(columnsOrOptions).length > 0) {
|
|
455
|
+
return {
|
|
456
|
+
name,
|
|
457
|
+
columns: columnsOrOptions,
|
|
458
|
+
schema: columnsOrOptions,
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
return { name };
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function isPlaneOnlyOptions(
|
|
466
|
+
value: Readonly<Record<string, unknown>>,
|
|
467
|
+
): value is { readonly plane: string } {
|
|
468
|
+
const keys = Object.keys(value);
|
|
469
|
+
return keys.length === 1 && keys[0] === "plane" && typeof value.plane === "string";
|
|
470
|
+
}
|
|
@@ -93,22 +93,24 @@ describe("router — RegExp + Trie + Linear + Smart", () => {
|
|
|
93
93
|
regexp.match("GET", target);
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
const iterations =
|
|
96
|
+
const iterations = 20_000;
|
|
97
|
+
let best = 0;
|
|
98
|
+
for (let trial = 0; trial < 3; trial++) {
|
|
99
|
+
const t0 = performance.now();
|
|
100
|
+
for (let i = 0; i < iterations; i++) {
|
|
101
|
+
linear.match("GET", target);
|
|
102
|
+
}
|
|
103
|
+
const linearMs = performance.now() - t0;
|
|
97
104
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const t1 = performance.now();
|
|
105
|
-
for (let i = 0; i < iterations; i++) {
|
|
106
|
-
regexp.match("GET", target);
|
|
105
|
+
const t1 = performance.now();
|
|
106
|
+
for (let i = 0; i < iterations; i++) {
|
|
107
|
+
regexp.match("GET", target);
|
|
108
|
+
}
|
|
109
|
+
const regexpMs = performance.now() - t1;
|
|
110
|
+
best = Math.max(best, linearMs / regexpMs);
|
|
107
111
|
}
|
|
108
|
-
const regexpMs = performance.now() - t1;
|
|
109
112
|
|
|
110
|
-
const speedup = linearMs / regexpMs;
|
|
111
113
|
expect(regexp.match("GET", target)?.value).toBe(N - 1);
|
|
112
|
-
expect(
|
|
114
|
+
expect(best).toBeGreaterThanOrEqual(10);
|
|
113
115
|
});
|
|
114
116
|
});
|
package/src/kernel/router.ts
CHANGED
|
@@ -50,9 +50,7 @@ export interface Router<T> {
|
|
|
50
50
|
/** True when the pattern cannot be expressed by the RegExp strategy. */
|
|
51
51
|
export function isUnsupportedByRegExp(path: string): boolean {
|
|
52
52
|
// optional params, wildcards, custom regex segments, greedy rests
|
|
53
|
-
return /\/:/.test(path) === false
|
|
54
|
-
? /[*?{}()]/.test(path)
|
|
55
|
-
: /[*?{}]|\/:[^/]+\?/.test(path);
|
|
53
|
+
return /\/:/.test(path) === false ? /[*?{}()]/.test(path) : /[*?{}]|\/:[^/]+\?/.test(path);
|
|
56
54
|
}
|
|
57
55
|
|
|
58
56
|
function escapeRegex(segment: string): string {
|
|
@@ -85,17 +83,13 @@ function emptyTable<T>(): MethodTable<T> {
|
|
|
85
83
|
|
|
86
84
|
/** First segment key used for dynamic bucketing (`""` if param/empty). */
|
|
87
85
|
function bucketKey(path: string): string {
|
|
88
|
-
const parts = path.startsWith("/")
|
|
89
|
-
? path.split("/").slice(1)
|
|
90
|
-
: path.split("/");
|
|
86
|
+
const parts = path.startsWith("/") ? path.split("/").slice(1) : path.split("/");
|
|
91
87
|
const first = parts[0] ?? "";
|
|
92
88
|
if (first.startsWith(":") || first === "*" || first === "") return "";
|
|
93
89
|
return first;
|
|
94
90
|
}
|
|
95
91
|
|
|
96
|
-
function compileDynamic<T>(
|
|
97
|
-
routes: readonly { path: string; value: T }[],
|
|
98
|
-
): CompiledDynamic<T> {
|
|
92
|
+
function compileDynamic<T>(routes: readonly { path: string; value: T }[]): CompiledDynamic<T> {
|
|
99
93
|
const alts: CompiledDynamic<T>["alts"][number][] = [];
|
|
100
94
|
const parts: string[] = [];
|
|
101
95
|
let group = 1;
|
|
@@ -121,18 +115,12 @@ function compileDynamic<T>(
|
|
|
121
115
|
group += 1 + keys.length;
|
|
122
116
|
}
|
|
123
117
|
|
|
124
|
-
const regex =
|
|
125
|
-
parts.length === 0
|
|
126
|
-
? /(?!)/
|
|
127
|
-
: new RegExp(`^(?:${parts.join("|")})$`);
|
|
118
|
+
const regex = parts.length === 0 ? /(?!)/ : new RegExp(`^(?:${parts.join("|")})$`);
|
|
128
119
|
|
|
129
120
|
return { regex, alts };
|
|
130
121
|
}
|
|
131
122
|
|
|
132
|
-
function matchCompiled<T>(
|
|
133
|
-
dyn: CompiledDynamic<T>,
|
|
134
|
-
path: string,
|
|
135
|
-
): RouteMatch<T> | undefined {
|
|
123
|
+
function matchCompiled<T>(dyn: CompiledDynamic<T>, path: string): RouteMatch<T> | undefined {
|
|
136
124
|
const m = dyn.regex.exec(path);
|
|
137
125
|
if (!m) return undefined;
|
|
138
126
|
|
|
@@ -272,9 +260,7 @@ export class TrieRouter<T> implements Router<T> {
|
|
|
272
260
|
root = newTrieNode();
|
|
273
261
|
this.#roots.set(method, root);
|
|
274
262
|
}
|
|
275
|
-
const parts = path.startsWith("/")
|
|
276
|
-
? path.split("/").slice(1)
|
|
277
|
-
: path.split("/");
|
|
263
|
+
const parts = path.startsWith("/") ? path.split("/").slice(1) : path.split("/");
|
|
278
264
|
|
|
279
265
|
let node = root;
|
|
280
266
|
for (const seg of parts) {
|
|
@@ -306,9 +292,7 @@ export class TrieRouter<T> implements Router<T> {
|
|
|
306
292
|
match(method: string, path: string): RouteMatch<T> | undefined {
|
|
307
293
|
const root = this.#roots.get(method);
|
|
308
294
|
if (!root) return undefined;
|
|
309
|
-
const parts = path.startsWith("/")
|
|
310
|
-
? path.split("/").slice(1)
|
|
311
|
-
: path.split("/");
|
|
295
|
+
const parts = path.startsWith("/") ? path.split("/").slice(1) : path.split("/");
|
|
312
296
|
// trailing slash: empty last segment
|
|
313
297
|
if (parts.length > 0 && parts[parts.length - 1] === "") {
|
|
314
298
|
parts.pop();
|
|
@@ -369,9 +353,7 @@ export class LinearRouter<T> implements Router<T> {
|
|
|
369
353
|
* @param value - Route value
|
|
370
354
|
*/
|
|
371
355
|
add(method: string, path: string, value: T): void {
|
|
372
|
-
const parts = path.startsWith("/")
|
|
373
|
-
? path.split("/").slice(1)
|
|
374
|
-
: path.split("/");
|
|
356
|
+
const parts = path.startsWith("/") ? path.split("/").slice(1) : path.split("/");
|
|
375
357
|
this.#routes.push({ method, path, value, parts });
|
|
376
358
|
}
|
|
377
359
|
|
|
@@ -380,9 +362,7 @@ export class LinearRouter<T> implements Router<T> {
|
|
|
380
362
|
* @param path - Pathname
|
|
381
363
|
*/
|
|
382
364
|
match(method: string, path: string): RouteMatch<T> | undefined {
|
|
383
|
-
const pathParts = path.startsWith("/")
|
|
384
|
-
? path.split("/").slice(1)
|
|
385
|
-
: path.split("/");
|
|
365
|
+
const pathParts = path.startsWith("/") ? path.split("/").slice(1) : path.split("/");
|
|
386
366
|
if (pathParts.length > 0 && pathParts[pathParts.length - 1] === "") {
|
|
387
367
|
pathParts.pop();
|
|
388
368
|
}
|
|
@@ -10,9 +10,7 @@ import { measureRoutingP99Ms } from "../release/measure.ts";
|
|
|
10
10
|
describe("routing overhead budget", () => {
|
|
11
11
|
test(`p99 match < ${ROUTING_P99_BUDGET_MS} ms`, () => {
|
|
12
12
|
const p99 = measureRoutingP99Ms();
|
|
13
|
-
console.log(
|
|
14
|
-
`routing p99=${p99.toFixed(4)} ms budget=${ROUTING_P99_BUDGET_MS}`,
|
|
15
|
-
);
|
|
13
|
+
console.log(`routing p99=${p99.toFixed(4)} ms budget=${ROUTING_P99_BUDGET_MS}`);
|
|
16
14
|
expect(p99).toBeGreaterThanOrEqual(0);
|
|
17
15
|
expect(p99).toBeLessThan(ROUTING_P99_BUDGET_MS);
|
|
18
16
|
});
|