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
|
@@ -7,11 +7,7 @@ import { ai, createAiRuntime, runPromptEvals } from "../../elements/ai.ts";
|
|
|
7
7
|
import { createMockAiDriver } from "../../drivers/ai-mock.ts";
|
|
8
8
|
import { createGateRuntime, gate } from "../../elements/gate.ts";
|
|
9
9
|
import type { Manifest } from "../../manifest/types.ts";
|
|
10
|
-
import {
|
|
11
|
-
effectsForFlowFromManifest,
|
|
12
|
-
projectAiPanel,
|
|
13
|
-
projectAllowPii,
|
|
14
|
-
} from "./ai.ts";
|
|
10
|
+
import { effectsForFlowFromManifest, projectAiPanel, projectAllowPii } from "./ai.ts";
|
|
15
11
|
|
|
16
12
|
const manifest = {
|
|
17
13
|
oke: "1.0",
|
|
@@ -54,9 +50,7 @@ const manifest = {
|
|
|
54
50
|
describe("projectAiPanel", () => {
|
|
55
51
|
test("surfaces allowPii standing table from Manifest", () => {
|
|
56
52
|
const rows = projectAllowPii(manifest);
|
|
57
|
-
expect(rows.some((r) => r.flowId === "support.createTicket" && r.allowPii)).toBe(
|
|
58
|
-
true,
|
|
59
|
-
);
|
|
53
|
+
expect(rows.some((r) => r.flowId === "support.createTicket" && r.allowPii)).toBe(true);
|
|
60
54
|
});
|
|
61
55
|
|
|
62
56
|
test("effectsForFlowFromManifest matches trail vocabulary", () => {
|
|
@@ -147,9 +141,7 @@ describe("projectAiPanel", () => {
|
|
|
147
141
|
aiRuntime: runtime,
|
|
148
142
|
evalResults: [evals],
|
|
149
143
|
});
|
|
150
|
-
expect(okProj.prompts[0]!.manifestDiffPath).toBe(
|
|
151
|
-
"/ai/prompts/ticket-triage/version",
|
|
152
|
-
);
|
|
144
|
+
expect(okProj.prompts[0]!.manifestDiffPath).toBe("/ai/prompts/ticket-triage/version");
|
|
153
145
|
expect(okProj.versions[0]!.evalScore.samples.length).toBeGreaterThan(0);
|
|
154
146
|
expect(okProj.agentRuns[0]!.trail[0]!.status).toBe("denied");
|
|
155
147
|
expect(okProj.agentRuns[0]!.trail[0]!.denial?.gate).toBe("member");
|
package/src/console/server/ai.ts
CHANGED
|
@@ -168,19 +168,17 @@ export function createManifestAiRuntime(
|
|
|
168
168
|
}),
|
|
169
169
|
);
|
|
170
170
|
const modelByName = new Map(models.map((m) => [m.name, m]));
|
|
171
|
-
const prompts = Object.entries(manifest?.ai?.prompts ?? {}).map(
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
},
|
|
183
|
-
);
|
|
171
|
+
const prompts = Object.entries(manifest?.ai?.prompts ?? {}).map(([name, p]) => {
|
|
172
|
+
const modelName = p.model ?? models[0]?.name ?? "mock";
|
|
173
|
+
const handle = modelByName.get(modelName) ?? ai.model(modelName);
|
|
174
|
+
return handle.prompt(name, {
|
|
175
|
+
...(p.version !== undefined ? { version: p.version } : {}),
|
|
176
|
+
...(p.evals !== undefined ? { evals: p.evals } : {}),
|
|
177
|
+
...(p.budget !== undefined ? { budget: p.budget } : {}),
|
|
178
|
+
...(p.in !== undefined ? { in: p.in } : {}),
|
|
179
|
+
...(p.out !== undefined ? { out: p.out } : {}),
|
|
180
|
+
});
|
|
181
|
+
});
|
|
184
182
|
const agents = Object.entries(manifest?.ai?.agents ?? {}).map(([name, a]) =>
|
|
185
183
|
ai.agent(name, {
|
|
186
184
|
tools: a.tools ?? [],
|
|
@@ -200,8 +198,7 @@ export function createManifestAiRuntime(
|
|
|
200
198
|
prompts,
|
|
201
199
|
agents,
|
|
202
200
|
defaultDriver: mockAiDriver,
|
|
203
|
-
effectsForFlow: (flowName) =>
|
|
204
|
-
effectsForFlowFromManifest(manifest, flowName),
|
|
201
|
+
effectsForFlow: (flowName) => effectsForFlowFromManifest(manifest, flowName),
|
|
205
202
|
now: options.now,
|
|
206
203
|
});
|
|
207
204
|
}
|
|
@@ -355,8 +352,7 @@ export function projectAllowPii(manifest: Manifest | null): readonly AllowPiiRow
|
|
|
355
352
|
if (!manifest?.flows) return [];
|
|
356
353
|
const rows: AllowPiiRow[] = [];
|
|
357
354
|
for (const [flowId, flow] of Object.entries(manifest.flows)) {
|
|
358
|
-
const allow =
|
|
359
|
-
flow.allowPii === true || flow.pii === "allow";
|
|
355
|
+
const allow = flow.allowPii === true || flow.pii === "allow";
|
|
360
356
|
const asks = flow.effects?.asks ?? [];
|
|
361
357
|
if (!allow && asks.length === 0) continue;
|
|
362
358
|
if (!allow && flow.pii === undefined) continue;
|
|
@@ -377,9 +373,7 @@ export function projectAllowPii(manifest: Manifest | null): readonly AllowPiiRow
|
|
|
377
373
|
});
|
|
378
374
|
}
|
|
379
375
|
|
|
380
|
-
function projectFallbackChains(
|
|
381
|
-
journal: readonly AiJournalEntry[],
|
|
382
|
-
): readonly FallbackChainRow[] {
|
|
376
|
+
function projectFallbackChains(journal: readonly AiJournalEntry[]): readonly FallbackChainRow[] {
|
|
383
377
|
const rows: FallbackChainRow[] = [];
|
|
384
378
|
for (const entry of journal) {
|
|
385
379
|
if (entry.attempts.length < 2) continue;
|
|
@@ -411,9 +405,7 @@ function projectFallbackChains(
|
|
|
411
405
|
return rows.sort((a, b) => b.at - a.at);
|
|
412
406
|
}
|
|
413
407
|
|
|
414
|
-
function projectAgentRuns(
|
|
415
|
-
runs: readonly AgentRunRecord[],
|
|
416
|
-
): readonly AgentRunRow[] {
|
|
408
|
+
function projectAgentRuns(runs: readonly AgentRunRecord[]): readonly AgentRunRow[] {
|
|
417
409
|
return [...runs]
|
|
418
410
|
.sort((a, b) => b.at - a.at)
|
|
419
411
|
.map((r) => ({
|
|
@@ -439,10 +431,7 @@ function buildVersionMetrics(input: {
|
|
|
439
431
|
readonly journal: readonly AiJournalEntry[];
|
|
440
432
|
readonly runs: readonly WideEvent[];
|
|
441
433
|
readonly evalResults: readonly EvalSuiteResult[];
|
|
442
|
-
readonly promptMeta: Map<
|
|
443
|
-
string,
|
|
444
|
-
{ version?: number; budget?: number | null; model?: string }
|
|
445
|
-
>;
|
|
434
|
+
readonly promptMeta: Map<string, { version?: number; budget?: number | null; model?: string }>;
|
|
446
435
|
readonly bucketCount: number;
|
|
447
436
|
}): readonly PromptVersionMetrics[] {
|
|
448
437
|
type Acc = {
|
|
@@ -480,10 +469,7 @@ function buildVersionMetrics(input: {
|
|
|
480
469
|
};
|
|
481
470
|
|
|
482
471
|
for (const entry of input.journal) {
|
|
483
|
-
const version =
|
|
484
|
-
entry.version ??
|
|
485
|
-
input.promptMeta.get(entry.prompt)?.version ??
|
|
486
|
-
0;
|
|
472
|
+
const version = entry.version ?? input.promptMeta.get(entry.prompt)?.version ?? 0;
|
|
487
473
|
const acc = ensure(entry.prompt, version);
|
|
488
474
|
acc.costs.push(entry.cost);
|
|
489
475
|
acc.latencies.push(entry.latencyMs);
|
|
@@ -528,9 +514,7 @@ function buildVersionMetrics(input: {
|
|
|
528
514
|
const out: PromptVersionMetrics[] = [];
|
|
529
515
|
for (const acc of map.values()) {
|
|
530
516
|
const totalOutcomes =
|
|
531
|
-
acc.outcomes.ok +
|
|
532
|
-
acc.outcomes.provider_error +
|
|
533
|
-
acc.outcomes.schema_invalid;
|
|
517
|
+
acc.outcomes.ok + acc.outcomes.provider_error + acc.outcomes.schema_invalid;
|
|
534
518
|
out.push({
|
|
535
519
|
prompt: acc.prompt,
|
|
536
520
|
version: acc.version,
|
|
@@ -538,13 +522,10 @@ function buildVersionMetrics(input: {
|
|
|
538
522
|
cost: metricBlock(acc.costs, input.bucketCount),
|
|
539
523
|
latencyMs: metricBlock(acc.latencies, input.bucketCount),
|
|
540
524
|
evalScore: metricBlock(acc.evals, input.bucketCount),
|
|
541
|
-
schemaInvalidRate:
|
|
542
|
-
|
|
543
|
-
providerErrorRate:
|
|
544
|
-
totalOutcomes === 0 ? 0 : acc.outcomes.provider_error / totalOutcomes,
|
|
525
|
+
schemaInvalidRate: totalOutcomes === 0 ? 0 : acc.outcomes.schema_invalid / totalOutcomes,
|
|
526
|
+
providerErrorRate: totalOutcomes === 0 ? 0 : acc.outcomes.provider_error / totalOutcomes,
|
|
545
527
|
okRate: totalOutcomes === 0 ? 0 : acc.outcomes.ok / totalOutcomes,
|
|
546
|
-
overBudgetRate:
|
|
547
|
-
acc.costs.length === 0 ? 0 : acc.overBudget / acc.costs.length,
|
|
528
|
+
overBudgetRate: acc.costs.length === 0 ? 0 : acc.overBudget / acc.costs.length,
|
|
548
529
|
budgetMaxCostPerCall: acc.budget,
|
|
549
530
|
outcomeCounts: acc.outcomes,
|
|
550
531
|
});
|
|
@@ -590,10 +571,7 @@ export function mean(values: readonly number[]): number {
|
|
|
590
571
|
export function percentile(sorted: readonly number[], p: number): number {
|
|
591
572
|
if (sorted.length === 0) return 0;
|
|
592
573
|
if (sorted.length === 1) return sorted[0]!;
|
|
593
|
-
const idx = Math.min(
|
|
594
|
-
sorted.length - 1,
|
|
595
|
-
Math.max(0, Math.ceil(p * sorted.length) - 1),
|
|
596
|
-
);
|
|
574
|
+
const idx = Math.min(sorted.length - 1, Math.max(0, Math.ceil(p * sorted.length) - 1));
|
|
597
575
|
return sorted[idx]!;
|
|
598
576
|
}
|
|
599
577
|
|
|
@@ -617,8 +595,7 @@ export function histogram(
|
|
|
617
595
|
const buckets: AiDistributionBucket[] = [];
|
|
618
596
|
for (let i = 0; i < bucketCount; i++) {
|
|
619
597
|
const lo = min + i * width;
|
|
620
|
-
const hi =
|
|
621
|
-
i === bucketCount - 1 ? max + Number.EPSILON : min + (i + 1) * width;
|
|
598
|
+
const hi = i === bucketCount - 1 ? max + Number.EPSILON : min + (i + 1) * width;
|
|
622
599
|
buckets.push({ min: lo, max: hi, count: 0 });
|
|
623
600
|
}
|
|
624
601
|
for (const v of sorted) {
|
|
@@ -45,9 +45,7 @@ export interface ConsoleAppHandle {
|
|
|
45
45
|
*
|
|
46
46
|
* @param options - Secret, cwd, Manifest seed
|
|
47
47
|
*/
|
|
48
|
-
export function createConsoleApp(
|
|
49
|
-
options: CreateConsoleAppOptions = {},
|
|
50
|
-
): ConsoleAppHandle {
|
|
48
|
+
export function createConsoleApp(options: CreateConsoleAppOptions = {}): ConsoleAppHandle {
|
|
51
49
|
const state = createConsoleState(options);
|
|
52
50
|
// Spec §2.5 — claim prints only while setup is open (no operators yet).
|
|
53
51
|
if (!options.silentClaim && !state.setupClosed) {
|
|
@@ -132,9 +130,7 @@ export function createConsoleApp(
|
|
|
132
130
|
*
|
|
133
131
|
* @param handle - Console app handle
|
|
134
132
|
*/
|
|
135
|
-
export async function bootConsoleApp(
|
|
136
|
-
handle: ConsoleAppHandle,
|
|
137
|
-
): Promise<OkeApp> {
|
|
133
|
+
export async function bootConsoleApp(handle: ConsoleAppHandle): Promise<OkeApp> {
|
|
138
134
|
await handle.app.boot({ env: "test" });
|
|
139
135
|
handle.state.listRuns = async () => {
|
|
140
136
|
const runs = handle.app.bootResult?.runs;
|
|
@@ -154,14 +150,7 @@ export async function bootConsoleApp(
|
|
|
154
150
|
*/
|
|
155
151
|
export async function ensureConsolePanelRuntimes(
|
|
156
152
|
state: ConsoleState,
|
|
157
|
-
panel:
|
|
158
|
-
| "signals"
|
|
159
|
-
| "store"
|
|
160
|
-
| "vault"
|
|
161
|
-
| "gates"
|
|
162
|
-
| "clock"
|
|
163
|
-
| "ai"
|
|
164
|
-
| "channels",
|
|
153
|
+
panel: "signals" | "store" | "vault" | "gates" | "clock" | "ai" | "channels",
|
|
165
154
|
): Promise<void> {
|
|
166
155
|
switch (panel) {
|
|
167
156
|
case "signals":
|
|
@@ -196,10 +185,7 @@ export async function ensureConsolePanelRuntimes(
|
|
|
196
185
|
*/
|
|
197
186
|
export function bindManifestChannelRuntime(state: ConsoleState): void {
|
|
198
187
|
if (state.channelRuntime) return;
|
|
199
|
-
if (
|
|
200
|
-
!state.manifest?.channels ||
|
|
201
|
-
Object.keys(state.manifest.channels).length === 0
|
|
202
|
-
) {
|
|
188
|
+
if (!state.manifest?.channels || Object.keys(state.manifest.channels).length === 0) {
|
|
203
189
|
return;
|
|
204
190
|
}
|
|
205
191
|
const bound = createManifestChannelRuntime(state.manifest, {
|
|
@@ -216,16 +202,11 @@ export function bindManifestChannelRuntime(state: ConsoleState): void {
|
|
|
216
202
|
*
|
|
217
203
|
* @param state - Console state
|
|
218
204
|
*/
|
|
219
|
-
export async function bindManifestClockRuntime(
|
|
220
|
-
state: ConsoleState,
|
|
221
|
-
): Promise<void> {
|
|
205
|
+
export async function bindManifestClockRuntime(state: ConsoleState): Promise<void> {
|
|
222
206
|
if (state.clockRuntime) return;
|
|
223
207
|
const hasClocks =
|
|
224
|
-
(state.manifest?.clocks &&
|
|
225
|
-
|
|
226
|
-
Object.values(state.manifest?.flows ?? {}).some(
|
|
227
|
-
(f) => f.trigger?.cron || f.trigger?.every,
|
|
228
|
-
);
|
|
208
|
+
(state.manifest?.clocks && Object.keys(state.manifest.clocks).length > 0) ||
|
|
209
|
+
Object.values(state.manifest?.flows ?? {}).some((f) => f.trigger?.cron || f.trigger?.every);
|
|
229
210
|
if (!hasClocks) return;
|
|
230
211
|
state.clockRuntime = createManifestClockRuntime(state.manifest, {
|
|
231
212
|
now: state.now,
|
|
@@ -246,22 +227,17 @@ export function bindManifestAiRuntime(state: ConsoleState): void {
|
|
|
246
227
|
Object.keys(state.manifest.ai.agents ?? {}).length > 0 ||
|
|
247
228
|
Object.keys(state.manifest.ai.models ?? {}).length > 0);
|
|
248
229
|
if (!hasAi) return;
|
|
249
|
-
bindAiRuntime(
|
|
250
|
-
state,
|
|
251
|
-
createManifestAiRuntime(state.manifest, { now: state.now }),
|
|
252
|
-
);
|
|
230
|
+
bindAiRuntime(state, createManifestAiRuntime(state.manifest, { now: state.now }));
|
|
253
231
|
}
|
|
254
232
|
|
|
255
233
|
/**
|
|
256
234
|
* Open a VaultRuntime from the Manifest when no host runtime is attached.
|
|
257
|
-
* Uses the standard resolution chain (process.env → .env.local → .env.
|
|
235
|
+
* Uses the standard resolution chain (process.env → .env.local → .env.docker
|
|
258
236
|
* → driver) — Console never parses dotenv itself.
|
|
259
237
|
*
|
|
260
238
|
* @param state - Console state
|
|
261
239
|
*/
|
|
262
|
-
export async function bindManifestVaultRuntime(
|
|
263
|
-
state: ConsoleState,
|
|
264
|
-
): Promise<void> {
|
|
240
|
+
export async function bindManifestVaultRuntime(state: ConsoleState): Promise<void> {
|
|
265
241
|
if (state.vaultRuntime) return;
|
|
266
242
|
if (!state.manifest?.vault || Object.keys(state.manifest.vault).length === 0) {
|
|
267
243
|
return;
|
|
@@ -269,7 +245,7 @@ export async function bindManifestVaultRuntime(
|
|
|
269
245
|
try {
|
|
270
246
|
state.vaultRuntime = await createManifestVaultRuntime(state.manifest, {
|
|
271
247
|
cwd: state.cwd,
|
|
272
|
-
env: state.production ? "prod" : "
|
|
248
|
+
env: state.production ? "prod" : "local",
|
|
273
249
|
allowDevFallbacks: !state.production,
|
|
274
250
|
now: state.now,
|
|
275
251
|
});
|
|
@@ -285,17 +261,12 @@ export async function bindManifestVaultRuntime(
|
|
|
285
261
|
*
|
|
286
262
|
* @param state - Console state
|
|
287
263
|
*/
|
|
288
|
-
export async function bindManifestStoreRuntime(
|
|
289
|
-
state: ConsoleState,
|
|
290
|
-
): Promise<void> {
|
|
264
|
+
export async function bindManifestStoreRuntime(state: ConsoleState): Promise<void> {
|
|
291
265
|
if (state.storeRuntime) return;
|
|
292
266
|
if (!state.manifest?.stores || Object.keys(state.manifest.stores).length === 0) {
|
|
293
267
|
return;
|
|
294
268
|
}
|
|
295
|
-
state.storeRuntime = await createManifestStoreRuntime(
|
|
296
|
-
state.manifest,
|
|
297
|
-
state.now,
|
|
298
|
-
);
|
|
269
|
+
state.storeRuntime = await createManifestStoreRuntime(state.manifest, state.now);
|
|
299
270
|
}
|
|
300
271
|
|
|
301
272
|
/**
|
|
@@ -304,9 +275,7 @@ export async function bindManifestStoreRuntime(
|
|
|
304
275
|
*
|
|
305
276
|
* @param state - Console state
|
|
306
277
|
*/
|
|
307
|
-
export async function bindManifestSignalBus(
|
|
308
|
-
state: ConsoleState,
|
|
309
|
-
): Promise<void> {
|
|
278
|
+
export async function bindManifestSignalBus(state: ConsoleState): Promise<void> {
|
|
310
279
|
if (state.signalBus) return;
|
|
311
280
|
const declared = Object.entries(state.manifest?.signals ?? {});
|
|
312
281
|
if (declared.length === 0) return;
|
|
@@ -29,9 +29,7 @@ describe("auth-rate strategy", () => {
|
|
|
29
29
|
for (let i = 0; i < AUTH_RATE_LIMIT; i++) {
|
|
30
30
|
expect(touchLoginRateLimit(bag, "Ops@Example.com", t++)).toBe("ok");
|
|
31
31
|
}
|
|
32
|
-
expect(touchLoginRateLimit(bag, "ops@example.com", t)).toBe(
|
|
33
|
-
"rate_limited",
|
|
34
|
-
);
|
|
32
|
+
expect(touchLoginRateLimit(bag, "ops@example.com", t)).toBe("rate_limited");
|
|
35
33
|
expect(touchLoginRateLimit(bag, "other@example.com", t)).toBe("ok");
|
|
36
34
|
});
|
|
37
35
|
|
|
@@ -59,20 +57,14 @@ describe("auth-rate strategy", () => {
|
|
|
59
57
|
});
|
|
60
58
|
|
|
61
59
|
const tMissing = performance.now();
|
|
62
|
-
expect(
|
|
63
|
-
await authenticateOperator(store, "missing@example.com", "password123"),
|
|
64
|
-
).toBeNull();
|
|
60
|
+
expect(await authenticateOperator(store, "missing@example.com", "password123")).toBeNull();
|
|
65
61
|
const missingMs = performance.now() - tMissing;
|
|
66
62
|
|
|
67
63
|
const tBad = performance.now();
|
|
68
|
-
expect(
|
|
69
|
-
await authenticateOperator(store, "ops@example.com", "wrong-password"),
|
|
70
|
-
).toBeNull();
|
|
64
|
+
expect(await authenticateOperator(store, "ops@example.com", "wrong-password")).toBeNull();
|
|
71
65
|
const badMs = performance.now() - tBad;
|
|
72
66
|
|
|
73
|
-
expect(
|
|
74
|
-
await authenticateOperator(store, "ops@example.com", "password123"),
|
|
75
|
-
).not.toBeNull();
|
|
67
|
+
expect(await authenticateOperator(store, "ops@example.com", "password123")).not.toBeNull();
|
|
76
68
|
|
|
77
69
|
// Both paths pay an argon2 verify — neither should be near-instant.
|
|
78
70
|
expect(missingMs).toBeGreaterThan(5);
|
|
@@ -4,11 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import type { AnyFlowDef } from "../../kernel/flow.ts";
|
|
6
6
|
import type { Binding } from "../../kernel/on.ts";
|
|
7
|
-
import {
|
|
8
|
-
normalizeTrigger,
|
|
9
|
-
type HttpTrigger,
|
|
10
|
-
type Trigger,
|
|
11
|
-
} from "../../kernel/triggers.ts";
|
|
7
|
+
import { normalizeTrigger, type HttpTrigger, type Trigger } from "../../kernel/triggers.ts";
|
|
12
8
|
|
|
13
9
|
/**
|
|
14
10
|
* Bind an HTTP trigger to a flow without registering on the global `on` list.
|
|
@@ -73,9 +73,7 @@ describe("projectChannelsList", () => {
|
|
|
73
73
|
expect(list.inbox[0]!.toMasked).toContain("***");
|
|
74
74
|
expect(list.outcomes[0]!.state).toBe("delivered-then-complained");
|
|
75
75
|
expect(list.outcomes[0]!.verdict).toBe("review");
|
|
76
|
-
expect(list.suppression.some((s) => s.reason === "prior-bounce")).toBe(
|
|
77
|
-
true,
|
|
78
|
-
);
|
|
76
|
+
expect(list.suppression.some((s) => s.reason === "prior-bounce")).toBe(true);
|
|
79
77
|
});
|
|
80
78
|
|
|
81
79
|
test("fallback summary is a weekly bill line", () => {
|
|
@@ -169,9 +167,7 @@ describe("console.channel.sendTest", () => {
|
|
|
169
167
|
expect(okBody.error).toBeNull();
|
|
170
168
|
expect(okBody.data.ok).toBe(true);
|
|
171
169
|
expect(okBody.data.messageId.length).toBeGreaterThan(0);
|
|
172
|
-
expect(handle.state.channelInbox?.entries.length ?? 0).toBeGreaterThan(
|
|
173
|
-
before,
|
|
174
|
-
);
|
|
170
|
+
expect(handle.state.channelInbox?.entries.length ?? 0).toBeGreaterThan(before);
|
|
175
171
|
} finally {
|
|
176
172
|
await handle.app.stop();
|
|
177
173
|
}
|
|
@@ -135,9 +135,7 @@ export interface ProjectChannelsOptions {
|
|
|
135
135
|
*
|
|
136
136
|
* @param options - Manifest, runtime, inbox, env
|
|
137
137
|
*/
|
|
138
|
-
export function projectChannelsList(
|
|
139
|
-
options: ProjectChannelsOptions,
|
|
140
|
-
): ConsoleChannelsList {
|
|
138
|
+
export function projectChannelsList(options: ProjectChannelsOptions): ConsoleChannelsList {
|
|
141
139
|
const face: ChannelsFace = options.production ? "deliverability" : "inbox";
|
|
142
140
|
const templates = projectTemplates(options.manifest);
|
|
143
141
|
const receipts = options.runtime?.receipts.all() ?? [];
|
|
@@ -184,10 +182,7 @@ export function projectChannelsList(
|
|
|
184
182
|
fallback,
|
|
185
183
|
inbox: projectInbox(options.inbox?.entries ?? [], reveal),
|
|
186
184
|
receipts: projectReceipts(receipts, reveal),
|
|
187
|
-
suppression: projectSuppression(
|
|
188
|
-
options.runtime?.suppression.list() ?? [],
|
|
189
|
-
reveal,
|
|
190
|
-
),
|
|
185
|
+
suppression: projectSuppression(options.runtime?.suppression.list() ?? [], reveal),
|
|
191
186
|
};
|
|
192
187
|
}
|
|
193
188
|
|
|
@@ -215,9 +210,7 @@ export function formatFallbackSummary(delta: {
|
|
|
215
210
|
*
|
|
216
211
|
* @param manifest - Manifest snapshot
|
|
217
212
|
*/
|
|
218
|
-
export function projectTemplates(
|
|
219
|
-
manifest: Manifest | null,
|
|
220
|
-
): readonly ConsoleChannelTemplate[] {
|
|
213
|
+
export function projectTemplates(manifest: Manifest | null): readonly ConsoleChannelTemplate[] {
|
|
221
214
|
return Object.entries(manifest?.channels ?? {})
|
|
222
215
|
.map(([name, c]) => ({
|
|
223
216
|
name,
|
|
@@ -254,18 +247,12 @@ export function previewChannelTemplate(options: {
|
|
|
254
247
|
});
|
|
255
248
|
const catalog = options.catalog ?? {};
|
|
256
249
|
const byLocale = catalog[options.template];
|
|
257
|
-
const entry =
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
byLocale?.en;
|
|
261
|
-
const data = options.data ?? sampleDataFromSchema(
|
|
262
|
-
options.manifest?.channels?.[options.template]?.schema,
|
|
263
|
-
);
|
|
250
|
+
const entry = byLocale?.[resolved.locale] ?? byLocale?.[defaultLocale] ?? byLocale?.en;
|
|
251
|
+
const data =
|
|
252
|
+
options.data ?? sampleDataFromSchema(options.manifest?.channels?.[options.template]?.schema);
|
|
264
253
|
const interpolate = (s: string | undefined): string | null => {
|
|
265
254
|
if (s === undefined) return null;
|
|
266
|
-
return s.replace(/\{\{(\w+)\}\}/g, (_, key: string) =>
|
|
267
|
-
String(data[key] ?? `{{${key}}}`),
|
|
268
|
-
);
|
|
255
|
+
return s.replace(/\{\{(\w+)\}\}/g, (_, key: string) => String(data[key] ?? `{{${key}}}`));
|
|
269
256
|
};
|
|
270
257
|
return {
|
|
271
258
|
template: options.template,
|
|
@@ -348,9 +335,7 @@ export async function sendChannelTest(
|
|
|
348
335
|
locale: input.locale,
|
|
349
336
|
data: input.data,
|
|
350
337
|
});
|
|
351
|
-
const receipt =
|
|
352
|
-
runtime.receipts.byMessageId(result.messageId) ??
|
|
353
|
-
runtime.receipts.all().at(-1);
|
|
338
|
+
const receipt = runtime.receipts.byMessageId(result.messageId) ?? runtime.receipts.all().at(-1);
|
|
354
339
|
return {
|
|
355
340
|
ok: result.ok,
|
|
356
341
|
messageId: result.messageId,
|
|
@@ -451,19 +436,9 @@ function sampleDataFromSchema(schema: unknown): Record<string, unknown> {
|
|
|
451
436
|
const data: Record<string, unknown> = {};
|
|
452
437
|
for (const [key, def] of Object.entries(props)) {
|
|
453
438
|
const t = (def as { type?: string }).type;
|
|
454
|
-
data[key] =
|
|
455
|
-
t === "number" || t === "integer"
|
|
456
|
-
? 1
|
|
457
|
-
: t === "boolean"
|
|
458
|
-
? true
|
|
459
|
-
: `{{${key}}}`;
|
|
439
|
+
data[key] = t === "number" || t === "integer" ? 1 : t === "boolean" ? true : `{{${key}}}`;
|
|
460
440
|
}
|
|
461
441
|
return data;
|
|
462
442
|
}
|
|
463
443
|
|
|
464
|
-
export type {
|
|
465
|
-
DeliveryOutcomeState,
|
|
466
|
-
DeliveryVerdict,
|
|
467
|
-
EmailAuthResult,
|
|
468
|
-
OutcomeRow,
|
|
469
|
-
};
|
|
444
|
+
export type { DeliveryOutcomeState, DeliveryVerdict, EmailAuthResult, OutcomeRow };
|
|
@@ -6,11 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { formatClaimNote } from "../../term.ts";
|
|
9
|
-
import {
|
|
10
|
-
AUTH_RATE_LIMIT,
|
|
11
|
-
AUTH_RATE_WINDOW_MS,
|
|
12
|
-
touchRateLimit,
|
|
13
|
-
} from "./auth-rate.ts";
|
|
9
|
+
import { AUTH_RATE_LIMIT, AUTH_RATE_WINDOW_MS, touchRateLimit } from "./auth-rate.ts";
|
|
14
10
|
|
|
15
11
|
/** Claim-code lifetime (30 minutes). */
|
|
16
12
|
export const CLAIM_TTL_MS = 30 * 60 * 1000;
|
|
@@ -43,9 +39,7 @@ export interface ClaimCodeState {
|
|
|
43
39
|
export function mintClaimCode(now: () => number = Date.now): ClaimCodeState {
|
|
44
40
|
const bytes = new Uint8Array(16);
|
|
45
41
|
crypto.getRandomValues(bytes);
|
|
46
|
-
const code = [...bytes]
|
|
47
|
-
.map((b) => b.toString(16).padStart(2, "0"))
|
|
48
|
-
.join("");
|
|
42
|
+
const code = [...bytes].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
49
43
|
const mintedAt = now();
|
|
50
44
|
return {
|
|
51
45
|
code,
|
|
@@ -116,13 +116,9 @@ describe("projectClocksList", () => {
|
|
|
116
116
|
|
|
117
117
|
expect(list.waitingOn.length).toBe(2);
|
|
118
118
|
expect(list.waitingOn[0]?.label).toBe("verify-window");
|
|
119
|
-
expect(list.waitingOnCounts.some((c) => c.label === "trial-period")).toBe(
|
|
120
|
-
true,
|
|
121
|
-
);
|
|
119
|
+
expect(list.waitingOnCounts.some((c) => c.label === "trial-period")).toBe(true);
|
|
122
120
|
expect(list.timeline.some((e) => e.kind === "wake")).toBe(true);
|
|
123
|
-
expect(list.timeline.every((e) => e.at >= now && e.at < now + 86_400_000)).toBe(
|
|
124
|
-
true,
|
|
125
|
-
);
|
|
121
|
+
expect(list.timeline.every((e) => e.at >= now && e.at < now + 86_400_000)).toBe(true);
|
|
126
122
|
});
|
|
127
123
|
|
|
128
124
|
test("DST ambiguity surfaces only when attached on the row", async () => {
|
|
@@ -93,9 +93,7 @@ const DAY_MS = 24 * 60 * 60 * 1000;
|
|
|
93
93
|
*
|
|
94
94
|
* @param options - Manifest, runtime, journal
|
|
95
95
|
*/
|
|
96
|
-
export async function projectClocksList(
|
|
97
|
-
options: ProjectClocksOptions,
|
|
98
|
-
): Promise<ConsoleClockList> {
|
|
96
|
+
export async function projectClocksList(options: ProjectClocksOptions): Promise<ConsoleClockList> {
|
|
99
97
|
const now = (options.now ?? (() => Date.now()))();
|
|
100
98
|
const until = now + DAY_MS;
|
|
101
99
|
|
|
@@ -131,10 +129,7 @@ export async function projectClocksList(
|
|
|
131
129
|
})
|
|
132
130
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
133
131
|
|
|
134
|
-
const waitingOn = projectWaitingOn(
|
|
135
|
-
options.journal ? await options.journal.list() : [],
|
|
136
|
-
now,
|
|
137
|
-
);
|
|
132
|
+
const waitingOn = projectWaitingOn(options.journal ? await options.journal.list() : [], now);
|
|
138
133
|
const waitingOnCounts = aggregateWaitingOn(waitingOn);
|
|
139
134
|
|
|
140
135
|
const timeline: ConsoleTimelineEvent[] = [];
|
|
@@ -231,10 +226,7 @@ export async function runCronNow(
|
|
|
231
226
|
* @param runtime - Clock runtime
|
|
232
227
|
* @param name - Cron name
|
|
233
228
|
*/
|
|
234
|
-
export async function pauseCronNow(
|
|
235
|
-
runtime: ClockRuntime,
|
|
236
|
-
name: string,
|
|
237
|
-
): Promise<CronRow> {
|
|
229
|
+
export async function pauseCronNow(runtime: ClockRuntime, name: string): Promise<CronRow> {
|
|
238
230
|
return pauseCron(runtime.store, name);
|
|
239
231
|
}
|
|
240
232
|
|
|
@@ -274,10 +266,7 @@ export async function wakeEarlyNow(
|
|
|
274
266
|
});
|
|
275
267
|
}
|
|
276
268
|
|
|
277
|
-
export {
|
|
278
|
-
ClockResourceNotFoundError,
|
|
279
|
-
ScheduleNotOverridableError,
|
|
280
|
-
};
|
|
269
|
+
export { ClockResourceNotFoundError, ScheduleNotOverridableError };
|
|
281
270
|
|
|
282
271
|
/**
|
|
283
272
|
* Bind a ClockRuntime from Manifest clocks (memory store).
|
|
@@ -356,10 +345,7 @@ function rowsFromManifest(manifest: Manifest | null): CronRow[] {
|
|
|
356
345
|
* @param row - Cron row
|
|
357
346
|
* @param manifest - Manifest
|
|
358
347
|
*/
|
|
359
|
-
export function flowIdsForCronRow(
|
|
360
|
-
row: CronRow,
|
|
361
|
-
manifest: Manifest | null,
|
|
362
|
-
): readonly string[] {
|
|
348
|
+
export function flowIdsForCronRow(row: CronRow, manifest: Manifest | null): readonly string[] {
|
|
363
349
|
if (!manifest?.flows) return [];
|
|
364
350
|
const out = new Set<string>();
|
|
365
351
|
for (const [flowId, flow] of Object.entries(manifest.flows)) {
|
|
@@ -370,10 +356,8 @@ export function flowIdsForCronRow(
|
|
|
370
356
|
flowId === row.name ||
|
|
371
357
|
flowId.endsWith(`.${row.name}`) ||
|
|
372
358
|
cronNameForFlow(flowId, every, cron) === row.name ||
|
|
373
|
-
(cron &&
|
|
374
|
-
|
|
375
|
-
(every &&
|
|
376
|
-
(every === row.effectiveEvery || every === row.declaredEvery))
|
|
359
|
+
(cron && (cron === row.effectiveCron || cron === row.declaredCron)) ||
|
|
360
|
+
(every && (every === row.effectiveEvery || every === row.declaredEvery))
|
|
377
361
|
) {
|
|
378
362
|
out.add(flowId);
|
|
379
363
|
}
|
|
@@ -381,9 +365,7 @@ export function flowIdsForCronRow(
|
|
|
381
365
|
return [...out].sort();
|
|
382
366
|
}
|
|
383
367
|
|
|
384
|
-
function isExternal(
|
|
385
|
-
flow: NonNullable<Manifest["flows"]>[string] | undefined,
|
|
386
|
-
): boolean {
|
|
368
|
+
function isExternal(flow: NonNullable<Manifest["flows"]>[string] | undefined): boolean {
|
|
387
369
|
if (!flow?.effects) return false;
|
|
388
370
|
const e = flow.effects;
|
|
389
371
|
return (e.sends?.length ?? 0) > 0 || (e.asks?.length ?? 0) > 0;
|
|
@@ -153,9 +153,7 @@ describe("console kernel", () => {
|
|
|
153
153
|
expect(names).toContain("console.action.ping");
|
|
154
154
|
const pingRun = runs.find((r) => r.flow === "console.action.ping");
|
|
155
155
|
expect(pingRun?.plane).toBe("operator");
|
|
156
|
-
expect(pingRun?.logs.some((l) => l.message.includes("console.action.ping"))).toBe(
|
|
157
|
-
true,
|
|
158
|
-
);
|
|
156
|
+
expect(pingRun?.logs.some((l) => l.message.includes("console.action.ping"))).toBe(true);
|
|
159
157
|
} finally {
|
|
160
158
|
await handle.app.stop();
|
|
161
159
|
}
|
|
@@ -17,11 +17,7 @@ import {
|
|
|
17
17
|
|
|
18
18
|
const NOW = 1_700_000_000_000;
|
|
19
19
|
|
|
20
|
-
function run(
|
|
21
|
-
flow: string,
|
|
22
|
-
startedAt: number,
|
|
23
|
-
id = `${flow}-${startedAt}`,
|
|
24
|
-
): WideEvent {
|
|
20
|
+
function run(flow: string, startedAt: number, id = `${flow}-${startedAt}`): WideEvent {
|
|
25
21
|
return {
|
|
26
22
|
id,
|
|
27
23
|
flow,
|
|
@@ -170,19 +166,11 @@ describe("projectManifestDiff", () => {
|
|
|
170
166
|
});
|
|
171
167
|
|
|
172
168
|
expect(projection.hasBaseline).toBe(true);
|
|
173
|
-
expect(
|
|
174
|
-
|
|
175
|
-
).toBe(true);
|
|
176
|
-
expect(
|
|
177
|
-
projection.changes.some((c) => c.category === "permission-widening"),
|
|
178
|
-
).toBe(true);
|
|
179
|
-
expect(
|
|
180
|
-
projection.changes.some((c) => c.category === "contract-breaking"),
|
|
181
|
-
).toBe(true);
|
|
169
|
+
expect(projection.changes.some((c) => c.category === "effect-widening")).toBe(true);
|
|
170
|
+
expect(projection.changes.some((c) => c.category === "permission-widening")).toBe(true);
|
|
171
|
+
expect(projection.changes.some((c) => c.category === "contract-breaking")).toBe(true);
|
|
182
172
|
|
|
183
|
-
const send = projection.changes.find(
|
|
184
|
-
(c) => c.path.includes("sends") || c.blastLine !== null,
|
|
185
|
-
);
|
|
173
|
+
const send = projection.changes.find((c) => c.path.includes("sends") || c.blastLine !== null);
|
|
186
174
|
expect(send?.runCountLastWeek).toBe(100);
|
|
187
175
|
expect(send?.blastLine).toContain("ran 100 times last week");
|
|
188
176
|
expect(send?.blastLine).toContain("sent nothing");
|