@storyshelf/core 0.6.2 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (727) hide show
  1. package/README.md +49 -32
  2. package/dist/adapter/capture-queue.d.mts +44 -4
  3. package/dist/adapter/capture-runner.d.mts +134 -12
  4. package/dist/adapter/capture-runner.mjs +9 -12
  5. package/dist/adapter/database.d.mts +89 -10
  6. package/dist/adapter/database.mjs +4 -3
  7. package/dist/adapter/database.mjs.map +1 -1
  8. package/dist/adapter/design.d.mts +83 -0
  9. package/dist/adapter/design.mjs +27 -0
  10. package/dist/adapter/design.mjs.map +1 -0
  11. package/dist/adapter/email-sender.d.mts +0 -2
  12. package/dist/adapter/metadata.d.mts +3 -12
  13. package/dist/adapter/notifier.d.mts +6 -3
  14. package/dist/adapter/notifier.mjs +5 -1
  15. package/dist/adapter/oauth.d.mts +50 -0
  16. package/dist/adapter/setup.d.mts +4 -7
  17. package/dist/adapter/setup.mjs +3 -3
  18. package/dist/adapter/setup.mjs.map +1 -1
  19. package/dist/adapter/storage.d.mts +1 -3
  20. package/dist/adapter/webhook-events.d.mts +0 -2
  21. package/dist/adapter/webhook-events.mjs +13 -14
  22. package/dist/adapter/webhook-events.mjs.map +1 -1
  23. package/dist/adapters/capture-target-offers.d.mts +26 -0
  24. package/dist/adapters/capture-target-offers.mjs +57 -0
  25. package/dist/adapters/capture-target-offers.mjs.map +1 -0
  26. package/dist/adapters/capture-target.d.mts +69 -0
  27. package/dist/adapters/capture-target.mjs +75 -0
  28. package/dist/adapters/capture-target.mjs.map +1 -0
  29. package/dist/adapters/notifier/build-comment.d.mts +22 -0
  30. package/dist/adapters/notifier/build-comment.mjs +23 -0
  31. package/dist/adapters/notifier/build-comment.mjs.map +1 -0
  32. package/dist/adapters/notifier/build-state.d.mts +97 -0
  33. package/dist/adapters/notifier/build-state.mjs +217 -0
  34. package/dist/adapters/notifier/build-state.mjs.map +1 -0
  35. package/dist/adapters/notifier/events.d.mts +4 -4
  36. package/dist/adapters/notifier/events.mjs +32 -20
  37. package/dist/adapters/notifier/events.mjs.map +1 -1
  38. package/dist/adapters/notifier/format.d.mts +0 -2
  39. package/dist/adapters/notifier/format.mjs +1 -2
  40. package/dist/adapters/notifier/provider.d.mts +53 -9
  41. package/dist/adapters/notifier/provider.mjs +11 -0
  42. package/dist/adapters/notifier/provider.mjs.map +1 -0
  43. package/dist/adapters/notifier/state.d.mts +22 -0
  44. package/dist/adapters/notifier/state.mjs +65 -0
  45. package/dist/adapters/notifier/state.mjs.map +1 -0
  46. package/dist/adapters/notifier/types.d.mts +51 -4
  47. package/dist/adapters/remote-browser.d.mts +168 -0
  48. package/dist/adapters/remote-browser.mjs +201 -0
  49. package/dist/adapters/remote-browser.mjs.map +1 -0
  50. package/dist/adapters/remote-lease-attempt.mjs +39 -0
  51. package/dist/adapters/remote-lease-attempt.mjs.map +1 -0
  52. package/dist/adapters/remote-lease-error.d.mts +25 -0
  53. package/dist/adapters/remote-lease-error.mjs +54 -0
  54. package/dist/adapters/remote-lease-error.mjs.map +1 -0
  55. package/dist/adapters/remote-lease-held.d.mts +15 -0
  56. package/dist/adapters/remote-lease-held.mjs +86 -0
  57. package/dist/adapters/remote-lease-held.mjs.map +1 -0
  58. package/dist/adapters/remote-lease-shutdown.d.mts +12 -0
  59. package/dist/adapters/remote-lease-shutdown.mjs +32 -0
  60. package/dist/adapters/remote-lease-shutdown.mjs.map +1 -0
  61. package/dist/adapters/remote-lease.d.mts +39 -0
  62. package/dist/adapters/remote-lease.mjs +175 -0
  63. package/dist/adapters/remote-lease.mjs.map +1 -0
  64. package/dist/adapters/remote-limiter.mjs +121 -0
  65. package/dist/adapters/remote-limiter.mjs.map +1 -0
  66. package/dist/adapters/remote-pool.d.mts +56 -0
  67. package/dist/adapters/remote-pool.mjs +195 -0
  68. package/dist/adapters/remote-pool.mjs.map +1 -0
  69. package/dist/adapters/render-runs.d.mts +23 -0
  70. package/dist/adapters/render-runs.mjs +40 -0
  71. package/dist/adapters/render-runs.mjs.map +1 -0
  72. package/dist/adapters/setup-runner.d.mts +0 -2
  73. package/dist/adapters/setup-runner.mjs +3 -6
  74. package/dist/adapters/setup-runner.mjs.map +1 -1
  75. package/dist/adapters/sources.d.mts +10 -0
  76. package/dist/adapters/sources.mjs +19 -0
  77. package/dist/adapters/sources.mjs.map +1 -0
  78. package/dist/adapters/validate.d.mts +0 -2
  79. package/dist/adapters/validate.mjs +27 -20
  80. package/dist/adapters/validate.mjs.map +1 -1
  81. package/dist/ai.d.mts +103 -0
  82. package/dist/ai.mjs +18 -0
  83. package/dist/ai.mjs.map +1 -0
  84. package/dist/auth.d.mts +0 -2
  85. package/dist/auth.mjs +1 -2
  86. package/dist/brand-packs.d.mts +0 -2
  87. package/dist/brand-packs.mjs +0 -1
  88. package/dist/capture/a11y/axe-source.d.mts +16 -0
  89. package/dist/capture/a11y/axe-source.mjs +36 -0
  90. package/dist/capture/a11y/axe-source.mjs.map +1 -0
  91. package/dist/capture/a11y/in-page.d.mts +25 -0
  92. package/dist/capture/a11y/in-page.mjs +59 -0
  93. package/dist/capture/a11y/in-page.mjs.map +1 -0
  94. package/dist/capture/a11y/map.d.mts +22 -0
  95. package/dist/capture/a11y/map.mjs +47 -0
  96. package/dist/capture/a11y/map.mjs.map +1 -0
  97. package/dist/capture/a11y/options.d.mts +21 -0
  98. package/dist/capture/a11y/options.mjs +74 -0
  99. package/dist/capture/a11y/options.mjs.map +1 -0
  100. package/dist/capture/adapter.d.mts +46 -5
  101. package/dist/capture/adapter.mjs +1 -2
  102. package/dist/capture/adapter.mjs.map +1 -1
  103. package/dist/capture/affected.d.mts +2 -2
  104. package/dist/capture/affected.mjs +14 -6
  105. package/dist/capture/affected.mjs.map +1 -1
  106. package/dist/capture/attempt-logger.mjs +83 -0
  107. package/dist/capture/attempt-logger.mjs.map +1 -0
  108. package/dist/capture/browsers.d.mts +33 -0
  109. package/dist/capture/browsers.mjs +66 -0
  110. package/dist/capture/browsers.mjs.map +1 -0
  111. package/dist/capture/build-state/deliver.d.mts +30 -0
  112. package/dist/capture/build-state/deliver.mjs +117 -0
  113. package/dist/capture/build-state/deliver.mjs.map +1 -0
  114. package/dist/capture/build-state/index.d.mts +8 -0
  115. package/dist/capture/build-state/notify-job.d.mts +54 -0
  116. package/dist/capture/build-state/notify-job.mjs +132 -0
  117. package/dist/capture/build-state/notify-job.mjs.map +1 -0
  118. package/dist/capture/build-state/publisher.d.mts +21 -0
  119. package/dist/capture/build-state/publisher.mjs +106 -0
  120. package/dist/capture/build-state/publisher.mjs.map +1 -0
  121. package/dist/capture/build-state/resume.d.mts +7 -0
  122. package/dist/capture/build-state/resume.mjs +46 -0
  123. package/dist/capture/build-state/resume.mjs.map +1 -0
  124. package/dist/capture/build-state/types.d.mts +47 -0
  125. package/dist/capture/catalog/catalogue.d.mts +20 -0
  126. package/dist/capture/catalog/catalogue.mjs +52 -0
  127. package/dist/capture/catalog/catalogue.mjs.map +1 -0
  128. package/dist/capture/catalog/components.d.mts +21 -0
  129. package/dist/capture/catalog/components.mjs +54 -0
  130. package/dist/capture/catalog/components.mjs.map +1 -0
  131. package/dist/capture/catalog/history.d.mts +28 -0
  132. package/dist/capture/catalog/history.mjs +50 -0
  133. package/dist/capture/catalog/history.mjs.map +1 -0
  134. package/dist/capture/catalog/hook.d.mts +12 -0
  135. package/dist/capture/catalog/hook.mjs +18 -0
  136. package/dist/capture/catalog/hook.mjs.map +1 -0
  137. package/dist/capture/catalog/index.d.mts +11 -0
  138. package/dist/capture/catalog/load.d.mts +24 -0
  139. package/dist/capture/catalog/load.mjs +48 -0
  140. package/dist/capture/catalog/load.mjs.map +1 -0
  141. package/dist/capture/catalog/parse.d.mts +13 -0
  142. package/dist/capture/catalog/parse.mjs +55 -0
  143. package/dist/capture/catalog/parse.mjs.map +1 -0
  144. package/dist/capture/catalog/read.d.mts +15 -0
  145. package/dist/capture/catalog/read.mjs +39 -0
  146. package/dist/capture/catalog/read.mjs.map +1 -0
  147. package/dist/capture/catalog/types.d.mts +31 -0
  148. package/dist/capture/comparison-reference.d.mts +27 -0
  149. package/dist/capture/comparison-reference.mjs +75 -0
  150. package/dist/capture/comparison-reference.mjs.map +1 -0
  151. package/dist/capture/consumer/capture-handler.d.mts +56 -0
  152. package/dist/capture/consumer/capture-handler.mjs +117 -0
  153. package/dist/capture/consumer/capture-handler.mjs.map +1 -0
  154. package/dist/capture/consumer/idle.d.mts +15 -0
  155. package/dist/capture/consumer/idle.mjs +24 -0
  156. package/dist/capture/consumer/idle.mjs.map +1 -0
  157. package/dist/capture/consumer/index.d.mts +11 -0
  158. package/dist/capture/consumer/index.mjs +138 -0
  159. package/dist/capture/consumer/index.mjs.map +1 -0
  160. package/dist/capture/consumer/loop.mjs +109 -0
  161. package/dist/capture/consumer/loop.mjs.map +1 -0
  162. package/dist/capture/consumer/metrics.d.mts +39 -0
  163. package/dist/capture/consumer/metrics.mjs +37 -0
  164. package/dist/capture/consumer/metrics.mjs.map +1 -0
  165. package/dist/capture/consumer/retry.d.mts +31 -0
  166. package/dist/capture/consumer/retry.mjs +33 -0
  167. package/dist/capture/consumer/retry.mjs.map +1 -0
  168. package/dist/capture/consumer/run-job.mjs +194 -0
  169. package/dist/capture/consumer/run-job.mjs.map +1 -0
  170. package/dist/capture/consumer/startup.mjs +37 -0
  171. package/dist/capture/consumer/startup.mjs.map +1 -0
  172. package/dist/capture/consumer/types.d.mts +95 -0
  173. package/dist/capture/crash-failure.d.mts +23 -0
  174. package/dist/capture/crash-failure.mjs +69 -0
  175. package/dist/capture/crash-failure.mjs.map +1 -0
  176. package/dist/capture/db-queue/cadence.d.mts +30 -0
  177. package/dist/capture/db-queue/cadence.mjs +37 -0
  178. package/dist/capture/db-queue/cadence.mjs.map +1 -0
  179. package/dist/capture/db-queue/claim.d.mts +7 -0
  180. package/dist/capture/db-queue/claim.mjs +148 -0
  181. package/dist/capture/db-queue/claim.mjs.map +1 -0
  182. package/dist/capture/db-queue/clock.mjs +11 -0
  183. package/dist/capture/db-queue/clock.mjs.map +1 -0
  184. package/dist/capture/db-queue/codec.mjs +75 -0
  185. package/dist/capture/db-queue/codec.mjs.map +1 -0
  186. package/dist/capture/db-queue/index.d.mts +18 -0
  187. package/dist/capture/db-queue/index.mjs +89 -0
  188. package/dist/capture/db-queue/index.mjs.map +1 -0
  189. package/dist/capture/db-queue/keeper.d.mts +34 -0
  190. package/dist/capture/db-queue/keeper.mjs +91 -0
  191. package/dist/capture/db-queue/keeper.mjs.map +1 -0
  192. package/dist/capture/db-queue/lease.mjs +45 -0
  193. package/dist/capture/db-queue/lease.mjs.map +1 -0
  194. package/dist/capture/db-queue/lifecycle.mjs +35 -0
  195. package/dist/capture/db-queue/lifecycle.mjs.map +1 -0
  196. package/dist/capture/db-queue/operations.mjs +93 -0
  197. package/dist/capture/db-queue/operations.mjs.map +1 -0
  198. package/dist/capture/db-queue/poll-loop.d.mts +28 -0
  199. package/dist/capture/db-queue/poll-loop.mjs +88 -0
  200. package/dist/capture/db-queue/poll-loop.mjs.map +1 -0
  201. package/dist/capture/db-queue/poll.d.mts +8 -0
  202. package/dist/capture/db-queue/poll.mjs +68 -0
  203. package/dist/capture/db-queue/poll.mjs.map +1 -0
  204. package/dist/capture/db-queue/timers.d.mts +10 -0
  205. package/dist/capture/db-queue/timers.mjs +36 -0
  206. package/dist/capture/db-queue/timers.mjs.map +1 -0
  207. package/dist/capture/db-queue/types.d.mts +81 -0
  208. package/dist/capture/db-queue/types.mjs +11 -0
  209. package/dist/capture/db-queue/types.mjs.map +1 -0
  210. package/dist/capture/db-queue/wake.mjs +47 -0
  211. package/dist/capture/db-queue/wake.mjs.map +1 -0
  212. package/dist/capture/design.mjs +38 -0
  213. package/dist/capture/design.mjs.map +1 -0
  214. package/dist/capture/diff-record.mjs +24 -5
  215. package/dist/capture/diff-record.mjs.map +1 -1
  216. package/dist/capture/dispatch.d.mts +13 -10
  217. package/dist/capture/dispatch.mjs +102 -111
  218. package/dist/capture/dispatch.mjs.map +1 -1
  219. package/dist/capture/enrich.mjs +59 -0
  220. package/dist/capture/enrich.mjs.map +1 -0
  221. package/dist/capture/failure-sets.mjs +21 -0
  222. package/dist/capture/failure-sets.mjs.map +1 -0
  223. package/dist/capture/fingerprint.d.mts +40 -0
  224. package/dist/capture/fingerprint.mjs +82 -0
  225. package/dist/capture/fingerprint.mjs.map +1 -0
  226. package/dist/capture/forked/channel.d.mts +23 -0
  227. package/dist/capture/forked/child.d.mts +32 -0
  228. package/dist/capture/forked/child.mjs +201 -0
  229. package/dist/capture/forked/child.mjs.map +1 -0
  230. package/dist/capture/forked/crash-tracker.mjs +22 -0
  231. package/dist/capture/forked/crash-tracker.mjs.map +1 -0
  232. package/dist/capture/forked/decision.d.mts +24 -0
  233. package/dist/capture/forked/decision.mjs +26 -0
  234. package/dist/capture/forked/decision.mjs.map +1 -0
  235. package/dist/capture/forked/exit.mjs +11 -0
  236. package/dist/capture/forked/exit.mjs.map +1 -0
  237. package/dist/capture/forked/fork.d.mts +29 -0
  238. package/dist/capture/forked/fork.mjs +92 -0
  239. package/dist/capture/forked/fork.mjs.map +1 -0
  240. package/dist/capture/forked/forked-capture.d.mts +38 -0
  241. package/dist/capture/forked/forked-capture.mjs +239 -0
  242. package/dist/capture/forked/forked-capture.mjs.map +1 -0
  243. package/dist/capture/forked/lease-book.mjs +45 -0
  244. package/dist/capture/forked/lease-book.mjs.map +1 -0
  245. package/dist/capture/forked/protocol.d.mts +36 -0
  246. package/dist/capture/forked/protocol.mjs +24 -0
  247. package/dist/capture/forked/protocol.mjs.map +1 -0
  248. package/dist/capture/forked/runs.mjs +74 -0
  249. package/dist/capture/forked/runs.mjs.map +1 -0
  250. package/dist/capture/guards.mjs +1 -2
  251. package/dist/capture/ignore-regions.d.mts +36 -0
  252. package/dist/capture/ignore-regions.mjs +65 -0
  253. package/dist/capture/ignore-regions.mjs.map +1 -0
  254. package/dist/capture/isolate.mjs +140 -0
  255. package/dist/capture/isolate.mjs.map +1 -0
  256. package/dist/capture/job-lease.d.mts +26 -0
  257. package/dist/capture/job-lease.mjs +56 -0
  258. package/dist/capture/job-lease.mjs.map +1 -0
  259. package/dist/capture/matrix.mjs +298 -0
  260. package/dist/capture/matrix.mjs.map +1 -0
  261. package/dist/capture/modes.d.mts +23 -0
  262. package/dist/capture/modes.mjs +106 -0
  263. package/dist/capture/modes.mjs.map +1 -0
  264. package/dist/capture/orchestrator.d.mts +37 -7
  265. package/dist/capture/orchestrator.mjs +120 -110
  266. package/dist/capture/orchestrator.mjs.map +1 -1
  267. package/dist/capture/pipeline.d.mts +9 -4
  268. package/dist/capture/pipeline.mjs +284 -48
  269. package/dist/capture/pipeline.mjs.map +1 -1
  270. package/dist/capture/progress.d.mts +9 -0
  271. package/dist/capture/progress.mjs +27 -0
  272. package/dist/capture/progress.mjs.map +1 -0
  273. package/dist/capture/publish/accept.d.mts +37 -0
  274. package/dist/capture/publish/accept.mjs +27 -0
  275. package/dist/capture/publish/accept.mjs.map +1 -0
  276. package/dist/capture/publish/complete.d.mts +44 -0
  277. package/dist/capture/publish/complete.mjs +63 -0
  278. package/dist/capture/publish/complete.mjs.map +1 -0
  279. package/dist/capture/publish/extract.d.mts +18 -0
  280. package/dist/capture/publish/extract.mjs +120 -0
  281. package/dist/capture/publish/extract.mjs.map +1 -0
  282. package/dist/capture/publish/handler.d.mts +26 -0
  283. package/dist/capture/publish/handler.mjs +61 -0
  284. package/dist/capture/publish/handler.mjs.map +1 -0
  285. package/dist/capture/publish/index.d.mts +11 -0
  286. package/dist/capture/publish/invalid-zip.d.mts +8 -0
  287. package/dist/capture/publish/invalid-zip.mjs +11 -0
  288. package/dist/capture/publish/invalid-zip.mjs.map +1 -0
  289. package/dist/capture/publish/limits.d.mts +35 -0
  290. package/dist/capture/publish/limits.mjs +38 -0
  291. package/dist/capture/publish/limits.mjs.map +1 -0
  292. package/dist/capture/publish/published.d.mts +13 -0
  293. package/dist/capture/publish/published.mjs +17 -0
  294. package/dist/capture/publish/published.mjs.map +1 -0
  295. package/dist/capture/publish/run.d.mts +31 -0
  296. package/dist/capture/publish/run.mjs +29 -0
  297. package/dist/capture/publish/run.mjs.map +1 -0
  298. package/dist/capture/rediff.d.mts +1 -3
  299. package/dist/capture/rediff.mjs +23 -9
  300. package/dist/capture/rediff.mjs.map +1 -1
  301. package/dist/capture/render.mjs +52 -0
  302. package/dist/capture/render.mjs.map +1 -0
  303. package/dist/capture/scratch.d.mts +42 -0
  304. package/dist/capture/scratch.mjs +136 -0
  305. package/dist/capture/scratch.mjs.map +1 -0
  306. package/dist/capture/shard-plan.mjs +127 -0
  307. package/dist/capture/shard-plan.mjs.map +1 -0
  308. package/dist/capture/shards/context.mjs +51 -0
  309. package/dist/capture/shards/context.mjs.map +1 -0
  310. package/dist/capture/shards/execute.mjs +175 -0
  311. package/dist/capture/shards/execute.mjs.map +1 -0
  312. package/dist/capture/shards/fan-out.mjs +125 -0
  313. package/dist/capture/shards/fan-out.mjs.map +1 -0
  314. package/dist/capture/shards/history.mjs +34 -0
  315. package/dist/capture/shards/history.mjs.map +1 -0
  316. package/dist/capture/shards/reduce.mjs +96 -0
  317. package/dist/capture/shards/reduce.mjs.map +1 -0
  318. package/dist/capture/sizing.d.mts +0 -2
  319. package/dist/capture/sizing.mjs +2 -13
  320. package/dist/capture/sizing.mjs.map +1 -1
  321. package/dist/capture/skip-checks.mjs +3 -67
  322. package/dist/capture/skip-checks.mjs.map +1 -1
  323. package/dist/capture/statics.d.mts +7 -10
  324. package/dist/capture/statics.mjs +26 -74
  325. package/dist/capture/statics.mjs.map +1 -1
  326. package/dist/capture/storybook-urls.d.mts +38 -0
  327. package/dist/capture/storybook-urls.mjs +41 -0
  328. package/dist/capture/storybook-urls.mjs.map +1 -0
  329. package/dist/capture/storybook.d.mts +12 -6
  330. package/dist/capture/storybook.mjs +63 -19
  331. package/dist/capture/storybook.mjs.map +1 -1
  332. package/dist/capture/target.mjs +20 -0
  333. package/dist/capture/target.mjs.map +1 -0
  334. package/dist/capture/targets.d.mts +23 -0
  335. package/dist/capture/targets.mjs +31 -0
  336. package/dist/capture/targets.mjs.map +1 -0
  337. package/dist/capture/tests.d.mts +35 -0
  338. package/dist/capture/tests.mjs +136 -0
  339. package/dist/capture/tests.mjs.map +1 -0
  340. package/dist/capture/token-chunks.mjs +91 -0
  341. package/dist/capture/token-chunks.mjs.map +1 -0
  342. package/dist/capture.d.mts +63 -7
  343. package/dist/capture.mjs +51 -3
  344. package/dist/config.d.mts +136 -14
  345. package/dist/config.mjs +14 -8
  346. package/dist/config.mjs.map +1 -1
  347. package/dist/diff.d.mts +7 -3
  348. package/dist/diff.mjs +15 -3
  349. package/dist/diff.mjs.map +1 -0
  350. package/dist/index.d.mts +3 -3
  351. package/dist/index.mjs +2 -2
  352. package/dist/insights/budget.d.mts +18 -0
  353. package/dist/insights/budget.mjs +32 -0
  354. package/dist/insights/budget.mjs.map +1 -0
  355. package/dist/insights/envelope.d.mts +57 -0
  356. package/dist/insights/envelope.mjs +59 -0
  357. package/dist/insights/envelope.mjs.map +1 -0
  358. package/dist/insights/evidence-health.d.mts +30 -0
  359. package/dist/insights/evidence-health.mjs +27 -0
  360. package/dist/insights/evidence-health.mjs.map +1 -0
  361. package/dist/insights/evidence.d.mts +53 -0
  362. package/dist/insights/evidence.mjs +63 -0
  363. package/dist/insights/evidence.mjs.map +1 -0
  364. package/dist/insights/hash.d.mts +16 -0
  365. package/dist/insights/hash.mjs +20 -0
  366. package/dist/insights/hash.mjs.map +1 -0
  367. package/dist/insights/limits.d.mts +22 -0
  368. package/dist/insights/limits.mjs +23 -0
  369. package/dist/insights/limits.mjs.map +1 -0
  370. package/dist/insights/prompts/v1.d.mts +11 -0
  371. package/dist/insights/prompts/v1.mjs +33 -0
  372. package/dist/insights/prompts/v1.mjs.map +1 -0
  373. package/dist/insights/redact.d.mts +7 -0
  374. package/dist/insights/redact.mjs +23 -0
  375. package/dist/insights/redact.mjs.map +1 -0
  376. package/dist/insights/text.mjs +43 -0
  377. package/dist/insights/text.mjs.map +1 -0
  378. package/dist/insights.d.mts +11 -0
  379. package/dist/insights.mjs +12 -0
  380. package/dist/logger.d.mts +0 -2
  381. package/dist/logger.mjs +18 -3
  382. package/dist/logger.mjs.map +1 -1
  383. package/dist/models/ai-budget-alert.d.mts +21 -0
  384. package/dist/models/ai-budget-alert.mjs +37 -0
  385. package/dist/models/ai-budget-alert.mjs.map +1 -0
  386. package/dist/models/ai-usage.d.mts +38 -0
  387. package/dist/models/ai-usage.mjs +60 -0
  388. package/dist/models/ai-usage.mjs.map +1 -0
  389. package/dist/models/baseline-approval.d.mts +18 -0
  390. package/dist/models/baseline-approval.mjs +41 -0
  391. package/dist/models/baseline-approval.mjs.map +1 -0
  392. package/dist/models/baseline-archive.d.mts +82 -0
  393. package/dist/models/baseline-archive.mjs +105 -0
  394. package/dist/models/baseline-archive.mjs.map +1 -0
  395. package/dist/models/baseline-atomic.mjs +66 -0
  396. package/dist/models/baseline-atomic.mjs.map +1 -0
  397. package/dist/models/baseline-conflict.d.mts +6 -0
  398. package/dist/models/baseline-conflict.mjs +9 -0
  399. package/dist/models/baseline-conflict.mjs.map +1 -0
  400. package/dist/models/baseline-export.d.mts +17 -0
  401. package/dist/models/baseline-export.mjs +135 -0
  402. package/dist/models/baseline-export.mjs.map +1 -0
  403. package/dist/models/baseline-import.mjs +117 -0
  404. package/dist/models/baseline-import.mjs.map +1 -0
  405. package/dist/models/baseline-origin.d.mts +16 -0
  406. package/dist/models/baseline-origin.mjs +35 -0
  407. package/dist/models/baseline-origin.mjs.map +1 -0
  408. package/dist/models/baseline-status.d.mts +0 -2
  409. package/dist/models/baseline-status.mjs +1 -2
  410. package/dist/models/baseline-transfer.d.mts +48 -0
  411. package/dist/models/baseline-transfer.mjs +149 -0
  412. package/dist/models/baseline-transfer.mjs.map +1 -0
  413. package/dist/models/baseline.d.mts +37 -7
  414. package/dist/models/baseline.mjs +152 -28
  415. package/dist/models/baseline.mjs.map +1 -1
  416. package/dist/models/build-component.d.mts +26 -0
  417. package/dist/models/build-component.mjs +54 -0
  418. package/dist/models/build-component.mjs.map +1 -0
  419. package/dist/models/build-review-status.d.mts +27 -0
  420. package/dist/models/build-review-status.mjs +36 -0
  421. package/dist/models/build-review-status.mjs.map +1 -0
  422. package/dist/models/build-review.d.mts +26 -0
  423. package/dist/models/build-review.mjs +53 -0
  424. package/dist/models/build-review.mjs.map +1 -0
  425. package/dist/models/build.d.mts +25 -5
  426. package/dist/models/build.mjs +53 -15
  427. package/dist/models/build.mjs.map +1 -1
  428. package/dist/models/capture-attempt.d.mts +7 -3
  429. package/dist/models/capture-attempt.mjs +30 -6
  430. package/dist/models/capture-attempt.mjs.map +1 -1
  431. package/dist/models/capture-job.d.mts +104 -0
  432. package/dist/models/capture-job.mjs +287 -0
  433. package/dist/models/capture-job.mjs.map +1 -0
  434. package/dist/models/capture-log.d.mts +1 -3
  435. package/dist/models/capture-log.mjs +5 -5
  436. package/dist/models/capture-log.mjs.map +1 -1
  437. package/dist/models/capture-shard.d.mts +60 -0
  438. package/dist/models/capture-shard.mjs +189 -0
  439. package/dist/models/capture-shard.mjs.map +1 -0
  440. package/dist/models/changeset.d.mts +46 -0
  441. package/dist/models/changeset.mjs +80 -0
  442. package/dist/models/changeset.mjs.map +1 -0
  443. package/dist/models/columns.mjs +18 -0
  444. package/dist/models/columns.mjs.map +1 -0
  445. package/dist/models/comment.d.mts +4 -3
  446. package/dist/models/comment.mjs +8 -6
  447. package/dist/models/comment.mjs.map +1 -1
  448. package/dist/models/component.d.mts +41 -0
  449. package/dist/models/component.mjs +59 -0
  450. package/dist/models/component.mjs.map +1 -0
  451. package/dist/models/connections.d.mts +39 -0
  452. package/dist/models/connections.mjs +111 -0
  453. package/dist/models/connections.mjs.map +1 -0
  454. package/dist/models/content-ref.d.mts +1 -3
  455. package/dist/models/content-ref.mjs +2 -3
  456. package/dist/models/content-ref.mjs.map +1 -1
  457. package/dist/models/credentials.d.mts +0 -2
  458. package/dist/models/credentials.mjs +13 -4
  459. package/dist/models/credentials.mjs.map +1 -1
  460. package/dist/models/design-credentials.d.mts +39 -0
  461. package/dist/models/design-credentials.mjs +85 -0
  462. package/dist/models/design-credentials.mjs.map +1 -0
  463. package/dist/models/design-health.d.mts +14 -0
  464. package/dist/models/design-health.mjs +24 -0
  465. package/dist/models/design-health.mjs.map +1 -0
  466. package/dist/models/design-nodes.d.mts +81 -0
  467. package/dist/models/design-nodes.mjs +221 -0
  468. package/dist/models/design-nodes.mjs.map +1 -0
  469. package/dist/models/design-renders.mjs +73 -0
  470. package/dist/models/design-renders.mjs.map +1 -0
  471. package/dist/models/design-resolve.d.mts +27 -0
  472. package/dist/models/design-resolve.mjs +40 -0
  473. package/dist/models/design-resolve.mjs.map +1 -0
  474. package/dist/models/design.d.mts +37 -0
  475. package/dist/models/design.mjs +89 -0
  476. package/dist/models/design.mjs.map +1 -0
  477. package/dist/models/inherited-ratio.d.mts +19 -0
  478. package/dist/models/inherited-ratio.mjs +21 -0
  479. package/dist/models/inherited-ratio.mjs.map +1 -0
  480. package/dist/models/insight.d.mts +68 -0
  481. package/dist/models/insight.mjs +161 -0
  482. package/dist/models/insight.mjs.map +1 -0
  483. package/dist/models/label.d.mts +4 -4
  484. package/dist/models/label.mjs +26 -12
  485. package/dist/models/label.mjs.map +1 -1
  486. package/dist/models/member.d.mts +1 -3
  487. package/dist/models/member.mjs +6 -6
  488. package/dist/models/member.mjs.map +1 -1
  489. package/dist/models/notification-channel.d.mts +37 -5
  490. package/dist/models/notification-channel.mjs +89 -11
  491. package/dist/models/notification-channel.mjs.map +1 -1
  492. package/dist/models/notification-subscription.d.mts +1 -4
  493. package/dist/models/notification-subscription.mjs +8 -11
  494. package/dist/models/notification-subscription.mjs.map +1 -1
  495. package/dist/models/project-group-mapping.d.mts +6 -3
  496. package/dist/models/project-group-mapping.mjs +15 -6
  497. package/dist/models/project-group-mapping.mjs.map +1 -1
  498. package/dist/models/project.d.mts +9 -3
  499. package/dist/models/project.mjs +10 -6
  500. package/dist/models/project.mjs.map +1 -1
  501. package/dist/models/public-origin.d.mts +61 -0
  502. package/dist/models/public-origin.mjs +113 -0
  503. package/dist/models/public-origin.mjs.map +1 -0
  504. package/dist/models/review-switch-off.d.mts +12 -0
  505. package/dist/models/review-switch-off.mjs +25 -0
  506. package/dist/models/review-switch-off.mjs.map +1 -0
  507. package/dist/models/site-settings.d.mts +21 -0
  508. package/dist/models/site-settings.mjs +47 -0
  509. package/dist/models/site-settings.mjs.map +1 -0
  510. package/dist/models/snapshot.d.mts +39 -3
  511. package/dist/models/snapshot.mjs +54 -5
  512. package/dist/models/snapshot.mjs.map +1 -1
  513. package/dist/models/token.d.mts +13 -3
  514. package/dist/models/token.mjs +24 -7
  515. package/dist/models/token.mjs.map +1 -1
  516. package/dist/models/usage.d.mts +74 -0
  517. package/dist/models/usage.mjs +148 -0
  518. package/dist/models/usage.mjs.map +1 -0
  519. package/dist/models/user.d.mts +1 -3
  520. package/dist/models/user.mjs +5 -5
  521. package/dist/models/user.mjs.map +1 -1
  522. package/dist/models/webhook.d.mts +15 -3
  523. package/dist/models/webhook.mjs +34 -6
  524. package/dist/models/webhook.mjs.map +1 -1
  525. package/dist/models.d.mts +30 -4
  526. package/dist/models.mjs +31 -6
  527. package/dist/options.d.mts +16 -0
  528. package/dist/options.mjs +88 -0
  529. package/dist/options.mjs.map +1 -0
  530. package/dist/paths.d.mts +21 -6
  531. package/dist/paths.mjs +57 -12
  532. package/dist/paths.mjs.map +1 -1
  533. package/dist/retention/ai.d.mts +16 -0
  534. package/dist/retention/ai.mjs +22 -0
  535. package/dist/retention/ai.mjs.map +1 -0
  536. package/dist/retention/pending.mjs +46 -0
  537. package/dist/retention/pending.mjs.map +1 -0
  538. package/dist/retention/published-gzip-sweep.mjs +28 -0
  539. package/dist/retention/published-gzip-sweep.mjs.map +1 -0
  540. package/dist/retention/screenshot-sweep.d.mts +49 -0
  541. package/dist/retention/screenshot-sweep.mjs +127 -0
  542. package/dist/retention/screenshot-sweep.mjs.map +1 -0
  543. package/dist/retention.d.mts +16 -4
  544. package/dist/retention.mjs +76 -16
  545. package/dist/retention.mjs.map +1 -1
  546. package/dist/schema/baseline.d.mts +8 -2
  547. package/dist/schema/build-component.d.mts +23 -0
  548. package/dist/schema/build-review.d.mts +15 -0
  549. package/dist/schema/build.d.mts +7 -2
  550. package/dist/schema/capture-attempt.d.mts +0 -2
  551. package/dist/schema/capture-job.d.mts +58 -0
  552. package/dist/schema/capture-shard.d.mts +33 -0
  553. package/dist/schema/comment.d.mts +2 -2
  554. package/dist/schema/connection.d.mts +22 -0
  555. package/dist/schema/content-ref.d.mts +0 -2
  556. package/dist/schema/design.d.mts +56 -0
  557. package/dist/schema/insight.d.mts +52 -0
  558. package/dist/schema/label.d.mts +0 -2
  559. package/dist/schema/member.d.mts +0 -2
  560. package/dist/schema/notification.d.mts +4 -2
  561. package/dist/schema/project-group-mapping.d.mts +0 -2
  562. package/dist/schema/project.d.mts +21 -2
  563. package/dist/schema/site-setting.d.mts +19 -0
  564. package/dist/schema/snapshot.d.mts +17 -2
  565. package/dist/schema/token.d.mts +0 -2
  566. package/dist/schema/usage.d.mts +28 -0
  567. package/dist/schema/user.d.mts +0 -2
  568. package/dist/schema/webhook.d.mts +0 -2
  569. package/dist/schema.d.mts +12 -6
  570. package/dist/serverless.d.mts +19 -0
  571. package/dist/serverless.mjs +36 -0
  572. package/dist/serverless.mjs.map +1 -0
  573. package/dist/test-helpers/build-reference-contract.d.mts +14 -0
  574. package/dist/test-helpers/build-reference-contract.mjs +66 -0
  575. package/dist/test-helpers/build-reference-contract.mjs.map +1 -0
  576. package/dist/test-helpers/create-project.d.mts +1 -3
  577. package/dist/test-helpers/create-project.mjs +1 -2
  578. package/dist/test-helpers/database-contract.d.mts +0 -2
  579. package/dist/test-helpers/database-contract.mjs +37 -2
  580. package/dist/test-helpers/database-contract.mjs.map +1 -1
  581. package/dist/test-helpers/deferred.d.mts +37 -0
  582. package/dist/test-helpers/deferred.mjs +60 -0
  583. package/dist/test-helpers/deferred.mjs.map +1 -0
  584. package/dist/test-helpers/design-contract.d.mts +19 -0
  585. package/dist/test-helpers/design-contract.mjs +39 -0
  586. package/dist/test-helpers/design-contract.mjs.map +1 -0
  587. package/dist/test-helpers/fake-adapters.d.mts +0 -2
  588. package/dist/test-helpers/fake-adapters.mjs +1 -2
  589. package/dist/test-helpers/fake-database.d.mts +0 -2
  590. package/dist/test-helpers/fake-database.mjs +21 -4
  591. package/dist/test-helpers/fake-database.mjs.map +1 -1
  592. package/dist/test-helpers/fake-design.d.mts +41 -0
  593. package/dist/test-helpers/fake-design.mjs +113 -0
  594. package/dist/test-helpers/fake-design.mjs.map +1 -0
  595. package/dist/test-helpers/fake-notifier.d.mts +19 -0
  596. package/dist/test-helpers/fake-notifier.mjs +43 -0
  597. package/dist/test-helpers/fake-notifier.mjs.map +1 -0
  598. package/dist/test-helpers/fake-storage.d.mts +0 -2
  599. package/dist/test-helpers/fake-storage.mjs +1 -2
  600. package/dist/test-helpers/fake-tables.mjs +260 -69
  601. package/dist/test-helpers/fake-tables.mjs.map +1 -1
  602. package/dist/test-helpers/manual-clock.d.mts +25 -0
  603. package/dist/test-helpers/manual-clock.mjs +55 -0
  604. package/dist/test-helpers/manual-clock.mjs.map +1 -0
  605. package/dist/test-helpers/notifier-contract.d.mts +7 -3
  606. package/dist/test-helpers/notifier-contract.mjs +33 -5
  607. package/dist/test-helpers/notifier-contract.mjs.map +1 -1
  608. package/dist/test-helpers/queue-contract.d.mts +16 -4
  609. package/dist/test-helpers/queue-contract.mjs +196 -3
  610. package/dist/test-helpers/queue-contract.mjs.map +1 -1
  611. package/dist/test-helpers/queue-multi-instance.d.mts +18 -0
  612. package/dist/test-helpers/queue-multi-instance.mjs +205 -0
  613. package/dist/test-helpers/queue-multi-instance.mjs.map +1 -0
  614. package/dist/test-helpers/runner-contract.d.mts +0 -2
  615. package/dist/test-helpers/runner-contract.mjs +12 -2
  616. package/dist/test-helpers/runner-contract.mjs.map +1 -1
  617. package/dist/test-helpers/sql-chunks.mjs +25 -2
  618. package/dist/test-helpers/sql-chunks.mjs.map +1 -1
  619. package/dist/test-helpers/storage-contract.d.mts +0 -2
  620. package/dist/test-helpers/storage-contract.mjs +2 -3
  621. package/dist/test-helpers.d.mts +10 -4
  622. package/dist/test-helpers.mjs +9 -3
  623. package/dist/tracing.mjs +36 -6
  624. package/dist/tracing.mjs.map +1 -1
  625. package/dist/types.d.mts +14 -5
  626. package/dist/types.mjs +22 -6
  627. package/dist/types.mjs.map +1 -1
  628. package/dist/urls.d.mts +4 -2
  629. package/dist/urls.mjs +12 -4
  630. package/dist/urls.mjs.map +1 -1
  631. package/dist/utils/adaptive-concurrency.d.mts +64 -0
  632. package/dist/utils/adaptive-concurrency.mjs +148 -0
  633. package/dist/utils/adaptive-concurrency.mjs.map +1 -0
  634. package/dist/utils/connect-retry.d.mts +26 -0
  635. package/dist/utils/connect-retry.mjs +42 -0
  636. package/dist/utils/connect-retry.mjs.map +1 -0
  637. package/dist/utils/encrypt.d.mts +0 -2
  638. package/dist/utils/encrypt.mjs +1 -2
  639. package/dist/utils/environment.d.mts +17 -0
  640. package/dist/utils/environment.mjs +58 -0
  641. package/dist/utils/environment.mjs.map +1 -0
  642. package/dist/utils/hash.d.mts +0 -2
  643. package/dist/utils/hash.mjs +1 -2
  644. package/dist/utils/http.d.mts +29 -3
  645. package/dist/utils/http.mjs +100 -19
  646. package/dist/utils/http.mjs.map +1 -1
  647. package/dist/utils/map-adaptive.d.mts +13 -0
  648. package/dist/utils/map-adaptive.mjs +71 -0
  649. package/dist/utils/map-adaptive.mjs.map +1 -0
  650. package/dist/utils/map-limit.d.mts +8 -0
  651. package/dist/utils/map-limit.mjs +31 -0
  652. package/dist/utils/map-limit.mjs.map +1 -0
  653. package/dist/utils/mime.d.mts +0 -2
  654. package/dist/utils/mime.mjs +1 -2
  655. package/dist/utils/page-limiter.d.mts +35 -0
  656. package/dist/utils/page-limiter.mjs +55 -0
  657. package/dist/utils/page-limiter.mjs.map +1 -0
  658. package/dist/utils/path-security.d.mts +0 -2
  659. package/dist/utils/path-security.mjs +2 -4
  660. package/dist/utils/path-security.mjs.map +1 -1
  661. package/dist/utils/public-origin.d.mts +18 -0
  662. package/dist/utils/public-origin.mjs +74 -0
  663. package/dist/utils/public-origin.mjs.map +1 -0
  664. package/dist/utils/redact.d.mts +0 -2
  665. package/dist/utils/redact.mjs +4 -2
  666. package/dist/utils/redact.mjs.map +1 -1
  667. package/dist/utils/remote-environment.d.mts +76 -0
  668. package/dist/utils/remote-environment.mjs +163 -0
  669. package/dist/utils/remote-environment.mjs.map +1 -0
  670. package/dist/utils/resources.d.mts +62 -0
  671. package/dist/utils/resources.mjs +121 -0
  672. package/dist/utils/resources.mjs.map +1 -0
  673. package/dist/utils/screenshot-store.d.mts +13 -0
  674. package/dist/utils/screenshot-store.mjs +40 -0
  675. package/dist/utils/screenshot-store.mjs.map +1 -0
  676. package/dist/utils/session-gate.d.mts +23 -0
  677. package/dist/utils/session-gate.mjs +69 -0
  678. package/dist/utils/session-gate.mjs.map +1 -0
  679. package/dist/utils/storybook-token.d.mts +89 -0
  680. package/dist/utils/storybook-token.mjs +135 -0
  681. package/dist/utils/storybook-token.mjs.map +1 -0
  682. package/dist/utils/storybook-url.d.mts +13 -0
  683. package/dist/utils/storybook-url.mjs +20 -0
  684. package/dist/utils/storybook-url.mjs.map +1 -0
  685. package/dist/utils/timing.d.mts +0 -2
  686. package/dist/utils/timing.mjs +2 -3
  687. package/dist/utils/timing.mjs.map +1 -1
  688. package/dist/utils/ulid.d.mts +0 -2
  689. package/dist/utils/ulid.mjs +1 -2
  690. package/dist/utils/zip-read.mjs +128 -0
  691. package/dist/utils/zip-read.mjs.map +1 -0
  692. package/dist/utils/zip-write.d.mts +16 -0
  693. package/dist/utils/zip-write.mjs +187 -0
  694. package/dist/utils/zip-write.mjs.map +1 -0
  695. package/dist/utils.d.mts +17 -3
  696. package/dist/utils.mjs +18 -4
  697. package/package.json +35 -26
  698. package/dist/adapter/capture-runner.mjs.map +0 -1
  699. package/dist/adapter/git-host/comments.d.mts +0 -41
  700. package/dist/adapter/git-host/comments.mjs +0 -54
  701. package/dist/adapter/git-host/comments.mjs.map +0 -1
  702. package/dist/adapter/git-host/helpers.d.mts +0 -13
  703. package/dist/adapter/git-host/helpers.mjs +0 -30
  704. package/dist/adapter/git-host/helpers.mjs.map +0 -1
  705. package/dist/adapter/git-host.d.mts +0 -42
  706. package/dist/capture/queue.d.mts +0 -38
  707. package/dist/capture/queue.mjs +0 -98
  708. package/dist/capture/queue.mjs.map +0 -1
  709. package/dist/capture/recovery.d.mts +0 -21
  710. package/dist/capture/recovery.mjs +0 -83
  711. package/dist/capture/recovery.mjs.map +0 -1
  712. package/dist/capture/status-fanout.mjs +0 -72
  713. package/dist/capture/status-fanout.mjs.map +0 -1
  714. package/dist/diff/engine.d.mts +0 -16
  715. package/dist/diff/engine.mjs +0 -87
  716. package/dist/diff/engine.mjs.map +0 -1
  717. package/dist/diff/options.d.mts +0 -42
  718. package/dist/diff/options.mjs +0 -15
  719. package/dist/diff/options.mjs.map +0 -1
  720. package/dist/models/status-config.d.mts +0 -38
  721. package/dist/models/status-config.mjs +0 -63
  722. package/dist/models/status-config.mjs.map +0 -1
  723. package/dist/schema/status-config.d.mts +0 -16
  724. package/dist/test-helpers/git-contract.d.mts +0 -11
  725. package/dist/test-helpers/git-contract.mjs +0 -34
  726. package/dist/test-helpers/git-contract.mjs.map +0 -1
  727. /package/dist/adapter/{git-host.mjs → oauth.mjs} +0 -0
@@ -0,0 +1,106 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { sanitizeErrorText } from "../../utils/redact.mjs";
5
+ import { NotificationChannelModel } from "../../models/notification-channel.mjs";
6
+ import { loadBuild, stateTargets, writeTo } from "./deliver.mjs";
7
+ // src/capture/build-state/publisher.ts
8
+ /**
9
+ * The one entry point for "this build changed, show it" (ADR 0014, decisions 5 and 7). Every build
10
+ * transition and the end of publishing call `request`; it hands each git channel of the project a
11
+ * durable `notify` job, or, on a host with no queue consumer, delivers inline. While no public
12
+ * origin is resolved it does neither (ADR 0014, decision 11): every link would be empty.
13
+ */
14
+ /** Logged once when the first request finds no public origin, and again after one came back and went. */
15
+ const PAUSED_MESSAGE = "notifications are paused until a public URL is set (PUBLIC_BASE_URL or a confirmed detected origin)";
16
+ /** A publisher over `options.deps`. */
17
+ function createBuildStatePublisher(options) {
18
+ const { deps } = options;
19
+ const pause = { logged: false };
20
+ return { request: async (buildId) => {
21
+ try {
22
+ const origin = await deps.publicOrigin();
23
+ if (!origin) {
24
+ logPaused(deps, pause, buildId);
25
+ return;
26
+ }
27
+ pause.logged = false;
28
+ await requestAll(options, {
29
+ buildId,
30
+ origin
31
+ });
32
+ } catch (error) {
33
+ deps.logger.warn({
34
+ err: error,
35
+ buildId
36
+ }, "failed to request the build state");
37
+ }
38
+ } };
39
+ }
40
+ /** Warn on the first request of a pause only. */
41
+ function logPaused(deps, pause, buildId) {
42
+ if (!pause.logged) deps.logger.warn({ buildId }, PAUSED_MESSAGE);
43
+ pause.logged = true;
44
+ }
45
+ /** Ask every state channel of the build's project to show it. */
46
+ async function requestAll(options, where) {
47
+ const { deps } = options;
48
+ const { buildId, origin } = where;
49
+ const loaded = await loadBuild(deps, buildId);
50
+ if (loaded === null) return;
51
+ const targets = await stateTargets(deps, loaded.project.id);
52
+ await Promise.allSettled(targets.map(async (target) => {
53
+ await requestOne(options, {
54
+ buildId,
55
+ loaded,
56
+ target,
57
+ origin
58
+ });
59
+ }));
60
+ }
61
+ /** Queue the delivery; inline when there is no queue, or when queueing itself failed. */
62
+ async function requestOne(options, request) {
63
+ const { enqueue, deps } = options;
64
+ const { buildId, loaded, target, origin } = request;
65
+ if (enqueue !== void 0) try {
66
+ await enqueue({
67
+ channelId: target.channel.id,
68
+ buildId
69
+ });
70
+ return;
71
+ } catch (error) {
72
+ deps.logger.warn({
73
+ err: error,
74
+ channelId: target.channel.id,
75
+ buildId
76
+ }, "failed to queue the state delivery; delivering inline");
77
+ }
78
+ await deliverInline(deps, loaded, {
79
+ target,
80
+ origin
81
+ });
82
+ }
83
+ /** Deliver now and record the outcome on the channel; never throws. */
84
+ async function deliverInline(deps, loaded, where) {
85
+ const { target } = where;
86
+ const channels = new NotificationChannelModel(deps.db, { notificationChannels: deps.db.tables.notificationChannels }, deps.secret);
87
+ let error;
88
+ try {
89
+ await writeTo(deps, loaded, where);
90
+ } catch (writeError) {
91
+ deps.logger.warn({
92
+ err: writeError,
93
+ channelId: target.channel.id
94
+ }, "state delivery failed");
95
+ error = sanitizeErrorText(writeError instanceof Error ? writeError.message : String(writeError), 500);
96
+ }
97
+ await channels.recordOutcome(target.channel.id, error).catch((recordError) => {
98
+ deps.logger.warn({
99
+ err: recordError,
100
+ channelId: target.channel.id
101
+ }, "failed to record outcome");
102
+ });
103
+ }
104
+ export { PAUSED_MESSAGE, createBuildStatePublisher };
105
+
106
+ //# sourceMappingURL=publisher.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publisher.mjs","names":[],"sources":["../../../src/capture/build-state/publisher.ts"],"sourcesContent":["/**\n * The one entry point for \"this build changed, show it\" (ADR 0014, decisions 5 and 7). Every build\n * transition and the end of publishing call `request`; it hands each git channel of the project a\n * durable `notify` job, or, on a host with no queue consumer, delivers inline. While no public\n * origin is resolved it does neither (ADR 0014, decision 11): every link would be empty.\n */\nimport { NotificationChannelModel } from \"../../models/notification-channel.ts\";\nimport { sanitizeErrorText } from \"../../utils/redact.ts\";\nimport { loadBuild, stateTargets, writeTo } from \"./deliver.ts\";\nimport type { BuildStateDeps, BuildStatePublisher, StateTarget } from \"./types.ts\";\n\n/** What {@link createBuildStatePublisher} needs. */\nexport interface BuildStatePublisherOptions {\n deps: BuildStateDeps;\n /**\n * Queues a `notify` job. Set when this instance (or another one) consumes the queue; absent, the\n * state is delivered inline in the caller's request, without durability.\n */\n enqueue?: ((job: { channelId: string; buildId: string }) => Promise<void>) | undefined;\n}\n\n/** Logged once when the first request finds no public origin, and again after one came back and went. */\nexport const PAUSED_MESSAGE =\n \"notifications are paused until a public URL is set (PUBLIC_BASE_URL or a confirmed detected origin)\";\n\n/** A publisher over `options.deps`. */\nexport function createBuildStatePublisher(\n options: BuildStatePublisherOptions,\n): BuildStatePublisher {\n const { deps } = options;\n const pause = { logged: false };\n return {\n request: async (buildId) => {\n try {\n const origin = await deps.publicOrigin();\n if (!origin) {\n logPaused(deps, pause, buildId);\n return;\n }\n pause.logged = false;\n await requestAll(options, { buildId, origin });\n } catch (error) {\n deps.logger.warn({ err: error, buildId }, \"failed to request the build state\");\n }\n },\n };\n}\n\n/** Warn on the first request of a pause only. */\nfunction logPaused(deps: BuildStateDeps, pause: { logged: boolean }, buildId: string): void {\n if (!pause.logged) {\n deps.logger.warn({ buildId }, PAUSED_MESSAGE);\n }\n pause.logged = true;\n}\n\n/** Ask every state channel of the build's project to show it. */\nasync function requestAll(\n options: BuildStatePublisherOptions,\n where: { buildId: string; origin: string },\n): Promise<void> {\n const { deps } = options;\n const { buildId, origin } = where;\n const loaded = await loadBuild(deps, buildId);\n if (loaded === null) {\n return;\n }\n const targets = await stateTargets(deps, loaded.project.id);\n await Promise.allSettled(\n targets.map(async (target) => {\n await requestOne(options, { buildId, loaded, target, origin });\n }),\n );\n}\n\n/** Queue the delivery; inline when there is no queue, or when queueing itself failed. */\nasync function requestOne(\n options: BuildStatePublisherOptions,\n request: {\n buildId: string;\n loaded: NonNullable<Awaited<ReturnType<typeof loadBuild>>>;\n target: StateTarget;\n origin: string;\n },\n): Promise<void> {\n const { enqueue, deps } = options;\n const { buildId, loaded, target, origin } = request;\n if (enqueue !== undefined) {\n try {\n await enqueue({ channelId: target.channel.id, buildId });\n return;\n } catch (error) {\n deps.logger.warn(\n { err: error, channelId: target.channel.id, buildId },\n \"failed to queue the state delivery; delivering inline\",\n );\n }\n }\n await deliverInline(deps, loaded, { target, origin });\n}\n\n/** Deliver now and record the outcome on the channel; never throws. */\nasync function deliverInline(\n deps: BuildStateDeps,\n loaded: Parameters<typeof writeTo>[1],\n where: Parameters<typeof writeTo>[2],\n): Promise<void> {\n const { target } = where;\n const channels = new NotificationChannelModel(\n deps.db,\n { notificationChannels: deps.db.tables.notificationChannels },\n deps.secret,\n );\n let error: string | undefined;\n try {\n await writeTo(deps, loaded, where);\n } catch (writeError) {\n deps.logger.warn({ err: writeError, channelId: target.channel.id }, \"state delivery failed\");\n error = sanitizeErrorText(\n writeError instanceof Error ? writeError.message : String(writeError),\n 500,\n );\n }\n await channels.recordOutcome(target.channel.id, error).catch((recordError: unknown) => {\n deps.logger.warn(\n { err: recordError, channelId: target.channel.id },\n \"failed to record outcome\",\n );\n });\n}\n"],"mappings":";;;;;;;;;;;;;;AAsBA,MAAa,iBACX;;AAGF,SAAgB,0BACd,SACqB;CACrB,MAAM,EAAE,SAAS;CACjB,MAAM,QAAQ,EAAE,QAAQ,MAAM;CAC9B,OAAO,EACL,SAAS,OAAO,YAAY;EAC1B,IAAI;GACF,MAAM,SAAS,MAAM,KAAK,aAAa;GACvC,IAAI,CAAC,QAAQ;IACX,UAAU,MAAM,OAAO,OAAO;IAC9B;GACF;GACA,MAAM,SAAS;GACf,MAAM,WAAW,SAAS;IAAE;IAAS;GAAO,CAAC;EAC/C,SAAS,OAAO;GACd,KAAK,OAAO,KAAK;IAAE,KAAK;IAAO;GAAQ,GAAG,mCAAmC;EAC/E;CACF,EACF;AACF;;AAGA,SAAS,UAAU,MAAsB,OAA4B,SAAuB;CAC1F,IAAI,CAAC,MAAM,QACT,KAAK,OAAO,KAAK,EAAE,QAAQ,GAAG,cAAc;CAE9C,MAAM,SAAS;AACjB;;AAGA,eAAe,WACb,SACA,OACe;CACf,MAAM,EAAE,SAAS;CACjB,MAAM,EAAE,SAAS,WAAW;CAC5B,MAAM,SAAS,MAAM,UAAU,MAAM,OAAO;CAC5C,IAAI,WAAW,MACb;CAEF,MAAM,UAAU,MAAM,aAAa,MAAM,OAAO,QAAQ,EAAE;CAC1D,MAAM,QAAQ,WACZ,QAAQ,IAAI,OAAO,WAAW;EAC5B,MAAM,WAAW,SAAS;GAAE;GAAS;GAAQ;GAAQ;EAAO,CAAC;CAC/D,CAAC,CACH;AACF;;AAGA,eAAe,WACb,SACA,SAMe;CACf,MAAM,EAAE,SAAS,SAAS;CAC1B,MAAM,EAAE,SAAS,QAAQ,QAAQ,WAAW;CAC5C,IAAI,YAAY,KAAA,GACd,IAAI;EACF,MAAM,QAAQ;GAAE,WAAW,OAAO,QAAQ;GAAI;EAAQ,CAAC;EACvD;CACF,SAAS,OAAO;EACd,KAAK,OAAO,KACV;GAAE,KAAK;GAAO,WAAW,OAAO,QAAQ;GAAI;EAAQ,GACpD,uDACF;CACF;CAEF,MAAM,cAAc,MAAM,QAAQ;EAAE;EAAQ;CAAO,CAAC;AACtD;;AAGA,eAAe,cACb,MACA,QACA,OACe;CACf,MAAM,EAAE,WAAW;CACnB,MAAM,WAAW,IAAI,yBACnB,KAAK,IACL,EAAE,sBAAsB,KAAK,GAAG,OAAO,qBAAqB,GAC5D,KAAK,MACP;CACA,IAAI;CACJ,IAAI;EACF,MAAM,QAAQ,MAAM,QAAQ,KAAK;CACnC,SAAS,YAAY;EACnB,KAAK,OAAO,KAAK;GAAE,KAAK;GAAY,WAAW,OAAO,QAAQ;EAAG,GAAG,uBAAuB;EAC3F,QAAQ,kBACN,sBAAsB,QAAQ,WAAW,UAAU,OAAO,UAAU,GACpE,GACF;CACF;CACA,MAAM,SAAS,cAAc,OAAO,QAAQ,IAAI,KAAK,CAAC,CAAC,OAAO,gBAAyB;EACrF,KAAK,OAAO,KACV;GAAE,KAAK;GAAa,WAAW,OAAO,QAAQ;EAAG,GACjD,0BACF;CACF,CAAC;AACH"}
@@ -0,0 +1,7 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { BuildStateDeps, BuildStatePublisher } from "./types.mjs";
4
+ /** Ask `publisher` for the state of every open recent build; resolves to how many were asked. Never rejects. */
5
+ declare function requestOpenBuildStates(deps: Pick<BuildStateDeps, "db" | "logger">, publisher: BuildStatePublisher): Promise<number>;
6
+ export { requestOpenBuildStates };
7
+ //# sourceMappingURL=resume.d.mts.map
@@ -0,0 +1,46 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { BuildModel } from "../../models/build.mjs";
5
+ import { ProjectModel } from "../../models/project.mjs";
6
+ import { LOCAL_SHA_PREFIX } from "@storyshelf/affected";
7
+ // src/capture/build-state/resume.ts
8
+ /**
9
+ * Re-requesting the state of builds still open. Requests made while no public origin was resolved
10
+ * were dropped (ADR 0014, decision 11), so once one is, the builds that can still change are asked
11
+ * again; settled builds keep what they last showed until their next transition.
12
+ */
13
+ /** Builds that have not reached a verdict. */
14
+ const OPEN = /* @__PURE__ */ new Set([
15
+ "pending",
16
+ "capturing",
17
+ "comparing",
18
+ "reviewing"
19
+ ]);
20
+ /** Newest builds looked at per project. */
21
+ const PER_PROJECT = 25;
22
+ /** Ask `publisher` for the state of every open recent build; resolves to how many were asked. Never rejects. */
23
+ async function requestOpenBuildStates(deps, publisher) {
24
+ try {
25
+ const projects = await new ProjectModel(deps.db).list();
26
+ const ids = (await Promise.all(projects.map(async (project) => await openBuildIds(deps, project.id)))).flat();
27
+ await Promise.all(ids.map(async (id) => {
28
+ await publisher.request(id);
29
+ }));
30
+ return ids.length;
31
+ } catch (error) {
32
+ deps.logger.warn({ err: error }, "failed to re-request the state of open builds");
33
+ return 0;
34
+ }
35
+ }
36
+ /** The newest builds of a project that have not reached a verdict. */
37
+ async function openBuildIds(deps, projectId) {
38
+ return (await new BuildModel(deps.db).list(projectId, { limit: PER_PROJECT })).filter((build) => OPEN.has(build.status) && hasGitCommit(build.gitSha)).map((build) => build.id);
39
+ }
40
+ /** A build with no commit, or a local upload, has no git state to show (see `statusesForBuild`). */
41
+ function hasGitCommit(gitSha) {
42
+ return gitSha.length > 0 && !gitSha.startsWith(LOCAL_SHA_PREFIX);
43
+ }
44
+ export { requestOpenBuildStates };
45
+
46
+ //# sourceMappingURL=resume.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resume.mjs","names":[],"sources":["../../../src/capture/build-state/resume.ts"],"sourcesContent":["/**\n * Re-requesting the state of builds still open. Requests made while no public origin was resolved\n * were dropped (ADR 0014, decision 11), so once one is, the builds that can still change are asked\n * again; settled builds keep what they last showed until their next transition.\n */\nimport { LOCAL_SHA_PREFIX } from \"@storyshelf/affected\";\nimport { BuildModel } from \"../../models/build.ts\";\nimport { ProjectModel } from \"../../models/project.ts\";\nimport type { BuildStatus } from \"../../types.ts\";\nimport type { BuildStateDeps, BuildStatePublisher } from \"./types.ts\";\n\n/** Builds that have not reached a verdict. */\nconst OPEN: ReadonlySet<BuildStatus> = new Set([\"pending\", \"capturing\", \"comparing\", \"reviewing\"]);\n\n/** Newest builds looked at per project. */\nconst PER_PROJECT = 25;\n\n/** Ask `publisher` for the state of every open recent build; resolves to how many were asked. Never rejects. */\nexport async function requestOpenBuildStates(\n deps: Pick<BuildStateDeps, \"db\" | \"logger\">,\n publisher: BuildStatePublisher,\n): Promise<number> {\n try {\n const projects = await new ProjectModel(deps.db).list();\n const lists = await Promise.all(\n projects.map(async (project) => await openBuildIds(deps, project.id)),\n );\n const ids = lists.flat();\n await Promise.all(\n ids.map(async (id) => {\n await publisher.request(id);\n }),\n );\n return ids.length;\n } catch (error) {\n deps.logger.warn({ err: error }, \"failed to re-request the state of open builds\");\n return 0;\n }\n}\n\n/** The newest builds of a project that have not reached a verdict. */\nasync function openBuildIds(\n deps: Pick<BuildStateDeps, \"db\">,\n projectId: string,\n): Promise<string[]> {\n const recent = await new BuildModel(deps.db).list(projectId, { limit: PER_PROJECT });\n return recent\n .filter((build) => OPEN.has(build.status) && hasGitCommit(build.gitSha))\n .map((build) => build.id);\n}\n\n/** A build with no commit, or a local upload, has no git state to show (see `statusesForBuild`). */\nfunction hasGitCommit(gitSha: string): boolean {\n return gitSha.length > 0 && !gitSha.startsWith(LOCAL_SHA_PREFIX);\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,MAAM,uBAAiC,IAAI,IAAI;CAAC;CAAW;CAAa;CAAa;AAAW,CAAC;;AAGjG,MAAM,cAAc;;AAGpB,eAAsB,uBACpB,MACA,WACiB;CACjB,IAAI;EACF,MAAM,WAAW,MAAM,IAAI,aAAa,KAAK,EAAE,CAAC,CAAC,KAAK;EAItD,MAAM,OAAM,MAHQ,QAAQ,IAC1B,SAAS,IAAI,OAAO,YAAY,MAAM,aAAa,MAAM,QAAQ,EAAE,CAAC,CACtE,EAAA,CACkB,KAAK;EACvB,MAAM,QAAQ,IACZ,IAAI,IAAI,OAAO,OAAO;GACpB,MAAM,UAAU,QAAQ,EAAE;EAC5B,CAAC,CACH;EACA,OAAO,IAAI;CACb,SAAS,OAAO;EACd,KAAK,OAAO,KAAK,EAAE,KAAK,MAAM,GAAG,+CAA+C;EAChF,OAAO;CACT;AACF;;AAGA,eAAe,aACb,MACA,WACmB;CAEnB,QAAO,MADc,IAAI,WAAW,KAAK,EAAE,CAAC,CAAC,KAAK,WAAW,EAAE,OAAO,YAAY,CAAC,EAAA,CAEhF,QAAQ,UAAU,KAAK,IAAI,MAAM,MAAM,KAAK,aAAa,MAAM,MAAM,CAAC,CAAC,CACvE,KAAK,UAAU,MAAM,EAAE;AAC5B;;AAGA,SAAS,aAAa,QAAyB;CAC7C,OAAO,OAAO,SAAS,KAAK,CAAC,OAAO,WAAW,gBAAgB;AACjE"}
@@ -0,0 +1,47 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { Logger } from "../../logger.mjs";
4
+ import { DatabaseAdapter } from "../../adapter/database.mjs";
5
+ import { NotificationChannel } from "../../adapters/notifier/types.mjs";
6
+ import { NotifierProvider, StateNotifierProvider } from "../../adapters/notifier/provider.mjs";
7
+ import { StorageAdapter } from "../../adapter/storage.mjs";
8
+ import { ShelfConfig } from "../../config.mjs";
9
+ import { BuildStateFlags } from "../../adapters/notifier/build-state.mjs";
10
+ import { SecretInput } from "../../utils/encrypt.mjs";
11
+ import { Project } from "../../schema/project.mjs";
12
+ /** What delivering a build's state needs. */
13
+ interface BuildStateDeps {
14
+ db: DatabaseAdapter;
15
+ /** Read to tell whether the build's Storybook is published; without it publishing reads as pending. */
16
+ storage?: StorageAdapter | undefined;
17
+ /** Notifier providers; only the `state` ones (git hosts) take part. */
18
+ notifiers: readonly NotifierProvider[];
19
+ /** Server secret that decrypts channel tokens. */
20
+ secret: SecretInput;
21
+ /** The published-Storybook domain for Storybook links. */
22
+ config: Pick<ShelfConfig, "publishedBaseDomain">;
23
+ /**
24
+ * The resolved public origin (ADR 0007, decision 6): the origin every link starts with. While it
25
+ * resolves to nothing, no state is requested or delivered (ADR 0014, decision 11).
26
+ */
27
+ publicOrigin: () => Promise<string | undefined>;
28
+ /** Which statuses a project's builds show: `testing` from the server options, review from the project. */
29
+ flags: (project: Project) => BuildStateFlags;
30
+ logger: Logger;
31
+ }
32
+ /** A channel with the provider that delivers to it. */
33
+ interface StateTarget {
34
+ channel: NotificationChannel;
35
+ provider: StateNotifierProvider;
36
+ }
37
+ /** Why a delivery wrote nothing. */
38
+ type SkipReason = "no-build" | "no-channel" | "disabled" | "no-provider" | "no-origin";
39
+ /**
40
+ * Asks for a build's current state to be shown on its project's git channels. Never rejects: the
41
+ * request that triggered it must not fail because a git host did.
42
+ */
43
+ interface BuildStatePublisher {
44
+ request(buildId: string): Promise<void>;
45
+ }
46
+ export { BuildStateDeps, BuildStatePublisher, SkipReason, StateTarget };
47
+ //# sourceMappingURL=types.d.mts.map
@@ -0,0 +1,20 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { DatabaseAdapter } from "../../adapter/database.mjs";
4
+ import { StorageAdapter } from "../../adapter/storage.mjs";
5
+ import { Catalog } from "./types.mjs";
6
+ /** What cataloguing reads and writes. */
7
+ interface CatalogDeps {
8
+ db: DatabaseAdapter;
9
+ storage: StorageAdapter;
10
+ }
11
+ /**
12
+ * Catalogue a build from its published statics: replace its `build_components` rows, then persist
13
+ * `catalog.json`. Resolves to the catalog, or null when the build has no readable index
14
+ * (statics purged, or not a Storybook), in which case nothing is written.
15
+ */
16
+ declare function catalogueBuild(deps: CatalogDeps, projectId: string, buildId: string): Promise<Catalog | null>;
17
+ /** A build's persisted catalog, or null when it has none (or an unreadable one). */
18
+ declare function readCatalog(storage: StorageAdapter, projectId: string, buildId: string): Promise<Catalog | null>;
19
+ export { CatalogDeps, catalogueBuild, readCatalog };
20
+ //# sourceMappingURL=catalogue.d.mts.map
@@ -0,0 +1,52 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { catalogPath } from "../../paths.mjs";
5
+ import { BuildComponentModel } from "../../models/build-component.mjs";
6
+ import { groupComponents, toBuildComponent } from "./components.mjs";
7
+ import { parseStorybookIndexText } from "./parse.mjs";
8
+ import { readPublishedFile } from "./read.mjs";
9
+ // src/capture/catalog/catalogue.ts
10
+ /** Index files a Storybook may publish, newest format first. */
11
+ const INDEX_FILES = ["index.json", "stories.json"];
12
+ /**
13
+ * Catalogue a build from its published statics: replace its `build_components` rows, then persist
14
+ * `catalog.json`. Resolves to the catalog, or null when the build has no readable index
15
+ * (statics purged, or not a Storybook), in which case nothing is written.
16
+ */
17
+ async function catalogueBuild(deps, projectId, buildId) {
18
+ const entries = await readIndexEntries(deps.storage, projectId, buildId);
19
+ if (!entries) return null;
20
+ const catalog = {
21
+ v: 1,
22
+ entries
23
+ };
24
+ await new BuildComponentModel(deps.db).replaceForBuild(projectId, buildId, groupComponents(entries).map((component) => toBuildComponent(component)));
25
+ await deps.storage.write(catalogPath(projectId, buildId), Buffer.from(JSON.stringify(catalog)));
26
+ return catalog;
27
+ }
28
+ /** A build's persisted catalog, or null when it has none (or an unreadable one). */
29
+ async function readCatalog(storage, projectId, buildId) {
30
+ const path = catalogPath(projectId, buildId);
31
+ try {
32
+ if (!await storage.exists(path)) return null;
33
+ const parsed = JSON.parse((await storage.read(path)).toString("utf8"));
34
+ return parsed.v === 1 && Array.isArray(parsed.entries) ? {
35
+ v: 1,
36
+ entries: parsed.entries
37
+ } : null;
38
+ } catch {
39
+ return null;
40
+ }
41
+ }
42
+ async function readIndexEntries(storage, projectId, buildId) {
43
+ for (const name of INDEX_FILES) {
44
+ const file = await readPublishedFile(storage, projectId, buildId, name).catch(() => null);
45
+ const entries = file ? parseStorybookIndexText(file.toString("utf8")) : null;
46
+ if (entries) return entries;
47
+ }
48
+ return null;
49
+ }
50
+ export { catalogueBuild, readCatalog };
51
+
52
+ //# sourceMappingURL=catalogue.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalogue.mjs","names":[],"sources":["../../../src/capture/catalog/catalogue.ts"],"sourcesContent":["/** Cataloguing a published build: read its Storybook index, persist `catalog.json` and component rows. */\nimport type { DatabaseAdapter } from \"../../adapters/database.ts\";\nimport type { StorageAdapter } from \"../../adapters/storage.ts\";\nimport { BuildComponentModel } from \"../../models/build-component.ts\";\nimport { catalogPath } from \"../../utils/paths.ts\";\nimport { groupComponents, toBuildComponent } from \"./components.ts\";\nimport { parseStorybookIndexText } from \"./parse.ts\";\nimport { readPublishedFile } from \"./read.ts\";\nimport type { Catalog, CatalogEntry } from \"./types.ts\";\n\n/** What cataloguing reads and writes. */\nexport interface CatalogDeps {\n db: DatabaseAdapter;\n storage: StorageAdapter;\n}\n\n/** Index files a Storybook may publish, newest format first. */\nconst INDEX_FILES = [\"index.json\", \"stories.json\"] as const;\n\n/**\n * Catalogue a build from its published statics: replace its `build_components` rows, then persist\n * `catalog.json`. Resolves to the catalog, or null when the build has no readable index\n * (statics purged, or not a Storybook), in which case nothing is written.\n */\nexport async function catalogueBuild(\n deps: CatalogDeps,\n projectId: string,\n buildId: string,\n): Promise<Catalog | null> {\n const entries = await readIndexEntries(deps.storage, projectId, buildId);\n if (!entries) {\n return null;\n }\n const catalog: Catalog = { v: 1, entries };\n // The rows go first: catalog.json is the marker that cataloguing finished, so a crash between the\n // two leaves a build the lazy loader catalogues again, never one with a catalog and no rows.\n await new BuildComponentModel(deps.db).replaceForBuild(\n projectId,\n buildId,\n groupComponents(entries).map((component) => toBuildComponent(component)),\n );\n await deps.storage.write(catalogPath(projectId, buildId), Buffer.from(JSON.stringify(catalog)));\n return catalog;\n}\n\n/** A build's persisted catalog, or null when it has none (or an unreadable one). */\nexport async function readCatalog(\n storage: StorageAdapter,\n projectId: string,\n buildId: string,\n): Promise<Catalog | null> {\n const path = catalogPath(projectId, buildId);\n try {\n if (!(await storage.exists(path))) {\n return null;\n }\n const parsed = JSON.parse((await storage.read(path)).toString(\"utf8\")) as Partial<Catalog>;\n return parsed.v === 1 && Array.isArray(parsed.entries)\n ? { v: 1, entries: parsed.entries }\n : null;\n } catch {\n return null;\n }\n}\n\nasync function readIndexEntries(\n storage: StorageAdapter,\n projectId: string,\n buildId: string,\n): Promise<CatalogEntry[] | null> {\n for (const name of INDEX_FILES) {\n // eslint-disable-next-line no-await-in-loop -- stop at the first index that parses\n const file = await readPublishedFile(storage, projectId, buildId, name).catch(() => null);\n const entries = file ? parseStorybookIndexText(file.toString(\"utf8\")) : null;\n if (entries) {\n return entries;\n }\n }\n return null;\n}\n"],"mappings":";;;;;;;;;;AAiBA,MAAM,cAAc,CAAC,cAAc,cAAc;;;;;;AAOjD,eAAsB,eACpB,MACA,WACA,SACyB;CACzB,MAAM,UAAU,MAAM,iBAAiB,KAAK,SAAS,WAAW,OAAO;CACvE,IAAI,CAAC,SACH,OAAO;CAET,MAAM,UAAmB;EAAE,GAAG;EAAG;CAAQ;CAGzC,MAAM,IAAI,oBAAoB,KAAK,EAAE,CAAC,CAAC,gBACrC,WACA,SACA,gBAAgB,OAAO,CAAC,CAAC,KAAK,cAAc,iBAAiB,SAAS,CAAC,CACzE;CACA,MAAM,KAAK,QAAQ,MAAM,YAAY,WAAW,OAAO,GAAG,OAAO,KAAK,KAAK,UAAU,OAAO,CAAC,CAAC;CAC9F,OAAO;AACT;;AAGA,eAAsB,YACpB,SACA,WACA,SACyB;CACzB,MAAM,OAAO,YAAY,WAAW,OAAO;CAC3C,IAAI;EACF,IAAI,CAAE,MAAM,QAAQ,OAAO,IAAI,GAC7B,OAAO;EAET,MAAM,SAAS,KAAK,OAAO,MAAM,QAAQ,KAAK,IAAI,EAAA,CAAG,SAAS,MAAM,CAAC;EACrE,OAAO,OAAO,MAAM,KAAK,MAAM,QAAQ,OAAO,OAAO,IACjD;GAAE,GAAG;GAAG,SAAS,OAAO;EAAQ,IAChC;CACN,QAAQ;EACN,OAAO;CACT;AACF;AAEA,eAAe,iBACb,SACA,WACA,SACgC;CAChC,KAAK,MAAM,QAAQ,aAAa;EAE9B,MAAM,OAAO,MAAM,kBAAkB,SAAS,WAAW,SAAS,IAAI,CAAC,CAAC,YAAY,IAAI;EACxF,MAAM,UAAU,OAAO,wBAAwB,KAAK,SAAS,MAAM,CAAC,IAAI;EACxE,IAAI,SACF,OAAO;CAEX;CACA,OAAO;AACT"}
@@ -0,0 +1,21 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { CatalogComponent, CatalogEntry } from "./types.mjs";
4
+ import { BuildComponentInput } from "../../models/build-component.mjs";
5
+ /** Group entries by story file (entries without one by title), ordered by title then file. */
6
+ declare function groupComponents(entries: readonly CatalogEntry[]): CatalogComponent[];
7
+ /** What `build_components` stores of a component. */
8
+ declare function toBuildComponent(component: CatalogComponent): BuildComponentInput;
9
+ /** SHA-256 over the entries' id, name, type and title, in id order: equal sets hash equal. */
10
+ declare function hashEntries(entries: readonly CatalogEntry[]): string;
11
+ /** How one component's entries differ between two builds. */
12
+ interface EntryChanges {
13
+ added: number;
14
+ removed: number;
15
+ /** Same id, new display name. */
16
+ renamed: number;
17
+ }
18
+ /** Entries added, removed and renamed from `before` to `after` (matched by entry id). */
19
+ declare function diffEntries(before: readonly CatalogEntry[], after: readonly CatalogEntry[]): EntryChanges;
20
+ export { EntryChanges, diffEntries, groupComponents, hashEntries, toBuildComponent };
21
+ //# sourceMappingURL=components.d.mts.map
@@ -0,0 +1,54 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { createHash } from "node:crypto";
5
+ // src/capture/catalog/components.ts
6
+ /** Catalog entries grouped into components, hashed, and compared between builds. */
7
+ /** Group entries by story file (entries without one by title), ordered by title then file. */
8
+ function groupComponents(entries) {
9
+ return [...Map.groupBy(entries, (entry) => entry.importPath || `title:${entry.title}`).values()].map((group) => {
10
+ const [first] = group;
11
+ return {
12
+ importPath: first?.importPath ?? "",
13
+ title: first?.title ?? "",
14
+ storyCount: group.filter((entry) => entry.type === "story").length,
15
+ hash: hashEntries(group),
16
+ entries: group
17
+ };
18
+ }).toSorted((a, b) => a.title.localeCompare(b.title) || a.importPath.localeCompare(b.importPath));
19
+ }
20
+ /** What `build_components` stores of a component. */
21
+ function toBuildComponent(component) {
22
+ const { importPath, title, storyCount, hash } = component;
23
+ return {
24
+ importPath,
25
+ title,
26
+ storyCount,
27
+ hash
28
+ };
29
+ }
30
+ /** SHA-256 over the entries' id, name, type and title, in id order: equal sets hash equal. */
31
+ function hashEntries(entries) {
32
+ const lines = entries.map((entry) => [
33
+ entry.id,
34
+ entry.name,
35
+ entry.type,
36
+ entry.title
37
+ ].join(" ")).toSorted();
38
+ return createHash("sha256").update(lines.join("\n")).digest("hex");
39
+ }
40
+ /** Entries added, removed and renamed from `before` to `after` (matched by entry id). */
41
+ function diffEntries(before, after) {
42
+ const was = new Map(before.map((entry) => [entry.id, entry]));
43
+ const now = new Map(after.map((entry) => [entry.id, entry]));
44
+ let renamed = 0;
45
+ for (const [id, entry] of now) if (was.has(id) && was.get(id)?.name !== entry.name) renamed += 1;
46
+ return {
47
+ added: [...now.keys()].filter((id) => !was.has(id)).length,
48
+ removed: [...was.keys()].filter((id) => !now.has(id)).length,
49
+ renamed
50
+ };
51
+ }
52
+ export { diffEntries, groupComponents, hashEntries, toBuildComponent };
53
+
54
+ //# sourceMappingURL=components.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"components.mjs","names":[],"sources":["../../../src/capture/catalog/components.ts"],"sourcesContent":["/** Catalog entries grouped into components, hashed, and compared between builds. */\nimport { createHash } from \"node:crypto\";\nimport type { BuildComponentInput } from \"../../models/build-component.ts\";\nimport type { CatalogComponent, CatalogEntry } from \"./types.ts\";\n\n/** Group entries by story file (entries without one by title), ordered by title then file. */\nexport function groupComponents(entries: readonly CatalogEntry[]): CatalogComponent[] {\n const groups = Map.groupBy(entries, (entry) => entry.importPath || `title:${entry.title}`);\n return [...groups.values()]\n .map((group): CatalogComponent => {\n const [first] = group;\n return {\n importPath: first?.importPath ?? \"\",\n title: first?.title ?? \"\",\n storyCount: group.filter((entry) => entry.type === \"story\").length,\n hash: hashEntries(group),\n entries: group,\n };\n })\n .toSorted((a, b) => a.title.localeCompare(b.title) || a.importPath.localeCompare(b.importPath));\n}\n\n/** What `build_components` stores of a component. */\nexport function toBuildComponent(component: CatalogComponent): BuildComponentInput {\n const { importPath, title, storyCount, hash } = component;\n return { importPath, title, storyCount, hash };\n}\n\n/** SHA-256 over the entries' id, name, type and title, in id order: equal sets hash equal. */\nexport function hashEntries(entries: readonly CatalogEntry[]): string {\n const lines = entries\n .map((entry) => [entry.id, entry.name, entry.type, entry.title].join(\"\\t\"))\n .toSorted();\n return createHash(\"sha256\").update(lines.join(\"\\n\")).digest(\"hex\");\n}\n\n/** How one component's entries differ between two builds. */\nexport interface EntryChanges {\n added: number;\n removed: number;\n /** Same id, new display name. */\n renamed: number;\n}\n\n/** Entries added, removed and renamed from `before` to `after` (matched by entry id). */\nexport function diffEntries(\n before: readonly CatalogEntry[],\n after: readonly CatalogEntry[],\n): EntryChanges {\n const was = new Map(before.map((entry) => [entry.id, entry] as const));\n const now = new Map(after.map((entry) => [entry.id, entry] as const));\n let renamed = 0;\n for (const [id, entry] of now) {\n if (was.has(id) && was.get(id)?.name !== entry.name) {\n renamed += 1;\n }\n }\n return {\n added: [...now.keys()].filter((id) => !was.has(id)).length,\n removed: [...was.keys()].filter((id) => !now.has(id)).length,\n renamed,\n };\n}\n"],"mappings":";;;;;;;AAMA,SAAgB,gBAAgB,SAAsD;CAEpF,OAAO,CAAC,GADO,IAAI,QAAQ,UAAU,UAAU,MAAM,cAAc,SAAS,MAAM,OAClE,CAAC,CAAC,OAAO,CAAC,CAAC,CACxB,KAAK,UAA4B;EAChC,MAAM,CAAC,SAAS;EAChB,OAAO;GACL,YAAY,OAAO,cAAc;GACjC,OAAO,OAAO,SAAS;GACvB,YAAY,MAAM,QAAQ,UAAU,MAAM,SAAS,OAAO,CAAC,CAAC;GAC5D,MAAM,YAAY,KAAK;GACvB,SAAS;EACX;CACF,CAAC,CAAC,CACD,UAAU,GAAG,MAAM,EAAE,MAAM,cAAc,EAAE,KAAK,KAAK,EAAE,WAAW,cAAc,EAAE,UAAU,CAAC;AAClG;;AAGA,SAAgB,iBAAiB,WAAkD;CACjF,MAAM,EAAE,YAAY,OAAO,YAAY,SAAS;CAChD,OAAO;EAAE;EAAY;EAAO;EAAY;CAAK;AAC/C;;AAGA,SAAgB,YAAY,SAA0C;CACpE,MAAM,QAAQ,QACX,KAAK,UAAU;EAAC,MAAM;EAAI,MAAM;EAAM,MAAM;EAAM,MAAM;CAAK,CAAC,CAAC,KAAK,GAAI,CAAC,CAAC,CAC1E,SAAS;CACZ,OAAO,WAAW,QAAQ,CAAC,CAAC,OAAO,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,KAAK;AACnE;;AAWA,SAAgB,YACd,QACA,OACc;CACd,MAAM,MAAM,IAAI,IAAI,OAAO,KAAK,UAAU,CAAC,MAAM,IAAI,KAAK,CAAU,CAAC;CACrE,MAAM,MAAM,IAAI,IAAI,MAAM,KAAK,UAAU,CAAC,MAAM,IAAI,KAAK,CAAU,CAAC;CACpE,IAAI,UAAU;CACd,KAAK,MAAM,CAAC,IAAI,UAAU,KACxB,IAAI,IAAI,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,CAAC,EAAE,SAAS,MAAM,MAC7C,WAAW;CAGf,OAAO;EACL,OAAO,CAAC,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,QAAQ,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;EACpD,SAAS,CAAC,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,QAAQ,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;EACtD;CACF;AACF"}
@@ -0,0 +1,28 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { Build } from "../../schema/build.mjs";
4
+ import { BuildComponent } from "../../schema/build-component.mjs";
5
+ import { ComponentPresence } from "../../models/component.mjs";
6
+ /** How a build's version of a component compares with the build before it on the same branch. */
7
+ type ComponentChange = "new" | "changed" | "unchanged";
8
+ /** One build's row of a component's history. */
9
+ interface ComponentBuildRow {
10
+ build: Build;
11
+ component: BuildComponent;
12
+ change: ComponentChange;
13
+ /** The same component in the build before on the branch; null when this is its first. */
14
+ previous: BuildComponent | null;
15
+ }
16
+ /**
17
+ * Component history, newest build first. `rows` are the component's `build_components` rows;
18
+ * a row whose build is missing is skipped. The build before is the next older one on the same
19
+ * branch, so a feature branch compares with itself rather than with an unrelated default build.
20
+ */
21
+ declare function componentBuildHistory(rows: readonly BuildComponent[], builds: readonly Build[]): ComponentBuildRow[];
22
+ /**
23
+ * Where a component stands against the project's latest build. `latest` holds that build's
24
+ * component rows, or null when it has no catalog (the answer is then unknown, never "deleted").
25
+ */
26
+ declare function catalogPresence(history: readonly ComponentBuildRow[], importPath: string, latest: readonly BuildComponent[] | null): ComponentPresence;
27
+ export { ComponentBuildRow, ComponentChange, catalogPresence, componentBuildHistory };
28
+ //# sourceMappingURL=history.d.mts.map
@@ -0,0 +1,50 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ // src/capture/catalog/history.ts
5
+ /**
6
+ * Component history, newest build first. `rows` are the component's `build_components` rows;
7
+ * a row whose build is missing is skipped. The build before is the next older one on the same
8
+ * branch, so a feature branch compares with itself rather than with an unrelated default build.
9
+ */
10
+ function componentBuildHistory(rows, builds) {
11
+ const byId = new Map(builds.map((build) => [build.id, build]));
12
+ const known = rows.flatMap((component) => {
13
+ const build = byId.get(component.buildId);
14
+ return build ? [{
15
+ build,
16
+ component
17
+ }] : [];
18
+ }).toSorted((a, b) => b.build.createdAt.localeCompare(a.build.createdAt));
19
+ return known.map((entry, index) => {
20
+ const previous = known.slice(index + 1).find((older) => older.build.gitBranch === entry.build.gitBranch)?.component ?? null;
21
+ const change = previous ? previous.hash === entry.component.hash ? "unchanged" : "changed" : "new";
22
+ return {
23
+ build: entry.build,
24
+ component: entry.component,
25
+ change,
26
+ previous
27
+ };
28
+ });
29
+ }
30
+ /**
31
+ * Where a component stands against the project's latest build. `latest` holds that build's
32
+ * component rows, or null when it has no catalog (the answer is then unknown, never "deleted").
33
+ */
34
+ function catalogPresence(history, importPath, latest) {
35
+ const newest = history[0];
36
+ if (!latest || !newest) return { kind: "unknown" };
37
+ if (latest.some((row) => row.importPath === importPath)) return { kind: "present" };
38
+ const moved = latest.find((row) => row.title === newest.component.title && row.importPath !== "");
39
+ return moved ? {
40
+ kind: "moved",
41
+ to: moved.importPath,
42
+ title: moved.title
43
+ } : {
44
+ kind: "deleted",
45
+ lastSeen: newest.build
46
+ };
47
+ }
48
+ export { catalogPresence, componentBuildHistory };
49
+
50
+ //# sourceMappingURL=history.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.mjs","names":[],"sources":["../../../src/capture/catalog/history.ts"],"sourcesContent":["/** A component across builds: which builds hold it, whether its stories changed, and where it went. */\nimport type { ComponentPresence } from \"../../models/component.ts\";\nimport type { BuildComponent } from \"../../schema/build-component.ts\";\nimport type { Build } from \"../../schema/build.ts\";\n\n/** How a build's version of a component compares with the build before it on the same branch. */\nexport type ComponentChange = \"new\" | \"changed\" | \"unchanged\";\n\n/** One build's row of a component's history. */\nexport interface ComponentBuildRow {\n build: Build;\n component: BuildComponent;\n change: ComponentChange;\n /** The same component in the build before on the branch; null when this is its first. */\n previous: BuildComponent | null;\n}\n\n/**\n * Component history, newest build first. `rows` are the component's `build_components` rows;\n * a row whose build is missing is skipped. The build before is the next older one on the same\n * branch, so a feature branch compares with itself rather than with an unrelated default build.\n */\nexport function componentBuildHistory(\n rows: readonly BuildComponent[],\n builds: readonly Build[],\n): ComponentBuildRow[] {\n const byId = new Map(builds.map((build) => [build.id, build] as const));\n const known = rows\n .flatMap((component) => {\n const build = byId.get(component.buildId);\n return build ? [{ build, component }] : [];\n })\n .toSorted((a, b) => b.build.createdAt.localeCompare(a.build.createdAt));\n return known.map((entry, index) => {\n const previous =\n known.slice(index + 1).find((older) => older.build.gitBranch === entry.build.gitBranch)\n ?.component ?? null;\n const change: ComponentChange = previous\n ? previous.hash === entry.component.hash\n ? \"unchanged\"\n : \"changed\"\n : \"new\";\n return { build: entry.build, component: entry.component, change, previous };\n });\n}\n\n/**\n * Where a component stands against the project's latest build. `latest` holds that build's\n * component rows, or null when it has no catalog (the answer is then unknown, never \"deleted\").\n */\nexport function catalogPresence(\n history: readonly ComponentBuildRow[],\n importPath: string,\n latest: readonly BuildComponent[] | null,\n): ComponentPresence {\n const newest = history[0];\n if (!latest || !newest) {\n return { kind: \"unknown\" };\n }\n if (latest.some((row) => row.importPath === importPath)) {\n return { kind: \"present\" };\n }\n const moved = latest.find((row) => row.title === newest.component.title && row.importPath !== \"\");\n return moved\n ? { kind: \"moved\", to: moved.importPath, title: moved.title }\n : { kind: \"deleted\", lastSeen: newest.build };\n}\n"],"mappings":";;;;;;;;;AAsBA,SAAgB,sBACd,MACA,QACqB;CACrB,MAAM,OAAO,IAAI,IAAI,OAAO,KAAK,UAAU,CAAC,MAAM,IAAI,KAAK,CAAU,CAAC;CACtE,MAAM,QAAQ,KACX,SAAS,cAAc;EACtB,MAAM,QAAQ,KAAK,IAAI,UAAU,OAAO;EACxC,OAAO,QAAQ,CAAC;GAAE;GAAO;EAAU,CAAC,IAAI,CAAC;CAC3C,CAAC,CAAC,CACD,UAAU,GAAG,MAAM,EAAE,MAAM,UAAU,cAAc,EAAE,MAAM,SAAS,CAAC;CACxE,OAAO,MAAM,KAAK,OAAO,UAAU;EACjC,MAAM,WACJ,MAAM,MAAM,QAAQ,CAAC,CAAC,CAAC,MAAM,UAAU,MAAM,MAAM,cAAc,MAAM,MAAM,SAAS,CAAC,EACnF,aAAa;EACnB,MAAM,SAA0B,WAC5B,SAAS,SAAS,MAAM,UAAU,OAChC,cACA,YACF;EACJ,OAAO;GAAE,OAAO,MAAM;GAAO,WAAW,MAAM;GAAW;GAAQ;EAAS;CAC5E,CAAC;AACH;;;;;AAMA,SAAgB,gBACd,SACA,YACA,QACmB;CACnB,MAAM,SAAS,QAAQ;CACvB,IAAI,CAAC,UAAU,CAAC,QACd,OAAO,EAAE,MAAM,UAAU;CAE3B,IAAI,OAAO,MAAM,QAAQ,IAAI,eAAe,UAAU,GACpD,OAAO,EAAE,MAAM,UAAU;CAE3B,MAAM,QAAQ,OAAO,MAAM,QAAQ,IAAI,UAAU,OAAO,UAAU,SAAS,IAAI,eAAe,EAAE;CAChG,OAAO,QACH;EAAE,MAAM;EAAS,IAAI,MAAM;EAAY,OAAO,MAAM;CAAM,IAC1D;EAAE,MAAM;EAAW,UAAU,OAAO;CAAM;AAChD"}
@@ -0,0 +1,12 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { AfterPublishHook } from "../publish/complete.mjs";
4
+ import { CatalogLoader } from "./load.mjs";
5
+ /**
6
+ * Catalogue every build that published successfully, whatever its verdict and with `testing` on or
7
+ * off. A failed publish writes nothing. A build with no readable index is logged and left for the
8
+ * lazy loader, which tries again on first view.
9
+ */
10
+ declare function createCatalogHook(loader: CatalogLoader): AfterPublishHook;
11
+ export { createCatalogHook };
12
+ //# sourceMappingURL=hook.d.mts.map
@@ -0,0 +1,18 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ // src/capture/catalog/hook.ts
5
+ /**
6
+ * Catalogue every build that published successfully, whatever its verdict and with `testing` on or
7
+ * off. A failed publish writes nothing. A build with no readable index is logged and left for the
8
+ * lazy loader, which tries again on first view.
9
+ */
10
+ function createCatalogHook(loader) {
11
+ return async ({ build, project, outcome, logger }) => {
12
+ if (!outcome.ok) return;
13
+ if (!await loader.refresh(project.id, build.id)) logger.warn("published build has no readable Storybook index; no catalog written");
14
+ };
15
+ }
16
+ export { createCatalogHook };
17
+
18
+ //# sourceMappingURL=hook.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook.mjs","names":[],"sources":["../../../src/capture/catalog/hook.ts"],"sourcesContent":["/** The `afterPublish` hook that catalogues a build the moment its publishing succeeds. */\nimport type { AfterPublishHook } from \"../publish/complete.ts\";\nimport type { CatalogLoader } from \"./load.ts\";\n\n/**\n * Catalogue every build that published successfully, whatever its verdict and with `testing` on or\n * off. A failed publish writes nothing. A build with no readable index is logged and left for the\n * lazy loader, which tries again on first view.\n */\nexport function createCatalogHook(loader: CatalogLoader): AfterPublishHook {\n return async ({ build, project, outcome, logger }) => {\n if (!outcome.ok) {\n return;\n }\n const catalog = await loader.refresh(project.id, build.id);\n if (!catalog) {\n logger.warn(\"published build has no readable Storybook index; no catalog written\");\n }\n };\n}\n"],"mappings":";;;;;;;;;AASA,SAAgB,kBAAkB,QAAyC;CACzE,OAAO,OAAO,EAAE,OAAO,SAAS,SAAS,aAAa;EACpD,IAAI,CAAC,QAAQ,IACX;EAGF,IAAI,CAAC,MADiB,OAAO,QAAQ,QAAQ,IAAI,MAAM,EAAE,GAEvD,OAAO,KAAK,qEAAqE;CAErF;AACF"}
@@ -0,0 +1,11 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { Catalog, CatalogComponent, CatalogEntry } from "./types.mjs";
4
+ import { CatalogDeps, catalogueBuild, readCatalog } from "./catalogue.mjs";
5
+ import { CatalogLoader, CatalogLoaderOptions, DEFAULT_CATALOG_CACHE_SIZE, createCatalogLoader } from "./load.mjs";
6
+ import { createCatalogHook } from "./hook.mjs";
7
+ import { EntryChanges, diffEntries, groupComponents, hashEntries, toBuildComponent } from "./components.mjs";
8
+ import { parseStorybookIndex, parseStorybookIndexText } from "./parse.mjs";
9
+ import { readPublishedFile, readPublishedFileInfo } from "./read.mjs";
10
+ import { ComponentBuildRow, ComponentChange, catalogPresence, componentBuildHistory } from "./history.mjs";
11
+ export { type Catalog, type CatalogComponent, type CatalogDeps, type CatalogEntry, type CatalogLoader, type CatalogLoaderOptions, type ComponentBuildRow, type ComponentChange, DEFAULT_CATALOG_CACHE_SIZE, type EntryChanges, catalogPresence, catalogueBuild, componentBuildHistory, createCatalogHook, createCatalogLoader, diffEntries, groupComponents, hashEntries, parseStorybookIndex, parseStorybookIndexText, readCatalog, readPublishedFile, readPublishedFileInfo, toBuildComponent };
@@ -0,0 +1,24 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { Logger } from "../../logger.mjs";
4
+ import { Catalog } from "./types.mjs";
5
+ import { CatalogDeps } from "./catalogue.mjs";
6
+ /** Reads catalogs; one per app, so the cache is shared by every request. */
7
+ interface CatalogLoader {
8
+ /** The build's catalog, or null when it has no catalog and no readable index. */
9
+ load(projectId: string, buildId: string): Promise<Catalog | null>;
10
+ /** Catalogue the build again from its statics (a publish ended) and cache the result. */
11
+ refresh(projectId: string, buildId: string): Promise<Catalog | null>;
12
+ }
13
+ /** Catalogs kept in memory by default. */
14
+ declare const DEFAULT_CATALOG_CACHE_SIZE = 32;
15
+ /** What {@link createCatalogLoader} needs. */
16
+ interface CatalogLoaderOptions extends CatalogDeps {
17
+ /** Catalogs kept in memory (least recently used leave first). */
18
+ cacheSize?: number;
19
+ logger?: Logger;
20
+ }
21
+ /** A loader over `options.db` and `options.storage`. */
22
+ declare function createCatalogLoader(options: CatalogLoaderOptions): CatalogLoader;
23
+ export { CatalogLoader, CatalogLoaderOptions, DEFAULT_CATALOG_CACHE_SIZE, createCatalogLoader };
24
+ //# sourceMappingURL=load.d.mts.map
@@ -0,0 +1,48 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { catalogueBuild, readCatalog } from "./catalogue.mjs";
5
+ // src/capture/catalog/load.ts
6
+ /** Catalogs kept in memory by default. */
7
+ const DEFAULT_CATALOG_CACHE_SIZE = 32;
8
+ /** A loader over `options.db` and `options.storage`. */
9
+ function createCatalogLoader(options) {
10
+ const limit = Math.max(1, options.cacheSize ?? 32);
11
+ const cache = /* @__PURE__ */ new Map();
12
+ const inflight = /* @__PURE__ */ new Map();
13
+ const remember = (buildId, catalog) => {
14
+ cache.delete(buildId);
15
+ cache.set(buildId, catalog);
16
+ const oldest = cache.keys().next().value;
17
+ if (cache.size > limit && oldest !== void 0) cache.delete(oldest);
18
+ return catalog;
19
+ };
20
+ const fetchCatalog = async (projectId, buildId) => {
21
+ const stored = await readCatalog(options.storage, projectId, buildId);
22
+ if (stored) return stored;
23
+ options.logger?.info({ buildId }, "cataloguing a build published before the catalog");
24
+ return await catalogueBuild(options, projectId, buildId);
25
+ };
26
+ return {
27
+ load: async (projectId, buildId) => {
28
+ const hit = cache.get(buildId);
29
+ if (hit) return remember(buildId, hit);
30
+ const pending = inflight.get(buildId) ?? fetchCatalog(projectId, buildId);
31
+ inflight.set(buildId, pending);
32
+ try {
33
+ const catalog = await pending;
34
+ return catalog ? remember(buildId, catalog) : null;
35
+ } finally {
36
+ inflight.delete(buildId);
37
+ }
38
+ },
39
+ refresh: async (projectId, buildId) => {
40
+ cache.delete(buildId);
41
+ const catalog = await catalogueBuild(options, projectId, buildId);
42
+ return catalog ? remember(buildId, catalog) : null;
43
+ }
44
+ };
45
+ }
46
+ export { DEFAULT_CATALOG_CACHE_SIZE, createCatalogLoader };
47
+
48
+ //# sourceMappingURL=load.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load.mjs","names":[],"sources":["../../../src/capture/catalog/load.ts"],"sourcesContent":["/**\n * The catalog loader: a build's catalog from `catalog.json`, kept in a small in-process LRU cache\n * by build id; a build that has none (published before the catalog existed) is catalogued on first\n * view from its persisted statics (ADR 0006, decision 9).\n */\nimport type { Logger } from \"../../logger.ts\";\nimport { catalogueBuild, readCatalog, type CatalogDeps } from \"./catalogue.ts\";\nimport type { Catalog } from \"./types.ts\";\n\n/** Reads catalogs; one per app, so the cache is shared by every request. */\nexport interface CatalogLoader {\n /** The build's catalog, or null when it has no catalog and no readable index. */\n load(projectId: string, buildId: string): Promise<Catalog | null>;\n /** Catalogue the build again from its statics (a publish ended) and cache the result. */\n refresh(projectId: string, buildId: string): Promise<Catalog | null>;\n}\n\n/** Catalogs kept in memory by default. */\nexport const DEFAULT_CATALOG_CACHE_SIZE = 32;\n\n/** What {@link createCatalogLoader} needs. */\nexport interface CatalogLoaderOptions extends CatalogDeps {\n /** Catalogs kept in memory (least recently used leave first). */\n cacheSize?: number;\n logger?: Logger;\n}\n\n/** A loader over `options.db` and `options.storage`. */\nexport function createCatalogLoader(options: CatalogLoaderOptions): CatalogLoader {\n const limit = Math.max(1, options.cacheSize ?? DEFAULT_CATALOG_CACHE_SIZE);\n const cache = new Map<string, Catalog>();\n const inflight = new Map<string, Promise<Catalog | null>>();\n const remember = (buildId: string, catalog: Catalog): Catalog => {\n cache.delete(buildId);\n cache.set(buildId, catalog);\n const oldest = cache.keys().next().value;\n if (cache.size > limit && oldest !== undefined) {\n cache.delete(oldest);\n }\n return catalog;\n };\n const fetchCatalog = async (projectId: string, buildId: string): Promise<Catalog | null> => {\n const stored = await readCatalog(options.storage, projectId, buildId);\n if (stored) {\n return stored;\n }\n options.logger?.info({ buildId }, \"cataloguing a build published before the catalog\");\n return await catalogueBuild(options, projectId, buildId);\n };\n return {\n load: async (projectId, buildId) => {\n const hit = cache.get(buildId);\n if (hit) {\n return remember(buildId, hit);\n }\n const pending = inflight.get(buildId) ?? fetchCatalog(projectId, buildId);\n inflight.set(buildId, pending);\n try {\n const catalog = await pending;\n return catalog ? remember(buildId, catalog) : null;\n } finally {\n inflight.delete(buildId);\n }\n },\n refresh: async (projectId, buildId) => {\n cache.delete(buildId);\n const catalog = await catalogueBuild(options, projectId, buildId);\n return catalog ? remember(buildId, catalog) : null;\n },\n };\n}\n"],"mappings":";;;;;;AAkBA,MAAa,6BAA6B;;AAU1C,SAAgB,oBAAoB,SAA8C;CAChF,MAAM,QAAQ,KAAK,IAAI,GAAG,QAAQ,aAAA,EAAuC;CACzE,MAAM,wBAAQ,IAAI,IAAqB;CACvC,MAAM,2BAAW,IAAI,IAAqC;CAC1D,MAAM,YAAY,SAAiB,YAA8B;EAC/D,MAAM,OAAO,OAAO;EACpB,MAAM,IAAI,SAAS,OAAO;EAC1B,MAAM,SAAS,MAAM,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;EACnC,IAAI,MAAM,OAAO,SAAS,WAAW,KAAA,GACnC,MAAM,OAAO,MAAM;EAErB,OAAO;CACT;CACA,MAAM,eAAe,OAAO,WAAmB,YAA6C;EAC1F,MAAM,SAAS,MAAM,YAAY,QAAQ,SAAS,WAAW,OAAO;EACpE,IAAI,QACF,OAAO;EAET,QAAQ,QAAQ,KAAK,EAAE,QAAQ,GAAG,kDAAkD;EACpF,OAAO,MAAM,eAAe,SAAS,WAAW,OAAO;CACzD;CACA,OAAO;EACL,MAAM,OAAO,WAAW,YAAY;GAClC,MAAM,MAAM,MAAM,IAAI,OAAO;GAC7B,IAAI,KACF,OAAO,SAAS,SAAS,GAAG;GAE9B,MAAM,UAAU,SAAS,IAAI,OAAO,KAAK,aAAa,WAAW,OAAO;GACxE,SAAS,IAAI,SAAS,OAAO;GAC7B,IAAI;IACF,MAAM,UAAU,MAAM;IACtB,OAAO,UAAU,SAAS,SAAS,OAAO,IAAI;GAChD,UAAU;IACR,SAAS,OAAO,OAAO;GACzB;EACF;EACA,SAAS,OAAO,WAAW,YAAY;GACrC,MAAM,OAAO,OAAO;GACpB,MAAM,UAAU,MAAM,eAAe,SAAS,WAAW,OAAO;GAChE,OAAO,UAAU,SAAS,SAAS,OAAO,IAAI;EAChD;CACF;AACF"}