@storyshelf/core 0.7.0 → 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 (531) hide show
  1. package/dist/adapter/capture-queue.d.mts +0 -2
  2. package/dist/adapter/capture-runner.d.mts +9 -4
  3. package/dist/adapter/capture-runner.mjs +6 -2
  4. package/dist/adapter/database.d.mts +63 -3
  5. package/dist/adapter/database.mjs +4 -3
  6. package/dist/adapter/database.mjs.map +1 -1
  7. package/dist/adapter/design.d.mts +0 -2
  8. package/dist/adapter/design.mjs +1 -2
  9. package/dist/adapter/email-sender.d.mts +0 -2
  10. package/dist/adapter/metadata.d.mts +0 -2
  11. package/dist/adapter/oauth.d.mts +0 -2
  12. package/dist/adapter/setup.d.mts +0 -2
  13. package/dist/adapter/setup.mjs +1 -2
  14. package/dist/adapter/storage.d.mts +1 -3
  15. package/dist/adapter/webhook-events.d.mts +0 -2
  16. package/dist/adapter/webhook-events.mjs +12 -13
  17. package/dist/adapter/webhook-events.mjs.map +1 -1
  18. package/dist/adapters/capture-target-offers.d.mts +0 -2
  19. package/dist/adapters/capture-target-offers.mjs +1 -2
  20. package/dist/adapters/capture-target.d.mts +0 -2
  21. package/dist/adapters/capture-target.mjs +1 -2
  22. package/dist/adapters/notifier/build-comment.d.mts +0 -2
  23. package/dist/adapters/notifier/build-comment.mjs +1 -2
  24. package/dist/adapters/notifier/build-state.d.mts +0 -2
  25. package/dist/adapters/notifier/build-state.mjs +1 -2
  26. package/dist/adapters/notifier/events.d.mts +0 -2
  27. package/dist/adapters/notifier/events.mjs +1 -2
  28. package/dist/adapters/notifier/format.d.mts +0 -2
  29. package/dist/adapters/notifier/format.mjs +1 -2
  30. package/dist/adapters/notifier/provider.d.mts +0 -2
  31. package/dist/adapters/notifier/provider.mjs +1 -2
  32. package/dist/adapters/notifier/state.d.mts +0 -2
  33. package/dist/adapters/notifier/state.mjs +1 -2
  34. package/dist/adapters/notifier/types.d.mts +0 -2
  35. package/dist/adapters/remote-browser.d.mts +112 -31
  36. package/dist/adapters/remote-browser.mjs +132 -34
  37. package/dist/adapters/remote-browser.mjs.map +1 -1
  38. package/dist/adapters/remote-lease-attempt.mjs +39 -0
  39. package/dist/adapters/remote-lease-attempt.mjs.map +1 -0
  40. package/dist/adapters/remote-lease-error.d.mts +25 -0
  41. package/dist/adapters/remote-lease-error.mjs +54 -0
  42. package/dist/adapters/remote-lease-error.mjs.map +1 -0
  43. package/dist/adapters/remote-lease-held.d.mts +15 -0
  44. package/dist/adapters/remote-lease-held.mjs +86 -0
  45. package/dist/adapters/remote-lease-held.mjs.map +1 -0
  46. package/dist/adapters/remote-lease-shutdown.d.mts +12 -0
  47. package/dist/adapters/remote-lease-shutdown.mjs +32 -0
  48. package/dist/adapters/remote-lease-shutdown.mjs.map +1 -0
  49. package/dist/adapters/remote-lease.d.mts +39 -0
  50. package/dist/adapters/remote-lease.mjs +175 -0
  51. package/dist/adapters/remote-lease.mjs.map +1 -0
  52. package/dist/adapters/remote-limiter.mjs +121 -0
  53. package/dist/adapters/remote-limiter.mjs.map +1 -0
  54. package/dist/adapters/remote-pool.d.mts +56 -0
  55. package/dist/adapters/remote-pool.mjs +195 -0
  56. package/dist/adapters/remote-pool.mjs.map +1 -0
  57. package/dist/adapters/render-runs.d.mts +0 -2
  58. package/dist/adapters/render-runs.mjs +1 -2
  59. package/dist/adapters/setup-runner.d.mts +0 -2
  60. package/dist/adapters/setup-runner.mjs +1 -2
  61. package/dist/adapters/sources.d.mts +0 -2
  62. package/dist/adapters/sources.mjs +1 -2
  63. package/dist/adapters/validate.d.mts +0 -2
  64. package/dist/adapters/validate.mjs +2 -2
  65. package/dist/adapters/validate.mjs.map +1 -1
  66. package/dist/ai.d.mts +0 -2
  67. package/dist/ai.mjs +1 -2
  68. package/dist/auth.d.mts +0 -2
  69. package/dist/auth.mjs +1 -2
  70. package/dist/brand-packs.d.mts +0 -2
  71. package/dist/brand-packs.mjs +0 -1
  72. package/dist/capture/a11y/axe-source.d.mts +0 -2
  73. package/dist/capture/a11y/axe-source.mjs +1 -2
  74. package/dist/capture/a11y/in-page.d.mts +1 -3
  75. package/dist/capture/a11y/in-page.mjs +3 -4
  76. package/dist/capture/a11y/in-page.mjs.map +1 -1
  77. package/dist/capture/a11y/map.d.mts +0 -2
  78. package/dist/capture/a11y/map.mjs +1 -2
  79. package/dist/capture/a11y/options.d.mts +0 -2
  80. package/dist/capture/a11y/options.mjs +1 -2
  81. package/dist/capture/adapter.d.mts +5 -2
  82. package/dist/capture/adapter.mjs +1 -2
  83. package/dist/capture/adapter.mjs.map +1 -1
  84. package/dist/capture/affected.d.mts +0 -2
  85. package/dist/capture/affected.mjs +1 -2
  86. package/dist/capture/attempt-logger.mjs +1 -2
  87. package/dist/capture/browsers.d.mts +0 -2
  88. package/dist/capture/browsers.mjs +1 -2
  89. package/dist/capture/build-state/deliver.d.mts +0 -2
  90. package/dist/capture/build-state/deliver.mjs +1 -2
  91. package/dist/capture/build-state/notify-job.d.mts +0 -2
  92. package/dist/capture/build-state/notify-job.mjs +1 -2
  93. package/dist/capture/build-state/publisher.d.mts +0 -2
  94. package/dist/capture/build-state/publisher.mjs +1 -2
  95. package/dist/capture/build-state/resume.d.mts +0 -2
  96. package/dist/capture/build-state/resume.mjs +1 -2
  97. package/dist/capture/build-state/types.d.mts +1 -3
  98. package/dist/capture/catalog/catalogue.d.mts +0 -2
  99. package/dist/capture/catalog/catalogue.mjs +1 -2
  100. package/dist/capture/catalog/components.d.mts +0 -2
  101. package/dist/capture/catalog/components.mjs +1 -2
  102. package/dist/capture/catalog/history.d.mts +0 -2
  103. package/dist/capture/catalog/history.mjs +1 -2
  104. package/dist/capture/catalog/hook.d.mts +0 -2
  105. package/dist/capture/catalog/hook.mjs +1 -2
  106. package/dist/capture/catalog/index.d.mts +2 -2
  107. package/dist/capture/catalog/load.d.mts +0 -2
  108. package/dist/capture/catalog/load.mjs +1 -2
  109. package/dist/capture/catalog/parse.d.mts +0 -2
  110. package/dist/capture/catalog/parse.mjs +1 -2
  111. package/dist/capture/catalog/read.d.mts +6 -3
  112. package/dist/capture/catalog/read.mjs +14 -8
  113. package/dist/capture/catalog/read.mjs.map +1 -1
  114. package/dist/capture/catalog/types.d.mts +0 -2
  115. package/dist/capture/comparison-reference.d.mts +27 -0
  116. package/dist/capture/comparison-reference.mjs +75 -0
  117. package/dist/capture/comparison-reference.mjs.map +1 -0
  118. package/dist/capture/consumer/capture-handler.d.mts +1 -3
  119. package/dist/capture/consumer/capture-handler.mjs +1 -2
  120. package/dist/capture/consumer/idle.d.mts +0 -2
  121. package/dist/capture/consumer/idle.mjs +1 -2
  122. package/dist/capture/consumer/index.d.mts +0 -2
  123. package/dist/capture/consumer/index.mjs +1 -2
  124. package/dist/capture/consumer/loop.mjs +1 -2
  125. package/dist/capture/consumer/metrics.d.mts +0 -2
  126. package/dist/capture/consumer/metrics.mjs +1 -2
  127. package/dist/capture/consumer/retry.d.mts +0 -2
  128. package/dist/capture/consumer/retry.mjs +1 -2
  129. package/dist/capture/consumer/run-job.mjs +1 -2
  130. package/dist/capture/consumer/startup.mjs +1 -2
  131. package/dist/capture/consumer/types.d.mts +0 -2
  132. package/dist/capture/crash-failure.d.mts +0 -2
  133. package/dist/capture/crash-failure.mjs +1 -2
  134. package/dist/capture/db-queue/cadence.d.mts +0 -2
  135. package/dist/capture/db-queue/cadence.mjs +1 -2
  136. package/dist/capture/db-queue/claim.d.mts +0 -2
  137. package/dist/capture/db-queue/claim.mjs +20 -4
  138. package/dist/capture/db-queue/claim.mjs.map +1 -1
  139. package/dist/capture/db-queue/clock.mjs +1 -2
  140. package/dist/capture/db-queue/codec.mjs +1 -2
  141. package/dist/capture/db-queue/index.d.mts +0 -2
  142. package/dist/capture/db-queue/index.mjs +3 -3
  143. package/dist/capture/db-queue/index.mjs.map +1 -1
  144. package/dist/capture/db-queue/keeper.d.mts +0 -2
  145. package/dist/capture/db-queue/keeper.mjs +1 -2
  146. package/dist/capture/db-queue/lease.mjs +1 -2
  147. package/dist/capture/db-queue/lifecycle.mjs +1 -2
  148. package/dist/capture/db-queue/operations.mjs +1 -2
  149. package/dist/capture/db-queue/poll-loop.d.mts +0 -2
  150. package/dist/capture/db-queue/poll-loop.mjs +1 -2
  151. package/dist/capture/db-queue/poll.d.mts +0 -2
  152. package/dist/capture/db-queue/poll.mjs +1 -2
  153. package/dist/capture/db-queue/timers.d.mts +0 -2
  154. package/dist/capture/db-queue/timers.mjs +1 -2
  155. package/dist/capture/db-queue/types.d.mts +0 -2
  156. package/dist/capture/db-queue/types.mjs +1 -2
  157. package/dist/capture/db-queue/types.mjs.map +1 -1
  158. package/dist/capture/db-queue/wake.mjs +1 -2
  159. package/dist/capture/design.mjs +1 -2
  160. package/dist/capture/diff-record.mjs +1 -2
  161. package/dist/capture/dispatch.d.mts +1 -3
  162. package/dist/capture/dispatch.mjs +17 -5
  163. package/dist/capture/dispatch.mjs.map +1 -1
  164. package/dist/capture/enrich.mjs +1 -2
  165. package/dist/capture/failure-sets.mjs +1 -2
  166. package/dist/capture/fingerprint.d.mts +0 -2
  167. package/dist/capture/fingerprint.mjs +1 -2
  168. package/dist/capture/forked/channel.d.mts +0 -2
  169. package/dist/capture/forked/child.d.mts +0 -2
  170. package/dist/capture/forked/child.mjs +1 -2
  171. package/dist/capture/forked/crash-tracker.mjs +1 -2
  172. package/dist/capture/forked/decision.d.mts +0 -2
  173. package/dist/capture/forked/decision.mjs +1 -2
  174. package/dist/capture/forked/exit.mjs +1 -2
  175. package/dist/capture/forked/fork.d.mts +0 -2
  176. package/dist/capture/forked/fork.mjs +1 -2
  177. package/dist/capture/forked/forked-capture.d.mts +0 -2
  178. package/dist/capture/forked/forked-capture.mjs +1 -2
  179. package/dist/capture/forked/lease-book.mjs +1 -2
  180. package/dist/capture/forked/protocol.d.mts +0 -2
  181. package/dist/capture/forked/protocol.mjs +1 -2
  182. package/dist/capture/forked/runs.mjs +1 -2
  183. package/dist/capture/guards.mjs +1 -2
  184. package/dist/capture/ignore-regions.d.mts +36 -0
  185. package/dist/capture/ignore-regions.mjs +65 -0
  186. package/dist/capture/ignore-regions.mjs.map +1 -0
  187. package/dist/capture/isolate.mjs +1 -2
  188. package/dist/capture/job-lease.d.mts +0 -2
  189. package/dist/capture/job-lease.mjs +1 -2
  190. package/dist/capture/matrix.mjs +4 -4
  191. package/dist/capture/matrix.mjs.map +1 -1
  192. package/dist/capture/modes.d.mts +0 -2
  193. package/dist/capture/modes.mjs +2 -3
  194. package/dist/capture/modes.mjs.map +1 -1
  195. package/dist/capture/orchestrator.d.mts +0 -2
  196. package/dist/capture/orchestrator.mjs +2 -3
  197. package/dist/capture/pipeline.d.mts +0 -2
  198. package/dist/capture/pipeline.mjs +37 -6
  199. package/dist/capture/pipeline.mjs.map +1 -1
  200. package/dist/capture/progress.d.mts +0 -2
  201. package/dist/capture/progress.mjs +1 -2
  202. package/dist/capture/publish/accept.d.mts +0 -2
  203. package/dist/capture/publish/accept.mjs +1 -2
  204. package/dist/capture/publish/complete.d.mts +1 -3
  205. package/dist/capture/publish/complete.mjs +1 -2
  206. package/dist/capture/publish/extract.d.mts +0 -2
  207. package/dist/capture/publish/extract.mjs +6 -5
  208. package/dist/capture/publish/extract.mjs.map +1 -1
  209. package/dist/capture/publish/handler.d.mts +1 -3
  210. package/dist/capture/publish/handler.mjs +1 -2
  211. package/dist/capture/publish/index.d.mts +2 -1
  212. package/dist/capture/publish/invalid-zip.d.mts +8 -0
  213. package/dist/capture/publish/invalid-zip.mjs +11 -0
  214. package/dist/capture/publish/invalid-zip.mjs.map +1 -0
  215. package/dist/capture/publish/limits.d.mts +0 -2
  216. package/dist/capture/publish/limits.mjs +1 -2
  217. package/dist/capture/publish/published.d.mts +0 -2
  218. package/dist/capture/publish/published.mjs +1 -2
  219. package/dist/capture/publish/run.d.mts +1 -3
  220. package/dist/capture/publish/run.mjs +1 -2
  221. package/dist/capture/rediff.d.mts +1 -3
  222. package/dist/capture/rediff.mjs +19 -6
  223. package/dist/capture/rediff.mjs.map +1 -1
  224. package/dist/capture/render.mjs +1 -2
  225. package/dist/capture/render.mjs.map +1 -1
  226. package/dist/capture/scratch.d.mts +0 -2
  227. package/dist/capture/scratch.mjs +2 -4
  228. package/dist/capture/scratch.mjs.map +1 -1
  229. package/dist/capture/shard-plan.mjs +1 -2
  230. package/dist/capture/shards/context.mjs +3 -3
  231. package/dist/capture/shards/context.mjs.map +1 -1
  232. package/dist/capture/shards/execute.mjs +4 -3
  233. package/dist/capture/shards/execute.mjs.map +1 -1
  234. package/dist/capture/shards/fan-out.mjs +1 -2
  235. package/dist/capture/shards/history.mjs +1 -2
  236. package/dist/capture/shards/reduce.mjs +1 -2
  237. package/dist/capture/sizing.d.mts +0 -2
  238. package/dist/capture/sizing.mjs +1 -2
  239. package/dist/capture/skip-checks.mjs +1 -2
  240. package/dist/capture/statics.d.mts +0 -2
  241. package/dist/capture/statics.mjs +2 -4
  242. package/dist/capture/statics.mjs.map +1 -1
  243. package/dist/capture/storybook-urls.d.mts +0 -2
  244. package/dist/capture/storybook-urls.mjs +3 -3
  245. package/dist/capture/storybook-urls.mjs.map +1 -1
  246. package/dist/capture/storybook.d.mts +0 -2
  247. package/dist/capture/storybook.mjs +8 -4
  248. package/dist/capture/storybook.mjs.map +1 -1
  249. package/dist/capture/target.mjs +1 -2
  250. package/dist/capture/targets.d.mts +0 -2
  251. package/dist/capture/targets.mjs +1 -2
  252. package/dist/capture/tests.d.mts +0 -2
  253. package/dist/capture/tests.mjs +13 -3
  254. package/dist/capture/tests.mjs.map +1 -1
  255. package/dist/capture/token-chunks.mjs +24 -7
  256. package/dist/capture/token-chunks.mjs.map +1 -1
  257. package/dist/capture.d.mts +5 -2
  258. package/dist/capture.mjs +5 -2
  259. package/dist/config.d.mts +16 -3
  260. package/dist/config.mjs +6 -3
  261. package/dist/config.mjs.map +1 -1
  262. package/dist/diff.d.mts +0 -2
  263. package/dist/diff.mjs +1 -2
  264. package/dist/index.d.mts +2 -2
  265. package/dist/index.mjs +2 -2
  266. package/dist/insights/budget.d.mts +0 -2
  267. package/dist/insights/budget.mjs +1 -2
  268. package/dist/insights/envelope.d.mts +0 -2
  269. package/dist/insights/envelope.mjs +1 -2
  270. package/dist/insights/evidence-health.d.mts +0 -2
  271. package/dist/insights/evidence-health.mjs +1 -2
  272. package/dist/insights/evidence.d.mts +0 -2
  273. package/dist/insights/evidence.mjs +1 -2
  274. package/dist/insights/hash.d.mts +0 -2
  275. package/dist/insights/hash.mjs +1 -2
  276. package/dist/insights/limits.d.mts +0 -2
  277. package/dist/insights/limits.mjs +1 -2
  278. package/dist/insights/prompts/v1.d.mts +0 -2
  279. package/dist/insights/prompts/v1.mjs +1 -2
  280. package/dist/insights/redact.d.mts +0 -2
  281. package/dist/insights/redact.mjs +1 -2
  282. package/dist/insights/text.mjs +1 -2
  283. package/dist/logger.d.mts +0 -2
  284. package/dist/logger.mjs +1 -2
  285. package/dist/models/ai-budget-alert.d.mts +0 -2
  286. package/dist/models/ai-budget-alert.mjs +1 -2
  287. package/dist/models/ai-usage.d.mts +0 -2
  288. package/dist/models/ai-usage.mjs +1 -2
  289. package/dist/models/baseline-approval.d.mts +18 -0
  290. package/dist/models/baseline-approval.mjs +41 -0
  291. package/dist/models/baseline-approval.mjs.map +1 -0
  292. package/dist/models/baseline-archive.d.mts +0 -2
  293. package/dist/models/baseline-archive.mjs +1 -2
  294. package/dist/models/baseline-atomic.mjs +66 -0
  295. package/dist/models/baseline-atomic.mjs.map +1 -0
  296. package/dist/models/baseline-conflict.d.mts +6 -0
  297. package/dist/models/baseline-conflict.mjs +9 -0
  298. package/dist/models/baseline-conflict.mjs.map +1 -0
  299. package/dist/models/baseline-export.d.mts +0 -2
  300. package/dist/models/baseline-export.mjs +1 -2
  301. package/dist/models/baseline-import.mjs +1 -2
  302. package/dist/models/baseline-origin.d.mts +16 -0
  303. package/dist/models/baseline-origin.mjs +35 -0
  304. package/dist/models/baseline-origin.mjs.map +1 -0
  305. package/dist/models/baseline-status.d.mts +0 -2
  306. package/dist/models/baseline-status.mjs +1 -2
  307. package/dist/models/baseline-transfer.d.mts +1 -2
  308. package/dist/models/baseline-transfer.mjs +30 -2
  309. package/dist/models/baseline-transfer.mjs.map +1 -1
  310. package/dist/models/baseline.d.mts +5 -2
  311. package/dist/models/baseline.mjs +91 -12
  312. package/dist/models/baseline.mjs.map +1 -1
  313. package/dist/models/build-component.d.mts +0 -2
  314. package/dist/models/build-component.mjs +1 -2
  315. package/dist/models/build-review-status.d.mts +0 -2
  316. package/dist/models/build-review-status.mjs +1 -2
  317. package/dist/models/build-review.d.mts +0 -2
  318. package/dist/models/build-review.mjs +1 -2
  319. package/dist/models/build.d.mts +1 -3
  320. package/dist/models/build.mjs +14 -15
  321. package/dist/models/build.mjs.map +1 -1
  322. package/dist/models/capture-attempt.d.mts +0 -2
  323. package/dist/models/capture-attempt.mjs +1 -2
  324. package/dist/models/capture-job.d.mts +0 -2
  325. package/dist/models/capture-job.mjs +1 -2
  326. package/dist/models/capture-log.d.mts +0 -2
  327. package/dist/models/capture-log.mjs +1 -2
  328. package/dist/models/capture-shard.d.mts +0 -2
  329. package/dist/models/capture-shard.mjs +1 -2
  330. package/dist/models/changeset.d.mts +0 -2
  331. package/dist/models/changeset.mjs +1 -2
  332. package/dist/models/columns.mjs +1 -2
  333. package/dist/models/comment.d.mts +0 -2
  334. package/dist/models/comment.mjs +1 -2
  335. package/dist/models/component.d.mts +0 -2
  336. package/dist/models/component.mjs +1 -2
  337. package/dist/models/connections.d.mts +0 -2
  338. package/dist/models/connections.mjs +1 -2
  339. package/dist/models/content-ref.d.mts +0 -2
  340. package/dist/models/content-ref.mjs +1 -2
  341. package/dist/models/credentials.d.mts +0 -2
  342. package/dist/models/credentials.mjs +1 -2
  343. package/dist/models/design-credentials.d.mts +0 -2
  344. package/dist/models/design-credentials.mjs +1 -2
  345. package/dist/models/design-health.d.mts +0 -2
  346. package/dist/models/design-health.mjs +1 -2
  347. package/dist/models/design-nodes.d.mts +2 -4
  348. package/dist/models/design-nodes.mjs +1 -2
  349. package/dist/models/design-renders.mjs +1 -2
  350. package/dist/models/design-resolve.d.mts +0 -2
  351. package/dist/models/design-resolve.mjs +1 -2
  352. package/dist/models/design.d.mts +0 -2
  353. package/dist/models/design.mjs +1 -2
  354. package/dist/models/inherited-ratio.d.mts +0 -2
  355. package/dist/models/inherited-ratio.mjs +1 -2
  356. package/dist/models/insight.d.mts +0 -2
  357. package/dist/models/insight.mjs +1 -2
  358. package/dist/models/label.d.mts +0 -2
  359. package/dist/models/label.mjs +1 -2
  360. package/dist/models/member.d.mts +0 -2
  361. package/dist/models/member.mjs +1 -2
  362. package/dist/models/notification-channel.d.mts +0 -2
  363. package/dist/models/notification-channel.mjs +1 -2
  364. package/dist/models/notification-subscription.d.mts +0 -2
  365. package/dist/models/notification-subscription.mjs +1 -2
  366. package/dist/models/project-group-mapping.d.mts +0 -2
  367. package/dist/models/project-group-mapping.mjs +1 -2
  368. package/dist/models/project.d.mts +0 -2
  369. package/dist/models/project.mjs +1 -2
  370. package/dist/models/public-origin.d.mts +0 -2
  371. package/dist/models/public-origin.mjs +1 -2
  372. package/dist/models/review-switch-off.d.mts +0 -2
  373. package/dist/models/review-switch-off.mjs +1 -2
  374. package/dist/models/site-settings.d.mts +0 -2
  375. package/dist/models/site-settings.mjs +1 -2
  376. package/dist/models/snapshot.d.mts +3 -2
  377. package/dist/models/snapshot.mjs +4 -2
  378. package/dist/models/snapshot.mjs.map +1 -1
  379. package/dist/models/token.d.mts +0 -2
  380. package/dist/models/token.mjs +1 -2
  381. package/dist/models/usage.d.mts +0 -2
  382. package/dist/models/usage.mjs +1 -2
  383. package/dist/models/user.d.mts +0 -2
  384. package/dist/models/user.mjs +1 -2
  385. package/dist/models/webhook.d.mts +0 -2
  386. package/dist/models/webhook.mjs +1 -2
  387. package/dist/models.d.mts +5 -2
  388. package/dist/models.mjs +5 -2
  389. package/dist/options.d.mts +0 -2
  390. package/dist/options.mjs +2 -4
  391. package/dist/options.mjs.map +1 -1
  392. package/dist/paths.d.mts +3 -3
  393. package/dist/paths.mjs +7 -3
  394. package/dist/paths.mjs.map +1 -1
  395. package/dist/retention/ai.d.mts +1 -3
  396. package/dist/retention/ai.mjs +0 -1
  397. package/dist/retention/pending.mjs +1 -2
  398. package/dist/retention/published-gzip-sweep.mjs +28 -0
  399. package/dist/retention/published-gzip-sweep.mjs.map +1 -0
  400. package/dist/retention/screenshot-sweep.d.mts +0 -2
  401. package/dist/retention/screenshot-sweep.mjs +1 -2
  402. package/dist/retention.d.mts +0 -2
  403. package/dist/retention.mjs +5 -2
  404. package/dist/retention.mjs.map +1 -1
  405. package/dist/schema/baseline.d.mts +2 -2
  406. package/dist/schema/build-component.d.mts +0 -2
  407. package/dist/schema/build-review.d.mts +0 -2
  408. package/dist/schema/build.d.mts +0 -2
  409. package/dist/schema/capture-attempt.d.mts +0 -2
  410. package/dist/schema/capture-job.d.mts +0 -2
  411. package/dist/schema/capture-shard.d.mts +0 -2
  412. package/dist/schema/comment.d.mts +0 -2
  413. package/dist/schema/connection.d.mts +0 -2
  414. package/dist/schema/content-ref.d.mts +0 -2
  415. package/dist/schema/design.d.mts +0 -2
  416. package/dist/schema/insight.d.mts +0 -2
  417. package/dist/schema/label.d.mts +0 -2
  418. package/dist/schema/member.d.mts +0 -2
  419. package/dist/schema/notification.d.mts +0 -2
  420. package/dist/schema/project-group-mapping.d.mts +0 -2
  421. package/dist/schema/project.d.mts +0 -2
  422. package/dist/schema/site-setting.d.mts +0 -2
  423. package/dist/schema/snapshot.d.mts +5 -2
  424. package/dist/schema/token.d.mts +0 -2
  425. package/dist/schema/usage.d.mts +0 -2
  426. package/dist/schema/user.d.mts +0 -2
  427. package/dist/schema/webhook.d.mts +0 -2
  428. package/dist/schema.d.mts +4 -6
  429. package/dist/serverless.d.mts +0 -2
  430. package/dist/serverless.mjs +1 -2
  431. package/dist/test-helpers/build-reference-contract.d.mts +14 -0
  432. package/dist/test-helpers/build-reference-contract.mjs +66 -0
  433. package/dist/test-helpers/build-reference-contract.mjs.map +1 -0
  434. package/dist/test-helpers/create-project.d.mts +0 -2
  435. package/dist/test-helpers/create-project.mjs +1 -2
  436. package/dist/test-helpers/database-contract.d.mts +0 -2
  437. package/dist/test-helpers/database-contract.mjs +37 -2
  438. package/dist/test-helpers/database-contract.mjs.map +1 -1
  439. package/dist/test-helpers/deferred.d.mts +0 -2
  440. package/dist/test-helpers/deferred.mjs +1 -2
  441. package/dist/test-helpers/design-contract.d.mts +0 -2
  442. package/dist/test-helpers/design-contract.mjs +1 -2
  443. package/dist/test-helpers/fake-adapters.d.mts +0 -2
  444. package/dist/test-helpers/fake-adapters.mjs +1 -2
  445. package/dist/test-helpers/fake-database.d.mts +0 -2
  446. package/dist/test-helpers/fake-database.mjs +7 -2
  447. package/dist/test-helpers/fake-database.mjs.map +1 -1
  448. package/dist/test-helpers/fake-design.d.mts +0 -2
  449. package/dist/test-helpers/fake-design.mjs +1 -2
  450. package/dist/test-helpers/fake-notifier.d.mts +0 -2
  451. package/dist/test-helpers/fake-notifier.mjs +1 -2
  452. package/dist/test-helpers/fake-storage.d.mts +0 -2
  453. package/dist/test-helpers/fake-storage.mjs +1 -2
  454. package/dist/test-helpers/fake-tables.mjs +5 -2
  455. package/dist/test-helpers/fake-tables.mjs.map +1 -1
  456. package/dist/test-helpers/manual-clock.d.mts +0 -2
  457. package/dist/test-helpers/manual-clock.mjs +1 -2
  458. package/dist/test-helpers/notifier-contract.d.mts +0 -2
  459. package/dist/test-helpers/notifier-contract.mjs +1 -2
  460. package/dist/test-helpers/queue-contract.d.mts +0 -2
  461. package/dist/test-helpers/queue-contract.mjs +1 -2
  462. package/dist/test-helpers/queue-multi-instance.d.mts +0 -2
  463. package/dist/test-helpers/queue-multi-instance.mjs +1 -2
  464. package/dist/test-helpers/runner-contract.d.mts +0 -2
  465. package/dist/test-helpers/runner-contract.mjs +1 -2
  466. package/dist/test-helpers/sql-chunks.mjs +2 -2
  467. package/dist/test-helpers/sql-chunks.mjs.map +1 -1
  468. package/dist/test-helpers/storage-contract.d.mts +0 -2
  469. package/dist/test-helpers/storage-contract.mjs +1 -2
  470. package/dist/test-helpers.d.mts +2 -1
  471. package/dist/test-helpers.mjs +2 -1
  472. package/dist/tracing.mjs +36 -6
  473. package/dist/tracing.mjs.map +1 -1
  474. package/dist/types.d.mts +0 -2
  475. package/dist/types.mjs +1 -2
  476. package/dist/urls.d.mts +0 -2
  477. package/dist/urls.mjs +1 -2
  478. package/dist/utils/adaptive-concurrency.d.mts +0 -2
  479. package/dist/utils/adaptive-concurrency.mjs +1 -2
  480. package/dist/utils/connect-retry.d.mts +2 -2
  481. package/dist/utils/connect-retry.mjs +2 -3
  482. package/dist/utils/connect-retry.mjs.map +1 -1
  483. package/dist/utils/encrypt.d.mts +0 -2
  484. package/dist/utils/encrypt.mjs +1 -2
  485. package/dist/utils/environment.d.mts +0 -2
  486. package/dist/utils/environment.mjs +1 -2
  487. package/dist/utils/hash.d.mts +0 -2
  488. package/dist/utils/hash.mjs +1 -2
  489. package/dist/utils/http.d.mts +13 -3
  490. package/dist/utils/http.mjs +79 -17
  491. package/dist/utils/http.mjs.map +1 -1
  492. package/dist/utils/map-adaptive.d.mts +0 -2
  493. package/dist/utils/map-adaptive.mjs +1 -2
  494. package/dist/utils/map-limit.d.mts +0 -2
  495. package/dist/utils/map-limit.mjs +1 -2
  496. package/dist/utils/mime.d.mts +0 -2
  497. package/dist/utils/mime.mjs +1 -2
  498. package/dist/utils/page-limiter.d.mts +0 -2
  499. package/dist/utils/page-limiter.mjs +1 -2
  500. package/dist/utils/path-security.d.mts +0 -2
  501. package/dist/utils/path-security.mjs +2 -4
  502. package/dist/utils/path-security.mjs.map +1 -1
  503. package/dist/utils/public-origin.d.mts +0 -2
  504. package/dist/utils/public-origin.mjs +1 -2
  505. package/dist/utils/redact.d.mts +0 -2
  506. package/dist/utils/redact.mjs +1 -2
  507. package/dist/utils/remote-environment.d.mts +40 -3
  508. package/dist/utils/remote-environment.mjs +52 -3
  509. package/dist/utils/remote-environment.mjs.map +1 -1
  510. package/dist/utils/resources.d.mts +0 -2
  511. package/dist/utils/resources.mjs +1 -2
  512. package/dist/utils/screenshot-store.d.mts +0 -2
  513. package/dist/utils/screenshot-store.mjs +1 -2
  514. package/dist/utils/session-gate.d.mts +7 -6
  515. package/dist/utils/session-gate.mjs +28 -12
  516. package/dist/utils/session-gate.mjs.map +1 -1
  517. package/dist/utils/storybook-token.d.mts +11 -3
  518. package/dist/utils/storybook-token.mjs +10 -9
  519. package/dist/utils/storybook-token.mjs.map +1 -1
  520. package/dist/utils/storybook-url.d.mts +0 -2
  521. package/dist/utils/storybook-url.mjs +1 -2
  522. package/dist/utils/timing.d.mts +0 -2
  523. package/dist/utils/timing.mjs +1 -2
  524. package/dist/utils/ulid.d.mts +0 -2
  525. package/dist/utils/ulid.mjs +1 -2
  526. package/dist/utils/zip-read.mjs +1 -2
  527. package/dist/utils/zip-write.d.mts +0 -2
  528. package/dist/utils/zip-write.mjs +1 -2
  529. package/dist/utils.d.mts +5 -5
  530. package/dist/utils.mjs +5 -5
  531. package/package.json +6 -6
@@ -1 +1 @@
1
- {"version":3,"file":"config.mjs","names":[],"sources":["../src/config.ts"],"sourcesContent":["import type { Logger } from \"pino\";\nimport { z } from \"zod\";\nimport type { CaptureRunner } from \"./adapters/capture-runner.ts\";\nimport type { DatabaseAdapter } from \"./adapters/database.ts\";\nimport type { DesignProvider } from \"./adapters/design.ts\";\nimport type { EmailSender } from \"./adapters/email-sender.ts\";\nimport type { AdapterCategory } from \"./adapters/metadata.ts\";\nimport type { NotifierProvider } from \"./adapters/notifier/provider.ts\";\nimport type { StorageAdapter } from \"./adapters/storage.ts\";\nimport type { Ai } from \"./ai.ts\";\nimport type { Auth } from \"./auth.ts\";\n\n/** Brand color theme for the server-rendered UI. */\nexport interface BrandTheme {\n accent: string;\n accentContrast?: string;\n ring?: string;\n surface: { base: string; card: string; muted?: string; subtle?: string };\n text: { primary: string; secondary: string; muted?: string };\n border: string;\n borderSubtle?: string;\n status: { approved: string; new: string; rejected: string };\n sidebarBg?: string;\n topbarBg?: string;\n radius?: string;\n radiusSm?: string;\n shadow?: string;\n}\n\n/** Text overrides for the auth (login) UI. */\nexport interface AuthUiConfig {\n /** Page title, default \"Sign in\". */\n title?: string;\n /** Optional subtitle under the title. */\n subtitle?: string;\n /** Password field label, default \"Password\". */\n passwordLabel?: string;\n /** Password field placeholder. */\n passwordPlaceholder?: string;\n /** Submit button label, default \"Sign in\". */\n submitLabel?: string;\n /**\n * Template for SSO buttons, default \"Sign in with {label}\".\n * Must contain \"{label}\" which is replaced with the provider label.\n */\n ssoLabelTemplate?: string;\n /** Help text shown under the form. */\n helpText?: string;\n /** Footer text shown at the bottom of the card. */\n footerText?: string;\n}\n\n/** Branding overrides for the server-rendered UI. */\nexport interface UIConfig {\n name?: string;\n logo?: string;\n /**\n * @deprecated Ignored. The favicon is the product's own mark, served by the\n * app itself; set `logo` to rebrand the sidebar instead.\n */\n favicon?: string;\n lightTheme?: BrandTheme;\n darkTheme?: BrandTheme;\n auth?: AuthUiConfig;\n}\n\n/** Default cap for a single Storybook zip upload (1 GiB). */\nexport const DEFAULT_MAX_UPLOAD_BYTES = 1024 * 1024 * 1024;\n\n/** A viewport in which stories are captured. */\nexport interface ShelfViewport {\n name: string;\n width: number;\n height: number;\n}\n\n/** Metadata snapshot of a configured adapter. */\nexport interface AdapterSnapshot {\n name: string;\n version: string;\n description?: string;\n kind: string;\n category: AdapterCategory;\n}\n\n/** Site-wide notification defaults (brand + sender identity for admin alerts). */\nexport interface NotificationsConfig {\n fromEmail?: string;\n fromName?: string;\n footerText?: string;\n slackUsername?: string;\n}\n/** Shelf-level configuration (validated by {@link shelfConfigSchema}). */\nexport interface ShelfConfig {\n secret?: string;\n /**\n * The secret `secret` replaced. Used only to decrypt stored credentials\n * (webhook, git-token, and notification secrets) written before a rotation;\n * new writes always use `secret`. Remove once credentials are re-encrypted.\n */\n previousSecret?: string;\n /**\n * Re-encrypt credentials still under `previousSecret` at boot. Default false:\n * site admins can run it from the System page instead. No effect without\n * `previousSecret`.\n */\n migrateCredentialsOnBoot?: boolean;\n /**\n * Bootstrap site-admin bearer token (`STORYSHELF_ADMIN_TOKEN`/`ADMIN_TOKEN`).\n * Grants site-admin API access when no admin user exists yet; never\n * mint sessions from it. Distinct from `secret` (session signing).\n */\n adminToken?: string;\n publishedBaseDomain?: string;\n /**\n * Public base URL of this deployment (e.g. `https://shelf.example.com`).\n * Used as the issuer in the `/.well-known/openid-configuration` relying-party\n * helper document; falls back to the request origin when unset.\n */\n publicBaseUrl?: string;\n /**\n * Working directory for capture and inline statics extraction. Defaults to\n * `<os.tmpdir()>/storyshelf`; publishing and capture extract there.\n */\n scratchDir?: string;\n purgeTtlDays?: number;\n /** Branch baseline TTL, days; null disables branch GC (default 30). */\n branchTtlDays?: number | null;\n /** Branch GC interval, ms; daily sweep via interval clock (default 86_400_000). */\n branchGcIntervalMs?: number;\n maxUploadBytes?: number;\n /**\n * Emit `Server-Timing` response headers (total + db/storage roll-ups).\n * Opt-in, off by default — some deployments prefer no timing headers.\n */\n serverTiming?: boolean;\n /**\n * Largest zip (bytes) extracted inline in the upload request; a larger zip is published by a\n * `publish` job (or refused with 413 on a host that runs no consumer). The count is taken\n * while the upload streams, never from `Content-Length`. Default 50 MB; `0` sends every zip to\n * a `publish` job.\n */\n maxInlineUnzipSize?: number;\n /** Most entries an uploaded Storybook zip may hold (default 50 000); more fails the publish. */\n maxZipEntries?: number;\n /**\n * Most uncompressed bytes an uploaded Storybook zip may expand to (default 2 GiB), counted while\n * extracting; more fails the publish. The compressed size is no bound on its own.\n */\n maxUnzippedBytes?: number;\n viewports?: ShelfViewport[];\n adapters?: Record<string, AdapterSnapshot>;\n}\n\nconst viewportSchema: z.ZodType<ShelfViewport> = z.object({\n name: z.string().min(1),\n width: z.number().int().positive(),\n height: z.number().int().positive(),\n});\n\nconst brandThemeSchema: z.ZodType<BrandTheme> = z.object({\n accent: z.string(),\n accentContrast: z.string().optional(),\n ring: z.string().optional(),\n surface: z.object({\n base: z.string(),\n card: z.string(),\n muted: z.string().optional(),\n subtle: z.string().optional(),\n }),\n text: z.object({ primary: z.string(), secondary: z.string(), muted: z.string().optional() }),\n border: z.string(),\n borderSubtle: z.string().optional(),\n status: z.object({ approved: z.string(), new: z.string(), rejected: z.string() }),\n sidebarBg: z.string().optional(),\n topbarBg: z.string().optional(),\n radius: z.string().optional(),\n radiusSm: z.string().optional(),\n shadow: z.string().optional(),\n});\n\nconst adapterSnapshotSchema: z.ZodType<AdapterSnapshot> = z.object({\n name: z.string(),\n version: z.string(),\n description: z.string().optional(),\n kind: z.string(),\n category: z.enum([\n \"database\",\n \"storage\",\n \"capture-runner\",\n \"capture-queue\",\n \"design\",\n \"notifier\",\n ]),\n});\n\nconst authUiConfigSchema: z.ZodType<AuthUiConfig> = z.object({\n title: z.string().min(1).optional(),\n subtitle: z.string().optional(),\n passwordLabel: z.string().min(1).optional(),\n passwordPlaceholder: z.string().optional(),\n submitLabel: z.string().min(1).optional(),\n ssoLabelTemplate: z.string().min(1).optional(),\n helpText: z.string().optional(),\n footerText: z.string().optional(),\n});\n\n/** Zod schema validating `notifications.config`. */\nexport const notificationsConfigSchema: z.ZodType<NotificationsConfig> = z.object({\n fromEmail: z.string().min(1).optional(),\n fromName: z.string().min(1).optional(),\n footerText: z.string().min(1).optional(),\n slackUsername: z.string().min(1).optional(),\n});\n\n/** Zod schema validating the shelf-level configuration. */\nexport const shelfConfigSchema: z.ZodType<ShelfConfig> = z\n .object({\n secret: z.string().min(1).optional(),\n previousSecret: z.string().min(1).optional(),\n migrateCredentialsOnBoot: z.boolean().optional(),\n adminToken: z.string().min(1).optional(),\n publishedBaseDomain: z.string().optional(),\n // oxlint-disable-next-line typescript/no-deprecated -- z.string().url() kept for zod v3 API compat\n publicBaseUrl: z.string().url().optional(),\n scratchDir: z.string().optional(),\n purgeTtlDays: z.number().int().positive().optional(),\n branchTtlDays: z.number().int().positive().nullable().optional(),\n branchGcIntervalMs: z.number().int().positive().optional(),\n maxUploadBytes: z.number().int().positive().optional(),\n serverTiming: z.boolean().optional(),\n maxInlineUnzipSize: z.number().int().min(0).optional(),\n maxZipEntries: z.number().int().positive().optional(),\n maxUnzippedBytes: z.number().int().positive().optional(),\n viewports: z.array(viewportSchema).min(1, \"at least one viewport required\").optional(),\n adapters: z.record(z.string(), adapterSnapshotSchema).optional(),\n })\n .strict()\n .superRefine((config, ctx) => {\n if (config.previousSecret !== undefined && config.secret === undefined) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"previousSecret\"],\n message: \"previousSecret requires secret\",\n });\n }\n if (config.previousSecret !== undefined && config.previousSecret === config.secret) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"previousSecret\"],\n message: \"previousSecret must differ from secret\",\n });\n }\n });\n\n/** Zod schema validating the UI branding configuration. */\nexport const uiConfigSchema: z.ZodType<UIConfig> = z\n .object({\n name: z.string().optional(),\n // oxlint-disable-next-line typescript/no-deprecated -- z.string().url() kept for zod v3 API compat\n logo: z.string().url().optional(),\n // Accepted but ignored (see UIConfig.favicon) so existing configs keep\n // validating under .strict().\n // oxlint-disable-next-line typescript/no-deprecated -- z.string().url() kept for zod v3 API compat\n favicon: z.string().url().optional(),\n lightTheme: brandThemeSchema.optional(),\n darkTheme: brandThemeSchema.optional(),\n auth: authUiConfigSchema.optional(),\n })\n .strict();\n\n/**\n * Parse and validate a raw shelf-level configuration object.\n *\n * @param config - Unvalidated configuration record.\n * @returns The validated shelf configuration.\n */\nexport function validateConfig(config: Record<string, unknown>): ShelfConfig {\n const result = shelfConfigSchema.safeParse(config);\n if (!result.success) {\n const issues = result.error.issues.map((i) => `${i.path.join(\".\")}: ${i.message}`).join(\"; \");\n throw new Error(`Invalid ShelfConfig: ${issues}`);\n }\n return result.data;\n}\n\n/**\n * Parse and validate a raw UI branding configuration object.\n *\n * @param config - Unvalidated UI configuration record.\n * @returns The validated UI configuration.\n */\nexport function validateUiConfig(config: Record<string, unknown>): UIConfig {\n const result = uiConfigSchema.safeParse(config);\n if (!result.success) {\n const issues = result.error.issues.map((i) => `${i.path.join(\".\")}: ${i.message}`).join(\"; \");\n throw new Error(`Invalid UIConfig: ${issues}`);\n }\n return result.data;\n}\n\n/** Testing options: what renders, how many run at once, and how screenshots are compared. */\nexport interface ShelfTestingOptions {\n /** Pure renderer. Required: `testing` without a `runner` throws. */\n runner: CaptureRunner;\n /** Jobs this instance runs at once; auto-sized from CPU and memory when unset. */\n concurrency?: number;\n /**\n * Retries after a first failed attempt before a capture job fails for good (default 2: three\n * attempts). One limit covers failed attempts, lost leases and forked-child crashes.\n */\n retries?: number;\n /**\n * Lease of a job of the database queue, in seconds (default 300: 5 minutes). A running job\n * renews it on a heartbeat (every `min(30 s, lease / 3)`) and on progress, so a stage that prints\n * nothing is not redelivered while its process lives; a crashed holder's job is claimed by\n * another instance once the lease runs out, so a shorter lease recovers crashes sooner.\n */\n leaseSeconds?: number;\n /**\n * Module run in a forked capture child (it calls `runCaptureChild` from `@storyshelf/core/capture`).\n * The app consumes the queue and pushes each job to the child over IPC. Needs `runner`, which\n * serves as the in-process fallback.\n */\n workerEntry?: string;\n /**\n * Split a big build across the queue: captures (story x viewport x engine) per shard. A build of\n * up to twice this size still renders in one piece. Unset keeps every build in one job. Needs\n * `runner`. With `workerEntry` the forked child plans and renders shards and puts them on the\n * database queue itself.\n */\n shardSize?: number;\n /**\n * Requests per minute one client IP may make to the signed Storybook URL route, `/_s/<token>/*`\n * (ADR 0007, decision 5). Default 6000, enough for a render fetching thousands of assets from one\n * farm IP; a larger farm behind one address raises it. Over the limit the route answers `429`\n * before it looks at the token, so the answer says nothing about a token's validity.\n */\n storybookUrlRateLimit?: number;\n /**\n * Where captures run. `auto` (default) forks when `workerEntry` is set and the host can afford\n * a second process; `in-process` never forks; `fork` forks regardless of the host and fails at\n * boot if it cannot.\n */\n mode?: \"auto\" | \"in-process\" | \"fork\";\n /** Screenshot comparison, shared by capture and the re-diff endpoint. */\n compare?: ShelfCompareOptions;\n /** Image library selection; see {@link ShelfImagesOptions}. */\n images?: ShelfImagesOptions;\n /**\n * Clock and timers of the database job queue. Tests inject a manual clock so lease and poll\n * transitions do not depend on wall time; production leaves it unset (`Date.now` and the global\n * timers).\n */\n queueClock?: {\n now: () => number;\n timers: {\n setTimeout(callback: () => void, ms: number): unknown;\n clearTimeout(handle: unknown): void;\n };\n };\n}\n\n/** Notification options: who can deliver, over which transport, with what branding. */\nexport interface ShelfNotificationsOptions {\n /** Provider adapters (Slack, Teams, email, ...); a channel's `provider` must name one of these. */\n notifiers?: NotifierProvider[];\n /** Email transport. Listed here so its setup/teardown/validation hooks run with the app's. */\n emailSender?: EmailSender;\n /** Site-wide brand and sender settings for outgoing notifications. */\n config?: NotificationsConfig;\n}\n\n/** Comparison options. */\nexport interface ShelfCompareOptions {\n /**\n * Worker threads for pixel diffs: default CPU count minus one (min 1), `0` diffs on the main\n * thread. Takes precedence over `STORYSHELF_DIFF_WORKERS`.\n */\n threads?: number;\n}\n\n/** Image-handling options: which library decodes, encodes and resizes the PNGs. */\nexport interface ShelfImagesOptions {\n /**\n * Image library for diffs, diff overlays and AI thumbnails: `\"pngjs\"` (default, pure JavaScript,\n * runs anywhere) or `\"sharp\"` (native, several times faster on large PNGs; needs the optional\n * `sharp` package installed). Falls back to `STORYSHELF_IMAGE_ENGINE`. The pixel comparison is\n * pixelmatch either way, so verdicts match.\n */\n engine?: \"pngjs\" | \"sharp\";\n}\n\n/** Adapter and configuration options for creating the shelf router. */\nexport interface ShelfOptions {\n database: DatabaseAdapter;\n storage: StorageAdapter;\n /**\n * Testing (render + diff in the background). Absent means Storybook hosting only: no renderer,\n * no queue, and the tuning below is unreachable rather than silently ignored.\n */\n testing?: ShelfTestingOptions;\n auth?: Auth;\n /** AI insights surface (ADR 0016). Set ⇒ AI on site-wide; absent ⇒ off. */\n ai?: Ai;\n /** Design-tool providers (Figma, …) that resolve links, metadata and previews. */\n design?: DesignProvider[];\n /** Notification subsystem: providers, the email transport, and shared brand/sender settings. */\n notifications?: ShelfNotificationsOptions;\n logger?: Logger;\n ui?: UIConfig;\n config?: ShelfConfig;\n /**\n * Externally-managed observability SDK handle (e.g. from\n * `initObservabilityFromEnv`). Structural — core never imports the\n * observability package. Flushed on `app.lifecycle.teardown()`.\n */\n observability?: ObservabilityHandle;\n}\n\n/**\n * Shutdown hook for an externally-managed observability SDK.\n * Structural so core stays dependency-free.\n */\nexport interface ObservabilityHandle {\n /** Flush exporters and release SDK resources. Must be idempotent. */\n shutdown(): Promise<void>;\n}\nexport { DEFAULT_SCRATCH_DIR, resolveShelfOptions } from \"./options.ts\";\nexport { ALLOW_SERVERLESS_ENV, assertServerless, isServerlessHost } from \"./serverless.ts\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"config.mjs","names":[],"sources":["../src/config.ts"],"sourcesContent":["import type { Logger } from \"pino\";\nimport { z } from \"zod\";\nimport type { CaptureRunner } from \"./adapters/capture-runner.ts\";\nimport type { DatabaseAdapter } from \"./adapters/database.ts\";\nimport type { DesignProvider } from \"./adapters/design.ts\";\nimport type { EmailSender } from \"./adapters/email-sender.ts\";\nimport type { AdapterCategory } from \"./adapters/metadata.ts\";\nimport type { NotifierProvider } from \"./adapters/notifier/provider.ts\";\nimport type { StorageAdapter } from \"./adapters/storage.ts\";\nimport type { Ai } from \"./ai.ts\";\nimport type { Auth } from \"./auth.ts\";\n\n/** Brand color theme for the server-rendered UI. */\nexport interface BrandTheme {\n accent: string;\n accentContrast?: string;\n ring?: string;\n surface: { base: string; card: string; muted?: string; subtle?: string };\n text: { primary: string; secondary: string; muted?: string };\n border: string;\n borderSubtle?: string;\n status: { approved: string; new: string; rejected: string };\n sidebarBg?: string;\n topbarBg?: string;\n radius?: string;\n radiusSm?: string;\n shadow?: string;\n}\n\n/** Text overrides for the auth (login) UI. */\nexport interface AuthUiConfig {\n /** Page title, default \"Sign in\". */\n title?: string;\n /** Optional subtitle under the title. */\n subtitle?: string;\n /** Password field label, default \"Password\". */\n passwordLabel?: string;\n /** Password field placeholder. */\n passwordPlaceholder?: string;\n /** Submit button label, default \"Sign in\". */\n submitLabel?: string;\n /**\n * Template for SSO buttons, default \"Sign in with {label}\".\n * Must contain \"{label}\" which is replaced with the provider label.\n */\n ssoLabelTemplate?: string;\n /** Help text shown under the form. */\n helpText?: string;\n /** Footer text shown at the bottom of the card. */\n footerText?: string;\n}\n\n/** Branding overrides for the server-rendered UI. */\nexport interface UIConfig {\n name?: string;\n logo?: string;\n /**\n * @deprecated Ignored. The favicon is the product's own mark, served by the\n * app itself; set `logo` to rebrand the sidebar instead.\n */\n favicon?: string;\n lightTheme?: BrandTheme;\n darkTheme?: BrandTheme;\n auth?: AuthUiConfig;\n}\n\n/** Default cap for a single Storybook zip upload (1 GiB). */\nexport const DEFAULT_MAX_UPLOAD_BYTES = 1024 * 1024 * 1024;\n\n/** A viewport in which stories are captured. */\nexport interface ShelfViewport {\n name: string;\n width: number;\n height: number;\n}\n\n/** Metadata snapshot of a configured adapter. */\nexport interface AdapterSnapshot {\n name: string;\n version: string;\n description?: string;\n kind: string;\n category: AdapterCategory;\n}\n\n/** Site-wide notification defaults (brand + sender identity for admin alerts). */\nexport interface NotificationsConfig {\n fromEmail?: string;\n fromName?: string;\n footerText?: string;\n slackUsername?: string;\n}\n/** Longest browser-private freshness a signed capture asset may be given, in seconds (1 hour). */\nexport const MAX_CAPTURE_ASSET_CACHE_SECONDS = 3600;\n\n/** Signed Storybook asset serving for remote capture browsers (ADR 0007, decision 5). */\nexport interface CaptureAssetsConfig {\n /**\n * Opt-in browser-private freshness of capture-scoped signed assets, in whole seconds from 0 to\n * {@link MAX_CAPTURE_ASSET_CACHE_SECONDS}. 0 (default) keeps every signed answer `no-store`. A\n * positive value is a cap: the answer's `max-age` never exceeds the grant's remaining lifetime.\n */\n cacheMaxAgeSeconds?: number;\n}\n\n/** Shelf-level configuration (validated by {@link shelfConfigSchema}). */\nexport interface ShelfConfig {\n secret?: string;\n /**\n * The secret `secret` replaced. Used only to decrypt stored credentials\n * (webhook, git-token, and notification secrets) written before a rotation;\n * new writes always use `secret`. Remove once credentials are re-encrypted.\n */\n previousSecret?: string;\n /**\n * Re-encrypt credentials still under `previousSecret` at boot. Default false:\n * site admins can run it from the System page instead. No effect without\n * `previousSecret`.\n */\n migrateCredentialsOnBoot?: boolean;\n /**\n * Bootstrap site-admin bearer token (`STORYSHELF_ADMIN_TOKEN`/`ADMIN_TOKEN`).\n * Grants site-admin API access when no admin user exists yet; never\n * mint sessions from it. Distinct from `secret` (session signing).\n */\n adminToken?: string;\n publishedBaseDomain?: string;\n /**\n * Public base URL of this deployment (e.g. `https://shelf.example.com`).\n * Used as the issuer in the `/.well-known/openid-configuration` relying-party\n * helper document; falls back to the request origin when unset.\n */\n publicBaseUrl?: string;\n /**\n * Working directory for capture and inline statics extraction. Defaults to\n * `<os.tmpdir()>/storyshelf`; publishing and capture extract there.\n */\n scratchDir?: string;\n purgeTtlDays?: number;\n /** Branch baseline TTL, days; null disables branch GC (default 30). */\n branchTtlDays?: number | null;\n /** Branch GC interval, ms; daily sweep via interval clock (default 86_400_000). */\n branchGcIntervalMs?: number;\n maxUploadBytes?: number;\n /**\n * Emit `Server-Timing` response headers (total + db/storage roll-ups).\n * Opt-in, off by default — some deployments prefer no timing headers.\n */\n serverTiming?: boolean;\n /** Persist gzip variants for published Storybook files (default off). */\n publishedCompression?: boolean;\n /** Signed Storybook asset serving for remote capture browsers; see {@link CaptureAssetsConfig}. */\n captureAssets?: CaptureAssetsConfig;\n /**\n * Largest zip (bytes) extracted inline in the upload request; a larger zip is published by a\n * `publish` job (or refused with 413 on a host that runs no consumer). The count is taken\n * while the upload streams, never from `Content-Length`. Default 50 MB; `0` sends every zip to\n * a `publish` job.\n */\n maxInlineUnzipSize?: number;\n /** Most entries an uploaded Storybook zip may hold (default 50 000); more fails the publish. */\n maxZipEntries?: number;\n /**\n * Most uncompressed bytes an uploaded Storybook zip may expand to (default 2 GiB), counted while\n * extracting; more fails the publish. The compressed size is no bound on its own.\n */\n maxUnzippedBytes?: number;\n viewports?: ShelfViewport[];\n adapters?: Record<string, AdapterSnapshot>;\n}\n\nconst viewportSchema: z.ZodType<ShelfViewport> = z.object({\n name: z.string().min(1),\n width: z.number().int().positive(),\n height: z.number().int().positive(),\n});\n\nconst brandThemeSchema: z.ZodType<BrandTheme> = z.object({\n accent: z.string(),\n accentContrast: z.string().optional(),\n ring: z.string().optional(),\n surface: z.object({\n base: z.string(),\n card: z.string(),\n muted: z.string().optional(),\n subtle: z.string().optional(),\n }),\n text: z.object({ primary: z.string(), secondary: z.string(), muted: z.string().optional() }),\n border: z.string(),\n borderSubtle: z.string().optional(),\n status: z.object({ approved: z.string(), new: z.string(), rejected: z.string() }),\n sidebarBg: z.string().optional(),\n topbarBg: z.string().optional(),\n radius: z.string().optional(),\n radiusSm: z.string().optional(),\n shadow: z.string().optional(),\n});\n\nconst adapterSnapshotSchema: z.ZodType<AdapterSnapshot> = z.object({\n name: z.string(),\n version: z.string(),\n description: z.string().optional(),\n kind: z.string(),\n category: z.enum([\n \"database\",\n \"storage\",\n \"capture-runner\",\n \"capture-queue\",\n \"design\",\n \"notifier\",\n ]),\n});\n\nconst authUiConfigSchema: z.ZodType<AuthUiConfig> = z.object({\n title: z.string().min(1).optional(),\n subtitle: z.string().optional(),\n passwordLabel: z.string().min(1).optional(),\n passwordPlaceholder: z.string().optional(),\n submitLabel: z.string().min(1).optional(),\n ssoLabelTemplate: z.string().min(1).optional(),\n helpText: z.string().optional(),\n footerText: z.string().optional(),\n});\n\n/** Zod schema validating `notifications.config`. */\nexport const notificationsConfigSchema: z.ZodType<NotificationsConfig> = z.object({\n fromEmail: z.string().min(1).optional(),\n fromName: z.string().min(1).optional(),\n footerText: z.string().min(1).optional(),\n slackUsername: z.string().min(1).optional(),\n});\n\n/** Zod schema validating the shelf-level configuration. */\nexport const shelfConfigSchema: z.ZodType<ShelfConfig> = z\n .object({\n secret: z.string().min(1).optional(),\n previousSecret: z.string().min(1).optional(),\n migrateCredentialsOnBoot: z.boolean().optional(),\n adminToken: z.string().min(1).optional(),\n publishedBaseDomain: z.string().optional(),\n // oxlint-disable-next-line typescript/no-deprecated -- z.string().url() kept for zod v3 API compat\n publicBaseUrl: z.string().url().optional(),\n scratchDir: z.string().optional(),\n purgeTtlDays: z.number().int().positive().optional(),\n branchTtlDays: z.number().int().positive().nullable().optional(),\n branchGcIntervalMs: z.number().int().positive().optional(),\n maxUploadBytes: z.number().int().positive().optional(),\n serverTiming: z.boolean().optional(),\n publishedCompression: z.boolean().optional(),\n captureAssets: z\n .object({\n cacheMaxAgeSeconds: z.number().int().min(0).max(MAX_CAPTURE_ASSET_CACHE_SECONDS).optional(),\n })\n .strict()\n .optional(),\n maxInlineUnzipSize: z.number().int().min(0).optional(),\n maxZipEntries: z.number().int().positive().optional(),\n maxUnzippedBytes: z.number().int().positive().optional(),\n viewports: z.array(viewportSchema).min(1, \"at least one viewport required\").optional(),\n adapters: z.record(z.string(), adapterSnapshotSchema).optional(),\n })\n .strict()\n .superRefine((config, ctx) => {\n if (config.previousSecret !== undefined && config.secret === undefined) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"previousSecret\"],\n message: \"previousSecret requires secret\",\n });\n }\n if (config.previousSecret !== undefined && config.previousSecret === config.secret) {\n ctx.addIssue({\n code: \"custom\",\n path: [\"previousSecret\"],\n message: \"previousSecret must differ from secret\",\n });\n }\n });\n\n/** Zod schema validating the UI branding configuration. */\nexport const uiConfigSchema: z.ZodType<UIConfig> = z\n .object({\n name: z.string().optional(),\n // oxlint-disable-next-line typescript/no-deprecated -- z.string().url() kept for zod v3 API compat\n logo: z.string().url().optional(),\n // Accepted but ignored (see UIConfig.favicon) so existing configs keep\n // validating under .strict().\n // oxlint-disable-next-line typescript/no-deprecated -- z.string().url() kept for zod v3 API compat\n favicon: z.string().url().optional(),\n lightTheme: brandThemeSchema.optional(),\n darkTheme: brandThemeSchema.optional(),\n auth: authUiConfigSchema.optional(),\n })\n .strict();\n\n/**\n * Parse and validate a raw shelf-level configuration object.\n *\n * @param config - Unvalidated configuration record.\n * @returns The validated shelf configuration.\n */\nexport function validateConfig(config: Record<string, unknown>): ShelfConfig {\n const result = shelfConfigSchema.safeParse(config);\n if (!result.success) {\n const issues = result.error.issues.map((i) => `${i.path.join(\".\")}: ${i.message}`).join(\"; \");\n throw new Error(`Invalid ShelfConfig: ${issues}`);\n }\n return result.data;\n}\n\n/**\n * Parse and validate a raw UI branding configuration object.\n *\n * @param config - Unvalidated UI configuration record.\n * @returns The validated UI configuration.\n */\nexport function validateUiConfig(config: Record<string, unknown>): UIConfig {\n const result = uiConfigSchema.safeParse(config);\n if (!result.success) {\n const issues = result.error.issues.map((i) => `${i.path.join(\".\")}: ${i.message}`).join(\"; \");\n throw new Error(`Invalid UIConfig: ${issues}`);\n }\n return result.data;\n}\n\n/** Testing options: what renders, how many run at once, and how screenshots are compared. */\nexport interface ShelfTestingOptions {\n /** Pure renderer. Required: `testing` without a `runner` throws. */\n runner: CaptureRunner;\n /** Jobs this instance runs at once; auto-sized from CPU and memory when unset. */\n concurrency?: number;\n /**\n * Retries after a first failed attempt before a capture job fails for good (default 2: three\n * attempts). One limit covers failed attempts, lost leases and forked-child crashes.\n */\n retries?: number;\n /**\n * Lease of a job of the database queue, in seconds (default 300: 5 minutes). A running job\n * renews it on a heartbeat (every `min(30 s, lease / 3)`) and on progress, so a stage that prints\n * nothing is not redelivered while its process lives; a crashed holder's job is claimed by\n * another instance once the lease runs out, so a shorter lease recovers crashes sooner.\n */\n leaseSeconds?: number;\n /**\n * Module run in a forked capture child (it calls `runCaptureChild` from `@storyshelf/core/capture`).\n * The app consumes the queue and pushes each job to the child over IPC. Needs `runner`, which\n * serves as the in-process fallback.\n */\n workerEntry?: string;\n /**\n * Split a big build across the queue: captures (story x viewport x engine) per shard. A build of\n * up to twice this size still renders in one piece. Unset keeps every build in one job. Needs\n * `runner`. With `workerEntry` the forked child plans and renders shards and puts them on the\n * database queue itself.\n */\n shardSize?: number;\n /**\n * Requests per minute one client IP may make to the signed Storybook URL route, `/_s/<token>/*`\n * (ADR 0007, decision 5). Default 6000, enough for a render fetching thousands of assets from one\n * farm IP; a larger farm behind one address raises it. Over the limit the route answers `429`\n * before it looks at the token, so the answer says nothing about a token's validity.\n */\n storybookUrlRateLimit?: number;\n /**\n * Where captures run. `auto` (default) forks when `workerEntry` is set and the host can afford\n * a second process; `in-process` never forks; `fork` forks regardless of the host and fails at\n * boot if it cannot.\n */\n mode?: \"auto\" | \"in-process\" | \"fork\";\n /** Screenshot comparison, shared by capture and the re-diff endpoint. */\n compare?: ShelfCompareOptions;\n /** Image library selection; see {@link ShelfImagesOptions}. */\n images?: ShelfImagesOptions;\n /**\n * Clock and timers of the database job queue. Tests inject a manual clock so lease and poll\n * transitions do not depend on wall time; production leaves it unset (`Date.now` and the global\n * timers).\n */\n queueClock?: {\n now: () => number;\n timers: {\n setTimeout(callback: () => void, ms: number): unknown;\n clearTimeout(handle: unknown): void;\n };\n };\n}\n\n/** Notification options: who can deliver, over which transport, with what branding. */\nexport interface ShelfNotificationsOptions {\n /** Provider adapters (Slack, Teams, email, ...); a channel's `provider` must name one of these. */\n notifiers?: NotifierProvider[];\n /** Email transport. Listed here so its setup/teardown/validation hooks run with the app's. */\n emailSender?: EmailSender;\n /** Site-wide brand and sender settings for outgoing notifications. */\n config?: NotificationsConfig;\n}\n\n/** Comparison options. */\nexport interface ShelfCompareOptions {\n /**\n * Worker threads for pixel diffs: default CPU count minus one (min 1), `0` diffs on the main\n * thread. Takes precedence over `STORYSHELF_DIFF_WORKERS`.\n */\n threads?: number;\n}\n\n/** Image-handling options: which library decodes, encodes and resizes the PNGs. */\nexport interface ShelfImagesOptions {\n /**\n * Image library for diffs, diff overlays and AI thumbnails: `\"pngjs\"` (default, pure JavaScript,\n * runs anywhere) or `\"sharp\"` (native, several times faster on large PNGs; needs the optional\n * `sharp` package installed). Falls back to `STORYSHELF_IMAGE_ENGINE`. The pixel comparison is\n * pixelmatch either way, so verdicts match.\n */\n engine?: \"pngjs\" | \"sharp\";\n}\n\n/** Adapter and configuration options for creating the shelf router. */\nexport interface ShelfOptions {\n database: DatabaseAdapter;\n storage: StorageAdapter;\n /**\n * Testing (render + diff in the background). Absent means Storybook hosting only: no renderer,\n * no queue, and the tuning below is unreachable rather than silently ignored.\n */\n testing?: ShelfTestingOptions;\n auth?: Auth;\n /** AI insights surface (ADR 0016). Set ⇒ AI on site-wide; absent ⇒ off. */\n ai?: Ai;\n /** Design-tool providers (Figma, …) that resolve links, metadata and previews. */\n design?: DesignProvider[];\n /** Notification subsystem: providers, the email transport, and shared brand/sender settings. */\n notifications?: ShelfNotificationsOptions;\n logger?: Logger;\n ui?: UIConfig;\n config?: ShelfConfig;\n /**\n * Externally-managed observability SDK handle (e.g. from\n * `initObservabilityFromEnv`). Structural — core never imports the\n * observability package. Flushed on `app.lifecycle.teardown()`.\n */\n observability?: ObservabilityHandle;\n}\n\n/**\n * Shutdown hook for an externally-managed observability SDK.\n * Structural so core stays dependency-free.\n */\nexport interface ObservabilityHandle {\n /** Flush exporters and release SDK resources. Must be idempotent. */\n shutdown(): Promise<void>;\n}\nexport { DEFAULT_SCRATCH_DIR, resolveShelfOptions } from \"./options.ts\";\nexport { ALLOW_SERVERLESS_ENV, assertServerless, isServerlessHost } from \"./serverless.ts\";\n"],"mappings":"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"}
package/dist/diff.d.mts CHANGED
@@ -1,11 +1,9 @@
1
1
  import __tsdown_shims_path from 'node:path';
2
2
  import __tsdown_shims_url from 'node:url';
3
3
  import { DEFAULT_DIFF_OPTIONS, DIFF_WORKERS_ENV, DiffOptions, DiffResult, IMAGE_ENGINE_ENV, ImageEngine, configureImages, diffImages, diffImagesAsync, shutdownDiffPool, verifyImageEngine } from "@storyshelf/image";
4
- //#region src/diff/index.d.ts
5
4
  /** @deprecated Use `configureImages`, which also takes the image engine. */
6
5
  declare function configureDiffPool(options: {
7
6
  threads?: number;
8
7
  }): void;
9
- //#endregion
10
8
  export { DEFAULT_DIFF_OPTIONS, DIFF_WORKERS_ENV, type DiffOptions, type DiffResult, IMAGE_ENGINE_ENV, type ImageEngine, configureDiffPool, configureImages, diffImages, diffImagesAsync, shutdownDiffPool, verifyImageEngine };
11
9
  //# sourceMappingURL=diff.d.mts.map
package/dist/diff.mjs CHANGED
@@ -2,7 +2,7 @@ import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
4
  import { DEFAULT_DIFF_OPTIONS, DIFF_WORKERS_ENV, IMAGE_ENGINE_ENV, configureImages, configureImages as configureImages$1, diffImages, diffImagesAsync, shutdownDiffPool, verifyImageEngine } from "@storyshelf/image";
5
- //#region src/diff/index.ts
5
+ // src/diff/index.ts
6
6
  /**
7
7
  * Pixel diff engine (re-exported from `@storyshelf/image`, which owns the codecs and worker pool).
8
8
  *
@@ -13,7 +13,6 @@ import { DEFAULT_DIFF_OPTIONS, DIFF_WORKERS_ENV, IMAGE_ENGINE_ENV, configureImag
13
13
  function configureDiffPool(options) {
14
14
  configureImages$1(options);
15
15
  }
16
- //#endregion
17
16
  export { DEFAULT_DIFF_OPTIONS, DIFF_WORKERS_ENV, IMAGE_ENGINE_ENV, configureDiffPool, configureImages, diffImages, diffImagesAsync, shutdownDiffPool, verifyImageEngine };
18
17
 
19
18
  //# sourceMappingURL=diff.mjs.map
package/dist/index.d.mts CHANGED
@@ -2,6 +2,6 @@ import __tsdown_shims_path from 'node:path';
2
2
  import __tsdown_shims_url from 'node:url';
3
3
  import { Logger, LoggerOptions, PinoTransport, createShelfLogger } from "./logger.mjs";
4
4
  import { BUILD_STATUSES, BuildStatus, ProjectRole, SNAPSHOT_STATUSES, SiteRole, SnapshotStatus, TERMINAL_BUILD_STATUSES } from "./types.mjs";
5
- import { AdapterSnapshot, BrandTheme, DEFAULT_MAX_UPLOAD_BYTES, ShelfConfig, ShelfOptions, ShelfViewport, UIConfig, shelfConfigSchema, uiConfigSchema, validateConfig, validateUiConfig } from "./config.mjs";
5
+ import { AdapterSnapshot, BrandTheme, CaptureAssetsConfig, DEFAULT_MAX_UPLOAD_BYTES, MAX_CAPTURE_ASSET_CACHE_SECONDS, ShelfConfig, ShelfOptions, ShelfViewport, UIConfig, shelfConfigSchema, uiConfigSchema, validateConfig, validateUiConfig } from "./config.mjs";
6
6
  import { BrandPack, brandPack, brandPacks } from "./brand-packs.mjs";
7
- export { type AdapterSnapshot, BUILD_STATUSES, type BrandPack, type BrandTheme, type BuildStatus, DEFAULT_MAX_UPLOAD_BYTES, type Logger, type LoggerOptions, type PinoTransport, type ProjectRole, SNAPSHOT_STATUSES, type ShelfConfig, type ShelfOptions, type ShelfViewport, type SiteRole, type SnapshotStatus, TERMINAL_BUILD_STATUSES, type UIConfig, brandPack, brandPacks, createShelfLogger, shelfConfigSchema, uiConfigSchema, validateConfig, validateUiConfig };
7
+ export { type AdapterSnapshot, BUILD_STATUSES, type BrandPack, type BrandTheme, type BuildStatus, type CaptureAssetsConfig, DEFAULT_MAX_UPLOAD_BYTES, type Logger, type LoggerOptions, MAX_CAPTURE_ASSET_CACHE_SECONDS, type PinoTransport, type ProjectRole, SNAPSHOT_STATUSES, type ShelfConfig, type ShelfOptions, type ShelfViewport, type SiteRole, type SnapshotStatus, TERMINAL_BUILD_STATUSES, type UIConfig, brandPack, brandPacks, createShelfLogger, shelfConfigSchema, uiConfigSchema, validateConfig, validateUiConfig };
package/dist/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
- import { DEFAULT_MAX_UPLOAD_BYTES, shelfConfigSchema, uiConfigSchema, validateConfig, validateUiConfig } from "./config.mjs";
4
+ import { DEFAULT_MAX_UPLOAD_BYTES, MAX_CAPTURE_ASSET_CACHE_SECONDS, shelfConfigSchema, uiConfigSchema, validateConfig, validateUiConfig } from "./config.mjs";
5
5
  import { brandPack, brandPacks } from "./brand-packs.mjs";
6
6
  import { createShelfLogger } from "./logger.mjs";
7
7
  import { BUILD_STATUSES, SNAPSHOT_STATUSES, TERMINAL_BUILD_STATUSES } from "./types.mjs";
8
- export { BUILD_STATUSES, DEFAULT_MAX_UPLOAD_BYTES, SNAPSHOT_STATUSES, TERMINAL_BUILD_STATUSES, brandPack, brandPacks, createShelfLogger, shelfConfigSchema, uiConfigSchema, validateConfig, validateUiConfig };
8
+ export { BUILD_STATUSES, DEFAULT_MAX_UPLOAD_BYTES, MAX_CAPTURE_ASSET_CACHE_SECONDS, SNAPSHOT_STATUSES, TERMINAL_BUILD_STATUSES, brandPack, brandPacks, createShelfLogger, shelfConfigSchema, uiConfigSchema, validateConfig, validateUiConfig };
@@ -1,7 +1,6 @@
1
1
  import __tsdown_shims_path from 'node:path';
2
2
  import __tsdown_shims_url from 'node:url';
3
3
  import { AiBudget } from "../ai.mjs";
4
- //#region src/insights/budget.d.ts
5
4
  /** Alert thresholds as percentages of the daily cap. */
6
5
  declare const BUDGET_THRESHOLDS: readonly [50, 75, 90, 100];
7
6
  /** UTC day key (`YYYY-MM-DD`). */
@@ -15,6 +14,5 @@ declare function countedTokens(usage: {
15
14
  }, images: number, budget: Pick<AiBudget, "visionWeight">): number;
16
15
  /** Thresholds crossed when moving from `before` to `after` tokens of `cap`. */
17
16
  declare function crossedThresholds(before: number, after: number, cap: number): number[];
18
- //#endregion
19
17
  export { BUDGET_THRESHOLDS, countedTokens, crossedThresholds, utcDay, utcDayStart };
20
18
  //# sourceMappingURL=budget.d.mts.map
@@ -1,7 +1,7 @@
1
1
  import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
- //#region src/insights/budget.ts
4
+ // src/insights/budget.ts
5
5
  /** Alert thresholds as percentages of the daily cap. */
6
6
  const BUDGET_THRESHOLDS = [
7
7
  50,
@@ -27,7 +27,6 @@ function crossedThresholds(before, after, cap) {
27
27
  if (cap <= 0) return [];
28
28
  return BUDGET_THRESHOLDS.filter((t) => before < cap * t / 100 && after >= cap * t / 100);
29
29
  }
30
- //#endregion
31
30
  export { BUDGET_THRESHOLDS, countedTokens, crossedThresholds, utcDay, utcDayStart };
32
31
 
33
32
  //# sourceMappingURL=budget.mjs.map
@@ -1,7 +1,6 @@
1
1
  import __tsdown_shims_path from 'node:path';
2
2
  import __tsdown_shims_url from 'node:url';
3
3
  import { z } from "zod";
4
- //#region src/insights/envelope.d.ts
5
4
  /** Build triage envelope. */
6
5
  declare const triageEnvelopeSchema: z.ZodObject<{
7
6
  verdict: z.ZodEnum<{
@@ -54,6 +53,5 @@ declare const healthEnvelopeSchema: z.ZodObject<{
54
53
  type TriageEnvelope = z.infer<typeof triageEnvelopeSchema>;
55
54
  /** A parsed health result. */
56
55
  type HealthEnvelope = z.infer<typeof healthEnvelopeSchema>;
57
- //#endregion
58
56
  export { HealthEnvelope, TriageEnvelope, healthEnvelopeSchema, triageEnvelopeSchema };
59
57
  //# sourceMappingURL=envelope.d.mts.map
@@ -2,7 +2,7 @@ import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
4
  import { z } from "zod";
5
- //#region src/insights/envelope.ts
5
+ // src/insights/envelope.ts
6
6
  /** Result envelopes the model must produce (validated; stored as opaque JSON text). */
7
7
  const severitySchema = z.enum([
8
8
  "info",
@@ -54,7 +54,6 @@ const healthEnvelopeSchema = z.object({
54
54
  })).max(10),
55
55
  confidence: confidenceSchema
56
56
  });
57
- //#endregion
58
57
  export { HEALTH_VERDICTS, TRIAGE_VERDICTS, healthEnvelopeSchema, triageEnvelopeSchema };
59
58
 
60
59
  //# sourceMappingURL=envelope.mjs.map
@@ -2,7 +2,6 @@ import __tsdown_shims_path from 'node:path';
2
2
  import __tsdown_shims_url from 'node:url';
3
3
  import { EvidenceLimits } from "./limits.mjs";
4
4
  import { BuiltEvidence } from "./evidence.mjs";
5
- //#region src/insights/evidence-health.d.ts
6
5
  /** One build in the window, summarized. */
7
6
  interface BuildSummary {
8
7
  createdAt: string;
@@ -27,6 +26,5 @@ interface HealthEvidenceInput {
27
26
  }
28
27
  /** Assemble health evidence deterministically. */
29
28
  declare function buildHealthEvidence(input: HealthEvidenceInput): BuiltEvidence;
30
- //#endregion
31
29
  export { BuildSummary, HealthEvidenceInput, buildHealthEvidence };
32
30
  //# sourceMappingURL=evidence-health.d.mts.map
@@ -3,7 +3,7 @@ import "node:url";
3
3
  import.meta.url;
4
4
  import { resolveLimits } from "./limits.mjs";
5
5
  import { capBytes, field } from "./text.mjs";
6
- //#region src/insights/evidence-health.ts
6
+ // src/insights/evidence-health.ts
7
7
  /** Assemble health evidence deterministically. */
8
8
  function buildHealthEvidence(input) {
9
9
  const limits = resolveLimits(input.limits);
@@ -22,7 +22,6 @@ function buildHealthEvidence(input) {
22
22
  omitted: 0
23
23
  };
24
24
  }
25
- //#endregion
26
25
  export { buildHealthEvidence };
27
26
 
28
27
  //# sourceMappingURL=evidence-health.mjs.map
@@ -2,7 +2,6 @@ import __tsdown_shims_path from 'node:path';
2
2
  import __tsdown_shims_url from 'node:url';
3
3
  import { EvidenceLimits } from "./limits.mjs";
4
4
  import { AiEvidence } from "../ai.mjs";
5
- //#region src/insights/evidence.d.ts
6
5
  /** One changed (or failed) snapshot as evidence. */
7
6
  interface SnapshotEvidence {
8
7
  storyId: string;
@@ -50,6 +49,5 @@ declare function snapshotKey(s: Pick<SnapshotEvidence, "title" | "name" | "viewp
50
49
  declare function rankSnapshots(a: SnapshotEvidence, b: SnapshotEvidence): number;
51
50
  /** Assemble triage evidence deterministically (redacted, capped, ranked). */
52
51
  declare function buildTriageEvidence(input: TriageEvidenceInput): Promise<BuiltEvidence>;
53
- //#endregion
54
52
  export { BuiltEvidence, SnapshotEvidence, TriageEvidenceInput, buildTriageEvidence, rankSnapshots, snapshotKey };
55
53
  //# sourceMappingURL=evidence.d.mts.map
@@ -4,7 +4,7 @@ import.meta.url;
4
4
  import { resolveLimits } from "./limits.mjs";
5
5
  import { capBytes, field, headTail } from "./text.mjs";
6
6
  import { downscalePng } from "@storyshelf/image";
7
- //#region src/insights/evidence.ts
7
+ // src/insights/evidence.ts
8
8
  /** Pure evidence builders: already-loaded inputs in, delimited text + images out. */
9
9
  /** Stable story key shown to the model and echoed back in `snapshotKey`. */
10
10
  function snapshotKey(s) {
@@ -58,7 +58,6 @@ async function triageImages(listed, limits) {
58
58
  label: snapshotKey(item)
59
59
  })));
60
60
  }
61
- //#endregion
62
61
  export { buildTriageEvidence, rankSnapshots, snapshotKey };
63
62
 
64
63
  //# sourceMappingURL=evidence.mjs.map
@@ -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/insights/hash.d.ts
4
3
  /** Parts that define whether a cached insight is still valid. */
5
4
  interface InputHashParts {
6
5
  evidenceText: string;
@@ -13,6 +12,5 @@ interface InputHashParts {
13
12
  }
14
13
  /** Hash the final assembled evidence plus prompt/task/profile/model. */
15
14
  declare function computeInputHash(parts: InputHashParts): string;
16
- //#endregion
17
15
  export { InputHashParts, computeInputHash };
18
16
  //# sourceMappingURL=hash.d.mts.map
@@ -2,7 +2,7 @@ import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
4
  import { sha256 } from "../utils/hash.mjs";
5
- //#region src/insights/hash.ts
5
+ // src/insights/hash.ts
6
6
  /** Cache key for an insight: identical evidence + prompt + model is a free hit. */
7
7
  /** Hash the final assembled evidence plus prompt/task/profile/model. */
8
8
  function computeInputHash(parts) {
@@ -15,7 +15,6 @@ function computeInputHash(parts) {
15
15
  parts.evidenceText
16
16
  ]));
17
17
  }
18
- //#endregion
19
18
  export { computeInputHash };
20
19
 
21
20
  //# sourceMappingURL=hash.mjs.map
@@ -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/insights/limits.d.ts
4
3
  /** Deterministic evidence limits (defaults; overridable in `createAi` options). */
5
4
  /** Caps applied when assembling evidence. */
6
5
  interface EvidenceLimits {
@@ -19,6 +18,5 @@ interface EvidenceLimits {
19
18
  declare const DEFAULT_EVIDENCE_LIMITS: EvidenceLimits;
20
19
  /** Merge partial overrides onto the defaults. */
21
20
  declare function resolveLimits(overrides?: Partial<EvidenceLimits>): EvidenceLimits;
22
- //#endregion
23
21
  export { DEFAULT_EVIDENCE_LIMITS, EvidenceLimits, resolveLimits };
24
22
  //# sourceMappingURL=limits.d.mts.map
@@ -1,7 +1,7 @@
1
1
  import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
- //#region src/insights/limits.ts
4
+ // src/insights/limits.ts
5
5
  /** Default limits from ADR 0016 §5. */
6
6
  const DEFAULT_EVIDENCE_LIMITS = {
7
7
  maxImages: 3,
@@ -18,7 +18,6 @@ function resolveLimits(overrides) {
18
18
  ...overrides
19
19
  };
20
20
  }
21
- //#endregion
22
21
  export { DEFAULT_EVIDENCE_LIMITS, resolveLimits };
23
22
 
24
23
  //# sourceMappingURL=limits.mjs.map
@@ -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/insights/prompts/v1.d.ts
4
3
  /** Versioned prompts (pinned and logged; bump `PROMPT_VERSION` on any change). */
5
4
  /** Identifier folded into every `inputHash` and stored on each row. */
6
5
  declare const PROMPT_VERSION = "v1";
@@ -8,6 +7,5 @@ declare const PROMPT_VERSION = "v1";
8
7
  declare const TRIAGE_SYSTEM: string;
9
8
  /** System prompt for project health. */
10
9
  declare const HEALTH_SYSTEM: string;
11
- //#endregion
12
10
  export { HEALTH_SYSTEM, PROMPT_VERSION, TRIAGE_SYSTEM };
13
11
  //# sourceMappingURL=v1.d.mts.map
@@ -1,7 +1,7 @@
1
1
  import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
- //#region src/insights/prompts/v1.ts
4
+ // src/insights/prompts/v1.ts
5
5
  /** Versioned prompts (pinned and logged; bump `PROMPT_VERSION` on any change). */
6
6
  /** Identifier folded into every `inputHash` and stored on each row. */
7
7
  const PROMPT_VERSION = "v1";
@@ -28,7 +28,6 @@ const HEALTH_SYSTEM = [
28
28
  "a verdict and a few short trends.",
29
29
  SHARED
30
30
  ].join(" ");
31
- //#endregion
32
31
  export { HEALTH_SYSTEM, PROMPT_VERSION, TRIAGE_SYSTEM };
33
32
 
34
33
  //# sourceMappingURL=v1.mjs.map
@@ -1,9 +1,7 @@
1
1
  import __tsdown_shims_path from 'node:path';
2
2
  import __tsdown_shims_url from 'node:url';
3
- //#region src/insights/redact.d.ts
4
3
  /** Secret redaction applied to every string before it can reach a model. */
5
4
  /** Replace secrets in a string with a fixed marker (never throws). */
6
5
  declare function redactText(input: string): string;
7
- //#endregion
8
6
  export { redactText };
9
7
  //# sourceMappingURL=redact.d.mts.map
@@ -1,7 +1,7 @@
1
1
  import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
- //#region src/insights/redact.ts
4
+ // src/insights/redact.ts
5
5
  /** Secret redaction applied to every string before it can reach a model. */
6
6
  const MARK = "[REDACTED]";
7
7
  const RULES = [
@@ -18,7 +18,6 @@ function redactText(input) {
18
18
  for (const [pattern, replacement] of RULES) out = out.replaceAll(pattern, replacement);
19
19
  return out;
20
20
  }
21
- //#endregion
22
21
  export { redactText };
23
22
 
24
23
  //# sourceMappingURL=redact.mjs.map
@@ -2,7 +2,7 @@ import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
4
  import { redactText } from "./redact.mjs";
5
- //#region src/insights/text.ts
5
+ // src/insights/text.ts
6
6
  /** Text helpers for deterministic, safe evidence. */
7
7
  const LT = "‹";
8
8
  const GT = "›";
@@ -38,7 +38,6 @@ function capBytes(lines, maxBytes) {
38
38
  }
39
39
  return kept.join("\n");
40
40
  }
41
- //#endregion
42
41
  export { capBytes, field, headTail, neutralize };
43
42
 
44
43
  //# sourceMappingURL=text.mjs.map
package/dist/logger.d.mts CHANGED
@@ -1,7 +1,6 @@
1
1
  import __tsdown_shims_path from 'node:path';
2
2
  import __tsdown_shims_url from 'node:url';
3
3
  import { Logger } from "pino";
4
- //#region src/logger.d.ts
5
4
  /**
6
5
  * Create the structured JSON logger used across StoryShelf.
7
6
  *
@@ -43,6 +42,5 @@ interface LoggerOptions {
43
42
  */
44
43
  mixin?: () => Record<string, unknown>;
45
44
  }
46
- //#endregion
47
45
  export { type Logger, LoggerOptions, PinoTransport, createShelfLogger };
48
46
  //# sourceMappingURL=logger.d.mts.map
package/dist/logger.mjs CHANGED
@@ -3,7 +3,7 @@ import "node:url";
3
3
  import.meta.url;
4
4
  import { redactSecrets } from "./utils/redact.mjs";
5
5
  import pino from "pino";
6
- //#region src/logger.ts
6
+ // src/logger.ts
7
7
  /**
8
8
  * Create the structured JSON logger used across StoryShelf.
9
9
  *
@@ -50,7 +50,6 @@ function redactedError(err) {
50
50
  }
51
51
  return record;
52
52
  }
53
- //#endregion
54
53
  export { createShelfLogger };
55
54
 
56
55
  //# sourceMappingURL=logger.mjs.map
@@ -3,7 +3,6 @@ import __tsdown_shims_url from 'node:url';
3
3
  import { DatabaseAdapter } from "../adapter/database.mjs";
4
4
  import { AiBudgetAlertRow } from "../schema/insight.mjs";
5
5
  import { Table } from "drizzle-orm";
6
- //#region src/models/ai-budget-alert.d.ts
7
6
  /** Tables required by {@link AiBudgetAlertModel}. */
8
7
  interface AiBudgetAlertTables {
9
8
  aiBudgetAlerts: Table;
@@ -18,6 +17,5 @@ declare class AiBudgetAlertModel {
18
17
  /** Claims already made for a day. */
19
18
  listForDay(day: string): Promise<AiBudgetAlertRow[]>;
20
19
  }
21
- //#endregion
22
20
  export { AiBudgetAlertModel, AiBudgetAlertTables };
23
21
  //# sourceMappingURL=ai-budget-alert.d.mts.map
@@ -3,7 +3,7 @@ import "node:url";
3
3
  import.meta.url;
4
4
  import { col } from "./columns.mjs";
5
5
  import { eq } from "drizzle-orm";
6
- //#region src/models/ai-budget-alert.ts
6
+ // src/models/ai-budget-alert.ts
7
7
  /** Budget-threshold alert claims: the primary key makes "once per day" atomic. */
8
8
  /** Data operations for budget alert claims. */
9
9
  var AiBudgetAlertModel = class {
@@ -32,7 +32,6 @@ var AiBudgetAlertModel = class {
32
32
  return await this.db.list(this.tables.aiBudgetAlerts, { where: eq(col(this.tables.aiBudgetAlerts, "day"), day) });
33
33
  }
34
34
  };
35
- //#endregion
36
35
  export { AiBudgetAlertModel };
37
36
 
38
37
  //# sourceMappingURL=ai-budget-alert.mjs.map
@@ -3,7 +3,6 @@ import __tsdown_shims_url from 'node:url';
3
3
  import { DatabaseAdapter } from "../adapter/database.mjs";
4
4
  import { AiUsageRow } from "../schema/insight.mjs";
5
5
  import { Table } from "drizzle-orm";
6
- //#region src/models/ai-usage.d.ts
7
6
  /** Tables required by {@link AiUsageModel}. */
8
7
  interface AiUsageTables {
9
8
  aiUsage: Table;
@@ -35,6 +34,5 @@ declare class AiUsageModel {
35
34
  purgeBefore(cutoffIso: string): Promise<number>;
36
35
  private col;
37
36
  }
38
- //#endregion
39
37
  export { AiUsageInput, AiUsageModel, AiUsageTables };
40
38
  //# sourceMappingURL=ai-usage.d.mts.map
@@ -4,7 +4,7 @@ import.meta.url;
4
4
  import { ulid } from "../utils/ulid.mjs";
5
5
  import { col } from "./columns.mjs";
6
6
  import { and, asc, eq, gte, lt } from "drizzle-orm";
7
- //#region src/models/ai-usage.ts
7
+ // src/models/ai-usage.ts
8
8
  /** Provider-reported AI usage rows; budget and hourly limits are counted from them. */
9
9
  const PAGE = 500;
10
10
  /** Data operations for AI usage rows. */
@@ -55,7 +55,6 @@ var AiUsageModel = class {
55
55
  return col(this.tables.aiUsage, name);
56
56
  }
57
57
  };
58
- //#endregion
59
58
  export { AiUsageModel };
60
59
 
61
60
  //# sourceMappingURL=ai-usage.mjs.map
@@ -0,0 +1,18 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import "../adapter/database.mjs";
4
+ import { Snapshot } from "../schema/snapshot.mjs";
5
+ import { BaselineWriteConflict } from "./baseline-conflict.mjs";
6
+ import { BaselineStatus } from "./baseline-status.mjs";
7
+ interface AtomicBaselineApproval {
8
+ snapshot: Snapshot;
9
+ reviewedBy: string | null;
10
+ force: boolean;
11
+ branch: string;
12
+ }
13
+ declare class BaselineApprovalConflict extends BaselineWriteConflict {
14
+ readonly driftStatus?: BaselineStatus;
15
+ constructor(message: string, driftStatus?: BaselineStatus);
16
+ }
17
+ export { AtomicBaselineApproval, BaselineApprovalConflict };
18
+ //# sourceMappingURL=baseline-approval.d.mts.map
@@ -0,0 +1,41 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { col } from "./columns.mjs";
5
+ import { BaselineWriteConflict } from "./baseline-conflict.mjs";
6
+ import { baselineStatus, isBaselineDrifted } from "./baseline-status.mjs";
7
+ import { and, eq } from "drizzle-orm";
8
+ // src/models/baseline-approval.ts
9
+ /** Review checks and decision persisted inside the baseline/reference transaction. */
10
+ var BaselineApprovalConflict = class extends BaselineWriteConflict {
11
+ driftStatus;
12
+ constructor(message, driftStatus) {
13
+ super(message);
14
+ this.driftStatus = driftStatus;
15
+ }
16
+ };
17
+ async function approveInTransaction(tx, tables, input) {
18
+ const snapshot = await tx.get(tables.snapshots, input.snapshot.id);
19
+ if (!snapshot || snapshot.projectId !== input.snapshot.projectId || snapshot.buildId !== input.snapshot.buildId || snapshot.status !== input.snapshot.status || snapshot.updatedAt !== input.snapshot.updatedAt || snapshot.screenshotPath !== input.snapshot.screenshotPath || snapshot.baselineId !== input.snapshot.baselineId || snapshot.baselineVersion !== input.snapshot.baselineVersion) throw new BaselineApprovalConflict("Snapshot changed during approval; reload and retry");
20
+ const build = await tx.get(tables.builds, snapshot.buildId);
21
+ const project = await tx.get(tables.projects, snapshot.projectId);
22
+ if (!build || !project || build.projectId !== project.id || build.status === "cancelled" || build.gitBranch !== input.branch) throw new BaselineApprovalConflict("Build is unavailable for approval");
23
+ const current = await baselineFor(tx, tables, snapshot, build.gitBranch) ?? (build.gitBranch === project.gitDefaultBranch ? null : await baselineFor(tx, tables, snapshot, project.gitDefaultBranch));
24
+ const status = baselineStatus(snapshot, current);
25
+ if ((snapshot.status === "new" || snapshot.status === "changed") && isBaselineDrifted(status) && !input.force) throw new BaselineApprovalConflict("Baseline changed after this diff was computed", status);
26
+ await tx.update(tables.snapshots, snapshot.id, {
27
+ status: "approved",
28
+ reviewedBy: input.reviewedBy,
29
+ reviewedAt: (/* @__PURE__ */ new Date()).toISOString(),
30
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
31
+ });
32
+ }
33
+ async function baselineFor(tx, tables, snapshot, branch) {
34
+ return (await tx.list(tables.baselines, {
35
+ where: and(eq(col(tables.baselines, "projectId"), snapshot.projectId), eq(col(tables.baselines, "storyId"), snapshot.storyId), eq(col(tables.baselines, "viewportName"), snapshot.viewportName), eq(col(tables.baselines, "browser"), snapshot.browser ?? "chromium"), eq(col(tables.baselines, "branch"), branch)),
36
+ limit: 1
37
+ }))[0] ?? null;
38
+ }
39
+ export { BaselineApprovalConflict, approveInTransaction };
40
+
41
+ //# sourceMappingURL=baseline-approval.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseline-approval.mjs","names":[],"sources":["../../src/models/baseline-approval.ts"],"sourcesContent":["/** Review checks and decision persisted inside the baseline/reference transaction. */\nimport { and, eq } from \"drizzle-orm\";\nimport type { Tables, TxStore } from \"../adapters/database.ts\";\nimport type { Baseline } from \"../schema/baseline.ts\";\nimport type { Build } from \"../schema/build.ts\";\nimport type { Project } from \"../schema/project.ts\";\nimport type { Snapshot } from \"../schema/snapshot.ts\";\nimport { BaselineWriteConflict } from \"./baseline-conflict.ts\";\nimport { baselineStatus, isBaselineDrifted, type BaselineStatus } from \"./baseline-status.ts\";\nimport { col } from \"./columns.ts\";\n\nexport interface AtomicBaselineApproval {\n snapshot: Snapshot;\n reviewedBy: string | null;\n force: boolean;\n branch: string;\n}\nexport class BaselineApprovalConflict extends BaselineWriteConflict {\n readonly driftStatus?: BaselineStatus;\n constructor(message: string, driftStatus?: BaselineStatus) {\n super(message);\n this.driftStatus = driftStatus;\n }\n}\n\nexport async function approveInTransaction(\n tx: TxStore,\n tables: Tables,\n input: AtomicBaselineApproval,\n): Promise<void> {\n const snapshot = (await tx.get(\n tables.snapshots,\n input.snapshot.id,\n )) as unknown as Snapshot | null;\n if (\n !snapshot ||\n snapshot.projectId !== input.snapshot.projectId ||\n snapshot.buildId !== input.snapshot.buildId ||\n snapshot.status !== input.snapshot.status ||\n snapshot.updatedAt !== input.snapshot.updatedAt ||\n snapshot.screenshotPath !== input.snapshot.screenshotPath ||\n snapshot.baselineId !== input.snapshot.baselineId ||\n snapshot.baselineVersion !== input.snapshot.baselineVersion\n )\n throw new BaselineApprovalConflict(\"Snapshot changed during approval; reload and retry\");\n const build = (await tx.get(tables.builds, snapshot.buildId)) as unknown as Build | null;\n const project = (await tx.get(tables.projects, snapshot.projectId)) as unknown as Project | null;\n if (\n !build ||\n !project ||\n build.projectId !== project.id ||\n build.status === \"cancelled\" ||\n build.gitBranch !== input.branch\n )\n throw new BaselineApprovalConflict(\"Build is unavailable for approval\");\n const own = await baselineFor(tx, tables, snapshot, build.gitBranch);\n const current =\n own ??\n (build.gitBranch === project.gitDefaultBranch\n ? null\n : await baselineFor(tx, tables, snapshot, project.gitDefaultBranch));\n const status = baselineStatus(snapshot, current);\n if (\n (snapshot.status === \"new\" || snapshot.status === \"changed\") &&\n isBaselineDrifted(status) &&\n !input.force\n )\n throw new BaselineApprovalConflict(\"Baseline changed after this diff was computed\", status);\n await tx.update(tables.snapshots, snapshot.id, {\n status: \"approved\",\n reviewedBy: input.reviewedBy,\n reviewedAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n });\n}\n\nasync function baselineFor(\n tx: TxStore,\n tables: Tables,\n snapshot: Snapshot,\n branch: string,\n): Promise<Baseline | null> {\n const rows = await tx.list(tables.baselines, {\n where: and(\n eq(col(tables.baselines, \"projectId\"), snapshot.projectId),\n eq(col(tables.baselines, \"storyId\"), snapshot.storyId),\n eq(col(tables.baselines, \"viewportName\"), snapshot.viewportName),\n eq(col(tables.baselines, \"browser\"), snapshot.browser ?? \"chromium\"),\n eq(col(tables.baselines, \"branch\"), branch),\n ),\n limit: 1,\n });\n return (rows[0] as unknown as Baseline | undefined) ?? null;\n}\n"],"mappings":";;;;;;;;;AAiBA,IAAa,2BAAb,cAA8C,sBAAsB;CAClE;CACA,YAAY,SAAiB,aAA8B;EACzD,MAAM,OAAO;EACb,KAAK,cAAc;CACrB;AACF;AAEA,eAAsB,qBACpB,IACA,QACA,OACe;CACf,MAAM,WAAY,MAAM,GAAG,IACzB,OAAO,WACP,MAAM,SAAS,EACjB;CACA,IACE,CAAC,YACD,SAAS,cAAc,MAAM,SAAS,aACtC,SAAS,YAAY,MAAM,SAAS,WACpC,SAAS,WAAW,MAAM,SAAS,UACnC,SAAS,cAAc,MAAM,SAAS,aACtC,SAAS,mBAAmB,MAAM,SAAS,kBAC3C,SAAS,eAAe,MAAM,SAAS,cACvC,SAAS,oBAAoB,MAAM,SAAS,iBAE5C,MAAM,IAAI,yBAAyB,oDAAoD;CACzF,MAAM,QAAS,MAAM,GAAG,IAAI,OAAO,QAAQ,SAAS,OAAO;CAC3D,MAAM,UAAW,MAAM,GAAG,IAAI,OAAO,UAAU,SAAS,SAAS;CACjE,IACE,CAAC,SACD,CAAC,WACD,MAAM,cAAc,QAAQ,MAC5B,MAAM,WAAW,eACjB,MAAM,cAAc,MAAM,QAE1B,MAAM,IAAI,yBAAyB,mCAAmC;CAExE,MAAM,UACJ,MAFgB,YAAY,IAAI,QAAQ,UAAU,MAAM,SAAS,MAGhE,MAAM,cAAc,QAAQ,mBACzB,OACA,MAAM,YAAY,IAAI,QAAQ,UAAU,QAAQ,gBAAgB;CACtE,MAAM,SAAS,eAAe,UAAU,OAAO;CAC/C,KACG,SAAS,WAAW,SAAS,SAAS,WAAW,cAClD,kBAAkB,MAAM,KACxB,CAAC,MAAM,OAEP,MAAM,IAAI,yBAAyB,iDAAiD,MAAM;CAC5F,MAAM,GAAG,OAAO,OAAO,WAAW,SAAS,IAAI;EAC7C,QAAQ;EACR,YAAY,MAAM;EAClB,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;EACnC,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;CACpC,CAAC;AACH;AAEA,eAAe,YACb,IACA,QACA,UACA,QAC0B;CAW1B,QAAQ,MAVW,GAAG,KAAK,OAAO,WAAW;EAC3C,OAAO,IACL,GAAG,IAAI,OAAO,WAAW,WAAW,GAAG,SAAS,SAAS,GACzD,GAAG,IAAI,OAAO,WAAW,SAAS,GAAG,SAAS,OAAO,GACrD,GAAG,IAAI,OAAO,WAAW,cAAc,GAAG,SAAS,YAAY,GAC/D,GAAG,IAAI,OAAO,WAAW,SAAS,GAAG,SAAS,WAAW,UAAU,GACnE,GAAG,IAAI,OAAO,WAAW,QAAQ,GAAG,MAAM,CAC5C;EACA,OAAO;CACT,CAAC,EAAA,CACY,MAA0C;AACzD"}