@hot-updater/console 1.0.0-rc.9 → 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 (341) 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-CyMmr0O9.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-CKvQ4VIE.mjs → alert-dialog-C43Doa0I.mjs} +6 -83
  74. package/.output/server/_ssr/{api-keys-CzZ7Ont4.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-DH6Bhwcz.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-BrGSjz4S.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-DDKmIrpV.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-cIsU-kHG.mjs → insights_.distribution-DN9pR422.mjs} +50 -22
  120. package/.output/server/_ssr/installations-BHmbbnH8.mjs +5 -0
  121. package/.output/server/_ssr/{installations-C5anhyP0.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-BuanSsRI.mjs → router-D8NuoJ_I.mjs} +107 -134
  135. package/.output/server/_ssr/{routes-DY-vqU6R.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-DD2szs3Y.mjs → select-t3iXRwc9.mjs} +3 -3
  140. package/.output/server/_ssr/server-h4VxnExB.mjs +8325 -0
  141. package/.output/server/_ssr/{createSsrRpc-CdlfejmI.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-CTj6n-4F.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 +309 -211
  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 +69 -74
  158. package/src/components/ConsoleFeatureUnavailable.tsx +80 -0
  159. package/src/components/NotFoundPage.tsx +7 -7
  160. package/src/components/features/FeatureSlots.tsx +103 -0
  161. package/src/components/features/api-keys/apiKeysFeatureUi.tsx +15 -0
  162. package/src/components/features/bundles/BundleMetadata.tsx +8 -5
  163. package/src/components/features/bundles/RolloutCohortsDialog.tsx +1 -1
  164. package/src/components/features/channels/ChannelManagementDialog.tsx +8 -6
  165. package/src/components/features/insights/AppUsage.tsx +41 -14
  166. package/src/components/features/insights/BuiltinBundle.tsx +36 -0
  167. package/src/components/features/insights/ComparedBundlesChart.tsx +310 -0
  168. package/src/components/features/insights/EstimatedCount.tsx +18 -0
  169. package/src/components/features/insights/EventDetails.tsx +390 -26
  170. package/src/components/features/insights/EventHistoryCard.tsx +111 -25
  171. package/src/components/features/insights/EventHistoryList.tsx +1 -1
  172. package/src/components/features/insights/FailureReports.tsx +407 -0
  173. package/src/components/features/insights/InsightsControls.tsx +240 -142
  174. package/src/components/features/insights/InsightsErrorAlert.tsx +14 -1
  175. package/src/components/features/insights/InsightsOverview.tsx +601 -403
  176. package/src/components/features/insights/InsightsPageHeader.tsx +19 -14
  177. package/src/components/features/insights/InsightsPeriodSelector.tsx +67 -12
  178. package/src/components/features/insights/InstallationHistoryCard.tsx +65 -10
  179. package/src/components/features/insights/InstallationMatchesCard.tsx +1 -1
  180. package/src/components/features/insights/ReleaseActivity.tsx +308 -0
  181. package/src/components/features/insights/ReportingDevicesSummary.tsx +13 -13
  182. package/src/components/features/insights/RollbackButton.tsx +118 -0
  183. package/src/components/features/insights/UpdateFailures.tsx +382 -0
  184. package/src/components/features/insights/insightsFeatureUi.tsx +35 -0
  185. package/src/components/features/releases/ReleaseEditorSheet.tsx +27 -13
  186. package/src/components/features/remote-config/ConditionDialog.tsx +592 -0
  187. package/src/components/features/remote-config/ConditionsCard.tsx +247 -0
  188. package/src/components/features/remote-config/ParameterDialog.tsx +426 -0
  189. package/src/components/features/remote-config/ParametersCard.tsx +254 -0
  190. package/src/components/features/remote-config/PreviewCard.tsx +284 -0
  191. package/src/components/features/remote-config/PublishDialog.tsx +325 -0
  192. package/src/components/features/remote-config/RemoteConfigPage.tsx +353 -0
  193. package/src/components/features/remote-config/RuleSummary.tsx +21 -0
  194. package/src/components/features/remote-config/ValueInput.tsx +151 -0
  195. package/src/components/features/remote-config/VersionsCard.tsx +384 -0
  196. package/src/components/features/remote-config/remoteConfigFeatureUi.tsx +15 -0
  197. package/src/components/features/remote-config/useDateTimeText.ts +16 -0
  198. package/src/components/ui/sidebar.tsx +22 -29
  199. package/src/index.ts +26 -19
  200. package/src/lib/api-keys-api.ts +0 -28
  201. package/src/lib/api-keys-rpc.ts +27 -38
  202. package/src/lib/api-rpc.ts +125 -288
  203. package/src/lib/api.ts +15 -134
  204. package/src/lib/bundle-activity.ts +24 -4
  205. package/src/lib/console-access.ts +20 -0
  206. package/src/lib/console-features-api.ts +68 -0
  207. package/src/lib/console-features-rpc.ts +13 -0
  208. package/src/lib/console-features.ts +98 -0
  209. package/src/lib/insights-api.ts +56 -2
  210. package/src/lib/insights-errors.ts +64 -0
  211. package/src/lib/insights-failures-rpc.ts +36 -0
  212. package/src/lib/insights-failures.ts +130 -0
  213. package/src/lib/insights-recovery-rpc.ts +13 -17
  214. package/src/lib/insights-recovery.ts +12 -36
  215. package/src/lib/insights-retention.ts +21 -0
  216. package/src/lib/insights-rpc.ts +30 -12
  217. package/src/lib/insights-search.ts +50 -4
  218. package/src/lib/insights-usage-rpc.ts +15 -9
  219. package/src/lib/insights-usage.ts +41 -3
  220. package/src/lib/insights-view.ts +34 -5
  221. package/src/lib/release-adoption-api.ts +214 -0
  222. package/src/lib/release-adoption-rpc.ts +49 -0
  223. package/src/lib/release-adoption.ts +164 -0
  224. package/src/lib/remote-config-api.ts +119 -0
  225. package/src/lib/remote-config-draft.ts +666 -0
  226. package/src/lib/remote-config-rpc.ts +196 -0
  227. package/src/lib/scroll-restoration.ts +21 -0
  228. package/src/lib/server/auth.server.ts +13 -5
  229. package/src/lib/server/bundleActivity.ts +27 -28
  230. package/src/lib/server/config.server.ts +21 -76
  231. package/src/lib/server/console-feature-apis.ts +70 -0
  232. package/src/lib/server/console-runtime.server.ts +82 -38
  233. package/src/lib/server/downloadBundle.ts +14 -15
  234. package/src/lib/server/failureReports.ts +50 -0
  235. package/src/lib/server/getBundleChildren.ts +31 -122
  236. package/src/lib/server/insightsUsage.ts +52 -113
  237. package/src/lib/server/listReleases.ts +109 -44
  238. package/src/lib/server/releaseAdoption.ts +151 -0
  239. package/src/lib/server/releaseReachability.ts +8 -8
  240. package/src/lib/server/remoteConfig.ts +75 -0
  241. package/src/lib/server/runtime.server.ts +120 -31
  242. package/src/lib/server/updateFailures.ts +66 -0
  243. package/src/lib/use-dialog-target.ts +27 -0
  244. package/src/routeTree.gen.ts +44 -44
  245. package/src/router.tsx +3 -2
  246. package/src/routes/-installations-search.ts +32 -8
  247. package/src/routes/-releases-search.ts +76 -29
  248. package/src/routes/__root.tsx +7 -1
  249. package/src/routes/api/bundles/$bundleId/download.ts +2 -5
  250. package/src/routes/api-keys.tsx +5 -2
  251. package/src/routes/index.tsx +210 -152
  252. package/src/routes/insights.tsx +91 -23
  253. package/src/routes/insights_.distribution.tsx +50 -9
  254. package/src/routes/installations.tsx +97 -40
  255. package/src/routes/remote-config.tsx +42 -0
  256. package/src/styles.css +9 -0
  257. package/src/vite-internal.ts +15 -3
  258. package/src/vite.ts +2 -0
  259. package/.output/public/assets/HashValueDisplay-BpTc3Oyg.js +0 -1
  260. package/.output/public/assets/InsightsPageHeader-DC2eEst8.js +0 -1
  261. package/.output/public/assets/api-CdUyUqzR.js +0 -42
  262. package/.output/public/assets/api-keys-64PM9PwW.js +0 -1
  263. package/.output/public/assets/api-keys-api-BeaJnvY5.js +0 -1
  264. package/.output/public/assets/arrow-left-04Rh8Zgp.js +0 -1
  265. package/.output/public/assets/card-CYHs5FZv.js +0 -1
  266. package/.output/public/assets/chart-no-axes-combined-DwyMsVFW.js +0 -1
  267. package/.output/public/assets/createServerFn-DU71xucx.js +0 -3
  268. package/.output/public/assets/dialog-IVMkBRCq.js +0 -1
  269. package/.output/public/assets/dist-BR4GzeEu.js +0 -1
  270. package/.output/public/assets/field-B3CYDpjg.js +0 -1
  271. package/.output/public/assets/index-Cb_D1D6N.js +0 -10
  272. package/.output/public/assets/info-C3y9HNoU.js +0 -1
  273. package/.output/public/assets/input-group-nLZylhWF.js +0 -1
  274. package/.output/public/assets/insights-Bm9v8uO3.js +0 -2
  275. package/.output/public/assets/insights-DS3iO7Up.js +0 -1
  276. package/.output/public/assets/insights-search-Byj3g3Mp.js +0 -1
  277. package/.output/public/assets/insights-usage-rpc-BaGR3lgq.js +0 -1
  278. package/.output/public/assets/insights_.distribution-B1i6cjlQ.js +0 -1
  279. package/.output/public/assets/insights_.distribution-C1Wf27eB.js +0 -2
  280. package/.output/public/assets/installations-CkFW4fV9.js +0 -2
  281. package/.output/public/assets/installations-DxTaIcHD.js +0 -1
  282. package/.output/public/assets/lazyRouteComponent-BapzjYnb.js +0 -1
  283. package/.output/public/assets/list-Dqt53fWZ.js +0 -1
  284. package/.output/public/assets/loader-circle-CUKfUqow.js +0 -1
  285. package/.output/public/assets/preload-helper-ClBMtM1g.js +0 -1
  286. package/.output/public/assets/refresh-cw-CNE_2PnD.js +0 -1
  287. package/.output/public/assets/routes-Cgtvspjg.js +0 -2
  288. package/.output/public/assets/routes-O2r2UUN8.js +0 -1
  289. package/.output/public/assets/shield-check-BFcJ46kz.js +0 -1
  290. package/.output/public/assets/signing-BgspC-xP.js +0 -1
  291. package/.output/public/assets/styles-DnrWuBwd.css +0 -2
  292. package/.output/public/assets/table-BuWQgxJJ.js +0 -1
  293. package/.output/public/assets/useMutation-CSV9NCUl.js +0 -1
  294. package/.output/public/assets/useOpenInteractionType-D5kduCTD.js +0 -1
  295. package/.output/public/assets/valueToPercent-BAtcbSLk.js +0 -1
  296. package/.output/server/__23tanstack-start-server-fn-resolver-DBRojHaG.mjs +0 -150
  297. package/.output/server/_ssr/InsightsPageHeader-mtxVuZKK.mjs +0 -64
  298. package/.output/server/_ssr/api-BfCgYlj5.mjs +0 -332
  299. package/.output/server/_ssr/api-keys-api-C3oeq01R.mjs +0 -60
  300. package/.output/server/_ssr/api-keys-rpc-CdPFdGOx.mjs +0 -136
  301. package/.output/server/_ssr/api-rpc-B2E1ZIG5.mjs +0 -1399
  302. package/.output/server/_ssr/auth.server-CmicHh0J.mjs +0 -47
  303. package/.output/server/_ssr/bundle-signing-rpc-Di7-I6fE.mjs +0 -16
  304. package/.output/server/_ssr/bundle-signing.server-Uqt1OF49.mjs +0 -12
  305. package/.output/server/_ssr/bundleActivity-pBrPSG01.mjs +0 -28
  306. package/.output/server/_ssr/card-Bemj0dpY.mjs +0 -108
  307. package/.output/server/_ssr/config-Dv8qLDZ0.mjs +0 -13
  308. package/.output/server/_ssr/config.server-B8WsT3s0.mjs +0 -368
  309. package/.output/server/_ssr/databaseRows-5bCRTxm-.mjs +0 -126
  310. package/.output/server/_ssr/deleteBundle-8X-jq7Z7.mjs +0 -66
  311. package/.output/server/_ssr/field-BrQ2u0fT.mjs +0 -74
  312. package/.output/server/_ssr/getBundleChildren-DoL8l_AS.mjs +0 -50
  313. package/.output/server/_ssr/insights-BwQ-wF2a.mjs +0 -10
  314. package/.output/server/_ssr/insights-gr1I_dJU.mjs +0 -938
  315. package/.output/server/_ssr/insights-recovery-Cv6RSyeR.mjs +0 -21
  316. package/.output/server/_ssr/insights-recovery-rpc-DOzxfYfv.mjs +0 -37
  317. package/.output/server/_ssr/insights-search-1czJMZgk.mjs +0 -21
  318. package/.output/server/_ssr/insights-usage-rpc-4ImOq_0p.mjs +0 -184
  319. package/.output/server/_ssr/insights-usage-rpc-BUruODjE.mjs +0 -24
  320. package/.output/server/_ssr/insightsContract-B09K_Px1.mjs +0 -303
  321. package/.output/server/_ssr/insightsHistory-Ci4rYAgl.mjs +0 -41
  322. package/.output/server/_ssr/insightsRecovery-CaghWL2t.mjs +0 -113
  323. package/.output/server/_ssr/insightsUsage-DNIj6jxF.mjs +0 -71
  324. package/.output/server/_ssr/insights_.distribution-VmHuikRE.mjs +0 -10
  325. package/.output/server/_ssr/installations-HXMF_kKf.mjs +0 -29
  326. package/.output/server/_ssr/routes-Dru3IRj0.mjs +0 -37
  327. package/.output/server/_ssr/runtime.server-CsiKFp_Z.mjs +0 -436
  328. package/.output/server/_ssr/server-DJm72Kj-.mjs +0 -7468
  329. package/.output/server/_ssr/signing-H8Lg4lPe.mjs +0 -133
  330. package/.output/server/_ssr/start-DpViQGnt.mjs +0 -4
  331. package/.output/server/_tanstack-start-manifest_v-DsFcTLw_.mjs +0 -125
  332. package/src/components/features/bundles/BundleActivityChart.tsx +0 -97
  333. package/src/components/features/bundles/BundleInsightsSummary.tsx +0 -126
  334. package/src/components/features/signing/BundleSigningPage.tsx +0 -139
  335. package/src/lib/bundle-signing-api.ts +0 -14
  336. package/src/lib/bundle-signing-rpc.ts +0 -16
  337. package/src/lib/server/bundle-signing.server.ts +0 -23
  338. package/src/lib/server/deleteBundle.ts +0 -145
  339. package/src/lib/server/insightsHistory.ts +0 -52
  340. package/src/lib/server/insightsRecovery.ts +0 -187
  341. 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