@hot-updater/console 1.0.0-rc.0 → 1.0.0-rc.2
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.
- package/.output/nitro.json +1 -1
- package/.output/public/assets/HashValueDisplay-CB0Eskit.js +1 -0
- package/.output/public/assets/InsightsPageHeader-Car5LNiZ.js +1 -0
- package/.output/public/assets/api-keys-BzKocqRy.js +1 -0
- package/.output/public/assets/api-keys-api-BHcODB7q.js +1 -0
- package/.output/public/assets/card-Dhr_eFYj.js +1 -0
- package/.output/public/assets/{chart-no-axes-combined-FaYMGmQS.js → chart-no-axes-combined-Dy4WJv2U.js} +1 -1
- package/.output/public/assets/composite-Bp98A0Ld.js +1 -0
- package/.output/public/assets/createServerFn-CA8fs7QD.js +3 -0
- package/.output/public/assets/dialog-CUTrcPlB.js +1 -0
- package/.output/public/assets/{dist-DspNKfMj.js → dist-C_NydL0e.js} +1 -1
- package/.output/public/assets/index-DdAz-CXv.js +10 -0
- package/.output/public/assets/input-group-cSOG4wh_.js +1 -0
- package/.output/public/assets/insights-C0PBSZ-n.js +1 -0
- package/.output/public/assets/installations-CE33wgbY.js +2 -0
- package/.output/public/assets/installations-CStZja8x.js +1 -0
- package/.output/public/assets/lazyRouteComponent-Ccp3bwBY.js +1 -0
- package/.output/public/assets/link-CI8idAUi.js +1 -0
- package/.output/public/assets/loader-circle-BoxLrsOu.js +1 -0
- package/.output/public/assets/refresh-cw-Bqc72UZG.js +1 -0
- package/.output/public/assets/{routes-DcQnVajO.js → routes-DGVXdzpw.js} +2 -2
- package/.output/public/assets/routes-DTlwOr8I.js +1 -0
- package/.output/public/assets/{shield-check-DE_hVuHu.js → shield-check-uK3MHWJZ.js} +1 -1
- package/.output/public/assets/signing-CMf4aqDO.js +1 -0
- package/.output/public/assets/styles-BCvbtKsm.css +2 -0
- package/.output/public/assets/table-2vcV89QB.js +1 -0
- package/.output/public/assets/useCompositeListItem-CHLITE_4.js +1 -0
- package/.output/public/assets/x-DCd0j8c6.js +1 -0
- package/.output/server/{__23tanstack-start-server-fn-resolver-DBP9TQ7K.mjs → __23tanstack-start-server-fn-resolver-B7ioJhtE.mjs} +44 -52
- package/.output/server/_libs/@base-ui/react+[...].mjs +1906 -4040
- package/.output/server/_libs/@tanstack/react-router+[...].mjs +52 -4
- package/.output/server/_libs/@tanstack/react-router-ssr-query+[...].mjs +2 -2
- package/.output/server/_libs/lucide-react.mjs +36 -3
- package/.output/server/_libs/next-themes.mjs +2 -2
- package/.output/server/_libs/sonner.mjs +2 -2
- package/.output/server/_libs/tanstack__react-query.mjs +2 -2
- package/.output/server/_libs/verkit.mjs +20 -15
- package/.output/server/_runtime.mjs +1 -10
- package/.output/server/_ssr/HashValueDisplay-DwpGLfrl.mjs +55 -0
- package/.output/server/_ssr/InsightsPageHeader-Df4Brj8u.mjs +484 -0
- package/.output/server/_ssr/{api-keys-BnM_o2nS.mjs → api-keys-CZeTPQys.mjs} +11 -13
- package/.output/server/_ssr/{api-keys-api-CIywsSF5.mjs → api-keys-api-BUPQVSpk.mjs} +2 -2
- package/.output/server/_ssr/{api-keys-rpc-BSp1wkIV.mjs → api-keys-rpc-Cs7tS5_j.mjs} +5 -5
- package/.output/server/_ssr/{api-rpc-cG5wd_tO.mjs → api-rpc-tAupfGQm.mjs} +73 -142
- package/.output/server/_ssr/{auth-rpc-BrJ6obHJ.mjs → auth-rpc-DUaeOWKK.mjs} +4 -4
- package/.output/server/_ssr/{auth.server-DwKoZoQM.mjs → auth.server-DW71WzsD.mjs} +2 -5
- package/.output/server/_ssr/{bundle-signing-rpc-COoQhW8E.mjs → bundle-signing-rpc-BhnBw0-d.mjs} +2 -2
- package/.output/server/_ssr/bundle-signing.server-C4NW5mWx.mjs +12 -0
- package/.output/server/_ssr/{alert-Dim3MGY5.mjs → card-BRiPmi0C.mjs} +61 -39
- package/.output/server/_ssr/{config.server-DEiLhKmy.mjs → config.server-afDuAwaG.mjs} +15 -8
- package/.output/server/_ssr/{createSsrRpc-9P0S0lJ3.mjs → createSsrRpc-DjWNJ0uc.mjs} +6 -6
- package/.output/server/_ssr/databaseJsonValue-d6I3nAS4.mjs +45 -0
- package/.output/server/_ssr/{databaseRows-CwbNwYSl.mjs → databaseRows-5bCRTxm-.mjs} +4 -44
- package/.output/server/_ssr/{deleteBundle-Cu_XOMt0.mjs → deleteBundle-BTGwBgzx.mjs} +2 -2
- package/.output/server/_ssr/{dialog-CQuRMNZ4.mjs → dialog-DS-nw-pA.mjs} +2 -2
- package/.output/server/_ssr/{dist-BVSLTpoP.mjs → dist-CyzPaI5v.mjs} +2 -2
- package/.output/server/_ssr/{getBundleChildren-BcRMFoDF.mjs → getBundleChildren-C0vh4ZvE.mjs} +2 -2
- package/.output/server/_ssr/input-group-BpsnmvZw.mjs +70 -0
- package/.output/server/_ssr/insights-BdS364Xu.mjs +460 -0
- package/.output/server/_ssr/insights-rpc-38DujK0G.mjs +57 -0
- package/.output/server/_ssr/insightsContract-fjJDBeEE.mjs +303 -0
- package/.output/server/_ssr/installations-CtA59MQG.mjs +29 -0
- package/.output/server/_ssr/installations-DiVKEF5T.mjs +627 -0
- package/.output/server/_ssr/{router-C-KUBfOi.mjs → router-B9wG_9f8.mjs} +37 -46
- package/.output/server/_ssr/{routes-Z7TwC6nC.mjs → routes-CKrrS2q2.mjs} +3 -3
- package/.output/server/_ssr/{routes-BM4ht9jb.mjs → routes-D7Yh_jfj.mjs} +402 -390
- package/.output/server/_ssr/runtime.server-DacU1TBV.mjs +438 -0
- package/.output/server/_ssr/{server-BjzmvXnO.mjs → server-D_C2rMzf.mjs} +5 -5
- package/.output/server/_ssr/{signing-k8GxyBDF.mjs → signing-Dz1WkZOf.mjs} +16 -85
- package/.output/server/_ssr/ssr.mjs +1 -1
- package/.output/server/_ssr/{field-DRIXKjZG.mjs → table-CnZmon_Z.mjs} +51 -5
- package/.output/server/_ssr/{uuidv7-BbJ-9D_I.mjs → uuidv7-D0QFkPL_.mjs} +3 -3
- package/.output/server/_tanstack-start-manifest_v-2MjTyxil.mjs +97 -0
- package/.output/server/index.mjs +168 -203
- package/lib/index.d.mts +4 -4
- package/lib/vite-internal.mjs +1 -1
- package/lib/vite.d.mts +0 -1
- package/package.json +8 -8
- package/src/components/AppSidebar.tsx +12 -16
- package/src/components/ConsoleAccessPage.tsx +1 -1
- package/src/components/HashValueDisplay.tsx +11 -2
- package/src/components/features/api-keys/ApiKeysPage.tsx +1 -1
- package/src/components/features/bundles/BundleChildrenPanel.tsx +7 -6
- package/src/components/features/bundles/BundleMetadata.tsx +1 -20
- package/src/components/features/channels/ChannelManagementDialog.tsx +1 -1
- package/src/components/features/insights/EventDetails.tsx +151 -0
- package/src/components/features/insights/EventHistoryCard.tsx +245 -0
- package/src/components/features/insights/EventHistoryList.tsx +63 -0
- package/src/components/features/insights/InsightsBundleReports.tsx +51 -0
- package/src/components/features/insights/InsightsControls.tsx +121 -0
- package/src/components/features/{analytics/AnalyticsErrorAlert.tsx → insights/InsightsErrorAlert.tsx} +6 -6
- package/src/components/features/insights/InsightsOverview.tsx +203 -0
- package/src/components/features/insights/InsightsPageHeader.tsx +48 -0
- package/src/components/features/insights/InsightsPagination.tsx +52 -0
- package/src/components/features/insights/InstallationHistoryCard.tsx +250 -0
- package/src/components/features/insights/InstallationMatchesCard.tsx +178 -0
- package/src/components/features/insights/InstallationPageHeader.tsx +90 -0
- package/src/components/features/releases/ReleaseEditorSheet.tsx +24 -24
- package/src/components/features/signing/BundleSigningPage.tsx +18 -126
- package/src/components/ui/badge.tsx +2 -0
- package/src/components/ui/combobox.tsx +1 -0
- package/src/components/ui/skeleton.tsx +4 -1
- package/src/components/ui/tooltip.tsx +1 -1
- package/src/index.ts +7 -3
- package/src/lib/api-rpc.ts +19 -90
- package/src/lib/api.ts +0 -99
- package/src/lib/insights-api.ts +100 -0
- package/src/lib/insights-rpc.ts +88 -0
- package/src/lib/insights-view.ts +15 -0
- package/src/lib/public-bundle-error.ts +19 -0
- package/src/lib/server/bundle-signing.server.ts +5 -82
- package/src/lib/server/console-runtime.server.ts +0 -9
- package/src/lib/server/releaseReachability.ts +1 -4
- package/src/lib/server/runtime.server.ts +6 -142
- package/src/routeTree.gen.ts +21 -21
- package/src/router.tsx +3 -0
- package/src/routes/-installations-search.ts +25 -12
- package/src/routes/__root.tsx +6 -16
- package/src/routes/api-keys.tsx +1 -1
- package/src/routes/index.tsx +21 -81
- package/src/routes/insights.tsx +84 -0
- package/src/routes/installations.tsx +294 -142
- package/src/styles.css +6 -0
- package/.output/public/assets/AnalyticsCapabilityContext-BCke57-7.js +0 -1
- package/.output/public/assets/BundleActivityChart-CnsBe_1J.js +0 -42
- package/.output/public/assets/BundleIdDisplay-Dky75zLU.js +0 -1
- package/.output/public/assets/alert-C-1KvDW8.js +0 -1
- package/.output/public/assets/analytics-Bqz0c-BT.js +0 -1
- package/.output/public/assets/analytics-api-CJdrTLLO.js +0 -1
- package/.output/public/assets/api-B_Rh-uzC.js +0 -1
- package/.output/public/assets/api-keys-BurCFhzH.js +0 -1
- package/.output/public/assets/api-keys-api-BEDJdQg3.js +0 -1
- package/.output/public/assets/badge-Bf0fZ-Gx.js +0 -1
- package/.output/public/assets/createServerFn-gM2-LFBy.js +0 -3
- package/.output/public/assets/dialog-BS60BRr2.js +0 -1
- package/.output/public/assets/download-O-yNBc9H.js +0 -1
- package/.output/public/assets/field-Buq148-A.js +0 -1
- package/.output/public/assets/index-kFhd2S78.js +0 -10
- package/.output/public/assets/installations-BrQ-od41.js +0 -2
- package/.output/public/assets/installations-CGlZ3ROz.js +0 -1
- package/.output/public/assets/lazyRouteComponent-rPzgA7S-.js +0 -1
- package/.output/public/assets/loader-circle-DCYF-wJl.js +0 -1
- package/.output/public/assets/refresh-cw-n8XYbPPj.js +0 -1
- package/.output/public/assets/routes-CrdokJ80.js +0 -1
- package/.output/public/assets/search-DLhbWw3W.js +0 -1
- package/.output/public/assets/signing-HRexfjsH.js +0 -1
- package/.output/public/assets/styles-eB4EtvFS.css +0 -2
- package/.output/public/assets/table-D8CLieHX.js +0 -1
- package/.output/public/assets/textarea-YJLTVAoq.js +0 -1
- package/.output/public/assets/useMutation-JsGVjQMY.js +0 -1
- package/.output/public/assets/useOpenInteractionType-4cRD5xO0.js +0 -1
- package/.output/server/_libs/@reduxjs/toolkit+[...].mjs +0 -1554
- package/.output/server/_libs/d3-array.mjs +0 -231
- package/.output/server/_libs/d3-color.mjs +0 -330
- package/.output/server/_libs/d3-format.mjs +0 -252
- package/.output/server/_libs/d3-interpolate.mjs +0 -207
- package/.output/server/_libs/d3-path.mjs +0 -77
- package/.output/server/_libs/d3-scale+[...].mjs +0 -1907
- package/.output/server/_libs/d3-shape.mjs +0 -818
- package/.output/server/_libs/decimal.js-light.mjs +0 -884
- package/.output/server/_libs/es-toolkit.mjs +0 -1134
- package/.output/server/_libs/eventemitter3.mjs +0 -236
- package/.output/server/_libs/immer.mjs +0 -532
- package/.output/server/_libs/react-redux+[...].mjs +0 -205
- package/.output/server/_libs/recharts+[...].mjs +0 -14117
- package/.output/server/_ssr/AnalyticsCapabilityContext-ui4DX8GO.mjs +0 -15
- package/.output/server/_ssr/BundleActivityChart-BiB9ZORH.mjs +0 -288
- package/.output/server/_ssr/BundleIdDisplay-Czk6iR6p.mjs +0 -13
- package/.output/server/_ssr/analytics-DtMTn8fn.mjs +0 -858
- package/.output/server/_ssr/analytics-api-Cg1M5v_H.mjs +0 -71
- package/.output/server/_ssr/analytics-input-fRRRn0uA.mjs +0 -96
- package/.output/server/_ssr/analytics-rpc-DY5uXvHT.mjs +0 -155
- package/.output/server/_ssr/api-BTSv1tZb.mjs +0 -282
- package/.output/server/_ssr/badge-DCxbEeof.mjs +0 -26
- package/.output/server/_ssr/bundle-signing.server-D5u8KkMp.mjs +0 -51
- package/.output/server/_ssr/installations-B-azgAvX.mjs +0 -19
- package/.output/server/_ssr/installations-Ctvzp2JH.mjs +0 -535
- package/.output/server/_ssr/runtime.server-awTLiiXW.mjs +0 -527
- package/.output/server/_ssr/table-v1yCvYo7.mjs +0 -53
- package/.output/server/_ssr/textarea-DYHnskhb.mjs +0 -14
- package/.output/server/_tanstack-start-manifest_v-CH4StzJu.mjs +0 -108
- package/src/components/features/analytics/ActivityChart.tsx +0 -150
- package/src/components/features/analytics/AnalyticsCapabilityContext.tsx +0 -24
- package/src/components/features/analytics/AnalyticsControls.tsx +0 -115
- package/src/components/features/analytics/AnalyticsOverview.tsx +0 -208
- package/src/components/features/analytics/BundleDistribution.tsx +0 -133
- package/src/components/features/analytics/BundleSelector.tsx +0 -114
- package/src/components/features/analytics/InstallationHistoryCard.tsx +0 -248
- package/src/components/features/analytics/InstallationMatchesCard.tsx +0 -132
- package/src/components/features/analytics/InstallationPageHeader.tsx +0 -138
- package/src/components/features/analytics/InstallationPagination.tsx +0 -48
- package/src/components/features/analytics/InstallationSearch.tsx +0 -230
- package/src/components/features/analytics/UpdateOutcomes.tsx +0 -147
- package/src/components/features/bundles/BundleActivityChart.tsx +0 -193
- package/src/components/features/bundles/BundleAnalyticsSummary.tsx +0 -123
- package/src/lib/analytics-api.ts +0 -145
- package/src/lib/analytics-error.ts +0 -19
- package/src/lib/analytics-input.ts +0 -187
- package/src/lib/analytics-overview.ts +0 -170
- package/src/lib/analytics-rpc.ts +0 -218
- package/src/lib/server/releaseActivity.ts +0 -27
- package/src/routes/analytics.tsx +0 -139
- /package/.output/public/assets/{preload-helper-TKOBYGYD.js → preload-helper-CQ36nxok.js} +0 -0
|
@@ -1,12 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AlertTriangle,
|
|
3
|
-
CheckCircle2,
|
|
4
|
-
Clipboard,
|
|
5
|
-
Download,
|
|
6
|
-
Info,
|
|
7
|
-
RefreshCw,
|
|
8
|
-
} from "lucide-react";
|
|
9
|
-
import { toast } from "sonner";
|
|
1
|
+
import { AlertTriangle, CheckCircle2, Info, RefreshCw } from "lucide-react";
|
|
10
2
|
|
|
11
3
|
import {
|
|
12
4
|
Alert,
|
|
@@ -24,12 +16,9 @@ import {
|
|
|
24
16
|
CardTitle,
|
|
25
17
|
} from "@/components/ui/card";
|
|
26
18
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
27
|
-
import { Textarea } from "@/components/ui/textarea";
|
|
28
19
|
import { useBundleSigningInspectionQuery } from "@/lib/bundle-signing-api";
|
|
29
20
|
import type { BundleSigningInspection } from "@/lib/bundle-signing-rpc";
|
|
30
21
|
|
|
31
|
-
const PUBLIC_KEY_FILENAME = "hot-updater-public-key.pem";
|
|
32
|
-
|
|
33
22
|
function InspectionLoading() {
|
|
34
23
|
return (
|
|
35
24
|
<div aria-label="Loading bundle signing" className="flex flex-col gap-6">
|
|
@@ -80,12 +69,7 @@ function SigningStatusCard({
|
|
|
80
69
|
readonly inspection: BundleSigningInspection;
|
|
81
70
|
}) {
|
|
82
71
|
const enabled = inspection.status === "enabled";
|
|
83
|
-
const
|
|
84
|
-
const status = enabled
|
|
85
|
-
? "Enabled"
|
|
86
|
-
: misconfigured
|
|
87
|
-
? "Misconfigured"
|
|
88
|
-
: "Disabled";
|
|
72
|
+
const status = enabled ? "Enabled" : "Disabled";
|
|
89
73
|
|
|
90
74
|
return (
|
|
91
75
|
<Card>
|
|
@@ -94,20 +78,12 @@ function SigningStatusCard({
|
|
|
94
78
|
<CardTitle className="text-sm font-medium">
|
|
95
79
|
<h2>Signing status</h2>
|
|
96
80
|
</CardTitle>
|
|
97
|
-
<Badge
|
|
98
|
-
variant={
|
|
99
|
-
misconfigured ? "destructive" : enabled ? "default" : "outline"
|
|
100
|
-
}
|
|
101
|
-
>
|
|
102
|
-
{status}
|
|
103
|
-
</Badge>
|
|
81
|
+
<Badge variant={enabled ? "default" : "outline"}>{status}</Badge>
|
|
104
82
|
</div>
|
|
105
83
|
<CardDescription>
|
|
106
84
|
{enabled
|
|
107
|
-
? "
|
|
108
|
-
:
|
|
109
|
-
? "Signing is enabled, but the public key cannot be inspected safely."
|
|
110
|
-
: "Bundle signing is disabled in the current Hot Updater configuration."}
|
|
85
|
+
? "Bundle signing is enabled in the current Hot Updater configuration."
|
|
86
|
+
: "Bundle signing is disabled in the current Hot Updater configuration."}
|
|
111
87
|
</CardDescription>
|
|
112
88
|
</CardHeader>
|
|
113
89
|
<CardContent className="flex flex-col gap-5">
|
|
@@ -121,105 +97,24 @@ function SigningStatusCard({
|
|
|
121
97
|
</AlertDescription>
|
|
122
98
|
</Alert>
|
|
123
99
|
) : (
|
|
124
|
-
|
|
125
|
-
<
|
|
126
|
-
<
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
{inspection.algorithm}
|
|
137
|
-
</dd>
|
|
138
|
-
</div>
|
|
139
|
-
) : null}
|
|
140
|
-
</dl>
|
|
141
|
-
{inspection.status === "enabled" ? (
|
|
142
|
-
<div className="flex min-w-0 flex-col gap-1 border-t pt-4">
|
|
143
|
-
<p className="text-xs text-muted-foreground">
|
|
144
|
-
SPKI SHA-256 fingerprint
|
|
145
|
-
</p>
|
|
146
|
-
<p className="break-all font-mono text-xs">
|
|
147
|
-
{inspection.fingerprint}
|
|
148
|
-
</p>
|
|
149
|
-
</div>
|
|
150
|
-
) : (
|
|
151
|
-
<Alert variant="destructive">
|
|
152
|
-
<AlertTriangle aria-hidden="true" />
|
|
153
|
-
<AlertTitle>Public key unavailable</AlertTitle>
|
|
154
|
-
<AlertDescription>{inspection.message}</AlertDescription>
|
|
155
|
-
</Alert>
|
|
156
|
-
)}
|
|
157
|
-
</>
|
|
100
|
+
<dl className="grid gap-4 sm:grid-cols-2">
|
|
101
|
+
<div className="flex min-w-0 flex-col gap-1">
|
|
102
|
+
<dt className="text-xs text-muted-foreground">Provider</dt>
|
|
103
|
+
<dd className="truncate text-sm font-medium">
|
|
104
|
+
{inspection.provider}
|
|
105
|
+
</dd>
|
|
106
|
+
</div>
|
|
107
|
+
<div className="flex min-w-0 flex-col gap-1">
|
|
108
|
+
<dt className="text-xs text-muted-foreground">Algorithm</dt>
|
|
109
|
+
<dd className="text-sm font-medium">{inspection.algorithm}</dd>
|
|
110
|
+
</div>
|
|
111
|
+
</dl>
|
|
158
112
|
)}
|
|
159
113
|
</CardContent>
|
|
160
114
|
</Card>
|
|
161
115
|
);
|
|
162
116
|
}
|
|
163
117
|
|
|
164
|
-
function PublicKeyCard({ publicKey }: { readonly publicKey: string }) {
|
|
165
|
-
const copyPublicKey = async () => {
|
|
166
|
-
try {
|
|
167
|
-
await navigator.clipboard.writeText(publicKey);
|
|
168
|
-
toast.success("Public key copied");
|
|
169
|
-
} catch {
|
|
170
|
-
toast.error("Unable to copy public key");
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
const downloadPublicKey = () => {
|
|
175
|
-
const url = URL.createObjectURL(
|
|
176
|
-
new Blob([`${publicKey}\n`], { type: "application/x-pem-file" }),
|
|
177
|
-
);
|
|
178
|
-
const link = document.createElement("a");
|
|
179
|
-
link.download = PUBLIC_KEY_FILENAME;
|
|
180
|
-
link.href = url;
|
|
181
|
-
link.click();
|
|
182
|
-
URL.revokeObjectURL(url);
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
return (
|
|
186
|
-
<Card>
|
|
187
|
-
<CardHeader>
|
|
188
|
-
<CardTitle className="text-sm font-medium">
|
|
189
|
-
<h2>Public key</h2>
|
|
190
|
-
</CardTitle>
|
|
191
|
-
<CardDescription>
|
|
192
|
-
This public key may be embedded in native app configuration. Private
|
|
193
|
-
key material is never available in the Console.
|
|
194
|
-
</CardDescription>
|
|
195
|
-
</CardHeader>
|
|
196
|
-
<CardContent className="flex flex-col gap-3">
|
|
197
|
-
<Textarea
|
|
198
|
-
aria-label="Bundle signing public key"
|
|
199
|
-
className="min-h-56 resize-none font-mono text-xs"
|
|
200
|
-
readOnly
|
|
201
|
-
spellCheck={false}
|
|
202
|
-
value={publicKey}
|
|
203
|
-
/>
|
|
204
|
-
<div className="flex flex-wrap gap-2">
|
|
205
|
-
<Button
|
|
206
|
-
onClick={() => void copyPublicKey()}
|
|
207
|
-
size="sm"
|
|
208
|
-
variant="outline"
|
|
209
|
-
>
|
|
210
|
-
<Clipboard data-icon="inline-start" />
|
|
211
|
-
Copy
|
|
212
|
-
</Button>
|
|
213
|
-
<Button onClick={downloadPublicKey} size="sm" variant="outline">
|
|
214
|
-
<Download data-icon="inline-start" />
|
|
215
|
-
Download
|
|
216
|
-
</Button>
|
|
217
|
-
</div>
|
|
218
|
-
</CardContent>
|
|
219
|
-
</Card>
|
|
220
|
-
);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
118
|
export function BundleSigningPage() {
|
|
224
119
|
const inspection = useBundleSigningInspectionQuery();
|
|
225
120
|
|
|
@@ -231,15 +126,12 @@ export function BundleSigningPage() {
|
|
|
231
126
|
return (
|
|
232
127
|
<div className="flex flex-col gap-6">
|
|
233
128
|
<SigningStatusCard inspection={inspection.data} />
|
|
234
|
-
{inspection.data.status === "enabled" ? (
|
|
235
|
-
<PublicKeyCard publicKey={inspection.data.publicKey} />
|
|
236
|
-
) : null}
|
|
237
129
|
<Alert>
|
|
238
130
|
<CheckCircle2 aria-hidden="true" />
|
|
239
131
|
<AlertTitle>Read-only inspection</AlertTitle>
|
|
240
132
|
<AlertDescription>
|
|
241
133
|
Configure or rotate signing keys through the provider or Hot Updater
|
|
242
|
-
CLI. The Console
|
|
134
|
+
CLI. The Console never accesses signing credentials.
|
|
243
135
|
</AlertDescription>
|
|
244
136
|
</Alert>
|
|
245
137
|
</div>
|
|
@@ -13,6 +13,8 @@ const badgeVariants = cva(
|
|
|
13
13
|
"border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
|
|
14
14
|
secondary:
|
|
15
15
|
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
16
|
+
success: "border-success/20 bg-success/10 text-success",
|
|
17
|
+
warning: "border-warning/20 bg-warning/10 text-warning",
|
|
16
18
|
destructive:
|
|
17
19
|
"border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
|
|
18
20
|
outline: "text-foreground",
|
|
@@ -39,6 +39,7 @@ function ComboboxTrigger({
|
|
|
39
39
|
function ComboboxClear({ className, ...props }: ComboboxPrimitive.Clear.Props) {
|
|
40
40
|
return (
|
|
41
41
|
<ComboboxPrimitive.Clear
|
|
42
|
+
aria-label="Clear selection"
|
|
42
43
|
data-slot="combobox-clear"
|
|
43
44
|
render={<InputGroupButton variant="ghost" size="icon-xs" />}
|
|
44
45
|
className={cn(className)}
|
|
@@ -4,7 +4,10 @@ function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
|
|
|
4
4
|
return (
|
|
5
5
|
<div
|
|
6
6
|
data-slot="skeleton"
|
|
7
|
-
className={cn(
|
|
7
|
+
className={cn(
|
|
8
|
+
"bg-muted rounded-md animate-pulse motion-reduce:animate-none",
|
|
9
|
+
className,
|
|
10
|
+
)}
|
|
8
11
|
{...props}
|
|
9
12
|
/>
|
|
10
13
|
);
|
|
@@ -50,7 +50,7 @@ function TooltipContent({
|
|
|
50
50
|
<TooltipPrimitive.Popup
|
|
51
51
|
data-slot="tooltip-content"
|
|
52
52
|
className={cn(
|
|
53
|
-
"z-50 inline-flex w-fit max-w-xs origin-(--transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
53
|
+
"z-50 inline-flex w-fit max-w-xs origin-(--transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 motion-reduce:animate-none! data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
54
54
|
className,
|
|
55
55
|
)}
|
|
56
56
|
{...props}
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ConfigInput } from "@hot-updater/plugin-core";
|
|
1
|
+
import type { ConfigInput, DatabasePlugin } from "@hot-updater/plugin-core";
|
|
2
2
|
|
|
3
3
|
export type ConsoleAuthProvider = "google" | "github";
|
|
4
4
|
|
|
@@ -22,11 +22,15 @@ export type ConsoleAuthAdapter = Readonly<{
|
|
|
22
22
|
export type ConsoleSigningConfig = Readonly<{
|
|
23
23
|
enabled: boolean;
|
|
24
24
|
provider?: string;
|
|
25
|
-
publicKeyPath?: string;
|
|
26
25
|
}>;
|
|
27
26
|
|
|
28
27
|
export type HotUpdaterConsoleConfig = Readonly<
|
|
29
|
-
|
|
28
|
+
Omit<
|
|
29
|
+
Pick<ConfigInput, "console" | "database" | "signing" | "storage">,
|
|
30
|
+
"database"
|
|
31
|
+
> & {
|
|
32
|
+
database: DatabasePlugin;
|
|
33
|
+
}
|
|
30
34
|
>;
|
|
31
35
|
|
|
32
36
|
export type ResolvedHotUpdaterConsoleConfig = Readonly<
|
package/src/lib/api-rpc.ts
CHANGED
|
@@ -12,15 +12,9 @@ import {
|
|
|
12
12
|
} from "@hot-updater/plugin-core";
|
|
13
13
|
import { createServerFn } from "@tanstack/react-start";
|
|
14
14
|
|
|
15
|
-
import {
|
|
16
|
-
parseBundleEventAnalyticsInput,
|
|
17
|
-
parseBundleEventSummaryInput,
|
|
18
|
-
parseInstallationHistoryInput,
|
|
19
|
-
parseSearchInstallationsInput,
|
|
20
|
-
} from "./analytics-input";
|
|
21
15
|
import { DEFAULT_PAGE_LIMIT } from "./constants";
|
|
16
|
+
import { withPublicBundleMutationErrors } from "./public-bundle-error";
|
|
22
17
|
import { listReleases } from "./server/listReleases";
|
|
23
|
-
import { getReleaseActivity30d } from "./server/releaseActivity";
|
|
24
18
|
import { addReleaseReachability } from "./server/releaseReachability";
|
|
25
19
|
|
|
26
20
|
type GetBundlesInput = {
|
|
@@ -78,7 +72,7 @@ export const getReleases = createServerFn({ method: "GET" })
|
|
|
78
72
|
.inputValidator((input: GetReleasesInput | undefined) => input)
|
|
79
73
|
.handler(async ({ data }) => {
|
|
80
74
|
const { prepareConfig } = await import("./server/config.server");
|
|
81
|
-
const { config
|
|
75
|
+
const { config } = await prepareConfig();
|
|
82
76
|
const result = await listReleases(config.database.models.releases, {
|
|
83
77
|
...(data?.afterReleaseId === undefined
|
|
84
78
|
? {}
|
|
@@ -96,22 +90,13 @@ export const getReleases = createServerFn({ method: "GET" })
|
|
|
96
90
|
: { targetAppVersion: data.targetAppVersion }),
|
|
97
91
|
limit: data?.limit ?? DEFAULT_PAGE_LIMIT,
|
|
98
92
|
});
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
),
|
|
104
|
-
getReleaseActivity30d(hotUpdater, result.data),
|
|
105
|
-
]);
|
|
93
|
+
const releases = await addReleaseReachability(
|
|
94
|
+
config.database.models.releaseCatalogs,
|
|
95
|
+
result.data,
|
|
96
|
+
);
|
|
106
97
|
return {
|
|
107
98
|
...result,
|
|
108
|
-
data: releases
|
|
109
|
-
...release,
|
|
110
|
-
activity30d:
|
|
111
|
-
release.bundle_id === null
|
|
112
|
-
? null
|
|
113
|
-
: (activityByBundleId.get(release.bundle_id) ?? null),
|
|
114
|
-
})),
|
|
99
|
+
data: releases,
|
|
115
100
|
};
|
|
116
101
|
});
|
|
117
102
|
|
|
@@ -128,7 +113,9 @@ export const updateRelease = createServerFn({ method: "POST" })
|
|
|
128
113
|
.handler(async ({ data }) => {
|
|
129
114
|
const { prepareConfig } = await import("./server/config.server");
|
|
130
115
|
const { config } = await prepareConfig();
|
|
131
|
-
return
|
|
116
|
+
return withPublicBundleMutationErrors(() =>
|
|
117
|
+
updateReleasePolicy({ database: config.database, ...data }),
|
|
118
|
+
);
|
|
132
119
|
});
|
|
133
120
|
|
|
134
121
|
export const preflightRelease = createServerFn({ method: "POST" })
|
|
@@ -136,7 +123,9 @@ export const preflightRelease = createServerFn({ method: "POST" })
|
|
|
136
123
|
.handler(async ({ data }) => {
|
|
137
124
|
const { prepareConfig } = await import("./server/config.server");
|
|
138
125
|
const { config } = await prepareConfig();
|
|
139
|
-
return
|
|
126
|
+
return withPublicBundleMutationErrors(() =>
|
|
127
|
+
preflightReleasePolicy({ database: config.database, ...data }),
|
|
128
|
+
);
|
|
140
129
|
});
|
|
141
130
|
|
|
142
131
|
export const deleteRelease = createServerFn({ method: "POST" })
|
|
@@ -144,7 +133,9 @@ export const deleteRelease = createServerFn({ method: "POST" })
|
|
|
144
133
|
.handler(async ({ data }) => {
|
|
145
134
|
const { prepareConfig } = await import("./server/config.server");
|
|
146
135
|
const { config } = await prepareConfig();
|
|
147
|
-
return
|
|
136
|
+
return withPublicBundleMutationErrors(() =>
|
|
137
|
+
deleteReleaseMutation({ database: config.database, ...data }),
|
|
138
|
+
);
|
|
148
139
|
});
|
|
149
140
|
|
|
150
141
|
export const promoteRelease = createServerFn({ method: "POST" })
|
|
@@ -159,7 +150,9 @@ export const promoteRelease = createServerFn({ method: "POST" })
|
|
|
159
150
|
.handler(async ({ data }) => {
|
|
160
151
|
const { prepareConfig } = await import("./server/config.server");
|
|
161
152
|
const { config } = await prepareConfig();
|
|
162
|
-
return
|
|
153
|
+
return withPublicBundleMutationErrors(() =>
|
|
154
|
+
promoteReleaseMutation({ database: config.database, ...data }),
|
|
155
|
+
);
|
|
163
156
|
});
|
|
164
157
|
|
|
165
158
|
export const getReleaseCatalogDiagnostics = createServerFn({ method: "GET" })
|
|
@@ -317,70 +310,6 @@ export const getBundle = createServerFn({ method: "GET" })
|
|
|
317
310
|
}
|
|
318
311
|
});
|
|
319
312
|
|
|
320
|
-
export const getBundleEventSummary = createServerFn({ method: "GET" })
|
|
321
|
-
.inputValidator(parseBundleEventSummaryInput)
|
|
322
|
-
.handler(async ({ data }) => {
|
|
323
|
-
try {
|
|
324
|
-
const { prepareConfig } = await import("./server/config.server");
|
|
325
|
-
const { getBundleEventSummary: getBundleEventSummaryWithRuntime } =
|
|
326
|
-
await import("./server/runtime.server");
|
|
327
|
-
const { hotUpdater } = await prepareConfig();
|
|
328
|
-
|
|
329
|
-
return await getBundleEventSummaryWithRuntime(hotUpdater, data);
|
|
330
|
-
} catch (error) {
|
|
331
|
-
console.error("Error during bundle event summary retrieval:", error);
|
|
332
|
-
throw error;
|
|
333
|
-
}
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
export const getBundleEventAnalytics = createServerFn({ method: "GET" })
|
|
337
|
-
.inputValidator(parseBundleEventAnalyticsInput)
|
|
338
|
-
.handler(async ({ data }) => {
|
|
339
|
-
try {
|
|
340
|
-
const { prepareConfig } = await import("./server/config.server");
|
|
341
|
-
const { getBundleEventAnalytics: getBundleEventAnalyticsWithRuntime } =
|
|
342
|
-
await import("./server/runtime.server");
|
|
343
|
-
const { hotUpdater } = await prepareConfig();
|
|
344
|
-
|
|
345
|
-
return await getBundleEventAnalyticsWithRuntime(hotUpdater, data);
|
|
346
|
-
} catch (error) {
|
|
347
|
-
console.error("Error during bundle event analytics retrieval:", error);
|
|
348
|
-
throw error;
|
|
349
|
-
}
|
|
350
|
-
});
|
|
351
|
-
|
|
352
|
-
export const searchInstallations = createServerFn({ method: "GET" })
|
|
353
|
-
.inputValidator(parseSearchInstallationsInput)
|
|
354
|
-
.handler(async ({ data }) => {
|
|
355
|
-
try {
|
|
356
|
-
const { prepareConfig } = await import("./server/config.server");
|
|
357
|
-
const { searchInstallations: searchInstallationsWithRuntime } =
|
|
358
|
-
await import("./server/runtime.server");
|
|
359
|
-
const { hotUpdater } = await prepareConfig();
|
|
360
|
-
|
|
361
|
-
return await searchInstallationsWithRuntime(hotUpdater, data);
|
|
362
|
-
} catch (error) {
|
|
363
|
-
console.error("Error during installation search:", error);
|
|
364
|
-
throw error;
|
|
365
|
-
}
|
|
366
|
-
});
|
|
367
|
-
|
|
368
|
-
export const getInstallationHistory = createServerFn({ method: "GET" })
|
|
369
|
-
.inputValidator(parseInstallationHistoryInput)
|
|
370
|
-
.handler(async ({ data }) => {
|
|
371
|
-
try {
|
|
372
|
-
const { prepareConfig } = await import("./server/config.server");
|
|
373
|
-
const { getInstallationHistory: getInstallationHistoryWithRuntime } =
|
|
374
|
-
await import("./server/runtime.server");
|
|
375
|
-
const { hotUpdater } = await prepareConfig();
|
|
376
|
-
|
|
377
|
-
return await getInstallationHistoryWithRuntime(hotUpdater, data);
|
|
378
|
-
} catch (error) {
|
|
379
|
-
console.error("Error during installation history retrieval:", error);
|
|
380
|
-
throw error;
|
|
381
|
-
}
|
|
382
|
-
});
|
|
383
|
-
|
|
384
313
|
export const getBundleChildren = createServerFn({ method: "GET" })
|
|
385
314
|
.inputValidator((input: GetBundleChildrenInput) => input)
|
|
386
315
|
.handler(async ({ data }) => {
|
package/src/lib/api.ts
CHANGED
|
@@ -3,7 +3,6 @@ import type {
|
|
|
3
3
|
ChannelInsertInput,
|
|
4
4
|
ReleasePolicyPatch,
|
|
5
5
|
} from "@hot-updater/plugin-core";
|
|
6
|
-
import type { BundleEventAnalyticsWindow } from "@hot-updater/server";
|
|
7
6
|
import {
|
|
8
7
|
type QueryClient,
|
|
9
8
|
type QueryKey,
|
|
@@ -21,19 +20,15 @@ import {
|
|
|
21
20
|
getBundle,
|
|
22
21
|
getBundleChildCounts,
|
|
23
22
|
getBundleChildren,
|
|
24
|
-
getBundleEventAnalytics as getBundleEventAnalyticsApi,
|
|
25
|
-
getBundleEventSummary as getBundleEventSummaryApi,
|
|
26
23
|
getBundles,
|
|
27
24
|
getChannels,
|
|
28
25
|
getConfig,
|
|
29
26
|
getConfigLoaded,
|
|
30
|
-
getInstallationHistory as getInstallationHistoryApi,
|
|
31
27
|
getRelease,
|
|
32
28
|
getReleaseCatalogDiagnostics,
|
|
33
29
|
getReleases,
|
|
34
30
|
preflightRelease as preflightReleaseApi,
|
|
35
31
|
promoteRelease as promoteReleaseApi,
|
|
36
|
-
searchInstallations as searchInstallationsApi,
|
|
37
32
|
updateRelease as updateReleaseApi,
|
|
38
33
|
} from "./api-rpc";
|
|
39
34
|
|
|
@@ -47,23 +42,6 @@ type BundleFilters = {
|
|
|
47
42
|
|
|
48
43
|
type BundlesQueryData = Awaited<ReturnType<typeof getBundles>>;
|
|
49
44
|
|
|
50
|
-
const ANALYTICS_STALE_TIME_MS = 30_000;
|
|
51
|
-
|
|
52
|
-
export type BundleEventSummary = Awaited<
|
|
53
|
-
ReturnType<typeof getBundleEventSummaryApi>
|
|
54
|
-
>;
|
|
55
|
-
export type BundleEventAnalytics = Awaited<
|
|
56
|
-
ReturnType<typeof getBundleEventAnalyticsApi>
|
|
57
|
-
>;
|
|
58
|
-
export type InstallationSearchResult = Awaited<
|
|
59
|
-
ReturnType<typeof searchInstallationsApi>
|
|
60
|
-
>;
|
|
61
|
-
export type InstallationHistoryResult = Awaited<
|
|
62
|
-
ReturnType<typeof getInstallationHistoryApi>
|
|
63
|
-
>;
|
|
64
|
-
export type InstallationSearchRow = InstallationSearchResult["data"][number];
|
|
65
|
-
export type InstallationHistoryRow = InstallationHistoryResult["data"][number];
|
|
66
|
-
|
|
67
45
|
const bundleListQueryKey = ["bundles"] as const;
|
|
68
46
|
const releaseListQueryKey = ["releases"] as const;
|
|
69
47
|
|
|
@@ -90,21 +68,6 @@ export const queryKeys = {
|
|
|
90
68
|
["bundle-children", "counts", ...bundleIds] as const,
|
|
91
69
|
},
|
|
92
70
|
bundle: (bundleId: string) => ["bundle", bundleId] as const,
|
|
93
|
-
bundleEventSummary: (bundleId: string) =>
|
|
94
|
-
["bundle-event-summary", bundleId] as const,
|
|
95
|
-
bundleEventAnalytics: (input: {
|
|
96
|
-
bundleId: string;
|
|
97
|
-
window: BundleEventAnalyticsWindow;
|
|
98
|
-
limit?: number;
|
|
99
|
-
offset?: number;
|
|
100
|
-
}) => ["bundle-event-analytics", input] as const,
|
|
101
|
-
|
|
102
|
-
installations: {
|
|
103
|
-
search: (input: { query: string; limit?: number; offset?: number }) =>
|
|
104
|
-
["installations", "search", input] as const,
|
|
105
|
-
history: (input: { installId: string; limit?: number; offset?: number }) =>
|
|
106
|
-
["installations", "history", input] as const,
|
|
107
|
-
},
|
|
108
71
|
};
|
|
109
72
|
|
|
110
73
|
export type ReleaseFilters = {
|
|
@@ -222,68 +185,6 @@ export function useBundleQuery(bundleId: string) {
|
|
|
222
185
|
});
|
|
223
186
|
}
|
|
224
187
|
|
|
225
|
-
export function useBundleEventSummaryQuery(bundleId: string, enabled: boolean) {
|
|
226
|
-
return useQuery({
|
|
227
|
-
queryKey: queryKeys.bundleEventSummary(bundleId),
|
|
228
|
-
queryFn: () => getBundleEventSummaryApi({ data: { bundleId } }),
|
|
229
|
-
staleTime: ANALYTICS_STALE_TIME_MS,
|
|
230
|
-
refetchOnWindowFocus: true,
|
|
231
|
-
enabled: enabled && bundleId.length > 0,
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
export function useBundleEventAnalyticsQuery(
|
|
236
|
-
input: {
|
|
237
|
-
bundleId: string;
|
|
238
|
-
window: BundleEventAnalyticsWindow;
|
|
239
|
-
limit?: number;
|
|
240
|
-
offset?: number;
|
|
241
|
-
},
|
|
242
|
-
enabled: boolean,
|
|
243
|
-
) {
|
|
244
|
-
return useQuery({
|
|
245
|
-
queryKey: queryKeys.bundleEventAnalytics(input),
|
|
246
|
-
queryFn: () => getBundleEventAnalyticsApi({ data: input }),
|
|
247
|
-
staleTime: ANALYTICS_STALE_TIME_MS,
|
|
248
|
-
refetchOnWindowFocus: true,
|
|
249
|
-
enabled: enabled && input.bundleId.length > 0,
|
|
250
|
-
});
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
export function useInstallationSearchQuery(
|
|
254
|
-
input: {
|
|
255
|
-
query: string;
|
|
256
|
-
limit?: number;
|
|
257
|
-
offset?: number;
|
|
258
|
-
},
|
|
259
|
-
enabled: boolean,
|
|
260
|
-
) {
|
|
261
|
-
return useQuery({
|
|
262
|
-
queryKey: queryKeys.installations.search(input),
|
|
263
|
-
queryFn: () => searchInstallationsApi({ data: input }),
|
|
264
|
-
staleTime: ANALYTICS_STALE_TIME_MS,
|
|
265
|
-
refetchOnWindowFocus: true,
|
|
266
|
-
enabled: enabled && input.query.trim().length > 0,
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
export function useInstallationHistoryQuery(
|
|
271
|
-
input: {
|
|
272
|
-
installId: string;
|
|
273
|
-
limit?: number;
|
|
274
|
-
offset?: number;
|
|
275
|
-
},
|
|
276
|
-
enabled: boolean,
|
|
277
|
-
) {
|
|
278
|
-
return useQuery({
|
|
279
|
-
queryKey: queryKeys.installations.history(input),
|
|
280
|
-
queryFn: () => getInstallationHistoryApi({ data: input }),
|
|
281
|
-
staleTime: ANALYTICS_STALE_TIME_MS,
|
|
282
|
-
refetchOnWindowFocus: true,
|
|
283
|
-
enabled: enabled && input.installId.length > 0,
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
|
|
287
188
|
export function useBundleChildrenQuery(baseBundleId: string) {
|
|
288
189
|
return useQuery({
|
|
289
190
|
queryKey: queryKeys.bundleChildren.list(baseBundleId),
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { InsightsEventPageInput } from "@hot-updater/server";
|
|
2
|
+
import { useQuery } from "@tanstack/react-query";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
findInsightsInstallationsRpc,
|
|
6
|
+
getInsightsInstallationRpc,
|
|
7
|
+
getReportingInstallationsRpc,
|
|
8
|
+
listInsightsEventsRpc,
|
|
9
|
+
listInsightsInstallationEventsRpc,
|
|
10
|
+
type InsightsWindow,
|
|
11
|
+
type InsightsOverviewInput,
|
|
12
|
+
type ReportingInstallations,
|
|
13
|
+
} from "./insights-rpc";
|
|
14
|
+
|
|
15
|
+
export type { InsightsWindow, InsightsOverviewInput, ReportingInstallations };
|
|
16
|
+
|
|
17
|
+
const STALE_TIME_MS = 30_000;
|
|
18
|
+
|
|
19
|
+
const queryKeys = {
|
|
20
|
+
reportingInstallations: (input: InsightsOverviewInput) =>
|
|
21
|
+
["insights", "reporting-installations", input] as const,
|
|
22
|
+
events: (input: InsightsEventPageInput) =>
|
|
23
|
+
["insights", "events", input] as const,
|
|
24
|
+
installations: (input: {
|
|
25
|
+
readonly cursor?: string;
|
|
26
|
+
readonly identity: string;
|
|
27
|
+
readonly limit: number;
|
|
28
|
+
}) => ["insights", "installations", input] as const,
|
|
29
|
+
installation: (installId: string) =>
|
|
30
|
+
["insights", "installation", installId] as const,
|
|
31
|
+
installationEvents: (input: {
|
|
32
|
+
readonly beforeReceivedAtMs: number;
|
|
33
|
+
readonly cursor?: string;
|
|
34
|
+
readonly installId: string;
|
|
35
|
+
readonly limit: number;
|
|
36
|
+
}) => ["insights", "installation-events", input] as const,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const useReportingInstallationsQuery = (input: InsightsOverviewInput) =>
|
|
40
|
+
useQuery({
|
|
41
|
+
queryKey: queryKeys.reportingInstallations(input),
|
|
42
|
+
queryFn: () => getReportingInstallationsRpc({ data: input }),
|
|
43
|
+
refetchOnWindowFocus: true,
|
|
44
|
+
staleTime: STALE_TIME_MS,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
export const useInsightsEventsQuery = (
|
|
48
|
+
input: InsightsEventPageInput,
|
|
49
|
+
enabled: boolean,
|
|
50
|
+
) =>
|
|
51
|
+
useQuery({
|
|
52
|
+
queryKey: queryKeys.events(input),
|
|
53
|
+
queryFn: () => listInsightsEventsRpc({ data: input }),
|
|
54
|
+
enabled,
|
|
55
|
+
refetchOnWindowFocus: true,
|
|
56
|
+
staleTime: STALE_TIME_MS,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
export const useInsightsInstallationsQuery = (
|
|
60
|
+
input: {
|
|
61
|
+
readonly cursor?: string;
|
|
62
|
+
readonly identity: string;
|
|
63
|
+
readonly limit: number;
|
|
64
|
+
},
|
|
65
|
+
enabled: boolean,
|
|
66
|
+
) =>
|
|
67
|
+
useQuery({
|
|
68
|
+
queryKey: queryKeys.installations(input),
|
|
69
|
+
queryFn: () => findInsightsInstallationsRpc({ data: input }),
|
|
70
|
+
enabled: enabled && input.identity.length > 0,
|
|
71
|
+
staleTime: STALE_TIME_MS,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
export const useInsightsInstallationQuery = (
|
|
75
|
+
installId: string,
|
|
76
|
+
enabled: boolean,
|
|
77
|
+
) =>
|
|
78
|
+
useQuery({
|
|
79
|
+
queryKey: queryKeys.installation(installId),
|
|
80
|
+
queryFn: () => getInsightsInstallationRpc({ data: { installId } }),
|
|
81
|
+
enabled: enabled && installId.length > 0,
|
|
82
|
+
staleTime: STALE_TIME_MS,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
export const useInsightsInstallationEventsQuery = (
|
|
86
|
+
input: {
|
|
87
|
+
readonly beforeReceivedAtMs: number;
|
|
88
|
+
readonly cursor?: string;
|
|
89
|
+
readonly installId: string;
|
|
90
|
+
readonly limit: number;
|
|
91
|
+
},
|
|
92
|
+
enabled: boolean,
|
|
93
|
+
) =>
|
|
94
|
+
useQuery({
|
|
95
|
+
queryKey: queryKeys.installationEvents(input),
|
|
96
|
+
queryFn: () => listInsightsInstallationEventsRpc({ data: input }),
|
|
97
|
+
enabled: enabled && input.installId.length > 0,
|
|
98
|
+
refetchOnWindowFocus: true,
|
|
99
|
+
staleTime: STALE_TIME_MS,
|
|
100
|
+
});
|