@hot-updater/console 1.0.0-rc.4 → 1.0.0-rc.40

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 (288) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/ConsoleFeatureUnavailable-BH7LLqAg.js +1 -0
  3. package/.output/public/assets/EventDetails-3DgVjwDn.js +1 -0
  4. package/.output/public/assets/InsightsInfo-NUuLFYqg.js +1 -0
  5. package/.output/public/assets/InsightsPageHeader-DqCp0vf7.js +1 -0
  6. package/.output/public/assets/NotFoundPage-CkgdpWvl.js +1 -0
  7. package/.output/public/assets/alert-dialog-DXxrSU0G.js +1 -0
  8. package/.output/public/assets/api-BiZP_i-u.js +1 -0
  9. package/.output/public/assets/api-keys-DQDqmKtq.js +1 -0
  10. package/.output/public/assets/api-keys-DTQ1HrkR.js +1 -0
  11. package/.output/public/assets/arrow-left-BPK7iqvj.js +1 -0
  12. package/.output/public/assets/card-DKr2pZMA.js +1 -0
  13. package/.output/public/assets/console-features-api-BhUIxeL-.js +1 -0
  14. package/.output/public/assets/dialog-DxjO7ofz.js +1 -0
  15. package/.output/public/assets/dist-BzWwzt98.js +1 -0
  16. package/.output/public/assets/empty-DtangHOp.js +1 -0
  17. package/.output/public/assets/field-bPoDrs6K.js +1 -0
  18. package/.output/public/assets/index-B7BSdp0k.js +11 -0
  19. package/.output/public/assets/input-group-_PD0i7wZ.js +1 -0
  20. package/.output/public/assets/insights-BBya_x8N.js +1 -0
  21. package/.output/public/assets/insights-CevVB_8E.js +2 -0
  22. package/.output/public/assets/insights-DMH-zhbe.js +42 -0
  23. package/.output/public/assets/insights-usage-rpc-pz2XQBi3.js +1 -0
  24. package/.output/public/assets/insights_.distribution-B9MOEnzZ.js +2 -0
  25. package/.output/public/assets/insights_.distribution-O73SKvoa.js +1 -0
  26. package/.output/public/assets/insights_.distribution-WTcKITzb.js +1 -0
  27. package/.output/public/assets/installations-CstW4tEL.js +1 -0
  28. package/.output/public/assets/installations-DtZj5jk2.js +1 -0
  29. package/.output/public/assets/installations-LJBhFDEM.js +2 -0
  30. package/.output/public/assets/loader-circle-iTGehfyV.js +1 -0
  31. package/.output/public/assets/mutation-B4EZNS91.js +1 -0
  32. package/.output/public/assets/preload-helper-D9SUwQT7.js +1 -0
  33. package/.output/public/assets/refresh-cw-3fSQ1FYY.js +1 -0
  34. package/.output/public/assets/routes-CJSxovHS.js +1 -0
  35. package/.output/public/assets/routes-DyZCr794.js +2 -0
  36. package/.output/public/assets/sidebar-RBvHzq8e.js +3 -0
  37. package/.output/public/assets/styles-DwA6mhnh.css +2 -0
  38. package/.output/public/assets/table-BYmouPt9.js +1 -0
  39. package/.output/public/assets/useCompositeListItem-BxJspDxS.js +1 -0
  40. package/.output/public/assets/valueToPercent-Ci2-fmWp.js +1 -0
  41. package/.output/server/{__23tanstack-start-server-fn-resolver-Dr2ixDgQ.mjs → __23tanstack-start-server-fn-resolver-CUp7Too4.mjs} +60 -52
  42. package/.output/server/_libs/@base-ui/react+[...].mjs +7219 -3692
  43. package/.output/server/_libs/@tanstack/react-router+[...].mjs +3802 -4022
  44. package/.output/server/_libs/@tanstack/react-router-ssr-query+[...].mjs +140 -97
  45. package/.output/server/_libs/lucide-react.mjs +114 -31
  46. package/.output/server/_libs/next-themes.mjs +1 -1
  47. package/.output/server/_libs/react-redux+[...].mjs +1 -1
  48. package/.output/server/_libs/recharts+[...].mjs +483 -901
  49. package/.output/server/_libs/sonner.mjs +1 -1
  50. package/.output/server/_libs/tanstack__history.mjs +68 -41
  51. package/.output/server/_libs/tanstack__query-core.mjs +1994 -310
  52. package/.output/server/_libs/tanstack__react-query.mjs +448 -21
  53. package/.output/server/_libs/verkit.mjs +99 -1
  54. package/.output/server/_ssr/ConsoleFeatureUnavailable-BxaV7ca0.mjs +58 -0
  55. package/.output/server/_ssr/EventDetails-B5HHZsCk.mjs +344 -0
  56. package/.output/server/_ssr/InsightsInfo-C7K_HKHZ.mjs +75 -0
  57. package/.output/server/_ssr/InsightsPageHeader-BPaYzzkg.mjs +183 -0
  58. package/.output/server/_ssr/NotFoundPage-CyBONH8d.mjs +37 -0
  59. package/.output/server/_ssr/{dialog-DUaIgpgd.mjs → alert-dialog-BsqgyNOZ.mjs} +6 -83
  60. package/.output/server/_ssr/api-keys-CY1d8bCZ.mjs +5 -0
  61. package/.output/server/_ssr/{api-keys-DJml_XoK.mjs → api-keys-D8R-eRJ-.mjs} +49 -10
  62. package/.output/server/_ssr/api-keys-rpc-CC1ERVtk.mjs +52 -0
  63. package/.output/server/_ssr/api-otC0m2Cl.mjs +203 -0
  64. package/.output/server/_ssr/api-rpc-C99iexLk.mjs +296 -0
  65. package/.output/server/_ssr/{auth-rpc-D_hv52-J.mjs → auth-rpc-PABg7kHk.mjs} +6 -6
  66. package/.output/server/_ssr/auth.server-8-IRXBc-.mjs +5712 -0
  67. package/.output/server/_ssr/bundleActivity-BXSJbaQY.mjs +18 -0
  68. package/.output/server/_ssr/card-ijGSudc_.mjs +49 -0
  69. package/.output/server/_ssr/config-nsIcsHh8.mjs +15 -0
  70. package/.output/server/_ssr/config.server-08RES1G-.mjs +36 -0
  71. package/.output/server/_ssr/console-access-D0bQJ9tx.mjs +17 -0
  72. package/.output/server/_ssr/console-features-AGV2b_l5.mjs +55 -0
  73. package/.output/server/_ssr/console-features-api-BRGAxAgc.mjs +43 -0
  74. package/.output/server/_ssr/console-features-rpc-845alOXy.mjs +19 -0
  75. package/.output/server/_ssr/{createServerFn-B2hcXoPM.mjs → createMiddleware-BdBf_ezN.mjs} +67 -56
  76. package/.output/server/_ssr/{createServerRpc-DB29C_5p.mjs → createServerRpc-B_y2lrwA.mjs} +2 -2
  77. package/.output/server/_ssr/{databaseJsonValue-d6I3nAS4.mjs → databaseJsonValue-Bhxciy7Z.mjs} +28 -5
  78. package/.output/server/_ssr/databaseRows-DwMAjaF8.mjs +74 -0
  79. package/.output/server/_ssr/dialog-BnfVyv4I.mjs +84 -0
  80. package/.output/server/_ssr/{dist-CyzPaI5v.mjs → dist-Cxo9ghYv.mjs} +140 -6
  81. package/.output/server/_ssr/{downloadBundle-B3ert-pY.mjs → downloadBundle-D10vIrle.mjs} +10 -10
  82. package/.output/server/_ssr/empty-CnGZqF1a.mjs +49 -0
  83. package/.output/server/_ssr/{empty-plugin-adapters-B5QvGpEl.mjs → empty-plugin-adapters-CYdinE-i.mjs} +1 -1
  84. package/.output/server/_ssr/failureReports-_trbWCVo.mjs +33 -0
  85. package/.output/server/_ssr/{field-CqNUlqUq.mjs → field-CysUuRJx.mjs} +62 -4
  86. package/.output/server/_ssr/getBundleChildren-DLGwrnCV.mjs +22 -0
  87. package/.output/server/_ssr/{input-group-Bb8ueylQ.mjs → input-group-C44twsSf.mjs} +2 -2
  88. package/.output/server/_ssr/insights-Br6JnctH.mjs +5 -0
  89. package/.output/server/_ssr/insights-CgRV7dlP.mjs +2314 -0
  90. package/.output/server/_ssr/insights-CrrlG-bz.mjs +14 -0
  91. package/.output/server/_ssr/insights-api-MpLvDjmC.mjs +122 -0
  92. package/.output/server/_ssr/insights-errors-Cy03daYs.mjs +34 -0
  93. package/.output/server/_ssr/insights-failures-HHiiIbag.mjs +46 -0
  94. package/.output/server/_ssr/insights-failures-rpc-CGiDJbg-.mjs +36 -0
  95. package/.output/server/_ssr/{insights-recovery-DSFM-YTL.mjs → insights-recovery-Dpk6Mfb9.mjs} +9 -2
  96. package/.output/server/_ssr/insights-recovery-rpc-Bul_1cyL.mjs +32 -0
  97. package/.output/server/_ssr/{insights-rpc-DrIQCjpD.mjs → insights-rpc-D24DKKlx.mjs} +22 -14
  98. package/.output/server/_ssr/insights-usage-CLUWjUFz.mjs +29 -0
  99. package/.output/server/_ssr/insights-usage-rpc-iG8wRo4G.mjs +29 -0
  100. package/.output/server/_ssr/insights-usage-rpc-tVCHkzGH.mjs +41 -0
  101. package/.output/server/_ssr/insightsUsage-9X2sp3ja.mjs +56 -0
  102. package/.output/server/_ssr/insights_.distribution-Ckc_O360.mjs +16 -0
  103. package/.output/server/_ssr/insights_.distribution-DbO4X6X6.mjs +7 -0
  104. package/.output/server/_ssr/insights_.distribution-DsujaomV.mjs +347 -0
  105. package/.output/server/_ssr/{installations-YumqpNpa.mjs → installations-DV3sNoM5.mjs} +280 -364
  106. package/.output/server/_ssr/installations-DkJq_y8i.mjs +5 -0
  107. package/.output/server/_ssr/installations-F6vBSPUU.mjs +69 -0
  108. package/.output/server/_ssr/listReleases-BitHzOYB.mjs +79 -0
  109. package/.output/server/_ssr/release-adoption-NO2DVJwF.mjs +55 -0
  110. package/.output/server/_ssr/release-adoption-rpc-h_r3KQsi.mjs +41 -0
  111. package/.output/server/_ssr/releaseAdoption-CwFUzIZA.mjs +114 -0
  112. package/.output/server/_ssr/releaseManagement-B3e7I8J9.mjs +11 -0
  113. package/.output/server/_ssr/{router-iP95Vqi2.mjs → router-C_IshN2d.mjs} +134 -138
  114. package/.output/server/_ssr/{routes-ivsV2TDu.mjs → routes-BEHlOXKL.mjs} +190 -674
  115. package/.output/server/_ssr/routes-DeSps20R.mjs +391 -0
  116. package/.output/server/_ssr/runtime.server-C1SVch_-.mjs +1604 -0
  117. package/.output/server/_ssr/schema-BKY9SqaY.mjs +25 -0
  118. package/.output/server/_ssr/select-BL10bGzk.mjs +114 -0
  119. package/.output/server/_ssr/server-DIIIVgcN.mjs +8334 -0
  120. package/.output/server/_ssr/{createSsrRpc-NHF2PxuK.mjs → sidebar-DLus-ndm.mjs} +107 -47
  121. package/.output/server/_ssr/ssr.mjs +1 -1
  122. package/.output/server/_ssr/start-BXUOv_n8.mjs +4 -0
  123. package/.output/server/_ssr/{table-D1mL8fJu.mjs → table-U7InIZlH.mjs} +2 -2
  124. package/.output/server/_ssr/updateFailures-BLs3R7j0.mjs +40 -0
  125. package/.output/server/_ssr/{uuidv7-D0QFkPL_.mjs → uuidv7-C8bwiZr8.mjs} +2 -2
  126. package/.output/server/_tanstack-start-manifest_v-VxUXUIhM.mjs +123 -0
  127. package/.output/server/index.mjs +240 -163
  128. package/LICENSE +13 -14
  129. package/README.md +82 -72
  130. package/lib/index.d.mts +23 -11
  131. package/lib/vite-internal.mjs +13 -3
  132. package/lib/vite.d.mts +2 -0
  133. package/package.json +14 -14
  134. package/src/components/AppSidebar.tsx +100 -71
  135. package/src/components/ConsoleAccessPage.tsx +5 -1
  136. package/src/components/ConsoleFeatureUnavailable.tsx +80 -0
  137. package/src/components/NotFoundPage.tsx +7 -7
  138. package/src/components/features/FeatureSlots.tsx +101 -0
  139. package/src/components/features/api-keys/apiKeysFeatureUi.tsx +15 -0
  140. package/src/components/features/bundles/BundleMetadata.tsx +8 -5
  141. package/src/components/features/bundles/RolloutCohortsDialog.tsx +1 -1
  142. package/src/components/features/channels/ChannelManagementDialog.tsx +2 -5
  143. package/src/components/features/insights/AppUsage.tsx +366 -0
  144. package/src/components/features/insights/BuiltinBundle.tsx +36 -0
  145. package/src/components/features/insights/ComparedBundlesChart.tsx +310 -0
  146. package/src/components/features/insights/EstimatedCount.tsx +18 -0
  147. package/src/components/features/insights/EventDetails.tsx +400 -39
  148. package/src/components/features/insights/EventHistoryCard.tsx +112 -26
  149. package/src/components/features/insights/EventHistoryList.tsx +2 -2
  150. package/src/components/features/insights/FailureReports.tsx +407 -0
  151. package/src/components/features/insights/InsightsControls.tsx +265 -88
  152. package/src/components/features/insights/InsightsErrorAlert.tsx +14 -1
  153. package/src/components/features/insights/InsightsInfo.tsx +48 -0
  154. package/src/components/features/insights/InsightsOverview.tsx +604 -355
  155. package/src/components/features/insights/InsightsPageHeader.tsx +35 -20
  156. package/src/components/features/insights/InsightsPeriodSelector.tsx +89 -0
  157. package/src/components/features/insights/InstallationHistoryCard.tsx +66 -11
  158. package/src/components/features/insights/InstallationMatchesCard.tsx +1 -1
  159. package/src/components/features/insights/ReleaseActivity.tsx +308 -0
  160. package/src/components/features/insights/ReportingDevicesSummary.tsx +48 -0
  161. package/src/components/features/insights/RollbackButton.tsx +118 -0
  162. package/src/components/features/insights/UpdateFailures.tsx +382 -0
  163. package/src/components/features/insights/insightsFeatureUi.tsx +35 -0
  164. package/src/components/features/releases/ReleaseEditorSheet.tsx +26 -12
  165. package/src/components/ui/card.tsx +1 -1
  166. package/src/components/ui/scroll-area.tsx +52 -0
  167. package/src/components/ui/sidebar.tsx +22 -29
  168. package/src/components/ui/tabs.tsx +81 -0
  169. package/src/index.ts +26 -19
  170. package/src/lib/api-keys-api.ts +0 -28
  171. package/src/lib/api-keys-rpc.ts +27 -38
  172. package/src/lib/api-rpc.ts +189 -266
  173. package/src/lib/api.ts +19 -102
  174. package/src/lib/bundle-activity.ts +24 -4
  175. package/src/lib/console-access.ts +20 -0
  176. package/src/lib/console-features-api.ts +68 -0
  177. package/src/lib/console-features-rpc.ts +13 -0
  178. package/src/lib/console-features.ts +91 -0
  179. package/src/lib/insights-api.ts +56 -2
  180. package/src/lib/insights-errors.ts +64 -0
  181. package/src/lib/insights-failures-rpc.ts +36 -0
  182. package/src/lib/insights-failures.ts +130 -0
  183. package/src/lib/insights-recovery-rpc.ts +13 -17
  184. package/src/lib/insights-recovery.ts +10 -27
  185. package/src/lib/insights-retention.ts +21 -0
  186. package/src/lib/insights-rpc.ts +30 -12
  187. package/src/lib/insights-search.ts +93 -0
  188. package/src/lib/insights-usage-rpc.ts +29 -0
  189. package/src/lib/insights-usage.ts +76 -0
  190. package/src/lib/insights-view.ts +34 -5
  191. package/src/lib/release-adoption-api.ts +214 -0
  192. package/src/lib/release-adoption-rpc.ts +49 -0
  193. package/src/lib/release-adoption.ts +164 -0
  194. package/src/lib/scroll-restoration.ts +21 -0
  195. package/src/lib/server/adminInsights.ts +124 -0
  196. package/src/lib/server/auth.server.ts +13 -5
  197. package/src/lib/server/bundleActivity.ts +27 -28
  198. package/src/lib/server/config.server.ts +21 -74
  199. package/src/lib/server/console-feature-apis.ts +59 -0
  200. package/src/lib/server/console-runtime.server.ts +82 -38
  201. package/src/lib/server/downloadBundle.ts +16 -15
  202. package/src/lib/server/failureReports.ts +49 -0
  203. package/src/lib/server/getBundleChildren.ts +31 -122
  204. package/src/lib/server/insightsUsage.ts +63 -0
  205. package/src/lib/server/listReleases.ts +109 -44
  206. package/src/lib/server/releaseAdoption.ts +154 -0
  207. package/src/lib/server/releaseReachability.ts +8 -7
  208. package/src/lib/server/runtime.server.ts +120 -31
  209. package/src/lib/server/updateFailures.ts +65 -0
  210. package/src/routeTree.gen.ts +44 -44
  211. package/src/router.tsx +3 -2
  212. package/src/routes/-installations-search.ts +32 -8
  213. package/src/routes/-releases-search.ts +76 -29
  214. package/src/routes/__root.tsx +10 -4
  215. package/src/routes/api/bundles/$bundleId/download.ts +2 -5
  216. package/src/routes/api-keys.tsx +5 -2
  217. package/src/routes/index.tsx +210 -152
  218. package/src/routes/insights.tsx +133 -18
  219. package/src/routes/insights_.distribution.tsx +422 -0
  220. package/src/routes/installations.tsx +98 -41
  221. package/src/styles.css +9 -0
  222. package/src/vite-internal.ts +15 -3
  223. package/src/vite.ts +2 -0
  224. package/.output/public/assets/InsightsPageHeader-C-Xc2MB9.js +0 -1
  225. package/.output/public/assets/api-keys-C1sgC6ko.js +0 -1
  226. package/.output/public/assets/api-keys-api-LchP65vQ.js +0 -1
  227. package/.output/public/assets/badge-BuMDU0Rf.js +0 -1
  228. package/.output/public/assets/card-BEvx_QKh.js +0 -1
  229. package/.output/public/assets/chart-no-axes-combined-C0G0fQ3J.js +0 -1
  230. package/.output/public/assets/composite-CHTH1Xhh.js +0 -1
  231. package/.output/public/assets/createServerFn-DHc2erub.js +0 -3
  232. package/.output/public/assets/dialog-dyZ1SphZ.js +0 -1
  233. package/.output/public/assets/dist-Bh1gaDfB.js +0 -1
  234. package/.output/public/assets/field-79SVH26s.js +0 -1
  235. package/.output/public/assets/index-BNkxg4jz.js +0 -10
  236. package/.output/public/assets/input-group-BbHfaBzQ.js +0 -1
  237. package/.output/public/assets/insights-D_7uSKfc.js +0 -1
  238. package/.output/public/assets/installations-BzoHWuXw.js +0 -1
  239. package/.output/public/assets/installations-DvjbUqd1.js +0 -2
  240. package/.output/public/assets/lazyRouteComponent-BN0MS05o.js +0 -1
  241. package/.output/public/assets/link-BG06whwB.js +0 -1
  242. package/.output/public/assets/loader-circle-Bbp8LGVC.js +0 -1
  243. package/.output/public/assets/preload-helper-uTix4PVD.js +0 -1
  244. package/.output/public/assets/refresh-cw-DZgiAOMk.js +0 -1
  245. package/.output/public/assets/routes-BFE-oRIT.js +0 -1
  246. package/.output/public/assets/routes-DaPMY31P.js +0 -2
  247. package/.output/public/assets/shield-check-DoIiaaXU.js +0 -1
  248. package/.output/public/assets/signing-BTRhaF5D.js +0 -1
  249. package/.output/public/assets/styles-C7U0oVke.css +0 -2
  250. package/.output/public/assets/table-BBEzJ7Xl.js +0 -1
  251. package/.output/public/assets/useCompositeListItem-BkPDaqyj.js +0 -42
  252. package/.output/server/_ssr/InsightsPageHeader-C5Has8Ry.mjs +0 -60
  253. package/.output/server/_ssr/api-keys-api-CrCZyvnl.mjs +0 -60
  254. package/.output/server/_ssr/api-keys-rpc-CFaNf-q0.mjs +0 -136
  255. package/.output/server/_ssr/api-rpc-B61KL3Eo.mjs +0 -1399
  256. package/.output/server/_ssr/auth.server-DF_shCeq.mjs +0 -47
  257. package/.output/server/_ssr/badge-BgsCP9Dp.mjs +0 -28
  258. package/.output/server/_ssr/bundle-signing-rpc-BBipZnFs.mjs +0 -16
  259. package/.output/server/_ssr/bundle-signing.server-Co_zHdJx.mjs +0 -12
  260. package/.output/server/_ssr/bundleActivity-D3_fIda2.mjs +0 -27
  261. package/.output/server/_ssr/card-DrbxCPtG.mjs +0 -86
  262. package/.output/server/_ssr/chart-qxa-_30a.mjs +0 -162
  263. package/.output/server/_ssr/config-Dv8qLDZ0.mjs +0 -13
  264. package/.output/server/_ssr/config.server-CBr6PDj5.mjs +0 -368
  265. package/.output/server/_ssr/databaseRows-5bCRTxm-.mjs +0 -126
  266. package/.output/server/_ssr/deleteBundle-BAq3JuGr.mjs +0 -66
  267. package/.output/server/_ssr/getBundleChildren-COMt16m_.mjs +0 -50
  268. package/.output/server/_ssr/insights-B-DUbksX.mjs +0 -502
  269. package/.output/server/_ssr/insights-recovery-rpc-P71FH66n.mjs +0 -37
  270. package/.output/server/_ssr/insightsContract-fjJDBeEE.mjs +0 -303
  271. package/.output/server/_ssr/insightsRecovery-CqcosG7B.mjs +0 -149
  272. package/.output/server/_ssr/installations-BQrppti7.mjs +0 -29
  273. package/.output/server/_ssr/routes-BDabsmc7.mjs +0 -37
  274. package/.output/server/_ssr/runtime.server-jmZOKIQM.mjs +0 -438
  275. package/.output/server/_ssr/server-p7yrVBfD.mjs +0 -7468
  276. package/.output/server/_ssr/signing-CxCbnFCt.mjs +0 -134
  277. package/.output/server/_ssr/start-DpViQGnt.mjs +0 -4
  278. package/.output/server/_tanstack-start-manifest_v-Cwpu0C9Q.mjs +0 -100
  279. package/src/components/features/bundles/BundleActivityChart.tsx +0 -95
  280. package/src/components/features/bundles/BundleInsightsSummary.tsx +0 -121
  281. package/src/components/features/signing/BundleSigningPage.tsx +0 -139
  282. package/src/lib/bundle-signing-api.ts +0 -14
  283. package/src/lib/bundle-signing-rpc.ts +0 -16
  284. package/src/lib/server/bundle-signing.server.ts +0 -23
  285. package/src/lib/server/deleteBundle.ts +0 -145
  286. package/src/lib/server/insightsHistory.ts +0 -52
  287. package/src/lib/server/insightsRecovery.ts +0 -186
  288. package/src/routes/signing.tsx +0 -37
@@ -1,145 +0,0 @@
1
- import {
2
- getBundlePatches,
3
- getManifestStorageUri,
4
- getPatchStorageUri,
5
- } from "@hot-updater/core";
6
- import type {
7
- Bundle,
8
- DatabaseClient,
9
- StoragePluginWith,
10
- } from "@hot-updater/plugin-core";
11
-
12
- interface DeleteBundleInput {
13
- bundleId: string;
14
- }
15
-
16
- interface DeleteBundlesInput {
17
- bundleIds: readonly string[];
18
- }
19
-
20
- interface DeleteBundleDependencies {
21
- databaseClient: DatabaseClient;
22
- storagePlugin: StoragePluginWith<"delete">;
23
- waitForStorageCleanup?: boolean;
24
- }
25
-
26
- function resolveStorageUriForDeletion(
27
- storageUri: string,
28
- storagePlugin: StoragePluginWith<"delete">,
29
- ) {
30
- const protocol = new URL(storageUri).protocol.replace(":", "");
31
-
32
- if (storagePlugin.protocol === protocol) {
33
- return storageUri;
34
- }
35
-
36
- if (protocol === "http" || protocol === "https") {
37
- return null;
38
- }
39
-
40
- throw new Error(`No storage plugin for protocol: ${protocol}`);
41
- }
42
-
43
- async function cleanupBundleStorage(
44
- bundle: Bundle,
45
- storagePlugin: StoragePluginWith<"delete">,
46
- ) {
47
- const cleanupUris = new Set<string>();
48
- const addCleanupUri = (storageUri: string | undefined) => {
49
- if (!storageUri) return;
50
- const resolvedStorageUri = resolveStorageUriForDeletion(
51
- storageUri,
52
- storagePlugin,
53
- );
54
- if (resolvedStorageUri) cleanupUris.add(resolvedStorageUri);
55
- };
56
-
57
- addCleanupUri(bundle.storageUri);
58
- addCleanupUri(getManifestStorageUri(bundle) ?? undefined);
59
- addCleanupUri(getPatchStorageUri(bundle) ?? undefined);
60
- for (const patch of getBundlePatches(bundle)) {
61
- addCleanupUri(patch.patchStorageUri);
62
- }
63
-
64
- for (const storageUri of cleanupUris) {
65
- try {
66
- await storagePlugin.delete({ storageUri });
67
- } catch (error) {
68
- console.error("Failed to delete bundle from storage:", error);
69
- }
70
- }
71
- }
72
-
73
- export async function deleteBundles(
74
- { bundleIds }: DeleteBundlesInput,
75
- {
76
- databaseClient,
77
- storagePlugin,
78
- waitForStorageCleanup = true,
79
- }: DeleteBundleDependencies,
80
- ) {
81
- const uniqueBundleIds = [...new Set(bundleIds)];
82
- const { data: matchedBundles } = await databaseClient.getBundles({
83
- where: { id: { in: uniqueBundleIds } },
84
- limit: uniqueBundleIds.length,
85
- });
86
- const matchedById = new Map(
87
- matchedBundles.map((bundle) => [bundle.id, bundle]),
88
- );
89
- const bundles = uniqueBundleIds.flatMap((bundleId) => {
90
- const bundle = matchedById.get(bundleId);
91
- return bundle ? [bundle] : [];
92
- });
93
- const missingBundleIds = uniqueBundleIds.filter(
94
- (bundleId) => !matchedById.has(bundleId),
95
- );
96
-
97
- for (const bundle of bundles) {
98
- const cleanupCandidates = [
99
- bundle.storageUri,
100
- getManifestStorageUri(bundle),
101
- getPatchStorageUri(bundle),
102
- ...getBundlePatches(bundle).map((patch) => patch.patchStorageUri),
103
- ].filter((value): value is string => Boolean(value));
104
- for (const candidate of cleanupCandidates) {
105
- resolveStorageUriForDeletion(candidate, storagePlugin);
106
- }
107
- }
108
-
109
- if (bundles.length > 0) {
110
- await databaseClient.mutate(async (mutation) => {
111
- for (const bundle of bundles) {
112
- await mutation.deleteBundleById(bundle.id);
113
- }
114
- });
115
- }
116
-
117
- const cleanupStorage = async () => {
118
- for (const bundle of bundles) {
119
- await cleanupBundleStorage(bundle, storagePlugin);
120
- }
121
- };
122
-
123
- if (waitForStorageCleanup) {
124
- await cleanupStorage();
125
- } else {
126
- void cleanupStorage().catch((error) => {
127
- console.error("Failed to clean up bundle storage:", error);
128
- });
129
- }
130
-
131
- return {
132
- deletedBundleIds: bundles.map((bundle) => bundle.id),
133
- missingBundleIds,
134
- };
135
- }
136
-
137
- export async function deleteBundle(
138
- { bundleId }: DeleteBundleInput,
139
- dependencies: DeleteBundleDependencies,
140
- ) {
141
- const result = await deleteBundles({ bundleIds: [bundleId] }, dependencies);
142
- if (result.missingBundleIds.length > 0) {
143
- throw new Error(`Bundle not found: ${bundleId}`);
144
- }
145
- }
@@ -1,52 +0,0 @@
1
- import type {
2
- BundleEventRow,
3
- InsightsEventCursor,
4
- InsightsModel,
5
- } from "@hot-updater/plugin-core";
6
-
7
- import { recoveryWindows, type RecoveryInput } from "../insights-recovery";
8
-
9
- export async function readInsightsHistory(
10
- model: InsightsModel,
11
- window: RecoveryInput["window"],
12
- beforeReceivedAtMs = Date.now(),
13
- ) {
14
- const { durationMs, intervalMs } = recoveryWindows[window];
15
- const sinceMs = Math.max(0, beforeReceivedAtMs - durationMs);
16
- let completeSinceMs = sinceMs;
17
- let after: InsightsEventCursor | undefined;
18
- let truncated = false;
19
- const events: BundleEventRow[] = [];
20
- while (events.length < 50_000) {
21
- const limit = Math.min(100, 50_000 - events.length);
22
- const rows = await model.listEvents({
23
- filter: { kind: "all" },
24
- sinceMs,
25
- beforeReceivedAtMs,
26
- after,
27
- limit: limit + 1,
28
- });
29
- const page = rows.slice(0, limit);
30
- events.push(...page);
31
- const last = page.at(-1);
32
- if (!last || rows.length <= limit) break;
33
- after = { id: last.id, receivedAtMs: last.received_at_ms };
34
- if (events.length === 50_000) {
35
- truncated = true;
36
- // Exclude the partially read interval, including its unknown denominator.
37
- completeSinceMs =
38
- Math.floor(last.received_at_ms / intervalMs) * intervalMs + intervalMs;
39
- }
40
- }
41
- return {
42
- events: events
43
- .filter((row) => row.received_at_ms >= completeSinceMs)
44
- .reverse(),
45
- sinceMs: completeSinceMs,
46
- beforeReceivedAtMs,
47
- intervalMs,
48
- truncated,
49
- };
50
- }
51
-
52
- export type InsightsHistory = Awaited<ReturnType<typeof readInsightsHistory>>;
@@ -1,186 +0,0 @@
1
- import type { InsightsModel } from "@hot-updater/plugin-core";
2
-
3
- import {
4
- readRecoveryInput,
5
- type RecoveryInput,
6
- type RecoveryReport,
7
- type RecoverySeries,
8
- } from "../insights-recovery";
9
- import { readInsightsHistory, type InsightsHistory } from "./insightsHistory";
10
-
11
- export async function getRecoveryReport(
12
- model: InsightsModel,
13
- input: RecoveryInput,
14
- beforeReceivedAtMs = Date.now(),
15
- ): Promise<RecoveryReport> {
16
- readRecoveryInput(input);
17
- return buildRecoveryReport(
18
- await readInsightsHistory(model, input.window, beforeReceivedAtMs),
19
- input,
20
- );
21
- }
22
-
23
- export function buildRecoveryReport(
24
- history: InsightsHistory,
25
- input: RecoveryInput,
26
- ): RecoveryReport {
27
- const { events, sinceMs, beforeReceivedAtMs, intervalMs, truncated } =
28
- history;
29
- const bucketStart = (time: number) =>
30
- Math.floor(time / intervalMs) * intervalMs;
31
- const releases = new Map<
32
- string,
33
- {
34
- firstAdoptedAtMs: number | null;
35
- recovered: Set<string>;
36
- buckets: Map<
37
- number,
38
- {
39
- adopted: number;
40
- recovered: number;
41
- installations: Set<string>;
42
- lastRecoveredAtMs: number;
43
- }
44
- >;
45
- }
46
- >();
47
- const ensureRelease = (id: string) => {
48
- let release = releases.get(id);
49
- if (!release) {
50
- release = {
51
- firstAdoptedAtMs: null,
52
- recovered: new Set(),
53
- buckets: new Map(),
54
- };
55
- releases.set(id, release);
56
- }
57
- return release;
58
- };
59
- const latest = new Map<
60
- string,
61
- { releaseId: string | null; bundleId: string; inScope: boolean }
62
- >();
63
- const active = new Map<string, number>();
64
- const snapshots = new Map<number, Map<string, number> | null>();
65
- let unattributedInstallations = 0;
66
- let observed = false;
67
- let eventIndex = 0;
68
- for (
69
- let startMs = bucketStart(sinceMs);
70
- startMs < beforeReceivedAtMs;
71
- startMs += intervalMs
72
- ) {
73
- while (
74
- eventIndex < events.length &&
75
- events[eventIndex].received_at_ms < startMs + intervalMs
76
- ) {
77
- const row = events[eventIndex++];
78
- const inScope =
79
- row.platform === input.platform && row.channel === input.channel;
80
- const previous = latest.get(row.install_id);
81
- // Older SDKs omit the ID on UNCHANGED. Only retain an observed ID for the same file and scope.
82
- const releaseId =
83
- row.to_release_id ??
84
- (row.type === "UNCHANGED" &&
85
- previous?.bundleId === row.to_bundle_id &&
86
- previous.inScope === inScope
87
- ? previous.releaseId
88
- : null);
89
- if (previous?.inScope) {
90
- if (previous.releaseId)
91
- active.set(
92
- previous.releaseId,
93
- (active.get(previous.releaseId) ?? 0) - 1,
94
- );
95
- else unattributedInstallations -= 1;
96
- }
97
- latest.set(row.install_id, {
98
- releaseId,
99
- bundleId: row.to_bundle_id,
100
- inScope,
101
- });
102
- if (!inScope) continue;
103
- observed = true;
104
- if (releaseId) {
105
- ensureRelease(releaseId);
106
- active.set(releaseId, (active.get(releaseId) ?? 0) + 1);
107
- } else unattributedInstallations += 1;
108
- if (row.from_release_id) ensureRelease(row.from_release_id);
109
- const outcomeId =
110
- row.type === "RECOVERED" ? row.from_release_id : row.to_release_id;
111
- if (
112
- !outcomeId ||
113
- (row.type !== "RECOVERED" &&
114
- row.type !== "RELEASE_ADOPTED" &&
115
- row.type !== "UPDATE_APPLIED")
116
- )
117
- continue;
118
- const release = ensureRelease(outcomeId);
119
- const bucket = release.buckets.get(startMs) ?? {
120
- adopted: 0,
121
- recovered: 0,
122
- installations: new Set<string>(),
123
- lastRecoveredAtMs: -1,
124
- };
125
- if (row.type === "RECOVERED") {
126
- bucket.recovered += 1;
127
- bucket.installations.add(row.install_id);
128
- bucket.lastRecoveredAtMs = row.received_at_ms;
129
- release.recovered.add(row.install_id);
130
- } else {
131
- bucket.adopted += 1;
132
- release.firstAdoptedAtMs ??= row.received_at_ms;
133
- }
134
- release.buckets.set(startMs, bucket);
135
- }
136
- // Before the first report there is no observed installation state to chart.
137
- snapshots.set(startMs, observed ? new Map(active) : null);
138
- }
139
- const series: RecoverySeries[] = [];
140
- for (const [releaseId, release] of releases) {
141
- if (input.releaseId && input.releaseId !== releaseId) continue;
142
- let previousRate: number | null = null;
143
- const points = Array.from(snapshots, ([startMs, snapshot]) => {
144
- const bucket = release.buckets.get(startMs);
145
- const adopted = bucket?.adopted ?? 0;
146
- const recovered = bucket?.recovered ?? 0;
147
- const total = adopted + recovered;
148
- const rate = total === 0 ? null : (recovered / total) * 100;
149
- const spike =
150
- release.firstAdoptedAtMs !== null &&
151
- (bucket?.lastRecoveredAtMs ?? -1) >= release.firstAdoptedAtMs &&
152
- (!truncated || previousRate !== null) &&
153
- rate !== null &&
154
- total >= 10 &&
155
- recovered >= 3 &&
156
- rate >= 10 &&
157
- rate - (previousRate ?? 0) >= 10;
158
- if (rate !== null) previousRate = rate;
159
- return {
160
- startMs,
161
- active: snapshot ? (snapshot.get(releaseId) ?? 0) : null,
162
- recoveredInstallations: bucket?.installations.size ?? 0,
163
- adopted,
164
- recovered,
165
- rate,
166
- spike,
167
- };
168
- });
169
- series.push({
170
- releaseId,
171
- firstAdoptedAtMs: release.firstAdoptedAtMs,
172
- activeInstallations: active.get(releaseId) ?? 0,
173
- recoveredInstallations: release.recovered.size,
174
- points,
175
- });
176
- }
177
- series.sort((a, b) => b.releaseId.localeCompare(a.releaseId));
178
- return {
179
- sinceMs,
180
- beforeReceivedAtMs,
181
- intervalMs,
182
- truncated,
183
- unattributedInstallations,
184
- series,
185
- };
186
- }
@@ -1,37 +0,0 @@
1
- import { createFileRoute } from "@tanstack/react-router";
2
- import { ShieldCheck } from "lucide-react";
3
-
4
- import { BundleSigningPage } from "@/components/features/signing/BundleSigningPage";
5
- import { Badge } from "@/components/ui/badge";
6
- import { SidebarTrigger } from "@/components/ui/sidebar";
7
-
8
- export const Route = createFileRoute("/signing")({
9
- component: BundleSigningRoute,
10
- });
11
-
12
- function BundleSigningRoute() {
13
- return (
14
- <div className="flex h-svh min-h-0 flex-col">
15
- <header className="sticky top-0 z-10 flex shrink-0 flex-wrap items-center gap-x-3 gap-y-1 border-b bg-background px-3 py-3 sm:min-h-12 sm:flex-nowrap sm:bg-card/70 sm:px-4 sm:backdrop-blur-sm">
16
- <SidebarTrigger className="-ml-1" />
17
- <div className="flex items-center gap-1.5">
18
- <ShieldCheck
19
- aria-hidden="true"
20
- className="size-3.5 text-muted-foreground"
21
- />
22
- <h1 className="text-sm font-medium">Bundle signing</h1>
23
- </div>
24
- <Badge variant="outline">Read-only</Badge>
25
- <p className="basis-full pl-9 text-xs text-muted-foreground sm:basis-auto sm:pl-0">
26
- Inspect the public key used to verify signed updates.
27
- </p>
28
- </header>
29
-
30
- <div className="min-h-0 min-w-0 flex-1 overflow-y-auto bg-muted/5 p-3 sm:p-6">
31
- <div className="mx-auto w-full max-w-5xl">
32
- <BundleSigningPage />
33
- </div>
34
- </div>
35
- </div>
36
- );
37
- }