@crvouga/atlas 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (444) hide show
  1. package/CHANGELOG.md +13 -1
  2. package/README.md +191 -611
  3. package/dist/bun/src/driver.d.ts +41 -7
  4. package/dist/bun/src/driver.js +47 -6
  5. package/dist/bun/src/index.d.ts +8 -0
  6. package/dist/bun/src/index.js +8 -0
  7. package/dist/core/src/cli.d.ts +14 -1
  8. package/dist/core/src/cli.js +35 -1
  9. package/dist/core/src/config.d.ts +77 -4
  10. package/dist/core/src/config.js +110 -17
  11. package/dist/core/src/events/cloudevents.d.ts +54 -9
  12. package/dist/core/src/events/cloudevents.js +60 -9
  13. package/dist/core/src/graph.d.ts +21 -0
  14. package/dist/core/src/graph.js +26 -0
  15. package/dist/core/src/index.d.ts +11 -0
  16. package/dist/core/src/index.js +11 -0
  17. package/dist/core/src/lint.d.ts +30 -0
  18. package/dist/core/src/lint.js +13 -0
  19. package/dist/core/src/plan.d.ts +39 -1
  20. package/dist/core/src/plan.js +28 -1
  21. package/dist/core/src/privacy.d.ts +29 -2
  22. package/dist/core/src/privacy.js +19 -2
  23. package/dist/core/src/report/formats.d.ts +34 -4
  24. package/dist/core/src/report/formats.js +24 -4
  25. package/dist/core/src/report/markdown.d.ts +15 -0
  26. package/dist/core/src/report/markdown.js +8 -0
  27. package/dist/core/src/run/clients.d.ts +44 -5
  28. package/dist/core/src/run/clients.js +46 -2
  29. package/dist/core/src/run/execute.d.ts +75 -16
  30. package/dist/core/src/run/execute.js +71 -18
  31. package/dist/core/src/run/frames.d.ts +13 -4
  32. package/dist/core/src/run/frames.js +19 -4
  33. package/dist/core/src/run/http.d.ts +34 -1
  34. package/dist/core/src/run/http.js +14 -1
  35. package/dist/core/src/run/types.d.ts +76 -3
  36. package/dist/core/src/run/types.js +19 -3
  37. package/dist/core/src/signals.d.ts +49 -5
  38. package/dist/core/src/signals.js +22 -5
  39. package/dist/core/src/spec/compose.d.ts +23 -1
  40. package/dist/core/src/spec/compose.js +10 -1
  41. package/dist/core/src/spec/index.d.ts +9 -1
  42. package/dist/core/src/spec/index.js +9 -1
  43. package/dist/core/src/spec/load.d.ts +22 -1
  44. package/dist/core/src/spec/load.js +31 -1
  45. package/dist/core/src/spec/parse.d.ts +16 -2
  46. package/dist/core/src/spec/parse.js +25 -2
  47. package/dist/core/src/spec/scxml.d.ts +25 -4
  48. package/dist/core/src/spec/scxml.js +36 -4
  49. package/dist/core/src/spec/types.d.ts +52 -1
  50. package/dist/core/src/spec/types.js +24 -0
  51. package/dist/detox/src/index.d.ts +54 -11
  52. package/dist/detox/src/index.js +45 -7
  53. package/dist/playwright/src/driver.d.ts +39 -3
  54. package/dist/playwright/src/driver.js +27 -3
  55. package/dist/playwright/src/index.d.ts +10 -0
  56. package/dist/playwright/src/index.js +10 -0
  57. package/dist/playwright/src/media.d.ts +50 -4
  58. package/dist/playwright/src/media.js +55 -4
  59. package/dist/playwright/src/signals.d.ts +44 -5
  60. package/dist/playwright/src/signals.js +29 -5
  61. package/dist/reports/src/attachment-files.d.ts +44 -0
  62. package/dist/reports/src/attachment-files.js +121 -0
  63. package/dist/reports/src/attachment-response.d.ts +31 -0
  64. package/dist/reports/src/attachment-response.js +55 -0
  65. package/dist/reports/src/aws-credentials.d.ts +48 -0
  66. package/dist/reports/src/aws-credentials.js +221 -0
  67. package/dist/reports/src/browser-navigation.d.ts +14 -0
  68. package/dist/reports/src/browser-navigation.js +7 -0
  69. package/dist/reports/src/bundle.d.ts +34 -2
  70. package/dist/reports/src/bundle.js +38 -2
  71. package/dist/reports/src/catalog.d.ts +34 -3
  72. package/dist/reports/src/catalog.js +17 -3
  73. package/dist/reports/src/cli-stores.d.ts +36 -0
  74. package/dist/reports/src/cli-stores.js +73 -0
  75. package/dist/reports/src/clock.d.ts +7 -2
  76. package/dist/reports/src/clock.js +5 -2
  77. package/dist/reports/src/completion-order.d.ts +18 -5
  78. package/dist/reports/src/completion-order.js +18 -5
  79. package/dist/reports/src/compose.d.ts +80 -0
  80. package/dist/reports/src/compose.js +117 -0
  81. package/dist/reports/src/copy-store.d.ts +29 -0
  82. package/dist/reports/src/copy-store.js +52 -0
  83. package/dist/reports/src/directory-outline.d.ts +38 -0
  84. package/dist/reports/src/directory-outline.js +103 -0
  85. package/dist/reports/src/directory-store.d.ts +20 -0
  86. package/dist/reports/src/directory-store.js +166 -0
  87. package/dist/reports/src/doctor.d.ts +29 -0
  88. package/dist/reports/src/doctor.js +85 -0
  89. package/dist/reports/src/effective-delta.d.ts +34 -0
  90. package/dist/reports/src/effective-delta.js +25 -0
  91. package/dist/reports/src/evidence-detail.d.ts +64 -0
  92. package/dist/reports/src/evidence-detail.js +92 -0
  93. package/dist/reports/src/evidence-live.d.ts +35 -5
  94. package/dist/reports/src/evidence-live.js +18 -2
  95. package/dist/reports/src/evidence-types.d.ts +68 -1
  96. package/dist/reports/src/evidence-types.js +5 -1
  97. package/dist/reports/src/evidence-view.d.ts +43 -4
  98. package/dist/reports/src/evidence-view.js +13 -2
  99. package/dist/reports/src/explorer-types.d.ts +40 -3
  100. package/dist/reports/src/explorer-types.js +8 -0
  101. package/dist/reports/src/explorer-versions.d.ts +9 -1
  102. package/dist/reports/src/explorer-versions.js +18 -1
  103. package/dist/reports/src/export-evidence.d.ts +16 -1
  104. package/dist/reports/src/export-evidence.js +52 -1
  105. package/dist/reports/src/fetcher.d.ts +27 -3
  106. package/dist/reports/src/fetcher.js +11 -3
  107. package/dist/reports/src/format-date.d.ts +6 -0
  108. package/dist/reports/src/format-date.js +6 -0
  109. package/dist/reports/src/format.d.ts +16 -0
  110. package/dist/reports/src/format.js +10 -0
  111. package/dist/reports/src/frames.d.ts +36 -3
  112. package/dist/reports/src/frames.js +22 -3
  113. package/dist/reports/src/hash.d.ts +18 -0
  114. package/dist/reports/src/hash.js +13 -0
  115. package/dist/reports/src/host.d.ts +29 -0
  116. package/dist/reports/src/host.js +64 -0
  117. package/dist/reports/src/html-frame.d.ts +5 -6
  118. package/dist/reports/src/html-frame.js +12 -1
  119. package/dist/reports/src/http-store.d.ts +56 -0
  120. package/dist/reports/src/http-store.js +148 -0
  121. package/dist/reports/src/http.d.ts +7 -0
  122. package/dist/reports/src/http.js +6 -0
  123. package/dist/reports/src/ingest.d.ts +54 -0
  124. package/dist/reports/src/ingest.js +210 -0
  125. package/dist/reports/src/init.d.ts +40 -0
  126. package/dist/reports/src/init.js +369 -0
  127. package/dist/reports/src/junit.d.ts +33 -6
  128. package/dist/reports/src/junit.js +87 -21
  129. package/dist/reports/src/keyboard.d.ts +20 -0
  130. package/dist/reports/src/keyboard.js +11 -0
  131. package/dist/reports/src/keys.d.ts +21 -3
  132. package/dist/reports/src/keys.js +21 -3
  133. package/dist/reports/src/layer-axes.d.ts +35 -5
  134. package/dist/reports/src/layer-axes.js +25 -5
  135. package/dist/reports/src/layer-catalog.d.ts +28 -1
  136. package/dist/reports/src/layer-catalog.js +18 -1
  137. package/dist/reports/src/layer-merge.d.ts +98 -9
  138. package/dist/reports/src/layer-merge.js +147 -31
  139. package/dist/reports/src/layer-source.d.ts +18 -0
  140. package/dist/reports/src/layer-source.js +11 -0
  141. package/dist/reports/src/layer-store.d.ts +42 -0
  142. package/dist/reports/src/layer-store.js +63 -5
  143. package/dist/reports/src/layer-types.d.ts +32 -1
  144. package/dist/reports/src/layers-route.d.ts +47 -4
  145. package/dist/reports/src/layers-route.js +86 -7
  146. package/dist/reports/src/live-reporter.d.ts +34 -0
  147. package/dist/reports/src/live-reporter.js +122 -0
  148. package/dist/reports/src/media-types.d.ts +11 -0
  149. package/dist/reports/src/media-types.js +22 -0
  150. package/dist/reports/src/namespace-guard.d.ts +10 -1
  151. package/dist/reports/src/namespace-guard.js +10 -1
  152. package/dist/reports/src/navigation.d.ts +12 -0
  153. package/dist/reports/src/navigation.js +7 -0
  154. package/dist/reports/src/object-io.d.ts +11 -4
  155. package/dist/reports/src/object-io.js +4 -4
  156. package/dist/reports/src/object-store-conformance.d.ts +27 -0
  157. package/dist/reports/src/object-store-conformance.js +87 -0
  158. package/dist/reports/src/object-store.d.ts +33 -24
  159. package/dist/reports/src/object-store.js +17 -24
  160. package/dist/reports/src/parse-with.d.ts +16 -0
  161. package/dist/reports/src/parse-with.js +14 -0
  162. package/dist/reports/src/performance-part.d.ts +25 -1
  163. package/dist/reports/src/performance-part.js +15 -1
  164. package/dist/reports/src/performance.d.ts +22 -2
  165. package/dist/reports/src/performance.js +12 -2
  166. package/dist/reports/src/persist.d.ts +12 -3
  167. package/dist/reports/src/persist.js +12 -3
  168. package/dist/reports/src/phone.d.ts +18 -1
  169. package/dist/reports/src/phone.js +18 -1
  170. package/dist/reports/src/protocol.d.ts +26 -4
  171. package/dist/reports/src/protocol.js +15 -4
  172. package/dist/reports/src/publication.d.ts +21 -1
  173. package/dist/reports/src/publication.js +21 -1
  174. package/dist/reports/src/publish-checks.d.ts +35 -0
  175. package/dist/reports/src/publish-checks.js +122 -0
  176. package/dist/reports/src/publish.d.ts +42 -9
  177. package/dist/reports/src/publish.js +36 -7
  178. package/dist/reports/src/read.d.ts +46 -16
  179. package/dist/reports/src/read.js +38 -14
  180. package/dist/reports/src/recording-bundle.d.ts +13 -2
  181. package/dist/reports/src/recording-bundle.js +4 -2
  182. package/dist/reports/src/recording-keys.d.ts +15 -1
  183. package/dist/reports/src/recording-keys.js +15 -1
  184. package/dist/reports/src/remote-report.d.ts +28 -7
  185. package/dist/reports/src/remote-report.js +15 -7
  186. package/dist/reports/src/report-cli.d.ts +51 -0
  187. package/dist/reports/src/report-cli.js +486 -0
  188. package/dist/reports/src/report-index.d.ts +99 -0
  189. package/dist/reports/src/report-index.js +337 -0
  190. package/dist/reports/src/report-loader.d.ts +10 -0
  191. package/dist/reports/src/report-loader.js +6 -0
  192. package/dist/reports/src/report-parts.d.ts +29 -3
  193. package/dist/reports/src/report-parts.js +37 -3
  194. package/dist/reports/src/report-status.d.ts +48 -0
  195. package/dist/reports/src/report-status.js +156 -0
  196. package/dist/reports/src/report-types.d.ts +73 -0
  197. package/dist/reports/src/report-types.js +3 -0
  198. package/dist/reports/src/reporter.d.ts +67 -0
  199. package/dist/reports/src/reporter.js +128 -0
  200. package/dist/reports/src/reports-explorer-route.d.ts +541 -0
  201. package/dist/reports/src/reports-explorer-route.js +11 -0
  202. package/dist/reports/src/reports-list-route.d.ts +9 -0
  203. package/dist/reports/src/reports-list-route.js +9 -0
  204. package/dist/reports/src/reports-route.d.ts +561 -22
  205. package/dist/reports/src/reports-route.js +11 -3
  206. package/dist/reports/src/reports-store.d.ts +19 -2
  207. package/dist/reports/src/reports-store.js +10 -2
  208. package/dist/reports/src/resilient-cache.d.ts +14 -1
  209. package/dist/reports/src/resilient-cache.js +8 -1
  210. package/dist/reports/src/retention.d.ts +17 -1
  211. package/dist/reports/src/retention.js +5 -1
  212. package/dist/reports/src/run-bundle.d.ts +63 -0
  213. package/dist/reports/src/run-bundle.js +159 -0
  214. package/dist/reports/src/s3-store.d.ts +79 -0
  215. package/dist/reports/src/s3-store.js +295 -0
  216. package/dist/reports/src/scenario.d.ts +14 -4
  217. package/dist/reports/src/scenario.js +5 -4
  218. package/dist/reports/src/sigv4.d.ts +72 -0
  219. package/dist/reports/src/sigv4.js +96 -0
  220. package/dist/reports/src/snapshot-bundle.d.ts +24 -1
  221. package/dist/reports/src/snapshot-bundle.js +27 -2
  222. package/dist/reports/src/snapshot-surface.d.ts +20 -9
  223. package/dist/reports/src/snapshot-surface.js +32 -19
  224. package/dist/reports/src/source-content.d.ts +23 -0
  225. package/dist/reports/src/source-content.js +30 -1
  226. package/dist/reports/src/source-entries.d.ts +13 -0
  227. package/dist/reports/src/source-entries.js +6 -0
  228. package/dist/reports/src/source-part.d.ts +15 -0
  229. package/dist/reports/src/source-part.js +8 -0
  230. package/dist/reports/src/source-reader.d.ts +11 -0
  231. package/dist/reports/src/source-reader.js +5 -0
  232. package/dist/reports/src/spec-evidence.d.ts +12 -2
  233. package/dist/reports/src/spec-evidence.js +6 -2
  234. package/dist/reports/src/spec-inventory.d.ts +15 -1
  235. package/dist/reports/src/spec-inventory.js +22 -1
  236. package/dist/reports/src/spec-link.d.ts +28 -0
  237. package/dist/reports/src/spec-link.js +70 -0
  238. package/dist/reports/src/spec-set.d.ts +63 -0
  239. package/dist/reports/src/spec-set.js +177 -0
  240. package/dist/reports/src/status.d.ts +10 -0
  241. package/dist/reports/src/status.js +5 -0
  242. package/dist/reports/src/store-prefix.d.ts +28 -0
  243. package/dist/reports/src/store-prefix.js +22 -0
  244. package/dist/reports/src/store-url.d.ts +89 -0
  245. package/dist/reports/src/store-url.js +160 -0
  246. package/dist/reports/src/test-catalog-entity.d.ts +11 -0
  247. package/dist/reports/src/test-catalog-entity.js +6 -0
  248. package/dist/reports/src/types.d.ts +6 -1
  249. package/dist/reports/src/use-report-nav.d.ts +35 -0
  250. package/dist/reports/src/use-report-nav.js +12 -0
  251. package/dist/runners/src/codecept.d.ts +14 -0
  252. package/dist/runners/src/codecept.js +16 -0
  253. package/dist/runners/src/jest.d.ts +50 -0
  254. package/dist/runners/src/jest.js +52 -0
  255. package/dist/runners/src/mocha.d.ts +40 -0
  256. package/dist/runners/src/mocha.js +39 -0
  257. package/dist/runners/src/node-test.d.ts +28 -0
  258. package/dist/runners/src/node-test.js +44 -0
  259. package/dist/runners/src/publish.d.ts +30 -0
  260. package/dist/runners/src/publish.js +68 -0
  261. package/dist/schema/src/api.d.ts +800 -0
  262. package/dist/schema/src/api.js +201 -0
  263. package/dist/schema/src/cli-results.d.ts +210 -0
  264. package/dist/schema/src/cli-results.js +124 -0
  265. package/dist/schema/src/common.d.ts +53 -0
  266. package/dist/schema/src/common.js +42 -0
  267. package/dist/schema/src/index.d.ts +16 -0
  268. package/dist/schema/src/index.js +16 -0
  269. package/dist/schema/src/layer.d.ts +2273 -0
  270. package/dist/schema/src/layer.js +462 -0
  271. package/dist/schema/src/live-run.d.ts +123 -0
  272. package/dist/schema/src/live-run.js +30 -0
  273. package/dist/schema/src/manifest.d.ts +97 -2
  274. package/dist/schema/src/manifest.js +84 -0
  275. package/dist/schema/src/project.d.ts +20 -0
  276. package/dist/schema/src/project.js +10 -0
  277. package/dist/schema/src/report-sources.d.ts +29 -0
  278. package/dist/schema/src/report-sources.js +27 -1
  279. package/dist/schema/src/runs-index.d.ts +17 -1
  280. package/dist/schema/src/runs-index.js +15 -0
  281. package/dist/schema/src/server-config.d.ts +177 -0
  282. package/dist/schema/src/server-config.js +85 -0
  283. package/dist/schema/src/spec.d.ts +69 -0
  284. package/dist/schema/src/spec.js +58 -0
  285. package/dist/server/src/app.d.ts +72 -0
  286. package/dist/server/src/app.js +557 -0
  287. package/dist/server/src/auth.d.ts +41 -0
  288. package/dist/server/src/auth.js +59 -0
  289. package/dist/server/src/config.d.ts +83 -0
  290. package/dist/server/src/config.js +204 -0
  291. package/dist/server/src/dev.d.ts +12 -0
  292. package/dist/server/src/dev.js +89 -0
  293. package/dist/server/src/events.d.ts +29 -0
  294. package/dist/server/src/events.js +101 -0
  295. package/dist/server/src/host.d.ts +30 -0
  296. package/dist/server/src/host.js +115 -0
  297. package/dist/server/src/index.d.ts +18 -0
  298. package/dist/server/src/index.js +18 -0
  299. package/dist/server/src/live-runs.d.ts +52 -0
  300. package/dist/server/src/live-runs.js +229 -0
  301. package/dist/server/src/llms.d.ts +19 -0
  302. package/dist/server/src/llms.js +63 -0
  303. package/dist/server/src/main.d.ts +30 -0
  304. package/dist/server/src/main.js +114 -0
  305. package/dist/server/src/openapi.d.ts +56 -0
  306. package/dist/server/src/openapi.js +438 -0
  307. package/dist/server/src/problem.d.ts +8 -0
  308. package/dist/server/src/problem.js +39 -0
  309. package/dist/server/src/projects.d.ts +3 -0
  310. package/dist/server/src/projects.js +154 -0
  311. package/dist/server/src/settings-page.d.ts +9 -0
  312. package/dist/server/src/settings-page.js +93 -0
  313. package/dist/server/src/settings.d.ts +23 -0
  314. package/dist/server/src/settings.js +72 -0
  315. package/dist/server/src/site.d.ts +15 -0
  316. package/dist/server/src/site.js +78 -0
  317. package/dist/server/src/store-api.d.ts +28 -0
  318. package/dist/server/src/store-api.js +180 -0
  319. package/dist/server/src/validate.d.ts +71 -0
  320. package/dist/server/src/validate.js +197 -0
  321. package/dist/vitest/src/index.d.ts +27 -5
  322. package/dist/vitest/src/index.js +18 -5
  323. package/dist/webdriver/src/driver.d.ts +63 -11
  324. package/dist/webdriver/src/driver.js +57 -6
  325. package/dist/webdriver/src/index.d.ts +8 -0
  326. package/dist/webdriver/src/index.js +1 -0
  327. package/dist/webdriver/src/protocol.d.ts +75 -6
  328. package/dist/webdriver/src/protocol.js +79 -6
  329. package/docs/agents.md +137 -0
  330. package/docs/deploying.md +345 -0
  331. package/docs/dogfooding.md +175 -0
  332. package/docs/extending.md +242 -0
  333. package/docs/integrating.md +485 -0
  334. package/docs/reference/bun.md +141 -0
  335. package/docs/reference/cli.md +148 -0
  336. package/docs/reference/core.md +2432 -0
  337. package/docs/reference/detox.md +150 -0
  338. package/docs/reference/http-api.md +799 -0
  339. package/docs/reference/playwright.md +303 -0
  340. package/docs/reference/reports.md +7152 -0
  341. package/docs/reference/runners.md +169 -0
  342. package/docs/reference/schema.md +1762 -0
  343. package/docs/reference/server.md +825 -0
  344. package/docs/reference/vitest.md +45 -0
  345. package/docs/reference/webdriver.md +330 -0
  346. package/docs/report-backends.md +144 -0
  347. package/docs/report-contract.md +400 -0
  348. package/docs/reporting-issues.md +160 -0
  349. package/docs/runners.md +69 -0
  350. package/docs/server.md +321 -0
  351. package/docs/statecharts.md +643 -0
  352. package/llms-full.txt +4114 -0
  353. package/llms.txt +49 -0
  354. package/package.json +61 -11
  355. package/packages/core/README.md +2 -1
  356. package/packages/reports/README.md +65 -0
  357. package/packages/reports/STORAGE.md +4 -0
  358. package/packages/runners/README.md +6 -0
  359. package/packages/runners/compat/codecept.cjs +2 -0
  360. package/packages/runners/compat/jest.cjs +2 -0
  361. package/packages/runners/compat/mocha.cjs +2 -0
  362. package/packages/schema/README.md +14 -0
  363. package/packages/schema/schemas/atlas-change.schema.json +4 -0
  364. package/packages/schema/schemas/check-detail.schema.json +1032 -0
  365. package/packages/schema/schemas/checks-result.schema.json +26 -0
  366. package/packages/schema/schemas/command-error.schema.json +35 -0
  367. package/packages/schema/schemas/doctor-result.schema.json +60 -0
  368. package/packages/schema/schemas/effective-delta.schema.json +490 -0
  369. package/packages/schema/schemas/effective-evidence.schema.json +471 -0
  370. package/packages/schema/schemas/evidence-page.schema.json +271 -0
  371. package/packages/schema/schemas/hello-event.schema.json +26 -0
  372. package/packages/schema/schemas/init-plan.schema.json +347 -0
  373. package/packages/schema/schemas/layer-rows.schema.json +199 -0
  374. package/packages/schema/schemas/layer.schema.json +2888 -0
  375. package/packages/schema/schemas/live-run-start.schema.json +42 -0
  376. package/packages/schema/schemas/live-run-update.schema.json +93 -0
  377. package/packages/schema/schemas/live-run.schema.json +225 -0
  378. package/packages/schema/schemas/merge-result.schema.json +40 -0
  379. package/packages/schema/schemas/outline.schema.json +62 -0
  380. package/packages/schema/schemas/problem.schema.json +37 -0
  381. package/packages/schema/schemas/project-slug.schema.json +8 -0
  382. package/packages/schema/schemas/project.schema.json +22 -0
  383. package/packages/schema/schemas/projects.schema.json +33 -0
  384. package/packages/schema/schemas/publish-checks.schema.json +1413 -0
  385. package/packages/schema/schemas/publish-result.schema.json +168 -0
  386. package/packages/schema/schemas/ready.schema.json +68 -0
  387. package/packages/schema/schemas/report-event.schema.json +100 -0
  388. package/packages/schema/schemas/report-status.schema.json +370 -0
  389. package/packages/schema/schemas/server-config.schema.json +208 -0
  390. package/packages/schema/schemas/server-editable-settings.schema.json +132 -0
  391. package/packages/schema/schemas/server-info.schema.json +114 -0
  392. package/packages/schema/schemas/server-settings-snapshot.schema.json +285 -0
  393. package/packages/schema/schemas/spec-set.schema.json +103 -0
  394. package/packages/schema/schemas/store-listing.schema.json +29 -0
  395. package/packages/schema/schemas/store-write-result.schema.json +28 -0
  396. package/packages/schema/schemas/stream-result.schema.json +59 -0
  397. package/packages/server/README.md +43 -0
  398. package/packages/server/openapi.json +11021 -0
  399. package/packages/visualizer/README.md +32 -11
  400. package/packages/visualizer/bin/atlas-client.mjs +176 -0
  401. package/packages/visualizer/bin/atlas-visualizer.mjs +2 -175
  402. package/packages/visualizer/src/app/AppShell.tsx +32 -16
  403. package/packages/visualizer/src/app/report-sources.tsx +7 -4
  404. package/packages/visualizer/src/app/router.tsx +3 -3
  405. package/packages/visualizer/src/components/ActivityIndicator.module.css +4 -0
  406. package/packages/visualizer/src/components/ActivityIndicator.tsx +6 -0
  407. package/packages/visualizer/src/components/Header.module.css +101 -192
  408. package/packages/visualizer/src/components/Header.tsx +88 -13
  409. package/packages/visualizer/src/components/ProjectPicker.tsx +64 -0
  410. package/packages/visualizer/src/data/adapters/adapter.ts +5 -17
  411. package/packages/visualizer/src/data/adapters/index.ts +10 -1
  412. package/packages/visualizer/src/data/adapters/report-backend.test.ts +3 -2
  413. package/packages/visualizer/src/data/adapters/report-backend.ts +1 -1
  414. package/packages/visualizer/src/data/queries.ts +14 -7
  415. package/packages/visualizer/src/evidence/api.ts +16 -3
  416. package/packages/visualizer/src/evidence/artifacts.module.css +213 -0
  417. package/packages/visualizer/src/evidence/artifacts.tsx +272 -0
  418. package/packages/visualizer/src/evidence/check-detail.tsx +21 -4
  419. package/packages/visualizer/src/evidence/document-page.tsx +6 -2
  420. package/packages/visualizer/src/evidence/evidence-context.tsx +79 -12
  421. package/packages/visualizer/src/evidence/evidence.module.css +11 -1
  422. package/packages/visualizer/src/evidence/feature-page.tsx +7 -3
  423. package/packages/visualizer/src/evidence/model-page.tsx +6 -2
  424. package/packages/visualizer/src/evidence/project-home.tsx +45 -0
  425. package/packages/visualizer/src/evidence/recording-page.tsx +4 -1
  426. package/packages/visualizer/src/evidence/spec-index.tsx +2 -1
  427. package/packages/visualizer/src/evidence/spec-page.tsx +23 -16
  428. package/packages/visualizer/src/evidence/test-filter.tsx +21 -0
  429. package/packages/visualizer/src/find/Finder.tsx +1 -7
  430. package/packages/visualizer/src/find/open.ts +4 -0
  431. package/packages/visualizer/src/live/live-query.ts +21 -0
  432. package/packages/visualizer/src/live/live-runs.tsx +69 -0
  433. package/packages/visualizer/src/live/live-stream.ts +225 -0
  434. package/packages/visualizer/src/live/report-progress.ts +62 -0
  435. package/packages/visualizer/src/live/test-progress.tsx +34 -0
  436. package/packages/visualizer/src/runtime.ts +35 -0
  437. package/packages/visualizer/src/state/ui-store.ts +3 -2
  438. package/packages/visualizer/src/views/ChartPage.tsx +2 -0
  439. package/packages/visualizer/src/views/ChartTests.tsx +43 -0
  440. package/packages/visualizer/src/views/SidePanel.tsx +2 -0
  441. package/packages/visualizer/vite/atlas-files.test.ts +4 -4
  442. package/packages/visualizer/vite/atlas-files.ts +1 -5
  443. package/packages/visualizer/vite/atlas-server-proxy.ts +37 -0
  444. package/packages/visualizer/vite.config.ts +11 -3
@@ -0,0 +1,122 @@
1
+ /**
2
+ * @module Publishing checks as a layer
3
+ *
4
+ * `publishChecks` turns the checks of one producer into one immutable layer in any store: the whole integration for a suite
5
+ * that has no timeline to record. Attachments of any kind are stored by content (the same screenshot attached ten times is
6
+ * stored once). Nothing here reads a clock or the environment, so the same input is always the same layer and a retried CI
7
+ * step changes nothing.
8
+ *
9
+ * @see docs/integrating.md
10
+ * @see docs/extending.md
11
+ */
12
+ import { PublishChecksSchema } from '../../schema/src/layer.js';
13
+ import { writeBundle } from './bundle.js';
14
+ import { normalizeEnvironment } from './layer-axes.js';
15
+ import { publishLayerBundle } from './layer-store.js';
16
+ import { contentTypeOf } from './media-types.js';
17
+ import { parseWith } from './parse-with.js';
18
+ import { sha256Hex } from './sigv4.js';
19
+ /** A small text value stays in the layer's own document; anything longer is stored as a file. */
20
+ const INLINE_TEXT_BYTES = 8 * 1024;
21
+ const encoder = new TextEncoder();
22
+ function decodeBase64(text) {
23
+ const binary = atob(text);
24
+ return Uint8Array.from(binary, char => char.charCodeAt(0));
25
+ }
26
+ /**
27
+ * Move the bytes of every attachment, at every level, into the layer: a file by its content (so the same
28
+ * screenshot attached ten times is stored once), referred to by `bundleKey`. What a producer wrote as `data`,
29
+ * `base64` or a long `text` becomes a reference; a short `text` stays inline; a `uri` is left alone.
30
+ */
31
+ async function materialize(holder, entries, limit) {
32
+ const out = { ...holder };
33
+ if (Array.isArray(out.attachments)) {
34
+ out.attachments = await Promise.all(out.attachments.map(async (given) => {
35
+ const { path: file, base64, data, ...kept } = given;
36
+ if (file !== undefined)
37
+ throw new Error(`publishChecks: attachment "${String(kept.name)}" names a file (path). Reading files is the command line's job: read it and pass its bytes as data`);
38
+ const text = typeof kept.text === 'string' ? kept.text : undefined;
39
+ let bytes = data ?? (base64 === undefined ? null : decodeBase64(base64));
40
+ if (!bytes && text !== undefined && encoder.encode(text).length > INLINE_TEXT_BYTES)
41
+ bytes = encoder.encode(text);
42
+ if (!bytes)
43
+ return { ...kept, ...(text !== undefined ? { bytes: encoder.encode(text).length } : {}) };
44
+ if (bytes.length > limit)
45
+ throw new Error(`publishChecks: attachment "${String(kept.name)}" is ${bytes.length} bytes, over the limit of ${limit}. Store it elsewhere and attach its uri`);
46
+ const sha256 = await sha256Hex(bytes);
47
+ const contentType = kept.contentType ?? contentTypeOf(String(kept.name));
48
+ entries.set(`attachments/${sha256}`, { key: `attachments/${sha256}`, bytes, contentType });
49
+ const { text: _inline, ...rest } = kept;
50
+ return { ...rest, contentType, bundleKey: `attachments/${sha256}`, bytes: bytes.length, sha256 };
51
+ }));
52
+ }
53
+ if (Array.isArray(out.steps))
54
+ out.steps = await Promise.all(out.steps.map(step => materialize(step, entries, limit)));
55
+ if (Array.isArray(out.attempts))
56
+ out.attempts = await Promise.all(out.attempts.map(attempt => materialize(attempt, entries, limit)));
57
+ return out;
58
+ }
59
+ /**
60
+ * Publish the checks of one producer as one immutable layer. This is the whole integration for a
61
+ * suite that has no timelines to record: Gherkin scenarios, a Quint run, a DMN table test, an SLO
62
+ * evaluation, a linter, anything that ends in "this check passed or failed".
63
+ *
64
+ * A check may carry whatever evidence its framework has: attachments of any media type (screenshots,
65
+ * videos, traces, logs, DOM snapshots…), timeline steps, annotations, retries, tags, labels, links and
66
+ * namespaced `extensions`. All of it is optional (docs/extending.md).
67
+ *
68
+ * Nothing here reads a clock: `recordedAtMs` is when the checks ran, given by the caller. Publishing
69
+ * the same input twice therefore writes the same layer, and a retried CI step changes nothing.
70
+ * Each check's `id` is its identity across runs. It must be stable and unique within the layer.
71
+ */
72
+ export async function publishChecks(store, input, options = {}) {
73
+ const args = parseWith(PublishChecksSchema, input, 'publishChecks');
74
+ const seen = new Set();
75
+ for (const check of args.checks) {
76
+ if (seen.has(check.id))
77
+ throw new Error(`publishChecks: check id "${check.id}" appears twice; a check keeps one id across runs, so ids must be unique`);
78
+ seen.add(check.id);
79
+ }
80
+ const limit = options.maxAttachmentBytes ?? 512 * 1024 * 1024;
81
+ const entries = new Map();
82
+ const checks = await Promise.all(args.checks.map(check => materialize(check, entries, limit)));
83
+ const layerEvidence = await materialize({ attachments: args.attachments }, entries, limit);
84
+ const total = [...entries.values()].reduce((sum, entry) => sum + entry.bytes.length, 0);
85
+ const totalLimit = options.maxTotalAttachmentBytes ?? 2 * 1024 * 1024 * 1024;
86
+ if (total > totalLimit)
87
+ throw new Error(`publishChecks: attachments total ${total} bytes, over the limit of ${totalLimit}. Attach the largest by uri, or publish in several layers`);
88
+ const environment = normalizeEnvironment(args.environment ?? args.parameters.environment);
89
+ const { environment: _folded, ...parameters } = args.parameters;
90
+ const part = {
91
+ sha: args.sha ?? '',
92
+ id: args.producer,
93
+ kind: args.kind,
94
+ title: args.title ?? args.producer,
95
+ recordedAtMs: args.recordedAtMs,
96
+ checks: checks
97
+ };
98
+ // Key order is part of the layer's identity: build it the one way.
99
+ const summary = {
100
+ ...(args.freshness ? { freshness: args.freshness } : {}),
101
+ producer: args.producer,
102
+ recordedAtMs: args.recordedAtMs,
103
+ sha: args.sha,
104
+ branch: args.branch,
105
+ runUrl: args.runUrl,
106
+ ...(environment ? { environment } : {}),
107
+ parameters: Object.fromEntries(Object.entries(parameters).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))),
108
+ specs: args.specs,
109
+ parts: [part],
110
+ source: null,
111
+ recording: null,
112
+ ...(args.tags?.length ? { tags: args.tags } : {}),
113
+ ...(args.labels && Object.keys(args.labels).length ? { labels: Object.fromEntries(Object.entries(args.labels).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))) } : {}),
114
+ ...(args.links?.length ? { links: args.links } : {}),
115
+ ...(layerEvidence.attachments?.length ? { attachments: layerEvidence.attachments } : {}),
116
+ ...(args.annotations?.length ? { annotations: args.annotations } : {}),
117
+ ...(args.extensions && Object.keys(args.extensions).length ? { extensions: args.extensions } : {})
118
+ };
119
+ const bundle = entries.size ? await writeBundle(store, (async function* () { for (const entry of [...entries.values()].sort((a, b) => (a.key < b.key ? -1 : 1)))
120
+ yield entry; })(), 'layers/blobs/') : {};
121
+ return publishLayerBundle(store, summary, bundle);
122
+ }
@@ -5,50 +5,83 @@ import type { CommitRecord, SourceRecord } from './protocol.js';
5
5
  import type { SourceIdentity } from './source-content.js';
6
6
  /** The run id every spec suite writes its bucket under. */
7
7
  export declare const SPEC_RUN_ID = "latest";
8
+ /** What `openCommit` needs to start a commit's run. */
8
9
  export type OpenCommitArgs = {
10
+ /** The full 40-hex commit sha. */
9
11
  readonly sha: string;
10
12
  readonly branch: string;
13
+ /** The CI run publishing this commit, or `null`. */
11
14
  readonly runUrl: string | null;
15
+ /** When the run started, epoch milliseconds; it also orders the commit list (newest first). */
12
16
  readonly startedAtMs: number;
13
17
  /** Stylesheet the commit's HTML snapshots render with. */
14
18
  readonly frameCss: string;
15
- /** Concurrent CI attempts own independent commit-local files. */
19
+ /** Concurrent CI attempts own independent commit-local files. Letters, digits, `.`, `_`, `:` and `-`; see `publicationStore`. */
16
20
  readonly publicationId?: string;
17
21
  };
18
22
  /**
19
- * Mark a commit's run as started and list it (newest first). Its snapshot
20
- * stylesheet goes up first, so a test is viewable the moment it lands.
23
+ * Marks a commit's run as started and lists it (newest first), returning the `running` record.
24
+ *
25
+ * Writes the snapshot stylesheet first, so a test is viewable the moment it lands, then `commit.json`, then the
26
+ * `index/` entry that lists the commit, and, only when `publicationId` is given, last the pointer that tells readers
27
+ * to look under that attempt. With a `publicationId` the stylesheet and record are written in the attempt's scope, not
28
+ * the shared one. Calling it again for the same sha and attempt rewrites the same keys. Store errors reject.
21
29
  */
22
30
  export declare function openCommit(store: ObjectStore, args: OpenCommitArgs): Promise<CommitRecord>;
31
+ /** What `publishSource` needs to publish one package bucket of recorded tests. */
23
32
  export type PublishSourceArgs = {
24
- /** Execution completion time, separate from a virtual timeline clock. */
33
+ /** Execution completion time, separate from a virtual timeline clock. Epoch milliseconds. Default: the latest test's `endedAtMs`. */
25
34
  readonly recordedAtMs?: number;
35
+ /** Recorded on the layer: `modified` when the run was from a checkout with uncommitted changes, `unknown` when its origin is unknown. */
26
36
  readonly freshness?: 'unknown' | 'modified';
27
37
  /** The client this run checked: desktop web, mobile web, iOS, Android, or another recorded name. */
28
38
  readonly environment?: string;
39
+ /** Choices other than the client that make this its own slot (see `LayerParameters`). */
29
40
  readonly parameters?: LayerParameters;
41
+ /** The full 40-hex commit sha the run is for. */
30
42
  readonly sha: string;
43
+ /** Repo-relative package dir; with `bucket` it forms the source id (`libs-chess--part-2`). */
31
44
  readonly packageDir: string;
45
+ /** The bucket under the package's report dir (`part-2`, `all`). */
32
46
  readonly bucket: string;
33
47
  /** The package's local report bucket (`.cache/harness-report/<bucket>`). */
34
48
  readonly local: ObjectStore;
49
+ /** The run id the tests were written under in `local`. Default: `latest` (`SPEC_RUN_ID`). */
35
50
  readonly runId?: string;
36
51
  /** Only a passing execution is reusable under its exact task hash. */
37
52
  readonly identity?: SourceIdentity;
53
+ /** Forces the source's status to `failed`; any other value is ignored and the status is computed from the tests. */
38
54
  readonly status?: ReportTestStatus;
39
55
  };
40
56
  /**
41
- * Copy one package bucket into the store: every test (runner outcomes
42
- * applied) and its frame files, then the source record, last, so a reader
43
- * that sees the record can read every test it names. Null when the bucket
44
- * recorded no test.
57
+ * Copies one package bucket into the store: every test (runner outcomes from the bucket's `junit.xml` applied) and its
58
+ * frame files, then the source record last, so a reader that sees the record can read every test it names; finally it
59
+ * archives the source as an immutable layer. Returns the record, or `null` when the bucket recorded no test and
60
+ * neither `identity` nor `status` was given.
61
+ *
62
+ * The source's status is `failed` when `args.status` is `failed`, else `failed` if any test failed, `skipped` if all
63
+ * were skipped, else `passed`. A passing source with an `identity` is stored once, content-addressed by its task
64
+ * hash, and referenced from the commit; any other source gets its files in the commit's bundle. When the bucket has no
65
+ * `ui-quality` or `performance` part of its own, a `performance` part with a 50 ms allowance is derived from the
66
+ * tests. Throws on a source id that is not a valid key segment, a part that fails `validatePart`, or a store error;
67
+ * a failure part-way leaves unreferenced content, never a record that names missing content.
45
68
  */
46
69
  export declare function publishSource(store: ObjectStore, args: PublishSourceArgs): Promise<SourceRecord | null>;
70
+ /** What `closeCommit` needs to finish a commit's run. */
47
71
  export type CloseCommitArgs = {
72
+ /** The full 40-hex commit sha. */
48
73
  readonly sha: string;
74
+ /** When the run ended, epoch milliseconds. */
49
75
  readonly endedAtMs: number;
76
+ /** The attempt given to `openCommit`, when it was given one. */
50
77
  readonly publicationId?: string;
78
+ /** `failed` forces the commit's status to `failed`; any other value is ignored. */
51
79
  readonly status?: ReportTestStatus;
52
80
  };
53
- /** Mark a commit's run complete, with the worst status of its sources. */
81
+ /**
82
+ * Marks a commit's run `complete` and returns the record, with the worst status of its sources: `failed` if
83
+ * `args.status` is `failed` or any source failed, `skipped` when there are no sources or all were skipped, else
84
+ * `passed`. Throws `no open report for <sha>; openCommit runs first` when the commit was never opened. Calling it
85
+ * again rewrites the record with the sources present at that time.
86
+ */
54
87
  export declare function closeCommit(store: ObjectStore, args: CloseCommitArgs): Promise<CommitRecord>;
@@ -1,3 +1,16 @@
1
+ /**
2
+ * @module Publishing commit-keyed recordings
3
+ *
4
+ * The write side of the older, commit-keyed shared store: what CI runs after a spec suite recorded timelines with
5
+ * screenshots. `openCommit` starts a commit, `publishSource` copies one package bucket's recorded tests into the store
6
+ * (and also archives it as an immutable layer, so it composes with every other layer), and `closeCommit` finishes the
7
+ * commit. Pure over two injected `ObjectStore`s, the local report bucket a test run wrote and the shared store, so it
8
+ * runs the same against a directory, S3 or memory. Writes go content first, then the record that names it, so a
9
+ * reader that sees a record can read everything it names. Plain checks from JUnit, CTRF or a checks file do not go
10
+ * through here: they use `publishChecks`.
11
+ *
12
+ * @see docs/report-backends.md
13
+ */
1
14
  import { archiveSourceLayer } from './layer-source.js';
2
15
  import { normalizeEnvironment } from './layer-axes.js';
3
16
  import { performancePart } from './performance-part.js';
@@ -21,8 +34,12 @@ export const SPEC_RUN_ID = 'latest';
21
34
  const WRITE_WIDTH = 32;
22
35
  const JSON_TYPE = 'application/json; charset=utf-8';
23
36
  /**
24
- * Mark a commit's run as started and list it (newest first). Its snapshot
25
- * stylesheet goes up first, so a test is viewable the moment it lands.
37
+ * Marks a commit's run as started and lists it (newest first), returning the `running` record.
38
+ *
39
+ * Writes the snapshot stylesheet first, so a test is viewable the moment it lands, then `commit.json`, then the
40
+ * `index/` entry that lists the commit, and, only when `publicationId` is given, last the pointer that tells readers
41
+ * to look under that attempt. With a `publicationId` the stylesheet and record are written in the attempt's scope, not
42
+ * the shared one. Calling it again for the same sha and attempt rewrites the same keys. Store errors reject.
26
43
  */
27
44
  export async function openCommit(store, args) {
28
45
  const { frameCss, publicationId, ...fields } = args;
@@ -83,10 +100,17 @@ async function publishSnapshots(store, args, tests, contentPrefix) {
83
100
  });
84
101
  }
85
102
  /**
86
- * Copy one package bucket into the store: every test (runner outcomes
87
- * applied) and its frame files, then the source record, last, so a reader
88
- * that sees the record can read every test it names. Null when the bucket
89
- * recorded no test.
103
+ * Copies one package bucket into the store: every test (runner outcomes from the bucket's `junit.xml` applied) and its
104
+ * frame files, then the source record last, so a reader that sees the record can read every test it names; finally it
105
+ * archives the source as an immutable layer. Returns the record, or `null` when the bucket recorded no test and
106
+ * neither `identity` nor `status` was given.
107
+ *
108
+ * The source's status is `failed` when `args.status` is `failed`, else `failed` if any test failed, `skipped` if all
109
+ * were skipped, else `passed`. A passing source with an `identity` is stored once, content-addressed by its task
110
+ * hash, and referenced from the commit; any other source gets its files in the commit's bundle. When the bucket has no
111
+ * `ui-quality` or `performance` part of its own, a `performance` part with a 50 ms allowance is derived from the
112
+ * tests. Throws on a source id that is not a valid key segment, a part that fails `validatePart`, or a store error;
113
+ * a failure part-way leaves unreferenced content, never a record that names missing content.
90
114
  */
91
115
  export async function publishSource(store, args) {
92
116
  const runId = args.runId ?? SPEC_RUN_ID;
@@ -152,7 +176,12 @@ async function sourceEvidence(local, sha, source, tests) {
152
176
  validatePart({ ...part, sha, id: source, recordedAtMs: 0 });
153
177
  return { evidence };
154
178
  }
155
- /** Mark a commit's run complete, with the worst status of its sources. */
179
+ /**
180
+ * Marks a commit's run `complete` and returns the record, with the worst status of its sources: `failed` if
181
+ * `args.status` is `failed` or any source failed, `skipped` when there are no sources or all were skipped, else
182
+ * `passed`. Throws `no open report for <sha>; openCommit runs first` when the commit was never opened. Calling it
183
+ * again rewrites the record with the sources present at that time.
184
+ */
156
185
  export async function closeCommit(store, args) {
157
186
  if (args.publicationId !== undefined)
158
187
  store = publicationStore(store, args.publicationId);
@@ -1,60 +1,90 @@
1
1
  /**
2
- * Read side of the shared reports store: what a reports API serves. Pure over
3
- * an injected {@link ObjectStore}, {@link Clock} and {@link Timers}; nothing
4
- * here imports a runtime or an HTTP framework.
2
+ * @module Reading commit-keyed recordings
3
+ *
4
+ * The read side of the older, commit-keyed shared store: what the reports API serves for a commit (its record, its
5
+ * sources, each test's timeline and frame files) and the event streams that deliver them. Pure over an injected
6
+ * `ObjectStore`, `Clock` and `Timers`; nothing here imports a runtime or an HTTP framework. Every read goes through
7
+ * `reportStore`, so a commit published by an attempt (`publicationId`) is read from that attempt's records.
8
+ *
9
+ * @see docs/report-backends.md
5
10
  */
6
11
  import type { Clock, Timers } from './clock.js';
7
12
  import type { RunReport } from './report-types.js';
8
13
  import type { ObjectStore, StoredObject } from './object-store.js';
9
14
  import type { CommitEvent, CommitPage, CommitRecord, SourceRecord, TestEvent } from './protocol.js';
15
+ /** Reads a commit's record, or `null` when it is missing or not valid JSON. */
10
16
  export declare function readCommit(store: ObjectStore, sha: string): Promise<CommitRecord | null>;
17
+ /** Reads the stylesheet a commit's snapshots render with, or `null` when the commit has none. */
11
18
  export declare function readFrameCss(store: ObjectStore, sha: string): Promise<StoredObject | null>;
12
19
  /**
13
- * Newest commits first, `limit` per page. A commit published twice (a rerun)
14
- * has two index entries; only the newer one is ever listed, on any page.
20
+ * Lists commits newest first, `limit` per page (at least 1).
21
+ *
22
+ * A commit published twice (a rerun) has two index entries; only the newer one is ever listed, on any page.
23
+ * `cursor` is the previous page's `cursor`; `null` starts at the newest. The returned `cursor` is `null` on the last
24
+ * page. An index entry whose commit record is missing or unreadable is left out, so a page may hold fewer than
25
+ * `limit` commits. Store errors reject.
15
26
  */
16
27
  export declare function listCommits(store: ObjectStore, options: {
17
28
  readonly limit: number;
18
29
  readonly cursor: string | null;
19
30
  }): Promise<CommitPage>;
31
+ /** How `commitEvents` tails a running commit. */
20
32
  export type CommitEventsOptions = {
33
+ /** Time source for `tailMs`. */
21
34
  readonly clock: Clock;
35
+ /** Timer functions used to wait `pollMs` between listings. */
22
36
  readonly timers: Timers;
23
37
  /** Sources the client already holds (a reconnect): never sent again. */
24
38
  readonly have?: ReadonlySet<string>;
25
- /** How often a running commit is re-listed for new sources. */
39
+ /** How often, in milliseconds, a running commit is re-listed for new sources. */
26
40
  readonly pollMs: number;
27
- /** A running commit's stream ends after this long; the client reconnects. */
41
+ /** A running commit's stream ends after this many milliseconds; the client reconnects. */
28
42
  readonly tailMs: number;
29
43
  };
30
44
  /**
31
- * The commit, then every source in the order its read finishes. While the
32
- * commit is running, its sources are re-listed every `pollMs` and each new
33
- * one is sent as it lands, until the commit completes or `tailMs` passes.
34
- * The state is read before each listing, so a listing after `complete` is
35
- * the final one.
45
+ * Streams a commit as events: the commit record, then every source in the order its read finishes. While the
46
+ * commit is running, its sources are re-listed every `pollMs` and each new one is sent as it lands, until the commit
47
+ * completes or `tailMs` passes. The state is read before each listing, so a listing after `complete` is the final
48
+ * one. A `commit` event is sent again when the commit's state changes.
49
+ *
50
+ * Ends with `{ type: 'end', state }`: `missing` when there is no commit record and no source, `complete` when the
51
+ * commit closed, `running` when `tailMs` passed first (reconnect with `have` to continue). A source is never sent
52
+ * twice in one stream, nor one listed in `options.have`. Trap: a source is counted as sent as soon as it is listed,
53
+ * so one whose record cannot be read at that moment is not retried in the same stream.
36
54
  */
37
55
  export declare function commitEvents(store: ObjectStore, sha: string, options: CommitEventsOptions): AsyncGenerator<CommitEvent>;
38
- /** One test's timeline, without its frame files. */
56
+ /**
57
+ * Reads one test's timeline (`RunReport`) without its frame files, or `null` when the source or test is not in the
58
+ * commit. A timeline stored as a reusable source is parsed leniently (`null` if not JSON); one in the commit's bundle
59
+ * throws if its bytes are not JSON.
60
+ */
39
61
  export declare function readTestReport(store: ObjectStore, args: {
40
62
  readonly sha: string;
41
63
  readonly source: string;
42
64
  readonly testId: string;
43
65
  }): Promise<RunReport | null>;
66
+ /** One frame file's content. */
44
67
  export type FrameBody = {
68
+ /** The file's bytes. */
45
69
  readonly bytes: Uint8Array;
70
+ /** The media type the file was stored with. */
46
71
  readonly contentType: string;
47
72
  };
48
- /** One frame file's bytes, or null when the test never wrote it. */
73
+ /** Reads one frame file of a test, or `null` when the test never wrote it. Throws `Invalid report frame` when `file` is not a safe relative frame path. */
49
74
  export declare function readFrameBody(store: ObjectStore, args: {
50
75
  readonly sha: string;
51
76
  readonly source: string;
52
77
  readonly testId: string;
53
78
  readonly file: string;
54
79
  }): Promise<FrameBody | null>;
55
- /** Every source record of a commit, in the order each read finishes. */
80
+ /** Lists every source record of a commit, in the order each read finishes. A source whose record cannot be read is left out. */
56
81
  export declare function listSourceRecords(store: ObjectStore, sha: string): Promise<SourceRecord[]>;
57
- /** A test's report, then each of its frame files as its read finishes. */
82
+ /**
83
+ * Streams a test as events: its report, then each frame file the report names as its read finishes, then
84
+ * `{ type: 'end', found: true }`. A test that is not in the commit yields only `{ type: 'end', found: false }`. A frame
85
+ * the report names but the store lacks is skipped. Text media (`html`, `json`, `text`) arrive as inline text, the rest
86
+ * as base64.
87
+ */
58
88
  export declare function testEvents(store: ObjectStore, args: {
59
89
  readonly sha: string;
60
90
  readonly source: string;
@@ -1,7 +1,12 @@
1
1
  /**
2
- * Read side of the shared reports store: what a reports API serves. Pure over
3
- * an injected {@link ObjectStore}, {@link Clock} and {@link Timers}; nothing
4
- * here imports a runtime or an HTTP framework.
2
+ * @module Reading commit-keyed recordings
3
+ *
4
+ * The read side of the older, commit-keyed shared store: what the reports API serves for a commit (its record, its
5
+ * sources, each test's timeline and frame files) and the event streams that deliver them. Pure over an injected
6
+ * `ObjectStore`, `Clock` and `Timers`; nothing here imports a runtime or an HTTP framework. Every read goes through
7
+ * `reportStore`, so a commit published by an attempt (`publicationId`) is read from that attempt's records.
8
+ *
9
+ * @see docs/report-backends.md
5
10
  */
6
11
  import { readUtf8 } from './object-io.js';
7
12
  import { inCompletionOrder } from './completion-order.js';
@@ -24,15 +29,21 @@ async function readJson(store, key) {
24
29
  return null;
25
30
  }
26
31
  }
32
+ /** Reads a commit's record, or `null` when it is missing or not valid JSON. */
27
33
  export async function readCommit(store, sha) {
28
34
  return readJson(await reportStore(store, sha), commitKey(sha));
29
35
  }
36
+ /** Reads the stylesheet a commit's snapshots render with, or `null` when the commit has none. */
30
37
  export async function readFrameCss(store, sha) {
31
38
  return (await reportStore(store, sha)).get(frameCssKey(sha));
32
39
  }
33
40
  /**
34
- * Newest commits first, `limit` per page. A commit published twice (a rerun)
35
- * has two index entries; only the newer one is ever listed, on any page.
41
+ * Lists commits newest first, `limit` per page (at least 1).
42
+ *
43
+ * A commit published twice (a rerun) has two index entries; only the newer one is ever listed, on any page.
44
+ * `cursor` is the previous page's `cursor`; `null` starts at the newest. The returned `cursor` is `null` on the last
45
+ * page. An index entry whose commit record is missing or unreadable is left out, so a page may hold fewer than
46
+ * `limit` commits. Store errors reject.
36
47
  */
37
48
  export async function listCommits(store, options) {
38
49
  const seen = new Set();
@@ -73,11 +84,15 @@ async function* newSources(store, sha, sent) {
73
84
  }
74
85
  }
75
86
  /**
76
- * The commit, then every source in the order its read finishes. While the
77
- * commit is running, its sources are re-listed every `pollMs` and each new
78
- * one is sent as it lands, until the commit completes or `tailMs` passes.
79
- * The state is read before each listing, so a listing after `complete` is
80
- * the final one.
87
+ * Streams a commit as events: the commit record, then every source in the order its read finishes. While the
88
+ * commit is running, its sources are re-listed every `pollMs` and each new one is sent as it lands, until the commit
89
+ * completes or `tailMs` passes. The state is read before each listing, so a listing after `complete` is the final
90
+ * one. A `commit` event is sent again when the commit's state changes.
91
+ *
92
+ * Ends with `{ type: 'end', state }`: `missing` when there is no commit record and no source, `complete` when the
93
+ * commit closed, `running` when `tailMs` passed first (reconnect with `have` to continue). A source is never sent
94
+ * twice in one stream, nor one listed in `options.have`. Trap: a source is counted as sent as soon as it is listed,
95
+ * so one whose record cannot be read at that moment is not retried in the same stream.
81
96
  */
82
97
  export async function* commitEvents(store, sha, options) {
83
98
  const startedAt = options.clock.now();
@@ -133,7 +148,11 @@ function frameBlob(obj, media) {
133
148
  }
134
149
  : { contentType: obj.contentType, base64: bytesToBase64(obj.bytes) };
135
150
  }
136
- /** One test's timeline, without its frame files. */
151
+ /**
152
+ * Reads one test's timeline (`RunReport`) without its frame files, or `null` when the source or test is not in the
153
+ * commit. A timeline stored as a reusable source is parsed leniently (`null` if not JSON); one in the commit's bundle
154
+ * throws if its bytes are not JSON.
155
+ */
137
156
  export async function readTestReport(store, args) {
138
157
  store = await reportStore(store, args.sha);
139
158
  const prefix = await sourceTestPrefix(store, args);
@@ -147,7 +166,7 @@ export async function readTestReport(store, args) {
147
166
  ? null
148
167
  : JSON.parse(new TextDecoder().decode(obj.bytes));
149
168
  }
150
- /** One frame file's bytes, or null when the test never wrote it. */
169
+ /** Reads one frame file of a test, or `null` when the test never wrote it. Throws `Invalid report frame` when `file` is not a safe relative frame path. */
151
170
  export async function readFrameBody(store, args) {
152
171
  store = await reportStore(store, args.sha);
153
172
  if (!isFramePath(args.file))
@@ -164,7 +183,7 @@ export async function readFrameBody(store, args) {
164
183
  ? null
165
184
  : { bytes: obj.bytes, contentType: obj.contentType };
166
185
  }
167
- /** Every source record of a commit, in the order each read finishes. */
186
+ /** Lists every source record of a commit, in the order each read finishes. A source whose record cannot be read is left out. */
168
187
  export async function listSourceRecords(store, sha) {
169
188
  const out = [];
170
189
  for await (const source of newSources(store, sha, new Set())) {
@@ -172,7 +191,12 @@ export async function listSourceRecords(store, sha) {
172
191
  }
173
192
  return out;
174
193
  }
175
- /** A test's report, then each of its frame files as its read finishes. */
194
+ /**
195
+ * Streams a test as events: its report, then each frame file the report names as its read finishes, then
196
+ * `{ type: 'end', found: true }`. A test that is not in the commit yields only `{ type: 'end', found: false }`. A frame
197
+ * the report names but the store lacks is skipped. Text media (`html`, `json`, `text`) arrive as inline text, the rest
198
+ * as base64.
199
+ */
176
200
  export async function* testEvents(store, args) {
177
201
  store = await reportStore(store, args.sha);
178
202
  const prefix = await sourceTestPrefix(store, args);
@@ -1,22 +1,33 @@
1
1
  /**
2
- * A report test with its frame files in memory: what a viewer renders. Text
3
- * media are inline, binary media base64.
2
+ * @module In-memory recorded test
3
+ *
4
+ * Types for a recorded test with its frame files held in memory, which is what a viewer renders and what a publisher
5
+ * copies: text media inline, binary media as base64.
4
6
  */
5
7
  import type { ReportTestStatus, RunReport } from './report-types.js';
6
8
  /** One embedded frame file: text media inline, binary media as base64. */
7
9
  export type HtmlReportBlob = {
10
+ /** The media type of the file. */
8
11
  readonly contentType: string;
12
+ /** The file's content for text media. */
9
13
  readonly text?: string;
14
+ /** The file's content for binary media, base64-encoded. */
10
15
  readonly base64?: string;
11
16
  };
17
+ /** One recorded test: its timeline and its frame files. */
12
18
  export type HtmlReportTest = {
19
+ /** The test's timeline. */
13
20
  readonly report: RunReport;
14
21
  /** Keyed by the blob's `file` (relative to the test dir). */
15
22
  readonly blobs: Readonly<Record<string, HtmlReportBlob>>;
16
23
  };
24
+ /** The tests of one run held in memory. */
17
25
  export type HtmlReportBundle = {
18
26
  readonly runId: string;
27
+ /** The run's overall outcome. */
19
28
  readonly status: ReportTestStatus;
29
+ /** When the run was last updated, epoch milliseconds. */
20
30
  readonly updatedAtMs: number;
31
+ /** The run's tests. */
21
32
  readonly tests: readonly HtmlReportTest[];
22
33
  };
@@ -1,4 +1,6 @@
1
1
  /**
2
- * A report test with its frame files in memory: what a viewer renders. Text
3
- * media are inline, binary media base64.
2
+ * @module In-memory recorded test
3
+ *
4
+ * Types for a recorded test with its frame files held in memory, which is what a viewer renders and what a publisher
5
+ * copies: text media inline, binary media as base64.
4
6
  */
@@ -1,9 +1,23 @@
1
- /** Object-store key layout for one report bucket. */
1
+ /**
2
+ * @module Key layout of one report bucket
3
+ *
4
+ * Where a test run writes its recordings inside one local report bucket (an `ObjectStore`): `runs/index.json`,
5
+ * `runs/<runId>/manifest.json` and `runs/<runId>/tests/<testId>/report.json` plus the test's frame files beside it.
6
+ * Pure string functions. Neither id is validated here; callers sanitise them (`sanitizeRunId`, `sanitizeTestId`).
7
+ */
8
+ /** The key of the index of the runs in a bucket. */
2
9
  export declare const RUNS_INDEX_KEY = "runs/index.json";
10
+ /** The key prefix of one run, without a trailing slash: `runs/<runId>`. */
3
11
  export declare function runPrefix(runId: string): string;
12
+ /** The key of a run's manifest: `runs/<runId>/manifest.json`. */
4
13
  export declare function runManifestKey(runId: string): string;
14
+ /** The key prefix of one test, without a trailing slash: `runs/<runId>/tests/<testId>`. With an empty `testId` it ends in `/tests/`, which lists all tests of the run. */
5
15
  export declare function testPrefix(runId: string, testId: string): string;
16
+ /** The key of a test's timeline: `runs/<runId>/tests/<testId>/report.json`. */
6
17
  export declare function testReportKey(runId: string, testId: string): string;
18
+ /** The key of one frame file of a test: the test prefix and `frameFile` with any leading `/` removed. With an empty `frameFile` it is the test's prefix with a trailing slash. */
7
19
  export declare function testFrameKey(runId: string, testId: string, frameFile: string): string;
20
+ /** The file extension for a snapshot media kind (`html`, `png`, `json`, `txt`, `bin`, `mp4`); an unknown kind is `bin`. */
8
21
  export declare function mediaExtension(media: string): string;
22
+ /** The media type for a snapshot media kind (`html`, `png`, `json`, `text`, `bytes`, `video`); an unknown kind is `application/octet-stream`. */
9
23
  export declare function contentTypeForMedia(media: string): string;
@@ -1,21 +1,34 @@
1
- /** Object-store key layout for one report bucket. */
1
+ /**
2
+ * @module Key layout of one report bucket
3
+ *
4
+ * Where a test run writes its recordings inside one local report bucket (an `ObjectStore`): `runs/index.json`,
5
+ * `runs/<runId>/manifest.json` and `runs/<runId>/tests/<testId>/report.json` plus the test's frame files beside it.
6
+ * Pure string functions. Neither id is validated here; callers sanitise them (`sanitizeRunId`, `sanitizeTestId`).
7
+ */
8
+ /** The key of the index of the runs in a bucket. */
2
9
  export const RUNS_INDEX_KEY = 'runs/index.json';
10
+ /** The key prefix of one run, without a trailing slash: `runs/<runId>`. */
3
11
  export function runPrefix(runId) {
4
12
  return `runs/${runId}`;
5
13
  }
14
+ /** The key of a run's manifest: `runs/<runId>/manifest.json`. */
6
15
  export function runManifestKey(runId) {
7
16
  return `${runPrefix(runId)}/manifest.json`;
8
17
  }
18
+ /** The key prefix of one test, without a trailing slash: `runs/<runId>/tests/<testId>`. With an empty `testId` it ends in `/tests/`, which lists all tests of the run. */
9
19
  export function testPrefix(runId, testId) {
10
20
  return `${runPrefix(runId)}/tests/${testId}`;
11
21
  }
22
+ /** The key of a test's timeline: `runs/<runId>/tests/<testId>/report.json`. */
12
23
  export function testReportKey(runId, testId) {
13
24
  return `${testPrefix(runId, testId)}/report.json`;
14
25
  }
26
+ /** The key of one frame file of a test: the test prefix and `frameFile` with any leading `/` removed. With an empty `frameFile` it is the test's prefix with a trailing slash. */
15
27
  export function testFrameKey(runId, testId, frameFile) {
16
28
  const rel = frameFile.replace(/^\/+/, '');
17
29
  return `${testPrefix(runId, testId)}/${rel}`;
18
30
  }
31
+ /** The file extension for a snapshot media kind (`html`, `png`, `json`, `txt`, `bin`, `mp4`); an unknown kind is `bin`. */
19
32
  export function mediaExtension(media) {
20
33
  switch (media) {
21
34
  case 'html':
@@ -34,6 +47,7 @@ export function mediaExtension(media) {
34
47
  return 'bin';
35
48
  }
36
49
  }
50
+ /** The media type for a snapshot media kind (`html`, `png`, `json`, `text`, `bytes`, `video`); an unknown kind is `application/octet-stream`. */
37
51
  export function contentTypeForMedia(media) {
38
52
  switch (media) {
39
53
  case 'html':