@limrun/ui 0.9.0-rc.14 → 0.9.0-rc.15
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/dist/components/remote-control.d.ts +125 -1
- package/dist/core/device-install/apple/provisioning.d.ts +55 -4
- package/dist/core/device-install/operations/limbuild-client.d.ts +15 -1
- package/dist/core/device-install/storage/browser-storage.d.ts +9 -5
- package/dist/core/device-install/types.d.ts +4 -1
- package/dist/device-install/index.cjs +1 -1
- package/dist/device-install/index.js +70 -64
- package/dist/device-install/react.cjs +1 -1
- package/dist/device-install/react.js +1 -1
- package/dist/device-install-dialog-DY35un0b.js +9 -0
- package/dist/device-install-dialog-chNLeiiL.mjs +2000 -0
- package/dist/device-install-dialog.css +1 -1
- package/dist/hooks/use-device-install.d.ts +5 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1286 -1116
- package/dist/use-device-install-BIrl0v-k.js +31 -0
- package/dist/{use-device-install-sDVvby1V.mjs → use-device-install-LGfEdqyM.mjs} +4388 -4271
- package/package.json +4 -2
- package/src/components/device-install/device-install-dialog.css +29 -0
- package/src/components/device-install/device-install-dialog.tsx +91 -30
- package/src/components/remote-control.tsx +535 -5
- package/src/core/device-install/apple/provisioning.test.ts +84 -0
- package/src/core/device-install/apple/provisioning.ts +91 -7
- package/src/core/device-install/operations/limbuild-client.ts +32 -2
- package/src/core/device-install/storage/browser-storage.ts +29 -14
- package/src/core/device-install/types.ts +5 -1
- package/src/hooks/use-device-install.ts +135 -59
- package/dist/device-install-dialog-CjH25hnN.js +0 -2
- package/dist/device-install-dialog-W5Xv9kWL.mjs +0 -443
- package/dist/use-device-install-Y1u6vIBB.js +0 -31
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
closeDeviceRelayTarget,
|
|
4
|
+
createAdHocProfileRequest,
|
|
4
5
|
createBundleIDRequest,
|
|
5
6
|
createDevelopmentProfileRequest,
|
|
6
7
|
downloadCertificateRequest,
|
|
8
|
+
downloadDistributionCertificateRequest,
|
|
7
9
|
downloadProfileRequest,
|
|
8
10
|
exportAppleCertificateP12,
|
|
9
11
|
fetchLimbuildInfo,
|
|
12
|
+
findAdHocProfilesRequest,
|
|
10
13
|
findDevelopmentCertificatesRequest,
|
|
14
|
+
findDistributionCertificatesRequest,
|
|
11
15
|
findBundleIDRequest,
|
|
12
16
|
findDeviceRequest,
|
|
13
17
|
findDevelopmentProfilesRequest,
|
|
@@ -29,8 +33,10 @@ import {
|
|
|
29
33
|
requestUSBAccess as requestDeviceUSBAccess,
|
|
30
34
|
startBrowserOwnedAppleIDLogin,
|
|
31
35
|
startSignedDeviceBuild,
|
|
36
|
+
getIOSOTAInstall,
|
|
32
37
|
startInstallRelay,
|
|
33
38
|
startPairingRelay,
|
|
39
|
+
submitDistributionCSRRequest,
|
|
34
40
|
submitDevelopmentCSRRequest,
|
|
35
41
|
watchBuildLogEvents,
|
|
36
42
|
type AppleIDLoginResult,
|
|
@@ -43,7 +49,9 @@ import {
|
|
|
43
49
|
type DeviceInstallBusyAction,
|
|
44
50
|
type DeviceInstallStep,
|
|
45
51
|
type DeviceInstallStepStatus,
|
|
52
|
+
type DeviceInstallSigningMode,
|
|
46
53
|
type DeviceRelayTarget,
|
|
54
|
+
type IOSOTAInstall,
|
|
47
55
|
type StoredPairRecord,
|
|
48
56
|
type StoredSigningAssets,
|
|
49
57
|
} from '../core/device-install';
|
|
@@ -74,6 +82,7 @@ export type UseDeviceInstallResult = {
|
|
|
74
82
|
logs: string[];
|
|
75
83
|
buildLogs: BuildLogLine[];
|
|
76
84
|
buildStatus: DeviceInstallBuildStatus;
|
|
85
|
+
currentExecID?: string;
|
|
77
86
|
appleSigningStatus: DeviceInstallAppleSigningStatus;
|
|
78
87
|
appleTeams: AppleDeveloperPortalTeam[];
|
|
79
88
|
appleDevices: AppleDeveloperPortalDevice[];
|
|
@@ -81,10 +90,12 @@ export type UseDeviceInstallResult = {
|
|
|
81
90
|
applePortalSummary?: ApplePortalSummary;
|
|
82
91
|
selectedAppleTeamID?: string;
|
|
83
92
|
selectedAppleDeviceIDs: string[];
|
|
93
|
+
signingMode: DeviceInstallSigningMode;
|
|
84
94
|
connectedAppleDeviceRegistered: boolean;
|
|
85
95
|
connectedDeviceInProfile?: boolean;
|
|
86
96
|
hasReusableAppleCertificate: boolean;
|
|
87
97
|
appleBundleID: string;
|
|
98
|
+
otaInstall?: IOSOTAInstall;
|
|
88
99
|
buildLogPanelOpen: boolean;
|
|
89
100
|
busyAction?: DeviceInstallBusyAction;
|
|
90
101
|
error?: string;
|
|
@@ -96,6 +107,7 @@ export type UseDeviceInstallResult = {
|
|
|
96
107
|
setSigningFiles: (files: DeviceInstallSigningFiles) => void;
|
|
97
108
|
setAppleBundleID: (bundleID: string) => void;
|
|
98
109
|
setSelectedAppleDeviceIDs: (deviceIDs: string[]) => void;
|
|
110
|
+
setSigningMode: (mode: DeviceInstallSigningMode) => void;
|
|
99
111
|
setBuildLogPanelOpen: (open: boolean) => void;
|
|
100
112
|
startAppleIDLogin: (input: DeviceInstallAppleIDLoginInput) => Promise<void>;
|
|
101
113
|
submitAppleTwoFactorCode: (code: string) => Promise<void>;
|
|
@@ -167,12 +179,15 @@ export function useDeviceInstall({
|
|
|
167
179
|
const [appleTeams, setAppleTeams] = useState<AppleDeveloperPortalTeam[]>([]);
|
|
168
180
|
const [appleDevices, setAppleDevices] = useState<AppleDeveloperPortalDevice[]>([]);
|
|
169
181
|
const [appleAppIDs, setAppleAppIDs] = useState<AppleDeveloperPortalAppID[]>([]);
|
|
182
|
+
const [signingMode, setSigningModeState] = useState<DeviceInstallSigningMode>('development');
|
|
170
183
|
const [selectedAppleDeviceIDs, setSelectedAppleDeviceIDs] = useState<string[]>([]);
|
|
171
184
|
const [applePortalSummary, setApplePortalSummary] = useState<ApplePortalSummary | undefined>();
|
|
172
185
|
const [selectedAppleTeamID, setSelectedAppleTeamID] = useState<string | undefined>();
|
|
173
186
|
const [appleBundleID, setAppleBundleID] = useState('');
|
|
174
187
|
const [reusableAppleCertificate, setReusableAppleCertificate] = useState<ReusableAppleCertificate | undefined>();
|
|
175
188
|
const [buildLogPanelOpen, setBuildLogPanelOpen] = useState(false);
|
|
189
|
+
const [otaInstall, setOTAInstall] = useState<IOSOTAInstall | undefined>();
|
|
190
|
+
const [currentExecID, setCurrentExecID] = useState<string | undefined>();
|
|
176
191
|
const [busyAction, setBusyAction] = useState<DeviceInstallBusyAction | undefined>();
|
|
177
192
|
const [error, setError] = useState<string | undefined>();
|
|
178
193
|
const [pairConfirmationRequired, setPairConfirmationRequired] = useState(false);
|
|
@@ -194,7 +209,7 @@ export function useDeviceInstall({
|
|
|
194
209
|
const setSigningFiles = useCallback((files: DeviceInstallSigningFiles) => {
|
|
195
210
|
setSigningFilesState((current) => {
|
|
196
211
|
const next = { ...current, ...files };
|
|
197
|
-
const ready = !!next.certificateFile && !!next.provisioningProfileFile
|
|
212
|
+
const ready = !!next.certificateFile && !!next.provisioningProfileFile;
|
|
198
213
|
setStepStatus('signing', ready ? 'complete' : 'active');
|
|
199
214
|
if (ready) {
|
|
200
215
|
setAppleSigningStatus('assets-ready');
|
|
@@ -205,9 +220,19 @@ export function useDeviceInstall({
|
|
|
205
220
|
setSigningAssets(undefined);
|
|
206
221
|
}, [setStepStatus]);
|
|
207
222
|
|
|
223
|
+
const setSigningMode = useCallback((mode: DeviceInstallSigningMode) => {
|
|
224
|
+
setSigningModeState(mode);
|
|
225
|
+
setSigningAssets(undefined);
|
|
226
|
+
setOTAInstall(undefined);
|
|
227
|
+
setCurrentStep('signing');
|
|
228
|
+
setStepStatuses(initialStepStatuses);
|
|
229
|
+
setAppleSigningStatus('idle');
|
|
230
|
+
log(mode === 'adhoc' ? 'Using Ad Hoc signing mode' : 'Using development signing mode');
|
|
231
|
+
}, [log]);
|
|
232
|
+
|
|
208
233
|
useEffect(() => {
|
|
209
234
|
let cancelled = false;
|
|
210
|
-
void getLatestSigningAssets().then((stored) => {
|
|
235
|
+
void getLatestSigningAssets(signingMode).then((stored) => {
|
|
211
236
|
if (cancelled || !stored) return;
|
|
212
237
|
setSigningAssets(stored);
|
|
213
238
|
setAppleBundleID(stored.bundleID);
|
|
@@ -219,7 +244,7 @@ export function useDeviceInstall({
|
|
|
219
244
|
return () => {
|
|
220
245
|
cancelled = true;
|
|
221
246
|
};
|
|
222
|
-
}, [log, setStepStatus]);
|
|
247
|
+
}, [log, setStepStatus, signingMode]);
|
|
223
248
|
|
|
224
249
|
const selectedDeveloperTeamID = useCallback(() => {
|
|
225
250
|
return developerPortalTeamID(appleTeams.find((team) => appleTeamSelectionID(team) === selectedAppleTeamID));
|
|
@@ -232,7 +257,7 @@ export function useDeviceInstall({
|
|
|
232
257
|
return;
|
|
233
258
|
}
|
|
234
259
|
let cancelled = false;
|
|
235
|
-
void findReusableAppleCertificate(teamID).then((certificate) => {
|
|
260
|
+
void findReusableAppleCertificate(teamID, signingMode).then((certificate) => {
|
|
236
261
|
if (!cancelled) {
|
|
237
262
|
setReusableAppleCertificate(certificate);
|
|
238
263
|
}
|
|
@@ -240,14 +265,14 @@ export function useDeviceInstall({
|
|
|
240
265
|
return () => {
|
|
241
266
|
cancelled = true;
|
|
242
267
|
};
|
|
243
|
-
}, [selectedDeveloperTeamID]);
|
|
268
|
+
}, [selectedDeveloperTeamID, signingMode]);
|
|
244
269
|
|
|
245
270
|
const connectedAppleDevice = selectedDevice?.hello.serialNumber
|
|
246
271
|
? appleDevices.find((device) => normalizeAppleUDID(device.deviceNumber) === normalizeAppleUDID(selectedDevice.hello.serialNumber))
|
|
247
272
|
: undefined;
|
|
248
273
|
const connectedAppleDeviceRegistered = !!connectedAppleDevice?.deviceId;
|
|
249
274
|
const manualSigningFilesReady =
|
|
250
|
-
!!signingFiles.certificateFile && !!signingFiles.provisioningProfileFile
|
|
275
|
+
!!signingFiles.certificateFile && !!signingFiles.provisioningProfileFile;
|
|
251
276
|
const signingInputsReady = !!signingAssets || manualSigningFilesReady;
|
|
252
277
|
const connectedDeviceInProfile =
|
|
253
278
|
selectedDevice?.hello.serialNumber && signingAssets
|
|
@@ -288,6 +313,7 @@ export function useDeviceInstall({
|
|
|
288
313
|
bundleID,
|
|
289
314
|
deviceUDID: selectedDevice?.hello.serialNumber,
|
|
290
315
|
teamID: selectedDeveloperTeamID(),
|
|
316
|
+
signingMode,
|
|
291
317
|
});
|
|
292
318
|
if (cached) {
|
|
293
319
|
setAppleSigningStatus('using-cached-profile');
|
|
@@ -296,7 +322,7 @@ export function useDeviceInstall({
|
|
|
296
322
|
return cached;
|
|
297
323
|
}
|
|
298
324
|
}
|
|
299
|
-
const stored = await getLatestSigningAssets();
|
|
325
|
+
const stored = await getLatestSigningAssets(signingMode);
|
|
300
326
|
if (stored) {
|
|
301
327
|
log('Using stored signing assets', stored.bundleID);
|
|
302
328
|
setSigningAssets(stored);
|
|
@@ -304,10 +330,9 @@ export function useDeviceInstall({
|
|
|
304
330
|
}
|
|
305
331
|
if (
|
|
306
332
|
!signingFiles.certificateFile ||
|
|
307
|
-
!signingFiles.provisioningProfileFile
|
|
308
|
-
!signingFiles.certificatePassword
|
|
333
|
+
!signingFiles.provisioningProfileFile
|
|
309
334
|
) {
|
|
310
|
-
throw new Error('Upload a certificate
|
|
335
|
+
throw new Error('Upload a certificate and provisioning profile.');
|
|
311
336
|
}
|
|
312
337
|
log('Preparing signing assets');
|
|
313
338
|
const [certificateP12Base64, provisioningProfileBase64, profile] = await Promise.all([
|
|
@@ -318,13 +343,17 @@ export function useDeviceInstall({
|
|
|
318
343
|
if (selectedDevice?.hello.serialNumber && !profileContainsDevice(profile, selectedDevice.hello.serialNumber)) {
|
|
319
344
|
throw new Error('Provisioning profile does not include the selected iPhone.');
|
|
320
345
|
}
|
|
346
|
+
if (signingMode === 'adhoc' && profile.getTaskAllow) {
|
|
347
|
+
throw new Error('Ad Hoc mode requires an Ad Hoc provisioning profile, not a development profile.');
|
|
348
|
+
}
|
|
321
349
|
const storageBundleId = profile.bundleID ?? profile.applicationIdentifier ?? signingFiles.provisioningProfileFile.name;
|
|
322
350
|
const storedAssets = await putSigningAssets({
|
|
323
351
|
deviceUDID: selectedDevice?.hello.serialNumber,
|
|
352
|
+
signingMode,
|
|
324
353
|
bundleID: storageBundleId,
|
|
325
354
|
certificateP12Base64,
|
|
326
355
|
certificateFileName: signingFiles.certificateFile.name,
|
|
327
|
-
certificatePassword: signingFiles.certificatePassword,
|
|
356
|
+
certificatePassword: signingFiles.certificatePassword || undefined,
|
|
328
357
|
provisioningProfileBase64,
|
|
329
358
|
profileFileName: signingFiles.provisioningProfileFile.name,
|
|
330
359
|
profile,
|
|
@@ -332,7 +361,7 @@ export function useDeviceInstall({
|
|
|
332
361
|
setSigningAssets(storedAssets);
|
|
333
362
|
log('Signing assets stored locally', storageBundleId);
|
|
334
363
|
return storedAssets;
|
|
335
|
-
}, [apiUrl, appleBundleID, log, selectedDeveloperTeamID, selectedDevice?.hello.serialNumber, signingAssets, signingFiles, token]);
|
|
364
|
+
}, [apiUrl, appleBundleID, log, selectedDeveloperTeamID, selectedDevice?.hello.serialNumber, signingAssets, signingFiles, signingMode, token]);
|
|
336
365
|
|
|
337
366
|
const startAppleIDLogin = useCallback(
|
|
338
367
|
async ({ accountName, password }: DeviceInstallAppleIDLoginInput) => {
|
|
@@ -368,7 +397,7 @@ export function useDeviceInstall({
|
|
|
368
397
|
log,
|
|
369
398
|
});
|
|
370
399
|
}
|
|
371
|
-
await refreshApplePortalSummary(apiUrl, session.appleSessionId, token, teamID, setApplePortalSummary, log);
|
|
400
|
+
await refreshApplePortalSummary(apiUrl, session.appleSessionId, token, teamID, signingMode, setApplePortalSummary, log);
|
|
372
401
|
}
|
|
373
402
|
setAppleSigningStatus(session.requiresTwoFactor ? 'two-factor-required' : 'authenticated');
|
|
374
403
|
log(
|
|
@@ -384,7 +413,7 @@ export function useDeviceInstall({
|
|
|
384
413
|
setBusyAction(undefined);
|
|
385
414
|
}
|
|
386
415
|
},
|
|
387
|
-
[apiUrl, log, setStepStatus, token],
|
|
416
|
+
[apiUrl, log, setStepStatus, signingMode, token],
|
|
388
417
|
);
|
|
389
418
|
|
|
390
419
|
const submitAppleTwoFactorCode = useCallback(
|
|
@@ -421,7 +450,7 @@ export function useDeviceInstall({
|
|
|
421
450
|
log,
|
|
422
451
|
});
|
|
423
452
|
}
|
|
424
|
-
await refreshApplePortalSummary(apiUrl, session.appleSessionId, token, teamID, setApplePortalSummary, log);
|
|
453
|
+
await refreshApplePortalSummary(apiUrl, session.appleSessionId, token, teamID, signingMode, setApplePortalSummary, log);
|
|
425
454
|
}
|
|
426
455
|
setAppleSigningStatus('authenticated');
|
|
427
456
|
log('Apple ID two-factor authentication accepted');
|
|
@@ -434,7 +463,7 @@ export function useDeviceInstall({
|
|
|
434
463
|
setBusyAction(undefined);
|
|
435
464
|
}
|
|
436
465
|
},
|
|
437
|
-
[apiUrl, log, setStepStatus, token],
|
|
466
|
+
[apiUrl, log, setStepStatus, signingMode, token],
|
|
438
467
|
);
|
|
439
468
|
|
|
440
469
|
const clearAppleIDLogin = useCallback(() => {
|
|
@@ -468,7 +497,7 @@ export function useDeviceInstall({
|
|
|
468
497
|
void (async () => {
|
|
469
498
|
try {
|
|
470
499
|
await refreshAppleAppIDs(apiUrl, session.appleSessionId, token, developerTeamID, setAppleAppIDs, setAppleBundleID);
|
|
471
|
-
await refreshApplePortalSummary(apiUrl, session.appleSessionId, token, developerTeamID, setApplePortalSummary, log);
|
|
500
|
+
await refreshApplePortalSummary(apiUrl, session.appleSessionId, token, developerTeamID, signingMode, setApplePortalSummary, log);
|
|
472
501
|
await refreshAppleDevices({
|
|
473
502
|
apiUrl,
|
|
474
503
|
token,
|
|
@@ -486,7 +515,7 @@ export function useDeviceInstall({
|
|
|
486
515
|
}
|
|
487
516
|
})();
|
|
488
517
|
},
|
|
489
|
-
[apiUrl, appleTeams, log, token],
|
|
518
|
+
[apiUrl, appleTeams, log, signingMode, token],
|
|
490
519
|
);
|
|
491
520
|
|
|
492
521
|
const registerConnectedAppleDevice = useCallback(async () => {
|
|
@@ -543,9 +572,6 @@ export function useDeviceInstall({
|
|
|
543
572
|
if (selectedAppleDeviceIDs.length === 0) {
|
|
544
573
|
throw new Error('Select at least one Apple Developer device before preparing signing assets.');
|
|
545
574
|
}
|
|
546
|
-
if (!reusableAppleCertificate && !signingFiles.certificatePassword) {
|
|
547
|
-
throw new Error('Enter a .p12 password before preparing signing assets.');
|
|
548
|
-
}
|
|
549
575
|
const selectedPortalDevice = appleDevices.find(
|
|
550
576
|
(device) => !!device.deviceNumber && selectedAppleDeviceIDs.includes(device.deviceId ?? ''),
|
|
551
577
|
);
|
|
@@ -560,6 +586,7 @@ export function useDeviceInstall({
|
|
|
560
586
|
bundleID,
|
|
561
587
|
deviceUDID: signingDeviceUDID,
|
|
562
588
|
teamID,
|
|
589
|
+
signingMode,
|
|
563
590
|
});
|
|
564
591
|
if (cached) {
|
|
565
592
|
setSigningAssets(cached);
|
|
@@ -577,8 +604,9 @@ export function useDeviceInstall({
|
|
|
577
604
|
bundleID,
|
|
578
605
|
deviceUDID: signingDeviceUDID,
|
|
579
606
|
deviceIDs: selectedAppleDeviceIDs,
|
|
580
|
-
certificatePassword: signingFiles.certificatePassword,
|
|
607
|
+
certificatePassword: signingFiles.certificatePassword || undefined,
|
|
581
608
|
reusableCertificate: reusableAppleCertificate,
|
|
609
|
+
signingMode,
|
|
582
610
|
});
|
|
583
611
|
setSigningAssets(assets);
|
|
584
612
|
setAppleSigningStatus('assets-ready');
|
|
@@ -609,6 +637,7 @@ export function useDeviceInstall({
|
|
|
609
637
|
setStepStatus,
|
|
610
638
|
reusableAppleCertificate,
|
|
611
639
|
signingFiles.certificatePassword,
|
|
640
|
+
signingMode,
|
|
612
641
|
token,
|
|
613
642
|
]);
|
|
614
643
|
|
|
@@ -621,6 +650,8 @@ export function useDeviceInstall({
|
|
|
621
650
|
setBuildLogPanelOpen(true);
|
|
622
651
|
setBuildLogs([]);
|
|
623
652
|
setBuildStatus('queued');
|
|
653
|
+
setOTAInstall(undefined);
|
|
654
|
+
setCurrentExecID(undefined);
|
|
624
655
|
stopBuildWatcherRef.current?.();
|
|
625
656
|
try {
|
|
626
657
|
const assets = await resolveSigningAssetsForBuild();
|
|
@@ -635,18 +666,38 @@ export function useDeviceInstall({
|
|
|
635
666
|
if (!result.execId) {
|
|
636
667
|
throw new Error('Build request did not return an exec ID.');
|
|
637
668
|
}
|
|
638
|
-
|
|
669
|
+
const execID = result.execId;
|
|
670
|
+
setCurrentExecID(execID);
|
|
671
|
+
log('Signed device build started', execID);
|
|
639
672
|
stopBuildWatcherRef.current = watchBuildLogEvents({
|
|
640
673
|
limbuildApiUrl: apiUrl,
|
|
641
|
-
execId:
|
|
674
|
+
execId: execID,
|
|
642
675
|
token,
|
|
643
676
|
onLine: (line) => setBuildLogs((current) => [...current, line]),
|
|
644
677
|
onStatus: (status) => {
|
|
645
678
|
setBuildStatus(status);
|
|
646
679
|
if (status === 'succeeded') {
|
|
647
680
|
setStepStatus('build', 'complete');
|
|
648
|
-
|
|
649
|
-
|
|
681
|
+
if (signingMode === 'adhoc') {
|
|
682
|
+
setStepStatus('connect', 'complete');
|
|
683
|
+
setStepStatus('install', 'active');
|
|
684
|
+
setCurrentStep('install');
|
|
685
|
+
void getIOSOTAInstall({ limbuildApiUrl: apiUrl, execId: execID, token })
|
|
686
|
+
.then((metadata) => {
|
|
687
|
+
setOTAInstall(metadata);
|
|
688
|
+
setStepStatus('install', 'complete');
|
|
689
|
+
log('Ad Hoc install QR is ready');
|
|
690
|
+
})
|
|
691
|
+
.catch((caught) => {
|
|
692
|
+
const message = errorMessage(caught);
|
|
693
|
+
setError(message);
|
|
694
|
+
setStepStatus('install', 'error');
|
|
695
|
+
log('Ad Hoc install metadata failed', message);
|
|
696
|
+
});
|
|
697
|
+
} else {
|
|
698
|
+
setStepStatus('connect', 'active');
|
|
699
|
+
setCurrentStep('connect');
|
|
700
|
+
}
|
|
650
701
|
} else if (status === 'failed' || status === 'cancelled') {
|
|
651
702
|
setStepStatus('build', 'error');
|
|
652
703
|
}
|
|
@@ -666,7 +717,7 @@ export function useDeviceInstall({
|
|
|
666
717
|
} finally {
|
|
667
718
|
setBusyAction(undefined);
|
|
668
719
|
}
|
|
669
|
-
}, [apiUrl, log, resolveSigningAssetsForBuild, setStepStatus, token]);
|
|
720
|
+
}, [apiUrl, log, resolveSigningAssetsForBuild, setStepStatus, signingMode, token]);
|
|
670
721
|
|
|
671
722
|
const requestUSBAccess = useCallback(async () => {
|
|
672
723
|
setBusyAction('usb');
|
|
@@ -679,7 +730,7 @@ export function useDeviceInstall({
|
|
|
679
730
|
target = await requestDeviceUSBAccess({ log });
|
|
680
731
|
setPairConfirmationRequired(false);
|
|
681
732
|
const storedPairRecord = await getPairRecord(target.hello.serialNumber);
|
|
682
|
-
const activeSigningAssets = signingAssets ?? (manualSigningFilesReady ? undefined : await getLatestSigningAssets());
|
|
733
|
+
const activeSigningAssets = signingAssets ?? (manualSigningFilesReady ? undefined : await getLatestSigningAssets(signingMode));
|
|
683
734
|
if (activeSigningAssets) {
|
|
684
735
|
if (!profileContainsDevice(activeSigningAssets.profile, target.hello.serialNumber)) {
|
|
685
736
|
throw new Error('Stored provisioning profile does not include the selected iPhone.');
|
|
@@ -717,7 +768,7 @@ export function useDeviceInstall({
|
|
|
717
768
|
} finally {
|
|
718
769
|
setBusyAction(undefined);
|
|
719
770
|
}
|
|
720
|
-
}, [apiUrl, cleanupDeviceAccess, log, manualSigningFilesReady, selectedDeveloperTeamID, setStepStatus, signingAssets, token]);
|
|
771
|
+
}, [apiUrl, cleanupDeviceAccess, log, manualSigningFilesReady, selectedDeveloperTeamID, setStepStatus, signingAssets, signingMode, token]);
|
|
721
772
|
|
|
722
773
|
const pairBrowser = useCallback(async () => {
|
|
723
774
|
if (!apiUrl || !selectedDevice) return;
|
|
@@ -800,6 +851,7 @@ export function useDeviceInstall({
|
|
|
800
851
|
logs,
|
|
801
852
|
buildLogs,
|
|
802
853
|
buildStatus,
|
|
854
|
+
currentExecID,
|
|
803
855
|
appleSigningStatus,
|
|
804
856
|
appleTeams,
|
|
805
857
|
appleDevices,
|
|
@@ -807,10 +859,12 @@ export function useDeviceInstall({
|
|
|
807
859
|
applePortalSummary,
|
|
808
860
|
selectedAppleTeamID,
|
|
809
861
|
selectedAppleDeviceIDs,
|
|
862
|
+
signingMode,
|
|
810
863
|
connectedAppleDeviceRegistered,
|
|
811
864
|
connectedDeviceInProfile,
|
|
812
865
|
hasReusableAppleCertificate: !!reusableAppleCertificate,
|
|
813
866
|
appleBundleID,
|
|
867
|
+
otaInstall,
|
|
814
868
|
buildLogPanelOpen,
|
|
815
869
|
busyAction,
|
|
816
870
|
error,
|
|
@@ -824,14 +878,14 @@ export function useDeviceInstall({
|
|
|
824
878
|
!!appleIDLoginRef.current &&
|
|
825
879
|
!!appleBundleID.trim() &&
|
|
826
880
|
!!selectedDeveloperTeamID() &&
|
|
827
|
-
selectedAppleDeviceIDs.length > 0
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
canInstall: !!apiUrl && !busyAction && buildStatus === 'succeeded' && !!selectedDevice && !!pairRecord,
|
|
881
|
+
selectedAppleDeviceIDs.length > 0,
|
|
882
|
+
canRequestUSBAccess: signingMode === 'development' && !busyAction && buildStatus === 'succeeded',
|
|
883
|
+
canPairBrowser: signingMode === 'development' && !!apiUrl && !busyAction && buildStatus === 'succeeded' && !!selectedDevice,
|
|
884
|
+
canInstall: signingMode === 'development' && !!apiUrl && !busyAction && buildStatus === 'succeeded' && !!selectedDevice && !!pairRecord,
|
|
832
885
|
setSigningFiles,
|
|
833
886
|
setAppleBundleID,
|
|
834
887
|
setSelectedAppleDeviceIDs,
|
|
888
|
+
setSigningMode,
|
|
835
889
|
setBuildLogPanelOpen,
|
|
836
890
|
startAppleIDLogin,
|
|
837
891
|
submitAppleTwoFactorCode,
|
|
@@ -851,9 +905,12 @@ async function fetchStoredBuildInfo(apiUrl: string, token?: string) {
|
|
|
851
905
|
return fetchLimbuildInfo(apiUrl, token);
|
|
852
906
|
}
|
|
853
907
|
|
|
854
|
-
async function findReusableAppleCertificate(
|
|
855
|
-
|
|
856
|
-
|
|
908
|
+
async function findReusableAppleCertificate(
|
|
909
|
+
teamID: string,
|
|
910
|
+
signingMode: DeviceInstallSigningMode,
|
|
911
|
+
): Promise<ReusableAppleCertificate | undefined> {
|
|
912
|
+
const stored = await getLatestSigningAssetsWithCertificate(teamID, signingMode);
|
|
913
|
+
if (!stored?.certificateID || !stored.certificateP12Base64) {
|
|
857
914
|
return undefined;
|
|
858
915
|
}
|
|
859
916
|
return {
|
|
@@ -937,6 +994,7 @@ async function refreshApplePortalSummary(
|
|
|
937
994
|
appleSessionId: string,
|
|
938
995
|
token: string | undefined,
|
|
939
996
|
teamID: string | undefined,
|
|
997
|
+
signingMode: DeviceInstallSigningMode,
|
|
940
998
|
setApplePortalSummary: (summary: ApplePortalSummary | undefined) => void,
|
|
941
999
|
log: (message: string, detail?: string) => void,
|
|
942
1000
|
) {
|
|
@@ -944,13 +1002,15 @@ async function refreshApplePortalSummary(
|
|
|
944
1002
|
proxyProvisioningRequest<AppleDeveloperPortalResponse>(
|
|
945
1003
|
apiUrl,
|
|
946
1004
|
appleSessionId,
|
|
947
|
-
findDevelopmentCertificatesRequest(teamID ?? ''),
|
|
1005
|
+
signingMode === 'adhoc' ? findDistributionCertificatesRequest(teamID ?? '') : findDevelopmentCertificatesRequest(teamID ?? ''),
|
|
948
1006
|
token,
|
|
949
1007
|
),
|
|
950
1008
|
proxyProvisioningRequest<AppleDeveloperPortalResponse>(
|
|
951
1009
|
apiUrl,
|
|
952
1010
|
appleSessionId,
|
|
953
|
-
|
|
1011
|
+
signingMode === 'adhoc'
|
|
1012
|
+
? findAdHocProfilesRequest({ bundleID: '', teamID: teamID ?? '' })
|
|
1013
|
+
: findDevelopmentProfilesRequest({ bundleID: '', teamID: teamID ?? '' }),
|
|
954
1014
|
token,
|
|
955
1015
|
),
|
|
956
1016
|
]);
|
|
@@ -1021,6 +1081,7 @@ async function prepareAppleSigningAssetsForDevice({
|
|
|
1021
1081
|
certificatePassword,
|
|
1022
1082
|
deviceIDs,
|
|
1023
1083
|
reusableCertificate,
|
|
1084
|
+
signingMode,
|
|
1024
1085
|
}: {
|
|
1025
1086
|
apiUrl: string;
|
|
1026
1087
|
token?: string;
|
|
@@ -1031,6 +1092,7 @@ async function prepareAppleSigningAssetsForDevice({
|
|
|
1031
1092
|
deviceIDs: string[];
|
|
1032
1093
|
certificatePassword?: string;
|
|
1033
1094
|
reusableCertificate?: ReusableAppleCertificate;
|
|
1095
|
+
signingMode: DeviceInstallSigningMode;
|
|
1034
1096
|
}) {
|
|
1035
1097
|
const normalizedUDID = deviceUDID?.replace(/-/g, '').replace(/[^a-fA-F0-9]/g, '') ?? '';
|
|
1036
1098
|
const appIDID = await findOrCreateAppleBundleID({
|
|
@@ -1043,21 +1105,20 @@ async function prepareAppleSigningAssetsForDevice({
|
|
|
1043
1105
|
|
|
1044
1106
|
let certificateID = reusableCertificate?.certificateID;
|
|
1045
1107
|
let certificateP12Base64 = reusableCertificate?.certificateP12Base64;
|
|
1046
|
-
let storedCertificatePassword = reusableCertificate?.certificatePassword;
|
|
1047
|
-
if (!certificateID || !certificateP12Base64
|
|
1048
|
-
if (!certificatePassword) {
|
|
1049
|
-
throw new Error('Enter a .p12 password before preparing signing assets.');
|
|
1050
|
-
}
|
|
1108
|
+
let storedCertificatePassword = reusableCertificate?.certificatePassword || undefined;
|
|
1109
|
+
if (!certificateID || !certificateP12Base64) {
|
|
1051
1110
|
const keyMaterial = await generateAppleSigningKeyAndCSR({
|
|
1052
1111
|
commonName: `Limrun ${bundleID}`,
|
|
1053
1112
|
});
|
|
1054
1113
|
const certificateResponse = await proxyProvisioningRequest<AppleDeveloperPortalResponse>(
|
|
1055
1114
|
apiUrl,
|
|
1056
1115
|
appleSessionId,
|
|
1057
|
-
|
|
1116
|
+
signingMode === 'adhoc'
|
|
1117
|
+
? submitDistributionCSRRequest({ csrPEM: keyMaterial.csrPEM, teamID })
|
|
1118
|
+
: submitDevelopmentCSRRequest({ csrPEM: keyMaterial.csrPEM, teamID }),
|
|
1058
1119
|
token,
|
|
1059
1120
|
);
|
|
1060
|
-
assertApplePortalResponseOK(certificateResponse.body, 'Apple Development certificate creation');
|
|
1121
|
+
assertApplePortalResponseOK(certificateResponse.body, signingMode === 'adhoc' ? 'Apple Distribution certificate creation' : 'Apple Development certificate creation');
|
|
1061
1122
|
certificateID =
|
|
1062
1123
|
stringField(certificateResponse.body?.certRequest, 'certificateId') ??
|
|
1063
1124
|
stringField(certificateResponse.body?.certRequest, 'certRequestId') ??
|
|
@@ -1070,7 +1131,9 @@ async function prepareAppleSigningAssetsForDevice({
|
|
|
1070
1131
|
const downloadedCertificate = await proxyProvisioningRequest(
|
|
1071
1132
|
apiUrl,
|
|
1072
1133
|
appleSessionId,
|
|
1073
|
-
|
|
1134
|
+
signingMode === 'adhoc'
|
|
1135
|
+
? downloadDistributionCertificateRequest(certificateID, teamID)
|
|
1136
|
+
: downloadCertificateRequest(certificateID, teamID),
|
|
1074
1137
|
token,
|
|
1075
1138
|
);
|
|
1076
1139
|
if (downloadedCertificate.status < 200 || downloadedCertificate.status >= 300 || !downloadedCertificate.rawBodyBase64) {
|
|
@@ -1079,24 +1142,33 @@ async function prepareAppleSigningAssetsForDevice({
|
|
|
1079
1142
|
certificateP12Base64 = exportAppleCertificateP12({
|
|
1080
1143
|
privateKeyPKCS8Base64: keyMaterial.privateKeyPKCS8Base64,
|
|
1081
1144
|
certificateBase64: downloadedCertificate.rawBodyBase64,
|
|
1082
|
-
password: certificatePassword,
|
|
1083
|
-
friendlyName: `Apple Development ${bundleID}`,
|
|
1145
|
+
password: certificatePassword ?? '',
|
|
1146
|
+
friendlyName: signingMode === 'adhoc' ? `Apple Distribution ${bundleID}` : `Apple Development ${bundleID}`,
|
|
1084
1147
|
});
|
|
1085
|
-
storedCertificatePassword = certificatePassword;
|
|
1148
|
+
storedCertificatePassword = certificatePassword || undefined;
|
|
1086
1149
|
}
|
|
1087
1150
|
|
|
1088
|
-
const profileName = `Limrun ${bundleID}`;
|
|
1151
|
+
const profileName = signingMode === 'adhoc' ? `Limrun Ad Hoc ${bundleID}` : `Limrun ${bundleID}`;
|
|
1089
1152
|
const profileResponse = await proxyProvisioningRequest<AppleDeveloperPortalResponse>(
|
|
1090
1153
|
apiUrl,
|
|
1091
1154
|
appleSessionId,
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1155
|
+
signingMode === 'adhoc'
|
|
1156
|
+
? createAdHocProfileRequest({
|
|
1157
|
+
bundleID,
|
|
1158
|
+
teamID,
|
|
1159
|
+
appIDID,
|
|
1160
|
+
certificateID,
|
|
1161
|
+
deviceIDs,
|
|
1162
|
+
name: profileName,
|
|
1163
|
+
})
|
|
1164
|
+
: createDevelopmentProfileRequest({
|
|
1165
|
+
bundleID,
|
|
1166
|
+
teamID,
|
|
1167
|
+
appIDID,
|
|
1168
|
+
certificateID,
|
|
1169
|
+
deviceIDs,
|
|
1170
|
+
name: profileName,
|
|
1171
|
+
}),
|
|
1100
1172
|
token,
|
|
1101
1173
|
);
|
|
1102
1174
|
assertApplePortalResponseOK(profileResponse.body, 'Apple provisioning profile creation');
|
|
@@ -1118,11 +1190,15 @@ async function prepareAppleSigningAssetsForDevice({
|
|
|
1118
1190
|
}
|
|
1119
1191
|
const provisioningProfileBase64 = downloadedProfile.rawBodyBase64;
|
|
1120
1192
|
const profile = parseProvisioningProfileBase64(provisioningProfileBase64);
|
|
1193
|
+
if (signingMode === 'adhoc' && profile.getTaskAllow) {
|
|
1194
|
+
throw new Error('Apple returned a development provisioning profile for Ad Hoc signing.');
|
|
1195
|
+
}
|
|
1121
1196
|
|
|
1122
1197
|
return putAppleGeneratedSigningAssets({
|
|
1123
1198
|
bundleID,
|
|
1124
1199
|
deviceUDID: normalizedUDID || undefined,
|
|
1125
1200
|
teamID,
|
|
1201
|
+
signingMode,
|
|
1126
1202
|
certificateID,
|
|
1127
1203
|
certificateP12Base64,
|
|
1128
1204
|
certificatePassword: storedCertificatePassword,
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
"use strict";require('./device-install-dialog.css');const e=require("react/jsx-runtime"),d=require("react"),w=require("./use-device-install-Y1u6vIBB.js");function S(l){var t,a,n="";if(typeof l=="string"||typeof l=="number")n+=l;else if(typeof l=="object")if(Array.isArray(l)){var c=l.length;for(t=0;t<c;t++)l[t]&&(a=S(l[t]))&&(n&&(n+=" "),n+=a)}else for(a in l)l[a]&&(n&&(n+=" "),n+=a);return n}function u(){for(var l,t,a=0,n="",c=arguments.length;a<c;a++)(l=arguments[a])&&(t=S(l))&&(n&&(n+=" "),n+=t);return n}const P=[{id:"signing",title:"Prepare signing",description:"Choose Apple ID login or upload certificates for a registered developer device."},{id:"build",title:"Build for device",description:"Start the signed iPhone build before connecting over USB."},{id:"connect",title:"Connect and pair",description:"After the build succeeds, connect the iPhone with WebUSB and pair this browser."},{id:"install",title:"Start installation",description:"Relay the last successful device build to the paired iPhone."}];function I({disabled:l,...t}){const[a,n]=d.useState(!1),[c,h]=d.useState("signing"),[o,b]=d.useState(),[g,y]=d.useState(""),[m,A]=d.useState(""),[x,C]=d.useState(""),j=d.useId(),i=w.useDeviceInstall(t);d.useEffect(()=>{h(i.currentStep)},[i.currentStep]);const f=(r,p)=>{i.setSigningFiles({[r]:p.currentTarget.files?.[0]})};return e.jsxs("div",{className:"lr-device-install",children:[e.jsx("button",{type:"button",className:"lr-device-install__trigger",disabled:l||!t.apiUrl,onClick:()=>n(!0),children:"Install to iPhone"}),a&&e.jsx("div",{className:"lr-device-install__backdrop",role:"presentation",children:e.jsxs("section",{"aria-labelledby":j,"aria-modal":"true",className:"lr-device-install__dialog",role:"dialog",children:[e.jsxs("header",{className:"lr-device-install__header",children:[e.jsxs("div",{children:[e.jsx("h2",{id:j,children:"Install to a real iPhone"}),e.jsx("p",{children:"Prepare signing, build for the registered device, connect and pair, then install from this browser."})]}),e.jsx("button",{type:"button",className:"lr-device-install__icon-button",onClick:()=>n(!1),children:"Close"})]}),i.error&&e.jsx("div",{className:"lr-device-install__error",children:i.error}),e.jsx("div",{className:"lr-device-install__steps",children:P.map((r,p)=>e.jsxs(T,{index:p+1,step:r,active:i.currentStep===r.id,open:c===r.id,status:i.stepStatuses[r.id],onToggle:()=>h(r.id),children:[r.id==="signing"&&e.jsxs("div",{className:"lr-device-install__step-body",children:[e.jsxs("div",{className:"lr-device-install__choice-grid",children:[e.jsxs("button",{type:"button",className:u("lr-device-install__choice",o==="apple-id"&&"lr-device-install__choice--active"),onClick:()=>b("apple-id"),children:[e.jsx("strong",{children:"Apple ID login"}),e.jsx("span",{children:"Sign in, choose team, bundle ID, and registered devices, then generate signing assets."})]}),e.jsxs("button",{type:"button",className:u("lr-device-install__choice",o==="upload"&&"lr-device-install__choice--active"),onClick:()=>b("upload"),children:[e.jsx("strong",{children:"Upload certificates"}),e.jsx("span",{children:"Use an existing .p12 certificate and provisioning profile."})]})]}),o==="apple-id"&&e.jsxs("div",{className:"lr-device-install__section-panel",children:[e.jsxs("div",{className:"lr-device-install__grid",children:[e.jsxs("label",{className:"lr-device-install__field",children:[e.jsx("span",{children:"Apple ID"}),e.jsx("input",{type:"email",autoComplete:"username",placeholder:"name@example.com",value:g,onChange:s=>y(s.currentTarget.value)})]}),e.jsxs("label",{className:"lr-device-install__field",children:[e.jsx("span",{children:"Apple ID password"}),e.jsx("input",{type:"password",autoComplete:"current-password",placeholder:"Password stays in this browser",value:m,onChange:s=>A(s.currentTarget.value)})]}),!i.hasReusableAppleCertificate&&e.jsxs("label",{className:"lr-device-install__field",children:[e.jsx("span",{children:"Generated .p12 password"}),e.jsx("input",{type:"password",placeholder:"Used when exporting Apple certificate",onChange:s=>i.setSigningFiles({certificatePassword:s.currentTarget.value})})]})]}),e.jsxs("div",{className:"lr-device-install__actions",children:[e.jsx("button",{type:"button",className:"lr-device-install__secondary",disabled:l||!t.apiUrl||!g||!m||i.busyAction==="signing",onClick:()=>void i.startAppleIDLogin({accountName:g,password:m}),children:i.appleSigningStatus==="authenticating"?"Signing in...":"Sign in with Apple ID"}),e.jsxs("span",{className:"lr-device-install__hint",children:["Apple password is used only by browser-side SRP. Status: ",i.appleSigningStatus]})]}),i.appleSigningStatus==="two-factor-required"&&e.jsxs("div",{className:"lr-device-install__grid",children:[e.jsxs("label",{className:"lr-device-install__field",children:[e.jsx("span",{children:"Two-factor code"}),e.jsx("input",{type:"text",inputMode:"numeric",autoComplete:"one-time-code",value:x,onChange:s=>C(s.currentTarget.value)})]}),e.jsx("button",{type:"button",className:"lr-device-install__secondary",disabled:!x||i.busyAction==="signing",onClick:()=>void i.submitAppleTwoFactorCode(x),children:"Submit Apple ID code"})]}),i.appleTeams.length>0&&e.jsxs("label",{className:"lr-device-install__field",children:[e.jsx("span",{children:"Apple Developer team"}),e.jsx("select",{value:i.selectedAppleTeamID??"",onChange:s=>i.setSelectedAppleTeamID(s.currentTarget.value||void 0),children:i.appleTeams.map((s,_)=>{const v=s.teamId??(s.providerId===void 0?void 0:String(s.providerId))??s.publicProviderId??"";return e.jsxs("option",{value:v,children:[s.name??"Apple Developer Team"," ",v?`(${v})`:""]},`${v}-${_}`)})})]}),i.appleDevices.length>0&&e.jsxs("label",{className:"lr-device-install__field",children:[e.jsx("span",{children:"Apple Developer devices"}),e.jsx("select",{multiple:!0,value:i.selectedAppleDeviceIDs,onChange:s=>i.setSelectedAppleDeviceIDs(Array.from(s.currentTarget.selectedOptions).map(_=>_.value)),children:i.appleDevices.map(s=>e.jsxs("option",{value:s.deviceId??"",children:[s.name??s.model??"Apple device"," ",s.deviceNumber??""]},s.deviceId??s.deviceNumber))})]}),i.applePortalSummary&&e.jsxs("p",{className:"lr-device-install__hint",children:["Found ",i.applePortalSummary.certificateCount," certificates and"," ",i.applePortalSummary.profileCount," provisioning profiles."]}),i.hasReusableAppleCertificate&&e.jsx("p",{className:"lr-device-install__hint",children:"Reusing the certificate and private key stored in this browser."}),e.jsx("button",{type:"button",className:"lr-device-install__primary",disabled:l||!i.canPrepareAppleSigningAssets,onClick:()=>void i.prepareAppleSigningAssets(),children:i.appleSigningStatus==="preparing-assets"?"Preparing signing assets...":"Generate certificate and profile"})]}),o==="upload"&&e.jsxs("div",{className:"lr-device-install__section-panel",children:[e.jsxs("div",{className:"lr-device-install__grid",children:[e.jsxs("label",{className:"lr-device-install__field",children:[e.jsx("span",{children:"Certificate (.p12)"}),e.jsx("input",{type:"file",accept:".p12,application/x-pkcs12",onChange:s=>f("certificateFile",s)})]}),e.jsxs("label",{className:"lr-device-install__field",children:[e.jsx("span",{children:"Provisioning profile"}),e.jsx("input",{type:"file",accept:".mobileprovision",onChange:s=>f("provisioningProfileFile",s)})]}),e.jsxs("label",{className:"lr-device-install__field",children:[e.jsx("span",{children:"Uploaded .p12 password"}),e.jsx("input",{type:"password",placeholder:"Export password",onChange:s=>i.setSigningFiles({certificatePassword:s.currentTarget.value})})]})]}),e.jsx("p",{className:"lr-device-install__hint",children:"The provisioning profile will be checked against the connected iPhone before installation."})]}),i.hasSigningAssets&&e.jsx("p",{children:"Signing assets are stored in this browser for the selected bundle and device."})]}),r.id==="connect"&&e.jsxs("div",{className:"lr-device-install__step-body",children:[e.jsx("p",{children:"WebUSB works in Chromium browsers on secure origins. Once the build succeeds, connect the iPhone over USB, approve the browser permission prompt, then pair this browser."}),e.jsxs("div",{className:"lr-device-install__actions",children:[e.jsx("button",{type:"button",className:"lr-device-install__primary",disabled:l||!i.canRequestUSBAccess,onClick:()=>void i.requestUSBAccess(),children:i.busyAction==="usb"?"Selecting iPhone...":"Allow USB access"}),e.jsx("button",{type:"button",className:"lr-device-install__secondary",disabled:l||!i.canPairBrowser,onClick:()=>void i.pairBrowser(),children:i.busyAction==="pair"?"Pairing...":i.pairConfirmationRequired?"Confirm pair record":"Pair browser"})]}),i.device&&e.jsx("div",{className:"lr-device-install__device",children:`${i.device.productName??"iPhone"} ${i.device.serialNumber??""}`.trim()}),i.pairConfirmationRequired&&e.jsxs("p",{children:["Unlock the iPhone and tap ",e.jsx("strong",{children:"Trust"})," in the system dialog, then confirm the pair record."]}),e.jsx("p",{children:i.hasPairRecord?"Pair record is stored locally. Continue to installation.":"Pair this browser once before installing."})]}),r.id==="build"&&e.jsxs("div",{className:"lr-device-install__step-body",children:[e.jsxs("div",{className:"lr-device-install__checklist",children:[e.jsx(N,{label:"Signing assets",ready:i.hasSigningInputs}),e.jsx(N,{label:"Device build",ready:i.buildStatus==="succeeded"?!0:void 0,pendingText:"Not started"})]}),e.jsx("button",{type:"button",className:"lr-device-install__primary",disabled:l||!i.canBuild,onClick:()=>void i.startDeviceBuild(),children:i.busyAction==="build"?"Starting build...":"Start device build"}),e.jsxs("details",{className:"lr-device-install__build-logs",open:i.buildLogPanelOpen,onToggle:s=>i.setBuildLogPanelOpen(s.currentTarget.open),children:[e.jsxs("summary",{children:["Build logs (",i.buildStatus,")"]}),e.jsx("pre",{children:i.buildLogs.length>0?i.buildLogs.filter(s=>s.type!=="meta").map(s=>s.data).join(`
|
|
2
|
-
`):"Build logs will appear here while the device build is running."})]})]}),r.id==="install"&&e.jsxs("div",{className:"lr-device-install__step-body",children:[e.jsx("button",{type:"button",className:"lr-device-install__primary",disabled:l||!i.canInstall,onClick:()=>void i.startInstallation(),children:i.busyAction==="install"?"Installing...":"Install last build"}),e.jsx("button",{type:"button",className:"lr-device-install__secondary",onClick:i.stopRelay,children:"Stop relay"})]})]},r.id))}),e.jsxs("footer",{className:"lr-device-install__logs",children:[e.jsx("h3",{children:"Progress"}),e.jsx("ol",{children:i.logs.map((r,p)=>e.jsx("li",{children:r},`${p}-${r.slice(0,24)}`))})]})]})})]})}function T({index:l,step:t,active:a,open:n,status:c,onToggle:h,children:o}){return e.jsxs("article",{className:u("lr-device-install__step",a&&"lr-device-install__step--active"),children:[e.jsxs("button",{type:"button",className:"lr-device-install__step-header","aria-expanded":n,onClick:h,children:[e.jsx("div",{className:"lr-device-install__step-number",children:l}),e.jsxs("div",{children:[e.jsx("h3",{children:t.title}),e.jsx("p",{children:t.description})]}),e.jsx("span",{className:u("lr-device-install__status",`lr-device-install__status--${c}`),children:c==="complete"?"✓ Completed":c})]}),n&&o]})}function N({label:l,ready:t,pendingText:a="Not ready"}){const n=t===void 0?a:t?"Ready":"Needs attention";return e.jsxs("div",{className:"lr-device-install__check-row",children:[e.jsx("span",{children:l}),e.jsx("strong",{children:n})]})}exports.DeviceInstallDialog=I;exports.clsx=u;
|