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

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 (330) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/ConsoleFeatureUnavailable-DRzeMGRM.js +1 -0
  3. package/.output/public/assets/EventDetails-SB5ygJzS.js +1 -0
  4. package/.output/public/assets/HashValueDisplay-BFX_kY3-.js +1 -0
  5. package/.output/public/assets/InsightsInfo-btYppp0B.js +1 -0
  6. package/.output/public/assets/InsightsPageHeader-Ba8psD8t.js +1 -0
  7. package/.output/public/assets/NotFoundPage-CyRG2eca.js +1 -0
  8. package/.output/public/assets/alert-dialog-Bbk_4-WJ.js +1 -0
  9. package/.output/public/assets/api-DUgI6yOI.js +1 -0
  10. package/.output/public/assets/api-keys-CIO9L_wu.js +1 -0
  11. package/.output/public/assets/api-keys-CmkNKOhS.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-BMsI3Bj8.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-BEfQ2_7f.js +11 -0
  22. package/.output/public/assets/input-group-ja_30qaF.js +1 -0
  23. package/.output/public/assets/insights-B0ib9qOE.js +2 -0
  24. package/.output/public/assets/insights-BIMJx-0p.js +1 -0
  25. package/.output/public/assets/insights-CndqcWEj.js +42 -0
  26. package/.output/public/assets/insights-api-B6Ewc-OG.js +1 -0
  27. package/.output/public/assets/insights-usage-rpc-DYEhsCKT.js +1 -0
  28. package/.output/public/assets/insights_.distribution-B26PMy4k.js +2 -0
  29. package/.output/public/assets/insights_.distribution-BBDtqqYS.js +1 -0
  30. package/.output/public/assets/insights_.distribution-DhHmYS8k.js +1 -0
  31. package/.output/public/assets/installations-C3cMuwRx.js +1 -0
  32. package/.output/public/assets/installations-C3yrjwDh.js +2 -0
  33. package/.output/public/assets/installations-D3edlN75.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-0i-gDkeU.js +1 -0
  38. package/.output/public/assets/remote-config-An1ROIOQ.js +6 -0
  39. package/.output/public/assets/remote-config-CoeWgA9i.js +1 -0
  40. package/.output/public/assets/routes-DNoaJIQV.js +2 -0
  41. package/.output/public/assets/routes-cWBDtghZ.js +1 -0
  42. package/.output/public/assets/search-DaTDPW25.js +1 -0
  43. package/.output/public/assets/select-CZMQKT7F.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-D8mxMvCB.css +2 -0
  47. package/.output/public/assets/switch-CU4-fupc.js +1 -0
  48. package/.output/public/assets/table-Gm4qRWwE.js +1 -0
  49. package/.output/public/assets/tabs-R1I8CRjR.js +1 -0
  50. package/.output/public/assets/undo-2-CmrHjwFc.js +1 -0
  51. package/.output/public/assets/useCompositeListItem-BaPeC9ZO.js +1 -0
  52. package/.output/public/assets/valueToPercent-CH8GCHaL.js +1 -0
  53. package/.output/server/__23tanstack-start-server-fn-resolver-DTAqlLRd.mjs +178 -0
  54. package/.output/server/_libs/@base-ui/react+[...].mjs +6450 -2741
  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 +235 -31
  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-BNoVW3Dv.mjs +13 -0
  67. package/.output/server/_ssr/ConsoleFeatureUnavailable-BPFa-cmJ.mjs +58 -0
  68. package/.output/server/_ssr/EventDetails-9CeshfdR.mjs +344 -0
  69. package/.output/server/_ssr/HashValueDisplay-DXZlkcps.mjs +55 -0
  70. package/.output/server/_ssr/InsightsInfo-DLNdJQ0m.mjs +75 -0
  71. package/.output/server/_ssr/InsightsPageHeader-DZGVDgvv.mjs +145 -0
  72. package/.output/server/_ssr/NotFoundPage-mYHHg-2s.mjs +37 -0
  73. package/.output/server/_ssr/{dialog-DUaIgpgd.mjs → alert-dialog-Chkim7vZ.mjs} +6 -83
  74. package/.output/server/_ssr/api-C-Il5-sa.mjs +203 -0
  75. package/.output/server/_ssr/api-keys-01FGqj4d.mjs +5 -0
  76. package/.output/server/_ssr/{api-keys-DJml_XoK.mjs → api-keys-B_f9h7ln.mjs} +48 -10
  77. package/.output/server/_ssr/api-keys-rpc-Cf4YCyFc.mjs +52 -0
  78. package/.output/server/_ssr/api-rpc-DRqwxxT_.mjs +296 -0
  79. package/.output/server/_ssr/{auth-BF8mbAgF.mjs → auth-UP0wXs4i.mjs} +1 -1
  80. package/.output/server/_ssr/{auth-rpc-D_hv52-J.mjs → auth-rpc-D8nFpU9C.mjs} +6 -6
  81. package/.output/server/_ssr/auth.server-COZoXu4i.mjs +5425 -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-Dm2l7w0O.mjs +36 -0
  85. package/.output/server/_ssr/console-access--o9FXikU.mjs +17 -0
  86. package/.output/server/_ssr/console-features-BftSkf3f.mjs +60 -0
  87. package/.output/server/_ssr/console-features-api-CYclUQ4h.mjs +43 -0
  88. package/.output/server/_ssr/console-features-rpc-1WaAkPM_.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-BUuNU-qt.mjs +74 -0
  94. package/.output/server/_ssr/dialog-mfSANqjC.mjs +84 -0
  95. package/.output/server/_ssr/{dist-CyzPaI5v.mjs → dist-wmnTk7w6.mjs} +140 -6
  96. package/.output/server/_ssr/{downloadBundle-B3ert-pY.mjs → downloadBundle-DViuIa9U.mjs} +10 -10
  97. package/.output/server/_ssr/empty-BPayFad3.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-DjZ5t7rH.mjs +189 -0
  101. package/.output/server/_ssr/getBundleChildren-CmjDg6Re.mjs +22 -0
  102. package/.output/server/_ssr/{input-group-Bb8ueylQ.mjs → input-group-Dx-MEkNM.mjs} +3 -52
  103. package/.output/server/_ssr/insights-BopxyJjk.mjs +14 -0
  104. package/.output/server/_ssr/insights-Bvm03d61.mjs +5 -0
  105. package/.output/server/_ssr/insights-CrLAHSDy.mjs +2315 -0
  106. package/.output/server/_ssr/insights-api-Bg8ZV_h_.mjs +122 -0
  107. package/.output/server/_ssr/insights-errors-BjnFUyZj.mjs +34 -0
  108. package/.output/server/_ssr/insights-failures-rpc-tyy5m9Cc.mjs +36 -0
  109. package/.output/server/_ssr/insights-failures-xaa41Buf.mjs +46 -0
  110. package/.output/server/_ssr/{insights-recovery-DSFM-YTL.mjs → insights-recovery-BWQhiZaF.mjs} +9 -2
  111. package/.output/server/_ssr/insights-recovery-rpc-CPJOiJAV.mjs +32 -0
  112. package/.output/server/_ssr/{insights-rpc-DrIQCjpD.mjs → insights-rpc-DoC3hla9.mjs} +22 -14
  113. package/.output/server/_ssr/insights-usage-BpBM0U0c.mjs +29 -0
  114. package/.output/server/_ssr/insights-usage-rpc-CFuTYp3T.mjs +29 -0
  115. package/.output/server/_ssr/insights-usage-rpc-O2ruP4iE.mjs +41 -0
  116. package/.output/server/_ssr/insightsUsage-CzhVjsc8.mjs +56 -0
  117. package/.output/server/_ssr/insights_.distribution-B3BVPD00.mjs +16 -0
  118. package/.output/server/_ssr/insights_.distribution-BMoisxRG.mjs +347 -0
  119. package/.output/server/_ssr/insights_.distribution-BiCcFyrG.mjs +7 -0
  120. package/.output/server/_ssr/{installations-YumqpNpa.mjs → installations-Cx3jIrwl.mjs} +280 -364
  121. package/.output/server/_ssr/installations-DTGPaKXx.mjs +69 -0
  122. package/.output/server/_ssr/installations-osiAuNKr.mjs +5 -0
  123. package/.output/server/_ssr/listReleases-BfUBlCHo.mjs +79 -0
  124. package/.output/server/_ssr/release-adoption-005tQRpo.mjs +55 -0
  125. package/.output/server/_ssr/release-adoption-rpc-BVySDR0L.mjs +41 -0
  126. package/.output/server/_ssr/releaseAdoption-2PJPA09N.mjs +114 -0
  127. package/.output/server/_ssr/releaseManagement-BTCWEY8-.mjs +11 -0
  128. package/.output/server/_ssr/remote-config-CUoAxUMy.mjs +430 -0
  129. package/.output/server/_ssr/remote-config-Cc5P4J-r.mjs +17 -0
  130. package/.output/server/_ssr/remote-config-CjdxcZ9B.mjs +5 -0
  131. package/.output/server/_ssr/remote-config-D2GmbGwI.mjs +2594 -0
  132. package/.output/server/_ssr/remote-config-rpc-kjoZ9PRS.mjs +115 -0
  133. package/.output/server/_ssr/rolldown-runtime-rSIU-vHC.mjs +13 -0
  134. package/.output/server/_ssr/{router-iP95Vqi2.mjs → router-DwGVewL-.mjs} +141 -139
  135. package/.output/server/_ssr/{routes-ivsV2TDu.mjs → routes-C4yxv3JU.mjs} +192 -685
  136. package/.output/server/_ssr/routes-D3_aegLY.mjs +409 -0
  137. package/.output/server/_ssr/runtime.server-BoWf4QhU.mjs +1716 -0
  138. package/.output/server/_ssr/schema-DrOtkRVD.mjs +361 -0
  139. package/.output/server/_ssr/select-DkzM2miy.mjs +107 -0
  140. package/.output/server/_ssr/server-BW0gzB0p.mjs +8325 -0
  141. package/.output/server/_ssr/{createSsrRpc-NHF2PxuK.mjs → sidebar-DPcOijvL.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-BqJ2mAwC.mjs +17 -0
  145. package/.output/server/_ssr/{table-D1mL8fJu.mjs → table-R7RY92q9.mjs} +2 -2
  146. package/.output/server/_ssr/tabs-trDcbRkT.mjs +45 -0
  147. package/.output/server/_ssr/updateFailures-H6pnnYK4.mjs +40 -0
  148. package/.output/server/_ssr/{uuidv7-D0QFkPL_.mjs → uuidv7-ctA_XVZA.mjs} +2 -2
  149. package/.output/server/_tanstack-start-manifest_v-BwInaUTw.mjs +139 -0
  150. package/.output/server/index.mjs +315 -154
  151. package/LICENSE +13 -14
  152. package/README.md +82 -72
  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 +100 -71
  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 +2 -5
  166. package/src/components/features/insights/AppUsage.tsx +366 -0
  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 +400 -39
  171. package/src/components/features/insights/EventHistoryCard.tsx +112 -26
  172. package/src/components/features/insights/EventHistoryList.tsx +2 -2
  173. package/src/components/features/insights/FailureReports.tsx +407 -0
  174. package/src/components/features/insights/InsightsControls.tsx +265 -88
  175. package/src/components/features/insights/InsightsErrorAlert.tsx +14 -1
  176. package/src/components/features/insights/InsightsInfo.tsx +48 -0
  177. package/src/components/features/insights/InsightsOverview.tsx +604 -355
  178. package/src/components/features/insights/InsightsPageHeader.tsx +35 -20
  179. package/src/components/features/insights/InsightsPeriodSelector.tsx +89 -0
  180. package/src/components/features/insights/InstallationHistoryCard.tsx +66 -11
  181. package/src/components/features/insights/InstallationMatchesCard.tsx +1 -1
  182. package/src/components/features/insights/ReleaseActivity.tsx +308 -0
  183. package/src/components/features/insights/ReportingDevicesSummary.tsx +48 -0
  184. package/src/components/features/insights/RollbackButton.tsx +118 -0
  185. package/src/components/features/insights/UpdateFailures.tsx +382 -0
  186. package/src/components/features/insights/insightsFeatureUi.tsx +35 -0
  187. package/src/components/features/releases/ReleaseEditorSheet.tsx +26 -12
  188. package/src/components/features/remote-config/ConditionDialog.tsx +581 -0
  189. package/src/components/features/remote-config/ConditionsCard.tsx +244 -0
  190. package/src/components/features/remote-config/ParameterDialog.tsx +407 -0
  191. package/src/components/features/remote-config/ParametersCard.tsx +244 -0
  192. package/src/components/features/remote-config/PreviewCard.tsx +284 -0
  193. package/src/components/features/remote-config/PublishDialog.tsx +319 -0
  194. package/src/components/features/remote-config/RemoteConfigPage.tsx +353 -0
  195. package/src/components/features/remote-config/RuleSummary.tsx +21 -0
  196. package/src/components/features/remote-config/ValueInput.tsx +148 -0
  197. package/src/components/features/remote-config/VersionsCard.tsx +361 -0
  198. package/src/components/features/remote-config/remoteConfigFeatureUi.tsx +15 -0
  199. package/src/components/features/remote-config/useDateTimeText.ts +16 -0
  200. package/src/components/ui/card.tsx +1 -1
  201. package/src/components/ui/scroll-area.tsx +52 -0
  202. package/src/components/ui/sidebar.tsx +22 -29
  203. package/src/components/ui/tabs.tsx +81 -0
  204. package/src/index.ts +26 -19
  205. package/src/lib/api-keys-api.ts +0 -28
  206. package/src/lib/api-keys-rpc.ts +27 -38
  207. package/src/lib/api-rpc.ts +189 -266
  208. package/src/lib/api.ts +19 -102
  209. package/src/lib/bundle-activity.ts +24 -4
  210. package/src/lib/console-access.ts +20 -0
  211. package/src/lib/console-features-api.ts +68 -0
  212. package/src/lib/console-features-rpc.ts +13 -0
  213. package/src/lib/console-features.ts +97 -0
  214. package/src/lib/insights-api.ts +56 -2
  215. package/src/lib/insights-errors.ts +64 -0
  216. package/src/lib/insights-failures-rpc.ts +36 -0
  217. package/src/lib/insights-failures.ts +130 -0
  218. package/src/lib/insights-recovery-rpc.ts +13 -17
  219. package/src/lib/insights-recovery.ts +10 -27
  220. package/src/lib/insights-retention.ts +21 -0
  221. package/src/lib/insights-rpc.ts +30 -12
  222. package/src/lib/insights-search.ts +93 -0
  223. package/src/lib/insights-usage-rpc.ts +29 -0
  224. package/src/lib/insights-usage.ts +76 -0
  225. package/src/lib/insights-view.ts +34 -5
  226. package/src/lib/release-adoption-api.ts +214 -0
  227. package/src/lib/release-adoption-rpc.ts +49 -0
  228. package/src/lib/release-adoption.ts +164 -0
  229. package/src/lib/remote-config-api.ts +119 -0
  230. package/src/lib/remote-config-draft.ts +652 -0
  231. package/src/lib/remote-config-rpc.ts +196 -0
  232. package/src/lib/scroll-restoration.ts +21 -0
  233. package/src/lib/server/adminInsights.ts +124 -0
  234. package/src/lib/server/auth.server.ts +13 -5
  235. package/src/lib/server/bundleActivity.ts +27 -28
  236. package/src/lib/server/config.server.ts +21 -74
  237. package/src/lib/server/console-feature-apis.ts +70 -0
  238. package/src/lib/server/console-runtime.server.ts +82 -38
  239. package/src/lib/server/downloadBundle.ts +16 -15
  240. package/src/lib/server/failureReports.ts +49 -0
  241. package/src/lib/server/getBundleChildren.ts +31 -122
  242. package/src/lib/server/insightsUsage.ts +63 -0
  243. package/src/lib/server/listReleases.ts +109 -44
  244. package/src/lib/server/releaseAdoption.ts +154 -0
  245. package/src/lib/server/releaseReachability.ts +8 -7
  246. package/src/lib/server/remoteConfig.ts +191 -0
  247. package/src/lib/server/runtime.server.ts +120 -31
  248. package/src/lib/server/updateFailures.ts +65 -0
  249. package/src/routeTree.gen.ts +65 -44
  250. package/src/router.tsx +3 -2
  251. package/src/routes/-installations-search.ts +32 -8
  252. package/src/routes/-releases-search.ts +76 -29
  253. package/src/routes/__root.tsx +10 -4
  254. package/src/routes/api/bundles/$bundleId/download.ts +2 -5
  255. package/src/routes/api-keys.tsx +5 -2
  256. package/src/routes/index.tsx +210 -152
  257. package/src/routes/insights.tsx +133 -18
  258. package/src/routes/insights_.distribution.tsx +422 -0
  259. package/src/routes/installations.tsx +98 -41
  260. package/src/routes/remote-config.tsx +42 -0
  261. package/src/styles.css +9 -0
  262. package/src/vite-internal.ts +15 -3
  263. package/src/vite.ts +2 -0
  264. package/.output/public/assets/InsightsPageHeader-C-Xc2MB9.js +0 -1
  265. package/.output/public/assets/api-keys-C1sgC6ko.js +0 -1
  266. package/.output/public/assets/api-keys-api-LchP65vQ.js +0 -1
  267. package/.output/public/assets/badge-BuMDU0Rf.js +0 -1
  268. package/.output/public/assets/card-BEvx_QKh.js +0 -1
  269. package/.output/public/assets/chart-no-axes-combined-C0G0fQ3J.js +0 -1
  270. package/.output/public/assets/composite-CHTH1Xhh.js +0 -1
  271. package/.output/public/assets/createServerFn-DHc2erub.js +0 -3
  272. package/.output/public/assets/dialog-dyZ1SphZ.js +0 -1
  273. package/.output/public/assets/dist-Bh1gaDfB.js +0 -1
  274. package/.output/public/assets/field-79SVH26s.js +0 -1
  275. package/.output/public/assets/index-BNkxg4jz.js +0 -10
  276. package/.output/public/assets/input-group-BbHfaBzQ.js +0 -1
  277. package/.output/public/assets/insights-D_7uSKfc.js +0 -1
  278. package/.output/public/assets/installations-BzoHWuXw.js +0 -1
  279. package/.output/public/assets/installations-DvjbUqd1.js +0 -2
  280. package/.output/public/assets/lazyRouteComponent-BN0MS05o.js +0 -1
  281. package/.output/public/assets/link-BG06whwB.js +0 -1
  282. package/.output/public/assets/loader-circle-Bbp8LGVC.js +0 -1
  283. package/.output/public/assets/preload-helper-uTix4PVD.js +0 -1
  284. package/.output/public/assets/refresh-cw-DZgiAOMk.js +0 -1
  285. package/.output/public/assets/routes-BFE-oRIT.js +0 -1
  286. package/.output/public/assets/routes-DaPMY31P.js +0 -2
  287. package/.output/public/assets/shield-check-DoIiaaXU.js +0 -1
  288. package/.output/public/assets/signing-BTRhaF5D.js +0 -1
  289. package/.output/public/assets/styles-C7U0oVke.css +0 -2
  290. package/.output/public/assets/table-BBEzJ7Xl.js +0 -1
  291. package/.output/public/assets/useCompositeListItem-BkPDaqyj.js +0 -42
  292. package/.output/server/__23tanstack-start-server-fn-resolver-Dr2ixDgQ.mjs +0 -146
  293. package/.output/server/_ssr/InsightsPageHeader-C5Has8Ry.mjs +0 -60
  294. package/.output/server/_ssr/api-keys-api-CrCZyvnl.mjs +0 -60
  295. package/.output/server/_ssr/api-keys-rpc-CFaNf-q0.mjs +0 -136
  296. package/.output/server/_ssr/api-rpc-B61KL3Eo.mjs +0 -1399
  297. package/.output/server/_ssr/auth.server-DF_shCeq.mjs +0 -47
  298. package/.output/server/_ssr/badge-BgsCP9Dp.mjs +0 -28
  299. package/.output/server/_ssr/bundle-signing-rpc-BBipZnFs.mjs +0 -16
  300. package/.output/server/_ssr/bundle-signing.server-Co_zHdJx.mjs +0 -12
  301. package/.output/server/_ssr/bundleActivity-D3_fIda2.mjs +0 -27
  302. package/.output/server/_ssr/card-DrbxCPtG.mjs +0 -86
  303. package/.output/server/_ssr/chart-qxa-_30a.mjs +0 -162
  304. package/.output/server/_ssr/config-Dv8qLDZ0.mjs +0 -13
  305. package/.output/server/_ssr/config.server-CBr6PDj5.mjs +0 -368
  306. package/.output/server/_ssr/databaseRows-5bCRTxm-.mjs +0 -126
  307. package/.output/server/_ssr/deleteBundle-BAq3JuGr.mjs +0 -66
  308. package/.output/server/_ssr/field-CqNUlqUq.mjs +0 -74
  309. package/.output/server/_ssr/getBundleChildren-COMt16m_.mjs +0 -50
  310. package/.output/server/_ssr/insights-B-DUbksX.mjs +0 -502
  311. package/.output/server/_ssr/insights-recovery-rpc-P71FH66n.mjs +0 -37
  312. package/.output/server/_ssr/insightsContract-fjJDBeEE.mjs +0 -303
  313. package/.output/server/_ssr/insightsRecovery-CqcosG7B.mjs +0 -149
  314. package/.output/server/_ssr/installations-BQrppti7.mjs +0 -29
  315. package/.output/server/_ssr/routes-BDabsmc7.mjs +0 -37
  316. package/.output/server/_ssr/runtime.server-jmZOKIQM.mjs +0 -438
  317. package/.output/server/_ssr/server-p7yrVBfD.mjs +0 -7468
  318. package/.output/server/_ssr/signing-CxCbnFCt.mjs +0 -134
  319. package/.output/server/_ssr/start-DpViQGnt.mjs +0 -4
  320. package/.output/server/_tanstack-start-manifest_v-Cwpu0C9Q.mjs +0 -100
  321. package/src/components/features/bundles/BundleActivityChart.tsx +0 -95
  322. package/src/components/features/bundles/BundleInsightsSummary.tsx +0 -121
  323. package/src/components/features/signing/BundleSigningPage.tsx +0 -139
  324. package/src/lib/bundle-signing-api.ts +0 -14
  325. package/src/lib/bundle-signing-rpc.ts +0 -16
  326. package/src/lib/server/bundle-signing.server.ts +0 -23
  327. package/src/lib/server/deleteBundle.ts +0 -145
  328. package/src/lib/server/insightsHistory.ts +0 -52
  329. package/src/lib/server/insightsRecovery.ts +0 -186
  330. package/src/routes/signing.tsx +0 -37
@@ -0,0 +1,244 @@
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
+
29
+ import { ParameterDialog } from "./ParameterDialog";
30
+
31
+ /** A value's text in one line, as the list shows it. */
32
+ function ValueText({ text }: { readonly text: string }) {
33
+ return (
34
+ <span
35
+ className="block min-w-0 truncate font-mono text-xs text-foreground"
36
+ title={text}
37
+ >
38
+ {text}
39
+ </span>
40
+ );
41
+ }
42
+
43
+ function ParameterRow({
44
+ parameterKey,
45
+ parameter,
46
+ conditions,
47
+ onEdit,
48
+ onRemove,
49
+ }: {
50
+ readonly parameterKey: string;
51
+ readonly parameter: RemoteConfigParameter;
52
+ readonly conditions: readonly RemoteConfigCondition[];
53
+ readonly onEdit: () => void;
54
+ readonly onRemove: () => void;
55
+ }) {
56
+ // In priority order, as devices resolve them.
57
+ const conditional = conditions.filter(
58
+ ({ name }) =>
59
+ conditionalValueFor(parameter.conditionalValues, name) !== undefined,
60
+ );
61
+ return (
62
+ <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">
63
+ <div className="min-w-0">
64
+ <div className="flex min-w-0 items-center gap-2">
65
+ <span className="truncate font-mono text-sm font-medium">
66
+ {parameterKey}
67
+ </span>
68
+ <Badge className="shrink-0" variant="outline">
69
+ {VALUE_TYPE_LABELS[parameter.valueType]}
70
+ </Badge>
71
+ </div>
72
+ {parameter.description === undefined ? null : (
73
+ <p className="mt-1 text-xs text-muted-foreground">
74
+ {parameter.description}
75
+ </p>
76
+ )}
77
+ </div>
78
+ <dl className="grid min-w-0 grid-cols-[minmax(0,7rem)_minmax(0,1fr)] gap-x-3 gap-y-1.5 text-xs">
79
+ {conditional.map(({ name }) => (
80
+ <div className="contents" key={name}>
81
+ <dt className="truncate text-muted-foreground" title={name}>
82
+ {name}
83
+ </dt>
84
+ <dd className="min-w-0">
85
+ <ValueText
86
+ text={describeValue(
87
+ conditionalValueFor(parameter.conditionalValues, name)!,
88
+ )}
89
+ />
90
+ </dd>
91
+ </div>
92
+ ))}
93
+ <dt className="text-muted-foreground">Default</dt>
94
+ <dd className="min-w-0">
95
+ {"value" in parameter.defaultValue ? (
96
+ <ValueText text={describeValue(parameter.defaultValue)} />
97
+ ) : (
98
+ <span className="text-muted-foreground">In-app default</span>
99
+ )}
100
+ </dd>
101
+ </dl>
102
+ <div className="flex gap-1 md:justify-end">
103
+ <Button
104
+ aria-label={`Edit ${parameterKey}`}
105
+ className="min-h-11 md:min-h-7"
106
+ onClick={onEdit}
107
+ size="sm"
108
+ variant="outline"
109
+ >
110
+ <Pencil data-icon="inline-start" />
111
+ Edit
112
+ </Button>
113
+ <Button
114
+ aria-label={`Delete ${parameterKey}`}
115
+ className="size-11 md:size-7"
116
+ onClick={onRemove}
117
+ size="icon"
118
+ variant="ghost"
119
+ >
120
+ <Trash2 />
121
+ </Button>
122
+ </div>
123
+ </li>
124
+ );
125
+ }
126
+
127
+ /** The draft's parameters, with what each device gets for them. */
128
+ export function ParametersCard({
129
+ template,
130
+ onSaveParameter,
131
+ onRemoveParameter,
132
+ onAddCondition,
133
+ }: {
134
+ readonly template: RemoteConfigTemplate;
135
+ readonly onSaveParameter: (
136
+ previousKey: string | null,
137
+ key: string,
138
+ parameter: RemoteConfigParameter,
139
+ ) => void;
140
+ readonly onRemoveParameter: (key: string) => void;
141
+ readonly onAddCondition: (condition: RemoteConfigCondition) => void;
142
+ }) {
143
+ const [editing, setEditing] = useState<{
144
+ readonly key: string | null;
145
+ } | null>(null);
146
+ const [filter, setFilter] = useState("");
147
+ const keys = Object.keys(template.parameters);
148
+ const shown = keys.filter((key) =>
149
+ key.toLowerCase().includes(filter.trim().toLowerCase()),
150
+ );
151
+ const editingKey = editing?.key ?? null;
152
+
153
+ return (
154
+ <Card className="overflow-hidden shadow-sm">
155
+ <CardHeader className="flex-row flex-wrap items-center justify-between gap-3 space-y-0 border-b px-4 py-3 sm:px-6">
156
+ <CardTitle className="text-sm">
157
+ <h2>Parameters</h2>
158
+ </CardTitle>
159
+ <div className="flex w-full flex-wrap gap-2 sm:w-auto">
160
+ {keys.length > 5 ? (
161
+ <InputGroup className="min-h-11 w-full sm:min-h-8 sm:w-56">
162
+ <InputGroupAddon>
163
+ <Search aria-hidden="true" />
164
+ </InputGroupAddon>
165
+ <InputGroupInput
166
+ aria-label="Filter parameters by key"
167
+ className="text-base sm:text-xs"
168
+ onChange={(event) => setFilter(event.target.value)}
169
+ placeholder="Filter by key"
170
+ value={filter}
171
+ />
172
+ </InputGroup>
173
+ ) : null}
174
+ <Button
175
+ className="min-h-11 sm:min-h-7"
176
+ onClick={() => setEditing({ key: null })}
177
+ >
178
+ <Plus data-icon="inline-start" />
179
+ Add parameter
180
+ </Button>
181
+ </div>
182
+ </CardHeader>
183
+ <CardContent className="p-0">
184
+ {keys.length === 0 ? (
185
+ <Empty className="py-10">
186
+ <EmptyHeader>
187
+ <EmptyMedia variant="icon">
188
+ <SlidersHorizontal />
189
+ </EmptyMedia>
190
+ <EmptyTitle>No parameters</EmptyTitle>
191
+ <EmptyDescription>
192
+ Add a parameter, give it a default, then publish to change the
193
+ app without a new build.
194
+ </EmptyDescription>
195
+ </EmptyHeader>
196
+ <EmptyContent>
197
+ <Button
198
+ className="min-h-11 sm:min-h-7"
199
+ onClick={() => setEditing({ key: null })}
200
+ >
201
+ <Plus data-icon="inline-start" />
202
+ Add parameter
203
+ </Button>
204
+ </EmptyContent>
205
+ </Empty>
206
+ ) : shown.length === 0 ? (
207
+ <div className="flex flex-col items-center gap-2 px-4 py-10 text-center text-xs text-muted-foreground">
208
+ <p className="font-medium text-foreground">No matching keys</p>
209
+ <Button onClick={() => setFilter("")} size="sm" variant="outline">
210
+ Clear filter
211
+ </Button>
212
+ </div>
213
+ ) : (
214
+ <ul aria-label="Parameters" className="divide-y">
215
+ {shown.map((key) => (
216
+ <ParameterRow
217
+ conditions={template.conditions}
218
+ key={key}
219
+ onEdit={() => setEditing({ key })}
220
+ onRemove={() => onRemoveParameter(key)}
221
+ parameter={template.parameters[key]!}
222
+ parameterKey={key}
223
+ />
224
+ ))}
225
+ </ul>
226
+ )}
227
+ </CardContent>
228
+ <ParameterDialog
229
+ conditions={template.conditions}
230
+ onAddCondition={onAddCondition}
231
+ onOpenChange={(open) => {
232
+ if (!open) setEditing(null);
233
+ }}
234
+ onSave={(key, parameter) => onSaveParameter(editingKey, key, parameter)}
235
+ open={editing !== null}
236
+ parameter={
237
+ editingKey === null ? null : (template.parameters[editingKey] ?? null)
238
+ }
239
+ parameterKey={editingKey}
240
+ takenKeys={keys.filter((key) => key !== editingKey)}
241
+ />
242
+ </Card>
243
+ );
244
+ }
@@ -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
+ }