@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
@@ -1,3 +1,16 @@
1
+ /**
2
+ * @module Path runner and manifest
3
+ *
4
+ * Runs planned paths against the product through a driver and turns what happened into a run: a
5
+ * directory holding `manifest.json`, `junit.xml`, `ctrf.json`, `chart.mmd`, `outcomes.json` and `media/`.
6
+ * The invariants: the manifest is a pure fold of the plan and the per-path outcomes in plan order (so
7
+ * worker scheduling, sharding and reruns never change the report); it is rewritten atomically after
8
+ * every path so a crash keeps what ran; a failed path is retried once, and passing the second time is
9
+ * `flaky`. This module is the only one that touches the driver and the file system for a run. Its
10
+ * outputs follow the manifest schema in `packages/schema` (`schemaVersion: 1`).
11
+ *
12
+ * @see docs/statecharts.md
13
+ */
1
14
  import { execSync } from 'node:child_process';
2
15
  import { createHash } from 'node:crypto';
3
16
  import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
@@ -25,7 +38,7 @@ function specVersion(bundle) {
25
38
  const relative = (root, file) => path.relative(root, file).split(path.sep).join('/');
26
39
  const pad = (n) => String(n).padStart(2, '0');
27
40
  const sameStates = (a, b) => a.length === b.length && [...a].sort().join('|') === [...b].sort().join('|');
28
- /** A rough cost of a path before it has ever run: setting it up, then each step. */
41
+ /** A rough cost in milliseconds of a path that has never run (5 s to set up, 2.5 s a step); used to order and shard paths. */
29
42
  export const estimateMs = (p) => 5_000 + 2_500 * p.steps.length;
30
43
  /**
31
44
  * The paths one shard runs: longest first onto the least loaded shard, by the plan alone, so
@@ -73,7 +86,10 @@ function copyMedia(outcome, from, to) {
73
86
  cpSync(source, path.join(to, file));
74
87
  }
75
88
  }
76
- /** The plan keys and outcomes a run wrote, for merging shards and reusing passed paths. */
89
+ /**
90
+ * Reads the `outcomes.json` of a run directory: the run id and each finished path's outcome by key.
91
+ * Returns `null` when the file is missing or unreadable, never throws.
92
+ */
77
93
  export function readOutcomes(runDir) {
78
94
  const file = path.join(runDir, 'outcomes.json');
79
95
  if (!existsSync(file))
@@ -86,7 +102,11 @@ export function readOutcomes(runDir) {
86
102
  return null;
87
103
  }
88
104
  }
89
- /** How long each path took in the newest run under `outputRoot` that recorded it, by path key. */
105
+ /**
106
+ * Milliseconds each path took, by path key, taken from the newest of the last 10 runs under
107
+ * `outputRoot` that ran it (outcomes reused from elsewhere are ignored). Empty when the directory
108
+ * does not exist. `runPaths` uses it to start the slowest paths first.
109
+ */
90
110
  export function durationHistory(outputRoot) {
91
111
  const history = {};
92
112
  if (!existsSync(outputRoot))
@@ -104,7 +124,7 @@ export function durationHistory(outputRoot) {
104
124
  }
105
125
  return history;
106
126
  }
107
- /** The newest run under `outputRoot` that wrote outcomes. */
127
+ /** The directory of the newest run under `outputRoot` that wrote `outcomes.json` (run ids sort by time), or `null`. */
108
128
  export function latestRun(outputRoot) {
109
129
  if (!existsSync(outputRoot))
110
130
  return null;
@@ -114,8 +134,20 @@ export function latestRun(outputRoot) {
114
134
  return runs.length ? path.join(outputRoot, runs.at(-1)) : null;
115
135
  }
116
136
  /**
117
- * Fold path outcomes into the run's report, in plan order: the same plan and outcomes always give
118
- * the same manifest, however many workers ran them, in whatever order they finished.
137
+ * Folds path outcomes into the run's manifest object, in plan order: the same plan and outcomes
138
+ * always give the same manifest, however many workers ran them, in whatever order they finished.
139
+ *
140
+ * A state or transition is `passed` when a path reached it, `flaky` when only a flaky path did,
141
+ * `failed` when any failure touched it (a failed check fails its state), else `not-reached`. Reaching a
142
+ * state also marks its ancestors reached. The whole manifest is scanned for privacy findings, and any
143
+ * finding sets `privacy.passed` to false. Reads the chart files (for `specVersion`) and runs `git`
144
+ * in the current directory (for `commit` and `branch`, `null` when that fails). Apart from the
145
+ * wall-clock fields (`finishedAt`, `updatedAt`, `durationMs`) and those that depend on the working
146
+ * directory (`commit`, `branch`, `specDirectory`), two folds of the same outcomes are identical.
147
+ *
148
+ * @param outcomes finished or in-progress outcomes by path key; a path with none is `queued` or `running`.
149
+ * @param run.activePaths ids of the paths in flight; they are reported `running` and not counted complete.
150
+ * @param run.extra extra fields merged into `run` of the manifest (workers, shard, reused, mergedFrom).
119
151
  */
120
152
  export function buildManifest(context, paths, outcomes, run) {
121
153
  const { implementation: impl, graph, scope } = context;
@@ -406,7 +438,11 @@ function writeAtomic(file, text) {
406
438
  writeFileSync(temporary, text);
407
439
  renameSync(temporary, file);
408
440
  }
409
- /** Write a run's manifest, reports and outcomes; returns the manifest. */
441
+ /**
442
+ * Writes a run's `junit.xml`, `ctrf.json`, `chart.mmd`, `outcomes.json` and `manifest.json` into
443
+ * `runDir` (each through a temporary file and a rename, so a reader never sees half a file) and returns
444
+ * the manifest. `outcomes.json` holds only finished paths, not those in `run.activePaths`.
445
+ */
410
446
  export function writeRun(runDir, context, paths, outcomes, run) {
411
447
  const manifest = buildManifest(context, paths, outcomes, run);
412
448
  writeAtomic(path.join(runDir, 'junit.xml'), toJUnit(manifest));
@@ -419,9 +455,14 @@ export function writeRun(runDir, context, paths, outcomes, run) {
419
455
  }
420
456
  const newRunId = (mode) => `${new Date().toISOString().replace(/[:.]/g, '-')}-${mode}`;
421
457
  /**
422
- * Compose the outcomes of several runs of the same plan (the shards of one run, or a rerun of the
423
- * paths that failed) into one run, folded in plan order. Media are copied in, so the merged run
424
- * stands on its own. Later runs win when two ran the same path.
458
+ * Composes the outcomes of several runs of the same plan (the shards of one run, or a rerun and
459
+ * the run before it) into one new run directory under `options.outputRoot`, folded in plan order. Media are
460
+ * copied in, so the merged run stands on its own. Later entries of `runDirs` win when two ran the same
461
+ * path; outcomes whose key is not in `paths` are ignored. The merged run's mode and driver name are
462
+ * taken from the run manifests unless `options` gives them.
463
+ *
464
+ * @returns the new `runDir`, its `manifest`, and `ok` (privacy passed and no path failed).
465
+ * @throws Error when a run directory has no `outcomes.json`.
425
466
  */
426
467
  export function mergeRuns(context, paths, runDirs, options) {
427
468
  const outcomes = new Map();
@@ -461,12 +502,22 @@ export function mergeRuns(context, paths, runDirs, options) {
461
502
  return { runDir, manifest, ok: manifest.privacy.passed && manifest.paths.every((r) => r.status !== 'failed') };
462
503
  }
463
504
  /**
464
- * Run planned paths against a system through a driver. Paths start from their seed (or the
465
- * implementation's `setup`) and run on a pool of workers, longest first, each attempt in its own
466
- * driver context; every state is recognised from the outside after every step; a failed path is
467
- * retried once to tell flaky from broken. The manifest is rewritten as each path finishes, from
468
- * all outcomes so far in plan order, so a crash keeps what ran and the order paths finished in
469
- * never changes the report.
505
+ * Runs planned paths against a system through a driver and writes the run to
506
+ * `<outputRoot>/<timestamp>-<mode>/`. Paths start from their seed (or the implementation's
507
+ * `setup`) and run on a pool of workers, longest first (by earlier timings, else `estimateMs`),
508
+ * each attempt in its own driver context; every state is recognised from the outside after every step;
509
+ * a failed path is retried once to tell flaky from broken. The manifest is rewritten as each path
510
+ * finishes, from all outcomes so far in plan order, so a crash keeps what ran and the order paths
511
+ * finished in never changes the report.
512
+ *
513
+ * Workers are capped by `driver.concurrency` (1 if the driver gives none) and by the number of paths.
514
+ * Without `implementation.correlate`, a run on several workers reports business events as "no
515
+ * signal" rather than guess which attempt they belong to. While it runs it installs
516
+ * `uncaughtException` and `unhandledRejection` handlers that log and swallow stray errors from
517
+ * drivers, and removes them when it ends. Passed paths of `options.reuse` are kept instead of re-run.
518
+ *
519
+ * @returns the run directory, the final manifest, and `ok` (privacy passed and no path failed).
520
+ * @see docs/statecharts.md
470
521
  */
471
522
  export async function runPaths(options) {
472
523
  const { driver, implementation: impl, graph, scope } = options;
@@ -840,7 +891,8 @@ export async function runPaths(options) {
840
891
  }
841
892
  });
842
893
  function publish() {
843
- writeRun(runDir, options, options.paths, new Map([...outcomes, ...activeOutcomes]), runInfo(false));
894
+ const snapshot = writeRun(runDir, options, options.paths, new Map([...outcomes, ...activeOutcomes]), runInfo(false));
895
+ options.onProgress?.(snapshot);
844
896
  }
845
897
  const history = durationHistory(options.outputRoot);
846
898
  const cost = (p) => history[p.key] ?? estimateMs(p);
@@ -848,7 +900,7 @@ export async function runPaths(options) {
848
900
  if (reused.size)
849
901
  log(`Reusing ${reused.size} passed path(s) from ${path.basename(options.reuse.runDir)}`);
850
902
  log(`Running ${queue.length} path(s) on ${workers} worker(s)`);
851
- writeRun(runDir, options, options.paths, outcomes, runInfo(false));
903
+ options.onProgress?.(writeRun(runDir, options, options.paths, outcomes, runInfo(false)));
852
904
  // A driver can throw outside any awaited call (a message for a context that just closed); it
853
905
  // belongs to one attempt, so it is logged and the run goes on instead of the process dying.
854
906
  const stray = (error) => log(` (ignored an error thrown outside any step: ${(error instanceof Error ? error.message : String(error)).split('\n')[0]})`);
@@ -873,5 +925,6 @@ export async function runPaths(options) {
873
925
  await driver.dispose?.();
874
926
  await Promise.all(sources.map((s) => s.close?.()));
875
927
  const manifest = writeRun(runDir, options, options.paths, outcomes, runInfo(true));
928
+ options.onProgress?.(manifest);
876
929
  return { runDir, manifest, ok: manifest.privacy.passed && manifest.paths.every((r) => r.status !== 'failed') };
877
930
  }
@@ -1,4 +1,5 @@
1
1
  import type { Clip } from './types.js';
2
+ /** Options for `recordFrames`. */
2
3
  export type FrameRecorderOptions = {
3
4
  /** The image format `capture` returns (default png). */
4
5
  extension?: 'png' | 'jpg';
@@ -6,10 +7,18 @@ export type FrameRecorderOptions = {
6
7
  maxFps?: number;
7
8
  };
8
9
  /**
9
- * Record a clip from any driver that can take a screenshot: capture frames back to back while the
10
- * step runs, then encode them with FFmpeg as H.264 MP4 at their real timing. Drivers without a
11
- * native screen recorder (Bun WebView, WebDriver) use it; it needs `ffmpeg` on the PATH and
12
- * returns no clip without it.
10
+ * Starts recording a clip from any driver that can take a screenshot: capture frames back to back
11
+ * while the step runs, then encode them with FFmpeg as H.264 MP4 at their real timing. Drivers
12
+ * without a native screen recorder (Bun WebView, WebDriver) use it; it needs `ffmpeg` on the PATH.
13
+ *
14
+ * Capturing starts immediately and continues until `stop` is called. A `capture` that throws or
15
+ * returns no bytes just skips that frame. The returned `stop(output)` ends capture, writes the MP4 to
16
+ * `output` and resolves to the clip (`durationMs` is wall-clock time since the call), or to `null`
17
+ * when no frame was captured or FFmpeg is missing or fails. It writes no poster. Frames and the
18
+ * FFmpeg frame list are left in `workDirectory`.
19
+ *
20
+ * @param capture returns one screenshot as encoded image bytes in `options.extension`'s format.
21
+ * @param workDirectory where the frames are written; created if missing.
13
22
  */
14
23
  export declare function recordFrames(capture: () => Promise<Uint8Array>, workDirectory: string, options?: FrameRecorderOptions): Promise<{
15
24
  stop(output: string): Promise<Clip | null>;
@@ -1,11 +1,26 @@
1
+ /**
2
+ * @module Frame-based clip recorder
3
+ *
4
+ * Builds a video clip for drivers that can only take screenshots: frames are captured repeatedly while
5
+ * a step runs and encoded afterwards with FFmpeg at their real timing. It owns no driver logic; the
6
+ * caller supplies the capture function. A missing or failing `ffmpeg` produces no clip, never an error.
7
+ */
1
8
  import { spawnSync } from 'node:child_process';
2
9
  import { mkdirSync, writeFileSync } from 'node:fs';
3
10
  import path from 'node:path';
4
11
  /**
5
- * Record a clip from any driver that can take a screenshot: capture frames back to back while the
6
- * step runs, then encode them with FFmpeg as H.264 MP4 at their real timing. Drivers without a
7
- * native screen recorder (Bun WebView, WebDriver) use it; it needs `ffmpeg` on the PATH and
8
- * returns no clip without it.
12
+ * Starts recording a clip from any driver that can take a screenshot: capture frames back to back
13
+ * while the step runs, then encode them with FFmpeg as H.264 MP4 at their real timing. Drivers
14
+ * without a native screen recorder (Bun WebView, WebDriver) use it; it needs `ffmpeg` on the PATH.
15
+ *
16
+ * Capturing starts immediately and continues until `stop` is called. A `capture` that throws or
17
+ * returns no bytes just skips that frame. The returned `stop(output)` ends capture, writes the MP4 to
18
+ * `output` and resolves to the clip (`durationMs` is wall-clock time since the call), or to `null`
19
+ * when no frame was captured or FFmpeg is missing or fails. It writes no poster. Frames and the
20
+ * FFmpeg frame list are left in `workDirectory`.
21
+ *
22
+ * @param capture returns one screenshot as encoded image bytes in `options.extension`'s format.
23
+ * @param workDirectory where the frames are written; created if missing.
9
24
  */
10
25
  export async function recordFrames(capture, workDirectory, options = {}) {
11
26
  mkdirSync(workDirectory, { recursive: true });
@@ -1,23 +1,40 @@
1
+ /**
2
+ * @module HTTP driver
3
+ *
4
+ * A driver (and a bare client) for acting on or observing a system over HTTP, with no browser or
5
+ * device: a fetch with a base URL, a cookie jar and timeline logging. It is the fastest driver and
6
+ * runs any number of attempts side by side, each with its own cookie jar. Uses the global `fetch`.
7
+ */
1
8
  import type { Driver, Timeline } from './types.js';
9
+ /** The response of an `HttpClient` call; the body is read in full. */
2
10
  export type HttpResponse = {
3
11
  status: number;
12
+ /** True for a 2xx status. A non-2xx status does not throw. */
4
13
  ok: boolean;
5
14
  headers: Headers;
15
+ /** The body as text. */
6
16
  text: string;
17
+ /** The body parsed as JSON when the content type is JSON and it parses; `null` otherwise (also for a literal JSON `null`). */
7
18
  json: unknown;
8
19
  };
20
+ /** Per-call options of an `HttpClient`. */
9
21
  export type HttpRequestOptions = {
22
+ /** A string is sent as is; anything else is sent as JSON with a `content-type: application/json` header. */
10
23
  body?: unknown;
24
+ /** Added to the client's headers for this call and overriding them (and the cookie header) on conflict. */
11
25
  headers?: Record<string, string>;
12
26
  /** What the timeline says this call was for; `METHOD /path` when omitted. */
13
27
  label?: string;
14
28
  };
15
29
  /** What every event and recogniser receives from an HTTP client: a fetch with a base URL and a cookie jar. */
16
30
  export type HttpClient = {
31
+ /** The URL that request paths are resolved against with `new URL(path, baseUrl)`: a path starting with `/` replaces any path in the base URL. */
17
32
  baseUrl: string;
18
33
  /** Sent with every request; set an `authorization` header here after signing in. */
19
34
  headers: Record<string, string>;
35
+ /** Cookie name to value, stored from `Set-Cookie` responses and sent back on every request. Only the name and value are kept (no expiry, path or domain handling). */
20
36
  cookies: Map<string, string>;
37
+ /** Sends a request. Rejects on a network error or timeout; resolves for any HTTP status. Each call adds a `system` entry (method, path, status, never bodies) to the timeline. */
21
38
  request(method: string, path: string, options?: HttpRequestOptions): Promise<HttpResponse>;
22
39
  get(path: string, options?: HttpRequestOptions): Promise<HttpResponse>;
23
40
  post(path: string, body?: unknown, options?: HttpRequestOptions): Promise<HttpResponse>;
@@ -25,17 +42,33 @@ export type HttpClient = {
25
42
  patch(path: string, body?: unknown, options?: HttpRequestOptions): Promise<HttpResponse>;
26
43
  delete(path: string, options?: HttpRequestOptions): Promise<HttpResponse>;
27
44
  };
45
+ /** Options for `httpDriver` and `httpClient`. */
28
46
  export type HttpDriverOptions = {
47
+ /** The driver's name and the `source` recorded on timeline entries; `http` when omitted. */
29
48
  name?: string;
49
+ /** Headers sent with every request. */
30
50
  headers?: Record<string, string>;
31
51
  /** Per request, in milliseconds (default 30 000). */
32
52
  timeoutMs?: number;
33
53
  };
54
+ /**
55
+ * Creates an `HttpClient` that logs each call to `timeline`. Use it directly when you need a client
56
+ * outside a driver; `httpDriver` creates one per path attempt.
57
+ *
58
+ * @param baseUrl the URL request paths are resolved against.
59
+ */
34
60
  export declare function httpClient(baseUrl: string, timeline: Timeline, options?: HttpDriverOptions): HttpClient;
35
61
  /**
36
62
  * The fastest driver: a client of an HTTP API, with no browser or device. Use it for actors that
37
63
  * only talk to the system (a partner webhook, an operator API, a back office job) or to drive a
38
64
  * whole chart at the API level. Each path attempt gets a fresh cookie jar; every call is logged to
39
- * the step's timeline (method, path, status; never bodies).
65
+ * the step's timeline (method, path, status; never bodies). Has no screenshots or clips, and no limit on
66
+ * concurrent attempts.
67
+ *
68
+ * @param baseUrl the API's base URL, or a function returning it (called for each attempt).
69
+ *
70
+ * @example
71
+ * const driver = httpDriver('http://127.0.0.1:4000', { headers: { 'x-test': '1' } });
72
+ * // events then receive an HttpClient: run: (api) => api.post('/orders', { sku: 'A1' })
40
73
  */
41
74
  export declare function httpDriver(baseUrl: string | (() => string | Promise<string>), options?: HttpDriverOptions): Driver<HttpClient>;
@@ -8,6 +8,12 @@ function parseBody(text, contentType) {
8
8
  return null;
9
9
  }
10
10
  }
11
+ /**
12
+ * Creates an `HttpClient` that logs each call to `timeline`. Use it directly when you need a client
13
+ * outside a driver; `httpDriver` creates one per path attempt.
14
+ *
15
+ * @param baseUrl the URL request paths are resolved against.
16
+ */
11
17
  export function httpClient(baseUrl, timeline, options = {}) {
12
18
  const source = options.name ?? 'http';
13
19
  const client = {
@@ -55,7 +61,14 @@ export function httpClient(baseUrl, timeline, options = {}) {
55
61
  * The fastest driver: a client of an HTTP API, with no browser or device. Use it for actors that
56
62
  * only talk to the system (a partner webhook, an operator API, a back office job) or to drive a
57
63
  * whole chart at the API level. Each path attempt gets a fresh cookie jar; every call is logged to
58
- * the step's timeline (method, path, status; never bodies).
64
+ * the step's timeline (method, path, status; never bodies). Has no screenshots or clips, and no limit on
65
+ * concurrent attempts.
66
+ *
67
+ * @param baseUrl the API's base URL, or a function returning it (called for each attempt).
68
+ *
69
+ * @example
70
+ * const driver = httpDriver('http://127.0.0.1:4000', { headers: { 'x-test': '1' } });
71
+ * // events then receive an HttpClient: run: (api) => api.post('/orders', { sku: 'A1' })
59
72
  */
60
73
  export function httpDriver(baseUrl, options = {}) {
61
74
  return {
@@ -1,29 +1,56 @@
1
+ /**
2
+ * @module Run types and function driver
3
+ *
4
+ * The contracts between a run and the things it drives: `Driver` (owns the system under test for one
5
+ * path attempt), `Implementation` (how each event is made to happen and each state recognised), `Seed`,
6
+ * event sources and privacy rules, plus the status vocabulary and `Timeline`. These shapes are what
7
+ * integrators write against, so they change only by adding optional fields. Also holds
8
+ * `functionDriver`, the simplest complete driver.
9
+ *
10
+ * @see docs/statecharts.md
11
+ */
1
12
  import type { CloudEvent } from '../events/cloudevents.js';
2
13
  import type { StateValue } from '../graph.js';
3
14
  import type { PlannedPath } from '../plan.js';
15
+ /** `fast` runs without pacing and takes screenshots only; `showcase` paces steps like a person and records a clip of every transition. */
4
16
  export type RunMode = 'fast' | 'showcase';
17
+ /** The result of a path, state, transition or journey: `flaky` passed only on the retry; `not-reached` was never run, was blocked, or has no covering path. */
5
18
  export type Status = 'passed' | 'failed' | 'flaky' | 'not-reached';
19
+ /** Who or what makes an event happen: a `user` action, a `system` call, the passing of `time`, or a `hand-off` from a child chart (inserted by the planner, usually a no-op). */
6
20
  export type EventKind = 'user' | 'system' | 'time' | 'hand-off';
7
21
  /** `client` names which client's screen it is in a multi-client run; `also` holds the other clients' screens at the same moment. */
8
22
  export type Image = {
23
+ /** Path to the PNG. A driver returns an absolute path; in a manifest it is relative to the run directory. */
9
24
  png: string;
25
+ /** Path to a WebP thumbnail, when one was made. */
10
26
  webp?: string;
11
27
  client?: string;
12
28
  also?: Image[];
13
29
  };
30
+ /** A recorded video of one transition. */
14
31
  export type Clip = {
32
+ /** Path to the MP4 (relative to the run directory in a manifest). */
15
33
  video: string;
34
+ /** Path to a poster image, when one was made. */
16
35
  poster?: string;
17
36
  durationMs: number;
37
+ /** The client whose screen was recorded, in a multi-client run. */
18
38
  client?: string;
19
39
  };
40
+ /** One thing that happened during a step, which becomes a caption on the step's clip. */
20
41
  export type TimelineEntry = {
42
+ /** Milliseconds since the step began (see `Timeline.restart`). */
21
43
  atMs: number;
44
+ /** What kind of thing happened. */
22
45
  kind: 'tap' | 'type' | 'system' | 'screen' | 'toast' | 'note' | 'time' | 'notification';
46
+ /** The caption. */
23
47
  label: string;
48
+ /** For a tap, where it landed (page pixels for the Playwright driver). */
24
49
  x?: number;
25
50
  y?: number;
51
+ /** For typing, what was typed; shown in the caption. */
26
52
  text?: string;
53
+ /** For a system call, what it was (never bodies). */
27
54
  system?: {
28
55
  source?: string;
29
56
  endpoint?: string;
@@ -40,26 +67,37 @@ type TimelineState = {
40
67
  };
41
68
  /**
42
69
  * What a step records while it runs: taps, typing, system calls, the screen change. `for(client)`
43
- * returns a view onto the same timeline that tags every entry with that client.
70
+ * returns a view onto the same timeline that tags every entry with that client. The runner restarts
71
+ * it at the start of every step, so entries are relative to the step they belong to.
44
72
  */
45
73
  export declare class Timeline {
46
74
  private readonly state;
75
+ /** The client this view tags entries with; `undefined` on the root timeline. */
47
76
  readonly client: string | undefined;
48
77
  constructor(state?: TimelineState, client?: string);
78
+ /** Every entry added since the last `restart`, in order, shared by all views of the timeline. */
49
79
  get entries(): TimelineEntry[];
80
+ /** Clears the entries and makes now the origin for `atMs`. */
50
81
  restart(): void;
82
+ /** Appends an entry stamped with the time since the origin, and with this view's client when it has one. */
51
83
  add(entry: Omit<TimelineEntry, 'atMs'>): void;
84
+ /** A view of the same timeline that tags what it adds with `client`. */
52
85
  for(client: string): Timeline;
53
86
  }
87
+ /** What a state recogniser found. */
54
88
  export type RecognizerResult = {
89
+ /** Whether the state is showing. */
55
90
  matched: boolean;
91
+ /** What was looked at, shown to explain a failure. `expected` is `visible` or `hidden`. */
56
92
  signals: {
57
93
  signal: string;
58
94
  expected: 'visible' | 'hidden' | string;
59
95
  visible: boolean;
60
96
  }[];
61
97
  };
98
+ /** The result of one of a state's `meta.checks`; a failed check fails the state. */
62
99
  export type CheckResult = {
100
+ /** The check statement, quoted from the spec. */
63
101
  check: string;
64
102
  passed: boolean;
65
103
  expected?: string;
@@ -87,7 +125,12 @@ export type Focus = {
87
125
  * required; media hooks are used when present. `combineDrivers` runs several at once.
88
126
  */
89
127
  export type Driver<C> = {
128
+ /** Shown in reports as the driver the run used. */
90
129
  name: string;
130
+ /**
131
+ * Creates a fresh context for one attempt of one path. `attempt` is 1, or 2 for the retry;
132
+ * `directory` is a scratch directory for this attempt; the driver should log what it does to `timeline`.
133
+ */
91
134
  open(input: {
92
135
  path: PlannedPath;
93
136
  attempt: number;
@@ -95,6 +138,10 @@ export type Driver<C> = {
95
138
  directory: string;
96
139
  timeline: Timeline;
97
140
  }): Promise<C>;
141
+ /**
142
+ * Releases the context. `traceFile` is where a trace may be written when `failed`; return the path
143
+ * actually written as `trace` (or one per client as `traces`) to attach it to the report.
144
+ */
98
145
  close(ctx: C, input: {
99
146
  failed: boolean;
100
147
  traceFile: string;
@@ -124,10 +171,12 @@ export type Driver<C> = {
124
171
  * single device is not). Runs use at most this many workers; 1 when omitted.
125
172
  */
126
173
  concurrency?: number;
174
+ /** Releases what is shared by all contexts (a browser, a server); called once after the last path. */
127
175
  dispose?(): Promise<void>;
128
176
  };
129
177
  /** How one event is made to happen. Keyed by the event's exact name in the spec. */
130
178
  export type EventImplementation<C> = {
179
+ /** Who makes the event happen; recorded with the event in the manifest. */
131
180
  kind: EventKind;
132
181
  /** The client that does it, in a multi-client run: its screen is recorded for the clip. */
133
182
  client?: string;
@@ -135,12 +184,14 @@ export type EventImplementation<C> = {
135
184
  how: string;
136
185
  /** Test data the event needs before the path starts (a condition modelled as an event). */
137
186
  prepare?(ctx: C, tools: StepTools): Promise<void>;
187
+ /** Makes the event happen. The runner then waits for the target state to be recognised, so `run` does not need to wait for it; it should throw only when the event cannot be done. */
138
188
  run(ctx: C, tools: StepTools): Promise<void>;
139
189
  /** Set when the event cannot be triggered reliably yet: the path stops before it. */
140
190
  blocked?: string;
141
191
  };
142
192
  /** How one state is recognised from the outside, and what is checked there. */
143
193
  export type StateImplementation<C> = {
194
+ /** Looks at the system from the outside and says whether the state is showing. Called repeatedly (with growing pauses, until `stepTimeoutMs`) while the runner waits for the state, so it must be cheap and side-effect free. */
144
195
  recognize(ctx: C): Promise<RecognizerResult>;
145
196
  /** The client whose screen shows it, in a multi-client run: that screen is the screenshot. */
146
197
  client?: string;
@@ -152,6 +203,7 @@ export type StateImplementation<C> = {
152
203
  lookIn?(ctx: C): Promise<void>;
153
204
  /** Within-state actions after the screenshot (dismiss a success message). */
154
205
  settle?(ctx: C): Promise<void>;
206
+ /** Results for the state's `meta.checks`, evaluated once the state is recognised. */
155
207
  checks?(ctx: C): Promise<CheckResult[]>;
156
208
  };
157
209
  /**
@@ -184,8 +236,15 @@ export type Seed<C> = {
184
236
  /** Set when the configuration cannot be seeded yet: paths start from another seed. */
185
237
  blocked?: string;
186
238
  };
239
+ /**
240
+ * How a driver makes each event of the spec happen and recognises each state: everything the charts
241
+ * do not say. Events and states are keyed by their exact names in the spec; only leaf states need a
242
+ * recogniser.
243
+ */
187
244
  export type Implementation<C> = {
245
+ /** By event name; an event with no entry is reported as blocked. */
188
246
  events: Record<string, EventImplementation<C>>;
247
+ /** By state name; only leaf states need one. */
189
248
  states: Record<string, StateImplementation<C>>;
190
249
  /**
191
250
  * Named seeds: configurations paths can start from. Journeys are cut at every seeded
@@ -207,13 +266,16 @@ export type Implementation<C> = {
207
266
  };
208
267
  /** Where business events come from: a CloudEvents endpoint, a log, a message queue. */
209
268
  export type EventSource = {
269
+ /** Identifies the source; a name starting with `log:` marks a log file, anything else counts as a CloudEvents source. */
210
270
  name: string;
211
271
  /** Where "now" is in the source; `collect` returns what arrived after this mark. */
212
272
  mark(): unknown;
273
+ /** Returns what arrived since `mark` (everything when omitted): CloudEvents and/or raw log text. */
213
274
  collect(mark?: unknown): Promise<{
214
275
  events: CloudEvent[];
215
276
  text?: string;
216
277
  }>;
278
+ /** Releases the source; called when the run ends. */
217
279
  close?(): Promise<void>;
218
280
  };
219
281
  /** How a business event named in `meta.events` is recognised in what a source collected. */
@@ -222,6 +284,7 @@ export type EventMatcher = {
222
284
  } | {
223
285
  pattern: RegExp;
224
286
  } | ((events: CloudEvent[], text: string) => boolean);
287
+ /** Rules for what may appear on screen and in a manifest. They extend the defaults (see `DEFAULT_PRIVACY`) except `allowHosts`, which replaces them. */
225
288
  export type PrivacyRules = {
226
289
  /** Patterns that must never appear on screen or in a manifest. */
227
290
  deny?: {
@@ -234,8 +297,18 @@ export type PrivacyRules = {
234
297
  allowHosts?: string[];
235
298
  };
236
299
  /**
237
- * A driver for anything you can reach from Node: a domain model, an API client, a CLI. `create`
238
- * returns a fresh context per path attempt; recognisers and events work on it directly.
300
+ * A driver for anything you can reach from code: a domain model, an API client, a CLI. `create`
301
+ * returns a fresh context per path attempt; recognisers and events work on it directly. It takes
302
+ * no screenshots or clips, and any number of attempts can run side by side unless `concurrency` says otherwise.
303
+ *
304
+ * @param create builds the context for one attempt; it may be async.
305
+ * @param options.name the driver's name in reports; `function` when omitted.
306
+ * @param options.dispose called with the context when the attempt ends.
307
+ * @param options.concurrency how many contexts may be open at once; unlimited when omitted.
308
+ * @see docs/statecharts.md
309
+ *
310
+ * @example
311
+ * const driver = functionDriver(() => new TodoModel());
239
312
  */
240
313
  export declare function functionDriver<C>(create: (input: {
241
314
  path: PlannedPath;
@@ -1,31 +1,47 @@
1
1
  /**
2
2
  * What a step records while it runs: taps, typing, system calls, the screen change. `for(client)`
3
- * returns a view onto the same timeline that tags every entry with that client.
3
+ * returns a view onto the same timeline that tags every entry with that client. The runner restarts
4
+ * it at the start of every step, so entries are relative to the step they belong to.
4
5
  */
5
6
  export class Timeline {
6
7
  state;
8
+ /** The client this view tags entries with; `undefined` on the root timeline. */
7
9
  client;
8
10
  constructor(state = { origin: Date.now(), entries: [] }, client) {
9
11
  this.state = state;
10
12
  this.client = client;
11
13
  }
14
+ /** Every entry added since the last `restart`, in order, shared by all views of the timeline. */
12
15
  get entries() {
13
16
  return this.state.entries;
14
17
  }
18
+ /** Clears the entries and makes now the origin for `atMs`. */
15
19
  restart() {
16
20
  this.state.origin = Date.now();
17
21
  this.state.entries = [];
18
22
  }
23
+ /** Appends an entry stamped with the time since the origin, and with this view's client when it has one. */
19
24
  add(entry) {
20
25
  this.state.entries.push({ atMs: Date.now() - this.state.origin, ...(this.client ? { client: this.client } : {}), ...entry });
21
26
  }
27
+ /** A view of the same timeline that tags what it adds with `client`. */
22
28
  for(client) {
23
29
  return new Timeline(this.state, client);
24
30
  }
25
31
  }
26
32
  /**
27
- * A driver for anything you can reach from Node: a domain model, an API client, a CLI. `create`
28
- * returns a fresh context per path attempt; recognisers and events work on it directly.
33
+ * A driver for anything you can reach from code: a domain model, an API client, a CLI. `create`
34
+ * returns a fresh context per path attempt; recognisers and events work on it directly. It takes
35
+ * no screenshots or clips, and any number of attempts can run side by side unless `concurrency` says otherwise.
36
+ *
37
+ * @param create builds the context for one attempt; it may be async.
38
+ * @param options.name the driver's name in reports; `function` when omitted.
39
+ * @param options.dispose called with the context when the attempt ends.
40
+ * @param options.concurrency how many contexts may be open at once; unlimited when omitted.
41
+ * @see docs/statecharts.md
42
+ *
43
+ * @example
44
+ * const driver = functionDriver(() => new TodoModel());
29
45
  */
30
46
  export function functionDriver(create, options = {}) {
31
47
  return {