okengine 0.1.4
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 +91 -0
- package/README.md +327 -0
- package/docs/spec/complete-example.md +1188 -0
- package/docs/spec/console.md +739 -0
- package/docs/spec/four-applications.md +1188 -0
- package/docs/spec/unified-theory.md +489 -0
- package/package.json +152 -0
- package/spec/manifest.v1.schema.json +624 -0
- package/src/auth/api-keys.ts +168 -0
- package/src/auth/attenuation.ts +116 -0
- package/src/auth/auth.test.ts +273 -0
- package/src/auth/cross-plane.ts +98 -0
- package/src/auth/index.ts +112 -0
- package/src/auth/invites.ts +66 -0
- package/src/auth/invoke-as.ts +49 -0
- package/src/auth/operator.ts +178 -0
- package/src/auth/planes.ts +102 -0
- package/src/auth/plugin.ts +44 -0
- package/src/auth/roles.ts +84 -0
- package/src/auth/sessions.ts +418 -0
- package/src/auth/tables.ts +131 -0
- package/src/cli/args.ts +50 -0
- package/src/cli/branch.ts +75 -0
- package/src/cli/build.ts +86 -0
- package/src/cli/client-add.test.ts +140 -0
- package/src/cli/client-add.ts +164 -0
- package/src/cli/completion.test.ts +58 -0
- package/src/cli/completion.ts +296 -0
- package/src/cli/dev-app-runner.ts +77 -0
- package/src/cli/dev.test.ts +435 -0
- package/src/cli/dev.ts +594 -0
- package/src/cli/doc-drift.test.ts +146 -0
- package/src/cli/doc-drift.ts +397 -0
- package/src/cli/docker-cli.test.ts +221 -0
- package/src/cli/docker.ts +127 -0
- package/src/cli/doctor-diff-examples.ts +92 -0
- package/src/cli/doctor-diff.test.ts +91 -0
- package/src/cli/doctor-diff.ts +274 -0
- package/src/cli/doctor-pii.test.ts +98 -0
- package/src/cli/doctor-pii.ts +151 -0
- package/src/cli/doctor.test.ts +150 -0
- package/src/cli/doctor.ts +223 -0
- package/src/cli/eval.ts +122 -0
- package/src/cli/exit.ts +19 -0
- package/src/cli/gates-list.test.ts +47 -0
- package/src/cli/gates-list.ts +84 -0
- package/src/cli/images.ts +277 -0
- package/src/cli/index.ts +99 -0
- package/src/cli/json-out.test.ts +129 -0
- package/src/cli/load-config.ts +71 -0
- package/src/cli/mcp-from-console.ts +50 -0
- package/src/cli/privacy-erase.ts +73 -0
- package/src/cli/registry.ts +455 -0
- package/src/cli/safe-defaults.test.ts +92 -0
- package/src/cli/schema.ts +196 -0
- package/src/cli/stack.ts +82 -0
- package/src/cli/start.ts +106 -0
- package/src/cli/upgrade.ts +105 -0
- package/src/cli/vault-cmd.ts +140 -0
- package/src/client/budget-entry.ts +34 -0
- package/src/client/budget.test.ts +17 -0
- package/src/client/create.test.ts +159 -0
- package/src/client/create.ts +152 -0
- package/src/client/errors.ts +60 -0
- package/src/client/index.ts +35 -0
- package/src/client/notes-contract.test.ts +289 -0
- package/src/client/transport.test.ts +123 -0
- package/src/client/transport.ts +254 -0
- package/src/client/types.ts +282 -0
- package/src/compiler/aot.test.ts +248 -0
- package/src/compiler/aot.ts +182 -0
- package/src/compiler/differential.test.ts +241 -0
- package/src/compiler/dynamic.ts +54 -0
- package/src/compiler/effects-infer.ts +541 -0
- package/src/compiler/emit.ts +40 -0
- package/src/compiler/extract.test.ts +177 -0
- package/src/compiler/extract.ts +1368 -0
- package/src/compiler/fixtures/raw/raw-unannotated.ts +28 -0
- package/src/compiler/fixtures/skyport/oke.config.ts +24 -0
- package/src/compiler/fixtures/skyport/src/ai.ts +15 -0
- package/src/compiler/fixtures/skyport/src/app.ts +10 -0
- package/src/compiler/fixtures/skyport/src/channels.ts +6 -0
- package/src/compiler/fixtures/skyport/src/core.ts +3 -0
- package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +57 -0
- package/src/compiler/fixtures/skyport/src/flows/bookings/signals.ts +11 -0
- package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +14 -0
- package/src/compiler/fixtures/skyport/src/flows/support/index.ts +20 -0
- package/src/compiler/fixtures/skyport/src/gates.ts +14 -0
- package/src/compiler/fixtures/skyport/src/journeys.ts +9 -0
- package/src/compiler/fixtures/skyport/src/schema.ts +3 -0
- package/src/compiler/fixtures/skyport/src/vault.ts +6 -0
- package/src/compiler/fixtures/skyport.expected.json +241 -0
- package/src/compiler/fixtures/triggers/five-triggers.ts +69 -0
- package/src/compiler/http-parse.ts +214 -0
- package/src/compiler/index.ts +67 -0
- package/src/compiler/response.ts +89 -0
- package/src/compiler/sucrose.ts +238 -0
- package/src/config/index.ts +167 -0
- package/src/console/budget.test.ts +73 -0
- package/src/console/index.ts +30 -0
- package/src/console/server/access.test.ts +370 -0
- package/src/console/server/access.ts +777 -0
- package/src/console/server/ai.test.ts +172 -0
- package/src/console/server/ai.ts +632 -0
- package/src/console/server/app.ts +294 -0
- package/src/console/server/auth-rate.test.ts +81 -0
- package/src/console/server/auth-rate.ts +72 -0
- package/src/console/server/bind.ts +25 -0
- package/src/console/server/channels.test.ts +179 -0
- package/src/console/server/channels.ts +469 -0
- package/src/console/server/claim.test.ts +66 -0
- package/src/console/server/claim.ts +134 -0
- package/src/console/server/clock.test.ts +239 -0
- package/src/console/server/clock.ts +390 -0
- package/src/console/server/console.test.ts +338 -0
- package/src/console/server/diff.test.ts +299 -0
- package/src/console/server/diff.ts +352 -0
- package/src/console/server/dry-run.audit.test.ts +118 -0
- package/src/console/server/flows-invoke.test.ts +148 -0
- package/src/console/server/flows.ts +3633 -0
- package/src/console/server/gates.test.ts +360 -0
- package/src/console/server/gates.ts +869 -0
- package/src/console/server/index.ts +141 -0
- package/src/console/server/live.test.ts +30 -0
- package/src/console/server/live.ts +109 -0
- package/src/console/server/plugin.ts +50 -0
- package/src/console/server/plugins.test.ts +131 -0
- package/src/console/server/plugins.ts +429 -0
- package/src/console/server/runs-pii.ts +98 -0
- package/src/console/server/security-headers.ts +97 -0
- package/src/console/server/security.gate.test.ts +286 -0
- package/src/console/server/serve.ts +319 -0
- package/src/console/server/signals.test.ts +88 -0
- package/src/console/server/signals.ts +282 -0
- package/src/console/server/state.ts +982 -0
- package/src/console/server/store.test.ts +233 -0
- package/src/console/server/store.ts +861 -0
- package/src/console/server/structural.ts +95 -0
- package/src/console/server/vault.test.ts +251 -0
- package/src/console/server/vault.ts +430 -0
- package/src/console/ui/access/AccessA11yView.tsx +237 -0
- package/src/console/ui/access/a11y.test.tsx +122 -0
- package/src/console/ui/access/acknowledgement.test.ts +13 -0
- package/src/console/ui/access/acknowledgement.ts +35 -0
- package/src/console/ui/access/blast-radius.test.ts +26 -0
- package/src/console/ui/access/blast-radius.ts +40 -0
- package/src/console/ui/access/confirmation.test.ts +38 -0
- package/src/console/ui/access/confirmation.ts +36 -0
- package/src/console/ui/access/fixture.ts +203 -0
- package/src/console/ui/access/grantable.test.ts +17 -0
- package/src/console/ui/access/grantable.ts +36 -0
- package/src/console/ui/access/hygiene.test.ts +12 -0
- package/src/console/ui/access/hygiene.ts +39 -0
- package/src/console/ui/access/index.ts +54 -0
- package/src/console/ui/access/provenance.test.ts +12 -0
- package/src/console/ui/access/provenance.ts +29 -0
- package/src/console/ui/access/search.test.ts +17 -0
- package/src/console/ui/access/search.ts +72 -0
- package/src/console/ui/access/types.ts +111 -0
- package/src/console/ui/ai/AiA11yView.tsx +265 -0
- package/src/console/ui/ai/a11y.test.tsx +99 -0
- package/src/console/ui/ai/findings.ts +41 -0
- package/src/console/ui/ai/fixture.ts +182 -0
- package/src/console/ui/ai/format.ts +90 -0
- package/src/console/ui/ai/group.test.ts +37 -0
- package/src/console/ui/ai/group.ts +88 -0
- package/src/console/ui/ai/index.ts +66 -0
- package/src/console/ui/ai/promotion.test.ts +77 -0
- package/src/console/ui/ai/promotion.ts +150 -0
- package/src/console/ui/ai/search.test.ts +40 -0
- package/src/console/ui/ai/search.ts +89 -0
- package/src/console/ui/ai/types.ts +139 -0
- package/src/console/ui/architecture/ArchitectureA11yView.tsx +163 -0
- package/src/console/ui/architecture/a11y.test.tsx +97 -0
- package/src/console/ui/architecture/boundary.ts +42 -0
- package/src/console/ui/architecture/declared.ts +165 -0
- package/src/console/ui/architecture/fixture.ts +74 -0
- package/src/console/ui/architecture/index.ts +84 -0
- package/src/console/ui/architecture/layers.ts +64 -0
- package/src/console/ui/architecture/layout.ts +68 -0
- package/src/console/ui/architecture/pathologies.ts +260 -0
- package/src/console/ui/architecture/search.ts +145 -0
- package/src/console/ui/architecture/traffic.ts +102 -0
- package/src/console/ui/architecture/types.ts +144 -0
- package/src/console/ui/architecture/view.test.ts +165 -0
- package/src/console/ui/architecture/view.ts +516 -0
- package/src/console/ui/channels/ChannelsA11yView.tsx +180 -0
- package/src/console/ui/channels/a11y.test.tsx +96 -0
- package/src/console/ui/channels/confirmation.test.ts +37 -0
- package/src/console/ui/channels/confirmation.ts +27 -0
- package/src/console/ui/channels/fallback.test.ts +15 -0
- package/src/console/ui/channels/fallback.ts +20 -0
- package/src/console/ui/channels/findings.ts +38 -0
- package/src/console/ui/channels/fixture.ts +134 -0
- package/src/console/ui/channels/group.ts +25 -0
- package/src/console/ui/channels/index.ts +57 -0
- package/src/console/ui/channels/locale.test.ts +17 -0
- package/src/console/ui/channels/locale.ts +31 -0
- package/src/console/ui/channels/mask.test.ts +14 -0
- package/src/console/ui/channels/mask.ts +12 -0
- package/src/console/ui/channels/search.ts +58 -0
- package/src/console/ui/channels/taxonomy.test.ts +17 -0
- package/src/console/ui/channels/taxonomy.ts +49 -0
- package/src/console/ui/channels/types.ts +117 -0
- package/src/console/ui/clock/ClockA11yView.tsx +182 -0
- package/src/console/ui/clock/a11y.test.tsx +99 -0
- package/src/console/ui/clock/confirmation.test.ts +32 -0
- package/src/console/ui/clock/confirmation.ts +34 -0
- package/src/console/ui/clock/findings.ts +40 -0
- package/src/console/ui/clock/fixture.ts +111 -0
- package/src/console/ui/clock/health.test.ts +25 -0
- package/src/console/ui/clock/health.ts +61 -0
- package/src/console/ui/clock/index.ts +49 -0
- package/src/console/ui/clock/search.test.ts +39 -0
- package/src/console/ui/clock/search.ts +76 -0
- package/src/console/ui/clock/timeline.test.ts +44 -0
- package/src/console/ui/clock/timeline.ts +41 -0
- package/src/console/ui/clock/types.ts +78 -0
- package/src/console/ui/clock/waiting-on.test.ts +34 -0
- package/src/console/ui/clock/waiting-on.ts +83 -0
- package/src/console/ui/confirmation.unify.test.ts +92 -0
- package/src/console/ui/diff/DiffA11yView.tsx +85 -0
- package/src/console/ui/diff/a11y.test.tsx +99 -0
- package/src/console/ui/diff/fixture.ts +85 -0
- package/src/console/ui/diff/group.test.ts +58 -0
- package/src/console/ui/diff/group.ts +97 -0
- package/src/console/ui/diff/index.ts +38 -0
- package/src/console/ui/diff/search.test.ts +32 -0
- package/src/console/ui/diff/search.ts +75 -0
- package/src/console/ui/diff/summary.ts +74 -0
- package/src/console/ui/diff/types.ts +48 -0
- package/src/console/ui/dist/assets/index-B71Yl_SS.js +10 -0
- package/src/console/ui/dist/assets/panel-access-Dd37LU2c.js +64 -0
- package/src/console/ui/dist/assets/panel-ai-CC7LR6-J.js +1 -0
- package/src/console/ui/dist/assets/panel-architecture-B5b3iKCz.js +1 -0
- package/src/console/ui/dist/assets/panel-channels-CeNjTKXp.js +1 -0
- package/src/console/ui/dist/assets/panel-clock-DgFTLoHV.js +1 -0
- package/src/console/ui/dist/assets/panel-diff-DxehccqB.js +1 -0
- package/src/console/ui/dist/assets/panel-flows-BtrVn-Eg.js +45 -0
- package/src/console/ui/dist/assets/panel-gates-Z9MKRGdH.js +1 -0
- package/src/console/ui/dist/assets/panel-overview-Bd48d9km.js +1 -0
- package/src/console/ui/dist/assets/panel-plugins-DWd0TowH.js +1 -0
- package/src/console/ui/dist/assets/panel-runs-BwsWqKeB.js +1 -0
- package/src/console/ui/dist/assets/panel-signals-9najbZY2.js +1 -0
- package/src/console/ui/dist/assets/panel-store-OHkP2pDp.js +1 -0
- package/src/console/ui/dist/assets/panel-traces-tn2JoY8U.js +1 -0
- package/src/console/ui/dist/assets/panel-vault-BbfWdox0.js +1 -0
- package/src/console/ui/dist/assets/rolldown-runtime-CNC7AqOf.js +1 -0
- package/src/console/ui/dist/assets/style-Cnl7WLya.css +3 -0
- package/src/console/ui/dist/index.html +14 -0
- package/src/console/ui/flows/FlowsA11yView.tsx +155 -0
- package/src/console/ui/flows/a11y.test.tsx +105 -0
- package/src/console/ui/flows/buffer.test.ts +91 -0
- package/src/console/ui/flows/buffer.ts +118 -0
- package/src/console/ui/flows/confirmation.ts +131 -0
- package/src/console/ui/flows/contract.test.ts +89 -0
- package/src/console/ui/flows/contract.ts +353 -0
- package/src/console/ui/flows/fixture.ts +81 -0
- package/src/console/ui/flows/graph.test.ts +101 -0
- package/src/console/ui/flows/graph.ts +549 -0
- package/src/console/ui/flows/index.ts +87 -0
- package/src/console/ui/flows/save-as-test.test.ts +47 -0
- package/src/console/ui/flows/save-as-test.ts +99 -0
- package/src/console/ui/flows/search.ts +255 -0
- package/src/console/ui/flows/tiers.ts +140 -0
- package/src/console/ui/gates/GatesA11yView.tsx +192 -0
- package/src/console/ui/gates/a11y.test.tsx +116 -0
- package/src/console/ui/gates/audit.test.ts +40 -0
- package/src/console/ui/gates/audit.ts +63 -0
- package/src/console/ui/gates/denial.test.ts +36 -0
- package/src/console/ui/gates/denial.ts +51 -0
- package/src/console/ui/gates/findings.ts +19 -0
- package/src/console/ui/gates/fixture.ts +189 -0
- package/src/console/ui/gates/group.test.ts +30 -0
- package/src/console/ui/gates/group.ts +102 -0
- package/src/console/ui/gates/index.ts +47 -0
- package/src/console/ui/gates/search.test.ts +49 -0
- package/src/console/ui/gates/search.ts +115 -0
- package/src/console/ui/gates/types.ts +121 -0
- package/src/console/ui/overview/OverviewA11yView.tsx +152 -0
- package/src/console/ui/overview/a11y.test.tsx +113 -0
- package/src/console/ui/overview/busiest.ts +26 -0
- package/src/console/ui/overview/compose.ts +133 -0
- package/src/console/ui/overview/cost.test.ts +39 -0
- package/src/console/ui/overview/cost.ts +138 -0
- package/src/console/ui/overview/fixture.ts +161 -0
- package/src/console/ui/overview/golden.ts +57 -0
- package/src/console/ui/overview/index.ts +59 -0
- package/src/console/ui/overview/rank.test.ts +136 -0
- package/src/console/ui/overview/rank.ts +210 -0
- package/src/console/ui/overview/slo.test.ts +73 -0
- package/src/console/ui/overview/slo.ts +229 -0
- package/src/console/ui/overview/types.ts +121 -0
- package/src/console/ui/overview/verdict.ts +131 -0
- package/src/console/ui/plugins/PluginsA11yView.tsx +227 -0
- package/src/console/ui/plugins/a11y.test.tsx +97 -0
- package/src/console/ui/plugins/command.test.ts +22 -0
- package/src/console/ui/plugins/command.ts +27 -0
- package/src/console/ui/plugins/findings.ts +39 -0
- package/src/console/ui/plugins/fixture.ts +233 -0
- package/src/console/ui/plugins/group.test.ts +38 -0
- package/src/console/ui/plugins/group.ts +67 -0
- package/src/console/ui/plugins/index.ts +40 -0
- package/src/console/ui/plugins/search.ts +67 -0
- package/src/console/ui/plugins/types.ts +115 -0
- package/src/console/ui/runs/RunsA11yView.tsx +267 -0
- package/src/console/ui/runs/a11y.test.tsx +99 -0
- package/src/console/ui/runs/explain.test.ts +23 -0
- package/src/console/ui/runs/explain.ts +32 -0
- package/src/console/ui/runs/fixture.ts +189 -0
- package/src/console/ui/runs/group.test.ts +24 -0
- package/src/console/ui/runs/group.ts +85 -0
- package/src/console/ui/runs/histogram.test.ts +31 -0
- package/src/console/ui/runs/histogram.ts +85 -0
- package/src/console/ui/runs/index.ts +75 -0
- package/src/console/ui/runs/project.ts +122 -0
- package/src/console/ui/runs/query.test.ts +50 -0
- package/src/console/ui/runs/query.ts +283 -0
- package/src/console/ui/runs/search.test.ts +45 -0
- package/src/console/ui/runs/search.ts +141 -0
- package/src/console/ui/runs/trace-link.test.ts +30 -0
- package/src/console/ui/runs/trace-link.ts +99 -0
- package/src/console/ui/runs/types.ts +137 -0
- package/src/console/ui/shell/App.tsx +56 -0
- package/src/console/ui/shell/client.ts +1715 -0
- package/src/console/ui/shell/components/ui.tsx +110 -0
- package/src/console/ui/shell/index.html +12 -0
- package/src/console/ui/shell/layout/Shell.tsx +95 -0
- package/src/console/ui/shell/main.tsx +281 -0
- package/src/console/ui/shell/panels/Access.tsx +5 -0
- package/src/console/ui/shell/panels/Ai.tsx +5 -0
- package/src/console/ui/shell/panels/Architecture.tsx +5 -0
- package/src/console/ui/shell/panels/Channels.tsx +5 -0
- package/src/console/ui/shell/panels/Clock.tsx +5 -0
- package/src/console/ui/shell/panels/Diff.tsx +5 -0
- package/src/console/ui/shell/panels/Flows.tsx +5 -0
- package/src/console/ui/shell/panels/Gates.tsx +5 -0
- package/src/console/ui/shell/panels/Overview.tsx +6 -0
- package/src/console/ui/shell/panels/Plugins.tsx +5 -0
- package/src/console/ui/shell/panels/Runs.tsx +5 -0
- package/src/console/ui/shell/panels/Signals.tsx +5 -0
- package/src/console/ui/shell/panels/Store.tsx +5 -0
- package/src/console/ui/shell/panels/Traces.tsx +5 -0
- package/src/console/ui/shell/panels/Vault.tsx +5 -0
- package/src/console/ui/shell/panels/access/AccessPanel.tsx +813 -0
- package/src/console/ui/shell/panels/ai/AiPanel.tsx +563 -0
- package/src/console/ui/shell/panels/architecture/ArchitecturePanel.tsx +377 -0
- package/src/console/ui/shell/panels/channels/ChannelsPanel.tsx +454 -0
- package/src/console/ui/shell/panels/clock/ClockPanel.tsx +479 -0
- package/src/console/ui/shell/panels/diff/DiffPanel.tsx +275 -0
- package/src/console/ui/shell/panels/flows/ContractEditor.tsx +301 -0
- package/src/console/ui/shell/panels/flows/FlowDrawer.tsx +350 -0
- package/src/console/ui/shell/panels/flows/FlowsPanel.tsx +502 -0
- package/src/console/ui/shell/panels/gates/GatesPanel.tsx +482 -0
- package/src/console/ui/shell/panels/overview/OverviewPanel.tsx +428 -0
- package/src/console/ui/shell/panels/plugins/PluginsPanel.tsx +413 -0
- package/src/console/ui/shell/panels/runs/RunsPanel.tsx +649 -0
- package/src/console/ui/shell/panels/signals/SignalsPanel.tsx +840 -0
- package/src/console/ui/shell/panels/store/StorePanel.tsx +787 -0
- package/src/console/ui/shell/panels/traces/TracesPanel.tsx +539 -0
- package/src/console/ui/shell/panels/vault/VaultPanel.tsx +449 -0
- package/src/console/ui/shell/plugin/Sandbox.tsx +29 -0
- package/src/console/ui/shell/setup/Wizard.tsx +189 -0
- package/src/console/ui/shell/styles.css +75 -0
- package/src/console/ui/signals/SignalsA11yView.tsx +276 -0
- package/src/console/ui/signals/a11y.test.tsx +99 -0
- package/src/console/ui/signals/confirmation.test.ts +39 -0
- package/src/console/ui/signals/confirmation.ts +63 -0
- package/src/console/ui/signals/dry-run.test.ts +18 -0
- package/src/console/ui/signals/dry-run.ts +36 -0
- package/src/console/ui/signals/durable.test.ts +22 -0
- package/src/console/ui/signals/durable.ts +41 -0
- package/src/console/ui/signals/findings.ts +33 -0
- package/src/console/ui/signals/fixture.ts +242 -0
- package/src/console/ui/signals/group.test.ts +32 -0
- package/src/console/ui/signals/group.ts +49 -0
- package/src/console/ui/signals/index.ts +52 -0
- package/src/console/ui/signals/monitor.test.ts +30 -0
- package/src/console/ui/signals/monitor.ts +79 -0
- package/src/console/ui/signals/schema-form.test.ts +34 -0
- package/src/console/ui/signals/schema-form.ts +112 -0
- package/src/console/ui/signals/search.ts +102 -0
- package/src/console/ui/signals/types.ts +71 -0
- package/src/console/ui/store/StoreA11yView.tsx +199 -0
- package/src/console/ui/store/a11y.test.tsx +99 -0
- package/src/console/ui/store/cache-view.test.ts +13 -0
- package/src/console/ui/store/cache-view.ts +36 -0
- package/src/console/ui/store/confirmation.test.ts +38 -0
- package/src/console/ui/store/confirmation.ts +55 -0
- package/src/console/ui/store/dry-run.test.ts +15 -0
- package/src/console/ui/store/dry-run.ts +29 -0
- package/src/console/ui/store/fixture.ts +163 -0
- package/src/console/ui/store/group.test.ts +21 -0
- package/src/console/ui/store/group.ts +41 -0
- package/src/console/ui/store/index.ts +40 -0
- package/src/console/ui/store/search.ts +78 -0
- package/src/console/ui/store/types.ts +65 -0
- package/src/console/ui/store/will-not-fire.test.ts +19 -0
- package/src/console/ui/store/will-not-fire.ts +40 -0
- package/src/console/ui/traces/TracesA11yView.tsx +200 -0
- package/src/console/ui/traces/a11y.test.tsx +97 -0
- package/src/console/ui/traces/chain.test.ts +61 -0
- package/src/console/ui/traces/chain.ts +144 -0
- package/src/console/ui/traces/critical-path.test.ts +24 -0
- package/src/console/ui/traces/critical-path.ts +59 -0
- package/src/console/ui/traces/filter.test.ts +78 -0
- package/src/console/ui/traces/filter.ts +112 -0
- package/src/console/ui/traces/fixture.ts +126 -0
- package/src/console/ui/traces/fold.test.ts +67 -0
- package/src/console/ui/traces/fold.ts +170 -0
- package/src/console/ui/traces/index.ts +64 -0
- package/src/console/ui/traces/mini.ts +65 -0
- package/src/console/ui/traces/replay.test.ts +24 -0
- package/src/console/ui/traces/replay.ts +35 -0
- package/src/console/ui/traces/sampling.test.ts +26 -0
- package/src/console/ui/traces/sampling.ts +66 -0
- package/src/console/ui/traces/search.ts +148 -0
- package/src/console/ui/traces/tier.ts +72 -0
- package/src/console/ui/traces/types.ts +125 -0
- package/src/console/ui/tsconfig.json +20 -0
- package/src/console/ui/vault/VaultA11yView.tsx +177 -0
- package/src/console/ui/vault/a11y.test.tsx +97 -0
- package/src/console/ui/vault/blast-radius.test.ts +35 -0
- package/src/console/ui/vault/blast-radius.ts +55 -0
- package/src/console/ui/vault/confirmation.test.ts +41 -0
- package/src/console/ui/vault/confirmation.ts +39 -0
- package/src/console/ui/vault/dormant.test.ts +37 -0
- package/src/console/ui/vault/dormant.ts +28 -0
- package/src/console/ui/vault/export-safe.test.ts +30 -0
- package/src/console/ui/vault/export-safe.ts +65 -0
- package/src/console/ui/vault/fixture.ts +75 -0
- package/src/console/ui/vault/group.test.ts +25 -0
- package/src/console/ui/vault/group.ts +50 -0
- package/src/console/ui/vault/index.ts +45 -0
- package/src/console/ui/vault/search.ts +62 -0
- package/src/console/ui/vault/types.ts +57 -0
- package/src/console/ui/vite.config.ts +84 -0
- package/src/console/xss.gate.test.ts +118 -0
- package/src/docker/compose.ts +226 -0
- package/src/docker/credentials.ts +25 -0
- package/src/docker/derive.ts +83 -0
- package/src/docker/docker.test.ts +185 -0
- package/src/docker/dockerfile.integration.test.ts +170 -0
- package/src/docker/dockerfile.ts +39 -0
- package/src/docker/helpers.ts +103 -0
- package/src/docker/index.ts +52 -0
- package/src/docker/pin.ts +90 -0
- package/src/docker/recipes/index.ts +33 -0
- package/src/docker/recipes/postgres.ts +18 -0
- package/src/docker/recipes/redis.ts +18 -0
- package/src/docker/stack.integration.test.ts +140 -0
- package/src/docker/stack.ts +62 -0
- package/src/docker/types.ts +134 -0
- package/src/drivers/ai-anthropic.ts +128 -0
- package/src/drivers/ai-mock.ts +82 -0
- package/src/drivers/ai-openai-compatible.ts +139 -0
- package/src/drivers/ai-providers.test.ts +163 -0
- package/src/drivers/ai-types.ts +83 -0
- package/src/drivers/bun-native-completeness.test.ts +155 -0
- package/src/drivers/channel-console.ts +118 -0
- package/src/drivers/channel-fcm.ts +96 -0
- package/src/drivers/channel-resend.ts +27 -0
- package/src/drivers/channel-smtp.ts +33 -0
- package/src/drivers/channel-types.ts +160 -0
- package/src/drivers/channel-unifonic.ts +79 -0
- package/src/drivers/channel-wa-cloud.ts +84 -0
- package/src/drivers/channel-webpush.ts +317 -0
- package/src/drivers/conformance.test.ts +89 -0
- package/src/drivers/conformance.ts +162 -0
- package/src/drivers/fs.ts +73 -0
- package/src/drivers/index.ts +194 -0
- package/src/drivers/kv-lua.ts +222 -0
- package/src/drivers/memory.ts +472 -0
- package/src/drivers/pgvector.ts +130 -0
- package/src/drivers/postgres.ts +221 -0
- package/src/drivers/redis.ts +254 -0
- package/src/drivers/s3.ts +129 -0
- package/src/drivers/signal-engine.ts +690 -0
- package/src/drivers/signal-memory.ts +27 -0
- package/src/drivers/signal-nats.ts +131 -0
- package/src/drivers/signal-postgres.ts +1089 -0
- package/src/drivers/signal-redis.ts +275 -0
- package/src/drivers/signal-types.ts +328 -0
- package/src/drivers/sqlite.ts +53 -0
- package/src/drivers/types.ts +334 -0
- package/src/drivers/vault-dotenv-parse.ts +56 -0
- package/src/drivers/vault-env.ts +101 -0
- package/src/drivers/vault-infisical.ts +61 -0
- package/src/drivers/vault-managed.ts +42 -0
- package/src/drivers/vault-memory.ts +38 -0
- package/src/drivers/vault-openbao.ts +80 -0
- package/src/drivers/vault-sops.ts +252 -0
- package/src/drivers/vault-types.ts +84 -0
- package/src/elements/ai/declare.ts +206 -0
- package/src/elements/ai/eval.ts +113 -0
- package/src/elements/ai/pii.ts +108 -0
- package/src/elements/ai/runtime.ts +540 -0
- package/src/elements/ai/schema.ts +194 -0
- package/src/elements/ai.test.ts +393 -0
- package/src/elements/ai.ts +56 -0
- package/src/elements/channel/consent.ts +81 -0
- package/src/elements/channel/costs.test.ts +62 -0
- package/src/elements/channel/costs.ts +130 -0
- package/src/elements/channel/declare.ts +141 -0
- package/src/elements/channel/email-auth.test.ts +47 -0
- package/src/elements/channel/email-auth.ts +109 -0
- package/src/elements/channel/locale.ts +97 -0
- package/src/elements/channel/mask.test.ts +19 -0
- package/src/elements/channel/mask.ts +60 -0
- package/src/elements/channel/mime.ts +23 -0
- package/src/elements/channel/outcomes.test.ts +40 -0
- package/src/elements/channel/outcomes.ts +126 -0
- package/src/elements/channel/receipts.ts +121 -0
- package/src/elements/channel/runtime.ts +500 -0
- package/src/elements/channel/suppression.ts +136 -0
- package/src/elements/channel.test.ts +232 -0
- package/src/elements/channel.ts +109 -0
- package/src/elements/clock/actions.ts +170 -0
- package/src/elements/clock/declare.ts +58 -0
- package/src/elements/clock/dst.ts +197 -0
- package/src/elements/clock/durable.ts +140 -0
- package/src/elements/clock/duration.ts +29 -0
- package/src/elements/clock/health.test.ts +103 -0
- package/src/elements/clock/health.ts +112 -0
- package/src/elements/clock/leader.ts +127 -0
- package/src/elements/clock/reconcile.ts +241 -0
- package/src/elements/clock/runtime.ts +243 -0
- package/src/elements/clock/schedule.ts +262 -0
- package/src/elements/clock/time-travel.ts +53 -0
- package/src/elements/clock.test.ts +365 -0
- package/src/elements/clock.ts +80 -0
- package/src/elements/gate/declare.ts +134 -0
- package/src/elements/gate/permissions.ts +104 -0
- package/src/elements/gate/runtime.ts +177 -0
- package/src/elements/gate/strategies.ts +388 -0
- package/src/elements/gate.test.ts +145 -0
- package/src/elements/gate.ts +41 -0
- package/src/elements/index.ts +169 -0
- package/src/elements/signal/chaos-child.ts +47 -0
- package/src/elements/signal/declare.ts +77 -0
- package/src/elements/signal/dry-run-replay.test.ts +95 -0
- package/src/elements/signal/dry-run-write-isolation.test.ts +94 -0
- package/src/elements/signal/reconcile.test.ts +23 -0
- package/src/elements/signal/reconcile.ts +122 -0
- package/src/elements/signal/runtime.ts +94 -0
- package/src/elements/signal.test.ts +457 -0
- package/src/elements/signal.ts +26 -0
- package/src/elements/store/cache.ts +197 -0
- package/src/elements/store/classify.ts +125 -0
- package/src/elements/store/declare.ts +200 -0
- package/src/elements/store/files-policy.test.ts +31 -0
- package/src/elements/store/files-policy.ts +70 -0
- package/src/elements/store/replica.ts +68 -0
- package/src/elements/store/runtime.ts +393 -0
- package/src/elements/store/sql-condition.ts +205 -0
- package/src/elements/store/sql-session.ts +579 -0
- package/src/elements/store/table.ts +282 -0
- package/src/elements/store.test.ts +370 -0
- package/src/elements/store.ts +99 -0
- package/src/elements/vault/declare.ts +143 -0
- package/src/elements/vault/fingerprint.ts +30 -0
- package/src/elements/vault/redact.ts +52 -0
- package/src/elements/vault/runtime.ts +461 -0
- package/src/elements/vault.test.ts +296 -0
- package/src/elements/vault.ts +44 -0
- package/src/index.ts +183 -0
- package/src/kernel/adopt-routes.ts +194 -0
- package/src/kernel/app.ts +1068 -0
- package/src/kernel/auth-resolve.ts +93 -0
- package/src/kernel/boot.test.ts +173 -0
- package/src/kernel/boot.ts +439 -0
- package/src/kernel/budget-entry.ts +55 -0
- package/src/kernel/budget.test.ts +19 -0
- package/src/kernel/call.test.ts +83 -0
- package/src/kernel/capability.ts +113 -0
- package/src/kernel/dry-run.test.ts +64 -0
- package/src/kernel/dry-run.ts +171 -0
- package/src/kernel/effects.test.ts +89 -0
- package/src/kernel/effects.ts +140 -0
- package/src/kernel/errors.registry.test.ts +39 -0
- package/src/kernel/errors.ts +225 -0
- package/src/kernel/flow.test.ts +154 -0
- package/src/kernel/flow.ts +290 -0
- package/src/kernel/fx.test.ts +245 -0
- package/src/kernel/fx.ts +996 -0
- package/src/kernel/hook-timing.test.ts +72 -0
- package/src/kernel/hook-timing.ts +190 -0
- package/src/kernel/hooks.test.ts +181 -0
- package/src/kernel/hooks.ts +275 -0
- package/src/kernel/index.ts +278 -0
- package/src/kernel/journal.ts +405 -0
- package/src/kernel/journey.ts +75 -0
- package/src/kernel/on.ts +74 -0
- package/src/kernel/pipeline.test.ts +349 -0
- package/src/kernel/pipeline.ts +245 -0
- package/src/kernel/plug.ts +82 -0
- package/src/kernel/plugin/capabilities.test.ts +84 -0
- package/src/kernel/plugin/conflicts.test.ts +106 -0
- package/src/kernel/plugin/decorate.test.ts +111 -0
- package/src/kernel/plugin/scoping.test.ts +138 -0
- package/src/kernel/plugin.ts +485 -0
- package/src/kernel/rate-limit.ts +25 -0
- package/src/kernel/registry.ts +398 -0
- package/src/kernel/router.test.ts +114 -0
- package/src/kernel/router.ts +556 -0
- package/src/kernel/routing-budget.test.ts +19 -0
- package/src/kernel/run-telemetry.ts +70 -0
- package/src/kernel/triggers.ts +324 -0
- package/src/kernel/unit.ts +88 -0
- package/src/manifest/diff.test.ts +866 -0
- package/src/manifest/diff.ts +1670 -0
- package/src/manifest/fixtures/base.manifest.json +112 -0
- package/src/manifest/fixtures/skyport.excerpt.json +51 -0
- package/src/manifest/fixtures/skyport.manifest.json +153 -0
- package/src/manifest/index.ts +27 -0
- package/src/manifest/types.ts +358 -0
- package/src/manifest/undeclared.test.ts +82 -0
- package/src/manifest/undeclared.ts +65 -0
- package/src/manifest/validate.test.ts +105 -0
- package/src/manifest/validate.ts +174 -0
- package/src/mcp/authorization.ts +340 -0
- package/src/mcp/confirmation.ts +174 -0
- package/src/mcp/data.ts +90 -0
- package/src/mcp/index.ts +80 -0
- package/src/mcp/injection.gate.test.ts +176 -0
- package/src/mcp/mcp.test.ts +348 -0
- package/src/mcp/protocol.ts +172 -0
- package/src/mcp/server.ts +283 -0
- package/src/mcp/session.ts +139 -0
- package/src/mcp/tools.ts +391 -0
- package/src/plugins/catalogue.test.ts +48 -0
- package/src/plugins/catalogue.ts +113 -0
- package/src/plugins/node-import-scan.test.ts +28 -0
- package/src/plugins/node-import-scan.ts +98 -0
- package/src/plugins/supply-chain.test.ts +48 -0
- package/src/plugins/supply-chain.ts +460 -0
- package/src/release/index.ts +30 -0
- package/src/release/limits.ts +20 -0
- package/src/release/measure.ts +443 -0
- package/src/release/publish.ts +56 -0
- package/src/runs/bench.test.ts +93 -0
- package/src/runs/collect.ts +144 -0
- package/src/runs/drivers/clickhouse.ts +108 -0
- package/src/runs/drivers/files.ts +201 -0
- package/src/runs/drivers/memory.ts +94 -0
- package/src/runs/drivers/postgres.ts +110 -0
- package/src/runs/duckdb.ts +99 -0
- package/src/runs/index.ts +82 -0
- package/src/runs/outlier.ts +180 -0
- package/src/runs/parquet.ts +210 -0
- package/src/runs/privacy.ts +49 -0
- package/src/runs/runs.test.ts +324 -0
- package/src/runs/runtime.ts +229 -0
- package/src/runs/shred.ts +243 -0
- package/src/runs/telemetry.ts +10 -0
- package/src/runs/types.ts +179 -0
- package/src/runtime/bun.ts +140 -0
- package/src/runtime/cold-start.bench.ts +20 -0
- package/src/runtime/index.ts +46 -0
- package/src/runtime/primitives.ts +242 -0
- package/src/runtime/security.test.ts +170 -0
- package/src/runtime/security.ts +168 -0
- package/src/runtime/serve.test.ts +223 -0
- package/src/runtime/types.ts +217 -0
- package/src/runtime/web-standard.ts +77 -0
- package/src/test/create-test-app.test.ts +161 -0
- package/src/test/create-test-app.ts +533 -0
- package/src/test/index.ts +21 -0
- package/src/test/provisions.integration.test.ts +174 -0
- package/src/upgrade/codemods.test.ts +58 -0
- package/src/upgrade/codemods.ts +83 -0
- package/src/validation/index.ts +23 -0
- package/src/validation/standard-schema.test.ts +96 -0
- package/src/validation/standard-schema.ts +316 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Folded-time waterfall tests (console §9.3).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, expect, test } from "bun:test";
|
|
6
|
+
import { TRACES_FIXTURE } from "./fixture.ts";
|
|
7
|
+
import {
|
|
8
|
+
COLLAPSED_FOLD_DISPLAY_MS,
|
|
9
|
+
foldTimeline,
|
|
10
|
+
formatFoldLabel,
|
|
11
|
+
intervalsFromSpans,
|
|
12
|
+
} from "./fold.ts";
|
|
13
|
+
|
|
14
|
+
describe("foldTimeline", () => {
|
|
15
|
+
test("collapses multi-day idle into one labelled fold", () => {
|
|
16
|
+
const chain = TRACES_FIXTURE.filter(
|
|
17
|
+
(s) => s.id === "run-create-ok" || s.id === "run-fulfill",
|
|
18
|
+
);
|
|
19
|
+
const folded = foldTimeline(intervalsFromSpans(chain));
|
|
20
|
+
const folds = folded.segments.filter((s) => s.kind === "fold");
|
|
21
|
+
expect(folds.length).toBe(1);
|
|
22
|
+
const fold = folds[0];
|
|
23
|
+
expect(fold?.kind).toBe("fold");
|
|
24
|
+
if (fold?.kind !== "fold") return;
|
|
25
|
+
expect(fold.durationMs).toBeGreaterThan(6 * 24 * 60 * 60 * 1000);
|
|
26
|
+
expect(fold.label).toContain("d idle");
|
|
27
|
+
expect(fold.displayMs).toBe(COLLAPSED_FOLD_DISPLAY_MS);
|
|
28
|
+
expect(fold.expanded).toBe(false);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("expanded fold restores proportional display weight", () => {
|
|
32
|
+
const chain = TRACES_FIXTURE.filter(
|
|
33
|
+
(s) => s.id === "run-create-ok" || s.id === "run-fulfill",
|
|
34
|
+
);
|
|
35
|
+
const intervals = intervalsFromSpans(chain);
|
|
36
|
+
const draft = foldTimeline(intervals);
|
|
37
|
+
const foldId = draft.segments.find((s) => s.kind === "fold")?.id;
|
|
38
|
+
expect(foldId).toBeDefined();
|
|
39
|
+
const folded = foldTimeline(intervals, {
|
|
40
|
+
expandedFolds: new Set([foldId!]),
|
|
41
|
+
});
|
|
42
|
+
const fold = folded.segments.find((s) => s.kind === "fold");
|
|
43
|
+
expect(fold?.kind).toBe("fold");
|
|
44
|
+
if (fold?.kind !== "fold") return;
|
|
45
|
+
expect(fold.expanded).toBe(true);
|
|
46
|
+
expect(fold.displayMs).toBe(fold.durationMs);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("work stays proportional — display sum excludes collapsed dead time", () => {
|
|
50
|
+
const chain = TRACES_FIXTURE.filter(
|
|
51
|
+
(s) => s.id === "run-create-ok" || s.id === "run-fulfill",
|
|
52
|
+
);
|
|
53
|
+
const folded = foldTimeline(intervalsFromSpans(chain));
|
|
54
|
+
const workDisplay = folded.segments
|
|
55
|
+
.filter((s) => s.kind === "work")
|
|
56
|
+
.reduce((s, seg) => s + seg.displayMs, 0);
|
|
57
|
+
expect(folded.displayDurationMs).toBe(
|
|
58
|
+
workDisplay + COLLAPSED_FOLD_DISPLAY_MS,
|
|
59
|
+
);
|
|
60
|
+
expect(folded.wallDurationMs).toBeGreaterThan(folded.displayDurationMs);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("formatFoldLabel uses human units", () => {
|
|
64
|
+
expect(formatFoldLabel(20)).toBe("20ms idle");
|
|
65
|
+
expect(formatFoldLabel(7 * 24 * 60 * 60 * 1000)).toBe("7d idle");
|
|
66
|
+
});
|
|
67
|
+
});
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Folded-time waterfall (console §9.3).
|
|
3
|
+
*
|
|
4
|
+
* Dead time collapses into a labelled, expandable bar the way a diff folds
|
|
5
|
+
* unchanged lines; real work stays exactly proportional. One linear scale
|
|
6
|
+
* serves a 20 ms trace and a week-long one — no modes, no log axis.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { tierOfKind } from "./tier.ts";
|
|
10
|
+
import type { TimelineSegment, TraceSpan, WorkInterval } from "./types.ts";
|
|
11
|
+
|
|
12
|
+
/** Collapsed fold occupies this much of the display scale (ms-equivalent). */
|
|
13
|
+
export const COLLAPSED_FOLD_DISPLAY_MS = 40;
|
|
14
|
+
|
|
15
|
+
/** Gaps at or above this threshold become folds. */
|
|
16
|
+
export const DEFAULT_FOLD_THRESHOLD_MS = 50;
|
|
17
|
+
|
|
18
|
+
/** Options for {@link foldTimeline}. */
|
|
19
|
+
export interface FoldOptions {
|
|
20
|
+
/** Gap threshold before collapsing (default {@link DEFAULT_FOLD_THRESHOLD_MS}). */
|
|
21
|
+
readonly foldThresholdMs?: number;
|
|
22
|
+
/** Ids of folds the operator has expanded. */
|
|
23
|
+
readonly expandedFolds?: ReadonlySet<string>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Result of folding a work timeline. */
|
|
27
|
+
export interface FoldedTimeline {
|
|
28
|
+
/** Ordered segments (work + folds). */
|
|
29
|
+
readonly segments: readonly TimelineSegment[];
|
|
30
|
+
/** Sum of display weights — denominator for proportional widths. */
|
|
31
|
+
readonly displayDurationMs: number;
|
|
32
|
+
/** Wall-clock span of the whole timeline. */
|
|
33
|
+
readonly wallDurationMs: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Format a duration for fold labels (`7d`, `2h`, `340ms`).
|
|
38
|
+
*
|
|
39
|
+
* @param ms - Duration in milliseconds
|
|
40
|
+
*/
|
|
41
|
+
export function formatFoldLabel(ms: number): string {
|
|
42
|
+
const abs = Math.max(0, Math.round(ms));
|
|
43
|
+
if (abs < 1000) return `${abs}ms idle`;
|
|
44
|
+
const sec = abs / 1000;
|
|
45
|
+
if (sec < 60) return `${trim(sec)}s idle`;
|
|
46
|
+
const min = sec / 60;
|
|
47
|
+
if (min < 60) return `${trim(min)}m idle`;
|
|
48
|
+
const hr = min / 60;
|
|
49
|
+
if (hr < 48) return `${trim(hr)}h idle`;
|
|
50
|
+
const day = hr / 24;
|
|
51
|
+
return `${trim(day)}d idle`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Fold dead time out of a sorted work timeline.
|
|
56
|
+
*
|
|
57
|
+
* @param intervals - Work intervals (any order; sorted internally)
|
|
58
|
+
* @param options - Fold threshold and expansion state
|
|
59
|
+
* @param criticalSpanIds - Spans on the critical path
|
|
60
|
+
*/
|
|
61
|
+
export function foldTimeline(
|
|
62
|
+
intervals: readonly WorkInterval[],
|
|
63
|
+
options: FoldOptions = {},
|
|
64
|
+
criticalSpanIds: ReadonlySet<string> = new Set(),
|
|
65
|
+
): FoldedTimeline {
|
|
66
|
+
const threshold = options.foldThresholdMs ?? DEFAULT_FOLD_THRESHOLD_MS;
|
|
67
|
+
const expanded = options.expandedFolds ?? new Set<string>();
|
|
68
|
+
const sorted = [...intervals].sort((a, b) => a.startMs - b.startMs);
|
|
69
|
+
|
|
70
|
+
if (sorted.length === 0) {
|
|
71
|
+
return { segments: [], displayDurationMs: 0, wallDurationMs: 0 };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const first = sorted[0];
|
|
75
|
+
const last = sorted[sorted.length - 1];
|
|
76
|
+
if (!first || !last) {
|
|
77
|
+
return { segments: [], displayDurationMs: 0, wallDurationMs: 0 };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const wallStart = first.startMs;
|
|
81
|
+
const wallEnd = Math.max(...sorted.map((i) => i.endMs));
|
|
82
|
+
const segments: TimelineSegment[] = [];
|
|
83
|
+
let cursor = wallStart;
|
|
84
|
+
|
|
85
|
+
for (const interval of sorted) {
|
|
86
|
+
const gap = interval.startMs - cursor;
|
|
87
|
+
if (gap >= threshold) {
|
|
88
|
+
const foldId = `fold:${cursor}:${interval.startMs}`;
|
|
89
|
+
const isExpanded = expanded.has(foldId);
|
|
90
|
+
const durationMs = gap;
|
|
91
|
+
segments.push({
|
|
92
|
+
kind: "fold",
|
|
93
|
+
id: foldId,
|
|
94
|
+
startMs: cursor,
|
|
95
|
+
endMs: interval.startMs,
|
|
96
|
+
durationMs,
|
|
97
|
+
label: formatFoldLabel(durationMs),
|
|
98
|
+
expanded: isExpanded,
|
|
99
|
+
displayMs: isExpanded ? durationMs : COLLAPSED_FOLD_DISPLAY_MS,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const durationMs = Math.max(0, interval.endMs - interval.startMs);
|
|
104
|
+
segments.push({
|
|
105
|
+
kind: "work",
|
|
106
|
+
id: interval.id,
|
|
107
|
+
label: interval.label,
|
|
108
|
+
startMs: interval.startMs,
|
|
109
|
+
endMs: interval.endMs,
|
|
110
|
+
durationMs,
|
|
111
|
+
tier: interval.tier,
|
|
112
|
+
spanId: interval.spanId,
|
|
113
|
+
critical: criticalSpanIds.has(interval.spanId),
|
|
114
|
+
failed: interval.failed === true,
|
|
115
|
+
displayMs: Math.max(1, durationMs),
|
|
116
|
+
});
|
|
117
|
+
cursor = Math.max(cursor, interval.endMs);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const displayDurationMs = segments.reduce((s, seg) => s + seg.displayMs, 0);
|
|
121
|
+
return {
|
|
122
|
+
segments,
|
|
123
|
+
displayDurationMs: Math.max(1, displayDurationMs),
|
|
124
|
+
wallDurationMs: wallEnd - wallStart,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Build work intervals from spans — one interval per span covering its
|
|
130
|
+
* active wall time. Prefer effect sub-intervals when present so intra-span
|
|
131
|
+
* idle (sleep) can fold too.
|
|
132
|
+
*
|
|
133
|
+
* @param spans - Spans in the open trace
|
|
134
|
+
*/
|
|
135
|
+
export function intervalsFromSpans(spans: readonly TraceSpan[]): WorkInterval[] {
|
|
136
|
+
const out: WorkInterval[] = [];
|
|
137
|
+
for (const span of spans) {
|
|
138
|
+
if (span.effects.length > 0) {
|
|
139
|
+
for (const e of span.effects) {
|
|
140
|
+
out.push({
|
|
141
|
+
id: `${span.id}:${e.kind}:${e.resource}:${e.timestamp}`,
|
|
142
|
+
label: `${e.kind} ${e.resource}`,
|
|
143
|
+
startMs: e.timestamp,
|
|
144
|
+
endMs: e.timestamp + Math.max(1, e.duration),
|
|
145
|
+
tier: tierOfKind(e.kind),
|
|
146
|
+
spanId: span.id,
|
|
147
|
+
failed:
|
|
148
|
+
span.errorCode != null &&
|
|
149
|
+
e === span.effects[span.effects.length - 1],
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
} else {
|
|
153
|
+
out.push({
|
|
154
|
+
id: span.id,
|
|
155
|
+
label: span.flow,
|
|
156
|
+
startMs: span.startedAt,
|
|
157
|
+
endMs: span.endedAt,
|
|
158
|
+
tier: "none",
|
|
159
|
+
spanId: span.id,
|
|
160
|
+
failed: span.errorCode != null,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return out;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function trim(n: number): string {
|
|
168
|
+
const r = Math.round(n * 10) / 10;
|
|
169
|
+
return Number.isInteger(r) ? String(r) : r.toFixed(1);
|
|
170
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Traces panel — folded-time causal chain (console §9.3).
|
|
3
|
+
*
|
|
4
|
+
* Pure modules live here so `bun test src/console/ui/traces` gates behaviour
|
|
5
|
+
* without mounting the full SPA.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
buildCausalChain,
|
|
10
|
+
groupTraceRoots,
|
|
11
|
+
indexSpans,
|
|
12
|
+
initialFocusSpanId,
|
|
13
|
+
type CausalChain,
|
|
14
|
+
type TraceRoot,
|
|
15
|
+
} from "./chain.ts";
|
|
16
|
+
export { criticalPathSpanIds, workMs } from "./critical-path.ts";
|
|
17
|
+
export {
|
|
18
|
+
matchesEffectFilter,
|
|
19
|
+
parseEffectFilter,
|
|
20
|
+
serializeEffectFilter,
|
|
21
|
+
traceMatchesEffectFilter,
|
|
22
|
+
} from "./filter.ts";
|
|
23
|
+
export {
|
|
24
|
+
COLLAPSED_FOLD_DISPLAY_MS,
|
|
25
|
+
DEFAULT_FOLD_THRESHOLD_MS,
|
|
26
|
+
foldTimeline,
|
|
27
|
+
formatFoldLabel,
|
|
28
|
+
intervalsFromSpans,
|
|
29
|
+
type FoldedTimeline,
|
|
30
|
+
type FoldOptions,
|
|
31
|
+
} from "./fold.ts";
|
|
32
|
+
export { miniWaterfall, rootErrorCode } from "./mini.ts";
|
|
33
|
+
export { replayDecision, type ReplayDecision } from "./replay.ts";
|
|
34
|
+
export {
|
|
35
|
+
boostFlowFully,
|
|
36
|
+
DEFAULT_SAMPLING_LABEL,
|
|
37
|
+
FULL_TRACE_BOOST_MS,
|
|
38
|
+
pruneBoosts,
|
|
39
|
+
samplingLabel,
|
|
40
|
+
type FullTraceBoost,
|
|
41
|
+
} from "./sampling.ts";
|
|
42
|
+
export {
|
|
43
|
+
closeTrace,
|
|
44
|
+
effectFilterOf,
|
|
45
|
+
expandedFoldsOf,
|
|
46
|
+
openTrace,
|
|
47
|
+
parseTracesSearch,
|
|
48
|
+
serializeTracesSearch,
|
|
49
|
+
setEffectFilter,
|
|
50
|
+
toggleFold,
|
|
51
|
+
TracesSearchSchema,
|
|
52
|
+
type TracesSearch,
|
|
53
|
+
} from "./search.ts";
|
|
54
|
+
export { peakSpanTier, tierOfKind, traceHasExternal } from "./tier.ts";
|
|
55
|
+
export type {
|
|
56
|
+
EffectFilter,
|
|
57
|
+
MiniBar,
|
|
58
|
+
SampleReason,
|
|
59
|
+
SpanTier,
|
|
60
|
+
TimelineSegment,
|
|
61
|
+
TraceEffect,
|
|
62
|
+
TraceSpan,
|
|
63
|
+
WorkInterval,
|
|
64
|
+
} from "./types.ts";
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inline mini-waterfall for list rows (console §9.3).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { peakSpanTier, tierOfKind } from "./tier.ts";
|
|
6
|
+
import type { MiniBar, TraceSpan } from "./types.ts";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Build proportional mini-bars for a root row (connected spans).
|
|
10
|
+
*
|
|
11
|
+
* @param spans - Spans in the root's connected component
|
|
12
|
+
*/
|
|
13
|
+
export function miniWaterfall(spans: readonly TraceSpan[]): MiniBar[] {
|
|
14
|
+
if (spans.length === 0) return [];
|
|
15
|
+
const start = Math.min(...spans.map((s) => s.startedAt));
|
|
16
|
+
const end = Math.max(...spans.map((s) => s.endedAt));
|
|
17
|
+
const wall = Math.max(1, end - start);
|
|
18
|
+
|
|
19
|
+
if (spans.every((s) => s.effects.length === 0)) {
|
|
20
|
+
return spans.map((s) => ({
|
|
21
|
+
start: (s.startedAt - start) / wall,
|
|
22
|
+
width: Math.max(0.02, s.durationMs / wall),
|
|
23
|
+
tier: peakSpanTier(s.effects),
|
|
24
|
+
failed: s.errorCode != null,
|
|
25
|
+
}));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const bars: MiniBar[] = [];
|
|
29
|
+
for (const s of spans) {
|
|
30
|
+
if (s.effects.length === 0) {
|
|
31
|
+
bars.push({
|
|
32
|
+
start: (s.startedAt - start) / wall,
|
|
33
|
+
width: Math.max(0.02, s.durationMs / wall),
|
|
34
|
+
tier: "none",
|
|
35
|
+
failed: s.errorCode != null,
|
|
36
|
+
});
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
for (let i = 0; i < s.effects.length; i++) {
|
|
40
|
+
const e = s.effects[i];
|
|
41
|
+
if (!e) continue;
|
|
42
|
+
bars.push({
|
|
43
|
+
start: (e.timestamp - start) / wall,
|
|
44
|
+
width: Math.max(0.02, e.duration / wall),
|
|
45
|
+
tier: tierOfKind(e.kind),
|
|
46
|
+
failed: s.errorCode != null && i === s.effects.length - 1,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return bars;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Typed error code for a root row — first failure in the chain, else null.
|
|
55
|
+
*
|
|
56
|
+
* @param spans - Connected spans
|
|
57
|
+
*/
|
|
58
|
+
export function rootErrorCode(
|
|
59
|
+
spans: readonly TraceSpan[],
|
|
60
|
+
): string | null {
|
|
61
|
+
for (const s of spans) {
|
|
62
|
+
if (s.errorCode) return s.errorCode;
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Replay reversibility tests (console §9.3).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, expect, test } from "bun:test";
|
|
6
|
+
import { TRACES_FIXTURE } from "./fixture.ts";
|
|
7
|
+
import { replayDecision } from "./replay.ts";
|
|
8
|
+
|
|
9
|
+
describe("replayDecision", () => {
|
|
10
|
+
test("offers dry-run when the trace has an external effect", () => {
|
|
11
|
+
const chain = TRACES_FIXTURE.filter(
|
|
12
|
+
(s) => s.id === "run-create-ok" || s.id === "run-fulfill",
|
|
13
|
+
);
|
|
14
|
+
const decision = replayDecision(chain);
|
|
15
|
+
expect(decision.mode).toBe("dry-run");
|
|
16
|
+
if (decision.mode !== "dry-run") return;
|
|
17
|
+
expect(decision.reason).toContain("external");
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test("allows full replay when every effect is reversible", () => {
|
|
21
|
+
const fail = TRACES_FIXTURE.filter((s) => s.id === "run-create-fail");
|
|
22
|
+
expect(replayDecision(fail)).toEqual({ mode: "replay" });
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Replay governed by reversibility (console §9.3 · §9.1 · §10.5).
|
|
3
|
+
*
|
|
4
|
+
* A trace containing an external effect offers a dry run with external
|
|
5
|
+
* effects stubbed — never a silent re-send of email / charge.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { traceHasExternal } from "./tier.ts";
|
|
9
|
+
import type { TraceSpan } from "./types.ts";
|
|
10
|
+
|
|
11
|
+
/** Replay decision for a connected trace. */
|
|
12
|
+
export type ReplayDecision =
|
|
13
|
+
| { readonly mode: "replay" }
|
|
14
|
+
| {
|
|
15
|
+
readonly mode: "dry-run";
|
|
16
|
+
readonly reason: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Decide how Replay may proceed for the open trace.
|
|
21
|
+
*
|
|
22
|
+
* @param spans - Connected spans
|
|
23
|
+
*/
|
|
24
|
+
export function replayDecision(
|
|
25
|
+
spans: readonly TraceSpan[],
|
|
26
|
+
): ReplayDecision {
|
|
27
|
+
if (traceHasExternal(spans)) {
|
|
28
|
+
return {
|
|
29
|
+
mode: "dry-run",
|
|
30
|
+
reason:
|
|
31
|
+
"This trace contains an external effect. Replay runs as a dry run with external effects stubbed.",
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
return { mode: "replay" };
|
|
35
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sampling honesty tests (console §9.3).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, expect, test } from "bun:test";
|
|
6
|
+
import {
|
|
7
|
+
boostFlowFully,
|
|
8
|
+
DEFAULT_SAMPLING_LABEL,
|
|
9
|
+
FULL_TRACE_BOOST_MS,
|
|
10
|
+
pruneBoosts,
|
|
11
|
+
samplingLabel,
|
|
12
|
+
} from "./sampling.ts";
|
|
13
|
+
|
|
14
|
+
describe("sampling", () => {
|
|
15
|
+
test("default label states 10% + all errors", () => {
|
|
16
|
+
expect(samplingLabel([])).toBe(DEFAULT_SAMPLING_LABEL);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test("boost adds a 10-minute full-trace escape hatch", () => {
|
|
20
|
+
const now = 1_000_000;
|
|
21
|
+
const boosts = boostFlowFully([], "bookings.create", now);
|
|
22
|
+
expect(boosts[0]?.until).toBe(now + FULL_TRACE_BOOST_MS);
|
|
23
|
+
expect(samplingLabel(boosts, now)).toContain("bookings.create");
|
|
24
|
+
expect(pruneBoosts(boosts, now + FULL_TRACE_BOOST_MS + 1)).toEqual([]);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Honest sampling labels + full-trace escape hatch (console §9.3).
|
|
3
|
+
*
|
|
4
|
+
* Sampling is stated in the list (10% + all errors) with a
|
|
5
|
+
* "trace this flow fully for 10 minutes" override.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** Default sampling policy shown in the list header. */
|
|
9
|
+
export const DEFAULT_SAMPLING_LABEL = "10% + all errors";
|
|
10
|
+
|
|
11
|
+
/** Full-trace boost window (10 minutes). */
|
|
12
|
+
export const FULL_TRACE_BOOST_MS = 10 * 60 * 1000;
|
|
13
|
+
|
|
14
|
+
/** Active boost for one flow. */
|
|
15
|
+
export interface FullTraceBoost {
|
|
16
|
+
/** Flow name. */
|
|
17
|
+
readonly flow: string;
|
|
18
|
+
/** Epoch-ms when the boost expires. */
|
|
19
|
+
readonly until: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Sampling line for the list header, including active boosts.
|
|
24
|
+
*
|
|
25
|
+
* @param boosts - Active boosts
|
|
26
|
+
* @param now - Clock
|
|
27
|
+
*/
|
|
28
|
+
export function samplingLabel(
|
|
29
|
+
boosts: readonly FullTraceBoost[],
|
|
30
|
+
now: number = Date.now(),
|
|
31
|
+
): string {
|
|
32
|
+
const live = boosts.filter((b) => b.until > now);
|
|
33
|
+
if (live.length === 0) return DEFAULT_SAMPLING_LABEL;
|
|
34
|
+
const flows = live.map((b) => b.flow).join(", ");
|
|
35
|
+
return `${DEFAULT_SAMPLING_LABEL} · full: ${flows}`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Create / refresh a 10-minute full-trace boost for a flow.
|
|
40
|
+
*
|
|
41
|
+
* @param boosts - Existing boosts
|
|
42
|
+
* @param flow - Flow to boost
|
|
43
|
+
* @param now - Clock
|
|
44
|
+
*/
|
|
45
|
+
export function boostFlowFully(
|
|
46
|
+
boosts: readonly FullTraceBoost[],
|
|
47
|
+
flow: string,
|
|
48
|
+
now: number = Date.now(),
|
|
49
|
+
): FullTraceBoost[] {
|
|
50
|
+
const until = now + FULL_TRACE_BOOST_MS;
|
|
51
|
+
const rest = boosts.filter((b) => b.flow !== flow && b.until > now);
|
|
52
|
+
return [...rest, { flow, until }];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Prune expired boosts.
|
|
57
|
+
*
|
|
58
|
+
* @param boosts - Boosts
|
|
59
|
+
* @param now - Clock
|
|
60
|
+
*/
|
|
61
|
+
export function pruneBoosts(
|
|
62
|
+
boosts: readonly FullTraceBoost[],
|
|
63
|
+
now: number = Date.now(),
|
|
64
|
+
): FullTraceBoost[] {
|
|
65
|
+
return boosts.filter((b) => b.until > now);
|
|
66
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed search params for the Traces panel (console §7 · §9.3).
|
|
3
|
+
*
|
|
4
|
+
* Pasted links reproduce the exact view — open trace, focus span, effect
|
|
5
|
+
* filter, expanded folds.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import {
|
|
10
|
+
parseEffectFilter,
|
|
11
|
+
serializeEffectFilter,
|
|
12
|
+
type EffectFilter,
|
|
13
|
+
} from "./filter.ts";
|
|
14
|
+
|
|
15
|
+
/** Zod schema for Traces URL search params. */
|
|
16
|
+
export const TracesSearchSchema = z.object({
|
|
17
|
+
/** Open root / connected-component id (usually the root span id). */
|
|
18
|
+
trace: z.string().optional(),
|
|
19
|
+
/** Focused span within the open trace. */
|
|
20
|
+
span: z.string().optional(),
|
|
21
|
+
/** Effect filter compact form (`wrote:sql:bookings`, `cost:0.05`, …). */
|
|
22
|
+
effect: z.string().optional(),
|
|
23
|
+
/** Free-text filter (dims, never hides). */
|
|
24
|
+
q: z.string().optional(),
|
|
25
|
+
/** Comma-separated expanded fold ids. */
|
|
26
|
+
folds: z.string().optional(),
|
|
27
|
+
/** Flow selected for the full-trace boost control (UI only). */
|
|
28
|
+
boost: z.string().optional(),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
/** Parsed, typed Traces search state. */
|
|
32
|
+
export type TracesSearch = z.infer<typeof TracesSearchSchema>;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Parse unknown search params into a typed {@link TracesSearch}.
|
|
36
|
+
*
|
|
37
|
+
* @param raw - Router search object
|
|
38
|
+
*/
|
|
39
|
+
export function parseTracesSearch(raw: unknown): TracesSearch {
|
|
40
|
+
const result = TracesSearchSchema.safeParse(raw ?? {});
|
|
41
|
+
if (result.success) return result.data;
|
|
42
|
+
return TracesSearchSchema.parse({});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Serialise typed search into a plain object suitable for TanStack Router.
|
|
47
|
+
*
|
|
48
|
+
* @param search - Typed search
|
|
49
|
+
*/
|
|
50
|
+
export function serializeTracesSearch(
|
|
51
|
+
search: TracesSearch,
|
|
52
|
+
): Record<string, string> {
|
|
53
|
+
const out: Record<string, string> = {};
|
|
54
|
+
if (search.trace) out.trace = search.trace;
|
|
55
|
+
if (search.span) out.span = search.span;
|
|
56
|
+
if (search.effect) out.effect = search.effect;
|
|
57
|
+
if (search.q) out.q = search.q;
|
|
58
|
+
if (search.folds) out.folds = search.folds;
|
|
59
|
+
if (search.boost) out.boost = search.boost;
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Effect filter derived from search.
|
|
65
|
+
*
|
|
66
|
+
* @param search - Typed search
|
|
67
|
+
*/
|
|
68
|
+
export function effectFilterOf(search: TracesSearch): EffectFilter | null {
|
|
69
|
+
return parseEffectFilter(search.effect);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Expanded fold ids from search.
|
|
74
|
+
*
|
|
75
|
+
* @param search - Typed search
|
|
76
|
+
*/
|
|
77
|
+
export function expandedFoldsOf(search: TracesSearch): Set<string> {
|
|
78
|
+
if (!search.folds) return new Set();
|
|
79
|
+
return new Set(
|
|
80
|
+
search.folds
|
|
81
|
+
.split(",")
|
|
82
|
+
.map((s) => s.trim())
|
|
83
|
+
.filter(Boolean),
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Open a trace (root id) and optional focus span.
|
|
89
|
+
*
|
|
90
|
+
* @param prev - Current search
|
|
91
|
+
* @param rootId - Root span id
|
|
92
|
+
* @param spanId - Optional focus span
|
|
93
|
+
*/
|
|
94
|
+
export function openTrace(
|
|
95
|
+
prev: TracesSearch,
|
|
96
|
+
rootId: string,
|
|
97
|
+
spanId?: string,
|
|
98
|
+
): TracesSearch {
|
|
99
|
+
return {
|
|
100
|
+
...prev,
|
|
101
|
+
trace: rootId,
|
|
102
|
+
span: spanId,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Close the detail view; stay on the Traces panel.
|
|
108
|
+
*
|
|
109
|
+
* @param prev - Current search
|
|
110
|
+
*/
|
|
111
|
+
export function closeTrace(prev: TracesSearch): TracesSearch {
|
|
112
|
+
return {
|
|
113
|
+
...prev,
|
|
114
|
+
trace: undefined,
|
|
115
|
+
span: undefined,
|
|
116
|
+
folds: undefined,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Toggle a fold's expanded state in the URL.
|
|
122
|
+
*
|
|
123
|
+
* @param prev - Current search
|
|
124
|
+
* @param foldId - Fold segment id
|
|
125
|
+
*/
|
|
126
|
+
export function toggleFold(prev: TracesSearch, foldId: string): TracesSearch {
|
|
127
|
+
const set = expandedFoldsOf(prev);
|
|
128
|
+
if (set.has(foldId)) set.delete(foldId);
|
|
129
|
+
else set.add(foldId);
|
|
130
|
+
const folds = [...set].join(",");
|
|
131
|
+
return { ...prev, folds: folds || undefined };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Set the effect filter (or clear with null).
|
|
136
|
+
*
|
|
137
|
+
* @param prev - Current search
|
|
138
|
+
* @param filter - Effect filter
|
|
139
|
+
*/
|
|
140
|
+
export function setEffectFilter(
|
|
141
|
+
prev: TracesSearch,
|
|
142
|
+
filter: EffectFilter | null,
|
|
143
|
+
): TracesSearch {
|
|
144
|
+
return {
|
|
145
|
+
...prev,
|
|
146
|
+
effect: serializeEffectFilter(filter),
|
|
147
|
+
};
|
|
148
|
+
}
|