@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
@@ -1,14 +1,12 @@
1
1
  import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
- import { credentialKeys } from "../credential-keys.mjs";
5
- import { getStore } from "../store.mjs";
6
4
  import { notFound, resolveAuthorizedProject } from "./helpers.mjs";
7
5
  import { notFound as notFound$1, unauthorized, webhookCreateSchema, webhookCreatedSchema, webhookPublicSchema } from "./schemas.mjs";
6
+ import { webhookModel } from "./scoped-models.mjs";
8
7
  import { createRoute, z } from "@hono/zod-openapi";
9
8
  import { WebhookModel } from "@storyshelf/core/models";
10
- import { randomToken } from "@storyshelf/core/utils";
11
- //#region src/routers/webhooks.ts
9
+ // src/routers/webhooks.ts
12
10
  const ADMIN_ROLES = ["admin"];
13
11
  const listWebhooksRoute = createRoute({
14
12
  method: "get",
@@ -60,7 +58,7 @@ const deleteWebhookRoute = createRoute({
60
58
  function registerWebhooks(app) {
61
59
  app.openapi(listWebhooksRoute, async (c) => {
62
60
  const project = await resolveAuthorizedProject(c, c.req.valid("param").slug, ...ADMIN_ROLES);
63
- const webhooks = await new WebhookModel(getStore().db, void 0, credentialKeys(getStore().config)).list(project.id);
61
+ const webhooks = await webhookModel().list(project.id);
64
62
  return c.json(webhooks.map((webhook) => ({
65
63
  id: webhook.id,
66
64
  url: webhook.url,
@@ -70,11 +68,7 @@ function registerWebhooks(app) {
70
68
  app.openapi(createWebhookRoute, async (c) => {
71
69
  const project = await resolveAuthorizedProject(c, c.req.valid("param").slug, ...ADMIN_ROLES);
72
70
  const body = c.req.valid("json");
73
- const secret = randomToken("whsec_").value;
74
- const webhook = await new WebhookModel(getStore().db, void 0, credentialKeys(getStore().config)).create(project.id, {
75
- ...body,
76
- secret
77
- });
71
+ const { webhook, secret } = await webhookModel().issue(project.id, body);
78
72
  return c.json({
79
73
  id: webhook.id,
80
74
  url: webhook.url,
@@ -85,13 +79,12 @@ function registerWebhooks(app) {
85
79
  app.openapi(deleteWebhookRoute, async (c) => {
86
80
  const { slug, webhookId } = c.req.valid("param");
87
81
  const project = await resolveAuthorizedProject(c, slug, ...ADMIN_ROLES);
88
- const webhook = await new WebhookModel(getStore().db, void 0, credentialKeys(getStore().config)).get(project.id, webhookId);
82
+ const webhook = await webhookModel().get(project.id, webhookId);
89
83
  if (!webhook) notFound("Webhook not found");
90
- await new WebhookModel(getStore().db, void 0, credentialKeys(getStore().config)).remove(project.id, webhook.id);
84
+ await webhookModel().remove(project.id, webhook.id);
91
85
  return c.body(null, 204);
92
86
  });
93
87
  }
94
- //#endregion
95
88
  export { registerWebhooks };
96
89
 
97
90
  //# sourceMappingURL=webhooks.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"webhooks.mjs","names":["notFoundResponse"],"sources":["../../src/routers/webhooks.ts"],"sourcesContent":["import { createRoute, z } from \"@hono/zod-openapi\";\nimport { WebhookModel } from \"@storyshelf/core/models\";\nimport type { ProjectRole } from \"@storyshelf/core/types\";\nimport { randomToken } from \"@storyshelf/core/utils\";\nimport type { ShelfRouter } from \"../app-types.ts\";\nimport { credentialKeys } from \"../credential-keys.ts\";\nimport { getStore } from \"../store.ts\";\nimport { resolveAuthorizedProject, notFound } from \"./helpers.ts\";\nimport {\n notFound as notFoundResponse,\n unauthorized,\n webhookCreatedSchema,\n webhookCreateSchema,\n webhookPublicSchema,\n} from \"./schemas.ts\";\nconst ADMIN_ROLES: readonly ProjectRole[] = [\"admin\"];\n\nconst listWebhooksRoute = createRoute({\n method: \"get\",\n tags: [\"Webhooks\"],\n summary: \"List webhooks\",\n path: \"/api/v1/projects/{slug}/webhooks\",\n request: { params: z.object({ slug: z.string() }) },\n responses: {\n 200: {\n content: { \"application/json\": { schema: webhookPublicSchema.array() } },\n description: \"List webhooks\",\n },\n ...notFoundResponse,\n ...unauthorized,\n },\n});\n\nconst createWebhookRoute = createRoute({\n method: \"post\",\n tags: [\"Webhooks\"],\n summary: \"Create a webhook\",\n path: \"/api/v1/projects/{slug}/webhooks\",\n request: {\n params: z.object({ slug: z.string() }),\n body: { content: { \"application/json\": { schema: webhookCreateSchema } } },\n },\n responses: {\n 201: {\n content: { \"application/json\": { schema: webhookCreatedSchema } },\n description: \"Created webhook\",\n },\n ...notFoundResponse,\n },\n});\n\nconst deleteWebhookRoute = createRoute({\n method: \"delete\",\n tags: [\"Webhooks\"],\n summary: \"Delete a webhook\",\n path: \"/api/v1/projects/{slug}/webhooks/{webhookId}\",\n request: { params: z.object({ slug: z.string(), webhookId: z.string() }) },\n responses: {\n 204: { description: \"Deleted webhook\" },\n ...notFoundResponse,\n },\n});\n\n/** Register the project webhook list, create, and delete endpoints. */\nexport function registerWebhooks(app: ShelfRouter): void {\n app.openapi(listWebhooksRoute, async (c) => {\n const project = await resolveAuthorizedProject(c, c.req.valid(\"param\").slug, ...ADMIN_ROLES);\n const webhooks = await new WebhookModel(\n getStore().db,\n undefined,\n credentialKeys(getStore().config),\n ).list(project.id);\n return c.json(\n webhooks.map((webhook) => ({\n id: webhook.id,\n url: webhook.url,\n events: WebhookModel.eventsOf(webhook),\n })),\n );\n });\n\n app.openapi(createWebhookRoute, async (c) => {\n const project = await resolveAuthorizedProject(c, c.req.valid(\"param\").slug, ...ADMIN_ROLES);\n const body = c.req.valid(\"json\");\n const secret = randomToken(\"whsec_\").value;\n const webhook = await new WebhookModel(\n getStore().db,\n undefined,\n credentialKeys(getStore().config),\n ).create(project.id, { ...body, secret });\n return c.json({ id: webhook.id, url: webhook.url, events: body.events ?? [], secret }, 201);\n });\n\n app.openapi(deleteWebhookRoute, async (c) => {\n const { slug, webhookId } = c.req.valid(\"param\");\n const project = await resolveAuthorizedProject(c, slug, ...ADMIN_ROLES);\n const webhook = await new WebhookModel(\n getStore().db,\n undefined,\n credentialKeys(getStore().config),\n ).get(project.id, webhookId);\n if (!webhook) {\n notFound(\"Webhook not found\");\n }\n await new WebhookModel(getStore().db, undefined, credentialKeys(getStore().config)).remove(\n project.id,\n webhook.id,\n );\n return c.body(null, 204);\n });\n}\n"],"mappings":";;;;;;;;;;;AAeA,MAAM,cAAsC,CAAC,OAAO;AAEpD,MAAM,oBAAoB,YAAY;CACpC,QAAQ;CACR,MAAM,CAAC,UAAU;CACjB,SAAS;CACT,MAAM;CACN,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE;CAClD,WAAW;EACT,KAAK;GACH,SAAS,EAAE,oBAAoB,EAAE,QAAQ,oBAAoB,MAAM,EAAE,EAAE;GACvE,aAAa;EACf;EACA,GAAGA;EACH,GAAG;CACL;AACF,CAAC;AAED,MAAM,qBAAqB,YAAY;CACrC,QAAQ;CACR,MAAM,CAAC,UAAU;CACjB,SAAS;CACT,MAAM;CACN,SAAS;EACP,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;EACrC,MAAM,EAAE,SAAS,EAAE,oBAAoB,EAAE,QAAQ,oBAAoB,EAAE,EAAE;CAC3E;CACA,WAAW;EACT,KAAK;GACH,SAAS,EAAE,oBAAoB,EAAE,QAAQ,qBAAqB,EAAE;GAChE,aAAa;EACf;EACA,GAAGA;CACL;AACF,CAAC;AAED,MAAM,qBAAqB,YAAY;CACrC,QAAQ;CACR,MAAM,CAAC,UAAU;CACjB,SAAS;CACT,MAAM;CACN,SAAS,EAAE,QAAQ,EAAE,OAAO;EAAE,MAAM,EAAE,OAAO;EAAG,WAAW,EAAE,OAAO;CAAE,CAAC,EAAE;CACzE,WAAW;EACT,KAAK,EAAE,aAAa,kBAAkB;EACtC,GAAGA;CACL;AACF,CAAC;;AAGD,SAAgB,iBAAiB,KAAwB;CACvD,IAAI,QAAQ,mBAAmB,OAAO,MAAM;EAC1C,MAAM,UAAU,MAAM,yBAAyB,GAAG,EAAE,IAAI,MAAM,OAAO,CAAC,CAAC,MAAM,GAAG,WAAW;EAC3F,MAAM,WAAW,MAAM,IAAI,aACzB,SAAS,CAAC,CAAC,IACX,KAAA,GACA,eAAe,SAAS,CAAC,CAAC,MAAM,CAClC,CAAC,CAAC,KAAK,QAAQ,EAAE;EACjB,OAAO,EAAE,KACP,SAAS,KAAK,aAAa;GACzB,IAAI,QAAQ;GACZ,KAAK,QAAQ;GACb,QAAQ,aAAa,SAAS,OAAO;EACvC,EAAE,CACJ;CACF,CAAC;CAED,IAAI,QAAQ,oBAAoB,OAAO,MAAM;EAC3C,MAAM,UAAU,MAAM,yBAAyB,GAAG,EAAE,IAAI,MAAM,OAAO,CAAC,CAAC,MAAM,GAAG,WAAW;EAC3F,MAAM,OAAO,EAAE,IAAI,MAAM,MAAM;EAC/B,MAAM,SAAS,YAAY,QAAQ,CAAC,CAAC;EACrC,MAAM,UAAU,MAAM,IAAI,aACxB,SAAS,CAAC,CAAC,IACX,KAAA,GACA,eAAe,SAAS,CAAC,CAAC,MAAM,CAClC,CAAC,CAAC,OAAO,QAAQ,IAAI;GAAE,GAAG;GAAM;EAAO,CAAC;EACxC,OAAO,EAAE,KAAK;GAAE,IAAI,QAAQ;GAAI,KAAK,QAAQ;GAAK,QAAQ,KAAK,UAAU,CAAC;GAAG;EAAO,GAAG,GAAG;CAC5F,CAAC;CAED,IAAI,QAAQ,oBAAoB,OAAO,MAAM;EAC3C,MAAM,EAAE,MAAM,cAAc,EAAE,IAAI,MAAM,OAAO;EAC/C,MAAM,UAAU,MAAM,yBAAyB,GAAG,MAAM,GAAG,WAAW;EACtE,MAAM,UAAU,MAAM,IAAI,aACxB,SAAS,CAAC,CAAC,IACX,KAAA,GACA,eAAe,SAAS,CAAC,CAAC,MAAM,CAClC,CAAC,CAAC,IAAI,QAAQ,IAAI,SAAS;EAC3B,IAAI,CAAC,SACH,SAAS,mBAAmB;EAE9B,MAAM,IAAI,aAAa,SAAS,CAAC,CAAC,IAAI,KAAA,GAAW,eAAe,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAClF,QAAQ,IACR,QAAQ,EACV;EACA,OAAO,EAAE,KAAK,MAAM,GAAG;CACzB,CAAC;AACH"}
1
+ {"version":3,"file":"webhooks.mjs","names":["notFoundResponse"],"sources":["../../src/routers/webhooks.ts"],"sourcesContent":["import { createRoute, z } from \"@hono/zod-openapi\";\nimport { WebhookModel } from \"@storyshelf/core/models\";\nimport type { ProjectRole } from \"@storyshelf/core/types\";\nimport type { ShelfRouter } from \"../app-types.ts\";\nimport { resolveAuthorizedProject, notFound } from \"./helpers.ts\";\nimport {\n notFound as notFoundResponse,\n unauthorized,\n webhookCreatedSchema,\n webhookCreateSchema,\n webhookPublicSchema,\n} from \"./schemas.ts\";\nimport { webhookModel } from \"./scoped-models.ts\";\nconst ADMIN_ROLES: readonly ProjectRole[] = [\"admin\"];\n\nconst listWebhooksRoute = createRoute({\n method: \"get\",\n tags: [\"Webhooks\"],\n summary: \"List webhooks\",\n path: \"/api/v1/projects/{slug}/webhooks\",\n request: { params: z.object({ slug: z.string() }) },\n responses: {\n 200: {\n content: { \"application/json\": { schema: webhookPublicSchema.array() } },\n description: \"List webhooks\",\n },\n ...notFoundResponse,\n ...unauthorized,\n },\n});\n\nconst createWebhookRoute = createRoute({\n method: \"post\",\n tags: [\"Webhooks\"],\n summary: \"Create a webhook\",\n path: \"/api/v1/projects/{slug}/webhooks\",\n request: {\n params: z.object({ slug: z.string() }),\n body: { content: { \"application/json\": { schema: webhookCreateSchema } } },\n },\n responses: {\n 201: {\n content: { \"application/json\": { schema: webhookCreatedSchema } },\n description: \"Created webhook\",\n },\n ...notFoundResponse,\n },\n});\n\nconst deleteWebhookRoute = createRoute({\n method: \"delete\",\n tags: [\"Webhooks\"],\n summary: \"Delete a webhook\",\n path: \"/api/v1/projects/{slug}/webhooks/{webhookId}\",\n request: { params: z.object({ slug: z.string(), webhookId: z.string() }) },\n responses: {\n 204: { description: \"Deleted webhook\" },\n ...notFoundResponse,\n },\n});\n\n/** Register the project webhook list, create, and delete endpoints. */\nexport function registerWebhooks(app: ShelfRouter): void {\n app.openapi(listWebhooksRoute, async (c) => {\n const project = await resolveAuthorizedProject(c, c.req.valid(\"param\").slug, ...ADMIN_ROLES);\n const webhooks = await webhookModel().list(project.id);\n return c.json(\n webhooks.map((webhook) => ({\n id: webhook.id,\n url: webhook.url,\n events: WebhookModel.eventsOf(webhook),\n })),\n );\n });\n\n app.openapi(createWebhookRoute, async (c) => {\n const project = await resolveAuthorizedProject(c, c.req.valid(\"param\").slug, ...ADMIN_ROLES);\n const body = c.req.valid(\"json\");\n const { webhook, secret } = await webhookModel().issue(project.id, body);\n return c.json({ id: webhook.id, url: webhook.url, events: body.events ?? [], secret }, 201);\n });\n\n app.openapi(deleteWebhookRoute, async (c) => {\n const { slug, webhookId } = c.req.valid(\"param\");\n const project = await resolveAuthorizedProject(c, slug, ...ADMIN_ROLES);\n const webhook = await webhookModel().get(project.id, webhookId);\n if (!webhook) {\n notFound(\"Webhook not found\");\n }\n await webhookModel().remove(project.id, webhook.id);\n return c.body(null, 204);\n });\n}\n"],"mappings":";;;;;;;;;AAaA,MAAM,cAAsC,CAAC,OAAO;AAEpD,MAAM,oBAAoB,YAAY;CACpC,QAAQ;CACR,MAAM,CAAC,UAAU;CACjB,SAAS;CACT,MAAM;CACN,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE;CAClD,WAAW;EACT,KAAK;GACH,SAAS,EAAE,oBAAoB,EAAE,QAAQ,oBAAoB,MAAM,EAAE,EAAE;GACvE,aAAa;EACf;EACA,GAAGA;EACH,GAAG;CACL;AACF,CAAC;AAED,MAAM,qBAAqB,YAAY;CACrC,QAAQ;CACR,MAAM,CAAC,UAAU;CACjB,SAAS;CACT,MAAM;CACN,SAAS;EACP,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;EACrC,MAAM,EAAE,SAAS,EAAE,oBAAoB,EAAE,QAAQ,oBAAoB,EAAE,EAAE;CAC3E;CACA,WAAW;EACT,KAAK;GACH,SAAS,EAAE,oBAAoB,EAAE,QAAQ,qBAAqB,EAAE;GAChE,aAAa;EACf;EACA,GAAGA;CACL;AACF,CAAC;AAED,MAAM,qBAAqB,YAAY;CACrC,QAAQ;CACR,MAAM,CAAC,UAAU;CACjB,SAAS;CACT,MAAM;CACN,SAAS,EAAE,QAAQ,EAAE,OAAO;EAAE,MAAM,EAAE,OAAO;EAAG,WAAW,EAAE,OAAO;CAAE,CAAC,EAAE;CACzE,WAAW;EACT,KAAK,EAAE,aAAa,kBAAkB;EACtC,GAAGA;CACL;AACF,CAAC;;AAGD,SAAgB,iBAAiB,KAAwB;CACvD,IAAI,QAAQ,mBAAmB,OAAO,MAAM;EAC1C,MAAM,UAAU,MAAM,yBAAyB,GAAG,EAAE,IAAI,MAAM,OAAO,CAAC,CAAC,MAAM,GAAG,WAAW;EAC3F,MAAM,WAAW,MAAM,aAAa,CAAC,CAAC,KAAK,QAAQ,EAAE;EACrD,OAAO,EAAE,KACP,SAAS,KAAK,aAAa;GACzB,IAAI,QAAQ;GACZ,KAAK,QAAQ;GACb,QAAQ,aAAa,SAAS,OAAO;EACvC,EAAE,CACJ;CACF,CAAC;CAED,IAAI,QAAQ,oBAAoB,OAAO,MAAM;EAC3C,MAAM,UAAU,MAAM,yBAAyB,GAAG,EAAE,IAAI,MAAM,OAAO,CAAC,CAAC,MAAM,GAAG,WAAW;EAC3F,MAAM,OAAO,EAAE,IAAI,MAAM,MAAM;EAC/B,MAAM,EAAE,SAAS,WAAW,MAAM,aAAa,CAAC,CAAC,MAAM,QAAQ,IAAI,IAAI;EACvE,OAAO,EAAE,KAAK;GAAE,IAAI,QAAQ;GAAI,KAAK,QAAQ;GAAK,QAAQ,KAAK,UAAU,CAAC;GAAG;EAAO,GAAG,GAAG;CAC5F,CAAC;CAED,IAAI,QAAQ,oBAAoB,OAAO,MAAM;EAC3C,MAAM,EAAE,MAAM,cAAc,EAAE,IAAI,MAAM,OAAO;EAC/C,MAAM,UAAU,MAAM,yBAAyB,GAAG,MAAM,GAAG,WAAW;EACtE,MAAM,UAAU,MAAM,aAAa,CAAC,CAAC,IAAI,QAAQ,IAAI,SAAS;EAC9D,IAAI,CAAC,SACH,SAAS,mBAAmB;EAE9B,MAAM,aAAa,CAAC,CAAC,OAAO,QAAQ,IAAI,QAAQ,EAAE;EAClD,OAAO,EAAE,KAAK,MAAM,GAAG;CACzB,CAAC;AACH"}
@@ -2,7 +2,7 @@ import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
4
  import { getStore } from "../store.mjs";
5
- //#region src/routers/well-known.ts
5
+ // src/routers/well-known.ts
6
6
  /** SSO-capable login methods (oauth buttons + SSO) with IdP reply URLs. */
7
7
  function ssoProviders(auth, origin) {
8
8
  return auth.loginMethods().filter((method) => method.kind === "oauth" || method.kind === "sso").map((method) => ({
@@ -11,13 +11,20 @@ function ssoProviders(auth, origin) {
11
11
  redirectUris: method.kind === "sso" ? [`${origin}/api/auth/sso/callback/${method.id}`, `${origin}/api/auth/sso/saml2/sp/acs/${method.id}`] : [`${origin}/api/auth/callback/${method.id}`]
12
12
  }));
13
13
  }
14
- function requestOrigin(c) {
15
- return getStore().config.publicBaseUrl ?? new URL(c.req.url).origin;
14
+ /**
15
+ * The origin of this interactive, request-bound document (ADR 0007, decision 6): the confirmed
16
+ * public origin, else the address the request came in on (the one place besides OAuth redirect
17
+ * URIs where authentication may use it).
18
+ */
19
+ async function requestOrigin(c) {
20
+ const { publicOrigin, config } = getStore();
21
+ const own = new URL(c.req.url).origin;
22
+ return publicOrigin ? await publicOrigin.authOrigin(own) : config.publicBaseUrl ?? own;
16
23
  }
17
24
  /** Register public relying-party helper documents (no auth required). */
18
25
  function registerWellKnown(app, auth) {
19
- app.get("/.well-known/openid-configuration", (c) => {
20
- const origin = requestOrigin(c);
26
+ app.get("/.well-known/openid-configuration", async (c) => {
27
+ const origin = await requestOrigin(c);
21
28
  const providers = ssoProviders(auth, origin);
22
29
  return c.json({
23
30
  issuer: origin,
@@ -37,7 +44,6 @@ function registerWellKnown(app, auth) {
37
44
  });
38
45
  app.get("/.well-known/change-password", (c) => c.redirect("/profile", 302));
39
46
  }
40
- //#endregion
41
47
  export { registerWellKnown };
42
48
 
43
49
  //# sourceMappingURL=well-known.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"well-known.mjs","names":[],"sources":["../../src/routers/well-known.ts"],"sourcesContent":["import type { Auth } from \"@storyshelf/core/auth\";\nimport type { Context } from \"hono\";\nimport type { ShelfRouter } from \"../app-types.ts\";\nimport { getStore } from \"../store.ts\";\n\n/** One SSO-capable login method with its IdP reply URLs. */\ninterface SsoProviderLink {\n id: string;\n label: string;\n redirectUris: string[];\n}\n\n/** SSO-capable login methods (oauth buttons + SSO) with IdP reply URLs. */\nfunction ssoProviders(auth: Auth, origin: string): SsoProviderLink[] {\n return auth\n .loginMethods()\n .filter((method) => method.kind === \"oauth\" || method.kind === \"sso\")\n .map((method) => ({\n id: method.id,\n label: method.label,\n redirectUris:\n method.kind === \"sso\"\n ? [\n `${origin}/api/auth/sso/callback/${method.id}`,\n `${origin}/api/auth/sso/saml2/sp/acs/${method.id}`,\n ]\n : [`${origin}/api/auth/callback/${method.id}`],\n }));\n}\n\nfunction requestOrigin(c: Context): string {\n return getStore().config.publicBaseUrl ?? new URL(c.req.url).origin;\n}\n\n/** Register public relying-party helper documents (no auth required). */\nexport function registerWellKnown(app: ShelfRouter, auth: Auth): void {\n app.get(\"/.well-known/openid-configuration\", (c) => {\n const origin = requestOrigin(c);\n const providers = ssoProviders(auth, origin);\n return c.json(\n {\n issuer: origin,\n note: \"StoryShelf is an OpenID Connect relying party, not an identity provider. This document helps operators register redirect URIs with their provider; it is not provider metadata.\",\n response_types_supported: [\"code\"],\n scopes_supported: [\"openid\", \"email\", \"profile\"],\n redirect_uris: providers.flatMap((provider) => provider.redirectUris),\n providers: providers.map((method) => ({ id: method.id, label: method.label })),\n },\n 200,\n { \"Cache-Control\": \"public, max-age=300\" },\n );\n });\n\n // oxlint-disable-next-line typescript/promise-function-async -- Hono handler may return Response directly\n app.get(\"/.well-known/change-password\", (c) => c.redirect(\"/profile\", 302));\n}\n"],"mappings":";;;;;;AAaA,SAAS,aAAa,MAAY,QAAmC;CACnE,OAAO,KACJ,aAAa,CAAC,CACd,QAAQ,WAAW,OAAO,SAAS,WAAW,OAAO,SAAS,KAAK,CAAC,CACpE,KAAK,YAAY;EAChB,IAAI,OAAO;EACX,OAAO,OAAO;EACd,cACE,OAAO,SAAS,QACZ,CACE,GAAG,OAAO,yBAAyB,OAAO,MAC1C,GAAG,OAAO,6BAA6B,OAAO,IAChD,IACA,CAAC,GAAG,OAAO,qBAAqB,OAAO,IAAI;CACnD,EAAE;AACN;AAEA,SAAS,cAAc,GAAoB;CACzC,OAAO,SAAS,CAAC,CAAC,OAAO,iBAAiB,IAAI,IAAI,EAAE,IAAI,GAAG,CAAC,CAAC;AAC/D;;AAGA,SAAgB,kBAAkB,KAAkB,MAAkB;CACpE,IAAI,IAAI,sCAAsC,MAAM;EAClD,MAAM,SAAS,cAAc,CAAC;EAC9B,MAAM,YAAY,aAAa,MAAM,MAAM;EAC3C,OAAO,EAAE,KACP;GACE,QAAQ;GACR,MAAM;GACN,0BAA0B,CAAC,MAAM;GACjC,kBAAkB;IAAC;IAAU;IAAS;GAAS;GAC/C,eAAe,UAAU,SAAS,aAAa,SAAS,YAAY;GACpE,WAAW,UAAU,KAAK,YAAY;IAAE,IAAI,OAAO;IAAI,OAAO,OAAO;GAAM,EAAE;EAC/E,GACA,KACA,EAAE,iBAAiB,sBAAsB,CAC3C;CACF,CAAC;CAGD,IAAI,IAAI,iCAAiC,MAAM,EAAE,SAAS,YAAY,GAAG,CAAC;AAC5E"}
1
+ {"version":3,"file":"well-known.mjs","names":[],"sources":["../../src/routers/well-known.ts"],"sourcesContent":["import type { Auth } from \"@storyshelf/core/auth\";\nimport type { Context } from \"hono\";\nimport type { ShelfRouter } from \"../app-types.ts\";\nimport { getStore } from \"../store.ts\";\n\n/** One SSO-capable login method with its IdP reply URLs. */\ninterface SsoProviderLink {\n id: string;\n label: string;\n redirectUris: string[];\n}\n\n/** SSO-capable login methods (oauth buttons + SSO) with IdP reply URLs. */\nfunction ssoProviders(auth: Auth, origin: string): SsoProviderLink[] {\n return auth\n .loginMethods()\n .filter((method) => method.kind === \"oauth\" || method.kind === \"sso\")\n .map((method) => ({\n id: method.id,\n label: method.label,\n redirectUris:\n method.kind === \"sso\"\n ? [\n `${origin}/api/auth/sso/callback/${method.id}`,\n `${origin}/api/auth/sso/saml2/sp/acs/${method.id}`,\n ]\n : [`${origin}/api/auth/callback/${method.id}`],\n }));\n}\n\n/**\n * The origin of this interactive, request-bound document (ADR 0007, decision 6): the confirmed\n * public origin, else the address the request came in on (the one place besides OAuth redirect\n * URIs where authentication may use it).\n */\nasync function requestOrigin(c: Context): Promise<string> {\n const { publicOrigin, config } = getStore();\n const own = new URL(c.req.url).origin;\n return publicOrigin ? await publicOrigin.authOrigin(own) : (config.publicBaseUrl ?? own);\n}\n\n/** Register public relying-party helper documents (no auth required). */\nexport function registerWellKnown(app: ShelfRouter, auth: Auth): void {\n app.get(\"/.well-known/openid-configuration\", async (c) => {\n const origin = await requestOrigin(c);\n const providers = ssoProviders(auth, origin);\n return c.json(\n {\n issuer: origin,\n note: \"StoryShelf is an OpenID Connect relying party, not an identity provider. This document helps operators register redirect URIs with their provider; it is not provider metadata.\",\n response_types_supported: [\"code\"],\n scopes_supported: [\"openid\", \"email\", \"profile\"],\n redirect_uris: providers.flatMap((provider) => provider.redirectUris),\n providers: providers.map((method) => ({ id: method.id, label: method.label })),\n },\n 200,\n { \"Cache-Control\": \"public, max-age=300\" },\n );\n });\n\n // oxlint-disable-next-line typescript/promise-function-async -- Hono handler may return Response directly\n app.get(\"/.well-known/change-password\", (c) => c.redirect(\"/profile\", 302));\n}\n"],"mappings":";;;;;;AAaA,SAAS,aAAa,MAAY,QAAmC;CACnE,OAAO,KACJ,aAAa,CAAC,CACd,QAAQ,WAAW,OAAO,SAAS,WAAW,OAAO,SAAS,KAAK,CAAC,CACpE,KAAK,YAAY;EAChB,IAAI,OAAO;EACX,OAAO,OAAO;EACd,cACE,OAAO,SAAS,QACZ,CACE,GAAG,OAAO,yBAAyB,OAAO,MAC1C,GAAG,OAAO,6BAA6B,OAAO,IAChD,IACA,CAAC,GAAG,OAAO,qBAAqB,OAAO,IAAI;CACnD,EAAE;AACN;;;;;;AAOA,eAAe,cAAc,GAA6B;CACxD,MAAM,EAAE,cAAc,WAAW,SAAS;CAC1C,MAAM,MAAM,IAAI,IAAI,EAAE,IAAI,GAAG,CAAC,CAAC;CAC/B,OAAO,eAAe,MAAM,aAAa,WAAW,GAAG,IAAK,OAAO,iBAAiB;AACtF;;AAGA,SAAgB,kBAAkB,KAAkB,MAAkB;CACpE,IAAI,IAAI,qCAAqC,OAAO,MAAM;EACxD,MAAM,SAAS,MAAM,cAAc,CAAC;EACpC,MAAM,YAAY,aAAa,MAAM,MAAM;EAC3C,OAAO,EAAE,KACP;GACE,QAAQ;GACR,MAAM;GACN,0BAA0B,CAAC,MAAM;GACjC,kBAAkB;IAAC;IAAU;IAAS;GAAS;GAC/C,eAAe,UAAU,SAAS,aAAa,SAAS,YAAY;GACpE,WAAW,UAAU,KAAK,YAAY;IAAE,IAAI,OAAO;IAAI,OAAO,OAAO;GAAM,EAAE;EAC/E,GACA,KACA,EAAE,iBAAiB,sBAAsB,CAC3C;CACF,CAAC;CAGD,IAAI,IAAI,iCAAiC,MAAM,EAAE,SAAS,YAAY,GAAG,CAAC;AAC5E"}
@@ -0,0 +1,92 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ // src/routes/api-routes.ts
5
+ /** JSON API routes, keyed by `METHOD /hono-pattern`. */
6
+ const API_ROUTE_CLASSES = {
7
+ "GET /api/v1/projects": "hosting",
8
+ "POST /api/v1/projects": "hosting",
9
+ "GET /api/v1/projects/:slug": "hosting",
10
+ "PATCH /api/v1/projects/:slug": "hosting",
11
+ "DELETE /api/v1/projects/:slug": "hosting",
12
+ "GET /api/v1/projects/:slug/builds": "hosting",
13
+ "POST /api/v1/projects/:slug/builds": "hosting",
14
+ "POST /api/v1/projects/:slug/builds/:buildId/usage": "hosting",
15
+ "PUT /api/v1/projects/:slug/builds/:buildId/zip": "hosting",
16
+ "POST /api/v1/projects/:slug/builds/:buildId/dedup": "hosting",
17
+ "POST /api/v1/projects/:slug/builds/:buildId/content": "hosting",
18
+ "POST /api/v1/projects/:slug/builds/:buildId/manifest": "hosting",
19
+ "GET /api/v1/projects/:slug/builds/:buildId": "hosting",
20
+ "DELETE /api/v1/projects/:slug/builds/:buildId": "hosting",
21
+ "GET /api/v1/projects/:slug/label-types": "hosting",
22
+ "POST /api/v1/projects/:slug/label-types": "hosting",
23
+ "DELETE /api/v1/projects/:slug/label-types/:key": "hosting",
24
+ "PATCH /api/v1/projects/:slug/label-types/:key": "hosting",
25
+ "GET /api/v1/projects/:slug/links": "hosting",
26
+ "PUT /api/v1/projects/:slug/links": "hosting",
27
+ "GET /api/v1/projects/:slug/members": "hosting",
28
+ "POST /api/v1/projects/:slug/members": "hosting",
29
+ "PATCH /api/v1/projects/:slug/members/:userId": "hosting",
30
+ "DELETE /api/v1/projects/:slug/members/:userId": "hosting",
31
+ "GET /api/v1/projects/:slug/group-mappings": "hosting",
32
+ "POST /api/v1/projects/:slug/group-mappings": "hosting",
33
+ "DELETE /api/v1/projects/:slug/group-mappings/:mappingId": "hosting",
34
+ "GET /api/v1/projects/:slug/tokens": "hosting",
35
+ "POST /api/v1/projects/:slug/tokens": "hosting",
36
+ "DELETE /api/v1/projects/:slug/tokens/:tokenId": "hosting",
37
+ "GET /api/v1/projects/:slug/webhooks": "hosting",
38
+ "POST /api/v1/projects/:slug/webhooks": "hosting",
39
+ "DELETE /api/v1/projects/:slug/webhooks/:webhookId": "hosting",
40
+ "GET /api/v1/projects/:slug/notification-channels": "hosting",
41
+ "POST /api/v1/projects/:slug/notification-channels": "hosting",
42
+ "DELETE /api/v1/projects/:slug/notification-channels/:channelId": "hosting",
43
+ "GET /api/v1/projects/:slug/notifications/me": "hosting",
44
+ "PUT /api/v1/projects/:slug/notifications/me": "hosting",
45
+ "DELETE /api/v1/projects/:slug/notifications/me": "hosting",
46
+ "GET /api/v1/projects/:slug/notifications": "hosting",
47
+ "GET /api/v1/admin/notification-channels": "hosting",
48
+ "POST /api/v1/admin/notification-channels": "hosting",
49
+ "DELETE /api/v1/admin/notification-channels/:channelId": "hosting",
50
+ "GET /api/v1/health": "hosting",
51
+ "POST /api/v1/health": "hosting",
52
+ "POST /api/v1/admin/credentials/reencrypt": "hosting",
53
+ "POST /api/v1/admin/purge": "hosting",
54
+ "GET /api/v1/openapi.json": "hosting",
55
+ "GET /api/v1/docs": "hosting",
56
+ "POST /api/v1/projects/:slug/builds/:buildId/affected": "testing",
57
+ "POST /api/v1/projects/:slug/builds/:buildId/retry": "testing",
58
+ "POST /api/v1/projects/:slug/builds/:buildId/cancel": "testing",
59
+ "GET /api/v1/projects/:slug/builds/:buildId/snapshots": "testing",
60
+ "GET /api/v1/projects/:slug/builds/:buildId/preview-token": "testing",
61
+ "POST /api/v1/projects/:slug/builds/:buildId/snapshots/:snapshotId/approve": "testing",
62
+ "POST /api/v1/projects/:slug/builds/:buildId/snapshots/:snapshotId/reject": "testing",
63
+ "POST /api/v1/projects/:slug/builds/:buildId/approve-all": "testing",
64
+ "POST /api/v1/projects/:slug/builds/:buildId/reject-all": "testing",
65
+ "POST /api/v1/projects/:slug/builds/:buildId/stories/:storyId/modes/:modeKey/approve": "testing",
66
+ "POST /api/v1/projects/:slug/builds/:buildId/stories/:storyId/modes/:modeKey/reject": "testing",
67
+ "POST /api/v1/projects/:slug/builds/:buildId/rediff": "testing",
68
+ "GET /api/v1/projects/:slug/builds/:buildId/attempts": "testing",
69
+ "GET /api/v1/projects/:slug/builds/:buildId/attempts/:attemptNo": "testing",
70
+ "GET /api/v1/projects/:slug/builds/:buildId/attempts/:attemptNo/logs": "testing",
71
+ "GET /api/v1/projects/:slug/builds/:buildId/snapshots/:snapshotId/usage": "testing",
72
+ "GET /api/v1/projects/:slug/builds/:buildId/snapshots/:snapshotId/image": "testing",
73
+ "GET /api/v1/projects/:slug/builds/:buildId/snapshots/:snapshotId/diff": "testing",
74
+ "GET /api/v1/projects/:slug/builds/:buildId/snapshots/:snapshotId/baseline": "testing",
75
+ "GET /api/v1/projects/:slug/design/renders/:renderId": "testing",
76
+ "GET /api/v1/projects/:slug/baselines/export": "testing",
77
+ "POST /api/v1/projects/:slug/baselines/import": "testing",
78
+ "GET /api/v1/projects/:slug/builds/:buildId/insights/latest": "testing",
79
+ "GET /api/v1/projects/:slug/builds/:buildId/insights": "testing",
80
+ "POST /api/v1/projects/:slug/builds/:buildId/insights": "testing",
81
+ "GET /api/v1/projects/:slug/insights/health": "testing",
82
+ "POST /api/v1/projects/:slug/insights/health": "testing",
83
+ "GET /api/v1/projects/:slug/builds/:buildId/comments": "review",
84
+ "POST /api/v1/projects/:slug/builds/:buildId/comments": "review",
85
+ "POST /api/v1/projects/:slug/builds/:buildId/comments/:commentId/resolve": "review",
86
+ "GET /api/v1/projects/:slug/builds/:buildId/reviews": "review",
87
+ "POST /api/v1/projects/:slug/builds/:buildId/reviews": "review",
88
+ "GET /api/v1/projects/:slug/builds/:buildId/changeset": "review"
89
+ };
90
+ export { API_ROUTE_CLASSES };
91
+
92
+ //# sourceMappingURL=api-routes.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-routes.mjs","names":[],"sources":["../../src/routes/api-routes.ts"],"sourcesContent":["/** Classes of the JSON API routes under `/api/v1`. */\nimport type { RouteClass } from \"./classification.ts\";\n\n/** JSON API routes, keyed by `METHOD /hono-pattern`. */\nexport const API_ROUTE_CLASSES: Readonly<Record<string, RouteClass>> = {\n // hosting\n \"GET /api/v1/projects\": \"hosting\",\n \"POST /api/v1/projects\": \"hosting\",\n \"GET /api/v1/projects/:slug\": \"hosting\",\n \"PATCH /api/v1/projects/:slug\": \"hosting\",\n \"DELETE /api/v1/projects/:slug\": \"hosting\",\n \"GET /api/v1/projects/:slug/builds\": \"hosting\",\n \"POST /api/v1/projects/:slug/builds\": \"hosting\",\n \"POST /api/v1/projects/:slug/builds/:buildId/usage\": \"hosting\",\n \"PUT /api/v1/projects/:slug/builds/:buildId/zip\": \"hosting\",\n \"POST /api/v1/projects/:slug/builds/:buildId/dedup\": \"hosting\",\n \"POST /api/v1/projects/:slug/builds/:buildId/content\": \"hosting\",\n \"POST /api/v1/projects/:slug/builds/:buildId/manifest\": \"hosting\",\n \"GET /api/v1/projects/:slug/builds/:buildId\": \"hosting\",\n \"DELETE /api/v1/projects/:slug/builds/:buildId\": \"hosting\",\n \"GET /api/v1/projects/:slug/label-types\": \"hosting\",\n \"POST /api/v1/projects/:slug/label-types\": \"hosting\",\n \"DELETE /api/v1/projects/:slug/label-types/:key\": \"hosting\",\n \"PATCH /api/v1/projects/:slug/label-types/:key\": \"hosting\",\n \"GET /api/v1/projects/:slug/links\": \"hosting\",\n \"PUT /api/v1/projects/:slug/links\": \"hosting\",\n \"GET /api/v1/projects/:slug/members\": \"hosting\",\n \"POST /api/v1/projects/:slug/members\": \"hosting\",\n \"PATCH /api/v1/projects/:slug/members/:userId\": \"hosting\",\n \"DELETE /api/v1/projects/:slug/members/:userId\": \"hosting\",\n \"GET /api/v1/projects/:slug/group-mappings\": \"hosting\",\n \"POST /api/v1/projects/:slug/group-mappings\": \"hosting\",\n \"DELETE /api/v1/projects/:slug/group-mappings/:mappingId\": \"hosting\",\n \"GET /api/v1/projects/:slug/tokens\": \"hosting\",\n \"POST /api/v1/projects/:slug/tokens\": \"hosting\",\n \"DELETE /api/v1/projects/:slug/tokens/:tokenId\": \"hosting\",\n \"GET /api/v1/projects/:slug/webhooks\": \"hosting\",\n \"POST /api/v1/projects/:slug/webhooks\": \"hosting\",\n \"DELETE /api/v1/projects/:slug/webhooks/:webhookId\": \"hosting\",\n \"GET /api/v1/projects/:slug/notification-channels\": \"hosting\",\n \"POST /api/v1/projects/:slug/notification-channels\": \"hosting\",\n \"DELETE /api/v1/projects/:slug/notification-channels/:channelId\": \"hosting\",\n \"GET /api/v1/projects/:slug/notifications/me\": \"hosting\",\n \"PUT /api/v1/projects/:slug/notifications/me\": \"hosting\",\n \"DELETE /api/v1/projects/:slug/notifications/me\": \"hosting\",\n \"GET /api/v1/projects/:slug/notifications\": \"hosting\",\n \"GET /api/v1/admin/notification-channels\": \"hosting\",\n \"POST /api/v1/admin/notification-channels\": \"hosting\",\n \"DELETE /api/v1/admin/notification-channels/:channelId\": \"hosting\",\n \"GET /api/v1/health\": \"hosting\",\n \"POST /api/v1/health\": \"hosting\",\n \"POST /api/v1/admin/credentials/reencrypt\": \"hosting\",\n \"POST /api/v1/admin/purge\": \"hosting\",\n \"GET /api/v1/openapi.json\": \"hosting\",\n \"GET /api/v1/docs\": \"hosting\",\n // testing\n \"POST /api/v1/projects/:slug/builds/:buildId/affected\": \"testing\",\n \"POST /api/v1/projects/:slug/builds/:buildId/retry\": \"testing\",\n \"POST /api/v1/projects/:slug/builds/:buildId/cancel\": \"testing\",\n \"GET /api/v1/projects/:slug/builds/:buildId/snapshots\": \"testing\",\n \"GET /api/v1/projects/:slug/builds/:buildId/preview-token\": \"testing\",\n \"POST /api/v1/projects/:slug/builds/:buildId/snapshots/:snapshotId/approve\": \"testing\",\n \"POST /api/v1/projects/:slug/builds/:buildId/snapshots/:snapshotId/reject\": \"testing\",\n \"POST /api/v1/projects/:slug/builds/:buildId/approve-all\": \"testing\",\n \"POST /api/v1/projects/:slug/builds/:buildId/reject-all\": \"testing\",\n \"POST /api/v1/projects/:slug/builds/:buildId/stories/:storyId/modes/:modeKey/approve\": \"testing\",\n \"POST /api/v1/projects/:slug/builds/:buildId/stories/:storyId/modes/:modeKey/reject\": \"testing\",\n \"POST /api/v1/projects/:slug/builds/:buildId/rediff\": \"testing\",\n \"GET /api/v1/projects/:slug/builds/:buildId/attempts\": \"testing\",\n \"GET /api/v1/projects/:slug/builds/:buildId/attempts/:attemptNo\": \"testing\",\n \"GET /api/v1/projects/:slug/builds/:buildId/attempts/:attemptNo/logs\": \"testing\",\n \"GET /api/v1/projects/:slug/builds/:buildId/snapshots/:snapshotId/usage\": \"testing\",\n \"GET /api/v1/projects/:slug/builds/:buildId/snapshots/:snapshotId/image\": \"testing\",\n \"GET /api/v1/projects/:slug/builds/:buildId/snapshots/:snapshotId/diff\": \"testing\",\n \"GET /api/v1/projects/:slug/builds/:buildId/snapshots/:snapshotId/baseline\": \"testing\",\n \"GET /api/v1/projects/:slug/design/renders/:renderId\": \"testing\",\n \"GET /api/v1/projects/:slug/baselines/export\": \"testing\",\n \"POST /api/v1/projects/:slug/baselines/import\": \"testing\",\n \"GET /api/v1/projects/:slug/builds/:buildId/insights/latest\": \"testing\",\n \"GET /api/v1/projects/:slug/builds/:buildId/insights\": \"testing\",\n \"POST /api/v1/projects/:slug/builds/:buildId/insights\": \"testing\",\n \"GET /api/v1/projects/:slug/insights/health\": \"testing\",\n \"POST /api/v1/projects/:slug/insights/health\": \"testing\",\n // review\n \"GET /api/v1/projects/:slug/builds/:buildId/comments\": \"review\",\n \"POST /api/v1/projects/:slug/builds/:buildId/comments\": \"review\",\n \"POST /api/v1/projects/:slug/builds/:buildId/comments/:commentId/resolve\": \"review\",\n \"GET /api/v1/projects/:slug/builds/:buildId/reviews\": \"review\",\n \"POST /api/v1/projects/:slug/builds/:buildId/reviews\": \"review\",\n \"GET /api/v1/projects/:slug/builds/:buildId/changeset\": \"review\",\n};\n"],"mappings":";;;;;AAIA,MAAa,oBAA0D;CAErE,wBAAwB;CACxB,yBAAyB;CACzB,8BAA8B;CAC9B,gCAAgC;CAChC,iCAAiC;CACjC,qCAAqC;CACrC,sCAAsC;CACtC,qDAAqD;CACrD,kDAAkD;CAClD,qDAAqD;CACrD,uDAAuD;CACvD,wDAAwD;CACxD,8CAA8C;CAC9C,iDAAiD;CACjD,0CAA0C;CAC1C,2CAA2C;CAC3C,kDAAkD;CAClD,iDAAiD;CACjD,oCAAoC;CACpC,oCAAoC;CACpC,sCAAsC;CACtC,uCAAuC;CACvC,gDAAgD;CAChD,iDAAiD;CACjD,6CAA6C;CAC7C,8CAA8C;CAC9C,2DAA2D;CAC3D,qCAAqC;CACrC,sCAAsC;CACtC,iDAAiD;CACjD,uCAAuC;CACvC,wCAAwC;CACxC,qDAAqD;CACrD,oDAAoD;CACpD,qDAAqD;CACrD,kEAAkE;CAClE,+CAA+C;CAC/C,+CAA+C;CAC/C,kDAAkD;CAClD,4CAA4C;CAC5C,2CAA2C;CAC3C,4CAA4C;CAC5C,yDAAyD;CACzD,sBAAsB;CACtB,uBAAuB;CACvB,4CAA4C;CAC5C,4BAA4B;CAC5B,4BAA4B;CAC5B,oBAAoB;CAEpB,wDAAwD;CACxD,qDAAqD;CACrD,sDAAsD;CACtD,wDAAwD;CACxD,4DAA4D;CAC5D,6EAA6E;CAC7E,4EAA4E;CAC5E,2DAA2D;CAC3D,0DAA0D;CAC1D,uFAAuF;CACvF,sFAAsF;CACtF,sDAAsD;CACtD,uDAAuD;CACvD,kEAAkE;CAClE,uEAAuE;CACvE,0EAA0E;CAC1E,0EAA0E;CAC1E,yEAAyE;CACzE,6EAA6E;CAC7E,uDAAuD;CACvD,+CAA+C;CAC/C,gDAAgD;CAChD,8DAA8D;CAC9D,uDAAuD;CACvD,wDAAwD;CACxD,8CAA8C;CAC9C,+CAA+C;CAE/C,uDAAuD;CACvD,wDAAwD;CACxD,2EAA2E;CAC3E,sDAAsD;CACtD,uDAAuD;CACvD,wDAAwD;AAC1D"}
@@ -0,0 +1,37 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { API_ROUTE_CLASSES } from "./api-routes.mjs";
5
+ import { PAGE_ROUTE_CLASSES } from "./page-routes.mjs";
6
+ // src/routes/classification.ts
7
+ /**
8
+ * Route classification (ADR 0006, decision 8): every route the app registers declares whether it
9
+ * belongs to hosting, testing, review, or both. `classification.test.ts` fails on any registered
10
+ * route missing here and on any entry that no longer matches a route, so a new route must be
11
+ * classified in `api-routes.ts` or `page-routes.ts` in the same change.
12
+ *
13
+ * Today the table only describes the routes; nothing is gated by it yet (gating comes with the
14
+ * `testing` option work, which will apply it as middleware).
15
+ */
16
+ /** The full table, keyed by `"METHOD /hono-pattern"` exactly as `app.routes` reports it. */
17
+ const ROUTE_CLASSES = {
18
+ ...API_ROUTE_CLASSES,
19
+ ...PAGE_ROUTE_CLASSES
20
+ };
21
+ /**
22
+ * Route families whose individual patterns are not worth listing (content-hashed static assets).
23
+ * A rule applies to any method whose path starts with `prefix`.
24
+ */
25
+ const ROUTE_PREFIX_CLASSES = [{
26
+ prefix: "/assets/",
27
+ routeClass: "hosting"
28
+ }];
29
+ /** The class of a registered route, or `undefined` when it is unclassified. */
30
+ function classOfRoute(method, path) {
31
+ const exact = ROUTE_CLASSES[`${method} ${path}`];
32
+ if (exact !== void 0) return exact;
33
+ return ROUTE_PREFIX_CLASSES.find((rule) => path.startsWith(rule.prefix))?.routeClass;
34
+ }
35
+ export { ROUTE_CLASSES, ROUTE_PREFIX_CLASSES, classOfRoute };
36
+
37
+ //# sourceMappingURL=classification.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classification.mjs","names":[],"sources":["../../src/routes/classification.ts"],"sourcesContent":["/**\n * Route classification (ADR 0006, decision 8): every route the app registers declares whether it\n * belongs to hosting, testing, review, or both. `classification.test.ts` fails on any registered\n * route missing here and on any entry that no longer matches a route, so a new route must be\n * classified in `api-routes.ts` or `page-routes.ts` in the same change.\n *\n * Today the table only describes the routes; nothing is gated by it yet (gating comes with the\n * `testing` option work, which will apply it as middleware).\n */\nimport { API_ROUTE_CLASSES } from \"./api-routes.ts\";\nimport { PAGE_ROUTE_CLASSES } from \"./page-routes.ts\";\n\n/**\n * - `hosting`: available with and without `testing`.\n * - `testing`: 404 without `testing`.\n * - `review`: 404 when the project's review switch is off.\n * - `both`: present in both modes, with sections gated by `testing`.\n */\nexport type RouteClass = \"hosting\" | \"testing\" | \"review\" | \"both\";\n\nexport const ROUTE_CLASS_VALUES: readonly RouteClass[] = [\"hosting\", \"testing\", \"review\", \"both\"];\n\n/** The full table, keyed by `\"METHOD /hono-pattern\"` exactly as `app.routes` reports it. */\nexport const ROUTE_CLASSES: Readonly<Record<string, RouteClass>> = {\n ...API_ROUTE_CLASSES,\n ...PAGE_ROUTE_CLASSES,\n};\n\n/**\n * Route families whose individual patterns are not worth listing (content-hashed static assets).\n * A rule applies to any method whose path starts with `prefix`.\n */\nexport const ROUTE_PREFIX_CLASSES: readonly { prefix: string; routeClass: RouteClass }[] = [\n { prefix: \"/assets/\", routeClass: \"hosting\" },\n];\n\n/** The class of a registered route, or `undefined` when it is unclassified. */\nexport function classOfRoute(method: string, path: string): RouteClass | undefined {\n const exact = ROUTE_CLASSES[`${method} ${path}`];\n if (exact !== undefined) {\n return exact;\n }\n return ROUTE_PREFIX_CLASSES.find((rule) => path.startsWith(rule.prefix))?.routeClass;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAuBA,MAAa,gBAAsD;CACjE,GAAG;CACH,GAAG;AACL;;;;;AAMA,MAAa,uBAA8E,CACzF;CAAE,QAAQ;CAAY,YAAY;AAAU,CAC9C;;AAGA,SAAgB,aAAa,QAAgB,MAAsC;CACjF,MAAM,QAAQ,cAAc,GAAG,OAAO,GAAG;CACzC,IAAI,UAAU,KAAA,GACZ,OAAO;CAET,OAAO,qBAAqB,MAAM,SAAS,KAAK,WAAW,KAAK,MAAM,CAAC,CAAC,EAAE;AAC5E"}
@@ -0,0 +1,21 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { classOfRoute } from "./classification.mjs";
5
+ // src/routes/openapi-classes.ts
6
+ /** Tags every operation of an OpenAPI document with the class of its route (`x-storyshelf-class`). */
7
+ /** OpenAPI path templates (`{slug}`) as Hono patterns (`:slug`), the form the route table uses. */
8
+ function honoPattern(path) {
9
+ return path.replaceAll(/\{(?<name>[^}]+)\}/gu, ":$<name>");
10
+ }
11
+ /** `document` with `x-storyshelf-class` on each operation whose route the table classifies. */
12
+ function markRouteClasses(document) {
13
+ for (const [path, operations] of Object.entries(document.paths ?? {})) for (const [method, operation] of Object.entries(operations)) {
14
+ const routeClass = classOfRoute(method.toUpperCase(), honoPattern(path));
15
+ if (routeClass !== void 0 && typeof operation === "object" && operation !== null) operation["x-storyshelf-class"] = routeClass;
16
+ }
17
+ return document;
18
+ }
19
+ export { markRouteClasses };
20
+
21
+ //# sourceMappingURL=openapi-classes.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openapi-classes.mjs","names":[],"sources":["../../src/routes/openapi-classes.ts"],"sourcesContent":["/** Tags every operation of an OpenAPI document with the class of its route (`x-storyshelf-class`). */\nimport { classOfRoute } from \"./classification.ts\";\n\ninterface OpenApiLike {\n paths?: object | undefined;\n}\n\n/** OpenAPI path templates (`{slug}`) as Hono patterns (`:slug`), the form the route table uses. */\nfunction honoPattern(path: string): string {\n return path.replaceAll(/\\{(?<name>[^}]+)\\}/gu, \":$<name>\");\n}\n\n/** `document` with `x-storyshelf-class` on each operation whose route the table classifies. */\nexport function markRouteClasses<T extends OpenApiLike>(document: T): T {\n for (const [path, operations] of Object.entries(document.paths ?? {}) as [string, object][]) {\n for (const [method, operation] of Object.entries(operations)) {\n const routeClass = classOfRoute(method.toUpperCase(), honoPattern(path));\n if (routeClass !== undefined && typeof operation === \"object\" && operation !== null) {\n (operation as Record<string, unknown>)[\"x-storyshelf-class\"] = routeClass;\n }\n }\n }\n return document;\n}\n"],"mappings":";;;;;;;AAQA,SAAS,YAAY,MAAsB;CACzC,OAAO,KAAK,WAAW,wBAAwB,UAAU;AAC3D;;AAGA,SAAgB,iBAAwC,UAAgB;CACtE,KAAK,MAAM,CAAC,MAAM,eAAe,OAAO,QAAQ,SAAS,SAAS,CAAC,CAAC,GAClE,KAAK,MAAM,CAAC,QAAQ,cAAc,OAAO,QAAQ,UAAU,GAAG;EAC5D,MAAM,aAAa,aAAa,OAAO,YAAY,GAAG,YAAY,IAAI,CAAC;EACvE,IAAI,eAAe,KAAA,KAAa,OAAO,cAAc,YAAY,cAAc,MAC7E,UAAuC,wBAAwB;CAEnE;CAEF,OAAO;AACT"}
@@ -0,0 +1,103 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ // src/routes/page-routes.ts
5
+ /** HTML and auth routes, keyed by `METHOD /hono-pattern`. */
6
+ const PAGE_ROUTE_CLASSES = {
7
+ "GET /": "hosting",
8
+ "GET /projects": "hosting",
9
+ "GET /projects/new": "hosting",
10
+ "POST /projects/new": "hosting",
11
+ "GET /projects/:slug/labels": "hosting",
12
+ "GET /projects/:slug/labels/:key/*": "hosting",
13
+ "GET /projects/:slug/settings": "hosting",
14
+ "POST /projects/:slug/settings": "hosting",
15
+ "POST /projects/:slug/settings/review": "hosting",
16
+ "POST /projects/:slug/delete": "hosting",
17
+ "GET /projects/:slug/settings/labels": "hosting",
18
+ "POST /projects/:slug/settings/labels": "hosting",
19
+ "POST /projects/:slug/settings/labels/:key": "hosting",
20
+ "POST /projects/:slug/settings/labels/:key/delete": "hosting",
21
+ "GET /projects/:slug/settings/links": "hosting",
22
+ "POST /projects/:slug/settings/links": "hosting",
23
+ "POST /projects/:slug/settings/links/delete": "hosting",
24
+ "GET /projects/:slug/settings/design": "hosting",
25
+ "POST /projects/:slug/settings/design/files": "hosting",
26
+ "POST /projects/:slug/settings/design/files/:id/delete": "hosting",
27
+ "POST /projects/:slug/settings/design/components": "hosting",
28
+ "POST /projects/:slug/settings/design/components/:id/delete": "hosting",
29
+ "POST /projects/:slug/settings/design/:provider/token": "hosting",
30
+ "POST /projects/:slug/settings/design/:provider/token/delete": "hosting",
31
+ "GET /projects/:slug/settings/tokens": "hosting",
32
+ "POST /projects/:slug/settings/tokens": "hosting",
33
+ "POST /projects/:slug/settings/tokens/:tokenId/delete": "hosting",
34
+ "GET /projects/:slug/settings/webhooks": "hosting",
35
+ "POST /projects/:slug/settings/webhooks": "hosting",
36
+ "POST /projects/:slug/settings/webhooks/:webhookId/delete": "hosting",
37
+ "GET /projects/:slug/settings/notifications": "hosting",
38
+ "POST /projects/:slug/settings/notifications": "hosting",
39
+ "POST /projects/:slug/settings/notifications/:channelId/delete": "hosting",
40
+ "POST /projects/:slug/settings/notifications/me": "hosting",
41
+ "GET /projects/:slug/settings/members": "hosting",
42
+ "POST /projects/:slug/settings/members": "hosting",
43
+ "POST /projects/:slug/settings/members/:userId/remove": "hosting",
44
+ "POST /projects/:slug/settings/members/groups": "hosting",
45
+ "POST /projects/:slug/settings/members/groups/:mappingId/remove": "hosting",
46
+ "GET /admin": "hosting",
47
+ "POST /admin/credentials/reencrypt": "hosting",
48
+ "POST /admin/public-origin": "hosting",
49
+ "POST /admin/public-origin/report": "hosting",
50
+ "POST /admin/public-origin/clear": "hosting",
51
+ "GET /_": "hosting",
52
+ "GET /_/": "hosting",
53
+ "GET /_/:id": "hosting",
54
+ "GET /_/:id/*": "hosting",
55
+ "GET /projects/:slug/storybook": "hosting",
56
+ "GET /projects/:slug/storybook/:key/*": "hosting",
57
+ "GET /projects/:slug/storybook/build/:buildId/*": "hosting",
58
+ "GET /_s/:token/*": "testing",
59
+ "GET /auth/login": "hosting",
60
+ "GET /auth/engine/login": "hosting",
61
+ "POST /auth/engine/login": "hosting",
62
+ "GET /auth/engine/:providerId": "hosting",
63
+ "GET /auth/invites/:inviteId": "hosting",
64
+ "POST /auth/invites/:inviteId": "hosting",
65
+ "POST /auth/logout": "hosting",
66
+ "GET /.well-known/openid-configuration": "hosting",
67
+ "GET /.well-known/change-password": "hosting",
68
+ "GET /profile": "hosting",
69
+ "POST /profile": "hosting",
70
+ "POST /profile/password": "hosting",
71
+ "POST /profile/sessions/revoke": "hosting",
72
+ "POST /profile/sessions/revoke-others": "hosting",
73
+ "POST /profile/passkeys/:passkeyId/delete": "hosting",
74
+ "POST /profile/notifications": "hosting",
75
+ "GET /connections/:service/start": "hosting",
76
+ "GET /connections/:service/callback": "hosting",
77
+ "POST /connections/:service/disconnect": "hosting",
78
+ "ALL /api/auth/*": "hosting",
79
+ "GET /projects/:slug/jobs": "testing",
80
+ "GET /projects/:slug/builds/:buildId/diff": "testing",
81
+ "GET /projects/:slug/settings/tests": "testing",
82
+ "POST /projects/:slug/settings/tests": "testing",
83
+ "GET /projects/:slug/settings/capture": "testing",
84
+ "POST /projects/:slug/settings/capture": "testing",
85
+ "GET /projects/:slug/settings/ai": "testing",
86
+ "POST /projects/:slug/settings/ai": "testing",
87
+ "GET /admin/ai": "testing",
88
+ "GET /projects/:slug/insights/health/panel": "testing",
89
+ "POST /projects/:slug/insights/health/generate": "testing",
90
+ "GET /projects/:slug/builds/:buildId/insights/panel": "testing",
91
+ "POST /projects/:slug/builds/:buildId/insights/generate": "testing",
92
+ "POST /projects/:slug/builds/:buildId/comments": "review",
93
+ "POST /projects/:slug/builds/:buildId/comments/:commentId/resolve": "review",
94
+ "POST /projects/:slug/builds/:buildId/reviews": "review",
95
+ "GET /projects/:slug": "both",
96
+ "GET /projects/:slug/builds": "both",
97
+ "GET /projects/:slug/builds/:buildId": "both",
98
+ "GET /projects/:slug/library": "both",
99
+ "GET /projects/:slug/components/*": "both"
100
+ };
101
+ export { PAGE_ROUTE_CLASSES };
102
+
103
+ //# sourceMappingURL=page-routes.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-routes.mjs","names":[],"sources":["../../src/routes/page-routes.ts"],"sourcesContent":["/** Classes of the HTML pages, Storybook serving, auth flow and engine routes. */\nimport type { RouteClass } from \"./classification.ts\";\n\n/** HTML and auth routes, keyed by `METHOD /hono-pattern`. */\nexport const PAGE_ROUTE_CLASSES: Readonly<Record<string, RouteClass>> = {\n // hosting\n \"GET /\": \"hosting\",\n \"GET /projects\": \"hosting\",\n \"GET /projects/new\": \"hosting\",\n \"POST /projects/new\": \"hosting\",\n \"GET /projects/:slug/labels\": \"hosting\",\n \"GET /projects/:slug/labels/:key/*\": \"hosting\",\n \"GET /projects/:slug/settings\": \"hosting\",\n \"POST /projects/:slug/settings\": \"hosting\",\n \"POST /projects/:slug/settings/review\": \"hosting\",\n \"POST /projects/:slug/delete\": \"hosting\",\n \"GET /projects/:slug/settings/labels\": \"hosting\",\n \"POST /projects/:slug/settings/labels\": \"hosting\",\n \"POST /projects/:slug/settings/labels/:key\": \"hosting\",\n \"POST /projects/:slug/settings/labels/:key/delete\": \"hosting\",\n \"GET /projects/:slug/settings/links\": \"hosting\",\n \"POST /projects/:slug/settings/links\": \"hosting\",\n \"POST /projects/:slug/settings/links/delete\": \"hosting\",\n \"GET /projects/:slug/settings/design\": \"hosting\",\n \"POST /projects/:slug/settings/design/files\": \"hosting\",\n \"POST /projects/:slug/settings/design/files/:id/delete\": \"hosting\",\n \"POST /projects/:slug/settings/design/components\": \"hosting\",\n \"POST /projects/:slug/settings/design/components/:id/delete\": \"hosting\",\n \"POST /projects/:slug/settings/design/:provider/token\": \"hosting\",\n \"POST /projects/:slug/settings/design/:provider/token/delete\": \"hosting\",\n \"GET /projects/:slug/settings/tokens\": \"hosting\",\n \"POST /projects/:slug/settings/tokens\": \"hosting\",\n \"POST /projects/:slug/settings/tokens/:tokenId/delete\": \"hosting\",\n \"GET /projects/:slug/settings/webhooks\": \"hosting\",\n \"POST /projects/:slug/settings/webhooks\": \"hosting\",\n \"POST /projects/:slug/settings/webhooks/:webhookId/delete\": \"hosting\",\n \"GET /projects/:slug/settings/notifications\": \"hosting\",\n \"POST /projects/:slug/settings/notifications\": \"hosting\",\n \"POST /projects/:slug/settings/notifications/:channelId/delete\": \"hosting\",\n \"POST /projects/:slug/settings/notifications/me\": \"hosting\",\n \"GET /projects/:slug/settings/members\": \"hosting\",\n \"POST /projects/:slug/settings/members\": \"hosting\",\n \"POST /projects/:slug/settings/members/:userId/remove\": \"hosting\",\n \"POST /projects/:slug/settings/members/groups\": \"hosting\",\n \"POST /projects/:slug/settings/members/groups/:mappingId/remove\": \"hosting\",\n \"GET /admin\": \"hosting\",\n \"POST /admin/credentials/reencrypt\": \"hosting\",\n \"POST /admin/public-origin\": \"hosting\",\n \"POST /admin/public-origin/report\": \"hosting\",\n \"POST /admin/public-origin/clear\": \"hosting\",\n \"GET /_\": \"hosting\",\n \"GET /_/\": \"hosting\",\n \"GET /_/:id\": \"hosting\",\n \"GET /_/:id/*\": \"hosting\",\n \"GET /projects/:slug/storybook\": \"hosting\",\n \"GET /projects/:slug/storybook/:key/*\": \"hosting\",\n \"GET /projects/:slug/storybook/build/:buildId/*\": \"hosting\",\n \"GET /_s/:token/*\": \"testing\",\n \"GET /auth/login\": \"hosting\",\n \"GET /auth/engine/login\": \"hosting\",\n \"POST /auth/engine/login\": \"hosting\",\n \"GET /auth/engine/:providerId\": \"hosting\",\n \"GET /auth/invites/:inviteId\": \"hosting\",\n \"POST /auth/invites/:inviteId\": \"hosting\",\n \"POST /auth/logout\": \"hosting\",\n \"GET /.well-known/openid-configuration\": \"hosting\",\n \"GET /.well-known/change-password\": \"hosting\",\n \"GET /profile\": \"hosting\",\n \"POST /profile\": \"hosting\",\n \"POST /profile/password\": \"hosting\",\n \"POST /profile/sessions/revoke\": \"hosting\",\n \"POST /profile/sessions/revoke-others\": \"hosting\",\n \"POST /profile/passkeys/:passkeyId/delete\": \"hosting\",\n \"POST /profile/notifications\": \"hosting\",\n \"GET /connections/:service/start\": \"hosting\",\n \"GET /connections/:service/callback\": \"hosting\",\n \"POST /connections/:service/disconnect\": \"hosting\",\n \"ALL /api/auth/*\": \"hosting\",\n // testing\n \"GET /projects/:slug/jobs\": \"testing\",\n \"GET /projects/:slug/builds/:buildId/diff\": \"testing\",\n \"GET /projects/:slug/settings/tests\": \"testing\",\n \"POST /projects/:slug/settings/tests\": \"testing\",\n \"GET /projects/:slug/settings/capture\": \"testing\",\n \"POST /projects/:slug/settings/capture\": \"testing\",\n \"GET /projects/:slug/settings/ai\": \"testing\",\n \"POST /projects/:slug/settings/ai\": \"testing\",\n \"GET /admin/ai\": \"testing\",\n \"GET /projects/:slug/insights/health/panel\": \"testing\",\n \"POST /projects/:slug/insights/health/generate\": \"testing\",\n \"GET /projects/:slug/builds/:buildId/insights/panel\": \"testing\",\n \"POST /projects/:slug/builds/:buildId/insights/generate\": \"testing\",\n // review\n \"POST /projects/:slug/builds/:buildId/comments\": \"review\",\n \"POST /projects/:slug/builds/:buildId/comments/:commentId/resolve\": \"review\",\n \"POST /projects/:slug/builds/:buildId/reviews\": \"review\",\n // both\n \"GET /projects/:slug\": \"both\",\n \"GET /projects/:slug/builds\": \"both\",\n \"GET /projects/:slug/builds/:buildId\": \"both\",\n \"GET /projects/:slug/library\": \"both\",\n \"GET /projects/:slug/components/*\": \"both\",\n};\n"],"mappings":";;;;;AAIA,MAAa,qBAA2D;CAEtE,SAAS;CACT,iBAAiB;CACjB,qBAAqB;CACrB,sBAAsB;CACtB,8BAA8B;CAC9B,qCAAqC;CACrC,gCAAgC;CAChC,iCAAiC;CACjC,wCAAwC;CACxC,+BAA+B;CAC/B,uCAAuC;CACvC,wCAAwC;CACxC,6CAA6C;CAC7C,oDAAoD;CACpD,sCAAsC;CACtC,uCAAuC;CACvC,8CAA8C;CAC9C,uCAAuC;CACvC,8CAA8C;CAC9C,yDAAyD;CACzD,mDAAmD;CACnD,8DAA8D;CAC9D,wDAAwD;CACxD,+DAA+D;CAC/D,uCAAuC;CACvC,wCAAwC;CACxC,wDAAwD;CACxD,yCAAyC;CACzC,0CAA0C;CAC1C,4DAA4D;CAC5D,8CAA8C;CAC9C,+CAA+C;CAC/C,iEAAiE;CACjE,kDAAkD;CAClD,wCAAwC;CACxC,yCAAyC;CACzC,wDAAwD;CACxD,gDAAgD;CAChD,kEAAkE;CAClE,cAAc;CACd,qCAAqC;CACrC,6BAA6B;CAC7B,oCAAoC;CACpC,mCAAmC;CACnC,UAAU;CACV,WAAW;CACX,cAAc;CACd,gBAAgB;CAChB,iCAAiC;CACjC,wCAAwC;CACxC,kDAAkD;CAClD,oBAAoB;CACpB,mBAAmB;CACnB,0BAA0B;CAC1B,2BAA2B;CAC3B,gCAAgC;CAChC,+BAA+B;CAC/B,gCAAgC;CAChC,qBAAqB;CACrB,yCAAyC;CACzC,oCAAoC;CACpC,gBAAgB;CAChB,iBAAiB;CACjB,0BAA0B;CAC1B,iCAAiC;CACjC,wCAAwC;CACxC,4CAA4C;CAC5C,+BAA+B;CAC/B,mCAAmC;CACnC,sCAAsC;CACtC,yCAAyC;CACzC,mBAAmB;CAEnB,4BAA4B;CAC5B,4CAA4C;CAC5C,sCAAsC;CACtC,uCAAuC;CACvC,wCAAwC;CACxC,yCAAyC;CACzC,mCAAmC;CACnC,oCAAoC;CACpC,iBAAiB;CACjB,6CAA6C;CAC7C,iDAAiD;CACjD,sDAAsD;CACtD,0DAA0D;CAE1D,iDAAiD;CACjD,oEAAoE;CACpE,gDAAgD;CAEhD,uBAAuB;CACvB,8BAA8B;CAC9B,uCAAuC;CACvC,+BAA+B;CAC/B,oCAAoC;AACtC"}
package/dist/runtime.mjs CHANGED
@@ -2,11 +2,11 @@ import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
4
  import { validateConfig, validateUiConfig } from "@storyshelf/core/config";
5
+ import { createPublicOriginResolver } from "@storyshelf/core/models";
5
6
  import { createShelfLogger } from "@storyshelf/core/logger";
6
- //#region src/runtime.ts
7
+ // src/runtime.ts
7
8
  function addOptionalSnapshots(snap, options) {
8
- if (options.captureRunner) snap["captureRunner"] = options.captureRunner.metadata;
9
- if (options.captureQueue) snap["captureQueue"] = options.captureQueue.metadata;
9
+ if (options.testing?.runner) snap["captureRunner"] = options.testing.runner.metadata;
10
10
  }
11
11
  /**
12
12
  * Build a snapshot of adapter metadata for the `/api/v1/health` and docs.
@@ -14,7 +14,7 @@ function addOptionalSnapshots(snap, options) {
14
14
  * the running configuration at a glance.
15
15
  *
16
16
  * @param options - Router options containing the wired adapters
17
- * @returns Metadata map keyed by adapter category (e.g. `database`, `git:github`)
17
+ * @returns Metadata map keyed by adapter category (e.g. `database`, `notify:github`)
18
18
  */
19
19
  function buildAdapterSnapshot(options) {
20
20
  const snap = {
@@ -22,8 +22,8 @@ function buildAdapterSnapshot(options) {
22
22
  storage: options.storage.metadata
23
23
  };
24
24
  addOptionalSnapshots(snap, options);
25
- for (const p of options.gitHosts ?? []) snap[`git:${p.metadata.kind}`] = p.metadata;
26
- for (const n of options.notifiers ?? []) snap[`notify:${n.metadata.kind}`] = n.metadata;
25
+ for (const p of options.design ?? []) snap[`design:${p.metadata.kind}`] = p.metadata;
26
+ for (const n of options.notifications?.notifiers ?? []) snap[`notify:${n.metadata.kind}`] = n.metadata;
27
27
  return snap;
28
28
  }
29
29
  /** Validate config/ui and derive runtime singletons from options. */
@@ -32,21 +32,25 @@ function resolveRuntime(options) {
32
32
  const ui = options.ui ? validateUiConfig(options.ui) : {};
33
33
  const logger = options.logger ?? createShelfLogger();
34
34
  const authEnabled = options.auth !== void 0;
35
- const gitHosts = options.gitHosts ?? [];
36
- const notifiers = options.notifiers ?? [];
35
+ const design = options.design ?? [];
36
+ const notifiers = options.notifications?.notifiers ?? [];
37
+ const config = rawConfig.adapters ? rawConfig : {
38
+ ...rawConfig,
39
+ adapters: buildAdapterSnapshot(options)
40
+ };
37
41
  return {
38
- config: rawConfig.adapters ? rawConfig : {
39
- ...rawConfig,
40
- adapters: buildAdapterSnapshot(options)
41
- },
42
+ config,
42
43
  ui,
43
44
  logger,
44
45
  authEnabled,
45
- gitHosts,
46
- notifiers
46
+ design,
47
+ notifiers,
48
+ publicOrigin: createPublicOriginResolver({
49
+ db: options.database,
50
+ config
51
+ })
47
52
  };
48
53
  }
49
- //#endregion
50
54
  export { buildAdapterSnapshot, resolveRuntime };
51
55
 
52
56
  //# sourceMappingURL=runtime.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.mjs","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["import type { GitHostProvider } from \"@storyshelf/core/adapter/git-host\";\nimport type { AdapterMetadata, GitAdapterMetadata } from \"@storyshelf/core/adapter/metadata\";\nimport type { NotifierProvider } from \"@storyshelf/core/adapter/notifier\";\nimport type { ShelfConfig, ShelfOptions, UIConfig } from \"@storyshelf/core/config\";\nimport { validateConfig, validateUiConfig } from \"@storyshelf/core/config\";\nimport type { Logger } from \"@storyshelf/core/logger\";\nimport { createShelfLogger } from \"@storyshelf/core/logger\";\n\n/**\n * Resolved server runtime derived from {@link ShelfOptions}.\n * Holds the validated config, UI branding, structured logger, and\n * computed helpers like whether auth is enabled and which git hosts are wired.\n */\nexport interface ServerRuntime {\n config: ShelfConfig;\n ui: UIConfig;\n logger: Logger;\n authEnabled: boolean;\n gitHosts: GitHostProvider[];\n notifiers: NotifierProvider[];\n}\n\nfunction addOptionalSnapshots(\n snap: Record<string, AdapterMetadata | GitAdapterMetadata>,\n options: ShelfOptions,\n): void {\n if (options.captureRunner) {\n snap[\"captureRunner\"] = options.captureRunner.metadata;\n }\n if (options.captureQueue) {\n snap[\"captureQueue\"] = options.captureQueue.metadata;\n }\n}\n\n/**\n * Build a snapshot of adapter metadata for the `/api/v1/health` and docs.\n * Collects the name/version of every wired adapter so operators can verify\n * the running configuration at a glance.\n *\n * @param options - Router options containing the wired adapters\n * @returns Metadata map keyed by adapter category (e.g. `database`, `git:github`)\n */\nexport function buildAdapterSnapshot(\n options: ShelfOptions,\n): Record<string, AdapterMetadata | GitAdapterMetadata> {\n const snap: Record<string, AdapterMetadata | GitAdapterMetadata> = {\n database: options.database.metadata,\n storage: options.storage.metadata,\n };\n addOptionalSnapshots(snap, options);\n for (const p of options.gitHosts ?? []) {\n snap[`git:${p.metadata.kind}`] = p.metadata;\n }\n for (const n of options.notifiers ?? []) {\n snap[`notify:${n.metadata.kind}`] = n.metadata;\n }\n return snap;\n}\n\n/** Validate config/ui and derive runtime singletons from options. */\nexport function resolveRuntime(options: ShelfOptions): ServerRuntime {\n // eslint-disable-next-line typescript/no-unnecessary-type-assertion -- ShelfConfig lacks index signature\n const rawConfig = options.config\n ? validateConfig(options.config as unknown as Record<string, unknown>)\n : {};\n // eslint-disable-next-line typescript/no-unnecessary-type-assertion -- UIConfig lacks index signature\n const ui = options.ui ? validateUiConfig(options.ui as unknown as Record<string, unknown>) : {};\n const logger = options.logger ?? createShelfLogger();\n const authEnabled = options.auth !== undefined;\n const gitHosts = options.gitHosts ?? [];\n const notifiers = options.notifiers ?? [];\n // Adapter introspection — auto-populate config.adapters if not supplied\n const config: ShelfConfig = rawConfig.adapters\n ? rawConfig\n : {\n ...rawConfig,\n adapters: buildAdapterSnapshot(options),\n };\n return { config, ui, logger, authEnabled, gitHosts, notifiers };\n}\n"],"mappings":";;;;;;AAsBA,SAAS,qBACP,MACA,SACM;CACN,IAAI,QAAQ,eACV,KAAK,mBAAmB,QAAQ,cAAc;CAEhD,IAAI,QAAQ,cACV,KAAK,kBAAkB,QAAQ,aAAa;AAEhD;;;;;;;;;AAUA,SAAgB,qBACd,SACsD;CACtD,MAAM,OAA6D;EACjE,UAAU,QAAQ,SAAS;EAC3B,SAAS,QAAQ,QAAQ;CAC3B;CACA,qBAAqB,MAAM,OAAO;CAClC,KAAK,MAAM,KAAK,QAAQ,YAAY,CAAC,GACnC,KAAK,OAAO,EAAE,SAAS,UAAU,EAAE;CAErC,KAAK,MAAM,KAAK,QAAQ,aAAa,CAAC,GACpC,KAAK,UAAU,EAAE,SAAS,UAAU,EAAE;CAExC,OAAO;AACT;;AAGA,SAAgB,eAAe,SAAsC;CAEnE,MAAM,YAAY,QAAQ,SACtB,eAAe,QAAQ,MAA4C,IACnE,CAAC;CAEL,MAAM,KAAK,QAAQ,KAAK,iBAAiB,QAAQ,EAAwC,IAAI,CAAC;CAC9F,MAAM,SAAS,QAAQ,UAAU,kBAAkB;CACnD,MAAM,cAAc,QAAQ,SAAS,KAAA;CACrC,MAAM,WAAW,QAAQ,YAAY,CAAC;CACtC,MAAM,YAAY,QAAQ,aAAa,CAAC;CAQxC,OAAO;EAAE,QANmB,UAAU,WAClC,YACA;GACE,GAAG;GACH,UAAU,qBAAqB,OAAO;EACxC;EACa;EAAI;EAAQ;EAAa;EAAU;CAAU;AAChE"}
1
+ {"version":3,"file":"runtime.mjs","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["import type { DesignProvider } from \"@storyshelf/core/adapter/design\";\nimport type { AdapterMetadata } from \"@storyshelf/core/adapter/metadata\";\nimport type { NotifierProvider } from \"@storyshelf/core/adapter/notifier\";\nimport type { ShelfConfig, ShelfOptions, UIConfig } from \"@storyshelf/core/config\";\nimport { validateConfig, validateUiConfig } from \"@storyshelf/core/config\";\nimport type { Logger } from \"@storyshelf/core/logger\";\nimport { createShelfLogger } from \"@storyshelf/core/logger\";\nimport { createPublicOriginResolver, type PublicOriginResolver } from \"@storyshelf/core/models\";\n\n/**\n * Resolved server runtime derived from {@link ShelfOptions}.\n * Holds the validated config, UI branding, structured logger, and\n * computed helpers like whether auth is enabled and which notifiers are wired.\n */\nexport interface ServerRuntime {\n config: ShelfConfig;\n ui: UIConfig;\n logger: Logger;\n authEnabled: boolean;\n design: DesignProvider[];\n notifiers: NotifierProvider[];\n /** The public origin for links built in the background (ADR 0007, decision 6). */\n publicOrigin: PublicOriginResolver;\n}\n\nfunction addOptionalSnapshots(snap: Record<string, AdapterMetadata>, options: ShelfOptions): void {\n if (options.testing?.runner) {\n snap[\"captureRunner\"] = options.testing.runner.metadata;\n }\n}\n\n/**\n * Build a snapshot of adapter metadata for the `/api/v1/health` and docs.\n * Collects the name/version of every wired adapter so operators can verify\n * the running configuration at a glance.\n *\n * @param options - Router options containing the wired adapters\n * @returns Metadata map keyed by adapter category (e.g. `database`, `notify:github`)\n */\nexport function buildAdapterSnapshot(options: ShelfOptions): Record<string, AdapterMetadata> {\n const snap: Record<string, AdapterMetadata> = {\n database: options.database.metadata,\n storage: options.storage.metadata,\n };\n addOptionalSnapshots(snap, options);\n for (const p of options.design ?? []) {\n snap[`design:${p.metadata.kind}`] = p.metadata;\n }\n for (const n of options.notifications?.notifiers ?? []) {\n snap[`notify:${n.metadata.kind}`] = n.metadata;\n }\n return snap;\n}\n\n/** Validate config/ui and derive runtime singletons from options. */\nexport function resolveRuntime(options: ShelfOptions): ServerRuntime {\n // eslint-disable-next-line typescript/no-unnecessary-type-assertion -- ShelfConfig lacks index signature\n const rawConfig = options.config\n ? validateConfig(options.config as unknown as Record<string, unknown>)\n : {};\n // eslint-disable-next-line typescript/no-unnecessary-type-assertion -- UIConfig lacks index signature\n const ui = options.ui ? validateUiConfig(options.ui as unknown as Record<string, unknown>) : {};\n const logger = options.logger ?? createShelfLogger();\n const authEnabled = options.auth !== undefined;\n const design = options.design ?? [];\n const notifiers = options.notifications?.notifiers ?? [];\n // Adapter introspection — auto-populate config.adapters if not supplied\n const config: ShelfConfig = rawConfig.adapters\n ? rawConfig\n : {\n ...rawConfig,\n adapters: buildAdapterSnapshot(options),\n };\n const publicOrigin = createPublicOriginResolver({ db: options.database, config });\n return { config, ui, logger, authEnabled, design, notifiers, publicOrigin };\n}\n"],"mappings":";;;;;;;AAyBA,SAAS,qBAAqB,MAAuC,SAA6B;CAChG,IAAI,QAAQ,SAAS,QACnB,KAAK,mBAAmB,QAAQ,QAAQ,OAAO;AAEnD;;;;;;;;;AAUA,SAAgB,qBAAqB,SAAwD;CAC3F,MAAM,OAAwC;EAC5C,UAAU,QAAQ,SAAS;EAC3B,SAAS,QAAQ,QAAQ;CAC3B;CACA,qBAAqB,MAAM,OAAO;CAClC,KAAK,MAAM,KAAK,QAAQ,UAAU,CAAC,GACjC,KAAK,UAAU,EAAE,SAAS,UAAU,EAAE;CAExC,KAAK,MAAM,KAAK,QAAQ,eAAe,aAAa,CAAC,GACnD,KAAK,UAAU,EAAE,SAAS,UAAU,EAAE;CAExC,OAAO;AACT;;AAGA,SAAgB,eAAe,SAAsC;CAEnE,MAAM,YAAY,QAAQ,SACtB,eAAe,QAAQ,MAA4C,IACnE,CAAC;CAEL,MAAM,KAAK,QAAQ,KAAK,iBAAiB,QAAQ,EAAwC,IAAI,CAAC;CAC9F,MAAM,SAAS,QAAQ,UAAU,kBAAkB;CACnD,MAAM,cAAc,QAAQ,SAAS,KAAA;CACrC,MAAM,SAAS,QAAQ,UAAU,CAAC;CAClC,MAAM,YAAY,QAAQ,eAAe,aAAa,CAAC;CAEvD,MAAM,SAAsB,UAAU,WAClC,YACA;EACE,GAAG;EACH,UAAU,qBAAqB,OAAO;CACxC;CAEJ,OAAO;EAAE;EAAQ;EAAI;EAAQ;EAAa;EAAQ;EAAW,cADxC,2BAA2B;GAAE,IAAI,QAAQ;GAAU;EAAO,CACP;CAAE;AAC5E"}
@@ -0,0 +1,4 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ export { isServerlessHost } from "@storyshelf/core/config";
package/dist/store.mjs CHANGED
@@ -1,8 +1,9 @@
1
1
  import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
+ import { createCatalogLoader } from "@storyshelf/core/capture";
4
5
  import { AsyncLocalStorage } from "node:async_hooks";
5
- //#region src/store.ts
6
+ // src/store.ts
6
7
  const storage = new AsyncLocalStorage();
7
8
  /** Run a function with the given request store in scope. */
8
9
  function runWithStore(store, fn) {
@@ -14,7 +15,23 @@ function getStore() {
14
15
  if (!store) throw new Error("Store not available. Use runWithStore().");
15
16
  return store;
16
17
  }
17
- //#endregion
18
- export { getStore, runWithStore };
18
+ /**
19
+ * Whether this instance has `testing` (`options.testing` is set): it captures and compares builds,
20
+ * so pages layer snapshot data (screenshots, statuses, design links) onto what the catalog gives
21
+ * them. Without it the same pages render from the published Storybook alone, and the routes
22
+ * classified `testing` answer 404 (`requireTesting`).
23
+ */
24
+ function testingEnabled(store = getStore()) {
25
+ return store.testing;
26
+ }
27
+ /** The catalog loader pages read; hand-built stores without one get an uncached loader. */
28
+ function catalogOf(store = getStore()) {
29
+ return store.publish?.catalog ?? createCatalogLoader({
30
+ db: store.db,
31
+ storage: store.storage,
32
+ logger: store.logger
33
+ });
34
+ }
35
+ export { catalogOf, getStore, runWithStore, testingEnabled };
19
36
 
20
37
  //# sourceMappingURL=store.mjs.map