@hot-updater/console 1.0.0-rc.20 → 1.0.0-rc.21

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 (180) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{ConsoleFeatureUnavailable-B9VYGA3N.js → ConsoleFeatureUnavailable-D0LPL1Gy.js} +1 -1
  3. package/.output/public/assets/{HashValueDisplay-D880zntR.js → HashValueDisplay-BmuB4FW-.js} +1 -1
  4. package/.output/public/assets/InsightsInfo--v4SC07c.js +1 -0
  5. package/.output/public/assets/InsightsPageHeader-dU83CAQY.js +1 -0
  6. package/.output/public/assets/{NotFoundPage-Dys8C0cW.js → NotFoundPage-B5mhGG2a.js} +1 -1
  7. package/.output/public/assets/api-D-vOVlQ4.js +1 -0
  8. package/.output/public/assets/api-keys-Csh8ARKU.js +1 -0
  9. package/.output/public/assets/api-keys-OMPUoA_A.js +1 -0
  10. package/.output/public/assets/arrow-left-Bwq9X1eS.js +1 -0
  11. package/.output/public/assets/arrow-up-right-BkOVn4if.js +1 -0
  12. package/.output/public/assets/{card-DzCPSRsh.js → card-C_7d6O9a.js} +1 -1
  13. package/.output/public/assets/console-features-api-C1jRZTGw.js +1 -0
  14. package/.output/public/assets/dialog-DE8wFN_P.js +1 -0
  15. package/.output/public/assets/{dist-Clb6cQ9l.js → dist-C7ENGzpS.js} +1 -1
  16. package/.output/public/assets/empty-CVd5NlQD.js +1 -0
  17. package/.output/public/assets/{field-Bou7shoO.js → field-C06q1iC9.js} +1 -1
  18. package/.output/public/assets/index-BeWlQtO6.js +11 -0
  19. package/.output/public/assets/{input-group-DVtWFUUF.js → input-group-Bi61biIA.js} +1 -1
  20. package/.output/public/assets/insights-BjnAtC0f.js +2 -0
  21. package/.output/public/assets/insights-D86m11yH.js +42 -0
  22. package/.output/public/assets/insights-DpYstMoY.js +1 -0
  23. package/.output/public/assets/{insights-recovery-rpc-wvdyM4LD.js → insights-recovery-rpc-BIm5_ALc.js} +1 -1
  24. package/.output/public/assets/{insights-usage-rpc-qUkNtrWr.js → insights-usage-rpc-VHj8vyBt.js} +1 -1
  25. package/.output/public/assets/insights_.distribution-ADcrX48c.js +2 -0
  26. package/.output/public/assets/insights_.distribution-CuuJUN6Y.js +1 -0
  27. package/.output/public/assets/{insights_.distribution-CItZw3-8.js → insights_.distribution-DJRjuXsO.js} +1 -1
  28. package/.output/public/assets/installations-BSBBzqWs.js +2 -0
  29. package/.output/public/assets/installations-DqIE6WcO.js +1 -0
  30. package/.output/public/assets/installations-UsELbDvw.js +1 -0
  31. package/.output/public/assets/{loader-circle-Ca7C9YY1.js → loader-circle-CnCBxzHp.js} +1 -1
  32. package/.output/public/assets/mutation-Csp7xUNh.js +1 -0
  33. package/.output/public/assets/preload-helper-B-cOmpLH.js +1 -0
  34. package/.output/public/assets/{refresh-cw-CVGqvy8Z.js → refresh-cw-FF1NtzlQ.js} +1 -1
  35. package/.output/public/assets/{routes-veKtDW39.js → routes-CoN9XHP_.js} +2 -2
  36. package/.output/public/assets/routes-DT1jB0Zi.js +1 -0
  37. package/.output/public/assets/sidebar-D8mJRF15.js +3 -0
  38. package/.output/public/assets/styles-Bwt7v6U5.css +2 -0
  39. package/.output/public/assets/table-WBgfvgXg.js +1 -0
  40. package/.output/public/assets/{useCompositeListItem-CF7vsfcA.js → useCompositeListItem-CloBmDwn.js} +1 -1
  41. package/.output/public/assets/useMutation-DO8cvsTx.js +1 -0
  42. package/.output/public/assets/{useOpenInteractionType-AnAMWYIY.js → useOpenInteractionType-ReGr9GzJ.js} +1 -1
  43. package/.output/public/assets/valueToPercent-BvPAi4bP.js +1 -0
  44. package/.output/server/{__23tanstack-start-server-fn-resolver-CUQLz7hs.mjs → __23tanstack-start-server-fn-resolver-DMRD4e4f.mjs} +34 -42
  45. package/.output/server/_libs/@tanstack/react-router+[...].mjs +3756 -4022
  46. package/.output/server/_libs/@tanstack/react-router-ssr-query+[...].mjs +138 -95
  47. package/.output/server/_libs/tanstack__history.mjs +68 -41
  48. package/.output/server/_libs/tanstack__query-core.mjs +1618 -309
  49. package/.output/server/_libs/tanstack__react-query.mjs +255 -20
  50. package/.output/server/_ssr/{ConsoleFeatureUnavailable-DoxET2AT.mjs → ConsoleFeatureUnavailable-Du7jNPNS.mjs} +7 -7
  51. package/.output/server/_ssr/{HashValueDisplay-BplboHEb.mjs → HashValueDisplay-GQvFkXoi.mjs} +2 -2
  52. package/.output/server/_ssr/{InsightsInfo-o2YPd5Qc.mjs → InsightsInfo-Do7QSaFR.mjs} +2 -2
  53. package/.output/server/_ssr/{InsightsPageHeader-NExCJL1I.mjs → InsightsPageHeader-DSUWUWRc.mjs} +6 -6
  54. package/.output/server/_ssr/{NotFoundPage-Cd-A8ock.mjs → NotFoundPage-DsF4Vrhg.mjs} +2 -2
  55. package/.output/server/_ssr/{api-B1Ro0uys.mjs → api-BEiVs0H7.mjs} +9 -8
  56. package/.output/server/_ssr/{api-keys-Dvvy1sem.mjs → api-keys-BrvBWGRf.mjs} +2 -2
  57. package/.output/server/_ssr/{api-keys-CT3HG7KT.mjs → api-keys-K5v32nf7.mjs} +8 -8
  58. package/.output/server/_ssr/{api-keys-rpc-b1qTTFfG.mjs → api-keys-rpc-B96bBllm.mjs} +5 -5
  59. package/.output/server/_ssr/{api-rpc-Cbns2MGx.mjs → api-rpc-DcUe280B.mjs} +13 -55
  60. package/.output/server/_ssr/{auth-rpc-DChS7m9y.mjs → auth-rpc-C68W56DP.mjs} +6 -6
  61. package/.output/server/_ssr/{api-C0G9MTMI.mjs → auth.server-DM1J6NwR.mjs} +2815 -1308
  62. package/.output/server/_ssr/{bundleActivity-D17Pb_h5.mjs → bundleActivity-CpuY9CTP.mjs} +1 -1
  63. package/.output/server/_ssr/{card-DMbcvlPz.mjs → card-CPAEKx0w.mjs} +1 -1
  64. package/.output/server/_ssr/config-nsIcsHh8.mjs +15 -0
  65. package/.output/server/_ssr/config.server-DDCZk3Sq.mjs +36 -0
  66. package/.output/server/_ssr/{console-access-KpPv5lin.mjs → console-access-Da-2Qd7q.mjs} +3 -3
  67. package/.output/server/_ssr/{console-features-CsbyHYfK.mjs → console-features-Dzu2iUGD.mjs} +6 -6
  68. package/.output/server/_ssr/{console-features-api-B-KVuo4p.mjs → console-features-api-xAsSgFa_.mjs} +6 -6
  69. package/.output/server/_ssr/{console-features-rpc-Djyo5740.mjs → console-features-rpc-qARGpB24.mjs} +5 -5
  70. package/.output/server/_ssr/{createMiddleware-B_I3Ll4M.mjs → createMiddleware-BdBf_ezN.mjs} +41 -56
  71. package/.output/server/_ssr/{createServerRpc-DuNm5mmo.mjs → createServerRpc-B_y2lrwA.mjs} +2 -2
  72. package/.output/server/_ssr/databaseJsonValue-Bhxciy7Z.mjs +68 -0
  73. package/.output/server/_ssr/databaseRows-DwMAjaF8.mjs +74 -0
  74. package/.output/server/_ssr/{dialog-cOmLTUV2.mjs → dialog-q__BJ7mQ.mjs} +1 -1
  75. package/.output/server/_ssr/{dist-B-r4u3Lg.mjs → dist-Cxo9ghYv.mjs} +114 -3
  76. package/.output/server/_ssr/{downloadBundle-CexOFoZ4.mjs → downloadBundle-BW9I-pMQ.mjs} +6 -5
  77. package/.output/server/_ssr/{empty-BHoY_5jt.mjs → empty-DcBTAooP.mjs} +2 -2
  78. package/.output/server/_ssr/{empty-plugin-adapters-B5QvGpEl.mjs → empty-plugin-adapters-CYdinE-i.mjs} +1 -1
  79. package/.output/server/_ssr/{field-mjhcNEXD.mjs → field-QCDBVpXA.mjs} +2 -2
  80. package/.output/server/_ssr/{getBundleChildren-DbDXe9wB.mjs → getBundleChildren-DIAGCF4a.mjs} +2 -2
  81. package/.output/server/_ssr/{input-group-96H30HWC.mjs → input-group-hCk2nUoU.mjs} +1 -1
  82. package/.output/server/_ssr/{insights-DgFv1NsO.mjs → insights-BfBO0RFr.mjs} +18 -18
  83. package/.output/server/_ssr/{insights-D359GJFL.mjs → insights-DsAU3-TB.mjs} +5 -5
  84. package/.output/server/_ssr/{insights-D25VDVaz.mjs → insights-RIfg447W.mjs} +2 -2
  85. package/.output/server/_ssr/{insights-api-ChAKrbhG.mjs → insights-api-CDn-QQHU.mjs} +5 -5
  86. package/.output/server/_ssr/{insights-failures-WQ-ttjOx.mjs → insights-failures-BBGMhuUr.mjs} +2 -2
  87. package/.output/server/_ssr/{insights-failures-rpc-BFsqlltN.mjs → insights-failures-rpc-rA2dctK2.mjs} +8 -8
  88. package/.output/server/_ssr/{insights-recovery-DkL6bxMW.mjs → insights-recovery-Dpk6Mfb9.mjs} +1 -1
  89. package/.output/server/_ssr/{insights-recovery-rpc-2P5m8F62.mjs → insights-recovery-rpc-BCaF-xSd.mjs} +11 -11
  90. package/.output/server/_ssr/{insights-recovery-rpc-Tj8vNC19.mjs → insights-recovery-rpc-CcgYyUHk.mjs} +5 -5
  91. package/.output/server/_ssr/{insights-rpc-DrkVmV9o.mjs → insights-rpc-keycmwzw.mjs} +5 -5
  92. package/.output/server/_ssr/{insights-search-BsalnNw-.mjs → insights-search-BRg5VsNe.mjs} +1 -1
  93. package/.output/server/_ssr/{insights-usage-1nVTQrLy.mjs → insights-usage-cbw9n2Fq.mjs} +1 -1
  94. package/.output/server/_ssr/{insights-usage-rpc-Ct_4xHhZ.mjs → insights-usage-rpc-BKgV1QDf.mjs} +8 -8
  95. package/.output/server/_ssr/{insights-usage-rpc-DaYIRtFK.mjs → insights-usage-rpc-D-JYachy.mjs} +5 -5
  96. package/.output/server/_ssr/{insightsRecovery-CpGucWN1.mjs → insightsRecovery-B7oMc8d8.mjs} +2 -2
  97. package/.output/server/_ssr/{insightsUsage-JYpKZAF7.mjs → insightsUsage-Oa7kk5ek.mjs} +3 -3
  98. package/.output/server/_ssr/{insights_.distribution-jQZEF07J.mjs → insights_.distribution-BIqOqRW0.mjs} +13 -13
  99. package/.output/server/_ssr/{insights_.distribution-Bcu6uYs_.mjs → insights_.distribution-CuUrDa7P.mjs} +2 -2
  100. package/.output/server/_ssr/{insights_.distribution-D3Csuyjw.mjs → insights_.distribution-RT_6x_ud.mjs} +5 -5
  101. package/.output/server/_ssr/{installations-Cxikllmx.mjs → installations-BO5CjX2z.mjs} +11 -11
  102. package/.output/server/_ssr/{installations-BI5kelHv.mjs → installations-BjaHiIfh.mjs} +2 -2
  103. package/.output/server/_ssr/{installations-B8Vh54lH.mjs → installations-Dt5luA-N.mjs} +4 -4
  104. package/.output/server/_ssr/{listReleases-DqU9t1l3.mjs → listReleases-BitHzOYB.mjs} +1 -1
  105. package/.output/server/_ssr/{router-CRkm-wHD.mjs → router-DfVAixxe.mjs} +42 -39
  106. package/.output/server/_ssr/{routes-CNAi0Mmv.mjs → routes-C6LstNp8.mjs} +14 -14
  107. package/.output/server/_ssr/{routes-B3IJo_jL.mjs → routes-Q3Uhmwwz.mjs} +11 -11
  108. package/.output/server/_ssr/{runtime.server-NucbYjc7.mjs → runtime.server-fL0o6I2b.mjs} +500 -413
  109. package/.output/server/_ssr/schema-BKY9SqaY.mjs +25 -0
  110. package/.output/server/_ssr/{select-BkPAJFL7.mjs → select-CUlInmjk.mjs} +1 -1
  111. package/.output/server/_ssr/server-C43wq9ft.mjs +8330 -0
  112. package/.output/server/_ssr/{sidebar-Cw1VuC7d.mjs → sidebar-DKbx2ach.mjs} +3 -3
  113. package/.output/server/_ssr/ssr.mjs +1 -1
  114. package/.output/server/_ssr/start-BXUOv_n8.mjs +4 -0
  115. package/.output/server/_ssr/{table-q0P9wz7x.mjs → table-NGWV8B-S.mjs} +1 -1
  116. package/.output/server/_ssr/{updateFailures-DMU9f0pK.mjs → updateFailures-Jwe2Baab.mjs} +3 -3
  117. package/.output/server/_ssr/{uuidv7-BzSO-fr-.mjs → uuidv7-C8bwiZr8.mjs} +2 -2
  118. package/.output/server/_tanstack-start-manifest_v-WQ5qGn8n.mjs +124 -0
  119. package/.output/server/index.mjs +218 -218
  120. package/LICENSE +13 -14
  121. package/README.md +16 -12
  122. package/lib/index.d.mts +18 -8
  123. package/lib/vite-internal.mjs +15 -8
  124. package/lib/vite.d.mts +2 -0
  125. package/package.json +14 -14
  126. package/src/components/AppSidebar.tsx +9 -0
  127. package/src/components/ConsoleFeatureUnavailable.tsx +1 -3
  128. package/src/components/features/bundles/BundleMetadata.tsx +1 -1
  129. package/src/components/features/bundles/RolloutCohortsDialog.tsx +1 -1
  130. package/src/components/features/releases/ReleaseEditorSheet.tsx +6 -6
  131. package/src/index.ts +27 -15
  132. package/src/lib/api-rpc.ts +1 -54
  133. package/src/lib/api.ts +8 -89
  134. package/src/lib/console-features.ts +5 -5
  135. package/src/lib/scroll-restoration.ts +1 -1
  136. package/src/lib/server/config.server.ts +15 -52
  137. package/src/lib/server/console-runtime.server.ts +84 -6
  138. package/src/lib/server/downloadBundle.ts +10 -6
  139. package/src/lib/server/releaseReachability.ts +4 -4
  140. package/src/lib/server/runtime.server.ts +34 -46
  141. package/src/routeTree.gen.ts +31 -31
  142. package/src/routes/api/bundles/$bundleId/download.ts +2 -2
  143. package/src/vite-internal.ts +17 -8
  144. package/src/vite.ts +2 -0
  145. package/.output/public/assets/InsightsInfo-By_sPjTE.js +0 -1
  146. package/.output/public/assets/InsightsPageHeader-9_kx_LL7.js +0 -1
  147. package/.output/public/assets/api-CtarlV0l.js +0 -1
  148. package/.output/public/assets/api-keys-DFF_QqtN.js +0 -1
  149. package/.output/public/assets/api-keys-evfsQ4sN.js +0 -1
  150. package/.output/public/assets/arrow-left-BP9D-ta_.js +0 -1
  151. package/.output/public/assets/arrow-up-right-CDP9Tevw.js +0 -1
  152. package/.output/public/assets/console-features-api-yv7rm3DX.js +0 -1
  153. package/.output/public/assets/dialog-BDvCy_QO.js +0 -1
  154. package/.output/public/assets/empty-C5x9mn_s.js +0 -1
  155. package/.output/public/assets/index-0eg3l8aC.js +0 -10
  156. package/.output/public/assets/insights-2MbdiSNv.js +0 -1
  157. package/.output/public/assets/insights-C6tmCZHk.js +0 -2
  158. package/.output/public/assets/insights-CadS_aIA.js +0 -42
  159. package/.output/public/assets/insights_.distribution-BhBs6PNA.js +0 -1
  160. package/.output/public/assets/insights_.distribution-CJUH_wAS.js +0 -2
  161. package/.output/public/assets/installations-CH2H7JQt.js +0 -2
  162. package/.output/public/assets/installations-DMeMuwsW.js +0 -1
  163. package/.output/public/assets/installations-DnvxI9Dt.js +0 -1
  164. package/.output/public/assets/mutation-x9L28_CD.js +0 -1
  165. package/.output/public/assets/preload-helper-BN-UkjOE.js +0 -1
  166. package/.output/public/assets/routes-BhK8DuZA.js +0 -1
  167. package/.output/public/assets/sidebar-B45aMqRm.js +0 -3
  168. package/.output/public/assets/styles-Dn0pK1EX.css +0 -2
  169. package/.output/public/assets/table-CwLnN6KX.js +0 -1
  170. package/.output/public/assets/useMutation-CN1ygYEr.js +0 -1
  171. package/.output/public/assets/valueToPercent-C-t8FT0y.js +0 -1
  172. package/.output/server/_ssr/auth.server-Ccqz2iVv.mjs +0 -37
  173. package/.output/server/_ssr/config-DMEJdhoW.mjs +0 -13
  174. package/.output/server/_ssr/config.server-DyypN6cQ.mjs +0 -60
  175. package/.output/server/_ssr/databaseRows-CXxf_VIB.mjs +0 -132
  176. package/.output/server/_ssr/deleteBundle-Dcc21Lbd.mjs +0 -56
  177. package/.output/server/_ssr/server-DKJYsaCP.mjs +0 -7442
  178. package/.output/server/_ssr/start-DpViQGnt.mjs +0 -4
  179. package/.output/server/_tanstack-start-manifest_v-Bb0gKDbb.mjs +0 -124
  180. package/src/lib/server/deleteBundle.ts +0 -136
@@ -1,82 +1,45 @@
1
- import {
2
- assertStorageOperations,
3
- type HotUpdaterCoreApi,
4
- type StoragePluginWith,
5
- } from "@hot-updater/plugin-core";
6
- import { createDatabaseCoreApi } from "@hot-updater/server/db";
1
+ import type { HotUpdaterCoreApi } from "@hot-updater/plugin-core";
7
2
  import { getRequest } from "@tanstack/react-start/server";
8
3
 
9
- import type { HotUpdaterConsoleConfig } from "../../index";
10
4
  import { requireConsoleAccess } from "./auth.server";
11
- import { resolveConsoleConfig } from "./console-runtime.server";
5
+ import {
6
+ resolveConsoleConfig,
7
+ type ResolvedConsoleConfig,
8
+ } from "./console-runtime.server";
12
9
  import type { ConsoleRuntime } from "./runtime.server";
13
10
 
14
- type ResolvedConsoleConfig = HotUpdaterConsoleConfig & {
15
- readonly console: NonNullable<HotUpdaterConsoleConfig["console"]>;
16
- };
17
-
18
11
  let configPromise: Promise<ResolvedConsoleConfig> | null = null;
19
12
  let core: HotUpdaterCoreApi | null = null;
20
13
  let runtime: ConsoleRuntime | null = null;
21
- let storagePluginPromise: Promise<
22
- StoragePluginWith<"get" | "put" | "exists" | "delete">
23
- > | null = null;
24
14
 
25
15
  const loadCachedConfig = async (request: Request) => {
26
16
  if (!configPromise) {
27
- configPromise = resolveConsoleConfig(request)
28
- .then((config) => ({
29
- ...config,
30
- console: config.console ?? {},
31
- }))
32
- .catch((error) => {
33
- configPromise = null;
34
- throw error;
35
- });
17
+ configPromise = resolveConsoleConfig(request).catch((error) => {
18
+ configPromise = null;
19
+ throw error;
20
+ });
36
21
  }
37
22
 
38
23
  return configPromise;
39
24
  };
40
25
 
41
- const loadCachedStoragePlugin = async (config: ResolvedConsoleConfig) => {
42
- if (!storagePluginPromise) {
43
- storagePluginPromise = Promise.resolve(config.storage)
44
- .then((storagePlugin) => {
45
- assertStorageOperations(storagePlugin, [
46
- "get",
47
- "put",
48
- "exists",
49
- "delete",
50
- ]);
51
- return storagePlugin;
52
- })
53
- .catch((error) => {
54
- storagePluginPromise = null;
55
- throw error;
56
- });
57
- }
58
-
59
- return storagePluginPromise;
60
- };
61
-
62
26
  export const prepareConfig = async (request: Request = getRequest()) => {
63
27
  try {
64
28
  await requireConsoleAccess(request);
65
29
  const config = await loadCachedConfig(request);
66
30
 
67
- // Bundles, releases, catalogs, and channels: core's API, in process or
68
- // over a self-hosted server's admin API.
69
- core ??= createDatabaseCoreApi(config.database);
31
+ // Bundles, releases, catalogs, and channels: core assembled as the
32
+ // server's, on the server's own path, or a self-hosted server's admin API.
33
+ core ??= config.core;
70
34
 
71
- // The console's features: those of the plugins the server runs.
35
+ // The console's features: those of the plugins its config lists.
72
36
  if (!runtime) {
73
37
  const { createConsoleRuntime } = await import("./runtime.server");
74
38
  runtime = createConsoleRuntime(config);
75
39
  }
76
40
 
77
- const storagePlugin = await loadCachedStoragePlugin(config);
78
-
79
- return { config, core, runtime, storagePlugin };
41
+ // Each bundle file is read and deleted with its protocol's storage.
42
+ return { config, core, runtime, storage: config.storage };
80
43
  } catch (error) {
81
44
  if (
82
45
  !(
@@ -1,9 +1,62 @@
1
+ import {
2
+ type AnyHotUpdaterPlugin,
3
+ type ConfiguredDatabase,
4
+ createMemoryAdapter,
5
+ type EngineDatabase,
6
+ type HotUpdaterCoreApi,
7
+ isRemoteDatabase,
8
+ type StorageAdapter,
9
+ } from "@hot-updater/plugin-core";
10
+ import { createHotUpdater } from "@hot-updater/server";
11
+
1
12
  import type {
2
13
  ConsoleAuthAdapter,
3
- HotUpdaterConsoleConfig,
4
14
  HotUpdaterConsoleConfigSource,
5
15
  } from "../../index";
6
16
 
17
+ /** What the console runs on, assembled from its config as the server is. */
18
+ export interface ResolvedConsoleConfig {
19
+ readonly gitUrl?: string;
20
+ /** The server's database, or its admin API. */
21
+ readonly database: ConfiguredDatabase;
22
+ /**
23
+ * Core's API, assembled over the database as the server assembles it, so
24
+ * the console's writes take the server's path, or a self-hosted server's
25
+ * admin API.
26
+ */
27
+ readonly core: HotUpdaterCoreApi;
28
+ /** The server's storage; each bundle file is read with its protocol's. */
29
+ readonly storage: readonly StorageAdapter[];
30
+ /** The plugins the server runs, as the config lists them. */
31
+ readonly plugins: readonly AnyHotUpdaterPlugin[];
32
+ /**
33
+ * The plugins' APIs by id, which serve their features; absent over a
34
+ * self-hosted server's admin API, whose plugins run on the server.
35
+ */
36
+ readonly api?: Readonly<Record<string, unknown>>;
37
+ }
38
+
39
+ /**
40
+ * Core and the plugins over `database`, assembled by `createHotUpdater` as
41
+ * the server assembles them, with public client routes unless a plugin
42
+ * provides clientAuth: the console mounts no handlers. cli-tools'
43
+ * `assembleServer` does the same for the CLI; the console keeps its own
44
+ * copy, since a hosted console never loads cli-tools.
45
+ */
46
+ const assemble = (
47
+ database: EngineDatabase,
48
+ storage: StorageAdapter,
49
+ plugins: readonly AnyHotUpdaterPlugin[],
50
+ ) =>
51
+ createHotUpdater({
52
+ database,
53
+ storage: [storage],
54
+ plugins,
55
+ ...(plugins.some((plugin) => plugin.provides?.clientAuth)
56
+ ? {}
57
+ : { clientAccess: "public" }),
58
+ } as Parameters<typeof createHotUpdater>[0]);
59
+
7
60
  export const getConsoleAuthAdapter = async (): Promise<ConsoleAuthAdapter> => {
8
61
  const module = await import("virtual:hot-updater-console/auth");
9
62
  return module.default;
@@ -11,17 +64,42 @@ export const getConsoleAuthAdapter = async (): Promise<ConsoleAuthAdapter> => {
11
64
 
12
65
  export const resolveConsoleConfig = async (
13
66
  request: Request,
14
- ): Promise<HotUpdaterConsoleConfig> => {
67
+ ): Promise<ResolvedConsoleConfig> => {
15
68
  const { default: source } =
16
69
  (await import("virtual:hot-updater-console/config")) as {
17
70
  readonly default: HotUpdaterConsoleConfigSource;
18
71
  };
19
72
 
20
73
  const config = typeof source === "function" ? await source(request) : source;
74
+ const { database, storage, plugins = [] } = config;
75
+ const gitUrl =
76
+ config.console?.gitUrl === undefined
77
+ ? {}
78
+ : { gitUrl: config.console.gitUrl };
79
+ // A self-hosted server runs the plugins itself: core is its admin API.
80
+ // The plugins are still checked as the server checks them, on a database
81
+ // nothing reads, so one the server would refuse is refused here too.
82
+ if (isRemoteDatabase(database)) {
83
+ const checked = assemble(
84
+ { name: "memory", adapter: createMemoryAdapter() },
85
+ storage,
86
+ plugins,
87
+ );
88
+ return {
89
+ ...gitUrl,
90
+ database,
91
+ core: database.core,
92
+ storage: [storage],
93
+ plugins: checked.plugins,
94
+ };
95
+ }
96
+ const server = assemble(database, storage, plugins);
21
97
  return {
22
- console: config.console,
23
- database: config.database,
24
- storage: config.storage,
25
- ...(config.plugins === undefined ? {} : { plugins: config.plugins }),
98
+ ...gitUrl,
99
+ database,
100
+ core: server.core,
101
+ storage: server.storage,
102
+ plugins: server.plugins,
103
+ api: server.api,
26
104
  };
27
105
  };
@@ -1,16 +1,17 @@
1
1
  import type {
2
2
  HotUpdaterCoreApi,
3
- StoragePluginWith,
3
+ StorageAdapter,
4
4
  } from "@hot-updater/plugin-core";
5
5
 
6
6
  interface DownloadBundleDependencies {
7
7
  readonly core: Pick<HotUpdaterCoreApi, "getBundle">;
8
- readonly storagePlugin?: StoragePluginWith<"get">;
8
+ /** The server's storage; the manifest is read with its protocol's. */
9
+ readonly storage: readonly StorageAdapter[];
9
10
  }
10
11
 
11
12
  export const downloadBundle = async (
12
13
  bundleId: string,
13
- { core, storagePlugin }: DownloadBundleDependencies,
14
+ { core, storage }: DownloadBundleDependencies,
14
15
  ): Promise<Response> => {
15
16
  const detail = await core.getBundle(bundleId);
16
17
  if (!detail) return new Response("Bundle not found", { status: 404 });
@@ -18,8 +19,11 @@ export const downloadBundle = async (
18
19
  const storageUri = detail.bundle.manifest_storage_uri;
19
20
 
20
21
  const protocol = new URL(storageUri).protocol.replace(":", "");
21
- if (storagePlugin?.protocol === protocol) {
22
- const { response } = await storagePlugin.get({ storageUri });
22
+ const storageAdapter = storage.find(
23
+ (adapter) => adapter.protocol === protocol,
24
+ );
25
+ if (storageAdapter?.get !== undefined) {
26
+ const { response } = await storageAdapter.get({ storageUri });
23
27
  if (!response)
24
28
  return new Response("Storage object not found", { status: 404 });
25
29
 
@@ -34,7 +38,7 @@ export const downloadBundle = async (
34
38
  }
35
39
 
36
40
  if (protocol !== "http" && protocol !== "https") {
37
- return new Response(`No storage plugin for protocol: ${protocol}`, {
41
+ return new Response(`No storage adapter for protocol: ${protocol}`, {
38
42
  status: 503,
39
43
  });
40
44
  }
@@ -1,12 +1,12 @@
1
- import {
2
- isReleaseEligibleForCohort,
3
- NUMERIC_COHORT_SIZE,
4
- } from "@hot-updater/core";
5
1
  import type {
6
2
  CompiledReleaseCatalog,
7
3
  HotUpdaterCoreApi,
8
4
  ReleaseRow,
9
5
  } from "@hot-updater/plugin-core";
6
+ import {
7
+ isReleaseEligibleForCohort,
8
+ NUMERIC_COHORT_SIZE,
9
+ } from "@hot-updater/protocol";
10
10
 
11
11
  export type ReleaseReachabilityRow = ReleaseRow & {
12
12
  readonly currentlyUnreachable: boolean;
@@ -2,7 +2,6 @@ import {
2
2
  type ConfiguredDatabase,
3
3
  isRemoteDatabase,
4
4
  } from "@hot-updater/plugin-core";
5
- import { createDatabasePluginApis } from "@hot-updater/server/db";
6
5
 
7
6
  import {
8
7
  type ConsoleFeature,
@@ -14,7 +13,6 @@ import {
14
13
  import {
15
14
  type ConsoleFeatureApis,
16
15
  consoleFeatureApis,
17
- type FetchAdmin,
18
16
  } from "./console-feature-apis";
19
17
 
20
18
  export type { ConsoleFeatureApis } from "./console-feature-apis";
@@ -22,7 +20,7 @@ export type { ConsoleFeatureApis } from "./console-feature-apis";
22
20
  export interface ConsoleRuntime {
23
21
  /** Whether the console reaches a self-hosted server through its admin API. */
24
22
  readonly remote: boolean;
25
- /** The features on here, resolved once from the plugins the server runs. */
23
+ /** The features on here, from the plugins the console's config lists. */
26
24
  features(): Promise<ConsoleFeatures>;
27
25
  /** What serves the features the console can serve here; {@link requireFeature} hands it out. */
28
26
  readonly apis: Partial<ConsoleFeatureApis>;
@@ -31,32 +29,16 @@ export interface ConsoleRuntime {
31
29
  const isRecord = (value: unknown): value is Record<string, unknown> =>
32
30
  typeof value === "object" && value !== null;
33
31
 
34
- /** The ids of the plugins a self-hosted server lists on its admin `/version`. */
35
- const readServerPlugins = async (
36
- fetchAdmin: FetchAdmin,
37
- ): Promise<readonly string[]> => {
38
- const response = await fetchAdmin("/version");
39
- if (!response.ok) {
40
- throw new Error(`The server answered /version with ${response.status}.`);
41
- }
42
- const body: unknown = await response.json();
43
- const plugins = isRecord(body) ? body.plugins : undefined;
44
- // A server from before `/version` listed its plugins reports none, so the
45
- // console serves none of their features until the server is upgraded.
46
- return Array.isArray(plugins)
47
- ? plugins.filter((id): id is string => typeof id === "string")
48
- : [];
49
- };
50
-
51
- /** Runs `load` once and keeps its result; a failure is not kept, so the next call retries. */
52
- const once = <T>(load: () => Promise<T>): (() => Promise<T>) => {
53
- let pending: Promise<T> | undefined;
54
- return () =>
55
- (pending ??= load().catch((error: unknown) => {
56
- pending = undefined;
57
- throw error;
58
- }));
59
- };
32
+ /**
33
+ * Whether one of Hot Updater's own factories made `plugin`: the brand they
34
+ * set under a registered symbol, read here with a copy of the key so the
35
+ * console imports no package's internals. Assembly refuses any other plugin
36
+ * that takes one of their ids, so features key on it.
37
+ */
38
+ const isOfficialPlugin = (plugin: unknown): boolean =>
39
+ isRecord(plugin) &&
40
+ Reflect.get(plugin, Symbol.for("@hot-updater/server/official-plugin")) ===
41
+ true;
60
42
 
61
43
  const featureIds = Object.keys(consoleFeatureApis) as ConsoleFeature[];
62
44
 
@@ -76,41 +58,47 @@ const featureApis = (
76
58
  );
77
59
 
78
60
  /**
79
- * The console's features and what serves them, for a console config:
80
- * - a self-hosted server (`standaloneRepository`) runs its plugins and lists
81
- * them on its admin `/version`; the console serves what that server's admin
82
- * API serves, and nothing that needs the database;
83
- * - otherwise the console assembles `plugins` over the database, as the
84
- * server does, and serves the features of the plugins it assembled.
61
+ * The console's features and what serves them, for the plugins its config
62
+ * lists, the plugins the server runs:
63
+ * - a self-hosted server (`standaloneRepository`) runs them itself; the
64
+ * console serves what that server's admin API serves of their features,
65
+ * and nothing that needs the database;
66
+ * - otherwise the console runs them over the database, as the server does,
67
+ * and serves their features through `api`, their APIs.
85
68
  */
86
69
  export const createConsoleRuntime = (config: {
87
70
  readonly database: ConfiguredDatabase;
88
- readonly plugins?: readonly unknown[];
71
+ readonly plugins: readonly unknown[];
72
+ readonly api?: Readonly<Record<string, unknown>>;
89
73
  }): ConsoleRuntime => {
90
74
  const { database } = config;
75
+ // A feature's plugin is Hot Updater's own, which alone may take its id:
76
+ // the server's assembly refuses any other, and features key on the
77
+ // factory's mark, so another plugin under that id turns on nothing.
78
+ const official = new Set(
79
+ config.plugins
80
+ .filter(isOfficialPlugin)
81
+ .map((plugin) => (plugin as { id: string }).id),
82
+ );
91
83
  if (isRemoteDatabase(database)) {
92
84
  const { fetchAdmin } = database;
85
+ const features = resolveConsoleFeatures([...official], { remote: true });
93
86
  return {
94
87
  remote: true,
95
- features: once(async () =>
96
- resolveConsoleFeatures(await readServerPlugins(fetchAdmin), {
97
- remote: true,
98
- }),
99
- ),
88
+ features: async () => features,
100
89
  apis: featureApis((feature) =>
101
90
  consoleFeatureApis[feature].remote?.(fetchAdmin),
102
91
  ),
103
92
  };
104
93
  }
105
- const api = createDatabasePluginApis(database, config.plugins ?? []);
106
- const features = resolveConsoleFeatures(Object.keys(api), { remote: false });
94
+ const api = config.api ?? {};
95
+ const features = resolveConsoleFeatures([...official], { remote: false });
107
96
  return {
108
97
  remote: false,
109
98
  features: async () => features,
110
- // A feature reads the plugin with its plugin's id, taken to be Hot
111
- // Updater's own, as a self-hosted server's /version list is.
112
99
  apis: featureApis((feature) => {
113
- const pluginApi = api[consoleFeatures[feature].plugin];
100
+ const { plugin } = consoleFeatures[feature];
101
+ const pluginApi = official.has(plugin) ? api[plugin] : undefined;
114
102
  return pluginApi === undefined
115
103
  ? undefined
116
104
  : consoleFeatureApis[feature].local(pluginApi as never);
@@ -9,22 +9,17 @@
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 InstallationsRouteImport } from './routes/installations'
13
- import { Route as InsightsRouteImport } from './routes/insights'
14
- import { Route as ApiKeysRouteImport } from './routes/api-keys'
15
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
16
  import { Route as InsightsDistributionRouteImport } from './routes/insights_.distribution'
17
17
  import { Route as ApiAuthSplatRouteImport } from './routes/api/auth/$'
18
18
  import { Route as ApiBundlesBundleIdDownloadRouteImport } from './routes/api/bundles/$bundleId/download'
19
19
 
20
- const InstallationsRoute = InstallationsRouteImport.update({
21
- id: '/installations',
22
- path: '/installations',
23
- getParentRoute: () => rootRouteImport,
24
- } as any)
25
- const InsightsRoute = InsightsRouteImport.update({
26
- id: '/insights',
27
- path: '/insights',
20
+ const IndexRoute = IndexRouteImport.update({
21
+ id: '/',
22
+ path: '/',
28
23
  getParentRoute: () => rootRouteImport,
29
24
  } as any)
30
25
  const ApiKeysRoute = ApiKeysRouteImport.update({
@@ -32,9 +27,14 @@ const ApiKeysRoute = ApiKeysRouteImport.update({
32
27
  path: '/api-keys',
33
28
  getParentRoute: () => rootRouteImport,
34
29
  } as any)
35
- const IndexRoute = IndexRouteImport.update({
36
- id: '/',
37
- path: '/',
30
+ const InsightsRoute = InsightsRouteImport.update({
31
+ id: '/insights',
32
+ path: '/insights',
33
+ getParentRoute: () => rootRouteImport,
34
+ } as any)
35
+ const InstallationsRoute = InstallationsRouteImport.update({
36
+ id: '/installations',
37
+ path: '/installations',
38
38
  getParentRoute: () => rootRouteImport,
39
39
  } as any)
40
40
  const InsightsDistributionRoute = InsightsDistributionRouteImport.update({
@@ -124,18 +124,11 @@ export interface RootRouteChildren {
124
124
 
125
125
  declare module '@tanstack/react-router' {
126
126
  interface FileRoutesByPath {
127
- '/installations': {
128
- id: '/installations'
129
- path: '/installations'
130
- fullPath: '/installations'
131
- preLoaderRoute: typeof InstallationsRouteImport
132
- parentRoute: typeof rootRouteImport
133
- }
134
- '/insights': {
135
- id: '/insights'
136
- path: '/insights'
137
- fullPath: '/insights'
138
- preLoaderRoute: typeof InsightsRouteImport
127
+ '/': {
128
+ id: '/'
129
+ path: '/'
130
+ fullPath: '/'
131
+ preLoaderRoute: typeof IndexRouteImport
139
132
  parentRoute: typeof rootRouteImport
140
133
  }
141
134
  '/api-keys': {
@@ -145,11 +138,18 @@ declare module '@tanstack/react-router' {
145
138
  preLoaderRoute: typeof ApiKeysRouteImport
146
139
  parentRoute: typeof rootRouteImport
147
140
  }
148
- '/': {
149
- id: '/'
150
- path: '/'
151
- fullPath: '/'
152
- preLoaderRoute: typeof IndexRouteImport
141
+ '/insights': {
142
+ id: '/insights'
143
+ path: '/insights'
144
+ fullPath: '/insights'
145
+ preLoaderRoute: typeof InsightsRouteImport
146
+ parentRoute: typeof rootRouteImport
147
+ }
148
+ '/installations': {
149
+ id: '/installations'
150
+ path: '/installations'
151
+ fullPath: '/installations'
152
+ preLoaderRoute: typeof InstallationsRouteImport
153
153
  parentRoute: typeof rootRouteImport
154
154
  }
155
155
  '/insights_/distribution': {
@@ -6,8 +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 { core, storagePlugin } = await prepareConfig(request);
10
- return downloadBundle(params.bundleId, { core, storagePlugin });
9
+ const { core, storage } = await prepareConfig(request);
10
+ return downloadBundle(params.bundleId, { core, storage });
11
11
  },
12
12
  },
13
13
  },
@@ -70,7 +70,7 @@ const createConsoleModulesPlugin = (mode: ConsoleModuleMode): Plugin => {
70
70
  );
71
71
  configFile = resolveFromRoot(
72
72
  root,
73
- mode.options.config ?? "hot-updater.config.ts",
73
+ mode.options.config ?? "console.config.ts",
74
74
  );
75
75
 
76
76
  writeFileIfChanged(
@@ -128,18 +128,27 @@ const createConsoleModulesPlugin = (mode: ConsoleModuleMode): Plugin => {
128
128
 
129
129
  if (id === resolvedVirtualConfigModuleId) {
130
130
  if (mode.type === "local") {
131
+ // hot-updater.config.ts's database, storage, and plugins, as the
132
+ // CLI loads them.
131
133
  return [
132
- 'import { loadConfig, loadHotUpdaterPlugins } from "@hot-updater/cli-tools";',
134
+ 'import { loadConfig } from "@hot-updater/cli-tools";',
133
135
  "export default async () => {",
134
- " const [config, plugins] = await Promise.all([",
135
- " loadConfig(null),",
136
- " loadHotUpdaterPlugins(),",
137
- " ]);",
136
+ " const config = await loadConfig(null);",
137
+ " if (config.database === undefined) {",
138
+ " throw new Error(",
139
+ ' "Set database in hot-updater.config.ts: the database your server runs on, such as d1Database(...), or standaloneRepository({ baseUrl }) to reach a self-hosted server through its admin API.",',
140
+ " );",
141
+ " }",
142
+ " if (config.storage === undefined) {",
143
+ " throw new Error(",
144
+ ' "Set storage in hot-updater.config.ts: where your server stores bundles, which the console reads, such as r2Storage(...).",',
145
+ " );",
146
+ " }",
138
147
  " return {",
139
- " console: { gitUrl: config.console.gitUrl },",
140
148
  " database: config.database,",
141
149
  " storage: config.storage,",
142
- " ...(plugins === undefined ? {} : { plugins }),",
150
+ " plugins: config.plugins,",
151
+ " console: { gitUrl: config.console.gitUrl },",
143
152
  " };",
144
153
  "};",
145
154
  ].join("\n");
package/src/vite.ts CHANGED
@@ -3,7 +3,9 @@ import type { PluginOption } from "vite";
3
3
  import { createHostedConsolePlugins } from "./vite-internal";
4
4
 
5
5
  export interface HotUpdaterConsolePluginOptions {
6
+ /** The console's auth module, `console.auth.ts` by default. */
6
7
  readonly auth?: string;
8
+ /** The module whose default export is `defineConsoleConfig(...)`, `console.config.ts` by default. */
7
9
  readonly config?: string;
8
10
  }
9
11
 
@@ -1 +0,0 @@
1
- import{Gr as e,Hr as t,Pn as n,Q as r,Z as i,dr as a,et as o}from"./sidebar-B45aMqRm.js";import{y as s}from"./preload-helper-BN-UkjOE.js";var c=e(t(),1),l=a();function u({label:e,children:t}){let a=(0,c.useId)(),[u,d]=(0,c.useState)(!1);return(0,l.jsxs)(i,{open:u,onOpenChange:d,triggerId:a,children:[(0,l.jsx)(o,{id:a,"aria-describedby":u?`${a}-description`:void 0,closeOnClick:!1,onClick:()=>d(e=>!e),render:(0,l.jsx)(n,{"aria-label":e,className:`size-11 sm:size-7`,size:`icon`,variant:`ghost`}),children:(0,l.jsx)(s,{})}),(0,l.jsx)(r,{id:`${a}-description`,role:`tooltip`,className:`max-w-64`,side:`bottom`,children:t})]})}export{u as t};
@@ -1 +0,0 @@
1
- import{A as e,At as t,B as n,F as r,Fn as i,Gn as a,Gr as o,Gt as s,H as c,Hn as l,Hr as u,I as d,In as f,It as p,Jn as m,L as h,Ln as g,Lt as _,M as v,Mt as y,N as b,Nt as x,O as S,Ot as C,Pt as w,Rn as T,U as E,Un as D,V as O,Vn as k,Vt as A,Wn as j,Xt as M,_n as N,at as P,cn as F,dr as I,en as L,er as R,j as z,jt as B,k as ee,kt as V,ot as H,p as U,qn as W,sn as G,vn as K,yn as te,zn as q}from"./sidebar-B45aMqRm.js";import{i as J,l as Y,s as ne}from"./console-features-api-yv7rm3DX.js";import{b as re,y as ie}from"./preload-helper-BN-UkjOE.js";import{c as ae,d as oe,u as se}from"./field-Bou7shoO.js";import{a as ce,i as le,n as ue,r as de}from"./useCompositeListItem-CF7vsfcA.js";import{s as fe}from"./card-DzCPSRsh.js";var X=I();function pe({error:e,fallbackTitle:t}){return ne(e)?(0,X.jsxs)(ae,{children:[(0,X.jsx)(ie,{"aria-hidden":`true`}),(0,X.jsx)(oe,{children:`Insights not installed`}),(0,X.jsx)(se,{children:e.message})]}):(0,X.jsxs)(ae,{variant:`destructive`,children:[(0,X.jsx)(fe,{"aria-hidden":`true`}),(0,X.jsx)(oe,{children:t}),(0,X.jsx)(se,{children:`Refresh to try again. If this keeps happening, check your Insights provider connection.`})]})}var Z=o(u()),me=Z.createContext(void 0);function he(){let e=Z.useContext(me);if(e===void 0)throw Error(a(64));return e}var ge=function(e){return e.activationDirection=`data-activation-direction`,e.orientation=`data-orientation`,e}({}),_e={tabActivationDirection:e=>({[ge.activationDirection]:e})},ve=Z.forwardRef(function(e,t){let{className:n,defaultValue:r=0,onValueChange:i,orientation:a=`horizontal`,render:o,value:c,style:l,...u}=e,d=e.defaultValue!==void 0,f=Z.useRef([]),[p,h]=Z.useState(()=>new Map),[_,v]=le({controlled:c,default:r,name:`Tabs`,state:`value`}),y=c!==void 0,[b,x]=Z.useState(()=>new Map),S=Z.useCallback(e=>{if(e===void 0)return null;for(let[t,n]of b.entries())if(n!=null&&e===(n.value??n.index))return t;return null},[b]),[C,w]=Z.useState(()=>({previousValue:_,tabActivationDirection:`none`})),{previousValue:T,tabActivationDirection:E}=C,D=E,O=!1;T!==_&&(D=ye(T,_,a,b),O=T!=null&&_!=null&&S(_)==null);let k=O?T:_,A=T!==k||E!==D;W(()=>{A&&w({previousValue:k,tabActivationDirection:D})},[k,A,D]);let j=m((e,t)=>{t.activationDirection=ye(_,e,a,b),i?.(e,t),!t.isCanceled&&v(e)}),N=m((e,t)=>{i?.(e,s(t,void 0,void 0,{activationDirection:`none`}))}),P=m((e,t)=>{h(n=>{if(n.get(e)===t)return n;let r=new Map(n);return r.set(e,t),r})}),F=m((e,t)=>{h(n=>{if(!n.has(e)||n.get(e)!==t)return n;let r=new Map(n);return r.delete(e),r})}),I=Z.useCallback(e=>p.get(e),[p]),R=Z.useCallback(e=>{for(let t of b.values())if(e===t?.value)return t?.id},[b]),z=Z.useMemo(()=>({getTabElementBySelectedValue:S,getTabIdByPanelValue:R,getTabPanelIdByValue:I,onValueChange:j,orientation:a,registerMountedTabPanel:P,setTabMap:x,unregisterMountedTabPanel:F,tabActivationDirection:D,value:_}),[S,R,I,j,a,P,x,F,D,_]),B=Z.useMemo(()=>{for(let e of b.values())if(e!=null&&e.value===_)return e},[b,_]),ee=Z.useMemo(()=>{for(let e of b.values())if(e!=null&&!e.disabled)return e.value},[b]),V=Z.useRef(!d),H=Z.useRef(d),U=Z.useRef(!1);W(()=>{if(y)return;function e(e,t){v(e),w(t=>t.previousValue===e&&t.tabActivationDirection===`none`?t:{previousValue:e,tabActivationDirection:`none`}),N(e,t),V.current=!1}if(b.size===0){if(!U.current||_===null)return;e(null,G);return}U.current=!0;let t=B?.disabled,n=B==null&&_!==null;if(!t&&_===r&&(H.current=!1),H.current&&t&&_===r)return;let i=V.current;if(t||n){let n=ee??null;if(_===n){V.current=!1;return}let r=G;i?r=L:t&&(r=M),e(n,r);return}i&&B!=null&&(N(_,L),V.current=!1)},[r,ee,y,N,B,v,b,_]);let K=g(`div`,e,{state:{orientation:a,tabActivationDirection:D},ref:t,props:u,stateAttributesMapping:_e});return(0,X.jsx)(me.Provider,{value:z,children:(0,X.jsx)(de,{elementsRef:f,children:K})})});function ye(e,t,n,r){if(e==null||t==null)return`none`;let i=null,a=null;for(let[n,o]of r.entries()){if(o==null)continue;let r=o.value??o.index;if(e===r&&(i=n),t===r&&(a=n),i!=null&&a!=null)break}if(i==null||a==null)return i!==a&&(typeof e==`number`||typeof e==`string`)&&typeof e==typeof t?n===`horizontal`?t>e?`right`:`left`:t>e?`down`:`up`:`none`;let o=i.getBoundingClientRect(),s=a.getBoundingClientRect();if(n===`horizontal`){if(s.left<o.left)return`left`;if(s.left>o.left)return`right`}else{if(s.top<o.top)return`up`;if(s.top>o.top)return`down`}return`none`}var be=`data-composite-item-active`;function xe(e={}){let{highlightItemOnHover:t,highlightedIndex:n,onHighlightedIndexChange:r}=j(),{ref:i,index:a}=ue(e),o=n===a,s=Z.useRef(null),c=k(i,s);return{compositeProps:Z.useMemo(()=>({tabIndex:o?0:-1,onFocus(){r(a)},onMouseMove(){let e=s.current;if(!t||!e)return;let n=e.hasAttribute(`disabled`)||e.ariaDisabled===`true`;!o&&!n&&e.focus()}}),[o,r,a,t]),compositeRef:c,index:a}}var Se=Z.createContext(void 0);function Ce(){let e=Z.useContext(Se);if(e===void 0)throw Error(a(65));return e}var we=Z.forwardRef(function(e,t){let{className:n,disabled:r=!1,render:i,value:a,id:o,nativeButton:c=!0,style:u,...d}=e,{value:f,getTabPanelIdByValue:p,orientation:m}=he(),{activateOnFocus:h,highlightedTabIndex:_,onTabActivation:v,registerTabResizeObserverElement:y,setHighlightedTabIndex:b,tabsListElement:x}=Ce(),S=H(o),{compositeProps:C,compositeRef:w,index:T}=xe({metadata:Z.useMemo(()=>({disabled:r,id:S,value:a}),[r,S,a])}),E=a===f,D=Z.useRef(!1),O=Z.useRef(null);Z.useEffect(()=>{let e=O.current;if(e)return y(e)},[y]),W(()=>{if(D.current){D.current=!1;return}if(!(E&&T>-1&&_!==T))return;let e=x;if(e!=null){let t=N(A(e));if(t&&K(e,t))return}r||b(T)},[E,T,_,b,r,x]);let{getButtonProps:k,buttonRef:j}=l({disabled:r,native:c,focusableWhenDisabled:!0}),M=p(a),P=Z.useRef(!1),I=Z.useRef(!1);function L(e){E||r||v(a,s(F,e.nativeEvent,void 0,{activationDirection:`none`}))}function R(e){E||(T>-1&&!r&&b(T),!r&&h&&(!P.current||P.current&&I.current)&&v(a,s(F,e.nativeEvent,void 0,{activationDirection:`none`})))}function z(e){if(E||r)return;P.current=!0;function t(){P.current=!1,I.current=!1}(!e.button||e.button===0)&&(I.current=!0,A(e.currentTarget).addEventListener(`pointerup`,t,{once:!0}))}return g(`button`,e,{state:{disabled:r,active:E,orientation:m},ref:[t,j,w,O],props:[C,{role:`tab`,"aria-controls":M,"aria-selected":E,id:S,onClick:L,onFocus:R,onPointerDown:z,[be]:E?``:void 0,onKeyDownCapture(){D.current=!0}},d,k]})});function Te(e){return e==null||e.hasAttribute(`disabled`)||e.getAttribute(`aria-disabled`)===`true`}var Ee=[];function De(i){let{itemSizes:a,cols:o=1,loopFocus:s=!0,onLoop:l,dense:u=!1,orientation:f=`both`,direction:h,highlightedIndex:g,onHighlightedIndexChange:T,rootRef:D,enableHomeAndEndKeys:A=!1,stopEventPropagation:j=!1,disabledIndices:M,modifierKeys:N=Ee}=i,[P,F]=Z.useState(0),I=o>1,L=Z.useRef(null),R=k(L,D),H=Z.useRef([]),U=Z.useRef(!1),W=g??P,G=m((e,t=!1)=>{if((T??F)(e),t){let t=H.current[e];E(L.current,t,h,f)}}),K=m(e=>{if(e.size===0||U.current)return;U.current=!0;let t=Array.from(e.keys()),n=t.find(e=>e?.hasAttribute(`data-composite-item-active`))??null,r=n?t.indexOf(n):-1;r!==-1&&G(r),E(L.current,n,h,f)}),q=m((e,t,n)=>l?l?.(e,t,n,H):n),J=Z.useMemo(()=>({"aria-orientation":f===`both`?void 0:f,ref:R,onFocus(e){let t=L.current,n=te(e.nativeEvent);!t||n==null||!c(n)||n.setSelectionRange(0,n.value.length??0)},onKeyDown(i){let m=A?b:ee;if(!m.has(i.key)||Oe(i,N)||!L.current)return;let g=h===`rtl`,T=g?e:z,E={horizontal:T,vertical:S,both:T}[f],D=g?z:e,k={horizontal:D,vertical:v,both:D}[f],P=te(i.nativeEvent);if(P!=null&&c(P)&&!Te(P)){let e=P.selectionStart,t=P.selectionEnd,n=P.value??``;if(e==null||i.shiftKey||e!==t||i.key!==k&&e<n.length||i.key!==E&&e>0)return}let F=W,R=w(H,M),U=x(H,M);if(I){let e=a||Array.from({length:H.current.length},()=>({width:1,height:1})),n=C(e,o,u),r=n.findIndex(e=>e!=null&&!_(H.current,e,M)),c=n.reduce((e,t,n)=>t!=null&&!_(H.current,t,M)?n:e,-1);F=n[y(n.map(e=>e==null?null:H.current[e]),{event:i,orientation:f,loopFocus:s,onLoop:q,cols:o,disabledIndices:B([...M||H.current.map((e,t)=>_(H.current,t)?t:void 0),void 0],n),minIndex:r,maxIndex:c,prevIndex:t(W>U?R:W,e,n,o,i.key===`ArrowDown`?`bl`:i.key===`ArrowRight`?`tr`:`tl`),rtl:g})]}let K={horizontal:[T],vertical:[S],both:[T,S]}[f],J={horizontal:[D],vertical:[v],both:[D,v]}[f],Y=I?m:{horizontal:A?d:r,vertical:A?O:n,both:m}[f];A&&(i.key===`Home`?F=R:i.key===`End`&&(F=U)),F===W&&(K.includes(i.key)||J.includes(i.key))&&(s&&F===U&&K.includes(i.key)?(F=R,l&&(F=l(i,W,F,H))):s&&F===R&&J.includes(i.key)?(F=U,l&&(F=l(i,W,F,H))):F=V(H.current,{startingIndex:F,decrement:J.includes(i.key),disabledIndices:M})),F!==W&&!p(H.current,F)&&(j&&i.stopPropagation(),Y.has(i.key)&&i.preventDefault(),G(F,!0),queueMicrotask(()=>{H.current[F]?.focus()}))}}),[o,u,h,M,H,A,W,I,a,s,l,q,R,N,G,f,j]);return Z.useMemo(()=>({props:J,highlightedIndex:W,onHighlightedIndexChange:G,elementsRef:H,disabledIndices:M,onMapChange:K,relayKeyboardEvent:J.onKeyDown}),[J,W,G,H,M,K])}function Oe(e,t){for(let n of h.values())if(!t.includes(n)&&e.getModifierState(n))return!0;return!1}function ke(e){let{render:t,className:n,style:r,refs:i=T,props:a=T,state:o=q,stateAttributesMapping:s,highlightedIndex:c,onHighlightedIndexChange:l,orientation:u,dense:d,itemSizes:f,loopFocus:p,onLoop:m,cols:h,enableHomeAndEndKeys:_,onMapChange:v,stopEventPropagation:y=!0,rootRef:b,disabledIndices:x,modifierKeys:S,highlightItemOnHover:C=!1,tag:w=`div`,...E}=e,{props:O,highlightedIndex:k,onHighlightedIndexChange:A,elementsRef:j,onMapChange:M,relayKeyboardEvent:N}=De({itemSizes:f,cols:h,loopFocus:p,onLoop:m,dense:d,orientation:u,highlightedIndex:c,onHighlightedIndexChange:l,rootRef:b,stopEventPropagation:y,enableHomeAndEndKeys:_,direction:P(),disabledIndices:x,modifierKeys:S}),F=g(w,e,{state:o,ref:i,props:[O,...a,E],stateAttributesMapping:s}),I=Z.useMemo(()=>({highlightedIndex:k,onHighlightedIndexChange:A,highlightItemOnHover:C,relayKeyboardEvent:N}),[k,A,C,N]);return(0,X.jsx)(D.Provider,{value:I,children:(0,X.jsx)(de,{elementsRef:j,onMapChange:e=>{v?.(e),M(e)},children:F})})}var Ae=Z.forwardRef(function(e,t){let{activateOnFocus:n=!1,className:r,loopFocus:i=!0,render:a,style:o,...s}=e,{onValueChange:c,orientation:l,value:u,setTabMap:d,tabActivationDirection:f}=he(),[p,h]=Z.useState(0),[g,_]=Z.useState(null),v=Z.useRef(new Set),y=Z.useRef(new Set),b=Z.useRef(null);Z.useEffect(()=>{if(typeof ResizeObserver>`u`)return;let e=new ResizeObserver(()=>{v.current.forEach(e=>{e()})});return b.current=e,g&&e.observe(g),y.current.forEach(t=>{e.observe(t)}),()=>{e.disconnect(),b.current=null}},[g]);let x=m(e=>(v.current.add(e),()=>{v.current.delete(e)})),S=m(e=>(y.current.add(e),b.current?.observe(e),()=>{y.current.delete(e),b.current?.unobserve(e)})),C=m((e,t)=>{e!==u&&c(e,t)}),w={orientation:l,tabActivationDirection:f},E={"aria-orientation":l===`vertical`?`vertical`:void 0,role:`tablist`},D=Z.useMemo(()=>({activateOnFocus:n,highlightedTabIndex:p,registerIndicatorUpdateListener:x,registerTabResizeObserverElement:S,onTabActivation:C,setHighlightedTabIndex:h,tabsListElement:g}),[n,p,x,S,C,h,g]);return(0,X.jsx)(Se.Provider,{value:D,children:(0,X.jsx)(ke,{render:a,className:r,style:o,state:w,refs:[t,_],props:[E,s],stateAttributesMapping:_e,highlightedIndex:p,enableHomeAndEndKeys:!0,loopFocus:i,orientation:l,onHighlightedIndexChange:h,onMapChange:d,disabledIndices:T})})});function je({className:e,orientation:t=`horizontal`,...n}){return(0,X.jsx)(ve,{orientation:t,"data-slot":`tabs`,"data-orientation":t,className:R(`group/tabs flex gap-2 data-horizontal:flex-col`,e),...n})}var Me=f(`group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none`,{variants:{variant:{default:`bg-muted`,line:`gap-1 bg-transparent`}},defaultVariants:{variant:`default`}});function Ne({className:e,variant:t=`default`,...n}){return(0,X.jsx)(Ae,{"data-slot":`tabs-list`,"data-variant":t,className:R(Me({variant:t}),e),...n})}function Pe({className:e,...t}){return(0,X.jsx)(we,{"data-slot":`tabs-trigger`,className:R(`relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-xs font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start group-data-vertical/tabs:py-[calc(--spacing(1.25))] hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 has-data-[icon=inline-end]:pr-1 has-data-[icon=inline-start]:pl-1 aria-disabled:pointer-events-none aria-disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5`,`group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent`,`data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground`,`after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100`,e),...t})}var Q={"24h":{label:`DAU`,period:`24 hours`,interval:`hour`},"7d":{label:`WAU`,period:`7 days`,interval:`6 hours`},"30d":{label:`MAU`,period:`30 days`,interval:`day`},"12m":{label:`YAU`,period:`12 months`,interval:`week`}};function $({label:e,onPeriodChange:t,period:n,periods:r}){return(0,X.jsx)(je,{value:n,onValueChange:e=>{let n=r.find(t=>t.value===e);n&&t(n.value)},children:(0,X.jsx)(Ne,{"aria-label":e,className:`min-h-11 sm:min-h-9`,children:r.map(({value:e,name:t})=>(0,X.jsx)(Pe,{value:e,"aria-label":t,className:`min-w-12 px-3`,children:e},e))})})}var Fe=[`24h`,`7d`,`30d`].map(e=>({value:e,name:Q[e].period})),Ie=Object.keys(Q).map(e=>({value:e,name:Q[e].period}));function Le({window:e,onWindowChange:t}){return(0,X.jsx)($,{label:`Reporting period`,onPeriodChange:t,period:e,periods:Fe})}function Re({window:e,onWindowChange:t,twelveMonths:n=!0}){return(0,X.jsx)($,{label:`Reporting period`,onPeriodChange:t,period:e,periods:Ie.filter(({value:e})=>n||e!==`12m`)})}function ze({view:e,overviewSearch:t}){let n=J(`insightsAnalytics`);return(0,X.jsxs)(`header`,{className:`sticky top-0 z-10 flex shrink-0 flex-wrap items-center gap-3 border-b bg-background px-3 py-3 sm:bg-card/70 sm:px-4 sm:backdrop-blur-sm`,children:[(0,X.jsx)(U,{className:`-ml-1 size-11 lg:size-7`}),(0,X.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,X.jsx)(re,{"aria-hidden":`true`,className:`size-3.5 text-muted-foreground`}),(0,X.jsx)(`h1`,{className:`text-sm font-medium`,children:`Insights`})]}),(0,X.jsxs)(`nav`,{"aria-label":`Insights views`,className:`ml-auto flex gap-2`,children:[n?(0,X.jsx)(Y,{"aria-current":e===`overview`?`page`:void 0,className:R(i({className:`h-11 px-3 lg:h-8 lg:px-2.5`,size:`lg`,variant:e===`overview`?`secondary`:`ghost`})),search:t,to:`/insights`,children:`Overview`}):null,(0,X.jsxs)(Y,{"aria-current":e===`events`?`page`:void 0,className:R(i({className:`h-11 px-3 lg:h-8 lg:px-2.5`,size:`lg`,variant:e===`events`?`secondary`:`ghost`})),to:`/installations`,children:[(0,X.jsx)(ce,{"aria-hidden":`true`,"data-icon":`inline-start`}),`All events`]})]})]})}export{Q as a,Re as i,Le as n,pe as o,$ as r,ze as t};
@@ -1 +0,0 @@
1
- import{ar as e,cr as t,jr as n,nr as r,rr as i,ur as a}from"./sidebar-B45aMqRm.js";import{t as o}from"./useMutation-CN1ygYEr.js";var s=e(`arrow-right`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`m12 5 7 7-7 7`,key:`xquz4c`}]]),c=e(`chevron-right`,[[`path`,{d:`m9 18 6-6-6-6`,key:`mthhwq`}]]),l=i({method:`GET`}).middleware([r]).handler(n(`206547cb1526f961070a989818ca7b9e34f6b2b0e4ab851698c3807fe9fb5e0c`)),u=i({method:`GET`}).middleware([r]).handler(n(`a6f23116eeaf76166d405e28a95213123025613c6603030894e519015bf48032`)),d=i({method:`POST`}).middleware([r]).handler(n(`7ea0186f19f9f2bc2ca4b26e3c59636891cf046957f84287b6783f8d88bd8cb7`)),f=i({method:`POST`}).middleware([r]).handler(n(`b46c95dba95a6a3e8fa5c9d100e3622fa5ae7af4f38e10fb1ed2fa48289a3a8f`)),p=i({method:`POST`}).middleware([r]).handler(n(`d5b58722ce514e3b63a377f736b4823c2011782495442ae4870ed547e392c70b`)),m=i({method:`POST`}).middleware([r]).handler(n(`956539a300d79a7efa191c1cc2d529d62fc4bfd940442548fdbc1404e0d53078`)),h=i({method:`GET`}).middleware([r]).handler(n(`e8c24b7247936f045a145ffd5c177fd0e3df3b52769d67dfbd8d1de491d66396`)),g=i().middleware([r]).handler(n(`51a34c05479a893c7d320bd4cd1604427289d667698c48b9f30a01aabf8a5e68`)),_=i().middleware([r]).handler(n(`79ada05964de8f2123bfcd62b10097d59bf8fd689ef5c7161031e5871d8396c5`)),v=i({method:`POST`}).middleware([r]).handler(n(`2b9b8d1f49f79a511589617d8d4bfc6094a3acf5264f33651b9569ba66d3f321`)),y=i({method:`POST`}).middleware([r]).handler(n(`52756dde414919a906bfe83d1ab6d29910c63bcafdb47653d6f1df562d958920`));i().middleware([r]).handler(n(`f8bdca3d0579adb812d6404f55d9261a89cdb025e920b1fcad82883646a5fe9e`)),i({method:`GET`}).middleware([r]).handler(n(`00ccacb4a0212c83ec29f4d11719046ad91ea8291cfc557d514dbf00d3bd7f5f`));var b=i({method:`GET`}).middleware([r]).handler(n(`1bd85c2a50e24785cb6abb023a247a9f048f37ddfa85cbb1c57e579563bad013`)),x=i({method:`GET`}).middleware([r]).handler(n(`4370f1bf70b91f1168d85379d3008449a1bedb915e9878ca4ef89d5f3a80fa7f`)),S=i({method:`GET`}).middleware([r]).handler(n(`4ca367070b00f58179a572f0bb8196a4ccdd3881e9b1dbfe33deee0cb6e1f549`));i({method:`POST`}).middleware([r]).handler(n(`3a27ff5679228b86a346b3fe42142e7a5bf0264f73173c0dbe5f07fb37c43cf7`)),i({method:`POST`}).middleware([r]).handler(n(`61de3b69779c5ce2a5f5d3c27e2cfaca8fba8f14c8803559b9cd733c456494fa`));var C=[`bundles`],w=[`releases`],T={config:[`config`],channels:[`channels`],configLoaded:[`config-loaded`],bundles:{all:C,list:e=>[...C,e??{}]},releases:{all:w,list:e=>[...w,e??{}]},release:e=>[`release`,e],releaseCatalog:e=>[`release-catalog`,e],bundleChildren:{all:[`bundle-children`],list:e=>[`bundle-children`,e],counts:e=>[`bundle-children`,`counts`,...e]},bundle:e=>[`bundle`,e]};function E(){return t({queryKey:T.config,queryFn:()=>g(),staleTime:1/0})}function D(){return t({queryKey:T.channels,queryFn:()=>_(),staleTime:1/0})}function O(e){return t({queryKey:T.releases.list(e),queryFn:()=>l({data:e}),placeholderData:e=>e})}function k(e){return t({enabled:e.length>0,queryFn:()=>u({data:{releaseId:e}}),queryKey:T.release(e)})}function A(e){return t({enabled:e.length>0,queryFn:()=>h({data:{scopeKey:e}}),queryKey:T.releaseCatalog(e)})}function j(e){return t({queryKey:T.bundle(e),queryFn:()=>b({data:{bundleId:e}}),staleTime:1/0,enabled:!!e})}function M(e){return t({queryKey:T.bundleChildren.list(e),queryFn:()=>x({data:{baseBundleId:e}}),staleTime:1/0,enabled:!!e})}function N(e){let n=[...e].sort((e,t)=>e.localeCompare(t));return t({queryKey:T.bundleChildren.counts(n),queryFn:()=>S({data:{bundleIds:n}}),staleTime:1/0,enabled:n.length>0})}function P(){let e=a();return o({mutationFn:e=>v({data:e}).then(e=>e.data),onSuccess:async()=>{await e.invalidateQueries({queryKey:T.channels})}})}function F(){let e=a();return o({mutationFn:e=>y({data:e}).then(e=>e.data),onSettled:async()=>{await e.invalidateQueries({queryKey:T.channels})}})}function I(){let e=a();return o({mutationFn:e=>d({data:e}),onSuccess:async(t,n)=>{await Promise.all([e.invalidateQueries({queryKey:T.releases.all}),e.invalidateQueries({queryKey:T.release(n.releaseId)}),e.invalidateQueries({queryKey:[`release-catalog`]}),e.invalidateQueries({queryKey:T.channels})])}})}function L(){return o({mutationFn:e=>f({data:e})})}function R(){let e=a();return o({mutationFn:e=>p({data:e}),onSuccess:async(t,n)=>{e.removeQueries({queryKey:T.release(n.releaseId)}),await Promise.all([e.invalidateQueries({queryKey:T.releases.all}),e.invalidateQueries({queryKey:[`release-catalog`]}),e.invalidateQueries({queryKey:T.channels})])}})}function z(){let e=a();return o({mutationFn:e=>m({data:e}),onSuccess:async()=>{await Promise.all([e.invalidateQueries({queryKey:T.releases.all}),e.invalidateQueries({queryKey:[`release`]}),e.invalidateQueries({queryKey:[`release-catalog`]}),e.invalidateQueries({queryKey:T.channels})])}})}export{E as a,R as c,A as d,k as f,s as g,c as h,D as i,L as l,I as m,M as n,P as o,O as p,j as r,F as s,N as t,z as u};
@@ -1 +0,0 @@
1
- import{$n as e,Gr as t,Hr as n,Pn as r,Y as i,ar as a,cr as o,dr as s,jr as c,nr as l,p as u,rr as d,ur as f}from"./sidebar-B45aMqRm.js";import{t as p}from"./useMutation-CN1ygYEr.js";import{a as m,c as ee,d as te,f as ne,i as h,l as g,n as _,r as v,s as y,t as b,u as x}from"./field-Bou7shoO.js";import{n as S,t as re}from"./loader-circle-Ca7C9YY1.js";import{_ as ie,a as ae,c as C,d as w,f as T,g as E,h as D,i as O,l as k,m as A,n as j,o as M,p as N,r as P,t as F,u as I,v as L}from"./dialog-BDvCy_QO.js";import{t as R}from"./refresh-cw-CVGqvy8Z.js";import{a as z,n as B,o as V,s as oe,t as H}from"./card-DzCPSRsh.js";import{n as U}from"./dist-Clb6cQ9l.js";import{a as W,i as G,n as K,o as q,r as J,t as se}from"./table-CwLnN6KX.js";var ce=a(`clipboard`,[[`rect`,{width:`8`,height:`4`,x:`8`,y:`2`,rx:`1`,ry:`1`,key:`tgr4d6`}],[`path`,{d:`M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2`,key:`116196`}]]),Y=a(`shield-off`,[[`path`,{d:`m2 2 20 20`,key:`1ooewy`}],[`path`,{d:`M5 5a1 1 0 0 0-1 1v7c0 5 3.5 7.5 7.67 8.94a1 1 0 0 0 .67.01c2.35-.82 4.48-1.97 5.9-3.71`,key:`1jlk70`}],[`path`,{d:`M9.309 3.652A12.252 12.252 0 0 0 11.24 2.28a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1v7a9.784 9.784 0 0 1-.08 1.264`,key:`18rp1v`}]]),X=t(n(),1),Z=d({method:`GET`}).middleware([l]).handler(c(`2c7f3cdb9bd3cab2c026a48abdc84c362db0362924a08679052a325640aec56b`)),le=d({method:`POST`}).middleware([l]).handler(c(`68a2d94ee016be64936401f5eba60ab08a47ff373e1cf9de48e4413336e6034b`)),ue=d({method:`POST`}).middleware([l]).handler(c(`a1cb80b19ca72a64fb631ca28ebb9b6941db245983de082d5dd3203ec2eef795`)),Q={list:[`api-keys`,`list`]},de=()=>o({queryKey:Q.list,queryFn:()=>Z()}),fe=()=>{let e=f();return p({mutationFn:e=>le({data:{name:e}}),onSuccess:async()=>{await e.invalidateQueries({queryKey:Q.list})}})},pe=()=>{let e=f();return p({mutationFn:e=>ue({data:{id:e}}),onSuccess:async()=>{await e.invalidateQueries({queryKey:Q.list})}})},$=s(),me=e=>new Date(e).toISOString().slice(0,10);function he(){let[e,t]=(0,X.useState)(!1),[n,a]=(0,X.useState)(``),[o,s]=(0,X.useState)(null),c=fe(),l=n.trim(),u=l.length>64?`Name must be 64 characters or fewer.`:null,d=()=>{a(``),s(null),c.reset()},f=e=>{t(e),e||d()};return(0,$.jsxs)($.Fragment,{children:[(0,$.jsxs)(r,{onClick:()=>t(!0),children:[(0,$.jsx)(L,{"data-icon":`inline-start`}),`Create API key`]}),(0,$.jsx)(F,{open:e,onOpenChange:f,children:(0,$.jsxs)(j,{showCloseButton:o===null,children:[(0,$.jsxs)(ae,{children:[(0,$.jsx)(M,{children:o===null?`Create API key`:`Save your API key`}),(0,$.jsx)(P,{children:o===null?`Name the app or environment that will use this key.`:`This key is shown once. Store it securely before closing.`})]}),o===null?(0,$.jsxs)(`form`,{onSubmit:async e=>{if(e.preventDefault(),!(l.length===0||u!==null))try{s((await c.mutateAsync(l)).apiKey),U.success(`API key created`)}catch(e){U.error(e instanceof Error?e.message:`Unable to create API key`)}},children:[(0,$.jsx)(h,{children:(0,$.jsxs)(b,{"data-invalid":u!==null||void 0,children:[(0,$.jsx)(m,{htmlFor:`api-key-name`,children:`Name`}),(0,$.jsx)(i,{id:`api-key-name`,autoComplete:`off`,maxLength:65,onChange:e=>a(e.target.value),placeholder:`Production app`,value:n}),(0,$.jsx)(_,{children:`Use a name you can identify before revoking the key.`}),(0,$.jsx)(v,{children:u})]})}),(0,$.jsx)(O,{className:`mt-4`,children:(0,$.jsxs)(r,{disabled:c.isPending||l.length===0||u!==null,type:`submit`,children:[c.isPending?(0,$.jsx)(re,{"data-icon":`inline-start`,className:`animate-spin`}):(0,$.jsx)(S,{"data-icon":`inline-start`}),`Create API key`]})})]}):(0,$.jsxs)(h,{children:[(0,$.jsxs)(b,{children:[(0,$.jsx)(m,{htmlFor:`created-api-key`,children:`API key`}),(0,$.jsxs)(`div`,{className:`flex gap-2`,children:[(0,$.jsx)(i,{id:`created-api-key`,className:`font-mono`,readOnly:!0,value:o}),(0,$.jsxs)(r,{onClick:async()=>{if(o!==null)try{await navigator.clipboard.writeText(o),U.success(`API key copied`)}catch{U.error(`Unable to copy API key`)}},type:`button`,variant:`outline`,children:[(0,$.jsx)(ce,{"data-icon":`inline-start`}),`Copy`]})]})]}),(0,$.jsx)(O,{children:(0,$.jsxs)(r,{onClick:()=>f(!1),children:[(0,$.jsx)(ne,{"data-icon":`inline-start`}),`Done`]})})]})]})})]})}function ge({record:e}){let[t,n]=(0,X.useState)(!1),i=pe(),a=async t=>{t.preventDefault();try{await i.mutateAsync(e.id),n(!1),U.success(`API key revoked`)}catch(e){U.error(e instanceof Error?e.message:`Unable to revoke API key`)}};return(0,$.jsxs)(C,{open:t,onOpenChange:e=>{i.isPending||n(e)},children:[(0,$.jsxs)(ie,{render:(0,$.jsx)(r,{size:`sm`,variant:`ghost`}),children:[(0,$.jsx)(Y,{"data-icon":`inline-start`}),`Revoke`]}),(0,$.jsxs)(w,{children:[(0,$.jsxs)(A,{children:[(0,$.jsx)(D,{children:(0,$.jsx)(Y,{})}),(0,$.jsxs)(E,{children:[`Revoke `,e.name,`?`]}),(0,$.jsxs)(T,{children:[`Apps using `,e.prefix,`… will immediately lose OTA update and insights access. This action cannot be undone.`]})]}),(0,$.jsxs)(N,{children:[(0,$.jsx)(I,{disabled:i.isPending,children:`Cancel`}),(0,$.jsx)(k,{disabled:i.isPending,onClick:e=>void a(e),variant:`destructive`,children:`Revoke API key`})]})]})]})}function _e(){let t=de();return(0,$.jsxs)(H,{className:`overflow-hidden shadow-sm`,children:[(0,$.jsxs)(z,{className:`flex-row items-center justify-between space-y-0 border-b px-4 py-3`,children:[(0,$.jsx)(V,{className:`text-sm`,children:(0,$.jsx)(`h2`,{children:`API keys`})}),(0,$.jsx)(he,{})]}),(0,$.jsx)(B,{className:`p-0`,children:t.isError?(0,$.jsx)(`div`,{className:`p-4`,children:(0,$.jsxs)(ee,{variant:`destructive`,children:[(0,$.jsx)(oe,{}),(0,$.jsx)(te,{children:`API keys couldn't be loaded`}),(0,$.jsx)(x,{children:`Check your connection and try again.`}),(0,$.jsx)(g,{children:(0,$.jsxs)(r,{onClick:()=>void t.refetch(),size:`xs`,variant:`outline`,children:[(0,$.jsx)(R,{"data-icon":`inline-start`}),`Retry`]})})]})}):(0,$.jsxs)(se,{"aria-label":`API keys`,className:`table-fixed`,children:[(0,$.jsx)(W,{children:(0,$.jsxs)(q,{children:[(0,$.jsx)(G,{children:`Key`}),(0,$.jsx)(G,{className:`w-32`,children:`Created`}),(0,$.jsx)(G,{className:`w-24 text-right`,children:(0,$.jsx)(`span`,{className:`sr-only`,children:`Actions`})})]})}),(0,$.jsx)(K,{children:t.isLoading?Array.from({length:3},(t,n)=>(0,$.jsxs)(q,{children:[(0,$.jsxs)(J,{className:`space-y-2 py-3`,children:[n===0?(0,$.jsx)(`span`,{className:`sr-only`,children:`Loading API keys`}):null,(0,$.jsx)(e,{className:`h-3.5 w-32`}),(0,$.jsx)(e,{className:`h-3 w-20`})]}),(0,$.jsx)(J,{children:(0,$.jsx)(e,{className:`h-3.5 w-20`})}),(0,$.jsx)(J,{children:(0,$.jsx)(e,{className:`ml-auto h-6 w-16`})})]},n)):t.data?.length===0?(0,$.jsx)(q,{children:(0,$.jsx)(J,{colSpan:3,className:`h-40 text-center text-muted-foreground`,children:(0,$.jsxs)(`div`,{className:`mx-auto flex max-w-xs flex-col items-center gap-2`,children:[(0,$.jsx)(S,{className:`size-5`}),(0,$.jsx)(`p`,{className:`font-medium text-foreground`,children:`No API keys`}),(0,$.jsx)(`p`,{children:`Create an API key to connect an app.`})]})})}):t.data?.map(e=>(0,$.jsxs)(q,{className:e.revoked_at_ms===null?void 0:`text-muted-foreground`,children:[(0,$.jsx)(J,{className:`whitespace-normal py-3`,children:(0,$.jsxs)(`div`,{className:`min-w-0 space-y-1`,children:[(0,$.jsx)(`p`,{className:`break-words font-medium text-foreground`,children:e.name}),(0,$.jsxs)(`p`,{className:`font-mono text-xs text-muted-foreground`,children:[e.prefix,`…`]})]})}),(0,$.jsx)(J,{className:`text-xs text-muted-foreground`,children:(0,$.jsx)(`time`,{dateTime:new Date(e.created_at_ms).toISOString(),children:me(e.created_at_ms)})}),(0,$.jsx)(J,{className:`text-right`,children:e.revoked_at_ms===null?(0,$.jsx)(ge,{record:e}):(0,$.jsx)(y,{variant:`outline`,children:`Revoked`})})]},e.id))})]})})]})}function ve(){return(0,$.jsxs)(`div`,{className:`flex h-svh min-h-0 flex-col`,children:[(0,$.jsxs)(`header`,{className:`sticky top-0 z-10 flex shrink-0 flex-wrap items-center gap-x-3 gap-y-1 border-b bg-background px-3 py-3 sm:min-h-12 sm:flex-nowrap sm:bg-card/70 sm:px-4 sm:backdrop-blur-sm`,children:[(0,$.jsx)(u,{className:`-ml-1`}),(0,$.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,$.jsx)(S,{"aria-hidden":`true`,className:`size-3.5 text-muted-foreground`}),(0,$.jsx)(`h1`,{className:`text-sm font-medium`,children:`API keys`})]}),(0,$.jsx)(`p`,{className:`basis-full pl-9 text-xs text-muted-foreground sm:basis-auto sm:pl-0`,children:`API keys can download OTA updates and submit insights only.`})]}),(0,$.jsx)(`div`,{className:`min-h-0 min-w-0 flex-1 overflow-y-auto bg-muted/5 p-3 sm:p-6`,children:(0,$.jsx)(`div`,{className:`mx-auto w-full max-w-5xl`,children:(0,$.jsx)(_e,{})})})]})}export{ve as component};
@@ -1 +0,0 @@
1
- import{t as e}from"./ConsoleFeatureUnavailable-B9VYGA3N.js";var t=e;export{t as notFoundComponent};