@hot-updater/console 1.0.0-rc.2 → 1.0.0-rc.21

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 (285) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/ConsoleFeatureUnavailable-D0LPL1Gy.js +1 -0
  3. package/.output/public/assets/HashValueDisplay-BmuB4FW-.js +1 -0
  4. package/.output/public/assets/InsightsInfo--v4SC07c.js +1 -0
  5. package/.output/public/assets/InsightsPageHeader-dU83CAQY.js +1 -0
  6. package/.output/public/assets/NotFoundPage-B5mhGG2a.js +1 -0
  7. package/.output/public/assets/api-D-vOVlQ4.js +1 -0
  8. package/.output/public/assets/api-keys-Csh8ARKU.js +1 -0
  9. package/.output/public/assets/api-keys-OMPUoA_A.js +1 -0
  10. package/.output/public/assets/arrow-left-Bwq9X1eS.js +1 -0
  11. package/.output/public/assets/arrow-up-right-BkOVn4if.js +1 -0
  12. package/.output/public/assets/card-C_7d6O9a.js +1 -0
  13. package/.output/public/assets/console-features-api-C1jRZTGw.js +1 -0
  14. package/.output/public/assets/dialog-DE8wFN_P.js +1 -0
  15. package/.output/public/assets/dist-C7ENGzpS.js +1 -0
  16. package/.output/public/assets/empty-CVd5NlQD.js +1 -0
  17. package/.output/public/assets/field-C06q1iC9.js +1 -0
  18. package/.output/public/assets/index-BeWlQtO6.js +11 -0
  19. package/.output/public/assets/input-group-Bi61biIA.js +1 -0
  20. package/.output/public/assets/insights-BjnAtC0f.js +2 -0
  21. package/.output/public/assets/insights-D86m11yH.js +42 -0
  22. package/.output/public/assets/insights-DpYstMoY.js +1 -0
  23. package/.output/public/assets/insights-recovery-rpc-BIm5_ALc.js +1 -0
  24. package/.output/public/assets/insights-search-KIF7mRtB.js +1 -0
  25. package/.output/public/assets/insights-usage-rpc-VHj8vyBt.js +1 -0
  26. package/.output/public/assets/insights_.distribution-ADcrX48c.js +2 -0
  27. package/.output/public/assets/insights_.distribution-CuuJUN6Y.js +1 -0
  28. package/.output/public/assets/insights_.distribution-DJRjuXsO.js +1 -0
  29. package/.output/public/assets/installations-BSBBzqWs.js +2 -0
  30. package/.output/public/assets/installations-DqIE6WcO.js +1 -0
  31. package/.output/public/assets/installations-UsELbDvw.js +1 -0
  32. package/.output/public/assets/loader-circle-CnCBxzHp.js +1 -0
  33. package/.output/public/assets/mutation-Csp7xUNh.js +1 -0
  34. package/.output/public/assets/preload-helper-B-cOmpLH.js +1 -0
  35. package/.output/public/assets/refresh-cw-FF1NtzlQ.js +1 -0
  36. package/.output/public/assets/routes-CoN9XHP_.js +2 -0
  37. package/.output/public/assets/routes-DT1jB0Zi.js +1 -0
  38. package/.output/public/assets/sidebar-D8mJRF15.js +3 -0
  39. package/.output/public/assets/styles-Bwt7v6U5.css +2 -0
  40. package/.output/public/assets/table-WBgfvgXg.js +1 -0
  41. package/.output/public/assets/useCompositeListItem-CloBmDwn.js +1 -0
  42. package/.output/public/assets/useMutation-DO8cvsTx.js +1 -0
  43. package/.output/public/assets/useOpenInteractionType-ReGr9GzJ.js +1 -0
  44. package/.output/public/assets/valueToPercent-BvPAi4bP.js +1 -0
  45. package/.output/server/{__23tanstack-start-server-fn-resolver-B7ioJhtE.mjs → __23tanstack-start-server-fn-resolver-DMRD4e4f.mjs} +51 -47
  46. package/.output/server/_libs/@base-ui/react+[...].mjs +7044 -3622
  47. package/.output/server/_libs/@reduxjs/toolkit+[...].mjs +1554 -0
  48. package/.output/server/_libs/@tanstack/react-router+[...].mjs +3803 -4023
  49. package/.output/server/_libs/@tanstack/react-router-ssr-query+[...].mjs +141 -98
  50. package/.output/server/_libs/d3-array.mjs +231 -0
  51. package/.output/server/_libs/d3-color.mjs +330 -0
  52. package/.output/server/_libs/d3-format.mjs +252 -0
  53. package/.output/server/_libs/d3-interpolate.mjs +207 -0
  54. package/.output/server/_libs/d3-path.mjs +77 -0
  55. package/.output/server/_libs/d3-scale+[...].mjs +1907 -0
  56. package/.output/server/_libs/d3-shape.mjs +818 -0
  57. package/.output/server/_libs/decimal.js-light.mjs +884 -0
  58. package/.output/server/_libs/es-toolkit.mjs +1159 -0
  59. package/.output/server/_libs/eventemitter3.mjs +236 -0
  60. package/.output/server/_libs/immer.mjs +532 -0
  61. package/.output/server/_libs/lucide-react.mjs +46 -32
  62. package/.output/server/_libs/next-themes.mjs +2 -2
  63. package/.output/server/_libs/react-redux+[...].mjs +205 -0
  64. package/.output/server/_libs/recharts+[...].mjs +14350 -0
  65. package/.output/server/_libs/sonner.mjs +2 -2
  66. package/.output/server/_libs/tanstack__history.mjs +68 -41
  67. package/.output/server/_libs/tanstack__query-core.mjs +1618 -309
  68. package/.output/server/_libs/tanstack__react-query.mjs +262 -22
  69. package/.output/server/_libs/verkit.mjs +99 -1
  70. package/.output/server/_runtime.mjs +10 -1
  71. package/.output/server/_ssr/ConsoleFeatureUnavailable-Du7jNPNS.mjs +58 -0
  72. package/.output/server/_ssr/{HashValueDisplay-DwpGLfrl.mjs → HashValueDisplay-GQvFkXoi.mjs} +3 -3
  73. package/.output/server/_ssr/InsightsInfo-Do7QSaFR.mjs +37 -0
  74. package/.output/server/_ssr/InsightsPageHeader-DSUWUWRc.mjs +154 -0
  75. package/.output/server/_ssr/NotFoundPage-DsF4Vrhg.mjs +37 -0
  76. package/.output/server/_ssr/api-BEiVs0H7.mjs +203 -0
  77. package/.output/server/_ssr/api-keys-BrvBWGRf.mjs +5 -0
  78. package/.output/server/_ssr/{api-keys-CZeTPQys.mjs → api-keys-K5v32nf7.mjs} +49 -9
  79. package/.output/server/_ssr/api-keys-rpc-B96bBllm.mjs +52 -0
  80. package/.output/server/_ssr/api-rpc-DcUe280B.mjs +296 -0
  81. package/.output/server/_ssr/{auth-rpc-DUaeOWKK.mjs → auth-rpc-C68W56DP.mjs} +6 -6
  82. package/.output/server/_ssr/auth.server-DM1J6NwR.mjs +5712 -0
  83. package/.output/server/_ssr/bundleActivity-CpuY9CTP.mjs +19 -0
  84. package/.output/server/_ssr/card-CPAEKx0w.mjs +49 -0
  85. package/.output/server/_ssr/config-nsIcsHh8.mjs +15 -0
  86. package/.output/server/_ssr/config.server-DDCZk3Sq.mjs +36 -0
  87. package/.output/server/_ssr/console-access-Da-2Qd7q.mjs +17 -0
  88. package/.output/server/_ssr/console-features-Dzu2iUGD.mjs +55 -0
  89. package/.output/server/_ssr/console-features-api-xAsSgFa_.mjs +43 -0
  90. package/.output/server/_ssr/console-features-rpc-qARGpB24.mjs +19 -0
  91. package/.output/server/_ssr/{createServerFn-B2hcXoPM.mjs → createMiddleware-BdBf_ezN.mjs} +67 -56
  92. package/.output/server/_ssr/{createServerRpc-DB29C_5p.mjs → createServerRpc-B_y2lrwA.mjs} +2 -2
  93. package/.output/server/_ssr/{databaseJsonValue-d6I3nAS4.mjs → databaseJsonValue-Bhxciy7Z.mjs} +28 -5
  94. package/.output/server/_ssr/databaseRows-DwMAjaF8.mjs +74 -0
  95. package/.output/server/_ssr/{dialog-DS-nw-pA.mjs → dialog-q__BJ7mQ.mjs} +2 -2
  96. package/.output/server/_ssr/{dist-CyzPaI5v.mjs → dist-Cxo9ghYv.mjs} +140 -6
  97. package/.output/server/_ssr/{downloadBundle-CNnYxYO2.mjs → downloadBundle-BW9I-pMQ.mjs} +10 -10
  98. package/.output/server/_ssr/empty-DcBTAooP.mjs +49 -0
  99. package/.output/server/_ssr/{empty-plugin-adapters-B5QvGpEl.mjs → empty-plugin-adapters-CYdinE-i.mjs} +1 -1
  100. package/.output/server/_ssr/{table-CnZmon_Z.mjs → field-QCDBVpXA.mjs} +63 -51
  101. package/.output/server/_ssr/getBundleChildren-DIAGCF4a.mjs +22 -0
  102. package/.output/server/_ssr/{input-group-BpsnmvZw.mjs → input-group-hCk2nUoU.mjs} +2 -2
  103. package/.output/server/_ssr/insights-BfBO0RFr.mjs +1238 -0
  104. package/.output/server/_ssr/insights-DsAU3-TB.mjs +14 -0
  105. package/.output/server/_ssr/insights-RIfg447W.mjs +5 -0
  106. package/.output/server/_ssr/insights-api-CDn-QQHU.mjs +105 -0
  107. package/.output/server/_ssr/insights-failures-BBGMhuUr.mjs +44 -0
  108. package/.output/server/_ssr/insights-failures-rpc-rA2dctK2.mjs +21 -0
  109. package/.output/server/_ssr/insights-recovery-Dpk6Mfb9.mjs +28 -0
  110. package/.output/server/_ssr/insights-recovery-rpc-BCaF-xSd.mjs +46 -0
  111. package/.output/server/_ssr/insights-recovery-rpc-CcgYyUHk.mjs +20 -0
  112. package/.output/server/_ssr/{insights-rpc-38DujK0G.mjs → insights-rpc-keycmwzw.mjs} +22 -14
  113. package/.output/server/_ssr/insights-search-BRg5VsNe.mjs +25 -0
  114. package/.output/server/_ssr/insights-usage-cbw9n2Fq.mjs +29 -0
  115. package/.output/server/_ssr/insights-usage-rpc-BKgV1QDf.mjs +29 -0
  116. package/.output/server/_ssr/insights-usage-rpc-D-JYachy.mjs +41 -0
  117. package/.output/server/_ssr/insightsRecovery-B7oMc8d8.mjs +45 -0
  118. package/.output/server/_ssr/insightsUsage-Oa7kk5ek.mjs +56 -0
  119. package/.output/server/_ssr/insights_.distribution-BIqOqRW0.mjs +335 -0
  120. package/.output/server/_ssr/insights_.distribution-CuUrDa7P.mjs +5 -0
  121. package/.output/server/_ssr/insights_.distribution-RT_6x_ud.mjs +14 -0
  122. package/.output/server/_ssr/{installations-DiVKEF5T.mjs → installations-BO5CjX2z.mjs} +517 -54
  123. package/.output/server/_ssr/installations-BjaHiIfh.mjs +5 -0
  124. package/.output/server/_ssr/installations-Dt5luA-N.mjs +69 -0
  125. package/.output/server/_ssr/listReleases-BitHzOYB.mjs +79 -0
  126. package/.output/server/_ssr/releaseManagement-B3e7I8J9.mjs +11 -0
  127. package/.output/server/_ssr/{router-B9wG_9f8.mjs → router-DfVAixxe.mjs} +135 -139
  128. package/.output/server/_ssr/{routes-D7Yh_jfj.mjs → routes-C6LstNp8.mjs} +176 -455
  129. package/.output/server/_ssr/routes-Q3Uhmwwz.mjs +292 -0
  130. package/.output/server/_ssr/runtime.server-fL0o6I2b.mjs +1459 -0
  131. package/.output/server/_ssr/schema-BKY9SqaY.mjs +25 -0
  132. package/.output/server/_ssr/select-CUlInmjk.mjs +107 -0
  133. package/.output/server/_ssr/server-C43wq9ft.mjs +8330 -0
  134. package/.output/server/_ssr/{createSsrRpc-DjWNJ0uc.mjs → sidebar-DKbx2ach.mjs} +117 -63
  135. package/.output/server/_ssr/ssr.mjs +1 -1
  136. package/.output/server/_ssr/start-BXUOv_n8.mjs +4 -0
  137. package/.output/server/_ssr/table-NGWV8B-S.mjs +53 -0
  138. package/.output/server/_ssr/updateFailures-Jwe2Baab.mjs +24 -0
  139. package/.output/server/_ssr/{uuidv7-D0QFkPL_.mjs → uuidv7-C8bwiZr8.mjs} +2 -2
  140. package/.output/server/_tanstack-start-manifest_v-WQ5qGn8n.mjs +124 -0
  141. package/.output/server/index.mjs +267 -162
  142. package/LICENSE +13 -14
  143. package/README.md +82 -72
  144. package/lib/index.d.mts +23 -11
  145. package/lib/vite-internal.mjs +13 -3
  146. package/lib/vite.d.mts +2 -0
  147. package/package.json +14 -14
  148. package/src/components/AppSidebar.tsx +100 -71
  149. package/src/components/ConsoleAccessPage.tsx +5 -1
  150. package/src/components/ConsoleFeatureUnavailable.tsx +80 -0
  151. package/src/components/NotFoundPage.tsx +7 -7
  152. package/src/components/features/FeatureSlots.tsx +99 -0
  153. package/src/components/features/api-keys/apiKeysFeatureUi.tsx +15 -0
  154. package/src/components/features/bundles/BundleMetadata.tsx +8 -5
  155. package/src/components/features/bundles/RolloutCohortsDialog.tsx +1 -1
  156. package/src/components/features/channels/ChannelManagementDialog.tsx +2 -5
  157. package/src/components/features/insights/AppUsage.tsx +370 -0
  158. package/src/components/features/insights/EstimatedCount.tsx +18 -0
  159. package/src/components/features/insights/EventDetails.tsx +117 -37
  160. package/src/components/features/insights/EventHistoryCard.tsx +112 -26
  161. package/src/components/features/insights/EventHistoryList.tsx +2 -2
  162. package/src/components/features/insights/InsightsControls.tsx +265 -102
  163. package/src/components/features/insights/InsightsErrorAlert.tsx +14 -1
  164. package/src/components/features/insights/InsightsInfo.tsx +48 -0
  165. package/src/components/features/insights/InsightsOverview.tsx +176 -173
  166. package/src/components/features/insights/InsightsPageHeader.tsx +35 -20
  167. package/src/components/features/insights/InsightsPeriodSelector.tsx +89 -0
  168. package/src/components/features/insights/InstallationHistoryCard.tsx +52 -10
  169. package/src/components/features/insights/InstallationMatchesCard.tsx +1 -1
  170. package/src/components/features/insights/ReleaseActivity.tsx +188 -0
  171. package/src/components/features/insights/ReportingDevicesSummary.tsx +65 -0
  172. package/src/components/features/insights/UpdateFailures.tsx +319 -0
  173. package/src/components/features/insights/insightsFeatureUi.tsx +35 -0
  174. package/src/components/features/releases/ReleaseEditorSheet.tsx +30 -7
  175. package/src/components/ui/card.tsx +1 -1
  176. package/src/components/ui/empty.tsx +101 -0
  177. package/src/components/ui/scroll-area.tsx +52 -0
  178. package/src/components/ui/sidebar.tsx +22 -29
  179. package/src/components/ui/tabs.tsx +81 -0
  180. package/src/index.ts +26 -19
  181. package/src/lib/api-keys-api.ts +0 -28
  182. package/src/lib/api-keys-rpc.ts +27 -38
  183. package/src/lib/api-rpc.ts +189 -266
  184. package/src/lib/api.ts +19 -102
  185. package/src/lib/bundle-activity.ts +31 -0
  186. package/src/lib/console-access.ts +20 -0
  187. package/src/lib/console-features-api.ts +68 -0
  188. package/src/lib/console-features-rpc.ts +13 -0
  189. package/src/lib/console-features.ts +91 -0
  190. package/src/lib/insights-api.ts +37 -1
  191. package/src/lib/insights-failures-rpc.ts +21 -0
  192. package/src/lib/insights-failures.ts +129 -0
  193. package/src/lib/insights-recovery-rpc.ts +51 -0
  194. package/src/lib/insights-recovery.ts +68 -0
  195. package/src/lib/insights-retention.ts +21 -0
  196. package/src/lib/insights-rpc.ts +30 -12
  197. package/src/lib/insights-search.ts +58 -0
  198. package/src/lib/insights-usage-rpc.ts +29 -0
  199. package/src/lib/insights-usage.ts +74 -0
  200. package/src/lib/insights-view.ts +38 -2
  201. package/src/lib/scroll-restoration.ts +21 -0
  202. package/src/lib/server/adminInsights.ts +124 -0
  203. package/src/lib/server/auth.server.ts +13 -5
  204. package/src/lib/server/bundleActivity.ts +37 -0
  205. package/src/lib/server/config.server.ts +21 -74
  206. package/src/lib/server/console-feature-apis.ts +59 -0
  207. package/src/lib/server/console-runtime.server.ts +82 -38
  208. package/src/lib/server/downloadBundle.ts +16 -15
  209. package/src/lib/server/getBundleChildren.ts +31 -122
  210. package/src/lib/server/insightsRecovery.ts +55 -0
  211. package/src/lib/server/insightsUsage.ts +63 -0
  212. package/src/lib/server/listReleases.ts +109 -44
  213. package/src/lib/server/releaseReachability.ts +8 -7
  214. package/src/lib/server/runtime.server.ts +120 -31
  215. package/src/lib/server/updateFailures.ts +31 -0
  216. package/src/routeTree.gen.ts +44 -44
  217. package/src/router.tsx +3 -2
  218. package/src/routes/-installations-search.ts +32 -8
  219. package/src/routes/-releases-search.ts +76 -29
  220. package/src/routes/__root.tsx +10 -4
  221. package/src/routes/api/bundles/$bundleId/download.ts +2 -5
  222. package/src/routes/api-keys.tsx +5 -2
  223. package/src/routes/index.tsx +167 -104
  224. package/src/routes/insights.tsx +100 -59
  225. package/src/routes/insights_.distribution.tsx +398 -0
  226. package/src/routes/installations.tsx +98 -41
  227. package/src/vite-internal.ts +15 -3
  228. package/src/vite.ts +2 -0
  229. package/.output/public/assets/HashValueDisplay-CB0Eskit.js +0 -1
  230. package/.output/public/assets/InsightsPageHeader-Car5LNiZ.js +0 -1
  231. package/.output/public/assets/api-keys-BzKocqRy.js +0 -1
  232. package/.output/public/assets/api-keys-api-BHcODB7q.js +0 -1
  233. package/.output/public/assets/card-Dhr_eFYj.js +0 -1
  234. package/.output/public/assets/chart-no-axes-combined-Dy4WJv2U.js +0 -1
  235. package/.output/public/assets/composite-Bp98A0Ld.js +0 -1
  236. package/.output/public/assets/createServerFn-CA8fs7QD.js +0 -3
  237. package/.output/public/assets/dialog-CUTrcPlB.js +0 -1
  238. package/.output/public/assets/dist-C_NydL0e.js +0 -1
  239. package/.output/public/assets/index-DdAz-CXv.js +0 -10
  240. package/.output/public/assets/input-group-cSOG4wh_.js +0 -1
  241. package/.output/public/assets/insights-C0PBSZ-n.js +0 -1
  242. package/.output/public/assets/installations-CE33wgbY.js +0 -2
  243. package/.output/public/assets/installations-CStZja8x.js +0 -1
  244. package/.output/public/assets/lazyRouteComponent-Ccp3bwBY.js +0 -1
  245. package/.output/public/assets/link-CI8idAUi.js +0 -1
  246. package/.output/public/assets/loader-circle-BoxLrsOu.js +0 -1
  247. package/.output/public/assets/preload-helper-CQ36nxok.js +0 -1
  248. package/.output/public/assets/refresh-cw-Bqc72UZG.js +0 -1
  249. package/.output/public/assets/routes-DGVXdzpw.js +0 -2
  250. package/.output/public/assets/routes-DTlwOr8I.js +0 -1
  251. package/.output/public/assets/shield-check-uK3MHWJZ.js +0 -1
  252. package/.output/public/assets/signing-CMf4aqDO.js +0 -1
  253. package/.output/public/assets/styles-BCvbtKsm.css +0 -2
  254. package/.output/public/assets/table-2vcV89QB.js +0 -1
  255. package/.output/public/assets/useCompositeListItem-CHLITE_4.js +0 -1
  256. package/.output/public/assets/x-DCd0j8c6.js +0 -1
  257. package/.output/server/_ssr/InsightsPageHeader-Df4Brj8u.mjs +0 -484
  258. package/.output/server/_ssr/api-keys-api-BUPQVSpk.mjs +0 -60
  259. package/.output/server/_ssr/api-keys-rpc-Cs7tS5_j.mjs +0 -136
  260. package/.output/server/_ssr/api-rpc-tAupfGQm.mjs +0 -1399
  261. package/.output/server/_ssr/auth.server-DW71WzsD.mjs +0 -47
  262. package/.output/server/_ssr/bundle-signing-rpc-BhnBw0-d.mjs +0 -16
  263. package/.output/server/_ssr/bundle-signing.server-C4NW5mWx.mjs +0 -12
  264. package/.output/server/_ssr/card-BRiPmi0C.mjs +0 -108
  265. package/.output/server/_ssr/config-Dv8qLDZ0.mjs +0 -13
  266. package/.output/server/_ssr/config.server-afDuAwaG.mjs +0 -368
  267. package/.output/server/_ssr/databaseRows-5bCRTxm-.mjs +0 -126
  268. package/.output/server/_ssr/deleteBundle-BTGwBgzx.mjs +0 -66
  269. package/.output/server/_ssr/getBundleChildren-C0vh4ZvE.mjs +0 -50
  270. package/.output/server/_ssr/insights-BdS364Xu.mjs +0 -460
  271. package/.output/server/_ssr/insightsContract-fjJDBeEE.mjs +0 -303
  272. package/.output/server/_ssr/installations-CtA59MQG.mjs +0 -29
  273. package/.output/server/_ssr/routes-CKrrS2q2.mjs +0 -37
  274. package/.output/server/_ssr/runtime.server-DacU1TBV.mjs +0 -438
  275. package/.output/server/_ssr/server-D_C2rMzf.mjs +0 -7468
  276. package/.output/server/_ssr/signing-Dz1WkZOf.mjs +0 -133
  277. package/.output/server/_ssr/start-DpViQGnt.mjs +0 -4
  278. package/.output/server/_tanstack-start-manifest_v-2MjTyxil.mjs +0 -97
  279. package/src/components/features/insights/InsightsBundleReports.tsx +0 -51
  280. package/src/components/features/signing/BundleSigningPage.tsx +0 -139
  281. package/src/lib/bundle-signing-api.ts +0 -14
  282. package/src/lib/bundle-signing-rpc.ts +0 -16
  283. package/src/lib/server/bundle-signing.server.ts +0 -23
  284. package/src/lib/server/deleteBundle.ts +0 -145
  285. package/src/routes/signing.tsx +0 -37
@@ -1,27 +1,24 @@
1
1
  import {
2
- DatabasePluginInputError,
3
- type Bundle,
4
- type ChannelDeleteInput,
5
- type ChannelInsertInput,
6
- type DatabaseBundleQueryOptions,
7
- deleteRelease as deleteReleaseMutation,
8
- preflightReleasePolicy,
9
- promoteRelease as promoteReleaseMutation,
2
+ type ChannelDeleteResult,
3
+ type ChannelRow,
4
+ type ReleaseFilter,
10
5
  type ReleasePolicyPatch,
11
- updateReleasePolicy,
6
+ rowToBundle,
12
7
  } from "@hot-updater/plugin-core";
13
8
  import { createServerFn } from "@tanstack/react-start";
14
9
 
10
+ import { consoleAccess } from "./console-access";
15
11
  import { DEFAULT_PAGE_LIMIT } from "./constants";
16
12
  import { withPublicBundleMutationErrors } from "./public-bundle-error";
17
- import { listReleases } from "./server/listReleases";
13
+ import { listReleases, readReleaseFilter } from "./server/listReleases";
18
14
  import { addReleaseReachability } from "./server/releaseReachability";
19
15
 
20
16
  type GetBundlesInput = {
21
17
  platform?: "ios" | "android";
22
- page?: number;
23
- limit?: string;
18
+ limit?: number;
19
+ /** Bundles older than this id: the next page. */
24
20
  after?: string;
21
+ /** Bundles newer than this id: the previous page. */
25
22
  before?: string;
26
23
  };
27
24
 
@@ -37,24 +34,14 @@ type GetBundleChildCountsInput = {
37
34
  bundleIds: string[];
38
35
  };
39
36
 
40
- type DeleteBundleInput = {
41
- bundleId: string;
42
- };
43
-
44
- type DeleteBundlesInput = {
45
- bundleIds: string[];
46
- };
47
-
48
37
  type GetReleasesInput = {
49
- afterReleaseId?: string;
38
+ /** One of the filter sets the release indexes serve. */
39
+ filter?: ReleaseFilter;
40
+ /** Releases older than this id: the next page. */
50
41
  beforeReleaseId?: string;
51
- bundleId?: string;
52
- channelId?: string;
53
- enabled?: boolean;
54
- platform?: "ios" | "android";
42
+ /** Releases newer than this id: the previous page. */
43
+ afterReleaseId?: string;
55
44
  limit?: number;
56
- page?: number;
57
- targetAppVersion?: string;
58
45
  };
59
46
 
60
47
  type ReleaseMutationInput = {
@@ -68,78 +55,78 @@ type DeleteReleaseInput = {
68
55
  releaseId: string;
69
56
  };
70
57
 
58
+ const MAX_PAGE_LIMIT = 100;
59
+
60
+ const pageLimit = (limit: number | undefined) => {
61
+ const value = limit ?? DEFAULT_PAGE_LIMIT;
62
+ if (!Number.isSafeInteger(value) || value < 1 || value > MAX_PAGE_LIMIT) {
63
+ throw new Error(`limit must be between 1 and ${MAX_PAGE_LIMIT}.`);
64
+ }
65
+ return value;
66
+ };
67
+
68
+ const prepare = async () => {
69
+ const { prepareConfig } = await import("./server/config.server");
70
+ return prepareConfig();
71
+ };
72
+
71
73
  export const getReleases = createServerFn({ method: "GET" })
72
- .inputValidator((input: GetReleasesInput | undefined) => input)
74
+ .middleware([consoleAccess])
75
+ .validator((input: GetReleasesInput | undefined) => ({
76
+ filter: readReleaseFilter(input?.filter),
77
+ ...(input?.afterReleaseId === undefined
78
+ ? {}
79
+ : { afterReleaseId: input.afterReleaseId }),
80
+ ...(input?.beforeReleaseId === undefined
81
+ ? {}
82
+ : { beforeReleaseId: input.beforeReleaseId }),
83
+ limit: pageLimit(input?.limit),
84
+ }))
73
85
  .handler(async ({ data }) => {
74
- const { prepareConfig } = await import("./server/config.server");
75
- const { config } = await prepareConfig();
76
- const result = await listReleases(config.database.models.releases, {
77
- ...(data?.afterReleaseId === undefined
78
- ? {}
79
- : { afterReleaseId: data.afterReleaseId }),
80
- ...(data?.beforeReleaseId === undefined
81
- ? {}
82
- : { beforeReleaseId: data.beforeReleaseId }),
83
- ...(data?.bundleId === undefined ? {} : { bundleId: data.bundleId }),
84
- ...(data?.channelId === undefined ? {} : { channelId: data.channelId }),
85
- ...(data?.enabled === undefined ? {} : { enabled: data.enabled }),
86
- ...(data?.page === undefined ? {} : { page: data.page }),
87
- ...(data?.platform === undefined ? {} : { platform: data.platform }),
88
- ...(data?.targetAppVersion === undefined
89
- ? {}
90
- : { targetAppVersion: data.targetAppVersion }),
91
- limit: data?.limit ?? DEFAULT_PAGE_LIMIT,
92
- });
93
- const releases = await addReleaseReachability(
94
- config.database.models.releaseCatalogs,
95
- result.data,
96
- );
86
+ const { core } = await prepare();
87
+ const result = await listReleases(core, data);
97
88
  return {
98
89
  ...result,
99
- data: releases,
90
+ data: await addReleaseReachability(core, result.data),
100
91
  };
101
92
  });
102
93
 
103
94
  export const getRelease = createServerFn({ method: "GET" })
104
- .inputValidator((input: { releaseId: string }) => input)
105
- .handler(async ({ data }) => {
106
- const { prepareConfig } = await import("./server/config.server");
107
- const { config } = await prepareConfig();
108
- return config.database.models.releases.findById(data.releaseId);
109
- });
95
+ .middleware([consoleAccess])
96
+ .validator((input: { releaseId: string }) => input)
97
+ .handler(async ({ data }) =>
98
+ (await prepare()).core.getRelease(data.releaseId),
99
+ );
110
100
 
111
101
  export const updateRelease = createServerFn({ method: "POST" })
112
- .inputValidator((input: ReleaseMutationInput) => input)
102
+ .middleware([consoleAccess])
103
+ .validator((input: ReleaseMutationInput) => input)
113
104
  .handler(async ({ data }) => {
114
- const { prepareConfig } = await import("./server/config.server");
115
- const { config } = await prepareConfig();
116
- return withPublicBundleMutationErrors(() =>
117
- updateReleasePolicy({ database: config.database, ...data }),
118
- );
105
+ const { core } = await prepare();
106
+ return withPublicBundleMutationErrors(() => core.updateReleasePolicy(data));
119
107
  });
120
108
 
121
109
  export const preflightRelease = createServerFn({ method: "POST" })
122
- .inputValidator((input: ReleaseMutationInput) => input)
110
+ .middleware([consoleAccess])
111
+ .validator((input: ReleaseMutationInput) => input)
123
112
  .handler(async ({ data }) => {
124
- const { prepareConfig } = await import("./server/config.server");
125
- const { config } = await prepareConfig();
113
+ const { core } = await prepare();
126
114
  return withPublicBundleMutationErrors(() =>
127
- preflightReleasePolicy({ database: config.database, ...data }),
115
+ core.preflightReleasePolicy(data),
128
116
  );
129
117
  });
130
118
 
131
119
  export const deleteRelease = createServerFn({ method: "POST" })
132
- .inputValidator((input: DeleteReleaseInput) => input)
120
+ .middleware([consoleAccess])
121
+ .validator((input: DeleteReleaseInput) => input)
133
122
  .handler(async ({ data }) => {
134
- const { prepareConfig } = await import("./server/config.server");
135
- const { config } = await prepareConfig();
136
- return withPublicBundleMutationErrors(() =>
137
- deleteReleaseMutation({ database: config.database, ...data }),
138
- );
123
+ const { core } = await prepare();
124
+ return withPublicBundleMutationErrors(() => core.deleteRelease(data));
139
125
  });
140
126
 
141
127
  export const promoteRelease = createServerFn({ method: "POST" })
142
- .inputValidator(
128
+ .middleware([consoleAccess])
129
+ .validator(
143
130
  (input: {
144
131
  action: "copy" | "move";
145
132
  expectedRevision?: number;
@@ -148,54 +135,60 @@ export const promoteRelease = createServerFn({ method: "POST" })
148
135
  }) => input,
149
136
  )
150
137
  .handler(async ({ data }) => {
151
- const { prepareConfig } = await import("./server/config.server");
152
- const { config } = await prepareConfig();
153
- return withPublicBundleMutationErrors(() =>
154
- promoteReleaseMutation({ database: config.database, ...data }),
155
- );
138
+ const { core } = await prepare();
139
+ return withPublicBundleMutationErrors(() => core.promoteRelease(data));
156
140
  });
157
141
 
158
142
  export const getReleaseCatalogDiagnostics = createServerFn({ method: "GET" })
159
- .inputValidator((input: { scopeKey: string }) => input)
160
- .handler(async ({ data }) => {
161
- const { prepareConfig } = await import("./server/config.server");
162
- const { config } = await prepareConfig();
163
- return config.database.models.releaseCatalogs.findByScopeKey(data.scopeKey);
164
- });
143
+ .middleware([consoleAccess])
144
+ .validator((input: { scopeKey: string }) => input)
145
+ .handler(async ({ data }) =>
146
+ (await prepare()).core.getReleaseCatalogRow(data.scopeKey),
147
+ );
165
148
 
166
149
  // GET /api/config
167
- export const getConfig = createServerFn().handler(async () => {
168
- try {
169
- const { prepareConfig } = await import("./server/config.server");
170
- const { config } = await prepareConfig();
171
- return { console: config.console };
172
- } catch (error) {
173
- console.error("Error during config retrieval:", error);
174
- throw error;
175
- }
176
- });
150
+ export const getConfig = createServerFn()
151
+ .middleware([consoleAccess])
152
+ .handler(async () => {
153
+ try {
154
+ const { config } = await prepare();
155
+ return { console: { gitUrl: config.gitUrl } };
156
+ } catch (error) {
157
+ console.error("Error during config retrieval:", error);
158
+ throw error;
159
+ }
160
+ });
177
161
 
178
162
  // GET /api/channels
179
- export const getChannels = createServerFn().handler(async () => {
180
- try {
181
- const { prepareConfig } = await import("./server/config.server");
182
- const { databaseClient } = await prepareConfig();
183
- const channels = await databaseClient.getChannels();
184
- return channels ?? [];
185
- } catch (error) {
186
- console.error("Error during channel retrieval:", error);
187
- throw error;
188
- }
189
- });
163
+ export const getChannels = createServerFn()
164
+ .middleware([consoleAccess])
165
+ .handler(async (): Promise<ChannelRow[]> => {
166
+ try {
167
+ return await (await prepare()).core.listChannels();
168
+ } catch (error) {
169
+ console.error("Error during channel retrieval:", error);
170
+ throw error;
171
+ }
172
+ });
190
173
 
191
174
  // POST /api/channels
192
175
  export const createChannel = createServerFn({ method: "POST" })
193
- .inputValidator((input: ChannelInsertInput) => input)
176
+ .middleware([consoleAccess])
177
+ .validator((input: { name: string }) => {
178
+ const name = typeof input?.name === "string" ? input.name.trim() : "";
179
+ if (name.length === 0) throw new Error("Channel name is required.");
180
+ return { name };
181
+ })
194
182
  .handler(async ({ data }) => {
195
183
  try {
196
- const { prepareConfig } = await import("./server/config.server");
197
- const { databaseClient } = await prepareConfig();
198
- return { data: await databaseClient.insertChannel(data) };
184
+ const { core } = await prepare();
185
+ const existing = await core.findChannelByName(data.name);
186
+ if (existing !== null) {
187
+ return { data: { row: existing, inserted: false } };
188
+ }
189
+ return {
190
+ data: { row: await core.ensureChannel(data.name), inserted: true },
191
+ };
199
192
  } catch (error) {
200
193
  console.error("Error during channel creation:", error);
201
194
  throw error;
@@ -204,12 +197,11 @@ export const createChannel = createServerFn({ method: "POST" })
204
197
 
205
198
  // DELETE /api/channels/:id
206
199
  export const deleteChannel = createServerFn({ method: "POST" })
207
- .inputValidator((input: ChannelDeleteInput) => input)
208
- .handler(async ({ data }) => {
200
+ .middleware([consoleAccess])
201
+ .validator((input: { id: string }) => input)
202
+ .handler(async ({ data }): Promise<{ data: ChannelDeleteResult }> => {
209
203
  try {
210
- const { prepareConfig } = await import("./server/config.server");
211
- const { databaseClient } = await prepareConfig();
212
- return { data: await databaseClient.deleteChannel(data) };
204
+ return { data: await (await prepare()).core.deleteChannel(data.id) };
213
205
  } catch (error) {
214
206
  console.error("Error during channel deletion:", error);
215
207
  throw error;
@@ -217,78 +209,71 @@ export const deleteChannel = createServerFn({ method: "POST" })
217
209
  });
218
210
 
219
211
  // GET /api/config-loaded
220
- export const getConfigLoaded = createServerFn().handler(async () => {
221
- try {
222
- const [{ getRequest }, { requireConsoleAccess }] = await Promise.all([
223
- import("@tanstack/react-start/server"),
224
- import("./server/auth.server"),
225
- ]);
226
- await requireConsoleAccess(getRequest());
227
- const { isConfigLoaded } = await import("./server/config.server");
228
- const configLoaded = isConfigLoaded();
229
- return { configLoaded };
230
- } catch (error) {
231
- console.error("Error during config loaded retrieval:", error);
232
- throw error;
233
- }
234
- });
212
+ export const getConfigLoaded = createServerFn()
213
+ .middleware([consoleAccess])
214
+ .handler(async () => {
215
+ try {
216
+ const { isConfigLoaded } = await import("./server/config.server");
217
+ const configLoaded = isConfigLoaded();
218
+ return { configLoaded };
219
+ } catch (error) {
220
+ console.error("Error during config loaded retrieval:", error);
221
+ throw error;
222
+ }
223
+ });
235
224
 
236
- // GET /api/bundles
225
+ // GET /api/bundles: newest first, one page by key; the total is one counter row.
237
226
  export const getBundles = createServerFn({ method: "GET" })
238
- .inputValidator((input: GetBundlesInput | undefined) => input)
227
+ .middleware([consoleAccess])
228
+ .validator((input: GetBundlesInput | undefined) => {
229
+ if (input?.after !== undefined && input.before !== undefined) {
230
+ throw new Error("Page by after or before, not both.");
231
+ }
232
+ return {
233
+ ...(input?.platform === undefined ? {} : { platform: input.platform }),
234
+ ...(input?.after === undefined ? {} : { after: input.after }),
235
+ ...(input?.before === undefined ? {} : { before: input.before }),
236
+ limit: pageLimit(input?.limit),
237
+ };
238
+ })
239
239
  .handler(async ({ data }) => {
240
240
  try {
241
- const { prepareConfig } = await import("./server/config.server");
242
- const query = {
243
- platform: data?.platform ?? undefined,
244
- page:
245
- typeof data?.page === "number" &&
246
- Number.isInteger(data.page) &&
247
- data.page > 1
248
- ? data.page
249
- : undefined,
250
- limit: data?.limit ? Number(data.limit) : DEFAULT_PAGE_LIMIT,
251
- after: data?.after ?? undefined,
252
- before: data?.before ?? undefined,
241
+ const { core } = await prepare();
242
+ const platform =
243
+ data.platform === undefined ? {} : { platform: data.platform };
244
+ const [page, total] = await Promise.all([
245
+ data.before === undefined
246
+ ? core.listBundles({
247
+ ...platform,
248
+ order: "desc",
249
+ limit: data.limit,
250
+ ...(data.after === undefined ? {} : { after: data.after }),
251
+ })
252
+ : core
253
+ .listBundles({
254
+ ...platform,
255
+ order: "asc",
256
+ limit: data.limit,
257
+ after: data.before,
258
+ })
259
+ .then((rows) => rows.reverse()),
260
+ core.countBundles(data.platform),
261
+ ]);
262
+ const full = page.length === data.limit;
263
+ const first = page[0]?.bundle.id;
264
+ const last = page.at(-1)?.bundle.id;
265
+ return {
266
+ data: page.map(({ bundle, patches }) => rowToBundle(bundle, patches)),
267
+ total,
268
+ // A full page may have more past it; a short one ended the range.
269
+ ...(last !== undefined && (data.before !== undefined || full)
270
+ ? { next: last }
271
+ : {}),
272
+ ...(first !== undefined &&
273
+ (data.after !== undefined || (data.before !== undefined && full))
274
+ ? { previous: first }
275
+ : {}),
253
276
  };
254
- if (
255
- (query.after !== undefined && query.before !== undefined) ||
256
- (query.page !== undefined &&
257
- (query.after !== undefined || query.before !== undefined))
258
- ) {
259
- throw new DatabasePluginInputError("invalid-pagination");
260
- }
261
- const pagination =
262
- query.page !== undefined
263
- ? { page: query.page }
264
- : query.after !== undefined
265
- ? { cursor: { after: query.after } }
266
- : query.before !== undefined
267
- ? { cursor: { before: query.before } }
268
- : {};
269
-
270
- const { databaseClient } = await prepareConfig();
271
- const bundleQueryOptions: DatabaseBundleQueryOptions = {
272
- where: {
273
- platform: query.platform,
274
- },
275
- limit: query.limit,
276
- ...pagination,
277
- };
278
- const bundles = await databaseClient.getBundles(bundleQueryOptions);
279
-
280
- return (
281
- bundles ?? {
282
- data: [],
283
- pagination: {
284
- total: 0,
285
- hasNextPage: false,
286
- hasPreviousPage: false,
287
- currentPage: 1,
288
- totalPages: 0,
289
- },
290
- }
291
- );
292
277
  } catch (error) {
293
278
  console.error("Error during bundle retrieval:", error);
294
279
  throw error;
@@ -297,13 +282,14 @@ export const getBundles = createServerFn({ method: "GET" })
297
282
 
298
283
  // GET /api/bundles/:bundleId
299
284
  export const getBundle = createServerFn({ method: "GET" })
300
- .inputValidator((input: GetBundleInput) => input)
285
+ .middleware([consoleAccess])
286
+ .validator((input: GetBundleInput) => input)
301
287
  .handler(async ({ data }) => {
302
288
  try {
303
- const { prepareConfig } = await import("./server/config.server");
304
- const { databaseClient } = await prepareConfig();
305
- const bundle = await databaseClient.getBundleById(data.bundleId);
306
- return bundle ?? null;
289
+ const detail = await (await prepare()).core.getBundle(data.bundleId);
290
+ return detail === null
291
+ ? null
292
+ : rowToBundle(detail.bundle, detail.patches);
307
293
  } catch (error) {
308
294
  console.error("Error during bundle retrieval:", error);
309
295
  throw error;
@@ -311,17 +297,13 @@ export const getBundle = createServerFn({ method: "GET" })
311
297
  });
312
298
 
313
299
  export const getBundleChildren = createServerFn({ method: "GET" })
314
- .inputValidator((input: GetBundleChildrenInput) => input)
300
+ .middleware([consoleAccess])
301
+ .validator((input: GetBundleChildrenInput) => input)
315
302
  .handler(async ({ data }) => {
316
303
  try {
317
- const { prepareConfig } = await import("./server/config.server");
318
- const { getBundleChildren: getBundleChildrenWithConfig } =
319
- await import("./server/getBundleChildren");
320
- const { databaseClient } = await prepareConfig();
321
-
322
- return await getBundleChildrenWithConfig(data, {
323
- databaseClient,
324
- });
304
+ const [{ core }, { getBundleChildren: readBundleChildren }] =
305
+ await Promise.all([prepare(), import("./server/getBundleChildren")]);
306
+ return await readBundleChildren(core, data.baseBundleId);
325
307
  } catch (error) {
326
308
  console.error("Error during bundle children retrieval:", error);
327
309
  throw error;
@@ -329,79 +311,20 @@ export const getBundleChildren = createServerFn({ method: "GET" })
329
311
  });
330
312
 
331
313
  export const getBundleChildCounts = createServerFn({ method: "GET" })
332
- .inputValidator((input: GetBundleChildCountsInput) => input)
333
- .handler(async ({ data }) => {
334
- try {
335
- const { prepareConfig } = await import("./server/config.server");
336
- const { getBundleChildCounts: getBundleChildCountsWithConfig } =
337
- await import("./server/getBundleChildren");
338
- const { databaseClient } = await prepareConfig();
339
-
340
- return await getBundleChildCountsWithConfig(data.bundleIds, {
341
- databaseClient,
342
- });
343
- } catch (error) {
344
- console.error("Error during bundle child count retrieval:", error);
345
- throw error;
314
+ .middleware([consoleAccess])
315
+ .validator((input: GetBundleChildCountsInput) => {
316
+ if (!Array.isArray(input?.bundleIds) || input.bundleIds.length > 100) {
317
+ throw new Error("Choose up to 100 bundles.");
346
318
  }
347
- });
348
-
349
- // POST /api/bundles
350
- export const createBundle = createServerFn({ method: "POST" })
351
- .inputValidator((input: Bundle) => input)
352
- .handler(async ({ data }) => {
353
- try {
354
- const { prepareConfig } = await import("./server/config.server");
355
- const { databaseClient } = await prepareConfig();
356
- await databaseClient.insertBundle(data);
357
- return { success: true, bundleId: data.id };
358
- } catch (error) {
359
- console.error("Error during bundle creation:", error);
360
- throw error;
361
- }
362
- });
363
-
364
- // DELETE /api/bundles/:bundleId
365
- export const deleteBundle = createServerFn({ method: "POST" })
366
- .inputValidator((input: DeleteBundleInput) => input)
367
- .handler(async ({ data }) => {
368
- try {
369
- const { prepareConfig } = await import("./server/config.server");
370
- const { deleteBundle: deleteBundleWithStorage } =
371
- await import("./server/deleteBundle");
372
- const { databaseClient, storagePlugin } = await prepareConfig();
373
-
374
- await deleteBundleWithStorage(data, {
375
- databaseClient,
376
- storagePlugin,
377
- waitForStorageCleanup: false,
378
- });
379
-
380
- return { success: true };
381
- } catch (error) {
382
- console.error("Error during bundle deletion:", error);
383
- throw error;
384
- }
385
- });
386
-
387
- export const deleteBundles = createServerFn({ method: "POST" })
388
- .inputValidator((input: DeleteBundlesInput) => input)
319
+ return input;
320
+ })
389
321
  .handler(async ({ data }) => {
390
322
  try {
391
- const { prepareConfig } = await import("./server/config.server");
392
- const { deleteBundles: deleteBundlesWithStorage } =
393
- await import("./server/deleteBundle");
394
- const { databaseClient, storagePlugin } = await prepareConfig();
395
-
396
- const result = await deleteBundlesWithStorage(data, {
397
- databaseClient,
398
- storagePlugin,
399
- waitForStorageCleanup: false,
400
- });
401
-
402
- return { success: true, ...result };
323
+ const [{ core }, { getBundleChildCounts: readBundleChildCounts }] =
324
+ await Promise.all([prepare(), import("./server/getBundleChildren")]);
325
+ return await readBundleChildCounts(core, data.bundleIds);
403
326
  } catch (error) {
404
- console.error("Error during bundle deletion:", error);
327
+ console.error("Error during bundle child count retrieval:", error);
405
328
  throw error;
406
329
  }
407
330
  });