@storyshelf/app 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 (429) hide show
  1. package/README.md +42 -4
  2. package/dist/app-types.d.mts +2 -6
  3. package/dist/asset-manifest.mjs +14 -7
  4. package/dist/asset-manifest.mjs.map +1 -1
  5. package/dist/assets/{htmx.min.js → htmx.mjs} +9 -1
  6. package/dist/assets/htmx.mjs.map +1 -0
  7. package/dist/assets/mark.mjs +9 -0
  8. package/dist/assets/mark.mjs.map +1 -0
  9. package/dist/boot-tasks.mjs +79 -0
  10. package/dist/boot-tasks.mjs.map +1 -0
  11. package/dist/build-state-flags.mjs +17 -0
  12. package/dist/build-state-flags.mjs.map +1 -0
  13. package/dist/build-state-setup.mjs +74 -0
  14. package/dist/build-state-setup.mjs.map +1 -0
  15. package/dist/capture-alerts.mjs +45 -0
  16. package/dist/capture-alerts.mjs.map +1 -0
  17. package/dist/capture-process.mjs +58 -0
  18. package/dist/capture-process.mjs.map +1 -0
  19. package/dist/capture-setup.mjs +96 -119
  20. package/dist/capture-setup.mjs.map +1 -1
  21. package/dist/connections.mjs +33 -0
  22. package/dist/connections.mjs.map +1 -0
  23. package/dist/consumer-setup.mjs +57 -0
  24. package/dist/consumer-setup.mjs.map +1 -0
  25. package/dist/credential-keys.mjs +1 -2
  26. package/dist/credentials.mjs +1 -2
  27. package/dist/git-status.mjs +45 -0
  28. package/dist/git-status.mjs.map +1 -0
  29. package/dist/hidden-data.mjs +23 -0
  30. package/dist/hidden-data.mjs.map +1 -0
  31. package/dist/index.d.mts +3 -5
  32. package/dist/index.mjs +204 -127
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/insights/budget.mjs +48 -0
  35. package/dist/insights/budget.mjs.map +1 -0
  36. package/dist/insights/deps.mjs +20 -0
  37. package/dist/insights/deps.mjs.map +1 -0
  38. package/dist/insights/errors.mjs +21 -0
  39. package/dist/insights/errors.mjs.map +1 -0
  40. package/dist/insights/health-panel.mjs +39 -0
  41. package/dist/insights/health-panel.mjs.map +1 -0
  42. package/dist/insights/job.mjs +102 -0
  43. package/dist/insights/job.mjs.map +1 -0
  44. package/dist/insights/load-health.mjs +58 -0
  45. package/dist/insights/load-health.mjs.map +1 -0
  46. package/dist/insights/load-triage.mjs +97 -0
  47. package/dist/insights/load-triage.mjs.map +1 -0
  48. package/dist/insights/panel.mjs +27 -0
  49. package/dist/insights/panel.mjs.map +1 -0
  50. package/dist/insights/request.mjs +112 -0
  51. package/dist/insights/request.mjs.map +1 -0
  52. package/dist/insights/stale.mjs +20 -0
  53. package/dist/insights/stale.mjs.map +1 -0
  54. package/dist/insights/usage-report.mjs +59 -0
  55. package/dist/insights/usage-report.mjs.map +1 -0
  56. package/dist/insights/view.mjs +47 -0
  57. package/dist/insights/view.mjs.map +1 -0
  58. package/dist/job-canceller.mjs +13 -0
  59. package/dist/job-canceller.mjs.map +1 -0
  60. package/dist/job-queue.mjs +50 -0
  61. package/dist/job-queue.mjs.map +1 -0
  62. package/dist/jobs-setup.mjs +131 -0
  63. package/dist/jobs-setup.mjs.map +1 -0
  64. package/dist/lifecycle.mjs +93 -22
  65. package/dist/lifecycle.mjs.map +1 -1
  66. package/dist/middleware/auth-gate.mjs +5 -4
  67. package/dist/middleware/auth-gate.mjs.map +1 -1
  68. package/dist/middleware/csrf.mjs +1 -2
  69. package/dist/middleware/rate-limit.mjs +42 -35
  70. package/dist/middleware/rate-limit.mjs.map +1 -1
  71. package/dist/middleware/request-log.mjs +4 -4
  72. package/dist/middleware/request-log.mjs.map +1 -1
  73. package/dist/middleware/require-review.mjs +50 -0
  74. package/dist/middleware/require-review.mjs.map +1 -0
  75. package/dist/middleware/require-testing.mjs +40 -0
  76. package/dist/middleware/require-testing.mjs.map +1 -0
  77. package/dist/middleware/server-timing.mjs +1 -2
  78. package/dist/middleware/setup-gate.mjs +1 -2
  79. package/dist/middleware/setup-gate.mjs.map +1 -1
  80. package/dist/middleware/store-scope.mjs +13 -4
  81. package/dist/middleware/store-scope.mjs.map +1 -1
  82. package/dist/notifications-pause.mjs +32 -0
  83. package/dist/notifications-pause.mjs.map +1 -0
  84. package/dist/notify.d.mts +3 -4
  85. package/dist/notify.mjs +79 -41
  86. package/dist/notify.mjs.map +1 -1
  87. package/dist/pages/a11y-violations.mjs +115 -0
  88. package/dist/pages/a11y-violations.mjs.map +1 -0
  89. package/dist/pages/admin-ai.mjs +77 -0
  90. package/dist/pages/admin-ai.mjs.map +1 -0
  91. package/dist/pages/admin-system-origin.mjs +132 -0
  92. package/dist/pages/admin-system-origin.mjs.map +1 -0
  93. package/dist/pages/admin-system-targets.mjs +52 -0
  94. package/dist/pages/admin-system-targets.mjs.map +1 -0
  95. package/dist/pages/admin-system.mjs +64 -15
  96. package/dist/pages/admin-system.mjs.map +1 -1
  97. package/dist/pages/build-detail.mjs +105 -78
  98. package/dist/pages/build-detail.mjs.map +1 -1
  99. package/dist/pages/build-diff-actions.mjs +88 -35
  100. package/dist/pages/build-diff-actions.mjs.map +1 -1
  101. package/dist/pages/build-diff-comments.mjs +17 -16
  102. package/dist/pages/build-diff-comments.mjs.map +1 -1
  103. package/dist/pages/build-diff-default.mjs +53 -0
  104. package/dist/pages/build-diff-default.mjs.map +1 -0
  105. package/dist/pages/build-diff-environment.mjs +81 -0
  106. package/dist/pages/build-diff-environment.mjs.map +1 -0
  107. package/dist/pages/build-diff-header.mjs +23 -6
  108. package/dist/pages/build-diff-header.mjs.map +1 -1
  109. package/dist/pages/build-diff-insight.mjs +112 -0
  110. package/dist/pages/build-diff-insight.mjs.map +1 -0
  111. package/dist/pages/build-diff-model.mjs +74 -12
  112. package/dist/pages/build-diff-model.mjs.map +1 -1
  113. package/dist/pages/build-diff-nav.mjs +29 -14
  114. package/dist/pages/build-diff-nav.mjs.map +1 -1
  115. package/dist/pages/build-diff-reference.mjs +84 -0
  116. package/dist/pages/build-diff-reference.mjs.map +1 -0
  117. package/dist/pages/build-diff-shortcuts.mjs +6 -3
  118. package/dist/pages/build-diff-shortcuts.mjs.map +1 -1
  119. package/dist/pages/build-diff-stale.mjs +1 -2
  120. package/dist/pages/build-diff-usage.mjs +62 -0
  121. package/dist/pages/build-diff-usage.mjs.map +1 -0
  122. package/dist/pages/build-diff-viewer.mjs +97 -14
  123. package/dist/pages/build-diff-viewer.mjs.map +1 -1
  124. package/dist/pages/build-diff.mjs +37 -22
  125. package/dist/pages/build-diff.mjs.map +1 -1
  126. package/dist/pages/build-tests.mjs +73 -0
  127. package/dist/pages/build-tests.mjs.map +1 -0
  128. package/dist/pages/component-detail.mjs +248 -0
  129. package/dist/pages/component-detail.mjs.map +1 -0
  130. package/dist/pages/component-stories.mjs +167 -0
  131. package/dist/pages/component-stories.mjs.map +1 -0
  132. package/dist/pages/compute-jobs.mjs +14 -28
  133. package/dist/pages/compute-jobs.mjs.map +1 -1
  134. package/dist/pages/design-links.mjs +181 -0
  135. package/dist/pages/design-links.mjs.map +1 -0
  136. package/dist/pages/environment-change.mjs +52 -0
  137. package/dist/pages/environment-change.mjs.map +1 -0
  138. package/dist/pages/health-panel.mjs +125 -0
  139. package/dist/pages/health-panel.mjs.map +1 -0
  140. package/dist/pages/invite.mjs +1 -2
  141. package/dist/pages/label-detail.mjs +1 -2
  142. package/dist/pages/library-grid.mjs +104 -0
  143. package/dist/pages/library-grid.mjs.map +1 -0
  144. package/dist/pages/library-model.mjs +46 -0
  145. package/dist/pages/library-model.mjs.map +1 -0
  146. package/dist/pages/library-snapshots.mjs +129 -0
  147. package/dist/pages/library-snapshots.mjs.map +1 -0
  148. package/dist/pages/library.mjs +113 -220
  149. package/dist/pages/library.mjs.map +1 -1
  150. package/dist/pages/login.mjs +1 -2
  151. package/dist/pages/notifications-paused.mjs +21 -0
  152. package/dist/pages/notifications-paused.mjs.map +1 -0
  153. package/dist/pages/passkey-ceremony.mjs +1 -2
  154. package/dist/pages/profile.mjs +54 -50
  155. package/dist/pages/profile.mjs.map +1 -1
  156. package/dist/pages/project-builds-table.mjs +3 -4
  157. package/dist/pages/project-builds-table.mjs.map +1 -1
  158. package/dist/pages/project-builds.mjs +52 -23
  159. package/dist/pages/project-builds.mjs.map +1 -1
  160. package/dist/pages/project-create.mjs +1 -2
  161. package/dist/pages/project-settings.mjs +52 -14
  162. package/dist/pages/project-settings.mjs.map +1 -1
  163. package/dist/pages/projects-card.mjs +15 -3
  164. package/dist/pages/projects-card.mjs.map +1 -1
  165. package/dist/pages/projects.mjs +7 -4
  166. package/dist/pages/projects.mjs.map +1 -1
  167. package/dist/pages/review-changeset.mjs +115 -0
  168. package/dist/pages/review-changeset.mjs.map +1 -0
  169. package/dist/pages/review-comments.mjs +102 -0
  170. package/dist/pages/review-comments.mjs.map +1 -0
  171. package/dist/pages/review-verdict.mjs +101 -0
  172. package/dist/pages/review-verdict.mjs.map +1 -0
  173. package/dist/pages/root.mjs +1 -2
  174. package/dist/pages/settings-ai.mjs +68 -0
  175. package/dist/pages/settings-ai.mjs.map +1 -0
  176. package/dist/pages/settings-capture.mjs +123 -0
  177. package/dist/pages/settings-capture.mjs.map +1 -0
  178. package/dist/pages/settings-design-credential.mjs +98 -0
  179. package/dist/pages/settings-design-credential.mjs.map +1 -0
  180. package/dist/pages/settings-design-links.mjs +178 -0
  181. package/dist/pages/settings-design-links.mjs.map +1 -0
  182. package/dist/pages/settings-design.mjs +47 -0
  183. package/dist/pages/settings-design.mjs.map +1 -0
  184. package/dist/pages/settings-general.mjs +47 -23
  185. package/dist/pages/settings-general.mjs.map +1 -1
  186. package/dist/pages/settings-labels.mjs +44 -4
  187. package/dist/pages/settings-labels.mjs.map +1 -1
  188. package/dist/pages/settings-links.mjs +111 -0
  189. package/dist/pages/settings-links.mjs.map +1 -0
  190. package/dist/pages/settings-members.mjs +1 -2
  191. package/dist/pages/settings-notifications-git.mjs +127 -0
  192. package/dist/pages/settings-notifications-git.mjs.map +1 -0
  193. package/dist/pages/settings-notifications.mjs +80 -44
  194. package/dist/pages/settings-notifications.mjs.map +1 -1
  195. package/dist/pages/settings-tests.mjs +34 -4
  196. package/dist/pages/settings-tests.mjs.map +1 -1
  197. package/dist/pages/settings-tokens.mjs +1 -2
  198. package/dist/pages/settings-webhooks.mjs +1 -2
  199. package/dist/pages/storybook.mjs +1 -2
  200. package/dist/pages/target-choices.mjs +38 -0
  201. package/dist/pages/target-choices.mjs.map +1 -0
  202. package/dist/publish-setup.mjs +88 -0
  203. package/dist/publish-setup.mjs.map +1 -0
  204. package/dist/retention-timer.mjs +12 -12
  205. package/dist/retention-timer.mjs.map +1 -1
  206. package/dist/review-events.mjs +47 -0
  207. package/dist/review-events.mjs.map +1 -0
  208. package/dist/routers/admin-pages.mjs +46 -5
  209. package/dist/routers/admin-pages.mjs.map +1 -1
  210. package/dist/routers/admin-public-origin.mjs +92 -0
  211. package/dist/routers/admin-public-origin.mjs.map +1 -0
  212. package/dist/routers/admin.mjs +8 -4
  213. package/dist/routers/admin.mjs.map +1 -1
  214. package/dist/routers/assets.mjs +10 -4
  215. package/dist/routers/assets.mjs.map +1 -1
  216. package/dist/routers/attempts.mjs +1 -2
  217. package/dist/routers/auth-sync.mjs +1 -2
  218. package/dist/routers/auth.mjs +2 -3
  219. package/dist/routers/baseline-guard.mjs +4 -5
  220. package/dist/routers/baseline-guard.mjs.map +1 -1
  221. package/dist/routers/baseline-reference.mjs +72 -0
  222. package/dist/routers/baseline-reference.mjs.map +1 -0
  223. package/dist/routers/baselines.handlers.mjs +63 -0
  224. package/dist/routers/baselines.handlers.mjs.map +1 -0
  225. package/dist/routers/baselines.mjs +124 -0
  226. package/dist/routers/baselines.mjs.map +1 -0
  227. package/dist/routers/build-cancel.mjs +67 -0
  228. package/dist/routers/build-cancel.mjs.map +1 -0
  229. package/dist/routers/build-changeset.mjs +69 -0
  230. package/dist/routers/build-changeset.mjs.map +1 -0
  231. package/dist/routers/build-reviews.handlers.mjs +85 -0
  232. package/dist/routers/build-reviews.handlers.mjs.map +1 -0
  233. package/dist/routers/build-reviews.mjs +73 -0
  234. package/dist/routers/build-reviews.mjs.map +1 -0
  235. package/dist/routers/builds.handlers.mjs +65 -60
  236. package/dist/routers/builds.handlers.mjs.map +1 -1
  237. package/dist/routers/builds.mjs +77 -19
  238. package/dist/routers/builds.mjs.map +1 -1
  239. package/dist/routers/capture-cache.mjs +29 -0
  240. package/dist/routers/capture-cache.mjs.map +1 -0
  241. package/dist/routers/capture-config.mjs +34 -0
  242. package/dist/routers/capture-config.mjs.map +1 -0
  243. package/dist/routers/comments.mjs +42 -17
  244. package/dist/routers/comments.mjs.map +1 -1
  245. package/dist/routers/comparison-image.mjs +29 -0
  246. package/dist/routers/comparison-image.mjs.map +1 -0
  247. package/dist/routers/component-catalog.handlers.mjs +70 -0
  248. package/dist/routers/component-catalog.handlers.mjs.map +1 -0
  249. package/dist/routers/component.handlers.mjs +120 -0
  250. package/dist/routers/component.handlers.mjs.map +1 -0
  251. package/dist/routers/connections.mjs +117 -0
  252. package/dist/routers/connections.mjs.map +1 -0
  253. package/dist/routers/design-connect.handlers.mjs +43 -0
  254. package/dist/routers/design-connect.handlers.mjs.map +1 -0
  255. package/dist/routers/design.handlers.mjs +113 -0
  256. package/dist/routers/design.handlers.mjs.map +1 -0
  257. package/dist/routers/flash.mjs +1 -2
  258. package/dist/routers/health-report.mjs +3 -5
  259. package/dist/routers/health-report.mjs.map +1 -1
  260. package/dist/routers/health.mjs +5 -5
  261. package/dist/routers/health.mjs.map +1 -1
  262. package/dist/routers/helpers.mjs +20 -5
  263. package/dist/routers/helpers.mjs.map +1 -1
  264. package/dist/routers/htmx.mjs +1 -2
  265. package/dist/routers/insights-ui.mjs +63 -0
  266. package/dist/routers/insights-ui.mjs.map +1 -0
  267. package/dist/routers/insights.handlers.mjs +44 -0
  268. package/dist/routers/insights.handlers.mjs.map +1 -0
  269. package/dist/routers/insights.mjs +188 -0
  270. package/dist/routers/insights.mjs.map +1 -0
  271. package/dist/routers/labels.mjs +1 -2
  272. package/dist/routers/links.handlers.mjs +79 -0
  273. package/dist/routers/links.handlers.mjs.map +1 -0
  274. package/dist/routers/links.mjs +138 -0
  275. package/dist/routers/links.mjs.map +1 -0
  276. package/dist/routers/media.mjs +30 -7
  277. package/dist/routers/media.mjs.map +1 -1
  278. package/dist/routers/members.mjs +3 -3
  279. package/dist/routers/members.mjs.map +1 -1
  280. package/dist/routers/notification-channels.mjs +18 -25
  281. package/dist/routers/notification-channels.mjs.map +1 -1
  282. package/dist/routers/notification-subscriptions.mjs +1 -2
  283. package/dist/routers/oauth-state.mjs +44 -0
  284. package/dist/routers/oauth-state.mjs.map +1 -0
  285. package/dist/routers/preview-base.mjs +37 -0
  286. package/dist/routers/preview-base.mjs.map +1 -0
  287. package/dist/routers/preview-token.mjs +50 -0
  288. package/dist/routers/preview-token.mjs.map +1 -0
  289. package/dist/routers/profile.mjs +4 -3
  290. package/dist/routers/profile.mjs.map +1 -1
  291. package/dist/routers/projects.mjs +18 -3
  292. package/dist/routers/projects.mjs.map +1 -1
  293. package/dist/routers/publish-upload.mjs +85 -0
  294. package/dist/routers/publish-upload.mjs.map +1 -0
  295. package/dist/routers/published-access.mjs +51 -0
  296. package/dist/routers/published-access.mjs.map +1 -0
  297. package/dist/routers/published-compression.mjs +109 -0
  298. package/dist/routers/published-compression.mjs.map +1 -0
  299. package/dist/routers/published-files.mjs +69 -0
  300. package/dist/routers/published-files.mjs.map +1 -0
  301. package/dist/routers/review-forms.mjs +71 -0
  302. package/dist/routers/review-forms.mjs.map +1 -0
  303. package/dist/routers/review-next.mjs +1 -2
  304. package/dist/routers/review-section.handlers.mjs +84 -0
  305. package/dist/routers/review-section.handlers.mjs.map +1 -0
  306. package/dist/routers/review-switch-off.mjs +28 -0
  307. package/dist/routers/review-switch-off.mjs.map +1 -0
  308. package/dist/routers/schemas.mjs +141 -24
  309. package/dist/routers/schemas.mjs.map +1 -1
  310. package/dist/routers/scoped-models.mjs +21 -0
  311. package/dist/routers/scoped-models.mjs.map +1 -0
  312. package/dist/routers/settings-ai.mjs +34 -0
  313. package/dist/routers/settings-ai.mjs.map +1 -0
  314. package/dist/routers/settings-capture.mjs +76 -0
  315. package/dist/routers/settings-capture.mjs.map +1 -0
  316. package/dist/routers/settings-design.mjs +102 -0
  317. package/dist/routers/settings-design.mjs.map +1 -0
  318. package/dist/routers/settings-general.mjs +56 -12
  319. package/dist/routers/settings-general.mjs.map +1 -1
  320. package/dist/routers/settings-git-channel.mjs +76 -0
  321. package/dist/routers/settings-git-channel.mjs.map +1 -0
  322. package/dist/routers/settings-labels.mjs +28 -3
  323. package/dist/routers/settings-labels.mjs.map +1 -1
  324. package/dist/routers/settings-links.mjs +62 -0
  325. package/dist/routers/settings-links.mjs.map +1 -0
  326. package/dist/routers/settings-members.mjs +5 -9
  327. package/dist/routers/settings-members.mjs.map +1 -1
  328. package/dist/routers/settings-notifications.mjs +16 -12
  329. package/dist/routers/settings-notifications.mjs.map +1 -1
  330. package/dist/routers/settings-tokens.mjs +3 -7
  331. package/dist/routers/settings-tokens.mjs.map +1 -1
  332. package/dist/routers/settings-webhooks.mjs +8 -26
  333. package/dist/routers/settings-webhooks.mjs.map +1 -1
  334. package/dist/routers/settings.handlers.mjs +108 -28
  335. package/dist/routers/settings.handlers.mjs.map +1 -1
  336. package/dist/routers/settings.mjs +17 -6
  337. package/dist/routers/settings.mjs.map +1 -1
  338. package/dist/routers/signed-storybook.mjs +55 -0
  339. package/dist/routers/signed-storybook.mjs.map +1 -0
  340. package/dist/routers/snapshot-groups.mjs +62 -0
  341. package/dist/routers/snapshot-groups.mjs.map +1 -0
  342. package/dist/routers/snapshots.mjs +104 -7
  343. package/dist/routers/snapshots.mjs.map +1 -1
  344. package/dist/routers/storybook.mjs +57 -104
  345. package/dist/routers/storybook.mjs.map +1 -1
  346. package/dist/routers/tokens.mjs +3 -7
  347. package/dist/routers/tokens.mjs.map +1 -1
  348. package/dist/routers/ui.mjs +38 -7
  349. package/dist/routers/ui.mjs.map +1 -1
  350. package/dist/routers/webhooks.mjs +6 -13
  351. package/dist/routers/webhooks.mjs.map +1 -1
  352. package/dist/routers/well-known.mjs +12 -6
  353. package/dist/routers/well-known.mjs.map +1 -1
  354. package/dist/routes/api-routes.mjs +92 -0
  355. package/dist/routes/api-routes.mjs.map +1 -0
  356. package/dist/routes/classification.mjs +37 -0
  357. package/dist/routes/classification.mjs.map +1 -0
  358. package/dist/routes/openapi-classes.mjs +21 -0
  359. package/dist/routes/openapi-classes.mjs.map +1 -0
  360. package/dist/routes/page-routes.mjs +103 -0
  361. package/dist/routes/page-routes.mjs.map +1 -0
  362. package/dist/runtime.mjs +19 -15
  363. package/dist/runtime.mjs.map +1 -1
  364. package/dist/serverless.mjs +4 -0
  365. package/dist/store.mjs +20 -3
  366. package/dist/store.mjs.map +1 -1
  367. package/dist/targets.mjs +45 -0
  368. package/dist/targets.mjs.map +1 -0
  369. package/dist/ui/avatar.mjs +1 -2
  370. package/dist/ui/buttons.mjs +17 -5
  371. package/dist/ui/buttons.mjs.map +1 -1
  372. package/dist/ui/code-block.mjs +1 -2
  373. package/dist/ui/compare-stage.mjs +86 -54
  374. package/dist/ui/compare-stage.mjs.map +1 -1
  375. package/dist/ui/csrf-field.mjs +1 -2
  376. package/dist/ui/css.mjs +1 -2
  377. package/dist/ui/design-reference.mjs +96 -0
  378. package/dist/ui/design-reference.mjs.map +1 -0
  379. package/dist/ui/document.mjs +2 -4
  380. package/dist/ui/document.mjs.map +1 -1
  381. package/dist/ui/dropdown.mjs +1 -2
  382. package/dist/ui/feedback.mjs +1 -2
  383. package/dist/ui/filter-input.mjs +1 -2
  384. package/dist/ui/forms.mjs +7 -7
  385. package/dist/ui/forms.mjs.map +1 -1
  386. package/dist/ui/icons/icon.mjs +1 -2
  387. package/dist/ui/icons/paths.mjs +2 -2
  388. package/dist/ui/icons/paths.mjs.map +1 -1
  389. package/dist/ui/icons/sprite.mjs +1 -2
  390. package/dist/ui/kbd.mjs +1 -2
  391. package/dist/ui/layout.mjs +1 -2
  392. package/dist/ui/preview-embed.mjs +81 -0
  393. package/dist/ui/preview-embed.mjs.map +1 -0
  394. package/dist/ui/progress.mjs +1 -2
  395. package/dist/ui/segmented.mjs +1 -2
  396. package/dist/ui/shell/account.mjs +1 -2
  397. package/dist/ui/shell/bare.mjs +1 -2
  398. package/dist/ui/shell/boot-script.mjs +1 -2
  399. package/dist/ui/shell/client-script.mjs +86 -2
  400. package/dist/ui/shell/client-script.mjs.map +1 -1
  401. package/dist/ui/shell/nav.mjs +13 -10
  402. package/dist/ui/shell/nav.mjs.map +1 -1
  403. package/dist/ui/shell/review-script.mjs +25 -3
  404. package/dist/ui/shell/review-script.mjs.map +1 -1
  405. package/dist/ui/shell/sidebar.mjs +3 -4
  406. package/dist/ui/shell/sidebar.mjs.map +1 -1
  407. package/dist/ui/shell/topbar.mjs +1 -2
  408. package/dist/ui/stacks.mjs +1 -2
  409. package/dist/ui/styles/base.mjs +1 -2
  410. package/dist/ui/styles/behavior.mjs +1 -2
  411. package/dist/ui/styles/review-layout.mjs +1 -2
  412. package/dist/ui/styles/review.mjs +1 -2
  413. package/dist/ui/styles/tokens.mjs +1 -2
  414. package/dist/ui/styles.mjs +1 -2
  415. package/dist/ui/subnav.mjs +1 -2
  416. package/dist/ui/table.mjs +1 -2
  417. package/dist/ui/theme.mjs +1 -2
  418. package/dist/ui/thumbnail.mjs +1 -2
  419. package/dist/ui/time.mjs +1 -2
  420. package/package.json +14 -12
  421. package/dist/asset-paths.mjs +0 -23
  422. package/dist/asset-paths.mjs.map +0 -1
  423. package/dist/assets/mark.svg +0 -1
  424. package/dist/pages/settings-status.mjs +0 -137
  425. package/dist/pages/settings-status.mjs.map +0 -1
  426. package/dist/routers/settings-status.mjs +0 -77
  427. package/dist/routers/settings-status.mjs.map +0 -1
  428. package/dist/routers/status-configs.mjs +0 -108
  429. package/dist/routers/status-configs.mjs.map +0 -1
@@ -0,0 +1,71 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { resolveAuthorizedProject, resolveReviewer } from "./helpers.mjs";
5
+ import { hxRefresh } from "./htmx.mjs";
6
+ import { flash } from "./flash.mjs";
7
+ import { buildReviewCreateSchema, commentCreateSchema } from "./schemas.mjs";
8
+ import { APPROVER_ROLES, DEVELOPER_ROLES, buildForProject } from "./builds.handlers.mjs";
9
+ import { giveVerdict } from "./build-reviews.handlers.mjs";
10
+ import { createComment, resolveBuildComment } from "./comments.mjs";
11
+ import { HTTPException } from "hono/http-exception";
12
+ // src/routers/review-forms.ts
13
+ /** Register the form routes of review (`review` class). */
14
+ function registerReviewForms(app) {
15
+ const base = "/projects/:slug/builds/:buildId";
16
+ app.post(`${base}/comments`, async (c) => {
17
+ const { project, build } = await target(c, DEVELOPER_ROLES);
18
+ const input = commentCreateSchema.safeParse(await fields(c));
19
+ if (!input.success) throw new HTTPException(400, { message: "A comment needs some text (up to 4000 characters)" });
20
+ await createComment(project, build.id, input.data);
21
+ return done(c, build.id, "Comment added");
22
+ });
23
+ app.post(`${base}/comments/:commentId/resolve`, async (c) => {
24
+ const { build } = await target(c, DEVELOPER_ROLES);
25
+ await resolveBuildComment(build.id, c.req.param("commentId"));
26
+ return done(c, build.id, "Comment resolved");
27
+ });
28
+ app.post(`${base}/reviews`, async (c) => {
29
+ const { project, build } = await target(c, APPROVER_ROLES);
30
+ const input = buildReviewCreateSchema.safeParse(await fields(c));
31
+ if (!input.success) throw new HTTPException(400, { message: "Choose approve or reject" });
32
+ await giveVerdict(project, build, await resolveReviewer(c), input.data);
33
+ return done(c, build.id, "Verdict recorded");
34
+ });
35
+ }
36
+ async function target(c, roles) {
37
+ const project = await resolveAuthorizedProject(c, c.req.param("slug") ?? "", ...roles);
38
+ return {
39
+ project,
40
+ build: await buildForProject(project.id, c.req.param("buildId") ?? "")
41
+ };
42
+ }
43
+ /** The form's text fields, blanks left out (an empty `storyId` means no story). */
44
+ async function fields(c) {
45
+ const form = await c.req.formData();
46
+ const values = {};
47
+ for (const [key, value] of form.entries()) if (typeof value === "string" && key !== "csrf_token" && value.trim() !== "") values[key] = value.trim();
48
+ return values;
49
+ }
50
+ /** HTMX reloads the page it posted from; a plain form goes back to the page, else the build. */
51
+ function done(c, buildId, message) {
52
+ flash(c, message);
53
+ if (c.req.header("HX-Request") === "true") {
54
+ hxRefresh(c);
55
+ return c.body(null, 204);
56
+ }
57
+ return c.redirect(returnPath(c, buildId), 303);
58
+ }
59
+ /** The path the form was posted from when it is on this host, else the build page. */
60
+ function returnPath(c, buildId) {
61
+ const fallback = `/projects/${c.req.param("slug") ?? ""}/builds/${buildId}`;
62
+ try {
63
+ const referer = new URL(c.req.header("referer") ?? "", c.req.url);
64
+ return referer.origin === new URL(c.req.url).origin ? `${referer.pathname}${referer.search}` : fallback;
65
+ } catch {
66
+ return fallback;
67
+ }
68
+ }
69
+ export { registerReviewForms };
70
+
71
+ //# sourceMappingURL=review-forms.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-forms.mjs","names":[],"sources":["../../src/routers/review-forms.ts"],"sourcesContent":["/**\n * The review forms of the build, diff and component pages. HTMX and plain forms post\n * `application/x-www-form-urlencoded`, which the JSON endpoints under `/api/v1` refuse (415), so\n * each form has a page route that reads the form and calls the same handlers as the API. All\n * three are `review` routes: they answer 404 for a project with review off.\n */\nimport type { Build, Project } from \"@storyshelf/core/schema\";\nimport type { ProjectRole } from \"@storyshelf/core/types\";\nimport type { Context } from \"hono\";\nimport { HTTPException } from \"hono/http-exception\";\nimport type { ShelfRouter } from \"../app-types.ts\";\nimport { giveVerdict } from \"./build-reviews.handlers.ts\";\nimport { APPROVER_ROLES, DEVELOPER_ROLES, buildForProject } from \"./builds.handlers.ts\";\nimport { createComment, resolveBuildComment } from \"./comments.ts\";\nimport { flash } from \"./flash.ts\";\nimport { resolveAuthorizedProject, resolveReviewer } from \"./helpers.ts\";\nimport { hxRefresh } from \"./htmx.ts\";\nimport { buildReviewCreateSchema, commentCreateSchema } from \"./schemas.ts\";\n\n/** Register the form routes of review (`review` class). */\nexport function registerReviewForms(app: ShelfRouter): void {\n const base = \"/projects/:slug/builds/:buildId\";\n app.post(`${base}/comments`, async (c) => {\n const { project, build } = await target(c, DEVELOPER_ROLES);\n const input = commentCreateSchema.safeParse(await fields(c));\n if (!input.success) {\n throw new HTTPException(400, {\n message: \"A comment needs some text (up to 4000 characters)\",\n });\n }\n await createComment(project, build.id, input.data);\n return done(c, build.id, \"Comment added\");\n });\n\n app.post(`${base}/comments/:commentId/resolve`, async (c) => {\n const { build } = await target(c, DEVELOPER_ROLES);\n await resolveBuildComment(build.id, c.req.param(\"commentId\"));\n return done(c, build.id, \"Comment resolved\");\n });\n\n app.post(`${base}/reviews`, async (c) => {\n const { project, build } = await target(c, APPROVER_ROLES);\n const input = buildReviewCreateSchema.safeParse(await fields(c));\n if (!input.success) {\n throw new HTTPException(400, { message: \"Choose approve or reject\" });\n }\n await giveVerdict(project, build, await resolveReviewer(c), input.data);\n return done(c, build.id, \"Verdict recorded\");\n });\n}\n\nasync function target(\n c: Context,\n roles: readonly ProjectRole[],\n): Promise<{ project: Project; build: Build }> {\n const project = await resolveAuthorizedProject(c, c.req.param(\"slug\") ?? \"\", ...roles);\n const build = await buildForProject(project.id, c.req.param(\"buildId\") ?? \"\");\n return { project, build };\n}\n\n/** The form's text fields, blanks left out (an empty `storyId` means no story). */\nasync function fields(c: Context): Promise<Record<string, string>> {\n const form = await c.req.formData();\n const values: Record<string, string> = {};\n for (const [key, value] of form.entries()) {\n if (typeof value === \"string\" && key !== \"csrf_token\" && value.trim() !== \"\") {\n values[key] = value.trim();\n }\n }\n return values;\n}\n\n/** HTMX reloads the page it posted from; a plain form goes back to the page, else the build. */\nfunction done(c: Context, buildId: string, message: string): Response {\n flash(c, message);\n if (c.req.header(\"HX-Request\") === \"true\") {\n hxRefresh(c);\n return c.body(null, 204);\n }\n return c.redirect(returnPath(c, buildId), 303);\n}\n\n/** The path the form was posted from when it is on this host, else the build page. */\nfunction returnPath(c: Context, buildId: string): string {\n const slug = c.req.param(\"slug\") ?? \"\";\n const fallback = `/projects/${slug}/builds/${buildId}`;\n try {\n const referer = new URL(c.req.header(\"referer\") ?? \"\", c.req.url);\n return referer.origin === new URL(c.req.url).origin\n ? `${referer.pathname}${referer.search}`\n : fallback;\n } catch {\n return fallback;\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAoBA,SAAgB,oBAAoB,KAAwB;CAC1D,MAAM,OAAO;CACb,IAAI,KAAK,GAAG,KAAK,YAAY,OAAO,MAAM;EACxC,MAAM,EAAE,SAAS,UAAU,MAAM,OAAO,GAAG,eAAe;EAC1D,MAAM,QAAQ,oBAAoB,UAAU,MAAM,OAAO,CAAC,CAAC;EAC3D,IAAI,CAAC,MAAM,SACT,MAAM,IAAI,cAAc,KAAK,EAC3B,SAAS,oDACX,CAAC;EAEH,MAAM,cAAc,SAAS,MAAM,IAAI,MAAM,IAAI;EACjD,OAAO,KAAK,GAAG,MAAM,IAAI,eAAe;CAC1C,CAAC;CAED,IAAI,KAAK,GAAG,KAAK,+BAA+B,OAAO,MAAM;EAC3D,MAAM,EAAE,UAAU,MAAM,OAAO,GAAG,eAAe;EACjD,MAAM,oBAAoB,MAAM,IAAI,EAAE,IAAI,MAAM,WAAW,CAAC;EAC5D,OAAO,KAAK,GAAG,MAAM,IAAI,kBAAkB;CAC7C,CAAC;CAED,IAAI,KAAK,GAAG,KAAK,WAAW,OAAO,MAAM;EACvC,MAAM,EAAE,SAAS,UAAU,MAAM,OAAO,GAAG,cAAc;EACzD,MAAM,QAAQ,wBAAwB,UAAU,MAAM,OAAO,CAAC,CAAC;EAC/D,IAAI,CAAC,MAAM,SACT,MAAM,IAAI,cAAc,KAAK,EAAE,SAAS,2BAA2B,CAAC;EAEtE,MAAM,YAAY,SAAS,OAAO,MAAM,gBAAgB,CAAC,GAAG,MAAM,IAAI;EACtE,OAAO,KAAK,GAAG,MAAM,IAAI,kBAAkB;CAC7C,CAAC;AACH;AAEA,eAAe,OACb,GACA,OAC6C;CAC7C,MAAM,UAAU,MAAM,yBAAyB,GAAG,EAAE,IAAI,MAAM,MAAM,KAAK,IAAI,GAAG,KAAK;CAErF,OAAO;EAAE;EAAS,OAAA,MADE,gBAAgB,QAAQ,IAAI,EAAE,IAAI,MAAM,SAAS,KAAK,EAAE;CACpD;AAC1B;;AAGA,eAAe,OAAO,GAA6C;CACjE,MAAM,OAAO,MAAM,EAAE,IAAI,SAAS;CAClC,MAAM,SAAiC,CAAC;CACxC,KAAK,MAAM,CAAC,KAAK,UAAU,KAAK,QAAQ,GACtC,IAAI,OAAO,UAAU,YAAY,QAAQ,gBAAgB,MAAM,KAAK,MAAM,IACxE,OAAO,OAAO,MAAM,KAAK;CAG7B,OAAO;AACT;;AAGA,SAAS,KAAK,GAAY,SAAiB,SAA2B;CACpE,MAAM,GAAG,OAAO;CAChB,IAAI,EAAE,IAAI,OAAO,YAAY,MAAM,QAAQ;EACzC,UAAU,CAAC;EACX,OAAO,EAAE,KAAK,MAAM,GAAG;CACzB;CACA,OAAO,EAAE,SAAS,WAAW,GAAG,OAAO,GAAG,GAAG;AAC/C;;AAGA,SAAS,WAAW,GAAY,SAAyB;CAEvD,MAAM,WAAW,aADJ,EAAE,IAAI,MAAM,MAAM,KAAK,GACD,UAAU;CAC7C,IAAI;EACF,MAAM,UAAU,IAAI,IAAI,EAAE,IAAI,OAAO,SAAS,KAAK,IAAI,EAAE,IAAI,GAAG;EAChE,OAAO,QAAQ,WAAW,IAAI,IAAI,EAAE,IAAI,GAAG,CAAC,CAAC,SACzC,GAAG,QAAQ,WAAW,QAAQ,WAC9B;CACN,QAAQ;EACN,OAAO;CACT;AACF"}
@@ -5,7 +5,7 @@ import { getStore } from "../store.mjs";
5
5
  import { hxRefresh, isHxRequest } from "./htmx.mjs";
6
6
  import { isOpenSnapshot } from "./baseline-guard.mjs";
7
7
  import { SnapshotModel } from "@storyshelf/core/models";
8
- //#region src/routers/review-next.ts
8
+ // src/routers/review-next.ts
9
9
  /**
10
10
  * The next snapshot still waiting for a decision after `currentId`, in list
11
11
  * order, wrapping to the start. Null when nothing else is open.
@@ -41,7 +41,6 @@ async function hxAdvance(c, target) {
41
41
  }
42
42
  c.header("HX-Redirect", url);
43
43
  }
44
- //#endregion
45
44
  export { hxAdvance, nextOpenSnapshotId };
46
45
 
47
46
  //# sourceMappingURL=review-next.mjs.map
@@ -0,0 +1,84 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { getStore } from "../store.mjs";
5
+ import { currentProjectRole } from "./helpers.mjs";
6
+ import { reviewStateOf } from "./build-reviews.handlers.mjs";
7
+ import { publishingOf } from "@storyshelf/core/capture";
8
+ import { CommentModel, UserModel, changesetOf } from "@storyshelf/core/models";
9
+ // src/routers/review-section.handlers.ts
10
+ /** Data behind the review section of the build page (ADR 0013): verdicts, changeset and comments. */
11
+ /** Whether review is on for the project (a row without the column counts as on). */
12
+ function reviewIsOn(project) {
13
+ return project.reviewEnabled !== false;
14
+ }
15
+ /** The viewer's review rights: everything with auth off, else by their role on the project. */
16
+ async function reviewCapabilities(project) {
17
+ if (!getStore().authEnabled) return {
18
+ canComment: true,
19
+ canVerdict: true
20
+ };
21
+ const role = await currentProjectRole(project.id);
22
+ return {
23
+ canComment: role === "developer" || role === "approver" || role === "admin",
24
+ canVerdict: role === "approver" || role === "admin"
25
+ };
26
+ }
27
+ /** The review section of a build; null when the project has review off. */
28
+ async function loadReviewSection(project, build, catalog) {
29
+ if (!reviewIsOn(project)) return null;
30
+ const { db, testing } = getStore();
31
+ const [state, changeset, comments, capabilities, publishing] = await Promise.all([
32
+ reviewStateOf(project, build),
33
+ changesetOf(db, project, build),
34
+ new CommentModel(db).listByBuild(build.id),
35
+ reviewCapabilities(project),
36
+ publishingOrPending(build)
37
+ ]);
38
+ const shown = comments.filter((comment) => comment.snapshotId === null);
39
+ return {
40
+ project,
41
+ build,
42
+ state,
43
+ changeset,
44
+ firstStory: firstStoryOf(catalog),
45
+ comments: shown,
46
+ names: await namesOf([...state.latest, ...shown].map((item) => item.userId)),
47
+ testing,
48
+ publishing,
49
+ ...capabilities
50
+ };
51
+ }
52
+ /** How publishing stands; a storage probe that fails reads as the storage-independent state. */
53
+ async function publishingOrPending(build) {
54
+ try {
55
+ return await publishingOf(getStore().storage, build);
56
+ } catch {
57
+ return await publishingOf(void 0, build);
58
+ }
59
+ }
60
+ /** Display names of the given users; ids that no longer resolve show as the id. */
61
+ async function namesOf(userIds) {
62
+ const users = new UserModel(getStore().db);
63
+ const ids = [...new Set(userIds.filter((id) => id !== null))];
64
+ const found = await Promise.all(ids.map(async (id) => [id, await users.get(id)]));
65
+ return new Map(found.map(([id, user]) => [id, user?.name ?? user?.email ?? id]));
66
+ }
67
+ /** Story file -> id of its first story. */
68
+ function firstStoryOf(catalog) {
69
+ const first = /* @__PURE__ */ new Map();
70
+ for (const entry of catalog?.entries ?? []) if (entry.type === "story" && !first.has(entry.importPath)) first.set(entry.importPath, entry.id);
71
+ return first;
72
+ }
73
+ /** Story comments of `build` for a component page; null when the project has review off. */
74
+ async function loadComponentReview(project, build) {
75
+ if (!reviewIsOn(project)) return null;
76
+ const [comments, capabilities] = await Promise.all([new CommentModel(getStore().db).listByBuild(build.id), reviewCapabilities(project)]);
77
+ return {
78
+ comments: comments.filter((comment) => comment.storyId !== null),
79
+ canComment: capabilities.canComment
80
+ };
81
+ }
82
+ export { loadComponentReview, loadReviewSection, namesOf, reviewCapabilities, reviewIsOn };
83
+
84
+ //# sourceMappingURL=review-section.handlers.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-section.handlers.mjs","names":[],"sources":["../../src/routers/review-section.handlers.ts"],"sourcesContent":["/** Data behind the review section of the build page (ADR 0013): verdicts, changeset and comments. */\nimport { publishingOf, type Catalog } from \"@storyshelf/core/capture\";\nimport { changesetOf, CommentModel, UserModel, type BuildChangeset } from \"@storyshelf/core/models\";\nimport type { Build, Comment, Project } from \"@storyshelf/core/schema\";\nimport { getStore } from \"../store.ts\";\nimport { reviewStateOf, type ReviewState } from \"./build-reviews.handlers.ts\";\nimport { currentProjectRole } from \"./helpers.ts\";\n\n/** What the viewer may do in review. */\nexport interface ReviewCapabilities {\n /** Write build, story and snapshot comments (developer and above). */\n canComment: boolean;\n /** Give a verdict (approver and admin). */\n canVerdict: boolean;\n}\n\n/** Everything the review cards render. */\nexport interface ReviewSectionData extends ReviewCapabilities {\n project: Project;\n build: Build;\n /** The verdicts and what they make of the build. */\n state: ReviewState;\n changeset: BuildChangeset;\n /** First story of each story file in the build, to link a component to its published story. */\n firstStory: ReadonlyMap<string, string>;\n /** Build and story comments (snapshot comments belong to the diff view). */\n comments: Comment[];\n /** Display names of the users behind verdicts and comments, by user id. */\n names: ReadonlyMap<string, string>;\n /** Whether the snapshot rollup decides the build, so the verdict is a sign-off only. */\n testing: boolean;\n /** Whether the build's Storybook is published; a verdict waits for `success` (ADR 0013). */\n publishing: Awaited<ReturnType<typeof publishingOf>>;\n}\n\n/** Whether review is on for the project (a row without the column counts as on). */\nexport function reviewIsOn(project: Pick<Project, \"reviewEnabled\">): boolean {\n return project.reviewEnabled !== false;\n}\n\n/** The viewer's review rights: everything with auth off, else by their role on the project. */\nexport async function reviewCapabilities(project: Project): Promise<ReviewCapabilities> {\n if (!getStore().authEnabled) {\n return { canComment: true, canVerdict: true };\n }\n const role = await currentProjectRole(project.id);\n return {\n canComment: role === \"developer\" || role === \"approver\" || role === \"admin\",\n canVerdict: role === \"approver\" || role === \"admin\",\n };\n}\n\n/** The review section of a build; null when the project has review off. */\nexport async function loadReviewSection(\n project: Project,\n build: Build,\n catalog: Catalog | null,\n): Promise<ReviewSectionData | null> {\n if (!reviewIsOn(project)) {\n return null;\n }\n const { db, testing } = getStore();\n const [state, changeset, comments, capabilities, publishing] = await Promise.all([\n reviewStateOf(project, build),\n changesetOf(db, project, build),\n new CommentModel(db).listByBuild(build.id),\n reviewCapabilities(project),\n publishingOrPending(build),\n ]);\n const shown = comments.filter((comment) => comment.snapshotId === null);\n return {\n project,\n build,\n state,\n changeset,\n firstStory: firstStoryOf(catalog),\n comments: shown,\n names: await namesOf([...state.latest, ...shown].map((item) => item.userId)),\n testing,\n publishing,\n ...capabilities,\n };\n}\n\n/** How publishing stands; a storage probe that fails reads as the storage-independent state. */\nasync function publishingOrPending(build: Build): Promise<ReviewSectionData[\"publishing\"]> {\n try {\n return await publishingOf(getStore().storage, build);\n } catch {\n return await publishingOf(undefined, build);\n }\n}\n\n/** Display names of the given users; ids that no longer resolve show as the id. */\nexport async function namesOf(userIds: readonly (string | null)[]): Promise<Map<string, string>> {\n const users = new UserModel(getStore().db);\n const ids = [...new Set(userIds.filter((id): id is string => id !== null))];\n const found = await Promise.all(ids.map(async (id) => [id, await users.get(id)] as const));\n return new Map(found.map(([id, user]) => [id, user?.name ?? user?.email ?? id]));\n}\n\n/** Story file -> id of its first story. */\nfunction firstStoryOf(catalog: Catalog | null): Map<string, string> {\n const first = new Map<string, string>();\n for (const entry of catalog?.entries ?? []) {\n if (entry.type === \"story\" && !first.has(entry.importPath)) {\n first.set(entry.importPath, entry.id);\n }\n }\n return first;\n}\n\n/** What a component page needs of review: the story comments of the build it shows. */\nexport interface ComponentReview {\n comments: Comment[];\n canComment: boolean;\n}\n\n/** Story comments of `build` for a component page; null when the project has review off. */\nexport async function loadComponentReview(\n project: Project,\n build: Build,\n): Promise<ComponentReview | null> {\n if (!reviewIsOn(project)) {\n return null;\n }\n const [comments, capabilities] = await Promise.all([\n new CommentModel(getStore().db).listByBuild(build.id),\n reviewCapabilities(project),\n ]);\n return {\n comments: comments.filter((comment) => comment.storyId !== null),\n canComment: capabilities.canComment,\n };\n}\n"],"mappings":";;;;;;;;;;;AAoCA,SAAgB,WAAW,SAAkD;CAC3E,OAAO,QAAQ,kBAAkB;AACnC;;AAGA,eAAsB,mBAAmB,SAA+C;CACtF,IAAI,CAAC,SAAS,CAAC,CAAC,aACd,OAAO;EAAE,YAAY;EAAM,YAAY;CAAK;CAE9C,MAAM,OAAO,MAAM,mBAAmB,QAAQ,EAAE;CAChD,OAAO;EACL,YAAY,SAAS,eAAe,SAAS,cAAc,SAAS;EACpE,YAAY,SAAS,cAAc,SAAS;CAC9C;AACF;;AAGA,eAAsB,kBACpB,SACA,OACA,SACmC;CACnC,IAAI,CAAC,WAAW,OAAO,GACrB,OAAO;CAET,MAAM,EAAE,IAAI,YAAY,SAAS;CACjC,MAAM,CAAC,OAAO,WAAW,UAAU,cAAc,cAAc,MAAM,QAAQ,IAAI;EAC/E,cAAc,SAAS,KAAK;EAC5B,YAAY,IAAI,SAAS,KAAK;EAC9B,IAAI,aAAa,EAAE,CAAC,CAAC,YAAY,MAAM,EAAE;EACzC,mBAAmB,OAAO;EAC1B,oBAAoB,KAAK;CAC3B,CAAC;CACD,MAAM,QAAQ,SAAS,QAAQ,YAAY,QAAQ,eAAe,IAAI;CACtE,OAAO;EACL;EACA;EACA;EACA;EACA,YAAY,aAAa,OAAO;EAChC,UAAU;EACV,OAAO,MAAM,QAAQ,CAAC,GAAG,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,KAAK,SAAS,KAAK,MAAM,CAAC;EAC3E;EACA;EACA,GAAG;CACL;AACF;;AAGA,eAAe,oBAAoB,OAAwD;CACzF,IAAI;EACF,OAAO,MAAM,aAAa,SAAS,CAAC,CAAC,SAAS,KAAK;CACrD,QAAQ;EACN,OAAO,MAAM,aAAa,KAAA,GAAW,KAAK;CAC5C;AACF;;AAGA,eAAsB,QAAQ,SAAmE;CAC/F,MAAM,QAAQ,IAAI,UAAU,SAAS,CAAC,CAAC,EAAE;CACzC,MAAM,MAAM,CAAC,GAAG,IAAI,IAAI,QAAQ,QAAQ,OAAqB,OAAO,IAAI,CAAC,CAAC;CAC1E,MAAM,QAAQ,MAAM,QAAQ,IAAI,IAAI,IAAI,OAAO,OAAO,CAAC,IAAI,MAAM,MAAM,IAAI,EAAE,CAAC,CAAU,CAAC;CACzF,OAAO,IAAI,IAAI,MAAM,KAAK,CAAC,IAAI,UAAU,CAAC,IAAI,MAAM,QAAQ,MAAM,SAAS,EAAE,CAAC,CAAC;AACjF;;AAGA,SAAS,aAAa,SAA8C;CAClE,MAAM,wBAAQ,IAAI,IAAoB;CACtC,KAAK,MAAM,SAAS,SAAS,WAAW,CAAC,GACvC,IAAI,MAAM,SAAS,WAAW,CAAC,MAAM,IAAI,MAAM,UAAU,GACvD,MAAM,IAAI,MAAM,YAAY,MAAM,EAAE;CAGxC,OAAO;AACT;;AASA,eAAsB,oBACpB,SACA,OACiC;CACjC,IAAI,CAAC,WAAW,OAAO,GACrB,OAAO;CAET,MAAM,CAAC,UAAU,gBAAgB,MAAM,QAAQ,IAAI,CACjD,IAAI,aAAa,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,YAAY,MAAM,EAAE,GACpD,mBAAmB,OAAO,CAC5B,CAAC;CACD,OAAO;EACL,UAAU,SAAS,QAAQ,YAAY,QAAQ,YAAY,IAAI;EAC/D,YAAY,aAAa;CAC3B;AACF"}
@@ -0,0 +1,28 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { getStore } from "../store.mjs";
5
+ import { requestBuildState } from "../git-status.mjs";
6
+ import { acceptPendingWithoutWork } from "@storyshelf/core/models";
7
+ // src/routers/review-switch-off.ts
8
+ /** The switch-off pass at the app level (ADR 0013, decision 1): accept the queue review leaves behind. */
9
+ /**
10
+ * When a save turned review off (`before` had it on), accept the project's pending builds that no
11
+ * capture worked on, in one pass. It raises no approval event (nobody approved anything), but each
12
+ * build's git channels are asked to show its new state. Returns the number of builds accepted.
13
+ */
14
+ async function runSwitchOffPass(before, after) {
15
+ if (before.reviewEnabled === false || after.reviewEnabled !== false) return 0;
16
+ const accepted = await acceptPendingWithoutWork(getStore().db, after.id);
17
+ await Promise.all(accepted.map(async (build) => {
18
+ await requestBuildState(build.id);
19
+ }));
20
+ getStore().logger.info({
21
+ projectId: after.id,
22
+ accepted: accepted.length
23
+ }, "review turned off: accepted pending builds");
24
+ return accepted.length;
25
+ }
26
+ export { runSwitchOffPass };
27
+
28
+ //# sourceMappingURL=review-switch-off.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-switch-off.mjs","names":[],"sources":["../../src/routers/review-switch-off.ts"],"sourcesContent":["/** The switch-off pass at the app level (ADR 0013, decision 1): accept the queue review leaves behind. */\nimport { acceptPendingWithoutWork } from \"@storyshelf/core/models\";\nimport type { Project } from \"@storyshelf/core/schema\";\nimport { requestBuildState } from \"../git-status.ts\";\nimport { getStore } from \"../store.ts\";\n\n/**\n * When a save turned review off (`before` had it on), accept the project's pending builds that no\n * capture worked on, in one pass. It raises no approval event (nobody approved anything), but each\n * build's git channels are asked to show its new state. Returns the number of builds accepted.\n */\nexport async function runSwitchOffPass(before: Project, after: Project): Promise<number> {\n if (before.reviewEnabled === false || after.reviewEnabled !== false) {\n return 0;\n }\n const accepted = await acceptPendingWithoutWork(getStore().db, after.id);\n await Promise.all(\n accepted.map(async (build) => {\n await requestBuildState(build.id);\n }),\n );\n getStore().logger.info(\n { projectId: after.id, accepted: accepted.length },\n \"review turned off: accepted pending builds\",\n );\n return accepted.length;\n}\n"],"mappings":";;;;;;;;;;;;;AAWA,eAAsB,iBAAiB,QAAiB,OAAiC;CACvF,IAAI,OAAO,kBAAkB,SAAS,MAAM,kBAAkB,OAC5D,OAAO;CAET,MAAM,WAAW,MAAM,yBAAyB,SAAS,CAAC,CAAC,IAAI,MAAM,EAAE;CACvE,MAAM,QAAQ,IACZ,SAAS,IAAI,OAAO,UAAU;EAC5B,MAAM,kBAAkB,MAAM,EAAE;CAClC,CAAC,CACH;CACA,SAAS,CAAC,CAAC,OAAO,KAChB;EAAE,WAAW,MAAM;EAAI,UAAU,SAAS;CAAO,GACjD,4CACF;CACA,OAAO,SAAS;AAClB"}
@@ -2,9 +2,22 @@ import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
4
  import { z } from "@hono/zod-openapi";
5
- import { BUILD_STATUSES, PROJECT_ROLES, SNAPSHOT_STATUSES } from "@storyshelf/core/types";
6
- import { BROWSER_NAMES } from "@storyshelf/core/adapter/capture-runner";
7
- //#region src/routers/schemas.ts
5
+ import { storybookUrlTtlOverrideError } from "@storyshelf/core/utils";
6
+ import { WebhookModel } from "@storyshelf/core/models";
7
+ import { BUILD_STATUSES, PROJECT_ROLES, REVIEW_VERDICTS, SNAPSHOT_STATUSES } from "@storyshelf/core/types";
8
+ import { BROWSER_NAMES, TARGET_NAME_PATTERN } from "@storyshelf/core/adapter/capture-runner";
9
+ // src/routers/schemas.ts
10
+ /** A capture target: an engine (`chromium`) or a remote one, `<engine>@<name>` (ADR 0007). */
11
+ const captureTargetSchema = z.string().regex(new RegExp(`^(?:${BROWSER_NAMES.join("|")})(?:@${TARGET_NAME_PATTERN.source.slice(1, -1)})?$`, "u"), "Expected an engine (chromium, firefox, webkit, chrome) or <engine>@<name>");
12
+ const reviewApprovalsSchema = z.number().int().min(1).max(20);
13
+ /** Seconds a signed Storybook URL stays valid (ADR 0007, decision 5). */
14
+ const storybookUrlTtlSchema = z.number().int().superRefine((seconds, ctx) => {
15
+ const message = storybookUrlTtlOverrideError(seconds);
16
+ if (message !== void 0) ctx.addIssue({
17
+ code: "custom",
18
+ message
19
+ });
20
+ });
8
21
  const storybookMetaSchema = z.record(z.string(), z.unknown()).nullable().optional();
9
22
  /** OpenAPI schema for a project record. */
10
23
  const projectSchema = z.object({
@@ -19,7 +32,23 @@ const projectSchema = z.object({
19
32
  storybookMeta: z.string().nullable().optional(),
20
33
  executePlay: z.boolean(),
21
34
  playTimeoutMs: z.number(),
35
+ /** Axe accessibility checks run during capture (default on; results never block a build). */
36
+ runA11y: z.boolean().optional(),
37
+ /** Storybook 10 `.test()` entries run as interaction tests during capture (default off). */
38
+ runTests: z.boolean().optional(),
22
39
  browser: z.string().optional(),
40
+ /** JSON array of capture targets, primary first, primary first; null = just `browser`. */
41
+ browsers: z.string().nullable().optional(),
42
+ /** JSON array of mode names to capture; null = every declared mode. */
43
+ modesAllowlist: z.string().nullable().optional(),
44
+ /** AI profile gate: null/absent = AI off for this project. */
45
+ aiProfile: z.string().nullable().optional(),
46
+ /** Review is on for this project (ADR 0013, decision 1). */
47
+ reviewEnabled: z.boolean().optional(),
48
+ /** Approvals a build needs when `testing` is off. */
49
+ reviewApprovals: z.number().optional(),
50
+ /** Seconds the signed Storybook URLs of a render stay valid; null derives it from the stories. */
51
+ storybookUrlTtlSeconds: z.number().nullable().optional(),
23
52
  createdAt: z.string(),
24
53
  updatedAt: z.string()
25
54
  }).openapi("Project");
@@ -30,7 +59,13 @@ const projectCreateSchema = z.object({
30
59
  gitDefaultBranch: z.string().optional(),
31
60
  storybookMeta: storybookMetaSchema,
32
61
  executePlay: z.boolean().optional(),
33
- playTimeoutMs: z.number().int().min(1e3).max(3e4).optional()
62
+ playTimeoutMs: z.number().int().min(1e3).max(3e4).optional(),
63
+ /** Axe accessibility checks during capture; on when omitted. */
64
+ runA11y: z.boolean().optional(),
65
+ /** Run Storybook 10 `.test()` entries as interaction tests during capture; off when omitted. */
66
+ runTests: z.boolean().optional(),
67
+ reviewEnabled: z.boolean().optional(),
68
+ reviewApprovals: reviewApprovalsSchema.optional()
34
69
  }).openapi("ProjectCreateInput");
35
70
  /** OpenAPI schema for patching a project. */
36
71
  const projectUpdateSchema = z.object({
@@ -43,7 +78,24 @@ const projectUpdateSchema = z.object({
43
78
  storybookMeta: storybookMetaSchema,
44
79
  executePlay: z.boolean().optional(),
45
80
  playTimeoutMs: z.number().int().min(1e3).max(3e4).optional(),
46
- browser: z.enum(BROWSER_NAMES).optional()
81
+ /** Turn axe accessibility checks during capture on or off (admins). */
82
+ runA11y: z.boolean().optional(),
83
+ /** Turn the Storybook 10 `.test()` runs on or off (admins). */
84
+ runTests: z.boolean().optional(),
85
+ /** Single capture target; clears `browsers`. */
86
+ browser: captureTargetSchema.optional(),
87
+ /** Capture targets, primary first (max 3); null returns to single `browser`. */
88
+ browsers: z.array(captureTargetSchema).min(1).max(3).nullable().optional(),
89
+ /** Mode names to capture; null runs every declared mode. */
90
+ modesAllowlist: z.array(z.string().min(1)).max(50).nullable().optional(),
91
+ /** Site admins only: a configured AI profile name, or null to turn AI off. */
92
+ aiProfile: z.string().min(1).nullable().optional(),
93
+ /** Turn review (comments and build-level verdicts) on or off for the project. */
94
+ reviewEnabled: z.boolean().optional(),
95
+ /** Approvals a build needs before it is accepted when `testing` is off. */
96
+ reviewApprovals: reviewApprovalsSchema.optional(),
97
+ /** Seconds (at least one minimum slice plus grace, 1050, to 86400) the signed Storybook URLs of a render stay valid; null derives it from the stories. */
98
+ storybookUrlTtlSeconds: storybookUrlTtlSchema.nullable().optional()
47
99
  }).openapi("ProjectUpdateInput");
48
100
  /** OpenAPI schema for a build record. */
49
101
  const buildSchema = z.object({
@@ -61,10 +113,13 @@ const buildSchema = z.object({
61
113
  changedCount: z.number(),
62
114
  approvedCount: z.number(),
63
115
  rejectedCount: z.number(),
116
+ inheritedCount: z.number(),
64
117
  affectedOnly: z.boolean(),
65
118
  baselineSha: z.string().nullable(),
66
119
  changedFiles: z.string().nullable(),
67
120
  affectedImportPaths: z.string().nullable(),
121
+ /** JSON array of the build's Storybook `.test()` results (id, title, name, status, error); null when none ran. */
122
+ testResults: z.string().nullable().optional(),
68
123
  createdAt: z.string(),
69
124
  updatedAt: z.string()
70
125
  }).openapi("Build");
@@ -78,6 +133,8 @@ const snapshotSchema = z.object({
78
133
  storyTitle: z.string(),
79
134
  storyImportPath: z.string().nullable(),
80
135
  viewportName: z.string(),
136
+ /** Globals JSON the capture's mode applied; null for plain viewports. */
137
+ mode: z.string().nullable().optional(),
81
138
  viewportWidth: z.number(),
82
139
  viewportHeight: z.number(),
83
140
  screenshotPath: z.string(),
@@ -89,6 +146,8 @@ const snapshotSchema = z.object({
89
146
  reviewedBy: z.string().nullable(),
90
147
  reviewedAt: z.string().nullable(),
91
148
  inherited: z.boolean(),
149
+ /** JSON array of the axe violations found on this capture (non-blocking); null when none. */
150
+ a11yViolations: z.string().nullable().optional(),
92
151
  createdAt: z.string(),
93
152
  updatedAt: z.string()
94
153
  }).openapi("Snapshot");
@@ -133,6 +192,8 @@ const commentSchema = z.object({
133
192
  projectId: z.string(),
134
193
  buildId: z.string(),
135
194
  snapshotId: z.string().nullable(),
195
+ /** Storybook story id of a story-anchored comment. */
196
+ storyId: z.string().nullable().optional(),
136
197
  userId: z.string().nullable(),
137
198
  body: z.string(),
138
199
  parentId: z.string().nullable(),
@@ -143,9 +204,39 @@ const commentSchema = z.object({
143
204
  /** OpenAPI schema for creating a build comment. */
144
205
  const commentCreateSchema = z.object({
145
206
  body: z.string().min(1),
207
+ /** Anchor to a snapshot; not together with `storyId`. */
146
208
  snapshotId: z.string().optional(),
209
+ /** Anchor to a story of the build; not together with `snapshotId`. */
210
+ storyId: z.string().min(1).optional(),
147
211
  parentId: z.string().optional()
148
212
  }).openapi("CommentCreateInput");
213
+ /** OpenAPI schema for a build-level review verdict. */
214
+ const buildReviewSchema = z.object({
215
+ id: z.string(),
216
+ buildId: z.string(),
217
+ userId: z.string().nullable(),
218
+ verdict: z.enum(REVIEW_VERDICTS),
219
+ body: z.string().nullable(),
220
+ createdAt: z.string()
221
+ }).openapi("BuildReview");
222
+ /** OpenAPI schema for giving a build a verdict. */
223
+ const buildReviewCreateSchema = z.object({
224
+ verdict: z.enum(REVIEW_VERDICTS),
225
+ body: z.string().max(4e3).optional()
226
+ }).openapi("BuildReviewInput");
227
+ /** OpenAPI schema for a build's review state: the verdicts and what they make of the build. */
228
+ const buildReviewStateSchema = z.object({
229
+ /** Build status now. */
230
+ status: z.enum(BUILD_STATUSES),
231
+ /** Approvals the project requires. */
232
+ approvalsRequired: z.number(),
233
+ /** Approvals among the reviewers' latest verdicts. */
234
+ approvals: z.number(),
235
+ /** Every reviewer's latest verdict. */
236
+ latest: buildReviewSchema.array(),
237
+ /** Every verdict given, oldest first. */
238
+ history: buildReviewSchema.array()
239
+ }).openapi("BuildReviewState");
149
240
  /** OpenAPI schema for a project label type. */
150
241
  const labelTypeSchema = z.object({
151
242
  id: z.string(),
@@ -218,9 +309,10 @@ const webhookPublicSchema = z.object({
218
309
  url: z.string(),
219
310
  events: z.array(z.string())
220
311
  }).openapi("Webhook");
312
+ const webhookUrlBase = z.string().url();
221
313
  /** OpenAPI schema for creating a webhook. */
222
314
  const webhookCreateSchema = z.object({
223
- url: z.string().url(),
315
+ url: webhookUrlBase.refine((url) => WebhookModel.urlError(url) === null, { message: "URL must use http or https" }),
224
316
  events: z.array(z.string().min(1)).optional()
225
317
  }).openapi("WebhookCreateInput");
226
318
  /** OpenAPI schema for a newly created webhook including its signing secret. */
@@ -230,22 +322,6 @@ const webhookCreatedSchema = z.object({
230
322
  events: z.array(z.string()),
231
323
  secret: z.string()
232
324
  }).openapi("WebhookCreated");
233
- /** OpenAPI schema for a git status-check configuration. */
234
- const statusConfigSchema = z.object({
235
- id: z.string(),
236
- projectId: z.string(),
237
- provider: z.string(),
238
- config: z.record(z.string(), z.unknown()),
239
- hasToken: z.boolean(),
240
- createdAt: z.string(),
241
- updatedAt: z.string()
242
- }).openapi("StatusConfig");
243
- /** OpenAPI schema for creating a git status-check configuration. */
244
- const statusConfigCreateSchema = z.object({
245
- provider: z.string().min(1),
246
- config: z.record(z.string(), z.unknown()),
247
- token: z.string().min(1)
248
- }).openapi("StatusConfigCreateInput");
249
325
  /** OpenAPI schema for a public notification channel (secret omitted). */
250
326
  const notificationChannelSchema = z.object({
251
327
  id: z.string(),
@@ -255,6 +331,8 @@ const notificationChannelSchema = z.object({
255
331
  hasSecret: z.boolean(),
256
332
  events: z.array(z.string()),
257
333
  enabled: z.boolean(),
334
+ lastError: z.string().nullable(),
335
+ lastErrorAt: z.string().nullable(),
258
336
  createdAt: z.string(),
259
337
  updatedAt: z.string()
260
338
  }).openapi("NotificationChannel");
@@ -287,6 +365,11 @@ const approveAllResultSchema = z.object({
287
365
  ok: z.boolean(),
288
366
  skipped: z.array(z.string())
289
367
  }).openapi("ApproveAllResult");
368
+ /** Group decision result: the snapshots one story/mode decision covered. */
369
+ const groupDecisionResultSchema = z.object({
370
+ ok: z.boolean(),
371
+ snapshotIds: z.array(z.string())
372
+ }).openapi("GroupDecisionResult");
290
373
  /** Result of re-diffing a build against the baselines that apply now. */
291
374
  const rediffResultSchema = z.object({
292
375
  ok: z.boolean(),
@@ -331,7 +414,41 @@ const notFound = { 404: {
331
414
  content: { "application/json": { schema: errorSchema } },
332
415
  description: "Not found"
333
416
  } };
334
- //#endregion
335
- export { approveAllResultSchema, attemptLogSchema, attemptSchema, badRequest, baselineChangedSchema, buildSchema, commentCreateSchema, commentSchema, errorSchema, forbidden, groupMappingCreateSchema, groupMappingSchema, labelTypeCreateSchema, labelTypeSchema, labelTypeUpdateSchema, memberRoleSchema, memberSchema, memberSetSchema, notFound, notificationChannelCreateSchema, notificationChannelSchema, notificationSubscriptionPutSchema, notificationSubscriptionSchema, okSchema, projectCreateSchema, projectSchema, projectUpdateSchema, purgeInputSchema, purgeSchema, rediffResultSchema, snapshotSchema, statusConfigCreateSchema, statusConfigSchema, tokenCreateSchema, tokenCreatedSchema, tokenPublicSchema, unauthorized, webhookCreateSchema, webhookCreatedSchema, webhookPublicSchema };
417
+ /** OpenAPI schema for an insight (build triage or project health). */
418
+ const insightSchema = z.object({
419
+ id: z.string(),
420
+ kind: z.enum(["triage", "health"]),
421
+ buildId: z.string().nullable(),
422
+ window: z.string().nullable(),
423
+ status: z.enum([
424
+ "pending",
425
+ "running",
426
+ "done",
427
+ "failed"
428
+ ]),
429
+ profile: z.string(),
430
+ model: z.string(),
431
+ promptVersion: z.string(),
432
+ verdict: z.string().nullable(),
433
+ summary: z.string().nullable(),
434
+ output: z.unknown().nullable(),
435
+ meta: z.unknown().nullable(),
436
+ errorCode: z.string().nullable(),
437
+ createdAt: z.string(),
438
+ startedAt: z.string().nullable(),
439
+ finishedAt: z.string().nullable()
440
+ }).openapi("Insight");
441
+ /** Request body to (re)generate a build triage. */
442
+ const insightRequestSchema = z.object({
443
+ task: z.literal("triage").optional(),
444
+ force: z.boolean().optional(),
445
+ profile: z.string().min(1).optional()
446
+ }).openapi("InsightRequest");
447
+ /** Request body to (re)generate a project-health digest. */
448
+ const healthRequestSchema = z.object({
449
+ window: z.string().optional(),
450
+ force: z.boolean().optional()
451
+ }).openapi("HealthInsightRequest");
452
+ export { approveAllResultSchema, attemptLogSchema, attemptSchema, badRequest, baselineChangedSchema, buildReviewCreateSchema, buildReviewSchema, buildReviewStateSchema, buildSchema, commentCreateSchema, commentSchema, errorSchema, forbidden, groupDecisionResultSchema, groupMappingCreateSchema, groupMappingSchema, healthRequestSchema, insightRequestSchema, insightSchema, labelTypeCreateSchema, labelTypeSchema, labelTypeUpdateSchema, memberRoleSchema, memberSchema, memberSetSchema, notFound, notificationChannelCreateSchema, notificationChannelSchema, notificationSubscriptionPutSchema, notificationSubscriptionSchema, okSchema, projectCreateSchema, projectSchema, projectUpdateSchema, purgeInputSchema, purgeSchema, rediffResultSchema, snapshotSchema, tokenCreateSchema, tokenCreatedSchema, tokenPublicSchema, unauthorized, webhookCreateSchema, webhookCreatedSchema, webhookPublicSchema };
336
453
 
337
454
  //# sourceMappingURL=schemas.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"schemas.mjs","names":[],"sources":["../../src/routers/schemas.ts"],"sourcesContent":["import { z } from \"@hono/zod-openapi\";\nimport { BROWSER_NAMES } from \"@storyshelf/core/adapter/capture-runner\";\nimport { BUILD_STATUSES, PROJECT_ROLES, SNAPSHOT_STATUSES } from \"@storyshelf/core/types\";\n\nconst storybookMetaSchema = z.record(z.string(), z.unknown()).nullable().optional();\n\n/** OpenAPI schema for a project record. */\nexport const projectSchema = z\n .object({\n id: z.string(),\n name: z.string(),\n slug: z.string(),\n gitRepository: z.string().nullable(),\n gitDefaultBranch: z.string(),\n pixelThreshold: z.number(),\n maxDiffRatio: z.number(),\n publicBranchRegex: z.string().nullable(),\n storybookMeta: z.string().nullable().optional(),\n executePlay: z.boolean(),\n playTimeoutMs: z.number(),\n // Stored rows predate enum validation, so the response stays a plain string.\n browser: z.string().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n })\n .openapi(\"Project\");\n\n/** OpenAPI schema for creating a project. */\nexport const projectCreateSchema = z\n .object({\n name: z.string().min(1),\n gitRepository: z.string().optional(),\n gitDefaultBranch: z.string().optional(),\n storybookMeta: storybookMetaSchema,\n executePlay: z.boolean().optional(),\n playTimeoutMs: z.number().int().min(1000).max(30_000).optional(),\n })\n .openapi(\"ProjectCreateInput\");\n\n/** OpenAPI schema for patching a project. */\nexport const projectUpdateSchema = z\n .object({\n name: z.string().optional(),\n gitRepository: z.string().optional(),\n gitDefaultBranch: z.string().optional(),\n pixelThreshold: z.number().optional(),\n maxDiffRatio: z.number().optional(),\n publicBranchRegex: z.string().nullable().optional(),\n storybookMeta: storybookMetaSchema,\n executePlay: z.boolean().optional(),\n playTimeoutMs: z.number().int().min(1000).max(30_000).optional(),\n browser: z.enum(BROWSER_NAMES).optional(),\n })\n .openapi(\"ProjectUpdateInput\");\n\n/** OpenAPI schema for a build record. */\nexport const buildSchema = z\n .object({\n id: z.string(),\n projectId: z.string(),\n gitSha: z.string(),\n gitBranch: z.string(),\n isDefault: z.boolean(),\n authorEmail: z.string().nullable(),\n authorName: z.string().nullable(),\n message: z.string().nullable(),\n public: z.boolean(),\n status: z.enum(BUILD_STATUSES),\n snapshotCount: z.number(),\n changedCount: z.number(),\n approvedCount: z.number(),\n rejectedCount: z.number(),\n affectedOnly: z.boolean(),\n baselineSha: z.string().nullable(),\n changedFiles: z.string().nullable(),\n affectedImportPaths: z.string().nullable(),\n createdAt: z.string(),\n updatedAt: z.string(),\n })\n .openapi(\"Build\");\n\n/** OpenAPI schema for a snapshot record. */\nexport const snapshotSchema = z\n .object({\n id: z.string(),\n projectId: z.string(),\n buildId: z.string(),\n storyId: z.string(),\n storyName: z.string(),\n storyTitle: z.string(),\n storyImportPath: z.string().nullable(),\n viewportName: z.string(),\n viewportWidth: z.number(),\n viewportHeight: z.number(),\n screenshotPath: z.string(),\n diffPath: z.string().nullable(),\n diffPixels: z.number().nullable(),\n diffRatio: z.number().nullable(),\n diffPassed: z.boolean().nullable(),\n status: z.enum(SNAPSHOT_STATUSES),\n reviewedBy: z.string().nullable(),\n reviewedAt: z.string().nullable(),\n inherited: z.boolean(),\n createdAt: z.string(),\n updatedAt: z.string(),\n })\n .openapi(\"Snapshot\");\n\n/** OpenAPI schema for a capture attempt (one run of a build's capture). */\nexport const attemptSchema = z\n .object({\n id: z.string(),\n projectId: z.string(),\n buildId: z.string(),\n attemptNo: z.number(),\n status: z.enum([\"queued\", \"running\", \"completed\", \"failed\", \"cancelled\"]),\n error: z.string().nullable(),\n reqId: z.string().nullable(),\n storyCount: z.number(),\n failedCount: z.number(),\n queuedAt: z.string(),\n startedAt: z.string().nullable(),\n finishedAt: z.string().nullable(),\n createdAt: z.string(),\n updatedAt: z.string(),\n })\n .openapi(\"CaptureAttempt\");\n\n/** OpenAPI schema for a single capture log line within an attempt. */\nexport const attemptLogSchema = z\n .object({\n id: z.string(),\n projectId: z.string(),\n buildId: z.string(),\n attemptId: z.string(),\n seq: z.number(),\n level: z.string(),\n message: z.string(),\n fields: z.string().nullable(),\n createdAt: z.string(),\n })\n .openapi(\"CaptureLog\");\n\n/** OpenAPI schema for a build comment. */\nexport const commentSchema = z\n .object({\n id: z.string(),\n projectId: z.string(),\n buildId: z.string(),\n snapshotId: z.string().nullable(),\n userId: z.string().nullable(),\n body: z.string(),\n parentId: z.string().nullable(),\n resolved: z.boolean(),\n createdAt: z.string(),\n updatedAt: z.string(),\n })\n .openapi(\"Comment\");\n\n/** OpenAPI schema for creating a build comment. */\nexport const commentCreateSchema = z\n .object({\n body: z.string().min(1),\n snapshotId: z.string().optional(),\n parentId: z.string().optional(),\n })\n .openapi(\"CommentCreateInput\");\n\n/** OpenAPI schema for a project label type. */\nexport const labelTypeSchema = z\n .object({\n id: z.string(),\n projectId: z.string(),\n key: z.string(),\n name: z.string(),\n linkTemplate: z.string().nullable(),\n color: z.string().nullable(),\n createdAt: z.string(),\n })\n .openapi(\"LabelType\");\n\n/** OpenAPI schema for creating a label type. */\nexport const labelTypeCreateSchema = z\n .object({\n key: z.string().min(1),\n name: z.string().min(1),\n linkTemplate: z.string().optional(),\n color: z.string().optional(),\n })\n .openapi(\"LabelTypeCreateInput\");\n\n/** OpenAPI schema for patching a label type. */\nexport const labelTypeUpdateSchema = z\n .object({\n name: z.string().min(1).optional(),\n linkTemplate: z.string().nullable().optional(),\n color: z.string().nullable().optional(),\n })\n .openapi(\"LabelTypeUpdateInput\");\n\n/** OpenAPI schema for a public API token (hash omitted). */\nexport const tokenPublicSchema = z\n .object({\n id: z.string(),\n projectId: z.string(),\n name: z.string(),\n lastUsedAt: z.string().nullable(),\n createdAt: z.string(),\n })\n .openapi(\"Token\");\n\n/** OpenAPI schema for creating an API token. */\nexport const tokenCreateSchema = z.object({ name: z.string().min(1) }).openapi(\"TokenCreateInput\");\n\n/** OpenAPI schema for a newly created token including its secret value. */\nexport const tokenCreatedSchema = z\n .object({\n name: z.string(),\n token: z.string(),\n })\n .openapi(\"TokenCreated\");\n\n/** OpenAPI schema for a project member record. */\nexport const memberSchema = z\n .object({\n id: z.string(),\n projectId: z.string(),\n userId: z.string(),\n role: z.enum(PROJECT_ROLES),\n createdAt: z.string(),\n })\n .openapi(\"ProjectMember\");\n\n/** OpenAPI schema for updating a member's role. */\nexport const memberRoleSchema = z\n .object({ role: z.enum(PROJECT_ROLES) })\n .openapi(\"MemberRoleInput\");\n\n/** OpenAPI schema for adding a member to a project. */\nexport const memberSetSchema = z\n .object({\n userId: z.string().min(1),\n role: z.enum(PROJECT_ROLES),\n })\n .openapi(\"MemberSetInput\");\n\n/** OpenAPI schema for an identity-provider group mapping. */\nexport const groupMappingSchema = z\n .object({\n id: z.string(),\n projectId: z.string(),\n groupName: z.string(),\n role: z.enum(PROJECT_ROLES),\n createdAt: z.string(),\n })\n .openapi(\"GroupMapping\");\n\n/** OpenAPI schema for creating a group mapping. */\nexport const groupMappingCreateSchema = z\n .object({\n groupName: z.string().min(1),\n role: z.enum(PROJECT_ROLES),\n })\n .openapi(\"GroupMappingCreateInput\");\n\n/** OpenAPI schema for a public webhook (secret omitted). */\nexport const webhookPublicSchema = z\n .object({\n id: z.string(),\n url: z.string(),\n events: z.array(z.string()),\n })\n .openapi(\"Webhook\");\n\n/** OpenAPI schema for creating a webhook. */\nexport const webhookCreateSchema = z\n .object({\n // oxlint-disable-next-line typescript/no-deprecated -- z.string().url() kept for zod v3 API compat\n url: z.string().url(),\n events: z.array(z.string().min(1)).optional(),\n })\n .openapi(\"WebhookCreateInput\");\n\n/** OpenAPI schema for a newly created webhook including its signing secret. */\nexport const webhookCreatedSchema = z\n .object({\n id: z.string(),\n url: z.string(),\n events: z.array(z.string()),\n secret: z.string(),\n })\n .openapi(\"WebhookCreated\");\n\n/** OpenAPI schema for a git status-check configuration. */\nexport const statusConfigSchema = z\n .object({\n id: z.string(),\n projectId: z.string(),\n provider: z.string(),\n config: z.record(z.string(), z.unknown()),\n hasToken: z.boolean(),\n createdAt: z.string(),\n updatedAt: z.string(),\n })\n .openapi(\"StatusConfig\");\n\n/** OpenAPI schema for creating a git status-check configuration. */\nexport const statusConfigCreateSchema = z\n .object({\n provider: z.string().min(1),\n config: z.record(z.string(), z.unknown()),\n token: z.string().min(1),\n })\n .openapi(\"StatusConfigCreateInput\");\n\n/** OpenAPI schema for a public notification channel (secret omitted). */\nexport const notificationChannelSchema = z\n .object({\n id: z.string(),\n projectId: z.string().nullable(),\n provider: z.string(),\n config: z.record(z.string(), z.unknown()),\n hasSecret: z.boolean(),\n events: z.array(z.string()),\n enabled: z.boolean(),\n createdAt: z.string(),\n updatedAt: z.string(),\n })\n .openapi(\"NotificationChannel\");\n\n/** OpenAPI schema for creating a notification channel. */\nexport const notificationChannelCreateSchema = z\n .object({\n provider: z.string().min(1),\n config: z.record(z.string(), z.unknown()),\n secret: z.string().min(1).optional(),\n events: z.array(z.string().min(1)).optional(),\n enabled: z.boolean().optional(),\n })\n .openapi(\"NotificationChannelCreateInput\");\n\n/** OpenAPI schema for a per-user notification subscription. */\nexport const notificationSubscriptionSchema = z\n .object({\n projectId: z.string(),\n userId: z.string(),\n events: z.array(z.string()),\n via: z.array(z.string()),\n enabled: z.boolean(),\n })\n .openapi(\"NotificationSubscription\");\n\n/** OpenAPI schema for setting your own notification subscription. */\nexport const notificationSubscriptionPutSchema = z\n .object({\n events: z.array(z.string().min(1)).optional(),\n via: z.array(z.string().min(1)).optional(),\n enabled: z.boolean().optional(),\n })\n .openapi(\"NotificationSubscriptionPutInput\");\n\n/** OpenAPI schema for a generic `{ ok: true }` acknowledgement. */\nexport const okSchema = z.object({ ok: z.boolean() }).openapi(\"Ok\");\n\n/** Bulk approve result: ids skipped because their baseline changed after the diff. */\nexport const approveAllResultSchema = z\n .object({ ok: z.boolean(), skipped: z.array(z.string()) })\n .openapi(\"ApproveAllResult\");\n\n/** Result of re-diffing a build against the baselines that apply now. */\nexport const rediffResultSchema = z\n .object({\n ok: z.boolean(),\n rediffed: z.number().int(),\n statusChanged: z.number().int(),\n missingScreenshots: z.array(z.string()),\n })\n .openapi(\"RediffResult\");\n\n/** 409 returned when approving a snapshot whose baseline changed after the diff. */\nexport const baselineChangedSchema = z\n .object({\n code: z.literal(\"baseline_changed\"),\n message: z.string(),\n snapshotId: z.string(),\n baselineStatus: z.enum([\"stale\", \"removed\"]),\n })\n .openapi(\"BaselineChanged\");\n\n/** OpenAPI schema for an error response message. */\nexport const errorSchema = z.object({ message: z.string() }).openapi(\"Error\");\n\n/** OpenAPI schema for the retention purge result. */\nexport const purgeSchema = z\n .object({\n removedBuilds: z.number(),\n removedBranches: z.number().optional(),\n removedBaselines: z.number().optional(),\n })\n .openapi(\"PurgeResult\");\n\n/** OpenAPI schema for the retention purge input. */\nexport const purgeInputSchema = z.object({ ttlDays: z.number().optional() }).openapi(\"PurgeInput\");\n\n/** Shared response spec for a 400 Bad Request. */\nexport const badRequest = {\n 400: { content: { \"application/json\": { schema: errorSchema } }, description: \"Bad request\" },\n} as const;\n\n/** Shared response spec for a 401 Unauthorized. */\nexport const unauthorized = {\n 401: { content: { \"application/json\": { schema: errorSchema } }, description: \"Unauthorized\" },\n} as const;\n\n/** Shared response spec for a 403 Forbidden. */\nexport const forbidden = {\n 403: { content: { \"application/json\": { schema: errorSchema } }, description: \"Forbidden\" },\n} as const;\n\n/** Shared response spec for a 404 Not Found. */\nexport const notFound = {\n 404: { content: { \"application/json\": { schema: errorSchema } }, description: \"Not found\" },\n} as const;\n"],"mappings":"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"}
1
+ {"version":3,"file":"schemas.mjs","names":[],"sources":["../../src/routers/schemas.ts"],"sourcesContent":["import { z } from \"@hono/zod-openapi\";\nimport { BROWSER_NAMES, TARGET_NAME_PATTERN } from \"@storyshelf/core/adapter/capture-runner\";\nimport { WebhookModel } from \"@storyshelf/core/models\";\nimport {\n BUILD_STATUSES,\n PROJECT_ROLES,\n REVIEW_VERDICTS,\n SNAPSHOT_STATUSES,\n} from \"@storyshelf/core/types\";\nimport { storybookUrlTtlOverrideError } from \"@storyshelf/core/utils\";\n\n/** A capture target: an engine (`chromium`) or a remote one, `<engine>@<name>` (ADR 0007). */\nconst captureTargetSchema = z\n .string()\n .regex(\n new RegExp(\n `^(?:${BROWSER_NAMES.join(\"|\")})(?:@${TARGET_NAME_PATTERN.source.slice(1, -1)})?$`,\n \"u\",\n ),\n \"Expected an engine (chromium, firefox, webkit, chrome) or <engine>@<name>\",\n );\n\nconst reviewApprovalsSchema = z.number().int().min(1).max(20);\n\n/** Seconds a signed Storybook URL stays valid (ADR 0007, decision 5). */\nconst storybookUrlTtlSchema = z\n .number()\n .int()\n .superRefine((seconds, ctx) => {\n const message = storybookUrlTtlOverrideError(seconds);\n if (message !== undefined) {\n ctx.addIssue({ code: \"custom\", message });\n }\n });\n\nconst storybookMetaSchema = z.record(z.string(), z.unknown()).nullable().optional();\n\n/** OpenAPI schema for a project record. */\nexport const projectSchema = z\n .object({\n id: z.string(),\n name: z.string(),\n slug: z.string(),\n gitRepository: z.string().nullable(),\n gitDefaultBranch: z.string(),\n pixelThreshold: z.number(),\n maxDiffRatio: z.number(),\n publicBranchRegex: z.string().nullable(),\n storybookMeta: z.string().nullable().optional(),\n executePlay: z.boolean(),\n playTimeoutMs: z.number(),\n /** Axe accessibility checks run during capture (default on; results never block a build). */\n runA11y: z.boolean().optional(),\n /** Storybook 10 `.test()` entries run as interaction tests during capture (default off). */\n runTests: z.boolean().optional(),\n // Stored rows predate enum validation, so the response stays a plain string.\n browser: z.string().optional(),\n /** JSON array of capture targets, primary first, primary first; null = just `browser`. */\n browsers: z.string().nullable().optional(),\n /** JSON array of mode names to capture; null = every declared mode. */\n modesAllowlist: z.string().nullable().optional(),\n /** AI profile gate: null/absent = AI off for this project. */\n aiProfile: z.string().nullable().optional(),\n /** Review is on for this project (ADR 0013, decision 1). */\n reviewEnabled: z.boolean().optional(),\n /** Approvals a build needs when `testing` is off. */\n reviewApprovals: z.number().optional(),\n /** Seconds the signed Storybook URLs of a render stay valid; null derives it from the stories. */\n storybookUrlTtlSeconds: z.number().nullable().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n })\n .openapi(\"Project\");\n\n/** OpenAPI schema for creating a project. */\nexport const projectCreateSchema = z\n .object({\n name: z.string().min(1),\n gitRepository: z.string().optional(),\n gitDefaultBranch: z.string().optional(),\n storybookMeta: storybookMetaSchema,\n executePlay: z.boolean().optional(),\n playTimeoutMs: z.number().int().min(1000).max(30_000).optional(),\n /** Axe accessibility checks during capture; on when omitted. */\n runA11y: z.boolean().optional(),\n /** Run Storybook 10 `.test()` entries as interaction tests during capture; off when omitted. */\n runTests: z.boolean().optional(),\n reviewEnabled: z.boolean().optional(),\n reviewApprovals: reviewApprovalsSchema.optional(),\n })\n .openapi(\"ProjectCreateInput\");\n\n/** OpenAPI schema for patching a project. */\nexport const projectUpdateSchema = z\n .object({\n name: z.string().optional(),\n gitRepository: z.string().optional(),\n gitDefaultBranch: z.string().optional(),\n pixelThreshold: z.number().optional(),\n maxDiffRatio: z.number().optional(),\n publicBranchRegex: z.string().nullable().optional(),\n storybookMeta: storybookMetaSchema,\n executePlay: z.boolean().optional(),\n playTimeoutMs: z.number().int().min(1000).max(30_000).optional(),\n /** Turn axe accessibility checks during capture on or off (admins). */\n runA11y: z.boolean().optional(),\n /** Turn the Storybook 10 `.test()` runs on or off (admins). */\n runTests: z.boolean().optional(),\n /** Single capture target; clears `browsers`. */\n browser: captureTargetSchema.optional(),\n /** Capture targets, primary first (max 3); null returns to single `browser`. */\n browsers: z.array(captureTargetSchema).min(1).max(3).nullable().optional(),\n /** Mode names to capture; null runs every declared mode. */\n modesAllowlist: z.array(z.string().min(1)).max(50).nullable().optional(),\n /** Site admins only: a configured AI profile name, or null to turn AI off. */\n aiProfile: z.string().min(1).nullable().optional(),\n /** Turn review (comments and build-level verdicts) on or off for the project. */\n reviewEnabled: z.boolean().optional(),\n /** Approvals a build needs before it is accepted when `testing` is off. */\n reviewApprovals: reviewApprovalsSchema.optional(),\n /** Seconds (at least one minimum slice plus grace, 1050, to 86400) the signed Storybook URLs of a render stay valid; null derives it from the stories. */\n storybookUrlTtlSeconds: storybookUrlTtlSchema.nullable().optional(),\n })\n .openapi(\"ProjectUpdateInput\");\n\n/** OpenAPI schema for a build record. */\nexport const buildSchema = z\n .object({\n id: z.string(),\n projectId: z.string(),\n gitSha: z.string(),\n gitBranch: z.string(),\n isDefault: z.boolean(),\n authorEmail: z.string().nullable(),\n authorName: z.string().nullable(),\n message: z.string().nullable(),\n public: z.boolean(),\n status: z.enum(BUILD_STATUSES),\n snapshotCount: z.number(),\n changedCount: z.number(),\n approvedCount: z.number(),\n rejectedCount: z.number(),\n inheritedCount: z.number(),\n affectedOnly: z.boolean(),\n baselineSha: z.string().nullable(),\n changedFiles: z.string().nullable(),\n affectedImportPaths: z.string().nullable(),\n /** JSON array of the build's Storybook `.test()` results (id, title, name, status, error); null when none ran. */\n testResults: z.string().nullable().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n })\n .openapi(\"Build\");\n\n/** OpenAPI schema for a snapshot record. */\nexport const snapshotSchema = z\n .object({\n id: z.string(),\n projectId: z.string(),\n buildId: z.string(),\n storyId: z.string(),\n storyName: z.string(),\n storyTitle: z.string(),\n storyImportPath: z.string().nullable(),\n viewportName: z.string(),\n /** Globals JSON the capture's mode applied; null for plain viewports. */\n mode: z.string().nullable().optional(),\n viewportWidth: z.number(),\n viewportHeight: z.number(),\n screenshotPath: z.string(),\n diffPath: z.string().nullable(),\n diffPixels: z.number().nullable(),\n diffRatio: z.number().nullable(),\n diffPassed: z.boolean().nullable(),\n status: z.enum(SNAPSHOT_STATUSES),\n reviewedBy: z.string().nullable(),\n reviewedAt: z.string().nullable(),\n inherited: z.boolean(),\n /** JSON array of the axe violations found on this capture (non-blocking); null when none. */\n a11yViolations: z.string().nullable().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n })\n .openapi(\"Snapshot\");\n\n/** OpenAPI schema for a capture attempt (one run of a build's capture). */\nexport const attemptSchema = z\n .object({\n id: z.string(),\n projectId: z.string(),\n buildId: z.string(),\n attemptNo: z.number(),\n status: z.enum([\"queued\", \"running\", \"completed\", \"failed\", \"cancelled\"]),\n error: z.string().nullable(),\n reqId: z.string().nullable(),\n storyCount: z.number(),\n failedCount: z.number(),\n queuedAt: z.string(),\n startedAt: z.string().nullable(),\n finishedAt: z.string().nullable(),\n createdAt: z.string(),\n updatedAt: z.string(),\n })\n .openapi(\"CaptureAttempt\");\n\n/** OpenAPI schema for a single capture log line within an attempt. */\nexport const attemptLogSchema = z\n .object({\n id: z.string(),\n projectId: z.string(),\n buildId: z.string(),\n attemptId: z.string(),\n seq: z.number(),\n level: z.string(),\n message: z.string(),\n fields: z.string().nullable(),\n createdAt: z.string(),\n })\n .openapi(\"CaptureLog\");\n\n/** OpenAPI schema for a build comment. */\nexport const commentSchema = z\n .object({\n id: z.string(),\n projectId: z.string(),\n buildId: z.string(),\n snapshotId: z.string().nullable(),\n /** Storybook story id of a story-anchored comment. */\n storyId: z.string().nullable().optional(),\n userId: z.string().nullable(),\n body: z.string(),\n parentId: z.string().nullable(),\n resolved: z.boolean(),\n createdAt: z.string(),\n updatedAt: z.string(),\n })\n .openapi(\"Comment\");\n\n/** OpenAPI schema for creating a build comment. */\nexport const commentCreateSchema = z\n .object({\n body: z.string().min(1),\n /** Anchor to a snapshot; not together with `storyId`. */\n snapshotId: z.string().optional(),\n /** Anchor to a story of the build; not together with `snapshotId`. */\n storyId: z.string().min(1).optional(),\n parentId: z.string().optional(),\n })\n .openapi(\"CommentCreateInput\");\n\n/** OpenAPI schema for a build-level review verdict. */\nexport const buildReviewSchema = z\n .object({\n id: z.string(),\n buildId: z.string(),\n userId: z.string().nullable(),\n verdict: z.enum(REVIEW_VERDICTS),\n body: z.string().nullable(),\n createdAt: z.string(),\n })\n .openapi(\"BuildReview\");\n\n/** OpenAPI schema for giving a build a verdict. */\nexport const buildReviewCreateSchema = z\n .object({\n verdict: z.enum(REVIEW_VERDICTS),\n body: z.string().max(4000).optional(),\n })\n .openapi(\"BuildReviewInput\");\n\n/** OpenAPI schema for a build's review state: the verdicts and what they make of the build. */\nexport const buildReviewStateSchema = z\n .object({\n /** Build status now. */\n status: z.enum(BUILD_STATUSES),\n /** Approvals the project requires. */\n approvalsRequired: z.number(),\n /** Approvals among the reviewers' latest verdicts. */\n approvals: z.number(),\n /** Every reviewer's latest verdict. */\n latest: buildReviewSchema.array(),\n /** Every verdict given, oldest first. */\n history: buildReviewSchema.array(),\n })\n .openapi(\"BuildReviewState\");\n\n/** OpenAPI schema for a project label type. */\nexport const labelTypeSchema = z\n .object({\n id: z.string(),\n projectId: z.string(),\n key: z.string(),\n name: z.string(),\n linkTemplate: z.string().nullable(),\n color: z.string().nullable(),\n createdAt: z.string(),\n })\n .openapi(\"LabelType\");\n\n/** OpenAPI schema for creating a label type. */\nexport const labelTypeCreateSchema = z\n .object({\n key: z.string().min(1),\n name: z.string().min(1),\n linkTemplate: z.string().optional(),\n color: z.string().optional(),\n })\n .openapi(\"LabelTypeCreateInput\");\n\n/** OpenAPI schema for patching a label type. */\nexport const labelTypeUpdateSchema = z\n .object({\n name: z.string().min(1).optional(),\n linkTemplate: z.string().nullable().optional(),\n color: z.string().nullable().optional(),\n })\n .openapi(\"LabelTypeUpdateInput\");\n\n/** OpenAPI schema for a public API token (hash omitted). */\nexport const tokenPublicSchema = z\n .object({\n id: z.string(),\n projectId: z.string(),\n name: z.string(),\n lastUsedAt: z.string().nullable(),\n createdAt: z.string(),\n })\n .openapi(\"Token\");\n\n/** OpenAPI schema for creating an API token. */\nexport const tokenCreateSchema = z.object({ name: z.string().min(1) }).openapi(\"TokenCreateInput\");\n\n/** OpenAPI schema for a newly created token including its secret value. */\nexport const tokenCreatedSchema = z\n .object({\n name: z.string(),\n token: z.string(),\n })\n .openapi(\"TokenCreated\");\n\n/** OpenAPI schema for a project member record. */\nexport const memberSchema = z\n .object({\n id: z.string(),\n projectId: z.string(),\n userId: z.string(),\n role: z.enum(PROJECT_ROLES),\n createdAt: z.string(),\n })\n .openapi(\"ProjectMember\");\n\n/** OpenAPI schema for updating a member's role. */\nexport const memberRoleSchema = z\n .object({ role: z.enum(PROJECT_ROLES) })\n .openapi(\"MemberRoleInput\");\n\n/** OpenAPI schema for adding a member to a project. */\nexport const memberSetSchema = z\n .object({\n userId: z.string().min(1),\n role: z.enum(PROJECT_ROLES),\n })\n .openapi(\"MemberSetInput\");\n\n/** OpenAPI schema for an identity-provider group mapping. */\nexport const groupMappingSchema = z\n .object({\n id: z.string(),\n projectId: z.string(),\n groupName: z.string(),\n role: z.enum(PROJECT_ROLES),\n createdAt: z.string(),\n })\n .openapi(\"GroupMapping\");\n\n/** OpenAPI schema for creating a group mapping. */\nexport const groupMappingCreateSchema = z\n .object({\n groupName: z.string().min(1),\n role: z.enum(PROJECT_ROLES),\n })\n .openapi(\"GroupMappingCreateInput\");\n\n/** OpenAPI schema for a public webhook (secret omitted). */\nexport const webhookPublicSchema = z\n .object({\n id: z.string(),\n url: z.string(),\n events: z.array(z.string()),\n })\n .openapi(\"Webhook\");\n\n// oxlint-disable-next-line typescript/no-deprecated -- z.string().url() kept for zod v3 API compat\nconst webhookUrlBase = z.string().url();\n\n/** OpenAPI schema for creating a webhook. */\nexport const webhookCreateSchema = z\n .object({\n url: webhookUrlBase.refine((url) => WebhookModel.urlError(url) === null, {\n message: \"URL must use http or https\",\n }),\n events: z.array(z.string().min(1)).optional(),\n })\n .openapi(\"WebhookCreateInput\");\n\n/** OpenAPI schema for a newly created webhook including its signing secret. */\nexport const webhookCreatedSchema = z\n .object({\n id: z.string(),\n url: z.string(),\n events: z.array(z.string()),\n secret: z.string(),\n })\n .openapi(\"WebhookCreated\");\n\n/** OpenAPI schema for a public notification channel (secret omitted). */\nexport const notificationChannelSchema = z\n .object({\n id: z.string(),\n projectId: z.string().nullable(),\n provider: z.string(),\n config: z.record(z.string(), z.unknown()),\n hasSecret: z.boolean(),\n events: z.array(z.string()),\n enabled: z.boolean(),\n lastError: z.string().nullable(),\n lastErrorAt: z.string().nullable(),\n createdAt: z.string(),\n updatedAt: z.string(),\n })\n .openapi(\"NotificationChannel\");\n\n/** OpenAPI schema for creating a notification channel. */\nexport const notificationChannelCreateSchema = z\n .object({\n provider: z.string().min(1),\n config: z.record(z.string(), z.unknown()),\n secret: z.string().min(1).optional(),\n events: z.array(z.string().min(1)).optional(),\n enabled: z.boolean().optional(),\n })\n .openapi(\"NotificationChannelCreateInput\");\n\n/** OpenAPI schema for a per-user notification subscription. */\nexport const notificationSubscriptionSchema = z\n .object({\n projectId: z.string(),\n userId: z.string(),\n events: z.array(z.string()),\n via: z.array(z.string()),\n enabled: z.boolean(),\n })\n .openapi(\"NotificationSubscription\");\n\n/** OpenAPI schema for setting your own notification subscription. */\nexport const notificationSubscriptionPutSchema = z\n .object({\n events: z.array(z.string().min(1)).optional(),\n via: z.array(z.string().min(1)).optional(),\n enabled: z.boolean().optional(),\n })\n .openapi(\"NotificationSubscriptionPutInput\");\n\n/** OpenAPI schema for a generic `{ ok: true }` acknowledgement. */\nexport const okSchema = z.object({ ok: z.boolean() }).openapi(\"Ok\");\n\n/** Bulk approve result: ids skipped because their baseline changed after the diff. */\nexport const approveAllResultSchema = z\n .object({ ok: z.boolean(), skipped: z.array(z.string()) })\n .openapi(\"ApproveAllResult\");\n\n/** Group decision result: the snapshots one story/mode decision covered. */\nexport const groupDecisionResultSchema = z\n .object({ ok: z.boolean(), snapshotIds: z.array(z.string()) })\n .openapi(\"GroupDecisionResult\");\n\n/** Result of re-diffing a build against the baselines that apply now. */\nexport const rediffResultSchema = z\n .object({\n ok: z.boolean(),\n rediffed: z.number().int(),\n statusChanged: z.number().int(),\n missingScreenshots: z.array(z.string()),\n })\n .openapi(\"RediffResult\");\n\n/** 409 returned when approving a snapshot whose baseline changed after the diff. */\nexport const baselineChangedSchema = z\n .object({\n code: z.literal(\"baseline_changed\"),\n message: z.string(),\n snapshotId: z.string(),\n baselineStatus: z.enum([\"stale\", \"removed\"]),\n })\n .openapi(\"BaselineChanged\");\n\n/** OpenAPI schema for an error response message. */\nexport const errorSchema = z.object({ message: z.string() }).openapi(\"Error\");\n\n/** OpenAPI schema for the retention purge result. */\nexport const purgeSchema = z\n .object({\n removedBuilds: z.number(),\n removedBranches: z.number().optional(),\n removedBaselines: z.number().optional(),\n })\n .openapi(\"PurgeResult\");\n\n/** OpenAPI schema for the retention purge input. */\nexport const purgeInputSchema = z.object({ ttlDays: z.number().optional() }).openapi(\"PurgeInput\");\n\n/** Shared response spec for a 400 Bad Request. */\nexport const badRequest = {\n 400: { content: { \"application/json\": { schema: errorSchema } }, description: \"Bad request\" },\n} as const;\n\n/** Shared response spec for a 401 Unauthorized. */\nexport const unauthorized = {\n 401: { content: { \"application/json\": { schema: errorSchema } }, description: \"Unauthorized\" },\n} as const;\n\n/** Shared response spec for a 403 Forbidden. */\nexport const forbidden = {\n 403: { content: { \"application/json\": { schema: errorSchema } }, description: \"Forbidden\" },\n} as const;\n\n/** Shared response spec for a 404 Not Found. */\nexport const notFound = {\n 404: { content: { \"application/json\": { schema: errorSchema } }, description: \"Not found\" },\n} as const;\n\n/** OpenAPI schema for an insight (build triage or project health). */\nexport const insightSchema = z\n .object({\n id: z.string(),\n kind: z.enum([\"triage\", \"health\"]),\n buildId: z.string().nullable(),\n window: z.string().nullable(),\n status: z.enum([\"pending\", \"running\", \"done\", \"failed\"]),\n profile: z.string(),\n model: z.string(),\n promptVersion: z.string(),\n verdict: z.string().nullable(),\n summary: z.string().nullable(),\n output: z.unknown().nullable(),\n meta: z.unknown().nullable(),\n errorCode: z.string().nullable(),\n createdAt: z.string(),\n startedAt: z.string().nullable(),\n finishedAt: z.string().nullable(),\n })\n .openapi(\"Insight\");\n\n/** Request body to (re)generate a build triage. */\nexport const insightRequestSchema = z\n .object({\n task: z.literal(\"triage\").optional(),\n force: z.boolean().optional(),\n profile: z.string().min(1).optional(),\n })\n .openapi(\"InsightRequest\");\n\n/** Request body to (re)generate a project-health digest. */\nexport const healthRequestSchema = z\n .object({ window: z.string().optional(), force: z.boolean().optional() })\n .openapi(\"HealthInsightRequest\");\n"],"mappings":"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"}