okengine 0.2.6 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +33 -30
- package/README.md +74 -340
- package/{spec/manifest.v1.schema.json → manifest.v1.schema.json} +40 -9
- package/package.json +47 -44
- package/site/content/docs/ai/llms-txt.mdx +54 -0
- package/site/content/docs/ai/mcp.mdx +123 -0
- package/site/content/docs/ai/meta.json +5 -0
- package/site/content/docs/ai/skills.mdx +53 -0
- package/site/content/docs/console/access.mdx +29 -0
- package/site/content/docs/console/ai.mdx +35 -0
- package/site/content/docs/console/architecture.mdx +35 -0
- package/site/content/docs/console/channels.mdx +37 -0
- package/site/content/docs/console/clock.mdx +31 -0
- package/site/content/docs/console/flows.mdx +31 -0
- package/site/content/docs/console/gates.mdx +35 -0
- package/site/content/docs/console/manifest-diff.mdx +34 -0
- package/site/content/docs/console/meta.json +23 -0
- package/site/content/docs/console/overview.mdx +40 -0
- package/site/content/docs/console/plugins.mdx +41 -0
- package/site/content/docs/console/privacy.mdx +32 -0
- package/site/content/docs/console/runs.mdx +40 -0
- package/site/content/docs/console/signals.mdx +31 -0
- package/site/content/docs/console/store.mdx +32 -0
- package/site/content/docs/console/tenancy.mdx +32 -0
- package/site/content/docs/console/traces.mdx +34 -0
- package/site/content/docs/console/vault.mdx +37 -0
- package/site/content/docs/elements/ai.mdx +180 -0
- package/site/content/docs/elements/channel.mdx +167 -0
- package/site/content/docs/elements/clock.mdx +182 -0
- package/site/content/docs/elements/flow.mdx +288 -0
- package/site/content/docs/elements/gate.mdx +171 -0
- package/site/content/docs/elements/meta.json +5 -0
- package/site/content/docs/elements/signal.mdx +171 -0
- package/site/content/docs/elements/store.mdx +320 -0
- package/site/content/docs/elements/vault.mdx +263 -0
- package/site/content/docs/get-started/basic-usage.mdx +124 -0
- package/site/content/docs/get-started/comparison.mdx +65 -0
- package/site/content/docs/get-started/installation.mdx +113 -0
- package/site/content/docs/get-started/introduction.mdx +123 -0
- package/site/content/docs/get-started/meta.json +5 -0
- package/site/content/docs/index.mdx +63 -0
- package/site/content/docs/meta.json +5 -0
- package/site/content/docs/plugins/compression.mdx +60 -0
- package/site/content/docs/plugins/cors.mdx +92 -0
- package/site/content/docs/plugins/csrf.mdx +96 -0
- package/site/content/docs/plugins/ip-allowlist.mdx +92 -0
- package/site/content/docs/plugins/maintenance-mode.mdx +101 -0
- package/site/content/docs/plugins/meta.json +15 -0
- package/site/content/docs/plugins/security-headers.mdx +136 -0
- package/site/content/docs/reference/cli.md +101 -0
- package/site/content/docs/reference/configuration.mdx +159 -0
- package/site/content/docs/reference/environment-variables.mdx +87 -0
- package/site/content/docs/reference/errors.mdx +80 -0
- package/site/content/docs/reference/fx.mdx +117 -0
- package/site/content/docs/reference/meta.json +5 -0
- package/site/content/docs/reference/plugins.mdx +249 -0
- package/site/content/docs/reference/security.md +63 -0
- package/src/auth/api-keys.ts +2 -5
- package/src/auth/attenuation.ts +2 -6
- package/src/auth/auth.test.ts +56 -31
- package/src/auth/invoke-as.ts +1 -3
- package/src/auth/operator.ts +8 -26
- package/src/auth/planes.ts +2 -7
- package/src/auth/plugin.ts +4 -7
- package/src/auth/roles.ts +1 -5
- package/src/auth/sessions.ts +10 -39
- package/src/cli/args.ts +1 -5
- package/src/cli/ask-dev-mode.ts +40 -0
- package/src/cli/build.ts +1 -2
- package/src/cli/client-add.test.ts +8 -15
- package/src/cli/client-add.ts +5 -14
- package/src/cli/completion.test.ts +1 -5
- package/src/cli/completion.ts +4 -17
- package/src/cli/db-auto-push.test.ts +64 -0
- package/src/cli/db-auto-push.ts +72 -0
- package/src/cli/db.test.ts +189 -0
- package/src/cli/db.ts +456 -0
- package/src/cli/dev-app-runner.ts +2 -8
- package/src/cli/dev-db-push.test.ts +193 -0
- package/src/cli/dev-mode.test.ts +45 -0
- package/src/cli/dev-mode.ts +78 -0
- package/src/cli/dev-schema-sync.test.ts +66 -0
- package/src/cli/dev-schema-sync.ts +139 -0
- package/src/cli/dev.test.ts +264 -15
- package/src/cli/dev.ts +355 -139
- package/src/cli/doc-staleness.test.ts +69 -0
- package/src/cli/docker-cli.test.ts +27 -8
- package/src/cli/docker.ts +11 -3
- package/src/cli/doctor-diff.test.ts +1 -5
- package/src/cli/doctor-diff.ts +17 -46
- package/src/cli/doctor-pii.ts +2 -7
- package/src/cli/doctor.test.ts +26 -4
- package/src/cli/doctor.ts +35 -11
- package/src/cli/drizzle-env.test.ts +67 -0
- package/src/cli/drizzle-env.ts +78 -0
- package/src/cli/ensure-drizzle-config.ts +50 -0
- package/src/cli/eval.ts +4 -14
- package/src/cli/gates-list.ts +1 -4
- package/src/cli/hero-meta.test.ts +17 -19
- package/src/cli/hero-meta.ts +20 -30
- package/src/cli/images.ts +3 -8
- package/src/cli/index.ts +11 -2
- package/src/cli/load-config.images.test.ts +14 -14
- package/src/cli/load-config.ts +47 -47
- package/src/cli/mcp-from-console.ts +1 -4
- package/src/cli/mode.ts +65 -0
- package/src/cli/openbao-bootstrap.test.ts +147 -0
- package/src/cli/openbao-bootstrap.ts +280 -0
- package/src/cli/openbao-restart.integration.test.ts +136 -0
- package/src/cli/ports.test.ts +7 -14
- package/src/cli/ports.ts +7 -5
- package/src/cli/privacy-erase.ts +1 -3
- package/src/cli/registry.ts +75 -25
- package/src/cli/resolve-dev-sql-env.test.ts +48 -0
- package/src/cli/resolve-dev-sql-env.ts +42 -0
- package/src/cli/schema.ts +3 -10
- package/src/cli/stack.ts +8 -10
- package/src/cli/start.ts +4 -15
- package/src/cli/upgrade.ts +1 -4
- package/src/cli/vault-cmd.ts +63 -0
- package/src/client/budget-entry.ts +1 -6
- package/src/client/create.test.ts +6 -12
- package/src/client/create.ts +2 -8
- package/src/client/errors.ts +1 -4
- package/src/client/index.ts +1 -6
- package/src/client/notes-contract.test.ts +4 -13
- package/src/client/transport.ts +9 -30
- package/src/client/types.ts +15 -30
- package/src/compiler/aot.test.ts +2 -9
- package/src/compiler/aot.ts +1 -4
- package/src/compiler/differential.test.ts +3 -11
- package/src/compiler/dynamic.ts +1 -4
- package/src/compiler/effects-infer.ts +8 -34
- package/src/compiler/emit.ts +1 -3
- package/src/compiler/extract.test.ts +136 -30
- package/src/compiler/extract.ts +485 -157
- package/src/compiler/fixtures/skyport/oke.config.ts +3 -3
- package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +7 -3
- package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +1 -3
- package/src/compiler/fixtures/skyport/src/flows/support/index.ts +4 -1
- package/src/compiler/fixtures/skyport.expected.json +24 -83
- package/src/compiler/fixtures/triggers/five-triggers.ts +1 -2
- package/src/compiler/http-parse.ts +2 -9
- package/src/compiler/index.ts +1 -5
- package/src/compiler/response.ts +16 -7
- package/src/compiler/sucrose.ts +11 -31
- package/src/config/define-config.test.ts +55 -34
- package/src/config/index.ts +177 -46
- package/src/config/resolve-driver.test.ts +28 -17
- package/src/console/budget.test.ts +1 -4
- package/src/console/index.ts +1 -4
- package/src/console/server/access.test.ts +15 -43
- package/src/console/server/access.ts +19 -49
- package/src/console/server/ai.test.ts +3 -11
- package/src/console/server/ai.ts +23 -46
- package/src/console/server/app.ts +16 -45
- package/src/console/server/auth-rate.test.ts +4 -12
- package/src/console/server/bind.ts +1 -5
- package/src/console/server/channels.test.ts +2 -6
- package/src/console/server/channels.ts +10 -35
- package/src/console/server/claim.ts +2 -8
- package/src/console/server/clock.test.ts +2 -6
- package/src/console/server/clock.ts +8 -26
- package/src/console/server/console.test.ts +1 -3
- package/src/console/server/diff.test.ts +5 -17
- package/src/console/server/diff.ts +10 -31
- package/src/console/server/dry-run.audit.test.ts +2 -8
- package/src/console/server/flows.ts +64 -233
- package/src/console/server/gates.test.ts +14 -50
- package/src/console/server/gates.ts +13 -48
- package/src/console/server/index.ts +2 -9
- package/src/console/server/live.ts +3 -12
- package/src/console/server/operator-db.test.ts +4 -15
- package/src/console/server/operator-db.ts +13 -32
- package/src/console/server/plugin.ts +50 -53
- package/src/console/server/plugins.test.ts +2 -6
- package/src/console/server/plugins.ts +17 -56
- package/src/console/server/runs-pii.ts +2 -7
- package/src/console/server/security.gate.test.ts +18 -40
- package/src/console/server/serve.ts +10 -25
- package/src/console/server/signals.test.ts +1 -3
- package/src/console/server/signals.ts +17 -40
- package/src/console/server/state.ts +21 -59
- package/src/console/server/store.test.ts +20 -22
- package/src/console/server/store.ts +31 -76
- package/src/console/server/vault.test.ts +12 -29
- package/src/console/server/vault.ts +44 -66
- package/src/console/ui/access/AccessA11yView.tsx +6 -21
- package/src/console/ui/access/a11y.test.tsx +3 -12
- package/src/console/ui/access/acknowledgement.test.ts +1 -4
- package/src/console/ui/access/acknowledgement.ts +1 -3
- package/src/console/ui/access/blast-radius.ts +1 -3
- package/src/console/ui/access/confirmation.test.ts +1 -5
- package/src/console/ui/access/confirmation.ts +1 -4
- package/src/console/ui/access/fixture.ts +1 -5
- package/src/console/ui/access/grantable.test.ts +1 -3
- package/src/console/ui/access/grantable.ts +2 -7
- package/src/console/ui/access/index.ts +2 -9
- package/src/console/ui/access/provenance.test.ts +1 -3
- package/src/console/ui/access/provenance.ts +2 -6
- package/src/console/ui/access/search.test.ts +1 -5
- package/src/console/ui/access/search.ts +2 -6
- package/src/console/ui/ai/AiA11yView.tsx +6 -17
- package/src/console/ui/ai/a11y.test.tsx +2 -5
- package/src/console/ui/ai/fixture.ts +2 -7
- package/src/console/ui/ai/format.ts +1 -3
- package/src/console/ui/ai/group.test.ts +1 -3
- package/src/console/ui/ai/group.ts +4 -12
- package/src/console/ui/ai/index.ts +2 -9
- package/src/console/ui/ai/promotion.test.ts +2 -7
- package/src/console/ui/ai/promotion.ts +4 -13
- package/src/console/ui/ai/search.test.ts +2 -11
- package/src/console/ui/ai/search.ts +3 -13
- package/src/console/ui/ai/types.ts +1 -8
- package/src/console/ui/architecture/ArchitectureA11yView.tsx +8 -29
- package/src/console/ui/architecture/a11y.test.tsx +1 -2
- package/src/console/ui/architecture/declared.ts +1 -5
- package/src/console/ui/architecture/index.ts +7 -35
- package/src/console/ui/architecture/layout.ts +1 -3
- package/src/console/ui/architecture/pathologies.ts +10 -19
- package/src/console/ui/architecture/search.ts +6 -15
- package/src/console/ui/architecture/traffic.ts +4 -14
- package/src/console/ui/architecture/types.ts +2 -10
- package/src/console/ui/architecture/view.test.ts +7 -19
- package/src/console/ui/architecture/view.ts +9 -36
- package/src/console/ui/channels/ChannelsA11yView.tsx +4 -13
- package/src/console/ui/channels/a11y.test.tsx +1 -2
- package/src/console/ui/channels/confirmation.test.ts +1 -4
- package/src/console/ui/channels/confirmation.ts +1 -4
- package/src/console/ui/channels/findings.ts +1 -5
- package/src/console/ui/channels/index.ts +2 -8
- package/src/console/ui/channels/locale.test.ts +1 -3
- package/src/console/ui/channels/locale.ts +2 -8
- package/src/console/ui/channels/search.ts +4 -13
- package/src/console/ui/channels/taxonomy.ts +1 -3
- package/src/console/ui/clock/ClockA11yView.tsx +9 -26
- package/src/console/ui/clock/a11y.test.tsx +2 -5
- package/src/console/ui/clock/confirmation.test.ts +1 -3
- package/src/console/ui/clock/confirmation.ts +1 -4
- package/src/console/ui/clock/findings.ts +1 -4
- package/src/console/ui/clock/health.ts +2 -7
- package/src/console/ui/clock/index.ts +2 -10
- package/src/console/ui/clock/search.test.ts +1 -3
- package/src/console/ui/clock/search.ts +2 -6
- package/src/console/ui/clock/timeline.test.ts +1 -3
- package/src/console/ui/clock/waiting-on.test.ts +1 -5
- package/src/console/ui/clock/waiting-on.ts +2 -7
- package/src/console/ui/diff/DiffA11yView.tsx +8 -17
- package/src/console/ui/diff/a11y.test.tsx +2 -5
- package/src/console/ui/diff/group.test.ts +3 -13
- package/src/console/ui/diff/group.ts +2 -8
- package/src/console/ui/diff/index.ts +2 -8
- package/src/console/ui/diff/search.test.ts +1 -5
- package/src/console/ui/diff/search.ts +4 -16
- package/src/console/ui/diff/summary.ts +1 -2
- package/src/console/ui/dist/assets/{index-Dy4jht9P.js → index-BWo8R7NR.js} +2 -2
- package/src/console/ui/dist/assets/{panel-access-Dd37LU2c.js → panel-access-C0J2D-a2.js} +1 -1
- package/src/console/ui/dist/assets/{panel-ai-CC7LR6-J.js → panel-ai-D_m6WQI8.js} +1 -1
- package/src/console/ui/dist/assets/{panel-architecture-B5b3iKCz.js → panel-architecture-CKnXFyUx.js} +1 -1
- package/src/console/ui/dist/assets/{panel-channels-CeNjTKXp.js → panel-channels-BOmQ-onL.js} +1 -1
- package/src/console/ui/dist/assets/{panel-clock-DgFTLoHV.js → panel-clock-giAq0Ccv.js} +1 -1
- package/src/console/ui/dist/assets/{panel-diff-DxehccqB.js → panel-diff-cdonmH8c.js} +1 -1
- package/src/console/ui/dist/assets/{panel-flows-BtrVn-Eg.js → panel-flows-DlCU5zjA.js} +2 -2
- package/src/console/ui/dist/assets/{panel-gates-Z9MKRGdH.js → panel-gates-XclZxWD5.js} +1 -1
- package/src/console/ui/dist/assets/{panel-overview-Dt_AeXgd.js → panel-overview-BznEOTnb.js} +1 -1
- package/src/console/ui/dist/assets/{panel-plugins-DWd0TowH.js → panel-plugins-CcGM1g64.js} +1 -1
- package/src/console/ui/dist/assets/{panel-runs-DGstFHeq.js → panel-runs-CGWNHLR4.js} +1 -1
- package/src/console/ui/dist/assets/{panel-signals-DzEa2Fnt.js → panel-signals-CNywkdak.js} +1 -1
- package/src/console/ui/dist/assets/{panel-store-BJkbNgxx.js → panel-store-KmTbFHMH.js} +1 -1
- package/src/console/ui/dist/assets/{panel-traces-BaRVO3gM.js → panel-traces-DBLx2ilD.js} +1 -1
- package/src/console/ui/dist/assets/panel-vault-CEnFc0dk.js +1 -0
- package/src/console/ui/dist/index.html +1 -1
- package/src/console/ui/flows/FlowsA11yView.tsx +7 -22
- package/src/console/ui/flows/a11y.test.tsx +2 -8
- package/src/console/ui/flows/buffer.test.ts +3 -11
- package/src/console/ui/flows/buffer.ts +4 -11
- package/src/console/ui/flows/confirmation.ts +1 -3
- package/src/console/ui/flows/contract.test.ts +3 -7
- package/src/console/ui/flows/contract.ts +12 -36
- package/src/console/ui/flows/graph.test.ts +3 -11
- package/src/console/ui/flows/graph.ts +5 -15
- package/src/console/ui/flows/index.ts +1 -6
- package/src/console/ui/flows/save-as-test.ts +1 -3
- package/src/console/ui/flows/search.ts +8 -25
- package/src/console/ui/flows/tiers.ts +2 -9
- package/src/console/ui/gates/GatesA11yView.tsx +4 -13
- package/src/console/ui/gates/a11y.test.tsx +2 -5
- package/src/console/ui/gates/audit.ts +1 -3
- package/src/console/ui/gates/denial.test.ts +1 -3
- package/src/console/ui/gates/denial.ts +4 -12
- package/src/console/ui/gates/findings.ts +1 -3
- package/src/console/ui/gates/group.test.ts +3 -3
- package/src/console/ui/gates/group.ts +3 -11
- package/src/console/ui/gates/index.ts +2 -10
- package/src/console/ui/gates/search.ts +3 -10
- package/src/console/ui/overview/OverviewA11yView.tsx +9 -27
- package/src/console/ui/overview/a11y.test.tsx +1 -2
- package/src/console/ui/overview/busiest.ts +1 -3
- package/src/console/ui/overview/compose.ts +1 -13
- package/src/console/ui/overview/cost.ts +34 -38
- package/src/console/ui/overview/fixture.ts +21 -26
- package/src/console/ui/overview/golden.ts +4 -14
- package/src/console/ui/overview/index.ts +2 -9
- package/src/console/ui/overview/rank.test.ts +3 -10
- package/src/console/ui/overview/rank.ts +2 -7
- package/src/console/ui/overview/slo.test.ts +5 -9
- package/src/console/ui/overview/slo.ts +6 -23
- package/src/console/ui/overview/verdict.ts +3 -10
- package/src/console/ui/plugins/PluginsA11yView.tsx +8 -18
- package/src/console/ui/plugins/a11y.test.tsx +1 -2
- package/src/console/ui/plugins/fixture.ts +2 -4
- package/src/console/ui/plugins/group.test.ts +1 -3
- package/src/console/ui/plugins/group.ts +1 -6
- package/src/console/ui/plugins/index.ts +3 -13
- package/src/console/ui/plugins/search.ts +7 -19
- package/src/console/ui/runs/RunsA11yView.tsx +5 -20
- package/src/console/ui/runs/a11y.test.tsx +2 -5
- package/src/console/ui/runs/explain.ts +2 -6
- package/src/console/ui/runs/group.ts +3 -12
- package/src/console/ui/runs/histogram.test.ts +2 -11
- package/src/console/ui/runs/histogram.ts +1 -4
- package/src/console/ui/runs/index.ts +4 -18
- package/src/console/ui/runs/project.ts +2 -6
- package/src/console/ui/runs/query.test.ts +1 -3
- package/src/console/ui/runs/query.ts +12 -35
- package/src/console/ui/runs/search.ts +5 -19
- package/src/console/ui/runs/trace-link.test.ts +2 -6
- package/src/console/ui/runs/trace-link.ts +4 -16
- package/src/console/ui/runs/types.ts +1 -3
- package/src/console/ui/shell/App.tsx +2 -10
- package/src/console/ui/shell/client.ts +22 -115
- package/src/console/ui/shell/components/ui.tsx +1 -4
- package/src/console/ui/shell/layout/Shell.tsx +2 -4
- package/src/console/ui/shell/main.tsx +31 -96
- package/src/console/ui/shell/panels/access/AccessPanel.tsx +34 -98
- package/src/console/ui/shell/panels/ai/AiPanel.tsx +35 -106
- package/src/console/ui/shell/panels/architecture/ArchitecturePanel.tsx +18 -66
- package/src/console/ui/shell/panels/channels/ChannelsPanel.tsx +20 -57
- package/src/console/ui/shell/panels/clock/ClockPanel.tsx +22 -54
- package/src/console/ui/shell/panels/diff/DiffPanel.tsx +20 -61
- package/src/console/ui/shell/panels/flows/ContractEditor.tsx +6 -23
- package/src/console/ui/shell/panels/flows/FlowDrawer.tsx +13 -28
- package/src/console/ui/shell/panels/flows/FlowsPanel.tsx +9 -29
- package/src/console/ui/shell/panels/gates/GatesPanel.tsx +24 -80
- package/src/console/ui/shell/panels/overview/OverviewPanel.tsx +20 -58
- package/src/console/ui/shell/panels/plugins/PluginsPanel.tsx +16 -41
- package/src/console/ui/shell/panels/runs/RunsPanel.tsx +31 -99
- package/src/console/ui/shell/panels/signals/SignalsPanel.tsx +38 -101
- package/src/console/ui/shell/panels/store/StorePanel.tsx +27 -66
- package/src/console/ui/shell/panels/traces/TracesPanel.tsx +28 -89
- package/src/console/ui/shell/panels/vault/VaultPanel.tsx +22 -53
- package/src/console/ui/shell/setup/Wizard.tsx +3 -5
- package/src/console/ui/shell/styles.css +1 -2
- package/src/console/ui/signals/SignalsA11yView.tsx +9 -33
- package/src/console/ui/signals/a11y.test.tsx +2 -5
- package/src/console/ui/signals/confirmation.test.ts +1 -5
- package/src/console/ui/signals/confirmation.ts +2 -6
- package/src/console/ui/signals/dry-run.ts +1 -3
- package/src/console/ui/signals/durable.ts +1 -3
- package/src/console/ui/signals/findings.ts +1 -3
- package/src/console/ui/signals/group.test.ts +2 -8
- package/src/console/ui/signals/group.ts +2 -10
- package/src/console/ui/signals/index.ts +1 -4
- package/src/console/ui/signals/monitor.ts +2 -7
- package/src/console/ui/signals/schema-form.test.ts +3 -14
- package/src/console/ui/signals/schema-form.ts +1 -4
- package/src/console/ui/signals/search.ts +4 -13
- package/src/console/ui/store/StoreA11yView.tsx +3 -9
- package/src/console/ui/store/a11y.test.tsx +2 -5
- package/src/console/ui/store/confirmation.test.ts +1 -3
- package/src/console/ui/store/confirmation.ts +1 -4
- package/src/console/ui/store/dry-run.ts +2 -5
- package/src/console/ui/store/fixture.ts +1 -2
- package/src/console/ui/store/group.test.ts +1 -6
- package/src/console/ui/store/group.ts +1 -4
- package/src/console/ui/store/index.ts +1 -5
- package/src/console/ui/store/search.ts +2 -6
- package/src/console/ui/store/will-not-fire.ts +1 -2
- package/src/console/ui/traces/TracesA11yView.tsx +10 -29
- package/src/console/ui/traces/a11y.test.tsx +1 -2
- package/src/console/ui/traces/chain.test.ts +5 -19
- package/src/console/ui/traces/chain.ts +1 -3
- package/src/console/ui/traces/critical-path.test.ts +1 -3
- package/src/console/ui/traces/critical-path.ts +2 -6
- package/src/console/ui/traces/filter.test.ts +2 -6
- package/src/console/ui/traces/filter.ts +5 -13
- package/src/console/ui/traces/fold.test.ts +4 -12
- package/src/console/ui/traces/fold.ts +1 -3
- package/src/console/ui/traces/mini.ts +1 -3
- package/src/console/ui/traces/replay.test.ts +1 -3
- package/src/console/ui/traces/replay.ts +1 -3
- package/src/console/ui/traces/sampling.ts +1 -4
- package/src/console/ui/traces/search.ts +4 -17
- package/src/console/ui/traces/tier.ts +1 -3
- package/src/console/ui/vault/VaultA11yView.tsx +5 -17
- package/src/console/ui/vault/a11y.test.tsx +1 -2
- package/src/console/ui/vault/blast-radius.ts +1 -3
- package/src/console/ui/vault/confirmation.test.ts +1 -5
- package/src/console/ui/vault/confirmation.ts +1 -4
- package/src/console/ui/vault/dormant.test.ts +1 -4
- package/src/console/ui/vault/export-safe.test.ts +1 -5
- package/src/console/ui/vault/export-safe.ts +1 -4
- package/src/console/ui/vault/fixture.ts +3 -3
- package/src/console/ui/vault/group.ts +1 -2
- package/src/console/ui/vault/index.ts +2 -10
- package/src/console/ui/vault/search.ts +2 -6
- package/src/console/ui/vault/types.ts +1 -1
- package/src/console/xss.gate.test.ts +1 -3
- package/src/docker/compose.ts +215 -27
- package/src/docker/derive.ts +6 -14
- package/src/docker/docker.test.ts +118 -15
- package/src/docker/dockerfile.integration.test.ts +12 -21
- package/src/docker/helpers.ts +5 -4
- package/src/docker/index.ts +9 -6
- package/src/docker/pin.ts +1 -9
- package/src/docker/recipes/index.ts +6 -6
- package/src/docker/recipes/mailpit.ts +22 -0
- package/src/docker/recipes/openbao.ts +47 -0
- package/src/docker/recipes/postgres.ts +17 -6
- package/src/docker/recipes/redis.ts +11 -2
- package/src/docker/recipes/rustfs.ts +32 -0
- package/src/docker/stack-id.test.ts +73 -5
- package/src/docker/stack-id.ts +124 -33
- package/src/docker/stack.integration.test.ts +6 -21
- package/src/docker/stack.ts +36 -4
- package/src/docker/types.ts +16 -4
- package/src/docs-origin.ts +4 -4
- package/src/drivers/ai-anthropic.ts +5 -14
- package/src/drivers/ai-mock.ts +2 -5
- package/src/drivers/ai-openai-compatible.ts +4 -10
- package/src/drivers/ai-providers.test.ts +6 -13
- package/src/drivers/bun-native-completeness.test.ts +6 -15
- package/src/drivers/channel-console.ts +6 -7
- package/src/drivers/channel-fcm.ts +20 -30
- package/src/drivers/channel-resend.ts +1 -3
- package/src/drivers/channel-smtp.ts +2 -6
- package/src/drivers/channel-types.ts +2 -12
- package/src/drivers/channel-unifonic.ts +2 -6
- package/src/drivers/channel-wa-cloud.ts +2 -6
- package/src/drivers/channel-webpush.ts +21 -60
- package/src/drivers/conformance.test.ts +2 -10
- package/src/drivers/conformance.ts +8 -21
- package/src/drivers/drizzle-dialect.test.ts +20 -0
- package/src/drivers/drizzle-dialect.ts +37 -0
- package/src/drivers/fs.ts +2 -8
- package/src/drivers/index.ts +12 -57
- package/src/drivers/memory.ts +287 -75
- package/src/drivers/pgvector.ts +7 -11
- package/src/drivers/postgres.ts +7 -13
- package/src/drivers/redis.ts +13 -37
- package/src/drivers/s3.ts +15 -18
- package/src/drivers/signal-engine.ts +12 -49
- package/src/drivers/signal-memory.ts +2 -8
- package/src/drivers/signal-nats.ts +4 -9
- package/src/drivers/signal-postgres.ts +62 -129
- package/src/drivers/signal-redis.ts +7 -21
- package/src/drivers/signal-types.ts +1 -4
- package/src/drivers/sqlite.ts +3 -12
- package/src/drivers/types.ts +4 -23
- package/src/drivers/vault-driver-removal.test.ts +55 -0
- package/src/drivers/vault-env.ts +2 -6
- package/src/drivers/vault-infisical.ts +1 -5
- package/src/drivers/vault-managed.ts +1 -5
- package/src/drivers/vault-memory.ts +1 -5
- package/src/drivers/vault-openbao.test.ts +97 -0
- package/src/drivers/vault-openbao.ts +103 -40
- package/src/drivers/vault-types.ts +3 -16
- package/src/elements/ai/declare.ts +4 -14
- package/src/elements/ai/eval.ts +2 -6
- package/src/elements/ai/pii.ts +1 -3
- package/src/elements/ai/runtime.ts +12 -50
- package/src/elements/ai/schema.ts +4 -15
- package/src/elements/ai.test.ts +13 -24
- package/src/elements/ai.ts +1 -5
- package/src/elements/channel/consent.ts +3 -12
- package/src/elements/channel/costs.ts +4 -15
- package/src/elements/channel/declare.ts +1 -4
- package/src/elements/channel/email-auth.ts +1 -4
- package/src/elements/channel/locale.ts +2 -10
- package/src/elements/channel/mask.ts +1 -3
- package/src/elements/channel/mime.ts +2 -12
- package/src/elements/channel/outcomes.test.ts +1 -5
- package/src/elements/channel/outcomes.ts +5 -15
- package/src/elements/channel/receipts.ts +2 -7
- package/src/elements/channel/runtime.ts +28 -74
- package/src/elements/channel/suppression.ts +8 -14
- package/src/elements/channel.test.ts +8 -31
- package/src/elements/channel.ts +3 -14
- package/src/elements/clock/actions.ts +6 -18
- package/src/elements/clock/declare.ts +1 -3
- package/src/elements/clock/dst.ts +1 -5
- package/src/elements/clock/durable.ts +4 -16
- package/src/elements/clock/health.ts +2 -7
- package/src/elements/clock/leader.ts +2 -9
- package/src/elements/clock/reconcile.ts +4 -15
- package/src/elements/clock/runtime.ts +2 -5
- package/src/elements/clock/schedule.ts +4 -20
- package/src/elements/clock.test.ts +2 -7
- package/src/elements/clock.ts +5 -23
- package/src/elements/gate/permissions.ts +1 -4
- package/src/elements/gate/runtime.ts +7 -28
- package/src/elements/gate.ts +1 -5
- package/src/elements/index.ts +9 -7
- package/src/elements/signal/declare.ts +2 -7
- package/src/elements/signal/reconcile.test.ts +1 -4
- package/src/elements/signal/runtime.ts +1 -3
- package/src/elements/signal.test.ts +3 -15
- package/src/elements/signal.ts +2 -8
- package/src/elements/store/cache.test.ts +46 -0
- package/src/elements/store/cache.ts +3 -11
- package/src/elements/store/classify.ts +5 -22
- package/src/elements/store/declare.ts +11 -17
- package/src/elements/store/domain-ddl.test.ts +86 -0
- package/src/elements/store/emit-drizzle.ts +363 -0
- package/src/elements/store/files-policy.test.ts +1 -5
- package/src/elements/store/files-policy.ts +4 -12
- package/src/elements/store/load-plugin-tables.ts +103 -0
- package/src/elements/store/missing-relation.test.ts +83 -0
- package/src/elements/store/missing-relation.ts +38 -0
- package/src/elements/store/replica.ts +1 -4
- package/src/elements/store/resource-list-docs.fixture.ts +56 -0
- package/src/elements/store/resource-list-docs.test.ts +79 -0
- package/src/elements/store/resource.test.ts +253 -0
- package/src/elements/store/resource.ts +786 -0
- package/src/elements/store/runtime.ts +25 -28
- package/src/elements/store/schema-decl.test.ts +227 -0
- package/src/elements/store/schema-decl.ts +516 -0
- package/src/elements/store/sql-condition.test.ts +132 -0
- package/src/elements/store/sql-condition.ts +293 -65
- package/src/elements/store/sql-session.test.ts +135 -0
- package/src/elements/store/sql-session.ts +241 -84
- package/src/elements/store/table.ts +69 -23
- package/src/elements/store.test.ts +17 -39
- package/src/elements/store.ts +53 -31
- package/src/elements/vault/chain.ts +34 -0
- package/src/elements/vault/declare.ts +22 -32
- package/src/elements/vault/fingerprint.ts +2 -7
- package/src/elements/vault/redact.ts +2 -6
- package/src/elements/vault/runtime.ts +19 -33
- package/src/elements/vault.test.ts +12 -55
- package/src/elements/vault.ts +9 -13
- package/src/index.ts +5 -2
- package/src/kernel/adopt-routes.ts +15 -29
- package/src/kernel/app.ts +92 -118
- package/src/kernel/auth-resolve.ts +2 -9
- package/src/kernel/boot-bind/ai.ts +1 -4
- package/src/kernel/boot-bind/channel.test.ts +60 -0
- package/src/kernel/boot-bind/channel.ts +61 -5
- package/src/kernel/boot-bind/clock.ts +2 -6
- package/src/kernel/boot-bind/gate.ts +2 -8
- package/src/kernel/boot-bind/runs.ts +1 -3
- package/src/kernel/boot-bind/signal.ts +3 -10
- package/src/kernel/boot-bind/store.test.ts +27 -18
- package/src/kernel/boot-bind/store.ts +93 -52
- package/src/kernel/boot-bind/vault.ts +2 -8
- package/src/kernel/boot.test.ts +4 -10
- package/src/kernel/boot.ts +30 -77
- package/src/kernel/budget.test.ts +1 -3
- package/src/kernel/capability.ts +3 -10
- package/src/kernel/dry-run.test.ts +1 -4
- package/src/kernel/dry-run.ts +3 -11
- package/src/kernel/edge.test.ts +68 -0
- package/src/kernel/effects.test.ts +1 -5
- package/src/kernel/effects.ts +4 -11
- package/src/kernel/errors.registry.test.ts +2 -8
- package/src/kernel/errors.ts +23 -32
- package/src/kernel/flow.test.ts +12 -25
- package/src/kernel/flow.ts +13 -25
- package/src/kernel/fx.test.ts +31 -40
- package/src/kernel/fx.ts +135 -90
- package/src/kernel/hook-timing.test.ts +3 -6
- package/src/kernel/hook-timing.ts +5 -14
- package/src/kernel/hooks.test.ts +43 -10
- package/src/kernel/hooks.ts +25 -12
- package/src/kernel/index.ts +11 -17
- package/src/kernel/journal.ts +7 -31
- package/src/kernel/on.ts +45 -9
- package/src/kernel/pipeline.test.ts +10 -19
- package/src/kernel/pipeline.ts +5 -17
- package/src/kernel/plug.ts +4 -11
- package/src/kernel/plugin/conflicts.test.ts +13 -25
- package/src/kernel/plugin/decorate.test.ts +8 -13
- package/src/kernel/plugin/scoping.test.ts +4 -11
- package/src/kernel/plugin.ts +81 -27
- package/src/kernel/registry-isolation.test.ts +74 -0
- package/src/kernel/registry.ts +102 -30
- package/src/kernel/router.test.ts +15 -13
- package/src/kernel/router.ts +9 -29
- package/src/kernel/routing-budget.test.ts +1 -3
- package/src/kernel/run-telemetry.ts +1 -3
- package/src/kernel/triggers.ts +63 -21
- package/src/manifest/diff.test.ts +26 -91
- package/src/manifest/diff.ts +95 -225
- package/src/manifest/fixtures/skyport.excerpt.json +1 -1
- package/src/manifest/fixtures/skyport.manifest.json +1 -1
- package/src/manifest/index.ts +3 -10
- package/src/manifest/types.ts +30 -6
- package/src/manifest/undeclared.test.ts +4 -12
- package/src/manifest/undeclared.ts +1 -2
- package/src/manifest/validate.test.ts +2 -6
- package/src/manifest/validate.ts +5 -15
- package/src/mcp/authorization.ts +8 -27
- package/src/mcp/confirmation.ts +3 -10
- package/src/mcp/data.ts +2 -6
- package/src/mcp/docs-index.ts +4 -7
- package/src/mcp/docs-mcp.test.ts +3 -12
- package/src/mcp/docs-server.ts +7 -27
- package/src/mcp/docs-tools.ts +2 -6
- package/src/mcp/index.ts +1 -6
- package/src/mcp/injection.gate.test.ts +4 -18
- package/src/mcp/mcp.test.ts +18 -49
- package/src/mcp/protocol.ts +3 -10
- package/src/mcp/server.ts +11 -52
- package/src/mcp/session.ts +4 -14
- package/src/mcp/tools.ts +14 -50
- package/src/plugins/catalogue.test.ts +3 -7
- package/src/plugins/catalogue.ts +1 -3
- package/src/plugins/compression.test.ts +127 -0
- package/src/plugins/compression.ts +94 -0
- package/src/plugins/config-source.test.ts +204 -0
- package/src/plugins/config-source.ts +209 -0
- package/src/plugins/cors.test.ts +138 -0
- package/src/plugins/cors.ts +129 -0
- package/src/plugins/csrf.test.ts +102 -0
- package/src/plugins/csrf.ts +86 -0
- package/src/plugins/headers.ts +54 -0
- package/src/plugins/index.ts +26 -0
- package/src/plugins/ip-allowlist.test.ts +105 -0
- package/src/plugins/ip-allowlist.ts +76 -0
- package/src/plugins/maintenance-mode.test.ts +91 -0
- package/src/plugins/maintenance-mode.ts +85 -0
- package/src/plugins/node-import-scan.ts +2 -5
- package/src/plugins/security-headers.test.ts +243 -0
- package/src/plugins/security-headers.ts +255 -0
- package/src/plugins/supply-chain.ts +5 -17
- package/src/release/exports.ts +3 -8
- package/src/release/measure.exports.test.ts +1 -3
- package/src/release/measure.ts +16 -45
- package/src/runs/bench.test.ts +1 -3
- package/src/runs/collect.ts +8 -25
- package/src/runs/drivers/clickhouse.ts +2 -9
- package/src/runs/drivers/files.ts +9 -31
- package/src/runs/drivers/memory.ts +5 -22
- package/src/runs/drivers/postgres.ts +8 -20
- package/src/runs/duckdb.ts +2 -8
- package/src/runs/index.ts +3 -14
- package/src/runs/outlier.ts +3 -10
- package/src/runs/parquet.ts +8 -26
- package/src/runs/privacy.ts +2 -8
- package/src/runs/runs.test.ts +3 -9
- package/src/runs/runtime.ts +7 -32
- package/src/runs/shred.ts +10 -29
- package/src/runs/types.ts +1 -4
- package/src/runtime/bun.ts +4 -15
- package/src/runtime/cold-start.bench.ts +1 -3
- package/src/runtime/dev-request-log.test.ts +1 -4
- package/src/runtime/dev-request-log.ts +1 -4
- package/src/runtime/index.ts +1 -6
- package/src/runtime/primitives.ts +5 -4
- package/src/runtime/security.ts +3 -13
- package/src/runtime/serve.test.ts +4 -7
- package/src/runtime/types.ts +1 -4
- package/src/runtime/web-standard.ts +3 -15
- package/src/term.test.ts +4 -6
- package/src/term.ts +49 -98
- package/src/test/create-test-app.test.ts +4 -14
- package/src/test/create-test-app.ts +27 -33
- package/src/test/provisions.integration.test.ts +3 -11
- package/src/upgrade/codemods.test.ts +25 -6
- package/src/upgrade/codemods.ts +116 -3
- package/src/validation/standard-schema.test.ts +2 -5
- package/src/validation/standard-schema.ts +13 -33
- package/docs/spec/console.md +0 -739
- package/docs/spec/example.md +0 -1196
- package/docs/spec/four-applications.md +0 -1195
- package/docs/spec/unified-theory.md +0 -489
- package/src/cli/doc-drift.test.ts +0 -146
- package/src/cli/doc-drift.ts +0 -430
- package/src/cli/doctor-diff-examples.ts +0 -92
- package/src/console/ui/dist/assets/panel-vault-BbfWdox0.js +0 -1
- package/src/drivers/vault-sops.ts +0 -271
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gate: removed legacy stack-mode soft-compat stays gone.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors {@link ../drivers/vault-driver-removal.test.ts} — `git grep` over the
|
|
5
|
+
* tracked tree must find zero hits (changelog history may still document the
|
|
6
|
+
* rename; upgrade codemods may still rewrite the old tokens).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { describe, expect, test } from "bun:test";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
|
|
12
|
+
const ROOT = join(import.meta.dir, "../..");
|
|
13
|
+
|
|
14
|
+
/** Forbidden CLI flag, split so this file does not match itself. */
|
|
15
|
+
const FORBIDDEN_STACK_FLAG = ["--", "stack"].join("");
|
|
16
|
+
/** Forbidden compose env filename. */
|
|
17
|
+
const FORBIDDEN_ENV_STACK = [".env.", "stack"].join("");
|
|
18
|
+
/** Forbidden env var — name avoids the contiguous token so this file is clean. */
|
|
19
|
+
const FORBIDDEN_LEGACY_ENV = ["OKE_", "STACK"].join("");
|
|
20
|
+
/** Forbidden vault helper. */
|
|
21
|
+
const FORBIDDEN_FROM_STACK = ["from", "Stack"].join("");
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Run `git grep -F` and assert zero matches after ignoring allow-listed paths.
|
|
25
|
+
*
|
|
26
|
+
* @param pattern - Fixed-string pattern
|
|
27
|
+
* @param ignorePrefixes - Path prefixes to ignore (`path:line:` hits)
|
|
28
|
+
*/
|
|
29
|
+
function assertZeroGitGrep(pattern: string, ignorePrefixes: readonly string[] = []): void {
|
|
30
|
+
const proc = Bun.spawnSync(["git", "grep", "-F", "-n", "-e", pattern, "--"], {
|
|
31
|
+
cwd: ROOT,
|
|
32
|
+
stdout: "pipe",
|
|
33
|
+
stderr: "pipe",
|
|
34
|
+
});
|
|
35
|
+
// git grep exits 1 when there are no matches.
|
|
36
|
+
if (proc.exitCode === 1) {
|
|
37
|
+
expect(proc.stdout.toString()).toBe("");
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const hits = proc.stdout
|
|
41
|
+
.toString()
|
|
42
|
+
.trim()
|
|
43
|
+
.split("\n")
|
|
44
|
+
.filter((line) => line.length > 0)
|
|
45
|
+
.filter((line) => !ignorePrefixes.some((prefix) => line.startsWith(prefix)));
|
|
46
|
+
expect(hits.join("\n")).toBe("");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
describe("legacy stack-mode removal gate", () => {
|
|
50
|
+
test("tracked tree has zero legacy docker-mode flag outside changelog", () => {
|
|
51
|
+
assertZeroGitGrep(FORBIDDEN_STACK_FLAG, ["changelog.md:"]);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("tracked tree has zero legacy compose env filename outside changelog", () => {
|
|
55
|
+
assertZeroGitGrep(FORBIDDEN_ENV_STACK, ["changelog.md:"]);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("tracked tree has zero legacy OKE env outside changelog", () => {
|
|
59
|
+
assertZeroGitGrep(FORBIDDEN_LEGACY_ENV, ["changelog.md:"]);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("tracked tree has zero legacy vault helper outside changelog + upgrade", () => {
|
|
63
|
+
assertZeroGitGrep(FORBIDDEN_FROM_STACK, [
|
|
64
|
+
"changelog.md:",
|
|
65
|
+
"src/upgrade/codemods.ts:",
|
|
66
|
+
"src/upgrade/codemods.test.ts:",
|
|
67
|
+
]);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `oke docker` / `oke stack` / `oke images pin` / `oke schema` / `oke dev --
|
|
2
|
+
* `oke docker` / `oke stack` / `oke images pin` / `oke schema` / `oke dev --docker`.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { describe, expect, test } from "bun:test";
|
|
@@ -39,12 +39,10 @@ describe("oke docker CLI", () => {
|
|
|
39
39
|
expect(code).toBe(0);
|
|
40
40
|
expect(result).toBeDefined();
|
|
41
41
|
expect(await Bun.file(join(dir, "docker/Dockerfile")).exists()).toBe(true);
|
|
42
|
-
expect(
|
|
43
|
-
await Bun.file(join(dir, "docker/compose.store.sql.yml")).exists(),
|
|
44
|
-
).toBe(true);
|
|
42
|
+
expect(await Bun.file(join(dir, "docker/compose.store.sql.yml")).exists()).toBe(true);
|
|
45
43
|
const yml = await Bun.file(join(dir, "docker/compose.store.sql.yml")).text();
|
|
46
44
|
expect(yml).not.toContain("test-password-not-in-yaml");
|
|
47
|
-
expect(yml).toContain("
|
|
45
|
+
expect(yml).toContain(".env.docker");
|
|
48
46
|
expect(logs.join("")).toContain("docker/compose.override.yml");
|
|
49
47
|
});
|
|
50
48
|
});
|
|
@@ -65,6 +63,26 @@ describe("oke stack", () => {
|
|
|
65
63
|
expect(out).toContain("postgres");
|
|
66
64
|
expect(await Bun.file(join(dir, "compose.yml")).exists()).toBe(false);
|
|
67
65
|
});
|
|
66
|
+
|
|
67
|
+
test("uses per-project host ports (not raw recipe defaults)", async () => {
|
|
68
|
+
const { stackInstanceId, hostPortForInstance } = await import("../docker/index.ts");
|
|
69
|
+
const dir = await mkdtemp(join(tmpdir(), "oke-cli-stack-ports-"));
|
|
70
|
+
let out = "";
|
|
71
|
+
const code = await runStackPreview({
|
|
72
|
+
cwd: dir,
|
|
73
|
+
images: {
|
|
74
|
+
"channel.email": "axllent/mailpit:v1.22.3",
|
|
75
|
+
},
|
|
76
|
+
write: (t) => {
|
|
77
|
+
out += t;
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
expect(code).toBe(0);
|
|
81
|
+
const id = stackInstanceId(dir);
|
|
82
|
+
const smtp = hostPortForInstance("channel.email", 1025, id);
|
|
83
|
+
expect(out).toContain(`${smtp}:1025`);
|
|
84
|
+
expect(out).not.toContain("1025:1025");
|
|
85
|
+
});
|
|
68
86
|
});
|
|
69
87
|
|
|
70
88
|
describe("oke images pin", () => {
|
|
@@ -149,13 +167,14 @@ describe("oke schema generate", () => {
|
|
|
149
167
|
});
|
|
150
168
|
});
|
|
151
169
|
|
|
152
|
-
describe("oke dev --
|
|
153
|
-
test("plans
|
|
170
|
+
describe("oke dev --docker", () => {
|
|
171
|
+
test("plans docker with postgres and writes nothing on dryRun", async () => {
|
|
154
172
|
const dir = await mkdtemp(join(tmpdir(), "oke-cli-dev-dry-"));
|
|
155
173
|
await Bun.write(join(dir, "src/app.ts"), "export {}\n");
|
|
156
174
|
const { code, plan } = await runDev({
|
|
175
|
+
stdinIsTTY: false,
|
|
157
176
|
cwd: dir,
|
|
158
|
-
|
|
177
|
+
docker: ["store.sql"],
|
|
159
178
|
images,
|
|
160
179
|
credentials,
|
|
161
180
|
dryRun: true,
|
package/src/cli/docker.ts
CHANGED
|
@@ -88,14 +88,22 @@ export async function runDockerDerive(
|
|
|
88
88
|
await writeDerivedFiles(result, outDir, { writeStackEnv: false });
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
const vaultSpec = result.specs.find((s) => s.role === "vault");
|
|
92
|
+
if (vaultSpec) {
|
|
93
|
+
const rel = composeDir === "." ? ".oke/openbao/" : `${composeDir}/../.oke/openbao/`;
|
|
94
|
+
write(
|
|
95
|
+
`oke docker: OpenBao first boot — bring the stack up (e.g. \`oke dev -d\`), and oke ` +
|
|
96
|
+
`will initialize + unseal it once. Root/unseal material stays on the host at ${rel} ` +
|
|
97
|
+
`(0600, gitignored) — back it up; losing it loses every secret permanently.\n`,
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
91
101
|
write(`oke docker: wrote ${result.files.length} file(s) → ${composeDir}/\n`);
|
|
92
102
|
for (const f of result.files) write(` ${composeDir}/${f.path}\n`);
|
|
93
103
|
write(
|
|
94
104
|
`compose merge order (cwd ${composeDir}/):\n${result.composeFiles.map((f) => ` -f ${f}`).join("\n")}\n`,
|
|
95
105
|
);
|
|
96
|
-
write(
|
|
97
|
-
`(${composeDir}/compose.override.yml is layer 4 — user-owned, never written by oke)\n`,
|
|
98
|
-
);
|
|
106
|
+
write(`(${composeDir}/compose.override.yml is layer 4 — user-owned, never written by oke)\n`);
|
|
99
107
|
return { code: 0, result };
|
|
100
108
|
} catch (err) {
|
|
101
109
|
console.error(err instanceof Error ? err.message : String(err));
|
|
@@ -9,10 +9,7 @@ import type { Manifest } from "../manifest/types.ts";
|
|
|
9
9
|
import { parseManifest } from "../manifest/validate.ts";
|
|
10
10
|
import { runDoctorDiff } from "./doctor-diff.ts";
|
|
11
11
|
|
|
12
|
-
const baseUrl = new URL(
|
|
13
|
-
"../manifest/fixtures/base.manifest.json",
|
|
14
|
-
import.meta.url,
|
|
15
|
-
);
|
|
12
|
+
const baseUrl = new URL("../manifest/fixtures/base.manifest.json", import.meta.url);
|
|
16
13
|
|
|
17
14
|
async function loadBase(): Promise<Manifest> {
|
|
18
15
|
return parseManifest(await Bun.file(baseUrl).text());
|
|
@@ -88,4 +85,3 @@ describe("oke doctor --diff", () => {
|
|
|
88
85
|
}
|
|
89
86
|
});
|
|
90
87
|
});
|
|
91
|
-
|
package/src/cli/doctor-diff.ts
CHANGED
|
@@ -34,10 +34,7 @@ export interface DoctorDiffOptions {
|
|
|
34
34
|
* @param cwd - Repo root
|
|
35
35
|
* @param baseBranch - Preferred base
|
|
36
36
|
*/
|
|
37
|
-
readonly resolveMergeBase?: (
|
|
38
|
-
cwd: string,
|
|
39
|
-
baseBranch?: string,
|
|
40
|
-
) => Promise<string | null>;
|
|
37
|
+
readonly resolveMergeBase?: (cwd: string, baseBranch?: string) => Promise<string | null>;
|
|
41
38
|
/**
|
|
42
39
|
* Read a file at a git revision (tests).
|
|
43
40
|
*
|
|
@@ -45,11 +42,7 @@ export interface DoctorDiffOptions {
|
|
|
45
42
|
* @param rev - Commit-ish
|
|
46
43
|
* @param path - Path relative to repo root
|
|
47
44
|
*/
|
|
48
|
-
readonly readAtRevision?: (
|
|
49
|
-
cwd: string,
|
|
50
|
-
rev: string,
|
|
51
|
-
path: string,
|
|
52
|
-
) => Promise<string | null>;
|
|
45
|
+
readonly readAtRevision?: (cwd: string, rev: string, path: string) => Promise<string | null>;
|
|
53
46
|
/** Manifest relative path when using git (default: auto-detect). */
|
|
54
47
|
readonly manifestPath?: string;
|
|
55
48
|
readonly write?: (text: string) => void;
|
|
@@ -67,9 +60,7 @@ export interface DoctorDiffResult {
|
|
|
67
60
|
*
|
|
68
61
|
* @param options - Paths / injections / git helpers
|
|
69
62
|
*/
|
|
70
|
-
export async function runDoctorDiff(
|
|
71
|
-
options: DoctorDiffOptions = {},
|
|
72
|
-
): Promise<DoctorDiffResult> {
|
|
63
|
+
export async function runDoctorDiff(options: DoctorDiffOptions = {}): Promise<DoctorDiffResult> {
|
|
73
64
|
const write = options.write ?? ((t) => process.stdout.write(t));
|
|
74
65
|
const cwd = options.cwd ?? process.cwd();
|
|
75
66
|
|
|
@@ -86,15 +77,11 @@ export async function runDoctorDiff(
|
|
|
86
77
|
return { code: EXIT_OK, undeclared, allChanges: all };
|
|
87
78
|
}
|
|
88
79
|
|
|
89
|
-
write(
|
|
90
|
-
`oke doctor --diff: ${undeclared.length} undeclared contract-breaking change(s)\n`,
|
|
91
|
-
);
|
|
80
|
+
write(`oke doctor --diff: ${undeclared.length} undeclared contract-breaking change(s)\n`);
|
|
92
81
|
for (const c of undeclared) {
|
|
93
82
|
write(` [contract-breaking] ${c.path}: ${c.summary}\n`);
|
|
94
83
|
}
|
|
95
|
-
write(
|
|
96
|
-
"Acknowledge intentional breaks with `breaking: true` on the owning flow.\n",
|
|
97
|
-
);
|
|
84
|
+
write("Acknowledge intentional breaks with `breaking: true` on the owning flow.\n");
|
|
98
85
|
return { code: EXIT_RUNTIME, undeclared, allChanges: all };
|
|
99
86
|
}
|
|
100
87
|
|
|
@@ -125,20 +112,16 @@ async function resolveManifests(
|
|
|
125
112
|
);
|
|
126
113
|
}
|
|
127
114
|
|
|
128
|
-
const rel =
|
|
129
|
-
options.manifestPath ??
|
|
130
|
-
(await detectManifestRel(cwd));
|
|
115
|
+
const rel = options.manifestPath ?? (await detectManifestRel(cwd));
|
|
131
116
|
if (!rel) {
|
|
132
117
|
throw new Error(
|
|
133
118
|
"oke doctor --diff: no oke.manifest.json or manifest.oke.json in cwd — pass --before/--after",
|
|
134
119
|
);
|
|
135
120
|
}
|
|
136
121
|
|
|
137
|
-
const after =
|
|
138
|
-
options.after ?? (await loadManifest(resolve(cwd, rel)));
|
|
122
|
+
const after = options.after ?? (await loadManifest(resolve(cwd, rel)));
|
|
139
123
|
|
|
140
|
-
const resolveBase =
|
|
141
|
-
options.resolveMergeBase ?? gitMergeBase;
|
|
124
|
+
const resolveBase = options.resolveMergeBase ?? gitMergeBase;
|
|
142
125
|
const readAt = options.readAtRevision ?? gitShow;
|
|
143
126
|
const mergeBase = await resolveBase(cwd, options.baseBranch);
|
|
144
127
|
if (!mergeBase) {
|
|
@@ -177,23 +160,18 @@ async function detectManifestRel(cwd: string): Promise<string | null> {
|
|
|
177
160
|
* @param cwd - Repo root
|
|
178
161
|
* @param baseBranch - Preferred base
|
|
179
162
|
*/
|
|
180
|
-
export async function gitMergeBase(
|
|
181
|
-
cwd: string,
|
|
182
|
-
baseBranch?: string,
|
|
183
|
-
): Promise<string | null> {
|
|
163
|
+
export async function gitMergeBase(cwd: string, baseBranch?: string): Promise<string | null> {
|
|
184
164
|
const candidates = baseBranch
|
|
185
165
|
? [baseBranch, ...BASE_BRANCH_CANDIDATES.filter((b) => b !== baseBranch)]
|
|
186
166
|
: [...BASE_BRANCH_CANDIDATES];
|
|
187
167
|
|
|
188
168
|
for (const base of candidates) {
|
|
189
|
-
const proc = Bun.spawn(
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
proc.exited,
|
|
196
|
-
]);
|
|
169
|
+
const proc = Bun.spawn(["git", "merge-base", "HEAD", base], {
|
|
170
|
+
cwd,
|
|
171
|
+
stdout: "pipe",
|
|
172
|
+
stderr: "pipe",
|
|
173
|
+
});
|
|
174
|
+
const [stdout, exitCode] = await Promise.all([new Response(proc.stdout).text(), proc.exited]);
|
|
197
175
|
if (exitCode === 0) {
|
|
198
176
|
const rev = stdout.trim();
|
|
199
177
|
if (rev.length > 0) return rev;
|
|
@@ -209,20 +187,13 @@ export async function gitMergeBase(
|
|
|
209
187
|
* @param rev - Commit-ish
|
|
210
188
|
* @param path - Path relative to repo root
|
|
211
189
|
*/
|
|
212
|
-
export async function gitShow(
|
|
213
|
-
cwd: string,
|
|
214
|
-
rev: string,
|
|
215
|
-
path: string,
|
|
216
|
-
): Promise<string | null> {
|
|
190
|
+
export async function gitShow(cwd: string, rev: string, path: string): Promise<string | null> {
|
|
217
191
|
const proc = Bun.spawn(["git", "show", `${rev}:${path}`], {
|
|
218
192
|
cwd,
|
|
219
193
|
stdout: "pipe",
|
|
220
194
|
stderr: "pipe",
|
|
221
195
|
});
|
|
222
|
-
const [stdout, exitCode] = await Promise.all([
|
|
223
|
-
new Response(proc.stdout).text(),
|
|
224
|
-
proc.exited,
|
|
225
|
-
]);
|
|
196
|
+
const [stdout, exitCode] = await Promise.all([new Response(proc.stdout).text(), proc.exited]);
|
|
226
197
|
if (exitCode !== 0) return null;
|
|
227
198
|
return stdout;
|
|
228
199
|
}
|
package/src/cli/doctor-pii.ts
CHANGED
|
@@ -4,10 +4,7 @@
|
|
|
4
4
|
* Reuses {@link assertAllowPiiForAsk} — does not reimplement matching.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
AiPiiBuildError,
|
|
9
|
-
assertAllowPiiForAsk,
|
|
10
|
-
} from "../elements/ai/pii.ts";
|
|
7
|
+
import { AiPiiBuildError, assertAllowPiiForAsk } from "../elements/ai/pii.ts";
|
|
11
8
|
import type {
|
|
12
9
|
AiPrompt,
|
|
13
10
|
ClassificationValue,
|
|
@@ -23,9 +20,7 @@ import type { DoctorFinding } from "./doctor.ts";
|
|
|
23
20
|
*
|
|
24
21
|
* @param manifest - Extracted Manifest
|
|
25
22
|
*/
|
|
26
|
-
export function checkManifestPiiAsks(
|
|
27
|
-
manifest: Manifest,
|
|
28
|
-
): readonly DoctorFinding[] {
|
|
23
|
+
export function checkManifestPiiAsks(manifest: Manifest): readonly DoctorFinding[] {
|
|
29
24
|
const findings: DoctorFinding[] = [];
|
|
30
25
|
const classifications = collectClassifications(manifest);
|
|
31
26
|
const flows = manifest.flows ?? {};
|
package/src/cli/doctor.test.ts
CHANGED
|
@@ -14,13 +14,12 @@ describe("oke doctor", () => {
|
|
|
14
14
|
ports: [],
|
|
15
15
|
currentSchemaFingerprint: null,
|
|
16
16
|
expectedSchemaFingerprint: undefined,
|
|
17
|
+
skipDbDrift: true,
|
|
17
18
|
write: () => {},
|
|
18
19
|
});
|
|
19
20
|
expect(code).toBe(2);
|
|
20
21
|
expect(findings.some((f) => f.code === "missing_secret")).toBe(true);
|
|
21
|
-
expect(
|
|
22
|
-
findings.find((f) => f.message.includes("STRIPE_KEY")),
|
|
23
|
-
).toBeDefined();
|
|
22
|
+
expect(findings.find((f) => f.message.includes("STRIPE_KEY"))).toBeDefined();
|
|
24
23
|
});
|
|
25
24
|
|
|
26
25
|
test("catches a port conflict", async () => {
|
|
@@ -30,6 +29,7 @@ describe("oke doctor", () => {
|
|
|
30
29
|
isPortInUse: async (p) => p === 6530,
|
|
31
30
|
currentSchemaFingerprint: "abc",
|
|
32
31
|
expectedSchemaFingerprint: "abc",
|
|
32
|
+
skipDbDrift: true,
|
|
33
33
|
write: () => {},
|
|
34
34
|
});
|
|
35
35
|
expect(code).toBe(2);
|
|
@@ -37,17 +37,36 @@ describe("oke doctor", () => {
|
|
|
37
37
|
expect(findings[0]!.message).toContain("6530");
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
-
test("catches schema drift", async () => {
|
|
40
|
+
test("catches core stub schema drift", async () => {
|
|
41
41
|
const { code, findings } = await runDoctor({
|
|
42
42
|
secrets: [],
|
|
43
43
|
ports: [],
|
|
44
44
|
isPortInUse: async () => false,
|
|
45
45
|
expectedSchemaFingerprint: "aaa",
|
|
46
46
|
currentSchemaFingerprint: "bbb",
|
|
47
|
+
skipDbDrift: true,
|
|
47
48
|
write: () => {},
|
|
48
49
|
});
|
|
49
50
|
expect(code).toBe(2);
|
|
50
51
|
expect(findings.some((f) => f.code === "schema_drift")).toBe(true);
|
|
52
|
+
expect(findings.find((f) => f.code === "schema_drift")?.message).toContain(
|
|
53
|
+
"oke schema generate",
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("catches domain db_drift from drizzle-kit probe", async () => {
|
|
58
|
+
const { code, findings } = await runDoctor({
|
|
59
|
+
secrets: [],
|
|
60
|
+
ports: [],
|
|
61
|
+
isPortInUse: async () => false,
|
|
62
|
+
currentSchemaFingerprint: null,
|
|
63
|
+
skipDbDrift: false,
|
|
64
|
+
detectDbDrift: async () => ({ drifted: true, detail: "pending migrations" }),
|
|
65
|
+
write: () => {},
|
|
66
|
+
});
|
|
67
|
+
expect(code).toBe(2);
|
|
68
|
+
expect(findings.some((f) => f.code === "db_drift")).toBe(true);
|
|
69
|
+
expect(findings.find((f) => f.code === "db_drift")?.message).toContain("pending");
|
|
51
70
|
});
|
|
52
71
|
|
|
53
72
|
test("ok when secrets present, ports free, schema matches", async () => {
|
|
@@ -58,6 +77,7 @@ describe("oke doctor", () => {
|
|
|
58
77
|
isPortInUse: async () => false,
|
|
59
78
|
expectedSchemaFingerprint: "same",
|
|
60
79
|
currentSchemaFingerprint: "same",
|
|
80
|
+
skipDbDrift: true,
|
|
61
81
|
write: () => {},
|
|
62
82
|
});
|
|
63
83
|
expect(code).toBe(0);
|
|
@@ -99,6 +119,7 @@ describe("oke doctor", () => {
|
|
|
99
119
|
secrets: [],
|
|
100
120
|
ports: [],
|
|
101
121
|
currentSchemaFingerprint: null,
|
|
122
|
+
skipDbDrift: true,
|
|
102
123
|
write: () => {},
|
|
103
124
|
});
|
|
104
125
|
|
|
@@ -142,6 +163,7 @@ describe("oke doctor", () => {
|
|
|
142
163
|
ports: [],
|
|
143
164
|
expectedSchemaFingerprint: "same",
|
|
144
165
|
currentSchemaFingerprint: "same",
|
|
166
|
+
skipDbDrift: true,
|
|
145
167
|
write: () => {},
|
|
146
168
|
});
|
|
147
169
|
expect(code).toBe(0);
|
package/src/cli/doctor.ts
CHANGED
|
@@ -20,6 +20,7 @@ export interface DoctorFinding {
|
|
|
20
20
|
| "missing_secret"
|
|
21
21
|
| "port_conflict"
|
|
22
22
|
| "schema_drift"
|
|
23
|
+
| "db_drift"
|
|
23
24
|
| "tenancy"
|
|
24
25
|
| "driver"
|
|
25
26
|
| "pii_ask";
|
|
@@ -44,6 +45,16 @@ export interface DoctorOptions {
|
|
|
44
45
|
readonly expectedSchemaFingerprint?: string;
|
|
45
46
|
/** Current schema fingerprint (tests). */
|
|
46
47
|
readonly currentSchemaFingerprint?: string | null;
|
|
48
|
+
/**
|
|
49
|
+
* Inject domain DB drift probe (tests). When unset, runs drizzle-kit
|
|
50
|
+
* push explain when `drizzle.config.ts` exists.
|
|
51
|
+
*/
|
|
52
|
+
readonly detectDbDrift?: () => Promise<{
|
|
53
|
+
readonly drifted: boolean;
|
|
54
|
+
readonly detail?: string;
|
|
55
|
+
}>;
|
|
56
|
+
/** Skip live DB drift probe (default false). */
|
|
57
|
+
readonly skipDbDrift?: boolean;
|
|
47
58
|
readonly write?: (text: string) => void;
|
|
48
59
|
/** Write hints / progress (defaults to stderr). */
|
|
49
60
|
readonly writeErr?: (text: string) => void;
|
|
@@ -79,9 +90,7 @@ export async function runDoctor(options: DoctorOptions = {}): Promise<{
|
|
|
79
90
|
}
|
|
80
91
|
|
|
81
92
|
const env = options.env ?? ((k) => Bun.env[k] ?? process.env[k]);
|
|
82
|
-
const secretNames =
|
|
83
|
-
options.secrets ??
|
|
84
|
-
(manifest?.vault ? Object.keys(manifest.vault) : []);
|
|
93
|
+
const secretNames = options.secrets ?? (manifest?.vault ? Object.keys(manifest.vault) : []);
|
|
85
94
|
|
|
86
95
|
for (const name of secretNames) {
|
|
87
96
|
const value = env(name);
|
|
@@ -90,9 +99,7 @@ export async function runDoctor(options: DoctorOptions = {}): Promise<{
|
|
|
90
99
|
findings.push({
|
|
91
100
|
code: "missing_secret",
|
|
92
101
|
severity: "error",
|
|
93
|
-
message: description
|
|
94
|
-
? `missing secret ${name}: ${description}`
|
|
95
|
-
: `missing secret ${name}`,
|
|
102
|
+
message: description ? `missing secret ${name}: ${description}` : `missing secret ${name}`,
|
|
96
103
|
});
|
|
97
104
|
}
|
|
98
105
|
}
|
|
@@ -120,24 +127,42 @@ export async function runDoctor(options: DoctorOptions = {}): Promise<{
|
|
|
120
127
|
options.currentSchemaFingerprint !== undefined
|
|
121
128
|
) {
|
|
122
129
|
const expected =
|
|
123
|
-
options.expectedSchemaFingerprint ??
|
|
124
|
-
(await schemaFingerprint(cwd).catch(() => null));
|
|
130
|
+
options.expectedSchemaFingerprint ?? (await schemaFingerprint(cwd).catch(() => null));
|
|
125
131
|
if (expected !== null && current !== null && expected !== current) {
|
|
126
132
|
findings.push({
|
|
127
133
|
code: "schema_drift",
|
|
128
134
|
severity: "error",
|
|
129
135
|
message:
|
|
130
|
-
"schema drift
|
|
136
|
+
"core stub schema drift — run `oke schema generate` (schema/oke.ts; not domain migrations)",
|
|
131
137
|
});
|
|
132
138
|
} else if (expected !== null && current === null) {
|
|
133
139
|
findings.push({
|
|
134
140
|
code: "schema_drift",
|
|
135
141
|
severity: "error",
|
|
136
|
-
message: "schema/oke.ts missing — run `oke schema generate`",
|
|
142
|
+
message: "schema/oke.ts missing — run `oke schema generate` (core/plugin stubs)",
|
|
137
143
|
});
|
|
138
144
|
}
|
|
139
145
|
}
|
|
140
146
|
|
|
147
|
+
// Domain schema ↔ live DB — drizzle-kit is the single source of truth.
|
|
148
|
+
if (!options.skipDbDrift) {
|
|
149
|
+
const drizzleConfig = Bun.file(resolve(cwd, "drizzle.config.ts"));
|
|
150
|
+
if (options.detectDbDrift || (await drizzleConfig.exists())) {
|
|
151
|
+
const { detectDbDrift } = await import("./db.ts");
|
|
152
|
+
const probe = options.detectDbDrift ?? (() => detectDbDrift({ cwd }));
|
|
153
|
+
const drift = await probe();
|
|
154
|
+
if (drift.drifted) {
|
|
155
|
+
findings.push({
|
|
156
|
+
code: "db_drift",
|
|
157
|
+
severity: "error",
|
|
158
|
+
message:
|
|
159
|
+
drift.detail ??
|
|
160
|
+
"domain schema differs from the database — run `oke db generate` then `oke db migrate` (or `oke db push` in local)",
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
141
166
|
if (manifest?.tenancy?.isolation) {
|
|
142
167
|
// Structural tenancy check is compile-time; doctor warns when isolation
|
|
143
168
|
// is set but no tenant resolver string is recorded on the Manifest.
|
|
@@ -205,4 +230,3 @@ Verify secrets, ports, schema drift, and PII→model egress before serving.
|
|
|
205
230
|
const { code } = await runDoctor({ manifestPath, json });
|
|
206
231
|
return code;
|
|
207
232
|
}
|
|
208
|
-
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* drizzle-kit env resolution — dialect from configured driver, not URL sniffing.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { afterEach, describe, expect, test } from "bun:test";
|
|
6
|
+
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
7
|
+
import { tmpdir } from "node:os";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import type { OkeConfig } from "../config/index.ts";
|
|
10
|
+
import { resolveDrizzleKitEnv } from "./drizzle-env.ts";
|
|
11
|
+
|
|
12
|
+
const dirs: string[] = [];
|
|
13
|
+
|
|
14
|
+
afterEach(async () => {
|
|
15
|
+
await Promise.all(dirs.splice(0).map((d) => rm(d, { recursive: true, force: true })));
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
async function tempDir(): Promise<string> {
|
|
19
|
+
const dir = await mkdtemp(join(tmpdir(), "oke-drizzle-env-"));
|
|
20
|
+
dirs.push(dir);
|
|
21
|
+
return dir;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const dualConfig = {
|
|
25
|
+
drivers: {
|
|
26
|
+
store: {
|
|
27
|
+
sql: { local: "sqlite", docker: "postgres", prod: "postgres", test: "memory" },
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
} as unknown as OkeConfig;
|
|
31
|
+
|
|
32
|
+
describe("resolveDrizzleKitEnv", () => {
|
|
33
|
+
test("local env → sqlite dialect + sqlite url", async () => {
|
|
34
|
+
const dir = await tempDir();
|
|
35
|
+
const ctx = await resolveDrizzleKitEnv(dir, dualConfig, "local");
|
|
36
|
+
expect(ctx.dialect).toBe("sqlite");
|
|
37
|
+
expect(ctx.overlay.OKE_DRIZZLE_DIALECT).toBe("sqlite");
|
|
38
|
+
expect(ctx.overlay.OKE_SQLITE_URL).toContain(".oke/app.sqlite");
|
|
39
|
+
expect(ctx.overlay.DATABASE_URL).toBeUndefined();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("docker env → postgresql dialect + DATABASE_URL from compose env", async () => {
|
|
43
|
+
const dir = await tempDir();
|
|
44
|
+
await mkdir(join(dir, "docker"), { recursive: true });
|
|
45
|
+
await writeFile(
|
|
46
|
+
join(dir, "docker", ".env.docker"),
|
|
47
|
+
"DATABASE_URL=postgres://u:p@127.0.0.1:5432/oke\n",
|
|
48
|
+
);
|
|
49
|
+
const ctx = await resolveDrizzleKitEnv(dir, dualConfig, "docker");
|
|
50
|
+
expect(ctx.dialect).toBe("postgresql");
|
|
51
|
+
expect(ctx.overlay.OKE_DRIZZLE_DIALECT).toBe("postgresql");
|
|
52
|
+
expect(ctx.overlay.DATABASE_URL).toBe("postgres://u:p@127.0.0.1:5432/oke");
|
|
53
|
+
expect(ctx.overlay.OKE_SQLITE_URL).toBeUndefined();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("docker dialect is postgresql even when DATABASE_URL unset (no URL guessing)", async () => {
|
|
57
|
+
const dir = await tempDir();
|
|
58
|
+
const ctx = await resolveDrizzleKitEnv(dir, dualConfig, "docker");
|
|
59
|
+
expect(ctx.dialect).toBe("postgresql");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("unsupported driver id errors clearly", async () => {
|
|
63
|
+
const dir = await tempDir();
|
|
64
|
+
const bad = { drivers: { store: { sql: { local: "memory" } } } } as unknown as OkeConfig;
|
|
65
|
+
await expect(resolveDrizzleKitEnv(dir, bad, "local")).rejects.toThrow(/not supported/);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* drizzle-kit child-env overlay — resolved from the configured `store.sql`
|
|
3
|
+
* driver for the active env (never guessed from `DATABASE_URL` presence).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { resolveDriverId, type ConfigEnv, type OkeConfig } from "../config/index.ts";
|
|
7
|
+
import {
|
|
8
|
+
drizzleDialectFromSqlDriver,
|
|
9
|
+
type OkeDrizzleKitDialect,
|
|
10
|
+
} from "../drivers/drizzle-dialect.ts";
|
|
11
|
+
import { parseDotenv } from "../drivers/vault-dotenv-parse.ts";
|
|
12
|
+
import { resolveComposeEnvPath } from "../elements/vault/chain.ts";
|
|
13
|
+
|
|
14
|
+
/** Resolved drizzle env context for one project env. */
|
|
15
|
+
export interface DrizzleKitEnvContext {
|
|
16
|
+
/** Active env used for driver resolution. */
|
|
17
|
+
readonly env: ConfigEnv;
|
|
18
|
+
/** drizzle-kit dialect (from `SQL_DRIVER_TO_DRIZZLE_DIALECT`). */
|
|
19
|
+
readonly dialect: OkeDrizzleKitDialect;
|
|
20
|
+
/** Env overlay for the drizzle-kit child process. */
|
|
21
|
+
readonly overlay: Record<string, string>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Load `docker/.env.docker` (or legacy `.env.docker`) as a name→value map.
|
|
26
|
+
*
|
|
27
|
+
* @param cwd - Project root
|
|
28
|
+
*/
|
|
29
|
+
async function readComposeEnv(cwd: string): Promise<Map<string, string>> {
|
|
30
|
+
const { path } = resolveComposeEnvPath(cwd);
|
|
31
|
+
const file = Bun.file(path);
|
|
32
|
+
if (!(await file.exists())) return new Map();
|
|
33
|
+
try {
|
|
34
|
+
return parseDotenv(await file.text());
|
|
35
|
+
} catch {
|
|
36
|
+
return new Map();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Resolve the drizzle-kit env context for a project + env.
|
|
42
|
+
*
|
|
43
|
+
* Dialect comes from the configured driver via the exhaustive
|
|
44
|
+
* `SQL_DRIVER_TO_DRIZZLE_DIALECT` map — a missing/unsupported driver id is a
|
|
45
|
+
* compile-time gap there, and a clear runtime error here (never a silent
|
|
46
|
+
* sqlite fallback).
|
|
47
|
+
*
|
|
48
|
+
* @param cwd - Project root
|
|
49
|
+
* @param config - Loaded `oke.config.ts` (null → sqlite/local defaults)
|
|
50
|
+
* @param env - Active env (`local` | `docker` for dev tooling)
|
|
51
|
+
*/
|
|
52
|
+
export async function resolveDrizzleKitEnv(
|
|
53
|
+
cwd: string,
|
|
54
|
+
config: OkeConfig | null | undefined,
|
|
55
|
+
env: ConfigEnv,
|
|
56
|
+
): Promise<DrizzleKitEnvContext> {
|
|
57
|
+
const driverId = resolveDriverId(config?.drivers?.store?.sql, env) ?? "sqlite";
|
|
58
|
+
if (driverId !== "sqlite" && driverId !== "postgres") {
|
|
59
|
+
throw new Error(
|
|
60
|
+
`oke db: store.sql driver "${driverId}" is not supported by drizzle-kit (sqlite | postgres)`,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
const dialect = drizzleDialectFromSqlDriver(driverId);
|
|
64
|
+
|
|
65
|
+
const compose = env === "docker" ? await readComposeEnv(cwd) : new Map<string, string>();
|
|
66
|
+
|
|
67
|
+
const overlay: Record<string, string> = { OKE_DRIZZLE_DIALECT: dialect };
|
|
68
|
+
if (dialect === "postgresql") {
|
|
69
|
+
const url =
|
|
70
|
+
process.env.DATABASE_URL ?? compose.get("DATABASE_URL") ?? compose.get("OKE_STORE_SQL_URL");
|
|
71
|
+
if (url !== undefined) overlay.DATABASE_URL = url;
|
|
72
|
+
} else {
|
|
73
|
+
const url =
|
|
74
|
+
process.env.OKE_SQLITE_URL ?? compose.get("OKE_SQLITE_URL") ?? "file:.oke/app.sqlite";
|
|
75
|
+
overlay.OKE_SQLITE_URL = url;
|
|
76
|
+
}
|
|
77
|
+
return { env, dialect, overlay };
|
|
78
|
+
}
|