@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
@@ -4,7 +4,7 @@ import.meta.url;
4
4
  import { baseCss } from "./styles/base.mjs";
5
5
  import { behaviorCss } from "./styles/behavior.mjs";
6
6
  import { tokenCss } from "./styles/tokens.mjs";
7
- //#region src/ui/styles.ts
7
+ // src/ui/styles.ts
8
8
  /** Build the global CSS stylesheet from the light and dark brand themes. */
9
9
  function baseStyle(light, dark) {
10
10
  return [
@@ -13,7 +13,6 @@ function baseStyle(light, dark) {
13
13
  behaviorCss()
14
14
  ].join("\n");
15
15
  }
16
- //#endregion
17
16
  export { baseStyle };
18
17
 
19
18
  //# sourceMappingURL=styles.mjs.map
@@ -4,7 +4,7 @@ import.meta.url;
4
4
  import { css } from "./css.mjs";
5
5
  import { Icon } from "./icons/icon.mjs";
6
6
  import { jsx, jsxs } from "hono/jsx/jsx-runtime";
7
- //#region src/ui/subnav.tsx
7
+ // src/ui/subnav.tsx
8
8
  const layout = css`
9
9
  /* subnav-layout */
10
10
  display: grid;
@@ -85,7 +85,6 @@ const SubNavLayout = ({ items, label, children }) => {
85
85
  }), /* @__PURE__ */ jsx("div", { children })]
86
86
  });
87
87
  };
88
- //#endregion
89
88
  export { SubNavLayout };
90
89
 
91
90
  //# sourceMappingURL=subnav.mjs.map
package/dist/ui/table.mjs CHANGED
@@ -3,7 +3,7 @@ import "node:url";
3
3
  import.meta.url;
4
4
  import { css } from "./css.mjs";
5
5
  import { jsx } from "hono/jsx/jsx-runtime";
6
- //#region src/ui/table.tsx
6
+ // src/ui/table.tsx
7
7
  const tableWrap = css`
8
8
  /* table */
9
9
  overflow: auto;
@@ -67,7 +67,6 @@ const Table = ({ dense = false, children }) => {
67
67
  children
68
68
  });
69
69
  };
70
- //#endregion
71
70
  export { Table };
72
71
 
73
72
  //# sourceMappingURL=table.mjs.map
package/dist/ui/theme.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
- //#region src/ui/theme.ts
4
+ // src/ui/theme.ts
5
5
  /** Default light brand theme (shadcn-like zinc, content-first). */
6
6
  const LIGHT_THEME = {
7
7
  accent: "#1d5fcf",
@@ -58,7 +58,6 @@ const DARK_THEME = {
58
58
  radiusSm: "0.375rem",
59
59
  shadow: "0 1px 2px rgba(0,0,0,.3)"
60
60
  };
61
- //#endregion
62
61
  export { DARK_THEME, LIGHT_THEME };
63
62
 
64
63
  //# sourceMappingURL=theme.mjs.map
@@ -3,7 +3,7 @@ import "node:url";
3
3
  import.meta.url;
4
4
  import { css } from "./css.mjs";
5
5
  import { jsx } from "hono/jsx/jsx-runtime";
6
- //#region src/ui/thumbnail.tsx
6
+ // src/ui/thumbnail.tsx
7
7
  const thumbFrame = css`
8
8
  /* thumbnail */
9
9
  position: relative;
@@ -45,7 +45,6 @@ const Thumbnail = ({ src, alt, placeholder = "No preview" }) => {
45
45
  })
46
46
  });
47
47
  };
48
- //#endregion
49
48
  export { Thumbnail };
50
49
 
51
50
  //# sourceMappingURL=thumbnail.mjs.map
package/dist/ui/time.mjs CHANGED
@@ -2,7 +2,7 @@ import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
4
  import { jsx } from "hono/jsx/jsx-runtime";
5
- //#region src/ui/time.tsx
5
+ // src/ui/time.tsx
6
6
  const MINUTE = 60;
7
7
  const HOUR = 3600;
8
8
  const DAY = 86400;
@@ -44,7 +44,6 @@ const RelativeTime = ({ value }) => {
44
44
  children: formatRelative(value)
45
45
  });
46
46
  };
47
- //#endregion
48
47
  export { RelativeTime, formatRelative };
49
48
 
50
49
  //# sourceMappingURL=time.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storyshelf/app",
3
- "version": "0.6.2",
3
+ "version": "0.8.0",
4
4
  "description": "StoryShelf app: Hono app, API routes, and server-rendered UI over @storyshelf/core.",
5
5
  "keywords": [
6
6
  "chromatic-alternative",
@@ -27,9 +27,6 @@
27
27
  "dist"
28
28
  ],
29
29
  "type": "module",
30
- "engines": {
31
- "node": ">=24"
32
- },
33
30
  "sideEffects": false,
34
31
  "types": "./dist/index.d.mts",
35
32
  "exports": {
@@ -55,33 +52,38 @@
55
52
  "prepublishOnly": "nub run build",
56
53
  "test": "vitest run",
57
54
  "test:coverage": "vitest run --coverage",
58
- "test:watch": "vitest"
55
+ "test:watch": "vitest",
56
+ "test:flake": "vitest run --repeats=10 --maxWorkers=1 --no-file-parallelism src/jobs.integration.test.ts src/capture-status-fanout.test.ts src/routers/design.integration.test.ts"
59
57
  },
60
58
  "dependencies": {
61
59
  "@hono/swagger-ui": "^0.6.1",
62
60
  "@hono/zod-openapi": "^1.1.5",
63
- "@storyshelf/core": "0.6.2",
64
- "@storyshelf/observability": "0.6.2",
61
+ "@storyshelf/core": "0.8.0",
62
+ "@storyshelf/observability": "0.8.0",
65
63
  "hono": "^4.11.0",
66
- "zod": "^4.2.0"
64
+ "zod": "^4.6.7"
67
65
  },
68
66
  "devDependencies": {
69
67
  "@opentelemetry/api": "^1.9.0",
70
68
  "@opentelemetry/context-async-hooks": "^2.11.0",
71
69
  "@opentelemetry/core": "^2.11.0",
72
70
  "@opentelemetry/sdk-trace-base": "^2.11.0",
73
- "@storyshelf/auth": "0.6.2",
74
- "@storyshelf/db-sqlite": "0.6.2",
71
+ "@storyshelf/auth": "0.8.0",
72
+ "@storyshelf/db-sqlite": "0.8.0",
73
+ "@storyshelf/design-figma": "0.8.0",
75
74
  "@types/node": "^26.0.0",
76
75
  "@vitest/coverage-v8": "^4.0.0",
77
- "adm-zip": "0.6.0",
76
+ "adm-zip": "0.6.1",
78
77
  "oxfmt": "^0.65.0",
79
78
  "oxlint": "^1.80.0",
80
79
  "oxlint-tsgolint": "^7.0.2001",
81
80
  "pino": "^10.3.1",
82
81
  "tsdown": "^0.22.14",
83
82
  "typescript": "^7.0.2",
84
- "vitest": "^5.0.0"
83
+ "vitest": "^5.0.5"
84
+ },
85
+ "engines": {
86
+ "node": ">=24"
85
87
  },
86
88
  "jsr": {
87
89
  "runtimeCompat": {
@@ -1,23 +0,0 @@
1
- import "node:path";
2
- import "node:url";
3
- import.meta.url;
4
- import { existsSync } from "node:fs";
5
- import { fileURLToPath } from "node:url";
6
- //#region src/asset-paths.ts
7
- /**
8
- * Locate a vendored file under `assets/` for the three layouts the app runs in:
9
- * - from source / the published library build, `assets/` sits next to the module;
10
- * - in the bundled Fly server (`dist/server.mjs`) it sits one level up
11
- * (`/app/assets`, copied by the Dockerfile).
12
- * Throws with every path tried, since a missing file is a packaging bug.
13
- */
14
- function findAsset(name, from, exists = existsSync) {
15
- const candidates = [`assets/${name}`, `../assets/${name}`].map((relative) => fileURLToPath(new URL(relative, from)));
16
- const found = candidates.find((path) => exists(path));
17
- if (!found) throw new Error(`Vendored asset "${name}" not found. Looked in: ${candidates.join(", ")}`);
18
- return found;
19
- }
20
- //#endregion
21
- export { findAsset };
22
-
23
- //# sourceMappingURL=asset-paths.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"asset-paths.mjs","names":[],"sources":["../src/asset-paths.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\n\n/**\n * Locate a vendored file under `assets/` for the three layouts the app runs in:\n * - from source / the published library build, `assets/` sits next to the module;\n * - in the bundled Fly server (`dist/server.mjs`) it sits one level up\n * (`/app/assets`, copied by the Dockerfile).\n * Throws with every path tried, since a missing file is a packaging bug.\n */\nexport function findAsset(\n name: string,\n from: string | URL,\n exists: (path: string) => boolean = existsSync,\n): string {\n const candidates = [`assets/${name}`, `../assets/${name}`].map((relative) =>\n fileURLToPath(new URL(relative, from)),\n );\n const found = candidates.find((path) => exists(path));\n if (!found) {\n throw new Error(`Vendored asset \"${name}\" not found. Looked in: ${candidates.join(\", \")}`);\n }\n return found;\n}\n"],"mappings":";;;;;;;;;;;;;AAUA,SAAgB,UACd,MACA,MACA,SAAoC,YAC5B;CACR,MAAM,aAAa,CAAC,UAAU,QAAQ,aAAa,MAAM,CAAC,CAAC,KAAK,aAC9D,cAAc,IAAI,IAAI,UAAU,IAAI,CAAC,CACvC;CACA,MAAM,QAAQ,WAAW,MAAM,SAAS,OAAO,IAAI,CAAC;CACpD,IAAI,CAAC,OACH,MAAM,IAAI,MAAM,mBAAmB,KAAK,0BAA0B,WAAW,KAAK,IAAI,GAAG;CAE3F,OAAO;AACT"}
@@ -1 +0,0 @@
1
- <svg xmlns='http://www.w3.org/2000/svg' width='64' height='64' viewBox='0 0 64 64' role='img' aria-label='StoryShelf'><rect width='64' height='64' rx='14' fill='#1d5fcf'/><path d='M15 11 H49 A4 4 0 0 1 53 15 V15 A2 2 0 0 1 51 17 H13 A2 2 0 0 1 11 15 V15 A4 4 0 0 1 15 11 Z' fill='#ffffff'/><path d='M13 29 H51 A2 2 0 0 1 53 31 V33 A2 2 0 0 1 51 35 H13 A2 2 0 0 1 11 33 V31 A2 2 0 0 1 13 29 Z' fill='#ffffff'/><path d='M13 47 H51 A2 2 0 0 1 53 49 V49 A4 4 0 0 1 49 53 H15 A4 4 0 0 1 11 49 V49 A2 2 0 0 1 13 47 Z' fill='#ffffff'/><path d='M16 19 H16 A2 2 0 0 1 18 21 V27 A2 2 0 0 1 16 29 H16 A2 2 0 0 1 14 27 V21 A2 2 0 0 1 16 19 Z' fill='#ffffff'/><path d='M22 21 H22 A2 2 0 0 1 24 23 V27 A2 2 0 0 1 22 29 H22 A2 2 0 0 1 20 27 V23 A2 2 0 0 1 22 21 Z' fill='#ffffff'/><path d='M28 23 H28 A2 2 0 0 1 30 25 V27 A2 2 0 0 1 28 29 H28 A2 2 0 0 1 26 27 V25 A2 2 0 0 1 28 23 Z' fill='#ffffff'/><path d='M48 37 H48 A2 2 0 0 1 50 39 V45 A2 2 0 0 1 48 47 H48 A2 2 0 0 1 46 45 V39 A2 2 0 0 1 48 37 Z' fill='#ffffff'/><path d='M42 39 H42 A2 2 0 0 1 44 41 V45 A2 2 0 0 1 42 47 H42 A2 2 0 0 1 40 45 V41 A2 2 0 0 1 42 39 Z' fill='#ffffff'/><path d='M36 41 H36 A2 2 0 0 1 38 43 V45 A2 2 0 0 1 36 47 H36 A2 2 0 0 1 34 45 V43 A2 2 0 0 1 36 41 Z' fill='#ffffff'/></svg>
@@ -1,137 +0,0 @@
1
- import "node:path";
2
- import "node:url";
3
- import.meta.url;
4
- import { Button } from "../ui/buttons.mjs";
5
- import { Alert, Badge, Meta } from "../ui/feedback.mjs";
6
- import { Field, FormActions, SelectField, TextareaField } from "../ui/forms.mjs";
7
- import { Card, SectionTitle } from "../ui/layout.mjs";
8
- import { Table } from "../ui/table.mjs";
9
- import { csrfField } from "../ui/csrf-field.mjs";
10
- import { jsx, jsxs } from "hono/jsx/jsx-runtime";
11
- //#region src/pages/settings-status.tsx
12
- function providerOptions(providers) {
13
- return providers.map((provider) => ({
14
- value: provider.metadata.kind,
15
- label: provider.metadata.name
16
- }));
17
- }
18
- const StatusConfigRow = ({ config, provider, project, isAdmin }) => {
19
- const rendered = JSON.stringify(config.config);
20
- return /* @__PURE__ */ jsxs("tr", { children: [
21
- /* @__PURE__ */ jsx("td", { children: provider?.metadata.name ?? config.provider }),
22
- /* @__PURE__ */ jsx("td", {
23
- class: "truncate max-w-cell",
24
- title: rendered,
25
- children: /* @__PURE__ */ jsx("code", { children: rendered })
26
- }),
27
- /* @__PURE__ */ jsx("td", { children: config.hasToken ? /* @__PURE__ */ jsx(Badge, {
28
- tone: "success",
29
- children: "configured"
30
- }) : /* @__PURE__ */ jsx(Badge, {
31
- tone: "danger",
32
- children: "missing"
33
- }) }),
34
- /* @__PURE__ */ jsx("td", { children: new Date(config.createdAt).toLocaleDateString() }),
35
- /* @__PURE__ */ jsx("td", { children: isAdmin ? /* @__PURE__ */ jsxs("form", {
36
- method: "post",
37
- action: `/projects/${project.slug}/settings/status/${config.id}/delete`,
38
- "hx-post": `/projects/${project.slug}/settings/status/${config.id}/delete`,
39
- "hx-target": "body",
40
- "hx-confirm": "Remove this git status config?",
41
- children: [csrfField(), /* @__PURE__ */ jsx(Button, {
42
- variant: "ghost",
43
- type: "submit",
44
- children: "Delete"
45
- })]
46
- }) : null })
47
- ] }, config.id);
48
- };
49
- const StatusCreateCard = ({ project, providers, formState }) => {
50
- return /* @__PURE__ */ jsxs(Card, { children: [/* @__PURE__ */ jsx(SectionTitle, {
51
- level: 3,
52
- children: "Add git provider"
53
- }), /* @__PURE__ */ jsxs("form", {
54
- method: "post",
55
- action: `/projects/${project.slug}/settings/status`,
56
- "hx-post": `/projects/${project.slug}/settings/status`,
57
- "hx-target": "body",
58
- children: [
59
- csrfField(),
60
- /* @__PURE__ */ jsx(SelectField, {
61
- label: "Provider",
62
- name: "provider",
63
- options: providerOptions(providers),
64
- hint: "Integration that posts commit statuses for this project."
65
- }),
66
- /* @__PURE__ */ jsx(Field, {
67
- label: "Token",
68
- name: "token",
69
- type: "password",
70
- required: true,
71
- placeholder: "ghp_…",
72
- error: formState?.errors?.["token"],
73
- hint: "Scoped token for the provider (e.g. a GitHub PAT with repo:status)."
74
- }),
75
- /* @__PURE__ */ jsx(TextareaField, {
76
- label: "Config",
77
- name: "config",
78
- rows: 6,
79
- placeholder: "{\"owner\":\"my-org\",\"repo\":\"my-repo\"}",
80
- error: formState?.errors?.["config"],
81
- hint: "JSON configuration for the provider. See the provider documentation for its fields."
82
- }),
83
- /* @__PURE__ */ jsx(FormActions, { children: /* @__PURE__ */ jsx(Button, {
84
- variant: "primary",
85
- type: "submit",
86
- icon: "plus",
87
- children: "Add git provider"
88
- }) })
89
- ]
90
- })] });
91
- };
92
- function renderCreateSection(project, providers, formState) {
93
- if (providers.length === 0) return /* @__PURE__ */ jsx(Meta, { children: "No git providers registered on this server." });
94
- return /* @__PURE__ */ jsx(StatusCreateCard, {
95
- project,
96
- providers,
97
- formState
98
- });
99
- }
100
- /** Git status settings tab: configured providers plus the add-provider form. */
101
- function renderSettingsStatus(project, statusConfigs, providers, isAdmin, formState) {
102
- const byProvider = new Map(providers.map((provider) => [provider.metadata.kind, provider]));
103
- return /* @__PURE__ */ jsxs("div", {
104
- class: "grid max-w-form",
105
- children: [
106
- formState?.globalError ? /* @__PURE__ */ jsx(Alert, {
107
- tone: "danger",
108
- children: formState.globalError
109
- }) : null,
110
- /* @__PURE__ */ jsxs(Card, { children: [
111
- /* @__PURE__ */ jsx(SectionTitle, { children: "Git status" }),
112
- /* @__PURE__ */ jsx(Meta, { children: "Post commit statuses to a git provider so visual tests show up in your PR checks. Status is reported for each configured provider: pending while capturing, success on approval, failure on rejection or capture errors." }),
113
- /* @__PURE__ */ jsx(Table, { children: /* @__PURE__ */ jsxs("table", { children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
114
- /* @__PURE__ */ jsx("th", { children: "Provider" }),
115
- /* @__PURE__ */ jsx("th", { children: "Config" }),
116
- /* @__PURE__ */ jsx("th", { children: "Token" }),
117
- /* @__PURE__ */ jsx("th", { children: "Created" }),
118
- /* @__PURE__ */ jsx("th", { children: /* @__PURE__ */ jsx("span", {
119
- class: "visually-hidden",
120
- children: "Actions"
121
- }) })
122
- ] }) }), /* @__PURE__ */ jsx("tbody", { children: statusConfigs.map((config) => /* @__PURE__ */ jsx(StatusConfigRow, {
123
- config,
124
- provider: byProvider.get(config.provider),
125
- project,
126
- isAdmin
127
- }, config.id)) })] }) }),
128
- statusConfigs.length === 0 ? /* @__PURE__ */ jsx(Meta, { children: "No git providers configured for this project." }) : null
129
- ] }),
130
- isAdmin ? renderCreateSection(project, providers, formState) : null
131
- ]
132
- });
133
- }
134
- //#endregion
135
- export { renderSettingsStatus };
136
-
137
- //# sourceMappingURL=settings-status.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"settings-status.mjs","names":[],"sources":["../../src/pages/settings-status.tsx"],"sourcesContent":["import type { GitHostProvider } from \"@storyshelf/core/adapter/git-host\";\nimport type { Project } from \"@storyshelf/core/schema\";\nimport type { FC } from \"hono/jsx\";\nimport {\n Alert,\n Badge,\n Button,\n Card,\n Field,\n FormActions,\n Meta,\n SectionTitle,\n SelectField,\n Table,\n TextareaField,\n} from \"../ui/components.tsx\";\nimport { csrfField } from \"../ui/csrf-field.tsx\";\n\n/** Git status configuration row as rendered in the status settings tab. */\nexport interface SettingsStatusConfig {\n id: string;\n provider: string;\n config: Record<string, unknown>;\n hasToken: boolean;\n createdAt: string;\n updatedAt: string;\n}\n\n/** Form state for the git status settings tab. */\nexport interface StatusFormState {\n errors?: Record<string, string>;\n globalError?: string;\n}\n\n/* eslint-disable promise-function-async -- JSX components return HtmlEscapedString | Promise<HtmlEscapedString> */\n\nfunction providerOptions(providers: GitHostProvider[]): { value: string; label: string }[] {\n return providers.map((provider) => ({\n value: provider.metadata.kind,\n label: provider.metadata.name,\n }));\n}\n\nconst StatusConfigRow: FC<{\n config: SettingsStatusConfig;\n provider: GitHostProvider | undefined;\n project: Project;\n isAdmin: boolean;\n}> = ({ config, provider, project, isAdmin }) => {\n const rendered = JSON.stringify(config.config);\n return (\n <tr key={config.id}>\n <td>{provider?.metadata.name ?? config.provider}</td>\n <td class=\"truncate max-w-cell\" title={rendered}>\n <code>{rendered}</code>\n </td>\n <td>\n {config.hasToken ? (\n <Badge tone=\"success\">configured</Badge>\n ) : (\n <Badge tone=\"danger\">missing</Badge>\n )}\n </td>\n <td>{new Date(config.createdAt).toLocaleDateString()}</td>\n <td>\n {isAdmin ? (\n <form\n method=\"post\"\n action={`/projects/${project.slug}/settings/status/${config.id}/delete`}\n hx-post={`/projects/${project.slug}/settings/status/${config.id}/delete`}\n hx-target=\"body\"\n hx-confirm=\"Remove this git status config?\"\n >\n {csrfField()}\n <Button variant=\"ghost\" type=\"submit\">\n Delete\n </Button>\n </form>\n ) : null}\n </td>\n </tr>\n );\n};\n\nconst StatusCreateCard: FC<{\n project: Project;\n providers: GitHostProvider[];\n formState?: StatusFormState;\n}> = ({ project, providers, formState }) => {\n return (\n <Card>\n <SectionTitle level={3}>Add git provider</SectionTitle>\n <form\n method=\"post\"\n action={`/projects/${project.slug}/settings/status`}\n hx-post={`/projects/${project.slug}/settings/status`}\n hx-target=\"body\"\n >\n {csrfField()}\n <SelectField\n label=\"Provider\"\n name=\"provider\"\n options={providerOptions(providers)}\n hint=\"Integration that posts commit statuses for this project.\"\n />\n <Field\n label=\"Token\"\n name=\"token\"\n type=\"password\"\n required\n placeholder=\"ghp_…\"\n error={formState?.errors?.[\"token\"]}\n hint=\"Scoped token for the provider (e.g. a GitHub PAT with repo:status).\"\n />\n <TextareaField\n label=\"Config\"\n name=\"config\"\n rows={6}\n placeholder='{\"owner\":\"my-org\",\"repo\":\"my-repo\"}'\n error={formState?.errors?.[\"config\"]}\n hint=\"JSON configuration for the provider. See the provider documentation for its fields.\"\n />\n <FormActions>\n <Button variant=\"primary\" type=\"submit\" icon=\"plus\">\n Add git provider\n </Button>\n </FormActions>\n </form>\n </Card>\n );\n};\n\nfunction renderCreateSection(\n project: Project,\n providers: GitHostProvider[],\n formState?: StatusFormState,\n): unknown {\n if (providers.length === 0) {\n return <Meta>No git providers registered on this server.</Meta>;\n }\n return <StatusCreateCard project={project} providers={providers} formState={formState} />;\n}\n\n/** Git status settings tab: configured providers plus the add-provider form. */\n// eslint-disable-next-line max-params -- matches sibling settings render functions\nexport function renderSettingsStatus(\n project: Project,\n statusConfigs: SettingsStatusConfig[],\n providers: GitHostProvider[],\n isAdmin: boolean,\n formState?: StatusFormState,\n): unknown {\n const byProvider = new Map(providers.map((provider) => [provider.metadata.kind, provider]));\n return (\n <div class=\"grid max-w-form\">\n {formState?.globalError ? <Alert tone=\"danger\">{formState.globalError}</Alert> : null}\n\n <Card>\n <SectionTitle>Git status</SectionTitle>\n <Meta>\n Post commit statuses to a git provider so visual tests show up in your PR checks. Status\n is reported for each configured provider: pending while capturing, success on approval,\n failure on rejection or capture errors.\n </Meta>\n <Table>\n <table>\n <thead>\n <tr>\n <th>Provider</th>\n <th>Config</th>\n <th>Token</th>\n <th>Created</th>\n <th>\n <span class=\"visually-hidden\">Actions</span>\n </th>\n </tr>\n </thead>\n <tbody>\n {statusConfigs.map((config) => (\n <StatusConfigRow\n key={config.id}\n config={config}\n provider={byProvider.get(config.provider)}\n project={project}\n isAdmin={isAdmin}\n />\n ))}\n </tbody>\n </table>\n </Table>\n {statusConfigs.length === 0 ? (\n <Meta>No git providers configured for this project.</Meta>\n ) : null}\n </Card>\n\n {isAdmin ? renderCreateSection(project, providers, formState) : null}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,77 +0,0 @@
1
- import "node:path";
2
- import "node:url";
3
- import.meta.url;
4
- import { credentialKeys } from "../credential-keys.mjs";
5
- import { getStore } from "../store.mjs";
6
- import { hxRedirect } from "./htmx.mjs";
7
- import { flash } from "./flash.mjs";
8
- import { asString, findProject, renderSettingsPage } from "./settings.handlers.mjs";
9
- import { StatusConfigModel } from "@storyshelf/core/models";
10
- //#region src/routers/settings-status.ts
11
- /** Merge-gate status-config settings (provider configs + tokens, delete). */
12
- function registerStatusSettings(app) {
13
- app.get("/projects/:slug/settings/status", async (c) => c.html(await renderSettingsPage(c, "status")));
14
- app.post("/projects/:slug/settings/status", handleCreateStatus);
15
- app.post("/projects/:slug/settings/status/:id/delete", handleDeleteStatus);
16
- }
17
- async function unknownProviderResponse(c) {
18
- return c.html(await renderSettingsPage(c, "status", { globalError: "Unknown git provider" }) ?? "", 400);
19
- }
20
- async function missingTokenResponse(c) {
21
- return c.html(await renderSettingsPage(c, "status", { errors: { token: "Token is required" } }) ?? "", 400);
22
- }
23
- async function readStatusFields(c) {
24
- const project = await findProject(c.req.param("slug") ?? "");
25
- const form = await c.req.formData();
26
- const provider = getStore().gitHosts.find((p) => p.metadata.kind === asString(form.get("provider")));
27
- if (!provider) return await unknownProviderResponse(c);
28
- const token = asString(form.get("token"));
29
- if (!token) return await missingTokenResponse(c);
30
- return {
31
- project,
32
- provider,
33
- token,
34
- configRaw: asString(form.get("config")) ?? "{}"
35
- };
36
- }
37
- async function handleCreateStatus(c) {
38
- const fields = await readStatusFields(c);
39
- if (fields instanceof Response) return fields;
40
- return await createStatusFromForm(c, fields.project, fields.provider, fields.token, fields.configRaw);
41
- }
42
- async function createStatusFromForm(c, project, provider, token, configRaw) {
43
- const config = parseJsonConfig(configRaw);
44
- if (config === void 0) return c.html(await renderSettingsPage(c, "status", { errors: { config: "Config must be valid JSON" } }) ?? "", 400);
45
- const parsed = provider.metadata.schema.safeParse(config);
46
- if (!parsed.success) return c.html(await renderSettingsPage(c, "status", { errors: { config: parsed.error.message } }) ?? "", 400);
47
- return await persistStatusConfig(c, project, provider, token, parsed.data);
48
- }
49
- async function persistStatusConfig(c, project, provider, token, config) {
50
- const { db, config: shelfConfig } = getStore();
51
- await new StatusConfigModel(db, void 0, credentialKeys(shelfConfig)).create(project.id, {
52
- provider: provider.metadata.kind,
53
- config,
54
- token
55
- });
56
- flash(c, "Git status config added");
57
- return hxRedirect(c, `/projects/${project.slug}/settings/status`);
58
- }
59
- /** Parse the provider config JSON, or undefined when invalid. */
60
- function parseJsonConfig(raw) {
61
- try {
62
- return JSON.parse(raw);
63
- } catch {
64
- return;
65
- }
66
- }
67
- async function handleDeleteStatus(c) {
68
- const project = await findProject(c.req.param("slug") ?? "");
69
- const { db, config: shelfConfig } = getStore();
70
- await new StatusConfigModel(db, void 0, credentialKeys(shelfConfig)).remove(project.id, c.req.param("id") ?? "");
71
- flash(c, "Git status config removed");
72
- return hxRedirect(c, `/projects/${project.slug}/settings/status`);
73
- }
74
- //#endregion
75
- export { registerStatusSettings };
76
-
77
- //# sourceMappingURL=settings-status.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"settings-status.mjs","names":[],"sources":["../../src/routers/settings-status.ts"],"sourcesContent":["import type { GitHostProvider } from \"@storyshelf/core/adapter/git-host\";\nimport { StatusConfigModel } from \"@storyshelf/core/models\";\nimport type { Project } from \"@storyshelf/core/schema\";\nimport type { Context } from \"hono\";\nimport type { ShelfRouter } from \"../app-types.ts\";\nimport { credentialKeys } from \"../credential-keys.ts\";\nimport { getStore } from \"../store.ts\";\nimport { flash } from \"./flash.ts\";\nimport { hxRedirect } from \"./htmx.ts\";\nimport { asString, findProject, renderSettingsPage } from \"./settings.handlers.ts\";\n/** Merge-gate status-config settings (provider configs + tokens, delete). */\nexport function registerStatusSettings(app: ShelfRouter): void {\n app.get(\"/projects/:slug/settings/status\", async (c) =>\n c.html(await renderSettingsPage(c, \"status\")),\n );\n app.post(\"/projects/:slug/settings/status\", handleCreateStatus);\n app.post(\"/projects/:slug/settings/status/:id/delete\", handleDeleteStatus);\n}\n\nasync function unknownProviderResponse(c: Context): Promise<Response> {\n return c.html(\n (await renderSettingsPage(c, \"status\", { globalError: \"Unknown git provider\" })) ?? \"\",\n 400,\n );\n}\n\nasync function missingTokenResponse(c: Context): Promise<Response> {\n return c.html(\n (await renderSettingsPage(c, \"status\", { errors: { token: \"Token is required\" } })) ?? \"\",\n 400,\n );\n}\n\ninterface StatusFields {\n project: Project;\n provider: GitHostProvider;\n token: string;\n configRaw: string;\n}\n\nasync function readStatusFields(c: Context): Promise<StatusFields | Response> {\n const project = await findProject(c.req.param(\"slug\") ?? \"\");\n const form = await c.req.formData();\n const provider = getStore().gitHosts.find(\n (p) => p.metadata.kind === asString(form.get(\"provider\")),\n );\n if (!provider) {\n return await unknownProviderResponse(c);\n }\n const token = asString(form.get(\"token\"));\n if (!token) {\n return await missingTokenResponse(c);\n }\n return { project, provider, token, configRaw: asString(form.get(\"config\")) ?? \"{}\" };\n}\n\nasync function handleCreateStatus(c: Context): Promise<Response> {\n const fields = await readStatusFields(c);\n if (fields instanceof Response) {\n return fields;\n }\n return await createStatusFromForm(\n c,\n fields.project,\n fields.provider,\n fields.token,\n fields.configRaw,\n );\n}\n\nasync function createStatusFromForm(\n c: Context,\n project: Project,\n provider: GitHostProvider,\n token: string,\n configRaw: string,\n): Promise<Response> {\n const config = parseJsonConfig(configRaw);\n if (config === undefined) {\n return c.html(\n (await renderSettingsPage(c, \"status\", {\n errors: { config: \"Config must be valid JSON\" },\n })) ?? \"\",\n 400,\n );\n }\n const parsed = provider.metadata.schema.safeParse(config);\n if (!parsed.success) {\n return c.html(\n (await renderSettingsPage(c, \"status\", { errors: { config: parsed.error.message } })) ?? \"\",\n 400,\n );\n }\n return await persistStatusConfig(c, project, provider, token, parsed.data);\n}\n\nasync function persistStatusConfig(\n c: Context,\n project: Project,\n provider: GitHostProvider,\n token: string,\n config: unknown,\n): Promise<Response> {\n const { db, config: shelfConfig } = getStore();\n await new StatusConfigModel(db, undefined, credentialKeys(shelfConfig)).create(project.id, {\n provider: provider.metadata.kind,\n config,\n token,\n });\n flash(c, \"Git status config added\");\n return hxRedirect(c, `/projects/${project.slug}/settings/status`);\n}\n\n/** Parse the provider config JSON, or undefined when invalid. */\nfunction parseJsonConfig(raw: string): unknown {\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return undefined;\n }\n}\n\nasync function handleDeleteStatus(c: Context): Promise<Response> {\n const project = await findProject(c.req.param(\"slug\") ?? \"\");\n const { db, config: shelfConfig } = getStore();\n await new StatusConfigModel(db, undefined, credentialKeys(shelfConfig)).remove(\n project.id,\n c.req.param(\"id\") ?? \"\",\n );\n flash(c, \"Git status config removed\");\n return hxRedirect(c, `/projects/${project.slug}/settings/status`);\n}\n"],"mappings":"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"}
@@ -1,108 +0,0 @@
1
- import "node:path";
2
- import "node:url";
3
- import.meta.url;
4
- import { credentialKeys } from "../credential-keys.mjs";
5
- import { getStore } from "../store.mjs";
6
- import { resolveAuthorizedProject } from "./helpers.mjs";
7
- import { notFound, statusConfigCreateSchema, statusConfigSchema, unauthorized } from "./schemas.mjs";
8
- import { createRoute, z } from "@hono/zod-openapi";
9
- import { StatusConfigModel } from "@storyshelf/core/models";
10
- //#region src/routers/status-configs.ts
11
- const ADMIN_ROLES = ["admin"];
12
- const listRoute = createRoute({
13
- method: "get",
14
- tags: ["Git status"],
15
- summary: "List status configs",
16
- path: "/api/v1/projects/{slug}/status-configs",
17
- request: { params: z.object({ slug: z.string() }) },
18
- responses: {
19
- 200: {
20
- content: { "application/json": { schema: statusConfigSchema.array() } },
21
- description: "List status configs"
22
- },
23
- ...notFound,
24
- ...unauthorized
25
- }
26
- });
27
- const createRouteDef = createRoute({
28
- method: "post",
29
- tags: ["Git status"],
30
- summary: "Create a status config",
31
- path: "/api/v1/projects/{slug}/status-configs",
32
- request: {
33
- params: z.object({ slug: z.string() }),
34
- body: { content: { "application/json": { schema: statusConfigCreateSchema } } }
35
- },
36
- responses: {
37
- 201: {
38
- content: { "application/json": { schema: statusConfigSchema } },
39
- description: "Created status config"
40
- },
41
- 400: {
42
- content: { "application/json": { schema: z.object({ message: z.string() }) } },
43
- description: "Bad request"
44
- },
45
- ...notFound
46
- }
47
- });
48
- const deleteRoute = createRoute({
49
- method: "delete",
50
- tags: ["Git status"],
51
- summary: "Delete a status config",
52
- path: "/api/v1/projects/{slug}/status-configs/{id}",
53
- request: { params: z.object({
54
- slug: z.string(),
55
- id: z.string()
56
- }) },
57
- responses: {
58
- 204: { description: "Deleted status config" },
59
- ...notFound
60
- }
61
- });
62
- function toPublic(row) {
63
- return {
64
- id: row.id,
65
- projectId: row.projectId,
66
- provider: row.provider,
67
- config: JSON.parse(row.config),
68
- hasToken: true,
69
- createdAt: row.createdAt,
70
- updatedAt: row.updatedAt
71
- };
72
- }
73
- /** Register the git status-config list, create, and delete endpoints. */
74
- function registerStatusConfigs(app) {
75
- app.openapi(listRoute, async (c) => {
76
- const { slug } = c.req.valid("param");
77
- const project = await resolveAuthorizedProject(c, slug, "admin");
78
- const rows = await new StatusConfigModel(getStore().db, void 0, credentialKeys(getStore().config)).list(project.id);
79
- return c.json(rows.map((row) => toPublic(row)));
80
- });
81
- app.openapi(createRouteDef, async (c) => {
82
- const { slug } = c.req.valid("param");
83
- const project = await resolveAuthorizedProject(c, slug, ...ADMIN_ROLES);
84
- const body = c.req.valid("json");
85
- const provider = getStore().gitHosts.find((p) => p.metadata.kind === body.provider);
86
- if (!provider) return c.json({ message: `Unknown provider: ${body.provider}` }, 400);
87
- const parsed = provider.metadata.schema.safeParse(body.config);
88
- if (!parsed.success) return c.json({ message: parsed.error.message }, 400);
89
- const row = await new StatusConfigModel(getStore().db, void 0, credentialKeys(getStore().config)).create(project.id, {
90
- provider: body.provider,
91
- config: parsed.data,
92
- token: body.token
93
- });
94
- return c.json(toPublic(row), 201);
95
- });
96
- app.openapi(deleteRoute, async (c) => {
97
- const { slug, id } = c.req.valid("param");
98
- const project = await resolveAuthorizedProject(c, slug, ...ADMIN_ROLES);
99
- const model = new StatusConfigModel(getStore().db, void 0, credentialKeys(getStore().config));
100
- if (!await model.get(project.id, id)) return c.json({ message: "Status config not found" }, 404);
101
- await model.remove(project.id, id);
102
- return c.body(null, 204);
103
- });
104
- }
105
- //#endregion
106
- export { registerStatusConfigs };
107
-
108
- //# sourceMappingURL=status-configs.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"status-configs.mjs","names":[],"sources":["../../src/routers/status-configs.ts"],"sourcesContent":["import { createRoute, z } from \"@hono/zod-openapi\";\nimport { StatusConfigModel } from \"@storyshelf/core/models\";\nimport type { ProjectStatusConfig } from \"@storyshelf/core/schema\";\nimport type { ShelfRouter } from \"../app-types.ts\";\nimport { credentialKeys } from \"../credential-keys.ts\";\nimport { getStore } from \"../store.ts\";\nimport { resolveAuthorizedProject } from \"./helpers.ts\";\nimport { notFound, statusConfigCreateSchema, statusConfigSchema, unauthorized } from \"./schemas.ts\";\nconst ADMIN_ROLES = [\"admin\"] as const;\n\nconst listRoute = createRoute({\n method: \"get\",\n tags: [\"Git status\"],\n summary: \"List status configs\",\n path: \"/api/v1/projects/{slug}/status-configs\",\n request: { params: z.object({ slug: z.string() }) },\n responses: {\n 200: {\n content: { \"application/json\": { schema: statusConfigSchema.array() } },\n description: \"List status configs\",\n },\n ...notFound,\n ...unauthorized,\n },\n});\n\nconst createRouteDef = createRoute({\n method: \"post\",\n tags: [\"Git status\"],\n summary: \"Create a status config\",\n path: \"/api/v1/projects/{slug}/status-configs\",\n request: {\n params: z.object({ slug: z.string() }),\n body: { content: { \"application/json\": { schema: statusConfigCreateSchema } } },\n },\n responses: {\n 201: {\n content: { \"application/json\": { schema: statusConfigSchema } },\n description: \"Created status config\",\n },\n 400: {\n content: { \"application/json\": { schema: z.object({ message: z.string() }) } },\n description: \"Bad request\",\n },\n ...notFound,\n },\n});\n\nconst deleteRoute = createRoute({\n method: \"delete\",\n tags: [\"Git status\"],\n summary: \"Delete a status config\",\n path: \"/api/v1/projects/{slug}/status-configs/{id}\",\n request: { params: z.object({ slug: z.string(), id: z.string() }) },\n responses: {\n 204: { description: \"Deleted status config\" },\n ...notFound,\n },\n});\n\nfunction toPublic(row: ProjectStatusConfig): {\n id: string;\n projectId: string;\n provider: string;\n config: Record<string, unknown>;\n hasToken: boolean;\n createdAt: string;\n updatedAt: string;\n} {\n return {\n id: row.id,\n projectId: row.projectId,\n provider: row.provider,\n config: JSON.parse(row.config) as Record<string, unknown>,\n hasToken: true,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\n/** Register the git status-config list, create, and delete endpoints. */\nexport function registerStatusConfigs(app: ShelfRouter): void {\n app.openapi(listRoute, async (c) => {\n const { slug } = c.req.valid(\"param\");\n const project = await resolveAuthorizedProject(c, slug, \"admin\");\n const model = new StatusConfigModel(\n getStore().db,\n undefined,\n credentialKeys(getStore().config),\n );\n const rows = await model.list(project.id);\n return c.json(rows.map((row) => toPublic(row)));\n });\n\n app.openapi(createRouteDef, async (c) => {\n const { slug } = c.req.valid(\"param\");\n const project = await resolveAuthorizedProject(c, slug, ...ADMIN_ROLES);\n const body = c.req.valid(\"json\");\n const providers = getStore().gitHosts;\n const provider = providers.find((p) => p.metadata.kind === body.provider);\n if (!provider) {\n return c.json({ message: `Unknown provider: ${body.provider}` }, 400);\n }\n const parsed = provider.metadata.schema.safeParse(body.config);\n if (!parsed.success) {\n return c.json({ message: parsed.error.message }, 400);\n }\n const model = new StatusConfigModel(\n getStore().db,\n undefined,\n credentialKeys(getStore().config),\n );\n const row = await model.create(project.id, {\n provider: body.provider,\n config: parsed.data,\n token: body.token,\n });\n return c.json(toPublic(row), 201);\n });\n\n app.openapi(deleteRoute, async (c) => {\n const { slug, id } = c.req.valid(\"param\");\n const project = await resolveAuthorizedProject(c, slug, ...ADMIN_ROLES);\n const model = new StatusConfigModel(\n getStore().db,\n undefined,\n credentialKeys(getStore().config),\n );\n const existing = await model.get(project.id, id);\n if (!existing) {\n return c.json({ message: \"Status config not found\" }, 404);\n }\n await model.remove(project.id, id);\n return c.body(null, 204);\n });\n}\n"],"mappings":"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"}