@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,6 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* @module Commit-keyed object-store key layout
|
|
3
|
+
*
|
|
4
|
+
* Builds and validates the keys of the commit-addressed layout of the shared reports store. Historical recording
|
|
5
|
+
* addresses use the full commit sha. Immutable report layers (`layers/…`, see `docs/report-contract.md`) combine
|
|
6
|
+
* across those addresses:
|
|
4
7
|
*
|
|
5
8
|
* index/<13-digit inverted start ms>-<sha>.json one per published commit;
|
|
6
9
|
* sorted keys = newest first
|
|
@@ -15,38 +18,53 @@
|
|
|
15
18
|
* A source is one report bucket of one package (`libs-chess--part-2`).
|
|
16
19
|
* Writers put a source's tests first and its `sources/` record last, so a
|
|
17
20
|
* reader that sees the record can read every test it names.
|
|
21
|
+
*
|
|
22
|
+
* Every builder validates its inputs (a full 40-hex sha, path-safe segments) and throws on a bad one, so a key
|
|
23
|
+
* made here can never climb out of its prefix.
|
|
18
24
|
*/
|
|
19
25
|
/**
|
|
20
26
|
* Where the reports live in their bucket. Every reader and writer scopes its
|
|
21
27
|
* store to it, so the keys below are relative to it.
|
|
22
28
|
*/
|
|
23
29
|
export declare const REPORTS_ROOT_PREFIX = "spec-reports";
|
|
30
|
+
/** The prefix of the per-commit catalog entries, `index/`. */
|
|
24
31
|
export declare const COMMITS_INDEX_PREFIX = "index/";
|
|
32
|
+
/** Whether the value is a full 40-digit lowercase hex commit sha (an abbreviated sha is not). */
|
|
25
33
|
export declare function isCommitSha(value: string): boolean;
|
|
26
34
|
/** One path segment the harness could have written (never `.` or `..`). */
|
|
27
35
|
export declare function isKeySegment(value: string): boolean;
|
|
28
36
|
/** A frame file relative to its test (`frames/f-0001.state.json`). */
|
|
29
37
|
export declare function isFramePath(value: string): boolean;
|
|
30
|
-
/** `libs/chess` + `part-2` → `libs-chess--part-2`. */
|
|
38
|
+
/** The id of a source (one report bucket of one package): `libs/chess` + `part-2` → `libs-chess--part-2`. Throws `not a report source` when the result is not a safe key segment. */
|
|
31
39
|
export declare function sourceId(packageDir: string, bucket: string): string;
|
|
40
|
+
/** The catalog key of a commit, `index/<13-digit inverted start ms>-<sha>.json`: the time is inverted so a listing is newest first. Negative times count as 0. Throws for a sha that is not 40 hex digits. */
|
|
32
41
|
export declare function commitIndexKey(sha: string, startedAtMs: number): string;
|
|
33
42
|
/** The sha an index key names, or null for anything else. */
|
|
34
43
|
export declare function shaOfIndexKey(key: string): string | null;
|
|
44
|
+
/** The folder of everything recorded for a commit, `commits/<sha>/`. Throws for a sha that is not 40 hex digits. */
|
|
35
45
|
export declare function commitPrefix(sha: string): string;
|
|
46
|
+
/** The key of the commit's run record, `commits/<sha>/commit.json`. */
|
|
36
47
|
export declare function commitKey(sha: string): string;
|
|
48
|
+
/** The key of the stylesheet the commit's snapshots render with, `commits/<sha>/frame.css`. */
|
|
37
49
|
export declare function frameCssKey(sha: string): string;
|
|
50
|
+
/** The folder of a commit's source records, `commits/<sha>/sources/`. */
|
|
38
51
|
export declare function sourcesPrefix(sha: string): string;
|
|
52
|
+
/** The key of one source's record, `commits/<sha>/sources/<source>.json`; written last, after the source's tests. Throws `not a source` for an unsafe name. */
|
|
39
53
|
export declare function sourceKey(sha: string, source: string): string;
|
|
40
54
|
/** The source a `sources/` key names, or null for anything else. */
|
|
41
55
|
export declare function sourceOfKey(sha: string, key: string): string | null;
|
|
56
|
+
/** The folder of one recorded test, `commits/<sha>/tests/<source>/<testId>/`. Throws for an unsafe source or test id. */
|
|
42
57
|
export declare function remoteTestPrefix(sha: string, source: string, testId: string): string;
|
|
58
|
+
/** The key of a recorded test's report, `<test folder>/report.json`. */
|
|
43
59
|
export declare function remoteTestReportKey(sha: string, source: string, testId: string): string;
|
|
60
|
+
/** The key of a file a recorded test captured (a frame, a snapshot), inside its folder. A leading `/` is dropped; throws `not a frame file` for a path with an unsafe segment (`..`, empty or odd characters). */
|
|
44
61
|
export declare function remoteTestFileKey(sha: string, source: string, testId: string, file: string): string;
|
|
45
62
|
/**
|
|
46
63
|
* The id a viewer shows for a test of a source (`libs-chess--part-2/monkey`):
|
|
47
64
|
* unique across the commit, since two packages may both name a test `monkey`.
|
|
48
65
|
*/
|
|
49
66
|
export declare function viewerTestId(source: string, testId: string): string;
|
|
67
|
+
/** The inverse of {@link viewerTestId}: splits at the first `/`; null when either side is not a safe key segment. */
|
|
50
68
|
export declare function splitViewerTestId(id: string): {
|
|
51
69
|
readonly source: string;
|
|
52
70
|
readonly testId: string;
|
package/dist/reports/src/keys.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* @module Commit-keyed object-store key layout
|
|
3
|
+
*
|
|
4
|
+
* Builds and validates the keys of the commit-addressed layout of the shared reports store. Historical recording
|
|
5
|
+
* addresses use the full commit sha. Immutable report layers (`layers/…`, see `docs/report-contract.md`) combine
|
|
6
|
+
* across those addresses:
|
|
4
7
|
*
|
|
5
8
|
* index/<13-digit inverted start ms>-<sha>.json one per published commit;
|
|
6
9
|
* sorted keys = newest first
|
|
@@ -15,6 +18,9 @@
|
|
|
15
18
|
* A source is one report bucket of one package (`libs-chess--part-2`).
|
|
16
19
|
* Writers put a source's tests first and its `sources/` record last, so a
|
|
17
20
|
* reader that sees the record can read every test it names.
|
|
21
|
+
*
|
|
22
|
+
* Every builder validates its inputs (a full 40-hex sha, path-safe segments) and throws on a bad one, so a key
|
|
23
|
+
* made here can never climb out of its prefix.
|
|
18
24
|
*/
|
|
19
25
|
/**
|
|
20
26
|
* Where the reports live in their bucket. Every reader and writer scopes its
|
|
@@ -26,7 +32,9 @@ const SHA = /^[0-9a-f]{40}$/;
|
|
|
26
32
|
const SEGMENT = /^[a-zA-Z0-9._-]+$/;
|
|
27
33
|
/** Inverted start times sort newest first while there are 13-digit ms. */
|
|
28
34
|
const INVERT_FROM = 9_999_999_999_999;
|
|
35
|
+
/** The prefix of the per-commit catalog entries, `index/`. */
|
|
29
36
|
export const COMMITS_INDEX_PREFIX = 'index/';
|
|
37
|
+
/** Whether the value is a full 40-digit lowercase hex commit sha (an abbreviated sha is not). */
|
|
30
38
|
export function isCommitSha(value) {
|
|
31
39
|
return SHA.test(value);
|
|
32
40
|
}
|
|
@@ -44,13 +52,14 @@ function assertSha(sha) {
|
|
|
44
52
|
throw new Error(`report key needs a full 40-hex commit sha, got "${sha}"`);
|
|
45
53
|
}
|
|
46
54
|
}
|
|
47
|
-
/** `libs/chess` + `part-2` → `libs-chess--part-2`. */
|
|
55
|
+
/** The id of a source (one report bucket of one package): `libs/chess` + `part-2` → `libs-chess--part-2`. Throws `not a report source` when the result is not a safe key segment. */
|
|
48
56
|
export function sourceId(packageDir, bucket) {
|
|
49
57
|
const id = `${packageDir.replaceAll('/', '-')}--${bucket}`;
|
|
50
58
|
if (!isKeySegment(id))
|
|
51
59
|
throw new Error(`not a report source: "${id}"`);
|
|
52
60
|
return id;
|
|
53
61
|
}
|
|
62
|
+
/** The catalog key of a commit, `index/<13-digit inverted start ms>-<sha>.json`: the time is inverted so a listing is newest first. Negative times count as 0. Throws for a sha that is not 40 hex digits. */
|
|
54
63
|
export function commitIndexKey(sha, startedAtMs) {
|
|
55
64
|
assertSha(sha);
|
|
56
65
|
const inverted = String(INVERT_FROM - Math.max(0, Math.floor(startedAtMs)));
|
|
@@ -61,19 +70,24 @@ export function shaOfIndexKey(key) {
|
|
|
61
70
|
const m = /^index\/\d{13}-([0-9a-f]{40})\.json$/.exec(key);
|
|
62
71
|
return m === null ? null : (m[1] ?? null);
|
|
63
72
|
}
|
|
73
|
+
/** The folder of everything recorded for a commit, `commits/<sha>/`. Throws for a sha that is not 40 hex digits. */
|
|
64
74
|
export function commitPrefix(sha) {
|
|
65
75
|
assertSha(sha);
|
|
66
76
|
return `commits/${sha}/`;
|
|
67
77
|
}
|
|
78
|
+
/** The key of the commit's run record, `commits/<sha>/commit.json`. */
|
|
68
79
|
export function commitKey(sha) {
|
|
69
80
|
return `${commitPrefix(sha)}commit.json`;
|
|
70
81
|
}
|
|
82
|
+
/** The key of the stylesheet the commit's snapshots render with, `commits/<sha>/frame.css`. */
|
|
71
83
|
export function frameCssKey(sha) {
|
|
72
84
|
return `${commitPrefix(sha)}frame.css`;
|
|
73
85
|
}
|
|
86
|
+
/** The folder of a commit's source records, `commits/<sha>/sources/`. */
|
|
74
87
|
export function sourcesPrefix(sha) {
|
|
75
88
|
return `${commitPrefix(sha)}sources/`;
|
|
76
89
|
}
|
|
90
|
+
/** The key of one source's record, `commits/<sha>/sources/<source>.json`; written last, after the source's tests. Throws `not a source` for an unsafe name. */
|
|
77
91
|
export function sourceKey(sha, source) {
|
|
78
92
|
if (!isKeySegment(source))
|
|
79
93
|
throw new Error(`not a source: "${source}"`);
|
|
@@ -87,6 +101,7 @@ export function sourceOfKey(sha, key) {
|
|
|
87
101
|
const source = key.slice(head.length, -'.json'.length);
|
|
88
102
|
return isKeySegment(source) ? source : null;
|
|
89
103
|
}
|
|
104
|
+
/** The folder of one recorded test, `commits/<sha>/tests/<source>/<testId>/`. Throws for an unsafe source or test id. */
|
|
90
105
|
export function remoteTestPrefix(sha, source, testId) {
|
|
91
106
|
if (!isKeySegment(source))
|
|
92
107
|
throw new Error(`not a source: "${source}"`);
|
|
@@ -94,9 +109,11 @@ export function remoteTestPrefix(sha, source, testId) {
|
|
|
94
109
|
throw new Error(`not a test id: "${testId}"`);
|
|
95
110
|
return `${commitPrefix(sha)}tests/${source}/${testId}/`;
|
|
96
111
|
}
|
|
112
|
+
/** The key of a recorded test's report, `<test folder>/report.json`. */
|
|
97
113
|
export function remoteTestReportKey(sha, source, testId) {
|
|
98
114
|
return `${remoteTestPrefix(sha, source, testId)}report.json`;
|
|
99
115
|
}
|
|
116
|
+
/** The key of a file a recorded test captured (a frame, a snapshot), inside its folder. A leading `/` is dropped; throws `not a frame file` for a path with an unsafe segment (`..`, empty or odd characters). */
|
|
100
117
|
export function remoteTestFileKey(sha, source, testId, file) {
|
|
101
118
|
const rel = file.replace(/^\/+/, '');
|
|
102
119
|
if (!isFramePath(rel))
|
|
@@ -110,6 +127,7 @@ export function remoteTestFileKey(sha, source, testId, file) {
|
|
|
110
127
|
export function viewerTestId(source, testId) {
|
|
111
128
|
return `${source}/${testId}`;
|
|
112
129
|
}
|
|
130
|
+
/** The inverse of {@link viewerTestId}: splits at the first `/`; null when either side is not a safe key segment. */
|
|
113
131
|
export function splitViewerTestId(id) {
|
|
114
132
|
const slash = id.indexOf('/');
|
|
115
133
|
if (slash < 0)
|
|
@@ -1,18 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Environment axis of a layer
|
|
3
|
+
*
|
|
4
|
+
* Owns how a layer's `environment` (the client that was checked: `ios`, `desktop-web`, ...) is normalised to a stable
|
|
5
|
+
* slug, read from either the `environment` field or an `environment` parameter, and shown to people. The environment
|
|
6
|
+
* is part of the slot a check fills, so two spellings of one client must normalise to one id or their results would
|
|
7
|
+
* never replace each other; an unrecognised name is kept as its own slug rather than rejected.
|
|
8
|
+
*
|
|
9
|
+
* @see docs/report-contract.md
|
|
10
|
+
*/
|
|
1
11
|
import type { LayerParameters, LayerSummary } from './layer-types.js';
|
|
2
12
|
/**
|
|
3
|
-
*
|
|
13
|
+
* The environments Atlas names and labels out of the box. Any other recorded name is kept, so a new
|
|
4
14
|
* client layers beside these instead of being dropped or renamed away.
|
|
5
15
|
*/
|
|
6
16
|
export declare const REPORT_ENVIRONMENTS: readonly ["desktop-web", "mobile-web", "ios", "android"];
|
|
7
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* Turns any spelling of a client name into a stable lowercase slug, or `null` when none was given.
|
|
19
|
+
*
|
|
20
|
+
* Trims, lowercases, turns whitespace and underscores into `-`, drops every other character outside `a-z0-9-`,
|
|
21
|
+
* collapses repeated `-`, then maps known aliases (`iPhone` and `iPad` to `ios`, `mobile browser` to `mobile-web`,
|
|
22
|
+
* `desktop` to `desktop-web`). A name with no alias is returned as its slug. `null`, `undefined` and a value that
|
|
23
|
+
* slugs to nothing return `null`, which means "the layer did not say", so older layers still compose.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* normalizeEnvironment('Desktop Web'); // 'desktop-web'
|
|
27
|
+
* normalizeEnvironment('iPhone'); // 'ios'
|
|
28
|
+
* normalizeEnvironment('Smart TV'); // 'smart-tv'
|
|
29
|
+
* normalizeEnvironment(' '); // null
|
|
30
|
+
*/
|
|
8
31
|
export declare function normalizeEnvironment(value: string | null | undefined): string | null;
|
|
9
32
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
33
|
+
* Splits a layer into the two slot axes it fills: its normalised environment and its remaining parameters.
|
|
34
|
+
*
|
|
35
|
+
* The environment is the layer's `environment` field, or when that is `null` or absent the `environment` parameter
|
|
36
|
+
* (an empty-string field does not fall back to the parameter). The `environment` parameter is always removed from
|
|
37
|
+
* the returned `parameters`, so it is never both an environment and a free choice that splits the slot twice.
|
|
12
38
|
*/
|
|
13
39
|
export declare function layerPlace(summary: Pick<LayerSummary, 'environment' | 'parameters'>): {
|
|
14
40
|
environment: string | null;
|
|
15
41
|
parameters: LayerParameters;
|
|
16
42
|
};
|
|
17
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* The human label of an environment id: `Desktop web`, `Mobile web`, `iOS`, `Android` for the known ids,
|
|
45
|
+
* `Unspecified` for a missing one, and otherwise the id with its first word capitalised and `-` shown as a space
|
|
46
|
+
* (`smart-tv` reads `Smart tv`).
|
|
47
|
+
*/
|
|
18
48
|
export declare function environmentLabel(id: string | null | undefined): string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The environments Atlas names and labels out of the box. Any other recorded name is kept, so a new
|
|
3
3
|
* client layers beside these instead of being dropped or renamed away.
|
|
4
4
|
*/
|
|
5
5
|
export const REPORT_ENVIRONMENTS = ['desktop-web', 'mobile-web', 'ios', 'android'];
|
|
@@ -16,7 +16,20 @@ const ALIASES = {
|
|
|
16
16
|
ipad: 'ios',
|
|
17
17
|
android: 'android',
|
|
18
18
|
};
|
|
19
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* Turns any spelling of a client name into a stable lowercase slug, or `null` when none was given.
|
|
21
|
+
*
|
|
22
|
+
* Trims, lowercases, turns whitespace and underscores into `-`, drops every other character outside `a-z0-9-`,
|
|
23
|
+
* collapses repeated `-`, then maps known aliases (`iPhone` and `iPad` to `ios`, `mobile browser` to `mobile-web`,
|
|
24
|
+
* `desktop` to `desktop-web`). A name with no alias is returned as its slug. `null`, `undefined` and a value that
|
|
25
|
+
* slugs to nothing return `null`, which means "the layer did not say", so older layers still compose.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* normalizeEnvironment('Desktop Web'); // 'desktop-web'
|
|
29
|
+
* normalizeEnvironment('iPhone'); // 'ios'
|
|
30
|
+
* normalizeEnvironment('Smart TV'); // 'smart-tv'
|
|
31
|
+
* normalizeEnvironment(' '); // null
|
|
32
|
+
*/
|
|
20
33
|
export function normalizeEnvironment(value) {
|
|
21
34
|
if (value == null)
|
|
22
35
|
return null;
|
|
@@ -26,8 +39,11 @@ export function normalizeEnvironment(value) {
|
|
|
26
39
|
return ALIASES[slug] ?? slug;
|
|
27
40
|
}
|
|
28
41
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
42
|
+
* Splits a layer into the two slot axes it fills: its normalised environment and its remaining parameters.
|
|
43
|
+
*
|
|
44
|
+
* The environment is the layer's `environment` field, or when that is `null` or absent the `environment` parameter
|
|
45
|
+
* (an empty-string field does not fall back to the parameter). The `environment` parameter is always removed from
|
|
46
|
+
* the returned `parameters`, so it is never both an environment and a free choice that splits the slot twice.
|
|
31
47
|
*/
|
|
32
48
|
export function layerPlace(summary) {
|
|
33
49
|
const { environment: named, ...rest } = summary.parameters;
|
|
@@ -39,7 +55,11 @@ const LABELS = {
|
|
|
39
55
|
ios: 'iOS',
|
|
40
56
|
android: 'Android',
|
|
41
57
|
};
|
|
42
|
-
/**
|
|
58
|
+
/**
|
|
59
|
+
* The human label of an environment id: `Desktop web`, `Mobile web`, `iOS`, `Android` for the known ids,
|
|
60
|
+
* `Unspecified` for a missing one, and otherwise the id with its first word capitalised and `-` shown as a space
|
|
61
|
+
* (`smart-tv` reads `Smart tv`).
|
|
62
|
+
*/
|
|
43
63
|
export function environmentLabel(id) {
|
|
44
64
|
if (!id)
|
|
45
65
|
return 'Unspecified';
|
|
@@ -1,5 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Layer catalog of one backend
|
|
3
|
+
*
|
|
4
|
+
* Lists what one backend holds as catalog entries (immutable layers under `layers/index/`, and commit-keyed
|
|
5
|
+
* recordings written before layers existed) and turns one entry into the layer summaries it stands for. It only
|
|
6
|
+
* reads: opening Atlas never rewrites a store. Whether a backend can be read at all, and how entries from several
|
|
7
|
+
* backends combine, is decided by the callers (`compose.ts`, `layers-route.ts`).
|
|
8
|
+
*
|
|
9
|
+
* @see docs/report-contract.md
|
|
10
|
+
*/
|
|
1
11
|
import type { ObjectStore } from './object-store.js';
|
|
2
12
|
import type { LayerSummary } from './layer-types.js';
|
|
3
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* Lists one backend's catalog entries as opaque strings to pass to `catalogLayers`.
|
|
15
|
+
*
|
|
16
|
+
* An entry is `layer:<key>` for each key under `layers/index/` (listed newest first, in the store's own key order),
|
|
17
|
+
* followed by `commit:<sha>` for every 40-hex commit named by a key under `versions/` or `index/` (a store written
|
|
18
|
+
* before layers existed, sorted by sha). Only lists keys; reads no layer. A store that cannot be listed throws.
|
|
19
|
+
* Existing recordings are read in place and never rewritten.
|
|
20
|
+
*/
|
|
4
21
|
export declare function catalogEntries(store: ObjectStore): Promise<readonly string[]>;
|
|
22
|
+
/**
|
|
23
|
+
* Reads the layer summaries one catalog entry from `catalogEntries` stands for.
|
|
24
|
+
*
|
|
25
|
+
* A `layer:` entry yields exactly one summary (the layer the catalog entry names, without its bundle) and throws
|
|
26
|
+
* when the entry is not JSON, names no layer, the layer is missing, or the layer cannot be parsed, so the caller can
|
|
27
|
+
* report it as a notice instead of counting it as a pass. A `commit:` entry yields the older commit-keyed
|
|
28
|
+
* recordings of that sha: one summary per stored part (`part-<sha>-<id>`) and one per stored source
|
|
29
|
+
* (`source-<sha>-<id>`); a part whose checks a source already carries, and that has no parameters, is dropped so the
|
|
30
|
+
* same evidence is not counted twice. Those ids are mutable addresses, not content digests.
|
|
31
|
+
*/
|
|
5
32
|
export declare function catalogLayers(store: ObjectStore, entry: string): Promise<readonly LayerSummary[]>;
|
|
@@ -7,12 +7,29 @@ import { readStoredSource } from './source-content.js';
|
|
|
7
7
|
import { sourceParts } from './source-part.js';
|
|
8
8
|
import { LAYER_INDEX, readLayer, layerSummary } from './layer-store.js';
|
|
9
9
|
import { eachLimited } from './completion-order.js';
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Lists one backend's catalog entries as opaque strings to pass to `catalogLayers`.
|
|
12
|
+
*
|
|
13
|
+
* An entry is `layer:<key>` for each key under `layers/index/` (listed newest first, in the store's own key order),
|
|
14
|
+
* followed by `commit:<sha>` for every 40-hex commit named by a key under `versions/` or `index/` (a store written
|
|
15
|
+
* before layers existed, sorted by sha). Only lists keys; reads no layer. A store that cannot be listed throws.
|
|
16
|
+
* Existing recordings are read in place and never rewritten.
|
|
17
|
+
*/
|
|
11
18
|
export async function catalogEntries(store) {
|
|
12
19
|
const [layers, versions, commits] = await Promise.all([store.listKeys(LAYER_INDEX), store.listKeys('versions/'), store.listKeys('index/')]);
|
|
13
20
|
const shas = new Set([...versions, ...commits].flatMap(key => /([0-9a-f]{40})\.json$/.exec(key)?.[1] ?? []));
|
|
14
21
|
return [...layers.map(key => `layer:${key}`), ...[...shas].sort().map(sha => `commit:${sha}`)];
|
|
15
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Reads the layer summaries one catalog entry from `catalogEntries` stands for.
|
|
25
|
+
*
|
|
26
|
+
* A `layer:` entry yields exactly one summary (the layer the catalog entry names, without its bundle) and throws
|
|
27
|
+
* when the entry is not JSON, names no layer, the layer is missing, or the layer cannot be parsed, so the caller can
|
|
28
|
+
* report it as a notice instead of counting it as a pass. A `commit:` entry yields the older commit-keyed
|
|
29
|
+
* recordings of that sha: one summary per stored part (`part-<sha>-<id>`) and one per stored source
|
|
30
|
+
* (`source-<sha>-<id>`); a part whose checks a source already carries, and that has no parameters, is dropped so the
|
|
31
|
+
* same evidence is not counted twice. Those ids are mutable addresses, not content digests.
|
|
32
|
+
*/
|
|
16
33
|
export async function catalogLayers(store, entry) {
|
|
17
34
|
if (entry.startsWith('layer:')) {
|
|
18
35
|
const raw = await readUtf8(store, entry.slice(6));
|
|
@@ -1,43 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Layer composition: slots, winners and de-duplication
|
|
3
|
+
*
|
|
4
|
+
* The pure core of the composition rule: it flattens layers into rows, computes the slot key each row fills, decides
|
|
5
|
+
* which result wins a slot, and removes the duplicate copies of one immutable layer held by several backends. It does
|
|
6
|
+
* no I/O. The winner order (a completed result beats an unfinished one, then the newer `recordedAtMs`, then
|
|
7
|
+
* `failed` over `passed` and `running` over `not-run`, then the greater `layerId|backendId`) is a total order and is
|
|
8
|
+
* part of the stable report contract: changing it changes every report. `report-index.ts` folds layers into the same
|
|
9
|
+
* winners incrementally and must always equal `combineEvidence`.
|
|
10
|
+
*
|
|
11
|
+
* @see docs/report-contract.md#how-layers-compose
|
|
12
|
+
*/
|
|
1
13
|
import type { EvidenceStatus, SpecEntry } from './explorer-types.js';
|
|
2
14
|
import type { LayerEvidence, LayerHeader, LayerRow, StatusCounts } from './evidence-types.js';
|
|
3
15
|
import type { LayerParameters, LayerSummary, ReportOutline } from './layer-types.js';
|
|
4
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* A short, deterministic fingerprint of a spec's text, shaped `<length>:<hash>:<hash>` (the length in UTF-16 code
|
|
18
|
+
* units and two 32-bit hashes in hex). A layer records it per spec so a reader can warn when the spec changed
|
|
19
|
+
* since ("Potentially outdated: spec changed"). Advisory identity only: it is not collision resistant and never an
|
|
20
|
+
* integrity check.
|
|
21
|
+
*/
|
|
5
22
|
export declare function textFingerprint(text: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Normalises a check's or spec's path to its `specs/<path inside the specs directory>` form, so the same spec
|
|
25
|
+
* recorded from different checkouts is one spec.
|
|
26
|
+
*
|
|
27
|
+
* Converts `\` to `/`, drops a leading `./`, and drops everything before the first path segment named exactly
|
|
28
|
+
* `specs`. A path with no such segment is returned unchanged (apart from the first two steps).
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* specPath('packages/app/specs/join.feature'); // 'specs/join.feature'
|
|
32
|
+
* specPath('myspecs/x.feature'); // 'myspecs/x.feature'
|
|
33
|
+
*/
|
|
6
34
|
export declare function specPath(path: string): string;
|
|
35
|
+
/** Serialises parameters as JSON key/value pairs sorted by key, so equal parameter sets compare equal as strings. */
|
|
7
36
|
export declare function parameterKey(parameters: LayerParameters): string;
|
|
8
|
-
/**
|
|
37
|
+
/** Whether a part `kind` only qualifies an outcome (today only `performance`) and so is not counted as a check when anything else is recorded. */
|
|
9
38
|
export declare function isDiagnosticKind(kind: string): boolean;
|
|
39
|
+
/** A fresh status tally with every status at zero. */
|
|
10
40
|
export declare function emptyCounts(): Record<EvidenceStatus, number>;
|
|
11
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* Counts rows by status, leaving out the diagnostic rows (see `isDiagnosticKind`) that only qualify an outcome.
|
|
43
|
+
* When every row is diagnostic they are counted, so a layer of timings alone is not empty.
|
|
44
|
+
*/
|
|
12
45
|
export declare function outcomeCounts(rows: readonly LayerRow[]): StatusCounts;
|
|
13
|
-
/**
|
|
46
|
+
/**
|
|
47
|
+
* Flattens a layer into what composition reads: a header (origin, normalised environment and parameters, counts,
|
|
48
|
+
* evidence summary), one row per check of every part, and the spec fingerprints it recorded.
|
|
49
|
+
*
|
|
50
|
+
* `backend` is the id of the backend the layer was read from; it only breaks ties between copies. Paths in rows and
|
|
51
|
+
* fingerprints go through `specPath`. When the layer has a recorded `source`, a row whose check id matches one of its
|
|
52
|
+
* tests also gets that test's `testId`, `variant` and duration. The result is `live: false`: a layer read from a
|
|
53
|
+
* store is never a run still in progress.
|
|
54
|
+
*/
|
|
14
55
|
export declare function layerEvidence(summary: LayerSummary, backend: string): LayerEvidence;
|
|
56
|
+
/** The winning result of one slot: which layer and row it came from, and whether it may be stale. */
|
|
15
57
|
export type EvidenceResult = {
|
|
16
|
-
/** One producer's check of one kind under one parameter set. */
|
|
58
|
+
/** One producer's check of one kind under one parameter set. See `resultKey`. */
|
|
17
59
|
readonly key: string;
|
|
18
|
-
/** The check itself, whatever kind of evidence and parameters describe it. */
|
|
60
|
+
/** The check itself, whatever kind of evidence and parameters describe it. See `slotKey`. */
|
|
19
61
|
readonly slot: string;
|
|
62
|
+
/** The layer that recorded this result. */
|
|
20
63
|
readonly layer: LayerHeader;
|
|
64
|
+
/** The check as recorded. */
|
|
21
65
|
readonly row: LayerRow;
|
|
66
|
+
/** The layer's parameters other than the environment. */
|
|
22
67
|
readonly parameters: LayerParameters;
|
|
68
|
+
/** Why the result may be out of date, or `null` when nothing suggests it. Advisory: never changes the status. */
|
|
23
69
|
readonly warning: string | null;
|
|
24
70
|
};
|
|
71
|
+
/**
|
|
72
|
+
* Whether `next` should take the slot currently held by `prior`: the winner rule of the report contract.
|
|
73
|
+
*
|
|
74
|
+
* In order: a completed result (`passed`, `failed`) beats an unfinished one (`running`, `not-run`) whatever their
|
|
75
|
+
* times; otherwise the greater `recordedAtMs` wins; at the same time `failed` beats `passed` and `running` beats
|
|
76
|
+
* `not-run`; at the same status the greater `layerId|backendId` wins. The last step makes the order total, so the
|
|
77
|
+
* answer never depends on the order results are offered in. Returns `false` for two identical results.
|
|
78
|
+
*/
|
|
79
|
+
export declare function replaces(next: EvidenceResult, prior: EvidenceResult): boolean;
|
|
80
|
+
/** The winners of every slot, grouped under the spec of the current outline they belong to. */
|
|
25
81
|
export type CombinedEvidence = {
|
|
82
|
+
/** One entry per spec of the outline, in outline order (a spec with no results has an empty list). */
|
|
26
83
|
readonly specs: readonly {
|
|
27
84
|
readonly spec: SpecEntry;
|
|
28
85
|
readonly results: EvidenceResult[];
|
|
29
86
|
}[];
|
|
87
|
+
/** Winners whose spec path is absent or not in the outline (a removed spec keeps its evidence here). */
|
|
30
88
|
readonly unassigned: EvidenceResult[];
|
|
31
89
|
};
|
|
32
|
-
/**
|
|
90
|
+
/**
|
|
91
|
+
* Lays layers over the outline of current specs and returns the winner of every slot.
|
|
92
|
+
*
|
|
93
|
+
* One linear pass over the rows of the layers (after `distinctEvidence`). The slot is producer, kind, spec path,
|
|
94
|
+
* check id, environment and parameters; `replaces` picks the winner, so the result does not depend on the order of
|
|
95
|
+
* `layers`. Branch, sha, backend and run never split a slot. Each result carries a freshness `warning`, computed
|
|
96
|
+
* against `outline`, that does not affect which result wins.
|
|
97
|
+
*
|
|
98
|
+
* @see docs/report-contract.md#how-layers-compose
|
|
99
|
+
*/
|
|
33
100
|
export declare function combineEvidence(outline: ReportOutline, layers: readonly LayerEvidence[]): CombinedEvidence;
|
|
101
|
+
/**
|
|
102
|
+
* The key of the slot a row fills: a JSON array of producer, kind, spec path (`''` when none), check id, environment
|
|
103
|
+
* (`''` when none) and the sorted parameters. Two results with the same key compete; the winner is `replaces`.
|
|
104
|
+
*/
|
|
105
|
+
export declare function resultKey(layer: Pick<LayerHeader, 'producer' | 'environment' | 'parameters'>, row: Pick<LayerRow, 'kind' | 'specPath' | 'id'>): string;
|
|
106
|
+
/**
|
|
107
|
+
* `resultKey` for every row of one layer, which share all but three parts of it. The strings are exactly
|
|
108
|
+
* those `resultKey` makes (they are keys that persist in no store, but two ways of making one must agree),
|
|
109
|
+
* without sorting and writing the layer's parameters once per check.
|
|
110
|
+
*/
|
|
111
|
+
export declare function layerResultKeys(layer: Pick<LayerHeader, 'producer' | 'environment' | 'parameters'>): (row: Pick<LayerRow, 'kind' | 'specPath' | 'id'>) => string;
|
|
112
|
+
/** The key of a check regardless of producer, environment and parameters: a JSON array of its spec path and check id. */
|
|
34
113
|
export declare function slotKey(path: string, id: string): string;
|
|
35
|
-
/**
|
|
114
|
+
/**
|
|
115
|
+
* De-duplicates layer headers: the same layer held by several backends is one layer.
|
|
116
|
+
*
|
|
117
|
+
* Suppresses the mutable address of an execution already archived as an immutable layer. An
|
|
118
|
+
* immutable layer (64-hex id) held by several backends is one layer, reported by the backend whose id sorts
|
|
119
|
+
* first, whatever order they were read in. A mutable one is its backend's own and is kept once per backend.
|
|
120
|
+
* Returns the survivors, not necessarily in input order.
|
|
121
|
+
*/
|
|
36
122
|
export declare function distinctHeaders<T extends {
|
|
37
123
|
readonly id: string;
|
|
38
124
|
readonly execution: string;
|
|
125
|
+
readonly backend?: string;
|
|
39
126
|
}>(layers: readonly T[]): T[];
|
|
127
|
+
/** Keeps, in input order, only the layers `distinctHeaders` keeps, and each `backend|id` once. */
|
|
40
128
|
export declare function distinctEvidence(layers: readonly LayerEvidence[]): LayerEvidence[];
|
|
41
|
-
/**
|
|
129
|
+
/** Drops each mutable layer whose execution is already archived as an immutable one, and keeps one summary per id. */
|
|
42
130
|
export declare function distinctLayers(layers: readonly LayerSummary[]): LayerSummary[];
|
|
131
|
+
/** A string equal for the mutable and the archived address of one execution: its producer, sha, time and parts. */
|
|
43
132
|
export declare function layerExecutionKey(layer: LayerSummary): string;
|