@storyshelf/core 0.6.2 → 0.7.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 (628) hide show
  1. package/README.md +49 -32
  2. package/dist/adapter/capture-queue.d.mts +44 -2
  3. package/dist/adapter/capture-runner.d.mts +127 -10
  4. package/dist/adapter/capture-runner.mjs +5 -12
  5. package/dist/adapter/database.d.mts +27 -8
  6. package/dist/adapter/database.mjs.map +1 -1
  7. package/dist/adapter/design.d.mts +85 -0
  8. package/dist/adapter/design.mjs +28 -0
  9. package/dist/adapter/design.mjs.map +1 -0
  10. package/dist/adapter/metadata.d.mts +3 -10
  11. package/dist/adapter/notifier.d.mts +6 -3
  12. package/dist/adapter/notifier.mjs +5 -1
  13. package/dist/adapter/oauth.d.mts +52 -0
  14. package/dist/adapter/setup.d.mts +4 -5
  15. package/dist/adapter/setup.mjs +2 -1
  16. package/dist/adapter/setup.mjs.map +1 -1
  17. package/dist/adapter/webhook-events.mjs +1 -1
  18. package/dist/adapters/capture-target-offers.d.mts +28 -0
  19. package/dist/adapters/capture-target-offers.mjs +58 -0
  20. package/dist/adapters/capture-target-offers.mjs.map +1 -0
  21. package/dist/adapters/capture-target.d.mts +71 -0
  22. package/dist/adapters/capture-target.mjs +76 -0
  23. package/dist/adapters/capture-target.mjs.map +1 -0
  24. package/dist/adapters/notifier/build-comment.d.mts +24 -0
  25. package/dist/adapters/notifier/build-comment.mjs +24 -0
  26. package/dist/adapters/notifier/build-comment.mjs.map +1 -0
  27. package/dist/adapters/notifier/build-state.d.mts +99 -0
  28. package/dist/adapters/notifier/build-state.mjs +218 -0
  29. package/dist/adapters/notifier/build-state.mjs.map +1 -0
  30. package/dist/adapters/notifier/events.d.mts +4 -2
  31. package/dist/adapters/notifier/events.mjs +31 -18
  32. package/dist/adapters/notifier/events.mjs.map +1 -1
  33. package/dist/adapters/notifier/provider.d.mts +53 -7
  34. package/dist/adapters/notifier/provider.mjs +12 -0
  35. package/dist/adapters/notifier/provider.mjs.map +1 -0
  36. package/dist/adapters/notifier/state.d.mts +24 -0
  37. package/dist/adapters/notifier/state.mjs +66 -0
  38. package/dist/adapters/notifier/state.mjs.map +1 -0
  39. package/dist/adapters/notifier/types.d.mts +51 -2
  40. package/dist/adapters/remote-browser.d.mts +87 -0
  41. package/dist/adapters/remote-browser.mjs +103 -0
  42. package/dist/adapters/remote-browser.mjs.map +1 -0
  43. package/dist/adapters/render-runs.d.mts +25 -0
  44. package/dist/adapters/render-runs.mjs +41 -0
  45. package/dist/adapters/render-runs.mjs.map +1 -0
  46. package/dist/adapters/setup-runner.mjs +2 -4
  47. package/dist/adapters/setup-runner.mjs.map +1 -1
  48. package/dist/adapters/sources.d.mts +12 -0
  49. package/dist/adapters/sources.mjs +20 -0
  50. package/dist/adapters/sources.mjs.map +1 -0
  51. package/dist/adapters/validate.mjs +25 -18
  52. package/dist/adapters/validate.mjs.map +1 -1
  53. package/dist/ai.d.mts +105 -0
  54. package/dist/ai.mjs +19 -0
  55. package/dist/ai.mjs.map +1 -0
  56. package/dist/capture/a11y/axe-source.d.mts +18 -0
  57. package/dist/capture/a11y/axe-source.mjs +37 -0
  58. package/dist/capture/a11y/axe-source.mjs.map +1 -0
  59. package/dist/capture/a11y/in-page.d.mts +27 -0
  60. package/dist/capture/a11y/in-page.mjs +60 -0
  61. package/dist/capture/a11y/in-page.mjs.map +1 -0
  62. package/dist/capture/a11y/map.d.mts +24 -0
  63. package/dist/capture/a11y/map.mjs +48 -0
  64. package/dist/capture/a11y/map.mjs.map +1 -0
  65. package/dist/capture/a11y/options.d.mts +23 -0
  66. package/dist/capture/a11y/options.mjs +75 -0
  67. package/dist/capture/a11y/options.mjs.map +1 -0
  68. package/dist/capture/adapter.d.mts +41 -3
  69. package/dist/capture/adapter.mjs.map +1 -1
  70. package/dist/capture/affected.d.mts +2 -0
  71. package/dist/capture/affected.mjs +13 -4
  72. package/dist/capture/affected.mjs.map +1 -1
  73. package/dist/capture/attempt-logger.mjs +84 -0
  74. package/dist/capture/attempt-logger.mjs.map +1 -0
  75. package/dist/capture/browsers.d.mts +35 -0
  76. package/dist/capture/browsers.mjs +67 -0
  77. package/dist/capture/browsers.mjs.map +1 -0
  78. package/dist/capture/build-state/deliver.d.mts +32 -0
  79. package/dist/capture/build-state/deliver.mjs +118 -0
  80. package/dist/capture/build-state/deliver.mjs.map +1 -0
  81. package/dist/capture/build-state/index.d.mts +8 -0
  82. package/dist/capture/build-state/notify-job.d.mts +56 -0
  83. package/dist/capture/build-state/notify-job.mjs +133 -0
  84. package/dist/capture/build-state/notify-job.mjs.map +1 -0
  85. package/dist/capture/build-state/publisher.d.mts +23 -0
  86. package/dist/capture/build-state/publisher.mjs +107 -0
  87. package/dist/capture/build-state/publisher.mjs.map +1 -0
  88. package/dist/capture/build-state/resume.d.mts +9 -0
  89. package/dist/capture/build-state/resume.mjs +47 -0
  90. package/dist/capture/build-state/resume.mjs.map +1 -0
  91. package/dist/capture/build-state/types.d.mts +49 -0
  92. package/dist/capture/catalog/catalogue.d.mts +22 -0
  93. package/dist/capture/catalog/catalogue.mjs +53 -0
  94. package/dist/capture/catalog/catalogue.mjs.map +1 -0
  95. package/dist/capture/catalog/components.d.mts +23 -0
  96. package/dist/capture/catalog/components.mjs +55 -0
  97. package/dist/capture/catalog/components.mjs.map +1 -0
  98. package/dist/capture/catalog/history.d.mts +30 -0
  99. package/dist/capture/catalog/history.mjs +51 -0
  100. package/dist/capture/catalog/history.mjs.map +1 -0
  101. package/dist/capture/catalog/hook.d.mts +14 -0
  102. package/dist/capture/catalog/hook.mjs +19 -0
  103. package/dist/capture/catalog/hook.mjs.map +1 -0
  104. package/dist/capture/catalog/index.d.mts +11 -0
  105. package/dist/capture/catalog/load.d.mts +26 -0
  106. package/dist/capture/catalog/load.mjs +49 -0
  107. package/dist/capture/catalog/load.mjs.map +1 -0
  108. package/dist/capture/catalog/parse.d.mts +15 -0
  109. package/dist/capture/catalog/parse.mjs +56 -0
  110. package/dist/capture/catalog/parse.mjs.map +1 -0
  111. package/dist/capture/catalog/read.d.mts +12 -0
  112. package/dist/capture/catalog/read.mjs +33 -0
  113. package/dist/capture/catalog/read.mjs.map +1 -0
  114. package/dist/capture/catalog/types.d.mts +33 -0
  115. package/dist/capture/consumer/capture-handler.d.mts +58 -0
  116. package/dist/capture/consumer/capture-handler.mjs +118 -0
  117. package/dist/capture/consumer/capture-handler.mjs.map +1 -0
  118. package/dist/capture/consumer/idle.d.mts +17 -0
  119. package/dist/capture/consumer/idle.mjs +25 -0
  120. package/dist/capture/consumer/idle.mjs.map +1 -0
  121. package/dist/capture/consumer/index.d.mts +13 -0
  122. package/dist/capture/consumer/index.mjs +139 -0
  123. package/dist/capture/consumer/index.mjs.map +1 -0
  124. package/dist/capture/consumer/loop.mjs +110 -0
  125. package/dist/capture/consumer/loop.mjs.map +1 -0
  126. package/dist/capture/consumer/metrics.d.mts +41 -0
  127. package/dist/capture/consumer/metrics.mjs +38 -0
  128. package/dist/capture/consumer/metrics.mjs.map +1 -0
  129. package/dist/capture/consumer/retry.d.mts +33 -0
  130. package/dist/capture/consumer/retry.mjs +34 -0
  131. package/dist/capture/consumer/retry.mjs.map +1 -0
  132. package/dist/capture/consumer/run-job.mjs +195 -0
  133. package/dist/capture/consumer/run-job.mjs.map +1 -0
  134. package/dist/capture/consumer/startup.mjs +38 -0
  135. package/dist/capture/consumer/startup.mjs.map +1 -0
  136. package/dist/capture/consumer/types.d.mts +97 -0
  137. package/dist/capture/crash-failure.d.mts +25 -0
  138. package/dist/capture/crash-failure.mjs +70 -0
  139. package/dist/capture/crash-failure.mjs.map +1 -0
  140. package/dist/capture/db-queue/cadence.d.mts +32 -0
  141. package/dist/capture/db-queue/cadence.mjs +38 -0
  142. package/dist/capture/db-queue/cadence.mjs.map +1 -0
  143. package/dist/capture/db-queue/claim.d.mts +9 -0
  144. package/dist/capture/db-queue/claim.mjs +132 -0
  145. package/dist/capture/db-queue/claim.mjs.map +1 -0
  146. package/dist/capture/db-queue/clock.mjs +12 -0
  147. package/dist/capture/db-queue/clock.mjs.map +1 -0
  148. package/dist/capture/db-queue/codec.mjs +76 -0
  149. package/dist/capture/db-queue/codec.mjs.map +1 -0
  150. package/dist/capture/db-queue/index.d.mts +20 -0
  151. package/dist/capture/db-queue/index.mjs +89 -0
  152. package/dist/capture/db-queue/index.mjs.map +1 -0
  153. package/dist/capture/db-queue/keeper.d.mts +36 -0
  154. package/dist/capture/db-queue/keeper.mjs +92 -0
  155. package/dist/capture/db-queue/keeper.mjs.map +1 -0
  156. package/dist/capture/db-queue/lease.mjs +46 -0
  157. package/dist/capture/db-queue/lease.mjs.map +1 -0
  158. package/dist/capture/db-queue/lifecycle.mjs +36 -0
  159. package/dist/capture/db-queue/lifecycle.mjs.map +1 -0
  160. package/dist/capture/db-queue/operations.mjs +94 -0
  161. package/dist/capture/db-queue/operations.mjs.map +1 -0
  162. package/dist/capture/db-queue/poll-loop.d.mts +30 -0
  163. package/dist/capture/db-queue/poll-loop.mjs +89 -0
  164. package/dist/capture/db-queue/poll-loop.mjs.map +1 -0
  165. package/dist/capture/db-queue/poll.d.mts +10 -0
  166. package/dist/capture/db-queue/poll.mjs +69 -0
  167. package/dist/capture/db-queue/poll.mjs.map +1 -0
  168. package/dist/capture/db-queue/timers.d.mts +12 -0
  169. package/dist/capture/db-queue/timers.mjs +37 -0
  170. package/dist/capture/db-queue/timers.mjs.map +1 -0
  171. package/dist/capture/db-queue/types.d.mts +83 -0
  172. package/dist/capture/db-queue/types.mjs +12 -0
  173. package/dist/capture/db-queue/types.mjs.map +1 -0
  174. package/dist/capture/db-queue/wake.mjs +48 -0
  175. package/dist/capture/db-queue/wake.mjs.map +1 -0
  176. package/dist/capture/design.mjs +39 -0
  177. package/dist/capture/design.mjs.map +1 -0
  178. package/dist/capture/diff-record.mjs +23 -3
  179. package/dist/capture/diff-record.mjs.map +1 -1
  180. package/dist/capture/dispatch.d.mts +12 -7
  181. package/dist/capture/dispatch.mjs +86 -107
  182. package/dist/capture/dispatch.mjs.map +1 -1
  183. package/dist/capture/enrich.mjs +60 -0
  184. package/dist/capture/enrich.mjs.map +1 -0
  185. package/dist/capture/failure-sets.mjs +22 -0
  186. package/dist/capture/failure-sets.mjs.map +1 -0
  187. package/dist/capture/fingerprint.d.mts +42 -0
  188. package/dist/capture/fingerprint.mjs +83 -0
  189. package/dist/capture/fingerprint.mjs.map +1 -0
  190. package/dist/capture/forked/channel.d.mts +25 -0
  191. package/dist/capture/forked/child.d.mts +34 -0
  192. package/dist/capture/forked/child.mjs +202 -0
  193. package/dist/capture/forked/child.mjs.map +1 -0
  194. package/dist/capture/forked/crash-tracker.mjs +23 -0
  195. package/dist/capture/forked/crash-tracker.mjs.map +1 -0
  196. package/dist/capture/forked/decision.d.mts +26 -0
  197. package/dist/capture/forked/decision.mjs +27 -0
  198. package/dist/capture/forked/decision.mjs.map +1 -0
  199. package/dist/capture/forked/exit.mjs +12 -0
  200. package/dist/capture/forked/exit.mjs.map +1 -0
  201. package/dist/capture/forked/fork.d.mts +31 -0
  202. package/dist/capture/forked/fork.mjs +93 -0
  203. package/dist/capture/forked/fork.mjs.map +1 -0
  204. package/dist/capture/forked/forked-capture.d.mts +40 -0
  205. package/dist/capture/forked/forked-capture.mjs +240 -0
  206. package/dist/capture/forked/forked-capture.mjs.map +1 -0
  207. package/dist/capture/forked/lease-book.mjs +46 -0
  208. package/dist/capture/forked/lease-book.mjs.map +1 -0
  209. package/dist/capture/forked/protocol.d.mts +38 -0
  210. package/dist/capture/forked/protocol.mjs +25 -0
  211. package/dist/capture/forked/protocol.mjs.map +1 -0
  212. package/dist/capture/forked/runs.mjs +75 -0
  213. package/dist/capture/forked/runs.mjs.map +1 -0
  214. package/dist/capture/isolate.mjs +141 -0
  215. package/dist/capture/isolate.mjs.map +1 -0
  216. package/dist/capture/job-lease.d.mts +28 -0
  217. package/dist/capture/job-lease.mjs +57 -0
  218. package/dist/capture/job-lease.mjs.map +1 -0
  219. package/dist/capture/matrix.mjs +298 -0
  220. package/dist/capture/matrix.mjs.map +1 -0
  221. package/dist/capture/modes.d.mts +25 -0
  222. package/dist/capture/modes.mjs +107 -0
  223. package/dist/capture/modes.mjs.map +1 -0
  224. package/dist/capture/orchestrator.d.mts +37 -5
  225. package/dist/capture/orchestrator.mjs +118 -107
  226. package/dist/capture/orchestrator.mjs.map +1 -1
  227. package/dist/capture/pipeline.d.mts +9 -2
  228. package/dist/capture/pipeline.mjs +250 -45
  229. package/dist/capture/pipeline.mjs.map +1 -1
  230. package/dist/capture/progress.d.mts +11 -0
  231. package/dist/capture/progress.mjs +28 -0
  232. package/dist/capture/progress.mjs.map +1 -0
  233. package/dist/capture/publish/accept.d.mts +39 -0
  234. package/dist/capture/publish/accept.mjs +28 -0
  235. package/dist/capture/publish/accept.mjs.map +1 -0
  236. package/dist/capture/publish/complete.d.mts +46 -0
  237. package/dist/capture/publish/complete.mjs +64 -0
  238. package/dist/capture/publish/complete.mjs.map +1 -0
  239. package/dist/capture/publish/extract.d.mts +20 -0
  240. package/dist/capture/publish/extract.mjs +119 -0
  241. package/dist/capture/publish/extract.mjs.map +1 -0
  242. package/dist/capture/publish/handler.d.mts +28 -0
  243. package/dist/capture/publish/handler.mjs +62 -0
  244. package/dist/capture/publish/handler.mjs.map +1 -0
  245. package/dist/capture/publish/index.d.mts +10 -0
  246. package/dist/capture/publish/limits.d.mts +37 -0
  247. package/dist/capture/publish/limits.mjs +39 -0
  248. package/dist/capture/publish/limits.mjs.map +1 -0
  249. package/dist/capture/publish/published.d.mts +15 -0
  250. package/dist/capture/publish/published.mjs +18 -0
  251. package/dist/capture/publish/published.mjs.map +1 -0
  252. package/dist/capture/publish/run.d.mts +33 -0
  253. package/dist/capture/publish/run.mjs +30 -0
  254. package/dist/capture/publish/run.mjs.map +1 -0
  255. package/dist/capture/rediff.d.mts +1 -1
  256. package/dist/capture/rediff.mjs +4 -3
  257. package/dist/capture/rediff.mjs.map +1 -1
  258. package/dist/capture/render.mjs +53 -0
  259. package/dist/capture/render.mjs.map +1 -0
  260. package/dist/capture/scratch.d.mts +44 -0
  261. package/dist/capture/scratch.mjs +138 -0
  262. package/dist/capture/scratch.mjs.map +1 -0
  263. package/dist/capture/shard-plan.mjs +128 -0
  264. package/dist/capture/shard-plan.mjs.map +1 -0
  265. package/dist/capture/shards/context.mjs +51 -0
  266. package/dist/capture/shards/context.mjs.map +1 -0
  267. package/dist/capture/shards/execute.mjs +174 -0
  268. package/dist/capture/shards/execute.mjs.map +1 -0
  269. package/dist/capture/shards/fan-out.mjs +126 -0
  270. package/dist/capture/shards/fan-out.mjs.map +1 -0
  271. package/dist/capture/shards/history.mjs +35 -0
  272. package/dist/capture/shards/history.mjs.map +1 -0
  273. package/dist/capture/shards/reduce.mjs +97 -0
  274. package/dist/capture/shards/reduce.mjs.map +1 -0
  275. package/dist/capture/sizing.mjs +1 -11
  276. package/dist/capture/sizing.mjs.map +1 -1
  277. package/dist/capture/skip-checks.mjs +2 -65
  278. package/dist/capture/skip-checks.mjs.map +1 -1
  279. package/dist/capture/statics.d.mts +7 -8
  280. package/dist/capture/statics.mjs +25 -71
  281. package/dist/capture/statics.mjs.map +1 -1
  282. package/dist/capture/storybook-urls.d.mts +40 -0
  283. package/dist/capture/storybook-urls.mjs +41 -0
  284. package/dist/capture/storybook-urls.mjs.map +1 -0
  285. package/dist/capture/storybook.d.mts +12 -4
  286. package/dist/capture/storybook.mjs +56 -16
  287. package/dist/capture/storybook.mjs.map +1 -1
  288. package/dist/capture/target.mjs +21 -0
  289. package/dist/capture/target.mjs.map +1 -0
  290. package/dist/capture/targets.d.mts +25 -0
  291. package/dist/capture/targets.mjs +32 -0
  292. package/dist/capture/targets.mjs.map +1 -0
  293. package/dist/capture/tests.d.mts +37 -0
  294. package/dist/capture/tests.mjs +126 -0
  295. package/dist/capture/tests.mjs.map +1 -0
  296. package/dist/capture/token-chunks.mjs +74 -0
  297. package/dist/capture/token-chunks.mjs.map +1 -0
  298. package/dist/capture.d.mts +60 -7
  299. package/dist/capture.mjs +48 -3
  300. package/dist/config.d.mts +121 -12
  301. package/dist/config.mjs +9 -6
  302. package/dist/config.mjs.map +1 -1
  303. package/dist/diff.d.mts +9 -3
  304. package/dist/diff.mjs +16 -3
  305. package/dist/diff.mjs.map +1 -0
  306. package/dist/index.d.mts +1 -1
  307. package/dist/insights/budget.d.mts +20 -0
  308. package/dist/insights/budget.mjs +33 -0
  309. package/dist/insights/budget.mjs.map +1 -0
  310. package/dist/insights/envelope.d.mts +59 -0
  311. package/dist/insights/envelope.mjs +60 -0
  312. package/dist/insights/envelope.mjs.map +1 -0
  313. package/dist/insights/evidence-health.d.mts +32 -0
  314. package/dist/insights/evidence-health.mjs +28 -0
  315. package/dist/insights/evidence-health.mjs.map +1 -0
  316. package/dist/insights/evidence.d.mts +55 -0
  317. package/dist/insights/evidence.mjs +64 -0
  318. package/dist/insights/evidence.mjs.map +1 -0
  319. package/dist/insights/hash.d.mts +18 -0
  320. package/dist/insights/hash.mjs +21 -0
  321. package/dist/insights/hash.mjs.map +1 -0
  322. package/dist/insights/limits.d.mts +24 -0
  323. package/dist/insights/limits.mjs +24 -0
  324. package/dist/insights/limits.mjs.map +1 -0
  325. package/dist/insights/prompts/v1.d.mts +13 -0
  326. package/dist/insights/prompts/v1.mjs +34 -0
  327. package/dist/insights/prompts/v1.mjs.map +1 -0
  328. package/dist/insights/redact.d.mts +9 -0
  329. package/dist/insights/redact.mjs +24 -0
  330. package/dist/insights/redact.mjs.map +1 -0
  331. package/dist/insights/text.mjs +44 -0
  332. package/dist/insights/text.mjs.map +1 -0
  333. package/dist/insights.d.mts +11 -0
  334. package/dist/insights.mjs +12 -0
  335. package/dist/logger.mjs +17 -1
  336. package/dist/logger.mjs.map +1 -1
  337. package/dist/models/ai-budget-alert.d.mts +23 -0
  338. package/dist/models/ai-budget-alert.mjs +38 -0
  339. package/dist/models/ai-budget-alert.mjs.map +1 -0
  340. package/dist/models/ai-usage.d.mts +40 -0
  341. package/dist/models/ai-usage.mjs +61 -0
  342. package/dist/models/ai-usage.mjs.map +1 -0
  343. package/dist/models/baseline-archive.d.mts +84 -0
  344. package/dist/models/baseline-archive.mjs +106 -0
  345. package/dist/models/baseline-archive.mjs.map +1 -0
  346. package/dist/models/baseline-export.d.mts +19 -0
  347. package/dist/models/baseline-export.mjs +136 -0
  348. package/dist/models/baseline-export.mjs.map +1 -0
  349. package/dist/models/baseline-import.mjs +118 -0
  350. package/dist/models/baseline-import.mjs.map +1 -0
  351. package/dist/models/baseline-transfer.d.mts +49 -0
  352. package/dist/models/baseline-transfer.mjs +121 -0
  353. package/dist/models/baseline-transfer.mjs.map +1 -0
  354. package/dist/models/baseline.d.mts +32 -5
  355. package/dist/models/baseline.mjs +65 -20
  356. package/dist/models/baseline.mjs.map +1 -1
  357. package/dist/models/build-component.d.mts +28 -0
  358. package/dist/models/build-component.mjs +55 -0
  359. package/dist/models/build-component.mjs.map +1 -0
  360. package/dist/models/build-review-status.d.mts +29 -0
  361. package/dist/models/build-review-status.mjs +37 -0
  362. package/dist/models/build-review-status.mjs.map +1 -0
  363. package/dist/models/build-review.d.mts +28 -0
  364. package/dist/models/build-review.mjs +54 -0
  365. package/dist/models/build-review.mjs.map +1 -0
  366. package/dist/models/build.d.mts +25 -3
  367. package/dist/models/build.mjs +50 -11
  368. package/dist/models/build.mjs.map +1 -1
  369. package/dist/models/capture-attempt.d.mts +7 -1
  370. package/dist/models/capture-attempt.mjs +29 -4
  371. package/dist/models/capture-attempt.mjs.map +1 -1
  372. package/dist/models/capture-job.d.mts +106 -0
  373. package/dist/models/capture-job.mjs +288 -0
  374. package/dist/models/capture-job.mjs.map +1 -0
  375. package/dist/models/capture-log.d.mts +1 -1
  376. package/dist/models/capture-log.mjs +4 -3
  377. package/dist/models/capture-log.mjs.map +1 -1
  378. package/dist/models/capture-shard.d.mts +62 -0
  379. package/dist/models/capture-shard.mjs +190 -0
  380. package/dist/models/capture-shard.mjs.map +1 -0
  381. package/dist/models/changeset.d.mts +48 -0
  382. package/dist/models/changeset.mjs +81 -0
  383. package/dist/models/changeset.mjs.map +1 -0
  384. package/dist/models/columns.mjs +19 -0
  385. package/dist/models/columns.mjs.map +1 -0
  386. package/dist/models/comment.d.mts +4 -1
  387. package/dist/models/comment.mjs +7 -4
  388. package/dist/models/comment.mjs.map +1 -1
  389. package/dist/models/component.d.mts +43 -0
  390. package/dist/models/component.mjs +60 -0
  391. package/dist/models/component.mjs.map +1 -0
  392. package/dist/models/connections.d.mts +41 -0
  393. package/dist/models/connections.mjs +112 -0
  394. package/dist/models/connections.mjs.map +1 -0
  395. package/dist/models/content-ref.d.mts +1 -1
  396. package/dist/models/content-ref.mjs +1 -1
  397. package/dist/models/content-ref.mjs.map +1 -1
  398. package/dist/models/credentials.mjs +12 -2
  399. package/dist/models/credentials.mjs.map +1 -1
  400. package/dist/models/design-credentials.d.mts +41 -0
  401. package/dist/models/design-credentials.mjs +86 -0
  402. package/dist/models/design-credentials.mjs.map +1 -0
  403. package/dist/models/design-health.d.mts +16 -0
  404. package/dist/models/design-health.mjs +25 -0
  405. package/dist/models/design-health.mjs.map +1 -0
  406. package/dist/models/design-nodes.d.mts +83 -0
  407. package/dist/models/design-nodes.mjs +222 -0
  408. package/dist/models/design-nodes.mjs.map +1 -0
  409. package/dist/models/design-renders.mjs +74 -0
  410. package/dist/models/design-renders.mjs.map +1 -0
  411. package/dist/models/design-resolve.d.mts +29 -0
  412. package/dist/models/design-resolve.mjs +41 -0
  413. package/dist/models/design-resolve.mjs.map +1 -0
  414. package/dist/models/design.d.mts +39 -0
  415. package/dist/models/design.mjs +90 -0
  416. package/dist/models/design.mjs.map +1 -0
  417. package/dist/models/inherited-ratio.d.mts +21 -0
  418. package/dist/models/inherited-ratio.mjs +22 -0
  419. package/dist/models/inherited-ratio.mjs.map +1 -0
  420. package/dist/models/insight.d.mts +70 -0
  421. package/dist/models/insight.mjs +162 -0
  422. package/dist/models/insight.mjs.map +1 -0
  423. package/dist/models/label.d.mts +4 -2
  424. package/dist/models/label.mjs +25 -10
  425. package/dist/models/label.mjs.map +1 -1
  426. package/dist/models/member.d.mts +1 -1
  427. package/dist/models/member.mjs +5 -4
  428. package/dist/models/member.mjs.map +1 -1
  429. package/dist/models/notification-channel.d.mts +37 -3
  430. package/dist/models/notification-channel.mjs +88 -9
  431. package/dist/models/notification-channel.mjs.map +1 -1
  432. package/dist/models/notification-subscription.d.mts +1 -2
  433. package/dist/models/notification-subscription.mjs +7 -9
  434. package/dist/models/notification-subscription.mjs.map +1 -1
  435. package/dist/models/project-group-mapping.d.mts +6 -1
  436. package/dist/models/project-group-mapping.mjs +14 -4
  437. package/dist/models/project-group-mapping.mjs.map +1 -1
  438. package/dist/models/project.d.mts +9 -1
  439. package/dist/models/project.mjs +9 -4
  440. package/dist/models/project.mjs.map +1 -1
  441. package/dist/models/public-origin.d.mts +63 -0
  442. package/dist/models/public-origin.mjs +114 -0
  443. package/dist/models/public-origin.mjs.map +1 -0
  444. package/dist/models/review-switch-off.d.mts +14 -0
  445. package/dist/models/review-switch-off.mjs +26 -0
  446. package/dist/models/review-switch-off.mjs.map +1 -0
  447. package/dist/models/site-settings.d.mts +23 -0
  448. package/dist/models/site-settings.mjs +48 -0
  449. package/dist/models/site-settings.mjs.map +1 -0
  450. package/dist/models/snapshot.d.mts +36 -1
  451. package/dist/models/snapshot.mjs +50 -3
  452. package/dist/models/snapshot.mjs.map +1 -1
  453. package/dist/models/token.d.mts +13 -1
  454. package/dist/models/token.mjs +23 -5
  455. package/dist/models/token.mjs.map +1 -1
  456. package/dist/models/usage.d.mts +76 -0
  457. package/dist/models/usage.mjs +149 -0
  458. package/dist/models/usage.mjs.map +1 -0
  459. package/dist/models/user.d.mts +1 -1
  460. package/dist/models/user.mjs +4 -3
  461. package/dist/models/user.mjs.map +1 -1
  462. package/dist/models/webhook.d.mts +15 -1
  463. package/dist/models/webhook.mjs +33 -4
  464. package/dist/models/webhook.mjs.map +1 -1
  465. package/dist/models.d.mts +26 -3
  466. package/dist/models.mjs +27 -5
  467. package/dist/options.d.mts +18 -0
  468. package/dist/options.mjs +90 -0
  469. package/dist/options.mjs.map +1 -0
  470. package/dist/paths.d.mts +19 -4
  471. package/dist/paths.mjs +51 -10
  472. package/dist/paths.mjs.map +1 -1
  473. package/dist/retention/ai.d.mts +18 -0
  474. package/dist/retention/ai.mjs +23 -0
  475. package/dist/retention/ai.mjs.map +1 -0
  476. package/dist/retention/pending.mjs +47 -0
  477. package/dist/retention/pending.mjs.map +1 -0
  478. package/dist/retention/screenshot-sweep.d.mts +51 -0
  479. package/dist/retention/screenshot-sweep.mjs +128 -0
  480. package/dist/retention/screenshot-sweep.mjs.map +1 -0
  481. package/dist/retention.d.mts +16 -2
  482. package/dist/retention.mjs +71 -14
  483. package/dist/retention.mjs.map +1 -1
  484. package/dist/schema/baseline.d.mts +6 -0
  485. package/dist/schema/build-component.d.mts +25 -0
  486. package/dist/schema/build-review.d.mts +17 -0
  487. package/dist/schema/build.d.mts +7 -0
  488. package/dist/schema/capture-job.d.mts +60 -0
  489. package/dist/schema/capture-shard.d.mts +35 -0
  490. package/dist/schema/comment.d.mts +2 -0
  491. package/dist/schema/connection.d.mts +24 -0
  492. package/dist/schema/design.d.mts +58 -0
  493. package/dist/schema/insight.d.mts +54 -0
  494. package/dist/schema/notification.d.mts +4 -0
  495. package/dist/schema/project.d.mts +21 -0
  496. package/dist/schema/site-setting.d.mts +21 -0
  497. package/dist/schema/snapshot.d.mts +12 -0
  498. package/dist/schema/usage.d.mts +30 -0
  499. package/dist/schema.d.mts +11 -3
  500. package/dist/serverless.d.mts +21 -0
  501. package/dist/serverless.mjs +37 -0
  502. package/dist/serverless.mjs.map +1 -0
  503. package/dist/test-helpers/create-project.d.mts +1 -1
  504. package/dist/test-helpers/deferred.d.mts +39 -0
  505. package/dist/test-helpers/deferred.mjs +61 -0
  506. package/dist/test-helpers/deferred.mjs.map +1 -0
  507. package/dist/test-helpers/design-contract.d.mts +21 -0
  508. package/dist/test-helpers/design-contract.mjs +40 -0
  509. package/dist/test-helpers/design-contract.mjs.map +1 -0
  510. package/dist/test-helpers/fake-database.mjs +14 -2
  511. package/dist/test-helpers/fake-database.mjs.map +1 -1
  512. package/dist/test-helpers/fake-design.d.mts +43 -0
  513. package/dist/test-helpers/fake-design.mjs +114 -0
  514. package/dist/test-helpers/fake-design.mjs.map +1 -0
  515. package/dist/test-helpers/fake-notifier.d.mts +21 -0
  516. package/dist/test-helpers/fake-notifier.mjs +44 -0
  517. package/dist/test-helpers/fake-notifier.mjs.map +1 -0
  518. package/dist/test-helpers/fake-tables.mjs +255 -67
  519. package/dist/test-helpers/fake-tables.mjs.map +1 -1
  520. package/dist/test-helpers/manual-clock.d.mts +27 -0
  521. package/dist/test-helpers/manual-clock.mjs +56 -0
  522. package/dist/test-helpers/manual-clock.mjs.map +1 -0
  523. package/dist/test-helpers/notifier-contract.d.mts +7 -1
  524. package/dist/test-helpers/notifier-contract.mjs +32 -3
  525. package/dist/test-helpers/notifier-contract.mjs.map +1 -1
  526. package/dist/test-helpers/queue-contract.d.mts +16 -2
  527. package/dist/test-helpers/queue-contract.mjs +195 -1
  528. package/dist/test-helpers/queue-contract.mjs.map +1 -1
  529. package/dist/test-helpers/queue-multi-instance.d.mts +20 -0
  530. package/dist/test-helpers/queue-multi-instance.mjs +206 -0
  531. package/dist/test-helpers/queue-multi-instance.mjs.map +1 -0
  532. package/dist/test-helpers/runner-contract.mjs +11 -0
  533. package/dist/test-helpers/runner-contract.mjs.map +1 -1
  534. package/dist/test-helpers/sql-chunks.mjs +23 -0
  535. package/dist/test-helpers/sql-chunks.mjs.map +1 -1
  536. package/dist/test-helpers/storage-contract.mjs +1 -1
  537. package/dist/test-helpers.d.mts +9 -4
  538. package/dist/test-helpers.mjs +8 -3
  539. package/dist/types.d.mts +14 -3
  540. package/dist/types.mjs +21 -4
  541. package/dist/types.mjs.map +1 -1
  542. package/dist/urls.d.mts +4 -0
  543. package/dist/urls.mjs +11 -2
  544. package/dist/urls.mjs.map +1 -1
  545. package/dist/utils/adaptive-concurrency.d.mts +66 -0
  546. package/dist/utils/adaptive-concurrency.mjs +149 -0
  547. package/dist/utils/adaptive-concurrency.mjs.map +1 -0
  548. package/dist/utils/connect-retry.d.mts +26 -0
  549. package/dist/utils/connect-retry.mjs +43 -0
  550. package/dist/utils/connect-retry.mjs.map +1 -0
  551. package/dist/utils/environment.d.mts +19 -0
  552. package/dist/utils/environment.mjs +59 -0
  553. package/dist/utils/environment.mjs.map +1 -0
  554. package/dist/utils/http.d.mts +17 -1
  555. package/dist/utils/http.mjs +22 -3
  556. package/dist/utils/http.mjs.map +1 -1
  557. package/dist/utils/map-adaptive.d.mts +15 -0
  558. package/dist/utils/map-adaptive.mjs +72 -0
  559. package/dist/utils/map-adaptive.mjs.map +1 -0
  560. package/dist/utils/map-limit.d.mts +10 -0
  561. package/dist/utils/map-limit.mjs +32 -0
  562. package/dist/utils/map-limit.mjs.map +1 -0
  563. package/dist/utils/page-limiter.d.mts +37 -0
  564. package/dist/utils/page-limiter.mjs +56 -0
  565. package/dist/utils/page-limiter.mjs.map +1 -0
  566. package/dist/utils/public-origin.d.mts +20 -0
  567. package/dist/utils/public-origin.mjs +75 -0
  568. package/dist/utils/public-origin.mjs.map +1 -0
  569. package/dist/utils/redact.mjs +3 -0
  570. package/dist/utils/redact.mjs.map +1 -1
  571. package/dist/utils/remote-environment.d.mts +39 -0
  572. package/dist/utils/remote-environment.mjs +114 -0
  573. package/dist/utils/remote-environment.mjs.map +1 -0
  574. package/dist/utils/resources.d.mts +64 -0
  575. package/dist/utils/resources.mjs +122 -0
  576. package/dist/utils/resources.mjs.map +1 -0
  577. package/dist/utils/screenshot-store.d.mts +15 -0
  578. package/dist/utils/screenshot-store.mjs +41 -0
  579. package/dist/utils/screenshot-store.mjs.map +1 -0
  580. package/dist/utils/session-gate.d.mts +22 -0
  581. package/dist/utils/session-gate.mjs +53 -0
  582. package/dist/utils/session-gate.mjs.map +1 -0
  583. package/dist/utils/storybook-token.d.mts +81 -0
  584. package/dist/utils/storybook-token.mjs +134 -0
  585. package/dist/utils/storybook-token.mjs.map +1 -0
  586. package/dist/utils/storybook-url.d.mts +15 -0
  587. package/dist/utils/storybook-url.mjs +21 -0
  588. package/dist/utils/storybook-url.mjs.map +1 -0
  589. package/dist/utils/timing.mjs +1 -1
  590. package/dist/utils/timing.mjs.map +1 -1
  591. package/dist/utils/zip-read.mjs +129 -0
  592. package/dist/utils/zip-read.mjs.map +1 -0
  593. package/dist/utils/zip-write.d.mts +18 -0
  594. package/dist/utils/zip-write.mjs +188 -0
  595. package/dist/utils/zip-write.mjs.map +1 -0
  596. package/dist/utils.d.mts +17 -3
  597. package/dist/utils.mjs +18 -4
  598. package/package.json +32 -23
  599. package/dist/adapter/capture-runner.mjs.map +0 -1
  600. package/dist/adapter/git-host/comments.d.mts +0 -41
  601. package/dist/adapter/git-host/comments.mjs +0 -54
  602. package/dist/adapter/git-host/comments.mjs.map +0 -1
  603. package/dist/adapter/git-host/helpers.d.mts +0 -13
  604. package/dist/adapter/git-host/helpers.mjs +0 -30
  605. package/dist/adapter/git-host/helpers.mjs.map +0 -1
  606. package/dist/adapter/git-host.d.mts +0 -42
  607. package/dist/capture/queue.d.mts +0 -38
  608. package/dist/capture/queue.mjs +0 -98
  609. package/dist/capture/queue.mjs.map +0 -1
  610. package/dist/capture/recovery.d.mts +0 -21
  611. package/dist/capture/recovery.mjs +0 -83
  612. package/dist/capture/recovery.mjs.map +0 -1
  613. package/dist/capture/status-fanout.mjs +0 -72
  614. package/dist/capture/status-fanout.mjs.map +0 -1
  615. package/dist/diff/engine.d.mts +0 -16
  616. package/dist/diff/engine.mjs +0 -87
  617. package/dist/diff/engine.mjs.map +0 -1
  618. package/dist/diff/options.d.mts +0 -42
  619. package/dist/diff/options.mjs +0 -15
  620. package/dist/diff/options.mjs.map +0 -1
  621. package/dist/models/status-config.d.mts +0 -38
  622. package/dist/models/status-config.mjs +0 -63
  623. package/dist/models/status-config.mjs.map +0 -1
  624. package/dist/schema/status-config.d.mts +0 -16
  625. package/dist/test-helpers/git-contract.d.mts +0 -11
  626. package/dist/test-helpers/git-contract.mjs +0 -34
  627. package/dist/test-helpers/git-contract.mjs.map +0 -1
  628. /package/dist/adapter/{git-host.mjs → oauth.mjs} +0 -0
@@ -1,54 +0,0 @@
1
- import "node:path";
2
- import "node:url";
3
- import.meta.url;
4
- import { commentMarker } from "./helpers.mjs";
5
- //#region src/adapters/git-host/comments.ts
6
- /** Resolve the thread number, preferring the explicit value. */
7
- async function resolveThreadNumber(opts) {
8
- return opts.prNumber ?? await opts.resolveNumber();
9
- }
10
- /** Update the marked comment if present, else create it. */
11
- async function findOrCreateComment(thread, marker, body, prNumber, logger) {
12
- const existing = (await thread.list()).find((comment) => comment.body.includes(marker));
13
- if (existing) {
14
- const id = await thread.update(existing.id, body);
15
- logger?.info({
16
- prNumber,
17
- commentId: id
18
- }, "review comment updated");
19
- return id;
20
- }
21
- const id = await thread.create(body);
22
- logger?.info({
23
- prNumber,
24
- commentId: id
25
- }, "review comment created");
26
- return id;
27
- }
28
- /**
29
- * Create or update the single StoryShelf review comment for a build,
30
- * idempotent via the url marker. Returns the comment id, or `""` when no
31
- * review thread exists for the commit.
32
- */
33
- async function upsertReviewComment(opts) {
34
- const marker = commentMarker(opts.url);
35
- const body = `${marker}\n${opts.markdown}`;
36
- const number = await resolveThreadNumber(opts);
37
- if (number === void 0) {
38
- opts.logger?.debug({ sha: opts.sha }, "no review thread found for comment, skipping");
39
- return "";
40
- }
41
- try {
42
- return await findOrCreateComment(opts.thread(number), marker, body, number, opts.logger);
43
- } catch (error) {
44
- opts.logger?.error({
45
- err: error,
46
- prNumber: number
47
- }, "failed to upsert review comment");
48
- throw error;
49
- }
50
- }
51
- //#endregion
52
- export { upsertReviewComment };
53
-
54
- //# sourceMappingURL=comments.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"comments.mjs","names":[],"sources":["../../../src/adapters/git-host/comments.ts"],"sourcesContent":["import type { Logger } from \"pino\";\nimport { commentMarker } from \"./helpers.ts\";\n\n/** A review thread (PR or MR) hosting a single StoryShelf comment. */\nexport interface ReviewThread {\n /** List existing comments as id/body pairs. */\n list(): Promise<{ id: string | number; body: string }[]>;\n /** Replace the body of an existing comment, returning its id. */\n update(id: string | number, body: string): Promise<string>;\n /** Create a comment, returning its id. */\n create(body: string): Promise<string>;\n}\n\n/** Dependencies for an idempotent review-comment upsert. */\nexport interface UpsertReviewCommentOptions {\n /** Canonical build/review URL — anchors the idempotency marker. */\n url: string;\n /** Markdown body appended below the marker. */\n markdown: string;\n /** Known thread number, skipping the lookup when provided. */\n prNumber?: number;\n /** Commit SHA used for the thread lookup and log context. */\n sha: string;\n logger?: Logger;\n /** Resolve the thread number for the commit (PR number or MR iid). */\n resolveNumber: () => Promise<number | undefined>;\n /** Open the thread's comment store once the number is known. */\n thread: (number: number) => ReviewThread;\n}\n\n/** Resolve the thread number, preferring the explicit value. */\nasync function resolveThreadNumber(opts: UpsertReviewCommentOptions): Promise<number | undefined> {\n return opts.prNumber ?? (await opts.resolveNumber());\n}\n\n/** Update the marked comment if present, else create it. */\nasync function findOrCreateComment(\n thread: ReviewThread,\n marker: string,\n body: string,\n prNumber: number,\n logger?: Logger,\n): Promise<string> {\n const existing = (await thread.list()).find((comment) => comment.body.includes(marker));\n if (existing) {\n const id = await thread.update(existing.id, body);\n logger?.info({ prNumber, commentId: id }, \"review comment updated\");\n return id;\n }\n const id = await thread.create(body);\n logger?.info({ prNumber, commentId: id }, \"review comment created\");\n return id;\n}\n\n/**\n * Create or update the single StoryShelf review comment for a build,\n * idempotent via the url marker. Returns the comment id, or `\"\"` when no\n * review thread exists for the commit.\n */\nexport async function upsertReviewComment(opts: UpsertReviewCommentOptions): Promise<string> {\n const marker = commentMarker(opts.url);\n const body = `${marker}\\n${opts.markdown}`;\n const number = await resolveThreadNumber(opts);\n if (number === undefined) {\n opts.logger?.debug({ sha: opts.sha }, \"no review thread found for comment, skipping\");\n return \"\";\n }\n try {\n return await findOrCreateComment(opts.thread(number), marker, body, number, opts.logger);\n } catch (error) {\n opts.logger?.error({ err: error, prNumber: number }, \"failed to upsert review comment\");\n throw error;\n }\n}\n"],"mappings":";;;;;;AA+BA,eAAe,oBAAoB,MAA+D;CAChG,OAAO,KAAK,YAAa,MAAM,KAAK,cAAc;AACpD;;AAGA,eAAe,oBACb,QACA,QACA,MACA,UACA,QACiB;CACjB,MAAM,YAAY,MAAM,OAAO,KAAK,EAAA,CAAG,MAAM,YAAY,QAAQ,KAAK,SAAS,MAAM,CAAC;CACtF,IAAI,UAAU;EACZ,MAAM,KAAK,MAAM,OAAO,OAAO,SAAS,IAAI,IAAI;EAChD,QAAQ,KAAK;GAAE;GAAU,WAAW;EAAG,GAAG,wBAAwB;EAClE,OAAO;CACT;CACA,MAAM,KAAK,MAAM,OAAO,OAAO,IAAI;CACnC,QAAQ,KAAK;EAAE;EAAU,WAAW;CAAG,GAAG,wBAAwB;CAClE,OAAO;AACT;;;;;;AAOA,eAAsB,oBAAoB,MAAmD;CAC3F,MAAM,SAAS,cAAc,KAAK,GAAG;CACrC,MAAM,OAAO,GAAG,OAAO,IAAI,KAAK;CAChC,MAAM,SAAS,MAAM,oBAAoB,IAAI;CAC7C,IAAI,WAAW,KAAA,GAAW;EACxB,KAAK,QAAQ,MAAM,EAAE,KAAK,KAAK,IAAI,GAAG,8CAA8C;EACpF,OAAO;CACT;CACA,IAAI;EACF,OAAO,MAAM,oBAAoB,KAAK,OAAO,MAAM,GAAG,QAAQ,MAAM,QAAQ,KAAK,MAAM;CACzF,SAAS,OAAO;EACd,KAAK,QAAQ,MAAM;GAAE,KAAK;GAAO,UAAU;EAAO,GAAG,iCAAiC;EACtF,MAAM;CACR;AACF"}
@@ -1,13 +0,0 @@
1
- import __tsdown_shims_path from 'node:path';
2
- import __tsdown_shims_url from 'node:url';
3
- import { CheckStatus } from "../git-host.mjs";
4
- //#region src/adapters/git-host/helpers.d.ts
5
- /** Human description for a check status — shared across GitHub/GitLab. */
6
- declare function describeStatus(status: CheckStatus): string;
7
- /** Markdown comment body helpers — single comment per build, idempotent via marker. */
8
- declare function commentMarker(url: string): string;
9
- /** Build the Markdown body for a StoryShelf status comment. */
10
- declare function buildCommentMarkdown(status: CheckStatus, url: string, context: string): string;
11
- //#endregion
12
- export { buildCommentMarkdown, commentMarker, describeStatus };
13
- //# sourceMappingURL=helpers.d.mts.map
@@ -1,30 +0,0 @@
1
- import "node:path";
2
- import "node:url";
3
- import.meta.url;
4
- //#region src/adapters/git-host/helpers.ts
5
- /** Human description for a check status — shared across GitHub/GitLab. */
6
- function describeStatus(status) {
7
- switch (status) {
8
- case "pending": return "Visual tests pending";
9
- case "success": return "Visual tests passed";
10
- case "failure": return "Visual changes detected or tests failed";
11
- default: return "Visual changes detected or tests failed";
12
- }
13
- }
14
- /** Markdown comment body helpers — single comment per build, idempotent via marker. */
15
- function commentMarker(url) {
16
- return `<!-- storyshelf:${url} -->`;
17
- }
18
- /** Build the Markdown body for a StoryShelf status comment. */
19
- function buildCommentMarkdown(status, url, context) {
20
- switch (status) {
21
- case "pending": return `Visual tests pending for \`${context}\` — [View build](${url})`;
22
- case "success": return `Visual tests passed for \`${context}\` — [View build](${url})`;
23
- case "failure": return `Visual changes detected for \`${context}\` — [View build](${url})`;
24
- default: return `Visual tests for \`${context}\` — [View build](${url})`;
25
- }
26
- }
27
- //#endregion
28
- export { buildCommentMarkdown, commentMarker, describeStatus };
29
-
30
- //# sourceMappingURL=helpers.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"helpers.mjs","names":[],"sources":["../../../src/adapters/git-host/helpers.ts"],"sourcesContent":["import type { CheckStatus } from \"./index.ts\";\n\n/** Human description for a check status — shared across GitHub/GitLab. */\nexport function describeStatus(status: CheckStatus): string {\n switch (status) {\n case \"pending\": {\n return \"Visual tests pending\";\n }\n case \"success\": {\n return \"Visual tests passed\";\n }\n case \"failure\": {\n return \"Visual changes detected or tests failed\";\n }\n default: {\n return \"Visual changes detected or tests failed\";\n }\n }\n}\n\n/** Markdown comment body helpers — single comment per build, idempotent via marker. */\nexport function commentMarker(url: string): string {\n return `<!-- storyshelf:${url} -->`;\n}\n\n/** Build the Markdown body for a StoryShelf status comment. */\nexport function buildCommentMarkdown(status: CheckStatus, url: string, context: string): string {\n switch (status) {\n case \"pending\": {\n return `Visual tests pending for \\`${context}\\` — [View build](${url})`;\n }\n case \"success\": {\n return `Visual tests passed for \\`${context}\\` — [View build](${url})`;\n }\n case \"failure\": {\n return `Visual changes detected for \\`${context}\\` — [View build](${url})`;\n }\n default: {\n return `Visual tests for \\`${context}\\` — [View build](${url})`;\n }\n }\n}\n"],"mappings":";;;;;AAGA,SAAgB,eAAe,QAA6B;CAC1D,QAAQ,QAAR;EACE,KAAK,WACH,OAAO;EAET,KAAK,WACH,OAAO;EAET,KAAK,WACH,OAAO;EAET,SACE,OAAO;CAEX;AACF;;AAGA,SAAgB,cAAc,KAAqB;CACjD,OAAO,mBAAmB,IAAI;AAChC;;AAGA,SAAgB,qBAAqB,QAAqB,KAAa,SAAyB;CAC9F,QAAQ,QAAR;EACE,KAAK,WACH,OAAO,8BAA8B,QAAQ,oBAAoB,IAAI;EAEvE,KAAK,WACH,OAAO,6BAA6B,QAAQ,oBAAoB,IAAI;EAEtE,KAAK,WACH,OAAO,iCAAiC,QAAQ,oBAAoB,IAAI;EAE1E,SACE,OAAO,sBAAsB,QAAQ,oBAAoB,IAAI;CAEjE;AACF"}
@@ -1,42 +0,0 @@
1
- import __tsdown_shims_path from 'node:path';
2
- import __tsdown_shims_url from 'node:url';
3
- import { Adapter, GitAdapterMetadata } from "./metadata.mjs";
4
- import { Logger } from "pino";
5
- //#region src/adapters/git-host/index.d.ts
6
- /** Status of a git-host provider check. */
7
- type CheckStatus = "pending" | "success" | "failure";
8
- /** Descriptor — registered at startup, validates per-project config. */
9
- interface GitHostProvider extends Adapter<GitAdapterMetadata> {
10
- /** Create a configured instance bound to a project config + decrypted token. */
11
- create(opts: {
12
- config: unknown;
13
- token: string;
14
- logger?: Logger;
15
- }): GitHostAdapter;
16
- }
17
- /** Runtime — bound to a project config + token, posts statuses/comments. */
18
- interface GitHostAdapter extends Adapter<GitAdapterMetadata> {
19
- /** Set the status of a commit. */
20
- setStatus(opts: {
21
- context: string;
22
- gitSha: string;
23
- status: CheckStatus;
24
- url: string;
25
- }): Promise<void>;
26
- /** Whether the branch/sha is already merged — gate to skip capture. */
27
- isMerged?(opts: {
28
- sha: string;
29
- branch: string;
30
- }): Promise<boolean>;
31
- /** Create or update a single PR comment per build (idempotent via url marker). */
32
- upsertComment?(opts: {
33
- prNumber?: number;
34
- sha: string;
35
- url: string;
36
- status: CheckStatus;
37
- markdown: string;
38
- }): Promise<string>;
39
- }
40
- //#endregion
41
- export { CheckStatus, GitHostAdapter, GitHostProvider };
42
- //# sourceMappingURL=git-host.d.mts.map
@@ -1,38 +0,0 @@
1
- import __tsdown_shims_path from 'node:path';
2
- import __tsdown_shims_url from 'node:url';
3
- import { CaptureJob, CaptureQueue, QueueEntry } from "../adapter/capture-queue.mjs";
4
- import { Logger } from "pino";
5
- //#region src/capture/queue.d.ts
6
- /** Options for the in-process capture queue. */
7
- interface InMemoryCaptureQueueOptions {
8
- concurrency: number;
9
- runJob: (job: CaptureJob) => Promise<void>;
10
- logger?: Logger;
11
- }
12
- /** In-process capture queue with bounded concurrency. */
13
- declare class InMemoryCaptureQueue implements CaptureQueue {
14
- private readonly options;
15
- readonly metadata: {
16
- readonly name: "In-Memory Queue";
17
- readonly version: string;
18
- readonly description: "In-process capture queue";
19
- readonly kind: "memory";
20
- readonly category: "capture-queue";
21
- };
22
- private readonly entries;
23
- private running;
24
- private readonly waiting;
25
- private readonly inFlight;
26
- constructor(options: InMemoryCaptureQueueOptions);
27
- enqueue(job: CaptureJob): Promise<void>;
28
- status(buildId: string): Promise<QueueEntry | null>;
29
- active(): Promise<QueueEntry[]>;
30
- recent(limit: number): Promise<QueueEntry[]>;
31
- private process;
32
- private log;
33
- private track;
34
- private acquire;
35
- }
36
- //#endregion
37
- export { InMemoryCaptureQueue, InMemoryCaptureQueueOptions };
38
- //# sourceMappingURL=queue.d.mts.map
@@ -1,98 +0,0 @@
1
- import "node:path";
2
- import "node:url";
3
- import.meta.url;
4
- //#region src/capture/queue.ts
5
- /** In-process capture queue with bounded concurrency. */
6
- var InMemoryCaptureQueue = class {
7
- options;
8
- metadata = {
9
- name: "In-Memory Queue",
10
- version: globalThis.__PKG_VERSION__ ?? "0.0.0",
11
- description: "In-process capture queue",
12
- kind: "memory",
13
- category: "capture-queue"
14
- };
15
- entries = /* @__PURE__ */ new Map();
16
- running = 0;
17
- waiting = [];
18
- inFlight = /* @__PURE__ */ new Map();
19
- constructor(options) {
20
- this.options = options;
21
- }
22
- async enqueue(job) {
23
- const entry = this.track(job.buildId);
24
- this.log(job)?.info("capture queued");
25
- this.inFlight.set(job.buildId, this.process(job, entry));
26
- await Promise.resolve();
27
- }
28
- async status(buildId) {
29
- return await Promise.resolve(this.entries.get(buildId) ?? null);
30
- }
31
- async active() {
32
- return await Promise.resolve([...this.entries.values()].filter((entry) => entry.status === "queued" || entry.status === "running").toSorted((a, b) => a.queuedAt.localeCompare(b.queuedAt)));
33
- }
34
- async recent(limit) {
35
- return await Promise.resolve([...this.entries.values()].toSorted((a, b) => b.queuedAt.localeCompare(a.queuedAt)).slice(0, limit));
36
- }
37
- async process(job, entry) {
38
- const log = this.log(job);
39
- await this.acquire();
40
- entry.status = "running";
41
- entry.startedAt = (/* @__PURE__ */ new Date()).toISOString();
42
- log?.info("capture started");
43
- try {
44
- await this.options.runJob(job);
45
- } catch (error) {
46
- entry.status = "failed";
47
- entry.finishedAt = (/* @__PURE__ */ new Date()).toISOString();
48
- entry.error = error instanceof Error ? error.message : "Capture failed";
49
- log?.error({ err: error }, "capture failed");
50
- } finally {
51
- this.running -= 1;
52
- this.waiting.shift()?.();
53
- if (entry.status !== "failed") {
54
- entry.status = "completed";
55
- entry.finishedAt = (/* @__PURE__ */ new Date()).toISOString();
56
- log?.info("capture completed");
57
- }
58
- }
59
- }
60
- log(job) {
61
- return this.options.logger?.child({
62
- buildId: job.buildId,
63
- reqId: job.reqId
64
- });
65
- }
66
- track(buildId) {
67
- const existing = this.entries.get(buildId);
68
- if (existing) {
69
- existing.status = "queued";
70
- existing.queuedAt = (/* @__PURE__ */ new Date()).toISOString();
71
- existing.startedAt = void 0;
72
- existing.finishedAt = void 0;
73
- existing.error = void 0;
74
- return existing;
75
- }
76
- const entry = {
77
- buildId,
78
- status: "queued",
79
- queuedAt: (/* @__PURE__ */ new Date()).toISOString()
80
- };
81
- this.entries.set(buildId, entry);
82
- return entry;
83
- }
84
- async acquire() {
85
- if (this.running < this.options.concurrency) {
86
- this.running += 1;
87
- return;
88
- }
89
- await new Promise((resolve) => {
90
- this.waiting.push(resolve);
91
- });
92
- await this.acquire();
93
- }
94
- };
95
- //#endregion
96
- export { InMemoryCaptureQueue };
97
-
98
- //# sourceMappingURL=queue.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"queue.mjs","names":[],"sources":["../../src/capture/queue.ts"],"sourcesContent":["import type { Logger } from \"pino\";\nimport type { CaptureJob, CaptureQueue, QueueEntry } from \"../adapters/capture-queue.ts\";\n\ndeclare const __PKG_VERSION__: string | undefined;\n\n/** Options for the in-process capture queue. */\nexport interface InMemoryCaptureQueueOptions {\n concurrency: number;\n runJob: (job: CaptureJob) => Promise<void>;\n logger?: Logger;\n}\n/** In-process capture queue with bounded concurrency. */\nexport class InMemoryCaptureQueue implements CaptureQueue {\n readonly metadata = {\n name: \"In-Memory Queue\",\n version: (globalThis as unknown as { __PKG_VERSION__?: string }).__PKG_VERSION__ ?? \"0.0.0\",\n description: \"In-process capture queue\",\n kind: \"memory\",\n category: \"capture-queue\",\n } as const;\n\n private readonly entries = new Map<string, QueueEntry>();\n private running = 0;\n private readonly waiting: (() => void)[] = [];\n private readonly inFlight = new Map<string, Promise<void>>();\n\n constructor(private readonly options: InMemoryCaptureQueueOptions) {}\n\n async enqueue(job: CaptureJob): Promise<void> {\n const entry = this.track(job.buildId);\n this.log(job)?.info(\"capture queued\");\n this.inFlight.set(job.buildId, this.process(job, entry));\n await Promise.resolve();\n }\n\n async status(buildId: string): Promise<QueueEntry | null> {\n return await Promise.resolve(this.entries.get(buildId) ?? null);\n }\n\n async active(): Promise<QueueEntry[]> {\n return await Promise.resolve(\n [...this.entries.values()]\n .filter((entry) => entry.status === \"queued\" || entry.status === \"running\")\n .toSorted((a, b) => a.queuedAt.localeCompare(b.queuedAt)),\n );\n }\n\n async recent(limit: number): Promise<QueueEntry[]> {\n return await Promise.resolve(\n [...this.entries.values()]\n .toSorted((a, b) => b.queuedAt.localeCompare(a.queuedAt))\n .slice(0, limit),\n );\n }\n\n private async process(job: CaptureJob, entry: QueueEntry): Promise<void> {\n const log = this.log(job);\n await this.acquire();\n entry.status = \"running\";\n entry.startedAt = new Date().toISOString();\n log?.info(\"capture started\");\n try {\n await this.options.runJob(job);\n } catch (error) {\n entry.status = \"failed\";\n entry.finishedAt = new Date().toISOString();\n entry.error = error instanceof Error ? error.message : \"Capture failed\";\n log?.error({ err: error }, \"capture failed\");\n } finally {\n this.running -= 1;\n this.waiting.shift()?.();\n if (entry.status !== \"failed\") {\n entry.status = \"completed\";\n entry.finishedAt = new Date().toISOString();\n log?.info(\"capture completed\");\n }\n }\n }\n\n private log(job: CaptureJob): Logger | undefined {\n return this.options.logger?.child({ buildId: job.buildId, reqId: job.reqId });\n }\n\n private track(buildId: string): QueueEntry {\n const existing = this.entries.get(buildId);\n if (existing) {\n existing.status = \"queued\";\n existing.queuedAt = new Date().toISOString();\n existing.startedAt = undefined;\n existing.finishedAt = undefined;\n existing.error = undefined;\n return existing;\n }\n const entry: QueueEntry = { buildId, status: \"queued\", queuedAt: new Date().toISOString() };\n this.entries.set(buildId, entry);\n return entry;\n }\n\n private async acquire(): Promise<void> {\n if (this.running < this.options.concurrency) {\n this.running += 1;\n return;\n }\n await new Promise<void>((resolve) => {\n this.waiting.push(resolve);\n });\n await this.acquire();\n }\n}\n"],"mappings":";;;;;AAYA,IAAa,uBAAb,MAA0D;CAc3B;CAb7B,WAAoB;EAClB,MAAM;EACN,SAAU,WAAuD,mBAAmB;EACpF,aAAa;EACb,MAAM;EACN,UAAU;CACZ;CAEA,0BAA2B,IAAI,IAAwB;CACvD,UAAkB;CAClB,UAA2C,CAAC;CAC5C,2BAA4B,IAAI,IAA2B;CAE3D,YAAY,SAAuD;EAAtC,KAAA,UAAA;CAAuC;CAEpE,MAAM,QAAQ,KAAgC;EAC5C,MAAM,QAAQ,KAAK,MAAM,IAAI,OAAO;EACpC,KAAK,IAAI,GAAG,CAAC,EAAE,KAAK,gBAAgB;EACpC,KAAK,SAAS,IAAI,IAAI,SAAS,KAAK,QAAQ,KAAK,KAAK,CAAC;EACvD,MAAM,QAAQ,QAAQ;CACxB;CAEA,MAAM,OAAO,SAA6C;EACxD,OAAO,MAAM,QAAQ,QAAQ,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI;CAChE;CAEA,MAAM,SAAgC;EACpC,OAAO,MAAM,QAAQ,QACnB,CAAC,GAAG,KAAK,QAAQ,OAAO,CAAC,CAAC,CACvB,QAAQ,UAAU,MAAM,WAAW,YAAY,MAAM,WAAW,SAAS,CAAC,CAC1E,UAAU,GAAG,MAAM,EAAE,SAAS,cAAc,EAAE,QAAQ,CAAC,CAC5D;CACF;CAEA,MAAM,OAAO,OAAsC;EACjD,OAAO,MAAM,QAAQ,QACnB,CAAC,GAAG,KAAK,QAAQ,OAAO,CAAC,CAAC,CACvB,UAAU,GAAG,MAAM,EAAE,SAAS,cAAc,EAAE,QAAQ,CAAC,CAAC,CACxD,MAAM,GAAG,KAAK,CACnB;CACF;CAEA,MAAc,QAAQ,KAAiB,OAAkC;EACvE,MAAM,MAAM,KAAK,IAAI,GAAG;EACxB,MAAM,KAAK,QAAQ;EACnB,MAAM,SAAS;EACf,MAAM,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;EACzC,KAAK,KAAK,iBAAiB;EAC3B,IAAI;GACF,MAAM,KAAK,QAAQ,OAAO,GAAG;EAC/B,SAAS,OAAO;GACd,MAAM,SAAS;GACf,MAAM,8BAAa,IAAI,KAAK,EAAA,CAAE,YAAY;GAC1C,MAAM,QAAQ,iBAAiB,QAAQ,MAAM,UAAU;GACvD,KAAK,MAAM,EAAE,KAAK,MAAM,GAAG,gBAAgB;EAC7C,UAAU;GACR,KAAK,WAAW;GAChB,KAAK,QAAQ,MAAM,CAAC,GAAG;GACvB,IAAI,MAAM,WAAW,UAAU;IAC7B,MAAM,SAAS;IACf,MAAM,8BAAa,IAAI,KAAK,EAAA,CAAE,YAAY;IAC1C,KAAK,KAAK,mBAAmB;GAC/B;EACF;CACF;CAEA,IAAY,KAAqC;EAC/C,OAAO,KAAK,QAAQ,QAAQ,MAAM;GAAE,SAAS,IAAI;GAAS,OAAO,IAAI;EAAM,CAAC;CAC9E;CAEA,MAAc,SAA6B;EACzC,MAAM,WAAW,KAAK,QAAQ,IAAI,OAAO;EACzC,IAAI,UAAU;GACZ,SAAS,SAAS;GAClB,SAAS,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;GAC3C,SAAS,YAAY,KAAA;GACrB,SAAS,aAAa,KAAA;GACtB,SAAS,QAAQ,KAAA;GACjB,OAAO;EACT;EACA,MAAM,QAAoB;GAAE;GAAS,QAAQ;GAAU,2BAAU,IAAI,KAAK,EAAA,CAAE,YAAY;EAAE;EAC1F,KAAK,QAAQ,IAAI,SAAS,KAAK;EAC/B,OAAO;CACT;CAEA,MAAc,UAAyB;EACrC,IAAI,KAAK,UAAU,KAAK,QAAQ,aAAa;GAC3C,KAAK,WAAW;GAChB;EACF;EACA,MAAM,IAAI,SAAe,YAAY;GACnC,KAAK,QAAQ,KAAK,OAAO;EAC3B,CAAC;EACD,MAAM,KAAK,QAAQ;CACrB;AACF"}
@@ -1,21 +0,0 @@
1
- import __tsdown_shims_path from 'node:path';
2
- import __tsdown_shims_url from 'node:url';
3
- import { DispatchDeps } from "./dispatch.mjs";
4
- //#region src/capture/recovery.d.ts
5
- /** Error recorded on attempts that a restart cut short; also the requeue-once marker. */
6
- declare const INTERRUPTED_ERROR = "Interrupted by server restart";
7
- /** Outcome of one recovery sweep. */
8
- interface RecoveryResult {
9
- requeued: string[];
10
- failed: string[];
11
- }
12
- /** Inputs for {@link recoverStuckCaptures}. */
13
- interface RecoveryDeps {
14
- deps: DispatchDeps;
15
- enqueue: (buildId: string) => Promise<void>;
16
- }
17
- /** Requeue (once) or fail every build still `capturing`; call once at boot, before serving jobs. */
18
- declare function recoverStuckCaptures(recovery: RecoveryDeps): Promise<RecoveryResult>;
19
- //#endregion
20
- export { INTERRUPTED_ERROR, RecoveryDeps, RecoveryResult, recoverStuckCaptures };
21
- //# sourceMappingURL=recovery.d.mts.map
@@ -1,83 +0,0 @@
1
- import "node:path";
2
- import "node:url";
3
- import.meta.url;
4
- import { BuildModel } from "../models/build.mjs";
5
- import { CaptureAttemptModel } from "../models/capture-attempt.mjs";
6
- import { ProjectModel } from "../models/project.mjs";
7
- import { postStatusesForBuild } from "./status-fanout.mjs";
8
- import { eq, getTableColumns } from "drizzle-orm";
9
- //#region src/capture/recovery.ts
10
- /**
11
- * Boot-time recovery for builds left in `capturing` by a server restart.
12
- *
13
- * Policy: requeue once. The interrupted attempt is closed with
14
- * {@link INTERRUPTED_ERROR}; a build with no earlier interrupted attempt goes back to `pending`
15
- * and is re-enqueued, otherwise it is marked `failed` for manual retry. A build is failed instead
16
- * when the run before the interrupted one was itself interrupted, so a crash loop stops after
17
- * one requeue while manual retries stay unrestricted. In-process queues only: remote queues redeliver on their own.
18
- */
19
- /** Error recorded on attempts that a restart cut short; also the requeue-once marker. */
20
- const INTERRUPTED_ERROR = "Interrupted by server restart";
21
- /** Requeue (once) or fail every build still `capturing`; call once at boot, before serving jobs. */
22
- async function recoverStuckCaptures(recovery) {
23
- const { deps } = recovery;
24
- const stuck = await deps.db.list(deps.tables.builds, { where: eq(getTableColumns(deps.tables.builds)["status"], "capturing") });
25
- const outcomes = await Promise.all(stuck.map(async (build) => await recoverBuild(recovery, build)));
26
- const result = {
27
- requeued: stuck.filter((_, index) => outcomes[index]).map((build) => build.id),
28
- failed: stuck.filter((_, index) => !outcomes[index]).map((build) => build.id)
29
- };
30
- if (stuck.length > 0) deps.logger.warn({
31
- requeued: result.requeued,
32
- failed: result.failed
33
- }, "recovered builds interrupted by restart");
34
- return result;
35
- }
36
- /** Recover one build; returns true when it was requeued. */
37
- async function recoverBuild(recovery, build) {
38
- const { deps } = recovery;
39
- const attempts = new CaptureAttemptModel(deps.db, deps.tables);
40
- const history = await attempts.listByBuild(build.id);
41
- const open = history.filter((a) => a.status === "queued" || a.status === "running");
42
- const lastClosed = history.findLast((a) => !open.includes(a));
43
- await Promise.all(open.map(async (a) => await attempts.markFinished(a.id, "failed", INTERRUPTED_ERROR)));
44
- return lastClosed?.error === "Interrupted by server restart" ? await failInterrupted(deps, build) : await requeueInterrupted(recovery, build);
45
- }
46
- async function failInterrupted(deps, build) {
47
- await new BuildModel(deps.db, deps.tables).setStatus(build.id, "failed");
48
- await postFailure(deps, build);
49
- deps.logger.error({ buildId: build.id }, "build interrupted by restart again; marked failed for manual retry");
50
- return false;
51
- }
52
- async function requeueInterrupted(recovery, build) {
53
- const { deps } = recovery;
54
- await new BuildModel(deps.db, deps.tables).setStatus(build.id, "pending");
55
- await recovery.enqueue(build.id);
56
- deps.logger.warn({ buildId: build.id }, "build interrupted by restart; requeued once");
57
- return true;
58
- }
59
- /** Replace the lingering pending git status with a failure. */
60
- async function postFailure(deps, build) {
61
- const project = await new ProjectModel(deps.db, deps.tables).get(build.projectId);
62
- if (!project) return;
63
- await postStatusesForBuild({
64
- db: deps.db,
65
- tables: deps.tables,
66
- project,
67
- sha: build.gitSha,
68
- status: "failure",
69
- url: `/projects/${project.slug}/builds/${build.id}`,
70
- providers: deps.gitHosts,
71
- secret: deps.secret,
72
- logger: deps.logger
73
- }).catch((error) => {
74
- deps.logger.error({
75
- err: error,
76
- buildId: build.id
77
- }, "failed to post failure status");
78
- });
79
- }
80
- //#endregion
81
- export { INTERRUPTED_ERROR, recoverStuckCaptures };
82
-
83
- //# sourceMappingURL=recovery.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"recovery.mjs","names":[],"sources":["../../src/capture/recovery.ts"],"sourcesContent":["/**\n * Boot-time recovery for builds left in `capturing` by a server restart.\n *\n * Policy: requeue once. The interrupted attempt is closed with\n * {@link INTERRUPTED_ERROR}; a build with no earlier interrupted attempt goes back to `pending`\n * and is re-enqueued, otherwise it is marked `failed` for manual retry. A build is failed instead\n * when the run before the interrupted one was itself interrupted, so a crash loop stops after\n * one requeue while manual retries stay unrestricted. In-process queues only: remote queues redeliver on their own.\n */\nimport { eq, getTableColumns } from \"drizzle-orm\";\nimport type { SQLWrapper } from \"drizzle-orm\";\nimport { BuildModel } from \"../models/build.ts\";\nimport { CaptureAttemptModel } from \"../models/capture-attempt.ts\";\nimport { ProjectModel } from \"../models/project.ts\";\nimport type { Build } from \"../schema/build.ts\";\nimport type { DispatchDeps } from \"./dispatch.ts\";\nimport { postStatusesForBuild } from \"./status-fanout.ts\";\n\n/** Error recorded on attempts that a restart cut short; also the requeue-once marker. */\nexport const INTERRUPTED_ERROR = \"Interrupted by server restart\";\n\n/** Outcome of one recovery sweep. */\nexport interface RecoveryResult {\n requeued: string[];\n failed: string[];\n}\n\n/** Inputs for {@link recoverStuckCaptures}. */\nexport interface RecoveryDeps {\n deps: DispatchDeps;\n enqueue: (buildId: string) => Promise<void>;\n}\n\n/** Requeue (once) or fail every build still `capturing`; call once at boot, before serving jobs. */\nexport async function recoverStuckCaptures(recovery: RecoveryDeps): Promise<RecoveryResult> {\n const { deps } = recovery;\n const stuck = (await deps.db.list(deps.tables.builds, {\n where: eq(getTableColumns(deps.tables.builds)[\"status\"] as unknown as SQLWrapper, \"capturing\"),\n })) as unknown as Build[];\n const outcomes = await Promise.all(\n stuck.map(async (build) => await recoverBuild(recovery, build)),\n );\n const result: RecoveryResult = {\n requeued: stuck.filter((_, index) => outcomes[index]).map((build) => build.id),\n failed: stuck.filter((_, index) => !outcomes[index]).map((build) => build.id),\n };\n if (stuck.length > 0) {\n deps.logger.warn(\n { requeued: result.requeued, failed: result.failed },\n \"recovered builds interrupted by restart\",\n );\n }\n return result;\n}\n\n/** Recover one build; returns true when it was requeued. */\nasync function recoverBuild(recovery: RecoveryDeps, build: Build): Promise<boolean> {\n const { deps } = recovery;\n const attempts = new CaptureAttemptModel(deps.db, deps.tables);\n const history = await attempts.listByBuild(build.id);\n const open = history.filter((a) => a.status === \"queued\" || a.status === \"running\");\n // Requeue-once: the run before the interrupted one was itself interrupted => crash loop.\n const lastClosed = history.findLast((a) => !open.includes(a));\n await Promise.all(\n open.map(async (a) => await attempts.markFinished(a.id, \"failed\", INTERRUPTED_ERROR)),\n );\n return lastClosed?.error === INTERRUPTED_ERROR\n ? await failInterrupted(deps, build)\n : await requeueInterrupted(recovery, build);\n}\n\nasync function failInterrupted(deps: DispatchDeps, build: Build): Promise<false> {\n await new BuildModel(deps.db, deps.tables).setStatus(build.id, \"failed\");\n await postFailure(deps, build);\n deps.logger.error(\n { buildId: build.id },\n \"build interrupted by restart again; marked failed for manual retry\",\n );\n return false;\n}\n\nasync function requeueInterrupted(recovery: RecoveryDeps, build: Build): Promise<true> {\n const { deps } = recovery;\n await new BuildModel(deps.db, deps.tables).setStatus(build.id, \"pending\");\n await recovery.enqueue(build.id);\n deps.logger.warn({ buildId: build.id }, \"build interrupted by restart; requeued once\");\n return true;\n}\n\n/** Replace the lingering pending git status with a failure. */\nasync function postFailure(deps: DispatchDeps, build: Build): Promise<void> {\n const project = await new ProjectModel(deps.db, deps.tables).get(build.projectId);\n if (!project) {\n return;\n }\n await postStatusesForBuild({\n db: deps.db,\n tables: deps.tables,\n project,\n sha: build.gitSha,\n status: \"failure\",\n url: `/projects/${project.slug}/builds/${build.id}`,\n providers: deps.gitHosts,\n secret: deps.secret,\n logger: deps.logger,\n }).catch((error: unknown) => {\n deps.logger.error({ err: error, buildId: build.id }, \"failed to post failure status\");\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAmBA,MAAa,oBAAoB;;AAejC,eAAsB,qBAAqB,UAAiD;CAC1F,MAAM,EAAE,SAAS;CACjB,MAAM,QAAS,MAAM,KAAK,GAAG,KAAK,KAAK,OAAO,QAAQ,EACpD,OAAO,GAAG,gBAAgB,KAAK,OAAO,MAAM,CAAC,CAAC,WAAoC,WAAW,EAC/F,CAAC;CACD,MAAM,WAAW,MAAM,QAAQ,IAC7B,MAAM,IAAI,OAAO,UAAU,MAAM,aAAa,UAAU,KAAK,CAAC,CAChE;CACA,MAAM,SAAyB;EAC7B,UAAU,MAAM,QAAQ,GAAG,UAAU,SAAS,MAAM,CAAC,CAAC,KAAK,UAAU,MAAM,EAAE;EAC7E,QAAQ,MAAM,QAAQ,GAAG,UAAU,CAAC,SAAS,MAAM,CAAC,CAAC,KAAK,UAAU,MAAM,EAAE;CAC9E;CACA,IAAI,MAAM,SAAS,GACjB,KAAK,OAAO,KACV;EAAE,UAAU,OAAO;EAAU,QAAQ,OAAO;CAAO,GACnD,yCACF;CAEF,OAAO;AACT;;AAGA,eAAe,aAAa,UAAwB,OAAgC;CAClF,MAAM,EAAE,SAAS;CACjB,MAAM,WAAW,IAAI,oBAAoB,KAAK,IAAI,KAAK,MAAM;CAC7D,MAAM,UAAU,MAAM,SAAS,YAAY,MAAM,EAAE;CACnD,MAAM,OAAO,QAAQ,QAAQ,MAAM,EAAE,WAAW,YAAY,EAAE,WAAW,SAAS;CAElF,MAAM,aAAa,QAAQ,UAAU,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC;CAC5D,MAAM,QAAQ,IACZ,KAAK,IAAI,OAAO,MAAM,MAAM,SAAS,aAAa,EAAE,IAAI,UAAU,iBAAiB,CAAC,CACtF;CACA,OAAO,YAAY,UAAA,kCACf,MAAM,gBAAgB,MAAM,KAAK,IACjC,MAAM,mBAAmB,UAAU,KAAK;AAC9C;AAEA,eAAe,gBAAgB,MAAoB,OAA8B;CAC/E,MAAM,IAAI,WAAW,KAAK,IAAI,KAAK,MAAM,CAAC,CAAC,UAAU,MAAM,IAAI,QAAQ;CACvE,MAAM,YAAY,MAAM,KAAK;CAC7B,KAAK,OAAO,MACV,EAAE,SAAS,MAAM,GAAG,GACpB,oEACF;CACA,OAAO;AACT;AAEA,eAAe,mBAAmB,UAAwB,OAA6B;CACrF,MAAM,EAAE,SAAS;CACjB,MAAM,IAAI,WAAW,KAAK,IAAI,KAAK,MAAM,CAAC,CAAC,UAAU,MAAM,IAAI,SAAS;CACxE,MAAM,SAAS,QAAQ,MAAM,EAAE;CAC/B,KAAK,OAAO,KAAK,EAAE,SAAS,MAAM,GAAG,GAAG,6CAA6C;CACrF,OAAO;AACT;;AAGA,eAAe,YAAY,MAAoB,OAA6B;CAC1E,MAAM,UAAU,MAAM,IAAI,aAAa,KAAK,IAAI,KAAK,MAAM,CAAC,CAAC,IAAI,MAAM,SAAS;CAChF,IAAI,CAAC,SACH;CAEF,MAAM,qBAAqB;EACzB,IAAI,KAAK;EACT,QAAQ,KAAK;EACb;EACA,KAAK,MAAM;EACX,QAAQ;EACR,KAAK,aAAa,QAAQ,KAAK,UAAU,MAAM;EAC/C,WAAW,KAAK;EAChB,QAAQ,KAAK;EACb,QAAQ,KAAK;CACf,CAAC,CAAC,CAAC,OAAO,UAAmB;EAC3B,KAAK,OAAO,MAAM;GAAE,KAAK;GAAO,SAAS,MAAM;EAAG,GAAG,+BAA+B;CACtF,CAAC;AACH"}
@@ -1,72 +0,0 @@
1
- import "node:path";
2
- import "node:url";
3
- import.meta.url;
4
- import { buildCommentMarkdown } from "../adapter/git-host/helpers.mjs";
5
- import { StatusConfigModel } from "../models/status-config.mjs";
6
- import { LOCAL_SHA_PREFIX } from "@storyshelf/affected";
7
- //#region src/capture/status-fanout.ts
8
- /** Post build check statuses (and review comments) to every configured git provider. */
9
- async function postStatusesForBuild(opts) {
10
- if (opts.providers.length === 0) return;
11
- if (opts.sha.startsWith(LOCAL_SHA_PREFIX)) {
12
- opts.logger?.info({ sha: opts.sha }, "skipping git provider status for synthetic local identity");
13
- return;
14
- }
15
- const model = new StatusConfigModel(opts.db, opts.tables, opts.secret);
16
- const rows = await model.list(opts.project.id);
17
- const ctx = `storyshelf/${opts.project.slug}`;
18
- await Promise.allSettled(rows.map(async (row) => {
19
- const provider = opts.providers.find((p) => p.metadata.kind === row.provider);
20
- if (!provider) {
21
- opts.logger?.warn({ provider: row.provider }, "no provider registered for status config");
22
- return;
23
- }
24
- let parsed;
25
- try {
26
- parsed = JSON.parse(row.config);
27
- provider.metadata.schema.parse(parsed);
28
- } catch (error) {
29
- opts.logger?.warn({
30
- err: error,
31
- provider: row.provider
32
- }, "invalid status config");
33
- return;
34
- }
35
- let token;
36
- try {
37
- token = model.decryptToken(row);
38
- } catch (error) {
39
- opts.logger?.warn({ err: error }, "failed to decrypt status token");
40
- return;
41
- }
42
- const adapter = provider.create({
43
- config: parsed,
44
- token,
45
- logger: opts.logger
46
- });
47
- await adapter.setStatus({
48
- context: ctx,
49
- gitSha: opts.sha,
50
- status: opts.status,
51
- url: opts.url
52
- });
53
- if (adapter.upsertComment) {
54
- const markdown = buildCommentMarkdown(opts.status, opts.url, ctx);
55
- await adapter.upsertComment({
56
- sha: opts.sha,
57
- url: opts.url,
58
- status: opts.status,
59
- markdown
60
- }).catch((error) => {
61
- opts.logger?.warn({
62
- err: error,
63
- provider: row.provider
64
- }, "failed to upsert comment");
65
- });
66
- }
67
- }));
68
- }
69
- //#endregion
70
- export { postStatusesForBuild };
71
-
72
- //# sourceMappingURL=status-fanout.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"status-fanout.mjs","names":[],"sources":["../../src/capture/status-fanout.ts"],"sourcesContent":["import { LOCAL_SHA_PREFIX } from \"@storyshelf/affected\";\nimport type { Logger } from \"pino\";\nimport type { DatabaseAdapter } from \"../adapters/database.ts\";\nimport { buildCommentMarkdown } from \"../adapters/git-host/helpers.ts\";\nimport type { CheckStatus, GitHostProvider } from \"../adapters/git-host/index.ts\";\nimport { StatusConfigModel, type StatusConfigTables } from \"../models/status-config.ts\";\nimport type { Project } from \"../schema/project.ts\";\nimport type { SecretInput } from \"../utils/encrypt.ts\";\n\n/** Post build check statuses (and review comments) to every configured git provider. */\nasync function postStatusesForBuild(opts: {\n db: DatabaseAdapter;\n tables: StatusConfigTables;\n project: Project;\n sha: string;\n status: CheckStatus;\n url: string;\n providers: GitHostProvider[];\n secret: SecretInput;\n logger?: Logger;\n}): Promise<void> {\n if (opts.providers.length === 0) {\n return;\n }\n if (opts.sha.startsWith(LOCAL_SHA_PREFIX)) {\n opts.logger?.info(\n { sha: opts.sha },\n \"skipping git provider status for synthetic local identity\",\n );\n return;\n }\n const model = new StatusConfigModel(opts.db, opts.tables, opts.secret);\n const rows = await model.list(opts.project.id);\n const ctx = `storyshelf/${opts.project.slug}`;\n await Promise.allSettled(\n rows.map(async (row) => {\n const provider = opts.providers.find((p) => p.metadata.kind === row.provider);\n if (!provider) {\n opts.logger?.warn({ provider: row.provider }, \"no provider registered for status config\");\n return;\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(row.config);\n provider.metadata.schema.parse(parsed);\n } catch (error: unknown) {\n opts.logger?.warn({ err: error, provider: row.provider }, \"invalid status config\");\n return;\n }\n let token: string;\n try {\n token = model.decryptToken(row);\n } catch (error: unknown) {\n opts.logger?.warn({ err: error }, \"failed to decrypt status token\");\n return;\n }\n const adapter = provider.create({ config: parsed, token, logger: opts.logger });\n await adapter.setStatus({\n context: ctx,\n gitSha: opts.sha,\n status: opts.status,\n url: opts.url,\n });\n if (adapter.upsertComment) {\n const markdown = buildCommentMarkdown(opts.status, opts.url, ctx);\n await adapter\n .upsertComment({ sha: opts.sha, url: opts.url, status: opts.status, markdown })\n .catch((error: unknown) => {\n opts.logger?.warn({ err: error, provider: row.provider }, \"failed to upsert comment\");\n });\n }\n }),\n );\n}\n\nexport { postStatusesForBuild };\n"],"mappings":";;;;;;;;AAUA,eAAe,qBAAqB,MAUlB;CAChB,IAAI,KAAK,UAAU,WAAW,GAC5B;CAEF,IAAI,KAAK,IAAI,WAAW,gBAAgB,GAAG;EACzC,KAAK,QAAQ,KACX,EAAE,KAAK,KAAK,IAAI,GAChB,2DACF;EACA;CACF;CACA,MAAM,QAAQ,IAAI,kBAAkB,KAAK,IAAI,KAAK,QAAQ,KAAK,MAAM;CACrE,MAAM,OAAO,MAAM,MAAM,KAAK,KAAK,QAAQ,EAAE;CAC7C,MAAM,MAAM,cAAc,KAAK,QAAQ;CACvC,MAAM,QAAQ,WACZ,KAAK,IAAI,OAAO,QAAQ;EACtB,MAAM,WAAW,KAAK,UAAU,MAAM,MAAM,EAAE,SAAS,SAAS,IAAI,QAAQ;EAC5E,IAAI,CAAC,UAAU;GACb,KAAK,QAAQ,KAAK,EAAE,UAAU,IAAI,SAAS,GAAG,0CAA0C;GACxF;EACF;EACA,IAAI;EACJ,IAAI;GACF,SAAS,KAAK,MAAM,IAAI,MAAM;GAC9B,SAAS,SAAS,OAAO,MAAM,MAAM;EACvC,SAAS,OAAgB;GACvB,KAAK,QAAQ,KAAK;IAAE,KAAK;IAAO,UAAU,IAAI;GAAS,GAAG,uBAAuB;GACjF;EACF;EACA,IAAI;EACJ,IAAI;GACF,QAAQ,MAAM,aAAa,GAAG;EAChC,SAAS,OAAgB;GACvB,KAAK,QAAQ,KAAK,EAAE,KAAK,MAAM,GAAG,gCAAgC;GAClE;EACF;EACA,MAAM,UAAU,SAAS,OAAO;GAAE,QAAQ;GAAQ;GAAO,QAAQ,KAAK;EAAO,CAAC;EAC9E,MAAM,QAAQ,UAAU;GACtB,SAAS;GACT,QAAQ,KAAK;GACb,QAAQ,KAAK;GACb,KAAK,KAAK;EACZ,CAAC;EACD,IAAI,QAAQ,eAAe;GACzB,MAAM,WAAW,qBAAqB,KAAK,QAAQ,KAAK,KAAK,GAAG;GAChE,MAAM,QACH,cAAc;IAAE,KAAK,KAAK;IAAK,KAAK,KAAK;IAAK,QAAQ,KAAK;IAAQ;GAAS,CAAC,CAAC,CAC9E,OAAO,UAAmB;IACzB,KAAK,QAAQ,KAAK;KAAE,KAAK;KAAO,UAAU,IAAI;IAAS,GAAG,0BAA0B;GACtF,CAAC;EACL;CACF,CAAC,CACH;AACF"}
@@ -1,16 +0,0 @@
1
- import __tsdown_shims_path from 'node:path';
2
- import __tsdown_shims_url from 'node:url';
3
- import { DiffOptions, DiffResult } from "./options.mjs";
4
- //#region src/diff/engine.d.ts
5
- /**
6
- * Compare baseline and current screenshots, returning pass/fail and a diff image.
7
- *
8
- * @param baseline - Baseline PNG buffer.
9
- * @param current - Current capture PNG buffer.
10
- * @param options - Pixel threshold and ratio limits.
11
- * @returns The diff result with pixel counts and an optional overlay image.
12
- */
13
- declare function diffImages(baseline: Buffer, current: Buffer, options: DiffOptions): DiffResult;
14
- //#endregion
15
- export { diffImages };
16
- //# sourceMappingURL=engine.d.mts.map
@@ -1,87 +0,0 @@
1
- import "node:path";
2
- import "node:url";
3
- import.meta.url;
4
- import pixelmatch from "pixelmatch";
5
- import { PNG } from "pngjs";
6
- //#region src/diff/engine.ts
7
- /**
8
- * Compare baseline and current screenshots, returning pass/fail and a diff image.
9
- *
10
- * @param baseline - Baseline PNG buffer.
11
- * @param current - Current capture PNG buffer.
12
- * @param options - Pixel threshold and ratio limits.
13
- * @returns The diff result with pixel counts and an optional overlay image.
14
- */
15
- function diffImages(baseline, current, options) {
16
- const baselinePng = PNG.sync.read(baseline);
17
- const currentPng = PNG.sync.read(current);
18
- const baselineDimensions = {
19
- width: baselinePng.width,
20
- height: baselinePng.height
21
- };
22
- const currentDimensions = {
23
- width: currentPng.width,
24
- height: currentPng.height
25
- };
26
- if (baselineDimensions.width !== currentDimensions.width || baselineDimensions.height !== currentDimensions.height) {
27
- if (options.failOnSizeChange) return {
28
- passed: false,
29
- diffPixels: 0,
30
- diffRatio: 1,
31
- diffImage: null,
32
- baselineDimensions,
33
- currentDimensions,
34
- sizeChanged: true
35
- };
36
- const width = Math.min(baselineDimensions.width, currentDimensions.width);
37
- const height = Math.min(baselineDimensions.height, currentDimensions.height);
38
- const overlap = compareRegions(cropRgba(baselinePng.data, baselineDimensions.width, width, height), cropRgba(currentPng.data, currentDimensions.width, width, height), width, height, options);
39
- const diffRatio = overlap.diffPixels / (width * height);
40
- return {
41
- passed: diffRatio <= options.maxDiffRatio,
42
- diffPixels: overlap.diffPixels,
43
- diffRatio,
44
- diffImage: overlap.diffImage,
45
- baselineDimensions,
46
- currentDimensions,
47
- sizeChanged: true
48
- };
49
- }
50
- const { width } = baselineDimensions;
51
- const { height } = baselineDimensions;
52
- const overlap = compareRegions(baselinePng.data, currentPng.data, width, height, options);
53
- const diffRatio = overlap.diffPixels / (width * height);
54
- return {
55
- passed: diffRatio <= options.maxDiffRatio,
56
- diffPixels: overlap.diffPixels,
57
- diffRatio,
58
- diffImage: overlap.diffImage,
59
- baselineDimensions,
60
- currentDimensions,
61
- sizeChanged: false
62
- };
63
- }
64
- function cropRgba(source, sourceWidth, width, height) {
65
- const cropped = Buffer.alloc(width * height * 4);
66
- const rowBytes = width * 4;
67
- const sourceRowBytes = sourceWidth * 4;
68
- for (let y = 0; y < height; y += 1) source.copy(cropped, y * rowBytes, y * sourceRowBytes, y * sourceRowBytes + rowBytes);
69
- return cropped;
70
- }
71
- function compareRegions(baselineData, currentData, width, height, options) {
72
- const diffPng = new PNG({
73
- width,
74
- height
75
- });
76
- return {
77
- diffPixels: pixelmatch(baselineData, currentData, diffPng.data, width, height, {
78
- threshold: options.pixelThreshold,
79
- includeAA: options.includeAntialiasing
80
- }),
81
- diffImage: PNG.sync.write(diffPng)
82
- };
83
- }
84
- //#endregion
85
- export { diffImages };
86
-
87
- //# sourceMappingURL=engine.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"engine.mjs","names":[],"sources":["../../src/diff/engine.ts"],"sourcesContent":["import pixelmatch from \"pixelmatch\";\nimport { PNG } from \"pngjs\";\nimport type { DiffOptions, DiffResult } from \"./options.ts\";\n\n/**\n * Compare baseline and current screenshots, returning pass/fail and a diff image.\n *\n * @param baseline - Baseline PNG buffer.\n * @param current - Current capture PNG buffer.\n * @param options - Pixel threshold and ratio limits.\n * @returns The diff result with pixel counts and an optional overlay image.\n */\nexport function diffImages(baseline: Buffer, current: Buffer, options: DiffOptions): DiffResult {\n const baselinePng = PNG.sync.read(baseline);\n const currentPng = PNG.sync.read(current);\n\n const baselineDimensions = { width: baselinePng.width, height: baselinePng.height };\n const currentDimensions = { width: currentPng.width, height: currentPng.height };\n const sizeChanged =\n baselineDimensions.width !== currentDimensions.width ||\n baselineDimensions.height !== currentDimensions.height;\n\n if (sizeChanged) {\n if (options.failOnSizeChange) {\n return {\n passed: false,\n diffPixels: 0,\n diffRatio: 1,\n diffImage: null,\n baselineDimensions,\n currentDimensions,\n sizeChanged: true,\n };\n }\n\n // With `failOnSizeChange: false` a size mismatch is not a failure: diff only\n // The top-left overlapping region, normalised by its area. Pixelmatch needs\n // Equal-size inputs, so the larger image is cropped first.\n const width = Math.min(baselineDimensions.width, currentDimensions.width);\n const height = Math.min(baselineDimensions.height, currentDimensions.height);\n const overlap = compareRegions(\n cropRgba(baselinePng.data, baselineDimensions.width, width, height),\n cropRgba(currentPng.data, currentDimensions.width, width, height),\n width,\n height,\n options,\n );\n const diffRatio = overlap.diffPixels / (width * height);\n return {\n passed: diffRatio <= options.maxDiffRatio,\n diffPixels: overlap.diffPixels,\n diffRatio,\n diffImage: overlap.diffImage,\n baselineDimensions,\n currentDimensions,\n sizeChanged: true,\n };\n }\n\n const { width } = baselineDimensions;\n const { height } = baselineDimensions;\n const overlap = compareRegions(baselinePng.data, currentPng.data, width, height, options);\n const diffRatio = overlap.diffPixels / (width * height);\n return {\n passed: diffRatio <= options.maxDiffRatio,\n diffPixels: overlap.diffPixels,\n diffRatio,\n diffImage: overlap.diffImage,\n baselineDimensions,\n currentDimensions,\n sizeChanged: false,\n };\n}\n\nfunction cropRgba(source: Buffer, sourceWidth: number, width: number, height: number): Buffer {\n const cropped = Buffer.alloc(width * height * 4);\n const rowBytes = width * 4;\n const sourceRowBytes = sourceWidth * 4;\n for (let y = 0; y < height; y += 1) {\n source.copy(cropped, y * rowBytes, y * sourceRowBytes, y * sourceRowBytes + rowBytes);\n }\n return cropped;\n}\n\nfunction compareRegions(\n baselineData: Buffer,\n currentData: Buffer,\n width: number,\n height: number,\n options: DiffOptions,\n): { diffPixels: number; diffImage: Buffer } {\n const diffPng = new PNG({ width, height });\n const diffPixels = pixelmatch(baselineData, currentData, diffPng.data, width, height, {\n threshold: options.pixelThreshold,\n includeAA: options.includeAntialiasing,\n });\n return { diffPixels, diffImage: PNG.sync.write(diffPng) };\n}\n"],"mappings":";;;;;;;;;;;;;;AAYA,SAAgB,WAAW,UAAkB,SAAiB,SAAkC;CAC9F,MAAM,cAAc,IAAI,KAAK,KAAK,QAAQ;CAC1C,MAAM,aAAa,IAAI,KAAK,KAAK,OAAO;CAExC,MAAM,qBAAqB;EAAE,OAAO,YAAY;EAAO,QAAQ,YAAY;CAAO;CAClF,MAAM,oBAAoB;EAAE,OAAO,WAAW;EAAO,QAAQ,WAAW;CAAO;CAK/E,IAHE,mBAAmB,UAAU,kBAAkB,SAC/C,mBAAmB,WAAW,kBAAkB,QAEjC;EACf,IAAI,QAAQ,kBACV,OAAO;GACL,QAAQ;GACR,YAAY;GACZ,WAAW;GACX,WAAW;GACX;GACA;GACA,aAAa;EACf;EAMF,MAAM,QAAQ,KAAK,IAAI,mBAAmB,OAAO,kBAAkB,KAAK;EACxE,MAAM,SAAS,KAAK,IAAI,mBAAmB,QAAQ,kBAAkB,MAAM;EAC3E,MAAM,UAAU,eACd,SAAS,YAAY,MAAM,mBAAmB,OAAO,OAAO,MAAM,GAClE,SAAS,WAAW,MAAM,kBAAkB,OAAO,OAAO,MAAM,GAChE,OACA,QACA,OACF;EACA,MAAM,YAAY,QAAQ,cAAc,QAAQ;EAChD,OAAO;GACL,QAAQ,aAAa,QAAQ;GAC7B,YAAY,QAAQ;GACpB;GACA,WAAW,QAAQ;GACnB;GACA;GACA,aAAa;EACf;CACF;CAEA,MAAM,EAAE,UAAU;CAClB,MAAM,EAAE,WAAW;CACnB,MAAM,UAAU,eAAe,YAAY,MAAM,WAAW,MAAM,OAAO,QAAQ,OAAO;CACxF,MAAM,YAAY,QAAQ,cAAc,QAAQ;CAChD,OAAO;EACL,QAAQ,aAAa,QAAQ;EAC7B,YAAY,QAAQ;EACpB;EACA,WAAW,QAAQ;EACnB;EACA;EACA,aAAa;CACf;AACF;AAEA,SAAS,SAAS,QAAgB,aAAqB,OAAe,QAAwB;CAC5F,MAAM,UAAU,OAAO,MAAM,QAAQ,SAAS,CAAC;CAC/C,MAAM,WAAW,QAAQ;CACzB,MAAM,iBAAiB,cAAc;CACrC,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAAK,GAC/B,OAAO,KAAK,SAAS,IAAI,UAAU,IAAI,gBAAgB,IAAI,iBAAiB,QAAQ;CAEtF,OAAO;AACT;AAEA,SAAS,eACP,cACA,aACA,OACA,QACA,SAC2C;CAC3C,MAAM,UAAU,IAAI,IAAI;EAAE;EAAO;CAAO,CAAC;CAKzC,OAAO;EAAE,YAJU,WAAW,cAAc,aAAa,QAAQ,MAAM,OAAO,QAAQ;GACpF,WAAW,QAAQ;GACnB,WAAW,QAAQ;EACrB,CACkB;EAAG,WAAW,IAAI,KAAK,MAAM,OAAO;CAAE;AAC1D"}