stim 1.9.0 → 1.10.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/dist/{android-_y4Ohi5z.mjs → android-787HhP5w.mjs} +119 -29
- package/dist/{android-BPGizezh.mjs → android-Bu4mbDzc.mjs} +168 -95
- package/dist/{android-DEgo4oCo.mjs → android-DPov-fv2.mjs} +2 -2
- package/dist/{android-cas-eiExNLf7.mjs → android-cas-CITmIeWY.mjs} +9 -8
- package/dist/android-cas-compiler.mjs +1 -1
- package/dist/{app-install-Uf3a83Tv.mjs → app-install-Cfmqr3TQ.mjs} +2 -2
- package/dist/budget-nDCEwtJv.mjs +620 -0
- package/dist/build-progress-BXx-ZBe4.mjs +512 -0
- package/dist/{cache-manifest-Dg7OnMrp.mjs → cache-manifest-Pubfp8wV.mjs} +1 -1
- package/dist/cache-manifest.mjs +1 -1
- package/dist/cli.mjs +16 -16
- package/dist/collector-run.d.mts +5 -1
- package/dist/collector-run.mjs +7 -7
- package/dist/{command-output-gByVmIjy.mjs → command-output-D5z2_bcF.mjs} +1 -1
- package/dist/{config-Cp9lM3wX.mjs → config-BEq0Qw_a.mjs} +14 -131
- package/dist/{dependency-state-Bq5DcLGn.mjs → dependency-state-r9UesA9a.mjs} +2 -2
- package/dist/{deps-Cip5vUm1.mjs → deps-DP4eWqea.mjs} +3 -3
- package/dist/{detached-entry-KEu0_AXL.mjs → detached-entry-DJHoca49.mjs} +1 -1
- package/dist/{dev-client-HyqISM0h.mjs → dev-client-DExzPiOa.mjs} +137 -250
- package/dist/{device-D4U-xLty.mjs → device-Czh5kO8A.mjs} +7 -7
- package/dist/{build-lock-DPXPLgTc.mjs → device-lease-CbEaIk7b.mjs} +370 -12
- package/dist/{device-pool-CnTAz8X1.mjs → device-pool-BBWLAr55.mjs} +4 -4
- package/dist/{device-remote-AQ5rQPqr.mjs → device-remote-powUHdbK.mjs} +547 -468
- package/dist/{doctor-B_Ei3bZu.mjs → doctor-CmqK1LcQ.mjs} +58 -22
- package/dist/{error-diagnostics-Vfz83GCF.mjs → error-diagnostics-xxWKNO3-.mjs} +11 -12
- package/dist/{exec-jIAlgilk.mjs → exec-DK8KaVHK.mjs} +3 -2
- package/dist/{gc-Ckw8RQHi.mjs → gc-zCDpmdHU.mjs} +500 -1114
- package/dist/{guide-BiAbhs1J.mjs → guide-DwmaD_Wa.mjs} +882 -528
- package/dist/guide-status-CWvti2Lg.mjs +125 -0
- package/dist/idle--jn7pBNe.mjs +157 -0
- package/dist/in-use-CNIWU-r-.mjs +245 -0
- package/dist/{ios-BL2NFckr.mjs → ios-COGcGEcN.mjs} +39 -65
- package/dist/{ios-BzUJWk1K.mjs → ios-CbdqTqOc.mjs} +130 -89
- package/dist/{ios-device-DPsSm0v_.mjs → ios-device-BiOsSVzd.mjs} +1 -1
- package/dist/{ios-device-D972i9wf.mjs → ios-device-DNjPXBnb.mjs} +3 -3
- package/dist/{launch-verify-Q_OtW1Rf.mjs → launch-verify-BhgkYAws.mjs} +5 -5
- package/dist/{logs-CI9NQSK7.mjs → logs-MARIy6m9.mjs} +9 -9
- package/dist/{metro-DrLHaMn2.mjs → metro-BWLOJ_Wr.mjs} +116 -10
- package/dist/{named-ports-CmLQSIRj.mjs → named-ports-DiTfSz6p.mjs} +4 -4
- package/dist/{ndjson-9uFNRwfe.mjs → ndjson-CDY9IkVC.mjs} +3 -56
- package/dist/{ndjson-DvHSsNU9.d.mts → ndjson-Du3j0AQ9.d.mts} +1 -0
- package/dist/ownership-BfPNRf3-.mjs +1180 -0
- package/dist/{ownership-D15Op8vN.mjs → ownership-D2xbLVoz.mjs} +2 -3
- package/dist/{ports-BNKoWVWZ.mjs → ports-CLSSFOuz.mjs} +3 -3
- package/dist/{project-DS112DYB.mjs → project-BXZzOABt.mjs} +2 -2
- package/dist/{reload-ZNJUo1pl.mjs → reload-CymyF6Kk.mjs} +9 -10
- package/dist/{server-bare-DWkkcIxV.mjs → server-bare-DVbb7kXH.mjs} +1 -1
- package/dist/{server-expo-B_lctBR3.mjs → server-expo-BvOCeakp.mjs} +4 -4
- package/dist/server-expo-DBVTdult.mjs +2 -0
- package/dist/{settings-D030k0t4.mjs → settings-DOugPlPz.mjs} +16 -428
- package/dist/{settings-BKNh5rl4.mjs → settings-EWYNwe72.mjs} +16 -14
- package/dist/settings.schema.json +75 -0
- package/dist/{simslim-B_LsGLuJ.mjs → simslim-DZUxzsjq.mjs} +182 -5
- package/dist/{slot-launch-DU9A-gYw.mjs → slot-launch-Dk4oTREM.mjs} +4 -4
- package/dist/{spawn-claims-Dn3C_N6w.mjs → spawn-claims-CUleC2cM.mjs} +1 -1
- package/dist/{start-DYkkKF0s.mjs → start-RbmFPeZ7.mjs} +147 -98
- package/dist/start-qWapeB4W.mjs +2 -0
- package/dist/{state-NcJzMEBF.mjs → state-WGdIbi_d.mjs} +2 -2
- package/dist/{stats-DG9e66Rz.mjs → stats-BAgJaLA4.mjs} +1 -1
- package/dist/{stats-B63-JVAY.mjs → stats-DBYJ5bxL.mjs} +4 -4
- package/dist/status-Dr4fRkym.mjs +216 -0
- package/dist/{status-S6ehL4Ui.mjs → status-Zp8kvexe.mjs} +63 -231
- package/dist/{guide-status-BAMVU0ZA.mjs → stim-installations-CINXy_su.mjs} +3 -124
- package/dist/{stop-T1R-cZRz.mjs → stop-DI4BG4Os.mjs} +2 -2
- package/dist/{stop-BO28HGqF.mjs → stop-DcEv5sk-.mjs} +22 -18
- package/dist/supervisor-run.d.mts +11 -2
- package/dist/supervisor-run.mjs +185 -17
- package/dist/{workspace-process-lock-DWaiRD0e.mjs → workspace-process-lock-BXA96myD.mjs} +2 -2
- package/dist/workspaces-wrH6dXfu.mjs +1003 -0
- package/dist/{worktree-LGB-UwgG.mjs → worktree-Bd4dRvx7.mjs} +40 -122
- package/dist/{worktree-R_cUlE7s.mjs → worktree-BlizKDpZ.mjs} +143 -18
- package/dist/{worktree-DKhSF0UX.mjs → worktree-DEG2o9F8.mjs} +1 -1
- package/dist/{xcode-BZqyxh3e.mjs → xcode-B2tBkf0m.mjs} +9 -158
- package/package.json +6 -5
- package/dist/build-progress-CVqkfPC6.mjs +0 -188
- package/dist/device-lease-Crs-HkJY.mjs +0 -366
- package/dist/logs-query-Cqma3WIu.mjs +0 -298
- package/dist/ownership-DCQPuWEc.mjs +0 -489
- package/dist/public-http-probe-CyMDrQ3c.mjs +0 -61
- package/dist/server-expo-CeILEu86.mjs +0 -2
- package/dist/sim-pool-KaIsp2Ft.mjs +0 -723
- package/dist/spawn-entry-nCE6m770.mjs +0 -14
- package/dist/workspace-state-DF2gCFhx.mjs +0 -169
|
@@ -1,427 +1,537 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as getExecutor } from "./exec-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { a as
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { a as LAUNCH_ERROR, i as INSTALL_ERROR, l as devClientDeepLink } from "./app-install-
|
|
14
|
-
import {
|
|
15
|
-
import { t as
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
1
|
+
import { u as getConfigDir } from "./config-BEq0Qw_a.mjs";
|
|
2
|
+
import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
|
|
3
|
+
import { r as createNdjsonWriter } from "./ndjson-CDY9IkVC.mjs";
|
|
4
|
+
import { N as workspaceStateFile, O as workspaceDir, P as withDirLock, i as pidExists, j as workspaceLogsDir, k as workspaceId } from "./metro-BWLOJ_Wr.mjs";
|
|
5
|
+
import { c as ownedDeviceLabel, u as resolvePackageJson } from "./project-BXZzOABt.mjs";
|
|
6
|
+
import { a as clearRemoteSession, l as readRemoteSession, s as readMetroTunnel } from "./state-WGdIbi_d.mjs";
|
|
7
|
+
import { t as withWorkspaceProcessLock } from "./workspace-process-lock-BXA96myD.mjs";
|
|
8
|
+
import { n as stripAnsi } from "./process-output-Fpl8PYi8.mjs";
|
|
9
|
+
import { B as planMetroReach } from "./settings-DOugPlPz.mjs";
|
|
10
|
+
import { u as probePublicHttp } from "./ownership-BfPNRf3-.mjs";
|
|
11
|
+
import { C as sanitizeDeviceLabel } from "./ios-COGcGEcN.mjs";
|
|
12
|
+
import { n as expoBinFromPackage, r as expoBinPath, s as findBinUpward } from "./server-expo-BvOCeakp.mjs";
|
|
13
|
+
import { a as LAUNCH_ERROR, i as INSTALL_ERROR, l as devClientDeepLink } from "./app-install-Cfmqr3TQ.mjs";
|
|
14
|
+
import { c as readMetroRecords, o as isBundleProof } from "./launch-verify-BhgkYAws.mjs";
|
|
15
|
+
import { t as compareStimVersions } from "./stim-installations-CINXy_su.mjs";
|
|
16
|
+
import { createRequire } from "node:module";
|
|
17
|
+
import { existsSync, mkdirSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
18
|
+
import { easMachineStateRoot, easMachineStateRoot as easMachineStateRoot$1, easSessionLedgerFile, easSessionLedgerLock, readEasSessionLedger, readEasSessionLedger as readEasSessionLedger$1, readJsonObject, validEasSessionClaim } from "@stim-cli/core/state";
|
|
19
|
+
import { dirname, join, resolve } from "node:path";
|
|
20
|
+
import { pathToFileURL } from "node:url";
|
|
21
|
+
import { format } from "node:util";
|
|
22
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
23
|
+
//#region src/engine/remote-cache.ts
|
|
24
|
+
const EAS_PROVIDER_PACKAGE = "eas-build-cache-provider";
|
|
25
|
+
const RESOLVE_TIMEOUT_MS = 3e4;
|
|
26
|
+
const UPLOAD_TIMEOUT_MS = 6e4;
|
|
27
|
+
const CONFIG_TIMEOUT_MS = 3e4;
|
|
28
|
+
const DYNAMIC_CONFIG_FILES = [
|
|
29
|
+
"app.config.ts",
|
|
30
|
+
"app.config.js",
|
|
31
|
+
"app.config.mjs",
|
|
32
|
+
"app.config.cjs"
|
|
33
|
+
];
|
|
34
|
+
const TIMED_OUT = Symbol("timed-out");
|
|
35
|
+
function dynamicConfigFile(root) {
|
|
36
|
+
for (const name of DYNAMIC_CONFIG_FILES) if (existsSync(join(root, name))) return name;
|
|
37
|
+
return null;
|
|
37
38
|
}
|
|
38
|
-
function
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
39
|
+
function providerFromConfig(config) {
|
|
40
|
+
if (!config || typeof config !== "object") return null;
|
|
41
|
+
const expoField = config.expo;
|
|
42
|
+
const exp = expoField && typeof expoField === "object" ? expoField : config;
|
|
43
|
+
return exp.buildCacheProvider ?? exp.experiments?.buildCacheProvider ?? null;
|
|
44
|
+
}
|
|
45
|
+
function ownerFromConfig(config) {
|
|
46
|
+
if (!config || typeof config !== "object") return null;
|
|
47
|
+
const expoField = config.expo;
|
|
48
|
+
const owner = (expoField && typeof expoField === "object" ? expoField : config).owner;
|
|
49
|
+
return typeof owner === "string" && owner.trim() !== "" ? owner.trim() : null;
|
|
50
|
+
}
|
|
51
|
+
function normalizeProvider(raw) {
|
|
52
|
+
if (raw === null || raw === void 0 || raw === "") return null;
|
|
53
|
+
if (raw === "eas") return {
|
|
54
|
+
name: "eas",
|
|
55
|
+
reference: EAS_PROVIDER_PACKAGE,
|
|
56
|
+
options: {}
|
|
56
57
|
};
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
"
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
for (const session of sessions) try {
|
|
67
|
-
if (!list().some((current) => current.name === session.name && current.platform === session.platform && current.id === session.id && current.createdAt === session.createdAt)) continue;
|
|
68
|
-
if (!stillOwned()) return;
|
|
69
|
-
if (JSON.parse(run([
|
|
70
|
-
"close",
|
|
71
|
-
"--session",
|
|
72
|
-
session.name,
|
|
73
|
-
"--session-lock",
|
|
74
|
-
"reject",
|
|
75
|
-
"--platform",
|
|
76
|
-
device.platform,
|
|
77
|
-
device.platform === "ios" ? "--udid" : "--serial",
|
|
78
|
-
device.id
|
|
79
|
-
]))?.success !== true) throw new Error("agent-device did not confirm session close");
|
|
80
|
-
report(`closed agent-device session ${session.name} on ${device.id}`);
|
|
81
|
-
} catch (error) {
|
|
82
|
-
report(`could not close agent-device session ${session.name} on ${device.id}: ${error.message}`);
|
|
58
|
+
if (typeof raw === "object") {
|
|
59
|
+
const obj = raw;
|
|
60
|
+
if (typeof obj.plugin === "string" && obj.plugin.trim() !== "") {
|
|
61
|
+
const reference = obj.plugin.trim();
|
|
62
|
+
return {
|
|
63
|
+
name: reference,
|
|
64
|
+
reference,
|
|
65
|
+
options: obj.options && typeof obj.options === "object" ? obj.options : {}
|
|
66
|
+
};
|
|
83
67
|
}
|
|
84
|
-
} catch (error) {
|
|
85
|
-
report(`could not list agent-device sessions for ${device.id}: ${error.message}`);
|
|
86
68
|
}
|
|
69
|
+
return { invalid: typeof raw === "string" ? `"${raw}"` : JSON.stringify(raw) };
|
|
87
70
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
71
|
+
function runOptionsFor(platform) {
|
|
72
|
+
return platform === "android" ? { variant: "debug" } : { configuration: "Debug" };
|
|
73
|
+
}
|
|
74
|
+
function isProviderPlugin(plugin) {
|
|
75
|
+
if (!plugin || typeof plugin !== "object") return false;
|
|
76
|
+
const p = plugin;
|
|
77
|
+
const resolves = typeof p.resolveBuildCache === "function" || typeof p.resolveRemoteBuildCache === "function";
|
|
78
|
+
const uploads = typeof p.uploadBuildCache === "function" || typeof p.uploadRemoteBuildCache === "function";
|
|
79
|
+
return resolves && uploads;
|
|
80
|
+
}
|
|
81
|
+
function cacheLevel(value) {
|
|
82
|
+
return value === "local" || value === "remote" ? value : false;
|
|
83
|
+
}
|
|
84
|
+
function exitAfterFlush(code = 0, { exit = (c) => process.exit(c), stream = process.stdout } = {}) {
|
|
91
85
|
try {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
owner: { pool: true }
|
|
96
|
-
});
|
|
97
|
-
if (result.status !== "torn-down" && result.status !== "missing") throw new Error(result.reason);
|
|
98
|
-
}) ? {
|
|
99
|
-
status: "torn-down",
|
|
100
|
-
label: avdName
|
|
101
|
-
} : {
|
|
102
|
-
status: "skipped",
|
|
103
|
-
kind: "not-parked",
|
|
104
|
-
reason: "emulator is no longer parked"
|
|
105
|
-
};
|
|
106
|
-
} catch (error) {
|
|
107
|
-
return {
|
|
108
|
-
status: "failed",
|
|
109
|
-
reason: String(error?.message || error)
|
|
110
|
-
};
|
|
86
|
+
stream.write("", () => exit(code));
|
|
87
|
+
} catch {
|
|
88
|
+
exit(code);
|
|
111
89
|
}
|
|
112
90
|
}
|
|
113
|
-
function
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
deleteSim(udid);
|
|
121
|
-
});
|
|
122
|
-
if (!removed) return {
|
|
123
|
-
status: "skipped",
|
|
124
|
-
kind: "not-parked",
|
|
125
|
-
reason: "simulator is no longer parked"
|
|
126
|
-
};
|
|
127
|
-
return {
|
|
128
|
-
status: "torn-down",
|
|
129
|
-
label: label ?? removed.name
|
|
91
|
+
function readProjectConfig(root, { run = null, timeoutMs = CONFIG_TIMEOUT_MS } = {}) {
|
|
92
|
+
const dynamic = dynamicConfigFile(root);
|
|
93
|
+
if (!dynamic) {
|
|
94
|
+
const file = join(root, "app.json");
|
|
95
|
+
if (!existsSync(file)) return {
|
|
96
|
+
config: null,
|
|
97
|
+
source: null
|
|
130
98
|
};
|
|
131
|
-
|
|
99
|
+
try {
|
|
100
|
+
return {
|
|
101
|
+
config: JSON.parse(readFileSync(file, "utf-8")),
|
|
102
|
+
source: "app.json"
|
|
103
|
+
};
|
|
104
|
+
} catch (err) {
|
|
105
|
+
return { unavailable: `app.json could not be parsed: ${firstLine(err)}` };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const bin = expoBinPath(root);
|
|
109
|
+
if (!bin) return { unavailable: `${dynamic} is code, so it has to be evaluated to read its buildCacheProvider, and the \`expo\` package is not resolvable from this project (no expo/package.json to read a bin from, and no node_modules/.bin/expo here or in any parent)` };
|
|
110
|
+
const exec = run || ((file, args, opts) => getExecutor().runFile(file, args, opts));
|
|
111
|
+
let stdout;
|
|
112
|
+
try {
|
|
113
|
+
stdout = exec(bin, [
|
|
114
|
+
"config",
|
|
115
|
+
"--json",
|
|
116
|
+
root
|
|
117
|
+
], { timeoutMs });
|
|
118
|
+
} catch (err) {
|
|
119
|
+
return { unavailable: `\`expo config --json\` failed: ${firstLine(err)}` };
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
132
122
|
return {
|
|
133
|
-
|
|
134
|
-
|
|
123
|
+
config: JSON.parse(String(stdout)),
|
|
124
|
+
source: dynamic
|
|
135
125
|
};
|
|
126
|
+
} catch (err) {
|
|
127
|
+
return { unavailable: `\`expo config --json\` did not print JSON: ${firstLine(err)}` };
|
|
136
128
|
}
|
|
137
129
|
}
|
|
138
|
-
function
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if (!sim.dataPath) throw new Error(`simulator ${udid} did not report a data path for app cleanup`);
|
|
148
|
-
const container = findAppDataContainer(sim.dataPath, park.bundleId);
|
|
149
|
-
if (container) clearAppDataContainer(container);
|
|
130
|
+
async function loadPlugin(projectRoot, reference, { requireFrom = null } = {}) {
|
|
131
|
+
const localRequire = requireFrom ? requireFrom(projectRoot) : createRequire(join(projectRoot, "package.json"));
|
|
132
|
+
const file = localRequire.resolve(reference);
|
|
133
|
+
let mod;
|
|
134
|
+
try {
|
|
135
|
+
mod = localRequire(file);
|
|
136
|
+
} catch (err) {
|
|
137
|
+
if (err?.code !== "ERR_REQUIRE_ESM") throw err;
|
|
138
|
+
mod = await import(pathToFileURL(file).href);
|
|
150
139
|
}
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
140
|
+
const plugin = mod?.default ?? mod;
|
|
141
|
+
if (!isProviderPlugin(plugin)) throw new Error(`"${reference}" does not export resolveBuildCache and uploadBuildCache functions`);
|
|
142
|
+
return plugin;
|
|
143
|
+
}
|
|
144
|
+
async function loadProjectProvider(projectRoot, { isExpo = true, run = null, requireFrom = null, timeoutMs = CONFIG_TIMEOUT_MS } = {}) {
|
|
145
|
+
if (!isExpo) return { none: true };
|
|
146
|
+
const read = readProjectConfig(projectRoot, {
|
|
147
|
+
run,
|
|
148
|
+
timeoutMs
|
|
154
149
|
});
|
|
155
|
-
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
150
|
+
if (read.unavailable) return { unavailable: read.unavailable };
|
|
151
|
+
const normalized = normalizeProvider(providerFromConfig(read.config));
|
|
152
|
+
if (!normalized) return { none: true };
|
|
153
|
+
if (normalized.invalid) return { unavailable: `buildCacheProvider is ${normalized.invalid}, which is not "eas" or { plugin: <module> }` };
|
|
154
|
+
if (normalized.reference === "@stim-cli/expo-build-cache") return { none: true };
|
|
155
|
+
let plugin;
|
|
156
|
+
try {
|
|
157
|
+
plugin = await loadPlugin(projectRoot, normalized.reference, { requireFrom });
|
|
158
|
+
} catch (err) {
|
|
159
|
+
const missing = err?.code === "MODULE_NOT_FOUND";
|
|
160
|
+
return { unavailable: normalized.name === "eas" && missing ? `the EAS build cache needs the \`${EAS_PROVIDER_PACKAGE}\` package, which is not installed in this project` : `${normalized.name} could not be loaded: ${firstLine(err)}` };
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
provider: {
|
|
164
|
+
plugin,
|
|
165
|
+
options: normalized.options ?? {}
|
|
166
|
+
},
|
|
167
|
+
name: normalized.name,
|
|
168
|
+
owner: ownerFromConfig(read.config)
|
|
165
169
|
};
|
|
170
|
+
}
|
|
171
|
+
const WHOAMI_TIMEOUT_MS = 15e3;
|
|
172
|
+
const EAS_CLI_PACKAGE = "eas-cli";
|
|
173
|
+
const EAS_CLI_BIN = "eas";
|
|
174
|
+
function parseWhoami({ stdout = "", stderr = "", exitCode = 0 } = {}) {
|
|
175
|
+
const out = stripAnsi(stdout);
|
|
176
|
+
const combined = `${out}\n${stripAnsi(stderr)}`;
|
|
177
|
+
if (/^\s*Not logged in\s*$/m.test(combined)) return { loggedOut: true };
|
|
178
|
+
if (exitCode !== 0) return { unknown: firstLine(combined.trim() || `eas whoami exited ${exitCode}`) };
|
|
179
|
+
const lines = out.split("\n").map((line) => line.trim()).filter((line) => line !== "");
|
|
180
|
+
if (lines.length === 0) return { unknown: "eas whoami printed nothing" };
|
|
181
|
+
const raw = lines[0];
|
|
182
|
+
if (raw === void 0) return { unknown: "eas whoami printed nothing" };
|
|
183
|
+
const viaToken = /\(authenticated using EXPO_TOKEN\)\s*$/.test(raw);
|
|
184
|
+
const display = raw.replace(/\s*\(authenticated using EXPO_TOKEN\)\s*$/, "").trim();
|
|
185
|
+
const accounts = [];
|
|
186
|
+
for (const line of lines) {
|
|
187
|
+
const name = /^\u2022\s*(\S+)\s*\(Role:/.exec(line)?.[1];
|
|
188
|
+
if (name !== void 0) accounts.push(name);
|
|
189
|
+
}
|
|
190
|
+
if (accounts.length === 0 && !display.endsWith("(robot)") && display !== "robot") accounts.push(display);
|
|
166
191
|
return {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
192
|
+
loggedIn: true,
|
|
193
|
+
account: display,
|
|
194
|
+
accounts: accounts.length ? accounts : null,
|
|
195
|
+
viaToken
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function isEasAuthFailureText(text) {
|
|
199
|
+
const t = stripAnsi(text || "");
|
|
200
|
+
if (t.trim() === "") return false;
|
|
201
|
+
return /not logged in/i.test(t) || /\beas login\b/i.test(t) || /EXPO_TOKEN/.test(t) || /unauthorized/i.test(t) || /not authorized/i.test(t) || /authentication (failed|required)/i.test(t);
|
|
202
|
+
}
|
|
203
|
+
function easAuthNote(status) {
|
|
204
|
+
const { code, account, owner, reason, phase = "resolve" } = status || {};
|
|
205
|
+
const because = reason ? ` (${reason})` : "";
|
|
206
|
+
if (code === "logged-out") return `eas is not authenticated${because} -- run \`eas login\` (or set EXPO_TOKEN); ` + (phase === "upload" ? "this build stayed in the local cache" : "building with the local cache only");
|
|
207
|
+
if (code === "wrong-account") return `eas is authenticated as ${account}, and this project's owner is ${owner} -- run \`eas login\` as a member of ${owner} (or set EXPO_TOKEN); consulting the EAS cache anyway`;
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
function resolveEasCliBin(projectRoot, { lookupPath = null } = {}) {
|
|
211
|
+
const fromPackage = expoBinFromPackage(resolvePackageJson(projectRoot, EAS_CLI_PACKAGE), EAS_CLI_BIN);
|
|
212
|
+
if (fromPackage) return {
|
|
213
|
+
file: fromPackage,
|
|
214
|
+
source: "project"
|
|
175
215
|
};
|
|
216
|
+
const shim = findBinUpward(projectRoot, EAS_CLI_BIN);
|
|
217
|
+
if (shim) return {
|
|
218
|
+
file: shim,
|
|
219
|
+
source: "project"
|
|
220
|
+
};
|
|
221
|
+
const onPath = lookupPath ? lookupPath() : getExecutor().findExecutable(EAS_CLI_BIN);
|
|
222
|
+
const file = (String(onPath || "").split("\n")[0] ?? "").trim();
|
|
223
|
+
return file ? {
|
|
224
|
+
file,
|
|
225
|
+
source: "path"
|
|
226
|
+
} : null;
|
|
176
227
|
}
|
|
177
|
-
|
|
178
|
-
|
|
228
|
+
const easAuthCache = /* @__PURE__ */ new Map();
|
|
229
|
+
function checkEasAuth({ projectRoot, owner = null, run = null, resolveBin = null, timeoutMs = WHOAMI_TIMEOUT_MS, cache = easAuthCache }) {
|
|
230
|
+
const key = `${projectRoot}::${owner || ""}`;
|
|
231
|
+
if (cache?.has(key)) return cache.get(key);
|
|
232
|
+
const answer = probeEasAuth({
|
|
233
|
+
projectRoot,
|
|
234
|
+
owner,
|
|
235
|
+
run,
|
|
236
|
+
resolveBin,
|
|
237
|
+
timeoutMs
|
|
238
|
+
});
|
|
239
|
+
cache?.set(key, answer);
|
|
240
|
+
return answer;
|
|
241
|
+
}
|
|
242
|
+
function probeEasAuth({ projectRoot, owner, run, resolveBin, timeoutMs }) {
|
|
243
|
+
const bin = (resolveBin || resolveEasCliBin)(projectRoot);
|
|
244
|
+
if (!bin) return {
|
|
245
|
+
failed: true,
|
|
246
|
+
code: "no-cli",
|
|
247
|
+
reason: "no `eas` executable is resolvable from this project or on PATH",
|
|
248
|
+
remedy: "Install eas-cli (`npm i -g eas-cli`, or as a project devDependency), then run `eas login`."
|
|
249
|
+
};
|
|
250
|
+
const exec = run || ((file, args, opts) => getExecutor().runFile(file, args, opts));
|
|
251
|
+
let result;
|
|
179
252
|
try {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
kind: "not-owned",
|
|
184
|
-
reason: `sim is now named "${resolved.notOwned}", not Stim-owned by name`
|
|
185
|
-
};
|
|
186
|
-
if (resolved.missing) return { status: "missing" };
|
|
187
|
-
closeOwnedDeviceSessions({
|
|
188
|
-
platform: "ios",
|
|
189
|
-
id: udid
|
|
190
|
-
}, () => Boolean(resolveOwnedIosSim(udid).sim));
|
|
191
|
-
const current = resolveOwnedIosSim(udid);
|
|
192
|
-
if (current.missing) return { status: "missing" };
|
|
193
|
-
if (current.notOwned) return {
|
|
194
|
-
status: "skipped",
|
|
195
|
-
kind: "not-owned",
|
|
196
|
-
reason: "simulator ownership changed before shutdown"
|
|
197
|
-
};
|
|
198
|
-
shutdownIosSim(udid);
|
|
199
|
-
const sim = resolved.sim;
|
|
200
|
-
if (del && park && park.max > 0) try {
|
|
201
|
-
const { record, evicted } = parkOwnedIosSim(udid, park);
|
|
202
|
-
const removed = [];
|
|
203
|
-
const failures = [];
|
|
204
|
-
for (const entry of evicted) {
|
|
205
|
-
const result = teardownParkedIosSim(entry.udid, { label: entry.name });
|
|
206
|
-
if (result.status === "torn-down") removed.push({
|
|
207
|
-
udid: entry.udid,
|
|
208
|
-
name: entry.name
|
|
209
|
-
});
|
|
210
|
-
else if (result.status === "failed") failures.push(`could not delete evicted ${entry.name} (${entry.udid}): ${result.reason}`);
|
|
211
|
-
}
|
|
212
|
-
return {
|
|
213
|
-
status: "torn-down",
|
|
214
|
-
label: label ?? sim.name ?? udid,
|
|
215
|
-
parked: {
|
|
216
|
-
udid: record.udid,
|
|
217
|
-
name: record.name
|
|
218
|
-
},
|
|
219
|
-
evicted: removed,
|
|
220
|
-
...failures.length ? { evictionFailures: failures } : {}
|
|
221
|
-
};
|
|
222
|
-
} catch (e) {
|
|
223
|
-
parkFallback = String(e?.message || e);
|
|
224
|
-
}
|
|
225
|
-
if (del) deleteIosSim(udid);
|
|
226
|
-
return {
|
|
227
|
-
status: "torn-down",
|
|
228
|
-
label: label ?? sim.name ?? udid,
|
|
229
|
-
...parkFallback ? { parkFallback } : {}
|
|
253
|
+
result = {
|
|
254
|
+
stdout: String(exec(bin.file, ["whoami"], { timeoutMs }) ?? ""),
|
|
255
|
+
exitCode: 0
|
|
230
256
|
};
|
|
231
257
|
} catch (e) {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
258
|
+
const err = e;
|
|
259
|
+
if (err?.code === "ETIMEDOUT" || err?.signal === "SIGTERM" || err?.killed) return { unknown: `eas whoami timed out after ${timeoutMs}ms` };
|
|
260
|
+
result = {
|
|
261
|
+
stdout: String(err?.stdout ?? ""),
|
|
262
|
+
stderr: String(err?.stderr ?? err?.message ?? ""),
|
|
263
|
+
exitCode: typeof err?.status === "number" ? err.status : 1
|
|
236
264
|
};
|
|
237
265
|
}
|
|
266
|
+
const parsed = parseWhoami(result);
|
|
267
|
+
if (parsed.loggedOut) return {
|
|
268
|
+
failed: true,
|
|
269
|
+
code: "logged-out",
|
|
270
|
+
reason: "eas whoami says \"Not logged in\"",
|
|
271
|
+
remedy: "Run `eas login` (or set EXPO_TOKEN)."
|
|
272
|
+
};
|
|
273
|
+
if (parsed.unknown) return { unknown: parsed.unknown };
|
|
274
|
+
if (owner && Array.isArray(parsed.accounts) && !parsed.accounts.includes(owner)) return {
|
|
275
|
+
failed: true,
|
|
276
|
+
code: "wrong-account",
|
|
277
|
+
account: parsed.account,
|
|
278
|
+
accounts: parsed.accounts,
|
|
279
|
+
owner,
|
|
280
|
+
reason: `eas is authenticated as ${parsed.account} (accounts: ${parsed.accounts.join(", ")}), which does not include this project's owner ${owner}`,
|
|
281
|
+
remedy: `Run \`eas login\` as a member of ${owner}, or set EXPO_TOKEN to a token for it.`
|
|
282
|
+
};
|
|
283
|
+
return {
|
|
284
|
+
ok: true,
|
|
285
|
+
account: parsed.account,
|
|
286
|
+
accounts: parsed.accounts,
|
|
287
|
+
viaToken: parsed.viaToken,
|
|
288
|
+
source: bin.source
|
|
289
|
+
};
|
|
238
290
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
291
|
+
const capturing = [];
|
|
292
|
+
const abandoned = /* @__PURE__ */ new Set();
|
|
293
|
+
let patched = null;
|
|
294
|
+
const PROVIDER_CONTEXT = new AsyncLocalStorage();
|
|
295
|
+
function uploadDestination(lines) {
|
|
296
|
+
const text = (lines || []).map(stripAnsi);
|
|
297
|
+
for (const line of text) {
|
|
298
|
+
const url = /(https?:\/\/[^\s'"]+)/.exec(line)?.[1];
|
|
299
|
+
if (url !== void 0) return url.replace(/[.,)\]]+$/, "");
|
|
246
300
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const surveyed = listOrphanedAvdDirectories(candidate.name).find((entry) => entry.directory === candidate.directory);
|
|
251
|
-
if (!surveyed || surveyed.name !== candidate.name || surveyed.dev !== candidate.dev || surveyed.ino !== candidate.ino) throw new Error(`AVD data at ${candidate.directory} changed or is registered; it was kept.`);
|
|
252
|
-
assertOwnedAvdStopped(candidate.name, { resolveDirectory: () => candidate.directory });
|
|
253
|
-
const detached = withConfigLock(() => {
|
|
254
|
-
const current = lstatSync(candidate.directory);
|
|
255
|
-
if (!current.isDirectory() || current.dev !== candidate.dev || current.ino !== candidate.ino) throw new Error(`AVD data at ${candidate.directory} changed or is registered; it was kept.`);
|
|
256
|
-
assertAvdReferences(candidate.name, owner);
|
|
257
|
-
const destination = join(dirname(candidate.directory), `stim-gc-${randomUUID()}.avd`);
|
|
258
|
-
renameSync(candidate.directory, destination);
|
|
259
|
-
return destination;
|
|
260
|
-
});
|
|
261
|
-
const current = lstatSync(detached);
|
|
262
|
-
if (!current.isDirectory() || current.dev !== candidate.dev || current.ino !== candidate.ino) throw new Error(`Detached AVD data changed at ${detached}; it was kept.`);
|
|
263
|
-
try {
|
|
264
|
-
rmSync(detached, { recursive: true });
|
|
265
|
-
} catch (error) {
|
|
266
|
-
throw new Error(`Could not remove AVD data at ${detached}; retry gc --delete: ${error.message}`, { cause: error });
|
|
301
|
+
for (const line of text) {
|
|
302
|
+
const slug = /\bto\s+(@?[\w.-]+\/[\w.-]+)/i.exec(line)?.[1];
|
|
303
|
+
if (slug !== void 0) return slug.replace(/[.,)\]]+$/, "");
|
|
267
304
|
}
|
|
305
|
+
return null;
|
|
268
306
|
}
|
|
269
|
-
function
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
307
|
+
function providerNote(text) {
|
|
308
|
+
return `${"cache".padEnd(11)} ${text}`;
|
|
309
|
+
}
|
|
310
|
+
function currentFrame() {
|
|
311
|
+
const store = PROVIDER_CONTEXT.getStore();
|
|
312
|
+
return store && (capturing.includes(store) || abandoned.has(store)) ? store : null;
|
|
313
|
+
}
|
|
314
|
+
function install() {
|
|
315
|
+
if (patched && process.stdout.write === patched.patchedWrite) return;
|
|
316
|
+
const stdout = process.stdout;
|
|
317
|
+
const write = stdout.write.bind(stdout);
|
|
318
|
+
const log = console.log;
|
|
319
|
+
const passthrough = write;
|
|
320
|
+
const patchedWrite = ((chunk, encoding, callback) => {
|
|
321
|
+
const frame = currentFrame();
|
|
322
|
+
if (!frame) return passthrough(chunk, encoding, callback);
|
|
323
|
+
const cb = typeof encoding === "function" ? encoding : callback;
|
|
324
|
+
absorb(frame, typeof chunk === "string" ? chunk : String(chunk));
|
|
325
|
+
if (typeof cb === "function") cb();
|
|
326
|
+
return true;
|
|
327
|
+
});
|
|
328
|
+
const patchedLog = (...args) => {
|
|
329
|
+
const frame = currentFrame();
|
|
330
|
+
if (!frame) return log(...args);
|
|
331
|
+
absorb(frame, `${format(...args)}\n`);
|
|
278
332
|
};
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
333
|
+
stdout.write = patchedWrite;
|
|
334
|
+
console.log = patchedLog;
|
|
335
|
+
patched = {
|
|
336
|
+
stdout,
|
|
337
|
+
write,
|
|
338
|
+
log,
|
|
339
|
+
patchedWrite,
|
|
340
|
+
patchedLog
|
|
286
341
|
};
|
|
287
342
|
}
|
|
288
|
-
function
|
|
289
|
-
if (
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
343
|
+
function uninstall() {
|
|
344
|
+
if (!patched || capturing.length || abandoned.size) return;
|
|
345
|
+
if (patched.stdout.write === patched.patchedWrite) patched.stdout.write = patched.write;
|
|
346
|
+
if (console.log === patched.patchedLog) console.log = patched.log;
|
|
347
|
+
patched = null;
|
|
348
|
+
}
|
|
349
|
+
function absorb(frame, chunk) {
|
|
295
350
|
try {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
};
|
|
305
|
-
} finally {
|
|
306
|
-
(0, ownership_claim_exports.releaseClaim)(claim);
|
|
351
|
+
process.stderr.write(chunk);
|
|
352
|
+
} catch {}
|
|
353
|
+
frame.pending += chunk;
|
|
354
|
+
let index = frame.pending.indexOf("\n");
|
|
355
|
+
while (index !== -1) {
|
|
356
|
+
emitLine(frame, frame.pending.slice(0, index));
|
|
357
|
+
frame.pending = frame.pending.slice(index + 1);
|
|
358
|
+
index = frame.pending.indexOf("\n");
|
|
307
359
|
}
|
|
308
360
|
}
|
|
309
|
-
function
|
|
310
|
-
|
|
361
|
+
function emitLine(frame, raw) {
|
|
362
|
+
const line = stripAnsi(raw).trim();
|
|
363
|
+
if (line === "") return;
|
|
364
|
+
frame.lines.push(line);
|
|
365
|
+
const writer = frame.writer();
|
|
311
366
|
try {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
367
|
+
writer?.write({
|
|
368
|
+
src: "build",
|
|
369
|
+
level: "debug",
|
|
370
|
+
event: "provider",
|
|
371
|
+
msg: line
|
|
372
|
+
});
|
|
373
|
+
} catch {}
|
|
374
|
+
frame.onLine?.(line);
|
|
375
|
+
}
|
|
376
|
+
function beginCapture({ logWriter = null, projectRoot = null, platform = null, onLine = null } = {}) {
|
|
377
|
+
let own = null;
|
|
378
|
+
const frame = {
|
|
379
|
+
lines: [],
|
|
380
|
+
pending: "",
|
|
381
|
+
onLine,
|
|
382
|
+
writer: () => {
|
|
383
|
+
if (logWriter) return logWriter;
|
|
384
|
+
if (own) return own;
|
|
385
|
+
if (!projectRoot || !platform) return null;
|
|
386
|
+
own = createNdjsonWriter(join(workspaceLogsDir(projectRoot), `build-${platform}.ndjson`));
|
|
387
|
+
return own;
|
|
388
|
+
},
|
|
389
|
+
close: () => {
|
|
390
|
+
own?.close?.();
|
|
391
|
+
own = null;
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
capturing.push(frame);
|
|
395
|
+
install();
|
|
396
|
+
return frame;
|
|
397
|
+
}
|
|
398
|
+
function endCapture(frame) {
|
|
399
|
+
if (!frame) return;
|
|
400
|
+
const at = capturing.lastIndexOf(frame);
|
|
401
|
+
if (at !== -1) capturing.splice(at, 1);
|
|
402
|
+
abandoned.delete(frame);
|
|
403
|
+
if (frame.pending !== "") {
|
|
404
|
+
const rest = frame.pending;
|
|
405
|
+
frame.pending = "";
|
|
406
|
+
emitLine(frame, rest);
|
|
407
|
+
}
|
|
408
|
+
frame.close();
|
|
409
|
+
uninstall();
|
|
410
|
+
}
|
|
411
|
+
function abandonCapture(frame, work) {
|
|
412
|
+
if (!frame) return;
|
|
413
|
+
const at = capturing.lastIndexOf(frame);
|
|
414
|
+
if (at !== -1) capturing.splice(at, 1);
|
|
415
|
+
abandoned.add(frame);
|
|
416
|
+
Promise.resolve(work).then(() => endCapture(frame), () => endCapture(frame));
|
|
417
|
+
}
|
|
418
|
+
async function resolveRemote({ provider, platform, projectRoot, fingerprintHash, runOptions = null, timeoutMs = RESOLVE_TIMEOUT_MS, logWriter = null } = {}) {
|
|
419
|
+
if (!provider?.plugin || !fingerprintHash) return null;
|
|
420
|
+
const opts = runOptions || runOptionsFor(platform);
|
|
421
|
+
const outcome = await withBudget(async () => {
|
|
422
|
+
const props = {
|
|
423
|
+
fingerprintHash: await providerFingerprint({
|
|
424
|
+
provider,
|
|
425
|
+
platform,
|
|
426
|
+
projectRoot,
|
|
427
|
+
runOptions: opts
|
|
428
|
+
}) ?? fingerprintHash,
|
|
429
|
+
platform,
|
|
430
|
+
runOptions: opts,
|
|
431
|
+
projectRoot
|
|
323
432
|
};
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
433
|
+
return typeof provider.plugin.resolveBuildCache === "function" ? provider.plugin.resolveBuildCache(props, provider.options) : provider.plugin.resolveRemoteBuildCache(props, provider.options);
|
|
434
|
+
}, timeoutMs, {
|
|
435
|
+
logWriter,
|
|
436
|
+
projectRoot,
|
|
437
|
+
platform
|
|
438
|
+
});
|
|
439
|
+
if (outcome.timedOut) return { timedOut: true };
|
|
440
|
+
if (outcome.error) return { failed: firstLine(outcome.error) };
|
|
441
|
+
const appPath = typeof outcome.value === "string" ? outcome.value.trim() : "";
|
|
442
|
+
if (!appPath) return null;
|
|
443
|
+
if (!existsSync(appPath)) return { failed: `returned ${appPath}, which does not exist` };
|
|
444
|
+
return { appPath };
|
|
445
|
+
}
|
|
446
|
+
async function uploadRemote({ provider, platform, projectRoot, fingerprintHash, buildPath, runOptions = null, timeoutMs = UPLOAD_TIMEOUT_MS, logWriter = null, note = (line) => console.error(line) } = {}) {
|
|
447
|
+
if (!provider?.plugin || !fingerprintHash || !buildPath) return { skipped: true };
|
|
448
|
+
const opts = runOptions || runOptionsFor(platform);
|
|
449
|
+
let announced = false;
|
|
450
|
+
const onLine = (line) => {
|
|
451
|
+
if (announced) return;
|
|
452
|
+
const dest = uploadDestination([line]);
|
|
453
|
+
if (!dest) return;
|
|
454
|
+
announced = true;
|
|
455
|
+
note(providerNote(`uploading to ${dest}`));
|
|
456
|
+
};
|
|
457
|
+
const outcome = await withBudget(async () => {
|
|
458
|
+
const props = {
|
|
459
|
+
projectRoot,
|
|
460
|
+
platform,
|
|
461
|
+
fingerprintHash: await providerFingerprint({
|
|
462
|
+
provider,
|
|
463
|
+
platform,
|
|
464
|
+
projectRoot,
|
|
465
|
+
runOptions: opts
|
|
466
|
+
}) ?? fingerprintHash,
|
|
467
|
+
buildPath,
|
|
468
|
+
runOptions: opts
|
|
327
469
|
};
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
470
|
+
return typeof provider.plugin.uploadBuildCache === "function" ? provider.plugin.uploadBuildCache(props, provider.options) : provider.plugin.uploadRemoteBuildCache(props, provider.options);
|
|
471
|
+
}, timeoutMs, {
|
|
472
|
+
logWriter,
|
|
473
|
+
projectRoot,
|
|
474
|
+
platform,
|
|
475
|
+
onLine
|
|
476
|
+
});
|
|
477
|
+
if (outcome.timedOut) return { timedOut: true };
|
|
478
|
+
if (outcome.error) return { failed: firstLine(outcome.error) };
|
|
479
|
+
if (typeof outcome.value !== "string" || outcome.value.trim() === "") {
|
|
480
|
+
const authLine = outcome.lines.find((line) => isEasAuthFailureText(line));
|
|
481
|
+
return { failed: authLine ? firstLine(authLine) : "the provider returned no upload destination" };
|
|
482
|
+
}
|
|
483
|
+
const destination = uploadDestination(outcome.lines);
|
|
484
|
+
return destination ? {
|
|
485
|
+
uploaded: true,
|
|
486
|
+
destination
|
|
487
|
+
} : { uploaded: true };
|
|
488
|
+
}
|
|
489
|
+
async function providerFingerprint({ provider, platform, projectRoot, runOptions }) {
|
|
490
|
+
if (typeof provider.plugin.calculateFingerprintHash !== "function") return null;
|
|
491
|
+
try {
|
|
492
|
+
const hash = await provider.plugin.calculateFingerprintHash({
|
|
493
|
+
projectRoot,
|
|
494
|
+
platform,
|
|
495
|
+
runOptions
|
|
496
|
+
}, provider.options);
|
|
497
|
+
return typeof hash === "string" && hash.trim() !== "" ? hash.trim() : null;
|
|
498
|
+
} catch {
|
|
499
|
+
return null;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
async function withBudget(factory, ms, capture) {
|
|
503
|
+
let timer = null;
|
|
504
|
+
const timeout = new Promise((resolve) => {
|
|
505
|
+
timer = setTimeout(() => resolve(TIMED_OUT), ms);
|
|
506
|
+
timer?.unref?.();
|
|
507
|
+
});
|
|
508
|
+
const frame = beginCapture(capture || {});
|
|
509
|
+
const work = Promise.resolve().then(() => PROVIDER_CONTEXT.run(frame, factory)).then((value) => ({ value }), (error) => ({ error }));
|
|
510
|
+
try {
|
|
511
|
+
const settled = await Promise.race([work, timeout]);
|
|
512
|
+
if (settled === TIMED_OUT) {
|
|
513
|
+
abandonCapture(frame, work);
|
|
514
|
+
return {
|
|
515
|
+
timedOut: true,
|
|
516
|
+
lines: frame.lines
|
|
354
517
|
};
|
|
355
|
-
if (current.missing) return teardownUnregisteredAvd(avdName, del, owner);
|
|
356
|
-
if (current.serial) throw new Error(`Owned AVD ${avdName} started again before deletion.`);
|
|
357
|
-
assertStopped(avdName);
|
|
358
|
-
withConfigLock(() => assertAvdReferences(avdName, owner));
|
|
359
|
-
if (park && park.max > 0) try {
|
|
360
|
-
const systemImage = ownedAvdSystemImage(avdName);
|
|
361
|
-
if (!systemImage || !park.configuration || !ownedAvdMatchesConfiguration(avdName, park.configuration)) throw new Error("the AVD has no verified creation configuration");
|
|
362
|
-
const evicted = parkSim({
|
|
363
|
-
platform: "android",
|
|
364
|
-
projectPath: park.projectPath,
|
|
365
|
-
slot: park.slot,
|
|
366
|
-
max: park.max,
|
|
367
|
-
record: {
|
|
368
|
-
udid: avdName,
|
|
369
|
-
name: avdName,
|
|
370
|
-
systemImage,
|
|
371
|
-
configuration: park.configuration,
|
|
372
|
-
parkedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
373
|
-
}
|
|
374
|
-
});
|
|
375
|
-
const removed = [];
|
|
376
|
-
const failures = [];
|
|
377
|
-
for (const entry of evicted) {
|
|
378
|
-
const result = teardownParkedAvd(entry.name);
|
|
379
|
-
if (result.status === "torn-down") removed.push({
|
|
380
|
-
udid: entry.name,
|
|
381
|
-
name: entry.name,
|
|
382
|
-
platform: "android"
|
|
383
|
-
});
|
|
384
|
-
else if (result.status === "failed") failures.push(`could not delete evicted ${entry.name}: ${result.reason}`);
|
|
385
|
-
}
|
|
386
|
-
return {
|
|
387
|
-
status: "torn-down",
|
|
388
|
-
label: avdName,
|
|
389
|
-
parked: {
|
|
390
|
-
udid: avdName,
|
|
391
|
-
name: avdName,
|
|
392
|
-
platform: "android"
|
|
393
|
-
},
|
|
394
|
-
evicted: removed,
|
|
395
|
-
...failures.length ? { evictionFailures: failures } : {}
|
|
396
|
-
};
|
|
397
|
-
} catch (error) {
|
|
398
|
-
parkFallback = String(error?.message || error);
|
|
399
|
-
}
|
|
400
|
-
const directory = ownedAvdDirectory(avdName);
|
|
401
|
-
const paths = avdStorageRoots().map((root) => join(root, `${avdName}.ini`));
|
|
402
|
-
if (directory) paths.push(directory);
|
|
403
|
-
(0, ownership_claim_exports.markClaimChildPending)(claim);
|
|
404
|
-
try {
|
|
405
|
-
deleteAvd(avdName);
|
|
406
|
-
} finally {
|
|
407
|
-
(0, ownership_claim_exports.clearClaimChild)(claim);
|
|
408
|
-
}
|
|
409
|
-
const remaining = paths.filter(avdPathExists);
|
|
410
|
-
if (remaining.length) throw new Error(`AVD ${avdName} was only partially deleted; data remains at ${remaining.join(", ")}.`);
|
|
411
518
|
}
|
|
519
|
+
endCapture(frame);
|
|
412
520
|
return {
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
serial: resolved.serial ?? null,
|
|
416
|
-
...parkFallback ? { parkFallback } : {}
|
|
417
|
-
};
|
|
418
|
-
} catch (e) {
|
|
419
|
-
return {
|
|
420
|
-
status: "failed",
|
|
421
|
-
reason: String(e?.message || e)
|
|
521
|
+
...settled,
|
|
522
|
+
lines: frame.lines
|
|
422
523
|
};
|
|
524
|
+
} catch (err) {
|
|
525
|
+
endCapture(frame);
|
|
526
|
+
throw err;
|
|
527
|
+
} finally {
|
|
528
|
+
if (timer) clearTimeout(timer);
|
|
423
529
|
}
|
|
424
530
|
}
|
|
531
|
+
function firstLine(err) {
|
|
532
|
+
const line = (String(err?.message || err || "unknown error").trim().split("\n")[0] ?? "").trim();
|
|
533
|
+
return line.length > 200 ? `${line.slice(0, 197)}...` : line;
|
|
534
|
+
}
|
|
425
535
|
//#endregion
|
|
426
536
|
//#region src/engine/metro-gate.ts
|
|
427
537
|
const REMOTE_METRO_WRONG = "STIM_REMOTE_METRO_WRONG";
|
|
@@ -494,8 +604,10 @@ function remoteProfile({ daemon, platform, label }) {
|
|
|
494
604
|
tenant: scope,
|
|
495
605
|
runId: scope,
|
|
496
606
|
sessionIsolation: "tenant",
|
|
497
|
-
|
|
498
|
-
|
|
607
|
+
...platform === "android" ? {
|
|
608
|
+
leaseProvider: "proxy",
|
|
609
|
+
clientId: scope
|
|
610
|
+
} : {}
|
|
499
611
|
};
|
|
500
612
|
}
|
|
501
613
|
function daemonEnv(daemon) {
|
|
@@ -558,6 +670,18 @@ const LIVE_STATUSES$1 = ["new", "in-progress"];
|
|
|
558
670
|
const LIVE_SESSION_STATUSES = /* @__PURE__ */ new Set(["NEW", "IN_PROGRESS"]);
|
|
559
671
|
const TERMINAL_SESSION_STATUSES = /* @__PURE__ */ new Set(["STOPPED", "ERRORED"]);
|
|
560
672
|
const SESSION_PLATFORMS = /* @__PURE__ */ new Set(["ios", "android"]);
|
|
673
|
+
const MIN_EAS_CLI_SIMULATOR_VERSION = "21.6.0";
|
|
674
|
+
function easCliUpgradeRemedy(minimum) {
|
|
675
|
+
return `Upgrade eas-cli to ${minimum} or later (\`npm install --global eas-cli@latest\`, or the project's eas-cli dependency)`;
|
|
676
|
+
}
|
|
677
|
+
function easCliSupport(versionOutput, minimum) {
|
|
678
|
+
const version = /\beas-cli\/(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)/.exec(versionOutput ?? "")?.[1] ?? null;
|
|
679
|
+
const order = version ? compareStimVersions(version, minimum) : null;
|
|
680
|
+
return {
|
|
681
|
+
supported: order !== null && order >= 0,
|
|
682
|
+
version
|
|
683
|
+
};
|
|
684
|
+
}
|
|
561
685
|
function ownedSessionName(label) {
|
|
562
686
|
const clean = sanitizeDeviceLabel(label);
|
|
563
687
|
return `${OWNED_PREFIX}${clean.startsWith(OWNED_PREFIX) ? clean.slice(5) : clean}`;
|
|
@@ -827,80 +951,14 @@ function parseStoppedSession(stdout) {
|
|
|
827
951
|
};
|
|
828
952
|
}
|
|
829
953
|
//#endregion
|
|
954
|
+
//#region src/engine/eas-machine-root-guard-env.ts
|
|
955
|
+
const EAS_TEST_GUARD_ROOT_ENV = "STIM_TEST_GUARD_REAL_EAS_ROOT";
|
|
956
|
+
//#endregion
|
|
830
957
|
//#region src/engine/eas-session-ledger.ts
|
|
831
|
-
function
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
return join(root, "sessions.json");
|
|
836
|
-
}
|
|
837
|
-
function validClaim(id, value) {
|
|
838
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
839
|
-
const claim = value;
|
|
840
|
-
if (claim.sessionId !== id) return null;
|
|
841
|
-
if (typeof claim.name !== "string" || !claim.name.startsWith("stim-")) return null;
|
|
842
|
-
if (claim.platform !== "ios" && claim.platform !== "android") return null;
|
|
843
|
-
if (typeof claim.workspaceRoot !== "string" || !isAbsolute(claim.workspaceRoot)) return null;
|
|
844
|
-
if (typeof claim.workspaceHome !== "string" || !isAbsolute(claim.workspaceHome)) return null;
|
|
845
|
-
if (typeof claim.stateFile !== "string" || !isAbsolute(claim.stateFile)) return null;
|
|
846
|
-
const workspaceRoot = resolve(claim.workspaceRoot);
|
|
847
|
-
const workspaceHome = resolve(claim.workspaceHome);
|
|
848
|
-
const stateFile = resolve(claim.stateFile);
|
|
849
|
-
const stateRelative = relative(workspaceHome, stateFile);
|
|
850
|
-
if (!stateRelative || stateRelative.startsWith("..") || isAbsolute(stateRelative)) return null;
|
|
851
|
-
if (stateFile !== join(workspaceHome, "workspaces", workspaceName(workspaceRoot), "state.json")) return null;
|
|
852
|
-
return {
|
|
853
|
-
sessionId: id,
|
|
854
|
-
name: claim.name,
|
|
855
|
-
platform: claim.platform,
|
|
856
|
-
workspaceRoot,
|
|
857
|
-
workspaceHome,
|
|
858
|
-
stateFile
|
|
859
|
-
};
|
|
860
|
-
}
|
|
861
|
-
function readEasSessionLedger(root = easMachineStateRoot()) {
|
|
862
|
-
const file = easSessionLedgerFile(root);
|
|
863
|
-
if (!existsSync(file)) return {
|
|
864
|
-
claims: /* @__PURE__ */ new Map(),
|
|
865
|
-
notice: null,
|
|
866
|
-
safe: true
|
|
867
|
-
};
|
|
868
|
-
let parsed;
|
|
869
|
-
try {
|
|
870
|
-
parsed = JSON.parse(readFileSync(file, "utf-8"));
|
|
871
|
-
} catch (error) {
|
|
872
|
-
return {
|
|
873
|
-
claims: /* @__PURE__ */ new Map(),
|
|
874
|
-
notice: `EAS ownership ledger ${file} is unreadable: ${error.message}`,
|
|
875
|
-
safe: false
|
|
876
|
-
};
|
|
877
|
-
}
|
|
878
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {
|
|
879
|
-
claims: /* @__PURE__ */ new Map(),
|
|
880
|
-
notice: `EAS ownership ledger ${file} is malformed.`,
|
|
881
|
-
safe: false
|
|
882
|
-
};
|
|
883
|
-
const ledger = parsed;
|
|
884
|
-
if (ledger.version !== 1 || !ledger.claims || typeof ledger.claims !== "object" || Array.isArray(ledger.claims)) return {
|
|
885
|
-
claims: /* @__PURE__ */ new Map(),
|
|
886
|
-
notice: `EAS ownership ledger ${file} is malformed.`,
|
|
887
|
-
safe: false
|
|
888
|
-
};
|
|
889
|
-
const claims = /* @__PURE__ */ new Map();
|
|
890
|
-
for (const [id, value] of Object.entries(ledger.claims)) {
|
|
891
|
-
const claim = validClaim(id, value);
|
|
892
|
-
if (!claim) return {
|
|
893
|
-
claims: /* @__PURE__ */ new Map(),
|
|
894
|
-
notice: `EAS ownership ledger ${file} is malformed.`,
|
|
895
|
-
safe: false
|
|
896
|
-
};
|
|
897
|
-
claims.set(id, claim);
|
|
898
|
-
}
|
|
899
|
-
return {
|
|
900
|
-
claims,
|
|
901
|
-
notice: null,
|
|
902
|
-
safe: true
|
|
903
|
-
};
|
|
958
|
+
function assertEasMachineRootWritable(root) {
|
|
959
|
+
const guardedRoot = process.env[EAS_TEST_GUARD_ROOT_ENV];
|
|
960
|
+
if (!guardedRoot || resolve(root) !== resolve(guardedRoot)) return;
|
|
961
|
+
throw new Error(`Refusing to write the real EAS machine root ${root} from a test process. Pass a temporary ledgerRoot, machineRoot, or easLedgerRoot, or point HOME (and USERPROFILE on Windows) at a temporary directory.`);
|
|
904
962
|
}
|
|
905
963
|
function writeLedger(root, ledger) {
|
|
906
964
|
mkdirSync(root, { recursive: true });
|
|
@@ -915,9 +973,10 @@ function writeLedger(root, ledger) {
|
|
|
915
973
|
}
|
|
916
974
|
}
|
|
917
975
|
function recordEasSessionClaim(claim, root = easMachineStateRoot()) {
|
|
918
|
-
|
|
976
|
+
assertEasMachineRootWritable(root);
|
|
977
|
+
const normalized = validEasSessionClaim(claim.sessionId, claim);
|
|
919
978
|
if (!normalized) throw new Error(`Invalid EAS session claim for ${claim.sessionId}.`);
|
|
920
|
-
withDirLock(
|
|
979
|
+
withDirLock(easSessionLedgerLock(root), () => {
|
|
921
980
|
const current = readEasSessionLedger(root);
|
|
922
981
|
if (!current.safe) throw new Error(current.notice ?? "EAS ownership ledger is unreadable.");
|
|
923
982
|
current.claims.set(normalized.sessionId, normalized);
|
|
@@ -925,12 +984,13 @@ function recordEasSessionClaim(claim, root = easMachineStateRoot()) {
|
|
|
925
984
|
version: 1,
|
|
926
985
|
claims: Object.fromEntries(current.claims)
|
|
927
986
|
});
|
|
928
|
-
}, { ensureParent: () => mkdirSync(dirname(
|
|
987
|
+
}, { ensureParent: () => mkdirSync(dirname(easSessionLedgerLock(root)), { recursive: true }) });
|
|
929
988
|
}
|
|
930
989
|
function removeEasSessionClaim(sessionId, root = easMachineStateRoot()) {
|
|
931
990
|
const file = easSessionLedgerFile(root);
|
|
932
991
|
if (!existsSync(file)) return false;
|
|
933
|
-
|
|
992
|
+
assertEasMachineRootWritable(root);
|
|
993
|
+
return withDirLock(easSessionLedgerLock(root), () => {
|
|
934
994
|
const current = readEasSessionLedger(root);
|
|
935
995
|
if (!current.safe) return false;
|
|
936
996
|
if (!current.claims.delete(sessionId)) return false;
|
|
@@ -945,7 +1005,8 @@ function removeEasSessionClaim(sessionId, root = easMachineStateRoot()) {
|
|
|
945
1005
|
//#region src/engine/eas-project-lock.ts
|
|
946
1006
|
const EAS_PROJECT_LOCK_WAIT_MS = 24e4;
|
|
947
1007
|
function withEasProjectLock(_root, fn, options = {}) {
|
|
948
|
-
const { machineRoot = easMachineStateRoot(), ...lockOptions } = options;
|
|
1008
|
+
const { machineRoot = easMachineStateRoot$1(), ...lockOptions } = options;
|
|
1009
|
+
assertEasMachineRootWritable(machineRoot);
|
|
949
1010
|
return withWorkspaceProcessLock(machineRoot, "eas-project", fn, {
|
|
950
1011
|
waitMs: EAS_PROJECT_LOCK_WAIT_MS,
|
|
951
1012
|
...lockOptions,
|
|
@@ -1233,10 +1294,11 @@ function remoteDeviceDeps(ctx) {
|
|
|
1233
1294
|
}
|
|
1234
1295
|
return stopped;
|
|
1235
1296
|
},
|
|
1236
|
-
webPreviewUrl: () => session?.daemon.webPreviewUrl ?? null
|
|
1297
|
+
webPreviewUrl: () => session?.daemon.webPreviewUrl ?? null,
|
|
1298
|
+
failureRemedy: () => ctx.backend === "eas" && session?.id ? `EAS Simulator session ${session.id} is still running and billed until it reaches its time limit or \`stim stop\` ends it. Fix the error above and run this command again to reuse the session, or run \`stim stop\` to end it.` : "Check that the remote daemon is reachable and still has the device, then run this command again."
|
|
1237
1299
|
};
|
|
1238
1300
|
}
|
|
1239
|
-
async function resolveRemoteContext({ root, backend, platform = "ios", easBin, env = process.env, lookupAgentDevice = defaultLookupAgentDevice, maxDurationMinutes = null }) {
|
|
1301
|
+
async function resolveRemoteContext({ root, backend, platform = "ios", easBin, env = process.env, lookupAgentDevice = defaultLookupAgentDevice, readEasCliVersion = readInstalledEasCliVersion, maxDurationMinutes = null }) {
|
|
1240
1302
|
const agentDeviceBin = lookupAgentDevice();
|
|
1241
1303
|
if (!agentDeviceBin) return {
|
|
1242
1304
|
failed: "agent-device is not on PATH, and it is what drives a remote device.",
|
|
@@ -1270,6 +1332,14 @@ async function resolveRemoteContext({ root, backend, platform = "ios", easBin, e
|
|
|
1270
1332
|
remedy: "Install eas-cli, then run the device command with `--remote eas` again.",
|
|
1271
1333
|
code: "STIM_REMOTE_EAS_UNAVAILABLE"
|
|
1272
1334
|
};
|
|
1335
|
+
else {
|
|
1336
|
+
const { supported, version } = easCliSupport(readEasCliVersion(easBin, root), MIN_EAS_CLI_SIMULATOR_VERSION);
|
|
1337
|
+
if (!supported) return {
|
|
1338
|
+
failed: version ? `eas-cli ${version} (${easBin}) has no EAS Simulator commands; the eas backend needs eas-cli ${MIN_EAS_CLI_SIMULATOR_VERSION} or later.` : `Could not read an eas-cli version from \`${easBin} --version\`; the eas backend needs eas-cli ${MIN_EAS_CLI_SIMULATOR_VERSION} or later.`,
|
|
1339
|
+
remedy: `${easCliUpgradeRemedy(MIN_EAS_CLI_SIMULATOR_VERSION)}, then run the device command with \`--remote eas\` again.`,
|
|
1340
|
+
code: "STIM_REMOTE_EAS_UNAVAILABLE"
|
|
1341
|
+
};
|
|
1342
|
+
}
|
|
1273
1343
|
return { ctx: {
|
|
1274
1344
|
root,
|
|
1275
1345
|
label: `${ownedDeviceLabel(root)}-${workspaceId(root)}`,
|
|
@@ -1282,6 +1352,13 @@ async function resolveRemoteContext({ root, backend, platform = "ios", easBin, e
|
|
|
1282
1352
|
existingDaemon
|
|
1283
1353
|
} };
|
|
1284
1354
|
}
|
|
1355
|
+
function readInstalledEasCliVersion(easBin, root) {
|
|
1356
|
+
try {
|
|
1357
|
+
return getExecutor().runFile(easBin, ["--version"], easBoundedExecOptions(root));
|
|
1358
|
+
} catch {
|
|
1359
|
+
return null;
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1285
1362
|
function binOnPath(bin) {
|
|
1286
1363
|
try {
|
|
1287
1364
|
return Boolean(getExecutor().findExecutable(bin));
|
|
@@ -1360,7 +1437,7 @@ function withRemoteSessionLock(root, fn, options = {}) {
|
|
|
1360
1437
|
...options
|
|
1361
1438
|
});
|
|
1362
1439
|
}
|
|
1363
|
-
async function ensureRemoteBootOwned({ root, platform, sessionName, startedAt, boot, createdSessionId, abandonCreatedSession, webPreviewUrl = () => null, writeState, register = () => {}, withProjectLock = withEasProjectLock, withLock = withRemoteSessionLock, removeEasSessionClaim: removeClaim = removeEasSessionClaim, ledgerRoot = easMachineStateRoot() }) {
|
|
1440
|
+
async function ensureRemoteBootOwned({ root, platform, sessionName, startedAt, boot, createdSessionId, abandonCreatedSession, webPreviewUrl = () => null, writeState, register = () => {}, withProjectLock = withEasProjectLock, withLock = withRemoteSessionLock, removeEasSessionClaim: removeClaim = removeEasSessionClaim, ledgerRoot = easMachineStateRoot$1() }) {
|
|
1364
1441
|
try {
|
|
1365
1442
|
return await withProjectLock(root, () => withLock(root, async () => {
|
|
1366
1443
|
register();
|
|
@@ -1488,7 +1565,8 @@ function remoteIosDeps(ctx) {
|
|
|
1488
1565
|
}),
|
|
1489
1566
|
createdSessionId: core.createdSessionId,
|
|
1490
1567
|
abandonCreatedSession: core.abandonCreatedSession,
|
|
1491
|
-
webPreviewUrl: core.webPreviewUrl
|
|
1568
|
+
webPreviewUrl: core.webPreviewUrl,
|
|
1569
|
+
failureRemedy: core.failureRemedy
|
|
1492
1570
|
};
|
|
1493
1571
|
}
|
|
1494
1572
|
function remoteAndroidDeps(ctx) {
|
|
@@ -1516,7 +1594,8 @@ function remoteAndroidDeps(ctx) {
|
|
|
1516
1594
|
}),
|
|
1517
1595
|
createdSessionId: core.createdSessionId,
|
|
1518
1596
|
abandonCreatedSession: core.abandonCreatedSession,
|
|
1519
|
-
webPreviewUrl: core.webPreviewUrl
|
|
1597
|
+
webPreviewUrl: core.webPreviewUrl,
|
|
1598
|
+
failureRemedy: core.failureRemedy
|
|
1520
1599
|
};
|
|
1521
1600
|
}
|
|
1522
1601
|
function endRecordedSession({ root, sessionId, easBin, lookupAgentDevice, ledgerRoot }) {
|
|
@@ -1545,7 +1624,7 @@ function teardownRemote(ctx, { sessionId }) {
|
|
|
1545
1624
|
});
|
|
1546
1625
|
} catch {}
|
|
1547
1626
|
if (!sessionId) return { status: "torn-down" };
|
|
1548
|
-
const ledger = readEasSessionLedger(ctx.easLedgerRoot);
|
|
1627
|
+
const ledger = readEasSessionLedger$1(ctx.easLedgerRoot);
|
|
1549
1628
|
const claimNeedsRemoval = !ledger.safe || ledger.claims.has(sessionId);
|
|
1550
1629
|
const removeClaim = () => {
|
|
1551
1630
|
try {
|
|
@@ -1661,4 +1740,4 @@ function bundleEntryPoint(root, isExpo) {
|
|
|
1661
1740
|
return local ? normalized : `node_modules/${normalized}`;
|
|
1662
1741
|
}
|
|
1663
1742
|
//#endregion
|
|
1664
|
-
export {
|
|
1743
|
+
export { UPLOAD_TIMEOUT_MS as A, resolveRemote as B, listOwnedSessionsArgs as C, verifyStoppedSession as D, stopSessionArgs as E, isEasAuthFailureText as F, loadProjectProvider as I, ownerFromConfig as L, checkEasAuth as M, easAuthNote as N, gateMetroOrigin as O, exitAfterFlush as P, providerFromConfig as R, isDefinitiveMissingSessionError as S, parseSessionListPage as T, uploadRemote as V, easCliSupport as _, ensureMetroReachable as a, getSessionArgs as b, remoteAndroidDeps as c, withRemoteSessionLock as d, withEasProjectLock as f, MIN_EAS_CLI_SIMULATOR_VERSION as g, removeEasSessionClaim as h, endRecordedSession as i, cacheLevel as j, RESOLVE_TIMEOUT_MS as k, remoteIosDeps as l, readEasSessionLedger$1 as m, binOnPath as n, ensureRemoteBootOwned as o, easMachineStateRoot$1 as p, bundleEntryPoint as r, readInstalledEasCliVersion as s, REMOTE_SESSION_ERROR as t, resolveRemoteContext as u, easCliUpgradeRemedy as v, ownedSessionName as w, inspectSessionForTeardown as x, findOrphanedOwnedSessions as y, resolveEasCliBin as z };
|