@crvouga/atlas 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (429) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +178 -604
  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 +30 -1
  9. package/dist/core/src/config.d.ts +70 -4
  10. package/dist/core/src/config.js +62 -3
  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 +69 -16
  30. package/dist/core/src/run/execute.js +67 -16
  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 +83 -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 +40 -4
  94. package/dist/reports/src/evidence-live.js +52 -4
  95. package/dist/reports/src/evidence-types.d.ts +70 -1
  96. package/dist/reports/src/evidence-types.js +5 -1
  97. package/dist/reports/src/evidence-view.d.ts +58 -6
  98. package/dist/reports/src/evidence-view.js +44 -5
  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 +52 -0
  120. package/dist/reports/src/http-store.js +145 -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 +364 -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 +48 -0
  134. package/dist/reports/src/layer-axes.js +71 -0
  135. package/dist/reports/src/layer-catalog.d.ts +28 -1
  136. package/dist/reports/src/layer-catalog.js +19 -2
  137. package/dist/reports/src/layer-merge.d.ts +98 -9
  138. package/dist/reports/src/layer-merge.js +154 -33
  139. package/dist/reports/src/layer-source.d.ts +18 -0
  140. package/dist/reports/src/layer-source.js +14 -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 +34 -1
  144. package/dist/reports/src/layers-route.d.ts +47 -4
  145. package/dist/reports/src/layers-route.js +88 -12
  146. package/dist/reports/src/media-types.d.ts +11 -0
  147. package/dist/reports/src/media-types.js +22 -0
  148. package/dist/reports/src/namespace-guard.d.ts +10 -1
  149. package/dist/reports/src/namespace-guard.js +10 -1
  150. package/dist/reports/src/navigation.d.ts +12 -0
  151. package/dist/reports/src/navigation.js +7 -0
  152. package/dist/reports/src/object-io.d.ts +11 -4
  153. package/dist/reports/src/object-io.js +4 -4
  154. package/dist/reports/src/object-store-conformance.d.ts +27 -0
  155. package/dist/reports/src/object-store-conformance.js +87 -0
  156. package/dist/reports/src/object-store.d.ts +33 -24
  157. package/dist/reports/src/object-store.js +17 -24
  158. package/dist/reports/src/parse-with.d.ts +16 -0
  159. package/dist/reports/src/parse-with.js +14 -0
  160. package/dist/reports/src/performance-part.d.ts +25 -1
  161. package/dist/reports/src/performance-part.js +15 -1
  162. package/dist/reports/src/performance.d.ts +22 -2
  163. package/dist/reports/src/performance.js +12 -2
  164. package/dist/reports/src/persist.d.ts +12 -3
  165. package/dist/reports/src/persist.js +12 -3
  166. package/dist/reports/src/phone.d.ts +18 -1
  167. package/dist/reports/src/phone.js +18 -1
  168. package/dist/reports/src/protocol.d.ts +30 -4
  169. package/dist/reports/src/protocol.js +15 -4
  170. package/dist/reports/src/publication.d.ts +21 -1
  171. package/dist/reports/src/publication.js +21 -1
  172. package/dist/reports/src/publish-checks.d.ts +35 -0
  173. package/dist/reports/src/publish-checks.js +122 -0
  174. package/dist/reports/src/publish.d.ts +44 -9
  175. package/dist/reports/src/publish.js +40 -7
  176. package/dist/reports/src/read.d.ts +46 -16
  177. package/dist/reports/src/read.js +38 -14
  178. package/dist/reports/src/recording-bundle.d.ts +13 -2
  179. package/dist/reports/src/recording-bundle.js +4 -2
  180. package/dist/reports/src/recording-keys.d.ts +15 -1
  181. package/dist/reports/src/recording-keys.js +15 -1
  182. package/dist/reports/src/remote-report.d.ts +28 -7
  183. package/dist/reports/src/remote-report.js +15 -7
  184. package/dist/reports/src/report-cli.d.ts +51 -0
  185. package/dist/reports/src/report-cli.js +485 -0
  186. package/dist/reports/src/report-index.d.ts +99 -0
  187. package/dist/reports/src/report-index.js +337 -0
  188. package/dist/reports/src/report-loader.d.ts +10 -0
  189. package/dist/reports/src/report-loader.js +6 -0
  190. package/dist/reports/src/report-parts.d.ts +29 -3
  191. package/dist/reports/src/report-parts.js +40 -3
  192. package/dist/reports/src/report-status.d.ts +48 -0
  193. package/dist/reports/src/report-status.js +156 -0
  194. package/dist/reports/src/report-types.d.ts +73 -0
  195. package/dist/reports/src/report-types.js +3 -0
  196. package/dist/reports/src/reporter.d.ts +67 -0
  197. package/dist/reports/src/reporter.js +128 -0
  198. package/dist/reports/src/reports-explorer-route.d.ts +541 -0
  199. package/dist/reports/src/reports-explorer-route.js +11 -0
  200. package/dist/reports/src/reports-list-route.d.ts +9 -0
  201. package/dist/reports/src/reports-list-route.js +9 -0
  202. package/dist/reports/src/reports-route.d.ts +561 -22
  203. package/dist/reports/src/reports-route.js +11 -3
  204. package/dist/reports/src/reports-store.d.ts +19 -2
  205. package/dist/reports/src/reports-store.js +10 -2
  206. package/dist/reports/src/resilient-cache.d.ts +14 -1
  207. package/dist/reports/src/resilient-cache.js +8 -1
  208. package/dist/reports/src/retention.d.ts +17 -1
  209. package/dist/reports/src/retention.js +5 -1
  210. package/dist/reports/src/run-bundle.d.ts +63 -0
  211. package/dist/reports/src/run-bundle.js +159 -0
  212. package/dist/reports/src/s3-store.d.ts +79 -0
  213. package/dist/reports/src/s3-store.js +295 -0
  214. package/dist/reports/src/scenario.d.ts +14 -4
  215. package/dist/reports/src/scenario.js +5 -4
  216. package/dist/reports/src/sigv4.d.ts +72 -0
  217. package/dist/reports/src/sigv4.js +96 -0
  218. package/dist/reports/src/snapshot-bundle.d.ts +24 -1
  219. package/dist/reports/src/snapshot-bundle.js +27 -2
  220. package/dist/reports/src/snapshot-surface.d.ts +20 -9
  221. package/dist/reports/src/snapshot-surface.js +32 -19
  222. package/dist/reports/src/source-content.d.ts +23 -0
  223. package/dist/reports/src/source-content.js +30 -1
  224. package/dist/reports/src/source-entries.d.ts +13 -0
  225. package/dist/reports/src/source-entries.js +6 -0
  226. package/dist/reports/src/source-part.d.ts +15 -0
  227. package/dist/reports/src/source-part.js +8 -0
  228. package/dist/reports/src/source-reader.d.ts +11 -0
  229. package/dist/reports/src/source-reader.js +5 -0
  230. package/dist/reports/src/spec-evidence.d.ts +12 -2
  231. package/dist/reports/src/spec-evidence.js +6 -2
  232. package/dist/reports/src/spec-inventory.d.ts +15 -1
  233. package/dist/reports/src/spec-inventory.js +22 -1
  234. package/dist/reports/src/spec-link.d.ts +28 -0
  235. package/dist/reports/src/spec-link.js +70 -0
  236. package/dist/reports/src/spec-set.d.ts +63 -0
  237. package/dist/reports/src/spec-set.js +177 -0
  238. package/dist/reports/src/status.d.ts +10 -0
  239. package/dist/reports/src/status.js +5 -0
  240. package/dist/reports/src/store-prefix.d.ts +28 -0
  241. package/dist/reports/src/store-prefix.js +22 -0
  242. package/dist/reports/src/store-url.d.ts +89 -0
  243. package/dist/reports/src/store-url.js +160 -0
  244. package/dist/reports/src/test-catalog-entity.d.ts +11 -0
  245. package/dist/reports/src/test-catalog-entity.js +6 -0
  246. package/dist/reports/src/types.d.ts +6 -1
  247. package/dist/reports/src/use-report-nav.d.ts +35 -0
  248. package/dist/reports/src/use-report-nav.js +12 -0
  249. package/dist/schema/src/api.d.ts +799 -0
  250. package/dist/schema/src/api.js +201 -0
  251. package/dist/schema/src/cli-results.d.ts +210 -0
  252. package/dist/schema/src/cli-results.js +124 -0
  253. package/dist/schema/src/common.d.ts +53 -0
  254. package/dist/schema/src/common.js +42 -0
  255. package/dist/schema/src/index.d.ts +14 -0
  256. package/dist/schema/src/index.js +14 -0
  257. package/dist/schema/src/layer.d.ts +2273 -0
  258. package/dist/schema/src/layer.js +462 -0
  259. package/dist/schema/src/manifest.d.ts +95 -0
  260. package/dist/schema/src/manifest.js +84 -0
  261. package/dist/schema/src/report-sources.d.ts +28 -0
  262. package/dist/schema/src/report-sources.js +25 -0
  263. package/dist/schema/src/runs-index.d.ts +16 -0
  264. package/dist/schema/src/runs-index.js +15 -0
  265. package/dist/schema/src/server-config.d.ts +93 -0
  266. package/dist/schema/src/server-config.js +73 -0
  267. package/dist/schema/src/spec.d.ts +69 -0
  268. package/dist/schema/src/spec.js +58 -0
  269. package/dist/server/src/app.d.ts +62 -0
  270. package/dist/server/src/app.js +419 -0
  271. package/dist/server/src/auth.d.ts +41 -0
  272. package/dist/server/src/auth.js +59 -0
  273. package/dist/server/src/config.d.ts +83 -0
  274. package/dist/server/src/config.js +187 -0
  275. package/dist/server/src/dev.d.ts +12 -0
  276. package/dist/server/src/dev.js +80 -0
  277. package/dist/server/src/events.d.ts +29 -0
  278. package/dist/server/src/events.js +101 -0
  279. package/dist/server/src/host.d.ts +30 -0
  280. package/dist/server/src/host.js +115 -0
  281. package/dist/server/src/index.d.ts +16 -0
  282. package/dist/server/src/index.js +16 -0
  283. package/dist/server/src/llms.d.ts +19 -0
  284. package/dist/server/src/llms.js +63 -0
  285. package/dist/server/src/main.d.ts +30 -0
  286. package/dist/server/src/main.js +112 -0
  287. package/dist/server/src/openapi.d.ts +59 -0
  288. package/dist/server/src/openapi.js +374 -0
  289. package/dist/server/src/problem.d.ts +8 -0
  290. package/dist/server/src/problem.js +39 -0
  291. package/dist/server/src/site.d.ts +13 -0
  292. package/dist/server/src/site.js +43 -0
  293. package/dist/server/src/store-api.d.ts +28 -0
  294. package/dist/server/src/store-api.js +159 -0
  295. package/dist/server/src/validate.d.ts +71 -0
  296. package/dist/server/src/validate.js +197 -0
  297. package/dist/vitest/src/index.d.ts +27 -5
  298. package/dist/vitest/src/index.js +18 -5
  299. package/dist/webdriver/src/driver.d.ts +63 -11
  300. package/dist/webdriver/src/driver.js +57 -6
  301. package/dist/webdriver/src/index.d.ts +8 -0
  302. package/dist/webdriver/src/index.js +1 -0
  303. package/dist/webdriver/src/protocol.d.ts +75 -6
  304. package/dist/webdriver/src/protocol.js +79 -6
  305. package/docs/agents.md +137 -0
  306. package/docs/deploying.md +345 -0
  307. package/docs/dogfooding.md +175 -0
  308. package/docs/extending.md +242 -0
  309. package/docs/integrating.md +485 -0
  310. package/docs/reference/bun.md +141 -0
  311. package/docs/reference/cli.md +146 -0
  312. package/docs/reference/core.md +2426 -0
  313. package/docs/reference/detox.md +150 -0
  314. package/docs/reference/http-api.md +303 -0
  315. package/docs/reference/playwright.md +303 -0
  316. package/docs/reference/reports.md +7098 -0
  317. package/docs/reference/schema.md +1651 -0
  318. package/docs/reference/server.md +685 -0
  319. package/docs/reference/vitest.md +45 -0
  320. package/docs/reference/webdriver.md +330 -0
  321. package/docs/report-backends.md +144 -0
  322. package/docs/report-contract.md +400 -0
  323. package/docs/reporting-issues.md +160 -0
  324. package/docs/server.md +285 -0
  325. package/docs/statecharts.md +641 -0
  326. package/llms-full.txt +3506 -0
  327. package/llms.txt +47 -0
  328. package/package.json +33 -5
  329. package/packages/core/README.md +2 -1
  330. package/packages/reports/README.md +69 -2
  331. package/packages/reports/STORAGE.md +5 -1
  332. package/packages/schema/README.md +14 -0
  333. package/packages/schema/schemas/check-detail.schema.json +1032 -0
  334. package/packages/schema/schemas/checks-result.schema.json +26 -0
  335. package/packages/schema/schemas/command-error.schema.json +35 -0
  336. package/packages/schema/schemas/doctor-result.schema.json +60 -0
  337. package/packages/schema/schemas/effective-delta.schema.json +490 -0
  338. package/packages/schema/schemas/effective-evidence.schema.json +471 -0
  339. package/packages/schema/schemas/evidence-page.schema.json +271 -0
  340. package/packages/schema/schemas/hello-event.schema.json +22 -0
  341. package/packages/schema/schemas/init-plan.schema.json +347 -0
  342. package/packages/schema/schemas/layer-rows.schema.json +199 -0
  343. package/packages/schema/schemas/layer.schema.json +2888 -0
  344. package/packages/schema/schemas/merge-result.schema.json +40 -0
  345. package/packages/schema/schemas/outline.schema.json +62 -0
  346. package/packages/schema/schemas/problem.schema.json +37 -0
  347. package/packages/schema/schemas/publish-checks.schema.json +1413 -0
  348. package/packages/schema/schemas/publish-result.schema.json +168 -0
  349. package/packages/schema/schemas/ready.schema.json +68 -0
  350. package/packages/schema/schemas/report-event.schema.json +100 -0
  351. package/packages/schema/schemas/report-status.schema.json +370 -0
  352. package/packages/schema/schemas/server-config.schema.json +194 -0
  353. package/packages/schema/schemas/server-info.schema.json +114 -0
  354. package/packages/schema/schemas/spec-set.schema.json +103 -0
  355. package/packages/schema/schemas/store-listing.schema.json +29 -0
  356. package/packages/schema/schemas/store-write-result.schema.json +28 -0
  357. package/packages/schema/schemas/stream-result.schema.json +59 -0
  358. package/packages/server/README.md +43 -0
  359. package/packages/server/openapi.json +6699 -0
  360. package/packages/visualizer/README.md +27 -5
  361. package/packages/visualizer/example/specs/coffee/ordering/cart.qnt +7 -0
  362. package/packages/visualizer/example/specs/coffee/ordering/checkout.openslo.yaml +10 -0
  363. package/packages/visualizer/example/specs/coffee/ordering/drink-price.dmn +24 -0
  364. package/packages/visualizer/example/specs/coffee/ordering/loyalty.feature +7 -0
  365. package/packages/visualizer/example/specs/coffee/ordering/ordering.feature +36 -0
  366. package/packages/visualizer/example/specs/coffee/ordering/payment.als +4 -0
  367. package/packages/visualizer/fixtures/failures/specs/coffee/ordering/cart.qnt +7 -0
  368. package/packages/visualizer/fixtures/failures/specs/coffee/ordering/checkout.openslo.yaml +10 -0
  369. package/packages/visualizer/fixtures/failures/specs/coffee/ordering/drink-price.dmn +24 -0
  370. package/packages/visualizer/fixtures/failures/specs/coffee/ordering/loyalty.feature +7 -0
  371. package/packages/visualizer/fixtures/failures/specs/coffee/ordering/ordering.feature +36 -0
  372. package/packages/visualizer/fixtures/failures/specs/coffee/ordering/payment.als +4 -0
  373. package/packages/visualizer/fixtures/full/specs/coffee/ordering/cart.qnt +7 -0
  374. package/packages/visualizer/fixtures/full/specs/coffee/ordering/checkout.openslo.yaml +10 -0
  375. package/packages/visualizer/fixtures/full/specs/coffee/ordering/drink-price.dmn +24 -0
  376. package/packages/visualizer/fixtures/full/specs/coffee/ordering/loyalty.feature +7 -0
  377. package/packages/visualizer/fixtures/full/specs/coffee/ordering/ordering.feature +36 -0
  378. package/packages/visualizer/fixtures/full/specs/coffee/ordering/payment.als +4 -0
  379. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/cart.qnt +7 -0
  380. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/checkout.openslo.yaml +10 -0
  381. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/drink-price.dmn +24 -0
  382. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/loyalty.feature +7 -0
  383. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/ordering.feature +36 -0
  384. package/packages/visualizer/fixtures/malformed/specs/coffee/ordering/payment.als +4 -0
  385. package/packages/visualizer/fixtures/partial/specs/coffee/ordering/cart.qnt +7 -0
  386. package/packages/visualizer/fixtures/partial/specs/coffee/ordering/checkout.openslo.yaml +10 -0
  387. package/packages/visualizer/fixtures/partial/specs/coffee/ordering/drink-price.dmn +24 -0
  388. package/packages/visualizer/fixtures/partial/specs/coffee/ordering/loyalty.feature +7 -0
  389. package/packages/visualizer/fixtures/partial/specs/coffee/ordering/ordering.feature +36 -0
  390. package/packages/visualizer/fixtures/partial/specs/coffee/ordering/payment.als +4 -0
  391. package/packages/visualizer/fixtures/removed/specs/coffee/ordering/cart.qnt +7 -0
  392. package/packages/visualizer/fixtures/removed/specs/coffee/ordering/checkout.openslo.yaml +10 -0
  393. package/packages/visualizer/fixtures/removed/specs/coffee/ordering/drink-price.dmn +24 -0
  394. package/packages/visualizer/fixtures/removed/specs/coffee/ordering/loyalty.feature +7 -0
  395. package/packages/visualizer/fixtures/removed/specs/coffee/ordering/ordering.feature +36 -0
  396. package/packages/visualizer/fixtures/removed/specs/coffee/ordering/payment.als +4 -0
  397. package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/cart.qnt +7 -0
  398. package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/checkout.openslo.yaml +10 -0
  399. package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/drink-price.dmn +24 -0
  400. package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/loyalty.feature +7 -0
  401. package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/ordering.feature +36 -0
  402. package/packages/visualizer/fixtures/spec-only/specs/coffee/ordering/payment.als +4 -0
  403. package/packages/visualizer/scripts/make-fixtures.ts +2 -0
  404. package/packages/visualizer/scripts/publish-data.ts +1 -2
  405. package/packages/visualizer/src/app/AppShell.tsx +9 -2
  406. package/packages/visualizer/src/app/report-sources.tsx +6 -4
  407. package/packages/visualizer/src/app/router.tsx +3 -3
  408. package/packages/visualizer/src/components/Header.module.css +35 -0
  409. package/packages/visualizer/src/components/Header.tsx +41 -4
  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/evidence/api.ts +14 -2
  413. package/packages/visualizer/src/evidence/artifacts.module.css +213 -0
  414. package/packages/visualizer/src/evidence/artifacts.tsx +272 -0
  415. package/packages/visualizer/src/evidence/check-detail.tsx +38 -4
  416. package/packages/visualizer/src/evidence/evidence-context.tsx +74 -12
  417. package/packages/visualizer/src/evidence/evidence.module.css +20 -0
  418. package/packages/visualizer/src/evidence/marks.tsx +2 -0
  419. package/packages/visualizer/src/evidence/overview.tsx +3 -3
  420. package/packages/visualizer/src/evidence/sources-panel.tsx +88 -34
  421. package/packages/visualizer/src/evidence/spec-page.tsx +23 -16
  422. package/packages/visualizer/src/find/Finder.tsx +1 -7
  423. package/packages/visualizer/src/find/open.ts +4 -0
  424. package/packages/visualizer/src/live/live-stream.ts +204 -0
  425. package/packages/visualizer/src/runtime.ts +19 -0
  426. package/packages/visualizer/src/state/ui-store.ts +6 -2
  427. package/packages/visualizer/vite/atlas-server-proxy.ts +36 -0
  428. package/packages/visualizer/vite/example-reports.ts +475 -0
  429. package/packages/visualizer/vite.config.ts +18 -2
@@ -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 {
@@ -1,3 +1,14 @@
1
+ /**
2
+ * @module UI signals
3
+ *
4
+ * A driver-neutral vocabulary for saying what is on screen (`testId`, `role`, `label`, `text`, `css`),
5
+ * and `screen(...)`, which builds a state recogniser from signals. Every UI driver (Playwright, Bun
6
+ * WebView, WebDriver, Detox) resolves the same signals against its own UI tree, so an implementation
7
+ * written with them runs on any of them. Also holds the wire form and the in-page probe used by drivers
8
+ * that evaluate JavaScript in a page. This module is browser-safe and has no driver dependencies.
9
+ *
10
+ * @see docs/statecharts.md
11
+ */
1
12
  import type { StateImplementation } from './run/types.js';
2
13
  /**
3
14
  * A UI signal: something visible (or not) that proves where the app is. Test IDs first, then
@@ -19,35 +30,56 @@ export type Signal = {
19
30
  } | {
20
31
  css: string;
21
32
  };
33
+ /** A signal for the element with this test ID (`data-testid` on the web, the accessibility identifier on native). */
22
34
  export declare const testId: (id: string) => Signal;
35
+ /** A signal for visible text: a string matches as a case-insensitive substring unless `exact`, a RegExp is tested as is. */
23
36
  export declare const text: (value: string | RegExp, options?: {
24
37
  exact?: boolean;
25
38
  }) => Signal;
39
+ /** A signal for an element with an accessibility role (`button`, `heading`, ...), optionally filtered by its accessible name (same matching as `text`). */
26
40
  export declare const role: (r: string, name?: string | RegExp, options?: {
27
41
  exact?: boolean;
28
42
  }) => Signal;
43
+ /** A signal for a form control by its label text. */
29
44
  export declare const label: (value: string | RegExp) => Signal;
45
+ /** A signal for a CSS selector. Web only: the WebDriver and Detox drivers throw for it in native sessions, so prefer the other signals. */
30
46
  export declare const css: (selector: string) => Signal;
47
+ /** Describes a signal in words for recogniser output and failure messages, e.g. `button "Add"`. */
31
48
  export declare function describeSignal(signal: Signal): string;
49
+ /** What a screen looks like, as signals. */
32
50
  export type SignatureSpec<S = Signal> = {
51
+ /** Every one must be visible. */
33
52
  all?: S[];
53
+ /** At least one must be visible (ignored when empty). */
34
54
  any?: S[];
55
+ /** None may be visible. */
35
56
  none?: S[];
36
57
  };
58
+ /** A `SignatureSpec` plus the optional parts of a `StateImplementation`, which are passed through. */
37
59
  export type ScreenSpec<C, S = Signal> = SignatureSpec<S> & {
60
+ /** Each `check` is a statement from the state's `meta.checks`; it passes when its `signal` is visible. */
38
61
  checks?: {
39
62
  check: string;
40
63
  signal: S;
41
64
  }[];
65
+ /** See `StateImplementation.transient`. */
42
66
  transient?: boolean;
67
+ /** See `StateImplementation.sameAs`. */
43
68
  sameAs?: string;
69
+ /** See `StateImplementation.lookIn`. */
44
70
  lookIn?: (ctx: C) => Promise<void>;
71
+ /** See `StateImplementation.settle`. */
45
72
  settle?: (ctx: C) => Promise<void>;
46
73
  };
47
74
  /**
48
- * Build `screen()` for a driver from one question: is this signal visible right now? A state is
49
- * recognised when every `all` is visible, one `any` is visible and no `none` is. Drivers with
50
- * their own locators (WebDriver's) pass their signal type and how to describe it.
75
+ * Builds a `screen()` function for a driver from one question: is this signal visible right now?
76
+ * A state is recognised when every `all` is visible, one `any` is visible and no `none` is; the result
77
+ * lists every signal looked at with whether it was visible, for failure reports. An `isVisible` that
78
+ * rejects counts as not visible. Drivers with their own locators (WebDriver's) pass their signal type
79
+ * and how to describe it.
80
+ *
81
+ * @param isVisible answers whether one signal is visible in the context.
82
+ * @param describe names a signal in words.
51
83
  */
52
84
  export declare function signatureScreen<C, S = Signal>(isVisible: (ctx: C, signal: S) => Promise<boolean>, describe: (signal: S) => string): (spec: ScreenSpec<C, S>) => StateImplementation<C>;
53
85
  /**
@@ -58,14 +90,25 @@ export declare function signatureScreen<C, S = Signal>(isVisible: (ctx: C, signa
58
90
  export type SignalContext = {
59
91
  /** Open a URL (a path resolves against the driver's base URL; a deep link in a native app). */
60
92
  goto(url: string): Promise<void>;
93
+ /** Whether the signal is visible now. */
61
94
  isVisible(signal: Signal): Promise<boolean>;
95
+ /** Actions a person does. Drivers log each to the step's timeline, which becomes the clip's captions. */
62
96
  user: {
97
+ /** Taps or clicks the target; `label` is the caption shown for it. */
63
98
  tap(target: Signal, label: string): Promise<void>;
99
+ /** Types `text` into the target; `label` is the caption shown for it. */
64
100
  type(target: Signal, text: string, label: string): Promise<void>;
65
101
  };
66
102
  };
67
- /** A state recognised from signals on any driver that provides a `SignalContext`. */
103
+ /**
104
+ * Builds a state implementation that is recognised from signals on any driver that provides a
105
+ * `SignalContext`.
106
+ *
107
+ * @example
108
+ * states: { 'No todos': screen({ all: [text('Nothing to do yet')], none: [role('listitem')] }) }
109
+ */
68
110
  export declare const screen: (spec: ScreenSpec<SignalContext, Signal>) => StateImplementation<SignalContext>;
111
+ /** A string or regular expression as JSON. */
69
112
  type WireMatch = {
70
113
  text: string;
71
114
  exact: boolean;
@@ -73,6 +116,7 @@ type WireMatch = {
73
116
  regex: string;
74
117
  flags: string;
75
118
  };
119
+ /** A `Signal` as plain JSON, the form sent to the in-page `DOM_PROBE`. */
76
120
  export type WireSignal = {
77
121
  kind: 'css';
78
122
  selector: string;
@@ -90,7 +134,7 @@ export type WireSignal = {
90
134
  kind: 'text';
91
135
  match: WireMatch;
92
136
  };
93
- /** A signal as JSON, for a probe that runs inside the page. */
137
+ /** Converts a signal to its JSON form for a probe that runs inside the page. */
94
138
  export declare function toWire(signal: Signal): WireSignal;
95
139
  /** Where a probe found a signal: whether it is visible, and the centre of the first visible match in CSS pixels. */
96
140
  export type DomProbeResult = {
@@ -1,8 +1,14 @@
1
+ /** A signal for the element with this test ID (`data-testid` on the web, the accessibility identifier on native). */
1
2
  export const testId = (id) => ({ testId: id });
3
+ /** A signal for visible text: a string matches as a case-insensitive substring unless `exact`, a RegExp is tested as is. */
2
4
  export const text = (value, options = {}) => ({ text: value, ...options });
5
+ /** A signal for an element with an accessibility role (`button`, `heading`, ...), optionally filtered by its accessible name (same matching as `text`). */
3
6
  export const role = (r, name, options = {}) => ({ role: r, ...(name ? { name } : {}), ...options });
7
+ /** A signal for a form control by its label text. */
4
8
  export const label = (value) => ({ label: value });
9
+ /** A signal for a CSS selector. Web only: the WebDriver and Detox drivers throw for it in native sessions, so prefer the other signals. */
5
10
  export const css = (selector) => ({ css: selector });
11
+ /** Describes a signal in words for recogniser output and failure messages, e.g. `button "Add"`. */
6
12
  export function describeSignal(signal) {
7
13
  if ('testId' in signal)
8
14
  return `test ID "${signal.testId}"`;
@@ -15,9 +21,14 @@ export function describeSignal(signal) {
15
21
  return `text ${String(signal.text)}`;
16
22
  }
17
23
  /**
18
- * Build `screen()` for a driver from one question: is this signal visible right now? A state is
19
- * recognised when every `all` is visible, one `any` is visible and no `none` is. Drivers with
20
- * their own locators (WebDriver's) pass their signal type and how to describe it.
24
+ * Builds a `screen()` function for a driver from one question: is this signal visible right now?
25
+ * A state is recognised when every `all` is visible, one `any` is visible and no `none` is; the result
26
+ * lists every signal looked at with whether it was visible, for failure reports. An `isVisible` that
27
+ * rejects counts as not visible. Drivers with their own locators (WebDriver's) pass their signal type
28
+ * and how to describe it.
29
+ *
30
+ * @param isVisible answers whether one signal is visible in the context.
31
+ * @param describe names a signal in words.
21
32
  */
22
33
  export function signatureScreen(isVisible, describe) {
23
34
  const visible = (ctx, signal) => isVisible(ctx, signal).catch(() => false);
@@ -58,10 +69,16 @@ export function signatureScreen(isVisible, describe) {
58
69
  };
59
70
  };
60
71
  }
61
- /** A state recognised from signals on any driver that provides a `SignalContext`. */
72
+ /**
73
+ * Builds a state implementation that is recognised from signals on any driver that provides a
74
+ * `SignalContext`.
75
+ *
76
+ * @example
77
+ * states: { 'No todos': screen({ all: [text('Nothing to do yet')], none: [role('listitem')] }) }
78
+ */
62
79
  export const screen = signatureScreen((ctx, signal) => ctx.isVisible(signal), describeSignal);
63
80
  const wire = (value, exact = false) => typeof value === 'string' ? { text: value, exact } : { regex: value.source, flags: value.flags };
64
- /** A signal as JSON, for a probe that runs inside the page. */
81
+ /** Converts a signal to its JSON form for a probe that runs inside the page. */
65
82
  export function toWire(signal) {
66
83
  if ('testId' in signal)
67
84
  return { kind: 'testId', id: signal.testId };
@@ -1,11 +1,24 @@
1
+ /**
2
+ * @module Static chart composition
3
+ *
4
+ * Flattens a bundle of charts into one machine by inlining each child chart into the state that
5
+ * invokes it, so a plain graph traversal sees the whole product. Pure and deterministic; the input
6
+ * bundle is not modified. State names are global across the composed product (nothing is renamed or
7
+ * namespaced), which is why they must be unique across charts.
8
+ *
9
+ * @see docs/statecharts.md
10
+ */
1
11
  import type { MachineConfig, SpecBundle } from './types.js';
12
+ /** A child chart's final state and the event it passes to the parent, which the planner and replay insert automatically. */
2
13
  export type HandOff = {
3
14
  finalState: string;
4
15
  event: string;
5
16
  parentState: string;
6
17
  childChart: string;
7
18
  };
19
+ /** The result of composing a bundle. */
8
20
  export type Composition = {
21
+ /** The single flattened machine (a deep copy; the bundle is untouched). */
9
22
  machine: MachineConfig;
10
23
  /** Which chart each state came from. */
11
24
  chartOf: Map<string, string>;
@@ -15,7 +28,7 @@ export type Composition = {
15
28
  hosts: Map<string, string>;
16
29
  };
17
30
  /**
18
- * Inline every child chart where its parent invokes it, so XState's graph traversal (which cannot
31
+ * Inlines every child chart where its parent invokes it, so XState's graph traversal (which cannot
19
32
  * enter an invoked actor) walks straight through. Supports:
20
33
  *
21
34
  * - XState `invoke: { src, id, onDone }` and SCXML `<invoke>` + `done.invoke.<id>`;
@@ -24,5 +37,14 @@ export type Composition = {
24
37
  *
25
38
  * A child's final states stay as states (they keep their screenshots and checks) but stop being
26
39
  * final: each takes the parent's transition for its hand-off event.
40
+ *
41
+ * Every state without an `id` gets its own name as `id`. A child's `initial` replaces the host
42
+ * state's `initial`, and the host's transitions that consumed a hand-off event are removed from it.
43
+ *
44
+ * @throws Error when the root chart is not loaded, an invoked chart is not loaded, charts invoke
45
+ * each other in a cycle, or a child's final state has no matching transition (or `onDone`) in the parent.
46
+ *
47
+ * @example
48
+ * const { machine, handOffs } = composeCharts(loadSpecDirectory('./specs'));
27
49
  */
28
50
  export declare function composeCharts(bundle: SpecBundle): Composition;