@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.
Files changed (140) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +30 -11
  3. package/dist/core/src/cli.d.ts +1 -1
  4. package/dist/core/src/cli.js +8 -3
  5. package/dist/core/src/config.d.ts +7 -0
  6. package/dist/core/src/config.js +48 -14
  7. package/dist/core/src/run/execute.d.ts +6 -0
  8. package/dist/core/src/run/execute.js +4 -2
  9. package/dist/reports/src/doctor.d.ts +1 -1
  10. package/dist/reports/src/doctor.js +3 -1
  11. package/dist/reports/src/http-store.d.ts +4 -0
  12. package/dist/reports/src/http-store.js +6 -3
  13. package/dist/reports/src/init.js +6 -1
  14. package/dist/reports/src/live-reporter.d.ts +34 -0
  15. package/dist/reports/src/live-reporter.js +122 -0
  16. package/dist/reports/src/report-cli.d.ts +1 -1
  17. package/dist/reports/src/report-cli.js +3 -2
  18. package/dist/reports/src/store-url.js +1 -1
  19. package/dist/runners/src/codecept.d.ts +14 -0
  20. package/dist/runners/src/codecept.js +16 -0
  21. package/dist/runners/src/jest.d.ts +50 -0
  22. package/dist/runners/src/jest.js +52 -0
  23. package/dist/runners/src/mocha.d.ts +40 -0
  24. package/dist/runners/src/mocha.js +39 -0
  25. package/dist/runners/src/node-test.d.ts +28 -0
  26. package/dist/runners/src/node-test.js +44 -0
  27. package/dist/runners/src/publish.d.ts +30 -0
  28. package/dist/runners/src/publish.js +68 -0
  29. package/dist/schema/src/api.d.ts +1 -0
  30. package/dist/schema/src/api.js +1 -1
  31. package/dist/schema/src/index.d.ts +2 -0
  32. package/dist/schema/src/index.js +2 -0
  33. package/dist/schema/src/live-run.d.ts +123 -0
  34. package/dist/schema/src/live-run.js +30 -0
  35. package/dist/schema/src/manifest.d.ts +2 -2
  36. package/dist/schema/src/project.d.ts +20 -0
  37. package/dist/schema/src/project.js +10 -0
  38. package/dist/schema/src/report-sources.d.ts +1 -0
  39. package/dist/schema/src/report-sources.js +2 -1
  40. package/dist/schema/src/runs-index.d.ts +1 -1
  41. package/dist/schema/src/server-config.d.ts +84 -0
  42. package/dist/schema/src/server-config.js +12 -0
  43. package/dist/server/src/app.d.ts +10 -0
  44. package/dist/server/src/app.js +148 -10
  45. package/dist/server/src/config.d.ts +1 -1
  46. package/dist/server/src/config.js +20 -3
  47. package/dist/server/src/dev.d.ts +3 -3
  48. package/dist/server/src/dev.js +22 -13
  49. package/dist/server/src/events.d.ts +3 -3
  50. package/dist/server/src/events.js +1 -1
  51. package/dist/server/src/index.d.ts +2 -0
  52. package/dist/server/src/index.js +2 -0
  53. package/dist/server/src/live-runs.d.ts +52 -0
  54. package/dist/server/src/live-runs.js +229 -0
  55. package/dist/server/src/main.d.ts +1 -1
  56. package/dist/server/src/main.js +7 -5
  57. package/dist/server/src/openapi.d.ts +2 -5
  58. package/dist/server/src/openapi.js +71 -7
  59. package/dist/server/src/projects.d.ts +3 -0
  60. package/dist/server/src/projects.js +154 -0
  61. package/dist/server/src/settings-page.d.ts +9 -0
  62. package/dist/server/src/settings-page.js +93 -0
  63. package/dist/server/src/settings.d.ts +23 -0
  64. package/dist/server/src/settings.js +72 -0
  65. package/dist/server/src/site.d.ts +8 -6
  66. package/dist/server/src/site.js +45 -10
  67. package/dist/server/src/store-api.js +43 -22
  68. package/docs/deploying.md +19 -19
  69. package/docs/dogfooding.md +2 -2
  70. package/docs/extending.md +3 -3
  71. package/docs/integrating.md +9 -9
  72. package/docs/reference/cli.md +9 -7
  73. package/docs/reference/core.md +6 -0
  74. package/docs/reference/http-api.md +498 -2
  75. package/docs/reference/reports.md +55 -1
  76. package/docs/reference/runners.md +169 -0
  77. package/docs/reference/schema.md +111 -0
  78. package/docs/reference/server.md +154 -14
  79. package/docs/report-backends.md +8 -8
  80. package/docs/report-contract.md +7 -7
  81. package/docs/reporting-issues.md +3 -3
  82. package/docs/runners.md +69 -0
  83. package/docs/server.md +61 -25
  84. package/docs/statecharts.md +22 -20
  85. package/llms-full.txt +713 -105
  86. package/llms.txt +3 -1
  87. package/package.json +31 -9
  88. package/packages/runners/README.md +6 -0
  89. package/packages/runners/compat/codecept.cjs +2 -0
  90. package/packages/runners/compat/jest.cjs +2 -0
  91. package/packages/runners/compat/mocha.cjs +2 -0
  92. package/packages/schema/schemas/atlas-change.schema.json +4 -0
  93. package/packages/schema/schemas/hello-event.schema.json +4 -0
  94. package/packages/schema/schemas/live-run-start.schema.json +42 -0
  95. package/packages/schema/schemas/live-run-update.schema.json +93 -0
  96. package/packages/schema/schemas/live-run.schema.json +225 -0
  97. package/packages/schema/schemas/project-slug.schema.json +8 -0
  98. package/packages/schema/schemas/project.schema.json +22 -0
  99. package/packages/schema/schemas/projects.schema.json +33 -0
  100. package/packages/schema/schemas/server-config.schema.json +14 -0
  101. package/packages/schema/schemas/server-editable-settings.schema.json +132 -0
  102. package/packages/schema/schemas/server-settings-snapshot.schema.json +285 -0
  103. package/packages/server/openapi.json +5101 -779
  104. package/packages/visualizer/README.md +13 -13
  105. package/packages/visualizer/bin/atlas-client.mjs +176 -0
  106. package/packages/visualizer/bin/atlas-visualizer.mjs +2 -175
  107. package/packages/visualizer/src/app/AppShell.tsx +26 -17
  108. package/packages/visualizer/src/app/report-sources.tsx +2 -1
  109. package/packages/visualizer/src/components/ActivityIndicator.module.css +4 -0
  110. package/packages/visualizer/src/components/ActivityIndicator.tsx +6 -0
  111. package/packages/visualizer/src/components/Header.module.css +101 -227
  112. package/packages/visualizer/src/components/Header.tsx +79 -41
  113. package/packages/visualizer/src/components/ProjectPicker.tsx +64 -0
  114. package/packages/visualizer/src/data/adapters/report-backend.test.ts +3 -2
  115. package/packages/visualizer/src/data/adapters/report-backend.ts +1 -1
  116. package/packages/visualizer/src/data/queries.ts +14 -7
  117. package/packages/visualizer/src/evidence/api.ts +2 -1
  118. package/packages/visualizer/src/evidence/check-detail.tsx +19 -4
  119. package/packages/visualizer/src/evidence/document-page.tsx +6 -2
  120. package/packages/visualizer/src/evidence/evidence-context.tsx +17 -12
  121. package/packages/visualizer/src/evidence/evidence.module.css +11 -1
  122. package/packages/visualizer/src/evidence/feature-page.tsx +7 -3
  123. package/packages/visualizer/src/evidence/model-page.tsx +6 -2
  124. package/packages/visualizer/src/evidence/project-home.tsx +45 -0
  125. package/packages/visualizer/src/evidence/recording-page.tsx +4 -1
  126. package/packages/visualizer/src/evidence/spec-index.tsx +2 -1
  127. package/packages/visualizer/src/evidence/test-filter.tsx +21 -0
  128. package/packages/visualizer/src/live/live-query.ts +21 -0
  129. package/packages/visualizer/src/live/live-runs.tsx +69 -0
  130. package/packages/visualizer/src/live/live-stream.ts +30 -9
  131. package/packages/visualizer/src/live/report-progress.ts +62 -0
  132. package/packages/visualizer/src/live/test-progress.tsx +34 -0
  133. package/packages/visualizer/src/runtime.ts +17 -1
  134. package/packages/visualizer/src/state/ui-store.ts +3 -2
  135. package/packages/visualizer/src/views/ChartPage.tsx +2 -0
  136. package/packages/visualizer/src/views/ChartTests.tsx +43 -0
  137. package/packages/visualizer/src/views/SidePanel.tsx +2 -0
  138. package/packages/visualizer/vite/atlas-files.test.ts +4 -4
  139. package/packages/visualizer/vite/atlas-files.ts +1 -5
  140. package/packages/visualizer/vite/atlas-server-proxy.ts +2 -1
@@ -2,6 +2,134 @@
2
2
 
3
3
  > 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.
4
4
 
5
+ ### List projects on this Atlas node
6
+
7
+ `GET /api/projects` · role: read
8
+
9
+ 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.
10
+
11
+ Responses: `200` Available project identities.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `503` The project catalog is unavailable.
12
+
13
+ ### Live test progress and recent invocations
14
+
15
+ `GET /api/live` · role: read
16
+
17
+ 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.
18
+
19
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
20
+
21
+ Responses: `200` Recent live run summaries.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
22
+
23
+ ### Live test progress and recent invocations
24
+
25
+ `GET /api/projects/{project}/live` · role: read
26
+
27
+ 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.
28
+
29
+ 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.
30
+
31
+ - `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.
32
+
33
+ Responses: `200` Recent live run summaries.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
34
+
35
+ ### Start a live producer lease
36
+
37
+ `POST /api/live/{id}` · role: publish
38
+
39
+ 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.
40
+
41
+ - `id` (path, required): Producer-generated UUID, also given in the body.
42
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
43
+
44
+ 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.
45
+
46
+ ### Start a live producer lease
47
+
48
+ `POST /api/projects/{project}/live/{id}` · role: publish
49
+
50
+ 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.
51
+
52
+ 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.
53
+
54
+ - `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.
55
+ - `id` (path, required): Producer-generated UUID, also given in the body.
56
+
57
+ 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.
58
+
59
+ ### Publish progress or finish an invocation
60
+
61
+ `PATCH /api/live/{id}` · role: publish
62
+
63
+ 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.
64
+
65
+ - `id` (path, required): The UUID of a run started with this publisher token.
66
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
67
+
68
+ 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.
69
+
70
+ ### Publish progress or finish an invocation
71
+
72
+ `PATCH /api/projects/{project}/live/{id}` · role: publish
73
+
74
+ 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.
75
+
76
+ 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.
77
+
78
+ - `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.
79
+ - `id` (path, required): The UUID of a run started with this publisher token.
80
+
81
+ 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.
82
+
83
+ ### Renew a producer heartbeat
84
+
85
+ `POST /api/live/{id}/heartbeat` · role: publish
86
+
87
+ 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.
88
+
89
+ - `id` (path, required): The UUID of this producer invocation.
90
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
91
+
92
+ 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.
93
+
94
+ ### Renew a producer heartbeat
95
+
96
+ `POST /api/projects/{project}/live/{id}/heartbeat` · role: publish
97
+
98
+ 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.
99
+
100
+ 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.
101
+
102
+ - `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.
103
+ - `id` (path, required): The UUID of this producer invocation.
104
+
105
+ 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.
106
+
107
+ ### Server settings page
108
+
109
+ `GET /admin` · role: read
110
+
111
+ A standalone settings editor. Supply an admin Bearer token in the page to read or save configuration. The token is held only in memory.
112
+
113
+ Responses: `200` Settings editor.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
114
+
115
+ ### Read server settings
116
+
117
+ `GET /api/settings` · role: admin
118
+
119
+ 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.
120
+
121
+ 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.
122
+
123
+ ### Save settings for the next restart
124
+
125
+ `PUT /api/settings` · role: admin
126
+
127
+ 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.
128
+
129
+ - `If-Match` (header, required): The quoted revision returned by GET /api/settings.
130
+
131
+ 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.
132
+
5
133
  ### Is the process up
6
134
 
7
135
  `GET /healthz` · role: none
@@ -46,17 +174,44 @@ Responses: `200` The server.; `401` No token, or an unknown one. Send `Authoriza
46
174
 
47
175
  `GET /api/events` · role: read
48
176
 
49
- A `text/event-stream` that stays open. Events say *that* something changed; the state is always fetched, so a client that missed events (a dropped connection) loses nothing: read again on reconnect.
177
+ 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.
50
178
 
51
179
  | event | data |
52
180
  | --- | --- |
53
- | `hello` | `{ version, ready, time }`, sent first |
181
+ | `hello` | `{ version, ready, time, heartbeatMs? }`, sent first |
54
182
  | `report` | `{ version, totalLayers, added: [{ id, producer, environment, branch, sha, recordedAtMs, counts }], addedTotal }`: layers arrived |
55
183
  | `atlas:change` | `{ scope: "specs" \| "runs", files, runIds }`: new specs or runs |
184
+ | `run` | A LiveRun snapshot after start, progress, heartbeat, completion, or interruption; contains no producer credentials |
185
+ | `projects` | `{}` when the node discovers another project; refresh `/api/projects` |
56
186
  | `ping` | `{}` every `heartbeatSeconds`, so a quiet server is told apart from a dead connection |
57
187
 
58
188
  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`.
59
189
 
190
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
191
+
192
+ Responses: `200` The stream.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `503` Too many viewers are connected; poll instead.
193
+
194
+ ### Server-sent events: results arrived, specs or runs changed
195
+
196
+ `GET /api/projects/{project}/events` · role: read
197
+
198
+ 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.
199
+
200
+ | event | data |
201
+ | --- | --- |
202
+ | `hello` | `{ version, ready, time, heartbeatMs? }`, sent first |
203
+ | `report` | `{ version, totalLayers, added: [{ id, producer, environment, branch, sha, recordedAtMs, counts }], addedTotal }`: layers arrived |
204
+ | `atlas:change` | `{ scope: "specs" \| "runs", files, runIds }`: new specs or runs |
205
+ | `run` | A LiveRun snapshot after start, progress, heartbeat, completion, or interruption; contains no producer credentials |
206
+ | `projects` | `{}` when the node discovers another project; refresh `/api/projects` |
207
+ | `ping` | `{}` every `heartbeatSeconds`, so a quiet server is told apart from a dead connection |
208
+
209
+ 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`.
210
+
211
+ 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.
212
+
213
+ - `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.
214
+
60
215
  Responses: `200` The stream.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `503` Too many viewers are connected; poll instead.
61
216
 
62
217
  ### The whole report, or only what changed since a version
@@ -69,6 +224,25 @@ The report as it stands: only the layers that win at least one check, each with
69
224
 
70
225
  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`.
71
226
 
227
+ - `since` (query): The `version` of the report you hold.
228
+ - `if-none-match` (header): The ETag (the quoted version) of the report you hold.
229
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
230
+
231
+ 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`.
232
+
233
+ ### The whole report, or only what changed since a version
234
+
235
+ `GET /api/projects/{project}/reports/evidence/effective` · role: read
236
+
237
+ 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.
238
+
239
+ `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.
240
+
241
+ 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`.
242
+
243
+ 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.
244
+
245
+ - `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.
72
246
  - `since` (query): The `version` of the report you hold.
73
247
  - `if-none-match` (header): The ETag (the quoted version) of the report you hold.
74
248
 
@@ -82,6 +256,25 @@ The `atlas report status --format json` document, worked out by the server from
82
256
 
83
257
  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.
84
258
 
259
+ - `branch` (query): Only layers recorded on this branch. Repeatable.
260
+ - `ignoreModified` (query): `1`: leave out layers from modified checkouts and unknown origins.
261
+ - `requireEnvironments` (query): Comma-separated environments that must have results.
262
+ - `requireAllSpecs` (query): `1`: fail while any spec of the outline has no results.
263
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
264
+
265
+ 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`.
266
+
267
+ ### The gate: does the report pass
268
+
269
+ `GET /api/projects/{project}/status` · role: read
270
+
271
+ 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.**
272
+
273
+ 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.
274
+
275
+ 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.
276
+
277
+ - `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.
85
278
  - `branch` (query): Only layers recorded on this branch. Repeatable.
86
279
  - `ignoreModified` (query): `1`: leave out layers from modified checkouts and unknown origins.
87
280
  - `requireEnvironments` (query): Comma-separated environments that must have results.
@@ -97,6 +290,22 @@ The simplest way in: anything that can make an HTTP request can report. The body
97
290
 
98
291
  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`.
99
292
 
293
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
294
+
295
+ 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.
296
+
297
+ ### Upload one layer of checks as JSON
298
+
299
+ `POST /api/projects/{project}/checks` · role: publish
300
+
301
+ 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.
302
+
303
+ 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`.
304
+
305
+ 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.
306
+
307
+ - `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.
308
+
100
309
  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.
101
310
 
102
311
  ### List keys under layers/
@@ -105,6 +314,22 @@ Responses: `201` The layer was written.; `401` No token, or an unknown one. Send
105
314
 
106
315
  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.
107
316
 
317
+ - `prefix` (query): Only keys starting with this. Default `layers/`.
318
+ - `after` (query): Only keys after this one (exclusive).
319
+ - `limit` (query): Page size, 1 to 1000. Default 1000.
320
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
321
+
322
+ Responses: `200` A page.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `422` The prefix is not one Atlas holds.
323
+
324
+ ### List keys under layers/
325
+
326
+ `GET /api/projects/{project}/store` · role: read
327
+
328
+ 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.
329
+
330
+ 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.
331
+
332
+ - `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.
108
333
  - `prefix` (query): Only keys starting with this. Default `layers/`.
109
334
  - `after` (query): Only keys after this one (exclusive).
110
335
  - `limit` (query): Page size, 1 to 1000. Default 1000.
@@ -117,6 +342,20 @@ Responses: `200` A page.; `401` No token, or an unknown one. Send `Authorization
117
342
 
118
343
  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.
119
344
 
345
+ - `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.
346
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
347
+
348
+ 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.
349
+
350
+ ### Read an object
351
+
352
+ `GET /api/projects/{project}/store/{key}` · role: read
353
+
354
+ 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.
355
+
356
+ 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.
357
+
358
+ - `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.
120
359
  - `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.
121
360
 
122
361
  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.
@@ -127,6 +366,20 @@ Responses: `200` The object.; `401` No token, or an unknown one. Send `Authoriza
127
366
 
128
367
  `200` when the object exists, `404` when not. No body.
129
368
 
369
+ - `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.
370
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
371
+
372
+ Responses: `200` It exists.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No such object.
373
+
374
+ ### Does an object exist
375
+
376
+ `HEAD /api/projects/{project}/store/{key}` · role: read
377
+
378
+ `200` when the object exists, `404` when not. No body.
379
+
380
+ 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.
381
+
382
+ - `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.
130
383
  - `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.
131
384
 
132
385
  Responses: `200` It exists.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No such object.
@@ -145,6 +398,29 @@ The write half of the `ObjectStore` interface. The server checks what it can fro
145
398
 
146
399
  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.
147
400
 
401
+ - `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.
402
+ - `content-type` (header): Stored with the object and returned when it is read.
403
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
404
+
405
+ 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.
406
+
407
+ ### Upload an object
408
+
409
+ `PUT /api/projects/{project}/store/{key}` · role: publish
410
+
411
+ 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:
412
+
413
+ - 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);
414
+ - a **blob** (`layers/blobs/<sha256>.gz`) must be gzip of content whose SHA-256 is its name; a **spec file** likewise;
415
+ - a **catalog entry** (`…/index/…`) must name something already uploaded (`409` otherwise): it is what makes a layer visible, so it is written last;
416
+ - a **run manifest** must have passed its privacy scan;
417
+ - keys are immutable: the same bytes again are `200` (a retry), other bytes under the same key are `409`.
418
+
419
+ 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.
420
+
421
+ 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.
422
+
423
+ - `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.
148
424
  - `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.
149
425
  - `content-type` (header): Stored with the object and returned when it is read.
150
426
 
@@ -156,6 +432,20 @@ Responses: `200` Already there with the same bytes.; `201` Stored.; `401` No tok
156
432
 
157
433
  Only the scratch objects `atlas report doctor` writes (`layers/doctor-…`) can be removed. Layers, specs and runs are never removed through the API.
158
434
 
435
+ - `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.
436
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
437
+
438
+ 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.
439
+
440
+ ### Remove a scratch object
441
+
442
+ `DELETE /api/projects/{project}/store/{key}` · role: publish
443
+
444
+ Only the scratch objects `atlas report doctor` writes (`layers/doctor-…`) can be removed. Layers, specs and runs are never removed through the API.
445
+
446
+ 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.
447
+
448
+ - `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.
159
449
  - `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.
160
450
 
161
451
  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.
@@ -166,6 +456,20 @@ Responses: `204` Removed (or it was not there).; `401` No token, or an unknown o
166
456
 
167
457
  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.
168
458
 
459
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
460
+
461
+ Responses: `200` The outline.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
462
+
463
+ ### The specs a report is laid over
464
+
465
+ `GET /api/projects/{project}/reports/outline` · role: read
466
+
467
+ 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.
468
+
469
+ 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.
470
+
471
+ - `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.
472
+
169
473
  Responses: `200` The outline.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
170
474
 
171
475
  ### The text of one spec
@@ -174,6 +478,20 @@ Responses: `200` The outline.; `401` No token, or an unknown one. Send `Authoriz
174
478
 
175
479
  The text of a spec file of the outline, by its path.
176
480
 
481
+ - `path` (query, required): The spec's path, `specs/<path>`.
482
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
483
+
484
+ Responses: `200` The spec text.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No such spec in the outline.
485
+
486
+ ### The text of one spec
487
+
488
+ `GET /api/projects/{project}/reports/outline/spec` · role: read
489
+
490
+ The text of a spec file of the outline, by its path.
491
+
492
+ 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.
493
+
494
+ - `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.
177
495
  - `path` (query, required): The spec's path, `specs/<path>`.
178
496
 
179
497
  Responses: `200` The spec text.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No such spec in the outline.
@@ -184,6 +502,20 @@ Responses: `200` The spec text.; `401` No token, or an unknown one. Send `Author
184
502
 
185
503
  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.
186
504
 
505
+ - `cursor` (query): The `cursor` of the previous page.
506
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
507
+
508
+ 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`.
509
+
510
+ ### Page through every layer header
511
+
512
+ `GET /api/projects/{project}/reports/evidence` · role: read
513
+
514
+ 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.
515
+
516
+ 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.
517
+
518
+ - `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.
187
519
  - `cursor` (query): The `cursor` of the previous page.
188
520
 
189
521
  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`.
@@ -194,6 +526,21 @@ Responses: `200` A page of headers.; `401` No token, or an unknown one. Send `Au
194
526
 
195
527
  Every check of one layer (not only those that win), with the spec fingerprints it recorded.
196
528
 
529
+ - `backend` (path, required): A backend id from `/api/server`.
530
+ - `id` (path, required): A layer id: 64 lowercase hex digits.
531
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
532
+
533
+ Responses: `200` The rows.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No such layer in that backend.
534
+
535
+ ### The checks of one layer
536
+
537
+ `GET /api/projects/{project}/reports/evidence/rows/{backend}/{id}` · role: read
538
+
539
+ Every check of one layer (not only those that win), with the spec fingerprints it recorded.
540
+
541
+ 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.
542
+
543
+ - `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.
197
544
  - `backend` (path, required): A backend id from `/api/server`.
198
545
  - `id` (path, required): A layer id: 64 lowercase hex digits.
199
546
 
@@ -205,6 +552,23 @@ Responses: `200` The rows.; `401` No token, or an unknown one. Send `Authorizati
205
552
 
206
553
  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}`.
207
554
 
555
+ - `backend` (path, required): A backend id from `/api/server`.
556
+ - `id` (path, required): A layer id: 64 lowercase hex digits.
557
+ - `check` (query): The check id.
558
+ - `kind` (query): The kind of the part, when the same id is in several.
559
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
560
+
561
+ Responses: `200` The detail.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No such layer or check.
562
+
563
+ ### Everything one result carries
564
+
565
+ `GET /api/projects/{project}/reports/evidence/detail/{backend}/{id}` · role: read
566
+
567
+ 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}`.
568
+
569
+ 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.
570
+
571
+ - `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.
208
572
  - `backend` (path, required): A backend id from `/api/server`.
209
573
  - `id` (path, required): A layer id: 64 lowercase hex digits.
210
574
  - `check` (query): The check id.
@@ -218,6 +582,22 @@ Responses: `200` The detail.; `401` No token, or an unknown one. Send `Authoriza
218
582
 
219
583
  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`.
220
584
 
585
+ - `id` (path, required): A layer id: 64 lowercase hex digits.
586
+ - `bundleKey` (path, required): The attachment's `bundleKey`, which contains a slash.
587
+ - `range` (header): A byte range, `bytes=0-1023`.
588
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
589
+
590
+ 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.
591
+
592
+ ### A file a layer carries
593
+
594
+ `GET /api/projects/{project}/reports/layers/{id}/blobs/{bundleKey}` · role: read
595
+
596
+ 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`.
597
+
598
+ 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.
599
+
600
+ - `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.
221
601
  - `id` (path, required): A layer id: 64 lowercase hex digits.
222
602
  - `bundleKey` (path, required): The attachment's `bundleKey`, which contains a slash.
223
603
  - `range` (header): A byte range, `bytes=0-1023`.
@@ -230,6 +610,21 @@ Responses: `200` The bytes, with the type the producer gave (or `application/oct
230
610
 
231
611
  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.
232
612
 
613
+ - `id` (path, required): A layer id: 64 lowercase hex digits.
614
+ - `path` (path, required): The path under the layer.
615
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
616
+
617
+ Responses: `200` The file.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No such file.
618
+
619
+ ### A recorded test of a statechart run
620
+
621
+ `GET /api/projects/{project}/reports/layers/{id}/{path}` · role: read
622
+
623
+ 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.
624
+
625
+ 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.
626
+
627
+ - `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.
233
628
  - `id` (path, required): A layer id: 64 lowercase hex digits.
234
629
  - `path` (path, required): The path under the layer.
235
630
 
@@ -241,6 +636,20 @@ Responses: `200` The file.; `401` No token, or an unknown one. Send `Authorizati
241
636
 
242
637
  For spec runs writing on the same machine as a development host (`atlas-visualizer dev`). A server has none: it answers `404`.
243
638
 
639
+ - `source` (path, required): The live source id.
640
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
641
+
642
+ Responses: `200` The stylesheet.; `404` Not a live source.
643
+
644
+ ### Frame stylesheet of a live spec run (development only)
645
+
646
+ `GET /api/projects/{project}/reports/live/{source}/frame.css` · role: read
647
+
648
+ For spec runs writing on the same machine as a development host (`atlas-visualizer dev`). A server has none: it answers `404`.
649
+
650
+ 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.
651
+
652
+ - `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.
244
653
  - `source` (path, required): The live source id.
245
654
 
246
655
  Responses: `200` The stylesheet.; `404` Not a live source.
@@ -251,6 +660,22 @@ Responses: `200` The stylesheet.; `404` Not a live source.
251
660
 
252
661
  For spec runs writing on the same machine as a development host. A server has none: it answers `404`.
253
662
 
663
+ - `source` (path, required): The live source id.
664
+ - `testId` (path, required): The test id.
665
+ - `path` (path, required): The path under the test.
666
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
667
+
668
+ Responses: `200` The file.; `404` Not a live source.
669
+
670
+ ### A file of a test in a live spec run (development only)
671
+
672
+ `GET /api/projects/{project}/reports/live/{source}/tests/{testId}/{path}` · role: read
673
+
674
+ For spec runs writing on the same machine as a development host. A server has none: it answers `404`.
675
+
676
+ 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.
677
+
678
+ - `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.
254
679
  - `source` (path, required): The live source id.
255
680
  - `testId` (path, required): The test id.
256
681
  - `path` (path, required): The path under the test.
@@ -263,6 +688,20 @@ Responses: `200` The file.; `404` Not a live source.
263
688
 
264
689
  The viewer's address book of data sources, in the shape a static host serves. A server has one source, itself.
265
690
 
691
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
692
+
693
+ Responses: `200` The sources file.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
694
+
695
+ ### The sources the viewer reads
696
+
697
+ `GET /api/projects/{project}/data/sources.json` · role: read
698
+
699
+ The viewer's address book of data sources, in the shape a static host serves. A server has one source, itself.
700
+
701
+ 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.
702
+
703
+ - `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.
704
+
266
705
  Responses: `200` The sources file.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
267
706
 
268
707
  ### The spec files
@@ -271,6 +710,20 @@ Responses: `200` The sources file.; `401` No token, or an unknown one. Send `Aut
271
710
 
272
711
  The files of the newest committed spec set, relative to `specs/`.
273
712
 
713
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
714
+
715
+ Responses: `200` The index.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
716
+
717
+ ### The spec files
718
+
719
+ `GET /api/projects/{project}/data/specs/index.json` · role: read
720
+
721
+ The files of the newest committed spec set, relative to `specs/`.
722
+
723
+ 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.
724
+
725
+ - `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.
726
+
274
727
  Responses: `200` The index.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
275
728
 
276
729
  ### One spec file
@@ -279,6 +732,20 @@ Responses: `200` The index.; `401` No token, or an unknown one. Send `Authorizat
279
732
 
280
733
  The text of a spec file, with the digest of its content as `ETag`.
281
734
 
735
+ - `file` (path, required): The file's path relative to `specs/`.
736
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
737
+
738
+ Responses: `200` The text.; `304` Not modified.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No such spec.
739
+
740
+ ### One spec file
741
+
742
+ `GET /api/projects/{project}/data/specs/{file}` · role: read
743
+
744
+ The text of a spec file, with the digest of its content as `ETag`.
745
+
746
+ 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.
747
+
748
+ - `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.
282
749
  - `file` (path, required): The file's path relative to `specs/`.
283
750
 
284
751
  Responses: `200` The text.; `304` Not modified.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No such spec.
@@ -289,6 +756,20 @@ Responses: `200` The text.; `304` Not modified.; `401` No token, or an unknown o
289
756
 
290
757
  The newest uploaded statechart runs (`atlas report publish --manifest … --upload-run`), newest first.
291
758
 
759
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
760
+
761
+ Responses: `200` The index.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
762
+
763
+ ### The statechart runs
764
+
765
+ `GET /api/projects/{project}/data/runs/index.json` · role: read
766
+
767
+ The newest uploaded statechart runs (`atlas report publish --manifest … --upload-run`), newest first.
768
+
769
+ 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.
770
+
771
+ - `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.
772
+
292
773
  Responses: `200` The index.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.
293
774
 
294
775
  ### A file of an uploaded run
@@ -297,6 +778,21 @@ Responses: `200` The index.; `401` No token, or an unknown one. Send `Authorizat
297
778
 
298
779
  A file of an uploaded run: its manifest, timelines, screenshots, clips. Untrusted bytes, served sandboxed; immutable.
299
780
 
781
+ - `id` (path, required): The run id.
782
+ - `path` (path, required): The path inside the run.
783
+ - `project` (query): Project slug. Alternatively send X-Atlas-Project or use the project-prefixed route. Omit for the default project. Conflicting selectors are refused.
784
+
785
+ Responses: `200` The file.; `401` No token, or an unknown one. Send `Authorization: Bearer <token>`.; `404` No such run or file.
786
+
787
+ ### A file of an uploaded run
788
+
789
+ `GET /api/projects/{project}/data/runs/{id}/{path}` · role: read
790
+
791
+ A file of an uploaded run: its manifest, timelines, screenshots, clips. Untrusted bytes, served sandboxed; immutable.
792
+
793
+ 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.
794
+
795
+ - `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.
300
796
  - `id` (path, required): The run id.
301
797
  - `path` (path, required): The path inside the run.
302
798