@crvouga/atlas 0.4.0 → 0.5.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 +7 -1
- package/README.md +178 -617
- 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 +30 -1
- package/dist/core/src/config.d.ts +70 -4
- package/dist/core/src/config.js +62 -3
- 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 +69 -16
- package/dist/core/src/run/execute.js +67 -16
- 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 +83 -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 +52 -0
- package/dist/reports/src/http-store.js +145 -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 +364 -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/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 +485 -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/schema/src/api.d.ts +799 -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 +14 -0
- package/dist/schema/src/index.js +14 -0
- package/dist/schema/src/layer.d.ts +2273 -0
- package/dist/schema/src/layer.js +462 -0
- package/dist/schema/src/manifest.d.ts +95 -0
- package/dist/schema/src/manifest.js +84 -0
- package/dist/schema/src/report-sources.d.ts +28 -0
- package/dist/schema/src/report-sources.js +25 -0
- package/dist/schema/src/runs-index.d.ts +16 -0
- package/dist/schema/src/runs-index.js +15 -0
- package/dist/schema/src/server-config.d.ts +93 -0
- package/dist/schema/src/server-config.js +73 -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 +62 -0
- package/dist/server/src/app.js +419 -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 +187 -0
- package/dist/server/src/dev.d.ts +12 -0
- package/dist/server/src/dev.js +80 -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 +16 -0
- package/dist/server/src/index.js +16 -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 +112 -0
- package/dist/server/src/openapi.d.ts +59 -0
- package/dist/server/src/openapi.js +374 -0
- package/dist/server/src/problem.d.ts +8 -0
- package/dist/server/src/problem.js +39 -0
- package/dist/server/src/site.d.ts +13 -0
- package/dist/server/src/site.js +43 -0
- package/dist/server/src/store-api.d.ts +28 -0
- package/dist/server/src/store-api.js +159 -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 +146 -0
- package/docs/reference/core.md +2426 -0
- package/docs/reference/detox.md +150 -0
- package/docs/reference/http-api.md +303 -0
- package/docs/reference/playwright.md +303 -0
- package/docs/reference/reports.md +7098 -0
- package/docs/reference/schema.md +1651 -0
- package/docs/reference/server.md +685 -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/server.md +285 -0
- package/docs/statecharts.md +641 -0
- package/llms-full.txt +3506 -0
- package/llms.txt +47 -0
- package/package.json +32 -4
- package/packages/core/README.md +2 -1
- package/packages/reports/README.md +65 -0
- package/packages/reports/STORAGE.md +4 -0
- package/packages/schema/README.md +14 -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 +22 -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/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/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 +194 -0
- package/packages/schema/schemas/server-info.schema.json +114 -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 +6699 -0
- package/packages/visualizer/README.md +21 -0
- package/packages/visualizer/src/app/AppShell.tsx +9 -2
- package/packages/visualizer/src/app/report-sources.tsx +6 -4
- package/packages/visualizer/src/app/router.tsx +3 -3
- package/packages/visualizer/src/components/Header.module.css +35 -0
- package/packages/visualizer/src/components/Header.tsx +40 -3
- package/packages/visualizer/src/data/adapters/adapter.ts +5 -17
- package/packages/visualizer/src/data/adapters/index.ts +10 -1
- package/packages/visualizer/src/evidence/api.ts +14 -2
- 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 +3 -1
- package/packages/visualizer/src/evidence/evidence-context.tsx +74 -12
- package/packages/visualizer/src/evidence/spec-page.tsx +23 -16
- package/packages/visualizer/src/find/Finder.tsx +1 -7
- package/packages/visualizer/src/find/open.ts +4 -0
- package/packages/visualizer/src/live/live-stream.ts +204 -0
- package/packages/visualizer/src/runtime.ts +19 -0
- package/packages/visualizer/vite/atlas-server-proxy.ts +36 -0
- package/packages/visualizer/vite.config.ts +11 -3
package/docs/server.md
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
# The Atlas server
|
|
2
|
+
|
|
3
|
+
One process per project that **takes in results from every environment, keeps them, and shows everyone the
|
|
4
|
+
combined report, live**. It is a Bun API that serves a Vite-built single-page viewer: one host, one port, in
|
|
5
|
+
development and in production.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
laptop ──────┐ ┌── browsers (the viewer: reads /api, listens on /api/events)
|
|
9
|
+
CI job ──────┼── PUT /api/store/… POST /api/checks ─▶│
|
|
10
|
+
device lab ──┘ atlas report publish | stream │ atlas report status (the gate: asks /api/status)
|
|
11
|
+
│
|
|
12
|
+
backends: ./atlas-data (default), S3, other folders, another Atlas server
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
- **Clients upload directly to it.** `atlas report publish`, `atlas report stream`, `createReporter` and a plain
|
|
16
|
+
`curl` all end up as layers on the server. Nothing else needs deploying: no bucket access for CI, no artifact
|
|
17
|
+
merging, no static site to rebuild.
|
|
18
|
+
- **Its default backend is its own filesystem** (`./atlas-data`). That folder is the whole state: back it up,
|
|
19
|
+
mount it on a volume, or put the state in a bucket instead ([backends](#backends)). Several backends are one
|
|
20
|
+
report, as ever.
|
|
21
|
+
- **The report is live.** Every viewer holds one server-sent-events connection; when results arrive the server
|
|
22
|
+
says so and each viewer reads only what changed ([streaming](#streaming)).
|
|
23
|
+
- **Layered, never partitioned**, as everywhere in Atlas: the server only stores immutable, content-addressed
|
|
24
|
+
layers and works out the report from them. Replace it, restore it, or run a second one on a copy of the data:
|
|
25
|
+
the same layers give the same report ([the contract](report-contract.md)).
|
|
26
|
+
|
|
27
|
+
- [Run it](#run-it) · [Configuration](#configuration) · [Backends](#backends) · [Tokens and roles](#tokens-and-roles)
|
|
28
|
+
- [Sending results](#sending-results) · [Streaming](#streaming) · [API reference](#api-reference)
|
|
29
|
+
- [What the server refuses](#what-the-server-refuses) · [Performance](#performance) · [Operating it](#operating-it)
|
|
30
|
+
|
|
31
|
+
## Run it
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
bun add -d @crvouga/atlas
|
|
35
|
+
export ATLAS_TOKEN=$(openssl rand -hex 24) # admin token; see "Tokens and roles"
|
|
36
|
+
bunx atlas serve # http://127.0.0.1:8080, data in ./atlas-data
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
It runs on Bun and on Node 22.18 or later. The first start builds the viewer once into `~/.cache/atlas/site`
|
|
40
|
+
(or serves `./atlas-site`, or `--site <dir>`); the build is the same for every project, because the server writes
|
|
41
|
+
its own address book into the page (`window.__ATLAS_CONFIG__`).
|
|
42
|
+
|
|
43
|
+
**Working on Atlas or on the viewer:** `atlas dev` runs the server on a port of its own and the viewer's Vite dev
|
|
44
|
+
server in front of it. Vite proxies `/api` (server-sent events included) to the server, so the browser, the
|
|
45
|
+
uploaders and the viewer all use **one host**, exactly as in production, and a change to the viewer shows at once.
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
bunx atlas dev --data .atlas-data # http://127.0.0.1:5180
|
|
49
|
+
ATLAS_STORE=http://127.0.0.1:5180 bunx atlas report publish --producer unit --junit out.xml
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
For containers, Kubernetes and CI see [running Atlas for a project](deploying.md).
|
|
53
|
+
|
|
54
|
+
## Configuration
|
|
55
|
+
|
|
56
|
+
Everything has a default, so no configuration is a working server for this machine. Settings come from
|
|
57
|
+
`atlas.server.json` (or `--config <file>` / `ATLAS_CONFIG`), then environment variables, then flags; a later one
|
|
58
|
+
wins. A mistake (an unknown key, a short token, two write targets, listening beyond this machine without tokens)
|
|
59
|
+
is said in words and the server does not start. The file has a published
|
|
60
|
+
[JSON Schema](https://github.com/crvouga/atlas/blob/main/packages/schema/schemas/server-config.schema.json)
|
|
61
|
+
(`@crvouga/atlas/schemas/server-config.schema.json`).
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"$schema": "./node_modules/@crvouga/atlas/packages/schema/schemas/server-config.schema.json",
|
|
66
|
+
"host": "0.0.0.0",
|
|
67
|
+
"port": 8080,
|
|
68
|
+
"data": "./atlas-data",
|
|
69
|
+
"backends": [{ "id": "archive", "url": "s3://my-bucket/atlas/my-project?region=us-east-1", "label": "Archive" }],
|
|
70
|
+
"write": "data",
|
|
71
|
+
"auth": {
|
|
72
|
+
"tokens": [
|
|
73
|
+
{ "name": "ci", "role": "publish", "tokenEnv": "ATLAS_CI_TOKEN" },
|
|
74
|
+
{ "name": "dashboard", "role": "read", "tokenEnv": "ATLAS_DASHBOARD_TOKEN" }
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
"include": { "branches": ["main"], "ignoreModified": true },
|
|
78
|
+
"refreshSeconds": 10,
|
|
79
|
+
"limits": { "maxObjectMiB": 256, "maxJsonMiB": 32, "maxStreams": 500 }
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
<!-- generated:server-settings -->
|
|
84
|
+
<!-- /generated:server-settings -->
|
|
85
|
+
|
|
86
|
+
`ATLAS_HOST` and `ATLAS_PORT` win over `HOST` and `PORT`, which other tools on a machine often set for their own
|
|
87
|
+
purposes.
|
|
88
|
+
|
|
89
|
+
## Backends
|
|
90
|
+
|
|
91
|
+
A backend is anything that implements `ObjectStore`: a folder, an S3-compatible bucket (`s3://`, `r2://`,
|
|
92
|
+
`gs://`), or **another Atlas server** (`https://…`, with `ATLAS_TOKEN` for it). The server reads every backend
|
|
93
|
+
and shows one report; one that is down is named in the viewer and skipped, and the server recovers by itself.
|
|
94
|
+
|
|
95
|
+
- **Uploads go to one backend**: the `data` folder, or the one named by `write` / `ATLAS_WRITE`. Name a bucket
|
|
96
|
+
to make it the system of record, so the server holds nothing a replacement would lose:
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
ATLAS_STORE=project=s3://my-bucket/atlas/my-project ATLAS_WRITE=project atlas serve
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
- **Layers written to a backend by something else** (CI with bucket access, `atlas report merge`) are found at
|
|
103
|
+
the next refresh. Layers uploaded through the server are in the report at once.
|
|
104
|
+
- **A server can be a backend of another**: a local server reading the project's shared one shows both.
|
|
105
|
+
|
|
106
|
+
## Tokens and roles
|
|
107
|
+
|
|
108
|
+
| Role | May |
|
|
109
|
+
| --- | --- |
|
|
110
|
+
| `read` | look: the viewer, the report, `/api/status` |
|
|
111
|
+
| `publish` | also upload layers, specs and runs, and remove the scratch objects `atlas report doctor` writes |
|
|
112
|
+
| `admin` | all server operations |
|
|
113
|
+
|
|
114
|
+
Tokens are at least 12 characters (`openssl rand -hex 24`) and different from one another. Give them as
|
|
115
|
+
`ATLAS_TOKEN` (admin), `ATLAS_PUBLISH_TOKEN`, `ATLAS_READ_TOKEN`, or under `auth.tokens` in the file, preferably
|
|
116
|
+
with `tokenEnv` so the file holds no secret.
|
|
117
|
+
|
|
118
|
+
- **Sending a token:** `Authorization: Bearer <token>`. A browser's sign-in box also works for *looking* (any
|
|
119
|
+
user name, the token as the password). **Uploading needs the Bearer header, never the sign-in box**: a browser
|
|
120
|
+
sends those credentials by itself to any page that asks, which would let another site upload with them.
|
|
121
|
+
- **No tokens** means open, and then the server refuses to listen beyond this machine unless told
|
|
122
|
+
`--insecure` (for when a proxy in front does the signing in).
|
|
123
|
+
- `/healthz` and `/readyz` never need a token, so a load balancer can use them.
|
|
124
|
+
- Only this server's own clients need tokens; Atlas does not do accounts. Put it behind what your company already
|
|
125
|
+
uses (Cloudflare Access, an ALB with OIDC, `oauth2-proxy`, Tailscale) and TLS ends there too.
|
|
126
|
+
|
|
127
|
+
## Sending results
|
|
128
|
+
|
|
129
|
+
Every route ends as the same immutable layers, so use what fits:
|
|
130
|
+
|
|
131
|
+
| From | How |
|
|
132
|
+
| --- | --- |
|
|
133
|
+
| a CI job or laptop, after the run | `ATLAS_STORE=https://atlas.example.com ATLAS_TOKEN=… atlas report publish --producer unit --junit out.xml --specs ./specs` |
|
|
134
|
+
| a suite that can print JSON lines | `my-suite --json \| atlas report stream --producer e2e --environment ios` |
|
|
135
|
+
| code | `createReporter(identity, { store: httpStore({ url, token }) })`, below |
|
|
136
|
+
| anything that can make a request | `POST /api/checks` with a JSON body |
|
|
137
|
+
| a folder of layers you already have | `atlas report merge --store ./layers --into https://atlas.example.com` |
|
|
138
|
+
|
|
139
|
+
`ATLAS_STORE` may name the server instead of a folder or bucket: **every `atlas report` command works against it**
|
|
140
|
+
(`publish`, `stream`, `merge --into`, `doctor`, `status`). Keys never go in the URL; put the token in
|
|
141
|
+
`ATLAS_TOKEN` (or the first line of the file named by `ATLAS_TOKEN_FILE`). **A token belongs to one server.** With
|
|
142
|
+
one server in `ATLAS_STORE`, `ATLAS_TOKEN` is its token; with several, name each (`lab=https://lab.example.com`) and give
|
|
143
|
+
it `ATLAS_TOKEN_LAB`, because `ATLAS_TOKEN` is then sent to none of them. A token is never sent over plain `http://`
|
|
144
|
+
beyond this machine (`ATLAS_TRUST_NETWORK=1` says the network is yours).
|
|
145
|
+
|
|
146
|
+
### Streaming a run as it happens
|
|
147
|
+
|
|
148
|
+
`atlas report stream` reads one check per line (the fields of a check: `id`, `title`, `status`, and any
|
|
149
|
+
[evidence](extending.md)) and sends what has finished every second as a layer. A check sent first as `running` and
|
|
150
|
+
then as `passed` is two layers; the later, completed one wins, so the report follows the suite while it runs and
|
|
151
|
+
agrees with it when it ends. A layer that cannot be sent is kept and sent again, byte for byte the same, so a
|
|
152
|
+
retry never makes a second layer. It exits 1 if anything could not be sent.
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import { createReporter } from '@crvouga/atlas/reports/reporter';
|
|
156
|
+
import { httpStore } from '@crvouga/atlas/reports/http-store';
|
|
157
|
+
|
|
158
|
+
const reporter = createReporter(
|
|
159
|
+
{ producer: 'web-e2e', environment: 'desktop-web', branch: process.env.GITHUB_REF_NAME ?? null },
|
|
160
|
+
{ store: httpStore({ url: 'https://atlas.example.com', token: process.env.ATLAS_TOKEN }), flushMs: 1000 }
|
|
161
|
+
);
|
|
162
|
+
reporter.check({ id: 'checkout > pays', title: 'pays', status: 'running', specPath: 'specs/checkout.feature' });
|
|
163
|
+
// …
|
|
164
|
+
reporter.check({ id: 'checkout > pays', title: 'pays', status: 'passed', specPath: 'specs/checkout.feature', attachments: [{ name: 'end.png', data: png }] });
|
|
165
|
+
const { layers, checks, lost } = await reporter.close(); // never throws into the suite; `lost` counts what never arrived
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### `POST /api/checks`
|
|
169
|
+
|
|
170
|
+
```sh
|
|
171
|
+
curl -X POST https://atlas.example.com/api/checks -H "authorization: Bearer $ATLAS_TOKEN" -d '{
|
|
172
|
+
"producer": "smoke", "environment": "prod",
|
|
173
|
+
"checks": [{ "id": "login", "title": "can log in", "status": "passed" }]
|
|
174
|
+
}'
|
|
175
|
+
# 201 {"ok":true,"id":"…","checks":1}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
The body is [the checks file](integrating.md) (`recordedAtMs` defaults to now). Binary evidence goes in as
|
|
179
|
+
`base64`. Anything wrong is a `422` that says what.
|
|
180
|
+
|
|
181
|
+
### The store protocol
|
|
182
|
+
|
|
183
|
+
`httpStore` is an `ObjectStore` over `/api/store`, so `publishChecks`, spec sets, run uploads and `copyStore` work
|
|
184
|
+
against a server unchanged. A client uploads **in dependency order**: blobs, then the manifest, then the catalog
|
|
185
|
+
entry that makes it visible. The server checks each step and says no to a catalog entry whose manifest is not
|
|
186
|
+
there (`409`), so nothing half-uploaded is ever shown.
|
|
187
|
+
|
|
188
|
+
## Streaming
|
|
189
|
+
|
|
190
|
+
`GET /api/events` is a server-sent-events stream:
|
|
191
|
+
|
|
192
|
+
| Event | Data | Meaning |
|
|
193
|
+
| --- | --- | --- |
|
|
194
|
+
| `hello` | `{ version, ready, time }` | Sent first. The report's current version. |
|
|
195
|
+
| `report` | `{ version, totalLayers, added: [{ id, producer, environment, branch, sha, recordedAtMs, counts }], addedTotal }` | Layers arrived. Enough to say who sent what, without asking. |
|
|
196
|
+
| `atlas:change` | `{ scope: "specs" \| "runs", files, runIds }` | New specs or runs. |
|
|
197
|
+
| `ping` | `{}` | Every 15 s, so proxies keep the connection and the viewer can tell a quiet server from a dead connection. |
|
|
198
|
+
|
|
199
|
+
Events say *that* something changed; the state is always fetched. A viewer that missed some (a dropped
|
|
200
|
+
connection, a laptop that slept) loses nothing: it reads again when it reconnects, and the viewer also reads on a
|
|
201
|
+
slow timer behind the stream. Past `limits.maxStreams` viewers the server answers `503` with `Retry-After` and the
|
|
202
|
+
viewer polls instead; a viewer that stops reading is let go rather than held in memory.
|
|
203
|
+
|
|
204
|
+
### Reading only what changed
|
|
205
|
+
|
|
206
|
+
`GET /api/reports/evidence/effective` is the whole report: only the layers that win a check, each with only the
|
|
207
|
+
rows that win, with an ETag. A viewer that holds a version asks `?since=<version>` and is sent **only the layers
|
|
208
|
+
that changed since, and the ids that no longer win anything** (`"delta": true`). Applying that gives exactly the
|
|
209
|
+
report the server would have sent whole (`applyEffectiveDelta`, tested against every earlier version of random
|
|
210
|
+
runs); a version the server does not remember, or an older server, answers with the whole report, which a viewer
|
|
211
|
+
takes as it always did. A result streamed into a 100 000-check report costs a viewer a few kilobytes.
|
|
212
|
+
|
|
213
|
+
## API reference
|
|
214
|
+
|
|
215
|
+
<!-- generated:server-operations -->
|
|
216
|
+
<!-- /generated:server-operations -->
|
|
217
|
+
|
|
218
|
+
Errors are always [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) problem documents (`application/problem+json`: `type`,
|
|
219
|
+
`title`, `status`, and a `detail` that says what to do; `error` repeats `detail` for older clients) with a status that says
|
|
220
|
+
what to do: `401` send a token, `403` that token may not, `409` upload what this depends on first or you are changing
|
|
221
|
+
something immutable, `413` too large, `422` not valid, `503` still starting (see `Retry-After`).
|
|
222
|
+
|
|
223
|
+
**For agents:** a server describes itself. `GET /api/openapi.json` is the OpenAPI 3.1 description of everything above (also
|
|
224
|
+
shipped as `@crvouga/atlas/openapi.json`) and `GET /llms.txt` is a guide for an agent that was handed only the server's address;
|
|
225
|
+
neither needs a token. See [Atlas for AI agents](agents.md).
|
|
226
|
+
|
|
227
|
+
## What the server refuses
|
|
228
|
+
|
|
229
|
+
What is checked is what would otherwise corrupt the report for everyone, and it is checked from the bytes in hand:
|
|
230
|
+
|
|
231
|
+
- **Everything is named by its content.** A manifest whose content does not hash to its id (it was edited, or written
|
|
232
|
+
by something that does not follow the format) is refused, as is one that is not a valid layer; so is a blob
|
|
233
|
+
(the digest of what is in it) or a spec file that is not what its name says.
|
|
234
|
+
- **Dependencies come first.** A manifest needs its blobs; a catalog entry needs its manifest; a spec set needs its
|
|
235
|
+
files; a run's catalog entry needs its manifest.
|
|
236
|
+
- **Layers are immutable.** The same bytes again are fine (a retry); other bytes under the same key are a `409`.
|
|
237
|
+
- **A run that did not pass its privacy scan is never shared.**
|
|
238
|
+
- **Only keys Atlas writes**, under `layers/`, without traversal, backslashes or control characters.
|
|
239
|
+
- **Size.** Bodies over `limits.maxObjectMiB` are refused as they arrive, not after they were held.
|
|
240
|
+
- **Attachment bytes are untrusted.** They are served only through one function that forces a safe type and a
|
|
241
|
+
sandbox, whatever the producer claimed.
|
|
242
|
+
|
|
243
|
+
## Performance
|
|
244
|
+
|
|
245
|
+
`bun packages/server/bench/bench.ts [layers] [checks]` seeds a long history and measures the server on it. On a
|
|
246
|
+
laptop with 2 000 layers of 100 checks (200 000 results, 10 000 slots) and with 1 000 layers of 1 000 checks
|
|
247
|
+
(100 000 slots, a 22 MB report):
|
|
248
|
+
|
|
249
|
+
| | 10 000 slots | 100 000 slots |
|
|
250
|
+
| --- | --- | --- |
|
|
251
|
+
| Start: read and fold every layer | 0.4 s | 1.7 s |
|
|
252
|
+
| A refresh with nothing new | 4 ms | 4 ms |
|
|
253
|
+
| Upload one layer → every viewer told | 4 ms | 5 ms |
|
|
254
|
+
| `GET effective`, cached / `304` | 1 ms / 0.2 ms | 13 ms / 0.5 ms |
|
|
255
|
+
| `GET status`, cached for the version | 12 ms first | 70 ms first |
|
|
256
|
+
|
|
257
|
+
What makes it so, none of it at the cost of the contract:
|
|
258
|
+
|
|
259
|
+
- **A layer is read once.** The report is folded incrementally; only layers that still hold a winner are kept, so
|
|
260
|
+
memory follows the number of checks and not the age of the project.
|
|
261
|
+
- **A change costs one layer.** Each layer remembers the JSON of what it sends, the version is a hash of per-layer
|
|
262
|
+
digests, and a delta lists only layers that changed, so the work to take in a result does not grow with the
|
|
263
|
+
report.
|
|
264
|
+
- **An upload is read once.** A layer's manifest is parsed and verified when it arrives and handed to the report,
|
|
265
|
+
not read again; blob existence is asked 16 at a time.
|
|
266
|
+
- **The newest end of the catalog is all a refresh looks at**, with a full look now and then.
|
|
267
|
+
- **Compressed once.** The viewer's files are brotli-compressed once (gzip for clients that cannot read it), a
|
|
268
|
+
report version is gzipped once however many viewers fetch it, and events are encoded once for every viewer.
|
|
269
|
+
- **A small viewer.** The graph, the Gherkin parser, the recording player and the finder load when used: the
|
|
270
|
+
first page is about 250 KB over the wire.
|
|
271
|
+
|
|
272
|
+
## Operating it
|
|
273
|
+
|
|
274
|
+
- **One server per project.** It is a singleton by design: local environments and CI all talk to it, and it tells
|
|
275
|
+
every viewer at once. Two servers on one backend both work and show the same report, but a viewer hears about
|
|
276
|
+
an upload only from the server that took it and about the other's at the next refresh, so give a team one.
|
|
277
|
+
- **State is the write backend.** Back up `./atlas-data` (or the bucket). Restoring it, or starting a new server
|
|
278
|
+
on it, shows the same report.
|
|
279
|
+
- **Stopping.** `SIGTERM` stops accepting, lets requests in flight finish, ends the event streams and exits 0.
|
|
280
|
+
- **Logs.** One JSON line per request (method, path, status, ms) to stdout, none for the probes. The first lines
|
|
281
|
+
say what it reads and which backend takes uploads, and warn when there are no tokens.
|
|
282
|
+
- **A backend goes down.** The server keeps serving what it has, names the backend in the viewer and in
|
|
283
|
+
`/readyz`, and recovers by itself. The gate fails closed: unknown is not a pass.
|
|
284
|
+
- **Upgrades.** The layer format is a stable, versioned contract; upgrade the server before the clients that
|
|
285
|
+
publish when a release says the format moved.
|