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,418 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hybrid sessions — short JWT access + revocable refresh.
|
|
3
|
+
*
|
|
4
|
+
* Refresh tokens rotate on every use. Presenting a previously-used refresh
|
|
5
|
+
* token is reuse detection: the entire token family is revoked.
|
|
6
|
+
*
|
|
7
|
+
* @see docs/spec/unified-theory.md §13 · console.md §9.14
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { AuthPlane } from "./planes.ts";
|
|
11
|
+
import type { RefreshTokenRow, SessionRow } from "./tables.ts";
|
|
12
|
+
|
|
13
|
+
/** Default access-token TTL (14 minutes — residual validity after revoke). */
|
|
14
|
+
export const ACCESS_TTL_MS = 14 * 60 * 1000;
|
|
15
|
+
|
|
16
|
+
/** Default refresh-token TTL (30 days). */
|
|
17
|
+
export const REFRESH_TTL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
18
|
+
|
|
19
|
+
/** Session store. */
|
|
20
|
+
export interface SessionStore {
|
|
21
|
+
sessions: Map<string, SessionRow>;
|
|
22
|
+
refresh: Map<string, RefreshTokenRow>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Issued session bundle. */
|
|
26
|
+
export interface IssuedSession {
|
|
27
|
+
readonly session: SessionRow;
|
|
28
|
+
readonly accessToken: string;
|
|
29
|
+
readonly refreshToken: string;
|
|
30
|
+
readonly accessExpiresAt: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Access-token claims (unsigned JSON for the builtin path; HMAC below). */
|
|
34
|
+
export interface AccessClaims {
|
|
35
|
+
readonly sub: string;
|
|
36
|
+
readonly plane: AuthPlane;
|
|
37
|
+
readonly sid: string;
|
|
38
|
+
readonly scopes: string[];
|
|
39
|
+
readonly iat: number;
|
|
40
|
+
readonly exp: number;
|
|
41
|
+
/**
|
|
42
|
+
* Intended audience (`oke-console` · `oke-mcp` · `oke-app`).
|
|
43
|
+
* Validated when the verifier supplies {@link VerifyAccessOptions.audience}.
|
|
44
|
+
*/
|
|
45
|
+
readonly aud?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Options for {@link createSessionStore}. */
|
|
49
|
+
export interface SessionCrypto {
|
|
50
|
+
/** HMAC secret for access tokens. */
|
|
51
|
+
readonly secret: string;
|
|
52
|
+
readonly now?: () => number;
|
|
53
|
+
readonly accessTtlMs?: number;
|
|
54
|
+
readonly refreshTtlMs?: number;
|
|
55
|
+
/**
|
|
56
|
+
* Audience stamped on issued access tokens.
|
|
57
|
+
* MCP tokens must use `"oke-mcp"` (console §10.3 — never accept another aud).
|
|
58
|
+
*/
|
|
59
|
+
readonly audience?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Options for {@link verifyAccess}. */
|
|
63
|
+
export interface VerifyAccessOptions {
|
|
64
|
+
/** Clock (defaults to `Date.now`). */
|
|
65
|
+
readonly now?: () => number;
|
|
66
|
+
/**
|
|
67
|
+
* When set, the token's `aud` must match exactly.
|
|
68
|
+
* Tokens minted for another audience (or missing `aud`) are rejected.
|
|
69
|
+
*/
|
|
70
|
+
readonly audience?: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Create an empty session store.
|
|
75
|
+
*/
|
|
76
|
+
export function createSessionStore(): SessionStore {
|
|
77
|
+
return { sessions: new Map(), refresh: new Map() };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Issue a hybrid session for a principal.
|
|
82
|
+
*
|
|
83
|
+
* @param store - Session store
|
|
84
|
+
* @param crypto - Signing + TTLs
|
|
85
|
+
* @param principal - Subject
|
|
86
|
+
*/
|
|
87
|
+
export async function issueSession(
|
|
88
|
+
store: SessionStore,
|
|
89
|
+
crypto: SessionCrypto,
|
|
90
|
+
principal: {
|
|
91
|
+
readonly id: string;
|
|
92
|
+
readonly plane: AuthPlane;
|
|
93
|
+
readonly scopes: Iterable<string>;
|
|
94
|
+
},
|
|
95
|
+
): Promise<IssuedSession> {
|
|
96
|
+
const now = crypto.now ?? (() => Date.now());
|
|
97
|
+
const t = now();
|
|
98
|
+
const accessTtl = crypto.accessTtlMs ?? ACCESS_TTL_MS;
|
|
99
|
+
const refreshTtl = crypto.refreshTtlMs ?? REFRESH_TTL_MS;
|
|
100
|
+
const sessionId = cryptoRandomId();
|
|
101
|
+
const familyId = cryptoRandomId();
|
|
102
|
+
|
|
103
|
+
const session: SessionRow = {
|
|
104
|
+
id: sessionId,
|
|
105
|
+
plane: principal.plane,
|
|
106
|
+
principalId: principal.id,
|
|
107
|
+
familyId,
|
|
108
|
+
revokedAt: null,
|
|
109
|
+
createdAt: t,
|
|
110
|
+
expiresAt: t + refreshTtl,
|
|
111
|
+
};
|
|
112
|
+
store.sessions.set(sessionId, session);
|
|
113
|
+
if (crypto.audience !== undefined) {
|
|
114
|
+
sessionAudiences.set(sessionId, crypto.audience);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const refreshRaw = `rt_${cryptoRandomId()}`;
|
|
118
|
+
const refreshRow: RefreshTokenRow = {
|
|
119
|
+
id: cryptoRandomId(),
|
|
120
|
+
sessionId,
|
|
121
|
+
familyId,
|
|
122
|
+
hash: await hashToken(refreshRaw),
|
|
123
|
+
expiresAt: t + refreshTtl,
|
|
124
|
+
usedAt: null,
|
|
125
|
+
revokedAt: null,
|
|
126
|
+
};
|
|
127
|
+
store.refresh.set(refreshRow.id, refreshRow);
|
|
128
|
+
|
|
129
|
+
const accessExpiresAt = t + accessTtl;
|
|
130
|
+
const accessToken = await signAccess(crypto.secret, {
|
|
131
|
+
sub: principal.id,
|
|
132
|
+
plane: principal.plane,
|
|
133
|
+
sid: sessionId,
|
|
134
|
+
scopes: [...principal.scopes],
|
|
135
|
+
iat: t,
|
|
136
|
+
exp: accessExpiresAt,
|
|
137
|
+
...(crypto.audience !== undefined ? { aud: crypto.audience } : {}),
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
return { session, accessToken, refreshToken: refreshRaw, accessExpiresAt };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Rotate a refresh token. Reuse of an already-used token revokes the family.
|
|
145
|
+
*
|
|
146
|
+
* @param store - Session store
|
|
147
|
+
* @param crypto - Signing + TTLs
|
|
148
|
+
* @param refreshToken - Raw refresh token
|
|
149
|
+
*/
|
|
150
|
+
export async function rotateRefresh(
|
|
151
|
+
store: SessionStore,
|
|
152
|
+
crypto: SessionCrypto,
|
|
153
|
+
refreshToken: string,
|
|
154
|
+
): Promise<IssuedSession> {
|
|
155
|
+
const now = crypto.now ?? (() => Date.now());
|
|
156
|
+
const t = now();
|
|
157
|
+
const hash = await hashToken(refreshToken);
|
|
158
|
+
const existing = [...store.refresh.values()].find((r) => r.hash === hash);
|
|
159
|
+
|
|
160
|
+
if (!existing) {
|
|
161
|
+
throw new SessionError("unknown refresh token");
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Reuse detection: token already consumed → revoke family.
|
|
165
|
+
if (existing.usedAt !== null || existing.revokedAt !== null) {
|
|
166
|
+
revokeFamily(store, existing.familyId, t);
|
|
167
|
+
throw new SessionError("refresh token reuse detected; family revoked");
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const session = store.sessions.get(existing.sessionId);
|
|
171
|
+
if (!session || session.revokedAt !== null) {
|
|
172
|
+
throw new SessionError("session revoked");
|
|
173
|
+
}
|
|
174
|
+
if (existing.expiresAt <= t || session.expiresAt <= t) {
|
|
175
|
+
throw new SessionError("refresh token expired");
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
existing.usedAt = t;
|
|
179
|
+
existing.revokedAt = t;
|
|
180
|
+
|
|
181
|
+
const accessTtl = crypto.accessTtlMs ?? ACCESS_TTL_MS;
|
|
182
|
+
const refreshTtl = crypto.refreshTtlMs ?? REFRESH_TTL_MS;
|
|
183
|
+
|
|
184
|
+
const newRefreshRaw = `rt_${cryptoRandomId()}`;
|
|
185
|
+
const newRefresh: RefreshTokenRow = {
|
|
186
|
+
id: cryptoRandomId(),
|
|
187
|
+
sessionId: session.id,
|
|
188
|
+
familyId: existing.familyId,
|
|
189
|
+
hash: await hashToken(newRefreshRaw),
|
|
190
|
+
expiresAt: t + refreshTtl,
|
|
191
|
+
usedAt: null,
|
|
192
|
+
revokedAt: null,
|
|
193
|
+
};
|
|
194
|
+
store.refresh.set(newRefresh.id, newRefresh);
|
|
195
|
+
|
|
196
|
+
// Recover scopes from the previous access path — stored on session via
|
|
197
|
+
// a side map would be ideal; for builtin we re-sign with empty and let
|
|
198
|
+
// callers pass scopes through verify. We keep scopes on a claim cache:
|
|
199
|
+
const priorScopes = sessionScopes.get(session.id) ?? [];
|
|
200
|
+
const priorAud = sessionAudiences.get(session.id);
|
|
201
|
+
const accessExpiresAt = t + accessTtl;
|
|
202
|
+
const accessToken = await signAccess(crypto.secret, {
|
|
203
|
+
sub: session.principalId,
|
|
204
|
+
plane: session.plane,
|
|
205
|
+
sid: session.id,
|
|
206
|
+
scopes: priorScopes,
|
|
207
|
+
iat: t,
|
|
208
|
+
exp: accessExpiresAt,
|
|
209
|
+
...(priorAud !== undefined ? { aud: priorAud } : {}),
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
session,
|
|
214
|
+
accessToken,
|
|
215
|
+
refreshToken: newRefreshRaw,
|
|
216
|
+
accessExpiresAt,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** Session id → scopes (access-token material). */
|
|
221
|
+
const sessionScopes = new Map<string, string[]>();
|
|
222
|
+
|
|
223
|
+
/** Session id → audience stamped at issue time. */
|
|
224
|
+
const sessionAudiences = new Map<string, string>();
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Remember scopes for refresh rotation (call after {@link issueSession}).
|
|
228
|
+
*
|
|
229
|
+
* @param sessionId - Session id
|
|
230
|
+
* @param scopes - Scopes
|
|
231
|
+
*/
|
|
232
|
+
export function bindSessionScopes(
|
|
233
|
+
sessionId: string,
|
|
234
|
+
scopes: Iterable<string>,
|
|
235
|
+
): void {
|
|
236
|
+
sessionScopes.set(sessionId, [...scopes]);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Remember audience for refresh rotation (call after {@link issueSession}).
|
|
241
|
+
*
|
|
242
|
+
* @param sessionId - Session id
|
|
243
|
+
* @param audience - Audience claim
|
|
244
|
+
*/
|
|
245
|
+
export function bindSessionAudience(
|
|
246
|
+
sessionId: string,
|
|
247
|
+
audience: string,
|
|
248
|
+
): void {
|
|
249
|
+
sessionAudiences.set(sessionId, audience);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Issue a session and bind scopes for later rotation.
|
|
254
|
+
*
|
|
255
|
+
* @param store - Session store
|
|
256
|
+
* @param crypto - Crypto
|
|
257
|
+
* @param principal - Subject + scopes
|
|
258
|
+
*/
|
|
259
|
+
export async function issueSessionWithScopes(
|
|
260
|
+
store: SessionStore,
|
|
261
|
+
crypto: SessionCrypto,
|
|
262
|
+
principal: {
|
|
263
|
+
readonly id: string;
|
|
264
|
+
readonly plane: AuthPlane;
|
|
265
|
+
readonly scopes: Iterable<string>;
|
|
266
|
+
},
|
|
267
|
+
): Promise<IssuedSession> {
|
|
268
|
+
const issued = await issueSession(store, crypto, principal);
|
|
269
|
+
bindSessionScopes(issued.session.id, principal.scopes);
|
|
270
|
+
if (crypto.audience !== undefined) {
|
|
271
|
+
bindSessionAudience(issued.session.id, crypto.audience);
|
|
272
|
+
}
|
|
273
|
+
return issued;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Verify an access token; rejects revoked sessions and wrong audiences.
|
|
278
|
+
*
|
|
279
|
+
* The third argument may be a clock function (legacy) or
|
|
280
|
+
* {@link VerifyAccessOptions}. Prefer the options form when validating
|
|
281
|
+
* audience (console §10.3 — never accept a token minted for another surface).
|
|
282
|
+
*
|
|
283
|
+
* @param store - Session store
|
|
284
|
+
* @param secret - HMAC secret
|
|
285
|
+
* @param token - Access token
|
|
286
|
+
* @param nowOrOptions - Clock, or options including expected audience
|
|
287
|
+
*/
|
|
288
|
+
export async function verifyAccess(
|
|
289
|
+
store: SessionStore,
|
|
290
|
+
secret: string,
|
|
291
|
+
token: string,
|
|
292
|
+
nowOrOptions: (() => number) | VerifyAccessOptions = () => Date.now(),
|
|
293
|
+
): Promise<AccessClaims> {
|
|
294
|
+
const options: VerifyAccessOptions =
|
|
295
|
+
typeof nowOrOptions === "function"
|
|
296
|
+
? { now: nowOrOptions }
|
|
297
|
+
: nowOrOptions;
|
|
298
|
+
const now = options.now ?? (() => Date.now());
|
|
299
|
+
const claims = await verifyAccessSignature(secret, token);
|
|
300
|
+
if (claims.exp <= now()) {
|
|
301
|
+
throw new SessionError("access token expired");
|
|
302
|
+
}
|
|
303
|
+
if (options.audience !== undefined) {
|
|
304
|
+
if (claims.aud !== options.audience) {
|
|
305
|
+
throw new SessionError(
|
|
306
|
+
`access token audience mismatch: expected ${options.audience}`,
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
const session = store.sessions.get(claims.sid);
|
|
311
|
+
if (!session || session.revokedAt !== null) {
|
|
312
|
+
throw new SessionError("session revoked");
|
|
313
|
+
}
|
|
314
|
+
// Per-request: session must still belong to the token subject.
|
|
315
|
+
if (session.principalId !== claims.sub) {
|
|
316
|
+
throw new SessionError("session does not belong to requester");
|
|
317
|
+
}
|
|
318
|
+
return claims;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Revoke an entire refresh-token family (reuse detection / logout).
|
|
323
|
+
*
|
|
324
|
+
* @param store - Session store
|
|
325
|
+
* @param familyId - Family id
|
|
326
|
+
* @param at - Timestamp
|
|
327
|
+
*/
|
|
328
|
+
export function revokeFamily(
|
|
329
|
+
store: SessionStore,
|
|
330
|
+
familyId: string,
|
|
331
|
+
at: number = Date.now(),
|
|
332
|
+
): void {
|
|
333
|
+
for (const session of store.sessions.values()) {
|
|
334
|
+
if (session.familyId === familyId) session.revokedAt = at;
|
|
335
|
+
}
|
|
336
|
+
for (const token of store.refresh.values()) {
|
|
337
|
+
if (token.familyId === familyId) token.revokedAt = at;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/** Session / token error. */
|
|
342
|
+
export class SessionError extends Error {
|
|
343
|
+
/** @param message - Diagnostic */
|
|
344
|
+
constructor(message: string) {
|
|
345
|
+
super(message);
|
|
346
|
+
this.name = "SessionError";
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
async function hashToken(raw: string): Promise<string> {
|
|
351
|
+
const digest = await crypto.subtle.digest(
|
|
352
|
+
"SHA-256",
|
|
353
|
+
new TextEncoder().encode(raw),
|
|
354
|
+
);
|
|
355
|
+
return [...new Uint8Array(digest)]
|
|
356
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
357
|
+
.join("");
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function cryptoRandomId(): string {
|
|
361
|
+
return crypto.randomUUID().replace(/-/g, "");
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
async function signAccess(
|
|
365
|
+
secret: string,
|
|
366
|
+
claims: AccessClaims,
|
|
367
|
+
): Promise<string> {
|
|
368
|
+
const header = b64url(JSON.stringify({ alg: "HS256", typ: "JWT" }));
|
|
369
|
+
const payload = b64url(JSON.stringify(claims));
|
|
370
|
+
const data = `${header}.${payload}`;
|
|
371
|
+
const sig = await hmac(secret, data);
|
|
372
|
+
return `${data}.${sig}`;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
async function verifyAccessSignature(
|
|
376
|
+
secret: string,
|
|
377
|
+
token: string,
|
|
378
|
+
): Promise<AccessClaims> {
|
|
379
|
+
const parts = token.split(".");
|
|
380
|
+
if (parts.length !== 3) throw new SessionError("malformed access token");
|
|
381
|
+
const [header, payload, sig] = parts as [string, string, string];
|
|
382
|
+
const data = `${header}.${payload}`;
|
|
383
|
+
const expected = await hmac(secret, data);
|
|
384
|
+
if (sig !== expected) throw new SessionError("invalid access token signature");
|
|
385
|
+
return JSON.parse(b64urlDecode(payload)) as AccessClaims;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
async function hmac(secret: string, data: string): Promise<string> {
|
|
389
|
+
const key = await crypto.subtle.importKey(
|
|
390
|
+
"raw",
|
|
391
|
+
new TextEncoder().encode(secret),
|
|
392
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
393
|
+
false,
|
|
394
|
+
["sign"],
|
|
395
|
+
);
|
|
396
|
+
const sig = await crypto.subtle.sign(
|
|
397
|
+
"HMAC",
|
|
398
|
+
key,
|
|
399
|
+
new TextEncoder().encode(data),
|
|
400
|
+
);
|
|
401
|
+
return b64urlBytes(new Uint8Array(sig));
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
function b64url(s: string): string {
|
|
405
|
+
return b64urlBytes(new TextEncoder().encode(s));
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function b64urlBytes(bytes: Uint8Array): string {
|
|
409
|
+
let bin = "";
|
|
410
|
+
for (const b of bytes) bin += String.fromCharCode(b);
|
|
411
|
+
return btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function b64urlDecode(s: string): string {
|
|
415
|
+
const padded = s.replace(/-/g, "+").replace(/_/g, "/");
|
|
416
|
+
const pad = padded.length % 4 === 0 ? "" : "=".repeat(4 - (padded.length % 4));
|
|
417
|
+
return atob(padded + pad);
|
|
418
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth Store tables — `oke_` prefix, planes never joined.
|
|
3
|
+
*
|
|
4
|
+
* @see docs/spec/console.md §8
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** Auth / Console table names. */
|
|
8
|
+
export const AUTH_TABLES = {
|
|
9
|
+
// Operator plane — never joined to the user plane
|
|
10
|
+
operators: "oke_operators",
|
|
11
|
+
operatorCredentials: "oke_operator_credentials",
|
|
12
|
+
operatorSsoLinks: "oke_operator_sso_links",
|
|
13
|
+
operatorRoles: "oke_operator_roles",
|
|
14
|
+
operatorInvites: "oke_operator_invites",
|
|
15
|
+
// User plane
|
|
16
|
+
identities: "oke_identities",
|
|
17
|
+
credentials: "oke_credentials",
|
|
18
|
+
identityRoles: "oke_identity_roles",
|
|
19
|
+
// Shared grammar, separate grants
|
|
20
|
+
roles: "oke_roles",
|
|
21
|
+
roleGrants: "oke_role_grants",
|
|
22
|
+
apiKeys: "oke_api_keys",
|
|
23
|
+
// Session tables (auth element owns these)
|
|
24
|
+
sessions: "oke_sessions",
|
|
25
|
+
refreshTokens: "oke_refresh_tokens",
|
|
26
|
+
} as const;
|
|
27
|
+
|
|
28
|
+
/** Plane column values stored on shared tables. */
|
|
29
|
+
export type TablePlane = "user" | "operator";
|
|
30
|
+
|
|
31
|
+
/** Row shapes (in-memory / descriptor — not ORM-bound). */
|
|
32
|
+
export interface OperatorRow {
|
|
33
|
+
id: string;
|
|
34
|
+
email: string;
|
|
35
|
+
name: string;
|
|
36
|
+
status: "active" | "suspended" | "invited";
|
|
37
|
+
mfaEnabled: boolean;
|
|
38
|
+
invitedBy: string | null;
|
|
39
|
+
lastSeenAt: number | null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Local password hash — always present for operators, never removable. */
|
|
43
|
+
export interface OperatorCredentialRow {
|
|
44
|
+
operatorId: string;
|
|
45
|
+
passwordHash: string;
|
|
46
|
+
/** Local login may be disabled after SSO-primary, but the row remains. */
|
|
47
|
+
loginEnabled: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Optional linked SSO identity (additional method only). */
|
|
51
|
+
export interface OperatorSsoLinkRow {
|
|
52
|
+
operatorId: string;
|
|
53
|
+
provider: string;
|
|
54
|
+
subject: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** User-plane identity. */
|
|
58
|
+
export interface IdentityRow {
|
|
59
|
+
id: string;
|
|
60
|
+
provider: string;
|
|
61
|
+
subject: string;
|
|
62
|
+
email: string;
|
|
63
|
+
name: string;
|
|
64
|
+
status: "active" | "suspended";
|
|
65
|
+
lastSeenAt: number | null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Role (data, not code). */
|
|
69
|
+
export interface RoleRow {
|
|
70
|
+
id: string;
|
|
71
|
+
name: string;
|
|
72
|
+
plane: TablePlane;
|
|
73
|
+
description: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Role → Module:Action grant. */
|
|
77
|
+
export interface RoleGrantRow {
|
|
78
|
+
roleId: string;
|
|
79
|
+
action: string;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** API key principal. */
|
|
83
|
+
export interface ApiKeyRow {
|
|
84
|
+
id: string;
|
|
85
|
+
plane: TablePlane;
|
|
86
|
+
hash: string;
|
|
87
|
+
name: string;
|
|
88
|
+
scopes: string[];
|
|
89
|
+
expiresAt: number | null;
|
|
90
|
+
rateLimit: { max: number; per: string } | null;
|
|
91
|
+
ipAllowlist: string[];
|
|
92
|
+
creatorId: string;
|
|
93
|
+
creatorScopes: string[];
|
|
94
|
+
/** Epoch-ms when the key was created (hygiene: unused 90d+). */
|
|
95
|
+
createdAt: number;
|
|
96
|
+
lastUsedAt: number | null;
|
|
97
|
+
/** Epoch-ms when revoked; `null` while active. */
|
|
98
|
+
revokedAt: number | null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Pending operator invitation (invite-only plane). */
|
|
102
|
+
export interface OperatorInviteRow {
|
|
103
|
+
id: string;
|
|
104
|
+
email: string;
|
|
105
|
+
invitedBy: string;
|
|
106
|
+
createdAt: number;
|
|
107
|
+
expiresAt: number;
|
|
108
|
+
acceptedAt: number | null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Hybrid session (short JWT + revocable refresh). */
|
|
112
|
+
export interface SessionRow {
|
|
113
|
+
id: string;
|
|
114
|
+
plane: TablePlane;
|
|
115
|
+
principalId: string;
|
|
116
|
+
familyId: string;
|
|
117
|
+
revokedAt: number | null;
|
|
118
|
+
createdAt: number;
|
|
119
|
+
expiresAt: number;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Refresh token (hashed at rest); rotation with reuse detection. */
|
|
123
|
+
export interface RefreshTokenRow {
|
|
124
|
+
id: string;
|
|
125
|
+
sessionId: string;
|
|
126
|
+
familyId: string;
|
|
127
|
+
hash: string;
|
|
128
|
+
expiresAt: number;
|
|
129
|
+
usedAt: number | null;
|
|
130
|
+
revokedAt: number | null;
|
|
131
|
+
}
|
package/src/cli/args.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiny argv helpers shared by `oke` subcommands.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* True when `--json` / `-j` is present.
|
|
7
|
+
*
|
|
8
|
+
* @param args - Argv slice
|
|
9
|
+
*/
|
|
10
|
+
export function wantsJson(args: readonly string[]): boolean {
|
|
11
|
+
return args.includes("--json") || args.includes("-j");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Read a flag value for long and optional short forms.
|
|
16
|
+
*
|
|
17
|
+
* @param args - Argv slice
|
|
18
|
+
* @param long - Long flag (e.g. `--config`)
|
|
19
|
+
* @param short - Optional short flag (e.g. `-c`)
|
|
20
|
+
*/
|
|
21
|
+
export function flagValue(
|
|
22
|
+
args: readonly string[],
|
|
23
|
+
long: string,
|
|
24
|
+
short?: string,
|
|
25
|
+
): string | undefined {
|
|
26
|
+
for (let i = 0; i < args.length; i++) {
|
|
27
|
+
const a = args[i]!;
|
|
28
|
+
if (a === long || (short !== undefined && a === short)) {
|
|
29
|
+
return args[i + 1];
|
|
30
|
+
}
|
|
31
|
+
if (a.startsWith(`${long}=`)) return a.slice(long.length + 1);
|
|
32
|
+
if (short && a.startsWith(`${short}=`)) return a.slice(short.length + 1);
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* True when a boolean flag (long or short) is present.
|
|
39
|
+
*
|
|
40
|
+
* @param args - Argv slice
|
|
41
|
+
* @param long - Long flag
|
|
42
|
+
* @param short - Optional short flag
|
|
43
|
+
*/
|
|
44
|
+
export function hasFlag(
|
|
45
|
+
args: readonly string[],
|
|
46
|
+
long: string,
|
|
47
|
+
short?: string,
|
|
48
|
+
): boolean {
|
|
49
|
+
return args.includes(long) || (short !== undefined && args.includes(short));
|
|
50
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `oke branch <name> --at <when>` — fork journaled state into a sandbox.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/** Options for {@link runBranch}. */
|
|
6
|
+
export interface BranchOptions {
|
|
7
|
+
readonly name: string;
|
|
8
|
+
readonly at?: string;
|
|
9
|
+
readonly cwd?: string;
|
|
10
|
+
readonly write?: (text: string) => void;
|
|
11
|
+
/**
|
|
12
|
+
* Fork hook (tests / wired journal).
|
|
13
|
+
*
|
|
14
|
+
* @param name - Branch name
|
|
15
|
+
* @param at - Time expression
|
|
16
|
+
*/
|
|
17
|
+
readonly fork?: (name: string, at: string | undefined) => Promise<string>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Fork journaled state into a named sandbox branch.
|
|
22
|
+
*
|
|
23
|
+
* @param options - Name / time
|
|
24
|
+
*/
|
|
25
|
+
export async function runBranch(options: BranchOptions): Promise<number> {
|
|
26
|
+
const write = options.write ?? ((t) => process.stdout.write(t));
|
|
27
|
+
if (!options.name) {
|
|
28
|
+
console.error("Usage: oke branch <name> --at <when>");
|
|
29
|
+
return 1;
|
|
30
|
+
}
|
|
31
|
+
const fork =
|
|
32
|
+
options.fork ??
|
|
33
|
+
(async (name, at) => {
|
|
34
|
+
const dir = `${options.cwd ?? process.cwd()}/.oke/branches/${name}`;
|
|
35
|
+
await Bun.write(
|
|
36
|
+
`${dir}/meta.json`,
|
|
37
|
+
`${JSON.stringify({ name, at: at ?? "now", createdAt: new Date().toISOString() }, null, 2)}\n`,
|
|
38
|
+
);
|
|
39
|
+
return dir;
|
|
40
|
+
});
|
|
41
|
+
try {
|
|
42
|
+
const path = await fork(options.name, options.at);
|
|
43
|
+
write(`oke branch: ${options.name} at ${options.at ?? "now"} → ${path}\n`);
|
|
44
|
+
return 0;
|
|
45
|
+
} catch (err) {
|
|
46
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
47
|
+
return 1;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* CLI entry for `oke branch`.
|
|
53
|
+
*
|
|
54
|
+
* @param args - Args after `branch`
|
|
55
|
+
*/
|
|
56
|
+
export async function branchCli(args: readonly string[]): Promise<number> {
|
|
57
|
+
let name: string | undefined;
|
|
58
|
+
let at: string | undefined;
|
|
59
|
+
for (let i = 0; i < args.length; i++) {
|
|
60
|
+
const a = args[i]!;
|
|
61
|
+
if (a === "--at" || a === "-a") at = args[++i];
|
|
62
|
+
else if (a === "--help" || a === "-h") {
|
|
63
|
+
console.log(`oke branch <name> --at|-a "yesterday"
|
|
64
|
+
|
|
65
|
+
Fork journaled state into a sandbox for replay / time-travel.
|
|
66
|
+
`);
|
|
67
|
+
return 0;
|
|
68
|
+
} else if (!a.startsWith("-") && !name) name = a;
|
|
69
|
+
}
|
|
70
|
+
if (!name) {
|
|
71
|
+
console.error("Usage: oke branch <name> --at <when>");
|
|
72
|
+
return 1;
|
|
73
|
+
}
|
|
74
|
+
return runBranch({ name, at });
|
|
75
|
+
}
|