@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
package/dist/types.d.mts CHANGED
@@ -1,8 +1,7 @@
1
1
  import __tsdown_shims_path from 'node:path';
2
2
  import __tsdown_shims_url from 'node:url';
3
- //#region src/types.d.ts
4
3
  /** All lifecycle statuses a build can carry. */
5
- declare const BUILD_STATUSES: readonly ["pending", "capturing", "comparing", "reviewing", "approved", "rejected", "failed"];
4
+ declare const BUILD_STATUSES: readonly ["pending", "capturing", "comparing", "reviewing", "approved", "rejected", "failed", "cancelled"];
6
5
  /** Lifecycle status of a build. */
7
6
  type BuildStatus = (typeof BUILD_STATUSES)[number];
8
7
  /** All review statuses a snapshot can carry. */
@@ -11,10 +10,15 @@ declare const SNAPSHOT_STATUSES: readonly ["pending", "new", "unchanged", "chang
11
10
  type SnapshotStatus = (typeof SNAPSHOT_STATUSES)[number];
12
11
  /**
13
12
  * Build statuses considered terminal for retention purging.
14
- * Only builds that have finished review (`approved`, `rejected`, `failed`)
13
+ * Only builds that have finished review (`approved`, `rejected`, `failed`, `cancelled`)
15
14
  * are eligible for TTL-based cleanup; `pending`/`reviewing` builds are kept.
16
15
  */
17
16
  declare const TERMINAL_BUILD_STATUSES: readonly BuildStatus[];
17
+ /**
18
+ * Statuses of a build whose capture or compare work may still run: a user may cancel it (the build
19
+ * then ends `cancelled`, a terminal status no capture write moves it out of again).
20
+ */
21
+ declare const CANCELLABLE_BUILD_STATUSES: readonly BuildStatus[];
18
22
  /** All site-wide user roles. */
19
23
  declare const SITE_ROLES: readonly ["admin", "member", "viewer"];
20
24
  /** Site-wide role of a user. */
@@ -45,10 +49,16 @@ interface AuthUser {
45
49
  */
46
50
  providerId?: string;
47
51
  }
52
+ /** Build-level review verdicts (ADR 0013, decision 3). */
53
+ declare const REVIEW_VERDICTS: readonly ["approved", "rejected"];
54
+ /** A reviewer's verdict on a build. */
55
+ type ReviewVerdict = (typeof REVIEW_VERDICTS)[number];
48
56
  /** All per-project membership roles. */
49
57
  declare const PROJECT_ROLES: readonly ["admin", "approver", "developer", "viewer"];
50
58
  /** Per-project role of a member. */
51
59
  type ProjectRole = (typeof PROJECT_ROLES)[number];
60
+ /** Narrow an untrusted string to a {@link ProjectRole}. */
61
+ declare function isProjectRole(value: unknown): value is ProjectRole;
52
62
  /** Label type keys seeded for every new project. */
53
63
  declare const SEEDED_LABEL_KEYS: readonly ["branch", "persistent", "pr", "mr", "jira", "linear", "figma", "custom"];
54
64
  /** Label type keys reserved for internal bookkeeping (cannot be created by users). */
@@ -58,6 +68,5 @@ declare const RESERVED_LABEL_KEYS: readonly ["build"];
58
68
  * Attach `persistent=true` to keep a build indefinitely, even after its TTL expires.
59
69
  */
60
70
  declare const PERSISTENT_LABEL_KEY = "persistent";
61
- //#endregion
62
- export { AuthUser, BUILD_STATUSES, BuildStatus, PERSISTENT_LABEL_KEY, PROJECT_ROLES, ProjectRole, RESERVED_LABEL_KEYS, SEEDED_LABEL_KEYS, SESSION_COOKIE, SITE_ROLES, SNAPSHOT_STATUSES, SiteRole, SnapshotStatus, TERMINAL_BUILD_STATUSES };
71
+ export { AuthUser, BUILD_STATUSES, BuildStatus, CANCELLABLE_BUILD_STATUSES, PERSISTENT_LABEL_KEY, PROJECT_ROLES, ProjectRole, RESERVED_LABEL_KEYS, REVIEW_VERDICTS, ReviewVerdict, SEEDED_LABEL_KEYS, SESSION_COOKIE, SITE_ROLES, SNAPSHOT_STATUSES, SiteRole, SnapshotStatus, TERMINAL_BUILD_STATUSES, isProjectRole };
63
72
  //# sourceMappingURL=types.d.mts.map
package/dist/types.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
- //#region src/types.ts
4
+ // src/types.ts
5
5
  /** All lifecycle statuses a build can carry. */
6
6
  const BUILD_STATUSES = [
7
7
  "pending",
@@ -10,7 +10,8 @@ const BUILD_STATUSES = [
10
10
  "reviewing",
11
11
  "approved",
12
12
  "rejected",
13
- "failed"
13
+ "failed",
14
+ "cancelled"
14
15
  ];
15
16
  /** All review statuses a snapshot can carry. */
16
17
  const SNAPSHOT_STATUSES = [
@@ -23,13 +24,23 @@ const SNAPSHOT_STATUSES = [
23
24
  ];
24
25
  /**
25
26
  * Build statuses considered terminal for retention purging.
26
- * Only builds that have finished review (`approved`, `rejected`, `failed`)
27
+ * Only builds that have finished review (`approved`, `rejected`, `failed`, `cancelled`)
27
28
  * are eligible for TTL-based cleanup; `pending`/`reviewing` builds are kept.
28
29
  */
29
30
  const TERMINAL_BUILD_STATUSES = [
30
31
  "approved",
31
32
  "rejected",
32
- "failed"
33
+ "failed",
34
+ "cancelled"
35
+ ];
36
+ /**
37
+ * Statuses of a build whose capture or compare work may still run: a user may cancel it (the build
38
+ * then ends `cancelled`, a terminal status no capture write moves it out of again).
39
+ */
40
+ const CANCELLABLE_BUILD_STATUSES = [
41
+ "pending",
42
+ "capturing",
43
+ "comparing"
33
44
  ];
34
45
  /** All site-wide user roles. */
35
46
  const SITE_ROLES = [
@@ -39,6 +50,8 @@ const SITE_ROLES = [
39
50
  ];
40
51
  /** Shared session cookie name used by auth (ADR 0008). */
41
52
  const SESSION_COOKIE = "storyshelf_session";
53
+ /** Build-level review verdicts (ADR 0013, decision 3). */
54
+ const REVIEW_VERDICTS = ["approved", "rejected"];
42
55
  /** All per-project membership roles. */
43
56
  const PROJECT_ROLES = [
44
57
  "admin",
@@ -46,6 +59,10 @@ const PROJECT_ROLES = [
46
59
  "developer",
47
60
  "viewer"
48
61
  ];
62
+ /** Narrow an untrusted string to a {@link ProjectRole}. */
63
+ function isProjectRole(value) {
64
+ return typeof value === "string" && PROJECT_ROLES.includes(value);
65
+ }
49
66
  /** Label type keys seeded for every new project. */
50
67
  const SEEDED_LABEL_KEYS = [
51
68
  "branch",
@@ -64,7 +81,6 @@ const RESERVED_LABEL_KEYS = ["build"];
64
81
  * Attach `persistent=true` to keep a build indefinitely, even after its TTL expires.
65
82
  */
66
83
  const PERSISTENT_LABEL_KEY = "persistent";
67
- //#endregion
68
- export { BUILD_STATUSES, PERSISTENT_LABEL_KEY, PROJECT_ROLES, RESERVED_LABEL_KEYS, SEEDED_LABEL_KEYS, SESSION_COOKIE, SITE_ROLES, SNAPSHOT_STATUSES, TERMINAL_BUILD_STATUSES };
84
+ export { BUILD_STATUSES, CANCELLABLE_BUILD_STATUSES, PERSISTENT_LABEL_KEY, PROJECT_ROLES, RESERVED_LABEL_KEYS, REVIEW_VERDICTS, SEEDED_LABEL_KEYS, SESSION_COOKIE, SITE_ROLES, SNAPSHOT_STATUSES, TERMINAL_BUILD_STATUSES, isProjectRole };
69
85
 
70
86
  //# sourceMappingURL=types.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.mjs","names":[],"sources":["../src/types.ts"],"sourcesContent":["/** All lifecycle statuses a build can carry. */\nexport const BUILD_STATUSES = [\n \"pending\",\n \"capturing\",\n \"comparing\",\n \"reviewing\",\n \"approved\",\n \"rejected\",\n \"failed\",\n] as const;\n\n/** Lifecycle status of a build. */\nexport type BuildStatus = (typeof BUILD_STATUSES)[number];\n\n/** All review statuses a snapshot can carry. */\nexport const SNAPSHOT_STATUSES = [\n \"pending\",\n \"new\",\n \"unchanged\",\n \"changed\",\n \"approved\",\n \"rejected\",\n] as const;\n\n/** Review status of a snapshot. */\nexport type SnapshotStatus = (typeof SNAPSHOT_STATUSES)[number];\n\n/**\n * Build statuses considered terminal for retention purging.\n * Only builds that have finished review (`approved`, `rejected`, `failed`)\n * are eligible for TTL-based cleanup; `pending`/`reviewing` builds are kept.\n */\nexport const TERMINAL_BUILD_STATUSES: readonly BuildStatus[] = [\"approved\", \"rejected\", \"failed\"];\n\n/** All site-wide user roles. */\nexport const SITE_ROLES = [\"admin\", \"member\", \"viewer\"] as const;\n\n/** Site-wide role of a user. */\nexport type SiteRole = (typeof SITE_ROLES)[number];\n\n/** Shared session cookie name used by auth (ADR 0008). */\nexport const SESSION_COOKIE = \"storyshelf_session\";\n\n/** An authenticated user of the platform. */\nexport interface AuthUser {\n /** User ID. */\n id: string;\n /** User email. */\n email: string;\n /** Display name. */\n name: string;\n /** Optional avatar URL. */\n avatarUrl?: string;\n /** Site-wide role. */\n role: SiteRole;\n /**\n * Identity-provider group memberships (names or IDs, provider-dependent).\n * Populated when the provider exposes group claims; absent otherwise.\n * Drives group-to-role mapping at login.\n */\n groups?: string[];\n /**\n * Login method that minted this identity.\n * Matches an engine login method id; absent for single-method deployments.\n */\n providerId?: string;\n}\n\n/** All per-project membership roles. */\nexport const PROJECT_ROLES = [\"admin\", \"approver\", \"developer\", \"viewer\"] as const;\n\n/** Per-project role of a member. */\nexport type ProjectRole = (typeof PROJECT_ROLES)[number];\n\n/** Label type keys seeded for every new project. */\nexport const SEEDED_LABEL_KEYS = [\n \"branch\",\n \"persistent\",\n \"pr\",\n \"mr\",\n \"jira\",\n \"linear\",\n \"figma\",\n \"custom\",\n] as const;\n\n/** Label type keys reserved for internal bookkeeping (cannot be created by users). */\nexport const RESERVED_LABEL_KEYS = [\"build\"] as const;\n\n/**\n * Label key that marks a build as exempt from retention purging.\n * Attach `persistent=true` to keep a build indefinitely, even after its TTL expires.\n */\nexport const PERSISTENT_LABEL_KEY = \"persistent\";\n"],"mappings":";;;;;AACA,MAAa,iBAAiB;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAMA,MAAa,oBAAoB;CAC/B;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;AAUA,MAAa,0BAAkD;CAAC;CAAY;CAAY;AAAQ;;AAGhG,MAAa,aAAa;CAAC;CAAS;CAAU;AAAQ;;AAMtD,MAAa,iBAAiB;;AA4B9B,MAAa,gBAAgB;CAAC;CAAS;CAAY;CAAa;AAAQ;;AAMxE,MAAa,oBAAoB;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,MAAa,sBAAsB,CAAC,OAAO;;;;;AAM3C,MAAa,uBAAuB"}
1
+ {"version":3,"file":"types.mjs","names":[],"sources":["../src/types.ts"],"sourcesContent":["/** All lifecycle statuses a build can carry. */\nexport const BUILD_STATUSES = [\n \"pending\",\n \"capturing\",\n \"comparing\",\n \"reviewing\",\n \"approved\",\n \"rejected\",\n \"failed\",\n \"cancelled\",\n] as const;\n\n/** Lifecycle status of a build. */\nexport type BuildStatus = (typeof BUILD_STATUSES)[number];\n\n/** All review statuses a snapshot can carry. */\nexport const SNAPSHOT_STATUSES = [\n \"pending\",\n \"new\",\n \"unchanged\",\n \"changed\",\n \"approved\",\n \"rejected\",\n] as const;\n\n/** Review status of a snapshot. */\nexport type SnapshotStatus = (typeof SNAPSHOT_STATUSES)[number];\n\n/**\n * Build statuses considered terminal for retention purging.\n * Only builds that have finished review (`approved`, `rejected`, `failed`, `cancelled`)\n * are eligible for TTL-based cleanup; `pending`/`reviewing` builds are kept.\n */\nexport const TERMINAL_BUILD_STATUSES: readonly BuildStatus[] = [\n \"approved\",\n \"rejected\",\n \"failed\",\n \"cancelled\",\n];\n\n/**\n * Statuses of a build whose capture or compare work may still run: a user may cancel it (the build\n * then ends `cancelled`, a terminal status no capture write moves it out of again).\n */\nexport const CANCELLABLE_BUILD_STATUSES: readonly BuildStatus[] = [\n \"pending\",\n \"capturing\",\n \"comparing\",\n];\n\n/** All site-wide user roles. */\nexport const SITE_ROLES = [\"admin\", \"member\", \"viewer\"] as const;\n\n/** Site-wide role of a user. */\nexport type SiteRole = (typeof SITE_ROLES)[number];\n\n/** Shared session cookie name used by auth (ADR 0008). */\nexport const SESSION_COOKIE = \"storyshelf_session\";\n\n/** An authenticated user of the platform. */\nexport interface AuthUser {\n /** User ID. */\n id: string;\n /** User email. */\n email: string;\n /** Display name. */\n name: string;\n /** Optional avatar URL. */\n avatarUrl?: string;\n /** Site-wide role. */\n role: SiteRole;\n /**\n * Identity-provider group memberships (names or IDs, provider-dependent).\n * Populated when the provider exposes group claims; absent otherwise.\n * Drives group-to-role mapping at login.\n */\n groups?: string[];\n /**\n * Login method that minted this identity.\n * Matches an engine login method id; absent for single-method deployments.\n */\n providerId?: string;\n}\n\n/** Build-level review verdicts (ADR 0013, decision 3). */\nexport const REVIEW_VERDICTS = [\"approved\", \"rejected\"] as const;\n\n/** A reviewer's verdict on a build. */\nexport type ReviewVerdict = (typeof REVIEW_VERDICTS)[number];\n\n/** All per-project membership roles. */\nexport const PROJECT_ROLES = [\"admin\", \"approver\", \"developer\", \"viewer\"] as const;\n\n/** Per-project role of a member. */\nexport type ProjectRole = (typeof PROJECT_ROLES)[number];\n\n/** Narrow an untrusted string to a {@link ProjectRole}. */\nexport function isProjectRole(value: unknown): value is ProjectRole {\n return typeof value === \"string\" && (PROJECT_ROLES as readonly string[]).includes(value);\n}\n\n/** Label type keys seeded for every new project. */\nexport const SEEDED_LABEL_KEYS = [\n \"branch\",\n \"persistent\",\n \"pr\",\n \"mr\",\n \"jira\",\n \"linear\",\n \"figma\",\n \"custom\",\n] as const;\n\n/** Label type keys reserved for internal bookkeeping (cannot be created by users). */\nexport const RESERVED_LABEL_KEYS = [\"build\"] as const;\n\n/**\n * Label key that marks a build as exempt from retention purging.\n * Attach `persistent=true` to keep a build indefinitely, even after its TTL expires.\n */\nexport const PERSISTENT_LABEL_KEY = \"persistent\";\n"],"mappings":";;;;;AACA,MAAa,iBAAiB;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAMA,MAAa,oBAAoB;CAC/B;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;AAUA,MAAa,0BAAkD;CAC7D;CACA;CACA;CACA;AACF;;;;;AAMA,MAAa,6BAAqD;CAChE;CACA;CACA;AACF;;AAGA,MAAa,aAAa;CAAC;CAAS;CAAU;AAAQ;;AAMtD,MAAa,iBAAiB;;AA4B9B,MAAa,kBAAkB,CAAC,YAAY,UAAU;;AAMtD,MAAa,gBAAgB;CAAC;CAAS;CAAY;CAAa;AAAQ;;AAMxE,SAAgB,cAAc,OAAsC;CAClE,OAAO,OAAO,UAAU,YAAa,cAAoC,SAAS,KAAK;AACzF;;AAGA,MAAa,oBAAoB;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,MAAa,sBAAsB,CAAC,OAAO;;;;;AAM3C,MAAa,uBAAuB"}
package/dist/urls.d.mts CHANGED
@@ -1,6 +1,5 @@
1
1
  import __tsdown_shims_path from 'node:path';
2
2
  import __tsdown_shims_url from 'node:url';
3
- //#region src/urls.d.ts
4
3
  /** Type-safe URL builder for project pages and published Storybooks. */
5
4
  interface UrlBuilder {
6
5
  projectsList(): string;
@@ -10,10 +9,14 @@ interface UrlBuilder {
10
9
  buildsList(slug: string): string;
11
10
  build(slug: string, buildId: string): string;
12
11
  buildDiff(slug: string, buildId: string): string;
12
+ /** Review page of one snapshot: the build's diff page with that snapshot selected. */
13
+ snapshot(slug: string, buildId: string, snapshotId: string): string;
13
14
  library(slug: string): string;
14
15
  jobs(slug: string): string;
15
16
  labels(slug: string): string;
16
17
  label(slug: string, key: string, value: string): string;
18
+ /** Stable component page, keyed by the story file's import path. */
19
+ component(slug: string, importPath: string): string;
17
20
  storybook(slug: string): string;
18
21
  storybookLabel(slug: string, key: string, value: string): string;
19
22
  storybookBuild(slug: string, buildId: string): string;
@@ -33,6 +36,5 @@ declare function createUrlBuilder(baseUrl: string, publishedBaseDomain?: string)
33
36
  * app-relative paths only, so `javascript:`/`data:` payloads fall back.
34
37
  */
35
38
  declare function safeImageUrl(value: string | undefined): string | null;
36
- //#endregion
37
39
  export { UrlBuilder, createUrlBuilder, safeImageUrl };
38
40
  //# sourceMappingURL=urls.d.mts.map
package/dist/urls.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
- //#region src/urls.ts
4
+ // src/urls.ts
5
5
  /**
6
6
  * Create a URL builder rooted at the given base URL.
7
7
  *
@@ -19,12 +19,14 @@ function createUrlBuilder(baseUrl, publishedBaseDomain) {
19
19
  buildsList: (slug) => `${root}/projects/${slug}/builds`,
20
20
  build: (slug, buildId) => `${root}/projects/${slug}/builds/${buildId}`,
21
21
  buildDiff: (slug, buildId) => `${root}/projects/${slug}/builds/${buildId}/diff`,
22
+ snapshot: (slug, buildId, snapshotId) => `${root}/projects/${slug}/builds/${buildId}/diff?snapshot=${encodeURIComponent(snapshotId)}`,
22
23
  library: (slug) => `${root}/projects/${slug}/library`,
23
24
  jobs: (slug) => `${root}/projects/${slug}/jobs`,
24
25
  labels: (slug) => `${root}/projects/${slug}/labels`,
25
- label: (slug, key, value) => `${root}/projects/${slug}/labels/${encodeURIComponent(key)}/${encodeURI(value)}`,
26
+ label: (slug, key, value) => `${root}/projects/${slug}/labels/${encodeURIComponent(key)}/${encodePath(value)}`,
27
+ component: (slug, importPath) => `${root}/projects/${slug}/components/${encodePath(importPath.replace(/^(?:\.\/)+/u, ""))}`,
26
28
  storybook: (slug) => publishedBaseDomain ? `https://${slug}.${publishedBaseDomain}` : `${root}/projects/${slug}/storybook`,
27
- storybookLabel: (slug, key, value) => `${root}/projects/${slug}/storybook/${encodeURIComponent(key)}/${encodeURI(value)}`,
29
+ storybookLabel: (slug, key, value) => `${root}/projects/${slug}/storybook/${encodeURIComponent(key)}/${encodePath(value)}`,
28
30
  storybookBuild: (slug, buildId) => publishedBaseDomain ? `https://${buildId}.${slug}.${publishedBaseDomain}` : `${root}/projects/${slug}/storybook/build/${buildId}`,
29
31
  settings: (slug) => `${root}/projects/${slug}/settings`,
30
32
  short: (id) => `${root}/_/${id}/`
@@ -43,7 +45,13 @@ function safeImageUrl(value) {
43
45
  return null;
44
46
  }
45
47
  }
46
- //#endregion
48
+ /**
49
+ * Encode a value that may hold slashes (a label value, a branch, an import path) as URL path
50
+ * segments: each segment is escaped (`?`, `#` and `%` included), the slashes stay.
51
+ */
52
+ function encodePath(value) {
53
+ return value.split("/").map((segment) => encodeURIComponent(segment)).join("/");
54
+ }
47
55
  export { createUrlBuilder, safeImageUrl };
48
56
 
49
57
  //# sourceMappingURL=urls.mjs.map
package/dist/urls.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"urls.mjs","names":[],"sources":["../src/urls.ts"],"sourcesContent":["/** Type-safe URL builder for project pages and published Storybooks. */\nexport interface UrlBuilder {\n projectsList(): string;\n projects(): string;\n project(slug: string): string;\n projectsNew(): string;\n buildsList(slug: string): string;\n build(slug: string, buildId: string): string;\n buildDiff(slug: string, buildId: string): string;\n library(slug: string): string;\n jobs(slug: string): string;\n labels(slug: string): string;\n label(slug: string, key: string, value: string): string;\n storybook(slug: string): string;\n storybookLabel(slug: string, key: string, value: string): string;\n storybookBuild(slug: string, buildId: string): string;\n settings(slug: string): string;\n short(id: string): string;\n}\n\n/**\n * Create a URL builder rooted at the given base URL.\n *\n * @param baseUrl - Public root URL of the shelf server.\n * @param publishedBaseDomain - Optional wildcard domain for published Storybooks.\n * @returns The URL builder.\n */\nexport function createUrlBuilder(baseUrl: string, publishedBaseDomain?: string): UrlBuilder {\n const root = baseUrl.replace(/\\/+$/u, \"\");\n\n return {\n projectsList: () => root || \"/\",\n projects: () => `${root}/projects`,\n project: (slug) => `${root}/projects/${slug}`,\n projectsNew: () => `${root}/projects/new`,\n buildsList: (slug) => `${root}/projects/${slug}/builds`,\n build: (slug, buildId) => `${root}/projects/${slug}/builds/${buildId}`,\n buildDiff: (slug, buildId) => `${root}/projects/${slug}/builds/${buildId}/diff`,\n library: (slug) => `${root}/projects/${slug}/library`,\n jobs: (slug) => `${root}/projects/${slug}/jobs`,\n labels: (slug) => `${root}/projects/${slug}/labels`,\n label: (slug, key, value) =>\n `${root}/projects/${slug}/labels/${encodeURIComponent(key)}/${encodeURI(value)}`,\n storybook: (slug) =>\n publishedBaseDomain\n ? `https://${slug}.${publishedBaseDomain}`\n : `${root}/projects/${slug}/storybook`,\n storybookLabel: (slug, key, value) =>\n `${root}/projects/${slug}/storybook/${encodeURIComponent(key)}/${encodeURI(value)}`,\n storybookBuild: (slug, buildId) =>\n publishedBaseDomain\n ? `https://${buildId}.${slug}.${publishedBaseDomain}`\n : `${root}/projects/${slug}/storybook/build/${buildId}`,\n settings: (slug) => `${root}/projects/${slug}/settings`,\n short: (id) => `${root}/_/${id}/`,\n };\n}\n\n/**\n * Embeddable image URL check for IdP-supplied avatars: `https:` and\n * app-relative paths only, so `javascript:`/`data:` payloads fall back.\n */\nexport function safeImageUrl(value: string | undefined): string | null {\n if (!value) {\n return null;\n }\n if (value.startsWith(\"/\") && !value.startsWith(\"//\")) {\n return value;\n }\n try {\n const url = new URL(value);\n return url.protocol === \"https:\" ? value : null;\n } catch {\n return null;\n }\n}\n"],"mappings":";;;;;;;;;;;AA2BA,SAAgB,iBAAiB,SAAiB,qBAA0C;CAC1F,MAAM,OAAO,QAAQ,QAAQ,SAAS,EAAE;CAExC,OAAO;EACL,oBAAoB,QAAQ;EAC5B,gBAAgB,GAAG,KAAK;EACxB,UAAU,SAAS,GAAG,KAAK,YAAY;EACvC,mBAAmB,GAAG,KAAK;EAC3B,aAAa,SAAS,GAAG,KAAK,YAAY,KAAK;EAC/C,QAAQ,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,UAAU;EAC7D,YAAY,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,UAAU,QAAQ;EACzE,UAAU,SAAS,GAAG,KAAK,YAAY,KAAK;EAC5C,OAAO,SAAS,GAAG,KAAK,YAAY,KAAK;EACzC,SAAS,SAAS,GAAG,KAAK,YAAY,KAAK;EAC3C,QAAQ,MAAM,KAAK,UACjB,GAAG,KAAK,YAAY,KAAK,UAAU,mBAAmB,GAAG,EAAE,GAAG,UAAU,KAAK;EAC/E,YAAY,SACV,sBACI,WAAW,KAAK,GAAG,wBACnB,GAAG,KAAK,YAAY,KAAK;EAC/B,iBAAiB,MAAM,KAAK,UAC1B,GAAG,KAAK,YAAY,KAAK,aAAa,mBAAmB,GAAG,EAAE,GAAG,UAAU,KAAK;EAClF,iBAAiB,MAAM,YACrB,sBACI,WAAW,QAAQ,GAAG,KAAK,GAAG,wBAC9B,GAAG,KAAK,YAAY,KAAK,mBAAmB;EAClD,WAAW,SAAS,GAAG,KAAK,YAAY,KAAK;EAC7C,QAAQ,OAAO,GAAG,KAAK,KAAK,GAAG;CACjC;AACF;;;;;AAMA,SAAgB,aAAa,OAA0C;CACrE,IAAI,CAAC,OACH,OAAO;CAET,IAAI,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,WAAW,IAAI,GACjD,OAAO;CAET,IAAI;EAEF,OAAO,IADS,IAAI,KACX,CAAC,CAAC,aAAa,WAAW,QAAQ;CAC7C,QAAQ;EACN,OAAO;CACT;AACF"}
1
+ {"version":3,"file":"urls.mjs","names":[],"sources":["../src/urls.ts"],"sourcesContent":["/** Type-safe URL builder for project pages and published Storybooks. */\nexport interface UrlBuilder {\n projectsList(): string;\n projects(): string;\n project(slug: string): string;\n projectsNew(): string;\n buildsList(slug: string): string;\n build(slug: string, buildId: string): string;\n buildDiff(slug: string, buildId: string): string;\n /** Review page of one snapshot: the build's diff page with that snapshot selected. */\n snapshot(slug: string, buildId: string, snapshotId: string): string;\n library(slug: string): string;\n jobs(slug: string): string;\n labels(slug: string): string;\n label(slug: string, key: string, value: string): string;\n /** Stable component page, keyed by the story file's import path. */\n component(slug: string, importPath: string): string;\n storybook(slug: string): string;\n storybookLabel(slug: string, key: string, value: string): string;\n storybookBuild(slug: string, buildId: string): string;\n settings(slug: string): string;\n short(id: string): string;\n}\n\n/**\n * Create a URL builder rooted at the given base URL.\n *\n * @param baseUrl - Public root URL of the shelf server.\n * @param publishedBaseDomain - Optional wildcard domain for published Storybooks.\n * @returns The URL builder.\n */\nexport function createUrlBuilder(baseUrl: string, publishedBaseDomain?: string): UrlBuilder {\n const root = baseUrl.replace(/\\/+$/u, \"\");\n\n return {\n projectsList: () => root || \"/\",\n projects: () => `${root}/projects`,\n project: (slug) => `${root}/projects/${slug}`,\n projectsNew: () => `${root}/projects/new`,\n buildsList: (slug) => `${root}/projects/${slug}/builds`,\n build: (slug, buildId) => `${root}/projects/${slug}/builds/${buildId}`,\n buildDiff: (slug, buildId) => `${root}/projects/${slug}/builds/${buildId}/diff`,\n snapshot: (slug, buildId, snapshotId) =>\n `${root}/projects/${slug}/builds/${buildId}/diff?snapshot=${encodeURIComponent(snapshotId)}`,\n library: (slug) => `${root}/projects/${slug}/library`,\n jobs: (slug) => `${root}/projects/${slug}/jobs`,\n labels: (slug) => `${root}/projects/${slug}/labels`,\n label: (slug, key, value) =>\n `${root}/projects/${slug}/labels/${encodeURIComponent(key)}/${encodePath(value)}`,\n component: (slug, importPath) =>\n `${root}/projects/${slug}/components/${encodePath(importPath.replace(/^(?:\\.\\/)+/u, \"\"))}`,\n storybook: (slug) =>\n publishedBaseDomain\n ? `https://${slug}.${publishedBaseDomain}`\n : `${root}/projects/${slug}/storybook`,\n storybookLabel: (slug, key, value) =>\n `${root}/projects/${slug}/storybook/${encodeURIComponent(key)}/${encodePath(value)}`,\n storybookBuild: (slug, buildId) =>\n publishedBaseDomain\n ? `https://${buildId}.${slug}.${publishedBaseDomain}`\n : `${root}/projects/${slug}/storybook/build/${buildId}`,\n settings: (slug) => `${root}/projects/${slug}/settings`,\n short: (id) => `${root}/_/${id}/`,\n };\n}\n\n/**\n * Embeddable image URL check for IdP-supplied avatars: `https:` and\n * app-relative paths only, so `javascript:`/`data:` payloads fall back.\n */\nexport function safeImageUrl(value: string | undefined): string | null {\n if (!value) {\n return null;\n }\n if (value.startsWith(\"/\") && !value.startsWith(\"//\")) {\n return value;\n }\n try {\n const url = new URL(value);\n return url.protocol === \"https:\" ? value : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Encode a value that may hold slashes (a label value, a branch, an import path) as URL path\n * segments: each segment is escaped (`?`, `#` and `%` included), the slashes stay.\n */\nfunction encodePath(value: string): string {\n return value\n .split(\"/\")\n .map((segment) => encodeURIComponent(segment))\n .join(\"/\");\n}\n"],"mappings":";;;;;;;;;;;AA+BA,SAAgB,iBAAiB,SAAiB,qBAA0C;CAC1F,MAAM,OAAO,QAAQ,QAAQ,SAAS,EAAE;CAExC,OAAO;EACL,oBAAoB,QAAQ;EAC5B,gBAAgB,GAAG,KAAK;EACxB,UAAU,SAAS,GAAG,KAAK,YAAY;EACvC,mBAAmB,GAAG,KAAK;EAC3B,aAAa,SAAS,GAAG,KAAK,YAAY,KAAK;EAC/C,QAAQ,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,UAAU;EAC7D,YAAY,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,UAAU,QAAQ;EACzE,WAAW,MAAM,SAAS,eACxB,GAAG,KAAK,YAAY,KAAK,UAAU,QAAQ,iBAAiB,mBAAmB,UAAU;EAC3F,UAAU,SAAS,GAAG,KAAK,YAAY,KAAK;EAC5C,OAAO,SAAS,GAAG,KAAK,YAAY,KAAK;EACzC,SAAS,SAAS,GAAG,KAAK,YAAY,KAAK;EAC3C,QAAQ,MAAM,KAAK,UACjB,GAAG,KAAK,YAAY,KAAK,UAAU,mBAAmB,GAAG,EAAE,GAAG,WAAW,KAAK;EAChF,YAAY,MAAM,eAChB,GAAG,KAAK,YAAY,KAAK,cAAc,WAAW,WAAW,QAAQ,eAAe,EAAE,CAAC;EACzF,YAAY,SACV,sBACI,WAAW,KAAK,GAAG,wBACnB,GAAG,KAAK,YAAY,KAAK;EAC/B,iBAAiB,MAAM,KAAK,UAC1B,GAAG,KAAK,YAAY,KAAK,aAAa,mBAAmB,GAAG,EAAE,GAAG,WAAW,KAAK;EACnF,iBAAiB,MAAM,YACrB,sBACI,WAAW,QAAQ,GAAG,KAAK,GAAG,wBAC9B,GAAG,KAAK,YAAY,KAAK,mBAAmB;EAClD,WAAW,SAAS,GAAG,KAAK,YAAY,KAAK;EAC7C,QAAQ,OAAO,GAAG,KAAK,KAAK,GAAG;CACjC;AACF;;;;;AAMA,SAAgB,aAAa,OAA0C;CACrE,IAAI,CAAC,OACH,OAAO;CAET,IAAI,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,WAAW,IAAI,GACjD,OAAO;CAET,IAAI;EAEF,OAAO,IADS,IAAI,KACX,CAAC,CAAC,aAAa,WAAW,QAAQ;CAC7C,QAAQ;EACN,OAAO;CACT;AACF;;;;;AAMA,SAAS,WAAW,OAAuB;CACzC,OAAO,MACJ,MAAM,GAAG,CAAC,CACV,KAAK,YAAY,mBAAmB,OAAO,CAAC,CAAC,CAC7C,KAAK,GAAG;AACb"}
@@ -0,0 +1,64 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { Logger } from "../logger.mjs";
4
+ /** Tuning for {@link AdaptiveConcurrency}. */
5
+ interface AdaptiveOptions {
6
+ /** Starting in-flight limit. */
7
+ initial: number;
8
+ /** Lowest limit (default 1). */
9
+ min?: number;
10
+ /** Highest limit. */
11
+ max: number;
12
+ /** Event-loop lag p99 (ms) since the previous reading; defaults to a `perf_hooks` histogram. */
13
+ readLagMs?: () => number;
14
+ /** p95 latency may grow this much over the first window before the window counts as unhealthy (default 1.25). */
15
+ latencyTolerance?: number;
16
+ /** Event-loop lag p99 above this (ms) counts as unhealthy (default 100). */
17
+ lagLimitMs?: number;
18
+ /** Windows to hold after a timeout back-off before raising again (default 3). */
19
+ holdWindows?: number;
20
+ /** Scoped logger; every limit change is logged with its reason. */
21
+ logger?: Logger;
22
+ }
23
+ /** What one finished capture reports. */
24
+ interface Observation {
25
+ durationMs: number;
26
+ /** The capture hit a navigation/action timeout. */
27
+ timedOut?: boolean;
28
+ }
29
+ /**
30
+ * AIMD controller over the number of pages rendering at once.
31
+ *
32
+ * Captures are grouped in windows (at least 8, or two per slot). A window with any timeout halves
33
+ * the limit and holds it there for a few windows; a window whose p95 latency grew more than the
34
+ * tolerance over the first window, or whose event-loop lag p99 is high, lowers it by one; a healthy
35
+ * window raises it by one. The first window without timeouts sets the latency baseline, so it only
36
+ * ever holds.
37
+ */
38
+ declare class AdaptiveConcurrency {
39
+ private current;
40
+ private readonly min;
41
+ private readonly max;
42
+ private readonly options;
43
+ private window;
44
+ private baselineP95;
45
+ private hold;
46
+ private readonly lag;
47
+ constructor(options: AdaptiveOptions);
48
+ /** Pages allowed in flight right now. */
49
+ get limit(): number;
50
+ /** Record a finished capture; may change {@link limit} at a window boundary. */
51
+ observe(observation: Observation): void;
52
+ /** Release the lag monitor. */
53
+ dispose(): void;
54
+ private closeWindow;
55
+ /** Decide what a finished window means; updates the post-back-off hold. */
56
+ private judge;
57
+ /** A healthy window: set the baseline, sit out a back-off hold, or raise by one. */
58
+ private raiseOrHold;
59
+ private isSlow;
60
+ }
61
+ /** Whether an error is a navigation/action timeout (Playwright and Puppeteer both name it `TimeoutError`). */
62
+ declare function isTimeoutError(error: unknown): boolean;
63
+ export { AdaptiveConcurrency, AdaptiveOptions, Observation, isTimeoutError };
64
+ //# sourceMappingURL=adaptive-concurrency.d.mts.map
@@ -0,0 +1,148 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { monitorEventLoopDelay } from "node:perf_hooks";
5
+ // src/utils/adaptive-concurrency.ts
6
+ /** Adaptive page concurrency: raise while capture stays healthy, back off when it does not. */
7
+ const MIN_WINDOW = 8;
8
+ /**
9
+ * AIMD controller over the number of pages rendering at once.
10
+ *
11
+ * Captures are grouped in windows (at least 8, or two per slot). A window with any timeout halves
12
+ * the limit and holds it there for a few windows; a window whose p95 latency grew more than the
13
+ * tolerance over the first window, or whose event-loop lag p99 is high, lowers it by one; a healthy
14
+ * window raises it by one. The first window without timeouts sets the latency baseline, so it only
15
+ * ever holds.
16
+ */
17
+ var AdaptiveConcurrency = class {
18
+ current;
19
+ min;
20
+ max;
21
+ options;
22
+ window = [];
23
+ baselineP95 = null;
24
+ hold = 0;
25
+ lag;
26
+ constructor(options) {
27
+ this.options = options;
28
+ this.min = Math.max(1, Math.floor(options.min ?? 1));
29
+ this.max = Math.max(this.min, Math.floor(options.max));
30
+ this.current = clamp(Math.floor(options.initial), this.min, this.max);
31
+ this.lag = options.readLagMs ? {
32
+ read: options.readLagMs,
33
+ stop: noop
34
+ } : eventLoopLagReader();
35
+ }
36
+ /** Pages allowed in flight right now. */
37
+ get limit() {
38
+ return this.current;
39
+ }
40
+ /** Record a finished capture; may change {@link limit} at a window boundary. */
41
+ observe(observation) {
42
+ this.window.push(observation);
43
+ if (this.window.length >= Math.max(MIN_WINDOW, this.current * 2)) this.closeWindow();
44
+ }
45
+ /** Release the lag monitor. */
46
+ dispose() {
47
+ this.lag.stop();
48
+ }
49
+ closeWindow() {
50
+ const samples = this.window;
51
+ this.window = [];
52
+ const stats = {
53
+ p95: percentile(samples.map((sample) => sample.durationMs), .95),
54
+ timeouts: samples.filter((sample) => sample.timedOut).length,
55
+ lagP99: this.lag.read()
56
+ };
57
+ const from = this.current;
58
+ const verdict = this.judge(stats);
59
+ if (stats.timeouts === 0) this.baselineP95 ??= stats.p95;
60
+ this.current = verdict.halve ? Math.max(this.min, Math.floor(from / 2)) : clamp(from + verdict.delta, this.min, this.max);
61
+ if (this.current !== from) this.options.logger?.info({
62
+ from,
63
+ to: this.current,
64
+ reason: verdict.reason,
65
+ ...roundedStats(stats)
66
+ }, "capture concurrency adjusted");
67
+ }
68
+ /** Decide what a finished window means; updates the post-back-off hold. */
69
+ judge(window) {
70
+ if (window.timeouts > 0) {
71
+ this.hold = this.options.holdWindows ?? 3;
72
+ return {
73
+ delta: 0,
74
+ halve: true,
75
+ reason: "timeouts"
76
+ };
77
+ }
78
+ const slow = this.isSlow(window.p95);
79
+ if (slow || window.lagP99 > (this.options.lagLimitMs ?? 100)) return {
80
+ delta: -1,
81
+ halve: false,
82
+ reason: slow ? "latency" : "event-loop lag"
83
+ };
84
+ return this.raiseOrHold();
85
+ }
86
+ /** A healthy window: set the baseline, sit out a back-off hold, or raise by one. */
87
+ raiseOrHold() {
88
+ if (this.baselineP95 === null) return {
89
+ delta: 0,
90
+ halve: false,
91
+ reason: "baseline"
92
+ };
93
+ if (this.hold > 0) {
94
+ this.hold -= 1;
95
+ return {
96
+ delta: 0,
97
+ halve: false,
98
+ reason: "holding after back-off"
99
+ };
100
+ }
101
+ return {
102
+ delta: 1,
103
+ halve: false,
104
+ reason: "healthy"
105
+ };
106
+ }
107
+ isSlow(p95) {
108
+ return this.baselineP95 !== null && p95 > this.baselineP95 * (this.options.latencyTolerance ?? 1.25);
109
+ }
110
+ };
111
+ function roundedStats(stats) {
112
+ return {
113
+ p95Ms: Math.round(stats.p95),
114
+ lagP99Ms: Math.round(stats.lagP99),
115
+ timeouts: stats.timeouts
116
+ };
117
+ }
118
+ /** Whether an error is a navigation/action timeout (Playwright and Puppeteer both name it `TimeoutError`). */
119
+ function isTimeoutError(error) {
120
+ if (!(error instanceof Error)) return false;
121
+ return error.name === "TimeoutError" || /\btimed? ?out\b/iu.test(error.message);
122
+ }
123
+ function noop() {}
124
+ function clamp(value, min, max) {
125
+ return Math.min(max, Math.max(min, value));
126
+ }
127
+ function percentile(values, fraction) {
128
+ const sorted = values.toSorted((left, right) => left - right);
129
+ return sorted[Math.min(sorted.length - 1, Math.floor(sorted.length * fraction))] ?? 0;
130
+ }
131
+ /** p99 event-loop delay (ms) since the previous read, from a `perf_hooks` histogram. */
132
+ function eventLoopLagReader() {
133
+ const histogram = monitorEventLoopDelay({ resolution: 10 });
134
+ histogram.enable();
135
+ return {
136
+ read: () => {
137
+ const lag = histogram.percentile(99) / 1e6;
138
+ histogram.reset();
139
+ return lag;
140
+ },
141
+ stop: () => {
142
+ histogram.disable();
143
+ }
144
+ };
145
+ }
146
+ export { AdaptiveConcurrency, isTimeoutError };
147
+
148
+ //# sourceMappingURL=adaptive-concurrency.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adaptive-concurrency.mjs","names":[],"sources":["../../src/utils/adaptive-concurrency.ts"],"sourcesContent":["/** Adaptive page concurrency: raise while capture stays healthy, back off when it does not. */\nimport { monitorEventLoopDelay } from \"node:perf_hooks\";\nimport type { Logger } from \"../logger.ts\";\n\n/** Tuning for {@link AdaptiveConcurrency}. */\nexport interface AdaptiveOptions {\n /** Starting in-flight limit. */\n initial: number;\n /** Lowest limit (default 1). */\n min?: number;\n /** Highest limit. */\n max: number;\n /** Event-loop lag p99 (ms) since the previous reading; defaults to a `perf_hooks` histogram. */\n readLagMs?: () => number;\n /** p95 latency may grow this much over the first window before the window counts as unhealthy (default 1.25). */\n latencyTolerance?: number;\n /** Event-loop lag p99 above this (ms) counts as unhealthy (default 100). */\n lagLimitMs?: number;\n /** Windows to hold after a timeout back-off before raising again (default 3). */\n holdWindows?: number;\n /** Scoped logger; every limit change is logged with its reason. */\n logger?: Logger;\n}\n\n/** What one finished capture reports. */\nexport interface Observation {\n durationMs: number;\n /** The capture hit a navigation/action timeout. */\n timedOut?: boolean;\n}\n\nconst MIN_WINDOW = 8;\n\n/**\n * AIMD controller over the number of pages rendering at once.\n *\n * Captures are grouped in windows (at least 8, or two per slot). A window with any timeout halves\n * the limit and holds it there for a few windows; a window whose p95 latency grew more than the\n * tolerance over the first window, or whose event-loop lag p99 is high, lowers it by one; a healthy\n * window raises it by one. The first window without timeouts sets the latency baseline, so it only\n * ever holds.\n */\nexport class AdaptiveConcurrency {\n private current: number;\n private readonly min: number;\n private readonly max: number;\n private readonly options: AdaptiveOptions;\n private window: Observation[] = [];\n private baselineP95: number | null = null;\n private hold = 0;\n private readonly lag: { read: () => number; stop: () => void };\n\n constructor(options: AdaptiveOptions) {\n this.options = options;\n this.min = Math.max(1, Math.floor(options.min ?? 1));\n this.max = Math.max(this.min, Math.floor(options.max));\n this.current = clamp(Math.floor(options.initial), this.min, this.max);\n this.lag = options.readLagMs ? { read: options.readLagMs, stop: noop } : eventLoopLagReader();\n }\n\n /** Pages allowed in flight right now. */\n get limit(): number {\n return this.current;\n }\n\n /** Record a finished capture; may change {@link limit} at a window boundary. */\n observe(observation: Observation): void {\n this.window.push(observation);\n if (this.window.length >= Math.max(MIN_WINDOW, this.current * 2)) {\n this.closeWindow();\n }\n }\n\n /** Release the lag monitor. */\n dispose(): void {\n this.lag.stop();\n }\n\n private closeWindow(): void {\n const samples = this.window;\n this.window = [];\n const stats = {\n p95: percentile(\n samples.map((sample) => sample.durationMs),\n 0.95,\n ),\n timeouts: samples.filter((sample) => sample.timedOut).length,\n lagP99: this.lag.read(),\n };\n const from = this.current;\n const verdict = this.judge(stats);\n // A window with a timeout carries the timeout's duration in its p95: never a baseline.\n if (stats.timeouts === 0) {\n this.baselineP95 ??= stats.p95;\n }\n this.current = verdict.halve\n ? Math.max(this.min, Math.floor(from / 2))\n : clamp(from + verdict.delta, this.min, this.max);\n if (this.current !== from) {\n this.options.logger?.info(\n { from, to: this.current, reason: verdict.reason, ...roundedStats(stats) },\n \"capture concurrency adjusted\",\n );\n }\n }\n\n /** Decide what a finished window means; updates the post-back-off hold. */\n private judge(window: WindowStats): Verdict {\n if (window.timeouts > 0) {\n this.hold = this.options.holdWindows ?? 3;\n return { delta: 0, halve: true, reason: \"timeouts\" };\n }\n const slow = this.isSlow(window.p95);\n if (slow || window.lagP99 > (this.options.lagLimitMs ?? 100)) {\n return { delta: -1, halve: false, reason: slow ? \"latency\" : \"event-loop lag\" };\n }\n return this.raiseOrHold();\n }\n\n /** A healthy window: set the baseline, sit out a back-off hold, or raise by one. */\n private raiseOrHold(): Verdict {\n if (this.baselineP95 === null) {\n return { delta: 0, halve: false, reason: \"baseline\" };\n }\n if (this.hold > 0) {\n this.hold -= 1;\n return { delta: 0, halve: false, reason: \"holding after back-off\" };\n }\n return { delta: 1, halve: false, reason: \"healthy\" };\n }\n\n private isSlow(p95: number): boolean {\n return (\n this.baselineP95 !== null && p95 > this.baselineP95 * (this.options.latencyTolerance ?? 1.25)\n );\n }\n}\n\ninterface WindowStats {\n p95: number;\n timeouts: number;\n lagP99: number;\n}\n\nfunction roundedStats(stats: WindowStats): Record<string, number> {\n return {\n p95Ms: Math.round(stats.p95),\n lagP99Ms: Math.round(stats.lagP99),\n timeouts: stats.timeouts,\n };\n}\n\ninterface Verdict {\n delta: number;\n halve: boolean;\n reason: string;\n}\n\n/** Whether an error is a navigation/action timeout (Playwright and Puppeteer both name it `TimeoutError`). */\nexport function isTimeoutError(error: unknown): boolean {\n if (!(error instanceof Error)) {\n return false;\n }\n return error.name === \"TimeoutError\" || /\\btimed? ?out\\b/iu.test(error.message);\n}\n\nfunction noop(): void {}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\nfunction percentile(values: number[], fraction: number): number {\n const sorted = values.toSorted((left, right) => left - right);\n return sorted[Math.min(sorted.length - 1, Math.floor(sorted.length * fraction))] ?? 0;\n}\n\n/** p99 event-loop delay (ms) since the previous read, from a `perf_hooks` histogram. */\nfunction eventLoopLagReader(): { read: () => number; stop: () => void } {\n const histogram = monitorEventLoopDelay({ resolution: 10 });\n histogram.enable();\n return {\n read: () => {\n const lag = histogram.percentile(99) / 1e6;\n histogram.reset();\n return lag;\n },\n stop: () => {\n histogram.disable();\n },\n };\n}\n"],"mappings":";;;;;;AA+BA,MAAM,aAAa;;;;;;;;;;AAWnB,IAAa,sBAAb,MAAiC;CAC/B;CACA;CACA;CACA;CACA,SAAgC,CAAC;CACjC,cAAqC;CACrC,OAAe;CACf;CAEA,YAAY,SAA0B;EACpC,KAAK,UAAU;EACf,KAAK,MAAM,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,OAAO,CAAC,CAAC;EACnD,KAAK,MAAM,KAAK,IAAI,KAAK,KAAK,KAAK,MAAM,QAAQ,GAAG,CAAC;EACrD,KAAK,UAAU,MAAM,KAAK,MAAM,QAAQ,OAAO,GAAG,KAAK,KAAK,KAAK,GAAG;EACpE,KAAK,MAAM,QAAQ,YAAY;GAAE,MAAM,QAAQ;GAAW,MAAM;EAAK,IAAI,mBAAmB;CAC9F;;CAGA,IAAI,QAAgB;EAClB,OAAO,KAAK;CACd;;CAGA,QAAQ,aAAgC;EACtC,KAAK,OAAO,KAAK,WAAW;EAC5B,IAAI,KAAK,OAAO,UAAU,KAAK,IAAI,YAAY,KAAK,UAAU,CAAC,GAC7D,KAAK,YAAY;CAErB;;CAGA,UAAgB;EACd,KAAK,IAAI,KAAK;CAChB;CAEA,cAA4B;EAC1B,MAAM,UAAU,KAAK;EACrB,KAAK,SAAS,CAAC;EACf,MAAM,QAAQ;GACZ,KAAK,WACH,QAAQ,KAAK,WAAW,OAAO,UAAU,GACzC,GACF;GACA,UAAU,QAAQ,QAAQ,WAAW,OAAO,QAAQ,CAAC,CAAC;GACtD,QAAQ,KAAK,IAAI,KAAK;EACxB;EACA,MAAM,OAAO,KAAK;EAClB,MAAM,UAAU,KAAK,MAAM,KAAK;EAEhC,IAAI,MAAM,aAAa,GACrB,KAAK,gBAAgB,MAAM;EAE7B,KAAK,UAAU,QAAQ,QACnB,KAAK,IAAI,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC,CAAC,IACvC,MAAM,OAAO,QAAQ,OAAO,KAAK,KAAK,KAAK,GAAG;EAClD,IAAI,KAAK,YAAY,MACnB,KAAK,QAAQ,QAAQ,KACnB;GAAE;GAAM,IAAI,KAAK;GAAS,QAAQ,QAAQ;GAAQ,GAAG,aAAa,KAAK;EAAE,GACzE,8BACF;CAEJ;;CAGA,MAAc,QAA8B;EAC1C,IAAI,OAAO,WAAW,GAAG;GACvB,KAAK,OAAO,KAAK,QAAQ,eAAe;GACxC,OAAO;IAAE,OAAO;IAAG,OAAO;IAAM,QAAQ;GAAW;EACrD;EACA,MAAM,OAAO,KAAK,OAAO,OAAO,GAAG;EACnC,IAAI,QAAQ,OAAO,UAAU,KAAK,QAAQ,cAAc,MACtD,OAAO;GAAE,OAAO;GAAI,OAAO;GAAO,QAAQ,OAAO,YAAY;EAAiB;EAEhF,OAAO,KAAK,YAAY;CAC1B;;CAGA,cAA+B;EAC7B,IAAI,KAAK,gBAAgB,MACvB,OAAO;GAAE,OAAO;GAAG,OAAO;GAAO,QAAQ;EAAW;EAEtD,IAAI,KAAK,OAAO,GAAG;GACjB,KAAK,QAAQ;GACb,OAAO;IAAE,OAAO;IAAG,OAAO;IAAO,QAAQ;GAAyB;EACpE;EACA,OAAO;GAAE,OAAO;GAAG,OAAO;GAAO,QAAQ;EAAU;CACrD;CAEA,OAAe,KAAsB;EACnC,OACE,KAAK,gBAAgB,QAAQ,MAAM,KAAK,eAAe,KAAK,QAAQ,oBAAoB;CAE5F;AACF;AAQA,SAAS,aAAa,OAA4C;CAChE,OAAO;EACL,OAAO,KAAK,MAAM,MAAM,GAAG;EAC3B,UAAU,KAAK,MAAM,MAAM,MAAM;EACjC,UAAU,MAAM;CAClB;AACF;;AASA,SAAgB,eAAe,OAAyB;CACtD,IAAI,EAAE,iBAAiB,QACrB,OAAO;CAET,OAAO,MAAM,SAAS,kBAAkB,oBAAoB,KAAK,MAAM,OAAO;AAChF;AAEA,SAAS,OAAa,CAAC;AAEvB,SAAS,MAAM,OAAe,KAAa,KAAqB;CAC9D,OAAO,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,CAAC;AAC3C;AAEA,SAAS,WAAW,QAAkB,UAA0B;CAC9D,MAAM,SAAS,OAAO,UAAU,MAAM,UAAU,OAAO,KAAK;CAC5D,OAAO,OAAO,KAAK,IAAI,OAAO,SAAS,GAAG,KAAK,MAAM,OAAO,SAAS,QAAQ,CAAC,MAAM;AACtF;;AAGA,SAAS,qBAA+D;CACtE,MAAM,YAAY,sBAAsB,EAAE,YAAY,GAAG,CAAC;CAC1D,UAAU,OAAO;CACjB,OAAO;EACL,YAAY;GACV,MAAM,MAAM,UAAU,WAAW,EAAE,IAAI;GACvC,UAAU,MAAM;GAChB,OAAO;EACT;EACA,YAAY;GACV,UAAU,QAAQ;EACpB;CACF;AACF"}
@@ -0,0 +1,26 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ /** Retrying a connection to a remote browser service (ADR 0007, decision 4). */
4
+ /** Options of {@link retryConnect}. */
5
+ interface RetryConnectOptions {
6
+ /** Retries after the first attempt. */
7
+ retries: number;
8
+ /** Delay before the first retry in ms; doubles each time, with jitter, capped at 10 s. */
9
+ backoffMs: number;
10
+ /** Whether an error is worth another attempt; defaults to {@link isRetryableConnectError}. */
11
+ retryable?: (error: unknown) => boolean;
12
+ /** Called before each retry with the error, the retry's number (from 1) and its delay. */
13
+ onRetry?: (error: unknown, retry: number, delayMs: number) => void;
14
+ /** Injectable for tests. */
15
+ sleep?: (ms: number) => Promise<void>;
16
+ }
17
+ /** Whether a connect error is worth retrying: connection-level, not a configuration mistake. */
18
+ declare function isRetryableConnectError(error: unknown): boolean;
19
+ /**
20
+ * Run `connect`, retrying a connection-level failure with exponential backoff, so a provider
21
+ * outage or a full plan is absorbed here and crash isolation only ever sees a browser that died
22
+ * while rendering. The last error is thrown once the retries are spent.
23
+ */
24
+ declare function retryConnect<T>(connect: () => Promise<T>, options: RetryConnectOptions): Promise<T>;
25
+ export { RetryConnectOptions, isRetryableConnectError, retryConnect };
26
+ //# sourceMappingURL=connect-retry.d.mts.map
@@ -0,0 +1,42 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ // src/utils/connect-retry.ts
5
+ const MAX_DELAY_MS = 1e4;
6
+ /** Errors that no retry fixes: a refused credential, a missing endpoint, mismatched versions. */
7
+ const PERMANENT = /\b(?:401|403|404|428|unauthorized|forbidden|version mismatch|invalid (?:token|credentials)|not found)\b/iu;
8
+ /** Errors of the connection itself: refused, dropped, timed out, or a service with no free session. */
9
+ const CONNECTION = /(?:ECONNREFUSED|ECONNRESET|EPIPE|ETIMEDOUT|ENOTFOUND|EAI_AGAIN|EHOSTUNREACH|socket hang up|websocket error|connection (?:closed|refused|reset)|timeout|timed out|capacity|too many|queue(?:d)? full|no (?:free )?(?:session|browser)|\b(?:408|425|429|500|502|503|504)\b)/iu;
10
+ /** Whether a connect error is worth retrying: connection-level, not a configuration mistake. */
11
+ function isRetryableConnectError(error) {
12
+ const text = error instanceof Error ? error.message : String(error);
13
+ return !PERMANENT.test(text) && CONNECTION.test(text);
14
+ }
15
+ /**
16
+ * Run `connect`, retrying a connection-level failure with exponential backoff, so a provider
17
+ * outage or a full plan is absorbed here and crash isolation only ever sees a browser that died
18
+ * while rendering. The last error is thrown once the retries are spent.
19
+ */
20
+ async function retryConnect(connect, options) {
21
+ const sleep = options.sleep ?? sleepFor;
22
+ for (let retry = 0;; retry += 1) try {
23
+ return await connect();
24
+ } catch (error) {
25
+ if (retry >= options.retries || !(options.retryable ?? isRetryableConnectError)(error)) throw error;
26
+ const delayMs = Math.min(MAX_DELAY_MS, options.backoffMs * 2 ** retry) * jitter();
27
+ options.onRetry?.(error, retry + 1, Math.round(delayMs));
28
+ await sleep(delayMs);
29
+ }
30
+ }
31
+ /** 0.75 to 1.25: providers refusing for capacity should not see every shard retry in step. */
32
+ function jitter() {
33
+ return .75 + Math.random() * .5;
34
+ }
35
+ async function sleepFor(ms) {
36
+ await new Promise((resolve) => {
37
+ setTimeout(resolve, ms);
38
+ });
39
+ }
40
+ export { isRetryableConnectError, retryConnect };
41
+
42
+ //# sourceMappingURL=connect-retry.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connect-retry.mjs","names":[],"sources":["../../src/utils/connect-retry.ts"],"sourcesContent":["/** Retrying a connection to a remote browser service (ADR 0007, decision 4). */\n\n/** Options of {@link retryConnect}. */\nexport interface RetryConnectOptions {\n /** Retries after the first attempt. */\n retries: number;\n /** Delay before the first retry in ms; doubles each time, with jitter, capped at 10 s. */\n backoffMs: number;\n /** Whether an error is worth another attempt; defaults to {@link isRetryableConnectError}. */\n retryable?: (error: unknown) => boolean;\n /** Called before each retry with the error, the retry's number (from 1) and its delay. */\n onRetry?: (error: unknown, retry: number, delayMs: number) => void;\n /** Injectable for tests. */\n sleep?: (ms: number) => Promise<void>;\n}\n\nconst MAX_DELAY_MS = 10_000;\n\n/** Errors that no retry fixes: a refused credential, a missing endpoint, mismatched versions. */\nconst PERMANENT =\n /\\b(?:401|403|404|428|unauthorized|forbidden|version mismatch|invalid (?:token|credentials)|not found)\\b/iu;\n\n/** Errors of the connection itself: refused, dropped, timed out, or a service with no free session. */\nconst CONNECTION =\n /(?:ECONNREFUSED|ECONNRESET|EPIPE|ETIMEDOUT|ENOTFOUND|EAI_AGAIN|EHOSTUNREACH|socket hang up|websocket error|connection (?:closed|refused|reset)|timeout|timed out|capacity|too many|queue(?:d)? full|no (?:free )?(?:session|browser)|\\b(?:408|425|429|500|502|503|504)\\b)/iu;\n\n/** Whether a connect error is worth retrying: connection-level, not a configuration mistake. */\nexport function isRetryableConnectError(error: unknown): boolean {\n const text = error instanceof Error ? error.message : String(error);\n return !PERMANENT.test(text) && CONNECTION.test(text);\n}\n\n/**\n * Run `connect`, retrying a connection-level failure with exponential backoff, so a provider\n * outage or a full plan is absorbed here and crash isolation only ever sees a browser that died\n * while rendering. The last error is thrown once the retries are spent.\n */\nexport async function retryConnect<T>(\n connect: () => Promise<T>,\n options: RetryConnectOptions,\n): Promise<T> {\n const sleep = options.sleep ?? sleepFor;\n for (let retry = 0; ; retry += 1) {\n try {\n // oxlint-disable-next-line eslint/no-await-in-loop -- attempts are sequential by design\n return await connect();\n } catch (error) {\n if (retry >= options.retries || !(options.retryable ?? isRetryableConnectError)(error)) {\n throw error;\n }\n const delayMs = Math.min(MAX_DELAY_MS, options.backoffMs * 2 ** retry) * jitter();\n options.onRetry?.(error, retry + 1, Math.round(delayMs));\n // oxlint-disable-next-line eslint/no-await-in-loop -- backoff between sequential attempts\n await sleep(delayMs);\n }\n }\n}\n\n/** 0.75 to 1.25: providers refusing for capacity should not see every shard retry in step. */\nfunction jitter(): number {\n return 0.75 + Math.random() * 0.5;\n}\n\nasync function sleepFor(ms: number): Promise<void> {\n await new Promise<void>((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n"],"mappings":";;;;AAgBA,MAAM,eAAe;;AAGrB,MAAM,YACJ;;AAGF,MAAM,aACJ;;AAGF,SAAgB,wBAAwB,OAAyB;CAC/D,MAAM,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;CAClE,OAAO,CAAC,UAAU,KAAK,IAAI,KAAK,WAAW,KAAK,IAAI;AACtD;;;;;;AAOA,eAAsB,aACpB,SACA,SACY;CACZ,MAAM,QAAQ,QAAQ,SAAS;CAC/B,KAAK,IAAI,QAAQ,IAAK,SAAS,GAC7B,IAAI;EAEF,OAAO,MAAM,QAAQ;CACvB,SAAS,OAAO;EACd,IAAI,SAAS,QAAQ,WAAW,EAAE,QAAQ,aAAa,wBAAA,CAAyB,KAAK,GACnF,MAAM;EAER,MAAM,UAAU,KAAK,IAAI,cAAc,QAAQ,YAAY,KAAK,KAAK,IAAI,OAAO;EAChF,QAAQ,UAAU,OAAO,QAAQ,GAAG,KAAK,MAAM,OAAO,CAAC;EAEvD,MAAM,MAAM,OAAO;CACrB;AAEJ;;AAGA,SAAS,SAAiB;CACxB,OAAO,MAAO,KAAK,OAAO,IAAI;AAChC;AAEA,eAAe,SAAS,IAA2B;CACjD,MAAM,IAAI,SAAe,YAAY;EACnC,WAAW,SAAS,EAAE;CACxB,CAAC;AACH"}
@@ -1,6 +1,5 @@
1
1
  import __tsdown_shims_path from 'node:path';
2
2
  import __tsdown_shims_url from 'node:url';
3
- //#region src/utils/encrypt.d.ts
4
3
  /** Current server secret plus the one it replaced, kept only to decrypt older rows. */
5
4
  interface SecretKeys {
6
5
  current: string;
@@ -43,6 +42,5 @@ declare function decryptWithKey(input: SecretInput, ciphertext: string): {
43
42
  * rotation hint. A missing secret keeps its own configuration error.
44
43
  */
45
44
  declare function decryptCredential(input: SecretInput, ciphertext: string): string;
46
- //#endregion
47
45
  export { KeyUsed, SecretInput, SecretKeys, UndecryptableCredentialError, decrypt, decryptCredential, decryptWithKey, encrypt };
48
46
  //# sourceMappingURL=encrypt.d.mts.map
@@ -2,7 +2,7 @@ import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
4
  import { createCipheriv, createDecipheriv, createHash, randomBytes } from "node:crypto";
5
- //#region src/utils/encrypt.ts
5
+ // src/utils/encrypt.ts
6
6
  /** Thrown when a stored credential cannot be decrypted with any configured key. */
7
7
  var UndecryptableCredentialError = class extends Error {
8
8
  constructor(cause) {
@@ -97,7 +97,6 @@ function decryptWith(secret, ciphertext) {
97
97
  function deriveKey(secret) {
98
98
  return createHash("sha256").update(secret).digest();
99
99
  }
100
- //#endregion
101
100
  export { UndecryptableCredentialError, decrypt, decryptCredential, decryptWithKey, encrypt };
102
101
 
103
102
  //# sourceMappingURL=encrypt.mjs.map
@@ -0,0 +1,17 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { CaptureEnvironment } from "../adapter/capture-runner.mjs";
4
+ /**
5
+ * Digest of the installed system font families (`fc-list`), or undefined where fontconfig is not
6
+ * available. Cached for the process (fonts do not change under a running server), except a failed
7
+ * run such as a timeout under load: that is retried next time rather than reported as "no fonts"
8
+ * for the life of the process.
9
+ */
10
+ declare function systemFontsHash(): Promise<string | undefined>;
11
+ /**
12
+ * The environment a runner captured in: browser build, host platform, device scale factor and a
13
+ * font digest. Runners call this once per render with the version their driver reports.
14
+ */
15
+ declare function detectCaptureEnvironment(browserVersion?: string, deviceScaleFactor?: number): Promise<CaptureEnvironment>;
16
+ export { detectCaptureEnvironment, systemFontsHash };
17
+ //# sourceMappingURL=environment.d.mts.map