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,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request pipeline hooks for element integration.
|
|
3
|
+
*
|
|
4
|
+
* - `onAuth` resolves the principal into `fx.auth` / `fx.operator`
|
|
5
|
+
* - `beforeHandle` evaluates the declared gate chain in registration order,
|
|
6
|
+
* short-circuiting on the first denial with a typed error value
|
|
7
|
+
* (`Unauthorized` · `Forbidden` · `RateLimited { retryAfterMs }`)
|
|
8
|
+
*
|
|
9
|
+
* Every evaluation — pass and deny — is recorded on the run's gates dimension.
|
|
10
|
+
* Gate denial is a typed error value, never a thrown exception.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { GateEvaluation, GateRuntime } from "../elements/gate.ts";
|
|
14
|
+
import type { GatePolicyContext } from "../elements/gate/declare.ts";
|
|
15
|
+
import { fail, type FlowFailure } from "./errors.ts";
|
|
16
|
+
import type { Fx, FxAuth, FxOperator } from "./fx.ts";
|
|
17
|
+
import type { HookFn, InvocationContext } from "./hooks.ts";
|
|
18
|
+
import type { RunTelemetry } from "./run-telemetry.ts";
|
|
19
|
+
import type { HttpTrigger, Trigger } from "./triggers.ts";
|
|
20
|
+
|
|
21
|
+
/** Mutable principal bag shared with {@link createFx}. */
|
|
22
|
+
export interface PrincipalBag {
|
|
23
|
+
readonly auth: {
|
|
24
|
+
userId: string | null;
|
|
25
|
+
scopes: Set<string>;
|
|
26
|
+
verified?: boolean;
|
|
27
|
+
};
|
|
28
|
+
readonly operator: {
|
|
29
|
+
id: string | null;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Resolved identity from auth middleware / test harness. */
|
|
34
|
+
export interface ResolvedPrincipal {
|
|
35
|
+
readonly plane?: "user" | "operator";
|
|
36
|
+
readonly userId?: string | null;
|
|
37
|
+
readonly operatorId?: string | null;
|
|
38
|
+
readonly scopes?: Iterable<string>;
|
|
39
|
+
readonly verified?: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Dependencies for {@link createElementPipelineHooks}. */
|
|
43
|
+
export interface PipelineDeps {
|
|
44
|
+
/** Gate runtime (required for gate evaluation). */
|
|
45
|
+
readonly gates?: GateRuntime;
|
|
46
|
+
/**
|
|
47
|
+
* Cryptographically verify a Bearer access token.
|
|
48
|
+
* Required in production when an `Authorization` header is present.
|
|
49
|
+
*
|
|
50
|
+
* @param token - Raw token (no `Bearer ` prefix)
|
|
51
|
+
* @returns Principal on success
|
|
52
|
+
* @throws On forge / expiry / revoke — pipeline maps to `Unauthorized`
|
|
53
|
+
*/
|
|
54
|
+
readonly verifyBearer?: (token: string) => Promise<ResolvedPrincipal>;
|
|
55
|
+
/**
|
|
56
|
+
* When true, `ctx.state.principal` / execute `extras.principal` injection
|
|
57
|
+
* is honoured (test harness only). Must be false for production HTTP.
|
|
58
|
+
*/
|
|
59
|
+
readonly allowTestPrincipals?: boolean;
|
|
60
|
+
/** Per-invocation principal bag (same object passed into createFx). */
|
|
61
|
+
readonly principals: PrincipalBag;
|
|
62
|
+
/** Telemetry collector for the current run (gates dimension). */
|
|
63
|
+
readonly telemetry: RunTelemetry;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Typed gate-denial failures the Gates simulator promises.
|
|
68
|
+
*/
|
|
69
|
+
export type GateDenialCode = "Unauthorized" | "Forbidden" | "RateLimited";
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Map a denied gate evaluation to the typed error the simulator promises.
|
|
73
|
+
*
|
|
74
|
+
* @param evaluation - First denying evaluation
|
|
75
|
+
* @param ctx - Policy context at denial time
|
|
76
|
+
*/
|
|
77
|
+
export function gateDenialFailure(
|
|
78
|
+
evaluation: GateEvaluation,
|
|
79
|
+
ctx: GatePolicyContext,
|
|
80
|
+
): FlowFailure {
|
|
81
|
+
if (evaluation.kind === "rate" || evaluation.reason === "rate limited") {
|
|
82
|
+
return fail("RateLimited", {
|
|
83
|
+
retryAfterMs: evaluation.retryAfterMs ?? 0,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const authenticated =
|
|
88
|
+
ctx.auth.userId !== null && ctx.auth.userId !== undefined;
|
|
89
|
+
if (!authenticated) {
|
|
90
|
+
return fail("Unauthorized", {});
|
|
91
|
+
}
|
|
92
|
+
return fail("Forbidden", {
|
|
93
|
+
gate: evaluation.name,
|
|
94
|
+
reason: evaluation.reason ?? "policy denied",
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Collect gate names from an HTTP trigger (registration order).
|
|
100
|
+
*
|
|
101
|
+
* @param trigger - Active trigger
|
|
102
|
+
*/
|
|
103
|
+
export function gateNamesOf(trigger: Trigger): string[] {
|
|
104
|
+
if (trigger.kind !== "http") return [];
|
|
105
|
+
return (trigger as HttpTrigger).gates.map((g) =>
|
|
106
|
+
typeof g === "string" ? g : g.name,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Record evaluations onto run telemetry (pass and deny).
|
|
112
|
+
*
|
|
113
|
+
* @param telemetry - Run collector
|
|
114
|
+
* @param evaluations - Ordered results
|
|
115
|
+
*/
|
|
116
|
+
export function recordGateEvaluations(
|
|
117
|
+
telemetry: RunTelemetry,
|
|
118
|
+
evaluations: readonly GateEvaluation[],
|
|
119
|
+
): void {
|
|
120
|
+
for (const ev of evaluations) {
|
|
121
|
+
telemetry.gates.push(ev.name);
|
|
122
|
+
telemetry.dimensions[`gate:${ev.name}`] = ev.allowed ? "pass" : "deny";
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Apply a resolved principal onto the shared bags (and thus `fx`).
|
|
128
|
+
*
|
|
129
|
+
* @param bag - Mutable principal bag
|
|
130
|
+
* @param resolved - Identity
|
|
131
|
+
*/
|
|
132
|
+
export function applyPrincipal(
|
|
133
|
+
bag: PrincipalBag,
|
|
134
|
+
resolved: ResolvedPrincipal | undefined,
|
|
135
|
+
): void {
|
|
136
|
+
if (!resolved) return;
|
|
137
|
+
if (resolved.plane === "operator" || resolved.operatorId !== undefined) {
|
|
138
|
+
bag.operator.id = resolved.operatorId ?? null;
|
|
139
|
+
}
|
|
140
|
+
if (
|
|
141
|
+
resolved.plane === "user" ||
|
|
142
|
+
resolved.userId !== undefined ||
|
|
143
|
+
resolved.scopes !== undefined ||
|
|
144
|
+
resolved.verified !== undefined
|
|
145
|
+
) {
|
|
146
|
+
if (resolved.userId !== undefined) bag.auth.userId = resolved.userId;
|
|
147
|
+
if (resolved.scopes !== undefined) {
|
|
148
|
+
bag.auth.scopes.clear();
|
|
149
|
+
for (const s of resolved.scopes) bag.auth.scopes.add(s);
|
|
150
|
+
}
|
|
151
|
+
if (resolved.verified !== undefined) bag.auth.verified = resolved.verified;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Build `onAuth` + `beforeHandle` hooks for element-aware execution.
|
|
157
|
+
*
|
|
158
|
+
* @param deps - Gate runtime, principal bag, telemetry
|
|
159
|
+
*/
|
|
160
|
+
export function createElementPipelineHooks(deps: PipelineDeps): {
|
|
161
|
+
readonly onAuth: HookFn;
|
|
162
|
+
readonly beforeHandle: HookFn;
|
|
163
|
+
} {
|
|
164
|
+
const onAuth: HookFn = async (ctx) => {
|
|
165
|
+
// Production: never honour injected principals on the request bag.
|
|
166
|
+
if (!deps.allowTestPrincipals && "principal" in ctx.state) {
|
|
167
|
+
delete ctx.state.principal;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const header = ctx.request?.headers.get("authorization");
|
|
171
|
+
if (header?.startsWith("Bearer ")) {
|
|
172
|
+
const token = header.slice("Bearer ".length).trim();
|
|
173
|
+
if (!token) {
|
|
174
|
+
return fail("Unauthorized", {});
|
|
175
|
+
}
|
|
176
|
+
if (!deps.verifyBearer) {
|
|
177
|
+
// Bearer present but no auth binding — refuse rather than trust.
|
|
178
|
+
return fail("Unauthorized", {});
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
const principal = await deps.verifyBearer(token);
|
|
182
|
+
applyPrincipal(deps.principals, principal);
|
|
183
|
+
return;
|
|
184
|
+
} catch {
|
|
185
|
+
// Forge / expiry / revoke → typed Unauthorized (never throw).
|
|
186
|
+
return fail("Unauthorized", {});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Test-harness injection only (createTestApp / unit tests).
|
|
191
|
+
if (deps.allowTestPrincipals) {
|
|
192
|
+
const fromState = ctx.state.principal as ResolvedPrincipal | undefined;
|
|
193
|
+
if (fromState) applyPrincipal(deps.principals, fromState);
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const beforeHandle: HookFn = async (ctx, fxOrErr) => {
|
|
198
|
+
const names = gateNamesOf(ctx.trigger);
|
|
199
|
+
if (names.length === 0 || !deps.gates) return;
|
|
200
|
+
|
|
201
|
+
const policyCtx = policyContextOf(fxOrErr as Fx, ctx);
|
|
202
|
+
const evaluations = await deps.gates.check(names, policyCtx);
|
|
203
|
+
recordGateEvaluations(deps.telemetry, evaluations);
|
|
204
|
+
|
|
205
|
+
const denied = evaluations.find((e) => !e.allowed);
|
|
206
|
+
if (denied) {
|
|
207
|
+
return gateDenialFailure(denied, policyCtx);
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
return { onAuth, beforeHandle };
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Build a policy context from the live `fx` principals.
|
|
216
|
+
*
|
|
217
|
+
* @param fx - Fx door
|
|
218
|
+
* @param ctx - Invocation context (for IP / meta)
|
|
219
|
+
*/
|
|
220
|
+
export function policyContextOf(
|
|
221
|
+
fx: Fx,
|
|
222
|
+
ctx: InvocationContext,
|
|
223
|
+
): GatePolicyContext {
|
|
224
|
+
const auth = fx.auth as FxAuth;
|
|
225
|
+
const operator = fx.operator as FxOperator;
|
|
226
|
+
const ip =
|
|
227
|
+
ctx.request?.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ??
|
|
228
|
+
ctx.request?.headers.get("x-real-ip") ??
|
|
229
|
+
undefined;
|
|
230
|
+
return {
|
|
231
|
+
auth: {
|
|
232
|
+
userId: auth.userId,
|
|
233
|
+
scopes: auth.scopes,
|
|
234
|
+
verified: auth.verified,
|
|
235
|
+
},
|
|
236
|
+
operator: { id: operator.id },
|
|
237
|
+
meta: {
|
|
238
|
+
ip,
|
|
239
|
+
userId: auth.userId,
|
|
240
|
+
...(typeof ctx.state.meta === "object" && ctx.state.meta !== null
|
|
241
|
+
? (ctx.state.meta as Record<string, unknown>)
|
|
242
|
+
: {}),
|
|
243
|
+
},
|
|
244
|
+
};
|
|
245
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `.plug()` — attach a plugin at an attachment point.
|
|
3
|
+
*
|
|
4
|
+
* Scope is the attachment point:
|
|
5
|
+
* - `app.plug()` — app-wide
|
|
6
|
+
* - `unit.plug()` — that unit only
|
|
7
|
+
* - `flow.plug()` — one flow only
|
|
8
|
+
*
|
|
9
|
+
* No `global: true`, no escape hatch, no inheritance rule.
|
|
10
|
+
* The position is the scope.
|
|
11
|
+
*
|
|
12
|
+
* @see docs/spec/console.md §9.15
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import type { AnyFlowDef } from "./flow.ts";
|
|
16
|
+
import { isPlugin, type DecorationsOf, type PluginDef } from "./plugin.ts";
|
|
17
|
+
import {
|
|
18
|
+
type PluginRegistry,
|
|
19
|
+
type PluginScope,
|
|
20
|
+
} from "./registry.ts";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Apply a plugin to a registry at the given scope.
|
|
24
|
+
*
|
|
25
|
+
* @param registry - App plugin registry
|
|
26
|
+
* @param pluginDef - Plugin definition
|
|
27
|
+
* @param scope - Attachment point
|
|
28
|
+
*/
|
|
29
|
+
export function applyPlugin(
|
|
30
|
+
registry: PluginRegistry,
|
|
31
|
+
pluginDef: PluginDef,
|
|
32
|
+
scope: PluginScope,
|
|
33
|
+
): void {
|
|
34
|
+
if (!isPlugin(pluginDef)) {
|
|
35
|
+
throw new TypeError(".plug() expected a plugin() definition");
|
|
36
|
+
}
|
|
37
|
+
registry.plug(pluginDef, scope);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Type-level accumulation helper: merge decorations from a plugged plugin.
|
|
42
|
+
*
|
|
43
|
+
* @typeParam Base - Existing decorations
|
|
44
|
+
* @typeParam P - Plugin being plugged
|
|
45
|
+
*/
|
|
46
|
+
export type AccumulateDecorations<
|
|
47
|
+
Base extends Record<string, unknown>,
|
|
48
|
+
P,
|
|
49
|
+
> = Base & DecorationsOf<P>;
|
|
50
|
+
|
|
51
|
+
/** Something that can receive `.plug()` with type accumulation. */
|
|
52
|
+
export interface Pluggable<D extends Record<string, unknown> = {}> {
|
|
53
|
+
/**
|
|
54
|
+
* Attach a plugin. Scope is this attachment point.
|
|
55
|
+
*
|
|
56
|
+
* @param pluginDef - Plugin from {@link plugin}
|
|
57
|
+
*/
|
|
58
|
+
plug<P extends PluginDef>(
|
|
59
|
+
pluginDef: P,
|
|
60
|
+
): Pluggable<AccumulateDecorations<D, P>>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Resolve the plugin scope for a flow attachment.
|
|
65
|
+
*
|
|
66
|
+
* @param flowDef - Flow being plugged into
|
|
67
|
+
*/
|
|
68
|
+
export function flowPluginScope(flowDef: AnyFlowDef): PluginScope {
|
|
69
|
+
return { kind: "flow", name: flowDef.name };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Resolve the plugin scope for a unit attachment.
|
|
74
|
+
*
|
|
75
|
+
* @param unitName - Unit name
|
|
76
|
+
*/
|
|
77
|
+
export function unitPluginScope(unitName: string): PluginScope {
|
|
78
|
+
return { kind: "unit", name: unitName };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** App-wide plugin scope. */
|
|
82
|
+
export const appPluginScope: PluginScope = { kind: "app" };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capability capture — registration against the builder we supply.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, expect, test } from "bun:test";
|
|
6
|
+
import { flow } from "../flow.ts";
|
|
7
|
+
import { plugin } from "../plugin.ts";
|
|
8
|
+
import { createPluginRegistry, createRecordingApi } from "../registry.ts";
|
|
9
|
+
|
|
10
|
+
describe("plugin capability capture", () => {
|
|
11
|
+
test("recording api captures declares vs intercepts", () => {
|
|
12
|
+
const audit = plugin("audit", { version: "1.0.0" })
|
|
13
|
+
.config({} as never)
|
|
14
|
+
.element({ kind: "store.sql", name: "audit" })
|
|
15
|
+
.needs("store.kv")
|
|
16
|
+
.decorate("audit", { enabled: true })
|
|
17
|
+
.hook("afterHandle", async () => {})
|
|
18
|
+
.errors({ AuditWriteFailed: {} as never })
|
|
19
|
+
.consolePanel({
|
|
20
|
+
id: "audit",
|
|
21
|
+
title: "Audit Trail",
|
|
22
|
+
entry: "./panel.tsx",
|
|
23
|
+
})
|
|
24
|
+
.cli("audit:export", () => undefined)
|
|
25
|
+
.table("audit_events")
|
|
26
|
+
.driver("postgres")
|
|
27
|
+
.image("store.sql", "postgres:16")
|
|
28
|
+
.flow(flow({ name: "audit.flush", do: () => undefined }))
|
|
29
|
+
.client("audit", { subscribe: true });
|
|
30
|
+
|
|
31
|
+
const { api, snapshot } = createRecordingApi({
|
|
32
|
+
name: "audit",
|
|
33
|
+
version: "1.0.0",
|
|
34
|
+
});
|
|
35
|
+
audit.register(api);
|
|
36
|
+
const caps = snapshot().capabilities;
|
|
37
|
+
|
|
38
|
+
const expected = {
|
|
39
|
+
name: "audit",
|
|
40
|
+
version: "1.0.0",
|
|
41
|
+
declares: [
|
|
42
|
+
"config",
|
|
43
|
+
"store.sql:audit",
|
|
44
|
+
"decorate:audit",
|
|
45
|
+
"errors:AuditWriteFailed",
|
|
46
|
+
"consolePanel:audit",
|
|
47
|
+
"cli:audit:export",
|
|
48
|
+
"table:audit_events",
|
|
49
|
+
"driver:postgres",
|
|
50
|
+
"image:store.sql",
|
|
51
|
+
"flow:audit.flush",
|
|
52
|
+
"client:audit",
|
|
53
|
+
],
|
|
54
|
+
intercepts: ["afterHandle"],
|
|
55
|
+
needs: ["store.kv"],
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
expect(caps).toEqual(expected);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("registry.capabilities matches hand-written expectation after plug", () => {
|
|
62
|
+
const registry = createPluginRegistry();
|
|
63
|
+
const p = plugin("audit", { version: "1.0.0" })
|
|
64
|
+
.element({ kind: "store.sql", name: "audit" })
|
|
65
|
+
.consolePanel({
|
|
66
|
+
id: "audit",
|
|
67
|
+
title: "Audit Trail",
|
|
68
|
+
entry: "./panel.tsx",
|
|
69
|
+
})
|
|
70
|
+
.hook("afterHandle", () => {});
|
|
71
|
+
|
|
72
|
+
registry.plug(p, { kind: "app" });
|
|
73
|
+
|
|
74
|
+
expect(registry.capabilities()).toEqual({
|
|
75
|
+
audit: {
|
|
76
|
+
name: "audit",
|
|
77
|
+
version: "1.0.0",
|
|
78
|
+
declares: ["store.sql:audit", "consolePanel:audit"],
|
|
79
|
+
intercepts: ["afterHandle"],
|
|
80
|
+
needs: [],
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
});
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conflict detection — never last-write-wins.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, expect, test } from "bun:test";
|
|
6
|
+
import { plugin } from "../plugin.ts";
|
|
7
|
+
import { createPluginRegistry } from "../registry.ts";
|
|
8
|
+
|
|
9
|
+
describe("plugin conflict detection", () => {
|
|
10
|
+
test("table-name collision fails the boot with both plugin names", () => {
|
|
11
|
+
const registry = createPluginRegistry();
|
|
12
|
+
|
|
13
|
+
registry.plug(
|
|
14
|
+
plugin("audit", { version: "1.0.0" }).table("events"),
|
|
15
|
+
{ kind: "app" },
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
expect(() =>
|
|
19
|
+
registry.plug(
|
|
20
|
+
plugin("billing", { version: "1.0.0" }).table("events"),
|
|
21
|
+
{ kind: "app" },
|
|
22
|
+
),
|
|
23
|
+
).toThrow(
|
|
24
|
+
'Plugin conflict: table "events" claimed by "audit" and "billing"',
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test("panel-id collision names both sides", () => {
|
|
29
|
+
const registry = createPluginRegistry();
|
|
30
|
+
|
|
31
|
+
registry.plug(
|
|
32
|
+
plugin("a", { version: "1.0.0" }).consolePanel({
|
|
33
|
+
id: "trail",
|
|
34
|
+
title: "A",
|
|
35
|
+
entry: "./a.tsx",
|
|
36
|
+
}),
|
|
37
|
+
{ kind: "app" },
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
expect(() =>
|
|
41
|
+
registry.plug(
|
|
42
|
+
plugin("b", { version: "1.0.0" }).consolePanel({
|
|
43
|
+
id: "trail",
|
|
44
|
+
title: "B",
|
|
45
|
+
entry: "./b.tsx",
|
|
46
|
+
}),
|
|
47
|
+
{ kind: "app" },
|
|
48
|
+
),
|
|
49
|
+
).toThrow('Plugin conflict: panel "trail" claimed by "a" and "b"');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("driver-id collision names both sides", () => {
|
|
53
|
+
const registry = createPluginRegistry();
|
|
54
|
+
|
|
55
|
+
registry.plug(plugin("a", { version: "1.0.0" }).driver("postgres"), {
|
|
56
|
+
kind: "app",
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
expect(() =>
|
|
60
|
+
registry.plug(plugin("b", { version: "1.0.0" }).driver("postgres"), {
|
|
61
|
+
kind: "app",
|
|
62
|
+
}),
|
|
63
|
+
).toThrow('Plugin conflict: driver "postgres" claimed by "a" and "b"');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("same plugin twice at the same scope is a no-op", () => {
|
|
67
|
+
const registry = createPluginRegistry();
|
|
68
|
+
const p = plugin("audit", { version: "1.0.0" }).table("audit_log");
|
|
69
|
+
|
|
70
|
+
expect(registry.plug(p, { kind: "app" })).toBeDefined();
|
|
71
|
+
expect(registry.plug(p, { kind: "app" })).toBeUndefined();
|
|
72
|
+
expect(registry.installed).toHaveLength(1);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("same plugin+config at two scopes is allowed", () => {
|
|
76
|
+
const registry = createPluginRegistry();
|
|
77
|
+
const p = plugin("rate-limit", {
|
|
78
|
+
version: "1.0.0",
|
|
79
|
+
config: { max: 30 },
|
|
80
|
+
}).hook("onRequest", () => {});
|
|
81
|
+
|
|
82
|
+
expect(
|
|
83
|
+
registry.plug(p, { kind: "unit", name: "orders" }),
|
|
84
|
+
).toBeDefined();
|
|
85
|
+
expect(
|
|
86
|
+
registry.plug(p, { kind: "unit", name: "payments" }),
|
|
87
|
+
).toBeDefined();
|
|
88
|
+
expect(registry.installed).toHaveLength(2);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("same plugin twice with conflicting config is a boot error", () => {
|
|
92
|
+
const registry = createPluginRegistry();
|
|
93
|
+
|
|
94
|
+
registry.plug(
|
|
95
|
+
plugin("rate-limit", { version: "1.0.0", config: { max: 30 } }),
|
|
96
|
+
{ kind: "unit", name: "orders" },
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
expect(() =>
|
|
100
|
+
registry.plug(
|
|
101
|
+
plugin("rate-limit", { version: "1.0.0", config: { max: 60 } }),
|
|
102
|
+
{ kind: "unit", name: "payments" },
|
|
103
|
+
),
|
|
104
|
+
).toThrow(/conflicting config/);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type accumulation through `.plug()` — decorations visible downstream.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { beforeEach, describe, expect, test } from "bun:test";
|
|
6
|
+
import { oke, type OkeApp } from "../app.ts";
|
|
7
|
+
import { flow, resetFlowSeq } from "../flow.ts";
|
|
8
|
+
import { on, resetBindings } from "../on.ts";
|
|
9
|
+
import { plugin, type PluginDef } from "../plugin.ts";
|
|
10
|
+
import { http } from "../triggers.ts";
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
resetBindings();
|
|
14
|
+
resetFlowSeq();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
/** Compile-time assert: `Actual` extends `Expected`. */
|
|
18
|
+
type ExpectExtends<Actual, Expected> =
|
|
19
|
+
Actual extends Expected ? true : false;
|
|
20
|
+
|
|
21
|
+
describe("plugin decorate — types and runtime", () => {
|
|
22
|
+
test("decoration is visible in downstream handlers", async () => {
|
|
23
|
+
const audit = plugin("audit", { version: "1.0.0" }).decorate("audit", {
|
|
24
|
+
enabled: true,
|
|
25
|
+
retain: "2y",
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
let seen: unknown;
|
|
29
|
+
on(
|
|
30
|
+
http.get("/x"),
|
|
31
|
+
flow({
|
|
32
|
+
name: "x",
|
|
33
|
+
do: (_input, _fx) => {
|
|
34
|
+
return { ok: true };
|
|
35
|
+
},
|
|
36
|
+
}).hook("beforeHandle", (ctx) => {
|
|
37
|
+
seen = ctx.decorations.audit;
|
|
38
|
+
}),
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const app = oke({ name: "decorate" }).plug(audit);
|
|
42
|
+
await app.fetch(new Request("http://localhost/x"));
|
|
43
|
+
|
|
44
|
+
expect(seen).toEqual({ enabled: true, retain: "2y" });
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("types accumulate through .plug()", () => {
|
|
48
|
+
const withAudit = plugin("audit", { version: "1.0.0" }).decorate(
|
|
49
|
+
"audit",
|
|
50
|
+
{ enabled: true as const },
|
|
51
|
+
);
|
|
52
|
+
const withBilling = plugin("billing", { version: "1.0.0" }).decorate(
|
|
53
|
+
"billing",
|
|
54
|
+
{ currency: "SAR" as const },
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const app = oke({ name: "types" }).plug(withAudit).plug(withBilling);
|
|
58
|
+
|
|
59
|
+
type AppDeco = typeof app extends OkeApp<infer D> ? D : never;
|
|
60
|
+
type HasBoth = ExpectExtends<
|
|
61
|
+
AppDeco,
|
|
62
|
+
{ audit: { enabled: true }; billing: { currency: "SAR" } }
|
|
63
|
+
>;
|
|
64
|
+
|
|
65
|
+
const _typeCheck: HasBoth = true;
|
|
66
|
+
expect(_typeCheck).toBe(true);
|
|
67
|
+
|
|
68
|
+
// PluginDef decoration param also accumulates on the builder itself.
|
|
69
|
+
type AuditPlugin = typeof withAudit;
|
|
70
|
+
type AuditDeco = AuditPlugin extends PluginDef<infer D> ? D : never;
|
|
71
|
+
type HasAudit = ExpectExtends<AuditDeco, { audit: { enabled: true } }>;
|
|
72
|
+
const _pluginType: HasAudit = true;
|
|
73
|
+
expect(_pluginType).toBe(true);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("unit-scoped decoration does not leak to another unit", async () => {
|
|
77
|
+
const seen: Record<string, unknown> = {};
|
|
78
|
+
|
|
79
|
+
on(
|
|
80
|
+
http.get("/orders"),
|
|
81
|
+
flow({
|
|
82
|
+
name: "orders.list",
|
|
83
|
+
unit: "orders",
|
|
84
|
+
do: () => ({}),
|
|
85
|
+
}).hook("beforeHandle", (ctx) => {
|
|
86
|
+
seen.orders = ctx.decorations.flag;
|
|
87
|
+
}),
|
|
88
|
+
);
|
|
89
|
+
on(
|
|
90
|
+
http.get("/payments"),
|
|
91
|
+
flow({
|
|
92
|
+
name: "payments.list",
|
|
93
|
+
unit: "payments",
|
|
94
|
+
do: () => ({}),
|
|
95
|
+
}).hook("beforeHandle", (ctx) => {
|
|
96
|
+
seen.payments = ctx.decorations.flag;
|
|
97
|
+
}),
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
const app = oke({ name: "deco-scope" });
|
|
101
|
+
app.unit("orders").plug(
|
|
102
|
+
plugin("flag", { version: "1.0.0" }).decorate("flag", "orders-only"),
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
await app.fetch(new Request("http://localhost/orders"));
|
|
106
|
+
await app.fetch(new Request("http://localhost/payments"));
|
|
107
|
+
|
|
108
|
+
expect(seen.orders).toBe("orders-only");
|
|
109
|
+
expect(seen.payments).toBeUndefined();
|
|
110
|
+
});
|
|
111
|
+
});
|