@hot-updater/console 1.2.0-rc.0 → 1.2.0-rc.1
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/{index-PQ3UCeQV.js → index-BWU6owTG.js} +2 -2
- package/.output/public/assets/native-builds_._buildId-D_Spjl10.js +1 -0
- package/.output/public/assets/{native-builds_._buildId-9p4FFpa4.js → native-builds_._buildId-DtoXD8rz.js} +2 -2
- package/.output/server/{__23tanstack-start-server-fn-resolver-nWkGzoo3.mjs → __23tanstack-start-server-fn-resolver-CygMPYHZ.mjs} +46 -46
- package/.output/server/_libs/@tanstack/react-router-ssr-query+[...].mjs +1 -1
- package/.output/server/_ssr/{BundleIdDisplay-C2YJNpHa.mjs → BundleIdDisplay-DOPz4pUS.mjs} +2 -2
- package/.output/server/_ssr/{ConsoleFeatureUnavailable-Co4rDns4.mjs → ConsoleFeatureUnavailable-Xb1JKqcc.mjs} +6 -6
- package/.output/server/_ssr/{EventDetails-CTvni55k.mjs → EventDetails-D7MejFCN.mjs} +6 -6
- package/.output/server/_ssr/{HashValueDisplay-BBswr65a.mjs → HashValueDisplay-Dd-wu5rY.mjs} +2 -2
- package/.output/server/_ssr/{InsightsPageHeader-ueG4Pkov.mjs → InsightsPageHeader-CWf1n4Vt.mjs} +6 -6
- package/.output/server/_ssr/{NotFoundPage-BES4AfvN.mjs → NotFoundPage-C5rFdUpg.mjs} +2 -2
- package/.output/server/_ssr/{RolloutPercentageBadge-Bkl0uDbV.mjs → RolloutPercentageBadge-g0Bhfl3M.mjs} +3 -3
- package/.output/server/_ssr/{StoreSubmission-0TLWxjym.mjs → StoreSubmission-JZ2Zltak.mjs} +4 -4
- package/.output/server/_ssr/{alert-dialog-Cn0L__fU.mjs → alert-dialog-CvNvTvIJ.mjs} +1 -1
- package/.output/server/_ssr/{api-qUMT9H2M.mjs → api-0vtwA5vY.mjs} +3 -3
- package/.output/server/_ssr/{api-keys-Dt6_6uWi.mjs → api-keys-D5dyA4D1.mjs} +8 -8
- package/.output/server/_ssr/{api-keys-rpc-BqbL9Iyl.mjs → api-keys-rpc-BOIUHhDi.mjs} +3 -3
- package/.output/server/_ssr/{api-keys-DgiwJvLW.mjs → api-keys-yFlQDwQF.mjs} +2 -2
- package/.output/server/_ssr/{api-rpc-CzZPviuV.mjs → api-rpc-COeFOpYi.mjs} +3 -3
- package/.output/server/_ssr/{auth-rpc-CPZyE2Rz.mjs → auth-rpc-D1ss2GUI.mjs} +4 -4
- package/.output/server/_ssr/{auth.server-C2hyK1tQ.mjs → auth.server-DYS1OJ6P.mjs} +2 -2
- package/.output/server/_ssr/{badge-C4HK6j63.mjs → badge-CEdVRgyl.mjs} +1 -1
- package/.output/server/_ssr/{config.server-CwjEf3S5.mjs → config.server-NnMFjMFX.mjs} +3 -3
- package/.output/server/_ssr/{console-access-B2mUKj3_.mjs → console-access-33BNlH97.mjs} +2 -2
- package/.output/server/_ssr/{console-features-api-X8ItTwxM.mjs → console-features-api-v1fSycue.mjs} +5 -5
- package/.output/server/_ssr/{console-features-rpc-BRTvGLBV.mjs → console-features-rpc-C7XNVqm0.mjs} +3 -3
- package/.output/server/_ssr/{dialog-L9IrT3sY.mjs → dialog-C8CS8RMt.mjs} +1 -1
- package/.output/server/_ssr/{empty-CkTC2uZd.mjs → empty-CkdEAvCY.mjs} +2 -2
- package/.output/server/_ssr/{field-W7Ikmzjb.mjs → field-CW08sZXd.mjs} +2 -2
- package/.output/server/_ssr/{input-group-BFnD9l_p.mjs → input-group-D-TpFPuG.mjs} +1 -1
- package/.output/server/_ssr/{insights-CtPYme4Q.mjs → insights-CMyzPs8l.mjs} +19 -19
- package/.output/server/_ssr/{insights-C9KDOFcN.mjs → insights-CYeBl8N9.mjs} +5 -5
- package/.output/server/_ssr/{insights-Dz42GlcZ.mjs → insights-DAi9KknT.mjs} +2 -2
- package/.output/server/_ssr/{insights-api-Cuz8lmZx.mjs → insights-api-BFARQ5ct.mjs} +3 -3
- package/.output/server/_ssr/{insights-failures-rpc-CxI071Ew.mjs → insights-failures-rpc-Q4WNNJkU.mjs} +4 -4
- package/.output/server/_ssr/{insights-recovery-rpc-B-9bs9Gz.mjs → insights-recovery-rpc-CY5RYJKa.mjs} +3 -3
- package/.output/server/_ssr/{insights-rpc-5NfC16-Q.mjs → insights-rpc-BO7_evvs.mjs} +3 -3
- package/.output/server/_ssr/{insights-search-CtQj0m7f.mjs → insights-search-DKfxgHD3.mjs} +2 -2
- package/.output/server/_ssr/{insights-usage-rpc-CFWx4_pK.mjs → insights-usage-rpc-B4czku50.mjs} +3 -3
- package/.output/server/_ssr/{insights-usage-rpc-Qnyviyah.mjs → insights-usage-rpc-CUCTFska.mjs} +3 -3
- package/.output/server/_ssr/{insights_.distribution-Czd0Jtle.mjs → insights_.distribution-BDeUhZGj.mjs} +2 -2
- package/.output/server/_ssr/{insights_.distribution-BamrEztu.mjs → insights_.distribution-BRrbZN1X.mjs} +5 -5
- package/.output/server/_ssr/{insights_.distribution-CXItWbX1.mjs → insights_.distribution-C2MXpzKd.mjs} +13 -13
- package/.output/server/_ssr/{installations-Dy8zAJI_.mjs → installations-BVk7okiY.mjs} +4 -4
- package/.output/server/_ssr/{installations-BaHA_zCp.mjs → installations-BjLMgBoH.mjs} +2 -2
- package/.output/server/_ssr/{installations-Q6t6CEZ8.mjs → installations-DxGZEC5G.mjs} +11 -11
- package/.output/server/_ssr/{native-builds-BWTUWJUF.mjs → native-builds-CSCgFB21.mjs} +2 -2
- package/.output/server/_ssr/{native-builds-Cuw87Y51.mjs → native-builds-CdlyAldW.mjs} +9 -9
- package/.output/server/_ssr/{native-builds_._buildId-Dr3Mc32p.mjs → native-builds_._buildId-CMp1h8dT.mjs} +2 -2
- package/.output/server/_ssr/{native-builds_._buildId-CbhHK93c.mjs → native-builds_._buildId-GHpGaYyE.mjs} +50 -26
- package/.output/server/_ssr/{release-adoption-rpc-BHxQWHWw.mjs → release-adoption-rpc-BJXZvtoQ.mjs} +5 -5
- package/.output/server/_ssr/{remote-config-Bmh0t1FQ.mjs → remote-config-DjsEl270.mjs} +17 -17
- package/.output/server/_ssr/{remote-config-CrVQfJ9y.mjs → remote-config-DlyyohL2.mjs} +2 -2
- package/.output/server/_ssr/{remote-config-DWlhe-Nu.mjs → remote-config-XdYuByHz.mjs} +2 -2
- package/.output/server/_ssr/{remote-config-rpc-BYJbiG9k.mjs → remote-config-rpc-GMLPb-90.mjs} +3 -3
- package/.output/server/_ssr/{router-Bg_TI2qP.mjs → router-vpxd56RW.mjs} +53 -31
- package/.output/server/_ssr/{routes-fs827NQ-.mjs → routes-DyEM4b3x.mjs} +10 -10
- package/.output/server/_ssr/{routes-Do9CHvbC.mjs → routes-dQe3XhiS.mjs} +17 -17
- package/.output/server/_ssr/{schema-migration-rpc-vH6ZlJgo.mjs → schema-migration-rpc-BfGzEK_o.mjs} +3 -3
- package/.output/server/_ssr/{select-BoRQ8ytA.mjs → select-DM1uwtk9.mjs} +1 -1
- package/.output/server/_ssr/{server-DtM4lJ0t.mjs → server-BUUKNSPI.mjs} +3 -3
- package/.output/server/_ssr/{sidebar-D1AgCVIN.mjs → sidebar-DB2YQlok.mjs} +2 -2
- package/.output/server/_ssr/ssr.mjs +1 -1
- package/.output/server/_ssr/{switch-CY0ZEeD2.mjs → switch-DLD58zLy.mjs} +2 -2
- package/.output/server/_ssr/{table-ClsVe-Mz.mjs → table-P4TnAZhl.mjs} +1 -1
- package/.output/server/_ssr/{tabs-BJacHKeX.mjs → tabs-B7ZeLicF.mjs} +2 -2
- package/.output/server/{_tanstack-start-manifest_v-CF4kCd6q.mjs → _tanstack-start-manifest_v-C-KC63Zq.mjs} +5 -5
- package/.output/server/index.mjs +126 -126
- package/package.json +7 -7
- package/src/components/ConsoleAccessPage.tsx +36 -6
- package/src/components/features/native-builds/InstallCard.tsx +47 -24
- package/src/routes/api/native-builds/$buildId/download.ts +9 -4
- package/.output/public/assets/native-builds_._buildId-BRiNTN3j.js +0 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hot-updater/console",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.2.0-rc.
|
|
4
|
+
"version": "1.2.0-rc.1",
|
|
5
5
|
"files": [
|
|
6
6
|
".output",
|
|
7
7
|
"lib",
|
|
@@ -59,10 +59,10 @@
|
|
|
59
59
|
"tw-animate-css": "^1.4.0",
|
|
60
60
|
"uqr": "^0.1.3",
|
|
61
61
|
"verkit": "0.4.0",
|
|
62
|
-
"@hot-updater/bsdiff": "1.2.0-rc.
|
|
63
|
-
"@hot-updater/
|
|
64
|
-
"@hot-updater/
|
|
65
|
-
"@hot-updater/server": "1.2.0-rc.
|
|
62
|
+
"@hot-updater/bsdiff": "1.2.0-rc.1",
|
|
63
|
+
"@hot-updater/protocol": "1.2.0-rc.1",
|
|
64
|
+
"@hot-updater/plugin-core": "1.2.0-rc.1",
|
|
65
|
+
"@hot-updater/server": "1.2.0-rc.1"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
68
|
"@tanstack/devtools-vite": "^0.6.0",
|
|
@@ -87,8 +87,8 @@
|
|
|
87
87
|
"vite-tsconfig-paths": "^6.1.1",
|
|
88
88
|
"vitest": "4.1.4",
|
|
89
89
|
"web-vitals": "^5.1.0",
|
|
90
|
-
"@hot-updater/cli-tools": "1.2.0-rc.
|
|
91
|
-
"@hot-updater/mock": "1.2.0-rc.
|
|
90
|
+
"@hot-updater/cli-tools": "1.2.0-rc.1",
|
|
91
|
+
"@hot-updater/mock": "1.2.0-rc.1"
|
|
92
92
|
},
|
|
93
93
|
"description": "React Native OTA solution for self-hosted",
|
|
94
94
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState } from "react";
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
2
|
|
|
3
3
|
import { HotUpdaterLogo } from "@/components/HotUpdaterLogo";
|
|
4
4
|
import { Button } from "@/components/ui/button";
|
|
@@ -15,19 +15,40 @@ const providerLabel: Record<ConsoleAuthProvider, string> = {
|
|
|
15
15
|
google: "Google",
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
+
/** A path on this console, or the root for anything that could leave it. */
|
|
19
|
+
const consolePath = (target: string) =>
|
|
20
|
+
target.startsWith("/") && !/^\/[/\\]/.test(target) ? target : "/";
|
|
21
|
+
|
|
18
22
|
/**
|
|
19
23
|
* Where sign-in returns to: the page that asked for it, as a path on this
|
|
20
|
-
* console, so a link to a build lands on that build.
|
|
21
|
-
*
|
|
24
|
+
* console, so a link to a build lands on that build. A page a route sent
|
|
25
|
+
* here names its own target in `returnTo`, relative to the page, as the
|
|
26
|
+
* native build download does: sign-in returns there instead, when it is on
|
|
27
|
+
* this console's origin. Anything that could leave the console, such as
|
|
28
|
+
* `//host` or `/\host`, returns to the page, or to the root.
|
|
22
29
|
*/
|
|
23
30
|
export const signInCallbackURL = (location: {
|
|
31
|
+
readonly href: string;
|
|
24
32
|
readonly pathname: string;
|
|
25
33
|
readonly search: string;
|
|
26
34
|
}): string => {
|
|
27
|
-
const
|
|
28
|
-
|
|
35
|
+
const page = consolePath(`${location.pathname}${location.search}`);
|
|
36
|
+
const returnTo = new URLSearchParams(location.search).get("returnTo");
|
|
37
|
+
if (returnTo === null) return page;
|
|
38
|
+
try {
|
|
39
|
+
const target = new URL(returnTo, location.href);
|
|
40
|
+
return target.origin === new URL(location.href).origin
|
|
41
|
+
? consolePath(`${target.pathname}${target.search}`)
|
|
42
|
+
: page;
|
|
43
|
+
} catch {
|
|
44
|
+
return page;
|
|
45
|
+
}
|
|
29
46
|
};
|
|
30
47
|
|
|
48
|
+
/** Whether sign-in returns to a native build's download. */
|
|
49
|
+
const returnsToDownload = (callbackURL: string) =>
|
|
50
|
+
/\/api\/native-builds\/[^/]+\/download$/.test(callbackURL);
|
|
51
|
+
|
|
31
52
|
export function ConsoleAccessPage({
|
|
32
53
|
access,
|
|
33
54
|
providers,
|
|
@@ -35,6 +56,13 @@ export function ConsoleAccessPage({
|
|
|
35
56
|
const [pendingProvider, setPendingProvider] =
|
|
36
57
|
useState<ConsoleAuthProvider | null>(null);
|
|
37
58
|
const [signingOut, setSigningOut] = useState(false);
|
|
59
|
+
// Read after the page mounts: the server renders it without a location.
|
|
60
|
+
const [downloadAfterSignIn, setDownloadAfterSignIn] = useState(false);
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
setDownloadAfterSignIn(
|
|
63
|
+
returnsToDownload(signInCallbackURL(window.location)),
|
|
64
|
+
);
|
|
65
|
+
}, []);
|
|
38
66
|
const [error, setError] = useState<string | null>(null);
|
|
39
67
|
|
|
40
68
|
const signIn = async (provider: ConsoleAuthProvider) => {
|
|
@@ -87,7 +115,9 @@ export function ConsoleAccessPage({
|
|
|
87
115
|
<div>
|
|
88
116
|
<h1 className="text-lg font-semibold">Hot Updater Console</h1>
|
|
89
117
|
<p className="text-muted-foreground text-sm">
|
|
90
|
-
|
|
118
|
+
{downloadAfterSignIn
|
|
119
|
+
? "Sign in to download the build. It starts once you're in."
|
|
120
|
+
: "Sign in to manage OTA bundles."}
|
|
91
121
|
</p>
|
|
92
122
|
</div>
|
|
93
123
|
</div>
|
|
@@ -17,12 +17,25 @@ import {
|
|
|
17
17
|
import { CopyableText } from "./CopyableText";
|
|
18
18
|
import { isSubmitted } from "./StoreSubmission";
|
|
19
19
|
|
|
20
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* What an artifact installs on, where the file alone isn't enough: the card
|
|
22
|
+
* says it once, under the QR code, or without one, in its place.
|
|
23
|
+
*/
|
|
24
|
+
const INSTALL_LIMITS: Partial<Record<NativeBuildRow["artifact_kind"], string>> =
|
|
25
|
+
{
|
|
26
|
+
ipa: "The .ipa installs only on devices its signing profile allows (development or ad hoc); an App Store export reaches testers through TestFlight.",
|
|
27
|
+
aab: "The .aab installs through Google Play or bundletool, not from the file.",
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* What scanning a build's QR code gets, by its artifact. The install steps
|
|
32
|
+
* beside it add only what this doesn't say, so the card says each thing once.
|
|
33
|
+
*/
|
|
21
34
|
const QR_CAPTIONS: Record<NativeBuildRow["artifact_kind"], string> = {
|
|
22
35
|
apk: "Scan with an Android phone's camera, then open the APK to install it.",
|
|
23
|
-
ipa:
|
|
24
|
-
aab:
|
|
25
|
-
app: "Scan to download the .app.zip on a Mac
|
|
36
|
+
ipa: `Scan to download. ${INSTALL_LIMITS.ipa}`,
|
|
37
|
+
aab: `Scan to download. ${INSTALL_LIMITS.aab}`,
|
|
38
|
+
app: "Scan to download the .app.zip on a Mac.",
|
|
26
39
|
};
|
|
27
40
|
|
|
28
41
|
/**
|
|
@@ -36,12 +49,16 @@ function DownloadQrCode({ build }: { readonly build: NativeBuildRow }) {
|
|
|
36
49
|
// A storage without download URLs serves the build only through the
|
|
37
50
|
// console, which a phone that scans isn't signed in to.
|
|
38
51
|
if (url === null) {
|
|
52
|
+
const limits = INSTALL_LIMITS[build.artifact_kind];
|
|
39
53
|
return (
|
|
40
|
-
<
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
54
|
+
<div className="flex flex-col gap-2 text-xs text-muted-foreground">
|
|
55
|
+
<p>
|
|
56
|
+
This storage gives no download link a phone can open without signing
|
|
57
|
+
in, so there is no QR code. Download the build here, or open this page
|
|
58
|
+
on the phone signed in to the console.
|
|
59
|
+
</p>
|
|
60
|
+
{limits ? <p>{limits}</p> : null}
|
|
61
|
+
</div>
|
|
45
62
|
);
|
|
46
63
|
}
|
|
47
64
|
|
|
@@ -80,7 +97,10 @@ function SubmittedVersion({ build }: { readonly build: NativeBuildRow }) {
|
|
|
80
97
|
);
|
|
81
98
|
}
|
|
82
99
|
|
|
83
|
-
/**
|
|
100
|
+
/**
|
|
101
|
+
* How else the artifact installs, beside its QR code's caption and its
|
|
102
|
+
* download: none of it repeats the caption.
|
|
103
|
+
*/
|
|
84
104
|
function InstallSteps({ build }: { readonly build: NativeBuildRow }) {
|
|
85
105
|
switch (build.artifact_kind) {
|
|
86
106
|
case "apk":
|
|
@@ -99,8 +119,7 @@ function InstallSteps({ build }: { readonly build: NativeBuildRow }) {
|
|
|
99
119
|
return (
|
|
100
120
|
<div className="flex min-w-0 flex-col gap-2">
|
|
101
121
|
<p className="text-xs text-muted-foreground">
|
|
102
|
-
|
|
103
|
-
archive, then install it on the booted simulator:
|
|
122
|
+
It runs only in the iOS Simulator. Install it on the booted one:
|
|
104
123
|
</p>
|
|
105
124
|
<CopyableText
|
|
106
125
|
label="the install command"
|
|
@@ -112,27 +131,30 @@ function InstallSteps({ build }: { readonly build: NativeBuildRow }) {
|
|
|
112
131
|
return isSubmitted(build) ? (
|
|
113
132
|
<p className="text-xs text-muted-foreground">
|
|
114
133
|
Submitted to Google Play internal testing as{" "}
|
|
115
|
-
<SubmittedVersion build={build} />. Testers
|
|
116
|
-
|
|
117
|
-
|
|
134
|
+
<SubmittedVersion build={build} />. Testers get it once its release is
|
|
135
|
+
rolled out; on an app Play Console hasn't published, the release is a
|
|
136
|
+
draft you roll out in Play Console.
|
|
118
137
|
</p>
|
|
119
138
|
) : (
|
|
120
|
-
<
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
139
|
+
<div className="flex min-w-0 flex-col gap-2">
|
|
140
|
+
<p className="text-xs text-muted-foreground">
|
|
141
|
+
For testers, build and release to internal testing:
|
|
142
|
+
</p>
|
|
143
|
+
<CopyableText
|
|
144
|
+
label="the Google Play command"
|
|
145
|
+
value="npx hot-updater google-play upload"
|
|
146
|
+
/>
|
|
147
|
+
</div>
|
|
124
148
|
);
|
|
125
149
|
case "ipa":
|
|
126
150
|
return isSubmitted(build) ? (
|
|
127
151
|
<p className="text-xs text-muted-foreground">
|
|
128
|
-
On TestFlight as <SubmittedVersion build={build}
|
|
129
|
-
it from TestFlight.
|
|
152
|
+
On TestFlight as <SubmittedVersion build={build} />.
|
|
130
153
|
</p>
|
|
131
154
|
) : (
|
|
132
155
|
<div className="flex min-w-0 flex-col gap-2">
|
|
133
156
|
<p className="text-xs text-muted-foreground">
|
|
134
|
-
|
|
135
|
-
Configurator. For testers, upload it to TestFlight:
|
|
157
|
+
Over USB, Xcode or Apple Configurator installs it. For testers:
|
|
136
158
|
</p>
|
|
137
159
|
<CopyableText
|
|
138
160
|
label="the TestFlight command"
|
|
@@ -146,7 +168,8 @@ function InstallSteps({ build }: { readonly build: NativeBuildRow }) {
|
|
|
146
168
|
/**
|
|
147
169
|
* Installs one native build: every artifact by a QR code of its download,
|
|
148
170
|
* which a phone scans, and by download here; an APK also with `adb`, a
|
|
149
|
-
* simulator app with `xcrun simctl`, and an IPA's testers
|
|
171
|
+
* simulator app with `xcrun simctl`, and an IPA's or an AAB's testers through
|
|
172
|
+
* its store.
|
|
150
173
|
*/
|
|
151
174
|
export function InstallCard({ build }: { readonly build: NativeBuildRow }) {
|
|
152
175
|
const fileName = nativeBuildFileName(build);
|
|
@@ -20,18 +20,23 @@ export const Route = createFileRoute("/api/native-builds/$buildId/download")({
|
|
|
20
20
|
deps = await prepareConfig(request);
|
|
21
21
|
} catch (error) {
|
|
22
22
|
// A browser without a session opens the build's page instead,
|
|
23
|
-
// where the console signs it in and returns to
|
|
24
|
-
//
|
|
25
|
-
// own path, wherever that is
|
|
23
|
+
// where the console signs it in and returns to this download
|
|
24
|
+
// (`returnTo`, relative to that page). Both paths are relative,
|
|
25
|
+
// so they stay under the console's own path, wherever that is
|
|
26
|
+
// mounted; sign-in takes `returnTo` only on the console's origin.
|
|
26
27
|
if (
|
|
27
28
|
error instanceof Response &&
|
|
28
29
|
error.status === 401 &&
|
|
29
30
|
isNavigation(request)
|
|
30
31
|
) {
|
|
32
|
+
const buildId = encodeURIComponent(params.buildId);
|
|
33
|
+
const returnTo = encodeURIComponent(
|
|
34
|
+
`../api/native-builds/${buildId}/download`,
|
|
35
|
+
);
|
|
31
36
|
return new Response(null, {
|
|
32
37
|
headers: {
|
|
33
38
|
"cache-control": "no-store",
|
|
34
|
-
location: `../../../native-builds/${
|
|
39
|
+
location: `../../../native-builds/${buildId}?returnTo=${returnTo}`,
|
|
35
40
|
},
|
|
36
41
|
status: 302,
|
|
37
42
|
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{$ as e,Fn as t,In as n,Ln as r,Wr as i,ii as a,ir as o,p as s,ti as c}from"./sidebar-Di9SN47G.js";import{t as l}from"./link-DTEyW70e.js";import{t as u}from"./arrow-up-right-DK8Zdg40.js";import{a as d,c as f,f as p,n as m,o as h,p as ee,r as te,s as ne,t as re,u as ie}from"./native-builds-BOC71grI.js";import{t as ae}from"./chevron-right-BoUXo82O.js";import{n as oe,t as g}from"./native-builds_._buildId-9p4FFpa4.js";import{t as se}from"./download-Cf24LBde.js";import{n as ce,t as le}from"./history-DqHlgSuV.js";import{r as ue}from"./-native-builds-search-C-TGpFAm.js";import{t as de}from"./refresh-cw-B9HHjLej.js";import{a as _,i as fe,n as v,r as pe,t as me}from"./StoreSubmission-JpngSvHS.js";import{a as y,d as b,f as x,i as S,n as C,o as w,r as he,s as T,t as E,u as D}from"./badge-DWFcDWho.js";import{r as ge}from"./uuidv7-zXMtwR9Q.js";import{a as O,i as k,n as A,o as j,r as M,t as N}from"./empty-B3Uwdd6k.js";import{t as _e}from"./PlatformIcon-BBWQlWm9.js";import{d as ve,l as ye,u as be}from"./api-P2g8dCNg.js";import{a as P,i as F,n as I,o as L,r as R,t as z}from"./table-Bpy3SvSo.js";import{t as xe}from"./RolloutPercentageBadge-Cxogpi8F.js";var Se=o(`package-open`,[[`path`,{d:`M12 22v-9`,key:`x3hkom`}],[`path`,{d:`M15.17 2.21a1.67 1.67 0 0 1 1.63 0L21 4.57a1.93 1.93 0 0 1 0 3.36L8.82 14.79a1.655 1.655 0 0 1-1.64 0L3 12.43a1.93 1.93 0 0 1 0-3.36z`,key:`2ntwy6`}],[`path`,{d:`M20 13v3.87a2.06 2.06 0 0 1-1.11 1.83l-6 3.08a1.93 1.93 0 0 1-1.78 0l-6-3.08A2.06 2.06 0 0 1 4 16.87V13`,key:`1pmm1c`}],[`path`,{d:`M21 12.43a1.93 1.93 0 0 0 0-3.36L8.83 2.2a1.64 1.64 0 0 0-1.63 0L3 4.57a1.93 1.93 0 0 0 0 3.36l12.18 6.86a1.636 1.636 0 0 0 1.63 0z`,key:`12ttoo`}]]),B=i();function V({label:e,children:t}){return(0,B.jsxs)(`div`,{className:`grid gap-1 sm:grid-cols-[10rem_minmax(0,1fr)] sm:gap-4`,children:[(0,B.jsx)(`dt`,{className:`text-xs font-medium text-muted-foreground`,children:e}),(0,B.jsx)(`dd`,{className:`min-w-0 text-sm`,children:t})]})}function Ce({detail:e}){let{build:t,newestInScope:n}=e;return n===null?null:n.id===t.id?(0,B.jsxs)(`div`,{className:`flex items-start gap-2 rounded-md border bg-muted/40 p-3 text-xs`,children:[(0,B.jsx)(oe,{"aria-hidden":`true`,className:`mt-0.5 size-3.5 shrink-0 text-muted-foreground`}),(0,B.jsxs)(`p`,{children:[(0,B.jsx)(`span`,{className:`font-medium`,children:`Current baseline.`}),` New deploys to this scope add a patch from this build's bundle.`]})]}):(0,B.jsxs)(`div`,{className:`flex items-start gap-2 rounded-md border bg-muted/40 p-3 text-xs`,children:[(0,B.jsx)(le,{"aria-hidden":`true`,className:`mt-0.5 size-3.5 shrink-0 text-muted-foreground`}),(0,B.jsxs)(`p`,{children:[(0,B.jsx)(`span`,{className:`font-medium`,children:`Superseded`}),` by`,` `,(0,B.jsxs)(l,{className:`inline-flex items-center gap-0.5 font-medium underline underline-offset-4`,params:{buildId:n.id},to:`/native-builds/$buildId`,children:[f(n.platform),` `,te[n.artifact_kind].label,` ·`,` `,(0,B.jsx)(p,{uuid:n.id}),(0,B.jsx)(u,{"aria-hidden":`true`,className:`size-3`})]}),`. New deploys patch from that build, so this one gets no new patches.`]})]})}function we({detail:e}){let{build:t,builtInBundle:n,channel:r}=e,i=ne(t),a=n?.childCount??0;return(0,B.jsxs)(w,{className:`overflow-hidden shadow-sm`,children:[(0,B.jsx)(D,{className:`border-b px-4 py-3`,children:(0,B.jsx)(b,{className:`text-sm`,children:(0,B.jsx)(`h2`,{children:`Built-in bundle`})})}),(0,B.jsxs)(T,{className:`flex flex-col gap-4 p-4 sm:p-6`,children:[(0,B.jsxs)(`dl`,{className:`flex flex-col gap-3`,children:[(0,B.jsx)(V,{label:`Bundle ID`,children:(0,B.jsx)(`span`,{className:`break-all font-mono text-xs`,translate:`no`,children:t.min_bundle_id})}),(0,B.jsx)(V,{label:`OTAs patching from it`,children:(0,B.jsx)(`span`,{className:`tabular-nums`,children:a===1?`1 bundle`:`${a} bundles`})}),(0,B.jsx)(V,{label:`Scope`,children:(0,B.jsxs)(`span`,{className:`flex flex-wrap items-center gap-1.5`,children:[(0,B.jsx)(l,{"aria-label":`Show the builds that embed ${r}`,search:{channel:r},to:`/native-builds`,children:(0,B.jsx)(E,{translate:`no`,variant:`outline`,children:r})}),(0,B.jsx)(`span`,{className:`text-xs`,children:f(t.platform)}),(0,B.jsxs)(`span`,{className:`text-xs text-muted-foreground`,children:[`· `,i.label]}),t.fingerprint_hash===null?(0,B.jsx)(`span`,{className:`font-mono text-xs`,translate:`no`,children:i.value}):(0,B.jsx)(fe,{label:`fingerprint`,length:12,value:t.fingerprint_hash})]})}),t.build_number?(0,B.jsx)(V,{label:`Build number`,children:(0,B.jsx)(`span`,{className:`font-mono text-xs tabular-nums`,translate:`no`,children:t.build_number})}):null,v(t)?(0,B.jsx)(V,{label:`Store`,children:(0,B.jsx)(me,{build:t,withTime:!0})}):null,(0,B.jsx)(V,{label:`Commit`,children:(0,B.jsx)(pe,{hash:t.git_commit_hash})}),(0,B.jsx)(V,{label:`Created`,children:(0,B.jsx)(p,{format:`both`,uuid:t.id})})]}),(0,B.jsx)(Ce,{detail:e}),(0,B.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`A store or test install of this build runs this bundle until its first OTA. That OTA downloads as a patch from this bundle when one exists, and as the full bundle otherwise.`})]})]})}var Te=a(c(),1),H=(e=>(e[e.Border=-1]=`Border`,e[e.Data=0]=`Data`,e[e.Function=1]=`Function`,e[e.Position=2]=`Position`,e[e.Timing=3]=`Timing`,e[e.Alignment=4]=`Alignment`,e))(H||{}),Ee=[0,1],De=[1,0],Oe=[2,3],ke=[3,2],Ae={L:Ee,M:De,Q:Oe,H:ke},je=/^\d*$/,Me=/^[A-Z0-9 $%*+./:-]*$/,U=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:`,W=1,G=40,Ne=3,Pe=3,K=40,Fe=10,Ie=[[-1,7,10,15,20,26,18,20,24,30,18,20,24,26,30,22,24,28,30,28,28,28,28,30,30,26,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,10,16,26,18,24,16,18,22,22,26,30,22,22,24,24,28,28,26,26,26,26,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28],[-1,13,22,18,26,18,24,18,22,20,24,28,26,24,20,30,24,28,28,26,30,28,30,30,30,30,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,17,28,22,16,22,28,26,26,24,28,24,28,22,24,24,30,28,28,26,28,30,24,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30]],Le=[[-1,1,1,1,1,1,2,2,2,2,4,4,4,4,4,6,6,6,6,7,8,8,9,9,10,12,12,12,13,14,15,16,17,18,19,19,20,21,22,24,25],[-1,1,1,1,2,2,4,4,4,5,5,5,8,9,9,10,10,11,13,14,16,17,17,18,20,21,23,25,26,28,29,31,33,35,37,38,40,43,45,47,49],[-1,1,1,2,2,4,4,6,6,8,8,8,10,12,16,12,17,16,18,21,20,23,23,25,27,29,34,34,35,38,40,43,45,48,51,53,56,59,62,65,68],[-1,1,1,2,4,4,4,5,6,8,8,11,11,16,16,18,16,19,21,25,25,25,34,30,32,35,37,40,42,45,48,51,54,57,60,63,66,70,74,77,81]],Re=class{constructor(e,t,n,r){if(this.version=e,this.ecc=t,e<W||e>G)throw RangeError(`Version value out of range`);if(r<-1||r>7)throw RangeError(`Mask value out of range`);this.size=e*4+17;let i=Array.from({length:this.size}).fill(!1);for(let e=0;e<this.size;e++)this.modules.push(i.slice()),this.types.push(i.map(()=>0));this.drawFunctionPatterns();let a=this.addEccAndInterleave(n);if(this.drawCodewords(a),r===-1){let e=1e9;for(let t=0;t<8;t++){this.applyMask(t),this.drawFormatBits(t);let n=this.getPenaltyScore();n<e&&(r=t,e=n),this.applyMask(t)}}this.mask=r,this.applyMask(r),this.drawFormatBits(r)}size;mask;modules=[];types=[];getModule(e,t){return e>=0&&e<this.size&&t>=0&&t<this.size&&this.modules[t][e]}drawFunctionPatterns(){for(let e=0;e<this.size;e++)this.setFunctionModule(6,e,e%2==0,H.Timing),this.setFunctionModule(e,6,e%2==0,H.Timing);this.drawFinderPattern(3,3),this.drawFinderPattern(this.size-4,3),this.drawFinderPattern(3,this.size-4);let e=this.getAlignmentPatternPositions(),t=e.length;for(let n=0;n<t;n++)for(let r=0;r<t;r++)n===0&&r===0||n===0&&r===t-1||n===t-1&&r===0||this.drawAlignmentPattern(e[n],e[r]);this.drawFormatBits(0),this.drawVersion()}drawFormatBits(e){let t=this.ecc[1]<<3|e,n=t;for(let e=0;e<10;e++)n=n<<1^(n>>>9)*1335;let r=(t<<10|n)^21522;for(let e=0;e<=5;e++)this.setFunctionModule(8,e,J(r,e));this.setFunctionModule(8,7,J(r,6)),this.setFunctionModule(8,8,J(r,7)),this.setFunctionModule(7,8,J(r,8));for(let e=9;e<15;e++)this.setFunctionModule(14-e,8,J(r,e));for(let e=0;e<8;e++)this.setFunctionModule(this.size-1-e,8,J(r,e));for(let e=8;e<15;e++)this.setFunctionModule(8,this.size-15+e,J(r,e));this.setFunctionModule(8,this.size-8,!0)}drawVersion(){if(this.version<7)return;let e=this.version;for(let t=0;t<12;t++)e=e<<1^(e>>>11)*7973;let t=this.version<<12|e;for(let e=0;e<18;e++){let n=J(t,e),r=this.size-11+e%3,i=Math.floor(e/3);this.setFunctionModule(r,i,n),this.setFunctionModule(i,r,n)}}drawFinderPattern(e,t){for(let n=-4;n<=4;n++)for(let r=-4;r<=4;r++){let i=Math.max(Math.abs(r),Math.abs(n)),a=e+r,o=t+n;a>=0&&a<this.size&&o>=0&&o<this.size&&this.setFunctionModule(a,o,i!==2&&i!==4,H.Position)}}drawAlignmentPattern(e,t){for(let n=-2;n<=2;n++)for(let r=-2;r<=2;r++)this.setFunctionModule(e+r,t+n,Math.max(Math.abs(r),Math.abs(n))!==1,H.Alignment)}setFunctionModule(e,t,n,r=H.Function){this.modules[t][e]=n,this.types[t][e]=r}addEccAndInterleave(e){let t=this.version,n=this.ecc;if(e.length!==Z(t,n))throw RangeError(`Invalid argument`);let r=Le[n[0]][t],i=Ie[n[0]][t],a=Math.floor(X(t)/8),o=r-a%r,s=Math.floor(a/r),c=[],l=Ze(i);for(let t=0,n=0;t<r;t++){let r=e.slice(n,n+s-i+(t<o?0:1));n+=r.length;let a=Qe(r,l);t<o&&r.push(0),c.push(r.concat(a))}let u=[];for(let e=0;e<c[0].length;e++)c.forEach((t,n)=>{(e!==s-i||n>=o)&&u.push(t[e])});return u}drawCodewords(e){if(e.length!==Math.floor(X(this.version)/8))throw RangeError(`Invalid argument`);let t=0;for(let n=this.size-1;n>=1;n-=2){n===6&&(n=5);for(let r=0;r<this.size;r++)for(let i=0;i<2;i++){let a=n-i,o=n+1&2?r:this.size-1-r;!this.types[o][a]&&t<e.length*8&&(this.modules[o][a]=J(e[t>>>3],7-(t&7)),t++)}}}applyMask(e){if(e<0||e>7)throw RangeError(`Mask value out of range`);for(let t=0;t<this.size;t++)for(let n=0;n<this.size;n++){let r;switch(e){case 0:r=(n+t)%2==0;break;case 1:r=t%2==0;break;case 2:r=n%3==0;break;case 3:r=(n+t)%3==0;break;case 4:r=(Math.floor(n/3)+Math.floor(t/2))%2==0;break;case 5:r=n*t%2+n*t%3==0;break;case 6:r=(n*t%2+n*t%3)%2==0;break;case 7:r=((n+t)%2+n*t%3)%2==0;break;default:throw Error(`Unreachable`)}!this.types[t][n]&&r&&(this.modules[t][n]=!this.modules[t][n])}}getPenaltyScore(){let e=0;for(let t=0;t<this.size;t++){let n=!1,r=0,i=[0,0,0,0,0,0,0];for(let a=0;a<this.size;a++)this.modules[t][a]===n?(r++,r===5?e+=Ne:r>5&&e++):(this.finderPenaltyAddHistory(r,i),n||(e+=this.finderPenaltyCountPatterns(i)*K),n=this.modules[t][a],r=1);e+=this.finderPenaltyTerminateAndCount(n,r,i)*K}for(let t=0;t<this.size;t++){let n=!1,r=0,i=[0,0,0,0,0,0,0];for(let a=0;a<this.size;a++)this.modules[a][t]===n?(r++,r===5?e+=Ne:r>5&&e++):(this.finderPenaltyAddHistory(r,i),n||(e+=this.finderPenaltyCountPatterns(i)*K),n=this.modules[a][t],r=1);e+=this.finderPenaltyTerminateAndCount(n,r,i)*K}for(let t=0;t<this.size-1;t++)for(let n=0;n<this.size-1;n++){let r=this.modules[t][n];r===this.modules[t][n+1]&&r===this.modules[t+1][n]&&r===this.modules[t+1][n+1]&&(e+=Pe)}let t=0;for(let e of this.modules)t=e.reduce((e,t)=>e+ +!!t,t);let n=this.size*this.size,r=Math.ceil(Math.abs(t*20-n*10)/n)-1;return e+=r*Fe,e}getAlignmentPatternPositions(){if(this.version===1)return[];{let e=Math.floor(this.version/7)+2,t=this.version===32?26:Math.ceil((this.version*4+4)/(e*2-2))*2,n=[6];for(let r=this.size-7;n.length<e;r-=t)n.splice(1,0,r);return n}}finderPenaltyCountPatterns(e){let t=e[1],n=t>0&&e[2]===t&&e[3]===t*3&&e[4]===t&&e[5]===t;return(n&&e[0]>=t*4&&e[6]>=t?1:0)+(n&&e[6]>=t*4&&e[0]>=t?1:0)}finderPenaltyTerminateAndCount(e,t,n){return e&&(this.finderPenaltyAddHistory(t,n),t=0),t+=this.size,this.finderPenaltyAddHistory(t,n),this.finderPenaltyCountPatterns(n)}finderPenaltyAddHistory(e,t){t[0]===0&&(e+=this.size),t.pop(),t.unshift(e)}};function q(e,t,n){if(t<0||t>31||e>>>t)throw RangeError(`Value out of range`);for(let r=t-1;r>=0;r--)n.push(e>>>r&1)}function J(e,t){return(e>>>t&1)!=0}var Y=class{constructor(e,t,n){if(this.mode=e,this.numChars=t,this.bitData=n,t<0)throw RangeError(`Invalid argument`);this.bitData=n.slice()}getData(){return this.bitData.slice()}},ze=[1,10,12,14],Be=[2,9,11,13],Ve=[4,8,16,16];function He(e,t){return e[Math.floor((t+7)/17)+1]}function Ue(e){let t=[];for(let n of e)q(n,8,t);return new Y(Ve,e.length,t)}function We(e){if(!qe(e))throw RangeError(`String contains non-numeric characters`);let t=[];for(let n=0;n<e.length;){let r=Math.min(e.length-n,3);q(Number.parseInt(e.substring(n,n+r),10),r*3+1,t),n+=r}return new Y(ze,e.length,t)}function Ge(e){if(!Je(e))throw RangeError(`String contains unencodable characters in alphanumeric mode`);let t=[],n;for(n=0;n+2<=e.length;n+=2){let r=U.indexOf(e.charAt(n))*45;r+=U.indexOf(e.charAt(n+1)),q(r,11,t)}return n<e.length&&q(U.indexOf(e.charAt(n)),6,t),new Y(Be,e.length,t)}function Ke(e){return e===``?[]:qe(e)?[We(e)]:Je(e)?[Ge(e)]:[Ue(Xe(e))]}function qe(e){return je.test(e)}function Je(e){return Me.test(e)}function Ye(e,t){let n=0;for(let r of e){let e=He(r.mode,t);if(r.numChars>=1<<e)return 1/0;n+=4+e+r.bitData.length}return n}function Xe(e){e=encodeURI(e);let t=[];for(let n=0;n<e.length;n++)e.charAt(n)===`%`?(t.push(Number.parseInt(e.substring(n+1,n+3),16)),n+=2):t.push(e.charCodeAt(n));return t}function X(e){if(e<W||e>G)throw RangeError(`Version number out of range`);let t=(16*e+128)*e+64;if(e>=2){let n=Math.floor(e/7)+2;t-=(25*n-10)*n-55,e>=7&&(t-=36)}return t}function Z(e,t){return Math.floor(X(e)/8)-Ie[t[0]][e]*Le[t[0]][e]}function Ze(e){if(e<1||e>255)throw RangeError(`Degree out of range`);let t=[];for(let n=0;n<e-1;n++)t.push(0);t.push(1);let n=1;for(let r=0;r<e;r++){for(let e=0;e<t.length;e++)t[e]=Q(t[e],n),e+1<t.length&&(t[e]^=t[e+1]);n=Q(n,2)}return t}function Qe(e,t){let n=t.map(e=>0);for(let r of e){let e=r^n.shift();n.push(0),t.forEach((t,r)=>n[r]^=Q(t,e))}return n}function Q(e,t){if(e>>>8||t>>>8)throw RangeError(`Byte out of range`);let n=0;for(let r=7;r>=0;r--)n=n<<1^(n>>>7)*285,n^=(t>>>r&1)*e;return n}function $e(e,t,n=1,r=40,i=-1,a=!0){if(!(W<=n&&n<=r&&r<=G)||i<-1||i>7)throw RangeError(`Invalid value`);let o,s;for(o=n;;o++){let n=Z(o,t)*8,i=Ye(e,o);if(i<=n){s=i;break}if(o>=r)throw RangeError(`Data too long`)}for(let e of[De,Oe,ke])a&&s<=Z(o,e)*8&&(t=e);let c=[];for(let t of e){q(t.mode[0],4,c),q(t.numChars,He(t.mode,o),c);for(let e of t.getData())c.push(e)}let l=Z(o,t)*8;q(0,Math.min(4,l-c.length),c),q(0,(8-c.length%8)%8,c);for(let e=236;c.length<l;e^=253)q(e,8,c);let u=Array.from({length:Math.ceil(c.length/8)},()=>0);return c.forEach((e,t)=>u[t>>>3]|=e<<7-(t&7)),new Re(o,t,u,i)}function et(e,t){let{ecc:n=`L`,boostEcc:r=!1,minVersion:i=1,maxVersion:a=40,maskPattern:o=-1,border:s=1}=t||{},c=typeof e==`string`?Ke(e):Array.isArray(e)?[Ue(e)]:void 0;if(!c)throw Error(`uqr only supports encoding string and binary data, but got: ${typeof e}`);let l=$e(c,Ae[n],i,a,o,r),u=tt({version:l.version,maskPattern:l.mask,size:l.size,data:l.modules,types:l.types},s);return t?.invert&&(u.data=u.data.map(e=>e.map(e=>!e))),t?.onEncoded?.(u),u}function tt(e,t=1){if(!t)return e;let{size:n}=e,r=n+t*2;e.size=r,e.data.forEach(e=>{for(let n=0;n<t;n++)e.unshift(!1),e.push(!1)});for(let n=0;n<t;n++)e.data.unshift(Array.from({length:r},e=>!1)),e.data.push(Array.from({length:r},e=>!1));let i=H.Border;e.types.forEach(e=>{for(let n=0;n<t;n++)e.unshift(i),e.push(i)});for(let n=0;n<t;n++)e.types.unshift(Array.from({length:r},e=>i)),e.types.push(Array.from({length:r},e=>i));return e}var nt=e=>{let{data:t,size:n}=et(e,{ecc:`M`,border:4}),r=``;return t.forEach((e,t)=>e.forEach((e,n)=>{e&&(r+=`M${n} ${t}h1v1h-1z`)})),{size:n,path:r}};function rt({value:e,label:t,className:n}){let{size:i,path:a}=(0,Te.useMemo)(()=>nt(e),[e]);return(0,B.jsxs)(`svg`,{"aria-label":t,className:r(`aspect-square rounded-md`,n),role:`img`,shapeRendering:`crispEdges`,viewBox:`0 0 ${i} ${i}`,children:[(0,B.jsx)(`rect`,{fill:`#fff`,height:i,width:i}),(0,B.jsx)(`path`,{d:a,fill:`#000`})]})}var it={apk:`Scan with an Android phone's camera, then open the APK to install it.`,ipa:`Scan to download the .ipa. It installs only on devices its signing profile allows (development or ad hoc); an App Store export reaches testers through TestFlight.`,aab:`Scan to download the .aab. It installs through Google Play or bundletool, not from the file.`,app:`Scan to download the .app.zip on a Mac, then install it on a simulator.`};function at({build:t}){let n=be(t.id,!0),r=n.data?.url;return r===null?(0,B.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`This storage gives no download link a phone can open without signing in, so there is no QR code. Download the build here, or open this page on the phone signed in to the console.`}):(0,B.jsxs)(`div`,{className:`flex flex-col items-center gap-2`,children:[r===void 0?n.isError?(0,B.jsxs)(C,{variant:`destructive`,children:[(0,B.jsx)(x,{}),(0,B.jsx)(y,{children:`The download link couldn't be created`}),(0,B.jsx)(S,{children:n.error.message})]}):(0,B.jsx)(e,{className:`size-48`}):(0,B.jsx)(rt,{className:`size-48`,label:`Download ${h(t)}`,value:r}),(0,B.jsx)(`p`,{className:`max-w-56 text-center text-xs text-muted-foreground`,children:it[t.artifact_kind]})]})}function $({build:e}){return(0,B.jsx)(`span`,{className:`font-mono text-foreground`,translate:`no`,children:e.submitted_version??`this build`})}function ot({build:e}){switch(e.artifact_kind){case`apk`:return(0,B.jsxs)(`div`,{className:`flex min-w-0 flex-col gap-2`,children:[(0,B.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`On an emulator or a phone over USB, download the APK and install it:`}),(0,B.jsx)(_,{label:`the install command`,value:re(e)})]});case`app`:return(0,B.jsxs)(`div`,{className:`flex min-w-0 flex-col gap-2`,children:[(0,B.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`A simulator build runs only in the iOS Simulator. Download the archive, then install it on the booted simulator:`}),(0,B.jsx)(_,{label:`the install command`,value:ie(e)})]});case`aab`:return v(e)?(0,B.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[`Submitted to Google Play internal testing as`,` `,(0,B.jsx)($,{build:e}),`. Testers install it from Google Play once its release is rolled out; on an app Play Console hasn't published, the release is a draft you roll out in Play Console.`]}):(0,B.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`An AAB installs through Google Play or bundletool, not from a download.`});case`ipa`:return v(e)?(0,B.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[`On TestFlight as `,(0,B.jsx)($,{build:e}),`: testers install it from TestFlight.`]}):(0,B.jsxs)(`div`,{className:`flex min-w-0 flex-col gap-2`,children:[(0,B.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`An IPA installs on registered devices through Xcode or Apple Configurator. For testers, upload it to TestFlight:`}),(0,B.jsx)(_,{label:`the TestFlight command`,value:`npx hot-updater testflight`})]})}}function st({build:e}){let t=h(e);return(0,B.jsxs)(w,{className:`overflow-hidden shadow-sm`,children:[(0,B.jsx)(D,{className:`border-b px-4 py-3`,children:(0,B.jsx)(b,{className:`text-sm`,children:(0,B.jsx)(`h2`,{children:`Install`})})}),(0,B.jsxs)(T,{className:`grid gap-6 p-4 sm:grid-cols-[12rem_minmax(0,1fr)] sm:p-6`,children:[(0,B.jsx)(at,{build:e}),(0,B.jsxs)(`div`,{className:`flex min-w-0 flex-col gap-4`,children:[(0,B.jsx)(ot,{build:e}),(0,B.jsxs)(`a`,{className:n({className:`h-auto min-h-11 w-full min-w-0 py-2 whitespace-normal sm:min-h-8 sm:w-fit`,variant:`outline`}),download:!0,href:d(e.id),children:[(0,B.jsx)(se,{"data-icon":`inline-start`}),(0,B.jsxs)(`span`,{className:`text-left [overflow-wrap:anywhere]`,children:[`Download `,t]})]})]})]})]})}var ct=`https://hot-updater.dev/docs/guides/bundle-diffing#first-ota-update`;function lt({detail:r,page:i,onPage:a}){let o=i.before!==void 0||i.after!==void 0,s=ve(r.build.min_bundle_id,i,o),c=o?s.data:r.patches,{next:d,previous:f}=c??{};return(0,B.jsxs)(w,{className:`overflow-hidden shadow-sm`,id:`patches`,children:[(0,B.jsx)(D,{className:`border-b px-4 py-3`,children:(0,B.jsx)(b,{className:`text-sm`,children:(0,B.jsx)(`h2`,{children:`Patches from this build`})})}),(0,B.jsxs)(T,{className:`p-0`,children:[o&&s.isError?(0,B.jsx)(`div`,{className:`p-4`,children:(0,B.jsxs)(C,{variant:`destructive`,children:[(0,B.jsx)(x,{}),(0,B.jsx)(y,{children:`Patches couldn't be loaded`}),(0,B.jsx)(S,{children:s.error.message}),(0,B.jsx)(he,{children:(0,B.jsxs)(t,{onClick:()=>void s.refetch(),size:`xs`,variant:`outline`,children:[(0,B.jsx)(de,{"data-icon":`inline-start`}),`Retry`]})})]})}):c===void 0?(0,B.jsxs)(`div`,{className:`flex flex-col gap-2 p-4`,children:[(0,B.jsx)(`span`,{className:`sr-only`,children:`Loading patches`}),(0,B.jsx)(e,{className:`h-4 w-full`}),(0,B.jsx)(e,{className:`h-4 w-2/3`})]}):c.data.length===0?o?(0,B.jsxs)(N,{className:`py-10`,children:[(0,B.jsx)(k,{children:(0,B.jsx)(j,{children:`No more patches`})}),(0,B.jsx)(t,{className:`min-h-11 sm:min-h-8`,onClick:()=>a({}),variant:`outline`,children:`Show the newest patches`})]}):(0,B.jsxs)(N,{className:`py-10`,children:[(0,B.jsxs)(k,{children:[(0,B.jsx)(O,{variant:`icon`,children:(0,B.jsx)(ce,{})}),(0,B.jsx)(j,{children:`No patches from this build`}),(0,B.jsxs)(M,{children:[`A deploy adds a patch from this build's bundle while it is its scope's newest build and the deploy config turns patches on, with `,(0,B.jsx)(`code`,{className:`font-mono`,children:`patch`}),` in`,` `,(0,B.jsx)(`code`,{className:`font-mono`,children:`hot-updater.config.ts`}),`.`]})]}),(0,B.jsx)(A,{children:(0,B.jsxs)(`a`,{className:n({className:`min-h-11 sm:min-h-8`,variant:`outline`}),href:ct,rel:`noreferrer`,target:`_blank`,children:[`Bundle diffing guide`,(0,B.jsx)(u,{"data-icon":`inline-end`})]})})]}):(0,B.jsxs)(z,{"aria-busy":o&&s.isPlaceholderData,"aria-label":`Patches from this build`,className:`table-fixed`,children:[(0,B.jsx)(P,{children:(0,B.jsxs)(L,{children:[(0,B.jsx)(F,{children:`Target bundle`}),(0,B.jsx)(F,{className:`w-28`,children:`Patch size`}),(0,B.jsx)(F,{className:`hidden w-32 sm:table-cell`,children:`Created`})]})}),(0,B.jsx)(I,{children:c.data.map(e=>(0,B.jsxs)(L,{children:[(0,B.jsx)(R,{className:`py-3 whitespace-normal`,children:(0,B.jsx)(l,{className:`block font-mono text-xs [overflow-wrap:anywhere] underline-offset-4 hover:underline`,search:{bundleId:e.bundleId},title:e.bundleId,to:`/`,translate:`no`,children:e.bundleId})}),(0,B.jsx)(R,{className:`text-xs tabular-nums`,children:m(e.byteSize)}),(0,B.jsx)(R,{className:`hidden sm:table-cell`,children:(0,B.jsx)(p,{uuid:e.bundleId})})]},e.bundleId))})]}),d!==void 0||f!==void 0?(0,B.jsxs)(`nav`,{"aria-label":`Patch pages`,className:`flex items-center justify-end gap-2 border-t px-4 py-2`,children:[(0,B.jsxs)(t,{className:`min-h-11 sm:min-h-7`,disabled:f===void 0||o&&s.isPlaceholderData,onClick:()=>a({after:f}),size:`sm`,variant:`ghost`,children:[(0,B.jsx)(ee,{"data-icon":`inline-start`}),`Newer`]}),(0,B.jsxs)(t,{className:`min-h-11 sm:min-h-7`,disabled:d===void 0||o&&s.isPlaceholderData,onClick:()=>a({before:d}),size:`sm`,variant:`ghost`,children:[`Older`,(0,B.jsx)(ae,{"data-icon":`inline-end`})]})]}):null]})]})}var ut=(e,t)=>{let n=e.data.find(e=>e.bundleId===t);if(n!==void 0)return{kind:`patch`,byteSize:n.byteSize};let r=e.data.at(-1)?.bundleId;return e.next!==void 0&&r!==void 0&&t<r?{kind:`unknown`}:{kind:`full`}};function dt({download:e}){switch(e.kind){case`patch`:return(0,B.jsxs)(`span`,{className:`text-xs`,children:[`Patch`,` `,(0,B.jsxs)(`span`,{className:`text-muted-foreground tabular-nums`,children:[`(`,m(e.byteSize),`)`]})]});case`full`:return(0,B.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`Full bundle`});case`unknown`:return(0,B.jsx)(`a`,{className:`text-xs underline-offset-4 hover:underline`,href:`#patches`,children:`See patches`})}}function ft({detail:e}){let{servedNow:t,patches:r,catalogScopeKey:i}=e,a=(0,B.jsxs)(l,{className:`inline-flex items-center gap-0.5 underline-offset-4 hover:underline`,search:{scopeKey:i},to:`/`,children:[`All releases in this scope`,(0,B.jsx)(u,{"aria-hidden":`true`,className:`size-3`})]});return(0,B.jsxs)(w,{className:`overflow-hidden shadow-sm`,children:[(0,B.jsx)(D,{className:`border-b px-4 py-3`,children:(0,B.jsx)(b,{className:`text-sm`,children:(0,B.jsx)(`h2`,{children:`Served now`})})}),(0,B.jsx)(T,{className:`p-0`,children:t.length===0?(0,B.jsxs)(N,{className:`py-10`,children:[(0,B.jsxs)(k,{children:[(0,B.jsx)(O,{variant:`icon`,children:(0,B.jsx)(Se,{})}),(0,B.jsx)(j,{children:`No OTA for this build yet`}),(0,B.jsxs)(M,{children:[`No release in this build's scope is newer than its built-in bundle. Deploy one with`,` `,(0,B.jsx)(`code`,{className:`font-mono`,children:`hot-updater deploy`}),`, and it shows here.`]})]}),(0,B.jsx)(A,{children:(0,B.jsx)(l,{className:n({className:`min-h-11 sm:min-h-8`,variant:`outline`}),search:{scopeKey:i},to:`/`,children:`All releases in this scope`})})]}):(0,B.jsxs)(B.Fragment,{children:[(0,B.jsxs)(z,{"aria-label":`Served now`,className:`table-fixed`,children:[(0,B.jsx)(P,{children:(0,B.jsxs)(L,{children:[(0,B.jsx)(F,{children:`Bundle`}),(0,B.jsx)(F,{className:`hidden w-40 md:table-cell`,children:`Rollout`}),(0,B.jsx)(F,{className:`hidden w-32 sm:table-cell`,children:`Created`}),(0,B.jsx)(F,{className:`w-32`,children:`First OTA download`})]})}),(0,B.jsx)(I,{children:t.map(e=>{let t=e.bundleId,n=e.rolloutCohortCount/ge*100;return(0,B.jsxs)(L,{children:[(0,B.jsx)(R,{className:`py-3 whitespace-normal`,children:(0,B.jsxs)(`div`,{className:`flex min-w-0 flex-col gap-1`,children:[(0,B.jsx)(l,{className:`font-mono text-xs [overflow-wrap:anywhere] underline-offset-4 hover:underline`,search:{releaseId:e.releaseId},title:t,to:`/`,translate:`no`,children:t}),e.message?(0,B.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:e.message}):null]})}),(0,B.jsx)(R,{className:`hidden md:table-cell`,children:(0,B.jsxs)(`div`,{className:`flex flex-wrap gap-1`,children:[e.targetCohorts.length>0?(0,B.jsx)(E,{variant:`secondary`,children:e.targetCohorts.length===1?`1 cohort`:`${e.targetCohorts.length} cohorts`}):(0,B.jsx)(xe,{percentage:n}),e.shouldForceUpdate?(0,B.jsx)(E,{variant:`outline`,children:`Forced`}):null]})}),(0,B.jsx)(R,{className:`hidden sm:table-cell`,children:(0,B.jsx)(p,{uuid:t})}),(0,B.jsx)(R,{children:(0,B.jsx)(dt,{download:ut(r,t)})})]},e.releaseId)})})]}),(0,B.jsxs)(`p`,{className:`border-t px-4 py-3 text-xs text-muted-foreground`,children:[`What the update check serves an install of this build now, newest first: not the history. `,a]})]})})]})}function pt({buildId:r,search:i,onSearchChange:a}){let o=ye(r),c=o.data,u={...i.patchesBefore===void 0?{}:{before:i.patchesBefore},...i.patchesAfter===void 0?{}:{after:i.patchesAfter}};return(0,B.jsxs)(`div`,{className:`flex h-svh min-h-0 flex-col`,children:[(0,B.jsxs)(`header`,{className:`sticky top-0 z-10 flex shrink-0 items-center gap-x-2 border-b bg-background px-3 py-3 sm:min-h-12 sm:bg-card/70 sm:px-4 sm:backdrop-blur-sm`,children:[(0,B.jsx)(s,{className:`-ml-1 size-11 lg:size-7`}),(0,B.jsxs)(l,{className:n({className:`min-h-11 sm:min-h-7`,size:`sm`,variant:`ghost`}),to:`/native-builds`,children:[(0,B.jsx)(ee,{"data-icon":`inline-start`}),`Native builds`]}),c?(0,B.jsxs)(`h1`,{className:`flex min-w-0 items-center gap-1.5 text-sm font-medium`,children:[(0,B.jsx)(_e,{className:`size-3.5 shrink-0 text-muted-foreground`,platform:c.build.platform}),(0,B.jsxs)(`span`,{className:`min-w-0 [overflow-wrap:anywhere]`,children:[f(c.build.platform),` `,te[c.build.artifact_kind].label,` ·`,` `,(0,B.jsx)(`span`,{translate:`no`,children:c.channel})]}),(0,B.jsx)(`span`,{className:`hidden text-xs font-normal text-muted-foreground tabular-nums sm:inline`,children:m(c.build.byte_size)})]}):(0,B.jsx)(`h1`,{className:`sr-only`,children:`Native build`})]}),(0,B.jsx)(`div`,{className:`min-h-0 min-w-0 flex-1 overflow-y-auto bg-muted/5 p-3 sm:p-6`,children:(0,B.jsx)(`div`,{className:`mx-auto flex w-full max-w-5xl flex-col gap-4 sm:gap-6`,children:o.isError?(0,B.jsxs)(C,{variant:`destructive`,children:[(0,B.jsx)(x,{}),(0,B.jsx)(y,{children:`The native build couldn't be loaded`}),(0,B.jsx)(S,{children:o.error.message}),(0,B.jsx)(he,{children:(0,B.jsxs)(t,{onClick:()=>void o.refetch(),size:`xs`,variant:`outline`,children:[(0,B.jsx)(de,{"data-icon":`inline-start`}),`Retry`]})})]}):c===void 0?(0,B.jsxs)(B.Fragment,{children:[(0,B.jsx)(`span`,{className:`sr-only`,children:`Loading the native build`}),(0,B.jsx)(e,{className:`h-56 w-full rounded-xl`}),(0,B.jsx)(e,{className:`h-64 w-full rounded-xl`})]}):c===null?(0,B.jsxs)(N,{className:`border py-16`,children:[(0,B.jsxs)(k,{children:[(0,B.jsx)(O,{variant:`icon`,children:(0,B.jsx)(ue,{})}),(0,B.jsx)(j,{children:`Native build not found`}),(0,B.jsxs)(M,{children:[`No native build has this ID. It may have been deleted with`,` `,(0,B.jsx)(`code`,{className:`font-mono`,children:`native-build delete`}),`, or be from another console.`]})]}),(0,B.jsx)(A,{children:(0,B.jsx)(l,{className:n({className:`min-h-11 sm:min-h-8`,variant:`outline`}),to:`/native-builds`,children:`Show all native builds`})})]}):(0,B.jsxs)(B.Fragment,{children:[(0,B.jsx)(st,{build:c.build}),(0,B.jsx)(we,{detail:c}),(0,B.jsx)(ft,{detail:c}),(0,B.jsx)(lt,{detail:c,onPage:e=>a({...e.before===void 0?{}:{patchesBefore:e.before},...e.after===void 0?{}:{patchesAfter:e.after}}),page:u})]})})})]})}function mt(){let{buildId:e}=g.useParams(),t=g.useSearch(),n=g.useNavigate();return(0,B.jsx)(pt,{buildId:e,onSearchChange:e=>void n({search:e,replace:!0}),search:t})}export{mt as component};
|