@storyshelf/core 0.6.2 → 0.8.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 (727) hide show
  1. package/README.md +49 -32
  2. package/dist/adapter/capture-queue.d.mts +44 -4
  3. package/dist/adapter/capture-runner.d.mts +134 -12
  4. package/dist/adapter/capture-runner.mjs +9 -12
  5. package/dist/adapter/database.d.mts +89 -10
  6. package/dist/adapter/database.mjs +4 -3
  7. package/dist/adapter/database.mjs.map +1 -1
  8. package/dist/adapter/design.d.mts +83 -0
  9. package/dist/adapter/design.mjs +27 -0
  10. package/dist/adapter/design.mjs.map +1 -0
  11. package/dist/adapter/email-sender.d.mts +0 -2
  12. package/dist/adapter/metadata.d.mts +3 -12
  13. package/dist/adapter/notifier.d.mts +6 -3
  14. package/dist/adapter/notifier.mjs +5 -1
  15. package/dist/adapter/oauth.d.mts +50 -0
  16. package/dist/adapter/setup.d.mts +4 -7
  17. package/dist/adapter/setup.mjs +3 -3
  18. package/dist/adapter/setup.mjs.map +1 -1
  19. package/dist/adapter/storage.d.mts +1 -3
  20. package/dist/adapter/webhook-events.d.mts +0 -2
  21. package/dist/adapter/webhook-events.mjs +13 -14
  22. package/dist/adapter/webhook-events.mjs.map +1 -1
  23. package/dist/adapters/capture-target-offers.d.mts +26 -0
  24. package/dist/adapters/capture-target-offers.mjs +57 -0
  25. package/dist/adapters/capture-target-offers.mjs.map +1 -0
  26. package/dist/adapters/capture-target.d.mts +69 -0
  27. package/dist/adapters/capture-target.mjs +75 -0
  28. package/dist/adapters/capture-target.mjs.map +1 -0
  29. package/dist/adapters/notifier/build-comment.d.mts +22 -0
  30. package/dist/adapters/notifier/build-comment.mjs +23 -0
  31. package/dist/adapters/notifier/build-comment.mjs.map +1 -0
  32. package/dist/adapters/notifier/build-state.d.mts +97 -0
  33. package/dist/adapters/notifier/build-state.mjs +217 -0
  34. package/dist/adapters/notifier/build-state.mjs.map +1 -0
  35. package/dist/adapters/notifier/events.d.mts +4 -4
  36. package/dist/adapters/notifier/events.mjs +32 -20
  37. package/dist/adapters/notifier/events.mjs.map +1 -1
  38. package/dist/adapters/notifier/format.d.mts +0 -2
  39. package/dist/adapters/notifier/format.mjs +1 -2
  40. package/dist/adapters/notifier/provider.d.mts +53 -9
  41. package/dist/adapters/notifier/provider.mjs +11 -0
  42. package/dist/adapters/notifier/provider.mjs.map +1 -0
  43. package/dist/adapters/notifier/state.d.mts +22 -0
  44. package/dist/adapters/notifier/state.mjs +65 -0
  45. package/dist/adapters/notifier/state.mjs.map +1 -0
  46. package/dist/adapters/notifier/types.d.mts +51 -4
  47. package/dist/adapters/remote-browser.d.mts +168 -0
  48. package/dist/adapters/remote-browser.mjs +201 -0
  49. package/dist/adapters/remote-browser.mjs.map +1 -0
  50. package/dist/adapters/remote-lease-attempt.mjs +39 -0
  51. package/dist/adapters/remote-lease-attempt.mjs.map +1 -0
  52. package/dist/adapters/remote-lease-error.d.mts +25 -0
  53. package/dist/adapters/remote-lease-error.mjs +54 -0
  54. package/dist/adapters/remote-lease-error.mjs.map +1 -0
  55. package/dist/adapters/remote-lease-held.d.mts +15 -0
  56. package/dist/adapters/remote-lease-held.mjs +86 -0
  57. package/dist/adapters/remote-lease-held.mjs.map +1 -0
  58. package/dist/adapters/remote-lease-shutdown.d.mts +12 -0
  59. package/dist/adapters/remote-lease-shutdown.mjs +32 -0
  60. package/dist/adapters/remote-lease-shutdown.mjs.map +1 -0
  61. package/dist/adapters/remote-lease.d.mts +39 -0
  62. package/dist/adapters/remote-lease.mjs +175 -0
  63. package/dist/adapters/remote-lease.mjs.map +1 -0
  64. package/dist/adapters/remote-limiter.mjs +121 -0
  65. package/dist/adapters/remote-limiter.mjs.map +1 -0
  66. package/dist/adapters/remote-pool.d.mts +56 -0
  67. package/dist/adapters/remote-pool.mjs +195 -0
  68. package/dist/adapters/remote-pool.mjs.map +1 -0
  69. package/dist/adapters/render-runs.d.mts +23 -0
  70. package/dist/adapters/render-runs.mjs +40 -0
  71. package/dist/adapters/render-runs.mjs.map +1 -0
  72. package/dist/adapters/setup-runner.d.mts +0 -2
  73. package/dist/adapters/setup-runner.mjs +3 -6
  74. package/dist/adapters/setup-runner.mjs.map +1 -1
  75. package/dist/adapters/sources.d.mts +10 -0
  76. package/dist/adapters/sources.mjs +19 -0
  77. package/dist/adapters/sources.mjs.map +1 -0
  78. package/dist/adapters/validate.d.mts +0 -2
  79. package/dist/adapters/validate.mjs +27 -20
  80. package/dist/adapters/validate.mjs.map +1 -1
  81. package/dist/ai.d.mts +103 -0
  82. package/dist/ai.mjs +18 -0
  83. package/dist/ai.mjs.map +1 -0
  84. package/dist/auth.d.mts +0 -2
  85. package/dist/auth.mjs +1 -2
  86. package/dist/brand-packs.d.mts +0 -2
  87. package/dist/brand-packs.mjs +0 -1
  88. package/dist/capture/a11y/axe-source.d.mts +16 -0
  89. package/dist/capture/a11y/axe-source.mjs +36 -0
  90. package/dist/capture/a11y/axe-source.mjs.map +1 -0
  91. package/dist/capture/a11y/in-page.d.mts +25 -0
  92. package/dist/capture/a11y/in-page.mjs +59 -0
  93. package/dist/capture/a11y/in-page.mjs.map +1 -0
  94. package/dist/capture/a11y/map.d.mts +22 -0
  95. package/dist/capture/a11y/map.mjs +47 -0
  96. package/dist/capture/a11y/map.mjs.map +1 -0
  97. package/dist/capture/a11y/options.d.mts +21 -0
  98. package/dist/capture/a11y/options.mjs +74 -0
  99. package/dist/capture/a11y/options.mjs.map +1 -0
  100. package/dist/capture/adapter.d.mts +46 -5
  101. package/dist/capture/adapter.mjs +1 -2
  102. package/dist/capture/adapter.mjs.map +1 -1
  103. package/dist/capture/affected.d.mts +2 -2
  104. package/dist/capture/affected.mjs +14 -6
  105. package/dist/capture/affected.mjs.map +1 -1
  106. package/dist/capture/attempt-logger.mjs +83 -0
  107. package/dist/capture/attempt-logger.mjs.map +1 -0
  108. package/dist/capture/browsers.d.mts +33 -0
  109. package/dist/capture/browsers.mjs +66 -0
  110. package/dist/capture/browsers.mjs.map +1 -0
  111. package/dist/capture/build-state/deliver.d.mts +30 -0
  112. package/dist/capture/build-state/deliver.mjs +117 -0
  113. package/dist/capture/build-state/deliver.mjs.map +1 -0
  114. package/dist/capture/build-state/index.d.mts +8 -0
  115. package/dist/capture/build-state/notify-job.d.mts +54 -0
  116. package/dist/capture/build-state/notify-job.mjs +132 -0
  117. package/dist/capture/build-state/notify-job.mjs.map +1 -0
  118. package/dist/capture/build-state/publisher.d.mts +21 -0
  119. package/dist/capture/build-state/publisher.mjs +106 -0
  120. package/dist/capture/build-state/publisher.mjs.map +1 -0
  121. package/dist/capture/build-state/resume.d.mts +7 -0
  122. package/dist/capture/build-state/resume.mjs +46 -0
  123. package/dist/capture/build-state/resume.mjs.map +1 -0
  124. package/dist/capture/build-state/types.d.mts +47 -0
  125. package/dist/capture/catalog/catalogue.d.mts +20 -0
  126. package/dist/capture/catalog/catalogue.mjs +52 -0
  127. package/dist/capture/catalog/catalogue.mjs.map +1 -0
  128. package/dist/capture/catalog/components.d.mts +21 -0
  129. package/dist/capture/catalog/components.mjs +54 -0
  130. package/dist/capture/catalog/components.mjs.map +1 -0
  131. package/dist/capture/catalog/history.d.mts +28 -0
  132. package/dist/capture/catalog/history.mjs +50 -0
  133. package/dist/capture/catalog/history.mjs.map +1 -0
  134. package/dist/capture/catalog/hook.d.mts +12 -0
  135. package/dist/capture/catalog/hook.mjs +18 -0
  136. package/dist/capture/catalog/hook.mjs.map +1 -0
  137. package/dist/capture/catalog/index.d.mts +11 -0
  138. package/dist/capture/catalog/load.d.mts +24 -0
  139. package/dist/capture/catalog/load.mjs +48 -0
  140. package/dist/capture/catalog/load.mjs.map +1 -0
  141. package/dist/capture/catalog/parse.d.mts +13 -0
  142. package/dist/capture/catalog/parse.mjs +55 -0
  143. package/dist/capture/catalog/parse.mjs.map +1 -0
  144. package/dist/capture/catalog/read.d.mts +15 -0
  145. package/dist/capture/catalog/read.mjs +39 -0
  146. package/dist/capture/catalog/read.mjs.map +1 -0
  147. package/dist/capture/catalog/types.d.mts +31 -0
  148. package/dist/capture/comparison-reference.d.mts +27 -0
  149. package/dist/capture/comparison-reference.mjs +75 -0
  150. package/dist/capture/comparison-reference.mjs.map +1 -0
  151. package/dist/capture/consumer/capture-handler.d.mts +56 -0
  152. package/dist/capture/consumer/capture-handler.mjs +117 -0
  153. package/dist/capture/consumer/capture-handler.mjs.map +1 -0
  154. package/dist/capture/consumer/idle.d.mts +15 -0
  155. package/dist/capture/consumer/idle.mjs +24 -0
  156. package/dist/capture/consumer/idle.mjs.map +1 -0
  157. package/dist/capture/consumer/index.d.mts +11 -0
  158. package/dist/capture/consumer/index.mjs +138 -0
  159. package/dist/capture/consumer/index.mjs.map +1 -0
  160. package/dist/capture/consumer/loop.mjs +109 -0
  161. package/dist/capture/consumer/loop.mjs.map +1 -0
  162. package/dist/capture/consumer/metrics.d.mts +39 -0
  163. package/dist/capture/consumer/metrics.mjs +37 -0
  164. package/dist/capture/consumer/metrics.mjs.map +1 -0
  165. package/dist/capture/consumer/retry.d.mts +31 -0
  166. package/dist/capture/consumer/retry.mjs +33 -0
  167. package/dist/capture/consumer/retry.mjs.map +1 -0
  168. package/dist/capture/consumer/run-job.mjs +194 -0
  169. package/dist/capture/consumer/run-job.mjs.map +1 -0
  170. package/dist/capture/consumer/startup.mjs +37 -0
  171. package/dist/capture/consumer/startup.mjs.map +1 -0
  172. package/dist/capture/consumer/types.d.mts +95 -0
  173. package/dist/capture/crash-failure.d.mts +23 -0
  174. package/dist/capture/crash-failure.mjs +69 -0
  175. package/dist/capture/crash-failure.mjs.map +1 -0
  176. package/dist/capture/db-queue/cadence.d.mts +30 -0
  177. package/dist/capture/db-queue/cadence.mjs +37 -0
  178. package/dist/capture/db-queue/cadence.mjs.map +1 -0
  179. package/dist/capture/db-queue/claim.d.mts +7 -0
  180. package/dist/capture/db-queue/claim.mjs +148 -0
  181. package/dist/capture/db-queue/claim.mjs.map +1 -0
  182. package/dist/capture/db-queue/clock.mjs +11 -0
  183. package/dist/capture/db-queue/clock.mjs.map +1 -0
  184. package/dist/capture/db-queue/codec.mjs +75 -0
  185. package/dist/capture/db-queue/codec.mjs.map +1 -0
  186. package/dist/capture/db-queue/index.d.mts +18 -0
  187. package/dist/capture/db-queue/index.mjs +89 -0
  188. package/dist/capture/db-queue/index.mjs.map +1 -0
  189. package/dist/capture/db-queue/keeper.d.mts +34 -0
  190. package/dist/capture/db-queue/keeper.mjs +91 -0
  191. package/dist/capture/db-queue/keeper.mjs.map +1 -0
  192. package/dist/capture/db-queue/lease.mjs +45 -0
  193. package/dist/capture/db-queue/lease.mjs.map +1 -0
  194. package/dist/capture/db-queue/lifecycle.mjs +35 -0
  195. package/dist/capture/db-queue/lifecycle.mjs.map +1 -0
  196. package/dist/capture/db-queue/operations.mjs +93 -0
  197. package/dist/capture/db-queue/operations.mjs.map +1 -0
  198. package/dist/capture/db-queue/poll-loop.d.mts +28 -0
  199. package/dist/capture/db-queue/poll-loop.mjs +88 -0
  200. package/dist/capture/db-queue/poll-loop.mjs.map +1 -0
  201. package/dist/capture/db-queue/poll.d.mts +8 -0
  202. package/dist/capture/db-queue/poll.mjs +68 -0
  203. package/dist/capture/db-queue/poll.mjs.map +1 -0
  204. package/dist/capture/db-queue/timers.d.mts +10 -0
  205. package/dist/capture/db-queue/timers.mjs +36 -0
  206. package/dist/capture/db-queue/timers.mjs.map +1 -0
  207. package/dist/capture/db-queue/types.d.mts +81 -0
  208. package/dist/capture/db-queue/types.mjs +11 -0
  209. package/dist/capture/db-queue/types.mjs.map +1 -0
  210. package/dist/capture/db-queue/wake.mjs +47 -0
  211. package/dist/capture/db-queue/wake.mjs.map +1 -0
  212. package/dist/capture/design.mjs +38 -0
  213. package/dist/capture/design.mjs.map +1 -0
  214. package/dist/capture/diff-record.mjs +24 -5
  215. package/dist/capture/diff-record.mjs.map +1 -1
  216. package/dist/capture/dispatch.d.mts +13 -10
  217. package/dist/capture/dispatch.mjs +102 -111
  218. package/dist/capture/dispatch.mjs.map +1 -1
  219. package/dist/capture/enrich.mjs +59 -0
  220. package/dist/capture/enrich.mjs.map +1 -0
  221. package/dist/capture/failure-sets.mjs +21 -0
  222. package/dist/capture/failure-sets.mjs.map +1 -0
  223. package/dist/capture/fingerprint.d.mts +40 -0
  224. package/dist/capture/fingerprint.mjs +82 -0
  225. package/dist/capture/fingerprint.mjs.map +1 -0
  226. package/dist/capture/forked/channel.d.mts +23 -0
  227. package/dist/capture/forked/child.d.mts +32 -0
  228. package/dist/capture/forked/child.mjs +201 -0
  229. package/dist/capture/forked/child.mjs.map +1 -0
  230. package/dist/capture/forked/crash-tracker.mjs +22 -0
  231. package/dist/capture/forked/crash-tracker.mjs.map +1 -0
  232. package/dist/capture/forked/decision.d.mts +24 -0
  233. package/dist/capture/forked/decision.mjs +26 -0
  234. package/dist/capture/forked/decision.mjs.map +1 -0
  235. package/dist/capture/forked/exit.mjs +11 -0
  236. package/dist/capture/forked/exit.mjs.map +1 -0
  237. package/dist/capture/forked/fork.d.mts +29 -0
  238. package/dist/capture/forked/fork.mjs +92 -0
  239. package/dist/capture/forked/fork.mjs.map +1 -0
  240. package/dist/capture/forked/forked-capture.d.mts +38 -0
  241. package/dist/capture/forked/forked-capture.mjs +239 -0
  242. package/dist/capture/forked/forked-capture.mjs.map +1 -0
  243. package/dist/capture/forked/lease-book.mjs +45 -0
  244. package/dist/capture/forked/lease-book.mjs.map +1 -0
  245. package/dist/capture/forked/protocol.d.mts +36 -0
  246. package/dist/capture/forked/protocol.mjs +24 -0
  247. package/dist/capture/forked/protocol.mjs.map +1 -0
  248. package/dist/capture/forked/runs.mjs +74 -0
  249. package/dist/capture/forked/runs.mjs.map +1 -0
  250. package/dist/capture/guards.mjs +1 -2
  251. package/dist/capture/ignore-regions.d.mts +36 -0
  252. package/dist/capture/ignore-regions.mjs +65 -0
  253. package/dist/capture/ignore-regions.mjs.map +1 -0
  254. package/dist/capture/isolate.mjs +140 -0
  255. package/dist/capture/isolate.mjs.map +1 -0
  256. package/dist/capture/job-lease.d.mts +26 -0
  257. package/dist/capture/job-lease.mjs +56 -0
  258. package/dist/capture/job-lease.mjs.map +1 -0
  259. package/dist/capture/matrix.mjs +298 -0
  260. package/dist/capture/matrix.mjs.map +1 -0
  261. package/dist/capture/modes.d.mts +23 -0
  262. package/dist/capture/modes.mjs +106 -0
  263. package/dist/capture/modes.mjs.map +1 -0
  264. package/dist/capture/orchestrator.d.mts +37 -7
  265. package/dist/capture/orchestrator.mjs +120 -110
  266. package/dist/capture/orchestrator.mjs.map +1 -1
  267. package/dist/capture/pipeline.d.mts +9 -4
  268. package/dist/capture/pipeline.mjs +284 -48
  269. package/dist/capture/pipeline.mjs.map +1 -1
  270. package/dist/capture/progress.d.mts +9 -0
  271. package/dist/capture/progress.mjs +27 -0
  272. package/dist/capture/progress.mjs.map +1 -0
  273. package/dist/capture/publish/accept.d.mts +37 -0
  274. package/dist/capture/publish/accept.mjs +27 -0
  275. package/dist/capture/publish/accept.mjs.map +1 -0
  276. package/dist/capture/publish/complete.d.mts +44 -0
  277. package/dist/capture/publish/complete.mjs +63 -0
  278. package/dist/capture/publish/complete.mjs.map +1 -0
  279. package/dist/capture/publish/extract.d.mts +18 -0
  280. package/dist/capture/publish/extract.mjs +120 -0
  281. package/dist/capture/publish/extract.mjs.map +1 -0
  282. package/dist/capture/publish/handler.d.mts +26 -0
  283. package/dist/capture/publish/handler.mjs +61 -0
  284. package/dist/capture/publish/handler.mjs.map +1 -0
  285. package/dist/capture/publish/index.d.mts +11 -0
  286. package/dist/capture/publish/invalid-zip.d.mts +8 -0
  287. package/dist/capture/publish/invalid-zip.mjs +11 -0
  288. package/dist/capture/publish/invalid-zip.mjs.map +1 -0
  289. package/dist/capture/publish/limits.d.mts +35 -0
  290. package/dist/capture/publish/limits.mjs +38 -0
  291. package/dist/capture/publish/limits.mjs.map +1 -0
  292. package/dist/capture/publish/published.d.mts +13 -0
  293. package/dist/capture/publish/published.mjs +17 -0
  294. package/dist/capture/publish/published.mjs.map +1 -0
  295. package/dist/capture/publish/run.d.mts +31 -0
  296. package/dist/capture/publish/run.mjs +29 -0
  297. package/dist/capture/publish/run.mjs.map +1 -0
  298. package/dist/capture/rediff.d.mts +1 -3
  299. package/dist/capture/rediff.mjs +23 -9
  300. package/dist/capture/rediff.mjs.map +1 -1
  301. package/dist/capture/render.mjs +52 -0
  302. package/dist/capture/render.mjs.map +1 -0
  303. package/dist/capture/scratch.d.mts +42 -0
  304. package/dist/capture/scratch.mjs +136 -0
  305. package/dist/capture/scratch.mjs.map +1 -0
  306. package/dist/capture/shard-plan.mjs +127 -0
  307. package/dist/capture/shard-plan.mjs.map +1 -0
  308. package/dist/capture/shards/context.mjs +51 -0
  309. package/dist/capture/shards/context.mjs.map +1 -0
  310. package/dist/capture/shards/execute.mjs +175 -0
  311. package/dist/capture/shards/execute.mjs.map +1 -0
  312. package/dist/capture/shards/fan-out.mjs +125 -0
  313. package/dist/capture/shards/fan-out.mjs.map +1 -0
  314. package/dist/capture/shards/history.mjs +34 -0
  315. package/dist/capture/shards/history.mjs.map +1 -0
  316. package/dist/capture/shards/reduce.mjs +96 -0
  317. package/dist/capture/shards/reduce.mjs.map +1 -0
  318. package/dist/capture/sizing.d.mts +0 -2
  319. package/dist/capture/sizing.mjs +2 -13
  320. package/dist/capture/sizing.mjs.map +1 -1
  321. package/dist/capture/skip-checks.mjs +3 -67
  322. package/dist/capture/skip-checks.mjs.map +1 -1
  323. package/dist/capture/statics.d.mts +7 -10
  324. package/dist/capture/statics.mjs +26 -74
  325. package/dist/capture/statics.mjs.map +1 -1
  326. package/dist/capture/storybook-urls.d.mts +38 -0
  327. package/dist/capture/storybook-urls.mjs +41 -0
  328. package/dist/capture/storybook-urls.mjs.map +1 -0
  329. package/dist/capture/storybook.d.mts +12 -6
  330. package/dist/capture/storybook.mjs +63 -19
  331. package/dist/capture/storybook.mjs.map +1 -1
  332. package/dist/capture/target.mjs +20 -0
  333. package/dist/capture/target.mjs.map +1 -0
  334. package/dist/capture/targets.d.mts +23 -0
  335. package/dist/capture/targets.mjs +31 -0
  336. package/dist/capture/targets.mjs.map +1 -0
  337. package/dist/capture/tests.d.mts +35 -0
  338. package/dist/capture/tests.mjs +136 -0
  339. package/dist/capture/tests.mjs.map +1 -0
  340. package/dist/capture/token-chunks.mjs +91 -0
  341. package/dist/capture/token-chunks.mjs.map +1 -0
  342. package/dist/capture.d.mts +63 -7
  343. package/dist/capture.mjs +51 -3
  344. package/dist/config.d.mts +136 -14
  345. package/dist/config.mjs +14 -8
  346. package/dist/config.mjs.map +1 -1
  347. package/dist/diff.d.mts +7 -3
  348. package/dist/diff.mjs +15 -3
  349. package/dist/diff.mjs.map +1 -0
  350. package/dist/index.d.mts +3 -3
  351. package/dist/index.mjs +2 -2
  352. package/dist/insights/budget.d.mts +18 -0
  353. package/dist/insights/budget.mjs +32 -0
  354. package/dist/insights/budget.mjs.map +1 -0
  355. package/dist/insights/envelope.d.mts +57 -0
  356. package/dist/insights/envelope.mjs +59 -0
  357. package/dist/insights/envelope.mjs.map +1 -0
  358. package/dist/insights/evidence-health.d.mts +30 -0
  359. package/dist/insights/evidence-health.mjs +27 -0
  360. package/dist/insights/evidence-health.mjs.map +1 -0
  361. package/dist/insights/evidence.d.mts +53 -0
  362. package/dist/insights/evidence.mjs +63 -0
  363. package/dist/insights/evidence.mjs.map +1 -0
  364. package/dist/insights/hash.d.mts +16 -0
  365. package/dist/insights/hash.mjs +20 -0
  366. package/dist/insights/hash.mjs.map +1 -0
  367. package/dist/insights/limits.d.mts +22 -0
  368. package/dist/insights/limits.mjs +23 -0
  369. package/dist/insights/limits.mjs.map +1 -0
  370. package/dist/insights/prompts/v1.d.mts +11 -0
  371. package/dist/insights/prompts/v1.mjs +33 -0
  372. package/dist/insights/prompts/v1.mjs.map +1 -0
  373. package/dist/insights/redact.d.mts +7 -0
  374. package/dist/insights/redact.mjs +23 -0
  375. package/dist/insights/redact.mjs.map +1 -0
  376. package/dist/insights/text.mjs +43 -0
  377. package/dist/insights/text.mjs.map +1 -0
  378. package/dist/insights.d.mts +11 -0
  379. package/dist/insights.mjs +12 -0
  380. package/dist/logger.d.mts +0 -2
  381. package/dist/logger.mjs +18 -3
  382. package/dist/logger.mjs.map +1 -1
  383. package/dist/models/ai-budget-alert.d.mts +21 -0
  384. package/dist/models/ai-budget-alert.mjs +37 -0
  385. package/dist/models/ai-budget-alert.mjs.map +1 -0
  386. package/dist/models/ai-usage.d.mts +38 -0
  387. package/dist/models/ai-usage.mjs +60 -0
  388. package/dist/models/ai-usage.mjs.map +1 -0
  389. package/dist/models/baseline-approval.d.mts +18 -0
  390. package/dist/models/baseline-approval.mjs +41 -0
  391. package/dist/models/baseline-approval.mjs.map +1 -0
  392. package/dist/models/baseline-archive.d.mts +82 -0
  393. package/dist/models/baseline-archive.mjs +105 -0
  394. package/dist/models/baseline-archive.mjs.map +1 -0
  395. package/dist/models/baseline-atomic.mjs +66 -0
  396. package/dist/models/baseline-atomic.mjs.map +1 -0
  397. package/dist/models/baseline-conflict.d.mts +6 -0
  398. package/dist/models/baseline-conflict.mjs +9 -0
  399. package/dist/models/baseline-conflict.mjs.map +1 -0
  400. package/dist/models/baseline-export.d.mts +17 -0
  401. package/dist/models/baseline-export.mjs +135 -0
  402. package/dist/models/baseline-export.mjs.map +1 -0
  403. package/dist/models/baseline-import.mjs +117 -0
  404. package/dist/models/baseline-import.mjs.map +1 -0
  405. package/dist/models/baseline-origin.d.mts +16 -0
  406. package/dist/models/baseline-origin.mjs +35 -0
  407. package/dist/models/baseline-origin.mjs.map +1 -0
  408. package/dist/models/baseline-status.d.mts +0 -2
  409. package/dist/models/baseline-status.mjs +1 -2
  410. package/dist/models/baseline-transfer.d.mts +48 -0
  411. package/dist/models/baseline-transfer.mjs +149 -0
  412. package/dist/models/baseline-transfer.mjs.map +1 -0
  413. package/dist/models/baseline.d.mts +37 -7
  414. package/dist/models/baseline.mjs +152 -28
  415. package/dist/models/baseline.mjs.map +1 -1
  416. package/dist/models/build-component.d.mts +26 -0
  417. package/dist/models/build-component.mjs +54 -0
  418. package/dist/models/build-component.mjs.map +1 -0
  419. package/dist/models/build-review-status.d.mts +27 -0
  420. package/dist/models/build-review-status.mjs +36 -0
  421. package/dist/models/build-review-status.mjs.map +1 -0
  422. package/dist/models/build-review.d.mts +26 -0
  423. package/dist/models/build-review.mjs +53 -0
  424. package/dist/models/build-review.mjs.map +1 -0
  425. package/dist/models/build.d.mts +25 -5
  426. package/dist/models/build.mjs +53 -15
  427. package/dist/models/build.mjs.map +1 -1
  428. package/dist/models/capture-attempt.d.mts +7 -3
  429. package/dist/models/capture-attempt.mjs +30 -6
  430. package/dist/models/capture-attempt.mjs.map +1 -1
  431. package/dist/models/capture-job.d.mts +104 -0
  432. package/dist/models/capture-job.mjs +287 -0
  433. package/dist/models/capture-job.mjs.map +1 -0
  434. package/dist/models/capture-log.d.mts +1 -3
  435. package/dist/models/capture-log.mjs +5 -5
  436. package/dist/models/capture-log.mjs.map +1 -1
  437. package/dist/models/capture-shard.d.mts +60 -0
  438. package/dist/models/capture-shard.mjs +189 -0
  439. package/dist/models/capture-shard.mjs.map +1 -0
  440. package/dist/models/changeset.d.mts +46 -0
  441. package/dist/models/changeset.mjs +80 -0
  442. package/dist/models/changeset.mjs.map +1 -0
  443. package/dist/models/columns.mjs +18 -0
  444. package/dist/models/columns.mjs.map +1 -0
  445. package/dist/models/comment.d.mts +4 -3
  446. package/dist/models/comment.mjs +8 -6
  447. package/dist/models/comment.mjs.map +1 -1
  448. package/dist/models/component.d.mts +41 -0
  449. package/dist/models/component.mjs +59 -0
  450. package/dist/models/component.mjs.map +1 -0
  451. package/dist/models/connections.d.mts +39 -0
  452. package/dist/models/connections.mjs +111 -0
  453. package/dist/models/connections.mjs.map +1 -0
  454. package/dist/models/content-ref.d.mts +1 -3
  455. package/dist/models/content-ref.mjs +2 -3
  456. package/dist/models/content-ref.mjs.map +1 -1
  457. package/dist/models/credentials.d.mts +0 -2
  458. package/dist/models/credentials.mjs +13 -4
  459. package/dist/models/credentials.mjs.map +1 -1
  460. package/dist/models/design-credentials.d.mts +39 -0
  461. package/dist/models/design-credentials.mjs +85 -0
  462. package/dist/models/design-credentials.mjs.map +1 -0
  463. package/dist/models/design-health.d.mts +14 -0
  464. package/dist/models/design-health.mjs +24 -0
  465. package/dist/models/design-health.mjs.map +1 -0
  466. package/dist/models/design-nodes.d.mts +81 -0
  467. package/dist/models/design-nodes.mjs +221 -0
  468. package/dist/models/design-nodes.mjs.map +1 -0
  469. package/dist/models/design-renders.mjs +73 -0
  470. package/dist/models/design-renders.mjs.map +1 -0
  471. package/dist/models/design-resolve.d.mts +27 -0
  472. package/dist/models/design-resolve.mjs +40 -0
  473. package/dist/models/design-resolve.mjs.map +1 -0
  474. package/dist/models/design.d.mts +37 -0
  475. package/dist/models/design.mjs +89 -0
  476. package/dist/models/design.mjs.map +1 -0
  477. package/dist/models/inherited-ratio.d.mts +19 -0
  478. package/dist/models/inherited-ratio.mjs +21 -0
  479. package/dist/models/inherited-ratio.mjs.map +1 -0
  480. package/dist/models/insight.d.mts +68 -0
  481. package/dist/models/insight.mjs +161 -0
  482. package/dist/models/insight.mjs.map +1 -0
  483. package/dist/models/label.d.mts +4 -4
  484. package/dist/models/label.mjs +26 -12
  485. package/dist/models/label.mjs.map +1 -1
  486. package/dist/models/member.d.mts +1 -3
  487. package/dist/models/member.mjs +6 -6
  488. package/dist/models/member.mjs.map +1 -1
  489. package/dist/models/notification-channel.d.mts +37 -5
  490. package/dist/models/notification-channel.mjs +89 -11
  491. package/dist/models/notification-channel.mjs.map +1 -1
  492. package/dist/models/notification-subscription.d.mts +1 -4
  493. package/dist/models/notification-subscription.mjs +8 -11
  494. package/dist/models/notification-subscription.mjs.map +1 -1
  495. package/dist/models/project-group-mapping.d.mts +6 -3
  496. package/dist/models/project-group-mapping.mjs +15 -6
  497. package/dist/models/project-group-mapping.mjs.map +1 -1
  498. package/dist/models/project.d.mts +9 -3
  499. package/dist/models/project.mjs +10 -6
  500. package/dist/models/project.mjs.map +1 -1
  501. package/dist/models/public-origin.d.mts +61 -0
  502. package/dist/models/public-origin.mjs +113 -0
  503. package/dist/models/public-origin.mjs.map +1 -0
  504. package/dist/models/review-switch-off.d.mts +12 -0
  505. package/dist/models/review-switch-off.mjs +25 -0
  506. package/dist/models/review-switch-off.mjs.map +1 -0
  507. package/dist/models/site-settings.d.mts +21 -0
  508. package/dist/models/site-settings.mjs +47 -0
  509. package/dist/models/site-settings.mjs.map +1 -0
  510. package/dist/models/snapshot.d.mts +39 -3
  511. package/dist/models/snapshot.mjs +54 -5
  512. package/dist/models/snapshot.mjs.map +1 -1
  513. package/dist/models/token.d.mts +13 -3
  514. package/dist/models/token.mjs +24 -7
  515. package/dist/models/token.mjs.map +1 -1
  516. package/dist/models/usage.d.mts +74 -0
  517. package/dist/models/usage.mjs +148 -0
  518. package/dist/models/usage.mjs.map +1 -0
  519. package/dist/models/user.d.mts +1 -3
  520. package/dist/models/user.mjs +5 -5
  521. package/dist/models/user.mjs.map +1 -1
  522. package/dist/models/webhook.d.mts +15 -3
  523. package/dist/models/webhook.mjs +34 -6
  524. package/dist/models/webhook.mjs.map +1 -1
  525. package/dist/models.d.mts +30 -4
  526. package/dist/models.mjs +31 -6
  527. package/dist/options.d.mts +16 -0
  528. package/dist/options.mjs +88 -0
  529. package/dist/options.mjs.map +1 -0
  530. package/dist/paths.d.mts +21 -6
  531. package/dist/paths.mjs +57 -12
  532. package/dist/paths.mjs.map +1 -1
  533. package/dist/retention/ai.d.mts +16 -0
  534. package/dist/retention/ai.mjs +22 -0
  535. package/dist/retention/ai.mjs.map +1 -0
  536. package/dist/retention/pending.mjs +46 -0
  537. package/dist/retention/pending.mjs.map +1 -0
  538. package/dist/retention/published-gzip-sweep.mjs +28 -0
  539. package/dist/retention/published-gzip-sweep.mjs.map +1 -0
  540. package/dist/retention/screenshot-sweep.d.mts +49 -0
  541. package/dist/retention/screenshot-sweep.mjs +127 -0
  542. package/dist/retention/screenshot-sweep.mjs.map +1 -0
  543. package/dist/retention.d.mts +16 -4
  544. package/dist/retention.mjs +76 -16
  545. package/dist/retention.mjs.map +1 -1
  546. package/dist/schema/baseline.d.mts +8 -2
  547. package/dist/schema/build-component.d.mts +23 -0
  548. package/dist/schema/build-review.d.mts +15 -0
  549. package/dist/schema/build.d.mts +7 -2
  550. package/dist/schema/capture-attempt.d.mts +0 -2
  551. package/dist/schema/capture-job.d.mts +58 -0
  552. package/dist/schema/capture-shard.d.mts +33 -0
  553. package/dist/schema/comment.d.mts +2 -2
  554. package/dist/schema/connection.d.mts +22 -0
  555. package/dist/schema/content-ref.d.mts +0 -2
  556. package/dist/schema/design.d.mts +56 -0
  557. package/dist/schema/insight.d.mts +52 -0
  558. package/dist/schema/label.d.mts +0 -2
  559. package/dist/schema/member.d.mts +0 -2
  560. package/dist/schema/notification.d.mts +4 -2
  561. package/dist/schema/project-group-mapping.d.mts +0 -2
  562. package/dist/schema/project.d.mts +21 -2
  563. package/dist/schema/site-setting.d.mts +19 -0
  564. package/dist/schema/snapshot.d.mts +17 -2
  565. package/dist/schema/token.d.mts +0 -2
  566. package/dist/schema/usage.d.mts +28 -0
  567. package/dist/schema/user.d.mts +0 -2
  568. package/dist/schema/webhook.d.mts +0 -2
  569. package/dist/schema.d.mts +12 -6
  570. package/dist/serverless.d.mts +19 -0
  571. package/dist/serverless.mjs +36 -0
  572. package/dist/serverless.mjs.map +1 -0
  573. package/dist/test-helpers/build-reference-contract.d.mts +14 -0
  574. package/dist/test-helpers/build-reference-contract.mjs +66 -0
  575. package/dist/test-helpers/build-reference-contract.mjs.map +1 -0
  576. package/dist/test-helpers/create-project.d.mts +1 -3
  577. package/dist/test-helpers/create-project.mjs +1 -2
  578. package/dist/test-helpers/database-contract.d.mts +0 -2
  579. package/dist/test-helpers/database-contract.mjs +37 -2
  580. package/dist/test-helpers/database-contract.mjs.map +1 -1
  581. package/dist/test-helpers/deferred.d.mts +37 -0
  582. package/dist/test-helpers/deferred.mjs +60 -0
  583. package/dist/test-helpers/deferred.mjs.map +1 -0
  584. package/dist/test-helpers/design-contract.d.mts +19 -0
  585. package/dist/test-helpers/design-contract.mjs +39 -0
  586. package/dist/test-helpers/design-contract.mjs.map +1 -0
  587. package/dist/test-helpers/fake-adapters.d.mts +0 -2
  588. package/dist/test-helpers/fake-adapters.mjs +1 -2
  589. package/dist/test-helpers/fake-database.d.mts +0 -2
  590. package/dist/test-helpers/fake-database.mjs +21 -4
  591. package/dist/test-helpers/fake-database.mjs.map +1 -1
  592. package/dist/test-helpers/fake-design.d.mts +41 -0
  593. package/dist/test-helpers/fake-design.mjs +113 -0
  594. package/dist/test-helpers/fake-design.mjs.map +1 -0
  595. package/dist/test-helpers/fake-notifier.d.mts +19 -0
  596. package/dist/test-helpers/fake-notifier.mjs +43 -0
  597. package/dist/test-helpers/fake-notifier.mjs.map +1 -0
  598. package/dist/test-helpers/fake-storage.d.mts +0 -2
  599. package/dist/test-helpers/fake-storage.mjs +1 -2
  600. package/dist/test-helpers/fake-tables.mjs +260 -69
  601. package/dist/test-helpers/fake-tables.mjs.map +1 -1
  602. package/dist/test-helpers/manual-clock.d.mts +25 -0
  603. package/dist/test-helpers/manual-clock.mjs +55 -0
  604. package/dist/test-helpers/manual-clock.mjs.map +1 -0
  605. package/dist/test-helpers/notifier-contract.d.mts +7 -3
  606. package/dist/test-helpers/notifier-contract.mjs +33 -5
  607. package/dist/test-helpers/notifier-contract.mjs.map +1 -1
  608. package/dist/test-helpers/queue-contract.d.mts +16 -4
  609. package/dist/test-helpers/queue-contract.mjs +196 -3
  610. package/dist/test-helpers/queue-contract.mjs.map +1 -1
  611. package/dist/test-helpers/queue-multi-instance.d.mts +18 -0
  612. package/dist/test-helpers/queue-multi-instance.mjs +205 -0
  613. package/dist/test-helpers/queue-multi-instance.mjs.map +1 -0
  614. package/dist/test-helpers/runner-contract.d.mts +0 -2
  615. package/dist/test-helpers/runner-contract.mjs +12 -2
  616. package/dist/test-helpers/runner-contract.mjs.map +1 -1
  617. package/dist/test-helpers/sql-chunks.mjs +25 -2
  618. package/dist/test-helpers/sql-chunks.mjs.map +1 -1
  619. package/dist/test-helpers/storage-contract.d.mts +0 -2
  620. package/dist/test-helpers/storage-contract.mjs +2 -3
  621. package/dist/test-helpers.d.mts +10 -4
  622. package/dist/test-helpers.mjs +9 -3
  623. package/dist/tracing.mjs +36 -6
  624. package/dist/tracing.mjs.map +1 -1
  625. package/dist/types.d.mts +14 -5
  626. package/dist/types.mjs +22 -6
  627. package/dist/types.mjs.map +1 -1
  628. package/dist/urls.d.mts +4 -2
  629. package/dist/urls.mjs +12 -4
  630. package/dist/urls.mjs.map +1 -1
  631. package/dist/utils/adaptive-concurrency.d.mts +64 -0
  632. package/dist/utils/adaptive-concurrency.mjs +148 -0
  633. package/dist/utils/adaptive-concurrency.mjs.map +1 -0
  634. package/dist/utils/connect-retry.d.mts +26 -0
  635. package/dist/utils/connect-retry.mjs +42 -0
  636. package/dist/utils/connect-retry.mjs.map +1 -0
  637. package/dist/utils/encrypt.d.mts +0 -2
  638. package/dist/utils/encrypt.mjs +1 -2
  639. package/dist/utils/environment.d.mts +17 -0
  640. package/dist/utils/environment.mjs +58 -0
  641. package/dist/utils/environment.mjs.map +1 -0
  642. package/dist/utils/hash.d.mts +0 -2
  643. package/dist/utils/hash.mjs +1 -2
  644. package/dist/utils/http.d.mts +29 -3
  645. package/dist/utils/http.mjs +100 -19
  646. package/dist/utils/http.mjs.map +1 -1
  647. package/dist/utils/map-adaptive.d.mts +13 -0
  648. package/dist/utils/map-adaptive.mjs +71 -0
  649. package/dist/utils/map-adaptive.mjs.map +1 -0
  650. package/dist/utils/map-limit.d.mts +8 -0
  651. package/dist/utils/map-limit.mjs +31 -0
  652. package/dist/utils/map-limit.mjs.map +1 -0
  653. package/dist/utils/mime.d.mts +0 -2
  654. package/dist/utils/mime.mjs +1 -2
  655. package/dist/utils/page-limiter.d.mts +35 -0
  656. package/dist/utils/page-limiter.mjs +55 -0
  657. package/dist/utils/page-limiter.mjs.map +1 -0
  658. package/dist/utils/path-security.d.mts +0 -2
  659. package/dist/utils/path-security.mjs +2 -4
  660. package/dist/utils/path-security.mjs.map +1 -1
  661. package/dist/utils/public-origin.d.mts +18 -0
  662. package/dist/utils/public-origin.mjs +74 -0
  663. package/dist/utils/public-origin.mjs.map +1 -0
  664. package/dist/utils/redact.d.mts +0 -2
  665. package/dist/utils/redact.mjs +4 -2
  666. package/dist/utils/redact.mjs.map +1 -1
  667. package/dist/utils/remote-environment.d.mts +76 -0
  668. package/dist/utils/remote-environment.mjs +163 -0
  669. package/dist/utils/remote-environment.mjs.map +1 -0
  670. package/dist/utils/resources.d.mts +62 -0
  671. package/dist/utils/resources.mjs +121 -0
  672. package/dist/utils/resources.mjs.map +1 -0
  673. package/dist/utils/screenshot-store.d.mts +13 -0
  674. package/dist/utils/screenshot-store.mjs +40 -0
  675. package/dist/utils/screenshot-store.mjs.map +1 -0
  676. package/dist/utils/session-gate.d.mts +23 -0
  677. package/dist/utils/session-gate.mjs +69 -0
  678. package/dist/utils/session-gate.mjs.map +1 -0
  679. package/dist/utils/storybook-token.d.mts +89 -0
  680. package/dist/utils/storybook-token.mjs +135 -0
  681. package/dist/utils/storybook-token.mjs.map +1 -0
  682. package/dist/utils/storybook-url.d.mts +13 -0
  683. package/dist/utils/storybook-url.mjs +20 -0
  684. package/dist/utils/storybook-url.mjs.map +1 -0
  685. package/dist/utils/timing.d.mts +0 -2
  686. package/dist/utils/timing.mjs +2 -3
  687. package/dist/utils/timing.mjs.map +1 -1
  688. package/dist/utils/ulid.d.mts +0 -2
  689. package/dist/utils/ulid.mjs +1 -2
  690. package/dist/utils/zip-read.mjs +128 -0
  691. package/dist/utils/zip-read.mjs.map +1 -0
  692. package/dist/utils/zip-write.d.mts +16 -0
  693. package/dist/utils/zip-write.mjs +187 -0
  694. package/dist/utils/zip-write.mjs.map +1 -0
  695. package/dist/utils.d.mts +17 -3
  696. package/dist/utils.mjs +18 -4
  697. package/package.json +35 -26
  698. package/dist/adapter/capture-runner.mjs.map +0 -1
  699. package/dist/adapter/git-host/comments.d.mts +0 -41
  700. package/dist/adapter/git-host/comments.mjs +0 -54
  701. package/dist/adapter/git-host/comments.mjs.map +0 -1
  702. package/dist/adapter/git-host/helpers.d.mts +0 -13
  703. package/dist/adapter/git-host/helpers.mjs +0 -30
  704. package/dist/adapter/git-host/helpers.mjs.map +0 -1
  705. package/dist/adapter/git-host.d.mts +0 -42
  706. package/dist/capture/queue.d.mts +0 -38
  707. package/dist/capture/queue.mjs +0 -98
  708. package/dist/capture/queue.mjs.map +0 -1
  709. package/dist/capture/recovery.d.mts +0 -21
  710. package/dist/capture/recovery.mjs +0 -83
  711. package/dist/capture/recovery.mjs.map +0 -1
  712. package/dist/capture/status-fanout.mjs +0 -72
  713. package/dist/capture/status-fanout.mjs.map +0 -1
  714. package/dist/diff/engine.d.mts +0 -16
  715. package/dist/diff/engine.mjs +0 -87
  716. package/dist/diff/engine.mjs.map +0 -1
  717. package/dist/diff/options.d.mts +0 -42
  718. package/dist/diff/options.mjs +0 -15
  719. package/dist/diff/options.mjs.map +0 -1
  720. package/dist/models/status-config.d.mts +0 -38
  721. package/dist/models/status-config.mjs +0 -63
  722. package/dist/models/status-config.mjs.map +0 -1
  723. package/dist/schema/status-config.d.mts +0 -16
  724. package/dist/test-helpers/git-contract.d.mts +0 -11
  725. package/dist/test-helpers/git-contract.mjs +0 -34
  726. package/dist/test-helpers/git-contract.mjs.map +0 -1
  727. /package/dist/adapter/{git-host.mjs → oauth.mjs} +0 -0
@@ -0,0 +1,106 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ // src/capture/modes.ts
5
+ /** Upper bound on captures (global viewports + modes) per story. */
6
+ const MAX_MODES_PER_STORY = 8;
7
+ const SLUG_STRIP = /[^a-z0-9]+/gu;
8
+ const SLUG_EDGES = /^-+|-+$/gu;
9
+ const HEX_COLOR = /^#(?<hex>[0-9a-fA-F]{3,8})$/u;
10
+ /**
11
+ * Baseline identity for a mode name: lower-case, URL/path-safe, stable under
12
+ * whitespace/case edits. Throws for names with no usable characters.
13
+ */
14
+ function modeSlug(name) {
15
+ const slug = name.toLowerCase().replaceAll(SLUG_STRIP, "-").replaceAll(SLUG_EDGES, "");
16
+ if (slug === "") throw new Error(`Invalid mode name: ${JSON.stringify(name)}`);
17
+ return slug;
18
+ }
19
+ /**
20
+ * Apply `modes` on top of a story's base viewports. A mode named like an
21
+ * existing viewport replaces it; `disable: true` drops that entry (inherited
22
+ * mode or viewport). Output order: base viewports first, then new modes.
23
+ */
24
+ function applyModes(modes, base, lookup) {
25
+ if (!modes) return [...base];
26
+ const bySlug = new Map(base.map((viewport) => [modeSlug(viewport.name), viewport]));
27
+ const fallback = base[0] ?? {
28
+ name: "desktop",
29
+ width: 1280,
30
+ height: 720
31
+ };
32
+ for (const [name, definition] of Object.entries(modes)) {
33
+ const slug = modeSlug(name);
34
+ if (definition.disable === true) bySlug.delete(slug);
35
+ else bySlug.set(slug, modeViewport(slug, definition, fallback, lookup));
36
+ }
37
+ return [...bySlug.values()];
38
+ }
39
+ /** Keep only allow-listed modes; `null`/empty allowlist keeps all. */
40
+ function filterModes(modes, allowlist) {
41
+ if (!modes || !allowlist || allowlist.length === 0) return modes;
42
+ const allowed = new Set(allowlist.map((name) => modeSlug(name)));
43
+ return Object.fromEntries(Object.entries(modes).filter(([name, definition]) => definition.disable === true || allowed.has(modeSlug(name))));
44
+ }
45
+ /** Parse the project's JSON `modesAllowlist` column; `null` when unset/invalid. */
46
+ function parseModesAllowlist(raw) {
47
+ if (!raw) return null;
48
+ try {
49
+ const parsed = JSON.parse(raw);
50
+ return isStringArray(parsed) ? parsed : null;
51
+ } catch {
52
+ return null;
53
+ }
54
+ }
55
+ /**
56
+ * Encode globals for Storybook's `globals` URL arg (`a:b;c.d:e`). Nested
57
+ * objects flatten to dot paths; booleans/null/undefined/hex colors use the
58
+ * `!`-prefixed forms Storybook parses. Plain strings pass through (Storybook
59
+ * only accepts `[a-zA-Z0-9 _-]` and silently drops anything else).
60
+ */
61
+ function buildGlobalsParam(globals) {
62
+ return flatten(globals, "").map(([key, value]) => `${key}:${encodeValue(value)}`).join(";");
63
+ }
64
+ function isStringArray(value) {
65
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
66
+ }
67
+ function modeViewport(slug, definition, fallback, lookup) {
68
+ const { viewport, disable: _disable, ...globals } = definition;
69
+ const size = resolveSize(viewport, fallback, lookup);
70
+ return {
71
+ name: slug,
72
+ width: size.width,
73
+ height: size.height,
74
+ ...Object.keys(globals).length > 0 ? { globals } : {}
75
+ };
76
+ }
77
+ function resolveSize(value, fallback, lookup) {
78
+ if (value === void 0) return fallback;
79
+ if (typeof value === "number") return {
80
+ width: Math.round(value),
81
+ height: fallback.height
82
+ };
83
+ if (typeof value === "string") return lookup(value) ?? fallback;
84
+ return {
85
+ width: Math.round(value.width),
86
+ height: Math.round(value.height)
87
+ };
88
+ }
89
+ function flatten(value, prefix) {
90
+ return Object.entries(value).flatMap(([key, entry]) => isPlainObject(entry) ? flatten(entry, `${prefix}${key}.`) : [[`${prefix}${key}`, entry]]);
91
+ }
92
+ function isPlainObject(value) {
93
+ return typeof value === "object" && value !== null && !Array.isArray(value);
94
+ }
95
+ function encodeValue(value) {
96
+ if (value === true) return "!true";
97
+ if (value === false) return "!false";
98
+ if (value === null) return "!null";
99
+ if (value === void 0) return "!undefined";
100
+ const text = typeof value === "string" || typeof value === "number" ? String(value) : JSON.stringify(value) ?? "";
101
+ const hex = HEX_COLOR.exec(text)?.groups?.["hex"];
102
+ return hex ? `!hex(${hex})` : text;
103
+ }
104
+ export { MAX_MODES_PER_STORY, applyModes, buildGlobalsParam, filterModes, modeSlug, parseModesAllowlist };
105
+
106
+ //# sourceMappingURL=modes.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modes.mjs","names":[],"sources":["../../src/capture/modes.ts"],"sourcesContent":["/** Named capture modes: parameters → viewports carrying Storybook globals. */\nimport type { ModeDefinition, ModeMap, ModeViewportValue, Viewport } from \"./adapter.ts\";\n\n/** Upper bound on captures (global viewports + modes) per story. */\nexport const MAX_MODES_PER_STORY = 8;\n\n/** Resolves a Storybook viewport name to dimensions (story config, then builtins). */\nexport type ViewportLookup = (name: string) => Viewport | undefined;\n\nconst SLUG_STRIP = /[^a-z0-9]+/gu;\nconst SLUG_EDGES = /^-+|-+$/gu;\nconst HEX_COLOR = /^#(?<hex>[0-9a-fA-F]{3,8})$/u;\n\n/**\n * Baseline identity for a mode name: lower-case, URL/path-safe, stable under\n * whitespace/case edits. Throws for names with no usable characters.\n */\nexport function modeSlug(name: string): string {\n const slug = name.toLowerCase().replaceAll(SLUG_STRIP, \"-\").replaceAll(SLUG_EDGES, \"\");\n if (slug === \"\") {\n throw new Error(`Invalid mode name: ${JSON.stringify(name)}`);\n }\n return slug;\n}\n\n/**\n * Apply `modes` on top of a story's base viewports. A mode named like an\n * existing viewport replaces it; `disable: true` drops that entry (inherited\n * mode or viewport). Output order: base viewports first, then new modes.\n */\nexport function applyModes(\n modes: ModeMap | undefined,\n base: Viewport[],\n lookup: ViewportLookup,\n): Viewport[] {\n if (!modes) return [...base];\n const bySlug = new Map<string, Viewport>(\n base.map((viewport) => [modeSlug(viewport.name), viewport]),\n );\n const fallback = base[0] ?? { name: \"desktop\", width: 1280, height: 720 };\n for (const [name, definition] of Object.entries(modes)) {\n const slug = modeSlug(name);\n if (definition.disable === true) {\n bySlug.delete(slug);\n } else {\n bySlug.set(slug, modeViewport(slug, definition, fallback, lookup));\n }\n }\n return [...bySlug.values()];\n}\n\n/** Keep only allow-listed modes; `null`/empty allowlist keeps all. */\nexport function filterModes(\n modes: ModeMap | undefined,\n allowlist: readonly string[] | null,\n): ModeMap | undefined {\n if (!modes || !allowlist || allowlist.length === 0) return modes;\n const allowed = new Set(allowlist.map((name) => modeSlug(name)));\n return Object.fromEntries(\n Object.entries(modes).filter(\n ([name, definition]) => definition.disable === true || allowed.has(modeSlug(name)),\n ),\n );\n}\n\n/** Parse the project's JSON `modesAllowlist` column; `null` when unset/invalid. */\nexport function parseModesAllowlist(raw: string | null | undefined): string[] | null {\n if (!raw) return null;\n try {\n const parsed: unknown = JSON.parse(raw);\n return isStringArray(parsed) ? parsed : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Encode globals for Storybook's `globals` URL arg (`a:b;c.d:e`). Nested\n * objects flatten to dot paths; booleans/null/undefined/hex colors use the\n * `!`-prefixed forms Storybook parses. Plain strings pass through (Storybook\n * only accepts `[a-zA-Z0-9 _-]` and silently drops anything else).\n */\nexport function buildGlobalsParam(globals: Record<string, unknown>): string {\n return flatten(globals, \"\")\n .map(([key, value]) => `${key}:${encodeValue(value)}`)\n .join(\";\");\n}\n\nfunction isStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every((item) => typeof item === \"string\");\n}\n\nfunction modeViewport(\n slug: string,\n definition: ModeDefinition,\n fallback: Viewport,\n lookup: ViewportLookup,\n): Viewport {\n const { viewport, disable: _disable, ...globals } = definition;\n const size = resolveSize(viewport, fallback, lookup);\n return {\n name: slug,\n width: size.width,\n height: size.height,\n ...(Object.keys(globals).length > 0 ? { globals } : {}),\n };\n}\n\nfunction resolveSize(\n value: ModeViewportValue | undefined,\n fallback: Viewport,\n lookup: ViewportLookup,\n): { width: number; height: number } {\n if (value === undefined) return fallback;\n if (typeof value === \"number\") return { width: Math.round(value), height: fallback.height };\n if (typeof value === \"string\") return lookup(value) ?? fallback;\n return { width: Math.round(value.width), height: Math.round(value.height) };\n}\n\nfunction flatten(value: Record<string, unknown>, prefix: string): [string, unknown][] {\n return Object.entries(value).flatMap(([key, entry]): [string, unknown][] =>\n isPlainObject(entry) ? flatten(entry, `${prefix}${key}.`) : [[`${prefix}${key}`, entry]],\n );\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction encodeValue(value: unknown): string {\n if (value === true) return \"!true\";\n if (value === false) return \"!false\";\n if (value === null) return \"!null\";\n if (value === undefined) return \"!undefined\";\n const text =\n typeof value === \"string\" || typeof value === \"number\"\n ? String(value)\n : (JSON.stringify(value) ?? \"\");\n const hex = HEX_COLOR.exec(text)?.groups?.[\"hex\"];\n return hex ? `!hex(${hex})` : text;\n}\n"],"mappings":"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"}
@@ -3,15 +3,17 @@ import __tsdown_shims_url from 'node:url';
3
3
  import { Viewport } from "./adapter.mjs";
4
4
  import { CaptureRunner } from "../adapter/capture-runner.mjs";
5
5
  import { DatabaseAdapter } from "../adapter/database.mjs";
6
+ import { DesignProvider } from "../adapter/design.mjs";
6
7
  import { StorageAdapter } from "../adapter/storage.mjs";
7
8
  import { SecretInput } from "../utils/encrypt.mjs";
8
9
  import { BuildTables } from "../models/build.mjs";
9
10
  import { AttemptLogRecorder, CaptureAttemptTables } from "../models/capture-attempt.mjs";
10
11
  import { CaptureLogTables } from "../models/capture-log.mjs";
11
12
  import { ProjectTables } from "../models/project.mjs";
13
+ import { CaptureProgress } from "./progress.mjs";
12
14
  import { PipelineTables } from "./pipeline.mjs";
15
+ import { ExtractionLimits } from "./publish/limits.mjs";
13
16
  import { Logger } from "pino";
14
- //#region src/capture/orchestrator.d.ts
15
17
  /** Table handles required by the orchestrator. */
16
18
  type OrchestratorTables = BuildTables & ProjectTables & PipelineTables & CaptureAttemptTables & CaptureLogTables;
17
19
  /** Inputs for running a capture job against a Storybook build. */
@@ -21,12 +23,42 @@ interface CaptureJobOptions {
21
23
  storage: StorageAdapter;
22
24
  runner: CaptureRunner;
23
25
  scratchDir: string;
26
+ /** Entry and size caps of the zip extraction (`maxZipEntries`, `maxUnzippedBytes`); built-in defaults when unset. */
27
+ limits?: ExtractionLimits | undefined;
24
28
  viewports?: Viewport[];
25
29
  logger?: Logger;
26
30
  /** Server secret for decrypting webhook secrets at send time. */
27
31
  secret?: SecretInput;
32
+ /** Design providers validating declared design links; none ⇒ links are not extracted. */
33
+ design?: DesignProvider[];
34
+ /** The resolved public origin (ADR 0007, decision 6); targets that need a URL wait for it. */
35
+ publicOrigin?: (() => Promise<string | undefined>) | undefined;
28
36
  /** Render budget override (tests use a short fuse). */
29
37
  renderTimeoutMs?: number | undefined;
38
+ /**
39
+ * Target captures (story x viewport x engine) per shard. Unset turns sharding off; a build of up
40
+ * to twice this size still runs as one shard, in this process, exactly as without sharding.
41
+ */
42
+ shardSize?: number | undefined;
43
+ /**
44
+ * Puts a job on the capture queue. Sharding needs it to hand the shards out; without it every
45
+ * build runs in one piece.
46
+ */
47
+ enqueue?: ((job: ShardJob) => Promise<void>) | undefined;
48
+ }
49
+ /** A shard job: the build and the `capture_shards` row to render. */
50
+ interface ShardJob {
51
+ buildId: string;
52
+ shard: string;
53
+ reqId?: string | undefined;
54
+ traceparent?: string | undefined;
55
+ }
56
+ /** What a capture job reports: counts for the attempt row, and how many shards it handed out. */
57
+ interface CaptureSummary {
58
+ storyCount: number;
59
+ failedCount: number;
60
+ /** Set when the build was split: the shards are still to run and this job did not finish it. */
61
+ shards?: number;
30
62
  }
31
63
  /** Pointer to the attempt row owning this run's log history. */
32
64
  interface CaptureAttemptRef {
@@ -47,6 +79,8 @@ interface CaptureJobInput {
47
79
  attempt?: CaptureAttemptRef;
48
80
  /** Recorder mirroring phase logs into the attempt's log history. */
49
81
  recordLog?: AttemptLogRecorder;
82
+ /** Reports render and persist progress to the job's lease, apart from logging. */
83
+ progress?: CaptureProgress | undefined;
50
84
  }
51
85
  /**
52
86
  * Run the full capture for a build: extract, render, persist, and finalize.
@@ -58,10 +92,6 @@ interface CaptureJobInput {
58
92
  * @param options - Adapters, scratch dir, viewports, and logger.
59
93
  * @returns Story and blocking-failure counts for the attempt row.
60
94
  */
61
- declare function executeCaptureJob(input: CaptureJobInput, options: CaptureJobOptions): Promise<{
62
- storyCount: number;
63
- failedCount: number;
64
- }>;
65
- //#endregion
66
- export { CaptureAttemptRef, CaptureJobInput, CaptureJobOptions, OrchestratorTables, executeCaptureJob };
95
+ declare function executeCaptureJob(input: CaptureJobInput, options: CaptureJobOptions): Promise<CaptureSummary>;
96
+ export { CaptureAttemptRef, CaptureJobInput, CaptureJobOptions, CaptureSummary, OrchestratorTables, ShardJob, executeCaptureJob };
67
97
  //# sourceMappingURL=orchestrator.d.mts.map
@@ -1,51 +1,34 @@
1
1
  import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
- import { DEFAULT_VIEWPORTS, isDisabledStory, isFlakyStory } from "./adapter.mjs";
5
- import { BuildModel } from "../models/build.mjs";
6
- import { emitAttemptLog } from "../models/capture-attempt.mjs";
7
- import { ProjectModel } from "../models/project.mjs";
4
+ import { parseDesignUrl } from "../adapter/design.mjs";
8
5
  import { parentContext, withSpan } from "../tracing.mjs";
9
- import { roundedTimings, runWithTimings, timed } from "../utils/timing.mjs";
6
+ import { assertSupportedBrowsers, resolveBrowsers } from "./browsers.mjs";
7
+ import { offeredTargets } from "./targets.mjs";
8
+ import { storybookUrlSource } from "./storybook-urls.mjs";
9
+ import { parseModesAllowlist } from "./modes.mjs";
10
+ import { DEFAULT_VIEWPORTS, isDisabledStory } from "./adapter.mjs";
11
+ import { emitAttemptLog } from "../models/capture-attempt.mjs";
12
+ import { classifyFailures } from "./failure-sets.mjs";
13
+ import { logInvalidDesigns } from "./design.mjs";
10
14
  import { StorybookAdapter } from "./storybook.mjs";
11
- import { partitionAffectedStories } from "./affected.mjs";
15
+ import { runProjectTests } from "./tests.mjs";
16
+ import { BuildModel } from "../models/build.mjs";
17
+ import { roundedTimings, runWithTimings, timed } from "../utils/timing.mjs";
18
+ import { affectedPathsFor } from "./affected.mjs";
19
+ import { assertModeCaps, enrichStories } from "./enrich.mjs";
20
+ import { captureAcrossBrowsers } from "./matrix.mjs";
12
21
  import { resolveViewports } from "./sizing.mjs";
13
22
  import { persistCapture } from "./pipeline.mjs";
23
+ import { removeJobScratch } from "./scratch.mjs";
24
+ import { fanOutCapture } from "./shards/fan-out.mjs";
14
25
  import { extractStorybookToScratch, persistStorybookStatics } from "./statics.mjs";
15
- //#region src/capture/orchestrator.ts
16
- /** Default budget for one render call before the orchestrator cancels it. */
17
- const RENDER_TIMEOUT_MS = 9e5;
18
- /** Failure error text cap (persisted rows and logs stay bounded). */
19
- const FAILURE_ERROR_MAX = 500;
20
- /** Cap failure error text so one chatty runner cannot flood rows and logs. */
21
- function capFailures(result) {
22
- return {
23
- captures: result.captures,
24
- failures: result.failures.map((failure) => ({
25
- ...failure,
26
- error: failure.error.length > FAILURE_ERROR_MAX ? failure.error.slice(0, FAILURE_ERROR_MAX) : failure.error
27
- }))
28
- };
29
- }
30
- /** Render with a timeout; cancels the runner when the budget expires. */
31
- async function renderWithTimeout(runner, request, timeoutMs) {
32
- let timedOut = false;
33
- let timer;
34
- const timeout = new Promise((_, reject) => {
35
- timer = setTimeout(() => {
36
- timedOut = true;
37
- reject(/* @__PURE__ */ new Error(`Render timed out after ${timeoutMs}ms`));
38
- }, timeoutMs);
39
- });
40
- timer?.unref?.();
41
- try {
42
- return capFailures(await Promise.race([runner.render(request), timeout]));
43
- } catch (error) {
44
- if (timedOut) await runner.cancel(request.buildId).catch(() => {});
45
- throw error;
46
- } finally {
47
- clearTimeout(timer);
48
- }
26
+ import { loadTarget } from "./target.mjs";
27
+ // src/capture/orchestrator.ts
28
+ /** Parser over the configured design providers, or undefined when there are none. */
29
+ function designParser(providers) {
30
+ if (!providers || providers.length === 0) return void 0;
31
+ return (raw) => parseDesignUrl(providers, raw)?.ref ?? null;
49
32
  }
50
33
  /**
51
34
  * Run the full capture for a build: extract, render, persist, and finalize.
@@ -58,7 +41,7 @@ async function renderWithTimeout(runner, request, timeoutMs) {
58
41
  * @returns Story and blocking-failure counts for the attempt row.
59
42
  */
60
43
  async function executeCaptureJob(input, options) {
61
- const builds = new BuildModel(options.db, options.tables);
44
+ const builds = new BuildModel(options.db, options.tables, options.logger);
62
45
  const { build, project } = await loadTarget(options, input.buildId);
63
46
  return await withSpan("capture.job", async () => {
64
47
  const { result, timings } = await runWithTimings(async () => await runCapturePhases(input, options, builds, build, project));
@@ -80,13 +63,27 @@ async function runCapturePhases(input, options, builds, build, project) {
80
63
  reqId: input.reqId,
81
64
  ...input.attempt ? { attemptNo: input.attempt.attemptNo } : {}
82
65
  });
66
+ if (build.status === "cancelled") {
67
+ logger?.info("build is cancelled; capture skipped");
68
+ return {
69
+ storyCount: 0,
70
+ failedCount: 0
71
+ };
72
+ }
83
73
  await builds.setStatus(build.id, "capturing");
84
74
  const startTime = performance.now();
85
75
  let extractedDir;
76
+ let scratchPending = true;
77
+ const cleanScratch = async () => {
78
+ if (scratchPending) {
79
+ scratchPending = false;
80
+ await removeJobScratch(options.scratchDir, project.id, build.id, logger);
81
+ }
82
+ };
86
83
  try {
87
84
  const extractStart = performance.now();
88
85
  extractedDir = await timed("capture.extract", async () => await withSpan("capture.extract", async () => {
89
- return await extractStorybookToScratch(options.storage, options.scratchDir, project.id, build.id);
86
+ return await extractStorybookToScratch(options.storage, options.scratchDir, project.id, build.id, void 0, options.limits);
90
87
  }));
91
88
  const extractDuration = performance.now() - extractStart;
92
89
  logger?.info({ durationMs: Math.round(extractDuration) }, "storybook extracted");
@@ -94,69 +91,98 @@ async function runCapturePhases(input, options, builds, build, project) {
94
91
  const storybookDir = extractedDir;
95
92
  const staticsStart = performance.now();
96
93
  await timed("capture.persist-statics", async () => await withSpan("capture.persist-statics", async () => {
97
- await persistStorybookStatics(options.storage, storybookDir, project.id, build.id);
94
+ await persistStorybookStatics(options.storage, storybookDir, project.id, build.id, options.db);
98
95
  }));
99
96
  logger?.info({ durationMs: Math.round(performance.now() - staticsStart) }, "storybook statics persisted");
100
97
  await emitAttemptLog(input.recordLog, logger, "info", "storybook statics persisted", { durationMs: Math.round(performance.now() - staticsStart) });
101
- const stories = (await new StorybookAdapter().discover(extractedDir)).filter((s) => !isDisabledStory(s));
98
+ const discovered = await new StorybookAdapter().discover(extractedDir, { parseDesignUrl: designParser(options.design) });
99
+ logInvalidDesigns(logger, discovered);
102
100
  const rawViewports = project.viewports;
103
101
  const viewports = resolveViewports(rawViewports, DEFAULT_VIEWPORTS, options.viewports);
104
- const browser = project.browser;
105
- const partition = await partitionAffectedStories({
106
- db: options.db,
107
- tables: options.tables,
108
- projectId: project.id,
109
- branch: build.gitBranch,
110
- defaultBranch: project.gitDefaultBranch,
102
+ const browsers = resolveBrowsers(project);
103
+ assertSupportedBrowsers(browsers, offeredTargets(options.runner, {
104
+ publicOrigin: await options.publicOrigin?.(),
105
+ hasSecret: options.secret !== void 0
106
+ }));
107
+ const storybookUrl = storybookUrlSource(options, {
108
+ build,
109
+ project
110
+ });
111
+ const stories = (await enrichStories({
112
+ runner: options.runner,
113
+ buildId: build.id,
114
+ storybookDir,
115
+ stories: discovered.filter((s) => !isDisabledStory(s)),
116
+ target: browsers[0] ?? "chromium",
117
+ allowlist: parseModesAllowlist(project.modesAllowlist),
118
+ logger,
119
+ storybookUrl
120
+ })).filter((s) => !isDisabledStory(s));
121
+ assertModeCaps(stories, viewports);
122
+ const testRun = await runProjectTests({
123
+ runner: options.runner,
124
+ builds,
125
+ build,
126
+ project,
127
+ storybookDir,
128
+ stories: discovered,
129
+ target: browsers[0] ?? "chromium",
130
+ storybookUrl,
131
+ logger,
132
+ recordLog: input.recordLog
133
+ });
134
+ const fanned = await fanOutCapture({
135
+ options,
136
+ input,
137
+ build,
138
+ project,
111
139
  stories,
112
140
  viewports,
113
- affectedPaths: affectedPathsFor(build)
114
- });
115
- logger?.info({
116
- rendered: partition.render.length,
117
- inherited: partition.inherited.length,
118
- total: stories.length
119
- }, "affected capture partitioned");
120
- await emitAttemptLog(input.recordLog, logger, "info", "affected capture partitioned", {
121
- rendered: partition.render.length,
122
- inherited: partition.inherited.length,
123
- total: stories.length
141
+ browsers,
142
+ logger,
143
+ testFailed: testRun.blocking
124
144
  });
145
+ if (fanned) {
146
+ await cleanScratch();
147
+ return fanned;
148
+ }
125
149
  const renderStart = performance.now();
126
- const renderTimeoutMs = options.renderTimeoutMs ?? 9e5;
127
- const result = await timed("capture.render", async () => await withSpan("capture.render", async () => {
128
- if (partition.render.length === 0) return {
129
- captures: [],
130
- failures: []
131
- };
132
- return await renderWithTimeout(options.runner, {
133
- buildId: build.id,
134
- storybookDir,
135
- stories: partition.render,
136
- viewports,
137
- logger,
138
- executePlay: project.executePlay ?? false,
139
- playTimeoutMs: project.playTimeoutMs ?? 1e4,
140
- runA11y: project.runA11y ?? false,
141
- browser: browser ?? "chromium"
142
- }, renderTimeoutMs);
143
- }, { "storyshelf.render_count": partition.render.length }));
150
+ const matrix = await timed("capture.render", async () => await withSpan("capture.render", async () => await captureAcrossBrowsers({
151
+ db: options.db,
152
+ storage: options.storage,
153
+ tables: options.tables,
154
+ runner: options.runner,
155
+ recordLog: input.recordLog,
156
+ progress: input.progress,
157
+ build,
158
+ project,
159
+ stories,
160
+ viewports,
161
+ storybookDir,
162
+ browsers,
163
+ affectedPaths: affectedPathsFor(build),
164
+ renderTimeoutMs: options.renderTimeoutMs,
165
+ storybookUrl,
166
+ logger
167
+ }), { "storyshelf.browsers": browsers.join(",") }));
168
+ await cleanScratch();
169
+ const result = {
170
+ captures: matrix.captures,
171
+ failures: matrix.failures
172
+ };
144
173
  const renderDuration = performance.now() - renderStart;
145
174
  logger?.info({
146
175
  durationMs: Math.round(renderDuration),
147
- storyCount: stories.length
176
+ storyCount: stories.length,
177
+ browsers
148
178
  }, "stories rendered");
149
179
  await emitAttemptLog(input.recordLog, logger, "info", "stories rendered", {
150
180
  durationMs: Math.round(renderDuration),
151
- storyCount: stories.length
181
+ storyCount: stories.length,
182
+ rendered: matrix.renderCount
152
183
  });
153
- const flakyStoryIds = new Set(stories.filter((s) => isFlakyStory(s)).map((s) => s.id));
154
- const blockingFailed = /* @__PURE__ */ new Set();
155
- const flakyFailed = /* @__PURE__ */ new Set();
156
- const a11yFailed = /* @__PURE__ */ new Set();
157
- for (const f of result.failures) if (f.error.startsWith("a11y:")) a11yFailed.add(f.storyId);
158
- else if (flakyStoryIds.has(f.storyId)) flakyFailed.add(f.storyId);
159
- else blockingFailed.add(f.storyId);
184
+ const { blocking: blockingFailed, flaky: flakyFailed, a11y: a11yFailed } = classifyFailures(stories, result.failures);
185
+ for (const id of testRun.blocking) blockingFailed.add(id);
160
186
  const persistStart = performance.now();
161
187
  await timed("capture.persist", async () => await withSpan("capture.persist", async () => {
162
188
  await persistCapture({
@@ -167,9 +193,11 @@ async function runCapturePhases(input, options, builds, build, project) {
167
193
  build,
168
194
  viewports,
169
195
  captures: result.captures,
170
- inherited: partition.inherited,
196
+ inherited: matrix.inherited,
197
+ browsers,
171
198
  logger,
172
199
  recordLog: input.recordLog,
200
+ progress: input.progress,
173
201
  secret: options.secret
174
202
  }, blockingFailed, flakyFailed, a11yFailed);
175
203
  }));
@@ -184,6 +212,7 @@ async function runCapturePhases(input, options, builds, build, project) {
184
212
  failedCount: blockingFailed.size
185
213
  };
186
214
  } catch (error) {
215
+ await cleanScratch();
187
216
  const totalDuration = performance.now() - startTime;
188
217
  logger?.error({
189
218
  durationMs: Math.round(totalDuration),
@@ -196,25 +225,6 @@ async function runCapturePhases(input, options, builds, build, project) {
196
225
  throw error;
197
226
  }
198
227
  }
199
- /**
200
- * Resolve the affected import paths for a build, or `null` for full capture
201
- * (affected capture disabled, or no computation was posted).
202
- */
203
- function affectedPathsFor(build) {
204
- if (!build.affectedOnly) return null;
205
- return BuildModel.affectedPaths(build);
206
- }
207
- async function loadTarget(options, buildId) {
208
- const build = await new BuildModel(options.db, options.tables).get(buildId);
209
- if (!build) throw new Error(`Build not found: ${buildId}`);
210
- const project = await new ProjectModel(options.db, options.tables).get(build.projectId);
211
- if (!project) throw new Error(`Project not found: ${build.projectId}`);
212
- return {
213
- build,
214
- project
215
- };
216
- }
217
- //#endregion
218
- export { RENDER_TIMEOUT_MS, executeCaptureJob };
228
+ export { executeCaptureJob };
219
229
 
220
230
  //# sourceMappingURL=orchestrator.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator.mjs","names":[],"sources":["../../src/capture/orchestrator.ts"],"sourcesContent":["import type { Logger } from \"pino\";\nimport type { CaptureRunner, RenderResult } from \"../adapters/capture-runner.ts\";\nimport type { BrowserName } from \"../adapters/capture-runner.ts\";\nimport type { DatabaseAdapter } from \"../adapters/database.ts\";\nimport type { StorageAdapter } from \"../adapters/storage.ts\";\nimport { BuildModel, type BuildTables } from \"../models/build.ts\";\nimport {\n emitAttemptLog,\n type AttemptLogRecorder,\n type CaptureAttemptTables,\n} from \"../models/capture-attempt.ts\";\nimport type { CaptureLogTables } from \"../models/capture-log.ts\";\nimport { ProjectModel, type ProjectTables } from \"../models/project.ts\";\nimport type { Build } from \"../schema/build.ts\";\nimport type { Project } from \"../schema/project.ts\";\nimport { parentContext, withSpan } from \"../tracing.ts\";\nimport type { SecretInput } from \"../utils/encrypt.ts\";\nimport { roundedTimings, runWithTimings, timed } from \"../utils/timing.ts\";\nimport { DEFAULT_VIEWPORTS, isDisabledStory, isFlakyStory } from \"./adapter.ts\";\nimport type { Viewport } from \"./adapter.ts\";\nimport { partitionAffectedStories } from \"./affected.ts\";\nimport { persistCapture, type PipelineTables } from \"./pipeline.ts\";\nimport { resolveViewports } from \"./sizing.ts\";\nimport { extractStorybookToScratch, persistStorybookStatics } from \"./statics.ts\";\nimport { StorybookAdapter } from \"./storybook.ts\";\n\n/** Table handles required by the orchestrator. */\nexport type OrchestratorTables = BuildTables &\n ProjectTables &\n PipelineTables &\n CaptureAttemptTables &\n CaptureLogTables;\n\n/** Inputs for running a capture job against a Storybook build. */\nexport interface CaptureJobOptions {\n db: DatabaseAdapter;\n tables: OrchestratorTables;\n storage: StorageAdapter;\n runner: CaptureRunner;\n scratchDir: string;\n viewports?: Viewport[];\n logger?: Logger;\n /** Server secret for decrypting webhook secrets at send time. */\n secret?: SecretInput;\n /** Render budget override (tests use a short fuse). */\n renderTimeoutMs?: number | undefined;\n}\n\n/** Default budget for one render call before the orchestrator cancels it. */\nexport const RENDER_TIMEOUT_MS = 15 * 60_000;\n\n/** Failure error text cap (persisted rows and logs stay bounded). */\nconst FAILURE_ERROR_MAX = 500;\n\n/** Render input assembled by the orchestrator for one build. */\ninterface RenderRequest {\n buildId: string;\n storybookDir: string;\n stories: Parameters<CaptureRunner[\"render\"]>[0][\"stories\"];\n viewports: Parameters<CaptureRunner[\"render\"]>[0][\"viewports\"];\n logger: Logger | undefined;\n executePlay: boolean;\n playTimeoutMs: number;\n runA11y: boolean;\n browser: BrowserName;\n}\n\n/** Cap failure error text so one chatty runner cannot flood rows and logs. */\nfunction capFailures(result: RenderResult): RenderResult {\n return {\n captures: result.captures,\n failures: result.failures.map((failure) => ({\n ...failure,\n error:\n failure.error.length > FAILURE_ERROR_MAX\n ? failure.error.slice(0, FAILURE_ERROR_MAX)\n : failure.error,\n })),\n };\n}\n\n/** Render with a timeout; cancels the runner when the budget expires. */\nasync function renderWithTimeout(\n runner: CaptureRunner,\n request: RenderRequest,\n timeoutMs: number,\n): Promise<RenderResult> {\n let timedOut = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n timedOut = true;\n reject(new Error(`Render timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n });\n timer?.unref?.();\n try {\n return capFailures(await Promise.race([runner.render(request), timeout]));\n } catch (error) {\n if (timedOut) {\n await runner.cancel(request.buildId).catch(() => {});\n }\n throw error;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/** Pointer to the attempt row owning this run's log history. */\nexport interface CaptureAttemptRef {\n id: string;\n attemptNo: number;\n projectId: string;\n}\n\n/** Inputs for running a capture job against a Storybook build. */\nexport interface CaptureJobInput {\n buildId: string;\n reqId?: string;\n /**\n * W3C `traceparent` from the enqueueing request or queue payload.\n * Continues the inbound trace instead of starting a root span.\n */\n traceparent?: string;\n /** Attempt row owning this run; when omitted no per-attempt logs are stored. */\n attempt?: CaptureAttemptRef;\n /** Recorder mirroring phase logs into the attempt's log history. */\n recordLog?: AttemptLogRecorder;\n}\n/**\n * Run the full capture for a build: extract, render, persist, and finalize.\n *\n * The run executes inside a `capture.job` span (continuing `input.traceparent`\n * when present) with one child span per pipeline phase.\n *\n * @param input - Build id plus the originating request id.\n * @param options - Adapters, scratch dir, viewports, and logger.\n * @returns Story and blocking-failure counts for the attempt row.\n */\nexport async function executeCaptureJob(\n input: CaptureJobInput,\n options: CaptureJobOptions,\n): Promise<{ storyCount: number; failedCount: number }> {\n const builds = new BuildModel(options.db, options.tables);\n const { build, project } = await loadTarget(options, input.buildId);\n return await withSpan(\n \"capture.job\",\n async () => {\n const { result, timings } = await runWithTimings(\n async () => await runCapturePhases(input, options, builds, build, project),\n );\n options.logger\n ?.child({ buildId: build.id, ...(input.reqId ? { reqId: input.reqId } : {}) })\n ?.info({ timings: roundedTimings(timings) }, \"capture timings\");\n return result;\n },\n {\n \"storyshelf.build_id\": build.id,\n ...(input.reqId ? { \"storyshelf.req_id\": input.reqId } : {}),\n ...(input.attempt ? { \"storyshelf.attempt_no\": input.attempt.attemptNo } : {}),\n },\n parentContext(input.traceparent),\n );\n}\n\n/** Execute the phase pipeline inside the `capture.job` span. */\nasync function runCapturePhases(\n input: CaptureJobInput,\n options: CaptureJobOptions,\n builds: BuildModel,\n build: Build,\n project: Project,\n): Promise<{ storyCount: number; failedCount: number }> {\n const logger = options.logger?.child({\n buildId: input.buildId,\n reqId: input.reqId,\n ...(input.attempt ? { attemptNo: input.attempt.attemptNo } : {}),\n });\n await builds.setStatus(build.id, \"capturing\");\n\n const startTime = performance.now();\n let extractedDir: string | undefined;\n try {\n const extractStart = performance.now();\n extractedDir = await timed(\n \"capture.extract\",\n async () =>\n await withSpan(\"capture.extract\", async () => {\n return await extractStorybookToScratch(\n options.storage,\n options.scratchDir,\n project.id,\n build.id,\n );\n }),\n );\n const extractDuration = performance.now() - extractStart;\n logger?.info({ durationMs: Math.round(extractDuration) }, \"storybook extracted\");\n await emitAttemptLog(input.recordLog, logger, \"info\", \"storybook extracted\", {\n durationMs: Math.round(extractDuration),\n });\n\n // Persist the extracted statics to storage so the published Storybook\n // (`storybookDir`) can be served after the scratch dir is cleaned up.\n // Copy to a const: closures below need the narrowed string type.\n const storybookDir: string = extractedDir;\n const staticsStart = performance.now();\n await timed(\n \"capture.persist-statics\",\n async () =>\n await withSpan(\"capture.persist-statics\", async () => {\n await persistStorybookStatics(options.storage, storybookDir, project.id, build.id);\n }),\n );\n logger?.info(\n { durationMs: Math.round(performance.now() - staticsStart) },\n \"storybook statics persisted\",\n );\n await emitAttemptLog(input.recordLog, logger, \"info\", \"storybook statics persisted\", {\n durationMs: Math.round(performance.now() - staticsStart),\n });\n\n const adapter = new StorybookAdapter();\n const discovered = await adapter.discover(extractedDir);\n const stories = discovered.filter((s) => !isDisabledStory(s));\n // Resolve viewports via single helper (project JSON → server override → default)\n const rawViewports = (project as unknown as { viewports?: string | null }).viewports;\n const viewports = resolveViewports(rawViewports, DEFAULT_VIEWPORTS, options.viewports);\n const browser = (project as unknown as { browser?: string }).browser as BrowserName | undefined;\n\n const partition = await partitionAffectedStories({\n db: options.db,\n tables: options.tables,\n projectId: project.id,\n branch: build.gitBranch,\n defaultBranch: project.gitDefaultBranch,\n stories,\n viewports,\n affectedPaths: affectedPathsFor(build),\n });\n logger?.info(\n {\n rendered: partition.render.length,\n inherited: partition.inherited.length,\n total: stories.length,\n },\n \"affected capture partitioned\",\n );\n await emitAttemptLog(input.recordLog, logger, \"info\", \"affected capture partitioned\", {\n rendered: partition.render.length,\n inherited: partition.inherited.length,\n total: stories.length,\n });\n\n const renderStart = performance.now();\n const renderTimeoutMs = options.renderTimeoutMs ?? RENDER_TIMEOUT_MS;\n const result = await timed(\n \"capture.render\",\n async () =>\n await withSpan(\n \"capture.render\",\n async () => {\n if (partition.render.length === 0) {\n return { captures: [], failures: [] };\n }\n return await renderWithTimeout(\n options.runner,\n {\n buildId: build.id,\n storybookDir,\n stories: partition.render,\n viewports,\n logger,\n executePlay: project.executePlay ?? false,\n playTimeoutMs: project.playTimeoutMs ?? 10_000,\n runA11y: project.runA11y ?? false,\n browser: browser ?? \"chromium\",\n },\n renderTimeoutMs,\n );\n },\n { \"storyshelf.render_count\": partition.render.length },\n ),\n );\n const renderDuration = performance.now() - renderStart;\n logger?.info(\n { durationMs: Math.round(renderDuration), storyCount: stories.length },\n \"stories rendered\",\n );\n await emitAttemptLog(input.recordLog, logger, \"info\", \"stories rendered\", {\n durationMs: Math.round(renderDuration),\n storyCount: stories.length,\n });\n\n const flakyStoryIds = new Set(stories.filter((s) => isFlakyStory(s)).map((s) => s.id));\n const blockingFailed = new Set<string>();\n const flakyFailed = new Set<string>();\n const a11yFailed = new Set<string>();\n for (const f of result.failures) {\n if (f.error.startsWith(\"a11y:\")) a11yFailed.add(f.storyId);\n else if (flakyStoryIds.has(f.storyId)) flakyFailed.add(f.storyId);\n else blockingFailed.add(f.storyId);\n }\n\n const persistStart = performance.now();\n await timed(\n \"capture.persist\",\n async () =>\n await withSpan(\"capture.persist\", async () => {\n await persistCapture(\n {\n db: options.db,\n tables: options.tables,\n storage: options.storage,\n project,\n build,\n viewports,\n captures: result.captures,\n inherited: partition.inherited,\n logger,\n recordLog: input.recordLog,\n secret: options.secret,\n },\n blockingFailed,\n flakyFailed,\n a11yFailed,\n );\n }),\n );\n const persistDuration = performance.now() - persistStart;\n logger?.info({ durationMs: Math.round(persistDuration) }, \"capture persisted\");\n await emitAttemptLog(input.recordLog, logger, \"info\", \"capture persisted\", {\n durationMs: Math.round(persistDuration),\n });\n\n const totalDuration = performance.now() - startTime;\n logger?.info({ durationMs: Math.round(totalDuration) }, \"capture completed\");\n await emitAttemptLog(input.recordLog, logger, \"info\", \"capture completed\", {\n durationMs: Math.round(totalDuration),\n });\n return { storyCount: stories.length, failedCount: blockingFailed.size };\n } catch (error) {\n const totalDuration = performance.now() - startTime;\n logger?.error({ durationMs: Math.round(totalDuration), err: error }, \"capture failed\");\n await emitAttemptLog(input.recordLog, logger, \"error\", \"capture failed\", {\n durationMs: Math.round(totalDuration),\n });\n await builds.setStatus(build.id, \"failed\").catch((markError: unknown) => {\n logger?.error({ err: markError }, \"failed to mark build failed after capture error\");\n });\n throw error;\n }\n}\n\n/**\n * Resolve the affected import paths for a build, or `null` for full capture\n * (affected capture disabled, or no computation was posted).\n */\nfunction affectedPathsFor(build: Build): string[] | null {\n if (!build.affectedOnly) {\n return null;\n }\n return BuildModel.affectedPaths(build);\n}\n\nasync function loadTarget(\n options: CaptureJobOptions,\n buildId: string,\n): Promise<{ build: Build; project: Project }> {\n const build = await new BuildModel(options.db, options.tables).get(buildId);\n if (!build) {\n throw new Error(`Build not found: ${buildId}`);\n }\n const project = await new ProjectModel(options.db, options.tables).get(build.projectId);\n if (!project) {\n throw new Error(`Project not found: ${build.projectId}`);\n }\n return { build, project };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"orchestrator.mjs","names":[],"sources":["../../src/capture/orchestrator.ts"],"sourcesContent":["import type { Logger } from \"pino\";\nimport type { CaptureRunner } from \"../adapters/capture-runner.ts\";\nimport type { DatabaseAdapter } from \"../adapters/database.ts\";\nimport { parseDesignUrl, type DesignProvider } from \"../adapters/design.ts\";\nimport type { StorageAdapter } from \"../adapters/storage.ts\";\nimport { BuildModel, type BuildTables } from \"../models/build.ts\";\nimport {\n emitAttemptLog,\n type AttemptLogRecorder,\n type CaptureAttemptTables,\n} from \"../models/capture-attempt.ts\";\nimport type { CaptureLogTables } from \"../models/capture-log.ts\";\nimport type { ProjectTables } from \"../models/project.ts\";\nimport type { Build } from \"../schema/build.ts\";\nimport type { Project } from \"../schema/project.ts\";\nimport { parentContext, withSpan } from \"../tracing.ts\";\nimport type { SecretInput } from \"../utils/encrypt.ts\";\nimport { roundedTimings, runWithTimings, timed } from \"../utils/timing.ts\";\nimport { DEFAULT_VIEWPORTS, isDisabledStory } from \"./adapter.ts\";\nimport type { DiscoverOptions, Viewport } from \"./adapter.ts\";\nimport { affectedPathsFor } from \"./affected.ts\";\nimport { assertSupportedBrowsers, resolveBrowsers } from \"./browsers.ts\";\nimport { logInvalidDesigns } from \"./design.ts\";\nimport { assertModeCaps, enrichStories } from \"./enrich.ts\";\nimport { classifyFailures } from \"./failure-sets.ts\";\nimport { captureAcrossBrowsers } from \"./matrix.ts\";\nimport { parseModesAllowlist } from \"./modes.ts\";\nimport { persistCapture, type PipelineTables } from \"./pipeline.ts\";\nimport type { CaptureProgress } from \"./progress.ts\";\nimport type { ExtractionLimits } from \"./publish/limits.ts\";\nimport { removeJobScratch } from \"./scratch.ts\";\nimport { fanOutCapture } from \"./shards/fan-out.ts\";\nimport { resolveViewports } from \"./sizing.ts\";\nimport { extractStorybookToScratch, persistStorybookStatics } from \"./statics.ts\";\nimport { storybookUrlSource } from \"./storybook-urls.ts\";\nimport { StorybookAdapter } from \"./storybook.ts\";\nimport { loadTarget } from \"./target.ts\";\nimport { offeredTargets } from \"./targets.ts\";\nimport { runProjectTests } from \"./tests.ts\";\n\n/** Table handles required by the orchestrator. */\nexport type OrchestratorTables = BuildTables &\n ProjectTables &\n PipelineTables &\n CaptureAttemptTables &\n CaptureLogTables;\n\n/** Inputs for running a capture job against a Storybook build. */\nexport interface CaptureJobOptions {\n db: DatabaseAdapter;\n tables: OrchestratorTables;\n storage: StorageAdapter;\n runner: CaptureRunner;\n scratchDir: string;\n /** Entry and size caps of the zip extraction (`maxZipEntries`, `maxUnzippedBytes`); built-in defaults when unset. */\n limits?: ExtractionLimits | undefined;\n viewports?: Viewport[];\n logger?: Logger;\n /** Server secret for decrypting webhook secrets at send time. */\n secret?: SecretInput;\n /** Design providers validating declared design links; none ⇒ links are not extracted. */\n design?: DesignProvider[];\n /** The resolved public origin (ADR 0007, decision 6); targets that need a URL wait for it. */\n publicOrigin?: (() => Promise<string | undefined>) | undefined;\n /** Render budget override (tests use a short fuse). */\n renderTimeoutMs?: number | undefined;\n /**\n * Target captures (story x viewport x engine) per shard. Unset turns sharding off; a build of up\n * to twice this size still runs as one shard, in this process, exactly as without sharding.\n */\n shardSize?: number | undefined;\n /**\n * Puts a job on the capture queue. Sharding needs it to hand the shards out; without it every\n * build runs in one piece.\n */\n enqueue?: ((job: ShardJob) => Promise<void>) | undefined;\n}\n\n/** A shard job: the build and the `capture_shards` row to render. */\nexport interface ShardJob {\n buildId: string;\n shard: string;\n reqId?: string | undefined;\n traceparent?: string | undefined;\n}\n\n/** Parser over the configured design providers, or undefined when there are none. */\nfunction designParser(providers: DesignProvider[] | undefined): DiscoverOptions[\"parseDesignUrl\"] {\n if (!providers || providers.length === 0) return undefined;\n return (raw) => parseDesignUrl(providers, raw)?.ref ?? null;\n}\n\n/** What a capture job reports: counts for the attempt row, and how many shards it handed out. */\nexport interface CaptureSummary {\n storyCount: number;\n failedCount: number;\n /** Set when the build was split: the shards are still to run and this job did not finish it. */\n shards?: number;\n}\n\n/** Pointer to the attempt row owning this run's log history. */\nexport interface CaptureAttemptRef {\n id: string;\n attemptNo: number;\n projectId: string;\n}\n\n/** Inputs for running a capture job against a Storybook build. */\nexport interface CaptureJobInput {\n buildId: string;\n reqId?: string;\n /**\n * W3C `traceparent` from the enqueueing request or queue payload.\n * Continues the inbound trace instead of starting a root span.\n */\n traceparent?: string;\n /** Attempt row owning this run; when omitted no per-attempt logs are stored. */\n attempt?: CaptureAttemptRef;\n /** Recorder mirroring phase logs into the attempt's log history. */\n recordLog?: AttemptLogRecorder;\n /** Reports render and persist progress to the job's lease, apart from logging. */\n progress?: CaptureProgress | undefined;\n}\n/**\n * Run the full capture for a build: extract, render, persist, and finalize.\n *\n * The run executes inside a `capture.job` span (continuing `input.traceparent`\n * when present) with one child span per pipeline phase.\n *\n * @param input - Build id plus the originating request id.\n * @param options - Adapters, scratch dir, viewports, and logger.\n * @returns Story and blocking-failure counts for the attempt row.\n */\nexport async function executeCaptureJob(\n input: CaptureJobInput,\n options: CaptureJobOptions,\n): Promise<CaptureSummary> {\n const builds = new BuildModel(options.db, options.tables, options.logger);\n const { build, project } = await loadTarget(options, input.buildId);\n return await withSpan(\n \"capture.job\",\n async () => {\n const { result, timings } = await runWithTimings(\n async () => await runCapturePhases(input, options, builds, build, project),\n );\n options.logger\n ?.child({ buildId: build.id, ...(input.reqId ? { reqId: input.reqId } : {}) })\n ?.info({ timings: roundedTimings(timings) }, \"capture timings\");\n return result;\n },\n {\n \"storyshelf.build_id\": build.id,\n ...(input.reqId ? { \"storyshelf.req_id\": input.reqId } : {}),\n ...(input.attempt ? { \"storyshelf.attempt_no\": input.attempt.attemptNo } : {}),\n },\n parentContext(input.traceparent),\n );\n}\n\n/** Execute the phase pipeline inside the `capture.job` span. */\nasync function runCapturePhases(\n input: CaptureJobInput,\n options: CaptureJobOptions,\n builds: BuildModel,\n build: Build,\n project: Project,\n): Promise<CaptureSummary> {\n const logger = options.logger?.child({\n buildId: input.buildId,\n reqId: input.reqId,\n ...(input.attempt ? { attemptNo: input.attempt.attemptNo } : {}),\n });\n if (build.status === \"cancelled\") {\n logger?.info(\"build is cancelled; capture skipped\");\n return { storyCount: 0, failedCount: 0 };\n }\n await builds.setStatus(build.id, \"capturing\");\n\n const startTime = performance.now();\n let extractedDir: string | undefined;\n // Statics are persisted to storage once extracted; the copy on disk is only scratch. Removed as\n // soon as rendering ends (before persist, so no I/O sits between the build's final status and the\n // status fan-out) or on any failure, whichever comes first.\n let scratchPending = true;\n const cleanScratch = async (): Promise<void> => {\n if (scratchPending) {\n scratchPending = false;\n await removeJobScratch(options.scratchDir, project.id, build.id, logger);\n }\n };\n try {\n const extractStart = performance.now();\n extractedDir = await timed(\n \"capture.extract\",\n async () =>\n await withSpan(\"capture.extract\", async () => {\n return await extractStorybookToScratch(\n options.storage,\n options.scratchDir,\n project.id,\n build.id,\n undefined,\n options.limits,\n );\n }),\n );\n const extractDuration = performance.now() - extractStart;\n logger?.info({ durationMs: Math.round(extractDuration) }, \"storybook extracted\");\n await emitAttemptLog(input.recordLog, logger, \"info\", \"storybook extracted\", {\n durationMs: Math.round(extractDuration),\n });\n\n // Persist the extracted statics to storage so the published Storybook\n // (`storybookDir`) can be served after the scratch dir is cleaned up.\n // Copy to a const: closures below need the narrowed string type.\n const storybookDir: string = extractedDir;\n const staticsStart = performance.now();\n await timed(\n \"capture.persist-statics\",\n async () =>\n await withSpan(\"capture.persist-statics\", async () => {\n await persistStorybookStatics(\n options.storage,\n storybookDir,\n project.id,\n build.id,\n options.db,\n );\n }),\n );\n logger?.info(\n { durationMs: Math.round(performance.now() - staticsStart) },\n \"storybook statics persisted\",\n );\n await emitAttemptLog(input.recordLog, logger, \"info\", \"storybook statics persisted\", {\n durationMs: Math.round(performance.now() - staticsStart),\n });\n\n const adapter = new StorybookAdapter();\n const discovered = await adapter.discover(extractedDir, {\n parseDesignUrl: designParser(options.design),\n });\n logInvalidDesigns(logger, discovered);\n // Resolve viewports via single helper (project JSON → server override → default)\n const rawViewports = (project as unknown as { viewports?: string | null }).viewports;\n const viewports = resolveViewports(rawViewports, DEFAULT_VIEWPORTS, options.viewports);\n const browsers = resolveBrowsers(project);\n assertSupportedBrowsers(\n browsers,\n offeredTargets(options.runner, {\n publicOrigin: await options.publicOrigin?.(),\n hasSecret: options.secret !== undefined,\n }),\n );\n const storybookUrl = storybookUrlSource(options, { build, project });\n const enriched = await enrichStories({\n runner: options.runner,\n buildId: build.id,\n storybookDir,\n stories: discovered.filter((s) => !isDisabledStory(s)),\n target: browsers[0] ?? \"chromium\",\n allowlist: parseModesAllowlist(project.modesAllowlist),\n logger,\n storybookUrl,\n });\n const stories = enriched.filter((s) => !isDisabledStory(s));\n assertModeCaps(stories, viewports);\n // Opt-in `.test()` runs: a failing test fails the build like a failing play function.\n const testRun = await runProjectTests({\n runner: options.runner,\n builds,\n build,\n project,\n storybookDir,\n stories: discovered,\n target: browsers[0] ?? \"chromium\",\n storybookUrl,\n logger,\n recordLog: input.recordLog,\n });\n\n // A big build is planned into shards that other workers render; this job's part ends there.\n const fanned = await fanOutCapture({\n options,\n input,\n build,\n project,\n stories,\n viewports,\n browsers,\n logger,\n testFailed: testRun.blocking,\n });\n if (fanned) {\n await cleanScratch();\n return fanned;\n }\n\n const renderStart = performance.now();\n const matrix = await timed(\n \"capture.render\",\n async () =>\n await withSpan(\n \"capture.render\",\n async () =>\n await captureAcrossBrowsers({\n db: options.db,\n storage: options.storage,\n tables: options.tables,\n runner: options.runner,\n recordLog: input.recordLog,\n progress: input.progress,\n build,\n project,\n stories,\n viewports,\n storybookDir,\n browsers,\n affectedPaths: affectedPathsFor(build),\n renderTimeoutMs: options.renderTimeoutMs,\n storybookUrl,\n logger,\n }),\n { \"storyshelf.browsers\": browsers.join(\",\") },\n ),\n );\n await cleanScratch();\n const result = { captures: matrix.captures, failures: matrix.failures };\n const renderDuration = performance.now() - renderStart;\n logger?.info(\n { durationMs: Math.round(renderDuration), storyCount: stories.length, browsers },\n \"stories rendered\",\n );\n await emitAttemptLog(input.recordLog, logger, \"info\", \"stories rendered\", {\n durationMs: Math.round(renderDuration),\n storyCount: stories.length,\n rendered: matrix.renderCount,\n });\n\n const {\n blocking: blockingFailed,\n flaky: flakyFailed,\n a11y: a11yFailed,\n } = classifyFailures(stories, result.failures);\n for (const id of testRun.blocking) blockingFailed.add(id);\n\n const persistStart = performance.now();\n await timed(\n \"capture.persist\",\n async () =>\n await withSpan(\"capture.persist\", async () => {\n await persistCapture(\n {\n db: options.db,\n tables: options.tables,\n storage: options.storage,\n project,\n build,\n viewports,\n captures: result.captures,\n inherited: matrix.inherited,\n browsers,\n logger,\n recordLog: input.recordLog,\n progress: input.progress,\n secret: options.secret,\n },\n blockingFailed,\n flakyFailed,\n a11yFailed,\n );\n }),\n );\n const persistDuration = performance.now() - persistStart;\n logger?.info({ durationMs: Math.round(persistDuration) }, \"capture persisted\");\n await emitAttemptLog(input.recordLog, logger, \"info\", \"capture persisted\", {\n durationMs: Math.round(persistDuration),\n });\n\n const totalDuration = performance.now() - startTime;\n logger?.info({ durationMs: Math.round(totalDuration) }, \"capture completed\");\n await emitAttemptLog(input.recordLog, logger, \"info\", \"capture completed\", {\n durationMs: Math.round(totalDuration),\n });\n return { storyCount: stories.length, failedCount: blockingFailed.size };\n } catch (error) {\n await cleanScratch();\n const totalDuration = performance.now() - startTime;\n logger?.error({ durationMs: Math.round(totalDuration), err: error }, \"capture failed\");\n await emitAttemptLog(input.recordLog, logger, \"error\", \"capture failed\", {\n durationMs: Math.round(totalDuration),\n });\n await builds.setStatus(build.id, \"failed\").catch((markError: unknown) => {\n logger?.error({ err: markError }, \"failed to mark build failed after capture error\");\n });\n throw error;\n }\n}\n"],"mappings":"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"}