@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
@@ -0,0 +1,254 @@
1
+ import { Pencil, Plus, Search, SlidersHorizontal, Trash2 } from "lucide-react";
2
+ import { useState } from "react";
3
+
4
+ import { Badge } from "@/components/ui/badge";
5
+ import { Button } from "@/components/ui/button";
6
+ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
7
+ import {
8
+ Empty,
9
+ EmptyContent,
10
+ EmptyDescription,
11
+ EmptyHeader,
12
+ EmptyMedia,
13
+ EmptyTitle,
14
+ } from "@/components/ui/empty";
15
+ import {
16
+ InputGroup,
17
+ InputGroupAddon,
18
+ InputGroupInput,
19
+ } from "@/components/ui/input-group";
20
+ import {
21
+ conditionalValueFor,
22
+ describeValue,
23
+ type RemoteConfigCondition,
24
+ type RemoteConfigParameter,
25
+ type RemoteConfigTemplate,
26
+ VALUE_TYPE_LABELS,
27
+ } from "@/lib/remote-config-draft";
28
+ import { useDialogTarget } from "@/lib/use-dialog-target";
29
+
30
+ import { ParameterDialog } from "./ParameterDialog";
31
+
32
+ /** A value's text in up to two lines, as the list shows it; a phone has no hover for the rest. */
33
+ function ValueText({ text }: { readonly text: string }) {
34
+ return (
35
+ <span
36
+ className="line-clamp-2 block min-w-0 break-words font-mono text-xs text-foreground"
37
+ title={text}
38
+ >
39
+ {text}
40
+ </span>
41
+ );
42
+ }
43
+
44
+ function ParameterRow({
45
+ parameterKey,
46
+ parameter,
47
+ conditions,
48
+ onEdit,
49
+ onRemove,
50
+ }: {
51
+ readonly parameterKey: string;
52
+ readonly parameter: RemoteConfigParameter;
53
+ readonly conditions: readonly RemoteConfigCondition[];
54
+ readonly onEdit: () => void;
55
+ readonly onRemove: () => void;
56
+ }) {
57
+ // In priority order, as devices resolve them.
58
+ const conditional = conditions.filter(
59
+ ({ name }) =>
60
+ conditionalValueFor(parameter.conditionalValues, name) !== undefined,
61
+ );
62
+ return (
63
+ <li className="grid gap-3 px-4 py-3 sm:px-6 md:grid-cols-[minmax(0,15rem)_minmax(0,1fr)_auto] md:items-start">
64
+ <div className="min-w-0">
65
+ <div className="flex min-w-0 items-center gap-2">
66
+ <span className="truncate font-mono text-sm font-medium">
67
+ {parameterKey}
68
+ </span>
69
+ <Badge className="shrink-0" variant="outline">
70
+ {VALUE_TYPE_LABELS[parameter.valueType]}
71
+ </Badge>
72
+ </div>
73
+ {parameter.description === undefined ? null : (
74
+ <p className="mt-1 text-xs text-muted-foreground">
75
+ {parameter.description}
76
+ </p>
77
+ )}
78
+ </div>
79
+ <dl className="grid min-w-0 grid-cols-[minmax(0,9rem)_minmax(0,1fr)] gap-x-3 gap-y-1.5 text-xs">
80
+ {conditional.map(({ name }) => (
81
+ <div className="contents" key={name}>
82
+ <dt
83
+ className="line-clamp-2 break-words text-muted-foreground"
84
+ title={name}
85
+ >
86
+ {name}
87
+ </dt>
88
+ <dd className="min-w-0">
89
+ <ValueText
90
+ text={describeValue(
91
+ conditionalValueFor(parameter.conditionalValues, name)!,
92
+ )}
93
+ />
94
+ </dd>
95
+ </div>
96
+ ))}
97
+ <dt className="text-muted-foreground">Default</dt>
98
+ <dd className="min-w-0">
99
+ {"value" in parameter.defaultValue ? (
100
+ <ValueText text={describeValue(parameter.defaultValue)} />
101
+ ) : (
102
+ <span className="text-muted-foreground">In-app default</span>
103
+ )}
104
+ </dd>
105
+ </dl>
106
+ <div className="flex gap-1 md:justify-end">
107
+ <Button
108
+ aria-label={`Edit ${parameterKey}`}
109
+ className="min-h-11 md:min-h-7"
110
+ onClick={onEdit}
111
+ size="sm"
112
+ variant="outline"
113
+ >
114
+ <Pencil data-icon="inline-start" />
115
+ Edit
116
+ </Button>
117
+ <Button
118
+ aria-label={`Delete ${parameterKey}`}
119
+ className="size-11 md:size-7"
120
+ onClick={onRemove}
121
+ size="icon"
122
+ variant="ghost"
123
+ >
124
+ <Trash2 />
125
+ </Button>
126
+ </div>
127
+ </li>
128
+ );
129
+ }
130
+
131
+ /** The draft's parameters, with what each device gets for them. */
132
+ export function ParametersCard({
133
+ template,
134
+ onSaveParameter,
135
+ onRemoveParameter,
136
+ onAddCondition,
137
+ }: {
138
+ readonly template: RemoteConfigTemplate;
139
+ readonly onSaveParameter: (
140
+ previousKey: string | null,
141
+ key: string,
142
+ parameter: RemoteConfigParameter,
143
+ ) => void;
144
+ readonly onRemoveParameter: (key: string) => void;
145
+ readonly onAddCondition: (condition: RemoteConfigCondition) => void;
146
+ }) {
147
+ // Taken when the dialog opens, so it holds still while it animates closed.
148
+ const [editing, setEditing] = useState<{
149
+ readonly key: string | null;
150
+ readonly parameter: RemoteConfigParameter | null;
151
+ } | null>(null);
152
+ const shownEditing = useDialogTarget(editing);
153
+ const [filter, setFilter] = useState("");
154
+ const keys = Object.keys(template.parameters);
155
+ const shown = keys.filter((key) =>
156
+ key.toLowerCase().includes(filter.trim().toLowerCase()),
157
+ );
158
+ const editingKey = shownEditing?.key ?? null;
159
+
160
+ return (
161
+ <Card className="overflow-hidden shadow-sm">
162
+ <CardHeader className="flex-row flex-wrap items-center justify-between gap-3 space-y-0 border-b px-4 py-3 sm:px-6">
163
+ <CardTitle className="text-sm">
164
+ <h2>Parameters</h2>
165
+ </CardTitle>
166
+ <div className="flex w-full flex-wrap gap-2 sm:w-auto">
167
+ {keys.length > 5 ? (
168
+ <InputGroup className="min-h-11 w-full sm:min-h-8 sm:w-56">
169
+ <InputGroupAddon>
170
+ <Search aria-hidden="true" />
171
+ </InputGroupAddon>
172
+ <InputGroupInput
173
+ aria-label="Filter parameters by key"
174
+ className="text-base sm:text-xs"
175
+ onChange={(event) => setFilter(event.target.value)}
176
+ placeholder="Filter by key"
177
+ value={filter}
178
+ />
179
+ </InputGroup>
180
+ ) : null}
181
+ <Button
182
+ className="min-h-11 sm:min-h-7"
183
+ onClick={() => setEditing({ key: null, parameter: null })}
184
+ >
185
+ <Plus data-icon="inline-start" />
186
+ Add parameter
187
+ </Button>
188
+ </div>
189
+ </CardHeader>
190
+ <CardContent className="p-0">
191
+ {keys.length === 0 ? (
192
+ <Empty className="py-10">
193
+ <EmptyHeader>
194
+ <EmptyMedia variant="icon">
195
+ <SlidersHorizontal />
196
+ </EmptyMedia>
197
+ <EmptyTitle>No parameters</EmptyTitle>
198
+ <EmptyDescription>
199
+ Add a parameter, give it a default, then publish to change the
200
+ app without a new build.
201
+ </EmptyDescription>
202
+ </EmptyHeader>
203
+ <EmptyContent>
204
+ <Button
205
+ className="min-h-11 sm:min-h-7"
206
+ onClick={() => setEditing({ key: null, parameter: null })}
207
+ >
208
+ <Plus data-icon="inline-start" />
209
+ Add parameter
210
+ </Button>
211
+ </EmptyContent>
212
+ </Empty>
213
+ ) : shown.length === 0 ? (
214
+ <div className="flex flex-col items-center gap-2 px-4 py-10 text-center text-xs text-muted-foreground">
215
+ <p className="font-medium text-foreground">No matching keys</p>
216
+ <Button onClick={() => setFilter("")} size="sm" variant="outline">
217
+ Clear filter
218
+ </Button>
219
+ </div>
220
+ ) : (
221
+ <ul aria-label="Parameters" className="divide-y">
222
+ {shown.map((key) => (
223
+ <ParameterRow
224
+ conditions={template.conditions}
225
+ key={key}
226
+ onEdit={() =>
227
+ setEditing({
228
+ key,
229
+ parameter: template.parameters[key] ?? null,
230
+ })
231
+ }
232
+ onRemove={() => onRemoveParameter(key)}
233
+ parameter={template.parameters[key]!}
234
+ parameterKey={key}
235
+ />
236
+ ))}
237
+ </ul>
238
+ )}
239
+ </CardContent>
240
+ <ParameterDialog
241
+ conditions={template.conditions}
242
+ onAddCondition={onAddCondition}
243
+ onOpenChange={(open) => {
244
+ if (!open) setEditing(null);
245
+ }}
246
+ onSave={(key, parameter) => onSaveParameter(editingKey, key, parameter)}
247
+ open={editing !== null}
248
+ parameter={shownEditing?.parameter ?? null}
249
+ parameterKey={editingKey}
250
+ takenKeys={keys.filter((key) => key !== editingKey)}
251
+ />
252
+ </Card>
253
+ );
254
+ }
@@ -0,0 +1,284 @@
1
+ import { AlertTriangle, Smartphone } from "lucide-react";
2
+ import { useEffect, useId, useState } from "react";
3
+
4
+ import { PlatformIcon } from "@/components/PlatformIcon";
5
+ import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
6
+ import { Badge } from "@/components/ui/badge";
7
+ import {
8
+ Card,
9
+ CardContent,
10
+ CardDescription,
11
+ CardHeader,
12
+ CardTitle,
13
+ } from "@/components/ui/card";
14
+ import {
15
+ Empty,
16
+ EmptyDescription,
17
+ EmptyHeader,
18
+ EmptyMedia,
19
+ EmptyTitle,
20
+ } from "@/components/ui/empty";
21
+ import { Field, FieldLabel } from "@/components/ui/field";
22
+ import { Input } from "@/components/ui/input";
23
+ import {
24
+ InputGroup,
25
+ InputGroupAddon,
26
+ InputGroupButton,
27
+ InputGroupInput,
28
+ } from "@/components/ui/input-group";
29
+ import {
30
+ Select,
31
+ SelectContent,
32
+ SelectGroup,
33
+ SelectItem,
34
+ SelectTrigger,
35
+ SelectValue,
36
+ } from "@/components/ui/select";
37
+ import { Skeleton } from "@/components/ui/skeleton";
38
+ import { useRemoteConfigPreviewQuery } from "@/lib/remote-config-api";
39
+ import {
40
+ fromLocalDateTimeInput,
41
+ type RemoteConfigTemplate,
42
+ } from "@/lib/remote-config-draft";
43
+
44
+ interface PreviewDevice {
45
+ readonly platform: "ios" | "android";
46
+ readonly channel: string;
47
+ readonly appVersion: string;
48
+ readonly cohort: string;
49
+ readonly fingerprintHash: string;
50
+ /** A `datetime-local` value in the viewer's time zone; empty for now. */
51
+ readonly at: string;
52
+ }
53
+
54
+ const INITIAL_DEVICE: PreviewDevice = {
55
+ platform: "ios",
56
+ channel: "production",
57
+ appVersion: "1.0.0",
58
+ cohort: "1",
59
+ fingerprintHash: "",
60
+ at: "",
61
+ };
62
+
63
+ /** The device after typing pauses, so each keystroke does not ask the server. */
64
+ const useSettled = <T,>(value: T, delayMs = 300): T => {
65
+ const [settled, setSettled] = useState(value);
66
+ useEffect(() => {
67
+ const timer = setTimeout(() => setSettled(value), delayMs);
68
+ return () => clearTimeout(timer);
69
+ }, [value, delayMs]);
70
+ return settled;
71
+ };
72
+
73
+ /** What a device with the context entered gets from the draft. */
74
+ export function PreviewCard({
75
+ template,
76
+ isDraft,
77
+ }: {
78
+ readonly template: RemoteConfigTemplate;
79
+ /** The template has unpublished edits. */
80
+ readonly isDraft: boolean;
81
+ }) {
82
+ const id = useId();
83
+ const [device, setDevice] = useState(INITIAL_DEVICE);
84
+ const settled = useSettled(device);
85
+ const { at, ...deviceContext } = settled;
86
+ const atInstant = fromLocalDateTimeInput(at);
87
+ const preview = useRemoteConfigPreviewQuery({
88
+ template,
89
+ context: {
90
+ ...deviceContext,
91
+ // Without a time, the server evaluates at its own clock.
92
+ ...(atInstant === undefined ? {} : { now: Date.parse(atInstant) }),
93
+ },
94
+ });
95
+ const keys = Object.keys(template.parameters);
96
+ const set = (field: keyof PreviewDevice, value: string) =>
97
+ setDevice({ ...device, [field]: value });
98
+
99
+ return (
100
+ <Card className="overflow-hidden shadow-sm">
101
+ <CardHeader className="border-b px-4 py-3 sm:px-6">
102
+ <CardTitle className="text-sm">
103
+ <h2>Preview a device</h2>
104
+ </CardTitle>
105
+ <CardDescription className="text-xs">
106
+ {isDraft
107
+ ? "The values this device would get once your changes are published, now or at the time you pick."
108
+ : "The values this device gets from the active version, now or at the time you pick."}
109
+ </CardDescription>
110
+ </CardHeader>
111
+ <CardContent className="flex flex-col gap-4 p-4 sm:p-6">
112
+ <div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
113
+ <Field>
114
+ <FieldLabel htmlFor={`${id}-platform`}>Platform</FieldLabel>
115
+ <Select
116
+ items={{ ios: "iOS", android: "Android" }}
117
+ onValueChange={(value) => {
118
+ if (value === "ios" || value === "android") {
119
+ set("platform", value);
120
+ }
121
+ }}
122
+ value={device.platform}
123
+ >
124
+ <SelectTrigger
125
+ className="min-h-11 w-full sm:min-h-9"
126
+ id={`${id}-platform`}
127
+ >
128
+ <SelectValue>
129
+ <PlatformIcon
130
+ className="size-3.5"
131
+ platform={device.platform}
132
+ />
133
+ {device.platform === "ios" ? "iOS" : "Android"}
134
+ </SelectValue>
135
+ </SelectTrigger>
136
+ <SelectContent>
137
+ <SelectGroup>
138
+ <SelectItem value="ios">
139
+ <PlatformIcon className="size-3.5" platform="ios" />
140
+ iOS
141
+ </SelectItem>
142
+ <SelectItem value="android">
143
+ <PlatformIcon className="size-3.5" platform="android" />
144
+ Android
145
+ </SelectItem>
146
+ </SelectGroup>
147
+ </SelectContent>
148
+ </Select>
149
+ </Field>
150
+ {(
151
+ [
152
+ ["channel", "Channel", "production"],
153
+ ["appVersion", "App version", "1.0.0"],
154
+ ["cohort", "Cohort", "1-1000 or a name"],
155
+ ["fingerprintHash", "Fingerprint", "Optional"],
156
+ ] as const
157
+ ).map(([field, label, placeholder]) => (
158
+ <Field key={field}>
159
+ <FieldLabel htmlFor={`${id}-${field}`}>{label}</FieldLabel>
160
+ <Input
161
+ autoComplete="off"
162
+ className="min-h-11 text-base sm:min-h-9 sm:text-xs"
163
+ id={`${id}-${field}`}
164
+ onChange={(event) => set(field, event.target.value)}
165
+ placeholder={placeholder}
166
+ spellCheck={false}
167
+ value={device[field]}
168
+ />
169
+ </Field>
170
+ ))}
171
+ <Field>
172
+ <FieldLabel htmlFor={`${id}-at`}>Time</FieldLabel>
173
+ <InputGroup className="h-11 sm:h-9">
174
+ <InputGroupInput
175
+ className="h-11 text-base tabular-nums sm:h-9 sm:text-xs"
176
+ id={`${id}-at`}
177
+ onChange={(event) => set("at", event.target.value)}
178
+ type="datetime-local"
179
+ value={device.at}
180
+ />
181
+ {device.at.length === 0 ? null : (
182
+ <InputGroupAddon align="inline-end">
183
+ <InputGroupButton
184
+ className="min-h-11 sm:min-h-6"
185
+ onClick={() => set("at", "")}
186
+ size="xs"
187
+ >
188
+ Now
189
+ </InputGroupButton>
190
+ </InputGroupAddon>
191
+ )}
192
+ </InputGroup>
193
+ </Field>
194
+ </div>
195
+ {keys.length === 0 ? (
196
+ <Empty className="border py-8">
197
+ <EmptyHeader>
198
+ <EmptyMedia variant="icon">
199
+ <Smartphone />
200
+ </EmptyMedia>
201
+ <EmptyTitle>Nothing to preview</EmptyTitle>
202
+ <EmptyDescription>
203
+ Add a parameter, and its value for this device shows here.
204
+ </EmptyDescription>
205
+ </EmptyHeader>
206
+ </Empty>
207
+ ) : preview.data?.status === "invalid" ? (
208
+ <Alert variant="destructive">
209
+ <AlertTriangle />
210
+ <AlertTitle>The draft has problems to fix first</AlertTitle>
211
+ <AlertDescription>
212
+ <ul className="list-disc pl-4">
213
+ {preview.data.issues.slice(0, 5).map((issue) => (
214
+ <li key={`${issue.path}:${issue.message}`}>
215
+ {issue.path === "" ? "" : `${issue.path}: `}
216
+ {issue.message}
217
+ </li>
218
+ ))}
219
+ </ul>
220
+ </AlertDescription>
221
+ </Alert>
222
+ ) : preview.isError ? (
223
+ <Alert variant="destructive">
224
+ <AlertTriangle />
225
+ <AlertTitle>The preview couldn't be loaded</AlertTitle>
226
+ <AlertDescription>
227
+ Check the connection, then change a field to try again.
228
+ </AlertDescription>
229
+ </Alert>
230
+ ) : preview.data === undefined ? (
231
+ <div className="flex flex-col gap-2">
232
+ <span className="sr-only">Loading the preview</span>
233
+ {keys.slice(0, 4).map((key) => (
234
+ <Skeleton className="h-8 w-full" key={key} />
235
+ ))}
236
+ </div>
237
+ ) : (
238
+ <dl
239
+ aria-busy={preview.isFetching || undefined}
240
+ className="divide-y rounded-lg border"
241
+ >
242
+ {keys.map((key) => {
243
+ const result =
244
+ preview.data.status === "ok"
245
+ ? preview.data.parameters[key]
246
+ : undefined;
247
+ return (
248
+ <div
249
+ className="grid gap-1 px-3 py-2.5 sm:grid-cols-[minmax(0,14rem)_minmax(0,1fr)_auto] sm:items-center sm:gap-3"
250
+ key={key}
251
+ >
252
+ <dt className="truncate font-mono text-xs font-medium">
253
+ {key}
254
+ </dt>
255
+ <dd className="min-w-0 truncate font-mono text-xs">
256
+ {result === undefined ? (
257
+ "…"
258
+ ) : result.value === null ? (
259
+ <span className="font-sans text-muted-foreground">
260
+ In-app default
261
+ </span>
262
+ ) : (
263
+ <span title={result.value}>
264
+ {result.value.length === 0 ? '""' : result.value}
265
+ </span>
266
+ )}
267
+ </dd>
268
+ <dd>
269
+ {result?.condition ===
270
+ undefined ? null : result.condition === null ? (
271
+ <Badge variant="outline">Default value</Badge>
272
+ ) : (
273
+ <Badge variant="secondary">{result.condition}</Badge>
274
+ )}
275
+ </dd>
276
+ </div>
277
+ );
278
+ })}
279
+ </dl>
280
+ )}
281
+ </CardContent>
282
+ </Card>
283
+ );
284
+ }