@storyshelf/core 0.3.2 → 0.5.3

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 (393) hide show
  1. package/README.md +38 -31
  2. package/dist/adapter/capture-queue.d.mts +29 -1
  3. package/dist/adapter/capture-runner.d.mts +18 -2
  4. package/dist/adapter/capture-runner.mjs +12 -1
  5. package/dist/adapter/capture-runner.mjs.map +1 -0
  6. package/dist/adapter/database.d.mts +67 -17
  7. package/dist/adapter/database.mjs +22 -55
  8. package/dist/adapter/database.mjs.map +1 -1
  9. package/dist/adapter/email-sender.d.mts +27 -0
  10. package/dist/adapter/email-sender.mjs +4 -0
  11. package/dist/adapter/metadata.d.mts +21 -15
  12. package/dist/adapter/notifier.d.mts +7 -0
  13. package/dist/adapter/notifier.mjs +6 -0
  14. package/dist/adapter/setup.d.mts +61 -0
  15. package/dist/adapter/setup.mjs +29 -0
  16. package/dist/adapter/setup.mjs.map +1 -0
  17. package/dist/adapter/webhook-events.d.mts +29 -0
  18. package/dist/adapter/webhook-events.mjs +83 -0
  19. package/dist/adapter/webhook-events.mjs.map +1 -0
  20. package/dist/adapters/notifier/events.d.mts +26 -0
  21. package/dist/adapters/notifier/events.mjs +66 -0
  22. package/dist/adapters/notifier/events.mjs.map +1 -0
  23. package/dist/adapters/notifier/format.d.mts +14 -0
  24. package/dist/adapters/notifier/format.mjs +96 -0
  25. package/dist/adapters/notifier/format.mjs.map +1 -0
  26. package/dist/adapters/notifier/provider.d.mts +32 -0
  27. package/dist/adapters/notifier/types.d.mts +56 -0
  28. package/dist/adapters/setup-runner.d.mts +23 -0
  29. package/dist/adapters/setup-runner.mjs +149 -0
  30. package/dist/adapters/setup-runner.mjs.map +1 -0
  31. package/dist/adapters/validate.d.mts +30 -0
  32. package/dist/adapters/validate.mjs +313 -0
  33. package/dist/adapters/validate.mjs.map +1 -0
  34. package/dist/auth.d.mts +94 -0
  35. package/dist/auth.mjs +4 -0
  36. package/dist/brand-packs.d.mts +16 -0
  37. package/dist/brand-packs.mjs +130 -0
  38. package/dist/brand-packs.mjs.map +1 -0
  39. package/dist/capture/adapter.d.mts +51 -1
  40. package/dist/capture/adapter.mjs.map +1 -1
  41. package/dist/capture/affected.d.mts +16 -0
  42. package/dist/capture/affected.mjs +64 -0
  43. package/dist/capture/affected.mjs.map +1 -0
  44. package/dist/capture/diff-record.mjs +30 -0
  45. package/dist/capture/diff-record.mjs.map +1 -0
  46. package/dist/capture/dispatch.d.mts +36 -0
  47. package/dist/capture/dispatch.mjs +88 -31
  48. package/dist/capture/dispatch.mjs.map +1 -1
  49. package/dist/capture/guards.mjs +31 -0
  50. package/dist/capture/guards.mjs.map +1 -0
  51. package/dist/capture/orchestrator.d.mts +41 -6
  52. package/dist/capture/orchestrator.mjs +151 -28
  53. package/dist/capture/orchestrator.mjs.map +1 -1
  54. package/dist/capture/pipeline.d.mts +30 -16
  55. package/dist/capture/pipeline.mjs +143 -39
  56. package/dist/capture/pipeline.mjs.map +1 -1
  57. package/dist/capture/recovery.d.mts +21 -0
  58. package/dist/capture/recovery.mjs +83 -0
  59. package/dist/capture/recovery.mjs.map +1 -0
  60. package/dist/capture/rediff.d.mts +35 -0
  61. package/dist/capture/rediff.mjs +77 -0
  62. package/dist/capture/rediff.mjs.map +1 -0
  63. package/dist/capture/sizing.d.mts +58 -0
  64. package/dist/capture/sizing.mjs +119 -0
  65. package/dist/capture/sizing.mjs.map +1 -0
  66. package/dist/capture/skip-checks.mjs +3 -3
  67. package/dist/capture/skip-checks.mjs.map +1 -1
  68. package/dist/capture/statics.d.mts +38 -0
  69. package/dist/capture/statics.mjs +38 -4
  70. package/dist/capture/statics.mjs.map +1 -1
  71. package/dist/capture/status-fanout.mjs +7 -2
  72. package/dist/capture/status-fanout.mjs.map +1 -1
  73. package/dist/capture/storybook.d.mts +31 -2
  74. package/dist/capture/storybook.mjs +77 -2
  75. package/dist/capture/storybook.mjs.map +1 -1
  76. package/dist/capture.d.mts +10 -4
  77. package/dist/capture.mjs +7 -2
  78. package/dist/config.d.mts +121 -4
  79. package/dist/config.mjs +55 -8
  80. package/dist/config.mjs.map +1 -1
  81. package/dist/index.d.mts +5 -56
  82. package/dist/index.mjs +4 -284
  83. package/dist/logger.d.mts +26 -17
  84. package/dist/logger.mjs +10 -5
  85. package/dist/logger.mjs.map +1 -1
  86. package/dist/models/baseline-status.d.mts +29 -0
  87. package/dist/models/baseline-status.mjs +26 -0
  88. package/dist/models/baseline-status.mjs.map +1 -0
  89. package/dist/models/baseline.d.mts +33 -0
  90. package/dist/models/baseline.mjs +35 -13
  91. package/dist/models/baseline.mjs.map +1 -1
  92. package/dist/models/build.d.mts +87 -0
  93. package/dist/models/build.mjs +83 -35
  94. package/dist/models/build.mjs.map +1 -1
  95. package/dist/models/capture-attempt.d.mts +40 -0
  96. package/dist/models/capture-attempt.mjs +85 -0
  97. package/dist/models/capture-attempt.mjs.map +1 -0
  98. package/dist/models/capture-log.d.mts +21 -0
  99. package/dist/models/capture-log.mjs +44 -0
  100. package/dist/models/capture-log.mjs.map +1 -0
  101. package/dist/models/comment.d.mts +29 -0
  102. package/dist/models/comment.mjs +11 -8
  103. package/dist/models/comment.mjs.map +1 -1
  104. package/dist/models/content-ref.d.mts +21 -0
  105. package/dist/models/content-ref.mjs +49 -0
  106. package/dist/models/content-ref.mjs.map +1 -0
  107. package/dist/models/credentials.d.mts +36 -0
  108. package/dist/models/credentials.mjs +103 -0
  109. package/dist/models/credentials.mjs.map +1 -0
  110. package/dist/models/label.d.mts +58 -0
  111. package/dist/models/label.mjs +32 -27
  112. package/dist/models/label.mjs.map +1 -1
  113. package/dist/models/member.d.mts +34 -0
  114. package/dist/models/member.mjs +20 -11
  115. package/dist/models/member.mjs.map +1 -1
  116. package/dist/models/notification-channel.d.mts +52 -0
  117. package/dist/models/notification-channel.mjs +93 -0
  118. package/dist/models/notification-channel.mjs.map +1 -0
  119. package/dist/models/notification-subscription.d.mts +44 -0
  120. package/dist/models/notification-subscription.mjs +89 -0
  121. package/dist/models/notification-subscription.mjs.map +1 -0
  122. package/dist/models/project-group-mapping.d.mts +30 -0
  123. package/dist/models/project-group-mapping.mjs +46 -0
  124. package/dist/models/project-group-mapping.mjs.map +1 -0
  125. package/dist/models/project.d.mts +54 -0
  126. package/dist/models/project.mjs +15 -11
  127. package/dist/models/project.mjs.map +1 -1
  128. package/dist/models/snapshot.d.mts +58 -0
  129. package/dist/models/snapshot.mjs +13 -7
  130. package/dist/models/snapshot.mjs.map +1 -1
  131. package/dist/models/status-config.d.mts +38 -0
  132. package/dist/models/status-config.mjs +12 -11
  133. package/dist/models/status-config.mjs.map +1 -1
  134. package/dist/models/token.d.mts +44 -0
  135. package/dist/models/token.mjs +18 -15
  136. package/dist/models/token.mjs.map +1 -1
  137. package/dist/models/user.d.mts +42 -0
  138. package/dist/models/user.mjs +65 -0
  139. package/dist/models/user.mjs.map +1 -0
  140. package/dist/models/webhook.d.mts +50 -0
  141. package/dist/models/webhook.mjs +12 -10
  142. package/dist/models/webhook.mjs.map +1 -1
  143. package/dist/models.d.mts +22 -0
  144. package/dist/models.mjs +23 -0
  145. package/dist/paths.mjs +29 -0
  146. package/dist/paths.mjs.map +1 -1
  147. package/dist/retention.d.mts +45 -0
  148. package/dist/retention.mjs +145 -0
  149. package/dist/retention.mjs.map +1 -0
  150. package/dist/schema/baseline.d.mts +1 -0
  151. package/dist/schema/build.d.mts +8 -0
  152. package/dist/schema/capture-attempt.d.mts +38 -0
  153. package/dist/schema/comment.d.mts +1 -1
  154. package/dist/schema/content-ref.d.mts +13 -0
  155. package/dist/schema/member.d.mts +2 -0
  156. package/dist/schema/notification.d.mts +35 -0
  157. package/dist/schema/project-group-mapping.d.mts +15 -0
  158. package/dist/schema/project.d.mts +4 -0
  159. package/dist/schema/snapshot.d.mts +7 -0
  160. package/dist/schema/token.d.mts +2 -0
  161. package/dist/schema/user.d.mts +11 -1
  162. package/dist/schema.d.mts +9 -46
  163. package/dist/schema.mjs +1 -55
  164. package/dist/test-helpers/create-project.d.mts +15 -0
  165. package/dist/test-helpers/create-project.mjs +28 -0
  166. package/dist/test-helpers/create-project.mjs.map +1 -0
  167. package/dist/test-helpers/database-contract.d.mts +13 -0
  168. package/dist/test-helpers/database-contract.mjs +58 -0
  169. package/dist/test-helpers/database-contract.mjs.map +1 -0
  170. package/dist/test-helpers/fake-adapters.d.mts +14 -0
  171. package/dist/test-helpers/fake-adapters.mjs +20 -0
  172. package/dist/test-helpers/fake-adapters.mjs.map +1 -0
  173. package/dist/test-helpers/fake-database.d.mts +11 -0
  174. package/dist/test-helpers/fake-database.mjs +104 -0
  175. package/dist/test-helpers/fake-database.mjs.map +1 -0
  176. package/dist/test-helpers/fake-storage.d.mts +14 -0
  177. package/dist/test-helpers/fake-storage.mjs +49 -0
  178. package/dist/test-helpers/fake-storage.mjs.map +1 -0
  179. package/dist/test-helpers/fake-tables.mjs +276 -0
  180. package/dist/test-helpers/fake-tables.mjs.map +1 -0
  181. package/dist/test-helpers/git-contract.d.mts +11 -0
  182. package/dist/test-helpers/git-contract.mjs +34 -0
  183. package/dist/test-helpers/git-contract.mjs.map +1 -0
  184. package/dist/test-helpers/notifier-contract.d.mts +11 -0
  185. package/dist/test-helpers/notifier-contract.mjs +34 -0
  186. package/dist/test-helpers/notifier-contract.mjs.map +1 -0
  187. package/dist/test-helpers/queue-contract.d.mts +11 -0
  188. package/dist/test-helpers/queue-contract.mjs +64 -0
  189. package/dist/test-helpers/queue-contract.mjs.map +1 -0
  190. package/dist/test-helpers/runner-contract.d.mts +11 -0
  191. package/dist/test-helpers/runner-contract.mjs +32 -0
  192. package/dist/test-helpers/runner-contract.mjs.map +1 -0
  193. package/dist/test-helpers/sql-chunks.mjs +138 -0
  194. package/dist/test-helpers/sql-chunks.mjs.map +1 -0
  195. package/dist/test-helpers/storage-contract.d.mts +11 -0
  196. package/dist/test-helpers/storage-contract.mjs +87 -0
  197. package/dist/test-helpers/storage-contract.mjs.map +1 -0
  198. package/dist/test-helpers.d.mts +13 -0
  199. package/dist/test-helpers.mjs +14 -0
  200. package/dist/tracing.mjs +63 -0
  201. package/dist/tracing.mjs.map +1 -0
  202. package/dist/types.d.mts +38 -5
  203. package/dist/types.mjs +18 -5
  204. package/dist/types.mjs.map +1 -1
  205. package/dist/urls.d.mts +12 -1
  206. package/dist/urls.mjs +22 -3
  207. package/dist/urls.mjs.map +1 -1
  208. package/dist/utils/encrypt.d.mts +48 -0
  209. package/dist/utils/encrypt.mjs +67 -13
  210. package/dist/utils/encrypt.mjs.map +1 -1
  211. package/dist/utils/hash.d.mts +17 -0
  212. package/dist/utils/hash.mjs +8 -2
  213. package/dist/utils/hash.mjs.map +1 -1
  214. package/dist/utils/http.d.mts +58 -0
  215. package/dist/utils/http.mjs +147 -0
  216. package/dist/utils/http.mjs.map +1 -0
  217. package/dist/utils/mime.d.mts +9 -0
  218. package/dist/utils/mime.mjs +33 -0
  219. package/dist/utils/mime.mjs.map +1 -0
  220. package/dist/utils/path-security.d.mts +12 -0
  221. package/dist/utils/path-security.mjs +24 -0
  222. package/dist/utils/path-security.mjs.map +1 -0
  223. package/dist/utils/redact.d.mts +17 -0
  224. package/dist/utils/redact.mjs +42 -0
  225. package/dist/utils/redact.mjs.map +1 -0
  226. package/dist/utils/timing.d.mts +19 -0
  227. package/dist/utils/timing.mjs +46 -0
  228. package/dist/utils/timing.mjs.map +1 -0
  229. package/dist/utils/ulid.d.mts +10 -0
  230. package/dist/utils/ulid.mjs +8 -8
  231. package/dist/utils/ulid.mjs.map +1 -1
  232. package/dist/utils.d.mts +12 -0
  233. package/dist/utils.mjs +13 -0
  234. package/package.json +69 -28
  235. package/dist/adapter/auth.d.mts +0 -50
  236. package/dist/adapter/auth.mjs +0 -10
  237. package/dist/adapter/auth.mjs.map +0 -1
  238. package/dist/adapter/init.d.mts +0 -58
  239. package/dist/adapter/init.mjs +0 -93
  240. package/dist/adapter/init.mjs.map +0 -1
  241. package/dist/adapters/webhook-events.mjs +0 -55
  242. package/dist/adapters/webhook-events.mjs.map +0 -1
  243. package/dist/ddl.d.mts +0 -8
  244. package/dist/ddl.mjs +0 -158
  245. package/dist/ddl.mjs.map +0 -1
  246. package/dist/index.mjs.map +0 -1
  247. package/dist/middleware/auth-gate.mjs +0 -36
  248. package/dist/middleware/auth-gate.mjs.map +0 -1
  249. package/dist/middleware/csrf.mjs +0 -40
  250. package/dist/middleware/csrf.mjs.map +0 -1
  251. package/dist/middleware/rate-limit.mjs +0 -39
  252. package/dist/middleware/rate-limit.mjs.map +0 -1
  253. package/dist/middleware/request-log.mjs +0 -28
  254. package/dist/middleware/request-log.mjs.map +0 -1
  255. package/dist/middleware/store-scope.mjs +0 -29
  256. package/dist/middleware/store-scope.mjs.map +0 -1
  257. package/dist/pages/build-detail.mjs +0 -339
  258. package/dist/pages/build-detail.mjs.map +0 -1
  259. package/dist/pages/build-diff-comments.mjs +0 -113
  260. package/dist/pages/build-diff-comments.mjs.map +0 -1
  261. package/dist/pages/build-diff-header.mjs +0 -163
  262. package/dist/pages/build-diff-header.mjs.map +0 -1
  263. package/dist/pages/build-diff-nav.mjs +0 -66
  264. package/dist/pages/build-diff-nav.mjs.map +0 -1
  265. package/dist/pages/build-diff-viewer.mjs +0 -197
  266. package/dist/pages/build-diff-viewer.mjs.map +0 -1
  267. package/dist/pages/build-diff.mjs +0 -90
  268. package/dist/pages/build-diff.mjs.map +0 -1
  269. package/dist/pages/compute-jobs.mjs +0 -198
  270. package/dist/pages/compute-jobs.mjs.map +0 -1
  271. package/dist/pages/label-detail.mjs +0 -228
  272. package/dist/pages/label-detail.mjs.map +0 -1
  273. package/dist/pages/login.mjs +0 -78
  274. package/dist/pages/login.mjs.map +0 -1
  275. package/dist/pages/project-builds.mjs +0 -231
  276. package/dist/pages/project-builds.mjs.map +0 -1
  277. package/dist/pages/project-create.mjs +0 -169
  278. package/dist/pages/project-create.mjs.map +0 -1
  279. package/dist/pages/project-settings.mjs +0 -102
  280. package/dist/pages/project-settings.mjs.map +0 -1
  281. package/dist/pages/projects.mjs +0 -184
  282. package/dist/pages/projects.mjs.map +0 -1
  283. package/dist/pages/root.mjs +0 -94
  284. package/dist/pages/root.mjs.map +0 -1
  285. package/dist/pages/settings-general.mjs +0 -192
  286. package/dist/pages/settings-general.mjs.map +0 -1
  287. package/dist/pages/settings-labels.mjs +0 -150
  288. package/dist/pages/settings-labels.mjs.map +0 -1
  289. package/dist/pages/settings-members.mjs +0 -125
  290. package/dist/pages/settings-members.mjs.map +0 -1
  291. package/dist/pages/settings-status.mjs +0 -152
  292. package/dist/pages/settings-status.mjs.map +0 -1
  293. package/dist/pages/settings-tests.mjs +0 -149
  294. package/dist/pages/settings-tests.mjs.map +0 -1
  295. package/dist/pages/settings-tokens.mjs +0 -96
  296. package/dist/pages/settings-tokens.mjs.map +0 -1
  297. package/dist/pages/settings-webhooks.mjs +0 -150
  298. package/dist/pages/settings-webhooks.mjs.map +0 -1
  299. package/dist/pages/storybook.mjs +0 -96
  300. package/dist/pages/storybook.mjs.map +0 -1
  301. package/dist/retention/purge.mjs +0 -70
  302. package/dist/retention/purge.mjs.map +0 -1
  303. package/dist/routers/admin.mjs +0 -42
  304. package/dist/routers/admin.mjs.map +0 -1
  305. package/dist/routers/assets.mjs +0 -25
  306. package/dist/routers/assets.mjs.map +0 -1
  307. package/dist/routers/auth.mjs +0 -78
  308. package/dist/routers/auth.mjs.map +0 -1
  309. package/dist/routers/builds.handlers.mjs +0 -184
  310. package/dist/routers/builds.handlers.mjs.map +0 -1
  311. package/dist/routers/builds.mjs +0 -185
  312. package/dist/routers/builds.mjs.map +0 -1
  313. package/dist/routers/comments.mjs +0 -90
  314. package/dist/routers/comments.mjs.map +0 -1
  315. package/dist/routers/health.mjs +0 -137
  316. package/dist/routers/health.mjs.map +0 -1
  317. package/dist/routers/helpers.mjs +0 -82
  318. package/dist/routers/helpers.mjs.map +0 -1
  319. package/dist/routers/htmx.mjs +0 -20
  320. package/dist/routers/htmx.mjs.map +0 -1
  321. package/dist/routers/labels.mjs +0 -110
  322. package/dist/routers/labels.mjs.map +0 -1
  323. package/dist/routers/media.mjs +0 -55
  324. package/dist/routers/media.mjs.map +0 -1
  325. package/dist/routers/members.mjs +0 -102
  326. package/dist/routers/members.mjs.map +0 -1
  327. package/dist/routers/projects.mjs +0 -122
  328. package/dist/routers/projects.mjs.map +0 -1
  329. package/dist/routers/schemas.mjs +0 -224
  330. package/dist/routers/schemas.mjs.map +0 -1
  331. package/dist/routers/settings-general.mjs +0 -95
  332. package/dist/routers/settings-general.mjs.map +0 -1
  333. package/dist/routers/settings-labels.mjs +0 -49
  334. package/dist/routers/settings-labels.mjs.map +0 -1
  335. package/dist/routers/settings-members.mjs +0 -30
  336. package/dist/routers/settings-members.mjs.map +0 -1
  337. package/dist/routers/settings-status.mjs +0 -73
  338. package/dist/routers/settings-status.mjs.map +0 -1
  339. package/dist/routers/settings-tokens.mjs +0 -40
  340. package/dist/routers/settings-tokens.mjs.map +0 -1
  341. package/dist/routers/settings-webhooks.mjs +0 -63
  342. package/dist/routers/settings-webhooks.mjs.map +0 -1
  343. package/dist/routers/settings.handlers.mjs +0 -93
  344. package/dist/routers/settings.handlers.mjs.map +0 -1
  345. package/dist/routers/settings.mjs +0 -23
  346. package/dist/routers/settings.mjs.map +0 -1
  347. package/dist/routers/snapshots.mjs +0 -144
  348. package/dist/routers/snapshots.mjs.map +0 -1
  349. package/dist/routers/status-configs.mjs +0 -101
  350. package/dist/routers/status-configs.mjs.map +0 -1
  351. package/dist/routers/storybook.mjs +0 -120
  352. package/dist/routers/storybook.mjs.map +0 -1
  353. package/dist/routers/tokens.mjs +0 -81
  354. package/dist/routers/tokens.mjs.map +0 -1
  355. package/dist/routers/ui.mjs +0 -165
  356. package/dist/routers/ui.mjs.map +0 -1
  357. package/dist/routers/webhooks.mjs +0 -90
  358. package/dist/routers/webhooks.mjs.map +0 -1
  359. package/dist/schema/baseline.mjs +0 -22
  360. package/dist/schema/baseline.mjs.map +0 -1
  361. package/dist/schema/build.mjs +0 -29
  362. package/dist/schema/build.mjs.map +0 -1
  363. package/dist/schema/comment.mjs +0 -26
  364. package/dist/schema/comment.mjs.map +0 -1
  365. package/dist/schema/label.mjs +0 -30
  366. package/dist/schema/label.mjs.map +0 -1
  367. package/dist/schema/member.mjs +0 -19
  368. package/dist/schema/member.mjs.map +0 -1
  369. package/dist/schema/project.mjs +0 -25
  370. package/dist/schema/project.mjs.map +0 -1
  371. package/dist/schema/snapshot.mjs +0 -34
  372. package/dist/schema/snapshot.mjs.map +0 -1
  373. package/dist/schema/status-config.mjs +0 -20
  374. package/dist/schema/status-config.mjs.map +0 -1
  375. package/dist/schema/token.mjs +0 -19
  376. package/dist/schema/token.mjs.map +0 -1
  377. package/dist/schema/user.mjs +0 -19
  378. package/dist/schema/user.mjs.map +0 -1
  379. package/dist/schema/webhook.mjs +0 -20
  380. package/dist/schema/webhook.mjs.map +0 -1
  381. package/dist/schema.mjs.map +0 -1
  382. package/dist/store.mjs +0 -20
  383. package/dist/store.mjs.map +0 -1
  384. package/dist/ui/document.mjs +0 -348
  385. package/dist/ui/document.mjs.map +0 -1
  386. package/dist/ui/feedback.mjs +0 -24
  387. package/dist/ui/feedback.mjs.map +0 -1
  388. package/dist/ui/forms.mjs +0 -117
  389. package/dist/ui/forms.mjs.map +0 -1
  390. package/dist/ui/styles.mjs +0 -174
  391. package/dist/ui/styles.mjs.map +0 -1
  392. package/dist/ui/theme.mjs +0 -44
  393. package/dist/ui/theme.mjs.map +0 -1
@@ -0,0 +1,94 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { AuthUser } from "./types.mjs";
4
+ //#region src/auth.d.ts
5
+ /** Login widget kinds in display order (the shelf plugin contract). */
6
+ type EngineLoginMethodKind = "password" | "oauth" | "passkey" | "sso";
7
+ /**
8
+ * One login widget on the descriptor-driven login page.
9
+ *
10
+ * Plugin contract: `password` posts the credential form to
11
+ * `/auth/engine/login`; `oauth`/`sso` link at `/auth/engine/:id` (the app
12
+ * starts the provider flow server-side); `passkey` is JS-driven on the page
13
+ * (its `url` is an unused fallback). Method ids must be unique across all
14
+ * providers (checked at boot).
15
+ */
16
+ interface EngineLoginMethod {
17
+ kind: EngineLoginMethodKind;
18
+ id: string;
19
+ label: string;
20
+ }
21
+ /** One device session for the profile device list. */
22
+ interface EngineSessionInfo {
23
+ id: string;
24
+ token: string;
25
+ ipAddress: string | null;
26
+ userAgent: string | null;
27
+ createdAt: string;
28
+ expiresAt: string;
29
+ }
30
+ /** One registered passkey for the profile page. */
31
+ interface EnginePasskeyInfo {
32
+ id: string;
33
+ name: string | null;
34
+ deviceType: string;
35
+ backedUp: boolean;
36
+ transports: string | null;
37
+ aaguid: string | null;
38
+ createdAt: string;
39
+ }
40
+ /** Auth singleton: the shelf authentication surface (not an adapter). */
41
+ interface Auth {
42
+ /** Raw engine handler (mount at `/api/auth/*`). */
43
+ handler: (request: Request) => Response | Promise<Response>;
44
+ /** Login methods in display order (drives the login page). */
45
+ loginMethods: () => EngineLoginMethod[];
46
+ /** One-shot boot validation (secret strength); the app calls it directly. */
47
+ setup: () => Promise<void>;
48
+ /** Stage a shelf user and mint a single-use invite token. */
49
+ issueInvite: (input: {
50
+ email: string;
51
+ name: string;
52
+ role: AuthUser["role"];
53
+ }) => Promise<{
54
+ inviteId: string;
55
+ token: string;
56
+ expiresAt: string;
57
+ }>;
58
+ /** Check an invite token without consuming it (drives the accept page). */
59
+ verifyInvite: (input: {
60
+ inviteId: string;
61
+ token: string;
62
+ }) => Promise<{
63
+ email: string;
64
+ name: string;
65
+ }>;
66
+ /** Consume an invite: set the engine credential and return the shelf user. */
67
+ acceptInvite: (input: {
68
+ inviteId: string;
69
+ token: string;
70
+ password: string;
71
+ }) => Promise<AuthUser>;
72
+ /** Whether WebAuthn passkeys are enabled (drives the profile section). */
73
+ passkeysEnabled: () => boolean;
74
+ /** Active device sessions for the profile page (newest first). */
75
+ listSessions: (userId: string) => Promise<EngineSessionInfo[]>;
76
+ /** Registered passkeys for the profile page (oldest first). */
77
+ listPasskeys: (userId: string) => Promise<EnginePasskeyInfo[]>;
78
+ /** Whether the user has a local credential (shows the password form). */
79
+ hasPassword: (userId: string) => Promise<boolean>;
80
+ /**
81
+ * Disable or re-enable a user: flips the shelf flag and eagerly revokes
82
+ * every engine session (the per-request check is the backstop).
83
+ */
84
+ setDisabled: (userId: string, disabled: boolean) => Promise<void>;
85
+ /** Resolve the session user from a request (null when anonymous). */
86
+ check: (request: Request) => Promise<AuthUser | null>;
87
+ /** Forbidden by design: sessions mint at engine endpoints, never here. */
88
+ createSession: (user: AuthUser) => Promise<string>;
89
+ /** Revoke one session by token (accepts the signed cookie value). */
90
+ destroySession: (sessionToken: string) => Promise<void>;
91
+ }
92
+ //#endregion
93
+ export { Auth, EngineLoginMethod, EngineLoginMethodKind, EnginePasskeyInfo, EngineSessionInfo };
94
+ //# sourceMappingURL=auth.d.mts.map
package/dist/auth.mjs ADDED
@@ -0,0 +1,4 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ export {};
@@ -0,0 +1,16 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { BrandTheme } from "./config.mjs";
4
+ //#region src/brand-packs.d.ts
5
+ /** One named light/dark theme pair. */
6
+ interface BrandPack {
7
+ light: BrandTheme;
8
+ dark: BrandTheme;
9
+ }
10
+ /** Curated brand packs keyed by name (`storyshelf` is the default look). */
11
+ declare const brandPacks: Record<string, BrandPack>;
12
+ /** Look up a brand pack by name (undefined for unknown names). */
13
+ declare function brandPack(name: string): BrandPack | undefined;
14
+ //#endregion
15
+ export { BrandPack, brandPack, brandPacks };
16
+ //# sourceMappingURL=brand-packs.d.mts.map
@@ -0,0 +1,130 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ /** Curated brand packs keyed by name (`storyshelf` is the default look). */
5
+ const brandPacks = {
6
+ storyshelf: {
7
+ light: {
8
+ accent: "#1d5fcf",
9
+ accentContrast: "#ffffff",
10
+ ring: "#1d5fcf",
11
+ surface: {
12
+ base: "#fafafa",
13
+ card: "#ffffff",
14
+ muted: "#f4f4f5",
15
+ subtle: "#fafafa"
16
+ },
17
+ text: {
18
+ primary: "#09090b",
19
+ secondary: "#5b5b64",
20
+ muted: "#6a6a73"
21
+ },
22
+ border: "#e4e4e7",
23
+ borderSubtle: "#f4f4f5",
24
+ status: {
25
+ approved: "#16a34a",
26
+ new: "#d97706",
27
+ rejected: "#dc2626"
28
+ },
29
+ sidebarBg: "#ffffff",
30
+ topbarBg: "#1d5fcf",
31
+ radius: "0.5rem",
32
+ radiusSm: "0.375rem",
33
+ shadow: "0 1px 2px rgba(0,0,0,.04)"
34
+ },
35
+ dark: {
36
+ accent: "#4f8fff",
37
+ accentContrast: "#09090b",
38
+ ring: "#4f8fff",
39
+ surface: {
40
+ base: "#09090b",
41
+ card: "#111113",
42
+ muted: "#27272a",
43
+ subtle: "#18181b"
44
+ },
45
+ text: {
46
+ primary: "#fafafa",
47
+ secondary: "#a1a1aa",
48
+ muted: "#8a8a94"
49
+ },
50
+ border: "#27272a",
51
+ borderSubtle: "#1e1e22",
52
+ status: {
53
+ approved: "#22c55e",
54
+ new: "#f59e0b",
55
+ rejected: "#ef4444"
56
+ },
57
+ sidebarBg: "#111113",
58
+ topbarBg: "#0f172a",
59
+ radius: "0.5rem",
60
+ radiusSm: "0.375rem",
61
+ shadow: "0 1px 2px rgba(0,0,0,.3)"
62
+ }
63
+ },
64
+ ocean: {
65
+ light: {
66
+ accent: "#0e7490",
67
+ accentContrast: "#ffffff",
68
+ ring: "#0e7490",
69
+ surface: {
70
+ base: "#faf7f0",
71
+ card: "#ffffff",
72
+ muted: "#f1ece1",
73
+ subtle: "#faf7f0"
74
+ },
75
+ text: {
76
+ primary: "#1c1917",
77
+ secondary: "#78716c",
78
+ muted: "#a8a29e"
79
+ },
80
+ border: "#e7e0d2",
81
+ borderSubtle: "#f1ece1",
82
+ status: {
83
+ approved: "#16a34a",
84
+ new: "#d97706",
85
+ rejected: "#dc2626"
86
+ },
87
+ sidebarBg: "#ffffff",
88
+ topbarBg: "#0e7490",
89
+ radius: "0.5rem",
90
+ radiusSm: "0.375rem",
91
+ shadow: "0 1px 2px rgba(0,0,0,.04)"
92
+ },
93
+ dark: {
94
+ accent: "#22d3ee",
95
+ accentContrast: "#082f36",
96
+ ring: "#22d3ee",
97
+ surface: {
98
+ base: "#081014",
99
+ card: "#0e1a21",
100
+ muted: "#1d303b",
101
+ subtle: "#101e25"
102
+ },
103
+ text: {
104
+ primary: "#f0f9fa",
105
+ secondary: "#93a7b0",
106
+ muted: "#5d747e"
107
+ },
108
+ border: "#1d303b",
109
+ borderSubtle: "#14242c",
110
+ status: {
111
+ approved: "#22c55e",
112
+ new: "#f59e0b",
113
+ rejected: "#ef4444"
114
+ },
115
+ sidebarBg: "#0e1a21",
116
+ topbarBg: "#082f36",
117
+ radius: "0.5rem",
118
+ radiusSm: "0.375rem",
119
+ shadow: "0 1px 2px rgba(0,0,0,.3)"
120
+ }
121
+ }
122
+ };
123
+ /** Look up a brand pack by name (undefined for unknown names). */
124
+ function brandPack(name) {
125
+ return brandPacks[name];
126
+ }
127
+ //#endregion
128
+ export { brandPack, brandPacks };
129
+
130
+ //# sourceMappingURL=brand-packs.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brand-packs.mjs","names":[],"sources":["../src/brand-packs.ts"],"sourcesContent":["/**\n * Brand packs: curated light/dark theme pairs for `UIConfig`.\n *\n * Drop one into the server options (`ui: { ...brandPacks.ocean }`) instead\n * of hand-rolling every token. Packs carry full `BrandTheme` pairs so both\n * color schemes stay coherent; every pack validates against\n * {@link uiConfigSchema}.\n */\nimport type { BrandTheme } from \"./config.ts\";\n\n/** One named light/dark theme pair. */\nexport interface BrandPack {\n light: BrandTheme;\n dark: BrandTheme;\n}\n\n/** Default StoryShelf look (matches the built-in UI themes). */\nconst storyshelf: BrandPack = {\n light: {\n accent: \"#1d5fcf\",\n accentContrast: \"#ffffff\",\n ring: \"#1d5fcf\",\n surface: { base: \"#fafafa\", card: \"#ffffff\", muted: \"#f4f4f5\", subtle: \"#fafafa\" },\n text: { primary: \"#09090b\", secondary: \"#5b5b64\", muted: \"#6a6a73\" },\n border: \"#e4e4e7\",\n borderSubtle: \"#f4f4f5\",\n status: { approved: \"#16a34a\", new: \"#d97706\", rejected: \"#dc2626\" },\n sidebarBg: \"#ffffff\",\n topbarBg: \"#1d5fcf\",\n radius: \"0.5rem\",\n radiusSm: \"0.375rem\",\n shadow: \"0 1px 2px rgba(0,0,0,.04)\",\n },\n dark: {\n accent: \"#4f8fff\",\n accentContrast: \"#09090b\",\n ring: \"#4f8fff\",\n surface: { base: \"#09090b\", card: \"#111113\", muted: \"#27272a\", subtle: \"#18181b\" },\n text: { primary: \"#fafafa\", secondary: \"#a1a1aa\", muted: \"#8a8a94\" },\n border: \"#27272a\",\n borderSubtle: \"#1e1e22\",\n status: { approved: \"#22c55e\", new: \"#f59e0b\", rejected: \"#ef4444\" },\n sidebarBg: \"#111113\",\n topbarBg: \"#0f172a\",\n radius: \"0.5rem\",\n radiusSm: \"0.375rem\",\n shadow: \"0 1px 2px rgba(0,0,0,.3)\",\n },\n};\n\n/** Deep teal on warm paper (light) / abyss (dark). */\nconst ocean: BrandPack = {\n light: {\n accent: \"#0e7490\",\n accentContrast: \"#ffffff\",\n ring: \"#0e7490\",\n surface: { base: \"#faf7f0\", card: \"#ffffff\", muted: \"#f1ece1\", subtle: \"#faf7f0\" },\n text: { primary: \"#1c1917\", secondary: \"#78716c\", muted: \"#a8a29e\" },\n border: \"#e7e0d2\",\n borderSubtle: \"#f1ece1\",\n status: { approved: \"#16a34a\", new: \"#d97706\", rejected: \"#dc2626\" },\n sidebarBg: \"#ffffff\",\n topbarBg: \"#0e7490\",\n radius: \"0.5rem\",\n radiusSm: \"0.375rem\",\n shadow: \"0 1px 2px rgba(0,0,0,.04)\",\n },\n dark: {\n accent: \"#22d3ee\",\n accentContrast: \"#082f36\",\n ring: \"#22d3ee\",\n surface: { base: \"#081014\", card: \"#0e1a21\", muted: \"#1d303b\", subtle: \"#101e25\" },\n text: { primary: \"#f0f9fa\", secondary: \"#93a7b0\", muted: \"#5d747e\" },\n border: \"#1d303b\",\n borderSubtle: \"#14242c\",\n status: { approved: \"#22c55e\", new: \"#f59e0b\", rejected: \"#ef4444\" },\n sidebarBg: \"#0e1a21\",\n topbarBg: \"#082f36\",\n radius: \"0.5rem\",\n radiusSm: \"0.375rem\",\n shadow: \"0 1px 2px rgba(0,0,0,.3)\",\n },\n};\n\n/** Curated brand packs keyed by name (`storyshelf` is the default look). */\nexport const brandPacks: Record<string, BrandPack> = { storyshelf, ocean };\n\n/** Look up a brand pack by name (undefined for unknown names). */\nexport function brandPack(name: string): BrandPack | undefined {\n return brandPacks[name];\n}\n"],"mappings":";;;;AAqFA,MAAa,aAAwC;CAAE;EAnErD,OAAO;GACL,QAAQ;GACR,gBAAgB;GAChB,MAAM;GACN,SAAS;IAAE,MAAM;IAAW,MAAM;IAAW,OAAO;IAAW,QAAQ;GAAU;GACjF,MAAM;IAAE,SAAS;IAAW,WAAW;IAAW,OAAO;GAAU;GACnE,QAAQ;GACR,cAAc;GACd,QAAQ;IAAE,UAAU;IAAW,KAAK;IAAW,UAAU;GAAU;GACnE,WAAW;GACX,UAAU;GACV,QAAQ;GACR,UAAU;GACV,QAAQ;EACV;EACA,MAAM;GACJ,QAAQ;GACR,gBAAgB;GAChB,MAAM;GACN,SAAS;IAAE,MAAM;IAAW,MAAM;IAAW,OAAO;IAAW,QAAQ;GAAU;GACjF,MAAM;IAAE,SAAS;IAAW,WAAW;IAAW,OAAO;GAAU;GACnE,QAAQ;GACR,cAAc;GACd,QAAQ;IAAE,UAAU;IAAW,KAAK;IAAW,UAAU;GAAU;GACnE,WAAW;GACX,UAAU;GACV,QAAQ;GACR,UAAU;GACV,QAAQ;EACV;CAsCqD;CAAY;EAjCjE,OAAO;GACL,QAAQ;GACR,gBAAgB;GAChB,MAAM;GACN,SAAS;IAAE,MAAM;IAAW,MAAM;IAAW,OAAO;IAAW,QAAQ;GAAU;GACjF,MAAM;IAAE,SAAS;IAAW,WAAW;IAAW,OAAO;GAAU;GACnE,QAAQ;GACR,cAAc;GACd,QAAQ;IAAE,UAAU;IAAW,KAAK;IAAW,UAAU;GAAU;GACnE,WAAW;GACX,UAAU;GACV,QAAQ;GACR,UAAU;GACV,QAAQ;EACV;EACA,MAAM;GACJ,QAAQ;GACR,gBAAgB;GAChB,MAAM;GACN,SAAS;IAAE,MAAM;IAAW,MAAM;IAAW,OAAO;IAAW,QAAQ;GAAU;GACjF,MAAM;IAAE,SAAS;IAAW,WAAW;IAAW,OAAO;GAAU;GACnE,QAAQ;GACR,cAAc;GACd,QAAQ;IAAE,UAAU;IAAW,KAAK;IAAW,UAAU;GAAU;GACnE,WAAW;GACX,UAAU;GACV,QAAQ;GACR,UAAU;GACV,QAAQ;EACV;CAIiE;AAAM;;AAGzE,SAAgB,UAAU,MAAqC;CAC7D,OAAO,WAAW;AACpB"}
@@ -1,6 +1,20 @@
1
1
  import __tsdown_shims_path from 'node:path';
2
2
  import __tsdown_shims_url from 'node:url';
3
+ import { DepGraph } from "@storyshelf/affected";
3
4
  //#region src/capture/adapter.d.ts
5
+ /** A custom viewport registered on a story via `parameters.viewport`. */
6
+ interface StoryViewportDefinition {
7
+ name?: string;
8
+ styles?: {
9
+ width?: string | number;
10
+ height?: string | number;
11
+ };
12
+ }
13
+ /** Storybook `parameters.viewport` config; carried through discovery for per-story viewport capture. */
14
+ interface StoryViewportConfig {
15
+ defaultViewport?: string;
16
+ viewports?: Record<string, StoryViewportDefinition>;
17
+ }
4
18
  /** Per-story capture parameters from the Storybook index. */
5
19
  interface StoryParameters {
6
20
  disableSnapshot?: boolean;
@@ -8,6 +22,23 @@ interface StoryParameters {
8
22
  diffThreshold?: number;
9
23
  pauseAnimationAtEnd?: boolean;
10
24
  flakyTest?: boolean;
25
+ /** Force auto-crop (true) or full viewport (false) for this story; undefined uses 60% whitespace rule. */
26
+ autoCrop?: boolean;
27
+ /** Whitespace fraction (0..1) above which we crop; default 0.6. */
28
+ autoCropThreshold?: number;
29
+ /** Whether overflow should trigger fullPage; default true. */
30
+ fullPageOnOverflow?: boolean;
31
+ /** Min dimensions for the final PNG (clamp after padding). */
32
+ minWidth?: number;
33
+ minHeight?: number;
34
+ maxWidth?: number;
35
+ maxHeight?: number;
36
+ /** Burst count for steady capture (1 = single shot, 3 = burst 100ms); default 1. */
37
+ burst?: number;
38
+ /** Whether to wait for fonts.ready before screenshot; default true when burst >1. */
39
+ waitForFonts?: boolean;
40
+ /** Storybook viewport config; adds the story's default viewport to the project list at capture time. */
41
+ viewport?: StoryViewportConfig;
11
42
  }
12
43
  /** Return whether a story is marked flaky (failures stay non-blocking). */
13
44
  declare function isFlakyStory(entry: Pick<StoryEntry, "tags" | "parameters">): boolean;
@@ -23,12 +54,31 @@ interface StoryEntry {
23
54
  type: "story" | "docs";
24
55
  parameters?: StoryParameters;
25
56
  }
57
+ /** Minimal structural page handle handed to `StorySourceAdapter.waitForReady`. */
58
+ interface CapturePage {
59
+ evaluate(pageFunction: string | ((...args: unknown[]) => unknown), arg?: unknown): Promise<unknown>;
60
+ waitForSelector(selector: string, options?: Record<string, unknown>): Promise<unknown>;
61
+ }
26
62
  /** Adapter that discovers and renders stories from a Storybook build. */
27
63
  interface StorySourceAdapter {
28
64
  name: string;
29
65
  discover(source: string): Promise<StoryEntry[]>;
30
66
  buildUrl(baseUrl: string, storyId: string): string;
31
67
  screenshotSelector?: string;
68
+ /**
69
+ * Optional hook loading the module dependency graph of an extracted build,
70
+ * enabling affected capture (render only stories downstream of a change).
71
+ * Absent (or resolving `null`) means the source cannot be traced, so the
72
+ * orchestrator renders every story.
73
+ */
74
+ loadDependencyGraph?(sourceDir: string): Promise<DepGraph | null>;
75
+ /**
76
+ * Optional hook invoked after navigation and before the screenshot sequence,
77
+ * letting a custom source wait until it is ready to capture. The built-in
78
+ * Storybook adapter leaves this undefined (rendered via iframe). See
79
+ * ADR 0005.
80
+ */
81
+ waitForReady?(page: CapturePage): Promise<void>;
32
82
  }
33
83
  /** A viewport size at which stories are captured. */
34
84
  interface Viewport {
@@ -39,5 +89,5 @@ interface Viewport {
39
89
  /** Default viewport used when none is configured. */
40
90
  declare const DEFAULT_VIEWPORTS: Viewport[];
41
91
  //#endregion
42
- export { DEFAULT_VIEWPORTS, StoryEntry, StoryParameters, StorySourceAdapter, Viewport, isDisabledStory, isFlakyStory };
92
+ export { CapturePage, DEFAULT_VIEWPORTS, StoryEntry, StoryParameters, StorySourceAdapter, StoryViewportConfig, StoryViewportDefinition, Viewport, isDisabledStory, isFlakyStory };
43
93
  //# sourceMappingURL=adapter.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.mjs","names":[],"sources":["../../src/capture/adapter.ts"],"sourcesContent":["/** Per-story capture parameters from the Storybook index. */\nexport interface StoryParameters {\n disableSnapshot?: boolean;\n delay?: number;\n diffThreshold?: number;\n pauseAnimationAtEnd?: boolean;\n flakyTest?: boolean;\n}\n\n/** Return whether a story is marked flaky (failures stay non-blocking). */\nexport function isFlakyStory(entry: Pick<StoryEntry, \"tags\" | \"parameters\">): boolean {\n if (entry.parameters?.flakyTest) return true;\n const tags = entry.tags ?? [];\n for (const t of tags) {\n if (t.toLowerCase() === \"flaky-test\") return true;\n }\n return false;\n}\n\n/** Return whether a story is excluded from snapshot capture. */\nexport function isDisabledStory(entry: Pick<StoryEntry, \"tags\" | \"parameters\">): boolean {\n if (entry.parameters?.disableSnapshot) return true;\n const tags = entry.tags ?? [];\n for (const t of tags) {\n const lower = t.toLowerCase();\n if (lower === \"skip\" || lower === \"disable\" || lower === \"disable-snapshot\") return true;\n }\n return false;\n}\n\n/** A single discoverable story or docs entry within a Storybook. */\nexport interface StoryEntry {\n id: string;\n title: string;\n name: string;\n importPath?: string;\n tags?: string[];\n type: \"story\" | \"docs\";\n parameters?: StoryParameters;\n}\n\n/** Adapter that discovers and renders stories from a Storybook build. */\nexport interface StorySourceAdapter {\n name: string;\n discover(source: string): Promise<StoryEntry[]>;\n buildUrl(baseUrl: string, storyId: string): string;\n screenshotSelector?: string;\n}\n\n/** A viewport size at which stories are captured. */\nexport interface Viewport {\n name: string;\n width: number;\n height: number;\n}\n\n/** Default viewport used when none is configured. */\nexport const DEFAULT_VIEWPORTS: Viewport[] = [{ name: \"desktop\", width: 1280, height: 720 }];\n"],"mappings":";;;;;AAUA,SAAgB,aAAa,OAAyD;CACpF,IAAI,MAAM,YAAY,WAAW,OAAO;CACxC,MAAM,OAAO,MAAM,QAAQ,CAAC;CAC5B,KAAK,MAAM,KAAK,MACd,IAAI,EAAE,YAAY,MAAM,cAAc,OAAO;CAE/C,OAAO;AACT;;AAGA,SAAgB,gBAAgB,OAAyD;CACvF,IAAI,MAAM,YAAY,iBAAiB,OAAO;CAC9C,MAAM,OAAO,MAAM,QAAQ,CAAC;CAC5B,KAAK,MAAM,KAAK,MAAM;EACpB,MAAM,QAAQ,EAAE,YAAY;EAC5B,IAAI,UAAU,UAAU,UAAU,aAAa,UAAU,oBAAoB,OAAO;CACtF;CACA,OAAO;AACT;;AA6BA,MAAa,oBAAgC,CAAC;CAAE,MAAM;CAAW,OAAO;CAAM,QAAQ;AAAI,CAAC"}
1
+ {"version":3,"file":"adapter.mjs","names":[],"sources":["../../src/capture/adapter.ts"],"sourcesContent":["import type { DepGraph } from \"@storyshelf/affected\";\n\n/** A custom viewport registered on a story via `parameters.viewport`. */\nexport interface StoryViewportDefinition {\n name?: string;\n styles?: {\n width?: string | number;\n height?: string | number;\n };\n}\n\n/** Storybook `parameters.viewport` config; carried through discovery for per-story viewport capture. */\nexport interface StoryViewportConfig {\n defaultViewport?: string;\n viewports?: Record<string, StoryViewportDefinition>;\n}\n\n/** Per-story capture parameters from the Storybook index. */\nexport interface StoryParameters {\n disableSnapshot?: boolean;\n delay?: number;\n diffThreshold?: number;\n pauseAnimationAtEnd?: boolean;\n flakyTest?: boolean;\n /** Force auto-crop (true) or full viewport (false) for this story; undefined uses 60% whitespace rule. */\n autoCrop?: boolean;\n /** Whitespace fraction (0..1) above which we crop; default 0.6. */\n autoCropThreshold?: number;\n /** Whether overflow should trigger fullPage; default true. */\n fullPageOnOverflow?: boolean;\n /** Min dimensions for the final PNG (clamp after padding). */\n minWidth?: number;\n minHeight?: number;\n maxWidth?: number;\n maxHeight?: number;\n /** Burst count for steady capture (1 = single shot, 3 = burst 100ms); default 1. */\n burst?: number;\n /** Whether to wait for fonts.ready before screenshot; default true when burst >1. */\n waitForFonts?: boolean;\n /** Storybook viewport config; adds the story's default viewport to the project list at capture time. */\n viewport?: StoryViewportConfig;\n}\n\n/** Return whether a story is marked flaky (failures stay non-blocking). */\nexport function isFlakyStory(entry: Pick<StoryEntry, \"tags\" | \"parameters\">): boolean {\n if (entry.parameters?.flakyTest) return true;\n const tags = entry.tags ?? [];\n for (const t of tags) {\n if (t.toLowerCase() === \"flaky-test\") return true;\n }\n return false;\n}\n\n/** Return whether a story is excluded from snapshot capture. */\nexport function isDisabledStory(entry: Pick<StoryEntry, \"tags\" | \"parameters\">): boolean {\n if (entry.parameters?.disableSnapshot) return true;\n const tags = entry.tags ?? [];\n for (const t of tags) {\n const lower = t.toLowerCase();\n if (lower === \"skip\" || lower === \"disable\" || lower === \"disable-snapshot\") return true;\n }\n return false;\n}\n\n/** A single discoverable story or docs entry within a Storybook. */\nexport interface StoryEntry {\n id: string;\n title: string;\n name: string;\n importPath?: string;\n tags?: string[];\n type: \"story\" | \"docs\";\n parameters?: StoryParameters;\n}\n\n/** Minimal structural page handle handed to `StorySourceAdapter.waitForReady`. */\nexport interface CapturePage {\n evaluate(\n pageFunction: string | ((...args: unknown[]) => unknown),\n arg?: unknown,\n ): Promise<unknown>;\n waitForSelector(selector: string, options?: Record<string, unknown>): Promise<unknown>;\n}\n\n/** Adapter that discovers and renders stories from a Storybook build. */\nexport interface StorySourceAdapter {\n name: string;\n discover(source: string): Promise<StoryEntry[]>;\n buildUrl(baseUrl: string, storyId: string): string;\n screenshotSelector?: string;\n /**\n * Optional hook loading the module dependency graph of an extracted build,\n * enabling affected capture (render only stories downstream of a change).\n * Absent (or resolving `null`) means the source cannot be traced, so the\n * orchestrator renders every story.\n */\n loadDependencyGraph?(sourceDir: string): Promise<DepGraph | null>;\n /**\n * Optional hook invoked after navigation and before the screenshot sequence,\n * letting a custom source wait until it is ready to capture. The built-in\n * Storybook adapter leaves this undefined (rendered via iframe). See\n * ADR 0005.\n */\n waitForReady?(page: CapturePage): Promise<void>;\n}\n\n/** A viewport size at which stories are captured. */\nexport interface Viewport {\n name: string;\n width: number;\n height: number;\n}\n\n/** Default viewport used when none is configured. */\nexport const DEFAULT_VIEWPORTS: Viewport[] = [{ name: \"desktop\", width: 1280, height: 720 }];\n"],"mappings":";;;;;AA4CA,SAAgB,aAAa,OAAyD;CACpF,IAAI,MAAM,YAAY,WAAW,OAAO;CACxC,MAAM,OAAO,MAAM,QAAQ,CAAC;CAC5B,KAAK,MAAM,KAAK,MACd,IAAI,EAAE,YAAY,MAAM,cAAc,OAAO;CAE/C,OAAO;AACT;;AAGA,SAAgB,gBAAgB,OAAyD;CACvF,IAAI,MAAM,YAAY,iBAAiB,OAAO;CAC9C,MAAM,OAAO,MAAM,QAAQ,CAAC;CAC5B,KAAK,MAAM,KAAK,MAAM;EACpB,MAAM,QAAQ,EAAE,YAAY;EAC5B,IAAI,UAAU,UAAU,UAAU,aAAa,UAAU,oBAAoB,OAAO;CACtF;CACA,OAAO;AACT;;AAoDA,MAAa,oBAAgC,CAAC;CAAE,MAAM;CAAW,OAAO;CAAM,QAAQ;AAAI,CAAC"}
@@ -0,0 +1,16 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { StoryEntry, Viewport } from "./adapter.mjs";
4
+ import "../adapter/database.mjs";
5
+ import { Baseline } from "../schema/baseline.mjs";
6
+ import "../models/baseline.mjs";
7
+ //#region src/capture/affected.d.ts
8
+ /** An inherit candidate paired with the baseline it reuses. */
9
+ interface InheritedStory {
10
+ story: StoryEntry;
11
+ viewport: Viewport;
12
+ baseline: Baseline;
13
+ }
14
+ //#endregion
15
+ export { InheritedStory };
16
+ //# sourceMappingURL=affected.d.mts.map
@@ -0,0 +1,64 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { BaselineModel } from "../models/baseline.mjs";
5
+ import { resolveStoryViewports } from "./storybook.mjs";
6
+ import { selectAffectedStories } from "@storyshelf/affected";
7
+ //#region src/capture/affected.ts
8
+ /** Split one inherit candidate by per-viewport baseline availability. */
9
+ async function splitStory(baselines, input, story) {
10
+ const render = [];
11
+ const inherited = [];
12
+ const viewports = resolveStoryViewports(story, input.viewports);
13
+ const settled = await Promise.all(viewports.map(async (viewport) => ({
14
+ viewport,
15
+ baseline: await baselines.resolve(input.projectId, story.id, viewport.name, input.branch, input.defaultBranch)
16
+ })));
17
+ for (const { viewport, baseline } of settled) if (baseline) inherited.push({
18
+ story,
19
+ viewport,
20
+ baseline
21
+ });
22
+ else if (!render.includes(story)) render.push(story);
23
+ return {
24
+ render,
25
+ inherited
26
+ };
27
+ }
28
+ /** Merge per-story partitions into a single render/inherit split. */
29
+ function mergePartitions(partitions) {
30
+ const render = [];
31
+ const inherited = [];
32
+ for (const partition of partitions) {
33
+ render.push(...partition.render);
34
+ inherited.push(...partition.inherited);
35
+ }
36
+ return {
37
+ render,
38
+ inherited
39
+ };
40
+ }
41
+ /**
42
+ * Partition discovered stories into render versus inherit sets.
43
+ *
44
+ * Stories outside the affected set inherit their baseline without rendering,
45
+ * except when no baseline exists (new stories always render). A `null`
46
+ * affected set renders everything.
47
+ */
48
+ async function partitionAffectedStories(input) {
49
+ const selected = selectAffectedStories(input.stories, input.affectedPaths);
50
+ if (selected.inherit.length === 0) return {
51
+ render: selected.render,
52
+ inherited: []
53
+ };
54
+ const baselines = new BaselineModel(input.db, input.tables);
55
+ const merged = mergePartitions(await Promise.all(selected.inherit.map(async (story) => await splitStory(baselines, input, story))));
56
+ return {
57
+ render: [...selected.render, ...merged.render],
58
+ inherited: merged.inherited
59
+ };
60
+ }
61
+ //#endregion
62
+ export { partitionAffectedStories };
63
+
64
+ //# sourceMappingURL=affected.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"affected.mjs","names":[],"sources":["../../src/capture/affected.ts"],"sourcesContent":["import { selectAffectedStories } from \"@storyshelf/affected\";\nimport type { DatabaseAdapter } from \"../adapters/database.ts\";\nimport { BaselineModel, type BaselineTables } from \"../models/baseline.ts\";\nimport type { Baseline } from \"../schema/baseline.ts\";\nimport type { StoryEntry, Viewport } from \"./adapter.ts\";\nimport { resolveStoryViewports } from \"./storybook.ts\";\n\n/** An inherit candidate paired with the baseline it reuses. */\nexport interface InheritedStory {\n story: StoryEntry;\n viewport: Viewport;\n baseline: Baseline;\n}\n\n/** Stories split into capture-now versus inherit-from-baseline sets. */\nexport interface AffectedPartition {\n render: StoryEntry[];\n inherited: InheritedStory[];\n}\n\n/** Inputs for partitioning a build's stories by affected status. */\nexport interface PartitionInput {\n db: DatabaseAdapter;\n tables: BaselineTables;\n projectId: string;\n branch: string;\n defaultBranch: string;\n stories: StoryEntry[];\n viewports: Viewport[];\n /** Affected import paths, or `null` to render everything. */\n affectedPaths: string[] | null;\n}\n\n/** Split one inherit candidate by per-viewport baseline availability. */\nasync function splitStory(\n baselines: BaselineModel,\n input: PartitionInput,\n story: StoryEntry,\n): Promise<AffectedPartition> {\n const render: StoryEntry[] = [];\n const inherited: InheritedStory[] = [];\n const viewports = resolveStoryViewports(story, input.viewports);\n const settled = await Promise.all(\n viewports.map(async (viewport) => ({\n viewport,\n baseline: await baselines.resolve(\n input.projectId,\n story.id,\n viewport.name,\n input.branch,\n input.defaultBranch,\n ),\n })),\n );\n for (const { viewport, baseline } of settled) {\n if (baseline) {\n inherited.push({ story, viewport, baseline });\n } else if (!render.includes(story)) {\n render.push(story);\n }\n }\n return { render, inherited };\n}\n\n/** Merge per-story partitions into a single render/inherit split. */\nfunction mergePartitions(partitions: AffectedPartition[]): AffectedPartition {\n const render: StoryEntry[] = [];\n const inherited: InheritedStory[] = [];\n for (const partition of partitions) {\n render.push(...partition.render);\n inherited.push(...partition.inherited);\n }\n return { render, inherited };\n}\n\n/**\n * Partition discovered stories into render versus inherit sets.\n *\n * Stories outside the affected set inherit their baseline without rendering,\n * except when no baseline exists (new stories always render). A `null`\n * affected set renders everything.\n */\nexport async function partitionAffectedStories(input: PartitionInput): Promise<AffectedPartition> {\n const selected = selectAffectedStories(input.stories, input.affectedPaths);\n if (selected.inherit.length === 0) {\n return { render: selected.render, inherited: [] };\n }\n const baselines = new BaselineModel(input.db, input.tables);\n const partitions = await Promise.all(\n selected.inherit.map(async (story) => await splitStory(baselines, input, story)),\n );\n const merged = mergePartitions(partitions);\n return { render: [...selected.render, ...merged.render], inherited: merged.inherited };\n}\n"],"mappings":";;;;;;;;AAkCA,eAAe,WACb,WACA,OACA,OAC4B;CAC5B,MAAM,SAAuB,CAAC;CAC9B,MAAM,YAA8B,CAAC;CACrC,MAAM,YAAY,sBAAsB,OAAO,MAAM,SAAS;CAC9D,MAAM,UAAU,MAAM,QAAQ,IAC5B,UAAU,IAAI,OAAO,cAAc;EACjC;EACA,UAAU,MAAM,UAAU,QACxB,MAAM,WACN,MAAM,IACN,SAAS,MACT,MAAM,QACN,MAAM,aACR;CACF,EAAE,CACJ;CACA,KAAK,MAAM,EAAE,UAAU,cAAc,SACnC,IAAI,UACF,UAAU,KAAK;EAAE;EAAO;EAAU;CAAS,CAAC;MACvC,IAAI,CAAC,OAAO,SAAS,KAAK,GAC/B,OAAO,KAAK,KAAK;CAGrB,OAAO;EAAE;EAAQ;CAAU;AAC7B;;AAGA,SAAS,gBAAgB,YAAoD;CAC3E,MAAM,SAAuB,CAAC;CAC9B,MAAM,YAA8B,CAAC;CACrC,KAAK,MAAM,aAAa,YAAY;EAClC,OAAO,KAAK,GAAG,UAAU,MAAM;EAC/B,UAAU,KAAK,GAAG,UAAU,SAAS;CACvC;CACA,OAAO;EAAE;EAAQ;CAAU;AAC7B;;;;;;;;AASA,eAAsB,yBAAyB,OAAmD;CAChG,MAAM,WAAW,sBAAsB,MAAM,SAAS,MAAM,aAAa;CACzE,IAAI,SAAS,QAAQ,WAAW,GAC9B,OAAO;EAAE,QAAQ,SAAS;EAAQ,WAAW,CAAC;CAAE;CAElD,MAAM,YAAY,IAAI,cAAc,MAAM,IAAI,MAAM,MAAM;CAI1D,MAAM,SAAS,gBAAgB,MAHN,QAAQ,IAC/B,SAAS,QAAQ,IAAI,OAAO,UAAU,MAAM,WAAW,WAAW,OAAO,KAAK,CAAC,CACjF,CACyC;CACzC,OAAO;EAAE,QAAQ,CAAC,GAAG,SAAS,QAAQ,GAAG,OAAO,MAAM;EAAG,WAAW,OAAO;CAAU;AACvF"}
@@ -0,0 +1,30 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { diffImages } from "../diff/engine.mjs";
5
+ import { DEFAULT_DIFF_OPTIONS } from "../diff/options.mjs";
6
+ //#region src/capture/diff-record.ts
7
+ /** Per-story `diffThreshold` when it is a finite number in 0..1; otherwise the project threshold. */
8
+ function resolvePixelThreshold(projectThreshold, override) {
9
+ return typeof override === "number" && Number.isFinite(override) && override >= 0 && override <= 1 ? override : projectThreshold;
10
+ }
11
+ /** Read two stored PNGs and diff them with the project's thresholds (optionally a per-story pixel threshold). */
12
+ async function diffStoredScreenshots(storage, project, baselinePath, currentPath, diffThreshold) {
13
+ const current = await storage.read(currentPath);
14
+ const previous = await storage.read(baselinePath);
15
+ return diffImages(previous, current, {
16
+ ...DEFAULT_DIFF_OPTIONS,
17
+ pixelThreshold: resolvePixelThreshold(project.pixelThreshold, diffThreshold),
18
+ maxDiffRatio: project.maxDiffRatio
19
+ });
20
+ }
21
+ /** Write the diff overlay for a failing diff; returns the stored path, or null when none applies. */
22
+ async function writeDiffOverlay(storage, path, result, passed) {
23
+ if (passed || !result.diffImage) return null;
24
+ await storage.write(path, result.diffImage);
25
+ return path;
26
+ }
27
+ //#endregion
28
+ export { diffStoredScreenshots, resolvePixelThreshold, writeDiffOverlay };
29
+
30
+ //# sourceMappingURL=diff-record.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-record.mjs","names":[],"sources":["../../src/capture/diff-record.ts"],"sourcesContent":["/** Diff a stored screenshot against a baseline and persist the overlay; shared by capture and re-diff. */\nimport type { StorageAdapter } from \"../adapters/storage.ts\";\nimport { diffImages } from \"../diff/engine.ts\";\nimport { DEFAULT_DIFF_OPTIONS, type DiffResult } from \"../diff/options.ts\";\n\n/** Project thresholds that drive a diff. */\nexport interface DiffThresholds {\n pixelThreshold: number;\n maxDiffRatio: number;\n}\n\n/** Per-story `diffThreshold` when it is a finite number in 0..1; otherwise the project threshold. */\nexport function resolvePixelThreshold(projectThreshold: number, override?: number): number {\n const valid = typeof override === \"number\" && Number.isFinite(override);\n return valid && override >= 0 && override <= 1 ? override : projectThreshold;\n}\n\n/** Read two stored PNGs and diff them with the project's thresholds (optionally a per-story pixel threshold). */\nexport async function diffStoredScreenshots(\n storage: StorageAdapter,\n project: DiffThresholds,\n baselinePath: string,\n currentPath: string,\n diffThreshold?: number,\n): Promise<DiffResult> {\n const current = await storage.read(currentPath);\n const previous = await storage.read(baselinePath);\n return diffImages(previous, current, {\n ...DEFAULT_DIFF_OPTIONS,\n pixelThreshold: resolvePixelThreshold(project.pixelThreshold, diffThreshold),\n maxDiffRatio: project.maxDiffRatio,\n });\n}\n\n/** Write the diff overlay for a failing diff; returns the stored path, or null when none applies. */\nexport async function writeDiffOverlay(\n storage: StorageAdapter,\n path: string,\n result: Pick<DiffResult, \"diffImage\">,\n passed: boolean,\n): Promise<string | null> {\n if (passed || !result.diffImage) {\n return null;\n }\n await storage.write(path, result.diffImage);\n return path;\n}\n"],"mappings":";;;;;;;AAYA,SAAgB,sBAAsB,kBAA0B,UAA2B;CAEzF,OADc,OAAO,aAAa,YAAY,OAAO,SAAS,QAAQ,KACtD,YAAY,KAAK,YAAY,IAAI,WAAW;AAC9D;;AAGA,eAAsB,sBACpB,SACA,SACA,cACA,aACA,eACqB;CACrB,MAAM,UAAU,MAAM,QAAQ,KAAK,WAAW;CAC9C,MAAM,WAAW,MAAM,QAAQ,KAAK,YAAY;CAChD,OAAO,WAAW,UAAU,SAAS;EACnC,GAAG;EACH,gBAAgB,sBAAsB,QAAQ,gBAAgB,aAAa;EAC3E,cAAc,QAAQ;CACxB,CAAC;AACH;;AAGA,eAAsB,iBACpB,SACA,MACA,QACA,QACwB;CACxB,IAAI,UAAU,CAAC,OAAO,WACpB,OAAO;CAET,MAAM,QAAQ,MAAM,MAAM,OAAO,SAAS;CAC1C,OAAO;AACT"}
@@ -0,0 +1,36 @@
1
+ import __tsdown_shims_path from 'node:path';
2
+ import __tsdown_shims_url from 'node:url';
3
+ import { DatabaseAdapter } from "../adapter/database.mjs";
4
+ import { GitHostProvider } from "../adapter/git-host.mjs";
5
+ import { Logger } from "../logger.mjs";
6
+ import { SecretInput } from "../utils/encrypt.mjs";
7
+ import { BuildTables } from "../models/build.mjs";
8
+ import { CaptureAttemptTables } from "../models/capture-attempt.mjs";
9
+ import { CaptureLogTables } from "../models/capture-log.mjs";
10
+ import { ProjectTables } from "../models/project.mjs";
11
+ import { CaptureJobOptions } from "./orchestrator.mjs";
12
+ import { StatusConfigTables } from "../models/status-config.mjs";
13
+ //#region src/capture/dispatch.d.ts
14
+ /** Build the queue's job runner: post pending, apply skip rules, capture, report. */
15
+ declare function createDispatchJob(deps: DispatchDeps): (job: CaptureDispatchJob) => Promise<void>;
16
+ /** Table handles required by dispatch. */
17
+ type DispatchTables = BuildTables & ProjectTables & StatusConfigTables & CaptureAttemptTables & CaptureLogTables;
18
+ /** Dependencies for building the capture queue's job runner. */
19
+ interface DispatchDeps {
20
+ db: DatabaseAdapter;
21
+ tables: DispatchTables;
22
+ jobOptions: CaptureJobOptions;
23
+ gitHosts: GitHostProvider[];
24
+ secret: SecretInput;
25
+ logger: Logger;
26
+ }
27
+ /** A queued capture job. */
28
+ interface CaptureDispatchJob {
29
+ buildId: string;
30
+ reqId?: string;
31
+ /** W3C `traceparent` continuing the enqueueing request's trace. */
32
+ traceparent?: string;
33
+ }
34
+ //#endregion
35
+ export { CaptureDispatchJob, DispatchDeps, DispatchTables, createDispatchJob };
36
+ //# sourceMappingURL=dispatch.d.mts.map