@crvouga/atlas 0.4.0 → 0.6.0
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/CHANGELOG.md +13 -1
- package/README.md +191 -611
- package/dist/bun/src/driver.d.ts +41 -7
- package/dist/bun/src/driver.js +47 -6
- package/dist/bun/src/index.d.ts +8 -0
- package/dist/bun/src/index.js +8 -0
- package/dist/core/src/cli.d.ts +14 -1
- package/dist/core/src/cli.js +35 -1
- package/dist/core/src/config.d.ts +77 -4
- package/dist/core/src/config.js +110 -17
- package/dist/core/src/events/cloudevents.d.ts +54 -9
- package/dist/core/src/events/cloudevents.js +60 -9
- package/dist/core/src/graph.d.ts +21 -0
- package/dist/core/src/graph.js +26 -0
- package/dist/core/src/index.d.ts +11 -0
- package/dist/core/src/index.js +11 -0
- package/dist/core/src/lint.d.ts +30 -0
- package/dist/core/src/lint.js +13 -0
- package/dist/core/src/plan.d.ts +39 -1
- package/dist/core/src/plan.js +28 -1
- package/dist/core/src/privacy.d.ts +29 -2
- package/dist/core/src/privacy.js +19 -2
- package/dist/core/src/report/formats.d.ts +34 -4
- package/dist/core/src/report/formats.js +24 -4
- package/dist/core/src/report/markdown.d.ts +15 -0
- package/dist/core/src/report/markdown.js +8 -0
- package/dist/core/src/run/clients.d.ts +44 -5
- package/dist/core/src/run/clients.js +46 -2
- package/dist/core/src/run/execute.d.ts +75 -16
- package/dist/core/src/run/execute.js +71 -18
- package/dist/core/src/run/frames.d.ts +13 -4
- package/dist/core/src/run/frames.js +19 -4
- package/dist/core/src/run/http.d.ts +34 -1
- package/dist/core/src/run/http.js +14 -1
- package/dist/core/src/run/types.d.ts +76 -3
- package/dist/core/src/run/types.js +19 -3
- package/dist/core/src/signals.d.ts +49 -5
- package/dist/core/src/signals.js +22 -5
- package/dist/core/src/spec/compose.d.ts +23 -1
- package/dist/core/src/spec/compose.js +10 -1
- package/dist/core/src/spec/index.d.ts +9 -1
- package/dist/core/src/spec/index.js +9 -1
- package/dist/core/src/spec/load.d.ts +22 -1
- package/dist/core/src/spec/load.js +31 -1
- package/dist/core/src/spec/parse.d.ts +16 -2
- package/dist/core/src/spec/parse.js +25 -2
- package/dist/core/src/spec/scxml.d.ts +25 -4
- package/dist/core/src/spec/scxml.js +36 -4
- package/dist/core/src/spec/types.d.ts +52 -1
- package/dist/core/src/spec/types.js +24 -0
- package/dist/detox/src/index.d.ts +54 -11
- package/dist/detox/src/index.js +45 -7
- package/dist/playwright/src/driver.d.ts +39 -3
- package/dist/playwright/src/driver.js +27 -3
- package/dist/playwright/src/index.d.ts +10 -0
- package/dist/playwright/src/index.js +10 -0
- package/dist/playwright/src/media.d.ts +50 -4
- package/dist/playwright/src/media.js +55 -4
- package/dist/playwright/src/signals.d.ts +44 -5
- package/dist/playwright/src/signals.js +29 -5
- package/dist/reports/src/attachment-files.d.ts +44 -0
- package/dist/reports/src/attachment-files.js +121 -0
- package/dist/reports/src/attachment-response.d.ts +31 -0
- package/dist/reports/src/attachment-response.js +55 -0
- package/dist/reports/src/aws-credentials.d.ts +48 -0
- package/dist/reports/src/aws-credentials.js +221 -0
- package/dist/reports/src/browser-navigation.d.ts +14 -0
- package/dist/reports/src/browser-navigation.js +7 -0
- package/dist/reports/src/bundle.d.ts +34 -2
- package/dist/reports/src/bundle.js +38 -2
- package/dist/reports/src/catalog.d.ts +34 -3
- package/dist/reports/src/catalog.js +17 -3
- package/dist/reports/src/cli-stores.d.ts +36 -0
- package/dist/reports/src/cli-stores.js +73 -0
- package/dist/reports/src/clock.d.ts +7 -2
- package/dist/reports/src/clock.js +5 -2
- package/dist/reports/src/completion-order.d.ts +18 -5
- package/dist/reports/src/completion-order.js +18 -5
- package/dist/reports/src/compose.d.ts +80 -0
- package/dist/reports/src/compose.js +117 -0
- package/dist/reports/src/copy-store.d.ts +29 -0
- package/dist/reports/src/copy-store.js +52 -0
- package/dist/reports/src/directory-outline.d.ts +38 -0
- package/dist/reports/src/directory-outline.js +103 -0
- package/dist/reports/src/directory-store.d.ts +20 -0
- package/dist/reports/src/directory-store.js +166 -0
- package/dist/reports/src/doctor.d.ts +29 -0
- package/dist/reports/src/doctor.js +85 -0
- package/dist/reports/src/effective-delta.d.ts +34 -0
- package/dist/reports/src/effective-delta.js +25 -0
- package/dist/reports/src/evidence-detail.d.ts +64 -0
- package/dist/reports/src/evidence-detail.js +92 -0
- package/dist/reports/src/evidence-live.d.ts +35 -5
- package/dist/reports/src/evidence-live.js +18 -2
- package/dist/reports/src/evidence-types.d.ts +68 -1
- package/dist/reports/src/evidence-types.js +5 -1
- package/dist/reports/src/evidence-view.d.ts +43 -4
- package/dist/reports/src/evidence-view.js +13 -2
- package/dist/reports/src/explorer-types.d.ts +40 -3
- package/dist/reports/src/explorer-types.js +8 -0
- package/dist/reports/src/explorer-versions.d.ts +9 -1
- package/dist/reports/src/explorer-versions.js +18 -1
- package/dist/reports/src/export-evidence.d.ts +16 -1
- package/dist/reports/src/export-evidence.js +52 -1
- package/dist/reports/src/fetcher.d.ts +27 -3
- package/dist/reports/src/fetcher.js +11 -3
- package/dist/reports/src/format-date.d.ts +6 -0
- package/dist/reports/src/format-date.js +6 -0
- package/dist/reports/src/format.d.ts +16 -0
- package/dist/reports/src/format.js +10 -0
- package/dist/reports/src/frames.d.ts +36 -3
- package/dist/reports/src/frames.js +22 -3
- package/dist/reports/src/hash.d.ts +18 -0
- package/dist/reports/src/hash.js +13 -0
- package/dist/reports/src/host.d.ts +29 -0
- package/dist/reports/src/host.js +64 -0
- package/dist/reports/src/html-frame.d.ts +5 -6
- package/dist/reports/src/html-frame.js +12 -1
- package/dist/reports/src/http-store.d.ts +56 -0
- package/dist/reports/src/http-store.js +148 -0
- package/dist/reports/src/http.d.ts +7 -0
- package/dist/reports/src/http.js +6 -0
- package/dist/reports/src/ingest.d.ts +54 -0
- package/dist/reports/src/ingest.js +210 -0
- package/dist/reports/src/init.d.ts +40 -0
- package/dist/reports/src/init.js +369 -0
- package/dist/reports/src/junit.d.ts +33 -6
- package/dist/reports/src/junit.js +87 -21
- package/dist/reports/src/keyboard.d.ts +20 -0
- package/dist/reports/src/keyboard.js +11 -0
- package/dist/reports/src/keys.d.ts +21 -3
- package/dist/reports/src/keys.js +21 -3
- package/dist/reports/src/layer-axes.d.ts +35 -5
- package/dist/reports/src/layer-axes.js +25 -5
- package/dist/reports/src/layer-catalog.d.ts +28 -1
- package/dist/reports/src/layer-catalog.js +18 -1
- package/dist/reports/src/layer-merge.d.ts +98 -9
- package/dist/reports/src/layer-merge.js +147 -31
- package/dist/reports/src/layer-source.d.ts +18 -0
- package/dist/reports/src/layer-source.js +11 -0
- package/dist/reports/src/layer-store.d.ts +42 -0
- package/dist/reports/src/layer-store.js +63 -5
- package/dist/reports/src/layer-types.d.ts +32 -1
- package/dist/reports/src/layers-route.d.ts +47 -4
- package/dist/reports/src/layers-route.js +86 -7
- package/dist/reports/src/live-reporter.d.ts +34 -0
- package/dist/reports/src/live-reporter.js +122 -0
- package/dist/reports/src/media-types.d.ts +11 -0
- package/dist/reports/src/media-types.js +22 -0
- package/dist/reports/src/namespace-guard.d.ts +10 -1
- package/dist/reports/src/namespace-guard.js +10 -1
- package/dist/reports/src/navigation.d.ts +12 -0
- package/dist/reports/src/navigation.js +7 -0
- package/dist/reports/src/object-io.d.ts +11 -4
- package/dist/reports/src/object-io.js +4 -4
- package/dist/reports/src/object-store-conformance.d.ts +27 -0
- package/dist/reports/src/object-store-conformance.js +87 -0
- package/dist/reports/src/object-store.d.ts +33 -24
- package/dist/reports/src/object-store.js +17 -24
- package/dist/reports/src/parse-with.d.ts +16 -0
- package/dist/reports/src/parse-with.js +14 -0
- package/dist/reports/src/performance-part.d.ts +25 -1
- package/dist/reports/src/performance-part.js +15 -1
- package/dist/reports/src/performance.d.ts +22 -2
- package/dist/reports/src/performance.js +12 -2
- package/dist/reports/src/persist.d.ts +12 -3
- package/dist/reports/src/persist.js +12 -3
- package/dist/reports/src/phone.d.ts +18 -1
- package/dist/reports/src/phone.js +18 -1
- package/dist/reports/src/protocol.d.ts +26 -4
- package/dist/reports/src/protocol.js +15 -4
- package/dist/reports/src/publication.d.ts +21 -1
- package/dist/reports/src/publication.js +21 -1
- package/dist/reports/src/publish-checks.d.ts +35 -0
- package/dist/reports/src/publish-checks.js +122 -0
- package/dist/reports/src/publish.d.ts +42 -9
- package/dist/reports/src/publish.js +36 -7
- package/dist/reports/src/read.d.ts +46 -16
- package/dist/reports/src/read.js +38 -14
- package/dist/reports/src/recording-bundle.d.ts +13 -2
- package/dist/reports/src/recording-bundle.js +4 -2
- package/dist/reports/src/recording-keys.d.ts +15 -1
- package/dist/reports/src/recording-keys.js +15 -1
- package/dist/reports/src/remote-report.d.ts +28 -7
- package/dist/reports/src/remote-report.js +15 -7
- package/dist/reports/src/report-cli.d.ts +51 -0
- package/dist/reports/src/report-cli.js +486 -0
- package/dist/reports/src/report-index.d.ts +99 -0
- package/dist/reports/src/report-index.js +337 -0
- package/dist/reports/src/report-loader.d.ts +10 -0
- package/dist/reports/src/report-loader.js +6 -0
- package/dist/reports/src/report-parts.d.ts +29 -3
- package/dist/reports/src/report-parts.js +37 -3
- package/dist/reports/src/report-status.d.ts +48 -0
- package/dist/reports/src/report-status.js +156 -0
- package/dist/reports/src/report-types.d.ts +73 -0
- package/dist/reports/src/report-types.js +3 -0
- package/dist/reports/src/reporter.d.ts +67 -0
- package/dist/reports/src/reporter.js +128 -0
- package/dist/reports/src/reports-explorer-route.d.ts +541 -0
- package/dist/reports/src/reports-explorer-route.js +11 -0
- package/dist/reports/src/reports-list-route.d.ts +9 -0
- package/dist/reports/src/reports-list-route.js +9 -0
- package/dist/reports/src/reports-route.d.ts +561 -22
- package/dist/reports/src/reports-route.js +11 -3
- package/dist/reports/src/reports-store.d.ts +19 -2
- package/dist/reports/src/reports-store.js +10 -2
- package/dist/reports/src/resilient-cache.d.ts +14 -1
- package/dist/reports/src/resilient-cache.js +8 -1
- package/dist/reports/src/retention.d.ts +17 -1
- package/dist/reports/src/retention.js +5 -1
- package/dist/reports/src/run-bundle.d.ts +63 -0
- package/dist/reports/src/run-bundle.js +159 -0
- package/dist/reports/src/s3-store.d.ts +79 -0
- package/dist/reports/src/s3-store.js +295 -0
- package/dist/reports/src/scenario.d.ts +14 -4
- package/dist/reports/src/scenario.js +5 -4
- package/dist/reports/src/sigv4.d.ts +72 -0
- package/dist/reports/src/sigv4.js +96 -0
- package/dist/reports/src/snapshot-bundle.d.ts +24 -1
- package/dist/reports/src/snapshot-bundle.js +27 -2
- package/dist/reports/src/snapshot-surface.d.ts +20 -9
- package/dist/reports/src/snapshot-surface.js +32 -19
- package/dist/reports/src/source-content.d.ts +23 -0
- package/dist/reports/src/source-content.js +30 -1
- package/dist/reports/src/source-entries.d.ts +13 -0
- package/dist/reports/src/source-entries.js +6 -0
- package/dist/reports/src/source-part.d.ts +15 -0
- package/dist/reports/src/source-part.js +8 -0
- package/dist/reports/src/source-reader.d.ts +11 -0
- package/dist/reports/src/source-reader.js +5 -0
- package/dist/reports/src/spec-evidence.d.ts +12 -2
- package/dist/reports/src/spec-evidence.js +6 -2
- package/dist/reports/src/spec-inventory.d.ts +15 -1
- package/dist/reports/src/spec-inventory.js +22 -1
- package/dist/reports/src/spec-link.d.ts +28 -0
- package/dist/reports/src/spec-link.js +70 -0
- package/dist/reports/src/spec-set.d.ts +63 -0
- package/dist/reports/src/spec-set.js +177 -0
- package/dist/reports/src/status.d.ts +10 -0
- package/dist/reports/src/status.js +5 -0
- package/dist/reports/src/store-prefix.d.ts +28 -0
- package/dist/reports/src/store-prefix.js +22 -0
- package/dist/reports/src/store-url.d.ts +89 -0
- package/dist/reports/src/store-url.js +160 -0
- package/dist/reports/src/test-catalog-entity.d.ts +11 -0
- package/dist/reports/src/test-catalog-entity.js +6 -0
- package/dist/reports/src/types.d.ts +6 -1
- package/dist/reports/src/use-report-nav.d.ts +35 -0
- package/dist/reports/src/use-report-nav.js +12 -0
- package/dist/runners/src/codecept.d.ts +14 -0
- package/dist/runners/src/codecept.js +16 -0
- package/dist/runners/src/jest.d.ts +50 -0
- package/dist/runners/src/jest.js +52 -0
- package/dist/runners/src/mocha.d.ts +40 -0
- package/dist/runners/src/mocha.js +39 -0
- package/dist/runners/src/node-test.d.ts +28 -0
- package/dist/runners/src/node-test.js +44 -0
- package/dist/runners/src/publish.d.ts +30 -0
- package/dist/runners/src/publish.js +68 -0
- package/dist/schema/src/api.d.ts +800 -0
- package/dist/schema/src/api.js +201 -0
- package/dist/schema/src/cli-results.d.ts +210 -0
- package/dist/schema/src/cli-results.js +124 -0
- package/dist/schema/src/common.d.ts +53 -0
- package/dist/schema/src/common.js +42 -0
- package/dist/schema/src/index.d.ts +16 -0
- package/dist/schema/src/index.js +16 -0
- package/dist/schema/src/layer.d.ts +2273 -0
- package/dist/schema/src/layer.js +462 -0
- package/dist/schema/src/live-run.d.ts +123 -0
- package/dist/schema/src/live-run.js +30 -0
- package/dist/schema/src/manifest.d.ts +97 -2
- package/dist/schema/src/manifest.js +84 -0
- package/dist/schema/src/project.d.ts +20 -0
- package/dist/schema/src/project.js +10 -0
- package/dist/schema/src/report-sources.d.ts +29 -0
- package/dist/schema/src/report-sources.js +27 -1
- package/dist/schema/src/runs-index.d.ts +17 -1
- package/dist/schema/src/runs-index.js +15 -0
- package/dist/schema/src/server-config.d.ts +177 -0
- package/dist/schema/src/server-config.js +85 -0
- package/dist/schema/src/spec.d.ts +69 -0
- package/dist/schema/src/spec.js +58 -0
- package/dist/server/src/app.d.ts +72 -0
- package/dist/server/src/app.js +557 -0
- package/dist/server/src/auth.d.ts +41 -0
- package/dist/server/src/auth.js +59 -0
- package/dist/server/src/config.d.ts +83 -0
- package/dist/server/src/config.js +204 -0
- package/dist/server/src/dev.d.ts +12 -0
- package/dist/server/src/dev.js +89 -0
- package/dist/server/src/events.d.ts +29 -0
- package/dist/server/src/events.js +101 -0
- package/dist/server/src/host.d.ts +30 -0
- package/dist/server/src/host.js +115 -0
- package/dist/server/src/index.d.ts +18 -0
- package/dist/server/src/index.js +18 -0
- package/dist/server/src/live-runs.d.ts +52 -0
- package/dist/server/src/live-runs.js +229 -0
- package/dist/server/src/llms.d.ts +19 -0
- package/dist/server/src/llms.js +63 -0
- package/dist/server/src/main.d.ts +30 -0
- package/dist/server/src/main.js +114 -0
- package/dist/server/src/openapi.d.ts +56 -0
- package/dist/server/src/openapi.js +438 -0
- package/dist/server/src/problem.d.ts +8 -0
- package/dist/server/src/problem.js +39 -0
- package/dist/server/src/projects.d.ts +3 -0
- package/dist/server/src/projects.js +154 -0
- package/dist/server/src/settings-page.d.ts +9 -0
- package/dist/server/src/settings-page.js +93 -0
- package/dist/server/src/settings.d.ts +23 -0
- package/dist/server/src/settings.js +72 -0
- package/dist/server/src/site.d.ts +15 -0
- package/dist/server/src/site.js +78 -0
- package/dist/server/src/store-api.d.ts +28 -0
- package/dist/server/src/store-api.js +180 -0
- package/dist/server/src/validate.d.ts +71 -0
- package/dist/server/src/validate.js +197 -0
- package/dist/vitest/src/index.d.ts +27 -5
- package/dist/vitest/src/index.js +18 -5
- package/dist/webdriver/src/driver.d.ts +63 -11
- package/dist/webdriver/src/driver.js +57 -6
- package/dist/webdriver/src/index.d.ts +8 -0
- package/dist/webdriver/src/index.js +1 -0
- package/dist/webdriver/src/protocol.d.ts +75 -6
- package/dist/webdriver/src/protocol.js +79 -6
- package/docs/agents.md +137 -0
- package/docs/deploying.md +345 -0
- package/docs/dogfooding.md +175 -0
- package/docs/extending.md +242 -0
- package/docs/integrating.md +485 -0
- package/docs/reference/bun.md +141 -0
- package/docs/reference/cli.md +148 -0
- package/docs/reference/core.md +2432 -0
- package/docs/reference/detox.md +150 -0
- package/docs/reference/http-api.md +799 -0
- package/docs/reference/playwright.md +303 -0
- package/docs/reference/reports.md +7152 -0
- package/docs/reference/runners.md +169 -0
- package/docs/reference/schema.md +1762 -0
- package/docs/reference/server.md +825 -0
- package/docs/reference/vitest.md +45 -0
- package/docs/reference/webdriver.md +330 -0
- package/docs/report-backends.md +144 -0
- package/docs/report-contract.md +400 -0
- package/docs/reporting-issues.md +160 -0
- package/docs/runners.md +69 -0
- package/docs/server.md +321 -0
- package/docs/statecharts.md +643 -0
- package/llms-full.txt +4114 -0
- package/llms.txt +49 -0
- package/package.json +61 -11
- package/packages/core/README.md +2 -1
- package/packages/reports/README.md +65 -0
- package/packages/reports/STORAGE.md +4 -0
- package/packages/runners/README.md +6 -0
- package/packages/runners/compat/codecept.cjs +2 -0
- package/packages/runners/compat/jest.cjs +2 -0
- package/packages/runners/compat/mocha.cjs +2 -0
- package/packages/schema/README.md +14 -0
- package/packages/schema/schemas/atlas-change.schema.json +4 -0
- package/packages/schema/schemas/check-detail.schema.json +1032 -0
- package/packages/schema/schemas/checks-result.schema.json +26 -0
- package/packages/schema/schemas/command-error.schema.json +35 -0
- package/packages/schema/schemas/doctor-result.schema.json +60 -0
- package/packages/schema/schemas/effective-delta.schema.json +490 -0
- package/packages/schema/schemas/effective-evidence.schema.json +471 -0
- package/packages/schema/schemas/evidence-page.schema.json +271 -0
- package/packages/schema/schemas/hello-event.schema.json +26 -0
- package/packages/schema/schemas/init-plan.schema.json +347 -0
- package/packages/schema/schemas/layer-rows.schema.json +199 -0
- package/packages/schema/schemas/layer.schema.json +2888 -0
- package/packages/schema/schemas/live-run-start.schema.json +42 -0
- package/packages/schema/schemas/live-run-update.schema.json +93 -0
- package/packages/schema/schemas/live-run.schema.json +225 -0
- package/packages/schema/schemas/merge-result.schema.json +40 -0
- package/packages/schema/schemas/outline.schema.json +62 -0
- package/packages/schema/schemas/problem.schema.json +37 -0
- package/packages/schema/schemas/project-slug.schema.json +8 -0
- package/packages/schema/schemas/project.schema.json +22 -0
- package/packages/schema/schemas/projects.schema.json +33 -0
- package/packages/schema/schemas/publish-checks.schema.json +1413 -0
- package/packages/schema/schemas/publish-result.schema.json +168 -0
- package/packages/schema/schemas/ready.schema.json +68 -0
- package/packages/schema/schemas/report-event.schema.json +100 -0
- package/packages/schema/schemas/report-status.schema.json +370 -0
- package/packages/schema/schemas/server-config.schema.json +208 -0
- package/packages/schema/schemas/server-editable-settings.schema.json +132 -0
- package/packages/schema/schemas/server-info.schema.json +114 -0
- package/packages/schema/schemas/server-settings-snapshot.schema.json +285 -0
- package/packages/schema/schemas/spec-set.schema.json +103 -0
- package/packages/schema/schemas/store-listing.schema.json +29 -0
- package/packages/schema/schemas/store-write-result.schema.json +28 -0
- package/packages/schema/schemas/stream-result.schema.json +59 -0
- package/packages/server/README.md +43 -0
- package/packages/server/openapi.json +11021 -0
- package/packages/visualizer/README.md +32 -11
- package/packages/visualizer/bin/atlas-client.mjs +176 -0
- package/packages/visualizer/bin/atlas-visualizer.mjs +2 -175
- package/packages/visualizer/src/app/AppShell.tsx +32 -16
- package/packages/visualizer/src/app/report-sources.tsx +7 -4
- package/packages/visualizer/src/app/router.tsx +3 -3
- package/packages/visualizer/src/components/ActivityIndicator.module.css +4 -0
- package/packages/visualizer/src/components/ActivityIndicator.tsx +6 -0
- package/packages/visualizer/src/components/Header.module.css +101 -192
- package/packages/visualizer/src/components/Header.tsx +88 -13
- package/packages/visualizer/src/components/ProjectPicker.tsx +64 -0
- package/packages/visualizer/src/data/adapters/adapter.ts +5 -17
- package/packages/visualizer/src/data/adapters/index.ts +10 -1
- package/packages/visualizer/src/data/adapters/report-backend.test.ts +3 -2
- package/packages/visualizer/src/data/adapters/report-backend.ts +1 -1
- package/packages/visualizer/src/data/queries.ts +14 -7
- package/packages/visualizer/src/evidence/api.ts +16 -3
- package/packages/visualizer/src/evidence/artifacts.module.css +213 -0
- package/packages/visualizer/src/evidence/artifacts.tsx +272 -0
- package/packages/visualizer/src/evidence/check-detail.tsx +21 -4
- package/packages/visualizer/src/evidence/document-page.tsx +6 -2
- package/packages/visualizer/src/evidence/evidence-context.tsx +79 -12
- package/packages/visualizer/src/evidence/evidence.module.css +11 -1
- package/packages/visualizer/src/evidence/feature-page.tsx +7 -3
- package/packages/visualizer/src/evidence/model-page.tsx +6 -2
- package/packages/visualizer/src/evidence/project-home.tsx +45 -0
- package/packages/visualizer/src/evidence/recording-page.tsx +4 -1
- package/packages/visualizer/src/evidence/spec-index.tsx +2 -1
- package/packages/visualizer/src/evidence/spec-page.tsx +23 -16
- package/packages/visualizer/src/evidence/test-filter.tsx +21 -0
- package/packages/visualizer/src/find/Finder.tsx +1 -7
- package/packages/visualizer/src/find/open.ts +4 -0
- package/packages/visualizer/src/live/live-query.ts +21 -0
- package/packages/visualizer/src/live/live-runs.tsx +69 -0
- package/packages/visualizer/src/live/live-stream.ts +225 -0
- package/packages/visualizer/src/live/report-progress.ts +62 -0
- package/packages/visualizer/src/live/test-progress.tsx +34 -0
- package/packages/visualizer/src/runtime.ts +35 -0
- package/packages/visualizer/src/state/ui-store.ts +3 -2
- package/packages/visualizer/src/views/ChartPage.tsx +2 -0
- package/packages/visualizer/src/views/ChartTests.tsx +43 -0
- package/packages/visualizer/src/views/SidePanel.tsx +2 -0
- package/packages/visualizer/vite/atlas-files.test.ts +4 -4
- package/packages/visualizer/vite/atlas-files.ts +1 -5
- package/packages/visualizer/vite/atlas-server-proxy.ts +37 -0
- package/packages/visualizer/vite.config.ts +11 -3
|
@@ -1,41 +1,34 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* @module ObjectStore interface
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* The one interface a backend implements: seven async methods over keys and bytes, with no transactions, renames,
|
|
5
|
+
* locks or conditional writes. That is what lets a directory, an S3-compatible bucket, an HTTP server and a device
|
|
6
|
+
* lab hold the same report. Implementations here are `directoryStore`, `s3Store` and `httpStore`; `verifyObjectStore`
|
|
7
|
+
* proves a new one. This interface is part of the stable report contract.
|
|
7
8
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
9
|
+
* Read semantics: `get` returns `null` when the key is missing; transport and parse errors throw. `head` returns
|
|
10
|
+
* `false` for a missing key and never throws on "not found".
|
|
10
11
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* parse errors throw.
|
|
14
|
-
* - {@link ObjectStore.head} returns `false` for a missing key (never throws on
|
|
15
|
-
* "not found"). Transport errors throw.
|
|
12
|
+
* Write semantics: `put` is idempotent (writing a key twice overwrites without error) and the stored `contentType`
|
|
13
|
+
* round-trips through `get`. `delete` and `deleteMany` on a missing key are no-ops.
|
|
16
14
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* overwrites without error. Stored `contentType` MUST round-trip through
|
|
20
|
-
* {@link ObjectStore.get}.
|
|
21
|
-
* - {@link ObjectStore.delete} on a missing key is a no-op (does not throw).
|
|
15
|
+
* URI semantics: `getUri` returns a URL the host can load directly (a `file://` URL for a directory, a presigned URL
|
|
16
|
+
* for S3), or `null` for a missing key or a store with no addressable URL.
|
|
22
17
|
*
|
|
23
|
-
*
|
|
24
|
-
* - {@link ObjectStore.getUri} returns a URL the host runtime can load
|
|
25
|
-
* directly (`file://` on native, `blob:` on web). Stores that don't expose
|
|
26
|
-
* direct URLs (e.g. remote R2 — bytes must be streamed through HTTP)
|
|
27
|
-
* return `null`. Returns `null` when the key is missing.
|
|
18
|
+
* Listing: `listKeys` returns keys in sorted code-unit order, optionally only those starting with `prefix`.
|
|
28
19
|
*
|
|
29
|
-
*
|
|
30
|
-
* - {@link ObjectStore.listKeys} returns keys in sorted code-unit order
|
|
31
|
-
* (deterministic). Optional `prefix` filters to keys that start with it.
|
|
20
|
+
* @see docs/report-contract.md#backends
|
|
32
21
|
*/
|
|
22
|
+
/** An object read from a store: a one-shot byte stream with its media type and length. */
|
|
33
23
|
export interface StoredObject {
|
|
34
24
|
/** Stream of stored bytes. Single-use; consume or discard before issuing more I/O on the same store. */
|
|
35
25
|
readonly body: ReadableStream<Uint8Array>;
|
|
26
|
+
/** The media type the object was written with. */
|
|
36
27
|
readonly contentType: string;
|
|
28
|
+
/** The length of the object in bytes. */
|
|
37
29
|
readonly size: number;
|
|
38
30
|
}
|
|
31
|
+
/** A place that holds objects by key: the backend interface of the report contract. Keys are `/`-separated strings; see each method for its rules. */
|
|
39
32
|
export interface ObjectStore {
|
|
40
33
|
/** Returns the stored object, or `null` if no value exists for `key`. */
|
|
41
34
|
get(key: string): Promise<StoredObject | null>;
|
|
@@ -65,3 +58,19 @@ export interface ObjectStore {
|
|
|
65
58
|
*/
|
|
66
59
|
withPrefix(prefix: string): ObjectStore;
|
|
67
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Optional, beyond the seven methods: list one page of keys, starting after a key. A reader that has
|
|
63
|
+
* already seen most of a catalog uses it to find what is new without listing all of it. A store without
|
|
64
|
+
* it works the same, a little slower. Pages are in the same code-unit order as {@link ObjectStore.listKeys}.
|
|
65
|
+
*/
|
|
66
|
+
export interface PagedListing {
|
|
67
|
+
listPage(prefix: string, options?: {
|
|
68
|
+
readonly after?: string;
|
|
69
|
+
readonly limit?: number;
|
|
70
|
+
}): Promise<{
|
|
71
|
+
readonly keys: readonly string[]; /** The `after` for the next page, or null on the last. */
|
|
72
|
+
readonly next: string | null;
|
|
73
|
+
}>;
|
|
74
|
+
}
|
|
75
|
+
/** Whether a store also implements `PagedListing`. */
|
|
76
|
+
export declare function isPaged(store: ObjectStore): store is ObjectStore & PagedListing;
|
|
@@ -1,32 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* @module ObjectStore interface
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* The one interface a backend implements: seven async methods over keys and bytes, with no transactions, renames,
|
|
5
|
+
* locks or conditional writes. That is what lets a directory, an S3-compatible bucket, an HTTP server and a device
|
|
6
|
+
* lab hold the same report. Implementations here are `directoryStore`, `s3Store` and `httpStore`; `verifyObjectStore`
|
|
7
|
+
* proves a new one. This interface is part of the stable report contract.
|
|
7
8
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
9
|
+
* Read semantics: `get` returns `null` when the key is missing; transport and parse errors throw. `head` returns
|
|
10
|
+
* `false` for a missing key and never throws on "not found".
|
|
10
11
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* parse errors throw.
|
|
14
|
-
* - {@link ObjectStore.head} returns `false` for a missing key (never throws on
|
|
15
|
-
* "not found"). Transport errors throw.
|
|
12
|
+
* Write semantics: `put` is idempotent (writing a key twice overwrites without error) and the stored `contentType`
|
|
13
|
+
* round-trips through `get`. `delete` and `deleteMany` on a missing key are no-ops.
|
|
16
14
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* overwrites without error. Stored `contentType` MUST round-trip through
|
|
20
|
-
* {@link ObjectStore.get}.
|
|
21
|
-
* - {@link ObjectStore.delete} on a missing key is a no-op (does not throw).
|
|
15
|
+
* URI semantics: `getUri` returns a URL the host can load directly (a `file://` URL for a directory, a presigned URL
|
|
16
|
+
* for S3), or `null` for a missing key or a store with no addressable URL.
|
|
22
17
|
*
|
|
23
|
-
*
|
|
24
|
-
* - {@link ObjectStore.getUri} returns a URL the host runtime can load
|
|
25
|
-
* directly (`file://` on native, `blob:` on web). Stores that don't expose
|
|
26
|
-
* direct URLs (e.g. remote R2 — bytes must be streamed through HTTP)
|
|
27
|
-
* return `null`. Returns `null` when the key is missing.
|
|
18
|
+
* Listing: `listKeys` returns keys in sorted code-unit order, optionally only those starting with `prefix`.
|
|
28
19
|
*
|
|
29
|
-
*
|
|
30
|
-
* - {@link ObjectStore.listKeys} returns keys in sorted code-unit order
|
|
31
|
-
* (deterministic). Optional `prefix` filters to keys that start with it.
|
|
20
|
+
* @see docs/report-contract.md#backends
|
|
32
21
|
*/
|
|
22
|
+
/** Whether a store also implements `PagedListing`. */
|
|
23
|
+
export function isPaged(store) {
|
|
24
|
+
return typeof store.listPage === 'function';
|
|
25
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Schema parsing with readable errors
|
|
3
|
+
*
|
|
4
|
+
* One helper that parses untrusted input with a Zod schema and turns every problem into a single error message that
|
|
5
|
+
* names each failing path, so a publisher can tell a person exactly which field to fix.
|
|
6
|
+
*/
|
|
7
|
+
import type { z } from 'zod/v4';
|
|
8
|
+
/**
|
|
9
|
+
* Parses `input` with `schema` and returns the parsed value, or throws one `Error` naming every problem by its path.
|
|
10
|
+
*
|
|
11
|
+
* The message is `<subject>: <path>: <message>; <path>: <message>`, with `(input)` as the path of a problem at the
|
|
12
|
+
* root. Nothing is returned partially: on any problem it throws.
|
|
13
|
+
*
|
|
14
|
+
* @param subject what is being parsed, as the person would call it (for example `checks file`); prefixes the message.
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseWith<S extends z.ZodType>(schema: S, input: unknown, subject: string): z.output<S>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses `input` with `schema` and returns the parsed value, or throws one `Error` naming every problem by its path.
|
|
3
|
+
*
|
|
4
|
+
* The message is `<subject>: <path>: <message>; <path>: <message>`, with `(input)` as the path of a problem at the
|
|
5
|
+
* root. Nothing is returned partially: on any problem it throws.
|
|
6
|
+
*
|
|
7
|
+
* @param subject what is being parsed, as the person would call it (for example `checks file`); prefixes the message.
|
|
8
|
+
*/
|
|
9
|
+
export function parseWith(schema, input, subject) {
|
|
10
|
+
const parsed = schema.safeParse(input);
|
|
11
|
+
if (parsed.success)
|
|
12
|
+
return parsed.data;
|
|
13
|
+
throw new Error(`${subject}: ${parsed.error.issues.map(issue => `${issue.path.join('.') || '(input)'}: ${issue.message}`).join('; ')}`);
|
|
14
|
+
}
|
|
@@ -1,6 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Performance part of a report
|
|
3
|
+
*
|
|
4
|
+
* Turns the measured step timings of recorded test runs into a `performance`-kind report part, one check per run,
|
|
5
|
+
* so slow actions show beside the behaviour checks. The part is diagnostic: `performance` is the kind that composition
|
|
6
|
+
* leaves out of counts when anything else was recorded, and a measurement over its limit never fails a check on its
|
|
7
|
+
* own (here only a step over the allowance marks the diagnostic check `failed`).
|
|
8
|
+
*
|
|
9
|
+
* @see docs/report-contract.md#statuses-and-the-gate
|
|
10
|
+
*/
|
|
1
11
|
import type { RunReport } from './report-types.js';
|
|
2
12
|
import type { ReportPart } from './explorer-types.js';
|
|
3
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* Builds a `performance` part with one check per run report, judging each step's own recorded time against
|
|
15
|
+
* `allowanceMs`. No missing measurement becomes a pass.
|
|
16
|
+
*
|
|
17
|
+
* A check is `failed` when any step's self time is over `allowanceMs`; `not-run` when the run has no steps or any step
|
|
18
|
+
* has no measurement; otherwise `passed`. Its `id` and `title` are the run's `testId` and `title`, its `specPath` the
|
|
19
|
+
* run's `sourceFile` when known, and it carries one measurement, `Longest own action` in ms with the allowance as its
|
|
20
|
+
* `limit`, when anything was measured. The part's id is `recorded-performance`. Throws `Invalid performance allowance`
|
|
21
|
+
* when `allowanceMs` is not a positive finite number.
|
|
22
|
+
*
|
|
23
|
+
* @param args.sha the commit the runs were recorded at.
|
|
24
|
+
* @param args.recordedAtMs when the runs were recorded, epoch milliseconds.
|
|
25
|
+
* @param args.allowanceMs the diagnostic allowance for one step's own time, in milliseconds.
|
|
26
|
+
* @param args.reports the recorded runs.
|
|
27
|
+
*/
|
|
4
28
|
export declare function performancePart(args: {
|
|
5
29
|
readonly sha: string;
|
|
6
30
|
readonly recordedAtMs: number;
|
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
import { performanceRows } from './performance.js';
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* Builds a `performance` part with one check per run report, judging each step's own recorded time against
|
|
4
|
+
* `allowanceMs`. No missing measurement becomes a pass.
|
|
5
|
+
*
|
|
6
|
+
* A check is `failed` when any step's self time is over `allowanceMs`; `not-run` when the run has no steps or any step
|
|
7
|
+
* has no measurement; otherwise `passed`. Its `id` and `title` are the run's `testId` and `title`, its `specPath` the
|
|
8
|
+
* run's `sourceFile` when known, and it carries one measurement, `Longest own action` in ms with the allowance as its
|
|
9
|
+
* `limit`, when anything was measured. The part's id is `recorded-performance`. Throws `Invalid performance allowance`
|
|
10
|
+
* when `allowanceMs` is not a positive finite number.
|
|
11
|
+
*
|
|
12
|
+
* @param args.sha the commit the runs were recorded at.
|
|
13
|
+
* @param args.recordedAtMs when the runs were recorded, epoch milliseconds.
|
|
14
|
+
* @param args.allowanceMs the diagnostic allowance for one step's own time, in milliseconds.
|
|
15
|
+
* @param args.reports the recorded runs.
|
|
16
|
+
*/
|
|
3
17
|
export function performancePart(args) {
|
|
4
18
|
if (!Number.isFinite(args.allowanceMs) || args.allowanceMs <= 0)
|
|
5
19
|
throw new Error('Invalid performance allowance');
|
|
@@ -1,13 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Performance heat of recorded steps
|
|
3
|
+
*
|
|
4
|
+
* Classifies each step of a recorded run by how long its own work took against an allowance, ranks hotspots, and
|
|
5
|
+
* indexes steps to a frame for a heatmap. Pure functions over `ReportStep` trees. The allowance is a diagnostic
|
|
6
|
+
* threshold, not a portable CPU or paint-time assertion.
|
|
7
|
+
*/
|
|
1
8
|
import type { ReportStep } from './report-types.js';
|
|
2
9
|
import { type FlatFrame, type FlatStep } from './frames.js';
|
|
10
|
+
/** How a step's own time compares with the allowance: `unmeasured` (no valid time), `cool`, `warm` (over a quarter of it) or `slow` (over it). */
|
|
3
11
|
export type HeatBand = 'unmeasured' | 'cool' | 'warm' | 'slow';
|
|
12
|
+
/** A flattened step with its heat band. */
|
|
4
13
|
export type PerformanceRow = FlatStep & {
|
|
14
|
+
/** The step's `performance.selfMs` classified by `heatBand`. */
|
|
5
15
|
readonly band: HeatBand;
|
|
6
16
|
};
|
|
17
|
+
/**
|
|
18
|
+
* Classifies a duration in milliseconds against `allowanceMs`: `unmeasured` when it is missing, not finite or
|
|
19
|
+
* negative; `slow` when over the allowance; `warm` when over a quarter of it; otherwise `cool`.
|
|
20
|
+
*/
|
|
7
21
|
export declare function heatBand(ms: number | undefined, allowanceMs: number): HeatBand;
|
|
22
|
+
/** Flattens a step tree depth-first (parents before children) into rows, each banded by its own recorded time (`performance.selfMs`) against `allowanceMs`. */
|
|
8
23
|
export declare function performanceRows(steps: readonly ReportStep[], allowanceMs: number): PerformanceRow[];
|
|
9
|
-
/** Self time attributes nested work once, instead of ranking every ancestor as slow. */
|
|
24
|
+
/** The measured rows, longest own time first and earlier rows first on a tie. Self time attributes nested work once, instead of ranking every ancestor as slow. Sorts in place the array it builds, not `rows`. */
|
|
10
25
|
export declare function performanceHotspots(rows: readonly PerformanceRow[]): PerformanceRow[];
|
|
26
|
+
/** Formats a millisecond duration for display with two decimals, like `12.34 ms`. */
|
|
11
27
|
export declare function measuredMs(ms: number): string;
|
|
12
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* Maps each step to a frame in one linear pass: its own first frame, or failing that the first frame of its first
|
|
30
|
+
* child that has one (found walking `rows` from the end, so deeper steps resolve first). Steps with no frame in their
|
|
31
|
+
* subtree are absent. Meant for a large heatmap where a per-step search would be quadratic.
|
|
32
|
+
*/
|
|
13
33
|
export declare function performanceFrameIndex(rows: readonly PerformanceRow[], frames: readonly FlatFrame[]): ReadonlyMap<ReportStep, FlatFrame>;
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { flattenSteps } from './frames.js';
|
|
2
|
+
/**
|
|
3
|
+
* Classifies a duration in milliseconds against `allowanceMs`: `unmeasured` when it is missing, not finite or
|
|
4
|
+
* negative; `slow` when over the allowance; `warm` when over a quarter of it; otherwise `cool`.
|
|
5
|
+
*/
|
|
2
6
|
export function heatBand(ms, allowanceMs) {
|
|
3
7
|
if (ms === undefined || !Number.isFinite(ms) || ms < 0)
|
|
4
8
|
return 'unmeasured';
|
|
@@ -6,23 +10,29 @@ export function heatBand(ms, allowanceMs) {
|
|
|
6
10
|
return 'slow';
|
|
7
11
|
return ms > allowanceMs / 4 ? 'warm' : 'cool';
|
|
8
12
|
}
|
|
13
|
+
/** Flattens a step tree depth-first (parents before children) into rows, each banded by its own recorded time (`performance.selfMs`) against `allowanceMs`. */
|
|
9
14
|
export function performanceRows(steps, allowanceMs) {
|
|
10
15
|
return flattenSteps(steps).map((row) => ({
|
|
11
16
|
...row,
|
|
12
17
|
band: heatBand(row.step.performance?.selfMs, allowanceMs),
|
|
13
18
|
}));
|
|
14
19
|
}
|
|
15
|
-
/** Self time attributes nested work once, instead of ranking every ancestor as slow. */
|
|
20
|
+
/** The measured rows, longest own time first and earlier rows first on a tie. Self time attributes nested work once, instead of ranking every ancestor as slow. Sorts in place the array it builds, not `rows`. */
|
|
16
21
|
export function performanceHotspots(rows) {
|
|
17
22
|
return rows
|
|
18
23
|
.filter((row) => row.band !== 'unmeasured')
|
|
19
24
|
.sort((a, b) => (b.step.performance?.selfMs ?? 0) - (a.step.performance?.selfMs ?? 0) ||
|
|
20
25
|
a.index - b.index);
|
|
21
26
|
}
|
|
27
|
+
/** Formats a millisecond duration for display with two decimals, like `12.34 ms`. */
|
|
22
28
|
export function measuredMs(ms) {
|
|
23
29
|
return `${ms.toFixed(2)} ms`;
|
|
24
30
|
}
|
|
25
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* Maps each step to a frame in one linear pass: its own first frame, or failing that the first frame of its first
|
|
33
|
+
* child that has one (found walking `rows` from the end, so deeper steps resolve first). Steps with no frame in their
|
|
34
|
+
* subtree are absent. Meant for a large heatmap where a per-step search would be quadratic.
|
|
35
|
+
*/
|
|
26
36
|
export function performanceFrameIndex(rows, frames) {
|
|
27
37
|
const byStep = new Map();
|
|
28
38
|
for (const frame of frames) {
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* @module Query cache persistence
|
|
3
|
+
*
|
|
4
|
+
* Persists the viewer's TanStack query cache into a `ReportCache` (IndexedDB in the browser) so a reload starts from
|
|
5
|
+
* what was already fetched. Frame-file queries stay out of this document: those bytes live in `ReportCache` on their
|
|
6
|
+
* own keys.
|
|
4
7
|
*/
|
|
5
8
|
import { type Persister } from '@tanstack/query-persist-client-core';
|
|
6
9
|
import type { QueryClient } from '@tanstack/solid-query';
|
|
7
10
|
import type { ReportCache } from './fetcher.js';
|
|
11
|
+
/** A TanStack `Persister` that keeps the whole query client as one JSON string under one key in `cache`. A stored value that is not valid JSON is removed and treated as no cache. */
|
|
8
12
|
export declare function reportPersister(cache: ReportCache): Persister;
|
|
9
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* Restores the query client from `cache`, then keeps writing it back as queries change. Returns
|
|
15
|
+
* `[unsubscribe, restored]`: the function that stops writing, and a promise that settles when the restore is done.
|
|
16
|
+
* Only successful queries are stored, never `blob` queries (those are the frame files); a stored cache older than a
|
|
17
|
+
* week, or from a different cache version, is discarded.
|
|
18
|
+
*/
|
|
10
19
|
export declare function attachReportCache(client: QueryClient, cache: ReportCache): [() => void, Promise<void>];
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* @module Query cache persistence
|
|
3
|
+
*
|
|
4
|
+
* Persists the viewer's TanStack query cache into a `ReportCache` (IndexedDB in the browser) so a reload starts from
|
|
5
|
+
* what was already fetched. Frame-file queries stay out of this document: those bytes live in `ReportCache` on their
|
|
6
|
+
* own keys.
|
|
4
7
|
*/
|
|
5
8
|
import { persistQueryClient, } from '@tanstack/query-persist-client-core';
|
|
6
9
|
const CACHE_KEY = 'reports-query-cache';
|
|
7
10
|
const WEEK = 7 * 24 * 60 * 60 * 1000;
|
|
11
|
+
/** A TanStack `Persister` that keeps the whole query client as one JSON string under one key in `cache`. A stored value that is not valid JSON is removed and treated as no cache. */
|
|
8
12
|
export function reportPersister(cache) {
|
|
9
13
|
return {
|
|
10
14
|
persistClient: (client) => cache.set(CACHE_KEY, JSON.stringify(client)),
|
|
@@ -26,7 +30,12 @@ export function reportPersister(cache) {
|
|
|
26
30
|
function keepQuery(query) {
|
|
27
31
|
return query.state.status === 'success' && query.queryKey[1] !== 'blob';
|
|
28
32
|
}
|
|
29
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* Restores the query client from `cache`, then keeps writing it back as queries change. Returns
|
|
35
|
+
* `[unsubscribe, restored]`: the function that stops writing, and a promise that settles when the restore is done.
|
|
36
|
+
* Only successful queries are stored, never `blob` queries (those are the frame files); a stored cache older than a
|
|
37
|
+
* week, or from a different cache version, is discarded.
|
|
38
|
+
*/
|
|
30
39
|
export function attachReportCache(client, cache) {
|
|
31
40
|
return persistQueryClient({
|
|
32
41
|
queryClient: client,
|
|
@@ -1,5 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Phone frame geometry
|
|
3
|
+
*
|
|
4
|
+
* The fixed size of the phone-shaped frame snapshots are shown in, how to scale it to a box, and cleaning of
|
|
5
|
+
* recorded page HTML before it is shown.
|
|
6
|
+
*/
|
|
7
|
+
/** Width of the phone frame snapshots render in, in CSS pixels. */
|
|
1
8
|
export declare const PHONE_W = 390;
|
|
9
|
+
/** Height of the phone frame snapshots render in, in CSS pixels. */
|
|
2
10
|
export declare const PHONE_H = 844;
|
|
11
|
+
/**
|
|
12
|
+
* The scale to draw the phone frame at: a fixed `0.5`, `0.75` or `1` for modes `'50'`, `'75'`, `'100'`; for any other
|
|
13
|
+
* mode, the largest scale up to 1 that fits a wrapper of `wrapW` by `wrapH` pixels (leaving 8 px), or `0.4` when
|
|
14
|
+
* that is not a positive finite number.
|
|
15
|
+
*/
|
|
3
16
|
export declare function zoomScale(mode: string, wrapW: number, wrapH: number): number;
|
|
4
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* Removes every `<script>` element and the `<link>` to `snapshot-shell.css` from recorded page HTML. The stylesheet is
|
|
19
|
+
* replaced by the layer's `frame.css`. This is a regex rewrite, not a sanitiser: inline event handlers and everything
|
|
20
|
+
* else stay, so it is not a security boundary (render snapshots in a sandbox).
|
|
21
|
+
*/
|
|
5
22
|
export declare function cleanSnapshotHtml(html: string): string;
|
|
@@ -1,7 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Phone frame geometry
|
|
3
|
+
*
|
|
4
|
+
* The fixed size of the phone-shaped frame snapshots are shown in, how to scale it to a box, and cleaning of
|
|
5
|
+
* recorded page HTML before it is shown.
|
|
6
|
+
*/
|
|
7
|
+
/** Width of the phone frame snapshots render in, in CSS pixels. */
|
|
1
8
|
export const PHONE_W = 390;
|
|
9
|
+
/** Height of the phone frame snapshots render in, in CSS pixels. */
|
|
2
10
|
export const PHONE_H = 844;
|
|
3
11
|
const SHELL_LINK_RE = /<link\b[^>]*href=["'][^"']*snapshot-shell\.css["'][^>]*>\s*/gi;
|
|
4
12
|
const SCRIPT_RE = /<script\b[^>]*>[\s\S]*?<\/script>/gi;
|
|
13
|
+
/**
|
|
14
|
+
* The scale to draw the phone frame at: a fixed `0.5`, `0.75` or `1` for modes `'50'`, `'75'`, `'100'`; for any other
|
|
15
|
+
* mode, the largest scale up to 1 that fits a wrapper of `wrapW` by `wrapH` pixels (leaving 8 px), or `0.4` when
|
|
16
|
+
* that is not a positive finite number.
|
|
17
|
+
*/
|
|
5
18
|
export function zoomScale(mode, wrapW, wrapH) {
|
|
6
19
|
if (mode === '50')
|
|
7
20
|
return 0.5;
|
|
@@ -12,7 +25,11 @@ export function zoomScale(mode, wrapW, wrapH) {
|
|
|
12
25
|
const s = Math.min(1, (wrapW - 8) / PHONE_W, (wrapH - 8) / PHONE_H);
|
|
13
26
|
return !Number.isFinite(s) || s <= 0 ? 0.4 : s;
|
|
14
27
|
}
|
|
15
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* Removes every `<script>` element and the `<link>` to `snapshot-shell.css` from recorded page HTML. The stylesheet is
|
|
30
|
+
* replaced by the layer's `frame.css`. This is a regex rewrite, not a sanitiser: inline event handlers and everything
|
|
31
|
+
* else stay, so it is not a security boundary (render snapshots in a sandbox).
|
|
32
|
+
*/
|
|
16
33
|
export function cleanSnapshotHtml(html) {
|
|
17
34
|
return html.replace(SCRIPT_RE, '').replace(SHELL_LINK_RE, '');
|
|
18
35
|
}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* @module Commit-keyed recording protocol
|
|
3
|
+
*
|
|
4
|
+
* The shapes of what the reports store holds for a commit (`commits/<sha>/commit.json`, `sources/<source>.json`) and of
|
|
5
|
+
* the Server-Sent Events a reports API streams about them, plus the codec for those events. These are the older,
|
|
6
|
+
* commit-keyed recordings that layers are composed beside; layers themselves are described by the layer document.
|
|
7
|
+
* Types and a small codec only, so it is safe in a Worker, a CLI and a browser alike.
|
|
8
|
+
*
|
|
9
|
+
* @see docs/report-backends.md
|
|
5
10
|
*/
|
|
6
11
|
import type { HtmlReportBlob } from './recording-bundle.js';
|
|
7
12
|
import type { ReportTestStatus, RunReport, RunReportMeta } from './report-types.js';
|
|
@@ -10,11 +15,15 @@ import type { ReportPartOutput, WorkspaceVersion } from './explorer-types.js';
|
|
|
10
15
|
export type CommitState = 'running' | 'complete';
|
|
11
16
|
/** `commits/<sha>/commit.json`: one published run of every spec of a commit. */
|
|
12
17
|
export type CommitRecord = {
|
|
18
|
+
/** The full 40-hex commit sha. */
|
|
13
19
|
readonly sha: string;
|
|
14
20
|
readonly branch: string;
|
|
21
|
+
/** The CI run that published it, or `null`. */
|
|
15
22
|
readonly runUrl: string | null;
|
|
16
23
|
readonly state: CommitState;
|
|
24
|
+
/** When the run started, epoch milliseconds. */
|
|
17
25
|
readonly startedAtMs: number;
|
|
26
|
+
/** When the run closed, epoch milliseconds; `null` while running. */
|
|
18
27
|
readonly endedAtMs: number | null;
|
|
19
28
|
/** Worst status over every source; null while running. */
|
|
20
29
|
readonly status: ReportTestStatus | null;
|
|
@@ -23,12 +32,15 @@ export type CommitRecord = {
|
|
|
23
32
|
export type SourceRecord = {
|
|
24
33
|
/** Producer measurements travel with reusable source content. */
|
|
25
34
|
readonly evidence?: readonly ReportPartOutput[];
|
|
35
|
+
/** The source id: the package dir with `/` as `-`, `--`, and the bucket (`libs-chess--part-2`). */
|
|
26
36
|
readonly source: string;
|
|
27
37
|
/** Repo-relative package dir (`libs/chess`). */
|
|
28
38
|
readonly packageDir: string;
|
|
29
39
|
/** The bucket under the package's report dir (`part-2`, `all`). */
|
|
30
40
|
readonly bucket: string;
|
|
41
|
+
/** `failed` if any test failed, `skipped` if all were skipped, else `passed`. */
|
|
31
42
|
readonly status: ReportTestStatus;
|
|
43
|
+
/** When the source was last updated, epoch milliseconds; the layer made from it is recorded at this time (or the commit's start if later). */
|
|
32
44
|
readonly updatedAtMs: number;
|
|
33
45
|
/** The client this source checked, when the run said. */
|
|
34
46
|
readonly environment?: string;
|
|
@@ -37,12 +49,16 @@ export type SourceRecord = {
|
|
|
37
49
|
/** Each test's meta, test-runner outcomes already applied. */
|
|
38
50
|
readonly tests: readonly RunReportMeta[];
|
|
39
51
|
};
|
|
52
|
+
/** One page of the commit list (`GET /` of the reports API), newest commit first. */
|
|
40
53
|
export type CommitPage = {
|
|
41
54
|
readonly commits: readonly CommitRecord[];
|
|
42
55
|
/** Pass back as `?cursor=` for the next, older page; null on the last. */
|
|
43
56
|
readonly cursor: string | null;
|
|
57
|
+
/** The checkout the host serves, when it serves one. */
|
|
44
58
|
readonly workspace?: WorkspaceVersion;
|
|
59
|
+
/** Why the list is partial or empty, for a person to read. */
|
|
45
60
|
readonly notice?: string;
|
|
61
|
+
/** Versions that have evidence in the stores, on the first page only. */
|
|
46
62
|
readonly evidenceVersions?: readonly string[];
|
|
47
63
|
};
|
|
48
64
|
/** `GET …/:sha/events`: the commit, then each source as it is read. */
|
|
@@ -68,8 +84,9 @@ export type TestEvent = {
|
|
|
68
84
|
readonly type: 'end';
|
|
69
85
|
readonly found: boolean;
|
|
70
86
|
};
|
|
87
|
+
/** The `content-type` of an event stream response. */
|
|
71
88
|
export declare const EVENT_STREAM_CONTENT_TYPE = "text/event-stream; charset=utf-8";
|
|
72
|
-
/**
|
|
89
|
+
/** Encodes one event as one SSE message: `event:` is the event's `type`, `data:` its JSON, ended by a blank line. */
|
|
73
90
|
export declare function encodeSseEvent(event: CommitEvent | TestEvent): string;
|
|
74
91
|
/**
|
|
75
92
|
* Incremental SSE decoder: feed it text as it arrives, get back each
|
|
@@ -78,5 +95,10 @@ export declare function encodeSseEvent(event: CommitEvent | TestEvent): string;
|
|
|
78
95
|
*/
|
|
79
96
|
export declare class SseDecoder<T> {
|
|
80
97
|
#private;
|
|
98
|
+
/**
|
|
99
|
+
* Adds `chunk` (any split of the stream, `\r\n` and `\r` read as `\n`) and returns the parsed `data` of every
|
|
100
|
+
* message it completes, in order. An unfinished message is kept for the next call. A message with no `data:`
|
|
101
|
+
* line is skipped. Throws a `SyntaxError` when a message's data is not JSON; that message is already consumed.
|
|
102
|
+
*/
|
|
81
103
|
push(chunk: string): T[];
|
|
82
104
|
}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* @module Commit-keyed recording protocol
|
|
3
|
+
*
|
|
4
|
+
* The shapes of what the reports store holds for a commit (`commits/<sha>/commit.json`, `sources/<source>.json`) and of
|
|
5
|
+
* the Server-Sent Events a reports API streams about them, plus the codec for those events. These are the older,
|
|
6
|
+
* commit-keyed recordings that layers are composed beside; layers themselves are described by the layer document.
|
|
7
|
+
* Types and a small codec only, so it is safe in a Worker, a CLI and a browser alike.
|
|
8
|
+
*
|
|
9
|
+
* @see docs/report-backends.md
|
|
5
10
|
*/
|
|
11
|
+
/** The `content-type` of an event stream response. */
|
|
6
12
|
export const EVENT_STREAM_CONTENT_TYPE = 'text/event-stream; charset=utf-8';
|
|
7
|
-
/**
|
|
13
|
+
/** Encodes one event as one SSE message: `event:` is the event's `type`, `data:` its JSON, ended by a blank line. */
|
|
8
14
|
export function encodeSseEvent(event) {
|
|
9
15
|
return `event: ${event.type}\ndata: ${JSON.stringify(event)}\n\n`;
|
|
10
16
|
}
|
|
@@ -15,6 +21,11 @@ export function encodeSseEvent(event) {
|
|
|
15
21
|
*/
|
|
16
22
|
export class SseDecoder {
|
|
17
23
|
#buffer = '';
|
|
24
|
+
/**
|
|
25
|
+
* Adds `chunk` (any split of the stream, `\r\n` and `\r` read as `\n`) and returns the parsed `data` of every
|
|
26
|
+
* message it completes, in order. An unfinished message is kept for the next call. A message with no `data:`
|
|
27
|
+
* line is skipped. Throws a `SyntaxError` when a message's data is not JSON; that message is already consumed.
|
|
28
|
+
*/
|
|
18
29
|
push(chunk) {
|
|
19
30
|
this.#buffer += chunk.replace(/\r\n?/g, '\n');
|
|
20
31
|
const out = [];
|
|
@@ -1,4 +1,24 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* @module Per-attempt publication scope
|
|
3
|
+
*
|
|
4
|
+
* Lets concurrent CI attempts for one commit publish without overwriting each other: a store view that redirects the
|
|
5
|
+
* commit-local keys (`commits/<sha>/...`) into `attempts/<publicationId>/`, while immutable shared content
|
|
6
|
+
* (the spec inventory and spec bodies, blobs, layers) stays where it is. `reportStore` finds the right view for a
|
|
7
|
+
* commit from the pointer `openCommit` leaves.
|
|
8
|
+
*/
|
|
2
9
|
import type { ObjectStore } from './object-store.js';
|
|
10
|
+
/**
|
|
11
|
+
* A view of `store` for one CI attempt: keys under `commits/` go to `attempts/<publicationId>/commits/...`, except
|
|
12
|
+
* `commits/<sha>/inventory.json` and `commits/<sha>/specs/...`, which stay shared; all other keys are unchanged.
|
|
13
|
+
* Listing a `commits/` prefix lists only the attempt's own copies, with the `attempts/<id>/` part removed.
|
|
14
|
+
*
|
|
15
|
+
* Throws `Invalid report publication id` unless `publicationId` is letters, digits, `.`, `_`, `:` or `-` and is not
|
|
16
|
+
* `.` or `..`, so an id can never address another key.
|
|
17
|
+
*/
|
|
3
18
|
export declare function publicationStore(store: ObjectStore, publicationId: string): ObjectStore;
|
|
19
|
+
/**
|
|
20
|
+
* The store view to read a commit's records from: the attempt-scoped view when the commit's `commit.json` is a
|
|
21
|
+
* pointer `{ "publicationId": ... }` (written by `openCommit` when given a `publicationId`), otherwise `store`
|
|
22
|
+
* itself, also when the commit has no record. Throws if `commit.json` is not JSON.
|
|
23
|
+
*/
|
|
4
24
|
export declare function reportStore(store: ObjectStore, sha: string): Promise<ObjectStore>;
|
|
@@ -1,7 +1,22 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* @module Per-attempt publication scope
|
|
3
|
+
*
|
|
4
|
+
* Lets concurrent CI attempts for one commit publish without overwriting each other: a store view that redirects the
|
|
5
|
+
* commit-local keys (`commits/<sha>/...`) into `attempts/<publicationId>/`, while immutable shared content
|
|
6
|
+
* (the spec inventory and spec bodies, blobs, layers) stays where it is. `reportStore` finds the right view for a
|
|
7
|
+
* commit from the pointer `openCommit` leaves.
|
|
8
|
+
*/
|
|
2
9
|
import { readUtf8 } from './object-io.js';
|
|
3
10
|
import { ObjectStoreWithPrefix } from './store-prefix.js';
|
|
4
11
|
import { commitKey } from './keys.js';
|
|
12
|
+
/**
|
|
13
|
+
* A view of `store` for one CI attempt: keys under `commits/` go to `attempts/<publicationId>/commits/...`, except
|
|
14
|
+
* `commits/<sha>/inventory.json` and `commits/<sha>/specs/...`, which stay shared; all other keys are unchanged.
|
|
15
|
+
* Listing a `commits/` prefix lists only the attempt's own copies, with the `attempts/<id>/` part removed.
|
|
16
|
+
*
|
|
17
|
+
* Throws `Invalid report publication id` unless `publicationId` is letters, digits, `.`, `_`, `:` or `-` and is not
|
|
18
|
+
* `.` or `..`, so an id can never address another key.
|
|
19
|
+
*/
|
|
5
20
|
export function publicationStore(store, publicationId) {
|
|
6
21
|
if (!/^[a-zA-Z0-9._:-]+$/.test(publicationId) ||
|
|
7
22
|
publicationId === '.' ||
|
|
@@ -24,6 +39,11 @@ export function publicationStore(store, publicationId) {
|
|
|
24
39
|
};
|
|
25
40
|
return scoped;
|
|
26
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* The store view to read a commit's records from: the attempt-scoped view when the commit's `commit.json` is a
|
|
44
|
+
* pointer `{ "publicationId": ... }` (written by `openCommit` when given a `publicationId`), otherwise `store`
|
|
45
|
+
* itself, also when the commit has no record. Throws if `commit.json` is not JSON.
|
|
46
|
+
*/
|
|
27
47
|
export async function reportStore(store, sha) {
|
|
28
48
|
const text = await readUtf8(store, commitKey(sha));
|
|
29
49
|
if (text === null)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Publishing checks as a layer
|
|
3
|
+
*
|
|
4
|
+
* `publishChecks` turns the checks of one producer into one immutable layer in any store: the whole integration for a suite
|
|
5
|
+
* that has no timeline to record. Attachments of any kind are stored by content (the same screenshot attached ten times is
|
|
6
|
+
* stored once). Nothing here reads a clock or the environment, so the same input is always the same layer and a retried CI
|
|
7
|
+
* step changes nothing.
|
|
8
|
+
*
|
|
9
|
+
* @see docs/integrating.md
|
|
10
|
+
* @see docs/extending.md
|
|
11
|
+
*/
|
|
12
|
+
import { type PublishChecksInput } from '../../schema/src/layer.js';
|
|
13
|
+
import type { ReportLayer } from './layer-types.js';
|
|
14
|
+
import type { ObjectStore } from './object-store.js';
|
|
15
|
+
/** Limits that protect the machine publishing: the largest single attachment, and the most attachment bytes in one layer (they are held in memory while stored). */
|
|
16
|
+
export type PublishChecksOptions = {
|
|
17
|
+
/** Refuse a single attachment larger than this many bytes. Default 512 MiB. */
|
|
18
|
+
readonly maxAttachmentBytes?: number;
|
|
19
|
+
/** Refuse a layer whose attachments together are larger than this, because they are held in memory while stored. Default 2 GiB. */
|
|
20
|
+
readonly maxTotalAttachmentBytes?: number;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Publish the checks of one producer as one immutable layer. This is the whole integration for a
|
|
24
|
+
* suite that has no timelines to record: Gherkin scenarios, a Quint run, a DMN table test, an SLO
|
|
25
|
+
* evaluation, a linter, anything that ends in "this check passed or failed".
|
|
26
|
+
*
|
|
27
|
+
* A check may carry whatever evidence its framework has: attachments of any media type (screenshots,
|
|
28
|
+
* videos, traces, logs, DOM snapshots…), timeline steps, annotations, retries, tags, labels, links and
|
|
29
|
+
* namespaced `extensions`. All of it is optional (docs/extending.md).
|
|
30
|
+
*
|
|
31
|
+
* Nothing here reads a clock: `recordedAtMs` is when the checks ran, given by the caller. Publishing
|
|
32
|
+
* the same input twice therefore writes the same layer, and a retried CI step changes nothing.
|
|
33
|
+
* Each check's `id` is its identity across runs. It must be stable and unique within the layer.
|
|
34
|
+
*/
|
|
35
|
+
export declare function publishChecks(store: ObjectStore, input: PublishChecksInput, options?: PublishChecksOptions): Promise<ReportLayer>;
|