@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,12 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { DEFAULT_EVIDENCE_LIMITS, resolveLimits } from "./insights/limits.mjs";
5
+ import { redactText } from "./insights/redact.mjs";
6
+ import { buildTriageEvidence, rankSnapshots, snapshotKey } from "./insights/evidence.mjs";
7
+ import { buildHealthEvidence } from "./insights/evidence-health.mjs";
8
+ import { healthEnvelopeSchema, triageEnvelopeSchema } from "./insights/envelope.mjs";
9
+ import { computeInputHash } from "./insights/hash.mjs";
10
+ import { BUDGET_THRESHOLDS, countedTokens, crossedThresholds, utcDay, utcDayStart } from "./insights/budget.mjs";
11
+ import { HEALTH_SYSTEM, PROMPT_VERSION, TRIAGE_SYSTEM } from "./insights/prompts/v1.mjs";
12
+ export { BUDGET_THRESHOLDS, DEFAULT_EVIDENCE_LIMITS, HEALTH_SYSTEM, PROMPT_VERSION, TRIAGE_SYSTEM, buildHealthEvidence, buildTriageEvidence, computeInputHash, countedTokens, crossedThresholds, healthEnvelopeSchema, rankSnapshots, redactText, resolveLimits, snapshotKey, triageEnvelopeSchema, utcDay, utcDayStart };
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
@@ -1,8 +1,9 @@
1
1
  import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
+ import { redactSecrets } from "./utils/redact.mjs";
4
5
  import pino from "pino";
5
- //#region src/logger.ts
6
+ // src/logger.ts
6
7
  /**
7
8
  * Create the structured JSON logger used across StoryShelf.
8
9
  *
@@ -31,10 +32,24 @@ function createShelfLogger(options = {}) {
31
32
  return pino({
32
33
  level: options.level ?? process.env["LOG_LEVEL"] ?? "info",
33
34
  base: { env: options.env ?? process.env["NODE_ENV"] },
34
- mixin: options.mixin
35
+ mixin: options.mixin,
36
+ serializers: { err: redactedError }
35
37
  }, transport);
36
38
  }
37
- //#endregion
39
+ /**
40
+ * Pino's error serializer, with secrets scrubbed from the message and stack: a runner's error can
41
+ * quote the signed Storybook URL it failed to open (ADR 0007, decision 5).
42
+ */
43
+ function redactedError(err) {
44
+ const serialized = pino.stdSerializers.err(err);
45
+ if (serialized === null || typeof serialized !== "object") return serialized;
46
+ const record = serialized;
47
+ for (const key of ["message", "stack"]) {
48
+ const value = record[key];
49
+ if (typeof value === "string") record[key] = redactSecrets(value);
50
+ }
51
+ return record;
52
+ }
38
53
  export { createShelfLogger };
39
54
 
40
55
  //# sourceMappingURL=logger.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"logger.mjs","names":[],"sources":["../src/logger.ts"],"sourcesContent":["import pino from \"pino\";\nimport type { Logger } from \"pino\";\n\n/**\n * Create the structured JSON logger used across StoryShelf.\n *\n * Logging conventions:\n * - Always log structured objects, never interpolate into the message:\n * `logger.info({ projectId, buildId }, \"build started\")`.\n * - Attach errors as an `err` child field rather than stringifying into the message:\n * `logger.error({ err }, \"capture failed\")`.\n * - Derive scoped child loggers for background work:\n * `const captureLogger = logger.child({ buildId })`.\n *\n * The default sink is stdout. The level resolves as explicit option, then\n * the `LOG_LEVEL` environment variable, then `\"info\"` — so `LOG_LEVEL=debug`\n * configures a default-constructed logger with no code changes. Unknown\n * levels throw at construction (fail fast on typos). Hosted observability\n * platforms (Sentry, PostHog, Datadog, GCP, OTEL collector, etc.) are added\n * as pino worker `transports` — they are sinks for this logger, not\n * standalone loggers.\n */\nexport function createShelfLogger(options: LoggerOptions = {}): Logger {\n const targets = [\n { target: \"pino/file\", options: { destination: 1 } },\n ...(options.transports ?? []),\n ];\n const transport = pino.transport({ targets });\n return pino(\n {\n level: options.level ?? process.env[\"LOG_LEVEL\"] ?? \"info\",\n base: { env: options.env ?? process.env[\"NODE_ENV\"] },\n mixin: options.mixin,\n },\n transport,\n );\n}\n\n/** Pino logger type shared across StoryShelf. */\nexport type { Logger };\n\n/** A pino worker transport to attach to the logger output. */\nexport interface PinoTransport {\n /** Package name or absolute path of the transport module. */\n target: string;\n /** Options passed to the transport worker. */\n options?: Record<string, unknown>;\n}\n\n/** Configuration for constructing the shelf logger. */\nexport interface LoggerOptions {\n /** Minimum level to emit. Defaults to `LOG_LEVEL` env, then `\"info\"`. */\n level?: string;\n /** Extra pino worker transports appended to the default stdout sink. */\n transports?: PinoTransport[];\n /** Deployment environment recorded in the `env` base field. Defaults to `NODE_ENV`. */\n env?: string;\n /**\n * Per-line mixin merged into every log record. Used for OTEL trace\n * correlation (`otelLogMixin` from `@storyshelf/observability`).\n */\n mixin?: () => Record<string, unknown>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,kBAAkB,UAAyB,CAAC,GAAW;CACrE,MAAM,UAAU,CACd;EAAE,QAAQ;EAAa,SAAS,EAAE,aAAa,EAAE;CAAE,GACnD,GAAI,QAAQ,cAAc,CAAC,CAC7B;CACA,MAAM,YAAY,KAAK,UAAU,EAAE,QAAQ,CAAC;CAC5C,OAAO,KACL;EACE,OAAO,QAAQ,SAAS,QAAQ,IAAI,gBAAgB;EACpD,MAAM,EAAE,KAAK,QAAQ,OAAO,QAAQ,IAAI,YAAY;EACpD,OAAO,QAAQ;CACjB,GACA,SACF;AACF"}
1
+ {"version":3,"file":"logger.mjs","names":[],"sources":["../src/logger.ts"],"sourcesContent":["import pino from \"pino\";\nimport type { Logger } from \"pino\";\nimport { redactSecrets } from \"./utils/redact.ts\";\n\n/**\n * Create the structured JSON logger used across StoryShelf.\n *\n * Logging conventions:\n * - Always log structured objects, never interpolate into the message:\n * `logger.info({ projectId, buildId }, \"build started\")`.\n * - Attach errors as an `err` child field rather than stringifying into the message:\n * `logger.error({ err }, \"capture failed\")`.\n * - Derive scoped child loggers for background work:\n * `const captureLogger = logger.child({ buildId })`.\n *\n * The default sink is stdout. The level resolves as explicit option, then\n * the `LOG_LEVEL` environment variable, then `\"info\"` — so `LOG_LEVEL=debug`\n * configures a default-constructed logger with no code changes. Unknown\n * levels throw at construction (fail fast on typos). Hosted observability\n * platforms (Sentry, PostHog, Datadog, GCP, OTEL collector, etc.) are added\n * as pino worker `transports` — they are sinks for this logger, not\n * standalone loggers.\n */\nexport function createShelfLogger(options: LoggerOptions = {}): Logger {\n const targets = [\n { target: \"pino/file\", options: { destination: 1 } },\n ...(options.transports ?? []),\n ];\n const transport = pino.transport({ targets });\n return pino(\n {\n level: options.level ?? process.env[\"LOG_LEVEL\"] ?? \"info\",\n base: { env: options.env ?? process.env[\"NODE_ENV\"] },\n mixin: options.mixin,\n serializers: { err: redactedError },\n },\n transport,\n );\n}\n\n/**\n * Pino's error serializer, with secrets scrubbed from the message and stack: a runner's error can\n * quote the signed Storybook URL it failed to open (ADR 0007, decision 5).\n */\nfunction redactedError(err: unknown): unknown {\n const serialized: unknown = pino.stdSerializers.err(err as Error);\n if (serialized === null || typeof serialized !== \"object\") {\n return serialized;\n }\n const record = serialized as Record<string, unknown>;\n for (const key of [\"message\", \"stack\"]) {\n const value = record[key];\n if (typeof value === \"string\") {\n record[key] = redactSecrets(value);\n }\n }\n return record;\n}\n\n/** Pino logger type shared across StoryShelf. */\nexport type { Logger };\n\n/** A pino worker transport to attach to the logger output. */\nexport interface PinoTransport {\n /** Package name or absolute path of the transport module. */\n target: string;\n /** Options passed to the transport worker. */\n options?: Record<string, unknown>;\n}\n\n/** Configuration for constructing the shelf logger. */\nexport interface LoggerOptions {\n /** Minimum level to emit. Defaults to `LOG_LEVEL` env, then `\"info\"`. */\n level?: string;\n /** Extra pino worker transports appended to the default stdout sink. */\n transports?: PinoTransport[];\n /** Deployment environment recorded in the `env` base field. Defaults to `NODE_ENV`. */\n env?: string;\n /**\n * Per-line mixin merged into every log record. Used for OTEL trace\n * correlation (`otelLogMixin` from `@storyshelf/observability`).\n */\n mixin?: () => Record<string, unknown>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,kBAAkB,UAAyB,CAAC,GAAW;CACrE,MAAM,UAAU,CACd;EAAE,QAAQ;EAAa,SAAS,EAAE,aAAa,EAAE;CAAE,GACnD,GAAI,QAAQ,cAAc,CAAC,CAC7B;CACA,MAAM,YAAY,KAAK,UAAU,EAAE,QAAQ,CAAC;CAC5C,OAAO,KACL;EACE,OAAO,QAAQ,SAAS,QAAQ,IAAI,gBAAgB;EACpD,MAAM,EAAE,KAAK,QAAQ,OAAO,QAAQ,IAAI,YAAY;EACpD,OAAO,QAAQ;EACf,aAAa,EAAE,KAAK,cAAc;CACpC,GACA,SACF;AACF;;;;;AAMA,SAAS,cAAc,KAAuB;CAC5C,MAAM,aAAsB,KAAK,eAAe,IAAI,GAAY;CAChE,IAAI,eAAe,QAAQ,OAAO,eAAe,UAC/C,OAAO;CAET,MAAM,SAAS;CACf,KAAK,MAAM,OAAO,CAAC,WAAW,OAAO,GAAG;EACtC,MAAM,QAAQ,OAAO;EACrB,IAAI,OAAO,UAAU,UACnB,OAAO,OAAO,cAAc,KAAK;CAErC;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 { DatabaseAdapter } from "../adapter/database.mjs";
4
+ import { AiBudgetAlertRow } from "../schema/insight.mjs";
5
+ import { Table } from "drizzle-orm";
6
+ /** Tables required by {@link AiBudgetAlertModel}. */
7
+ interface AiBudgetAlertTables {
8
+ aiBudgetAlerts: Table;
9
+ }
10
+ /** Data operations for budget alert claims. */
11
+ declare class AiBudgetAlertModel {
12
+ private readonly tables;
13
+ private readonly db;
14
+ constructor(db: DatabaseAdapter, tables?: AiBudgetAlertTables);
15
+ /** Claim `(day, threshold)`; true only for the single instance that inserted it. */
16
+ claim(day: string, threshold: number): Promise<boolean>;
17
+ /** Claims already made for a day. */
18
+ listForDay(day: string): Promise<AiBudgetAlertRow[]>;
19
+ }
20
+ export { AiBudgetAlertModel, AiBudgetAlertTables };
21
+ //# sourceMappingURL=ai-budget-alert.d.mts.map
@@ -0,0 +1,37 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { col } from "./columns.mjs";
5
+ import { eq } from "drizzle-orm";
6
+ // src/models/ai-budget-alert.ts
7
+ /** Budget-threshold alert claims: the primary key makes "once per day" atomic. */
8
+ /** Data operations for budget alert claims. */
9
+ var AiBudgetAlertModel = class {
10
+ tables;
11
+ db;
12
+ constructor(db, tables) {
13
+ this.db = db;
14
+ this.tables = tables ?? { aiBudgetAlerts: db.tables.aiBudgetAlerts };
15
+ }
16
+ /** Claim `(day, threshold)`; true only for the single instance that inserted it. */
17
+ async claim(day, threshold) {
18
+ try {
19
+ await this.db.insert(this.tables.aiBudgetAlerts, {
20
+ id: `${day}:${threshold}`,
21
+ day,
22
+ threshold,
23
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
24
+ });
25
+ return true;
26
+ } catch {
27
+ return false;
28
+ }
29
+ }
30
+ /** Claims already made for a day. */
31
+ async listForDay(day) {
32
+ return await this.db.list(this.tables.aiBudgetAlerts, { where: eq(col(this.tables.aiBudgetAlerts, "day"), day) });
33
+ }
34
+ };
35
+ export { AiBudgetAlertModel };
36
+
37
+ //# sourceMappingURL=ai-budget-alert.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-budget-alert.mjs","names":[],"sources":["../../src/models/ai-budget-alert.ts"],"sourcesContent":["/** Budget-threshold alert claims: the primary key makes \"once per day\" atomic. */\nimport { eq } from \"drizzle-orm\";\nimport type { Table } from \"drizzle-orm\";\nimport type { DatabaseAdapter } from \"../adapters/database.ts\";\nimport type { AiBudgetAlertRow } from \"../schema/insight.ts\";\nimport { col } from \"./columns.ts\";\n\n/** Tables required by {@link AiBudgetAlertModel}. */\nexport interface AiBudgetAlertTables {\n aiBudgetAlerts: Table;\n}\n\n/** Data operations for budget alert claims. */\nexport class AiBudgetAlertModel {\n private readonly tables: AiBudgetAlertTables;\n private readonly db: DatabaseAdapter;\n\n constructor(db: DatabaseAdapter, tables?: AiBudgetAlertTables) {\n this.db = db;\n this.tables = tables ?? { aiBudgetAlerts: db.tables.aiBudgetAlerts };\n }\n\n /** Claim `(day, threshold)`; true only for the single instance that inserted it. */\n async claim(day: string, threshold: number): Promise<boolean> {\n try {\n await this.db.insert(this.tables.aiBudgetAlerts, {\n id: `${day}:${threshold}`,\n day,\n threshold,\n createdAt: new Date().toISOString(),\n });\n return true;\n } catch {\n return false;\n }\n }\n\n /** Claims already made for a day. */\n async listForDay(day: string): Promise<AiBudgetAlertRow[]> {\n return (await this.db.list(this.tables.aiBudgetAlerts, {\n where: eq(col(this.tables.aiBudgetAlerts, \"day\"), day),\n })) as unknown as AiBudgetAlertRow[];\n }\n}\n"],"mappings":";;;;;;;;AAaA,IAAa,qBAAb,MAAgC;CAC9B;CACA;CAEA,YAAY,IAAqB,QAA8B;EAC7D,KAAK,KAAK;EACV,KAAK,SAAS,UAAU,EAAE,gBAAgB,GAAG,OAAO,eAAe;CACrE;;CAGA,MAAM,MAAM,KAAa,WAAqC;EAC5D,IAAI;GACF,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,gBAAgB;IAC/C,IAAI,GAAG,IAAI,GAAG;IACd;IACA;IACA,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;GACpC,CAAC;GACD,OAAO;EACT,QAAQ;GACN,OAAO;EACT;CACF;;CAGA,MAAM,WAAW,KAA0C;EACzD,OAAQ,MAAM,KAAK,GAAG,KAAK,KAAK,OAAO,gBAAgB,EACrD,OAAO,GAAG,IAAI,KAAK,OAAO,gBAAgB,KAAK,GAAG,GAAG,EACvD,CAAC;CACH;AACF"}
@@ -0,0 +1,38 @@
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 { AiUsageRow } from "../schema/insight.mjs";
5
+ import { Table } from "drizzle-orm";
6
+ /** Tables required by {@link AiUsageModel}. */
7
+ interface AiUsageTables {
8
+ aiUsage: Table;
9
+ }
10
+ /** Input for recording one provider call. */
11
+ interface AiUsageInput {
12
+ insightId: string | null;
13
+ projectId: string;
14
+ profile: string;
15
+ task: string;
16
+ model: string;
17
+ inputTokens: number;
18
+ outputTokens: number;
19
+ estimated: boolean;
20
+ images: number;
21
+ status: "ok" | "failed";
22
+ }
23
+ /** Data operations for AI usage rows. */
24
+ declare class AiUsageModel {
25
+ private readonly tables;
26
+ private readonly db;
27
+ constructor(db: DatabaseAdapter, tables?: AiUsageTables);
28
+ record(input: AiUsageInput): Promise<AiUsageRow>;
29
+ /** Page through rows since `sinceIso` (bounded pages; the list clamp is 1000). */
30
+ listSince(sinceIso: string): Promise<AiUsageRow[]>;
31
+ /** Calls recorded for a project since `sinceIso` (rolling-hour limit). */
32
+ countCalls(projectId: string, sinceIso: string): Promise<number>;
33
+ /** Delete rows older than `cutoffIso`; returns the number removed. */
34
+ purgeBefore(cutoffIso: string): Promise<number>;
35
+ private col;
36
+ }
37
+ export { AiUsageInput, AiUsageModel, AiUsageTables };
38
+ //# sourceMappingURL=ai-usage.d.mts.map
@@ -0,0 +1,60 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { ulid } from "../utils/ulid.mjs";
5
+ import { col } from "./columns.mjs";
6
+ import { and, asc, eq, gte, lt } from "drizzle-orm";
7
+ // src/models/ai-usage.ts
8
+ /** Provider-reported AI usage rows; budget and hourly limits are counted from them. */
9
+ const PAGE = 500;
10
+ /** Data operations for AI usage rows. */
11
+ var AiUsageModel = class {
12
+ tables;
13
+ db;
14
+ constructor(db, tables) {
15
+ this.db = db;
16
+ this.tables = tables ?? { aiUsage: db.tables.aiUsage };
17
+ }
18
+ async record(input) {
19
+ return await this.db.insert(this.tables.aiUsage, {
20
+ id: ulid(),
21
+ ...input,
22
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
23
+ });
24
+ }
25
+ /** Page through rows since `sinceIso` (bounded pages; the list clamp is 1000). */
26
+ async listSince(sinceIso) {
27
+ const all = [];
28
+ for (let offset = 0;; offset += PAGE) {
29
+ const page = await this.db.list(this.tables.aiUsage, {
30
+ where: gte(this.col("createdAt"), sinceIso),
31
+ orderBy: asc(this.col("id")),
32
+ limit: PAGE,
33
+ offset
34
+ });
35
+ all.push(...page);
36
+ if (page.length < PAGE) return all;
37
+ }
38
+ }
39
+ /** Calls recorded for a project since `sinceIso` (rolling-hour limit). */
40
+ async countCalls(projectId, sinceIso) {
41
+ return await this.db.count(this.tables.aiUsage, and(eq(this.col("projectId"), projectId), gte(this.col("createdAt"), sinceIso)));
42
+ }
43
+ /** Delete rows older than `cutoffIso`; returns the number removed. */
44
+ async purgeBefore(cutoffIso) {
45
+ const rows = await this.db.list(this.tables.aiUsage, {
46
+ where: lt(this.col("createdAt"), cutoffIso),
47
+ limit: 1e3
48
+ });
49
+ await Promise.all(rows.map(async (row) => {
50
+ await this.db.remove(this.tables.aiUsage, row.id);
51
+ }));
52
+ return rows.length;
53
+ }
54
+ col(name) {
55
+ return col(this.tables.aiUsage, name);
56
+ }
57
+ };
58
+ export { AiUsageModel };
59
+
60
+ //# sourceMappingURL=ai-usage.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-usage.mjs","names":[],"sources":["../../src/models/ai-usage.ts"],"sourcesContent":["/** Provider-reported AI usage rows; budget and hourly limits are counted from them. */\nimport { and, asc, eq, gte, lt } from \"drizzle-orm\";\nimport type { SQLWrapper, Table } from \"drizzle-orm\";\nimport type { DatabaseAdapter } from \"../adapters/database.ts\";\nimport type { AiUsageRow } from \"../schema/insight.ts\";\nimport { ulid } from \"../utils/ulid.ts\";\nimport { col } from \"./columns.ts\";\n\n/** Tables required by {@link AiUsageModel}. */\nexport interface AiUsageTables {\n aiUsage: Table;\n}\n\n/** Input for recording one provider call. */\nexport interface AiUsageInput {\n insightId: string | null;\n projectId: string;\n profile: string;\n task: string;\n model: string;\n inputTokens: number;\n outputTokens: number;\n estimated: boolean;\n images: number;\n status: \"ok\" | \"failed\";\n}\n\nconst PAGE = 500;\n\n/** Data operations for AI usage rows. */\nexport class AiUsageModel {\n private readonly tables: AiUsageTables;\n private readonly db: DatabaseAdapter;\n\n constructor(db: DatabaseAdapter, tables?: AiUsageTables) {\n this.db = db;\n this.tables = tables ?? { aiUsage: db.tables.aiUsage };\n }\n\n async record(input: AiUsageInput): Promise<AiUsageRow> {\n return (await this.db.insert(this.tables.aiUsage, {\n id: ulid(),\n ...input,\n createdAt: new Date().toISOString(),\n })) as unknown as AiUsageRow;\n }\n\n /** Page through rows since `sinceIso` (bounded pages; the list clamp is 1000). */\n async listSince(sinceIso: string): Promise<AiUsageRow[]> {\n const all: AiUsageRow[] = [];\n for (let offset = 0; ; offset += PAGE) {\n // Pages are inherently sequential (each needs the previous offset).\n // oxlint-disable-next-line no-await-in-loop\n const page = (await this.db.list(this.tables.aiUsage, {\n where: gte(this.col(\"createdAt\"), sinceIso),\n orderBy: asc(this.col(\"id\")),\n limit: PAGE,\n offset,\n })) as unknown as AiUsageRow[];\n all.push(...page);\n if (page.length < PAGE) {\n return all;\n }\n }\n }\n\n /** Calls recorded for a project since `sinceIso` (rolling-hour limit). */\n async countCalls(projectId: string, sinceIso: string): Promise<number> {\n return await this.db.count(\n this.tables.aiUsage,\n and(eq(this.col(\"projectId\"), projectId), gte(this.col(\"createdAt\"), sinceIso)),\n );\n }\n\n /** Delete rows older than `cutoffIso`; returns the number removed. */\n async purgeBefore(cutoffIso: string): Promise<number> {\n const rows = (await this.db.list(this.tables.aiUsage, {\n where: lt(this.col(\"createdAt\"), cutoffIso),\n limit: 1000,\n })) as unknown as AiUsageRow[];\n await Promise.all(\n rows.map(async (row) => {\n await this.db.remove(this.tables.aiUsage, row.id);\n }),\n );\n return rows.length;\n }\n\n private col(name: string): SQLWrapper {\n return col(this.tables.aiUsage, name);\n }\n}\n"],"mappings":";;;;;;;;AA2BA,MAAM,OAAO;;AAGb,IAAa,eAAb,MAA0B;CACxB;CACA;CAEA,YAAY,IAAqB,QAAwB;EACvD,KAAK,KAAK;EACV,KAAK,SAAS,UAAU,EAAE,SAAS,GAAG,OAAO,QAAQ;CACvD;CAEA,MAAM,OAAO,OAA0C;EACrD,OAAQ,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,SAAS;GAChD,IAAI,KAAK;GACT,GAAG;GACH,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;EACpC,CAAC;CACH;;CAGA,MAAM,UAAU,UAAyC;EACvD,MAAM,MAAoB,CAAC;EAC3B,KAAK,IAAI,SAAS,IAAK,UAAU,MAAM;GAGrC,MAAM,OAAQ,MAAM,KAAK,GAAG,KAAK,KAAK,OAAO,SAAS;IACpD,OAAO,IAAI,KAAK,IAAI,WAAW,GAAG,QAAQ;IAC1C,SAAS,IAAI,KAAK,IAAI,IAAI,CAAC;IAC3B,OAAO;IACP;GACF,CAAC;GACD,IAAI,KAAK,GAAG,IAAI;GAChB,IAAI,KAAK,SAAS,MAChB,OAAO;EAEX;CACF;;CAGA,MAAM,WAAW,WAAmB,UAAmC;EACrE,OAAO,MAAM,KAAK,GAAG,MACnB,KAAK,OAAO,SACZ,IAAI,GAAG,KAAK,IAAI,WAAW,GAAG,SAAS,GAAG,IAAI,KAAK,IAAI,WAAW,GAAG,QAAQ,CAAC,CAChF;CACF;;CAGA,MAAM,YAAY,WAAoC;EACpD,MAAM,OAAQ,MAAM,KAAK,GAAG,KAAK,KAAK,OAAO,SAAS;GACpD,OAAO,GAAG,KAAK,IAAI,WAAW,GAAG,SAAS;GAC1C,OAAO;EACT,CAAC;EACD,MAAM,QAAQ,IACZ,KAAK,IAAI,OAAO,QAAQ;GACtB,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,SAAS,IAAI,EAAE;EAClD,CAAC,CACH;EACA,OAAO,KAAK;CACd;CAEA,IAAY,MAA0B;EACpC,OAAO,IAAI,KAAK,OAAO,SAAS,IAAI;CACtC;AACF"}
@@ -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"}
@@ -0,0 +1,82 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { z } from "zod";
4
+ /** Identifies a StoryShelf baseline archive. */
5
+ declare const BASELINE_ARCHIVE_FORMAT = "storyshelf-baselines";
6
+ /** Current archive format version. */
7
+ declare const BASELINE_ARCHIVE_VERSION = 1;
8
+ /** Hard limits for archives (both directions). Zip64 is unsupported, so entries stay < 65535 and archives stay far below 4 GiB. */
9
+ declare const BASELINE_ARCHIVE_LIMITS: {
10
+ /** Maximum baselines in one archive. */
11
+ readonly maxBaselines: 50000;
12
+ /** Maximum size of one baseline PNG. */
13
+ readonly maxImageBytes: number;
14
+ /** Maximum size of `manifest.json`. */
15
+ readonly maxManifestBytes: number;
16
+ /**
17
+ * Maximum size of an archive in either direction: the combined uncompressed
18
+ * size of an import, and what an export may stream. Matches the import
19
+ * request-body ceiling, so every export can be imported back.
20
+ */
21
+ readonly maxArchiveBytes: number;
22
+ };
23
+ /** One baseline in the manifest. */
24
+ declare const baselineManifestEntrySchema: z.ZodObject<{
25
+ storyId: z.ZodString;
26
+ viewport: z.ZodString;
27
+ browser: z.ZodString;
28
+ branch: z.ZodString;
29
+ mode: z.ZodNullable<z.ZodString>;
30
+ infraHash: z.ZodNullable<z.ZodString>;
31
+ fingerprint: z.ZodOptional<z.ZodNullable<z.ZodString>>;
32
+ createdAt: z.ZodISODateTime;
33
+ updatedAt: z.ZodISODateTime;
34
+ file: z.ZodString;
35
+ sha256: z.ZodString;
36
+ }, z.core.$strip>;
37
+ /** Identity of a baseline the export could not read (listed, not archived). */
38
+ declare const baselineSkippedSchema: z.ZodObject<{
39
+ storyId: z.ZodString;
40
+ viewport: z.ZodString;
41
+ browser: z.ZodString;
42
+ branch: z.ZodString;
43
+ }, z.core.$strip>;
44
+ /** Archive manifest (`manifest.json`). */
45
+ declare const baselineManifestSchema: z.ZodObject<{
46
+ format: z.ZodLiteral<"storyshelf-baselines">;
47
+ version: z.ZodLiteral<1>;
48
+ exportedAt: z.ZodISODateTime;
49
+ project: z.ZodNullable<z.ZodString>;
50
+ branch: z.ZodNullable<z.ZodString>;
51
+ baselines: z.ZodArray<z.ZodObject<{
52
+ storyId: z.ZodString;
53
+ viewport: z.ZodString;
54
+ browser: z.ZodString;
55
+ branch: z.ZodString;
56
+ mode: z.ZodNullable<z.ZodString>;
57
+ infraHash: z.ZodNullable<z.ZodString>;
58
+ fingerprint: z.ZodOptional<z.ZodNullable<z.ZodString>>;
59
+ createdAt: z.ZodISODateTime;
60
+ updatedAt: z.ZodISODateTime;
61
+ file: z.ZodString;
62
+ sha256: z.ZodString;
63
+ }, z.core.$strip>>;
64
+ skipped: z.ZodOptional<z.ZodArray<z.ZodObject<{
65
+ storyId: z.ZodString;
66
+ viewport: z.ZodString;
67
+ browser: z.ZodString;
68
+ branch: z.ZodString;
69
+ }, z.core.$strip>>>;
70
+ }, z.core.$strip>;
71
+ /** One baseline in the manifest. */
72
+ type BaselineManifestEntry = z.infer<typeof baselineManifestEntrySchema>;
73
+ /** Archive manifest. */
74
+ type BaselineManifest = z.infer<typeof baselineManifestSchema>;
75
+ /** Identity of a baseline the export skipped. */
76
+ type BaselineSkipped = z.infer<typeof baselineSkippedSchema>;
77
+ /** An archive that is malformed, unsafe, over a limit, or inconsistent with its manifest. */
78
+ declare class BaselineArchiveError extends Error {
79
+ readonly name = "BaselineArchiveError";
80
+ }
81
+ export { BASELINE_ARCHIVE_FORMAT, BASELINE_ARCHIVE_LIMITS, BASELINE_ARCHIVE_VERSION, BaselineArchiveError, BaselineManifest, BaselineManifestEntry, BaselineSkipped, baselineManifestEntrySchema, baselineManifestSchema, baselineSkippedSchema };
82
+ //# sourceMappingURL=baseline-archive.d.mts.map
@@ -0,0 +1,105 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { modeSegment } from "../paths.mjs";
5
+ import { z } from "zod";
6
+ // src/models/baseline-archive.ts
7
+ /**
8
+ * Baseline archive format (v1): a zip holding `manifest.json` plus one PNG per
9
+ * baseline at `baselines/<branch>/<storyId>/<mode>.png` — the storage layout
10
+ * minus the instance-specific project id. The manifest is the source of truth
11
+ * on import; file names inside the zip are only lookup keys and are never used
12
+ * to build storage paths.
13
+ */
14
+ /** Identifies a StoryShelf baseline archive. */
15
+ const BASELINE_ARCHIVE_FORMAT = "storyshelf-baselines";
16
+ /** Current archive format version. */
17
+ const BASELINE_ARCHIVE_VERSION = 1;
18
+ /** Name of the manifest entry at the archive root. */
19
+ const BASELINE_MANIFEST_NAME = "manifest.json";
20
+ /** Hard limits for archives (both directions). Zip64 is unsupported, so entries stay < 65535 and archives stay far below 4 GiB. */
21
+ const BASELINE_ARCHIVE_LIMITS = {
22
+ /** Maximum baselines in one archive. */
23
+ maxBaselines: 5e4,
24
+ /** Maximum size of one baseline PNG. */
25
+ maxImageBytes: 67108864,
26
+ /** Maximum size of `manifest.json`. */
27
+ maxManifestBytes: 33554432,
28
+ /**
29
+ * Maximum size of an archive in either direction: the combined uncompressed
30
+ * size of an import, and what an export may stream. Matches the import
31
+ * request-body ceiling, so every export can be imported back.
32
+ */
33
+ maxArchiveBytes: 536870912
34
+ };
35
+ const isoTimestamp = z.iso.datetime({ offset: true });
36
+ /** One baseline in the manifest. */
37
+ const baselineManifestEntrySchema = z.object({
38
+ storyId: z.string().min(1).max(512),
39
+ viewport: z.string().min(1).max(256),
40
+ browser: z.string().min(1).max(64),
41
+ branch: z.string().min(1).max(512),
42
+ mode: z.string().max(65536).nullable(),
43
+ infraHash: z.string().max(512).nullable(),
44
+ /** JSON fingerprint behind `infraHash`; absent in archives from before fingerprints. */
45
+ fingerprint: z.string().max(4096).nullable().optional(),
46
+ createdAt: isoTimestamp,
47
+ updatedAt: isoTimestamp,
48
+ /** Zip entry holding the PNG. */
49
+ file: z.string().min(1).max(2048),
50
+ /** Lowercase hex SHA-256 of the PNG bytes. */
51
+ sha256: z.string().regex(/^[0-9a-f]{64}$/u)
52
+ });
53
+ /** Identity of a baseline the export could not read (listed, not archived). */
54
+ const baselineSkippedSchema = baselineManifestEntrySchema.pick({
55
+ storyId: true,
56
+ viewport: true,
57
+ browser: true,
58
+ branch: true
59
+ });
60
+ /** Archive manifest (`manifest.json`). */
61
+ const baselineManifestSchema = z.object({
62
+ format: z.literal(BASELINE_ARCHIVE_FORMAT),
63
+ version: z.literal(1),
64
+ exportedAt: isoTimestamp,
65
+ /** Source project slug (informational). */
66
+ project: z.string().nullable(),
67
+ /** Branch filter used by the export; null means every branch. */
68
+ branch: z.string().nullable(),
69
+ baselines: z.array(baselineManifestEntrySchema).max(BASELINE_ARCHIVE_LIMITS.maxBaselines),
70
+ skipped: z.array(baselineSkippedSchema).optional()
71
+ });
72
+ /** An archive that is malformed, unsafe, over a limit, or inconsistent with its manifest. */
73
+ var BaselineArchiveError = class extends Error {
74
+ name = "BaselineArchiveError";
75
+ };
76
+ /** Zip entry name for a baseline, mirroring the storage layout without the project id. */
77
+ function archiveFileName(branch, storyId, viewport, browser) {
78
+ return `baselines/${branch}/${storyId}/${modeSegment(viewport, browser)}.png`;
79
+ }
80
+ /** Stable identity key of a baseline (story, mode, browser, branch). */
81
+ function baselineIdentity(entry) {
82
+ return JSON.stringify([
83
+ entry.storyId,
84
+ entry.viewport,
85
+ entry.browser,
86
+ entry.branch
87
+ ]);
88
+ }
89
+ const PNG_SIGNATURE = Buffer.from([
90
+ 137,
91
+ 80,
92
+ 78,
93
+ 71,
94
+ 13,
95
+ 10,
96
+ 26,
97
+ 10
98
+ ]);
99
+ /** Whether `data` starts with the PNG file signature. */
100
+ function isPng(data) {
101
+ return data.length >= PNG_SIGNATURE.length && data.subarray(0, 8).equals(PNG_SIGNATURE);
102
+ }
103
+ export { BASELINE_ARCHIVE_FORMAT, BASELINE_ARCHIVE_LIMITS, BASELINE_ARCHIVE_VERSION, BASELINE_MANIFEST_NAME, BaselineArchiveError, archiveFileName, baselineIdentity, baselineManifestEntrySchema, baselineManifestSchema, baselineSkippedSchema, isPng };
104
+
105
+ //# sourceMappingURL=baseline-archive.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseline-archive.mjs","names":[],"sources":["../../src/models/baseline-archive.ts"],"sourcesContent":["/**\n * Baseline archive format (v1): a zip holding `manifest.json` plus one PNG per\n * baseline at `baselines/<branch>/<storyId>/<mode>.png` — the storage layout\n * minus the instance-specific project id. The manifest is the source of truth\n * on import; file names inside the zip are only lookup keys and are never used\n * to build storage paths.\n */\nimport { z } from \"zod\";\nimport { modeSegment } from \"../utils/paths.ts\";\n\n/** Identifies a StoryShelf baseline archive. */\nexport const BASELINE_ARCHIVE_FORMAT = \"storyshelf-baselines\";\n/** Current archive format version. */\nexport const BASELINE_ARCHIVE_VERSION = 1;\n/** Name of the manifest entry at the archive root. */\nexport const BASELINE_MANIFEST_NAME = \"manifest.json\";\n\n/** Hard limits for archives (both directions). Zip64 is unsupported, so entries stay < 65535 and archives stay far below 4 GiB. */\nexport const BASELINE_ARCHIVE_LIMITS = {\n /** Maximum baselines in one archive. */\n maxBaselines: 50_000,\n /** Maximum size of one baseline PNG. */\n maxImageBytes: 64 * 1024 * 1024,\n /** Maximum size of `manifest.json`. */\n maxManifestBytes: 32 * 1024 * 1024,\n /**\n * Maximum size of an archive in either direction: the combined uncompressed\n * size of an import, and what an export may stream. Matches the import\n * request-body ceiling, so every export can be imported back.\n */\n maxArchiveBytes: 512 * 1024 * 1024,\n} as const;\n\nconst isoTimestamp = z.iso.datetime({ offset: true });\n\n/** One baseline in the manifest. */\nexport const baselineManifestEntrySchema = z.object({\n storyId: z.string().min(1).max(512),\n viewport: z.string().min(1).max(256),\n browser: z.string().min(1).max(64),\n branch: z.string().min(1).max(512),\n mode: z.string().max(65_536).nullable(),\n infraHash: z.string().max(512).nullable(),\n /** JSON fingerprint behind `infraHash`; absent in archives from before fingerprints. */\n fingerprint: z.string().max(4096).nullable().optional(),\n createdAt: isoTimestamp,\n updatedAt: isoTimestamp,\n /** Zip entry holding the PNG. */\n file: z.string().min(1).max(2048),\n /** Lowercase hex SHA-256 of the PNG bytes. */\n sha256: z.string().regex(/^[0-9a-f]{64}$/u),\n});\n\n/** Identity of a baseline the export could not read (listed, not archived). */\nexport const baselineSkippedSchema = baselineManifestEntrySchema.pick({\n storyId: true,\n viewport: true,\n browser: true,\n branch: true,\n});\n\n/** Archive manifest (`manifest.json`). */\nexport const baselineManifestSchema = z.object({\n format: z.literal(BASELINE_ARCHIVE_FORMAT),\n version: z.literal(BASELINE_ARCHIVE_VERSION),\n exportedAt: isoTimestamp,\n /** Source project slug (informational). */\n project: z.string().nullable(),\n /** Branch filter used by the export; null means every branch. */\n branch: z.string().nullable(),\n baselines: z.array(baselineManifestEntrySchema).max(BASELINE_ARCHIVE_LIMITS.maxBaselines),\n skipped: z.array(baselineSkippedSchema).optional(),\n});\n\n/** One baseline in the manifest. */\nexport type BaselineManifestEntry = z.infer<typeof baselineManifestEntrySchema>;\n/** Archive manifest. */\nexport type BaselineManifest = z.infer<typeof baselineManifestSchema>;\n/** Identity of a baseline the export skipped. */\nexport type BaselineSkipped = z.infer<typeof baselineSkippedSchema>;\n\n/** An archive that is malformed, unsafe, over a limit, or inconsistent with its manifest. */\nexport class BaselineArchiveError extends Error {\n override readonly name = \"BaselineArchiveError\";\n}\n\n/** Zip entry name for a baseline, mirroring the storage layout without the project id. */\nexport function archiveFileName(\n branch: string,\n storyId: string,\n viewport: string,\n browser: string,\n): string {\n return `baselines/${branch}/${storyId}/${modeSegment(viewport, browser)}.png`;\n}\n\n/** Stable identity key of a baseline (story, mode, browser, branch). */\nexport function baselineIdentity(entry: BaselineSkipped): string {\n return JSON.stringify([entry.storyId, entry.viewport, entry.browser, entry.branch]);\n}\n\nconst PNG_SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);\n\n/** Whether `data` starts with the PNG file signature. */\nexport function isPng(data: Buffer): boolean {\n return data.length >= PNG_SIGNATURE.length && data.subarray(0, 8).equals(PNG_SIGNATURE);\n}\n"],"mappings":";;;;;;;;;;;;;;AAWA,MAAa,0BAA0B;;AAEvC,MAAa,2BAA2B;;AAExC,MAAa,yBAAyB;;AAGtC,MAAa,0BAA0B;;CAErC,cAAc;;CAEd,eAAe;;CAEf,kBAAkB;;;;;;CAMlB,iBAAiB;AACnB;AAEA,MAAM,eAAe,EAAE,IAAI,SAAS,EAAE,QAAQ,KAAK,CAAC;;AAGpD,MAAa,8BAA8B,EAAE,OAAO;CAClD,SAAS,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG;CAClC,UAAU,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG;CACnC,SAAS,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE;CACjC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG;CACjC,MAAM,EAAE,OAAO,CAAC,CAAC,IAAI,KAAM,CAAC,CAAC,SAAS;CACtC,WAAW,EAAE,OAAO,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,SAAS;;CAExC,aAAa,EAAE,OAAO,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS;CACtD,WAAW;CACX,WAAW;;CAEX,MAAM,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI;;CAEhC,QAAQ,EAAE,OAAO,CAAC,CAAC,MAAM,iBAAiB;AAC5C,CAAC;;AAGD,MAAa,wBAAwB,4BAA4B,KAAK;CACpE,SAAS;CACT,UAAU;CACV,SAAS;CACT,QAAQ;AACV,CAAC;;AAGD,MAAa,yBAAyB,EAAE,OAAO;CAC7C,QAAQ,EAAE,QAAQ,uBAAuB;CACzC,SAAS,EAAE,QAAA,CAAgC;CAC3C,YAAY;;CAEZ,SAAS,EAAE,OAAO,CAAC,CAAC,SAAS;;CAE7B,QAAQ,EAAE,OAAO,CAAC,CAAC,SAAS;CAC5B,WAAW,EAAE,MAAM,2BAA2B,CAAC,CAAC,IAAI,wBAAwB,YAAY;CACxF,SAAS,EAAE,MAAM,qBAAqB,CAAC,CAAC,SAAS;AACnD,CAAC;;AAUD,IAAa,uBAAb,cAA0C,MAAM;CAC9C,OAAyB;AAC3B;;AAGA,SAAgB,gBACd,QACA,SACA,UACA,SACQ;CACR,OAAO,aAAa,OAAO,GAAG,QAAQ,GAAG,YAAY,UAAU,OAAO,EAAE;AAC1E;;AAGA,SAAgB,iBAAiB,OAAgC;CAC/D,OAAO,KAAK,UAAU;EAAC,MAAM;EAAS,MAAM;EAAU,MAAM;EAAS,MAAM;CAAM,CAAC;AACpF;AAEA,MAAM,gBAAgB,OAAO,KAAK;CAAC;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;AAAI,CAAC;;AAGlF,SAAgB,MAAM,MAAuB;CAC3C,OAAO,KAAK,UAAU,cAAc,UAAU,KAAK,SAAS,GAAG,CAAC,CAAC,CAAC,OAAO,aAAa;AACxF"}
@@ -0,0 +1,66 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import "../adapters/capture-target.mjs";
5
+ import { col } from "./columns.mjs";
6
+ import { BaselineWriteConflict } from "./baseline-conflict.mjs";
7
+ import { and, eq } from "drizzle-orm";
8
+ // src/models/baseline-atomic.ts
9
+ /** Transactional baseline mutation for adapters with explicit reference lifecycle support. */
10
+ /** Atomically change the baseline row and its complete build-reference set. */
11
+ async function upsertAtomicBaseline(lifecycle, tables, input) {
12
+ const owner = {
13
+ projectId: input.projectId,
14
+ type: "baseline",
15
+ id: input.id
16
+ };
17
+ const generation = await lifecycle.referenceGeneration(owner);
18
+ return (await lifecycle.replaceFencedReferences(owner, generation, input.sourceBuildId ? [input.sourceBuildId] : [], async (tx) => {
19
+ await input.beforeWrite?.(tx);
20
+ return await writeBaseline(tx, tables, input);
21
+ })).result;
22
+ }
23
+ async function writeBaseline(tx, tables, input) {
24
+ const existing = (await tx.list(tables.baselines, {
25
+ where: and(eq(col(tables.baselines, "projectId"), input.projectId), eq(col(tables.baselines, "storyId"), input.storyId), eq(col(tables.baselines, "viewportName"), input.viewport), eq(col(tables.baselines, "branch"), input.branch), eq(col(tables.baselines, "browser"), input.browser)),
26
+ limit: 1
27
+ }))[0] ?? null;
28
+ assertBaselineUnchanged(existing, input);
29
+ if (input.sourceBuildId) await assertSource(tx, tables.snapshots, input);
30
+ const now = nextBaselineVersion(existing?.updatedAt ?? null, /* @__PURE__ */ new Date());
31
+ const fields = {
32
+ snapshotId: input.snapshotId,
33
+ sourceBuildId: input.sourceBuildId,
34
+ screenshotPath: input.screenshotPath,
35
+ infraHash: input.infraHash ?? existing?.infraHash ?? null,
36
+ fingerprint: input.fingerprint ?? existing?.fingerprint ?? null,
37
+ mode: input.mode ?? existing?.mode ?? null,
38
+ updatedAt: now
39
+ };
40
+ return existing ? await tx.update(tables.baselines, existing.id, fields) : await tx.insert(tables.baselines, {
41
+ ...fields,
42
+ id: input.id,
43
+ projectId: input.projectId,
44
+ storyId: input.storyId,
45
+ viewportName: input.viewport,
46
+ branch: input.branch,
47
+ browser: input.browser,
48
+ createdAt: now
49
+ });
50
+ }
51
+ function assertBaselineUnchanged(existing, input) {
52
+ if ((existing?.id ?? null) !== input.existingId || (existing?.updatedAt ?? null) !== input.existingVersion) throw new BaselineWriteConflict("Baseline changed during promotion; retry");
53
+ }
54
+ /** Keep the version advancing even when updates share a millisecond or clocks move backwards. */
55
+ function nextBaselineVersion(previous, now) {
56
+ const last = previous === null ? NaN : Date.parse(previous);
57
+ return new Date(Number.isFinite(last) ? Math.max(now.getTime(), last + 1) : now.getTime()).toISOString();
58
+ }
59
+ async function assertSource(tx, table, input) {
60
+ const row = await tx.get(table, input.snapshotId);
61
+ const origin = row?.inherited ? row.sourceBuildId : row?.buildId;
62
+ if (!row || row.projectId !== input.projectId || row.storyId !== input.storyId || row.viewportName !== input.viewport || (row.browser ?? "chromium") !== input.browser || row.screenshotPath !== input.originalPath || origin !== input.sourceBuildId) throw new BaselineWriteConflict("Source snapshot changed during promotion; retry");
63
+ }
64
+ export { nextBaselineVersion, upsertAtomicBaseline };
65
+
66
+ //# sourceMappingURL=baseline-atomic.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseline-atomic.mjs","names":[],"sources":["../../src/models/baseline-atomic.ts"],"sourcesContent":["/** Transactional baseline mutation for adapters with explicit reference lifecycle support. */\nimport { and, eq } from \"drizzle-orm\";\nimport type { Table } from \"drizzle-orm\";\nimport { DEFAULT_BROWSER } from \"../adapters/capture-runner.ts\";\nimport type { BuildReferenceLifecycle, TxStore } from \"../adapters/database.ts\";\nimport type { Baseline } from \"../schema/baseline.ts\";\nimport type { Snapshot } from \"../schema/snapshot.ts\";\nimport { BaselineWriteConflict } from \"./baseline-conflict.ts\";\nimport { col } from \"./columns.ts\";\n\nexport interface AtomicBaselineInput {\n id: string;\n existingId: string | null;\n existingVersion: string | null;\n projectId: string;\n storyId: string;\n viewport: string;\n branch: string;\n browser: string;\n snapshotId: string;\n sourceBuildId: string | null;\n originalPath: string;\n screenshotPath: string;\n infraHash: string | null | undefined;\n fingerprint: string | null | undefined;\n mode: string | null | undefined;\n beforeWrite?: (tx: TxStore) => Promise<void>;\n}\n\n/** Atomically change the baseline row and its complete build-reference set. */\nexport async function upsertAtomicBaseline(\n lifecycle: BuildReferenceLifecycle,\n tables: { baselines: Table; snapshots: Table },\n input: AtomicBaselineInput,\n): Promise<Baseline> {\n const owner = { projectId: input.projectId, type: \"baseline\" as const, id: input.id };\n const generation = await lifecycle.referenceGeneration(owner);\n const updated = await lifecycle.replaceFencedReferences(\n owner,\n generation,\n input.sourceBuildId ? [input.sourceBuildId] : [],\n async (tx) => {\n await input.beforeWrite?.(tx);\n return await writeBaseline(tx, tables, input);\n },\n );\n return updated.result;\n}\n\nasync function writeBaseline(\n tx: TxStore,\n tables: { baselines: Table; snapshots: Table },\n input: AtomicBaselineInput,\n): Promise<Baseline> {\n const rows = (await tx.list(tables.baselines, {\n where: and(\n eq(col(tables.baselines, \"projectId\"), input.projectId),\n eq(col(tables.baselines, \"storyId\"), input.storyId),\n eq(col(tables.baselines, \"viewportName\"), input.viewport),\n eq(col(tables.baselines, \"branch\"), input.branch),\n eq(col(tables.baselines, \"browser\"), input.browser),\n ),\n limit: 1,\n })) as unknown as Baseline[];\n const existing = rows[0] ?? null;\n assertBaselineUnchanged(existing, input);\n if (input.sourceBuildId) await assertSource(tx, tables.snapshots, input);\n const now = nextBaselineVersion(existing?.updatedAt ?? null, new Date());\n const fields = {\n snapshotId: input.snapshotId,\n sourceBuildId: input.sourceBuildId,\n screenshotPath: input.screenshotPath,\n infraHash: input.infraHash ?? existing?.infraHash ?? null,\n fingerprint: input.fingerprint ?? existing?.fingerprint ?? null,\n mode: input.mode ?? existing?.mode ?? null,\n updatedAt: now,\n };\n return (existing\n ? await tx.update(tables.baselines, existing.id, fields)\n : await tx.insert(tables.baselines, {\n ...fields,\n id: input.id,\n projectId: input.projectId,\n storyId: input.storyId,\n viewportName: input.viewport,\n branch: input.branch,\n browser: input.browser,\n createdAt: now,\n })) as unknown as Baseline;\n}\n\nfunction assertBaselineUnchanged(existing: Baseline | null, input: AtomicBaselineInput): void {\n if (\n (existing?.id ?? null) !== input.existingId ||\n (existing?.updatedAt ?? null) !== input.existingVersion\n )\n throw new BaselineWriteConflict(\"Baseline changed during promotion; retry\");\n}\n\n/** Keep the version advancing even when updates share a millisecond or clocks move backwards. */\nexport function nextBaselineVersion(previous: string | null, now: Date): string {\n const last = previous === null ? Number.NaN : Date.parse(previous);\n return new Date(\n Number.isFinite(last) ? Math.max(now.getTime(), last + 1) : now.getTime(),\n ).toISOString();\n}\n\nasync function assertSource(tx: TxStore, table: Table, input: AtomicBaselineInput): Promise<void> {\n const row = (await tx.get(table, input.snapshotId)) as unknown as Snapshot | null;\n const origin = row?.inherited ? row.sourceBuildId : row?.buildId;\n if (\n !row ||\n row.projectId !== input.projectId ||\n row.storyId !== input.storyId ||\n row.viewportName !== input.viewport ||\n (row.browser ?? DEFAULT_BROWSER) !== input.browser ||\n row.screenshotPath !== input.originalPath ||\n origin !== input.sourceBuildId\n ) {\n throw new BaselineWriteConflict(\"Source snapshot changed during promotion; retry\");\n }\n}\n"],"mappings":";;;;;;;;;;AA8BA,eAAsB,qBACpB,WACA,QACA,OACmB;CACnB,MAAM,QAAQ;EAAE,WAAW,MAAM;EAAW,MAAM;EAAqB,IAAI,MAAM;CAAG;CACpF,MAAM,aAAa,MAAM,UAAU,oBAAoB,KAAK;CAU5D,QAAO,MATe,UAAU,wBAC9B,OACA,YACA,MAAM,gBAAgB,CAAC,MAAM,aAAa,IAAI,CAAC,GAC/C,OAAO,OAAO;EACZ,MAAM,MAAM,cAAc,EAAE;EAC5B,OAAO,MAAM,cAAc,IAAI,QAAQ,KAAK;CAC9C,CACF,EAAA,CACe;AACjB;AAEA,eAAe,cACb,IACA,QACA,OACmB;CAWnB,MAAM,YAAW,MAVG,GAAG,KAAK,OAAO,WAAW;EAC5C,OAAO,IACL,GAAG,IAAI,OAAO,WAAW,WAAW,GAAG,MAAM,SAAS,GACtD,GAAG,IAAI,OAAO,WAAW,SAAS,GAAG,MAAM,OAAO,GAClD,GAAG,IAAI,OAAO,WAAW,cAAc,GAAG,MAAM,QAAQ,GACxD,GAAG,IAAI,OAAO,WAAW,QAAQ,GAAG,MAAM,MAAM,GAChD,GAAG,IAAI,OAAO,WAAW,SAAS,GAAG,MAAM,OAAO,CACpD;EACA,OAAO;CACT,CAAC,EAAA,CACqB,MAAM;CAC5B,wBAAwB,UAAU,KAAK;CACvC,IAAI,MAAM,eAAe,MAAM,aAAa,IAAI,OAAO,WAAW,KAAK;CACvE,MAAM,MAAM,oBAAoB,UAAU,aAAa,sBAAM,IAAI,KAAK,CAAC;CACvE,MAAM,SAAS;EACb,YAAY,MAAM;EAClB,eAAe,MAAM;EACrB,gBAAgB,MAAM;EACtB,WAAW,MAAM,aAAa,UAAU,aAAa;EACrD,aAAa,MAAM,eAAe,UAAU,eAAe;EAC3D,MAAM,MAAM,QAAQ,UAAU,QAAQ;EACtC,WAAW;CACb;CACA,OAAQ,WACJ,MAAM,GAAG,OAAO,OAAO,WAAW,SAAS,IAAI,MAAM,IACrD,MAAM,GAAG,OAAO,OAAO,WAAW;EAChC,GAAG;EACH,IAAI,MAAM;EACV,WAAW,MAAM;EACjB,SAAS,MAAM;EACf,cAAc,MAAM;EACpB,QAAQ,MAAM;EACd,SAAS,MAAM;EACf,WAAW;CACb,CAAC;AACP;AAEA,SAAS,wBAAwB,UAA2B,OAAkC;CAC5F,KACG,UAAU,MAAM,UAAU,MAAM,eAChC,UAAU,aAAa,UAAU,MAAM,iBAExC,MAAM,IAAI,sBAAsB,0CAA0C;AAC9E;;AAGA,SAAgB,oBAAoB,UAAyB,KAAmB;CAC9E,MAAM,OAAO,aAAa,OAAO,MAAa,KAAK,MAAM,QAAQ;CACjE,OAAO,IAAI,KACT,OAAO,SAAS,IAAI,IAAI,KAAK,IAAI,IAAI,QAAQ,GAAG,OAAO,CAAC,IAAI,IAAI,QAAQ,CAC1E,CAAC,CAAC,YAAY;AAChB;AAEA,eAAe,aAAa,IAAa,OAAc,OAA2C;CAChG,MAAM,MAAO,MAAM,GAAG,IAAI,OAAO,MAAM,UAAU;CACjD,MAAM,SAAS,KAAK,YAAY,IAAI,gBAAgB,KAAK;CACzD,IACE,CAAC,OACD,IAAI,cAAc,MAAM,aACxB,IAAI,YAAY,MAAM,WACtB,IAAI,iBAAiB,MAAM,aAC1B,IAAI,WAAA,gBAAgC,MAAM,WAC3C,IAAI,mBAAmB,MAAM,gBAC7B,WAAW,MAAM,eAEjB,MAAM,IAAI,sBAAsB,iDAAiD;AAErF"}
@@ -0,0 +1,6 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ /** A baseline write lost a concurrency check and should be retried. */
4
+ declare class BaselineWriteConflict extends Error {}
5
+ export { BaselineWriteConflict };
6
+ //# sourceMappingURL=baseline-conflict.d.mts.map