@expo/simulator-launcher 27.3.0 → 27.4.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/README.md CHANGED
@@ -15,11 +15,11 @@ exec bunx @expo/simulator-launcher@latest start
15
15
  - `start`: run one orphan serve-sim for the configured devices. Its default device becomes ready
16
16
  first; additional devices warm in the background. Argent and agent-device prestart on the default.
17
17
  - `claim ENGINE [DEVICE]`: reserve one job and return its selected device plus the existing server's
18
- identity, port and credentials. Engines: `serve-sim`, `agent-device`, `argent`.
18
+ identity, port and credentials. Engines: `serve-sim`, `agent-device`, `argent`, `appium`.
19
19
  No DEVICE means the first configured device. Claim does not boot the selected device or wait for
20
20
  its tool. Build-tools privately adopts that device on the existing serve-sim port.
21
21
  - `prepare-tools`: continue the consumed claim after adoption. Keep global Argent, reuse the default
22
- agent-device runner or prepare a runner for the selected device.
22
+ agent-device runner or prepare a runner for the selected device. Appium waits for old XCTest cleanup.
23
23
  - `stop`: permanently end warmup for this boot and wait for all owned resources to be cleaned up.
24
24
 
25
25
  ```sh
@@ -66,6 +66,7 @@ serializes updates; an abandoned lock fails closed. This private format requires
66
66
  and app actions. Job-time version and authentication checks remain authoritative.
67
67
  - Agent-device prestarts on the default device only. A secondary claim prepares its runner after
68
68
  adoption and old-runner cleanup finish. One device-independent Argent server is reused for the claimed device.
69
+ Appium waits for unused tools to stop before starting its own WDA.
69
70
  - Warmup downloads/extracts the latest stable Expo Go once and reuses it for the second device.
70
71
  Each initial device gets a preinstall attempt; ordinary failures warn. Claim prevents new
71
72
  preinstalls. `prepare-tools` waits for an install still running on the claimed device and
package/dist/index.js CHANGED
@@ -15,13 +15,54 @@ async function claimAsync(bootUuid, engine, requestedDevice) {
15
15
  if (!input.success) {
16
16
  throw new Error(`Invalid Simulator session request. Choose ${state_1.ClaimInputSchema.shape.engine.options.join(', ')} and an optional device name or UDID.`);
17
17
  }
18
+ // Startup and handoff share the worker's existing claim timeout.
19
+ const startedAt = Date.now();
20
+ const deadline = startedAt + 420_000;
21
+ let lastWaitLogAt;
22
+ let controller;
23
+ const ready = await (0, state_1.waitForLauncherStateAsync)(bootUuid, state => {
24
+ if (state?.status === 'stopping' || state?.status === 'disabled' || state?.error) {
25
+ throw new Error(`Simulator preparation was interrupted; cleanup may still be running.${state.error ? ` ${state.error}` : ''}`);
26
+ }
27
+ if (!state ||
28
+ (state.status !== 'starting' && state.status !== 'ready') ||
29
+ state.controllerPid === undefined) {
30
+ throw new Error('No warm Simulator session is available to claim on this VM.');
31
+ }
32
+ if (controller &&
33
+ (state.controllerPid !== controller.controllerPid ||
34
+ (controller.controllerStartTime !== undefined &&
35
+ state.controllerStartTime !== controller.controllerStartTime))) {
36
+ throw new Error('The Simulator launcher returned a different session or engine.');
37
+ }
38
+ controller = state;
39
+ if (state.status === 'starting') {
40
+ const now = Date.now();
41
+ if (lastWaitLogAt === undefined || now - lastWaitLogAt >= 30_000) {
42
+ process.stderr.write(`Warm Simulator is still starting; waiting (${Math.floor((now - startedAt) / 1_000)}s elapsed, 420s limit).\n`);
43
+ lastWaitLogAt = now;
44
+ }
45
+ }
46
+ return state.status === 'ready';
47
+ }, deadline - Date.now());
48
+ const prepared = state_1.WarmSessionInfoSchema.parse(ready);
18
49
  const acquired = await (0, state_1.updateLauncherStateAsync)(bootUuid, state => {
19
50
  if (state?.status !== 'ready') {
20
51
  throw new Error('No warm Simulator session is available to claim on this VM.');
21
52
  }
53
+ if (state.controllerPid !== prepared.controllerPid ||
54
+ state.controllerStartTime !== prepared.controllerStartTime) {
55
+ throw new Error('The Simulator launcher returned a different session or engine.');
56
+ }
57
+ if (Date.now() >= deadline) {
58
+ throw new Error('Timed out waiting for the Simulator launcher; cleanup may still be running.');
59
+ }
22
60
  state_1.WarmSessionInfoSchema.parse(state);
23
61
  return { ...state, ...input.data, status: 'claiming' };
24
62
  });
63
+ if (lastWaitLogAt !== undefined) {
64
+ process.stderr.write(`Warm Simulator became ready after waiting ${Math.floor((Date.now() - startedAt) / 1_000)}s.\n`);
65
+ }
25
66
  const claimed = await (0, state_1.waitForLauncherStateAsync)(bootUuid, state => {
26
67
  if (!state || state.status === 'stopping' || state.status === 'disabled') {
27
68
  throw new Error(`Simulator preparation was interrupted; cleanup may still be running.${state?.error ? ` ${state.error}` : ''}`);
@@ -32,7 +73,7 @@ async function claimAsync(bootUuid, engine, requestedDevice) {
32
73
  throw new Error('The Simulator launcher returned a different session or engine.');
33
74
  }
34
75
  return state.status === 'claimed';
35
- }, 420_000);
76
+ }, Math.max(0, deadline - Date.now()));
36
77
  const { device } = state_1.WarmSessionInfoSchema.parse(claimed);
37
78
  if (requestedDevice &&
38
79
  device.name !== requestedDevice &&
@@ -439,7 +480,8 @@ function createWarmSimulatorSession({ signal: parentSignal, throwIfStoppingAsync
439
480
  // runs in the background but is joined before teardown.
440
481
  startSimulatorsSetupAsync([info.device.udid], Promise.resolve()).catch(() => { });
441
482
  const tool = warmTools.find(tool => tool.name === engine);
442
- if (tool?.name === 'agent-device' && !startedTools.has(tool)) {
483
+ // In particular, Appium cannot start WDA until old XCTest retirement succeeded.
484
+ if (engine === 'appium' || (tool?.name === 'agent-device' && !startedTools.has(tool))) {
443
485
  const results = await toolRetirement;
444
486
  const failed = results.find(result => result.status === 'rejected');
445
487
  if (failed?.status === 'rejected') {
@@ -1538,7 +1580,7 @@ exports.WarmServerSchema = zod_1.z.object({
1538
1580
  });
1539
1581
  const ToolServerSchema = exports.WarmServerSchema.pick({ pid: true, port: true, token: true });
1540
1582
  exports.ClaimInputSchema = zod_1.z.object({
1541
- engine: zod_1.z.enum(['serve-sim', 'agent-device', 'argent']),
1583
+ engine: zod_1.z.enum(['serve-sim', 'agent-device', 'argent', 'appium']),
1542
1584
  requestedDevice: NonBlankStringSchema.optional(),
1543
1585
  });
1544
1586
  /** The Expo Go this launcher installed on `udid` and never launched. */
@@ -18076,7 +18118,7 @@ module.exports = exports.default;
18076
18118
  /***/ 8330:
18077
18119
  /***/ ((module) => {
18078
18120
 
18079
- module.exports = {"rE":"27.3.0"};
18121
+ module.exports = {"rE":"27.4.1"};
18080
18122
 
18081
18123
  /***/ })
18082
18124
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expo/simulator-launcher",
3
- "version": "27.3.0",
3
+ "version": "27.4.1",
4
4
  "description": "Launch and claim Simulator sessions on EAS workers",
5
5
  "bugs": "https://github.com/expo/eas-cli/issues",
6
6
  "license": "BUSL-1.1",
@@ -34,5 +34,5 @@
34
34
  "typescript": "^6.0.3",
35
35
  "zod": "^4.3.5"
36
36
  },
37
- "gitHead": "bc25602d655eb5d5e3f3174836e13b567cae919d"
37
+ "gitHead": "3263ecfa369459437d7b5180564a796192f1189a"
38
38
  }