@crvouga/atlas 0.5.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 +6 -0
- package/README.md +30 -11
- package/dist/core/src/cli.d.ts +1 -1
- package/dist/core/src/cli.js +8 -3
- package/dist/core/src/config.d.ts +7 -0
- package/dist/core/src/config.js +48 -14
- package/dist/core/src/run/execute.d.ts +6 -0
- package/dist/core/src/run/execute.js +4 -2
- package/dist/reports/src/doctor.d.ts +1 -1
- package/dist/reports/src/doctor.js +3 -1
- package/dist/reports/src/http-store.d.ts +4 -0
- package/dist/reports/src/http-store.js +6 -3
- package/dist/reports/src/init.js +6 -1
- package/dist/reports/src/live-reporter.d.ts +34 -0
- package/dist/reports/src/live-reporter.js +122 -0
- package/dist/reports/src/report-cli.d.ts +1 -1
- package/dist/reports/src/report-cli.js +3 -2
- package/dist/reports/src/store-url.js +1 -1
- 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 +1 -0
- package/dist/schema/src/api.js +1 -1
- package/dist/schema/src/index.d.ts +2 -0
- package/dist/schema/src/index.js +2 -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 +2 -2
- 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 +1 -0
- package/dist/schema/src/report-sources.js +2 -1
- package/dist/schema/src/runs-index.d.ts +1 -1
- package/dist/schema/src/server-config.d.ts +84 -0
- package/dist/schema/src/server-config.js +12 -0
- package/dist/server/src/app.d.ts +10 -0
- package/dist/server/src/app.js +148 -10
- package/dist/server/src/config.d.ts +1 -1
- package/dist/server/src/config.js +20 -3
- package/dist/server/src/dev.d.ts +3 -3
- package/dist/server/src/dev.js +22 -13
- package/dist/server/src/events.d.ts +3 -3
- package/dist/server/src/events.js +1 -1
- package/dist/server/src/index.d.ts +2 -0
- package/dist/server/src/index.js +2 -0
- package/dist/server/src/live-runs.d.ts +52 -0
- package/dist/server/src/live-runs.js +229 -0
- package/dist/server/src/main.d.ts +1 -1
- package/dist/server/src/main.js +7 -5
- package/dist/server/src/openapi.d.ts +2 -5
- package/dist/server/src/openapi.js +71 -7
- 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 +8 -6
- package/dist/server/src/site.js +45 -10
- package/dist/server/src/store-api.js +43 -22
- package/docs/deploying.md +19 -19
- package/docs/dogfooding.md +2 -2
- package/docs/extending.md +3 -3
- package/docs/integrating.md +9 -9
- package/docs/reference/cli.md +9 -7
- package/docs/reference/core.md +6 -0
- package/docs/reference/http-api.md +498 -2
- package/docs/reference/reports.md +55 -1
- package/docs/reference/runners.md +169 -0
- package/docs/reference/schema.md +111 -0
- package/docs/reference/server.md +154 -14
- package/docs/report-backends.md +8 -8
- package/docs/report-contract.md +7 -7
- package/docs/reporting-issues.md +3 -3
- package/docs/runners.md +69 -0
- package/docs/server.md +61 -25
- package/docs/statecharts.md +22 -20
- package/llms-full.txt +713 -105
- package/llms.txt +3 -1
- package/package.json +31 -9
- 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/schemas/atlas-change.schema.json +4 -0
- package/packages/schema/schemas/hello-event.schema.json +4 -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/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/server-config.schema.json +14 -0
- package/packages/schema/schemas/server-editable-settings.schema.json +132 -0
- package/packages/schema/schemas/server-settings-snapshot.schema.json +285 -0
- package/packages/server/openapi.json +5101 -779
- package/packages/visualizer/README.md +13 -13
- 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 +26 -17
- package/packages/visualizer/src/app/report-sources.tsx +2 -1
- 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 -227
- package/packages/visualizer/src/components/Header.tsx +79 -41
- package/packages/visualizer/src/components/ProjectPicker.tsx +64 -0
- 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 +2 -1
- package/packages/visualizer/src/evidence/check-detail.tsx +19 -4
- package/packages/visualizer/src/evidence/document-page.tsx +6 -2
- package/packages/visualizer/src/evidence/evidence-context.tsx +17 -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/test-filter.tsx +21 -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 +30 -9
- 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 +17 -1
- 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 +2 -1
package/llms-full.txt
CHANGED
|
@@ -177,7 +177,7 @@ integrate. To run it for a whole team, with a bucket and one node everyone looks
|
|
|
177
177
|
```
|
|
178
178
|
node 1: suite A, ios ──▶ layer ─┐
|
|
179
179
|
node 2: suite A, android ──▶ layer ─┤ ┌──▶ atlas report status (gate: exit 1 on failure)
|
|
180
|
-
node 3: suite B, shard 1 ──▶ layer ─┼──▶ backends ──▶ combine ──┼──▶ the
|
|
180
|
+
node 3: suite B, shard 1 ──▶ layer ─┼──▶ backends ──▶ combine ──┼──▶ the client (browse it)
|
|
181
181
|
node 4: suite B, shard 2 ──▶ layer ─┤ └──▶ your own code (combineBackends)
|
|
182
182
|
a laptop, one scenario ──▶ layer ─┘
|
|
183
183
|
```
|
|
@@ -543,7 +543,7 @@ unknown is not a pass.
|
|
|
543
543
|
|
|
544
544
|
## 6. Browse it
|
|
545
545
|
|
|
546
|
-
The
|
|
546
|
+
The Atlas client lays your stores over your specs directory. Add a module to your project:
|
|
547
547
|
|
|
548
548
|
```ts
|
|
549
549
|
// atlas.reports.ts
|
|
@@ -553,14 +553,14 @@ export const reportsDevFetch = reportsHost({ specs: './specs', stores: ['./atlas
|
|
|
553
553
|
```
|
|
554
554
|
|
|
555
555
|
```sh
|
|
556
|
-
ATLAS_REPORTS_MODULE="$(pwd)/atlas.reports.ts" bunx atlas
|
|
556
|
+
ATLAS_REPORTS_MODULE="$(pwd)/atlas.reports.ts" bunx atlas client dev --specs ./specs
|
|
557
557
|
```
|
|
558
558
|
|
|
559
559
|
`reportsHost(options)` returns `(request: Request, repoRoot: string) => Promise<Response>`, the
|
|
560
|
-
function the
|
|
561
|
-
against `repoRoot`, which the
|
|
560
|
+
function the client calls for every `/api/reports/…` request. `specs` and directory `stores` resolve
|
|
561
|
+
against `repoRoot`, which the client sets to where you ran the command (`INIT_CWD`), not against the
|
|
562
562
|
module. A wrong path comes back as a JSON error that names it. A `stores` entry that is not a string is
|
|
563
|
-
a backend of your own: `{ id, label?, store }`. You can call it yourself to look at what the
|
|
563
|
+
a backend of your own: `{ id, label?, store }`. You can call it yourself to look at what the client
|
|
564
564
|
sees:
|
|
565
565
|
|
|
566
566
|
```ts
|
|
@@ -573,11 +573,11 @@ const page = await (await reportsDevFetch(new Request('http://x/api/reports/evid
|
|
|
573
573
|
|
|
574
574
|
| Route (after `/api/reports`) | Returns |
|
|
575
575
|
| --- | --- |
|
|
576
|
-
| `/evidence?cursor=` | A page of layer headers, the backends and any notices. The
|
|
576
|
+
| `/evidence?cursor=` | A page of layer headers, the backends and any notices. The client combines them with the specs. |
|
|
577
577
|
| `/evidence/rows/:backend/:id` | One layer's checks. |
|
|
578
578
|
| `/outline`, `/outline/spec?path=` | The specs directory as an outline, and one spec's text. |
|
|
579
579
|
|
|
580
|
-
The combined result of each spec is computed in the
|
|
580
|
+
The combined result of each spec is computed in the client. To get it without a browser, use
|
|
581
581
|
`atlas report status --format json`: its `specs` array has each spec's counts per environment.
|
|
582
582
|
|
|
583
583
|
Specs are the files of the specs directory (`.feature` as Gherkin, `.qnt` as Quint, `.dmn`, `.als`,
|
|
@@ -618,7 +618,7 @@ An integration is complete when each of these holds. Run them and keep the outpu
|
|
|
618
618
|
| `X is unavailable` | A backend is down. The rest were combined; fix it or leave it out. |
|
|
619
619
|
| `check id "…" appears twice` | Your suite emits two checks with one name. Make the names unique. Importers number repeats as `#2`. |
|
|
620
620
|
| `Potentially outdated: spec changed` | The spec changed since the layer was recorded. Advisory: the recorded outcome still counts. Re-run to refresh. |
|
|
621
|
-
|
|
|
621
|
+
| Client shows `No report store is configured` | `ATLAS_REPORTS_MODULE` is unset, or `stores` is empty. |
|
|
622
622
|
|
|
623
623
|
## Rules
|
|
624
624
|
|
|
@@ -634,15 +634,87 @@ An integration is complete when each of these holds. Run them and keep the outpu
|
|
|
634
634
|
[stable schema](../packages/schema/schemas/report-status.schema.json).
|
|
635
635
|
</doc>
|
|
636
636
|
|
|
637
|
+
<doc path="docs/runners.md">
|
|
638
|
+
# Native test runner reporters
|
|
639
|
+
|
|
640
|
+
Projects upload results to a shared Atlas node under their own project slug. CodeceptJS, Mocha, Jest and Node's test runner have native reporters; other runners can publish their JUnit or CTRF output with `atlas report publish`. All reporters are entry points of the single `@crvouga/atlas` package.
|
|
641
|
+
|
|
642
|
+
## Configure the project once
|
|
643
|
+
|
|
644
|
+
Set these in the test process, locally or in CI:
|
|
645
|
+
|
|
646
|
+
```sh
|
|
647
|
+
export ATLAS_SERVER_URL=https://atlas.example.com
|
|
648
|
+
export ATLAS_PROJECT=checkout-service
|
|
649
|
+
export ATLAS_PUBLISH_TOKEN=your-publish-token
|
|
650
|
+
export ATLAS_ENVIRONMENT=linux-chromium
|
|
651
|
+
export ATLAS_BRANCH=main
|
|
652
|
+
export ATLAS_SHA=your-commit-sha
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
The server owns its storage configuration and credentials. Consumers only need the server URL and a publish token. Upload failures fail the test invocation; reporters wait for publication before finishing. Each invocation streams a live run, then publishes final evidence, with stable check IDs relative to the project directory, durations, failures and skipped outcomes. Unknown outcomes, TODOs and skipped tests are `not-run`, never passed. Parallel processes upload independent layers; use distinct producer/environment values for independent suites.
|
|
656
|
+
|
|
657
|
+
A test file is part of a check's identity, not automatically a specification: link checks to product specifications through the existing report mapping workflow when importing JUnit/CTRF, or publish explicit `specPath` checks through the API.
|
|
658
|
+
|
|
659
|
+
## CodeceptJS
|
|
660
|
+
|
|
661
|
+
Use its [Mocha reporter interface](https://codecept.io/reports/):
|
|
662
|
+
|
|
663
|
+
```sh
|
|
664
|
+
bunx codeceptjs run --reporter @crvouga/atlas/codecept
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
Streams scenario starts and outcomes, then records durations and scenario steps when supplied by CodeceptJS. Use the standard single-process runner; parallel workers should each publish their own layer. Runner-native screenshot/video attachments can also be imported from CTRF/JUnit; this reporter does not read arbitrary files from runner objects.
|
|
668
|
+
|
|
669
|
+
## Mocha
|
|
670
|
+
|
|
671
|
+
```sh
|
|
672
|
+
bunx mocha --reporter @crvouga/atlas/mocha
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
Or configure `reporter` and `reporterOptions` in Mocha. Options include `url`, `token`, `producer`, `environment`, `branch`, `sha`, `rootDir` and `timeoutMs` (30 seconds by default); explicit options override the environment. Final failures and hook failures are failed checks. Passing retries include a flaky label. Mocha parallel mode is not supported by this reporter's event model; run each shard separately.
|
|
676
|
+
|
|
677
|
+
## Jest
|
|
678
|
+
|
|
679
|
+
Keep Jest's console reporter alongside Atlas:
|
|
680
|
+
|
|
681
|
+
```js
|
|
682
|
+
export default {
|
|
683
|
+
reporters: ['default', ['@crvouga/atlas/jest', { producer: 'unit' }]],
|
|
684
|
+
};
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
The reporter streams test-case starts and results from workers and uploads full aggregated evidence after workers finish. File-level exceptions become failed checks even when no test ran. Watch mode resets publication errors on each invocation. It accepts the same options as Mocha.
|
|
688
|
+
|
|
689
|
+
## Node's test runner
|
|
690
|
+
|
|
691
|
+
```sh
|
|
692
|
+
node --test --test-reporter=spec --test-reporter-destination=stdout \
|
|
693
|
+
--test-reporter=@crvouga/atlas/node-test --test-reporter-destination=stdout
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
Uses the native async event stream, with environment configuration. Reports leaf tests; successful suite containers are excluded, while suite hook failures remain failed checks. Test names include enclosing suites so identical names in different suites keep distinct IDs. Skips and TODOs remain not-run, including TODO failures.
|
|
697
|
+
|
|
698
|
+
## Other runners and frameworks
|
|
699
|
+
|
|
700
|
+
Playwright, Vitest, Bun, WebDriver/Appium and Detox already have Atlas statechart adapters. Pytest, JUnit/TestNG, NUnit, xUnit, Go, Rust, Cypress, WebdriverIO, Cucumber and Robot Framework can publish JUnit XML or CTRF JSON through the existing importer. See [integration commands](integrating.md) and the [report contract](report-contract.md). These report importers complement native reporters; they do not require a storage backend in the consumer project.
|
|
701
|
+
|
|
702
|
+
## Operate the singleton
|
|
703
|
+
|
|
704
|
+
Run `atlas server` once for the projects the node hosts; point local and CI publishers at that URL and set each project's `ATLAS_PROJECT`. Configure backends using environment variables or open **Settings** in the client (`/admin`). Authentication and listening addresses remain deployment configuration. Settings changes are validated and saved atomically for the next server restart. Environment variables and flags override saved values. A backend change does not migrate historical data: retain the old backend as a read source when switching the upload destination.
|
|
705
|
+
|
|
706
|
+
Native reporters send a heartbeat every 5 seconds. The server interrupts invocations after 30 seconds of silence, or after the configurable progress-stall timeout. It preserves finished results and never marks missing tests as passed. See [live test runs](server.md#live-test-runs-and-heartbeats).
|
|
707
|
+
</doc>
|
|
708
|
+
|
|
637
709
|
<doc path="docs/server.md">
|
|
638
710
|
# The Atlas server
|
|
639
711
|
|
|
640
|
-
One
|
|
641
|
-
combined report, live**. It is a Bun API that serves a Vite-built single-page
|
|
712
|
+
One node for multiple projects that **takes in results from every environment, keeps them, and shows everyone the
|
|
713
|
+
combined report, live**. It is a Bun API that serves a Vite-built single-page client: one host, one port, in
|
|
642
714
|
development and in production.
|
|
643
715
|
|
|
644
716
|
```
|
|
645
|
-
laptop ──────┐ ┌── browsers (the
|
|
717
|
+
laptop ──────┐ ┌── browsers (the client: reads /api, listens on /api/events)
|
|
646
718
|
CI job ──────┼── PUT /api/store/… POST /api/checks ─▶│
|
|
647
719
|
device lab ──┘ atlas report publish | stream │ atlas report status (the gate: asks /api/status)
|
|
648
720
|
│
|
|
@@ -655,8 +727,8 @@ development and in production.
|
|
|
655
727
|
- **Its default backend is its own filesystem** (`./atlas-data`). That folder is the whole state: back it up,
|
|
656
728
|
mount it on a volume, or put the state in a bucket instead ([backends](#backends)). Several backends are one
|
|
657
729
|
report, as ever.
|
|
658
|
-
- **The report is live.** Every
|
|
659
|
-
says so and each
|
|
730
|
+
- **The report is live.** Every client holds one server-sent-events connection; when results arrive the server
|
|
731
|
+
says so and each client reads only what changed ([streaming](#streaming)).
|
|
660
732
|
- **Layered, never partitioned**, as everywhere in Atlas: the server only stores immutable, content-addressed
|
|
661
733
|
layers and works out the report from them. Replace it, restore it, or run a second one on a copy of the data:
|
|
662
734
|
the same layers give the same report ([the contract](report-contract.md)).
|
|
@@ -673,13 +745,13 @@ export ATLAS_TOKEN=$(openssl rand -hex 24) # admin token; see "Tokens and role
|
|
|
673
745
|
bunx atlas serve # http://127.0.0.1:8080, data in ./atlas-data
|
|
674
746
|
```
|
|
675
747
|
|
|
676
|
-
It runs on Bun and on Node 22.18 or later. The first start builds the
|
|
748
|
+
It runs on Bun and on Node 22.18 or later. The first start builds the client once into `~/.cache/atlas/site`
|
|
677
749
|
(or serves `./atlas-site`, or `--site <dir>`); the build is the same for every project, because the server writes
|
|
678
750
|
its own address book into the page (`window.__ATLAS_CONFIG__`).
|
|
679
751
|
|
|
680
|
-
**Working on Atlas or on the
|
|
752
|
+
**Working on Atlas or on the client:** `atlas dev` runs the server on a port of its own and the client's Vite dev
|
|
681
753
|
server in front of it. Vite proxies `/api` (server-sent events included) to the server, so the browser, the
|
|
682
|
-
uploaders and the
|
|
754
|
+
uploaders and the client all use **one host**, exactly as in production, and a change to the client shows at once.
|
|
683
755
|
|
|
684
756
|
```sh
|
|
685
757
|
bunx atlas dev --data .atlas-data # http://127.0.0.1:5180
|
|
@@ -727,7 +799,7 @@ purposes.
|
|
|
727
799
|
|
|
728
800
|
A backend is anything that implements `ObjectStore`: a folder, an S3-compatible bucket (`s3://`, `r2://`,
|
|
729
801
|
`gs://`), or **another Atlas server** (`https://…`, with `ATLAS_TOKEN` for it). The server reads every backend
|
|
730
|
-
and shows one report; one that is down is named in the
|
|
802
|
+
and shows one report; one that is down is named in the client and skipped, and the server recovers by itself.
|
|
731
803
|
|
|
732
804
|
- **Uploads go to one backend**: the `data` folder, or the one named by `write` / `ATLAS_WRITE`. Name a bucket
|
|
733
805
|
to make it the system of record, so the server holds nothing a replacement would lose:
|
|
@@ -744,7 +816,7 @@ and shows one report; one that is down is named in the viewer and skipped, and t
|
|
|
744
816
|
|
|
745
817
|
| Role | May |
|
|
746
818
|
| --- | --- |
|
|
747
|
-
| `read` | look: the
|
|
819
|
+
| `read` | look: the client, the report, `/api/status` |
|
|
748
820
|
| `publish` | also upload layers, specs and runs, and remove the scratch objects `atlas report doctor` writes |
|
|
749
821
|
| `admin` | all server operations |
|
|
750
822
|
|
|
@@ -828,24 +900,26 @@ there (`409`), so nothing half-uploaded is ever shown.
|
|
|
828
900
|
|
|
829
901
|
| Event | Data | Meaning |
|
|
830
902
|
| --- | --- | --- |
|
|
831
|
-
| `hello` | `{ version, ready, time }` | Sent first. The report's current version. |
|
|
903
|
+
| `hello` | `{ version, ready, time, heartbeatMs? }` | Sent first. The report's current version. |
|
|
832
904
|
| `report` | `{ version, totalLayers, added: [{ id, producer, environment, branch, sha, recordedAtMs, counts }], addedTotal }` | Layers arrived. Enough to say who sent what, without asking. |
|
|
833
905
|
| `atlas:change` | `{ scope: "specs" \| "runs", files, runIds }` | New specs or runs. |
|
|
834
|
-
| `
|
|
906
|
+
| `run` | A bounded `LiveRun` snapshot | Start, progress logs, heartbeat, completion, and interruption; no producer credentials. |
|
|
907
|
+
| `projects` | `{}` | Another project was discovered; refresh the project picker. |
|
|
908
|
+
| `ping` | `{}` | Every 15 s, so proxies keep the connection and the client can tell a quiet server from a dead connection. |
|
|
835
909
|
|
|
836
|
-
|
|
837
|
-
connection, a laptop that slept) loses nothing: it reads again when it reconnects, and the
|
|
910
|
+
Run events update progress directly in the client cache. Report and specification events trigger coalesced reads of the affected data. Events arriving during a read cause a trailing refresh rather than cancelling that read. A client that missed some (a dropped
|
|
911
|
+
connection, a laptop that slept) loses nothing: it reads again when it reconnects, and the client also reads on a
|
|
838
912
|
slow timer behind the stream. Past `limits.maxStreams` viewers the server answers `503` with `Retry-After` and the
|
|
839
|
-
|
|
913
|
+
client polls instead; a client that stops reading is let go rather than held in memory.
|
|
840
914
|
|
|
841
915
|
### Reading only what changed
|
|
842
916
|
|
|
843
917
|
`GET /api/reports/evidence/effective` is the whole report: only the layers that win a check, each with only the
|
|
844
|
-
rows that win, with an ETag. A
|
|
918
|
+
rows that win, with an ETag. A client that holds a version asks `?since=<version>` and is sent **only the layers
|
|
845
919
|
that changed since, and the ids that no longer win anything** (`"delta": true`). Applying that gives exactly the
|
|
846
920
|
report the server would have sent whole (`applyEffectiveDelta`, tested against every earlier version of random
|
|
847
|
-
runs); a version the server does not remember, or an older server, answers with the whole report, which a
|
|
848
|
-
takes as it always did. A result streamed into a 100 000-check report costs a
|
|
921
|
+
runs); a version the server does not remember, or an older server, answers with the whole report, which a client
|
|
922
|
+
takes as it always did. A result streamed into a 100 000-check report costs a client a few kilobytes.
|
|
849
923
|
|
|
850
924
|
## API reference
|
|
851
925
|
|
|
@@ -887,7 +961,7 @@ laptop with 2 000 layers of 100 checks (200 000 results, 10 000 slots) and with
|
|
|
887
961
|
| --- | --- | --- |
|
|
888
962
|
| Start: read and fold every layer | 0.4 s | 1.7 s |
|
|
889
963
|
| A refresh with nothing new | 4 ms | 4 ms |
|
|
890
|
-
| Upload one layer → every
|
|
964
|
+
| Upload one layer → every client told | 4 ms | 5 ms |
|
|
891
965
|
| `GET effective`, cached / `304` | 1 ms / 0.2 ms | 13 ms / 0.5 ms |
|
|
892
966
|
| `GET status`, cached for the version | 12 ms first | 70 ms first |
|
|
893
967
|
|
|
@@ -901,25 +975,59 @@ What makes it so, none of it at the cost of the contract:
|
|
|
901
975
|
- **An upload is read once.** A layer's manifest is parsed and verified when it arrives and handed to the report,
|
|
902
976
|
not read again; blob existence is asked 16 at a time.
|
|
903
977
|
- **The newest end of the catalog is all a refresh looks at**, with a full look now and then.
|
|
904
|
-
- **Compressed once.** The
|
|
905
|
-
report version is gzipped once however many viewers fetch it, and events are encoded once for every
|
|
906
|
-
- **A small
|
|
978
|
+
- **Compressed once.** The client's files are brotli-compressed once (gzip for clients that cannot read it), a
|
|
979
|
+
report version is gzipped once however many viewers fetch it, and events are encoded once for every client.
|
|
980
|
+
- **A small client.** The graph, the Gherkin parser, the recording player and the finder load when used: the
|
|
907
981
|
first page is about 250 KB over the wire.
|
|
908
982
|
|
|
909
983
|
## Operating it
|
|
910
984
|
|
|
911
|
-
- **One
|
|
912
|
-
every
|
|
985
|
+
- **One node for multiple projects.** Local environments and CI select their project slug and talk to the same node, which tells
|
|
986
|
+
every client at once. Two servers on one backend both work and show the same report, but a client hears about
|
|
913
987
|
an upload only from the server that took it and about the other's at the next refresh, so give a team one.
|
|
914
988
|
- **State is the write backend.** Back up `./atlas-data` (or the bucket). Restoring it, or starting a new server
|
|
915
989
|
on it, shows the same report.
|
|
916
990
|
- **Stopping.** `SIGTERM` stops accepting, lets requests in flight finish, ends the event streams and exits 0.
|
|
917
991
|
- **Logs.** One JSON line per request (method, path, status, ms) to stdout, none for the probes. The first lines
|
|
918
992
|
say what it reads and which backend takes uploads, and warn when there are no tokens.
|
|
919
|
-
- **A backend goes down.** The server keeps serving what it has, names the backend in the
|
|
993
|
+
- **A backend goes down.** The server keeps serving what it has, names the backend in the client and in
|
|
920
994
|
`/readyz`, and recovers by itself. The gate fails closed: unknown is not a pass.
|
|
921
995
|
- **Upgrades.** The layer format is a stable, versioned contract; upgrade the server before the clients that
|
|
922
996
|
publish when a release says the format moved.
|
|
997
|
+
|
|
998
|
+
## Configure from the client
|
|
999
|
+
|
|
1000
|
+
Open **Settings** (`/admin`) and enter an admin token. The token stays in page memory. Read and publish tokens cannot edit settings; the browser sign-in box only grants reading. The API uses `Authorization: Bearer` and refuses cross-origin browser writes.
|
|
1001
|
+
|
|
1002
|
+
Use the Storage, Live updates, and Report rules forms to edit saved settings. Advanced includes request limits, logging, a JSON editor, and a read-only view of the active configuration. Save changes and restart Atlas to apply them. Atlas validates the configuration and atomically replaces `atlas.server.json`, preserving authentication and deployment settings. Changes apply at the next restart; environment variables and flags retain precedence. Concurrent edits require reloading the current revision. Data is never moved or removed by changing settings. Keep an old backend as a read source when moving future uploads to a new one. Embedded servers can provide their own settings persistence or manage configuration outside this API.
|
|
1003
|
+
|
|
1004
|
+
Native test reporters for CodeceptJS, Mocha, Jest and Node upload directly to this server; see [runner setup](runners.md). Every publisher uses the same server address and only a publish token. Storage credentials belong in the server environment.
|
|
1005
|
+
|
|
1006
|
+
## Live test runs and heartbeats
|
|
1007
|
+
|
|
1008
|
+
The default native reporters and statechart runner stream tests and steps through `/api/live`, before the invocation finishes. Running tests appear inside their report with an animated status mark and the latest step. Open a test to read its progress log; its previous recorded result stays available separately. The **Running** filter narrows both the spec list and the test rows, and counts update as tests finish or time out. Statechart tests appear inside the chart and screen details. Selecting an archived run leaves live progress out of that historical view. Finished checks immediately enter normal immutable report layers. Operational progress is separate from historical winners, so a previous passed result never implies that the current invocation passed.
|
|
1009
|
+
|
|
1010
|
+
Start with `POST /api/live/<uuid>`, send ordered check deltas with `PATCH /api/live/<uuid>`, and renew the producer lease with `POST /api/live/<uuid>/heartbeat` every 5 seconds. Finish with a terminal update. Only the publisher token that registered the invocation can update it. Replayed sequences must have identical content; late writes cannot revive an expired invocation. `createLiveReporter` handles batching, retries, heartbeat timers and the final flush.
|
|
1011
|
+
|
|
1012
|
+
The server uses its own receipt clock. By default it interrupts a run after 30 seconds without a heartbeat (`ATLAS_RUN_TIMEOUT_SECONDS`). Heartbeats do not reset progress: after 15 minutes with no changed tests/steps, a separate stall timeout interrupts it (`ATLAS_RUN_STALL_SECONDS`, 0 disables). Both settings are editable in the admin UI. Healthy long tests continue renewing heartbeats; increase or disable the progress timeout for tests that legitimately make no observable progress for longer.
|
|
1013
|
+
|
|
1014
|
+
Interrupted runs retain completed results and show why the remaining work stopped. Missing outcomes never become passes. The server persists bounded summaries under `server/live/` in its write backend (an HTTP relay keeps operational leases in its own data folder; the remote server only accepts immutable report objects) and restores outstanding leases as interrupted after a server restart. S3 server credentials need GetObject/PutObject for that prefix; generate the updated `atlas report policy --role both` policy. Producers still receive no backend credentials. Live `run` events carry bounded snapshots directly into test rows, including step logs and interruption reasons. The legacy `atlas:change` announcement remains available for older clients; its optional `liveRunId` identifies lease updates. Reconnecting viewers re-fetch progress, reports, and specifications. With SSE connected, live progress uses a 60-second safety refresh; without SSE it polls every two seconds. Returning to the tab or coming back online also revalidates reports and progress.
|
|
1015
|
+
|
|
1016
|
+
In this repository, use `bun atlas` and `bun example:run` in two terminals. Every example Gherkin scenario executes, including sharing and renaming; `@unrecorded` no longer excludes tests.
|
|
1017
|
+
|
|
1018
|
+
## Multiple projects on one node
|
|
1019
|
+
|
|
1020
|
+
Start the node with `atlas server` (or `bun atlas` in this repository). The server builds or finds the Atlas client and serves it with the API from one process. It never imports a consumer or an example. In this repository the node uses port 5180 and `./atlas-data`; `bun example:run` publishes the Todo app to project `todo-app`.
|
|
1021
|
+
|
|
1022
|
+
Set `ATLAS_PROJECT=todo-app` alongside `ATLAS_SERVER_URL` for native reporters and statechart runs. Report CLI commands accept `--project todo-app` (or `ATLAS_PROJECT`) with an HTTP store. Programmatic HTTP stores, live reporters and native reporter options accept `project: 'todo-app'`. Keep the same slug for the invocation's live progress, final results, spec sets and recordings. Slugs use 1–64 lowercase letters, digits or hyphens, starting and ending with a letter or digit.
|
|
1023
|
+
|
|
1024
|
+
Every project API is available as `/api/projects/<slug>/…`, for example `/api/projects/todo-app/checks`, `/api/projects/todo-app/events` and `/api/projects/todo-app/reports/evidence/effective`. The unprefixed API accepts optional `?project=todo-app` or `X-Atlas-Project: todo-app`. Conflicting selectors are refused. `GET /api/projects` discovers projects. A successful authenticated upload creates a project; reads of an unknown project return 404.
|
|
1025
|
+
|
|
1026
|
+
Projects isolate check identities, specs, run IDs, recordings, lease summaries, event streams and report caches. Identical layer bytes are preserved as uploaded. The node stores each project's objects under `projects/<slug>/` and discovery markers under `server/projects/`. Unqualified requests continue reading the legacy default namespace, advertised as **Default** when it has reports. Existing data is never implicitly moved. For S3, use the combined server policy (`atlas report policy --role both`) with access to both project namespaces and the catalog. An HTTP relay selects the same project on its upstream node and keeps discovery and leases locally.
|
|
1027
|
+
|
|
1028
|
+
The project picker sits at the top right; the header also provides spec dropdown breadcrumbs. Project selection lives in the page URL, so links and refreshes preserve it. Switching projects reloads the client, clearing report queries, media and event connections. Custom report-source preferences are keyed by the project's data URL. Project namespaces share the node's authentication roles: they are organizational partitions, not separate tenant authorization policies. Settings and server identity remain node-wide.
|
|
1029
|
+
|
|
1030
|
+
Project indexes are opened lazily; at most 64 are active in memory. An index with no active requests or event subscribers is closed after five idle minutes. Event subscribers share the node-wide stream limit. Project discovery lists only small catalog markers, never every report layer.
|
|
923
1031
|
</doc>
|
|
924
1032
|
|
|
925
1033
|
<doc path="docs/deploying.md">
|
|
@@ -993,7 +1101,7 @@ so run `atlas report doctor` against yours before relying on it.
|
|
|
993
1101
|
```sh
|
|
994
1102
|
atlas report policy --store s3://my-bucket/atlas/my-project --role publisher # CI and developers
|
|
995
1103
|
atlas report policy --store s3://my-bucket/atlas/my-project --role reader # a server that only reads it, and the gate
|
|
996
|
-
# the server that uploads into it needs --role both
|
|
1104
|
+
# the server that uploads into it needs --role both (also grants server/live/* for live leases)
|
|
997
1105
|
```
|
|
998
1106
|
|
|
999
1107
|
A publisher may write and read `layers/*` and list the folder. A reader may read `layers/*` and list.
|
|
@@ -1102,7 +1210,7 @@ Everything is immutable and addressed by its content, so each publish is safe to
|
|
|
1102
1210
|
in parallel. A set of specs is named by the files and the commit, so publishing the same commit from ten
|
|
1103
1211
|
nodes writes it once.
|
|
1104
1212
|
|
|
1105
|
-
For statecharts, publish each run as a layer and upload it for the
|
|
1213
|
+
For statecharts, publish each run as a layer and upload it for the client:
|
|
1106
1214
|
|
|
1107
1215
|
```sh
|
|
1108
1216
|
bunx atlas run --config atlas.config.ts --shard 1/2
|
|
@@ -1110,7 +1218,7 @@ bunx atlas report publish --producer statecharts --environment desktop-web \
|
|
|
1110
1218
|
--manifest atlas-runs/<run>/manifest.json --specs ./specs --upload-run
|
|
1111
1219
|
```
|
|
1112
1220
|
|
|
1113
|
-
A run is uploaded only when its privacy scan passed: the same rule the static
|
|
1221
|
+
A run is uploaded only when its privacy scan passed: the same rule the static client applies.
|
|
1114
1222
|
|
|
1115
1223
|
## 4. The server
|
|
1116
1224
|
|
|
@@ -1118,7 +1226,7 @@ A run is uploaded only when its privacy scan passed: the same rule the static vi
|
|
|
1118
1226
|
atlas serve # ATLAS_STORE says where; listens on :8080
|
|
1119
1227
|
```
|
|
1120
1228
|
|
|
1121
|
-
It serves the
|
|
1229
|
+
It serves the client, the report and the project's specs and runs from all configured backends. It also
|
|
1122
1230
|
accepts uploads and announces new results on its event stream. Uploads go to `--data` by default;
|
|
1123
1231
|
use a named `--store project=s3://… --write project` to put uploads in a shared bucket, with publisher permissions.
|
|
1124
1232
|
|
|
@@ -1129,7 +1237,7 @@ use a named `--store project=s3://… --write project` to put uploads in a share
|
|
|
1129
1237
|
| `--write <id>` | `ATLAS_WRITE` | Backend that accepts uploads. Default `data`. |
|
|
1130
1238
|
| `--port <n>` | `ATLAS_PORT` or `PORT` | Default 8080. `0` picks a free one. |
|
|
1131
1239
|
| `--host <h>` | `ATLAS_HOST` or `HOST` | Default `127.0.0.1`. Listening beyond this machine requires tokens or `--insecure`. |
|
|
1132
|
-
| `--site <dir>` | `ATLAS_SITE` | The built
|
|
1240
|
+
| `--site <dir>` | `ATLAS_SITE` | The built client. Default: `./atlas-site`, else built once into `~/.cache/atlas/site`. |
|
|
1133
1241
|
| `--outline-branch <b>` | `ATLAS_OUTLINE_BRANCH` | Which branch's specs the report is laid over. Default `main`, then `master`, then the newest. |
|
|
1134
1242
|
| `--refresh <seconds>` | `ATLAS_REFRESH_SECONDS` | How often the bucket is looked at for new layers. Default 10. |
|
|
1135
1243
|
| `--branch <name>` (repeatable) | `ATLAS_ONLY_BRANCH` | Only layers recorded on these branches take part. |
|
|
@@ -1139,7 +1247,7 @@ use a named `--store project=s3://… --write project` to put uploads in a share
|
|
|
1139
1247
|
### Run it
|
|
1140
1248
|
|
|
1141
1249
|
**Docker.** [`examples/deploy/Dockerfile`](https://github.com/crvouga/atlas/blob/main/examples/deploy/Dockerfile)
|
|
1142
|
-
installs Atlas, builds the
|
|
1250
|
+
installs Atlas, builds the client once (it is the same for every project: the server tells the page where its
|
|
1143
1251
|
data is) and starts the server, keeping results on the volume at `/data`:
|
|
1144
1252
|
|
|
1145
1253
|
```sh
|
|
@@ -1148,7 +1256,7 @@ docker run -p 8080:8080 -v atlas-data:/data -e ATLAS_TOKEN=$(openssl rand -hex 2
|
|
|
1148
1256
|
```
|
|
1149
1257
|
|
|
1150
1258
|
For a bucket as the system of record add `-e ATLAS_STORE=project=s3://my-bucket/atlas/my-project -e ATLAS_WRITE=project -e AWS_REGION=us-east-1`.
|
|
1151
|
-
On ECS, EKS or EC2, attach
|
|
1259
|
+
On ECS, EKS or EC2, attach the combined **both** policy (including `server/live/*` for producer leases) to the task, service account or
|
|
1152
1260
|
instance and set no keys.
|
|
1153
1261
|
|
|
1154
1262
|
**Try it on one machine.** [`examples/deploy/compose.yaml`](https://github.com/crvouga/atlas/blob/main/examples/deploy/compose.yaml)
|
|
@@ -1159,7 +1267,7 @@ Publish to `http://localhost:8080` from your project and open it.
|
|
|
1159
1267
|
one copy (the server is a singleton for the project), results in the bucket, readiness on `/readyz`, an IRSA
|
|
1160
1268
|
service account.
|
|
1161
1269
|
|
|
1162
|
-
**Without a container.** `bun add -d @crvouga/atlas`, then `bunx atlas
|
|
1270
|
+
**Without a container.** `bun add -d @crvouga/atlas`, then `bunx atlas client build --no-data --out
|
|
1163
1271
|
atlas-site` and `bunx atlas serve`. It runs on Bun and on Node 22.18 or later. Everything it can be told is in
|
|
1164
1272
|
[the Atlas server](server.md#configuration).
|
|
1165
1273
|
|
|
@@ -1174,12 +1282,12 @@ layer too. Pass `--insecure` only when that proxy handles sign-in.
|
|
|
1174
1282
|
|
|
1175
1283
|
| Path | |
|
|
1176
1284
|
| --- | --- |
|
|
1177
|
-
| `/` | The
|
|
1285
|
+
| `/` | The client. Its page carries the server's address book, so one build serves every project. |
|
|
1178
1286
|
| `/api/reports/evidence/effective` | The whole report in one request: only the layers that win a check, each with only the rows that win. ETag, gzip. |
|
|
1179
1287
|
| `/api/reports/evidence`, `/evidence/rows/<backend>/<id>`, `/outline`, `/outline/spec?path=` | History, one layer's checks, the specs. |
|
|
1180
1288
|
| `/api/reports/evidence/detail/<backend>/<id>?check=<id>&kind=<kind>` | Everything one result carries: its timeline, annotations, retries, attachments and extensions, and the run's own. Without `check`, only the run's. |
|
|
1181
1289
|
| `/api/reports/layers/<id>/blobs/<key>` | One file a layer carries (screenshot, video, trace…), served as untrusted bytes with range support, cached for good. |
|
|
1182
|
-
| `/api/data/specs/…`, `/api/data/runs/…`, `/api/data/sources.json` | The specs and runs, laid out the way the
|
|
1290
|
+
| `/api/data/specs/…`, `/api/data/runs/…`, `/api/data/sources.json` | The specs and runs, laid out the way the client reads a static host. |
|
|
1183
1291
|
| `/api/checks` | Upload a layer of checks with `POST`. |
|
|
1184
1292
|
| `/api/events` | Live report updates over server-sent events. |
|
|
1185
1293
|
| `/healthz` | The process is up. |
|
|
@@ -1202,7 +1310,7 @@ Narrow it by choice, per consumer, never by moving data:
|
|
|
1202
1310
|
| A pull request's gate that inherits what it did not re-run from `main` | `--branch "$PR_BRANCH" --branch main --ignore-modified` |
|
|
1203
1311
|
| A business dashboard of what is committed | `atlas serve --ignore-modified` |
|
|
1204
1312
|
| Everything, as the team lives it | nothing (the default) |
|
|
1205
|
-
| One person's view of what leaving a source out changes | **Sources** in the
|
|
1313
|
+
| One person's view of what leaving a source out changes | **Sources** in the client: leave out a branch, environment, version or layer |
|
|
1206
1314
|
|
|
1207
1315
|
## 6. Operating it
|
|
1208
1316
|
|
|
@@ -1212,12 +1320,12 @@ Narrow it by choice, per consumer, never by moving data:
|
|
|
1212
1320
|
they never need to move together.
|
|
1213
1321
|
- **Logs.** One JSON line per request to stdout. `/healthz` and `/readyz` are not logged. At start it
|
|
1214
1322
|
prints what it reads and any store it cannot reach.
|
|
1215
|
-
- **A store goes down.** The server keeps serving what it has, names the store in the
|
|
1323
|
+
- **A store goes down.** The server keeps serving what it has, names the store in the client's notices and
|
|
1216
1324
|
in `/readyz`, and recovers by itself. The gate fails closed: unknown is not a pass.
|
|
1217
1325
|
- **A layer cannot be read** (corrupt, or written by a newer Atlas): a notice names it. It is tried again
|
|
1218
1326
|
every five minutes.
|
|
1219
|
-
- **Scaling.** One
|
|
1220
|
-
report of 100,000 checks costs a
|
|
1327
|
+
- **Scaling.** One Atlas node supports multiple project namespaces with independently loaded report indexes. It takes in an upload in milliseconds and a
|
|
1328
|
+
report of 100,000 checks costs a client kilobytes per change ([performance](server.md#performance)). Memory
|
|
1221
1329
|
grows with the number of distinct checks, plus about a hundred bytes for each layer ever seen (to know it has
|
|
1222
1330
|
read it). More than one server on a backend works and shows the same report, but each hears of uploads to
|
|
1223
1331
|
another only at its next refresh.
|
|
@@ -1243,13 +1351,13 @@ latency per request, which the server hides by reading 64 at a time):
|
|
|
1243
1351
|
| Publish a layer of plain checks | One `HEAD` and two small `PUT`s. Two thousand layers published in under two seconds from one process, in parallel. |
|
|
1244
1352
|
| Server start | About 0.2 ms of CPU per layer, plus S3 latency ÷ 64 per layer: 2,000 layers in well under a second on a fast store, a few seconds on S3. Each layer is read once, ever. |
|
|
1245
1353
|
| Refresh with nothing new | One `LIST` request for the newest page of the catalog, whatever the history. |
|
|
1246
|
-
| The report, to a
|
|
1247
|
-
| The
|
|
1248
|
-
| The
|
|
1354
|
+
| The report, to a client | One request. 12,000 checks from 2,000 layers is 108 KB gzipped, built once per change. |
|
|
1355
|
+
| The client asking again | `304 Not Modified` in under a millisecond. While the live stream is open it asks only when told, and then for only what changed. |
|
|
1356
|
+
| The client in a browser | One request for the report, plus the spec index, outline and run index and the specs it opens. None per layer, whatever the history (measured in Chromium against a server reading S3). |
|
|
1249
1357
|
|
|
1250
1358
|
How: each layer is folded into the winning result of every check once and dropped unless it still holds a
|
|
1251
1359
|
winner, so work and memory follow the number of checks. Because the winner rule is a total order, folding in
|
|
1252
|
-
any order is exact; a test proves the incremental report equals recomputing from every layer. The
|
|
1360
|
+
any order is exact; a test proves the incremental report equals recomputing from every layer. The client
|
|
1253
1361
|
reads that compact report in one request and only falls back to reading every layer when you ask it to
|
|
1254
1362
|
leave a source out (which needs the history).
|
|
1255
1363
|
|
|
@@ -1266,7 +1374,7 @@ leave a source out (which needs the history).
|
|
|
1266
1374
|
| The server says `listening … no backend can be read yet` | The bucket is unreachable from the server. It retries; `/readyz` stays 503 until it can read. |
|
|
1267
1375
|
| A new layer does not show | Uploaded through the server it is there at once: check the token (`401`/`403` say so). Written straight to a bucket, wait one refresh interval (10 s). Check `atlas report status --store <url>` sees it. |
|
|
1268
1376
|
| Everything is red because of one laptop | By design the newest result wins. Gate on `--ignore-modified` and a branch ([above](#5-choosing-what-takes-part)). |
|
|
1269
|
-
| Specs are empty in the
|
|
1377
|
+
| Specs are empty in the client | Nothing published with `--specs` yet, or only from a branch other than `main`: set `--outline-branch`. |
|
|
1270
1378
|
| `Run … is not shared: its privacy scan did not pass` | `--upload-run` refuses runs whose scan found real data. Fix what it found and run again. |
|
|
1271
1379
|
</doc>
|
|
1272
1380
|
|
|
@@ -1279,7 +1387,7 @@ unit tests, linters, anything that ends in "this check passed or failed". If thi
|
|
|
1279
1387
|
disagree, that is a bug: [file it](reporting-issues.md).
|
|
1280
1388
|
|
|
1281
1389
|
The contract is small on purpose. It is one document (the **layer**), one rule (how layers compose),
|
|
1282
|
-
and one interface (the **backend** that stores them). Everything else, the
|
|
1390
|
+
and one interface (the **backend** that stores them). Everything else, the client, the gate, the CLI,
|
|
1283
1391
|
is built on those three and can be replaced.
|
|
1284
1392
|
|
|
1285
1393
|
- [Concepts](#concepts)
|
|
@@ -1562,7 +1670,7 @@ import { verifyObjectStore } from '@crvouga/atlas/reports/object-store-conforman
|
|
|
1562
1670
|
const { ok, failures } = await verifyObjectStore(myS3Store); // writes under a scratch prefix, cleans up
|
|
1563
1671
|
```
|
|
1564
1672
|
|
|
1565
|
-
Several backends are one report: pass them all to `combineBackends`, to the
|
|
1673
|
+
Several backends are one report: pass them all to `combineBackends`, to the client
|
|
1566
1674
|
(`reportsHost`), or to the CLI (`--store` for directories, `--backends <module>` for the rest). A
|
|
1567
1675
|
backend that cannot be reached is named in the notices and leaves the others usable; asking again
|
|
1568
1676
|
retries it.
|
|
@@ -1575,7 +1683,7 @@ entry whose content has not arrived:
|
|
|
1575
1683
|
A layer's checks are the contract. Next to them the store holds the two other things a whole project
|
|
1576
1684
|
needs, written the same way (content first, catalog entry last, nothing overwritten):
|
|
1577
1685
|
|
|
1578
|
-
- **Spec sets** (`layers/specs/…`): the specs of one commit, so a
|
|
1686
|
+
- **Spec sets** (`layers/specs/…`): the specs of one commit, so a client needs no checkout. A spec set is
|
|
1579
1687
|
`{ schemaVersion, id, branch, sha, recordedAtMs, freshness?, files: [{ path, digest, fingerprint, kind,
|
|
1580
1688
|
title, domain, bytes }] }` ([`spec-set.schema.json`](../packages/schema/schemas/spec-set.schema.json)). Its
|
|
1581
1689
|
id is the digest of the branch, commit and file digests, so one commit's specs are one set however many
|
|
@@ -1583,7 +1691,7 @@ needs, written the same way (content first, catalog entry last, nothing overwrit
|
|
|
1583
1691
|
The outline a report is laid over is the **newest set from `main`** (then `master`, then the newest);
|
|
1584
1692
|
a set from a modified checkout is used only if no committed set exists.
|
|
1585
1693
|
- **Run bundles** (`layers/runs/<run>/…` and `layers/runs/index/…`): a finished statechart run with its
|
|
1586
|
-
screenshots and clips, for the
|
|
1694
|
+
screenshots and clips, for the client. Uploaded only when the run's privacy scan passed; the manifest is
|
|
1587
1695
|
written last, then the catalog entry.
|
|
1588
1696
|
|
|
1589
1697
|
The keys of a layer, bottom up:
|
|
@@ -1649,13 +1757,13 @@ and composed with layers; Atlas never rewrites them. `copyStore` and `atlas repo
|
|
|
1649
1757
|
the number of checks (plus a few bytes for each layer ever read), not the age of the project, and a refresh
|
|
1650
1758
|
with nothing new is one request for the newest page of the catalog. Folding is exact in any order because the winner
|
|
1651
1759
|
rule is a total order; a test proves the incremental report equals combining every layer from scratch.
|
|
1652
|
-
The node sends the
|
|
1760
|
+
The node sends the client only that: one request, only winning rows, with an ETag.
|
|
1653
1761
|
- Measured on a laptop with a directory backend: 300 layers of 50 checks in about 0.2 s; 1,000 layers
|
|
1654
1762
|
of 100 checks, each recorded against 1,000 specs (100,000 results), in about 0.9 s. Composing two
|
|
1655
1763
|
thousand layers of 100 checks (200,000 results) already in memory takes about 0.3 s.
|
|
1656
1764
|
`performance.test.ts` holds budgets ten times looser, to catch an accidental quadratic step on a
|
|
1657
1765
|
slow machine.
|
|
1658
|
-
- A directory backend lists only the directories a prefix can reach. The
|
|
1766
|
+
- A directory backend lists only the directories a prefix can reach. The client polls a small index,
|
|
1659
1767
|
reads an immutable layer once and caches it forever, and loads recordings only when opened.
|
|
1660
1768
|
|
|
1661
1769
|
## Other documents of the contract
|
|
@@ -1667,7 +1775,7 @@ and composed with layers; Atlas never rewrites them. `copyStore` and `atlas repo
|
|
|
1667
1775
|
| Report status | `report-status.schema.json` | The output of `atlas report status --format json`. |
|
|
1668
1776
|
| Spec set | `spec-set.schema.json` | The specs of one commit, as published beside the layers. |
|
|
1669
1777
|
| Run manifest | `manifest.schema.json` | What `atlas run` writes for a statechart run. Publish it as a layer with `--manifest`. |
|
|
1670
|
-
| Runs index, sources, change notices | `runs-index`, `report-sources`, `atlas-change` | How the
|
|
1778
|
+
| Runs index, sources, change notices | `runs-index`, `report-sources`, `atlas-change` | How the client finds runs. See [report backends](report-backends.md). |
|
|
1671
1779
|
| CloudEvents | `cloud-event.schema.json` | Business events a run observed. |
|
|
1672
1780
|
|
|
1673
1781
|
All of them are JSON Schema 2020-12 and ship in the package at `@crvouga/atlas/schemas/<name>.schema.json`.
|
|
@@ -1707,7 +1815,7 @@ carry any of these. Every one is optional.
|
|
|
1707
1815
|
| `attempts[]` | Every try, when the check was retried. |
|
|
1708
1816
|
| `tags[]` | Free labels to filter by: `smoke`, `payments`. |
|
|
1709
1817
|
| `labels{}` | Facts about the result that are not its identity: `owner`, `severity`, `browser`, `build`. |
|
|
1710
|
-
| `links[]` | Where to read more: the CI run, the issue, the trace
|
|
1818
|
+
| `links[]` | Where to read more: the CI run, the issue, the trace client. |
|
|
1711
1819
|
| `extensions{}` | Structured data of your own or a tool's, under a name you own. |
|
|
1712
1820
|
| `measurements[]` | Numbers, with units and an allowance (already part of the contract). |
|
|
1713
1821
|
|
|
@@ -1900,7 +2008,7 @@ Annotation `type`: `note`, `warning`, `deprecation`, `issue`, `accessibility`, `
|
|
|
1900
2008
|
| Something that should be shown well | Ask for a renderer (below). |
|
|
1901
2009
|
| A field every tool should have | Open an issue. It is added as an optional field, and the rules above guarantee nothing breaks. |
|
|
1902
2010
|
|
|
1903
|
-
**A renderer** is one entry in the
|
|
2011
|
+
**A renderer** is one entry in the client's list (`artifactRenderers` in
|
|
1904
2012
|
`packages/visualizer/src/evidence/artifacts.tsx`): how to show an attachment of a media type. The first one that
|
|
1905
2013
|
matches wins:
|
|
1906
2014
|
|
|
@@ -1912,7 +2020,7 @@ registerArtifactRenderer({
|
|
|
1912
2020
|
});
|
|
1913
2021
|
```
|
|
1914
2022
|
|
|
1915
|
-
The
|
|
2023
|
+
The client is part of Atlas, so a renderer for a new media type is a contribution to Atlas: file an issue
|
|
1916
2024
|
([reporting issues](reporting-issues.md)) with a sample file. Until it lands, the attachment is still stored,
|
|
1917
2025
|
listed with its name, role, type and size, and offered for download, and everything else about the result is
|
|
1918
2026
|
unaffected.
|
|
@@ -1924,7 +2032,7 @@ unaffected.
|
|
|
1924
2032
|
> [!NOTE]
|
|
1925
2033
|
> Atlas has two kinds of backend, and this page is about the first.
|
|
1926
2034
|
>
|
|
1927
|
-
> - **Run sources** (this page): where the
|
|
2035
|
+
> - **Run sources** (this page): where the client finds *statechart runs* (`manifest.json` per run)
|
|
1928
2036
|
> and live snapshots of a run in progress: a directory, HTTP files, or an HTTP API.
|
|
1929
2037
|
> - **Layer stores**: where *layers of evidence for any kind of spec* are kept, an `ObjectStore`
|
|
1930
2038
|
> such as a directory or a bucket. Any number of them are one report. See
|
|
@@ -1935,7 +2043,7 @@ unaffected.
|
|
|
1935
2043
|
|
|
1936
2044
|
Atlas maps the product's areas, screens, events and journeys from a spec, then overlays evidence
|
|
1937
2045
|
of what the product did. Specs and reports are independent. Local development, CI, device labs
|
|
1938
|
-
and hosted runners can supply reports to the same product atlas simultaneously. The
|
|
2046
|
+
and hosted runners can supply reports to the same product atlas simultaneously. The client works
|
|
1939
2047
|
before the first report exists.
|
|
1940
2048
|
|
|
1941
2049
|
## Connect sources
|
|
@@ -1954,9 +2062,9 @@ The default source is the directory passed to `--runs`. Add sources with a JSON
|
|
|
1954
2062
|
```
|
|
1955
2063
|
|
|
1956
2064
|
```sh
|
|
1957
|
-
atlas
|
|
1958
|
-
atlas
|
|
1959
|
-
atlas
|
|
2065
|
+
atlas client dev --specs ./specs --runs ./atlas-runs --sources ./atlas.sources.json
|
|
2066
|
+
atlas client build --specs ./specs --runs ./atlas-runs --sources ./atlas.sources.json --out ./atlas-site
|
|
2067
|
+
atlas client publish-data --specs ./specs --runs ./atlas-runs --sources ./atlas.sources.json --out ./atlas-data
|
|
1960
2068
|
```
|
|
1961
2069
|
|
|
1962
2070
|
Directory paths resolve against the configuration file. Source ids are unique, stable names
|
|
@@ -1966,7 +2074,7 @@ Credentials must not appear in this file or URLs: descriptors are sent to the br
|
|
|
1966
2074
|
included in static output.
|
|
1967
2075
|
|
|
1968
2076
|
Remote services must allow requests
|
|
1969
|
-
from the
|
|
2077
|
+
from the client's origin. For private services, use an authenticated same-origin gateway. Atlas
|
|
1970
2078
|
does not download private GitHub artifacts or sign object-storage requests itself: expose their
|
|
1971
2079
|
published data over HTTP or implement a gateway using the contract below.
|
|
1972
2080
|
|
|
@@ -2034,7 +2142,7 @@ updates to keep a snapshot steady; manual Refresh still works. Resuming refreshe
|
|
|
2034
2142
|
|
|
2035
2143
|
## Identity, failures and publishing
|
|
2036
2144
|
|
|
2037
|
-
|
|
2145
|
+
Client identities combine source ids and native run ids. Cache keys include the backend location
|
|
2038
2146
|
and transport. Matching run names cannot mix results or media. Shared links retain the qualified
|
|
2039
2147
|
identity; old links containing only a run id still resolve to workspace reports.
|
|
2040
2148
|
|
|
@@ -2057,7 +2165,7 @@ URLs and never expose the directory paths.
|
|
|
2057
2165
|
|
|
2058
2166
|
`src/data/adapters/report-backend.ts` defines `ReportBackend`: stable identity and cache key,
|
|
2059
2167
|
report listing, snapshot loading, media resolution and optional change subscription. The query
|
|
2060
|
-
layer consumes this separately from the spec adapter. An embedded
|
|
2168
|
+
layer consumes this separately from the spec adapter. An embedded client can supply a backend
|
|
2061
2169
|
through `ReportSourcesContext`; a new built-in transport can add a factory alongside
|
|
2062
2170
|
`createReportBackend`. Screens, maps and journeys require no transport-specific code.
|
|
2063
2171
|
|
|
@@ -2073,7 +2181,7 @@ paths that cover every transition, run those paths against the real product thro
|
|
|
2073
2181
|
browser, a phone, a plain function), and write a manifest of what happened, with screenshots, video
|
|
2074
2182
|
clips, captions, business events and standard test reports. Each run publishes as a layer
|
|
2075
2183
|
(`atlas report publish --manifest`), so it combines with every other suite's evidence. This page covers
|
|
2076
|
-
running them, from a runnable example to the
|
|
2184
|
+
running them, from a runnable example to the Atlas client.
|
|
2077
2185
|
|
|
2078
2186
|
```
|
|
2079
2187
|
specs/ atlas lint the charts are pure, reachable, free of silent dead ends,
|
|
@@ -2103,7 +2211,7 @@ served by a small Node server) specified as two charts:
|
|
|
2103
2211
|
- `specs/getting-started.feature` and `specs/working-the-list.feature`, the same stories in Gherkin.
|
|
2104
2212
|
- `specs/todo.qnt`, the list, its sync, and its actions as a Quint model.
|
|
2105
2213
|
|
|
2106
|
-
The
|
|
2214
|
+
The Atlas client lists the features under Gherkin and the model under Quint.
|
|
2107
2215
|
|
|
2108
2216
|
It has every kind of event: user events (taps and typing), a **system** event ("Sync fails", which
|
|
2109
2217
|
the test triggers through a real HTTP endpoint on the example server), a **time** event ("Retry
|
|
@@ -2133,24 +2241,26 @@ visualizer updates when a run finishes.
|
|
|
2133
2241
|
|
|
2134
2242
|
```sh
|
|
2135
2243
|
bun run atlas:run # example:clients, then example:run: every chart of the example, in showcase mode
|
|
2136
|
-
bun
|
|
2244
|
+
bun atlas # the example's specs, chart runs, and layered reports
|
|
2137
2245
|
```
|
|
2138
2246
|
|
|
2139
|
-
Each config writes its own run and the
|
|
2247
|
+
Each config writes its own run and the Atlas client shows one run at a time: the latest is the
|
|
2140
2248
|
single-browser run, and the run across clients is the one before it in the run picker.
|
|
2141
2249
|
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2250
|
+
Gherkin, Quint, DMN, Alloy and OpenSLO documents sit beside the charts. Results compose across
|
|
2251
|
+
environments, branches and backends within each project. **Sources** switches report sources on or off.
|
|
2252
|
+
|
|
2253
|
+
`bun atlas` runs the singleton Atlas server and the client together at `http://localhost:5180`.
|
|
2254
|
+
It starts a project-agnostic node with no example data. Select a project using the top-right picker.
|
|
2255
|
+
In another terminal run `bun run example:run`: statecharts, Gherkin scenarios and Quint traces stream running checks, completed results and current steps
|
|
2256
|
+
to project `todo-app` on that server while testing. Producers renew a heartbeat every 5 seconds; 30 seconds of silence
|
|
2257
|
+
marks an invocation interrupted. Final specs and recordings upload when their privacy scan completes.
|
|
2258
|
+
Tests show inline running indicators and logs without waiting for the whole suite to finish. Report history
|
|
2259
|
+
is retained in `atlas-data/projects/todo-app`; local run artifacts remain in `atlas-runs` and
|
|
2260
|
+
`atlas-reports`. To upload a completed run again without rerunning tests,
|
|
2261
|
+
use `bun run example:publish`. Set `ATLAS_SERVER_URL` for a different upload destination (and
|
|
2262
|
+
`ATLAS_PUBLISH_TOKEN` when it requires one). Restart `bun atlas` when switching from the older
|
|
2263
|
+
file-based example client; a busy port is an error so publishers cannot silently target another server.
|
|
2154
2264
|
|
|
2155
2265
|
A showcase run ends with:
|
|
2156
2266
|
|
|
@@ -2160,7 +2270,7 @@ Transitions 14/14 passed, 0 failed, 0 not reached
|
|
|
2160
2270
|
Manifest: examples/todo/atlas-runs/<run-id>/manifest.json
|
|
2161
2271
|
```
|
|
2162
2272
|
|
|
2163
|
-
`example:run` then runs the Gherkin features in a browser and the Quint model, and
|
|
2273
|
+
`example:run` then runs the Gherkin features in a browser and the Quint model, and streams every scenario and trace as it runs, including sharing and renaming. The final recordings are uploaded alongside the completed statechart run.
|
|
2164
2274
|
|
|
2165
2275
|
`bun test examples` runs [`model.test.ts`](https://github.com/crvouga/atlas/blob/main/examples/todo/model.test.ts): the same charts and journeys
|
|
2166
2276
|
against `TodoModel`, a plain class, through `functionDriver` and `describeAtlas`. Only the driver
|
|
@@ -2585,7 +2695,7 @@ atlas report publish --producer statecharts --environment desktop-web \
|
|
|
2585
2695
|
--manifest atlas-runs/<run>/manifest.json --specs ./specs --upload-run
|
|
2586
2696
|
```
|
|
2587
2697
|
|
|
2588
|
-
`--upload-run` also sends the run's screenshots and clips to the store (or the server) so the
|
|
2698
|
+
`--upload-run` also sends the run's screenshots and clips to the store (or the server) so the client can show them
|
|
2589
2699
|
(only when the run's privacy scan passed).
|
|
2590
2700
|
|
|
2591
2701
|
## Config reference
|
|
@@ -2695,7 +2805,7 @@ Runs produce media and manifests that get shared, so Atlas refuses to leak real
|
|
|
2695
2805
|
|
|
2696
2806
|
## Visualizer
|
|
2697
2807
|
|
|
2698
|
-
The [`atlas
|
|
2808
|
+
The [`atlas client`](../packages/visualizer) command renders the charts from the specs directory and
|
|
2699
2809
|
overlays runs from the runs directory: screenshots on states, clips on transitions, statuses and
|
|
2700
2810
|
history. See its README for how to point it at a project.
|
|
2701
2811
|
|
|
@@ -2706,7 +2816,7 @@ and completed steps while paths are still running.
|
|
|
2706
2816
|
|
|
2707
2817
|
Layered reports for any spec appear beside the charts: each Gherkin, Quint, DMN, Alloy and OpenSLO
|
|
2708
2818
|
document shows the combined result of its checks per environment, with the layer behind each. Point
|
|
2709
|
-
the
|
|
2819
|
+
the client at your stores with `reportsHost` ([integrating Atlas](integrating.md#6-browse-it)).
|
|
2710
2820
|
</doc>
|
|
2711
2821
|
|
|
2712
2822
|
<doc path="docs/dogfooding.md">
|
|
@@ -2763,7 +2873,7 @@ and nothing runs just because the package is installed.
|
|
|
2763
2873
|
| `@crvouga/atlas/reports/<module>` | Publishing, storing, combining, gating and serving test evidence for specs of any kind. |
|
|
2764
2874
|
|
|
2765
2875
|
It also installs two commands: `atlas` (report, lint, plan, run, merge, export) and
|
|
2766
|
-
`atlas
|
|
2876
|
+
`atlas client` (browse specs, runs and reports).
|
|
2767
2877
|
|
|
2768
2878
|
`playwright` and `detox` are optional peers: install the one your driver uses, as above. The
|
|
2769
2879
|
documentation ships in the package, matching the version you installed: the README of each part at
|
|
@@ -2863,7 +2973,7 @@ Do this once per project. Check first that the package is on npm:
|
|
|
2863
2973
|
| `@crvouga/atlas-schema` | `@crvouga/atlas/schema` |
|
|
2864
2974
|
| `@crvouga/atlas-schema/schemas/<file>` | `@crvouga/atlas/schemas/<file>` |
|
|
2865
2975
|
| `@crvouga/atlas-reports/<module>` | `@crvouga/atlas/reports/<module>` |
|
|
2866
|
-
| `@crvouga/atlas
|
|
2976
|
+
| `@crvouga/atlas client` (the `atlas client` command) | installed with `@crvouga/atlas` |
|
|
2867
2977
|
|
|
2868
2978
|
`@crvouga/atlas`, `@crvouga/atlas/spec` and `@crvouga/atlas/signals` are unchanged. One pass
|
|
2869
2979
|
over a project's sources does the rest:
|
|
@@ -2906,7 +3016,7 @@ This guide is written for coding agents. Read it top to bottom once, then use
|
|
|
2906
3016
|
|
|
2907
3017
|
`<part>` is the part of `@crvouga/atlas` the issue is about: `core` (the main import and the
|
|
2908
3018
|
`atlas` command), or the import path after the package name: `playwright`, `bun`, `webdriver`,
|
|
2909
|
-
`detox`, `vitest`, `schema`, `reports`; `visualizer` for the `atlas
|
|
3019
|
+
`detox`, `vitest`, `schema`, `reports`; `visualizer` for the `atlas client` command. Use `core`
|
|
2910
3020
|
when you cannot tell.
|
|
2911
3021
|
|
|
2912
3022
|
1. [Search for an existing issue](#1-search-first). Comment on it instead of opening a duplicate.
|
|
@@ -2933,10 +3043,10 @@ File when:
|
|
|
2933
3043
|
|
|
2934
3044
|
- **bug**: Atlas throws or hangs; lint, plan or a run gives a result the spec does not support;
|
|
2935
3045
|
a driver taps, types, waits or records differently from what its README says; the manifest or a
|
|
2936
|
-
report does not match its JSON Schema; the
|
|
3046
|
+
report does not match its JSON Schema; the Atlas client shows something other than what the run
|
|
2937
3047
|
recorded; the package fails to install, import, build or type-check.
|
|
2938
3048
|
- **feature**: you need something Atlas does not have: a spec construct, a config option, a driver
|
|
2939
|
-
capability, a CLI flag, a field in the manifest, a view in the
|
|
3049
|
+
capability, a CLI flag, a field in the manifest, a view in the Atlas client, an export format. Check
|
|
2940
3050
|
that part's README and `docs/` first.
|
|
2941
3051
|
|
|
2942
3052
|
Do not file when:
|
|
@@ -3069,8 +3179,9 @@ atlas — executable statecharts
|
|
|
3069
3179
|
[--no-retry] [--output <dir>]
|
|
3070
3180
|
atlas merge [--config atlas.config.ts] [--output <dir>] <run-dir> <run-dir>...
|
|
3071
3181
|
atlas export --specs <dir> --format scxml|mermaid|markdown|json [--out <file>]
|
|
3072
|
-
atlas
|
|
3073
|
-
atlas
|
|
3182
|
+
atlas server [--data <dir>] [--port 8080] [--store <url>]... one Atlas node: API, projects and client
|
|
3183
|
+
atlas client build [--no-data] [--out <dir>] build the project-agnostic Atlas client
|
|
3184
|
+
atlas dev [--port 5180] develop the Atlas server and client on one host
|
|
3074
3185
|
atlas init [--server <url>] [--write] integrate this project: detect its suites, print the plan (atlas init --help)
|
|
3075
3186
|
atlas report publish|stream|status|merge|doctor|policy … layered evidence for any kind of spec (atlas report --help)
|
|
3076
3187
|
|
|
@@ -3110,7 +3221,7 @@ atlas serve: the Atlas server
|
|
|
3110
3221
|
[--outline-branch <b>] [--branch <name>]... [--ignore-modified] [--refresh <seconds>]
|
|
3111
3222
|
[--anonymous-read] [--insecure] [--no-log]
|
|
3112
3223
|
|
|
3113
|
-
One process serves the
|
|
3224
|
+
One process serves the client and the API. Test results are uploaded to it from anywhere (laptops, CI) and it
|
|
3114
3225
|
shows everyone the combined report, live. It keeps its data in --data (default ./atlas-data) and can read more
|
|
3115
3226
|
backends (--store): S3, other servers, folders. Uploads go to the data folder unless --write names another.
|
|
3116
3227
|
|
|
@@ -3121,12 +3232,12 @@ atlas serve: the Atlas server
|
|
|
3121
3232
|
## atlas dev
|
|
3122
3233
|
|
|
3123
3234
|
```text
|
|
3124
|
-
atlas dev: the Atlas server and the
|
|
3235
|
+
atlas dev: the Atlas server and the client, for working on either
|
|
3125
3236
|
|
|
3126
3237
|
atlas dev [--port 5180] [--host 127.0.0.1] [--data <dir>] [--store <url|id=url>]... [--config atlas.server.json]
|
|
3127
3238
|
|
|
3128
|
-
Starts the server (API only, on a port of its own) and the
|
|
3129
|
-
browser talks to one host and a change to the
|
|
3239
|
+
Starts the server (API only, on a port of its own) and the client's dev server, which proxies /api to it, so the
|
|
3240
|
+
browser talks to one host and a change to the client shows at once. In production `atlas serve` does both from
|
|
3130
3241
|
one process.
|
|
3131
3242
|
```
|
|
3132
3243
|
|
|
@@ -3154,7 +3265,8 @@ atlas report — layered evidence for any kind of spec
|
|
|
3154
3265
|
atlas report policy --store s3://bucket/prefix [--role publisher|reader|both]
|
|
3155
3266
|
|
|
3156
3267
|
A store is a directory or s3://bucket/prefix (add ?region=…&endpoint=… for R2, MinIO and the
|
|
3157
|
-
rest).
|
|
3268
|
+
rest). Select a project on an Atlas node with --project <slug> or ATLAS_PROJECT. This scopes specs, reports and recordings together.
|
|
3269
|
+
When no --store is given, ATLAS_STORE is used. Keys never go in the URL: set
|
|
3158
3270
|
AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, or sign in with `aws sso login`, or use a role.
|
|
3159
3271
|
|
|
3160
3272
|
publish Write one immutable layer: the checks of one producer, on one environment. Safe to repeat.
|
|
@@ -3204,6 +3316,134 @@ atlas report — layered evidence for any kind of spec
|
|
|
3204
3316
|
|
|
3205
3317
|
> Generated from the operation table in `packages/server/src/openapi.ts` by `bun run docs`. Do not edit. The same description, for tools, is `openapi.json` (OpenAPI 3.1) and `GET /api/openapi.json` on every server.
|
|
3206
3318
|
|
|
3319
|
+
### List projects on this Atlas node
|
|
3320
|
+
|
|
3321
|
+
`GET /api/projects` · role: read
|
|
3322
|
+
|
|
3323
|
+
Projects are created on their first authenticated upload. All report, spec, recording and live-run data is isolated by project. Unqualified API calls address the legacy default project. Tokens retain their node-wide role; project partitioning is not a tenant authorization boundary.
|
|
3324
|
+
|
|
3325
|
+
Responses: `200` Available project identities.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `503` The project catalog is unavailable.
|
|
3326
|
+
|
|
3327
|
+
### Live test progress and recent invocations
|
|
3328
|
+
|
|
3329
|
+
`GET /api/live` · role: read
|
|
3330
|
+
|
|
3331
|
+
Returns up to 50 recent producer leases, including running, completed and interrupted runs. Counters and recent check/step updates are bounded; authentication credentials are never returned. Consume run events for immediate bounded snapshots; re-fetch after reconnect or atlas:change with scope runs on older servers.
|
|
3332
|
+
|
|
3333
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3334
|
+
|
|
3335
|
+
Responses: `200` Recent live run summaries.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
|
|
3336
|
+
|
|
3337
|
+
### Live test progress and recent invocations
|
|
3338
|
+
|
|
3339
|
+
`GET /api/projects/{project}/live` · role: read
|
|
3340
|
+
|
|
3341
|
+
Returns up to 50 recent producer leases, including running, completed and interrupted runs. Counters and recent check/step updates are bounded; authentication credentials are never returned. Consume run events for immediate bounded snapshots; re-fetch after reconnect or atlas:change with scope runs on older servers.
|
|
3342
|
+
|
|
3343
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
3344
|
+
|
|
3345
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3346
|
+
|
|
3347
|
+
Responses: `200` Recent live run summaries.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
|
|
3348
|
+
|
|
3349
|
+
### Start a live producer lease
|
|
3350
|
+
|
|
3351
|
+
`POST /api/live/{id}` · role: publish
|
|
3352
|
+
|
|
3353
|
+
Register a UUID run id and fixed producer identity before tests begin. Retrying the same identity and token is idempotent. The server timestamps receipt. Send heartbeats every 5 seconds and progress as tests execute. The default heartbeat timeout is 30 seconds; a 15-minute progress stall is configurable separately.
|
|
3354
|
+
|
|
3355
|
+
- `id` (path, required): Producer-generated UUID, also given in the body.
|
|
3356
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3357
|
+
|
|
3358
|
+
Responses: `201` The registered lease.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `403` The token is known but its role may not do this.; `409` The id already belongs to another invocation.; `413` Request too large.; `422` Invalid identity.; `429` Live run capacity reached.
|
|
3359
|
+
|
|
3360
|
+
### Start a live producer lease
|
|
3361
|
+
|
|
3362
|
+
`POST /api/projects/{project}/live/{id}` · role: publish
|
|
3363
|
+
|
|
3364
|
+
Register a UUID run id and fixed producer identity before tests begin. Retrying the same identity and token is idempotent. The server timestamps receipt. Send heartbeats every 5 seconds and progress as tests execute. The default heartbeat timeout is 30 seconds; a 15-minute progress stall is configurable separately.
|
|
3365
|
+
|
|
3366
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
3367
|
+
|
|
3368
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3369
|
+
- `id` (path, required): Producer-generated UUID, also given in the body.
|
|
3370
|
+
|
|
3371
|
+
Responses: `201` The registered lease.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `403` The token is known but its role may not do this.; `409` The id already belongs to another invocation.; `413` Request too large.; `422` Invalid identity.; `429` Live run capacity reached.
|
|
3372
|
+
|
|
3373
|
+
### Publish progress or finish an invocation
|
|
3374
|
+
|
|
3375
|
+
`PATCH /api/live/{id}` · role: publish
|
|
3376
|
+
|
|
3377
|
+
Apply ordered check deltas, starting at sequence 1. Retry a sequence with identical content only. Completed results become immutable report layers immediately; running checks remain operational progress and do not replace historical winners. Finish as completed or interrupted. Stale updates cannot revive an expired lease; pending checks never become passes.
|
|
3378
|
+
|
|
3379
|
+
- `id` (path, required): The UUID of a run started with this publisher token.
|
|
3380
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3381
|
+
|
|
3382
|
+
Responses: `200` Updated progress.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `403` The token is known but its role may not do this.; `404` Unknown run.; `409` Run ended or sequence is stale.; `413` Request too large.; `422` Invalid progress.; `429` Run check capacity reached.
|
|
3383
|
+
|
|
3384
|
+
### Publish progress or finish an invocation
|
|
3385
|
+
|
|
3386
|
+
`PATCH /api/projects/{project}/live/{id}` · role: publish
|
|
3387
|
+
|
|
3388
|
+
Apply ordered check deltas, starting at sequence 1. Retry a sequence with identical content only. Completed results become immutable report layers immediately; running checks remain operational progress and do not replace historical winners. Finish as completed or interrupted. Stale updates cannot revive an expired lease; pending checks never become passes.
|
|
3389
|
+
|
|
3390
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
3391
|
+
|
|
3392
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3393
|
+
- `id` (path, required): The UUID of a run started with this publisher token.
|
|
3394
|
+
|
|
3395
|
+
Responses: `200` Updated progress.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `403` The token is known but its role may not do this.; `404` Unknown run.; `409` Run ended or sequence is stale.; `413` Request too large.; `422` Invalid progress.; `429` Run check capacity reached.
|
|
3396
|
+
|
|
3397
|
+
### Renew a producer heartbeat
|
|
3398
|
+
|
|
3399
|
+
`POST /api/live/{id}/heartbeat` · role: publish
|
|
3400
|
+
|
|
3401
|
+
Renew a running lease using server receipt time, independently of test progress. No result layers are created. Heartbeats cannot revive terminal runs or bypass the configured progress-stall timeout. The producer token must be the one that started this invocation.
|
|
3402
|
+
|
|
3403
|
+
- `id` (path, required): The UUID of this producer invocation.
|
|
3404
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3405
|
+
|
|
3406
|
+
Responses: `200` Heartbeat received.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `403` The token is known but its role may not do this.; `404` Unknown run.; `409` Run ended or its lease expired.; `422` Invalid run id.
|
|
3407
|
+
|
|
3408
|
+
### Renew a producer heartbeat
|
|
3409
|
+
|
|
3410
|
+
`POST /api/projects/{project}/live/{id}/heartbeat` · role: publish
|
|
3411
|
+
|
|
3412
|
+
Renew a running lease using server receipt time, independently of test progress. No result layers are created. Heartbeats cannot revive terminal runs or bypass the configured progress-stall timeout. The producer token must be the one that started this invocation.
|
|
3413
|
+
|
|
3414
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
3415
|
+
|
|
3416
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3417
|
+
- `id` (path, required): The UUID of this producer invocation.
|
|
3418
|
+
|
|
3419
|
+
Responses: `200` Heartbeat received.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `403` The token is known but its role may not do this.; `404` Unknown run.; `409` Run ended or its lease expired.; `422` Invalid run id.
|
|
3420
|
+
|
|
3421
|
+
### Server settings page
|
|
3422
|
+
|
|
3423
|
+
`GET /admin` · role: read
|
|
3424
|
+
|
|
3425
|
+
A standalone settings editor. Supply an admin Bearer token in the page to read or save configuration. The token is held only in memory.
|
|
3426
|
+
|
|
3427
|
+
Responses: `200` Settings editor.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
|
|
3428
|
+
|
|
3429
|
+
### Read server settings
|
|
3430
|
+
|
|
3431
|
+
`GET /api/settings` · role: admin
|
|
3432
|
+
|
|
3433
|
+
Returns editable persisted storage/report settings, active settings, a revision, and configuration precedence. Authentication settings are excluded. Requires an admin Bearer token. Embedded applications may manage settings outside this API.
|
|
3434
|
+
|
|
3435
|
+
Responses: `200` Settings and revision.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `403` The token is known but its role may not do this.; `503` Configuration is managed by the embedding application.
|
|
3436
|
+
|
|
3437
|
+
### Save settings for the next restart
|
|
3438
|
+
|
|
3439
|
+
`PUT /api/settings` · role: admin
|
|
3440
|
+
|
|
3441
|
+
Replaces editable storage/report settings, preserving authentication and other file fields. Atomically persists a validated configuration; no report data is moved. Environment variables and flags override these values after restart. Requires an admin Bearer token, same-origin requests in browsers, and a current revision.
|
|
3442
|
+
|
|
3443
|
+
- `If-Match` (header, required): The quoted revision returned by GET /api/settings.
|
|
3444
|
+
|
|
3445
|
+
Responses: `200` Saved settings and new revision. Restart required.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `403` The token is known but its role may not do this.; `409` Settings changed; reload before saving.; `413` Settings exceed the body limit.; `422` Invalid configuration.; `428` A quoted settings revision is required.; `503` Configuration is managed by the embedding application.
|
|
3446
|
+
|
|
3207
3447
|
### Is the process up
|
|
3208
3448
|
|
|
3209
3449
|
`GET /healthz` · role: none
|
|
@@ -3248,17 +3488,44 @@ Responses: `200` The server.; `401` No token, or an unknown one. Send `Authoriza
|
|
|
3248
3488
|
|
|
3249
3489
|
`GET /api/events` · role: read
|
|
3250
3490
|
|
|
3251
|
-
A `text/event-stream` that stays open.
|
|
3491
|
+
A `text/event-stream` that stays open. Report events announce changes, and run events carry bounded live progress snapshots; authoritative state can always be fetched, so a client that missed events (a dropped connection) loses nothing: read again on reconnect.
|
|
3492
|
+
|
|
3493
|
+
| event | data |
|
|
3494
|
+
| --- | --- |
|
|
3495
|
+
| `hello` | `{ version, ready, time, heartbeatMs? }`, sent first |
|
|
3496
|
+
| `report` | `{ version, totalLayers, added: [{ id, producer, environment, branch, sha, recordedAtMs, counts }], addedTotal }`: layers arrived |
|
|
3497
|
+
| `atlas:change` | `{ scope: "specs" \| "runs", files, runIds }`: new specs or runs |
|
|
3498
|
+
| `run` | A LiveRun snapshot after start, progress, heartbeat, completion, or interruption; contains no producer credentials |
|
|
3499
|
+
| `projects` | `{}` when the node discovers another project; refresh `/api/projects` |
|
|
3500
|
+
| `ping` | `{}` every `heartbeatSeconds`, so a quiet server is told apart from a dead connection |
|
|
3501
|
+
|
|
3502
|
+
Past `limits.maxStreams` viewers the answer is `503` with `Retry-After`: poll `/api/reports/evidence/effective` instead. A browser needs no code beyond `new EventSource("/api/events")`; other clients send the token as `Authorization: Bearer`.
|
|
3503
|
+
|
|
3504
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3505
|
+
|
|
3506
|
+
Responses: `200` The stream.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `503` Too many viewers are connected; poll instead.
|
|
3507
|
+
|
|
3508
|
+
### Server-sent events: results arrived, specs or runs changed
|
|
3509
|
+
|
|
3510
|
+
`GET /api/projects/{project}/events` · role: read
|
|
3511
|
+
|
|
3512
|
+
A `text/event-stream` that stays open. Report events announce changes, and run events carry bounded live progress snapshots; authoritative state can always be fetched, so a client that missed events (a dropped connection) loses nothing: read again on reconnect.
|
|
3252
3513
|
|
|
3253
3514
|
| event | data |
|
|
3254
3515
|
| --- | --- |
|
|
3255
|
-
| `hello` | `{ version, ready, time }`, sent first |
|
|
3516
|
+
| `hello` | `{ version, ready, time, heartbeatMs? }`, sent first |
|
|
3256
3517
|
| `report` | `{ version, totalLayers, added: [{ id, producer, environment, branch, sha, recordedAtMs, counts }], addedTotal }`: layers arrived |
|
|
3257
3518
|
| `atlas:change` | `{ scope: "specs" \| "runs", files, runIds }`: new specs or runs |
|
|
3519
|
+
| `run` | A LiveRun snapshot after start, progress, heartbeat, completion, or interruption; contains no producer credentials |
|
|
3520
|
+
| `projects` | `{}` when the node discovers another project; refresh `/api/projects` |
|
|
3258
3521
|
| `ping` | `{}` every `heartbeatSeconds`, so a quiet server is told apart from a dead connection |
|
|
3259
3522
|
|
|
3260
3523
|
Past `limits.maxStreams` viewers the answer is `503` with `Retry-After`: poll `/api/reports/evidence/effective` instead. A browser needs no code beyond `new EventSource("/api/events")`; other clients send the token as `Authorization: Bearer`.
|
|
3261
3524
|
|
|
3525
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
3526
|
+
|
|
3527
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3528
|
+
|
|
3262
3529
|
Responses: `200` The stream.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `503` Too many viewers are connected; poll instead.
|
|
3263
3530
|
|
|
3264
3531
|
### The whole report, or only what changed since a version
|
|
@@ -3271,6 +3538,25 @@ The report as it stands: only the layers that win at least one check, each with
|
|
|
3271
3538
|
|
|
3272
3539
|
To combine layers yourself, a check's *slot* is `(producer, kind, specPath, check id, environment, parameters)`; the newest completed result wins it. See `docs/report-contract.md`.
|
|
3273
3540
|
|
|
3541
|
+
- `since` (query): The `version` of the report you hold.
|
|
3542
|
+
- `if-none-match` (header): The ETag (the quoted version) of the report you hold.
|
|
3543
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3544
|
+
|
|
3545
|
+
Responses: `200` The whole report, or a delta when `since` was given and remembered.; `304` You already hold this version.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `503` The server is still reading its backends. Retry after the number of seconds in `Retry-After`.
|
|
3546
|
+
|
|
3547
|
+
### The whole report, or only what changed since a version
|
|
3548
|
+
|
|
3549
|
+
`GET /api/projects/{project}/reports/evidence/effective` · role: read
|
|
3550
|
+
|
|
3551
|
+
The report as it stands: only the layers that win at least one check, each with only the rows that win. Whatever the history behind it, this is one request.
|
|
3552
|
+
|
|
3553
|
+
`version` changes exactly when the report does, so it works as an ETag: send `If-None-Match` and get `304`. Better, send `?since=<version>` of the report you hold and get **only what changed** (`delta: true`): replace the layers of the same id, drop `removed`, keep the rest. If the server does not remember that version it answers with the whole report (no `delta` key), so a client always handles both.
|
|
3554
|
+
|
|
3555
|
+
To combine layers yourself, a check's *slot* is `(producer, kind, specPath, check id, environment, parameters)`; the newest completed result wins it. See `docs/report-contract.md`.
|
|
3556
|
+
|
|
3557
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
3558
|
+
|
|
3559
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3274
3560
|
- `since` (query): The `version` of the report you hold.
|
|
3275
3561
|
- `if-none-match` (header): The ETag (the quoted version) of the report you hold.
|
|
3276
3562
|
|
|
@@ -3284,6 +3570,25 @@ The `atlas report status --format json` document, worked out by the server from
|
|
|
3284
3570
|
|
|
3285
3571
|
The header `X-Atlas-Ok: true|false` carries the verdict, so a shell can test it without parsing. Narrow it by choice, per request: `branch` (repeatable) and `ignoreModified` read only matching layers.
|
|
3286
3572
|
|
|
3573
|
+
- `branch` (query): Only layers recorded on this branch. Repeatable.
|
|
3574
|
+
- `ignoreModified` (query): `1`: leave out layers from modified checkouts and unknown origins.
|
|
3575
|
+
- `requireEnvironments` (query): Comma-separated environments that must have results.
|
|
3576
|
+
- `requireAllSpecs` (query): `1`: fail while any spec of the outline has no results.
|
|
3577
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3578
|
+
|
|
3579
|
+
Responses: `200` The verdict, whether or not it passes.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `503` The server is still reading its backends. Retry after the number of seconds in `Retry-After`.
|
|
3580
|
+
|
|
3581
|
+
### The gate: does the report pass
|
|
3582
|
+
|
|
3583
|
+
`GET /api/projects/{project}/status` · role: read
|
|
3584
|
+
|
|
3585
|
+
The `atlas report status --format json` document, worked out by the server from the layers it holds and remembered for each version of the report. It passes (`ok: true`) only if some check completed, none failed, none is still running, every layer and backend could be read, and every required environment has results. **Unknown is never a pass.**
|
|
3586
|
+
|
|
3587
|
+
The header `X-Atlas-Ok: true|false` carries the verdict, so a shell can test it without parsing. Narrow it by choice, per request: `branch` (repeatable) and `ignoreModified` read only matching layers.
|
|
3588
|
+
|
|
3589
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
3590
|
+
|
|
3591
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3287
3592
|
- `branch` (query): Only layers recorded on this branch. Repeatable.
|
|
3288
3593
|
- `ignoreModified` (query): `1`: leave out layers from modified checkouts and unknown origins.
|
|
3289
3594
|
- `requireEnvironments` (query): Comma-separated environments that must have results.
|
|
@@ -3299,6 +3604,22 @@ The simplest way in: anything that can make an HTTP request can report. The body
|
|
|
3299
3604
|
|
|
3300
3605
|
Send the token as `Authorization: Bearer <token>` (a `publish` or `admin` token). A browser's sign-in box is refused for uploads on purpose. A check id appearing twice in one body is `422`.
|
|
3301
3606
|
|
|
3607
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3608
|
+
|
|
3609
|
+
Responses: `201` The layer was written.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `403` The token is known but its role may not do this.; `413` The body is over `limits.maxJsonMiB`.; `422` The body is not valid: the detail says which field.
|
|
3610
|
+
|
|
3611
|
+
### Upload one layer of checks as JSON
|
|
3612
|
+
|
|
3613
|
+
`POST /api/projects/{project}/checks` · role: publish
|
|
3614
|
+
|
|
3615
|
+
The simplest way in: anything that can make an HTTP request can report. The body is the checks file (`packages/schema/schemas/publish-checks.schema.json`); `recordedAtMs` defaults to now. Binary evidence goes in as `base64`. The server writes the layer and it is in every viewer's report before this answers.
|
|
3616
|
+
|
|
3617
|
+
Send the token as `Authorization: Bearer <token>` (a `publish` or `admin` token). A browser's sign-in box is refused for uploads on purpose. A check id appearing twice in one body is `422`.
|
|
3618
|
+
|
|
3619
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
3620
|
+
|
|
3621
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3622
|
+
|
|
3302
3623
|
Responses: `201` The layer was written.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `403` The token is known but its role may not do this.; `413` The body is over `limits.maxJsonMiB`.; `422` The body is not valid: the detail says which field.
|
|
3303
3624
|
|
|
3304
3625
|
### List keys under layers/
|
|
@@ -3307,6 +3628,22 @@ Responses: `201` The layer was written.; `401` No token, or an unknown one. Send
|
|
|
3307
3628
|
|
|
3308
3629
|
One page of the keys of `layers/…` (never anything else), in code-unit order. Page with `after` = the `next` of the previous page. This is the `listPage` of the `ObjectStore` interface; `atlas report merge` and `httpStore` use it.
|
|
3309
3630
|
|
|
3631
|
+
- `prefix` (query): Only keys starting with this. Default `layers/`.
|
|
3632
|
+
- `after` (query): Only keys after this one (exclusive).
|
|
3633
|
+
- `limit` (query): Page size, 1 to 1000. Default 1000.
|
|
3634
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3635
|
+
|
|
3636
|
+
Responses: `200` A page.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `422` The prefix is not one Atlas holds.
|
|
3637
|
+
|
|
3638
|
+
### List keys under layers/
|
|
3639
|
+
|
|
3640
|
+
`GET /api/projects/{project}/store` · role: read
|
|
3641
|
+
|
|
3642
|
+
One page of the keys of `layers/…` (never anything else), in code-unit order. Page with `after` = the `next` of the previous page. This is the `listPage` of the `ObjectStore` interface; `atlas report merge` and `httpStore` use it.
|
|
3643
|
+
|
|
3644
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
3645
|
+
|
|
3646
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3310
3647
|
- `prefix` (query): Only keys starting with this. Default `layers/`.
|
|
3311
3648
|
- `after` (query): Only keys after this one (exclusive).
|
|
3312
3649
|
- `limit` (query): Page size, 1 to 1000. Default 1000.
|
|
@@ -3319,6 +3656,20 @@ Responses: `200` A page.; `401` No token, or an unknown one. Send `Authorization
|
|
|
3319
3656
|
|
|
3320
3657
|
The bytes of one object, with the content type it was stored with. Everything under `layers/` is immutable, so the answer is cacheable for good. The bytes came from a test run and are untrusted: they are served with `nosniff` and a sandboxing Content-Security-Policy, whatever type their uploader gave them.
|
|
3321
3658
|
|
|
3659
|
+
- `key` (path, required): An object key under `layers/`, such as `layers/manifests/<id>.json`. It contains slashes, which are not percent-encoded; every other character is.
|
|
3660
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3661
|
+
|
|
3662
|
+
Responses: `200` The object.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No such object.; `422` Not a key Atlas holds.
|
|
3663
|
+
|
|
3664
|
+
### Read an object
|
|
3665
|
+
|
|
3666
|
+
`GET /api/projects/{project}/store/{key}` · role: read
|
|
3667
|
+
|
|
3668
|
+
The bytes of one object, with the content type it was stored with. Everything under `layers/` is immutable, so the answer is cacheable for good. The bytes came from a test run and are untrusted: they are served with `nosniff` and a sandboxing Content-Security-Policy, whatever type their uploader gave them.
|
|
3669
|
+
|
|
3670
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
3671
|
+
|
|
3672
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3322
3673
|
- `key` (path, required): An object key under `layers/`, such as `layers/manifests/<id>.json`. It contains slashes, which are not percent-encoded; every other character is.
|
|
3323
3674
|
|
|
3324
3675
|
Responses: `200` The object.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No such object.; `422` Not a key Atlas holds.
|
|
@@ -3329,6 +3680,20 @@ Responses: `200` The object.; `401` No token, or an unknown one. Send `Authoriza
|
|
|
3329
3680
|
|
|
3330
3681
|
`200` when the object exists, `404` when not. No body.
|
|
3331
3682
|
|
|
3683
|
+
- `key` (path, required): An object key under `layers/`, such as `layers/manifests/<id>.json`. It contains slashes, which are not percent-encoded; every other character is.
|
|
3684
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3685
|
+
|
|
3686
|
+
Responses: `200` It exists.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No such object.
|
|
3687
|
+
|
|
3688
|
+
### Does an object exist
|
|
3689
|
+
|
|
3690
|
+
`HEAD /api/projects/{project}/store/{key}` · role: read
|
|
3691
|
+
|
|
3692
|
+
`200` when the object exists, `404` when not. No body.
|
|
3693
|
+
|
|
3694
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
3695
|
+
|
|
3696
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3332
3697
|
- `key` (path, required): An object key under `layers/`, such as `layers/manifests/<id>.json`. It contains slashes, which are not percent-encoded; every other character is.
|
|
3333
3698
|
|
|
3334
3699
|
Responses: `200` It exists.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No such object.
|
|
@@ -3347,6 +3712,29 @@ The write half of the `ObjectStore` interface. The server checks what it can fro
|
|
|
3347
3712
|
|
|
3348
3713
|
Upload in dependency order: blobs, then the manifest, then the catalog entry. `atlas report publish`, `atlas report stream` and `httpStore` do. Needs a `Bearer` token of role `publish` or `admin`; a browser's sign-in box is refused.
|
|
3349
3714
|
|
|
3715
|
+
- `key` (path, required): An object key under `layers/`, such as `layers/manifests/<id>.json`. It contains slashes, which are not percent-encoded; every other character is.
|
|
3716
|
+
- `content-type` (header): Stored with the object and returned when it is read.
|
|
3717
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3718
|
+
|
|
3719
|
+
Responses: `200` Already there with the same bytes.; `201` Stored.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `403` The token is known but its role may not do this.; `409` A dependency has not been uploaded yet, or other bytes are already stored under this key.; `413` Over `limits.maxObjectMiB`.; `422` Not a key Atlas writes, or the content is not what its name says.
|
|
3720
|
+
|
|
3721
|
+
### Upload an object
|
|
3722
|
+
|
|
3723
|
+
`PUT /api/projects/{project}/store/{key}` · role: publish
|
|
3724
|
+
|
|
3725
|
+
The write half of the `ObjectStore` interface. The server checks what it can from the bytes in hand and says no to what would corrupt the report for everyone:
|
|
3726
|
+
|
|
3727
|
+
- a **layer manifest** (`layers/manifests/<id>.json`) must be a valid layer whose content hashes to `<id>`, and its blobs must already be there (`409` otherwise);
|
|
3728
|
+
- a **blob** (`layers/blobs/<sha256>.gz`) must be gzip of content whose SHA-256 is its name; a **spec file** likewise;
|
|
3729
|
+
- a **catalog entry** (`…/index/…`) must name something already uploaded (`409` otherwise): it is what makes a layer visible, so it is written last;
|
|
3730
|
+
- a **run manifest** must have passed its privacy scan;
|
|
3731
|
+
- keys are immutable: the same bytes again are `200` (a retry), other bytes under the same key are `409`.
|
|
3732
|
+
|
|
3733
|
+
Upload in dependency order: blobs, then the manifest, then the catalog entry. `atlas report publish`, `atlas report stream` and `httpStore` do. Needs a `Bearer` token of role `publish` or `admin`; a browser's sign-in box is refused.
|
|
3734
|
+
|
|
3735
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
3736
|
+
|
|
3737
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3350
3738
|
- `key` (path, required): An object key under `layers/`, such as `layers/manifests/<id>.json`. It contains slashes, which are not percent-encoded; every other character is.
|
|
3351
3739
|
- `content-type` (header): Stored with the object and returned when it is read.
|
|
3352
3740
|
|
|
@@ -3358,6 +3746,20 @@ Responses: `200` Already there with the same bytes.; `201` Stored.; `401` No tok
|
|
|
3358
3746
|
|
|
3359
3747
|
Only the scratch objects `atlas report doctor` writes (`layers/doctor-…`) can be removed. Layers, specs and runs are never removed through the API.
|
|
3360
3748
|
|
|
3749
|
+
- `key` (path, required): An object key under `layers/`, such as `layers/manifests/<id>.json`. It contains slashes, which are not percent-encoded; every other character is.
|
|
3750
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3751
|
+
|
|
3752
|
+
Responses: `204` Removed (or it was not there).; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `403` Not a scratch object, or the token may not.
|
|
3753
|
+
|
|
3754
|
+
### Remove a scratch object
|
|
3755
|
+
|
|
3756
|
+
`DELETE /api/projects/{project}/store/{key}` · role: publish
|
|
3757
|
+
|
|
3758
|
+
Only the scratch objects `atlas report doctor` writes (`layers/doctor-…`) can be removed. Layers, specs and runs are never removed through the API.
|
|
3759
|
+
|
|
3760
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
3761
|
+
|
|
3762
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3361
3763
|
- `key` (path, required): An object key under `layers/`, such as `layers/manifests/<id>.json`. It contains slashes, which are not percent-encoded; every other character is.
|
|
3362
3764
|
|
|
3363
3765
|
Responses: `204` Removed (or it was not there).; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `403` Not a scratch object, or the token may not.
|
|
@@ -3368,6 +3770,20 @@ Responses: `204` Removed (or it was not there).; `401` No token, or an unknown o
|
|
|
3368
3770
|
|
|
3369
3771
|
The specs of the newest committed spec set (of `main`, else the newest), so the report needs no checkout. A spec here with no result shows as having none.
|
|
3370
3772
|
|
|
3773
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3774
|
+
|
|
3775
|
+
Responses: `200` The outline.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
|
|
3776
|
+
|
|
3777
|
+
### The specs a report is laid over
|
|
3778
|
+
|
|
3779
|
+
`GET /api/projects/{project}/reports/outline` · role: read
|
|
3780
|
+
|
|
3781
|
+
The specs of the newest committed spec set (of `main`, else the newest), so the report needs no checkout. A spec here with no result shows as having none.
|
|
3782
|
+
|
|
3783
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
3784
|
+
|
|
3785
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3786
|
+
|
|
3371
3787
|
Responses: `200` The outline.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
|
|
3372
3788
|
|
|
3373
3789
|
### The text of one spec
|
|
@@ -3376,6 +3792,20 @@ Responses: `200` The outline.; `401` No token, or an unknown one. Send `Authoriz
|
|
|
3376
3792
|
|
|
3377
3793
|
The text of a spec file of the outline, by its path.
|
|
3378
3794
|
|
|
3795
|
+
- `path` (query, required): The spec's path, `specs/<path>`.
|
|
3796
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3797
|
+
|
|
3798
|
+
Responses: `200` The spec text.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No such spec in the outline.
|
|
3799
|
+
|
|
3800
|
+
### The text of one spec
|
|
3801
|
+
|
|
3802
|
+
`GET /api/projects/{project}/reports/outline/spec` · role: read
|
|
3803
|
+
|
|
3804
|
+
The text of a spec file of the outline, by its path.
|
|
3805
|
+
|
|
3806
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
3807
|
+
|
|
3808
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3379
3809
|
- `path` (query, required): The spec's path, `specs/<path>`.
|
|
3380
3810
|
|
|
3381
3811
|
Responses: `200` The spec text.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No such spec in the outline.
|
|
@@ -3386,6 +3816,20 @@ Responses: `200` The spec text.; `401` No token, or an unknown one. Send `Author
|
|
|
3386
3816
|
|
|
3387
3817
|
The history: layer headers newest first, merged from every backend. Prefer `/api/reports/evidence/effective`, which is one request and holds only what wins. Use this to audit what was recorded.
|
|
3388
3818
|
|
|
3819
|
+
- `cursor` (query): The `cursor` of the previous page.
|
|
3820
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3821
|
+
|
|
3822
|
+
Responses: `200` A page of headers.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `503` The server is still reading its backends. Retry after the number of seconds in `Retry-After`.
|
|
3823
|
+
|
|
3824
|
+
### Page through every layer header
|
|
3825
|
+
|
|
3826
|
+
`GET /api/projects/{project}/reports/evidence` · role: read
|
|
3827
|
+
|
|
3828
|
+
The history: layer headers newest first, merged from every backend. Prefer `/api/reports/evidence/effective`, which is one request and holds only what wins. Use this to audit what was recorded.
|
|
3829
|
+
|
|
3830
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
3831
|
+
|
|
3832
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3389
3833
|
- `cursor` (query): The `cursor` of the previous page.
|
|
3390
3834
|
|
|
3391
3835
|
Responses: `200` A page of headers.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `503` The server is still reading its backends. Retry after the number of seconds in `Retry-After`.
|
|
@@ -3396,6 +3840,21 @@ Responses: `200` A page of headers.; `401` No token, or an unknown one. Send `Au
|
|
|
3396
3840
|
|
|
3397
3841
|
Every check of one layer (not only those that win), with the spec fingerprints it recorded.
|
|
3398
3842
|
|
|
3843
|
+
- `backend` (path, required): A backend id from `/api/server`.
|
|
3844
|
+
- `id` (path, required): A layer id: 64 lowercase hex digits.
|
|
3845
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3846
|
+
|
|
3847
|
+
Responses: `200` The rows.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No such layer in that backend.
|
|
3848
|
+
|
|
3849
|
+
### The checks of one layer
|
|
3850
|
+
|
|
3851
|
+
`GET /api/projects/{project}/reports/evidence/rows/{backend}/{id}` · role: read
|
|
3852
|
+
|
|
3853
|
+
Every check of one layer (not only those that win), with the spec fingerprints it recorded.
|
|
3854
|
+
|
|
3855
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
3856
|
+
|
|
3857
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3399
3858
|
- `backend` (path, required): A backend id from `/api/server`.
|
|
3400
3859
|
- `id` (path, required): A layer id: 64 lowercase hex digits.
|
|
3401
3860
|
|
|
@@ -3407,6 +3866,23 @@ Responses: `200` The rows.; `401` No token, or an unknown one. Send `Authorizati
|
|
|
3407
3866
|
|
|
3408
3867
|
The timeline, annotations, retries, attachments and extensions of one check, and what its run carries as a whole. Without `check`, only the run's. Attachment bytes are fetched from `/api/reports/layers/{id}/blobs/{bundleKey}`.
|
|
3409
3868
|
|
|
3869
|
+
- `backend` (path, required): A backend id from `/api/server`.
|
|
3870
|
+
- `id` (path, required): A layer id: 64 lowercase hex digits.
|
|
3871
|
+
- `check` (query): The check id.
|
|
3872
|
+
- `kind` (query): The kind of the part, when the same id is in several.
|
|
3873
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3874
|
+
|
|
3875
|
+
Responses: `200` The detail.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No such layer or check.
|
|
3876
|
+
|
|
3877
|
+
### Everything one result carries
|
|
3878
|
+
|
|
3879
|
+
`GET /api/projects/{project}/reports/evidence/detail/{backend}/{id}` · role: read
|
|
3880
|
+
|
|
3881
|
+
The timeline, annotations, retries, attachments and extensions of one check, and what its run carries as a whole. Without `check`, only the run's. Attachment bytes are fetched from `/api/reports/layers/{id}/blobs/{bundleKey}`.
|
|
3882
|
+
|
|
3883
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
3884
|
+
|
|
3885
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3410
3886
|
- `backend` (path, required): A backend id from `/api/server`.
|
|
3411
3887
|
- `id` (path, required): A layer id: 64 lowercase hex digits.
|
|
3412
3888
|
- `check` (query): The check id.
|
|
@@ -3420,6 +3896,22 @@ Responses: `200` The detail.; `401` No token, or an unknown one. Send `Authoriza
|
|
|
3420
3896
|
|
|
3421
3897
|
A screenshot, video, trace, log or any attachment of a layer, by the `bundleKey` its attachment names (`attachments/<sha256>`). Served as untrusted bytes: never sniffed, never run, sandboxed; immutable, cacheable for good; videos can be sought with `Range`.
|
|
3422
3898
|
|
|
3899
|
+
- `id` (path, required): A layer id: 64 lowercase hex digits.
|
|
3900
|
+
- `bundleKey` (path, required): The attachment's `bundleKey`, which contains a slash.
|
|
3901
|
+
- `range` (header): A byte range, `bytes=0-1023`.
|
|
3902
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3903
|
+
|
|
3904
|
+
Responses: `200` The bytes, with the type the producer gave (or `application/octet-stream`).; `206` The requested range.; `304` Not modified.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No such layer or file.
|
|
3905
|
+
|
|
3906
|
+
### A file a layer carries
|
|
3907
|
+
|
|
3908
|
+
`GET /api/projects/{project}/reports/layers/{id}/blobs/{bundleKey}` · role: read
|
|
3909
|
+
|
|
3910
|
+
A screenshot, video, trace, log or any attachment of a layer, by the `bundleKey` its attachment names (`attachments/<sha256>`). Served as untrusted bytes: never sniffed, never run, sandboxed; immutable, cacheable for good; videos can be sought with `Range`.
|
|
3911
|
+
|
|
3912
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
3913
|
+
|
|
3914
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3423
3915
|
- `id` (path, required): A layer id: 64 lowercase hex digits.
|
|
3424
3916
|
- `bundleKey` (path, required): The attachment's `bundleKey`, which contains a slash.
|
|
3425
3917
|
- `range` (header): A byte range, `bytes=0-1023`.
|
|
@@ -3432,6 +3924,21 @@ Responses: `200` The bytes, with the type the producer gave (or `application/oct
|
|
|
3432
3924
|
|
|
3433
3925
|
The `report.json`, captured files and frame stylesheet of a recorded statechart test of a layer (`tests/<testId>/report.json`, `tests/<testId>/files/…`, `frame.css`). Untrusted bytes, served like attachments.
|
|
3434
3926
|
|
|
3927
|
+
- `id` (path, required): A layer id: 64 lowercase hex digits.
|
|
3928
|
+
- `path` (path, required): The path under the layer.
|
|
3929
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3930
|
+
|
|
3931
|
+
Responses: `200` The file.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No such file.
|
|
3932
|
+
|
|
3933
|
+
### A recorded test of a statechart run
|
|
3934
|
+
|
|
3935
|
+
`GET /api/projects/{project}/reports/layers/{id}/{path}` · role: read
|
|
3936
|
+
|
|
3937
|
+
The `report.json`, captured files and frame stylesheet of a recorded statechart test of a layer (`tests/<testId>/report.json`, `tests/<testId>/files/…`, `frame.css`). Untrusted bytes, served like attachments.
|
|
3938
|
+
|
|
3939
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
3940
|
+
|
|
3941
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3435
3942
|
- `id` (path, required): A layer id: 64 lowercase hex digits.
|
|
3436
3943
|
- `path` (path, required): The path under the layer.
|
|
3437
3944
|
|
|
@@ -3443,6 +3950,20 @@ Responses: `200` The file.; `401` No token, or an unknown one. Send `Authorizati
|
|
|
3443
3950
|
|
|
3444
3951
|
For spec runs writing on the same machine as a development host (`atlas-visualizer dev`). A server has none: it answers `404`.
|
|
3445
3952
|
|
|
3953
|
+
- `source` (path, required): The live source id.
|
|
3954
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3955
|
+
|
|
3956
|
+
Responses: `200` The stylesheet.; `404` Not a live source.
|
|
3957
|
+
|
|
3958
|
+
### Frame stylesheet of a live spec run (development only)
|
|
3959
|
+
|
|
3960
|
+
`GET /api/projects/{project}/reports/live/{source}/frame.css` · role: read
|
|
3961
|
+
|
|
3962
|
+
For spec runs writing on the same machine as a development host (`atlas-visualizer dev`). A server has none: it answers `404`.
|
|
3963
|
+
|
|
3964
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
3965
|
+
|
|
3966
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3446
3967
|
- `source` (path, required): The live source id.
|
|
3447
3968
|
|
|
3448
3969
|
Responses: `200` The stylesheet.; `404` Not a live source.
|
|
@@ -3453,6 +3974,22 @@ Responses: `200` The stylesheet.; `404` Not a live source.
|
|
|
3453
3974
|
|
|
3454
3975
|
For spec runs writing on the same machine as a development host. A server has none: it answers `404`.
|
|
3455
3976
|
|
|
3977
|
+
- `source` (path, required): The live source id.
|
|
3978
|
+
- `testId` (path, required): The test id.
|
|
3979
|
+
- `path` (path, required): The path under the test.
|
|
3980
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3981
|
+
|
|
3982
|
+
Responses: `200` The file.; `404` Not a live source.
|
|
3983
|
+
|
|
3984
|
+
### A file of a test in a live spec run (development only)
|
|
3985
|
+
|
|
3986
|
+
`GET /api/projects/{project}/reports/live/{source}/tests/{testId}/{path}` · role: read
|
|
3987
|
+
|
|
3988
|
+
For spec runs writing on the same machine as a development host. A server has none: it answers `404`.
|
|
3989
|
+
|
|
3990
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
3991
|
+
|
|
3992
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3456
3993
|
- `source` (path, required): The live source id.
|
|
3457
3994
|
- `testId` (path, required): The test id.
|
|
3458
3995
|
- `path` (path, required): The path under the test.
|
|
@@ -3465,6 +4002,20 @@ Responses: `200` The file.; `404` Not a live source.
|
|
|
3465
4002
|
|
|
3466
4003
|
The viewer's address book of data sources, in the shape a static host serves. A server has one source, itself.
|
|
3467
4004
|
|
|
4005
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
4006
|
+
|
|
4007
|
+
Responses: `200` The sources file.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
|
|
4008
|
+
|
|
4009
|
+
### The sources the viewer reads
|
|
4010
|
+
|
|
4011
|
+
`GET /api/projects/{project}/data/sources.json` · role: read
|
|
4012
|
+
|
|
4013
|
+
The viewer's address book of data sources, in the shape a static host serves. A server has one source, itself.
|
|
4014
|
+
|
|
4015
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
4016
|
+
|
|
4017
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
4018
|
+
|
|
3468
4019
|
Responses: `200` The sources file.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
|
|
3469
4020
|
|
|
3470
4021
|
### The spec files
|
|
@@ -3473,6 +4024,20 @@ Responses: `200` The sources file.; `401` No token, or an unknown one. Send `Aut
|
|
|
3473
4024
|
|
|
3474
4025
|
The files of the newest committed spec set, relative to `specs/`.
|
|
3475
4026
|
|
|
4027
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
4028
|
+
|
|
4029
|
+
Responses: `200` The index.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
|
|
4030
|
+
|
|
4031
|
+
### The spec files
|
|
4032
|
+
|
|
4033
|
+
`GET /api/projects/{project}/data/specs/index.json` · role: read
|
|
4034
|
+
|
|
4035
|
+
The files of the newest committed spec set, relative to `specs/`.
|
|
4036
|
+
|
|
4037
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
4038
|
+
|
|
4039
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
4040
|
+
|
|
3476
4041
|
Responses: `200` The index.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
|
|
3477
4042
|
|
|
3478
4043
|
### One spec file
|
|
@@ -3481,6 +4046,20 @@ Responses: `200` The index.; `401` No token, or an unknown one. Send `Authorizat
|
|
|
3481
4046
|
|
|
3482
4047
|
The text of a spec file, with the digest of its content as `ETag`.
|
|
3483
4048
|
|
|
4049
|
+
- `file` (path, required): The file's path relative to `specs/`.
|
|
4050
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
4051
|
+
|
|
4052
|
+
Responses: `200` The text.; `304` Not modified.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No such spec.
|
|
4053
|
+
|
|
4054
|
+
### One spec file
|
|
4055
|
+
|
|
4056
|
+
`GET /api/projects/{project}/data/specs/{file}` · role: read
|
|
4057
|
+
|
|
4058
|
+
The text of a spec file, with the digest of its content as `ETag`.
|
|
4059
|
+
|
|
4060
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
4061
|
+
|
|
4062
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3484
4063
|
- `file` (path, required): The file's path relative to `specs/`.
|
|
3485
4064
|
|
|
3486
4065
|
Responses: `200` The text.; `304` Not modified.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No such spec.
|
|
@@ -3491,6 +4070,20 @@ Responses: `200` The text.; `304` Not modified.; `401` No token, or an unknown o
|
|
|
3491
4070
|
|
|
3492
4071
|
The newest uploaded statechart runs (`atlas report publish --manifest … --upload-run`), newest first.
|
|
3493
4072
|
|
|
4073
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
4074
|
+
|
|
4075
|
+
Responses: `200` The index.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
|
|
4076
|
+
|
|
4077
|
+
### The statechart runs
|
|
4078
|
+
|
|
4079
|
+
`GET /api/projects/{project}/data/runs/index.json` · role: read
|
|
4080
|
+
|
|
4081
|
+
The newest uploaded statechart runs (`atlas report publish --manifest … --upload-run`), newest first.
|
|
4082
|
+
|
|
4083
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
4084
|
+
|
|
4085
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
4086
|
+
|
|
3494
4087
|
Responses: `200` The index.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
|
|
3495
4088
|
|
|
3496
4089
|
### A file of an uploaded run
|
|
@@ -3499,6 +4092,21 @@ Responses: `200` The index.; `401` No token, or an unknown one. Send `Authorizat
|
|
|
3499
4092
|
|
|
3500
4093
|
A file of an uploaded run: its manifest, timelines, screenshots, clips. Untrusted bytes, served sandboxed; immutable.
|
|
3501
4094
|
|
|
4095
|
+
- `id` (path, required): The run id.
|
|
4096
|
+
- `path` (path, required): The path inside the run.
|
|
4097
|
+
- `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
4098
|
+
|
|
4099
|
+
Responses: `200` The file.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No such run or file.
|
|
4100
|
+
|
|
4101
|
+
### A file of an uploaded run
|
|
4102
|
+
|
|
4103
|
+
`GET /api/projects/{project}/data/runs/{id}/{path}` · role: read
|
|
4104
|
+
|
|
4105
|
+
A file of an uploaded run: its manifest, timelines, screenshots, clips. Untrusted bytes, served sandboxed; immutable.
|
|
4106
|
+
|
|
4107
|
+
Scoped to one project. The same project may be selected on the unprefixed API using ?project= or X-Atlas-Project. Unknown projects return 404 on reads and are created by an authenticated upload.
|
|
4108
|
+
|
|
4109
|
+
- `project` (path, required): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
|
|
3502
4110
|
- `id` (path, required): The run id.
|
|
3503
4111
|
- `path` (path, required): The path inside the run.
|
|
3504
4112
|
|