@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,73 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { designRenderPath } from "../paths.mjs";
5
+ // src/models/design-renders.ts
6
+ /**
7
+ * Renders live at `{projectId}/design/{provider}/{fileKey}/{node}.png` (a member's own
8
+ * connection: `…/{provider}/user-{id}/{fileKey}/…`), one per
9
+ * linked node and overwritten in place when the file version moves, so storage
10
+ * is bounded by the number of distinct linked nodes. A deleted node drops its
11
+ * render; a link removed from settings (or a deleted project) leaves its PNG behind.
12
+ */
13
+ var DesignRenderStore = class {
14
+ db;
15
+ table;
16
+ storage;
17
+ logger;
18
+ constructor(db, table, storage, logger) {
19
+ this.db = db;
20
+ this.table = table;
21
+ this.storage = storage;
22
+ this.logger = logger;
23
+ }
24
+ /** Cached render bytes of a node, or null when it has none (or storage is not wired). */
25
+ async read(node) {
26
+ if (!this.storage || !node.renderPath) return null;
27
+ return await this.storage.read(node.renderPath).catch(() => null);
28
+ }
29
+ /** Delete a node's stored render (its row is cleared by the caller's update). */
30
+ async remove(node) {
31
+ if (node.renderPath) await this.storage?.delete(node.renderPath).catch(() => {});
32
+ }
33
+ /**
34
+ * Fetch renders (one call per file) for the ok node rows that are missing one
35
+ * or hold an older file version, keyed by link URL. Failures keep the previous
36
+ * render and the row unchanged.
37
+ */
38
+ async ensure(projectId, client, fileKey, stored, call) {
39
+ const needing = [...stored].filter(([, node]) => needsRender(node));
40
+ if (!this.storage || needing.length === 0) return stored;
41
+ try {
42
+ const renders = await client.fetchRenders(fileKey, needing.map(([, node]) => node.nodeId), call);
43
+ const saved = await Promise.all(needing.map(async ([url, node]) => {
44
+ const png = renders.get(node.nodeId);
45
+ return png ? [url, await this.save(projectId, node, png)] : null;
46
+ }));
47
+ for (const entry of saved) if (entry) stored.set(entry[0], entry[1]);
48
+ } catch (error) {
49
+ this.logger?.warn({
50
+ err: error,
51
+ fileKey,
52
+ nodes: needing.length
53
+ }, "design render fetch failed");
54
+ }
55
+ return stored;
56
+ }
57
+ async save(projectId, node, png) {
58
+ const path = designRenderPath(projectId, node.provider, node.fileKey, node.nodeId, node.viewerId);
59
+ await this.storage?.write(path, png);
60
+ return await this.db.update(this.table, node.id, {
61
+ renderPath: path,
62
+ renderVersion: node.version,
63
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
64
+ });
65
+ }
66
+ };
67
+ /** An ok node row whose render is missing or taken at an older file version. */
68
+ function needsRender(node) {
69
+ return node.state === "ok" && node.nodeId !== "" && node.version !== null && node.renderVersion !== node.version;
70
+ }
71
+ export { DesignRenderStore };
72
+
73
+ //# sourceMappingURL=design-renders.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"design-renders.mjs","names":[],"sources":["../../src/models/design-renders.ts"],"sourcesContent":["/** Persistence of cached design node renders: PNGs in storage, version-tracked on the `design_nodes` row. */\nimport type { Table } from \"drizzle-orm\";\nimport type { Buffer } from \"node:buffer\";\nimport type { DatabaseAdapter } from \"../adapters/database.ts\";\nimport type { DesignCallOptions, DesignClient } from \"../adapters/design.ts\";\nimport type { StorageAdapter } from \"../adapters/storage.ts\";\nimport type { Logger } from \"../logger.ts\";\nimport type { DesignNode } from \"../schema/design.ts\";\nimport { designRenderPath } from \"../utils/paths.ts\";\n\n/**\n * Renders live at `{projectId}/design/{provider}/{fileKey}/{node}.png` (a member's own\n * connection: `…/{provider}/user-{id}/{fileKey}/…`), one per\n * linked node and overwritten in place when the file version moves, so storage\n * is bounded by the number of distinct linked nodes. A deleted node drops its\n * render; a link removed from settings (or a deleted project) leaves its PNG behind.\n */\nexport class DesignRenderStore {\n private readonly db: DatabaseAdapter;\n private readonly table: Table;\n private readonly storage: StorageAdapter | undefined;\n private readonly logger: Logger | undefined;\n\n constructor(\n db: DatabaseAdapter,\n table: Table,\n storage: StorageAdapter | undefined,\n logger: Logger | undefined,\n ) {\n this.db = db;\n this.table = table;\n this.storage = storage;\n this.logger = logger;\n }\n\n /** Cached render bytes of a node, or null when it has none (or storage is not wired). */\n async read(node: DesignNode): Promise<Buffer | null> {\n if (!this.storage || !node.renderPath) return null;\n return await this.storage.read(node.renderPath).catch(() => null);\n }\n\n /** Delete a node's stored render (its row is cleared by the caller's update). */\n async remove(node: DesignNode): Promise<void> {\n if (node.renderPath) await this.storage?.delete(node.renderPath).catch(() => {});\n }\n\n /**\n * Fetch renders (one call per file) for the ok node rows that are missing one\n * or hold an older file version, keyed by link URL. Failures keep the previous\n * render and the row unchanged.\n */\n async ensure(\n projectId: string,\n client: DesignClient,\n fileKey: string,\n stored: Map<string, DesignNode>,\n call: DesignCallOptions,\n ): Promise<Map<string, DesignNode>> {\n const needing = [...stored].filter(([, node]) => needsRender(node));\n if (!this.storage || needing.length === 0) return stored;\n try {\n const renders = await client.fetchRenders(\n fileKey,\n needing.map(([, node]) => node.nodeId),\n call,\n );\n const saved = await Promise.all(\n needing.map(async ([url, node]) => {\n const png = renders.get(node.nodeId);\n return png ? ([url, await this.save(projectId, node, png)] as const) : null;\n }),\n );\n for (const entry of saved) {\n if (entry) stored.set(entry[0], entry[1]);\n }\n } catch (error) {\n this.logger?.warn(\n { err: error, fileKey, nodes: needing.length },\n \"design render fetch failed\",\n );\n }\n return stored;\n }\n\n private async save(projectId: string, node: DesignNode, png: Buffer): Promise<DesignNode> {\n const path = designRenderPath(\n projectId,\n node.provider,\n node.fileKey,\n node.nodeId,\n node.viewerId,\n );\n await this.storage?.write(path, png);\n return (await this.db.update(this.table, node.id, {\n renderPath: path,\n renderVersion: node.version,\n updatedAt: new Date().toISOString(),\n })) as unknown as DesignNode;\n }\n}\n\n/** An ok node row whose render is missing or taken at an older file version. */\nfunction needsRender(node: DesignNode): boolean {\n return (\n node.state === \"ok\" &&\n node.nodeId !== \"\" &&\n node.version !== null &&\n node.renderVersion !== node.version\n );\n}\n"],"mappings":";;;;;;;;;;;;AAiBA,IAAa,oBAAb,MAA+B;CAC7B;CACA;CACA;CACA;CAEA,YACE,IACA,OACA,SACA,QACA;EACA,KAAK,KAAK;EACV,KAAK,QAAQ;EACb,KAAK,UAAU;EACf,KAAK,SAAS;CAChB;;CAGA,MAAM,KAAK,MAA0C;EACnD,IAAI,CAAC,KAAK,WAAW,CAAC,KAAK,YAAY,OAAO;EAC9C,OAAO,MAAM,KAAK,QAAQ,KAAK,KAAK,UAAU,CAAC,CAAC,YAAY,IAAI;CAClE;;CAGA,MAAM,OAAO,MAAiC;EAC5C,IAAI,KAAK,YAAY,MAAM,KAAK,SAAS,OAAO,KAAK,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC;CACjF;;;;;;CAOA,MAAM,OACJ,WACA,QACA,SACA,QACA,MACkC;EAClC,MAAM,UAAU,CAAC,GAAG,MAAM,CAAC,CAAC,QAAQ,GAAG,UAAU,YAAY,IAAI,CAAC;EAClE,IAAI,CAAC,KAAK,WAAW,QAAQ,WAAW,GAAG,OAAO;EAClD,IAAI;GACF,MAAM,UAAU,MAAM,OAAO,aAC3B,SACA,QAAQ,KAAK,GAAG,UAAU,KAAK,MAAM,GACrC,IACF;GACA,MAAM,QAAQ,MAAM,QAAQ,IAC1B,QAAQ,IAAI,OAAO,CAAC,KAAK,UAAU;IACjC,MAAM,MAAM,QAAQ,IAAI,KAAK,MAAM;IACnC,OAAO,MAAO,CAAC,KAAK,MAAM,KAAK,KAAK,WAAW,MAAM,GAAG,CAAC,IAAc;GACzE,CAAC,CACH;GACA,KAAK,MAAM,SAAS,OAClB,IAAI,OAAO,OAAO,IAAI,MAAM,IAAI,MAAM,EAAE;EAE5C,SAAS,OAAO;GACd,KAAK,QAAQ,KACX;IAAE,KAAK;IAAO;IAAS,OAAO,QAAQ;GAAO,GAC7C,4BACF;EACF;EACA,OAAO;CACT;CAEA,MAAc,KAAK,WAAmB,MAAkB,KAAkC;EACxF,MAAM,OAAO,iBACX,WACA,KAAK,UACL,KAAK,SACL,KAAK,QACL,KAAK,QACP;EACA,MAAM,KAAK,SAAS,MAAM,MAAM,GAAG;EACnC,OAAQ,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,KAAK,IAAI;GAChD,YAAY;GACZ,eAAe,KAAK;GACpB,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;EACpC,CAAC;CACH;AACF;;AAGA,SAAS,YAAY,MAA2B;CAC9C,OACE,KAAK,UAAU,QACf,KAAK,WAAW,MAChB,KAAK,YAAY,QACjB,KAAK,kBAAkB,KAAK;AAEhC"}
@@ -0,0 +1,27 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { DesignLink } from "../schema/design.mjs";
4
+ /** Last observed health of a design credential. */
5
+ type DesignCredentialStatus = "unknown" | "ok" | "unauthorized" | "forbidden";
6
+ /** Where a component's resolved design link came from. */
7
+ type DesignSource = "manual" | "story";
8
+ /** The design link(s) a story file resolves to. */
9
+ interface DesignResolution {
10
+ /** One URL, or the distinct set when states of the file disagree. */
11
+ urls: string[];
12
+ source: DesignSource;
13
+ }
14
+ /** Story-file key: path without a leading `./`, so index and manual entries compare equal. */
15
+ declare function normalizeImportPath(path: string): string;
16
+ /**
17
+ * Resolve design links per component (story file). Precedence: manual mapping
18
+ * > story parameters (`storyshelf.figma` over `design`, already merged at
19
+ * capture). States of one file are deduped; if they disagree the distinct set
20
+ * is returned rather than guessing. Files with no link are absent.
21
+ */
22
+ declare function resolveDesigns(manual: readonly Pick<DesignLink, "importPath" | "url">[], snapshots: readonly {
23
+ storyImportPath: string | null;
24
+ designUrl?: string | null;
25
+ }[]): Map<string, DesignResolution>;
26
+ export { DesignCredentialStatus, DesignResolution, DesignSource, normalizeImportPath, resolveDesigns };
27
+ //# sourceMappingURL=design-resolve.d.mts.map
@@ -0,0 +1,40 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ // src/models/design-resolve.ts
5
+ /** Story-file key: path without a leading `./`, so index and manual entries compare equal. */
6
+ function normalizeImportPath(path) {
7
+ return path.trim().replace(/^(?:\.\/)+/u, "");
8
+ }
9
+ /**
10
+ * Resolve design links per component (story file). Precedence: manual mapping
11
+ * > story parameters (`storyshelf.figma` over `design`, already merged at
12
+ * capture). States of one file are deduped; if they disagree the distinct set
13
+ * is returned rather than guessing. Files with no link are absent.
14
+ */
15
+ function resolveDesigns(manual, snapshots) {
16
+ const resolved = storyDesigns(snapshots);
17
+ for (const link of manual) if (link.importPath) resolved.set(normalizeImportPath(link.importPath), {
18
+ urls: [link.url],
19
+ source: "manual"
20
+ });
21
+ return resolved;
22
+ }
23
+ /** Distinct story-declared URLs per file. */
24
+ function storyDesigns(snapshots) {
25
+ const resolved = /* @__PURE__ */ new Map();
26
+ for (const snapshot of snapshots) {
27
+ const key = snapshot.storyImportPath ? normalizeImportPath(snapshot.storyImportPath) : "";
28
+ if (!key || !snapshot.designUrl) continue;
29
+ const urls = resolved.get(key)?.urls ?? [];
30
+ if (!urls.includes(snapshot.designUrl)) urls.push(snapshot.designUrl);
31
+ resolved.set(key, {
32
+ urls,
33
+ source: "story"
34
+ });
35
+ }
36
+ return resolved;
37
+ }
38
+ export { normalizeImportPath, resolveDesigns };
39
+
40
+ //# sourceMappingURL=design-resolve.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"design-resolve.mjs","names":[],"sources":["../../src/models/design-resolve.ts"],"sourcesContent":["/** Per-component design link resolution: manual mappings over story-declared URLs. */\nimport type { DesignLink } from \"../schema/design.ts\";\n\n/** Last observed health of a design credential. */\nexport type DesignCredentialStatus = \"unknown\" | \"ok\" | \"unauthorized\" | \"forbidden\";\n\n/** Where a component's resolved design link came from. */\nexport type DesignSource = \"manual\" | \"story\";\n\n/** The design link(s) a story file resolves to. */\nexport interface DesignResolution {\n /** One URL, or the distinct set when states of the file disagree. */\n urls: string[];\n source: DesignSource;\n}\n\n/** Story-file key: path without a leading `./`, so index and manual entries compare equal. */\nexport function normalizeImportPath(path: string): string {\n return path.trim().replace(/^(?:\\.\\/)+/u, \"\");\n}\n\n/**\n * Resolve design links per component (story file). Precedence: manual mapping\n * > story parameters (`storyshelf.figma` over `design`, already merged at\n * capture). States of one file are deduped; if they disagree the distinct set\n * is returned rather than guessing. Files with no link are absent.\n */\nexport function resolveDesigns(\n manual: readonly Pick<DesignLink, \"importPath\" | \"url\">[],\n snapshots: readonly { storyImportPath: string | null; designUrl?: string | null }[],\n): Map<string, DesignResolution> {\n const resolved = storyDesigns(snapshots);\n for (const link of manual) {\n if (link.importPath) {\n resolved.set(normalizeImportPath(link.importPath), { urls: [link.url], source: \"manual\" });\n }\n }\n return resolved;\n}\n\n/** Distinct story-declared URLs per file. */\nfunction storyDesigns(\n snapshots: readonly { storyImportPath: string | null; designUrl?: string | null }[],\n): Map<string, DesignResolution> {\n const resolved = new Map<string, DesignResolution>();\n for (const snapshot of snapshots) {\n const key = snapshot.storyImportPath ? normalizeImportPath(snapshot.storyImportPath) : \"\";\n if (!key || !snapshot.designUrl) continue;\n const urls = resolved.get(key)?.urls ?? [];\n if (!urls.includes(snapshot.designUrl)) urls.push(snapshot.designUrl);\n resolved.set(key, { urls, source: \"story\" });\n }\n return resolved;\n}\n"],"mappings":";;;;;AAiBA,SAAgB,oBAAoB,MAAsB;CACxD,OAAO,KAAK,KAAK,CAAC,CAAC,QAAQ,eAAe,EAAE;AAC9C;;;;;;;AAQA,SAAgB,eACd,QACA,WAC+B;CAC/B,MAAM,WAAW,aAAa,SAAS;CACvC,KAAK,MAAM,QAAQ,QACjB,IAAI,KAAK,YACP,SAAS,IAAI,oBAAoB,KAAK,UAAU,GAAG;EAAE,MAAM,CAAC,KAAK,GAAG;EAAG,QAAQ;CAAS,CAAC;CAG7F,OAAO;AACT;;AAGA,SAAS,aACP,WAC+B;CAC/B,MAAM,2BAAW,IAAI,IAA8B;CACnD,KAAK,MAAM,YAAY,WAAW;EAChC,MAAM,MAAM,SAAS,kBAAkB,oBAAoB,SAAS,eAAe,IAAI;EACvF,IAAI,CAAC,OAAO,CAAC,SAAS,WAAW;EACjC,MAAM,OAAO,SAAS,IAAI,GAAG,CAAC,EAAE,QAAQ,CAAC;EACzC,IAAI,CAAC,KAAK,SAAS,SAAS,SAAS,GAAG,KAAK,KAAK,SAAS,SAAS;EACpE,SAAS,IAAI,KAAK;GAAE;GAAM,QAAQ;EAAQ,CAAC;CAC7C;CACA,OAAO;AACT"}
@@ -0,0 +1,37 @@
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 { DesignProvider } from "../adapter/design.mjs";
5
+ import { DesignLink } from "../schema/design.mjs";
6
+ import { Table } from "drizzle-orm";
7
+ /** Tables required by {@link DesignModel}. */
8
+ interface DesignTables {
9
+ designLinks: Table;
10
+ }
11
+ /** Data operations for design links; URLs are validated by the configured providers. */
12
+ declare class DesignModel {
13
+ private readonly tables;
14
+ private readonly db;
15
+ private readonly providers;
16
+ constructor(db: DatabaseAdapter, providers: readonly DesignProvider[], tables?: DesignTables);
17
+ /** Project-level design file links, oldest first. */
18
+ projectLinks(projectId: string): Promise<DesignLink[]>;
19
+ /** Component mapping overrides (`import_path → URL`), by path. */
20
+ componentLinks(projectId: string): Promise<DesignLink[]>;
21
+ /** Add a project-level design file link. Throws {@link InvalidDesignUrlError}. */
22
+ addProjectLink(projectId: string, input: {
23
+ label: string;
24
+ url: string;
25
+ }): Promise<void>;
26
+ /** Map a story file to a design URL (replaces any existing mapping). Throws {@link InvalidDesignUrlError}. */
27
+ setComponentLink(projectId: string, importPath: string, rawUrl: string): Promise<void>;
28
+ /** Remove a link scoped to the project. */
29
+ removeLink(projectId: string, id: string): Promise<void>;
30
+ private validUrl;
31
+ /** Update the mapping of `key` when one exists; false when there is none. */
32
+ private updateComponentLink;
33
+ private links;
34
+ private insertLink;
35
+ }
36
+ export { DesignModel, DesignTables };
37
+ //# sourceMappingURL=design.d.mts.map
@@ -0,0 +1,89 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { InvalidDesignUrlError, parseDesignUrl } from "../adapter/design.mjs";
5
+ import { ulid } from "../utils/ulid.mjs";
6
+ import { col } from "./columns.mjs";
7
+ import { normalizeImportPath } from "./design-resolve.mjs";
8
+ import { eq } from "drizzle-orm";
9
+ // src/models/design.ts
10
+ /** Design-source links: project-level design files and per-component (story file) mappings. */
11
+ /** Data operations for design links; URLs are validated by the configured providers. */
12
+ var DesignModel = class {
13
+ tables;
14
+ db;
15
+ providers;
16
+ constructor(db, providers, tables) {
17
+ this.db = db;
18
+ this.providers = providers;
19
+ this.tables = tables ?? { designLinks: db.tables.designLinks };
20
+ }
21
+ /** Project-level design file links, oldest first. */
22
+ async projectLinks(projectId) {
23
+ return (await this.links(projectId)).filter((link) => link.importPath === null);
24
+ }
25
+ /** Component mapping overrides (`import_path → URL`), by path. */
26
+ async componentLinks(projectId) {
27
+ return (await this.links(projectId)).filter((link) => link.importPath !== null).toSorted((a, b) => (a.importPath ?? "").localeCompare(b.importPath ?? ""));
28
+ }
29
+ /** Add a project-level design file link. Throws {@link InvalidDesignUrlError}. */
30
+ async addProjectLink(projectId, input) {
31
+ const url = this.validUrl(input.url);
32
+ await this.insertLink(projectId, {
33
+ importPath: null,
34
+ label: input.label.trim() || null,
35
+ url
36
+ });
37
+ }
38
+ /** Map a story file to a design URL (replaces any existing mapping). Throws {@link InvalidDesignUrlError}. */
39
+ async setComponentLink(projectId, importPath, rawUrl) {
40
+ const url = this.validUrl(rawUrl);
41
+ const key = normalizeImportPath(importPath);
42
+ if (await this.updateComponentLink(projectId, key, url)) return;
43
+ try {
44
+ await this.insertLink(projectId, {
45
+ importPath: key,
46
+ label: null,
47
+ url
48
+ });
49
+ } catch (error) {
50
+ if (!await this.updateComponentLink(projectId, key, url)) throw error;
51
+ }
52
+ }
53
+ /** Remove a link scoped to the project. */
54
+ async removeLink(projectId, id) {
55
+ if ((await this.links(projectId)).find((link) => link.id === id)) await this.db.remove(this.tables.designLinks, id);
56
+ }
57
+ validUrl(raw) {
58
+ const parsed = parseDesignUrl(this.providers, raw);
59
+ if (!parsed) throw new InvalidDesignUrlError(raw, this.providers.map((p) => p.metadata.urlHint).join(" or "));
60
+ return parsed.ref.url;
61
+ }
62
+ /** Update the mapping of `key` when one exists; false when there is none. */
63
+ async updateComponentLink(projectId, key, url) {
64
+ const existing = (await this.componentLinks(projectId)).find((link) => normalizeImportPath(link.importPath ?? "") === key);
65
+ if (!existing) return false;
66
+ await this.db.update(this.tables.designLinks, existing.id, {
67
+ url,
68
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
69
+ });
70
+ return true;
71
+ }
72
+ async links(projectId) {
73
+ const column = col(this.tables.designLinks, "projectId");
74
+ return (await this.db.list(this.tables.designLinks, { where: eq(column, projectId) })).toSorted((a, b) => a.createdAt.localeCompare(b.createdAt));
75
+ }
76
+ async insertLink(projectId, input) {
77
+ const now = (/* @__PURE__ */ new Date()).toISOString();
78
+ await this.db.insert(this.tables.designLinks, {
79
+ id: ulid(),
80
+ projectId,
81
+ ...input,
82
+ createdAt: now,
83
+ updatedAt: now
84
+ });
85
+ }
86
+ };
87
+ export { DesignModel };
88
+
89
+ //# sourceMappingURL=design.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"design.mjs","names":[],"sources":["../../src/models/design.ts"],"sourcesContent":["/** Design-source links: project-level design files and per-component (story file) mappings. */\nimport { eq } from \"drizzle-orm\";\nimport type { Table } from \"drizzle-orm\";\nimport type { DatabaseAdapter } from \"../adapters/database.ts\";\nimport { InvalidDesignUrlError, parseDesignUrl, type DesignProvider } from \"../adapters/design.ts\";\nimport type { DesignLink } from \"../schema/design.ts\";\nimport { ulid } from \"../utils/ulid.ts\";\nimport { col } from \"./columns.ts\";\nimport { normalizeImportPath } from \"./design-resolve.ts\";\n\n/** Tables required by {@link DesignModel}. */\nexport interface DesignTables {\n designLinks: Table;\n}\n\n/** Data operations for design links; URLs are validated by the configured providers. */\nexport class DesignModel {\n private readonly tables: DesignTables;\n private readonly db: DatabaseAdapter;\n private readonly providers: readonly DesignProvider[];\n\n constructor(db: DatabaseAdapter, providers: readonly DesignProvider[], tables?: DesignTables) {\n this.db = db;\n this.providers = providers;\n this.tables = tables ?? { designLinks: db.tables.designLinks };\n }\n\n /** Project-level design file links, oldest first. */\n async projectLinks(projectId: string): Promise<DesignLink[]> {\n return (await this.links(projectId)).filter((link) => link.importPath === null);\n }\n\n /** Component mapping overrides (`import_path → URL`), by path. */\n async componentLinks(projectId: string): Promise<DesignLink[]> {\n return (await this.links(projectId))\n .filter((link) => link.importPath !== null)\n .toSorted((a, b) => (a.importPath ?? \"\").localeCompare(b.importPath ?? \"\"));\n }\n\n /** Add a project-level design file link. Throws {@link InvalidDesignUrlError}. */\n async addProjectLink(projectId: string, input: { label: string; url: string }): Promise<void> {\n const url = this.validUrl(input.url);\n await this.insertLink(projectId, { importPath: null, label: input.label.trim() || null, url });\n }\n\n /** Map a story file to a design URL (replaces any existing mapping). Throws {@link InvalidDesignUrlError}. */\n async setComponentLink(projectId: string, importPath: string, rawUrl: string): Promise<void> {\n const url = this.validUrl(rawUrl);\n const key = normalizeImportPath(importPath);\n if (await this.updateComponentLink(projectId, key, url)) return;\n try {\n await this.insertLink(projectId, { importPath: key, label: null, url });\n } catch (error) {\n // A concurrent writer won the (project_id, import_path) unique index: converge on an update.\n if (!(await this.updateComponentLink(projectId, key, url))) throw error;\n }\n }\n\n /** Remove a link scoped to the project. */\n async removeLink(projectId: string, id: string): Promise<void> {\n const found = (await this.links(projectId)).find((link) => link.id === id);\n if (found) await this.db.remove(this.tables.designLinks, id);\n }\n\n private validUrl(raw: string): string {\n const parsed = parseDesignUrl(this.providers, raw);\n if (!parsed) {\n throw new InvalidDesignUrlError(\n raw,\n this.providers.map((p) => p.metadata.urlHint).join(\" or \"),\n );\n }\n return parsed.ref.url;\n }\n\n /** Update the mapping of `key` when one exists; false when there is none. */\n private async updateComponentLink(projectId: string, key: string, url: string): Promise<boolean> {\n const existing = (await this.componentLinks(projectId)).find(\n (link) => normalizeImportPath(link.importPath ?? \"\") === key,\n );\n if (!existing) return false;\n await this.db.update(this.tables.designLinks, existing.id, {\n url,\n updatedAt: new Date().toISOString(),\n });\n return true;\n }\n\n private async links(projectId: string): Promise<DesignLink[]> {\n const column = col(this.tables.designLinks, \"projectId\");\n const rows = (await this.db.list(this.tables.designLinks, {\n where: eq(column, projectId),\n })) as unknown as DesignLink[];\n return rows.toSorted((a, b) => a.createdAt.localeCompare(b.createdAt));\n }\n\n private async insertLink(\n projectId: string,\n input: { importPath: string | null; label: string | null; url: string },\n ): Promise<void> {\n const now = new Date().toISOString();\n await this.db.insert(this.tables.designLinks, {\n id: ulid(),\n projectId,\n ...input,\n createdAt: now,\n updatedAt: now,\n });\n }\n}\n"],"mappings":";;;;;;;;;;;AAgBA,IAAa,cAAb,MAAyB;CACvB;CACA;CACA;CAEA,YAAY,IAAqB,WAAsC,QAAuB;EAC5F,KAAK,KAAK;EACV,KAAK,YAAY;EACjB,KAAK,SAAS,UAAU,EAAE,aAAa,GAAG,OAAO,YAAY;CAC/D;;CAGA,MAAM,aAAa,WAA0C;EAC3D,QAAQ,MAAM,KAAK,MAAM,SAAS,EAAA,CAAG,QAAQ,SAAS,KAAK,eAAe,IAAI;CAChF;;CAGA,MAAM,eAAe,WAA0C;EAC7D,QAAQ,MAAM,KAAK,MAAM,SAAS,EAAA,CAC/B,QAAQ,SAAS,KAAK,eAAe,IAAI,CAAC,CAC1C,UAAU,GAAG,OAAO,EAAE,cAAc,GAAA,CAAI,cAAc,EAAE,cAAc,EAAE,CAAC;CAC9E;;CAGA,MAAM,eAAe,WAAmB,OAAsD;EAC5F,MAAM,MAAM,KAAK,SAAS,MAAM,GAAG;EACnC,MAAM,KAAK,WAAW,WAAW;GAAE,YAAY;GAAM,OAAO,MAAM,MAAM,KAAK,KAAK;GAAM;EAAI,CAAC;CAC/F;;CAGA,MAAM,iBAAiB,WAAmB,YAAoB,QAA+B;EAC3F,MAAM,MAAM,KAAK,SAAS,MAAM;EAChC,MAAM,MAAM,oBAAoB,UAAU;EAC1C,IAAI,MAAM,KAAK,oBAAoB,WAAW,KAAK,GAAG,GAAG;EACzD,IAAI;GACF,MAAM,KAAK,WAAW,WAAW;IAAE,YAAY;IAAK,OAAO;IAAM;GAAI,CAAC;EACxE,SAAS,OAAO;GAEd,IAAI,CAAE,MAAM,KAAK,oBAAoB,WAAW,KAAK,GAAG,GAAI,MAAM;EACpE;CACF;;CAGA,MAAM,WAAW,WAAmB,IAA2B;EAE7D,KADe,MAAM,KAAK,MAAM,SAAS,EAAA,CAAG,MAAM,SAAS,KAAK,OAAO,EAC/D,GAAG,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,aAAa,EAAE;CAC7D;CAEA,SAAiB,KAAqB;EACpC,MAAM,SAAS,eAAe,KAAK,WAAW,GAAG;EACjD,IAAI,CAAC,QACH,MAAM,IAAI,sBACR,KACA,KAAK,UAAU,KAAK,MAAM,EAAE,SAAS,OAAO,CAAC,CAAC,KAAK,MAAM,CAC3D;EAEF,OAAO,OAAO,IAAI;CACpB;;CAGA,MAAc,oBAAoB,WAAmB,KAAa,KAA+B;EAC/F,MAAM,YAAY,MAAM,KAAK,eAAe,SAAS,EAAA,CAAG,MACrD,SAAS,oBAAoB,KAAK,cAAc,EAAE,MAAM,GAC3D;EACA,IAAI,CAAC,UAAU,OAAO;EACtB,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,aAAa,SAAS,IAAI;GACzD;GACA,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;EACpC,CAAC;EACD,OAAO;CACT;CAEA,MAAc,MAAM,WAA0C;EAC5D,MAAM,SAAS,IAAI,KAAK,OAAO,aAAa,WAAW;EAIvD,QAAO,MAHa,KAAK,GAAG,KAAK,KAAK,OAAO,aAAa,EACxD,OAAO,GAAG,QAAQ,SAAS,EAC7B,CAAC,EAAA,CACW,UAAU,GAAG,MAAM,EAAE,UAAU,cAAc,EAAE,SAAS,CAAC;CACvE;CAEA,MAAc,WACZ,WACA,OACe;EACf,MAAM,uBAAM,IAAI,KAAK,EAAA,CAAE,YAAY;EACnC,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,aAAa;GAC5C,IAAI,KAAK;GACT;GACA,GAAG;GACH,WAAW;GACX,WAAW;EACb,CAAC;CACH;AACF"}
@@ -0,0 +1,19 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { Build } from "../schema/build.mjs";
4
+ /** Builds the average looks at by default (newest first). */
5
+ declare const RECENT_BUILDS_FOR_INHERITED_RATIO = 20;
6
+ /** The average inherited ratio of a project's recent builds. */
7
+ interface InheritedRatio {
8
+ /** Mean of each build's `inheritedCount / snapshotCount`, from 0 to 1. */
9
+ ratio: number;
10
+ /** Builds that went into the mean. */
11
+ builds: number;
12
+ }
13
+ /**
14
+ * The mean inherited ratio over the newest `limit` builds that hold snapshots, or `null` when none
15
+ * does (no data is not a 0 % skip rate). A build with no snapshots has no ratio and is skipped.
16
+ */
17
+ declare function averageInheritedRatio(builds: readonly Pick<Build, "createdAt" | "snapshotCount" | "inheritedCount">[], limit?: number): InheritedRatio | null;
18
+ export { InheritedRatio, RECENT_BUILDS_FOR_INHERITED_RATIO, averageInheritedRatio };
19
+ //# sourceMappingURL=inherited-ratio.d.mts.map
@@ -0,0 +1,21 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ // src/models/inherited-ratio.ts
5
+ /** Builds the average looks at by default (newest first). */
6
+ const RECENT_BUILDS_FOR_INHERITED_RATIO = 20;
7
+ /**
8
+ * The mean inherited ratio over the newest `limit` builds that hold snapshots, or `null` when none
9
+ * does (no data is not a 0 % skip rate). A build with no snapshots has no ratio and is skipped.
10
+ */
11
+ function averageInheritedRatio(builds, limit = 20) {
12
+ const recent = builds.filter((build) => build.snapshotCount > 0).toSorted((a, b) => b.createdAt.localeCompare(a.createdAt)).slice(0, limit);
13
+ if (recent.length === 0) return null;
14
+ return {
15
+ ratio: recent.reduce((total, build) => total + Math.min(1, build.inheritedCount / build.snapshotCount), 0) / recent.length,
16
+ builds: recent.length
17
+ };
18
+ }
19
+ export { RECENT_BUILDS_FOR_INHERITED_RATIO, averageInheritedRatio };
20
+
21
+ //# sourceMappingURL=inherited-ratio.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inherited-ratio.mjs","names":[],"sources":["../../src/models/inherited-ratio.ts"],"sourcesContent":["/**\n * Affected-capture efficiency of a project (#140): how much of its recent builds was inherited from\n * the baseline instead of rendered. Pure and computed from the counts stored on the builds\n * (`snapshotCount`, `inheritedCount`), so a page needs no per-snapshot query.\n */\nimport type { Build } from \"../schema/build.ts\";\n\n/** Builds the average looks at by default (newest first). */\nexport const RECENT_BUILDS_FOR_INHERITED_RATIO = 20;\n\n/** The average inherited ratio of a project's recent builds. */\nexport interface InheritedRatio {\n /** Mean of each build's `inheritedCount / snapshotCount`, from 0 to 1. */\n ratio: number;\n /** Builds that went into the mean. */\n builds: number;\n}\n\n/**\n * The mean inherited ratio over the newest `limit` builds that hold snapshots, or `null` when none\n * does (no data is not a 0 % skip rate). A build with no snapshots has no ratio and is skipped.\n */\nexport function averageInheritedRatio(\n builds: readonly Pick<Build, \"createdAt\" | \"snapshotCount\" | \"inheritedCount\">[],\n limit: number = RECENT_BUILDS_FOR_INHERITED_RATIO,\n): InheritedRatio | null {\n const recent = builds\n .filter((build) => build.snapshotCount > 0)\n .toSorted((a, b) => b.createdAt.localeCompare(a.createdAt))\n .slice(0, limit);\n if (recent.length === 0) {\n return null;\n }\n const sum = recent.reduce(\n (total, build) => total + Math.min(1, build.inheritedCount / build.snapshotCount),\n 0,\n );\n return { ratio: sum / recent.length, builds: recent.length };\n}\n"],"mappings":";;;;;AAQA,MAAa,oCAAoC;;;;;AAcjD,SAAgB,sBACd,QACA,QAAA,IACuB;CACvB,MAAM,SAAS,OACZ,QAAQ,UAAU,MAAM,gBAAgB,CAAC,CAAC,CAC1C,UAAU,GAAG,MAAM,EAAE,UAAU,cAAc,EAAE,SAAS,CAAC,CAAC,CAC1D,MAAM,GAAG,KAAK;CACjB,IAAI,OAAO,WAAW,GACpB,OAAO;CAMT,OAAO;EAAE,OAJG,OAAO,QAChB,OAAO,UAAU,QAAQ,KAAK,IAAI,GAAG,MAAM,iBAAiB,MAAM,aAAa,GAChF,CAEgB,IAAI,OAAO;EAAQ,QAAQ,OAAO;CAAO;AAC7D"}
@@ -0,0 +1,68 @@
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 { InsightKind, InsightRow } from "../schema/insight.mjs";
5
+ import { Table } from "drizzle-orm";
6
+ /** Tables required by {@link InsightModel}. */
7
+ interface InsightTables {
8
+ insights: Table;
9
+ }
10
+ /** Identity and metadata of a run to start. */
11
+ interface InsightStartInput {
12
+ projectId: string;
13
+ buildId: string | null;
14
+ kind: InsightKind;
15
+ windowKey: string | null;
16
+ inputHash: string;
17
+ profile: string;
18
+ model: string;
19
+ promptVersion: string;
20
+ /** Re-run even when a finished row with the same hash exists. */
21
+ force?: boolean;
22
+ }
23
+ /** Outcome of {@link InsightModel.start}: the row and whether work must run. */
24
+ interface InsightStartResult {
25
+ row: InsightRow;
26
+ /** True when the caller should run inference for this row. */
27
+ run: boolean;
28
+ }
29
+ /** Result payload stored on success. */
30
+ interface InsightResultInput {
31
+ verdict: string;
32
+ summary: string;
33
+ result: string;
34
+ }
35
+ /** Data operations for insights. */
36
+ declare class InsightModel {
37
+ private readonly tables;
38
+ private readonly db;
39
+ constructor(db: DatabaseAdapter, tables?: InsightTables);
40
+ /**
41
+ * Insert a `pending` row, or return the existing one for the same unique key
42
+ * (the dedupe: concurrent identical requests share one row). Failed rows,
43
+ * replaced health rows, and `force` restart the existing row in place.
44
+ */
45
+ start(input: InsightStartInput): Promise<InsightStartResult>;
46
+ /** The existing row for a run's unique key, without creating one. */
47
+ peek(input: InsightStartInput): Promise<InsightRow | null>;
48
+ get(id: string): Promise<InsightRow | null>;
49
+ /** Newest triage rows for a build (any status), newest first. */
50
+ listForBuild(buildId: string, limit?: number): Promise<InsightRow[]>;
51
+ /** The health row for a project window, if any. */
52
+ getHealth(projectId: string, windowKey: string): Promise<InsightRow | null>;
53
+ markRunning(id: string): Promise<void>;
54
+ markDone(id: string, result: InsightResultInput): Promise<void>;
55
+ markFailed(id: string, errorCode: string): Promise<void>;
56
+ /** Explicitly remove all rows of a build (no reliance on FK cascade). */
57
+ removeForBuild(buildId: string): Promise<number>;
58
+ /** Remove health rows created before `cutoffIso`. */
59
+ purgeHealthBefore(cutoffIso: string): Promise<number>;
60
+ /** Mark pending/running rows older than `cutoffIso` as interrupted. */
61
+ sweepStale(cutoffIso: string): Promise<number>;
62
+ private removeWhere;
63
+ private findByKey;
64
+ private restartIfNeeded;
65
+ private col;
66
+ }
67
+ export { InsightModel, InsightResultInput, InsightStartInput, InsightStartResult, InsightTables };
68
+ //# sourceMappingURL=insight.d.mts.map
@@ -0,0 +1,161 @@
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, desc, eq, inArray, isNull, lt } from "drizzle-orm";
7
+ // src/models/insight.ts
8
+ /** Insight rows: pending/running/done/failed runs with dedupe by unique key. */
9
+ /** Data operations for insights. */
10
+ var InsightModel = class {
11
+ tables;
12
+ db;
13
+ constructor(db, tables) {
14
+ this.db = db;
15
+ this.tables = tables ?? { insights: db.tables.insights };
16
+ }
17
+ /**
18
+ * Insert a `pending` row, or return the existing one for the same unique key
19
+ * (the dedupe: concurrent identical requests share one row). Failed rows,
20
+ * replaced health rows, and `force` restart the existing row in place.
21
+ */
22
+ async start(input) {
23
+ const existing = await this.findByKey(input);
24
+ if (existing) return await this.restartIfNeeded(existing, input);
25
+ try {
26
+ return {
27
+ row: await this.db.insert(this.tables.insights, {
28
+ id: ulid(),
29
+ ...pick(input),
30
+ status: "pending",
31
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
32
+ }),
33
+ run: true
34
+ };
35
+ } catch (error) {
36
+ const raced = await this.findByKey(input);
37
+ if (raced) return {
38
+ row: raced,
39
+ run: false
40
+ };
41
+ throw error;
42
+ }
43
+ }
44
+ /** The existing row for a run's unique key, without creating one. */
45
+ async peek(input) {
46
+ return await this.findByKey(input);
47
+ }
48
+ async get(id) {
49
+ return await this.db.get(this.tables.insights, id);
50
+ }
51
+ /** Newest triage rows for a build (any status), newest first. */
52
+ async listForBuild(buildId, limit = 20) {
53
+ return await this.db.list(this.tables.insights, {
54
+ where: and(eq(this.col("buildId"), buildId), eq(this.col("kind"), "triage")),
55
+ orderBy: desc(this.col("createdAt")),
56
+ limit
57
+ });
58
+ }
59
+ /** The health row for a project window, if any. */
60
+ async getHealth(projectId, windowKey) {
61
+ return (await this.db.list(this.tables.insights, {
62
+ where: and(eq(this.col("projectId"), projectId), eq(this.col("kind"), "health"), eq(this.col("windowKey"), windowKey)),
63
+ limit: 1
64
+ }))[0] ?? null;
65
+ }
66
+ async markRunning(id) {
67
+ await this.db.update(this.tables.insights, id, {
68
+ status: "running",
69
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
70
+ });
71
+ }
72
+ async markDone(id, result) {
73
+ await this.db.update(this.tables.insights, id, {
74
+ status: "done",
75
+ ...result,
76
+ errorCode: null,
77
+ finishedAt: (/* @__PURE__ */ new Date()).toISOString()
78
+ });
79
+ }
80
+ async markFailed(id, errorCode) {
81
+ await this.db.update(this.tables.insights, id, {
82
+ status: "failed",
83
+ errorCode,
84
+ finishedAt: (/* @__PURE__ */ new Date()).toISOString()
85
+ });
86
+ }
87
+ /** Explicitly remove all rows of a build (no reliance on FK cascade). */
88
+ async removeForBuild(buildId) {
89
+ return await this.removeWhere(eq(this.col("buildId"), buildId));
90
+ }
91
+ /** Remove health rows created before `cutoffIso`. */
92
+ async purgeHealthBefore(cutoffIso) {
93
+ const where = and(eq(this.col("kind"), "health"), lt(this.col("createdAt"), cutoffIso));
94
+ return where ? await this.removeWhere(where) : 0;
95
+ }
96
+ /** Mark pending/running rows older than `cutoffIso` as interrupted. */
97
+ async sweepStale(cutoffIso) {
98
+ const stale = await this.db.list(this.tables.insights, { where: and(inArray(this.col("status"), ["pending", "running"]), lt(this.col("createdAt"), cutoffIso)) });
99
+ await Promise.all(stale.map(async (row) => {
100
+ await this.markFailed(row.id, "interrupted");
101
+ }));
102
+ return stale.length;
103
+ }
104
+ async removeWhere(where) {
105
+ const rows = await this.db.list(this.tables.insights, {
106
+ where,
107
+ orderBy: asc(this.col("id"))
108
+ });
109
+ await Promise.all(rows.map(async (row) => {
110
+ await this.db.remove(this.tables.insights, row.id);
111
+ }));
112
+ return rows.length;
113
+ }
114
+ async findByKey(input) {
115
+ const where = input.kind === "health" ? and(eq(this.col("projectId"), input.projectId), eq(this.col("kind"), "health"), input.windowKey === null ? isNull(this.col("windowKey")) : eq(this.col("windowKey"), input.windowKey)) : and(eq(this.col("projectId"), input.projectId), input.buildId === null ? isNull(this.col("buildId")) : eq(this.col("buildId"), input.buildId), eq(this.col("kind"), input.kind), eq(this.col("inputHash"), input.inputHash));
116
+ return (await this.db.list(this.tables.insights, {
117
+ where,
118
+ limit: 1
119
+ }))[0] ?? null;
120
+ }
121
+ async restartIfNeeded(existing, input) {
122
+ const inFlight = existing.status === "pending" || existing.status === "running";
123
+ const sameHash = existing.inputHash === input.inputHash;
124
+ if (inFlight || existing.status === "done" && sameHash && !input.force) return {
125
+ row: existing,
126
+ run: false
127
+ };
128
+ return {
129
+ row: await this.db.update(this.tables.insights, existing.id, {
130
+ ...pick(input),
131
+ status: "pending",
132
+ verdict: null,
133
+ summary: null,
134
+ result: null,
135
+ errorCode: null,
136
+ startedAt: null,
137
+ finishedAt: null,
138
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
139
+ }),
140
+ run: true
141
+ };
142
+ }
143
+ col(name) {
144
+ return col(this.tables.insights, name);
145
+ }
146
+ };
147
+ function pick(input) {
148
+ return {
149
+ projectId: input.projectId,
150
+ buildId: input.buildId,
151
+ kind: input.kind,
152
+ windowKey: input.windowKey,
153
+ inputHash: input.inputHash,
154
+ profile: input.profile,
155
+ model: input.model,
156
+ promptVersion: input.promptVersion
157
+ };
158
+ }
159
+ export { InsightModel };
160
+
161
+ //# sourceMappingURL=insight.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"insight.mjs","names":[],"sources":["../../src/models/insight.ts"],"sourcesContent":["/** Insight rows: pending/running/done/failed runs with dedupe by unique key. */\nimport { and, asc, desc, eq, inArray, isNull, lt } from \"drizzle-orm\";\nimport type { SQL, SQLWrapper, Table } from \"drizzle-orm\";\nimport type { DatabaseAdapter } from \"../adapters/database.ts\";\nimport type { InsightKind, InsightRow } from \"../schema/insight.ts\";\nimport { ulid } from \"../utils/ulid.ts\";\nimport { col } from \"./columns.ts\";\n\n/** Tables required by {@link InsightModel}. */\nexport interface InsightTables {\n insights: Table;\n}\n\n/** Identity and metadata of a run to start. */\nexport interface InsightStartInput {\n projectId: string;\n buildId: string | null;\n kind: InsightKind;\n windowKey: string | null;\n inputHash: string;\n profile: string;\n model: string;\n promptVersion: string;\n /** Re-run even when a finished row with the same hash exists. */\n force?: boolean;\n}\n\n/** Outcome of {@link InsightModel.start}: the row and whether work must run. */\nexport interface InsightStartResult {\n row: InsightRow;\n /** True when the caller should run inference for this row. */\n run: boolean;\n}\n\n/** Result payload stored on success. */\nexport interface InsightResultInput {\n verdict: string;\n summary: string;\n result: string;\n}\n\n/** Data operations for insights. */\nexport class InsightModel {\n private readonly tables: InsightTables;\n private readonly db: DatabaseAdapter;\n\n constructor(db: DatabaseAdapter, tables?: InsightTables) {\n this.db = db;\n this.tables = tables ?? { insights: db.tables.insights };\n }\n\n /**\n * Insert a `pending` row, or return the existing one for the same unique key\n * (the dedupe: concurrent identical requests share one row). Failed rows,\n * replaced health rows, and `force` restart the existing row in place.\n */\n async start(input: InsightStartInput): Promise<InsightStartResult> {\n const existing = await this.findByKey(input);\n if (existing) {\n return await this.restartIfNeeded(existing, input);\n }\n try {\n const row = (await this.db.insert(this.tables.insights, {\n id: ulid(),\n ...pick(input),\n status: \"pending\",\n createdAt: new Date().toISOString(),\n })) as unknown as InsightRow;\n return { row, run: true };\n } catch (error) {\n const raced = await this.findByKey(input);\n if (raced) {\n return { row: raced, run: false };\n }\n throw error;\n }\n }\n\n /** The existing row for a run's unique key, without creating one. */\n async peek(input: InsightStartInput): Promise<InsightRow | null> {\n return await this.findByKey(input);\n }\n\n async get(id: string): Promise<InsightRow | null> {\n return (await this.db.get(this.tables.insights, id)) as unknown as InsightRow | null;\n }\n\n /** Newest triage rows for a build (any status), newest first. */\n async listForBuild(buildId: string, limit = 20): Promise<InsightRow[]> {\n return (await this.db.list(this.tables.insights, {\n where: and(eq(this.col(\"buildId\"), buildId), eq(this.col(\"kind\"), \"triage\")),\n orderBy: desc(this.col(\"createdAt\")),\n limit,\n })) as unknown as InsightRow[];\n }\n\n /** The health row for a project window, if any. */\n async getHealth(projectId: string, windowKey: string): Promise<InsightRow | null> {\n const rows = (await this.db.list(this.tables.insights, {\n where: and(\n eq(this.col(\"projectId\"), projectId),\n eq(this.col(\"kind\"), \"health\"),\n eq(this.col(\"windowKey\"), windowKey),\n ),\n limit: 1,\n })) as unknown as InsightRow[];\n return rows[0] ?? null;\n }\n\n async markRunning(id: string): Promise<void> {\n await this.db.update(this.tables.insights, id, {\n status: \"running\",\n startedAt: new Date().toISOString(),\n });\n }\n\n async markDone(id: string, result: InsightResultInput): Promise<void> {\n await this.db.update(this.tables.insights, id, {\n status: \"done\",\n ...result,\n errorCode: null,\n finishedAt: new Date().toISOString(),\n });\n }\n\n async markFailed(id: string, errorCode: string): Promise<void> {\n await this.db.update(this.tables.insights, id, {\n status: \"failed\",\n errorCode,\n finishedAt: new Date().toISOString(),\n });\n }\n\n /** Explicitly remove all rows of a build (no reliance on FK cascade). */\n async removeForBuild(buildId: string): Promise<number> {\n return await this.removeWhere(eq(this.col(\"buildId\"), buildId));\n }\n\n /** Remove health rows created before `cutoffIso`. */\n async purgeHealthBefore(cutoffIso: string): Promise<number> {\n const where = and(eq(this.col(\"kind\"), \"health\"), lt(this.col(\"createdAt\"), cutoffIso));\n return where ? await this.removeWhere(where) : 0;\n }\n\n /** Mark pending/running rows older than `cutoffIso` as interrupted. */\n async sweepStale(cutoffIso: string): Promise<number> {\n const stale = (await this.db.list(this.tables.insights, {\n where: and(\n inArray(this.col(\"status\"), [\"pending\", \"running\"]),\n lt(this.col(\"createdAt\"), cutoffIso),\n ),\n })) as unknown as InsightRow[];\n await Promise.all(\n stale.map(async (row) => {\n await this.markFailed(row.id, \"interrupted\");\n }),\n );\n return stale.length;\n }\n\n private async removeWhere(where: SQL): Promise<number> {\n const rows = (await this.db.list(this.tables.insights, {\n where,\n orderBy: asc(this.col(\"id\")),\n })) as unknown as InsightRow[];\n await Promise.all(\n rows.map(async (row) => {\n await this.db.remove(this.tables.insights, row.id);\n }),\n );\n return rows.length;\n }\n\n private async findByKey(input: InsightStartInput): Promise<InsightRow | null> {\n const where =\n input.kind === \"health\"\n ? and(\n eq(this.col(\"projectId\"), input.projectId),\n eq(this.col(\"kind\"), \"health\"),\n input.windowKey === null\n ? isNull(this.col(\"windowKey\"))\n : eq(this.col(\"windowKey\"), input.windowKey),\n )\n : and(\n eq(this.col(\"projectId\"), input.projectId),\n input.buildId === null\n ? isNull(this.col(\"buildId\"))\n : eq(this.col(\"buildId\"), input.buildId),\n eq(this.col(\"kind\"), input.kind),\n eq(this.col(\"inputHash\"), input.inputHash),\n );\n const rows = (await this.db.list(this.tables.insights, {\n where,\n limit: 1,\n })) as unknown as InsightRow[];\n return rows[0] ?? null;\n }\n\n private async restartIfNeeded(\n existing: InsightRow,\n input: InsightStartInput,\n ): Promise<InsightStartResult> {\n const inFlight = existing.status === \"pending\" || existing.status === \"running\";\n const sameHash = existing.inputHash === input.inputHash;\n if (inFlight || (existing.status === \"done\" && sameHash && !input.force)) {\n return { row: existing, run: false };\n }\n const row = (await this.db.update(this.tables.insights, existing.id, {\n ...pick(input),\n status: \"pending\",\n verdict: null,\n summary: null,\n result: null,\n errorCode: null,\n startedAt: null,\n finishedAt: null,\n createdAt: new Date().toISOString(),\n })) as unknown as InsightRow;\n return { row, run: true };\n }\n\n private col(name: string): SQLWrapper {\n return col(this.tables.insights, name);\n }\n}\n\nfunction pick(input: InsightStartInput): Record<string, unknown> {\n return {\n projectId: input.projectId,\n buildId: input.buildId,\n kind: input.kind,\n windowKey: input.windowKey,\n inputHash: input.inputHash,\n profile: input.profile,\n model: input.model,\n promptVersion: input.promptVersion,\n };\n}\n"],"mappings":";;;;;;;;;AA0CA,IAAa,eAAb,MAA0B;CACxB;CACA;CAEA,YAAY,IAAqB,QAAwB;EACvD,KAAK,KAAK;EACV,KAAK,SAAS,UAAU,EAAE,UAAU,GAAG,OAAO,SAAS;CACzD;;;;;;CAOA,MAAM,MAAM,OAAuD;EACjE,MAAM,WAAW,MAAM,KAAK,UAAU,KAAK;EAC3C,IAAI,UACF,OAAO,MAAM,KAAK,gBAAgB,UAAU,KAAK;EAEnD,IAAI;GAOF,OAAO;IAAE,KAAA,MANU,KAAK,GAAG,OAAO,KAAK,OAAO,UAAU;KACtD,IAAI,KAAK;KACT,GAAG,KAAK,KAAK;KACb,QAAQ;KACR,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;IACpC,CAAC;IACa,KAAK;GAAK;EAC1B,SAAS,OAAO;GACd,MAAM,QAAQ,MAAM,KAAK,UAAU,KAAK;GACxC,IAAI,OACF,OAAO;IAAE,KAAK;IAAO,KAAK;GAAM;GAElC,MAAM;EACR;CACF;;CAGA,MAAM,KAAK,OAAsD;EAC/D,OAAO,MAAM,KAAK,UAAU,KAAK;CACnC;CAEA,MAAM,IAAI,IAAwC;EAChD,OAAQ,MAAM,KAAK,GAAG,IAAI,KAAK,OAAO,UAAU,EAAE;CACpD;;CAGA,MAAM,aAAa,SAAiB,QAAQ,IAA2B;EACrE,OAAQ,MAAM,KAAK,GAAG,KAAK,KAAK,OAAO,UAAU;GAC/C,OAAO,IAAI,GAAG,KAAK,IAAI,SAAS,GAAG,OAAO,GAAG,GAAG,KAAK,IAAI,MAAM,GAAG,QAAQ,CAAC;GAC3E,SAAS,KAAK,KAAK,IAAI,WAAW,CAAC;GACnC;EACF,CAAC;CACH;;CAGA,MAAM,UAAU,WAAmB,WAA+C;EAShF,QAAO,MARa,KAAK,GAAG,KAAK,KAAK,OAAO,UAAU;GACrD,OAAO,IACL,GAAG,KAAK,IAAI,WAAW,GAAG,SAAS,GACnC,GAAG,KAAK,IAAI,MAAM,GAAG,QAAQ,GAC7B,GAAG,KAAK,IAAI,WAAW,GAAG,SAAS,CACrC;GACA,OAAO;EACT,CAAC,EAAA,CACW,MAAM;CACpB;CAEA,MAAM,YAAY,IAA2B;EAC3C,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,UAAU,IAAI;GAC7C,QAAQ;GACR,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;EACpC,CAAC;CACH;CAEA,MAAM,SAAS,IAAY,QAA2C;EACpE,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,UAAU,IAAI;GAC7C,QAAQ;GACR,GAAG;GACH,WAAW;GACX,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;EACrC,CAAC;CACH;CAEA,MAAM,WAAW,IAAY,WAAkC;EAC7D,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,UAAU,IAAI;GAC7C,QAAQ;GACR;GACA,6BAAY,IAAI,KAAK,EAAA,CAAE,YAAY;EACrC,CAAC;CACH;;CAGA,MAAM,eAAe,SAAkC;EACrD,OAAO,MAAM,KAAK,YAAY,GAAG,KAAK,IAAI,SAAS,GAAG,OAAO,CAAC;CAChE;;CAGA,MAAM,kBAAkB,WAAoC;EAC1D,MAAM,QAAQ,IAAI,GAAG,KAAK,IAAI,MAAM,GAAG,QAAQ,GAAG,GAAG,KAAK,IAAI,WAAW,GAAG,SAAS,CAAC;EACtF,OAAO,QAAQ,MAAM,KAAK,YAAY,KAAK,IAAI;CACjD;;CAGA,MAAM,WAAW,WAAoC;EACnD,MAAM,QAAS,MAAM,KAAK,GAAG,KAAK,KAAK,OAAO,UAAU,EACtD,OAAO,IACL,QAAQ,KAAK,IAAI,QAAQ,GAAG,CAAC,WAAW,SAAS,CAAC,GAClD,GAAG,KAAK,IAAI,WAAW,GAAG,SAAS,CACrC,EACF,CAAC;EACD,MAAM,QAAQ,IACZ,MAAM,IAAI,OAAO,QAAQ;GACvB,MAAM,KAAK,WAAW,IAAI,IAAI,aAAa;EAC7C,CAAC,CACH;EACA,OAAO,MAAM;CACf;CAEA,MAAc,YAAY,OAA6B;EACrD,MAAM,OAAQ,MAAM,KAAK,GAAG,KAAK,KAAK,OAAO,UAAU;GACrD;GACA,SAAS,IAAI,KAAK,IAAI,IAAI,CAAC;EAC7B,CAAC;EACD,MAAM,QAAQ,IACZ,KAAK,IAAI,OAAO,QAAQ;GACtB,MAAM,KAAK,GAAG,OAAO,KAAK,OAAO,UAAU,IAAI,EAAE;EACnD,CAAC,CACH;EACA,OAAO,KAAK;CACd;CAEA,MAAc,UAAU,OAAsD;EAC5E,MAAM,QACJ,MAAM,SAAS,WACX,IACE,GAAG,KAAK,IAAI,WAAW,GAAG,MAAM,SAAS,GACzC,GAAG,KAAK,IAAI,MAAM,GAAG,QAAQ,GAC7B,MAAM,cAAc,OAChB,OAAO,KAAK,IAAI,WAAW,CAAC,IAC5B,GAAG,KAAK,IAAI,WAAW,GAAG,MAAM,SAAS,CAC/C,IACA,IACE,GAAG,KAAK,IAAI,WAAW,GAAG,MAAM,SAAS,GACzC,MAAM,YAAY,OACd,OAAO,KAAK,IAAI,SAAS,CAAC,IAC1B,GAAG,KAAK,IAAI,SAAS,GAAG,MAAM,OAAO,GACzC,GAAG,KAAK,IAAI,MAAM,GAAG,MAAM,IAAI,GAC/B,GAAG,KAAK,IAAI,WAAW,GAAG,MAAM,SAAS,CAC3C;EAKN,QAAO,MAJa,KAAK,GAAG,KAAK,KAAK,OAAO,UAAU;GACrD;GACA,OAAO;EACT,CAAC,EAAA,CACW,MAAM;CACpB;CAEA,MAAc,gBACZ,UACA,OAC6B;EAC7B,MAAM,WAAW,SAAS,WAAW,aAAa,SAAS,WAAW;EACtE,MAAM,WAAW,SAAS,cAAc,MAAM;EAC9C,IAAI,YAAa,SAAS,WAAW,UAAU,YAAY,CAAC,MAAM,OAChE,OAAO;GAAE,KAAK;GAAU,KAAK;EAAM;EAarC,OAAO;GAAE,KAAA,MAXU,KAAK,GAAG,OAAO,KAAK,OAAO,UAAU,SAAS,IAAI;IACnE,GAAG,KAAK,KAAK;IACb,QAAQ;IACR,SAAS;IACT,SAAS;IACT,QAAQ;IACR,WAAW;IACX,WAAW;IACX,YAAY;IACZ,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;GACpC,CAAC;GACa,KAAK;EAAK;CAC1B;CAEA,IAAY,MAA0B;EACpC,OAAO,IAAI,KAAK,OAAO,UAAU,IAAI;CACvC;AACF;AAEA,SAAS,KAAK,OAAmD;CAC/D,OAAO;EACL,WAAW,MAAM;EACjB,SAAS,MAAM;EACf,MAAM,MAAM;EACZ,WAAW,MAAM;EACjB,WAAW,MAAM;EACjB,SAAS,MAAM;EACf,OAAO,MAAM;EACb,eAAe,MAAM;CACvB;AACF"}
@@ -3,7 +3,6 @@ import __tsdown_shims_url from 'node:url';
3
3
  import { DatabaseAdapter } from "../adapter/database.mjs";
4
4
  import { BuildLabel, LabelType } from "../schema/label.mjs";
5
5
  import { Table } from "drizzle-orm";
6
- //#region src/models/label.d.ts
7
6
  /** Tables required by {@link LabelModel}. */
8
7
  interface LabelTables {
9
8
  builds: Table;
@@ -12,8 +11,8 @@ interface LabelTables {
12
11
  }
13
12
  /** Data operations for label types and build labels. */
14
13
  declare class LabelModel {
15
- private readonly db;
16
14
  private readonly tables;
15
+ private readonly db;
17
16
  /**
18
17
  * @param db - Database adapter.
19
18
  * @param tables - Table handles.
@@ -50,9 +49,10 @@ declare class LabelModel {
50
49
  listForBuild(buildId: string): Promise<BuildLabel[]>;
51
50
  /** Return the id of the latest build carrying a given label value, if any. */
52
51
  latestBuildId(projectId: string, typeKey: string, value: string): Promise<string | null>;
53
- /** Return whether a build is marked as persistent. */
52
+ /** Whether a build is marked as persistent. */
54
53
  hasPersistent(projectId: string, buildId: string): Promise<boolean>;
54
+ /** Ids of the project's builds marked persistent (exempt from retention). */
55
+ persistentBuildIds(projectId: string): Promise<Set<string>>;
55
56
  }
56
- //#endregion
57
57
  export { LabelModel, LabelTables };
58
58
  //# sourceMappingURL=label.d.mts.map