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,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundle entry for the kernel edge size budget (AGENTS.md / unified-theory §24).
|
|
3
|
+
*
|
|
4
|
+
* Anchors the tree-shaken edge profile — router, flow binding, fx, hooks,
|
|
5
|
+
* capability, contracts — without optional elements (runs, boot, drivers).
|
|
6
|
+
* Live bindings keep minify from dropping the runtime graph.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { compileRoute, encodeExecuteResult } from "../compiler/index.ts";
|
|
10
|
+
import { validate } from "../validation/standard-schema.ts";
|
|
11
|
+
import { createCapabilityToken } from "./capability.ts";
|
|
12
|
+
import { fail, OKE_ERRORS } from "./errors.ts";
|
|
13
|
+
import { flow } from "./flow.ts";
|
|
14
|
+
import { createFx } from "./fx.ts";
|
|
15
|
+
import { mergeHooks, runPipeline } from "./hooks.ts";
|
|
16
|
+
import { on, resetBindings } from "./on.ts";
|
|
17
|
+
import { createRouter } from "./router.ts";
|
|
18
|
+
import { http } from "./triggers.ts";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Anchor for the size check — must reference the edge-profile surface.
|
|
22
|
+
*/
|
|
23
|
+
export function __okeKernelBudgetAnchor(): {
|
|
24
|
+
createRouter: typeof createRouter;
|
|
25
|
+
flow: typeof flow;
|
|
26
|
+
on: typeof on;
|
|
27
|
+
resetBindings: typeof resetBindings;
|
|
28
|
+
http: typeof http;
|
|
29
|
+
createFx: typeof createFx;
|
|
30
|
+
fail: typeof fail;
|
|
31
|
+
OKE_ERRORS: typeof OKE_ERRORS;
|
|
32
|
+
runPipeline: typeof runPipeline;
|
|
33
|
+
mergeHooks: typeof mergeHooks;
|
|
34
|
+
createCapabilityToken: typeof createCapabilityToken;
|
|
35
|
+
compileRoute: typeof compileRoute;
|
|
36
|
+
encodeExecuteResult: typeof encodeExecuteResult;
|
|
37
|
+
validate: typeof validate;
|
|
38
|
+
} {
|
|
39
|
+
return {
|
|
40
|
+
createRouter,
|
|
41
|
+
flow,
|
|
42
|
+
on,
|
|
43
|
+
resetBindings,
|
|
44
|
+
http,
|
|
45
|
+
createFx,
|
|
46
|
+
fail,
|
|
47
|
+
OKE_ERRORS,
|
|
48
|
+
runPipeline,
|
|
49
|
+
mergeHooks,
|
|
50
|
+
createCapabilityToken,
|
|
51
|
+
compileRoute,
|
|
52
|
+
encodeExecuteResult,
|
|
53
|
+
validate,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kernel edge profile budget — AGENTS.md / unified-theory §24.
|
|
3
|
+
* Limit: < 15 kB gzipped (minified bundle).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, expect, test } from "bun:test";
|
|
7
|
+
import { KERNEL_EDGE_BUDGET_BYTES } from "../release/limits.ts";
|
|
8
|
+
import { measureKernelEdgeGzipBytes } from "../release/measure.ts";
|
|
9
|
+
|
|
10
|
+
describe("kernel edge bundle budget", () => {
|
|
11
|
+
test(`edge profile < ${KERNEL_EDGE_BUDGET_BYTES} bytes gzipped`, async () => {
|
|
12
|
+
const size = await measureKernelEdgeGzipBytes();
|
|
13
|
+
console.log(
|
|
14
|
+
`kernel edge gzip=${size} budget=${KERNEL_EDGE_BUDGET_BYTES}`,
|
|
15
|
+
);
|
|
16
|
+
expect(size).toBeGreaterThan(0);
|
|
17
|
+
expect(size).toBeLessThan(KERNEL_EDGE_BUDGET_BYTES);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { describe, expect, test, beforeEach } from "bun:test";
|
|
2
|
+
import { oke } from "./app.ts";
|
|
3
|
+
import { flow, resetFlowSeq } from "./flow.ts";
|
|
4
|
+
import { on, resetBindings } from "./on.ts";
|
|
5
|
+
import { http } from "./triggers.ts";
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
resetBindings();
|
|
9
|
+
resetFlowSeq();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
describe("fx.call — untriggered flows", () => {
|
|
13
|
+
test("untriggered flow is callable via app.call and fx.call", async () => {
|
|
14
|
+
const stats = flow({
|
|
15
|
+
name: "links.stats",
|
|
16
|
+
do: ({ code }: { code: string }) => ({ code, clicks: 7 }),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const parent = on(
|
|
20
|
+
http.post("/run"),
|
|
21
|
+
flow({
|
|
22
|
+
name: "links.run",
|
|
23
|
+
effects: { calls: ["links.stats"] },
|
|
24
|
+
do: async ({ code }: { code: string }, fx) => {
|
|
25
|
+
const result = await fx.call("links.stats", { code });
|
|
26
|
+
return result;
|
|
27
|
+
},
|
|
28
|
+
}),
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const app = oke({ name: "call" }).adopt(stats);
|
|
32
|
+
|
|
33
|
+
// Direct call (Linkly ⑤)
|
|
34
|
+
await expect(app.call(stats, { code: "sa" })).resolves.toEqual({
|
|
35
|
+
code: "sa",
|
|
36
|
+
clicks: 7,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Same path through fx.call from a triggered flow
|
|
40
|
+
const res = await app.fetch(
|
|
41
|
+
new Request("http://localhost/run", {
|
|
42
|
+
method: "POST",
|
|
43
|
+
body: JSON.stringify({ code: "sa" }),
|
|
44
|
+
headers: { "content-type": "application/json" },
|
|
45
|
+
}),
|
|
46
|
+
);
|
|
47
|
+
expect(res.status).toBe(200);
|
|
48
|
+
expect(await res.json()).toEqual({
|
|
49
|
+
data: { code: "sa", clicks: 7 },
|
|
50
|
+
error: null,
|
|
51
|
+
});
|
|
52
|
+
expect(parent.triggers).toHaveLength(1);
|
|
53
|
+
expect(stats.triggers).toHaveLength(0);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("http and signal invocations of the same flow execute identically", async () => {
|
|
57
|
+
let runs = 0;
|
|
58
|
+
const work = flow({
|
|
59
|
+
name: "work",
|
|
60
|
+
do: (input: { v: number }) => {
|
|
61
|
+
runs += 1;
|
|
62
|
+
return { out: input.v + 1 };
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
on(http.post("/work"), work);
|
|
67
|
+
on({ name: "tick", delivery: "broadcast" }, work);
|
|
68
|
+
|
|
69
|
+
const app = oke({ name: "identical" });
|
|
70
|
+
|
|
71
|
+
const a = await app.fetch(
|
|
72
|
+
new Request("http://localhost/work", {
|
|
73
|
+
method: "POST",
|
|
74
|
+
body: JSON.stringify({ v: 10 }),
|
|
75
|
+
}),
|
|
76
|
+
);
|
|
77
|
+
const b = await app.dispatchSignal("tick", { v: 10 });
|
|
78
|
+
|
|
79
|
+
expect(await a.json()).toEqual({ data: { out: 11 }, error: null });
|
|
80
|
+
expect(b[0]?.output).toEqual({ out: 11 });
|
|
81
|
+
expect(runs).toBe(2);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-flow capability tokens — least privilege by construction (§7.4).
|
|
3
|
+
*
|
|
4
|
+
* A flow receives a token covering only its declared effects. An undeclared
|
|
5
|
+
* access throws OKE1xxx with the flow name, the attempted resource, and the fix.
|
|
6
|
+
* Enforced at runtime, not merely documented.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { Effects } from "../manifest/types.ts";
|
|
10
|
+
import type { EffectKind } from "./effects.ts";
|
|
11
|
+
import { OKE_ERRORS, throwOke } from "./errors.ts";
|
|
12
|
+
|
|
13
|
+
/** Maps effect kind → the undeclared-access registry key. */
|
|
14
|
+
const UNDECLARED_KEY: Readonly<
|
|
15
|
+
Record<EffectKind, keyof typeof OKE_ERRORS>
|
|
16
|
+
> = {
|
|
17
|
+
read: "UNDECLARED_READ",
|
|
18
|
+
write: "UNDECLARED_WRITE",
|
|
19
|
+
emit: "UNDECLARED_EMIT",
|
|
20
|
+
send: "UNDECLARED_SEND",
|
|
21
|
+
ask: "UNDECLARED_ASK",
|
|
22
|
+
secret: "UNDECLARED_SECRET",
|
|
23
|
+
call: "UNDECLARED_CALL",
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/** Maps effect kind → the corresponding `Effects` field. */
|
|
27
|
+
const EFFECTS_FIELD: Readonly<
|
|
28
|
+
Record<EffectKind, keyof Effects>
|
|
29
|
+
> = {
|
|
30
|
+
read: "reads",
|
|
31
|
+
write: "writes",
|
|
32
|
+
emit: "emits",
|
|
33
|
+
send: "sends",
|
|
34
|
+
ask: "asks",
|
|
35
|
+
secret: "secrets",
|
|
36
|
+
call: "calls",
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Capability token for one flow invocation.
|
|
41
|
+
* Allows only the resources listed in the flow's declared effects.
|
|
42
|
+
*/
|
|
43
|
+
export interface CapabilityToken {
|
|
44
|
+
/** Flow id this token was issued for. */
|
|
45
|
+
readonly flow: string;
|
|
46
|
+
/** Declared effects that minted this token. */
|
|
47
|
+
readonly declared: Effects;
|
|
48
|
+
/**
|
|
49
|
+
* Assert that `kind` on `resource` is allowed.
|
|
50
|
+
* Throws {@link OkeError} (OKE1xxx) on violation.
|
|
51
|
+
*
|
|
52
|
+
* @param kind - Effect kind being attempted
|
|
53
|
+
* @param resource - Resource / signal / template / … ref
|
|
54
|
+
*/
|
|
55
|
+
assert(kind: EffectKind, resource: string): void;
|
|
56
|
+
/**
|
|
57
|
+
* Whether `kind` on `resource` is allowed (no throw).
|
|
58
|
+
*
|
|
59
|
+
* @param kind - Effect kind
|
|
60
|
+
* @param resource - Resource ref
|
|
61
|
+
*/
|
|
62
|
+
allows(kind: EffectKind, resource: string): boolean;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Mint a capability token from a flow's declared effects.
|
|
67
|
+
*
|
|
68
|
+
* When `declared` is `undefined` (compiler has not yet stamped effects),
|
|
69
|
+
* the token is open — every access is allowed and ledgered. An explicit
|
|
70
|
+
* `{}` or partial declaration is least-privilege (missing keys = deny).
|
|
71
|
+
*
|
|
72
|
+
* @param flow - Flow id (used in error messages)
|
|
73
|
+
* @param declared - Declared effect surface, or `undefined` for open
|
|
74
|
+
*/
|
|
75
|
+
export function createCapabilityToken(
|
|
76
|
+
flow: string,
|
|
77
|
+
declared?: Effects,
|
|
78
|
+
): CapabilityToken {
|
|
79
|
+
const open = declared === undefined;
|
|
80
|
+
const effects = declared ?? {};
|
|
81
|
+
const sets: Record<EffectKind, ReadonlySet<string>> = {
|
|
82
|
+
read: new Set(effects.reads ?? []),
|
|
83
|
+
write: new Set(effects.writes ?? []),
|
|
84
|
+
emit: new Set(effects.emits ?? []),
|
|
85
|
+
send: new Set(effects.sends ?? []),
|
|
86
|
+
ask: new Set(effects.asks ?? []),
|
|
87
|
+
secret: new Set(effects.secrets ?? []),
|
|
88
|
+
call: new Set(effects.calls ?? []),
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
flow,
|
|
93
|
+
declared: effects,
|
|
94
|
+
allows(kind: EffectKind, resource: string): boolean {
|
|
95
|
+
if (open) return true;
|
|
96
|
+
return sets[kind].has(resource);
|
|
97
|
+
},
|
|
98
|
+
assert(kind: EffectKind, resource: string): void {
|
|
99
|
+
if (open) return;
|
|
100
|
+
if (sets[kind].has(resource)) return;
|
|
101
|
+
throwOke(UNDECLARED_KEY[kind], { flow, resource });
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Effects-field name for a kind (e.g. `read` → `"reads"`).
|
|
108
|
+
*
|
|
109
|
+
* @param kind - Effect kind
|
|
110
|
+
*/
|
|
111
|
+
export function effectsFieldOf(kind: EffectKind): keyof Effects {
|
|
112
|
+
return EFFECTS_FIELD[kind];
|
|
113
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import type { ChannelRuntime } from "../elements/channel/runtime.ts";
|
|
3
|
+
import {
|
|
4
|
+
isDryRun,
|
|
5
|
+
withDryRun,
|
|
6
|
+
} from "./dry-run.ts";
|
|
7
|
+
import { createFx, type FxStubStoreHandle } from "./fx.ts";
|
|
8
|
+
|
|
9
|
+
describe("fx dry-run stubbing", () => {
|
|
10
|
+
test("send/ask are intercepted; writes still execute then roll back", async () => {
|
|
11
|
+
let realSends = 0;
|
|
12
|
+
let realAsks = 0;
|
|
13
|
+
const channelRuntime = {
|
|
14
|
+
async send() {
|
|
15
|
+
realSends += 1;
|
|
16
|
+
return { ok: true as const, receiptId: "r" };
|
|
17
|
+
},
|
|
18
|
+
} as unknown as ChannelRuntime;
|
|
19
|
+
const aiRuntime = {
|
|
20
|
+
async ask() {
|
|
21
|
+
realAsks += 1;
|
|
22
|
+
return { answer: "nope" };
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const stockRow = { qty: 100 };
|
|
27
|
+
const fx = createFx({
|
|
28
|
+
flow: "test.dry",
|
|
29
|
+
effects: {
|
|
30
|
+
reads: ["sql:t"],
|
|
31
|
+
writes: ["sql:t"],
|
|
32
|
+
sends: ["mail"],
|
|
33
|
+
asks: ["p@1"],
|
|
34
|
+
},
|
|
35
|
+
channelRuntime,
|
|
36
|
+
aiRuntime: aiRuntime as never,
|
|
37
|
+
storeData: { "sql:t": { sku: stockRow } },
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const stubbed = await withDryRun(async () => {
|
|
41
|
+
expect(isDryRun()).toBe(true);
|
|
42
|
+
const store = fx.store("sql:t") as FxStubStoreHandle;
|
|
43
|
+
const row = (await store.get("sku")) as { qty: number };
|
|
44
|
+
row.qty -= 1;
|
|
45
|
+
await store.set("sku", row);
|
|
46
|
+
expect(((await store.get("sku")) as { qty: number }).qty).toBe(99);
|
|
47
|
+
await fx.send("mail", { to: "a@b.c" });
|
|
48
|
+
await fx.ask("p@1", {});
|
|
49
|
+
return store.get("sku");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
expect(await stubbed.result).toEqual({ qty: 99 });
|
|
53
|
+
expect(realSends).toBe(0);
|
|
54
|
+
expect(realAsks).toBe(0);
|
|
55
|
+
expect(stubbed.wouldHaveFired).toEqual([
|
|
56
|
+
{ kind: "send", resource: "mail" },
|
|
57
|
+
{ kind: "ask", resource: "p@1" },
|
|
58
|
+
]);
|
|
59
|
+
// Rolled back — store is byte-for-byte restored.
|
|
60
|
+
const store = fx.store("sql:t") as FxStubStoreHandle;
|
|
61
|
+
expect(await store.get("sku")).toEqual({ qty: 100 });
|
|
62
|
+
expect(stockRow.qty).toBe(100);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dry-run effect stubbing + write isolation (console §9.1 · §9.3 · §9.4).
|
|
3
|
+
*
|
|
4
|
+
* - Irreversible effects (`send` / `ask`) are intercepted and recorded as
|
|
5
|
+
* "would have fired" — never contact a real channel or model.
|
|
6
|
+
* - Store writes run against real data for an honest pass/fail verdict, then
|
|
7
|
+
* are always rolled back (snapshot / restore) when the dry-run scope exits.
|
|
8
|
+
* - Drivers that cannot isolate writes throw {@link DryRunWriteIsolationError};
|
|
9
|
+
* the operator plane refuses rather than silently risk a double-write.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
13
|
+
|
|
14
|
+
/** One intercepted irreversible effect during a dry run. */
|
|
15
|
+
export interface DryRunWouldHaveFired {
|
|
16
|
+
/** Irreversible kind. */
|
|
17
|
+
readonly kind: "send" | "ask";
|
|
18
|
+
/** Template / prompt name. */
|
|
19
|
+
readonly resource: string;
|
|
20
|
+
/** Optional correlating message id (signal dry-run). */
|
|
21
|
+
readonly messageId?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Active dry-run bag. */
|
|
25
|
+
export interface DryRunContext {
|
|
26
|
+
/** Intercepted send/ask calls in order. */
|
|
27
|
+
readonly wouldHaveFired: DryRunWouldHaveFired[];
|
|
28
|
+
/** Optional message id stamped onto subsequent intercepts. */
|
|
29
|
+
messageId?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Deep-cloned table snapshots taken before the first touch of each stub store.
|
|
32
|
+
* Restored in `finally` so dry-run writes never persist.
|
|
33
|
+
*/
|
|
34
|
+
readonly storeSnapshots: Map<string, Map<string, unknown>>;
|
|
35
|
+
/** Live stub-store Maps to restore from {@link storeSnapshots}. */
|
|
36
|
+
readonly storeRefs: Map<string, Map<string, unknown>>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Thrown when a dry-run write cannot be transactionally isolated.
|
|
41
|
+
*
|
|
42
|
+
* The Console / signal bus must refuse the dry-run for that signal rather
|
|
43
|
+
* than risk a committed double-write.
|
|
44
|
+
*/
|
|
45
|
+
export class DryRunWriteIsolationError extends Error {
|
|
46
|
+
/** Stable machine code. */
|
|
47
|
+
readonly code = "dry_run_write_isolation" as const;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @param reason - Human-readable refusal reason
|
|
51
|
+
*/
|
|
52
|
+
constructor(reason: string) {
|
|
53
|
+
super(reason);
|
|
54
|
+
this.name = "DryRunWriteIsolationError";
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const storage = new AsyncLocalStorage<DryRunContext>();
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Whether the current async chain is inside a dry-run scope.
|
|
62
|
+
*/
|
|
63
|
+
export function isDryRun(): boolean {
|
|
64
|
+
return storage.getStore() !== undefined;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Active dry-run context, or `undefined` outside a dry-run.
|
|
69
|
+
*/
|
|
70
|
+
export function getDryRunContext(): DryRunContext | undefined {
|
|
71
|
+
return storage.getStore();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Snapshot of intercepted irreversible effects for the current dry-run.
|
|
76
|
+
*/
|
|
77
|
+
export function dryRunWouldHaveFired(): readonly DryRunWouldHaveFired[] {
|
|
78
|
+
return storage.getStore()?.wouldHaveFired ?? [];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Stamp the active dry-run with a signal message id (for correlating stubs).
|
|
83
|
+
*
|
|
84
|
+
* @param messageId - Dead-letter / message id
|
|
85
|
+
*/
|
|
86
|
+
export function setDryRunMessageId(messageId: string): void {
|
|
87
|
+
const ctx = storage.getStore();
|
|
88
|
+
if (ctx) ctx.messageId = messageId;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Record that a send/ask would have fired. No-op outside dry-run.
|
|
93
|
+
*
|
|
94
|
+
* @param kind - Irreversible kind
|
|
95
|
+
* @param resource - Template / prompt name
|
|
96
|
+
*/
|
|
97
|
+
export function recordWouldHaveFired(
|
|
98
|
+
kind: "send" | "ask",
|
|
99
|
+
resource: string,
|
|
100
|
+
): void {
|
|
101
|
+
const ctx = storage.getStore();
|
|
102
|
+
if (!ctx) return;
|
|
103
|
+
ctx.wouldHaveFired.push({
|
|
104
|
+
kind,
|
|
105
|
+
resource,
|
|
106
|
+
...(ctx.messageId !== undefined ? { messageId: ctx.messageId } : {}),
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Ensure a stub store table is snapshotted before dry-run mutation.
|
|
112
|
+
*
|
|
113
|
+
* First touch deep-clones the table; {@link withDryRun} restores it in `finally`.
|
|
114
|
+
*
|
|
115
|
+
* @param ref - Store resource ref (`sql:inventory`, …)
|
|
116
|
+
* @param table - Live in-memory table Map
|
|
117
|
+
*/
|
|
118
|
+
export function touchDryRunStore(
|
|
119
|
+
ref: string,
|
|
120
|
+
table: Map<string, unknown>,
|
|
121
|
+
): void {
|
|
122
|
+
const ctx = storage.getStore();
|
|
123
|
+
if (!ctx) return;
|
|
124
|
+
if (ctx.storeSnapshots.has(ref)) return;
|
|
125
|
+
ctx.storeRefs.set(ref, table);
|
|
126
|
+
ctx.storeSnapshots.set(
|
|
127
|
+
ref,
|
|
128
|
+
new Map(
|
|
129
|
+
[...table.entries()].map(([k, v]) => [k, structuredClone(v)]),
|
|
130
|
+
),
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Roll back every stub store touched during this dry-run scope.
|
|
136
|
+
*
|
|
137
|
+
* @param ctx - Dry-run bag
|
|
138
|
+
*/
|
|
139
|
+
function rollbackStores(ctx: DryRunContext): void {
|
|
140
|
+
for (const [ref, live] of ctx.storeRefs) {
|
|
141
|
+
const snap = ctx.storeSnapshots.get(ref);
|
|
142
|
+
if (!snap) continue;
|
|
143
|
+
live.clear();
|
|
144
|
+
for (const [k, v] of snap) {
|
|
145
|
+
live.set(k, structuredClone(v));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Run `fn` with irreversible effects stubbed and stub-store writes rolled back.
|
|
152
|
+
*
|
|
153
|
+
* @param fn - Work that may call `fx.send` / `fx.ask` / `fx.store`
|
|
154
|
+
*/
|
|
155
|
+
export async function withDryRun<T>(fn: () => T | Promise<T>): Promise<{
|
|
156
|
+
readonly result: T;
|
|
157
|
+
readonly wouldHaveFired: readonly DryRunWouldHaveFired[];
|
|
158
|
+
}> {
|
|
159
|
+
const ctx: DryRunContext = {
|
|
160
|
+
wouldHaveFired: [],
|
|
161
|
+
storeSnapshots: new Map(),
|
|
162
|
+
storeRefs: new Map(),
|
|
163
|
+
};
|
|
164
|
+
try {
|
|
165
|
+
const result = await storage.run(ctx, fn);
|
|
166
|
+
return { result, wouldHaveFired: ctx.wouldHaveFired };
|
|
167
|
+
} finally {
|
|
168
|
+
// Always roll back — success or failure. Pass/fail was observed before this.
|
|
169
|
+
rollbackStores(ctx);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import {
|
|
3
|
+
createEffectLedger,
|
|
4
|
+
EFFECT_KIND_TIERS,
|
|
5
|
+
recordEffect,
|
|
6
|
+
reversibilityOf,
|
|
7
|
+
type EffectKind,
|
|
8
|
+
type ReversibilityTier,
|
|
9
|
+
} from "./effects.ts";
|
|
10
|
+
|
|
11
|
+
describe("effects — reversibility tiers", () => {
|
|
12
|
+
test("all seven effect kinds have the correct reversibility tier", () => {
|
|
13
|
+
const expected: Record<EffectKind, ReversibilityTier> = {
|
|
14
|
+
read: "none",
|
|
15
|
+
write: "reversible",
|
|
16
|
+
emit: "deferred",
|
|
17
|
+
send: "irreversible",
|
|
18
|
+
ask: "irreversible",
|
|
19
|
+
secret: "capability",
|
|
20
|
+
call: "portal",
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
expect(EFFECT_KIND_TIERS).toHaveLength(7);
|
|
24
|
+
for (const { kind, reversibility } of EFFECT_KIND_TIERS) {
|
|
25
|
+
expect(reversibility).toBe(expected[kind]);
|
|
26
|
+
expect(reversibilityOf(kind)).toBe(expected[kind]);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe("effects — ledger", () => {
|
|
32
|
+
test("records kind, resource, timestamp, duration, reversibility in order", async () => {
|
|
33
|
+
const ledger = createEffectLedger();
|
|
34
|
+
let t = 1_000;
|
|
35
|
+
const now = () => t;
|
|
36
|
+
|
|
37
|
+
await recordEffect(ledger, "read", "sql:bookings", now, () => {
|
|
38
|
+
t += 5;
|
|
39
|
+
return "ok";
|
|
40
|
+
});
|
|
41
|
+
await recordEffect(ledger, "write", "sql:bookings", now, async () => {
|
|
42
|
+
t += 10;
|
|
43
|
+
});
|
|
44
|
+
await recordEffect(ledger, "emit", "order-placed", now, async () => {
|
|
45
|
+
t += 1;
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
expect(ledger.entries).toHaveLength(3);
|
|
49
|
+
expect(ledger.entries.map((e) => e.kind)).toEqual([
|
|
50
|
+
"read",
|
|
51
|
+
"write",
|
|
52
|
+
"emit",
|
|
53
|
+
]);
|
|
54
|
+
expect(ledger.entries[0]).toMatchObject({
|
|
55
|
+
kind: "read",
|
|
56
|
+
resource: "sql:bookings",
|
|
57
|
+
timestamp: 1_000,
|
|
58
|
+
duration: 5,
|
|
59
|
+
reversibility: "none",
|
|
60
|
+
});
|
|
61
|
+
expect(ledger.entries[1]).toMatchObject({
|
|
62
|
+
kind: "write",
|
|
63
|
+
resource: "sql:bookings",
|
|
64
|
+
timestamp: 1_005,
|
|
65
|
+
duration: 10,
|
|
66
|
+
reversibility: "reversible",
|
|
67
|
+
});
|
|
68
|
+
expect(ledger.entries[2]).toMatchObject({
|
|
69
|
+
kind: "emit",
|
|
70
|
+
resource: "order-placed",
|
|
71
|
+
timestamp: 1_015,
|
|
72
|
+
duration: 1,
|
|
73
|
+
reversibility: "deferred",
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("clear empties the ledger", () => {
|
|
78
|
+
const ledger = createEffectLedger();
|
|
79
|
+
ledger.record({
|
|
80
|
+
kind: "read",
|
|
81
|
+
resource: "sql:x",
|
|
82
|
+
timestamp: 0,
|
|
83
|
+
duration: 0,
|
|
84
|
+
reversibility: "none",
|
|
85
|
+
});
|
|
86
|
+
ledger.clear();
|
|
87
|
+
expect(ledger.entries).toEqual([]);
|
|
88
|
+
});
|
|
89
|
+
});
|