okengine 0.2.6 → 0.2.8
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 +24 -23
- package/README.md +52 -346
- package/docs/spec/console.md +165 -142
- package/docs/spec/example.md +490 -312
- package/docs/spec/four-applications.md +495 -314
- package/docs/spec/unified-theory.md +184 -175
- package/package.json +45 -37
- package/spec/manifest.v1.schema.json +40 -9
- package/src/auth/api-keys.ts +2 -5
- package/src/auth/attenuation.ts +2 -6
- package/src/auth/auth.test.ts +53 -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 +386 -0
- package/src/cli/dev-app-runner.ts +2 -8
- package/src/cli/dev-db-push.test.ts +163 -0
- package/src/cli/dev-mode.test.ts +45 -0
- package/src/cli/dev-mode.ts +78 -0
- package/src/cli/dev.test.ts +148 -21
- package/src/cli/dev.ts +208 -134
- package/src/cli/doc-drift.test.ts +3 -2
- package/src/cli/doc-drift.ts +21 -50
- package/src/cli/doc-staleness.test.ts +69 -0
- package/src/cli/docker-cli.test.ts +7 -8
- package/src/cli/docker.ts +1 -3
- package/src/cli/doctor-diff-examples.ts +1 -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/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 +41 -47
- package/src/cli/mcp-from-console.ts +1 -4
- package/src/cli/mode.ts +45 -0
- package/src/cli/ports.test.ts +4 -13
- package/src/cli/ports.ts +1 -3
- package/src/cli/privacy-erase.ts +1 -3
- package/src/cli/registry.ts +75 -25
- package/src/cli/schema.ts +3 -10
- package/src/cli/stack.ts +2 -7
- package/src/cli/start.ts +4 -15
- package/src/cli/upgrade.ts +1 -4
- 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 +8 -29
- 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 +96 -30
- package/src/compiler/extract.ts +362 -156
- package/src/compiler/fixtures/skyport/oke.config.ts +1 -1
- 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 +4 -7
- package/src/compiler/sucrose.ts +11 -31
- package/src/config/define-config.test.ts +57 -34
- package/src/config/index.ts +181 -37
- 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 +14 -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 +23 -60
- 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 +112 -20
- package/src/docker/derive.ts +5 -19
- package/src/docker/docker.test.ts +15 -15
- package/src/docker/dockerfile.integration.test.ts +12 -21
- package/src/docker/helpers.ts +5 -4
- package/src/docker/index.ts +4 -11
- package/src/docker/pin.ts +1 -9
- package/src/docker/recipes/index.ts +5 -6
- package/src/docker/recipes/mailpit.ts +22 -0
- package/src/docker/recipes/postgres.ts +17 -6
- package/src/docker/recipes/redis.ts +6 -1
- package/src/docker/recipes/rustfs.ts +33 -0
- package/src/docker/stack-id.test.ts +33 -0
- package/src/docker/stack-id.ts +25 -13
- package/src/docker/stack.integration.test.ts +6 -21
- package/src/docker/types.ts +13 -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/fs.ts +2 -8
- package/src/drivers/index.ts +12 -56
- package/src/drivers/memory.ts +14 -41
- 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 +5 -17
- 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-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.ts +1 -5
- package/src/drivers/vault-sops.ts +10 -35
- package/src/drivers/vault-types.ts +1 -7
- 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 +8 -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/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.ts +11 -21
- package/src/elements/store/sql-session.test.ts +50 -0
- package/src/elements/store/sql-session.ts +60 -63
- package/src/elements/store/table.ts +35 -19
- package/src/elements/store.test.ts +17 -39
- package/src/elements/store.ts +37 -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 +18 -32
- package/src/elements/vault.test.ts +12 -28
- package/src/elements/vault.ts +8 -12
- package/src/index.ts +5 -2
- package/src/kernel/adopt-routes.ts +15 -29
- package/src/kernel/app.ts +34 -94
- package/src/kernel/auth-resolve.ts +2 -9
- package/src/kernel/boot-bind/ai.ts +1 -4
- package/src/kernel/boot-bind/channel.ts +2 -8
- 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 +17 -17
- package/src/kernel/boot-bind/store.ts +44 -50
- package/src/kernel/boot-bind/vault.ts +2 -8
- package/src/kernel/boot.test.ts +4 -9
- package/src/kernel/boot.ts +29 -76
- 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/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 +5 -25
- package/src/kernel/fx.test.ts +15 -44
- package/src/kernel/fx.ts +27 -79
- package/src/kernel/hook-timing.test.ts +3 -6
- package/src/kernel/hook-timing.ts +5 -14
- package/src/kernel/hooks.test.ts +10 -10
- package/src/kernel/hooks.ts +3 -12
- package/src/kernel/index.ts +4 -17
- package/src/kernel/journal.ts +7 -31
- package/src/kernel/on.ts +1 -6
- 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 +48 -24
- package/src/kernel/registry.ts +80 -29
- 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 +4 -21
- package/src/manifest/diff.test.ts +26 -91
- package/src/manifest/diff.ts +95 -225
- package/src/manifest/index.ts +2 -9
- package/src/manifest/types.ts +29 -5
- 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 +4 -14
- 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/node-import-scan.ts +2 -5
- 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 +15 -43
- 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 +13 -31
- 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/src/console/ui/dist/assets/panel-vault-BbfWdox0.js +0 -1
package/src/compiler/extract.ts
CHANGED
|
@@ -15,6 +15,7 @@ import type {
|
|
|
15
15
|
AiPrompt,
|
|
16
16
|
Channel,
|
|
17
17
|
Clock,
|
|
18
|
+
DeclaredColumn,
|
|
18
19
|
Effects,
|
|
19
20
|
Flow,
|
|
20
21
|
Gate,
|
|
@@ -66,6 +67,11 @@ interface ProjectScope {
|
|
|
66
67
|
bindings: Map<string, InferBinding>;
|
|
67
68
|
signals: Record<string, Signal>;
|
|
68
69
|
stores: Record<string, Store>;
|
|
70
|
+
/** Binding or table name → declared columns from `store.schema.table`. */
|
|
71
|
+
schemaTables: Map<
|
|
72
|
+
string,
|
|
73
|
+
{ readonly name: string; readonly columns: Record<string, DeclaredColumn> }
|
|
74
|
+
>;
|
|
69
75
|
clocks: Record<string, Clock>;
|
|
70
76
|
gates: Record<string, Gate>;
|
|
71
77
|
/** Local binding name → gate manifest id (policy name or rate expression). */
|
|
@@ -89,9 +95,7 @@ interface ProjectScope {
|
|
|
89
95
|
*
|
|
90
96
|
* @param options - Root directory and/or explicit files
|
|
91
97
|
*/
|
|
92
|
-
export async function extractManifest(
|
|
93
|
-
options: ExtractManifestOptions = {},
|
|
94
|
-
): Promise<Manifest> {
|
|
98
|
+
export async function extractManifest(options: ExtractManifestOptions = {}): Promise<Manifest> {
|
|
95
99
|
const files = options.files
|
|
96
100
|
? [...options.files]
|
|
97
101
|
: await readSources(options.rootDir ?? ".", options.glob ?? "**/*.{ts,tsx}");
|
|
@@ -101,6 +105,7 @@ export async function extractManifest(
|
|
|
101
105
|
bindings: new Map(),
|
|
102
106
|
signals: {},
|
|
103
107
|
stores: {},
|
|
108
|
+
schemaTables: new Map(),
|
|
104
109
|
clocks: {},
|
|
105
110
|
gates: {},
|
|
106
111
|
gateIds: new Map(),
|
|
@@ -191,10 +196,7 @@ export async function extractFromSources(
|
|
|
191
196
|
return extractManifest({ files, app });
|
|
192
197
|
}
|
|
193
198
|
|
|
194
|
-
async function readSources(
|
|
195
|
-
rootDir: string,
|
|
196
|
-
pattern: string,
|
|
197
|
-
): Promise<SourceFile[]> {
|
|
199
|
+
async function readSources(rootDir: string, pattern: string): Promise<SourceFile[]> {
|
|
198
200
|
// Bun.Glob (global) — bare `import … from "bun"` is rejected by JSR.
|
|
199
201
|
const glob = new Bun.Glob(pattern);
|
|
200
202
|
const files: SourceFile[] = [];
|
|
@@ -273,13 +275,304 @@ function finalizeRefs(scope: ProjectScope): void {
|
|
|
273
275
|
(id) => scope.flowExports.get(id) ?? scope.bindings.get(id)?.ref ?? id,
|
|
274
276
|
);
|
|
275
277
|
}
|
|
278
|
+
|
|
279
|
+
// Merge declared columns into store.tables (handles declare-after-sql order).
|
|
280
|
+
for (const store of Object.values(scope.stores)) {
|
|
281
|
+
if (!store.tables) continue;
|
|
282
|
+
for (const [name, table] of Object.entries(store.tables)) {
|
|
283
|
+
const declared = [...scope.schemaTables.values()].find((t) => t.name === name);
|
|
284
|
+
if (!declared) continue;
|
|
285
|
+
const existing = table.columns ?? {};
|
|
286
|
+
if (Object.keys(existing).length === 0) {
|
|
287
|
+
store.tables[name] = { ...table, columns: declared.columns };
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Orphan abstract tables (declared but not wired via store.sql schema):
|
|
293
|
+
// attach under the first sql store, or create a synthetic "app" sql store.
|
|
294
|
+
const attachedNames = new Set<string>();
|
|
295
|
+
for (const store of Object.values(scope.stores)) {
|
|
296
|
+
if (!store.tables) continue;
|
|
297
|
+
for (const name of Object.keys(store.tables)) attachedNames.add(name);
|
|
298
|
+
}
|
|
299
|
+
const orphanByName = new Map<string, { name: string; columns: Record<string, DeclaredColumn> }>();
|
|
300
|
+
for (const t of scope.schemaTables.values()) {
|
|
301
|
+
if (!attachedNames.has(t.name)) orphanByName.set(t.name, t);
|
|
302
|
+
}
|
|
303
|
+
if (orphanByName.size > 0) {
|
|
304
|
+
let target = Object.entries(scope.stores).find(([, s]) => s.facet === "sql")?.[1];
|
|
305
|
+
if (!target) {
|
|
306
|
+
scope.stores.app = scope.stores.app ?? { facet: "sql" };
|
|
307
|
+
target = scope.stores.app!;
|
|
308
|
+
}
|
|
309
|
+
target.tables = target.tables ?? {};
|
|
310
|
+
for (const t of orphanByName.values()) {
|
|
311
|
+
if (target.tables[t.name]) continue;
|
|
312
|
+
target.tables[t.name] = { columns: t.columns };
|
|
313
|
+
}
|
|
314
|
+
}
|
|
276
315
|
}
|
|
277
316
|
|
|
278
|
-
function
|
|
279
|
-
call
|
|
280
|
-
|
|
317
|
+
function collectSchemaTable(call: CallExpression, program: AstNode, scope: ProjectScope): void {
|
|
318
|
+
const tableName = stringArg(call.arguments[0]);
|
|
319
|
+
if (!tableName) return;
|
|
320
|
+
const colsNode = objectArg(call.arguments[1]);
|
|
321
|
+
const columns = colsNode ? parseDeclaredColumns(colsNode) : {};
|
|
322
|
+
const entry = { name: tableName, columns };
|
|
323
|
+
scope.schemaTables.set(tableName, entry);
|
|
324
|
+
const bindingName = enclosingConstName(call, program);
|
|
325
|
+
if (bindingName) scope.schemaTables.set(bindingName, entry);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function attachSchemaOption(
|
|
329
|
+
optsNode: AstNode | undefined,
|
|
330
|
+
store: Store,
|
|
281
331
|
scope: ProjectScope,
|
|
282
332
|
): void {
|
|
333
|
+
const opts = objectArg(optsNode);
|
|
334
|
+
if (!opts) return;
|
|
335
|
+
const schemaNode = objectProp(opts, "schema");
|
|
336
|
+
if (!schemaNode) return;
|
|
337
|
+
|
|
338
|
+
// schema: { notes } or schema: { notes: store.schema.table(...) }
|
|
339
|
+
if (schemaNode.type === "ObjectExpression") {
|
|
340
|
+
store.tables = store.tables ?? {};
|
|
341
|
+
for (const prop of objectProperties(schemaNode)) {
|
|
342
|
+
const key = propKey(prop);
|
|
343
|
+
const value = (prop as AstNode & { value?: AstNode }).value;
|
|
344
|
+
if (!key || !value) continue;
|
|
345
|
+
|
|
346
|
+
if (value.type === "Identifier") {
|
|
347
|
+
const id = (value as Identifier).name;
|
|
348
|
+
const declared = scope.schemaTables.get(id) ?? scope.schemaTables.get(key);
|
|
349
|
+
if (declared) {
|
|
350
|
+
store.tables[declared.name] = { columns: declared.columns };
|
|
351
|
+
} else {
|
|
352
|
+
store.tables[key] = store.tables[key] ?? {};
|
|
353
|
+
}
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (value.type === "CallExpression") {
|
|
358
|
+
const inline = parseInlineSchemaTable(value as CallExpression);
|
|
359
|
+
if (inline) {
|
|
360
|
+
store.tables[inline.name] = { columns: inline.columns };
|
|
361
|
+
scope.schemaTables.set(inline.name, inline);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// schema: notesModule (identifier — unknown shape; skip columns)
|
|
369
|
+
if (schemaNode.type === "Identifier") {
|
|
370
|
+
// Namespace import — table names unknown at extract time.
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function parseInlineSchemaTable(
|
|
375
|
+
call: CallExpression,
|
|
376
|
+
): { name: string; columns: Record<string, DeclaredColumn> } | undefined {
|
|
377
|
+
const callee = call.callee;
|
|
378
|
+
if (callee.type !== "MemberExpression") return undefined;
|
|
379
|
+
const member = callee as AstNode & { object: AstNode; property: AstNode };
|
|
380
|
+
if (identifierName(member.property) !== "table") return undefined;
|
|
381
|
+
if (member.object.type !== "MemberExpression") return undefined;
|
|
382
|
+
const inner = member.object as AstNode & { object: AstNode; property: AstNode };
|
|
383
|
+
if (identifierName(inner.object) !== "store" || identifierName(inner.property) !== "schema") {
|
|
384
|
+
return undefined;
|
|
385
|
+
}
|
|
386
|
+
const tableName = stringArg(call.arguments[0]);
|
|
387
|
+
if (!tableName) return undefined;
|
|
388
|
+
const colsNode = objectArg(call.arguments[1]);
|
|
389
|
+
return {
|
|
390
|
+
name: tableName,
|
|
391
|
+
columns: colsNode ? parseDeclaredColumns(colsNode) : {},
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function parseDeclaredColumns(obj: AstNode): Record<string, DeclaredColumn> {
|
|
396
|
+
const out: Record<string, DeclaredColumn> = {};
|
|
397
|
+
for (const prop of objectProperties(obj)) {
|
|
398
|
+
const key = propKey(prop);
|
|
399
|
+
const value = (prop as AstNode & { value?: AstNode }).value;
|
|
400
|
+
if (!key || !value) continue;
|
|
401
|
+
const col = parseFieldChain(value, key);
|
|
402
|
+
if (col) out[key] = col;
|
|
403
|
+
}
|
|
404
|
+
return out;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Walk `field.text().notNull().pii()` (and similar) into a DeclaredColumn.
|
|
409
|
+
*
|
|
410
|
+
* @param node - AST node for the column value
|
|
411
|
+
* @param key - JS key (for default sqlName)
|
|
412
|
+
*/
|
|
413
|
+
function parseFieldChain(node: AstNode, key: string): DeclaredColumn | undefined {
|
|
414
|
+
const chain: string[] = [];
|
|
415
|
+
let sqlType: "text" | "integer" | undefined;
|
|
416
|
+
let sqlName: string | undefined;
|
|
417
|
+
let defaultValue: string | number | boolean | null | undefined;
|
|
418
|
+
let hasDefault = false;
|
|
419
|
+
let cur: AstNode | undefined = node;
|
|
420
|
+
|
|
421
|
+
while (cur && cur.type === "CallExpression") {
|
|
422
|
+
const call = cur as CallExpression;
|
|
423
|
+
const callee = call.callee;
|
|
424
|
+
if (callee.type === "MemberExpression") {
|
|
425
|
+
const member = callee as AstNode & { object: AstNode; property: AstNode };
|
|
426
|
+
const method = identifierName(member.property);
|
|
427
|
+
if (method) {
|
|
428
|
+
chain.push(method);
|
|
429
|
+
if (method === "as") {
|
|
430
|
+
sqlName = stringArg(call.arguments[0]) ?? sqlName;
|
|
431
|
+
}
|
|
432
|
+
if (method === "default") {
|
|
433
|
+
const lit = call.arguments[0];
|
|
434
|
+
if (lit && lit.type === "Literal") {
|
|
435
|
+
const v = (lit as Literal).value;
|
|
436
|
+
if (
|
|
437
|
+
v === null ||
|
|
438
|
+
typeof v === "string" ||
|
|
439
|
+
typeof v === "number" ||
|
|
440
|
+
typeof v === "boolean"
|
|
441
|
+
) {
|
|
442
|
+
defaultValue = v as string | number | boolean | null;
|
|
443
|
+
hasDefault = true;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
cur = member.object;
|
|
449
|
+
continue;
|
|
450
|
+
}
|
|
451
|
+
if (callee.type === "Identifier" && (callee as Identifier).name === "field") {
|
|
452
|
+
// shouldn't happen — field.text() is MemberExpression
|
|
453
|
+
break;
|
|
454
|
+
}
|
|
455
|
+
break;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// Remaining should be field.text / field.integer
|
|
459
|
+
if (cur && cur.type === "MemberExpression") {
|
|
460
|
+
const member = cur as AstNode & { object: AstNode; property: AstNode };
|
|
461
|
+
if (identifierName(member.object) === "field") {
|
|
462
|
+
const t = identifierName(member.property);
|
|
463
|
+
if (t === "text" || t === "integer") sqlType = t;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Also: field.text() ends as CallExpression with callee MemberExpression field.text
|
|
468
|
+
if (!sqlType && node.type === "CallExpression") {
|
|
469
|
+
// Re-walk to find field.text() / field.integer() as a call
|
|
470
|
+
let probe: AstNode | undefined = node;
|
|
471
|
+
while (probe && probe.type === "CallExpression") {
|
|
472
|
+
const call = probe as CallExpression;
|
|
473
|
+
const callee = call.callee;
|
|
474
|
+
if (callee.type === "MemberExpression") {
|
|
475
|
+
const member = callee as AstNode & { object: AstNode; property: AstNode };
|
|
476
|
+
if (
|
|
477
|
+
identifierName(member.object) === "field" &&
|
|
478
|
+
(identifierName(member.property) === "text" ||
|
|
479
|
+
identifierName(member.property) === "integer")
|
|
480
|
+
) {
|
|
481
|
+
sqlType = identifierName(member.property) as "text" | "integer";
|
|
482
|
+
break;
|
|
483
|
+
}
|
|
484
|
+
probe = member.object;
|
|
485
|
+
continue;
|
|
486
|
+
}
|
|
487
|
+
break;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
if (!sqlType) return undefined;
|
|
492
|
+
|
|
493
|
+
const methods = new Set(chain);
|
|
494
|
+
const col: DeclaredColumn = {
|
|
495
|
+
type: sqlType,
|
|
496
|
+
sqlName: sqlName ?? camelToSnakeKey(key),
|
|
497
|
+
nullable: !(methods.has("notNull") || methods.has("primaryKey")),
|
|
498
|
+
...(methods.has("primaryKey") ? { primaryKey: true } : {}),
|
|
499
|
+
...(methods.has("unique") ? { unique: true } : {}),
|
|
500
|
+
...(hasDefault ? { default: defaultValue ?? null } : {}),
|
|
501
|
+
...(methods.has("pii") ? { pii: true } : {}),
|
|
502
|
+
...(methods.has("sensitive") ? { sensitive: true } : {}),
|
|
503
|
+
};
|
|
504
|
+
if (methods.has("retain")) {
|
|
505
|
+
// retain("7y") — find the call in the original chain by re-walk
|
|
506
|
+
let probe: AstNode | undefined = node;
|
|
507
|
+
while (probe && probe.type === "CallExpression") {
|
|
508
|
+
const call = probe as CallExpression;
|
|
509
|
+
const callee = call.callee;
|
|
510
|
+
if (callee.type === "MemberExpression") {
|
|
511
|
+
const member = callee as AstNode & { object: AstNode; property: AstNode };
|
|
512
|
+
if (identifierName(member.property) === "retain") {
|
|
513
|
+
const dur = stringArg(call.arguments[0]);
|
|
514
|
+
if (dur) col.retain = dur;
|
|
515
|
+
break;
|
|
516
|
+
}
|
|
517
|
+
probe = member.object;
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
break;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
if (methods.has("references")) {
|
|
524
|
+
// .references(() => links.code) — record table.column when statically readable
|
|
525
|
+
let probe: AstNode | undefined = node;
|
|
526
|
+
while (probe && probe.type === "CallExpression") {
|
|
527
|
+
const call = probe as CallExpression;
|
|
528
|
+
const callee = call.callee;
|
|
529
|
+
if (callee.type === "MemberExpression") {
|
|
530
|
+
const member = callee as AstNode & { object: AstNode; property: AstNode };
|
|
531
|
+
if (identifierName(member.property) === "references") {
|
|
532
|
+
const ref = parseReferencesArg(call.arguments[0]);
|
|
533
|
+
if (ref) col.references = ref;
|
|
534
|
+
break;
|
|
535
|
+
}
|
|
536
|
+
probe = member.object;
|
|
537
|
+
continue;
|
|
538
|
+
}
|
|
539
|
+
break;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
return col;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Parse `.references(() => table.column)` into a Manifest reference.
|
|
547
|
+
*
|
|
548
|
+
* @param arg - First argument to `.references(...)`
|
|
549
|
+
*/
|
|
550
|
+
function parseReferencesArg(
|
|
551
|
+
arg: AstNode | undefined,
|
|
552
|
+
): { table?: string; column?: string } | undefined {
|
|
553
|
+
if (!arg) return undefined;
|
|
554
|
+
// ArrowFunctionExpression: () => links.code
|
|
555
|
+
if (arg.type === "ArrowFunctionExpression" || arg.type === "FunctionExpression") {
|
|
556
|
+
const fn = arg as AstNode & { body: AstNode };
|
|
557
|
+
const body = fn.body;
|
|
558
|
+
if (body.type === "MemberExpression") {
|
|
559
|
+
const member = body as AstNode & { object: AstNode; property: AstNode };
|
|
560
|
+
const table = identifierName(member.object);
|
|
561
|
+
const column = identifierName(member.property);
|
|
562
|
+
if (table || column) return { ...(table ? { table } : {}), ...(column ? { column } : {}) };
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
return {};
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
function camelToSnakeKey(key: string): string {
|
|
569
|
+
return key
|
|
570
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1_$2")
|
|
571
|
+
.replace(/([A-Z])([A-Z][a-z])/g, "$1_$2")
|
|
572
|
+
.toLowerCase();
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
function visitDeclarationCall(call: CallExpression, program: AstNode, scope: ProjectScope): void {
|
|
283
576
|
const callee = call.callee;
|
|
284
577
|
|
|
285
578
|
// store.sql("name") / store.kv(...) / …
|
|
@@ -299,6 +592,9 @@ function visitDeclarationCall(
|
|
|
299
592
|
const ref = `${facet}:${storeName}` as const;
|
|
300
593
|
const bindingName = enclosingConstName(call, program);
|
|
301
594
|
scope.stores[storeName] = scope.stores[storeName] ?? { facet };
|
|
595
|
+
if (facet === "sql") {
|
|
596
|
+
attachSchemaOption(call.arguments[1], scope.stores[storeName]!, scope);
|
|
597
|
+
}
|
|
302
598
|
if (bindingName) {
|
|
303
599
|
scope.bindings.set(bindingName, {
|
|
304
600
|
kind: "store",
|
|
@@ -309,6 +605,14 @@ function visitDeclarationCall(
|
|
|
309
605
|
}
|
|
310
606
|
}
|
|
311
607
|
|
|
608
|
+
// store.schema.table("notes", { … })
|
|
609
|
+
if (prop === "table" && member.object.type === "MemberExpression") {
|
|
610
|
+
const inner = member.object as AstNode & { object: AstNode; property: AstNode };
|
|
611
|
+
if (identifierName(inner.object) === "store" && identifierName(inner.property) === "schema") {
|
|
612
|
+
collectSchemaTable(call, program, scope);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
312
616
|
if (obj === "gate" && prop === "policy") {
|
|
313
617
|
const policyName = stringArg(call.arguments[0]);
|
|
314
618
|
if (policyName) {
|
|
@@ -326,8 +630,7 @@ function visitDeclarationCall(
|
|
|
326
630
|
|
|
327
631
|
if (obj === "gate" && prop === "rate") {
|
|
328
632
|
const opts = objectArg(call.arguments[0]);
|
|
329
|
-
const strategy = (stringProp(opts, "strategy") ??
|
|
330
|
-
"sliding-window-counter") as RateStrategy;
|
|
633
|
+
const strategy = (stringProp(opts, "strategy") ?? "sliding-window-counter") as RateStrategy;
|
|
331
634
|
const max = numberProp(opts, "max");
|
|
332
635
|
const per = stringProp(opts, "per");
|
|
333
636
|
const keyBy = stringProp(opts, "keyBy");
|
|
@@ -362,9 +665,7 @@ function visitDeclarationCall(
|
|
|
362
665
|
const medium = stringProp(opts, "medium");
|
|
363
666
|
const locales = stringArrayProp(opts, "locales");
|
|
364
667
|
scope.channels[templateName] = {
|
|
365
|
-
...(medium
|
|
366
|
-
? { medium: medium as Channel["medium"] }
|
|
367
|
-
: { medium: "email" }),
|
|
668
|
+
...(medium ? { medium: medium as Channel["medium"] } : { medium: "email" }),
|
|
368
669
|
...(locales ? { locales } : {}),
|
|
369
670
|
};
|
|
370
671
|
const bindingName = enclosingConstName(call, program);
|
|
@@ -382,12 +683,8 @@ function visitDeclarationCall(
|
|
|
382
683
|
const opts = objectArg(call.arguments[1]);
|
|
383
684
|
if (modelName) {
|
|
384
685
|
const model: AiModel = {
|
|
385
|
-
...(stringProp(opts, "provider")
|
|
386
|
-
|
|
387
|
-
: {}),
|
|
388
|
-
...(stringProp(opts, "tier")
|
|
389
|
-
? { tier: stringProp(opts, "tier") }
|
|
390
|
-
: {}),
|
|
686
|
+
...(stringProp(opts, "provider") ? { provider: stringProp(opts, "provider") } : {}),
|
|
687
|
+
...(stringProp(opts, "tier") ? { tier: stringProp(opts, "tier") } : {}),
|
|
391
688
|
};
|
|
392
689
|
scope.ai.models = scope.ai.models ?? {};
|
|
393
690
|
scope.ai.models[modelName] = model;
|
|
@@ -463,9 +760,7 @@ function visitDeclarationCall(
|
|
|
463
760
|
...(stringProp(opts, "description")
|
|
464
761
|
? { description: stringProp(opts, "description") }
|
|
465
762
|
: {}),
|
|
466
|
-
...(stringProp(opts, "rotate")
|
|
467
|
-
? { rotate: stringProp(opts, "rotate") }
|
|
468
|
-
: {}),
|
|
763
|
+
...(stringProp(opts, "rotate") ? { rotate: stringProp(opts, "rotate") } : {}),
|
|
469
764
|
};
|
|
470
765
|
const bindingName = enclosingConstName(call, program);
|
|
471
766
|
if (bindingName) {
|
|
@@ -512,9 +807,7 @@ function visitDeclarationCall(
|
|
|
512
807
|
const opts = objectArg(call.arguments[1]);
|
|
513
808
|
if (name && opts) {
|
|
514
809
|
scope.clocks[name] = {
|
|
515
|
-
...(stringProp(opts, "every")
|
|
516
|
-
? { every: stringProp(opts, "every") }
|
|
517
|
-
: {}),
|
|
810
|
+
...(stringProp(opts, "every") ? { every: stringProp(opts, "every") } : {}),
|
|
518
811
|
...(stringProp(opts, "cron") ? { cron: stringProp(opts, "cron") } : {}),
|
|
519
812
|
...(boolProp(opts, "overridable") !== undefined
|
|
520
813
|
? { overridable: boolProp(opts, "overridable") }
|
|
@@ -547,9 +840,7 @@ function visitDeclarationCall(
|
|
|
547
840
|
},
|
|
548
841
|
}
|
|
549
842
|
: {}),
|
|
550
|
-
...(stringProp(opts, "composes")
|
|
551
|
-
? { composes: stringProp(opts, "composes") }
|
|
552
|
-
: {}),
|
|
843
|
+
...(stringProp(opts, "composes") ? { composes: stringProp(opts, "composes") } : {}),
|
|
553
844
|
...(flows && flows.length > 0 ? { flows } : {}),
|
|
554
845
|
};
|
|
555
846
|
scope.journeys[name] = journey;
|
|
@@ -570,9 +861,7 @@ function visitDeclarationCall(
|
|
|
570
861
|
...(stringProp(opts, "description")
|
|
571
862
|
? { description: stringProp(opts, "description") }
|
|
572
863
|
: {}),
|
|
573
|
-
...(stringProp(opts, "rotate")
|
|
574
|
-
? { rotate: stringProp(opts, "rotate") }
|
|
575
|
-
: {}),
|
|
864
|
+
...(stringProp(opts, "rotate") ? { rotate: stringProp(opts, "rotate") } : {}),
|
|
576
865
|
};
|
|
577
866
|
const bindingName = enclosingConstName(call, program);
|
|
578
867
|
if (bindingName) {
|
|
@@ -601,20 +890,13 @@ function collectAgent(call: CallExpression, scope: ProjectScope): void {
|
|
|
601
890
|
scope.ai.agents[agentName] = agent;
|
|
602
891
|
}
|
|
603
892
|
|
|
604
|
-
function collectConfig(
|
|
605
|
-
opts: AstNode | undefined,
|
|
606
|
-
scope: ProjectScope,
|
|
607
|
-
): void {
|
|
893
|
+
function collectConfig(opts: AstNode | undefined, scope: ProjectScope): void {
|
|
608
894
|
if (!opts) return;
|
|
609
895
|
|
|
610
896
|
const tenancy = objectProp(opts, "tenancy");
|
|
611
897
|
if (tenancy) {
|
|
612
898
|
const isolation = stringProp(tenancy, "isolation");
|
|
613
|
-
if (
|
|
614
|
-
isolation === "row" ||
|
|
615
|
-
isolation === "schema" ||
|
|
616
|
-
isolation === "database"
|
|
617
|
-
) {
|
|
899
|
+
if (isolation === "row" || isolation === "schema" || isolation === "database") {
|
|
618
900
|
scope.tenancy = { isolation };
|
|
619
901
|
}
|
|
620
902
|
}
|
|
@@ -622,21 +904,15 @@ function collectConfig(
|
|
|
622
904
|
const i18n = objectProp(opts, "i18n");
|
|
623
905
|
if (i18n) {
|
|
624
906
|
scope.i18n = {
|
|
625
|
-
...(stringArrayProp(i18n, "locales")
|
|
626
|
-
|
|
627
|
-
: {}),
|
|
628
|
-
...(stringProp(i18n, "default")
|
|
629
|
-
? { default: stringProp(i18n, "default") }
|
|
630
|
-
: {}),
|
|
907
|
+
...(stringArrayProp(i18n, "locales") ? { locales: stringArrayProp(i18n, "locales") } : {}),
|
|
908
|
+
...(stringProp(i18n, "default") ? { default: stringProp(i18n, "default") } : {}),
|
|
631
909
|
};
|
|
632
910
|
const dir = objectProp(i18n, "dir");
|
|
633
911
|
if (dir && dir.type === "ObjectExpression") {
|
|
634
912
|
const dirMap: Record<string, "ltr" | "rtl"> = {};
|
|
635
913
|
for (const prop of objectProperties(dir)) {
|
|
636
914
|
const key = propKey(prop);
|
|
637
|
-
const val = stringArg(
|
|
638
|
-
(prop as AstNode & { value?: AstNode }).value,
|
|
639
|
-
);
|
|
915
|
+
const val = stringArg((prop as AstNode & { value?: AstNode }).value);
|
|
640
916
|
if (key && (val === "ltr" || val === "rtl")) dirMap[key] = val;
|
|
641
917
|
}
|
|
642
918
|
if (Object.keys(dirMap).length > 0) {
|
|
@@ -666,9 +942,7 @@ function collectConfig(
|
|
|
666
942
|
if (drivers) {
|
|
667
943
|
const prodArr = arrayProp(drivers, "prod");
|
|
668
944
|
if (prodArr && prodArr.length > 0 && prodArr.every((el) => stringArg(el))) {
|
|
669
|
-
scope.drivers.prod = prodArr
|
|
670
|
-
.map((el) => stringArg(el)!)
|
|
671
|
-
.filter((x) => x.length > 0);
|
|
945
|
+
scope.drivers.prod = prodArr.map((el) => stringArg(el)!).filter((x) => x.length > 0);
|
|
672
946
|
} else {
|
|
673
947
|
const prod = new Set<string>();
|
|
674
948
|
collectDriverProtocols(drivers, "prod", prod);
|
|
@@ -677,11 +951,7 @@ function collectConfig(
|
|
|
677
951
|
}
|
|
678
952
|
}
|
|
679
953
|
|
|
680
|
-
function collectDriverProtocols(
|
|
681
|
-
node: AstNode,
|
|
682
|
-
env: string,
|
|
683
|
-
into: Set<string>,
|
|
684
|
-
): void {
|
|
954
|
+
function collectDriverProtocols(node: AstNode, env: string, into: Set<string>): void {
|
|
685
955
|
if (node.type !== "ObjectExpression") return;
|
|
686
956
|
for (const prop of objectProperties(node)) {
|
|
687
957
|
const key = propKey(prop);
|
|
@@ -704,10 +974,7 @@ function collectDriverProtocols(
|
|
|
704
974
|
// role: { dev, test, prod } or nested store: { sql: { prod } }
|
|
705
975
|
const envVal = objectProp(value, env);
|
|
706
976
|
if (envVal) {
|
|
707
|
-
if (
|
|
708
|
-
envVal.type === "Literal" &&
|
|
709
|
-
typeof (envVal as Literal).value === "string"
|
|
710
|
-
) {
|
|
977
|
+
if (envVal.type === "Literal" && typeof (envVal as Literal).value === "string") {
|
|
711
978
|
into.add((envVal as Literal).value as string);
|
|
712
979
|
} else if (envVal.type === "ObjectExpression") {
|
|
713
980
|
const driver = stringProp(envVal, "driver");
|
|
@@ -720,11 +987,7 @@ function collectDriverProtocols(
|
|
|
720
987
|
}
|
|
721
988
|
}
|
|
722
989
|
|
|
723
|
-
function collectFlows(
|
|
724
|
-
file: SourceFile,
|
|
725
|
-
program: AstNode,
|
|
726
|
-
scope: ProjectScope,
|
|
727
|
-
): void {
|
|
990
|
+
function collectFlows(file: SourceFile, program: AstNode, scope: ProjectScope): void {
|
|
728
991
|
walk(program, (node) => {
|
|
729
992
|
if (node.type !== "CallExpression") return;
|
|
730
993
|
const call = node as CallExpression;
|
|
@@ -780,7 +1043,10 @@ function isOnFlowArgument(flowCall: CallExpression, program: AstNode): boolean {
|
|
|
780
1043
|
}
|
|
781
1044
|
|
|
782
1045
|
function unwrapFlowCall(node: AstNode): CallExpression | undefined {
|
|
783
|
-
if (
|
|
1046
|
+
if (
|
|
1047
|
+
node.type === "CallExpression" &&
|
|
1048
|
+
identifierName((node as CallExpression).callee) === "flow"
|
|
1049
|
+
) {
|
|
784
1050
|
return node as CallExpression;
|
|
785
1051
|
}
|
|
786
1052
|
return undefined;
|
|
@@ -845,15 +1111,11 @@ function registerFlow(args: {
|
|
|
845
1111
|
}
|
|
846
1112
|
}
|
|
847
1113
|
|
|
848
|
-
const trigger = args.triggerNode
|
|
849
|
-
? parseTrigger(args.triggerNode, args.scope)
|
|
850
|
-
: undefined;
|
|
1114
|
+
const trigger = args.triggerNode ? parseTrigger(args.triggerNode, args.scope) : undefined;
|
|
851
1115
|
|
|
852
1116
|
const gates = trigger?.gates;
|
|
853
1117
|
const liveFromTrigger = trigger?.live;
|
|
854
|
-
const manifestTrigger = trigger
|
|
855
|
-
? stripTriggerExtras(trigger.trigger)
|
|
856
|
-
: undefined;
|
|
1118
|
+
const manifestTrigger = trigger ? stripTriggerExtras(trigger.trigger) : undefined;
|
|
857
1119
|
|
|
858
1120
|
const flow: Flow = {};
|
|
859
1121
|
|
|
@@ -882,10 +1144,7 @@ function registerFlow(args: {
|
|
|
882
1144
|
if (slo) flow.slo = slo;
|
|
883
1145
|
|
|
884
1146
|
const stepsFromOpts = stringArrayProp(opts, "steps");
|
|
885
|
-
const steps =
|
|
886
|
-
stepsFromOpts && stepsFromOpts.length > 0
|
|
887
|
-
? stepsFromOpts
|
|
888
|
-
: inferred.steps;
|
|
1147
|
+
const steps = stepsFromOpts && stepsFromOpts.length > 0 ? stepsFromOpts : inferred.steps;
|
|
889
1148
|
if (steps.length > 0) flow.steps = steps;
|
|
890
1149
|
|
|
891
1150
|
if (boolProp(opts, "nondeterministic") || inferred.nondeterministic) {
|
|
@@ -898,17 +1157,14 @@ function registerFlow(args: {
|
|
|
898
1157
|
...(numberProp(cost, "estimatePerCall") !== undefined
|
|
899
1158
|
? { estimatePerCall: numberProp(cost, "estimatePerCall") }
|
|
900
1159
|
: {}),
|
|
901
|
-
...(numberProp(cost, "budget") !== undefined
|
|
902
|
-
? { budget: numberProp(cost, "budget") }
|
|
903
|
-
: {}),
|
|
1160
|
+
...(numberProp(cost, "budget") !== undefined ? { budget: numberProp(cost, "budget") } : {}),
|
|
904
1161
|
};
|
|
905
1162
|
} else if (inferred.nondeterministic) {
|
|
906
1163
|
// Derive budget from the first ask prompt when present.
|
|
907
1164
|
const ask = effects?.asks?.[0];
|
|
908
1165
|
if (ask) {
|
|
909
1166
|
const promptName = ask.split("@")[0]!;
|
|
910
|
-
const promptBudget = args.scope.ai.prompts?.[promptName]?.budget
|
|
911
|
-
?.maxCostPerCall;
|
|
1167
|
+
const promptBudget = args.scope.ai.prompts?.[promptName]?.budget?.maxCostPerCall;
|
|
912
1168
|
if (promptBudget !== undefined) {
|
|
913
1169
|
flow.cost = {
|
|
914
1170
|
estimatePerCall: Number((promptBudget * 0.55).toFixed(3)),
|
|
@@ -935,8 +1191,7 @@ function registerFlow(args: {
|
|
|
935
1191
|
if (inferred.cacheIneligible) {
|
|
936
1192
|
flow.cache = false;
|
|
937
1193
|
} else {
|
|
938
|
-
const cache = (opts &&
|
|
939
|
-
objectProperties(opts).find((p) => propKey(p) === "cache")) as
|
|
1194
|
+
const cache = (opts && objectProperties(opts).find((p) => propKey(p) === "cache")) as
|
|
940
1195
|
| AstNode
|
|
941
1196
|
| undefined;
|
|
942
1197
|
if (cache) {
|
|
@@ -1002,10 +1257,7 @@ function parseTrigger(node: AstNode, scope: ProjectScope): ParsedTrigger | undef
|
|
|
1002
1257
|
return undefined;
|
|
1003
1258
|
}
|
|
1004
1259
|
|
|
1005
|
-
function parseHttpTrigger(
|
|
1006
|
-
call: CallExpression,
|
|
1007
|
-
scope: ProjectScope,
|
|
1008
|
-
): ParsedTrigger | undefined {
|
|
1260
|
+
function parseHttpTrigger(call: CallExpression, scope: ProjectScope): ParsedTrigger | undefined {
|
|
1009
1261
|
// Walk the chain: http.METHOD(path).gate(...).live()
|
|
1010
1262
|
let current: AstNode = call;
|
|
1011
1263
|
let method: string | undefined;
|
|
@@ -1059,15 +1311,7 @@ function parseHttpTrigger(
|
|
|
1059
1311
|
|
|
1060
1312
|
if (!method || !path) return undefined;
|
|
1061
1313
|
|
|
1062
|
-
const httpMethods = [
|
|
1063
|
-
"GET",
|
|
1064
|
-
"POST",
|
|
1065
|
-
"PUT",
|
|
1066
|
-
"PATCH",
|
|
1067
|
-
"DELETE",
|
|
1068
|
-
"HEAD",
|
|
1069
|
-
"OPTIONS",
|
|
1070
|
-
] as const;
|
|
1314
|
+
const httpMethods = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"] as const;
|
|
1071
1315
|
if (!(httpMethods as readonly string[]).includes(method)) return undefined;
|
|
1072
1316
|
|
|
1073
1317
|
return {
|
|
@@ -1082,9 +1326,7 @@ function parseHttpTrigger(
|
|
|
1082
1326
|
};
|
|
1083
1327
|
}
|
|
1084
1328
|
|
|
1085
|
-
function parseCdcTrigger(
|
|
1086
|
-
call: CallExpression,
|
|
1087
|
-
): Trigger["cdc"] | undefined {
|
|
1329
|
+
function parseCdcTrigger(call: CallExpression): Trigger["cdc"] | undefined {
|
|
1088
1330
|
// *.changed("col") or *.changed()
|
|
1089
1331
|
const callee = call.callee;
|
|
1090
1332
|
if (callee.type !== "MemberExpression") return undefined;
|
|
@@ -1098,25 +1340,17 @@ function parseCdcTrigger(
|
|
|
1098
1340
|
const inner = obj as CallExpression;
|
|
1099
1341
|
const innerCallee = inner.callee;
|
|
1100
1342
|
if (identifierName(innerCallee) === "table") {
|
|
1101
|
-
const tableName =
|
|
1102
|
-
stringArg(inner.arguments[0]) ?? identifierName(inner.arguments[0]);
|
|
1343
|
+
const tableName = stringArg(inner.arguments[0]) ?? identifierName(inner.arguments[0]);
|
|
1103
1344
|
if (!tableName) return undefined;
|
|
1104
|
-
return column
|
|
1105
|
-
? { table: tableName, column }
|
|
1106
|
-
: { table: tableName };
|
|
1345
|
+
return column ? { table: tableName, column } : { table: tableName };
|
|
1107
1346
|
}
|
|
1108
1347
|
if (
|
|
1109
1348
|
innerCallee.type === "MemberExpression" &&
|
|
1110
|
-
identifierName(
|
|
1111
|
-
(innerCallee as AstNode & { property: AstNode }).property,
|
|
1112
|
-
) === "table"
|
|
1349
|
+
identifierName((innerCallee as AstNode & { property: AstNode }).property) === "table"
|
|
1113
1350
|
) {
|
|
1114
|
-
const tableName =
|
|
1115
|
-
stringArg(inner.arguments[0]) ?? identifierName(inner.arguments[0]);
|
|
1351
|
+
const tableName = stringArg(inner.arguments[0]) ?? identifierName(inner.arguments[0]);
|
|
1116
1352
|
if (!tableName) return undefined;
|
|
1117
|
-
return column
|
|
1118
|
-
? { table: tableName, column }
|
|
1119
|
-
: { table: tableName };
|
|
1353
|
+
return column ? { table: tableName, column } : { table: tableName };
|
|
1120
1354
|
}
|
|
1121
1355
|
}
|
|
1122
1356
|
return undefined;
|
|
@@ -1146,9 +1380,7 @@ function parseEffectsObject(node: AstNode | undefined): Effects | undefined {
|
|
|
1146
1380
|
return effects;
|
|
1147
1381
|
}
|
|
1148
1382
|
|
|
1149
|
-
function parseErrors(
|
|
1150
|
-
node: AstNode | undefined,
|
|
1151
|
-
): Flow["errors"] | undefined {
|
|
1383
|
+
function parseErrors(node: AstNode | undefined): Flow["errors"] | undefined {
|
|
1152
1384
|
if (!node) return undefined;
|
|
1153
1385
|
if (node.type === "ObjectExpression") {
|
|
1154
1386
|
const names: string[] = [];
|
|
@@ -1187,10 +1419,7 @@ function parseSlo(node: AstNode | undefined): Slo | undefined {
|
|
|
1187
1419
|
};
|
|
1188
1420
|
}
|
|
1189
1421
|
|
|
1190
|
-
function schemaProp(
|
|
1191
|
-
obj: AstNode | undefined,
|
|
1192
|
-
key: string,
|
|
1193
|
-
): string | undefined {
|
|
1422
|
+
function schemaProp(obj: AstNode | undefined, key: string): string | undefined {
|
|
1194
1423
|
const node = objectProp(obj, key);
|
|
1195
1424
|
if (!node) return undefined;
|
|
1196
1425
|
// Identifier / member schemas → opaque placeholder matching the spec excerpt.
|
|
@@ -1205,10 +1434,7 @@ function schemaProp(
|
|
|
1205
1434
|
|
|
1206
1435
|
// ── AST helpers ────────────────────────────────────────────────────────────
|
|
1207
1436
|
|
|
1208
|
-
function enclosingConstName(
|
|
1209
|
-
call: CallExpression,
|
|
1210
|
-
program: AstNode,
|
|
1211
|
-
): string | undefined {
|
|
1437
|
+
function enclosingConstName(call: CallExpression, program: AstNode): string | undefined {
|
|
1212
1438
|
const targetStart = call.start;
|
|
1213
1439
|
if (targetStart === undefined) return undefined;
|
|
1214
1440
|
let found: string | undefined;
|
|
@@ -1239,10 +1465,7 @@ function objectArg(node: AstNode | undefined): AstNode | undefined {
|
|
|
1239
1465
|
return undefined;
|
|
1240
1466
|
}
|
|
1241
1467
|
|
|
1242
|
-
function objectProp(
|
|
1243
|
-
obj: AstNode | undefined,
|
|
1244
|
-
key: string,
|
|
1245
|
-
): AstNode | undefined {
|
|
1468
|
+
function objectProp(obj: AstNode | undefined, key: string): AstNode | undefined {
|
|
1246
1469
|
if (!obj || obj.type !== "ObjectExpression") return undefined;
|
|
1247
1470
|
for (const prop of objectProperties(obj)) {
|
|
1248
1471
|
if (propKey(prop) === key) {
|
|
@@ -1253,9 +1476,9 @@ function objectProp(
|
|
|
1253
1476
|
}
|
|
1254
1477
|
|
|
1255
1478
|
function objectProperties(obj: AstNode): AstNode[] {
|
|
1256
|
-
return (
|
|
1257
|
-
(
|
|
1258
|
-
)
|
|
1479
|
+
return ((obj as AstNode & { properties?: AstNode[] }).properties ?? []).filter(
|
|
1480
|
+
(p) => p.type === "Property" || p.type === "ObjectProperty",
|
|
1481
|
+
);
|
|
1259
1482
|
}
|
|
1260
1483
|
|
|
1261
1484
|
function propKey(prop: AstNode): string | undefined {
|
|
@@ -1268,50 +1491,33 @@ function propKey(prop: AstNode): string | undefined {
|
|
|
1268
1491
|
return undefined;
|
|
1269
1492
|
}
|
|
1270
1493
|
|
|
1271
|
-
function stringProp(
|
|
1272
|
-
obj: AstNode | undefined,
|
|
1273
|
-
key: string,
|
|
1274
|
-
): string | undefined {
|
|
1494
|
+
function stringProp(obj: AstNode | undefined, key: string): string | undefined {
|
|
1275
1495
|
return stringArg(objectProp(obj, key));
|
|
1276
1496
|
}
|
|
1277
1497
|
|
|
1278
|
-
function numberProp(
|
|
1279
|
-
obj: AstNode | undefined,
|
|
1280
|
-
key: string,
|
|
1281
|
-
): number | undefined {
|
|
1498
|
+
function numberProp(obj: AstNode | undefined, key: string): number | undefined {
|
|
1282
1499
|
const node = objectProp(obj, key);
|
|
1283
1500
|
if (!node || node.type !== "Literal") return undefined;
|
|
1284
1501
|
const v = (node as Literal).value;
|
|
1285
1502
|
return typeof v === "number" ? v : undefined;
|
|
1286
1503
|
}
|
|
1287
1504
|
|
|
1288
|
-
function boolProp(
|
|
1289
|
-
obj: AstNode | undefined,
|
|
1290
|
-
key: string,
|
|
1291
|
-
): boolean | undefined {
|
|
1505
|
+
function boolProp(obj: AstNode | undefined, key: string): boolean | undefined {
|
|
1292
1506
|
const node = objectProp(obj, key);
|
|
1293
1507
|
if (!node || node.type !== "Literal") return undefined;
|
|
1294
1508
|
const v = (node as Literal).value;
|
|
1295
1509
|
return typeof v === "boolean" ? v : undefined;
|
|
1296
1510
|
}
|
|
1297
1511
|
|
|
1298
|
-
function stringArrayProp(
|
|
1299
|
-
obj: AstNode | undefined,
|
|
1300
|
-
key: string,
|
|
1301
|
-
): string[] | undefined {
|
|
1512
|
+
function stringArrayProp(obj: AstNode | undefined, key: string): string[] | undefined {
|
|
1302
1513
|
const node = objectProp(obj, key);
|
|
1303
1514
|
if (!node || node.type !== "ArrayExpression") return undefined;
|
|
1304
1515
|
const els = (node as AstNode & { elements?: AstNode[] }).elements ?? [];
|
|
1305
|
-
const out = els
|
|
1306
|
-
.map((el) => stringArg(el))
|
|
1307
|
-
.filter((x): x is string => typeof x === "string");
|
|
1516
|
+
const out = els.map((el) => stringArg(el)).filter((x): x is string => typeof x === "string");
|
|
1308
1517
|
return out;
|
|
1309
1518
|
}
|
|
1310
1519
|
|
|
1311
|
-
function arrayProp(
|
|
1312
|
-
obj: AstNode | undefined,
|
|
1313
|
-
key: string,
|
|
1314
|
-
): AstNode[] | undefined {
|
|
1520
|
+
function arrayProp(obj: AstNode | undefined, key: string): AstNode[] | undefined {
|
|
1315
1521
|
const node = objectProp(obj, key);
|
|
1316
1522
|
if (!node || node.type !== "ArrayExpression") return undefined;
|
|
1317
1523
|
return ((node as AstNode & { elements?: AstNode[] }).elements ?? []).filter(
|