@hot-updater/console 1.0.0-rc.8 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (342) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/ConsoleFeatureUnavailable-jB4Loglh.js +1 -0
  3. package/.output/public/assets/EventDetails-B6yUsyNA.js +1 -0
  4. package/.output/public/assets/HashValueDisplay-BFX_kY3-.js +1 -0
  5. package/.output/public/assets/InsightsInfo-BNO0WznZ.js +1 -0
  6. package/.output/public/assets/InsightsPageHeader-B892oVml.js +1 -0
  7. package/.output/public/assets/NotFoundPage-DIqCpWa3.js +1 -0
  8. package/.output/public/assets/alert-dialog-Bbk_4-WJ.js +1 -0
  9. package/.output/public/assets/api-DCM0wr6O.js +1 -0
  10. package/.output/public/assets/api-keys-CIO9L_wu.js +1 -0
  11. package/.output/public/assets/api-keys-DVTL_--f.js +1 -0
  12. package/.output/public/assets/arrow-left-CnMYpqB7.js +1 -0
  13. package/.output/public/assets/arrow-up-right-BtffZA6e.js +1 -0
  14. package/.output/public/assets/chevron-right-BqD5wtFb.js +1 -0
  15. package/.output/public/assets/clipboard-DS9ucUQL.js +1 -0
  16. package/.output/public/assets/console-features-api-BH5m_PtQ.js +1 -0
  17. package/.output/public/assets/dialog-Bqbb7B0N.js +1 -0
  18. package/.output/public/assets/dist-LxKJB-Vu.js +1 -0
  19. package/.output/public/assets/empty-CuT2UhFp.js +1 -0
  20. package/.output/public/assets/field-BBDpjIqu.js +1 -0
  21. package/.output/public/assets/index-6o51GkFe.js +11 -0
  22. package/.output/public/assets/input-group-ja_30qaF.js +1 -0
  23. package/.output/public/assets/insights-CmraDzQh.js +1 -0
  24. package/.output/public/assets/insights-CxZ2GCYV.js +2 -0
  25. package/.output/public/assets/insights-api-BigAU9sZ.js +1 -0
  26. package/.output/public/assets/insights-usage-rpc-DYEhsCKT.js +1 -0
  27. package/.output/public/assets/insights-vNRCrfnS.js +42 -0
  28. package/.output/public/assets/insights_.distribution-ChOerfJt.js +1 -0
  29. package/.output/public/assets/insights_.distribution-D-e4iga8.js +1 -0
  30. package/.output/public/assets/insights_.distribution-DZtkibX1.js +2 -0
  31. package/.output/public/assets/installations-BazSJXE0.js +2 -0
  32. package/.output/public/assets/installations-ClHTqdAO.js +1 -0
  33. package/.output/public/assets/installations-DpKsBuHi.js +1 -0
  34. package/.output/public/assets/key-round-wS_SIZ6b.js +1 -0
  35. package/.output/public/assets/list-CgrYiadM.js +1 -0
  36. package/.output/public/assets/refresh-cw-BYgoNCco.js +1 -0
  37. package/.output/public/assets/remote-config-BWwHOkCK.js +1 -0
  38. package/.output/public/assets/remote-config-Br56BODb.js +6 -0
  39. package/.output/public/assets/remote-config-CXOi0LRu.js +1 -0
  40. package/.output/public/assets/routes-B88Erkpk.js +2 -0
  41. package/.output/public/assets/routes-CfzsAleC.js +1 -0
  42. package/.output/public/assets/search-DaTDPW25.js +1 -0
  43. package/.output/public/assets/select-BZZBXMkr.js +1 -0
  44. package/.output/public/assets/sidebar-DNVyJPfX.js +3 -0
  45. package/.output/public/assets/smartphone-DpTFgtKf.js +1 -0
  46. package/.output/public/assets/styles-DTGEAJFv.css +2 -0
  47. package/.output/public/assets/switch-DZ1TPwx-.js +1 -0
  48. package/.output/public/assets/table-Gm4qRWwE.js +1 -0
  49. package/.output/public/assets/tabs-C7FOEjFC.js +1 -0
  50. package/.output/public/assets/undo-2-CmrHjwFc.js +1 -0
  51. package/.output/public/assets/useCompositeListItem-9E4pj_CH.js +1 -0
  52. package/.output/public/assets/valueToPercent-CH8GCHaL.js +1 -0
  53. package/.output/server/__23tanstack-start-server-fn-resolver-BpRlos5Q.mjs +170 -0
  54. package/.output/server/_libs/@base-ui/react+[...].mjs +4389 -4207
  55. package/.output/server/_libs/@tanstack/react-router+[...].mjs +3802 -4022
  56. package/.output/server/_libs/@tanstack/react-router-ssr-query+[...].mjs +140 -97
  57. package/.output/server/_libs/lucide-react.mjs +221 -9
  58. package/.output/server/_libs/next-themes.mjs +1 -1
  59. package/.output/server/_libs/react-redux+[...].mjs +1 -1
  60. package/.output/server/_libs/recharts+[...].mjs +483 -901
  61. package/.output/server/_libs/sonner.mjs +1 -1
  62. package/.output/server/_libs/tanstack__history.mjs +68 -41
  63. package/.output/server/_libs/tanstack__query-core.mjs +2010 -309
  64. package/.output/server/_libs/tanstack__react-query.mjs +448 -21
  65. package/.output/server/_libs/verkit.mjs +102 -1
  66. package/.output/server/_ssr/BundleIdDisplay-x94o9rlU.mjs +13 -0
  67. package/.output/server/_ssr/ConsoleFeatureUnavailable-ldW8v8-q.mjs +58 -0
  68. package/.output/server/_ssr/EventDetails-Q8kfj9Nr.mjs +344 -0
  69. package/.output/server/_ssr/{HashValueDisplay-C5tS4oGo.mjs → HashValueDisplay-n1GholGS.mjs} +3 -3
  70. package/.output/server/_ssr/InsightsInfo-DuJFatQO.mjs +75 -0
  71. package/.output/server/_ssr/InsightsPageHeader-BSUX3Ye9.mjs +145 -0
  72. package/.output/server/_ssr/NotFoundPage-DZzOOzS3.mjs +37 -0
  73. package/.output/server/_ssr/{dialog-WiIAKl4L.mjs → alert-dialog-C43Doa0I.mjs} +6 -83
  74. package/.output/server/_ssr/{api-keys-aXriWrv7.mjs → api-keys-B4sYm8dM.mjs} +48 -9
  75. package/.output/server/_ssr/api-keys-CEnM9fqG.mjs +5 -0
  76. package/.output/server/_ssr/api-keys-rpc-BIFuUgMt.mjs +52 -0
  77. package/.output/server/_ssr/api-oZjRn9tP.mjs +186 -0
  78. package/.output/server/_ssr/api-rpc-BNiFRRK8.mjs +240 -0
  79. package/.output/server/_ssr/{auth-BF8mbAgF.mjs → auth-UP0wXs4i.mjs} +1 -1
  80. package/.output/server/_ssr/{auth-rpc-B7w3AdRr.mjs → auth-rpc-DnZqYxyq.mjs} +6 -6
  81. package/.output/server/_ssr/auth.server-DFpyxRDd.mjs +5374 -0
  82. package/.output/server/_ssr/bundleActivity-M5gzBFNg.mjs +18 -0
  83. package/.output/server/_ssr/config-WVX4IxSR.mjs +15 -0
  84. package/.output/server/_ssr/config.server-DskXCAyI.mjs +35 -0
  85. package/.output/server/_ssr/console-access-BJfAXknd.mjs +17 -0
  86. package/.output/server/_ssr/console-features-Oz0q20jJ.mjs +61 -0
  87. package/.output/server/_ssr/console-features-api-C9kiKvaV.mjs +43 -0
  88. package/.output/server/_ssr/console-features-rpc-P0GL7Z-R.mjs +19 -0
  89. package/.output/server/_ssr/{createServerFn-B2hcXoPM.mjs → createMiddleware-Cm6Tn0_Y.mjs} +67 -56
  90. package/.output/server/_ssr/{createServerRpc-DB29C_5p.mjs → createServerRpc-RLR4H-Fn.mjs} +2 -2
  91. package/.output/server/_ssr/databaseConfig-C5SkAyUy.mjs +5 -0
  92. package/.output/server/_ssr/{databaseJsonValue-d6I3nAS4.mjs → databaseJsonValue-Csbuzc9Q.mjs} +28 -5
  93. package/.output/server/_ssr/databaseRows-CPphvbag.mjs +73 -0
  94. package/.output/server/_ssr/dialog-BbYDMjdC.mjs +84 -0
  95. package/.output/server/_ssr/{dist-CyzPaI5v.mjs → dist-CbQbBIw-.mjs} +140 -7
  96. package/.output/server/_ssr/{downloadBundle-CI7JUKvC.mjs → downloadBundle-CZysjmNW.mjs} +10 -10
  97. package/.output/server/_ssr/empty-CVLGfxuu.mjs +60 -0
  98. package/.output/server/_ssr/{empty-plugin-adapters-B5QvGpEl.mjs → empty-plugin-adapters-CPtwX8a7.mjs} +1 -1
  99. package/.output/server/_ssr/failureReports-DKDhVsXA.mjs +33 -0
  100. package/.output/server/_ssr/field-asw83X0v.mjs +189 -0
  101. package/.output/server/_ssr/getBundleChildren-Cv9iz1As.mjs +22 -0
  102. package/.output/server/_ssr/{input-group-Coj6SwVP.mjs → input-group-CuYJHosb.mjs} +2 -2
  103. package/.output/server/_ssr/insights-B55FG5fm.mjs +14 -0
  104. package/.output/server/_ssr/insights-CWnHIFUV.mjs +5 -0
  105. package/.output/server/_ssr/insights-CpLpedFZ.mjs +2315 -0
  106. package/.output/server/_ssr/insights-api-sjws23WF.mjs +122 -0
  107. package/.output/server/_ssr/insights-errors-BjnFUyZj.mjs +34 -0
  108. package/.output/server/_ssr/insights-failures-rpc-BvbWvqNf.mjs +36 -0
  109. package/.output/server/_ssr/insights-failures-xaa41Buf.mjs +46 -0
  110. package/.output/server/_ssr/insights-recovery-BWQhiZaF.mjs +28 -0
  111. package/.output/server/_ssr/insights-recovery-rpc-GiYXdkaY.mjs +32 -0
  112. package/.output/server/_ssr/{insights-rpc-l2-oBYth.mjs → insights-rpc-DP_8Rmz4.mjs} +22 -14
  113. package/.output/server/_ssr/insights-usage-BpBM0U0c.mjs +29 -0
  114. package/.output/server/_ssr/insights-usage-rpc-BiolgB8e.mjs +29 -0
  115. package/.output/server/_ssr/insights-usage-rpc-KStL0zOx.mjs +41 -0
  116. package/.output/server/_ssr/insightsUsage-CzhVjsc8.mjs +56 -0
  117. package/.output/server/_ssr/insights_.distribution-CVrnbP3R.mjs +7 -0
  118. package/.output/server/_ssr/insights_.distribution-D2HaNTAA.mjs +16 -0
  119. package/.output/server/_ssr/{insights_.distribution-INw6QxbU.mjs → insights_.distribution-DN9pR422.mjs} +50 -22
  120. package/.output/server/_ssr/installations-BHmbbnH8.mjs +5 -0
  121. package/.output/server/_ssr/{installations-DH-tQuRo.mjs → installations-BSCmFq8Q.mjs} +279 -367
  122. package/.output/server/_ssr/installations-DD1g__Nc.mjs +69 -0
  123. package/.output/server/_ssr/listReleases-BfUBlCHo.mjs +79 -0
  124. package/.output/server/_ssr/plugins-BaD1slHx.mjs +2086 -0
  125. package/.output/server/_ssr/release-adoption-005tQRpo.mjs +55 -0
  126. package/.output/server/_ssr/release-adoption-rpc-BsstqxUp.mjs +41 -0
  127. package/.output/server/_ssr/releaseAdoption-CtOFkwli.mjs +114 -0
  128. package/.output/server/_ssr/releaseManagement-DFMUnDF5.mjs +11 -0
  129. package/.output/server/_ssr/remote-config-C2Ee8lXO.mjs +5 -0
  130. package/.output/server/_ssr/remote-config-Dv1ccMo-.mjs +17 -0
  131. package/.output/server/_ssr/remote-config-of0lGQH8.mjs +2648 -0
  132. package/.output/server/_ssr/remote-config-rpc-BzX31mUS.mjs +115 -0
  133. package/.output/server/_ssr/rolldown-runtime-rSIU-vHC.mjs +13 -0
  134. package/.output/server/_ssr/{router-DfFyAp5p.mjs → router-D8NuoJ_I.mjs} +117 -136
  135. package/.output/server/_ssr/{routes-BtsfVx-p.mjs → routes-DgvnFqDy.mjs} +195 -429
  136. package/.output/server/_ssr/routes-V8sDybGf.mjs +409 -0
  137. package/.output/server/_ssr/runtime.server-De0QVWc9.mjs +104 -0
  138. package/.output/server/_ssr/schema-BiAVyEj2.mjs +361 -0
  139. package/.output/server/_ssr/{select-CyvLaMza.mjs → select-t3iXRwc9.mjs} +3 -3
  140. package/.output/server/_ssr/server-h4VxnExB.mjs +8325 -0
  141. package/.output/server/_ssr/{createSsrRpc-C-dLcQuy.mjs → sidebar-DJcErBMo.mjs} +107 -47
  142. package/.output/server/_ssr/ssr.mjs +1 -1
  143. package/.output/server/_ssr/start-BfFbHKMK.mjs +4 -0
  144. package/.output/server/_ssr/switch-E-btwMGt.mjs +43 -0
  145. package/.output/server/_ssr/{table-CkVhsNpe.mjs → table-37Dd23TN.mjs} +2 -2
  146. package/.output/server/_ssr/tabs-DEFnTm95.mjs +45 -0
  147. package/.output/server/_ssr/updateFailures-H6pnnYK4.mjs +40 -0
  148. package/.output/server/_ssr/{uuidv7-D0QFkPL_.mjs → uuidv7-C88s9jWF.mjs} +2 -2
  149. package/.output/server/_tanstack-start-manifest_v-55AGsehh.mjs +139 -0
  150. package/.output/server/index.mjs +303 -205
  151. package/LICENSE +13 -14
  152. package/README.md +80 -71
  153. package/lib/index.d.mts +23 -11
  154. package/lib/vite-internal.mjs +13 -3
  155. package/lib/vite.d.mts +2 -0
  156. package/package.json +14 -14
  157. package/src/components/AppSidebar.tsx +74 -75
  158. package/src/components/ConsoleAccessPage.tsx +5 -1
  159. package/src/components/ConsoleFeatureUnavailable.tsx +80 -0
  160. package/src/components/NotFoundPage.tsx +7 -7
  161. package/src/components/features/FeatureSlots.tsx +103 -0
  162. package/src/components/features/api-keys/apiKeysFeatureUi.tsx +15 -0
  163. package/src/components/features/bundles/BundleMetadata.tsx +8 -5
  164. package/src/components/features/bundles/RolloutCohortsDialog.tsx +1 -1
  165. package/src/components/features/channels/ChannelManagementDialog.tsx +8 -6
  166. package/src/components/features/insights/AppUsage.tsx +41 -14
  167. package/src/components/features/insights/BuiltinBundle.tsx +36 -0
  168. package/src/components/features/insights/ComparedBundlesChart.tsx +310 -0
  169. package/src/components/features/insights/EstimatedCount.tsx +18 -0
  170. package/src/components/features/insights/EventDetails.tsx +390 -26
  171. package/src/components/features/insights/EventHistoryCard.tsx +111 -25
  172. package/src/components/features/insights/EventHistoryList.tsx +1 -1
  173. package/src/components/features/insights/FailureReports.tsx +407 -0
  174. package/src/components/features/insights/InsightsControls.tsx +240 -142
  175. package/src/components/features/insights/InsightsErrorAlert.tsx +14 -1
  176. package/src/components/features/insights/InsightsOverview.tsx +601 -403
  177. package/src/components/features/insights/InsightsPageHeader.tsx +19 -14
  178. package/src/components/features/insights/InsightsPeriodSelector.tsx +67 -12
  179. package/src/components/features/insights/InstallationHistoryCard.tsx +65 -10
  180. package/src/components/features/insights/InstallationMatchesCard.tsx +1 -1
  181. package/src/components/features/insights/ReleaseActivity.tsx +308 -0
  182. package/src/components/features/insights/ReportingDevicesSummary.tsx +13 -13
  183. package/src/components/features/insights/RollbackButton.tsx +118 -0
  184. package/src/components/features/insights/UpdateFailures.tsx +382 -0
  185. package/src/components/features/insights/insightsFeatureUi.tsx +35 -0
  186. package/src/components/features/releases/ReleaseEditorSheet.tsx +27 -13
  187. package/src/components/features/remote-config/ConditionDialog.tsx +592 -0
  188. package/src/components/features/remote-config/ConditionsCard.tsx +247 -0
  189. package/src/components/features/remote-config/ParameterDialog.tsx +426 -0
  190. package/src/components/features/remote-config/ParametersCard.tsx +254 -0
  191. package/src/components/features/remote-config/PreviewCard.tsx +284 -0
  192. package/src/components/features/remote-config/PublishDialog.tsx +325 -0
  193. package/src/components/features/remote-config/RemoteConfigPage.tsx +353 -0
  194. package/src/components/features/remote-config/RuleSummary.tsx +21 -0
  195. package/src/components/features/remote-config/ValueInput.tsx +151 -0
  196. package/src/components/features/remote-config/VersionsCard.tsx +384 -0
  197. package/src/components/features/remote-config/remoteConfigFeatureUi.tsx +15 -0
  198. package/src/components/features/remote-config/useDateTimeText.ts +16 -0
  199. package/src/components/ui/sidebar.tsx +22 -29
  200. package/src/index.ts +26 -19
  201. package/src/lib/api-keys-api.ts +0 -28
  202. package/src/lib/api-keys-rpc.ts +27 -38
  203. package/src/lib/api-rpc.ts +125 -288
  204. package/src/lib/api.ts +15 -134
  205. package/src/lib/bundle-activity.ts +24 -4
  206. package/src/lib/console-access.ts +20 -0
  207. package/src/lib/console-features-api.ts +68 -0
  208. package/src/lib/console-features-rpc.ts +13 -0
  209. package/src/lib/console-features.ts +98 -0
  210. package/src/lib/insights-api.ts +56 -2
  211. package/src/lib/insights-errors.ts +64 -0
  212. package/src/lib/insights-failures-rpc.ts +36 -0
  213. package/src/lib/insights-failures.ts +130 -0
  214. package/src/lib/insights-recovery-rpc.ts +13 -17
  215. package/src/lib/insights-recovery.ts +12 -36
  216. package/src/lib/insights-retention.ts +21 -0
  217. package/src/lib/insights-rpc.ts +30 -12
  218. package/src/lib/insights-search.ts +50 -4
  219. package/src/lib/insights-usage-rpc.ts +15 -9
  220. package/src/lib/insights-usage.ts +41 -3
  221. package/src/lib/insights-view.ts +34 -5
  222. package/src/lib/release-adoption-api.ts +214 -0
  223. package/src/lib/release-adoption-rpc.ts +49 -0
  224. package/src/lib/release-adoption.ts +164 -0
  225. package/src/lib/remote-config-api.ts +119 -0
  226. package/src/lib/remote-config-draft.ts +666 -0
  227. package/src/lib/remote-config-rpc.ts +196 -0
  228. package/src/lib/scroll-restoration.ts +21 -0
  229. package/src/lib/server/auth.server.ts +13 -5
  230. package/src/lib/server/bundleActivity.ts +27 -28
  231. package/src/lib/server/config.server.ts +21 -76
  232. package/src/lib/server/console-feature-apis.ts +70 -0
  233. package/src/lib/server/console-runtime.server.ts +82 -38
  234. package/src/lib/server/downloadBundle.ts +14 -15
  235. package/src/lib/server/failureReports.ts +50 -0
  236. package/src/lib/server/getBundleChildren.ts +31 -122
  237. package/src/lib/server/insightsUsage.ts +52 -113
  238. package/src/lib/server/listReleases.ts +109 -44
  239. package/src/lib/server/releaseAdoption.ts +151 -0
  240. package/src/lib/server/releaseReachability.ts +8 -8
  241. package/src/lib/server/remoteConfig.ts +75 -0
  242. package/src/lib/server/runtime.server.ts +120 -31
  243. package/src/lib/server/updateFailures.ts +66 -0
  244. package/src/lib/use-dialog-target.ts +27 -0
  245. package/src/routeTree.gen.ts +44 -44
  246. package/src/router.tsx +3 -2
  247. package/src/routes/-installations-search.ts +32 -8
  248. package/src/routes/-releases-search.ts +76 -29
  249. package/src/routes/__root.tsx +7 -1
  250. package/src/routes/api/bundles/$bundleId/download.ts +2 -5
  251. package/src/routes/api-keys.tsx +5 -2
  252. package/src/routes/index.tsx +210 -152
  253. package/src/routes/insights.tsx +91 -23
  254. package/src/routes/insights_.distribution.tsx +50 -9
  255. package/src/routes/installations.tsx +97 -40
  256. package/src/routes/remote-config.tsx +42 -0
  257. package/src/styles.css +9 -0
  258. package/src/vite-internal.ts +15 -3
  259. package/src/vite.ts +2 -0
  260. package/.output/public/assets/HashValueDisplay-BpTc3Oyg.js +0 -1
  261. package/.output/public/assets/InsightsPageHeader-DC2eEst8.js +0 -1
  262. package/.output/public/assets/api-CdUyUqzR.js +0 -42
  263. package/.output/public/assets/api-keys-64PM9PwW.js +0 -1
  264. package/.output/public/assets/api-keys-api-BeaJnvY5.js +0 -1
  265. package/.output/public/assets/arrow-left-04Rh8Zgp.js +0 -1
  266. package/.output/public/assets/card-CYHs5FZv.js +0 -1
  267. package/.output/public/assets/chart-no-axes-combined-DwyMsVFW.js +0 -1
  268. package/.output/public/assets/createServerFn-DU71xucx.js +0 -3
  269. package/.output/public/assets/dialog-IVMkBRCq.js +0 -1
  270. package/.output/public/assets/dist-BR4GzeEu.js +0 -1
  271. package/.output/public/assets/field-B3CYDpjg.js +0 -1
  272. package/.output/public/assets/index-C39o7rJH.js +0 -10
  273. package/.output/public/assets/info-C3y9HNoU.js +0 -1
  274. package/.output/public/assets/input-group-nLZylhWF.js +0 -1
  275. package/.output/public/assets/insights-Bm9v8uO3.js +0 -2
  276. package/.output/public/assets/insights-DS3iO7Up.js +0 -1
  277. package/.output/public/assets/insights-search-Byj3g3Mp.js +0 -1
  278. package/.output/public/assets/insights-usage-rpc-BaGR3lgq.js +0 -1
  279. package/.output/public/assets/insights_.distribution-B1i6cjlQ.js +0 -1
  280. package/.output/public/assets/insights_.distribution-C1Wf27eB.js +0 -2
  281. package/.output/public/assets/installations-CkFW4fV9.js +0 -2
  282. package/.output/public/assets/installations-DxTaIcHD.js +0 -1
  283. package/.output/public/assets/lazyRouteComponent-BapzjYnb.js +0 -1
  284. package/.output/public/assets/list-Dqt53fWZ.js +0 -1
  285. package/.output/public/assets/loader-circle-CUKfUqow.js +0 -1
  286. package/.output/public/assets/preload-helper-ClBMtM1g.js +0 -1
  287. package/.output/public/assets/refresh-cw-CNE_2PnD.js +0 -1
  288. package/.output/public/assets/routes-Cgtvspjg.js +0 -2
  289. package/.output/public/assets/routes-O2r2UUN8.js +0 -1
  290. package/.output/public/assets/shield-check-BFcJ46kz.js +0 -1
  291. package/.output/public/assets/signing-BgspC-xP.js +0 -1
  292. package/.output/public/assets/styles-DnrWuBwd.css +0 -2
  293. package/.output/public/assets/table-BuWQgxJJ.js +0 -1
  294. package/.output/public/assets/useMutation-CSV9NCUl.js +0 -1
  295. package/.output/public/assets/useOpenInteractionType-D5kduCTD.js +0 -1
  296. package/.output/public/assets/valueToPercent-BAtcbSLk.js +0 -1
  297. package/.output/server/__23tanstack-start-server-fn-resolver-CmYkol9D.mjs +0 -150
  298. package/.output/server/_ssr/InsightsPageHeader-Dma3dVj1.mjs +0 -64
  299. package/.output/server/_ssr/api-C3bGmgY0.mjs +0 -332
  300. package/.output/server/_ssr/api-keys-api-BRF6rbRC.mjs +0 -60
  301. package/.output/server/_ssr/api-keys-rpc-BMa1ZM6N.mjs +0 -136
  302. package/.output/server/_ssr/api-rpc-BYQ2e0z6.mjs +0 -1399
  303. package/.output/server/_ssr/auth.server-CmicHh0J.mjs +0 -47
  304. package/.output/server/_ssr/bundle-signing-rpc-DbQ4pFAX.mjs +0 -16
  305. package/.output/server/_ssr/bundle-signing.server-Uqt1OF49.mjs +0 -12
  306. package/.output/server/_ssr/bundleActivity-pBrPSG01.mjs +0 -28
  307. package/.output/server/_ssr/card-B7KSO_25.mjs +0 -108
  308. package/.output/server/_ssr/config-Dv8qLDZ0.mjs +0 -13
  309. package/.output/server/_ssr/config.server-C-d1QaBU.mjs +0 -368
  310. package/.output/server/_ssr/databaseRows-5bCRTxm-.mjs +0 -126
  311. package/.output/server/_ssr/deleteBundle-8X-jq7Z7.mjs +0 -66
  312. package/.output/server/_ssr/field-BDwuU8RE.mjs +0 -74
  313. package/.output/server/_ssr/getBundleChildren-DoL8l_AS.mjs +0 -50
  314. package/.output/server/_ssr/insights-BDJjaDLp.mjs +0 -938
  315. package/.output/server/_ssr/insights-D0FWpfOS.mjs +0 -10
  316. package/.output/server/_ssr/insights-recovery-Cv6RSyeR.mjs +0 -21
  317. package/.output/server/_ssr/insights-recovery-rpc-BE9YsK_T.mjs +0 -37
  318. package/.output/server/_ssr/insights-search-1czJMZgk.mjs +0 -21
  319. package/.output/server/_ssr/insights-usage-rpc-BE_aCnea.mjs +0 -184
  320. package/.output/server/_ssr/insights-usage-rpc-CtAolz-t.mjs +0 -24
  321. package/.output/server/_ssr/insightsContract-B09K_Px1.mjs +0 -303
  322. package/.output/server/_ssr/insightsHistory-Ci4rYAgl.mjs +0 -41
  323. package/.output/server/_ssr/insightsRecovery-CaghWL2t.mjs +0 -113
  324. package/.output/server/_ssr/insightsUsage-DNIj6jxF.mjs +0 -71
  325. package/.output/server/_ssr/insights_.distribution-Cp0kf1vW.mjs +0 -10
  326. package/.output/server/_ssr/installations-Bhyiwx8G.mjs +0 -29
  327. package/.output/server/_ssr/routes-xBkI2Fmt.mjs +0 -37
  328. package/.output/server/_ssr/runtime.server-CsiKFp_Z.mjs +0 -436
  329. package/.output/server/_ssr/server-BdkuOWe8.mjs +0 -7468
  330. package/.output/server/_ssr/signing-CQ70saFm.mjs +0 -133
  331. package/.output/server/_ssr/start-DpViQGnt.mjs +0 -4
  332. package/.output/server/_tanstack-start-manifest_v-CrBsoKQQ.mjs +0 -125
  333. package/src/components/features/bundles/BundleActivityChart.tsx +0 -97
  334. package/src/components/features/bundles/BundleInsightsSummary.tsx +0 -126
  335. package/src/components/features/signing/BundleSigningPage.tsx +0 -139
  336. package/src/lib/bundle-signing-api.ts +0 -14
  337. package/src/lib/bundle-signing-rpc.ts +0 -16
  338. package/src/lib/server/bundle-signing.server.ts +0 -23
  339. package/src/lib/server/deleteBundle.ts +0 -145
  340. package/src/lib/server/insightsHistory.ts +0 -52
  341. package/src/lib/server/insightsRecovery.ts +0 -187
  342. package/src/routes/signing.tsx +0 -37
@@ -9,23 +9,23 @@
9
9
  // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
10
10
 
11
11
  import { Route as rootRouteImport } from './routes/__root'
12
- import { Route as SigningRouteImport } from './routes/signing'
13
- import { Route as InstallationsRouteImport } from './routes/installations'
14
- import { Route as InsightsRouteImport } from './routes/insights'
15
- import { Route as ApiKeysRouteImport } from './routes/api-keys'
16
12
  import { Route as IndexRouteImport } from './routes/index'
13
+ import { Route as ApiKeysRouteImport } from './routes/api-keys'
14
+ import { Route as InsightsRouteImport } from './routes/insights'
15
+ import { Route as InstallationsRouteImport } from './routes/installations'
16
+ import { Route as RemoteConfigRouteImport } from './routes/remote-config'
17
17
  import { Route as InsightsDistributionRouteImport } from './routes/insights_.distribution'
18
18
  import { Route as ApiAuthSplatRouteImport } from './routes/api/auth/$'
19
19
  import { Route as ApiBundlesBundleIdDownloadRouteImport } from './routes/api/bundles/$bundleId/download'
20
20
 
21
- const SigningRoute = SigningRouteImport.update({
22
- id: '/signing',
23
- path: '/signing',
21
+ const IndexRoute = IndexRouteImport.update({
22
+ id: '/',
23
+ path: '/',
24
24
  getParentRoute: () => rootRouteImport,
25
25
  } as any)
26
- const InstallationsRoute = InstallationsRouteImport.update({
27
- id: '/installations',
28
- path: '/installations',
26
+ const ApiKeysRoute = ApiKeysRouteImport.update({
27
+ id: '/api-keys',
28
+ path: '/api-keys',
29
29
  getParentRoute: () => rootRouteImport,
30
30
  } as any)
31
31
  const InsightsRoute = InsightsRouteImport.update({
@@ -33,14 +33,14 @@ const InsightsRoute = InsightsRouteImport.update({
33
33
  path: '/insights',
34
34
  getParentRoute: () => rootRouteImport,
35
35
  } as any)
36
- const ApiKeysRoute = ApiKeysRouteImport.update({
37
- id: '/api-keys',
38
- path: '/api-keys',
36
+ const InstallationsRoute = InstallationsRouteImport.update({
37
+ id: '/installations',
38
+ path: '/installations',
39
39
  getParentRoute: () => rootRouteImport,
40
40
  } as any)
41
- const IndexRoute = IndexRouteImport.update({
42
- id: '/',
43
- path: '/',
41
+ const RemoteConfigRoute = RemoteConfigRouteImport.update({
42
+ id: '/remote-config',
43
+ path: '/remote-config',
44
44
  getParentRoute: () => rootRouteImport,
45
45
  } as any)
46
46
  const InsightsDistributionRoute = InsightsDistributionRouteImport.update({
@@ -65,7 +65,7 @@ export interface FileRoutesByFullPath {
65
65
  '/api-keys': typeof ApiKeysRoute
66
66
  '/insights': typeof InsightsRoute
67
67
  '/installations': typeof InstallationsRoute
68
- '/signing': typeof SigningRoute
68
+ '/remote-config': typeof RemoteConfigRoute
69
69
  '/insights/distribution': typeof InsightsDistributionRoute
70
70
  '/api/auth/$': typeof ApiAuthSplatRoute
71
71
  '/api/bundles/$bundleId/download': typeof ApiBundlesBundleIdDownloadRoute
@@ -75,7 +75,7 @@ export interface FileRoutesByTo {
75
75
  '/api-keys': typeof ApiKeysRoute
76
76
  '/insights': typeof InsightsRoute
77
77
  '/installations': typeof InstallationsRoute
78
- '/signing': typeof SigningRoute
78
+ '/remote-config': typeof RemoteConfigRoute
79
79
  '/insights/distribution': typeof InsightsDistributionRoute
80
80
  '/api/auth/$': typeof ApiAuthSplatRoute
81
81
  '/api/bundles/$bundleId/download': typeof ApiBundlesBundleIdDownloadRoute
@@ -86,7 +86,7 @@ export interface FileRoutesById {
86
86
  '/api-keys': typeof ApiKeysRoute
87
87
  '/insights': typeof InsightsRoute
88
88
  '/installations': typeof InstallationsRoute
89
- '/signing': typeof SigningRoute
89
+ '/remote-config': typeof RemoteConfigRoute
90
90
  '/insights_/distribution': typeof InsightsDistributionRoute
91
91
  '/api/auth/$': typeof ApiAuthSplatRoute
92
92
  '/api/bundles/$bundleId/download': typeof ApiBundlesBundleIdDownloadRoute
@@ -98,7 +98,7 @@ export interface FileRouteTypes {
98
98
  | '/api-keys'
99
99
  | '/insights'
100
100
  | '/installations'
101
- | '/signing'
101
+ | '/remote-config'
102
102
  | '/insights/distribution'
103
103
  | '/api/auth/$'
104
104
  | '/api/bundles/$bundleId/download'
@@ -108,7 +108,7 @@ export interface FileRouteTypes {
108
108
  | '/api-keys'
109
109
  | '/insights'
110
110
  | '/installations'
111
- | '/signing'
111
+ | '/remote-config'
112
112
  | '/insights/distribution'
113
113
  | '/api/auth/$'
114
114
  | '/api/bundles/$bundleId/download'
@@ -118,7 +118,7 @@ export interface FileRouteTypes {
118
118
  | '/api-keys'
119
119
  | '/insights'
120
120
  | '/installations'
121
- | '/signing'
121
+ | '/remote-config'
122
122
  | '/insights_/distribution'
123
123
  | '/api/auth/$'
124
124
  | '/api/bundles/$bundleId/download'
@@ -129,7 +129,7 @@ export interface RootRouteChildren {
129
129
  ApiKeysRoute: typeof ApiKeysRoute
130
130
  InsightsRoute: typeof InsightsRoute
131
131
  InstallationsRoute: typeof InstallationsRoute
132
- SigningRoute: typeof SigningRoute
132
+ RemoteConfigRoute: typeof RemoteConfigRoute
133
133
  InsightsDistributionRoute: typeof InsightsDistributionRoute
134
134
  ApiAuthSplatRoute: typeof ApiAuthSplatRoute
135
135
  ApiBundlesBundleIdDownloadRoute: typeof ApiBundlesBundleIdDownloadRoute
@@ -137,18 +137,18 @@ export interface RootRouteChildren {
137
137
 
138
138
  declare module '@tanstack/react-router' {
139
139
  interface FileRoutesByPath {
140
- '/signing': {
141
- id: '/signing'
142
- path: '/signing'
143
- fullPath: '/signing'
144
- preLoaderRoute: typeof SigningRouteImport
140
+ '/': {
141
+ id: '/'
142
+ path: '/'
143
+ fullPath: '/'
144
+ preLoaderRoute: typeof IndexRouteImport
145
145
  parentRoute: typeof rootRouteImport
146
146
  }
147
- '/installations': {
148
- id: '/installations'
149
- path: '/installations'
150
- fullPath: '/installations'
151
- preLoaderRoute: typeof InstallationsRouteImport
147
+ '/api-keys': {
148
+ id: '/api-keys'
149
+ path: '/api-keys'
150
+ fullPath: '/api-keys'
151
+ preLoaderRoute: typeof ApiKeysRouteImport
152
152
  parentRoute: typeof rootRouteImport
153
153
  }
154
154
  '/insights': {
@@ -158,18 +158,18 @@ declare module '@tanstack/react-router' {
158
158
  preLoaderRoute: typeof InsightsRouteImport
159
159
  parentRoute: typeof rootRouteImport
160
160
  }
161
- '/api-keys': {
162
- id: '/api-keys'
163
- path: '/api-keys'
164
- fullPath: '/api-keys'
165
- preLoaderRoute: typeof ApiKeysRouteImport
161
+ '/installations': {
162
+ id: '/installations'
163
+ path: '/installations'
164
+ fullPath: '/installations'
165
+ preLoaderRoute: typeof InstallationsRouteImport
166
166
  parentRoute: typeof rootRouteImport
167
167
  }
168
- '/': {
169
- id: '/'
170
- path: '/'
171
- fullPath: '/'
172
- preLoaderRoute: typeof IndexRouteImport
168
+ '/remote-config': {
169
+ id: '/remote-config'
170
+ path: '/remote-config'
171
+ fullPath: '/remote-config'
172
+ preLoaderRoute: typeof RemoteConfigRouteImport
173
173
  parentRoute: typeof rootRouteImport
174
174
  }
175
175
  '/insights_/distribution': {
@@ -201,7 +201,7 @@ const rootRouteChildren: RootRouteChildren = {
201
201
  ApiKeysRoute: ApiKeysRoute,
202
202
  InsightsRoute: InsightsRoute,
203
203
  InstallationsRoute: InstallationsRoute,
204
- SigningRoute: SigningRoute,
204
+ RemoteConfigRoute: RemoteConfigRoute,
205
205
  InsightsDistributionRoute: InsightsDistributionRoute,
206
206
  ApiAuthSplatRoute: ApiAuthSplatRoute,
207
207
  ApiBundlesBundleIdDownloadRoute: ApiBundlesBundleIdDownloadRoute,
package/src/router.tsx CHANGED
@@ -4,7 +4,7 @@ import { setupRouterSsrQueryIntegration } from "@tanstack/react-router-ssr-query
4
4
  // Import the route tree selected by the local or hosted Vite integration.
5
5
  import { routeTree } from "virtual:hot-updater-console/route-tree";
6
6
 
7
- import { getInsightsScrollRestorationKey } from "./routes/-installations-search";
7
+ import { routeScrollRestorationKey } from "./lib/scroll-restoration";
8
8
 
9
9
  // Create a new router instance
10
10
  export const getRouter = () => {
@@ -14,7 +14,8 @@ export const getRouter = () => {
14
14
  context: { queryClient },
15
15
 
16
16
  scrollRestoration: true,
17
- getScrollRestorationKey: getInsightsScrollRestorationKey,
17
+ getScrollRestorationKey: (location): string =>
18
+ routeScrollRestorationKey(router, location),
18
19
  defaultPreloadStaleTime: 0,
19
20
  });
20
21
 
@@ -1,5 +1,23 @@
1
1
  import type { ParsedLocation } from "@tanstack/react-router";
2
2
 
3
+ import {
4
+ DEFAULT_EVENT_RANGE,
5
+ EVENT_RANGES,
6
+ type EventRange,
7
+ } from "../lib/insights-view";
8
+
9
+ export type InsightsPaginationState = {
10
+ readonly eventsBack?: readonly string[];
11
+ readonly searchBack?: readonly string[];
12
+ readonly historyBack?: readonly string[];
13
+ };
14
+
15
+ declare module "@tanstack/react-router" {
16
+ interface HistoryState {
17
+ insightsPagination?: InsightsPaginationState;
18
+ }
19
+ }
20
+
3
21
  const readCursor = (value: unknown): string | undefined =>
4
22
  typeof value === "string" && value.length > 0 ? value : undefined;
5
23
 
@@ -8,14 +26,19 @@ const readTimestamp = (value: unknown): number | undefined =>
8
26
  ? value
9
27
  : undefined;
10
28
 
11
- export function getInsightsScrollRestorationKey(location: ParsedLocation) {
12
- if (location.pathname === "/installations") {
13
- const search = validateInstallationsSearch(location.search);
14
- if (search.query === undefined && search.installId === undefined) {
15
- return `/installations?eventsBefore=${search.eventsBefore ?? "new"}&eventsCursor=${search.eventsCursor ?? "first"}`;
16
- }
17
- }
18
- return location.state.__TSR_key!;
29
+ const readEventRange = (value: unknown): EventRange | undefined =>
30
+ EVENT_RANGES.find((range) => range === value);
31
+
32
+ /**
33
+ * The installations route's scroll-restoration key: every visit to one page
34
+ * of the event list shares its scroll position, and a lookup keeps its own
35
+ * for each history entry.
36
+ */
37
+ export function installationsScrollRestorationKey(location: ParsedLocation) {
38
+ const search = validateInstallationsSearch(location.search);
39
+ return search.query === undefined && search.installId === undefined
40
+ ? `/installations?eventsBefore=${search.eventsBefore ?? "new"}&eventsRange=${search.eventsRange ?? DEFAULT_EVENT_RANGE}&eventsCursor=${search.eventsCursor ?? "first"}`
41
+ : location.state.__TSR_key!;
19
42
  }
20
43
 
21
44
  export function validateInstallationsSearch(search: Record<string, unknown>) {
@@ -25,6 +48,7 @@ export function validateInstallationsSearch(search: Record<string, unknown>) {
25
48
  typeof search.installId === "string" ? search.installId : undefined,
26
49
  eventsCursor: readCursor(search.eventsCursor),
27
50
  eventsBefore: readTimestamp(search.eventsBefore),
51
+ eventsRange: readEventRange(search.eventsRange),
28
52
  searchCursor: readCursor(search.searchCursor),
29
53
  historyCursor: readCursor(search.historyCursor),
30
54
  historyBefore: readTimestamp(search.historyBefore),
@@ -1,13 +1,17 @@
1
+ import type { ReleaseFilter } from "@hot-updater/plugin-core";
2
+
1
3
  export interface ReleaseSearch {
4
+ /** Releases newer than this id: the previous page. */
2
5
  afterReleaseId?: string;
6
+ /** Releases older than this id: the next page. */
3
7
  beforeReleaseId?: string;
4
8
  bundleId?: string;
5
9
  channelId?: string;
6
10
  enabled?: boolean;
7
- page?: number;
8
11
  platform?: "ios" | "android";
9
12
  releaseId?: string;
10
- targetAppVersion?: string;
13
+ /** One catalog scope: a channel, platform, and target kind. */
14
+ scopeKey?: string;
11
15
  }
12
16
 
13
17
  const optionalString = (value: unknown) =>
@@ -15,15 +19,14 @@ const optionalString = (value: unknown) =>
15
19
  ? value.trim()
16
20
  : undefined;
17
21
 
22
+ /**
23
+ * The search a URL holds, reduced to one of the filter sets the release
24
+ * indexes serve: a bundle, a scope (with enabled), or a channel with its
25
+ * platform (with enabled). A channel without a platform lists iOS.
26
+ */
18
27
  export function validateReleaseSearch(
19
28
  search: Record<string, unknown>,
20
29
  ): ReleaseSearch {
21
- const parsedPage =
22
- typeof search.page === "number"
23
- ? search.page
24
- : typeof search.page === "string"
25
- ? Number(search.page)
26
- : undefined;
27
30
  const beforeReleaseId = optionalString(search.beforeReleaseId);
28
31
  const afterReleaseId = beforeReleaseId
29
32
  ? undefined
@@ -34,41 +37,85 @@ export function validateReleaseSearch(
34
37
  : search.enabled === false || search.enabled === "false"
35
38
  ? false
36
39
  : undefined;
40
+ const bundleId = optionalString(search.bundleId);
41
+ const scopeKey = bundleId ? undefined : optionalString(search.scopeKey);
42
+ const channelId =
43
+ bundleId || scopeKey ? undefined : optionalString(search.channelId);
44
+ const platform =
45
+ channelId === undefined
46
+ ? undefined
47
+ : search.platform === "android"
48
+ ? "android"
49
+ : "ios";
37
50
 
38
51
  return {
39
52
  afterReleaseId,
40
53
  beforeReleaseId,
41
- bundleId: optionalString(search.bundleId),
42
- channelId: optionalString(search.channelId),
43
- enabled,
44
- page:
45
- parsedPage !== undefined && Number.isInteger(parsedPage) && parsedPage > 1
46
- ? parsedPage
47
- : undefined,
48
- platform:
49
- search.platform === "ios" || search.platform === "android"
50
- ? search.platform
51
- : undefined,
54
+ bundleId,
55
+ channelId,
56
+ enabled: scopeKey || channelId ? enabled : undefined,
57
+ platform,
52
58
  releaseId: optionalString(search.releaseId),
53
- targetAppVersion: optionalString(search.targetAppVersion),
59
+ scopeKey,
54
60
  };
55
61
  }
56
62
 
63
+ export function releaseFilterOf(search: ReleaseSearch): ReleaseFilter {
64
+ const enabled =
65
+ search.enabled === undefined ? {} : { enabled: search.enabled };
66
+ if (search.bundleId) return { kind: "bundle", bundleId: search.bundleId };
67
+ if (search.scopeKey) {
68
+ return { kind: "scope", scopeKey: search.scopeKey, ...enabled };
69
+ }
70
+ if (search.channelId && search.platform) {
71
+ return {
72
+ kind: "channelPlatform",
73
+ channelId: search.channelId,
74
+ platform: search.platform,
75
+ ...enabled,
76
+ };
77
+ }
78
+ return { kind: "all" };
79
+ }
80
+
81
+ export function hasReleaseFilters(search: ReleaseSearch): boolean {
82
+ return releaseFilterOf(search).kind !== "all";
83
+ }
84
+
85
+ /**
86
+ * A new filter starts from the first page. A bundle or scope filter replaces
87
+ * the others, and choosing a channel or platform clears them.
88
+ */
57
89
  export function updateReleaseFilters(
58
90
  current: ReleaseSearch,
59
91
  filters: Partial<
60
92
  Pick<
61
93
  ReleaseSearch,
62
- "bundleId" | "channelId" | "enabled" | "platform" | "targetAppVersion"
94
+ "bundleId" | "channelId" | "enabled" | "platform" | "scopeKey"
63
95
  >
64
96
  >,
65
97
  ): ReleaseSearch {
66
- return {
67
- ...current,
68
- ...filters,
69
- afterReleaseId: undefined,
70
- beforeReleaseId: undefined,
71
- page: undefined,
72
- releaseId: undefined,
73
- };
98
+ const next = { ...current, ...filters };
99
+ if (filters.bundleId)
100
+ return validateReleaseSearch({ bundleId: next.bundleId });
101
+ if (filters.scopeKey) {
102
+ return validateReleaseSearch({
103
+ scopeKey: next.scopeKey,
104
+ enabled: next.enabled,
105
+ });
106
+ }
107
+ if ("channelId" in filters || "platform" in filters) {
108
+ return validateReleaseSearch({
109
+ channelId: next.channelId,
110
+ enabled: next.enabled,
111
+ platform: next.platform,
112
+ });
113
+ }
114
+ return validateReleaseSearch({
115
+ bundleId: next.bundleId,
116
+ channelId: next.channelId,
117
+ enabled: next.enabled,
118
+ platform: next.platform,
119
+ scopeKey: next.scopeKey,
120
+ });
74
121
  }
@@ -18,6 +18,7 @@ import {
18
18
  getConsoleAccessRpc,
19
19
  getConsoleAuthProvidersRpc,
20
20
  } from "@/lib/auth-rpc";
21
+ import { consoleFeaturesQueryOptions } from "@/lib/console-features-api";
21
22
 
22
23
  import appCss from "../styles.css?url";
23
24
 
@@ -60,11 +61,16 @@ export const Route = createRootRouteWithContext<{
60
61
  ],
61
62
  }),
62
63
 
63
- loader: async () => {
64
+ loader: async ({ context }) => {
64
65
  const [access, providers] = await Promise.all([
65
66
  getConsoleAccessRpc(),
66
67
  getConsoleAuthProvidersRpc(),
67
68
  ]);
69
+ // The authorized layout's navigation shows only the features on, so they
70
+ // load with it; the query keeps them for the visit.
71
+ if (access.status === "authorized") {
72
+ await context.queryClient.prefetchQuery(consoleFeaturesQueryOptions());
73
+ }
68
74
  return { access, providers };
69
75
  },
70
76
 
@@ -6,11 +6,8 @@ export const Route = createFileRoute("/api/bundles/$bundleId/download")({
6
6
  GET: async ({ params, request }) => {
7
7
  const { prepareConfig } = await import("@/lib/server/config.server");
8
8
  const { downloadBundle } = await import("@/lib/server/downloadBundle");
9
- const { databaseClient, storagePlugin } = await prepareConfig(request);
10
- return downloadBundle(params.bundleId, {
11
- databaseClient,
12
- storagePlugin,
13
- });
9
+ const { core, storage } = await prepareConfig(request);
10
+ return downloadBundle(params.bundleId, { core, storage });
14
11
  },
15
12
  },
16
13
  },
@@ -1,12 +1,15 @@
1
1
  import { createFileRoute } from "@tanstack/react-router";
2
2
  import { KeyRound } from "lucide-react";
3
3
 
4
+ import { ConsoleFeatureUnavailable } from "@/components/ConsoleFeatureUnavailable";
4
5
  import { ApiKeysPage } from "@/components/features/api-keys/ApiKeysPage";
5
6
  import { SidebarTrigger } from "@/components/ui/sidebar";
6
- import { ensureApiKeyRouteAccess } from "@/lib/api-keys-api";
7
+ import { requireConsoleFeature } from "@/lib/console-features-api";
7
8
 
8
9
  export const Route = createFileRoute("/api-keys")({
9
- beforeLoad: ({ context }) => ensureApiKeyRouteAccess(context.queryClient),
10
+ beforeLoad: ({ context }) =>
11
+ requireConsoleFeature(context.queryClient, "apiKeys"),
12
+ notFoundComponent: ConsoleFeatureUnavailable,
10
13
  component: ApiKeysRoute,
11
14
  });
12
15