appium-xcuitest-driver 11.2.3 → 11.2.4

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/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## [11.2.4](https://github.com/appium/appium-xcuitest-driver/compare/v11.2.3...v11.2.4) (2026-05-08)
2
+
3
+ ### Bug Fixes
4
+
5
+ * Tunnels cleanup ([#2834](https://github.com/appium/appium-xcuitest-driver/issues/2834)) ([e17218c](https://github.com/appium/appium-xcuitest-driver/commit/e17218c49111c500bef98aeee8d3739aafdfeb24))
6
+
1
7
  ## [11.2.3](https://github.com/appium/appium-xcuitest-driver/compare/v11.2.2...v11.2.3) (2026-05-07)
2
8
 
3
9
  ### Miscellaneous Chores
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "appium-xcuitest-driver",
3
- "version": "11.2.3",
3
+ "version": "11.2.4",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "appium-xcuitest-driver",
9
- "version": "11.2.3",
9
+ "version": "11.2.4",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
12
  "@appium/strongbox": "^1.0.0-rc.1",
@@ -35,7 +35,7 @@
35
35
  "ws": "^8.13.0"
36
36
  },
37
37
  "devDependencies": {
38
- "@appium/docutils": "^2.0.0-rc.1",
38
+ "@appium/docutils": "^2.4.0",
39
39
  "@appium/eslint-config-appium-ts": "^3.0.0",
40
40
  "@appium/tsconfig": "^1.0.0-rc.1",
41
41
  "@appium/types": "^1.0.0-rc.1",
@@ -595,12 +595,12 @@
595
595
  }
596
596
  },
597
597
  "node_modules/appium-ios-simulator": {
598
- "version": "8.1.2",
599
- "resolved": "https://registry.npmjs.org/appium-ios-simulator/-/appium-ios-simulator-8.1.2.tgz",
600
- "integrity": "sha512-rA5FXFMMPYYNqStHK9k4OBlpqiogXnHASp3QdLtDOEEzjQZMPV1QPHfeoa/W3jmlLGxICkHSdlP2NB5CbJBJmA==",
598
+ "version": "8.1.3",
599
+ "resolved": "https://registry.npmjs.org/appium-ios-simulator/-/appium-ios-simulator-8.1.3.tgz",
600
+ "integrity": "sha512-ED3dNbxTO7YC/8UNKECY2mvePELtTKp9AXj+qwccK0UOMPWLURPszB1vVmZA5UGIykyeOeHBVcKbkSk709R8Gg==",
601
601
  "license": "Apache-2.0",
602
602
  "dependencies": {
603
- "@appium/support": "^7.0.0-rc.1",
603
+ "@appium/support": "^7.2.2",
604
604
  "@xmldom/xmldom": "^0.x",
605
605
  "appium-xcode": "^6.0.0",
606
606
  "async-lock": "^1.0.0",
@@ -676,12 +676,12 @@
676
676
  }
677
677
  },
678
678
  "node_modules/appium-xcode": {
679
- "version": "6.2.1",
680
- "resolved": "https://registry.npmjs.org/appium-xcode/-/appium-xcode-6.2.1.tgz",
681
- "integrity": "sha512-vY7D7GSm/m9KvRwJjk0AP9U+hT/MRoLN5OEohC2/vvbe5hxGp2H0nhUFYal2/6VwrL5U/P1zQKEIFUe3O8g0Dw==",
679
+ "version": "6.2.2",
680
+ "resolved": "https://registry.npmjs.org/appium-xcode/-/appium-xcode-6.2.2.tgz",
681
+ "integrity": "sha512-THnFNNPW2M680OzSdyHHcvF46CusrvW+/t+zCvVA+MK/sO1AE22GIHoUScbl8HeRxVI9gf1SsXravNSh8OoNaA==",
682
682
  "license": "Apache-2.0",
683
683
  "dependencies": {
684
- "@appium/support": "^7.0.0-rc.1",
684
+ "@appium/support": "^7.2.2",
685
685
  "asyncbox": "^6.0.1",
686
686
  "semver": "^7.0.0",
687
687
  "teen_process": "^4.0.4"
@@ -1062,9 +1062,9 @@
1062
1062
  }
1063
1063
  },
1064
1064
  "node_modules/brace-expansion": {
1065
- "version": "5.0.5",
1066
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
1067
- "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
1065
+ "version": "5.0.6",
1066
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
1067
+ "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
1068
1068
  "license": "MIT",
1069
1069
  "dependencies": {
1070
1070
  "balanced-match": "^4.0.2"
@@ -1953,9 +1953,9 @@
1953
1953
  }
1954
1954
  },
1955
1955
  "node_modules/get-east-asian-width": {
1956
- "version": "1.5.0",
1957
- "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz",
1958
- "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==",
1956
+ "version": "1.6.0",
1957
+ "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz",
1958
+ "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==",
1959
1959
  "license": "MIT",
1960
1960
  "engines": {
1961
1961
  "node": ">=18"
@@ -2780,9 +2780,9 @@
2780
2780
  }
2781
2781
  },
2782
2782
  "node_modules/node-devicectl": {
2783
- "version": "1.3.0",
2784
- "resolved": "https://registry.npmjs.org/node-devicectl/-/node-devicectl-1.3.0.tgz",
2785
- "integrity": "sha512-BrX8w5XkqeiZHW6wbfQBTnfu9HUAb/dPdNphtmiO4xrQJQBdxB44nyhtsTHMcdLzZLJJGJhyT+YWMNudFx9/dA==",
2783
+ "version": "1.3.1",
2784
+ "resolved": "https://registry.npmjs.org/node-devicectl/-/node-devicectl-1.3.1.tgz",
2785
+ "integrity": "sha512-hjjE/1RuvQ7BnjHqTfi4yhKGVVcTo/rEPdVzj1sIIQk29cvdsa1yXqfM4v4tQNiRcL2lMMqbO1hSkCBVAJ/w1g==",
2786
2786
  "license": "Apache-2.0",
2787
2787
  "dependencies": {
2788
2788
  "@appium/logger": "^2.0.0-rc.1",
@@ -2806,9 +2806,9 @@
2806
2806
  }
2807
2807
  },
2808
2808
  "node_modules/node-simctl": {
2809
- "version": "8.2.2",
2810
- "resolved": "https://registry.npmjs.org/node-simctl/-/node-simctl-8.2.2.tgz",
2811
- "integrity": "sha512-VdEsKHI9r1dih0UvYejNG1sFqb/EYjfr4fp5LiV3ny7PEni3j7IzYIqQzJ1XilTdI7mk8vZG7kTOKqr24OCq9Q==",
2809
+ "version": "8.2.3",
2810
+ "resolved": "https://registry.npmjs.org/node-simctl/-/node-simctl-8.2.3.tgz",
2811
+ "integrity": "sha512-udjYoXRsApFQP0fggKwGWFWUqinJKY11zIUmMxMv8Q4sfMLV0Uu9iavRUfiB3QOmJvL4WAXTaHv+tZvkiT+nyQ==",
2812
2812
  "license": "Apache-2.0",
2813
2813
  "dependencies": {
2814
2814
  "@appium/logger": "^2.0.0-rc.1",
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "xcuitest",
9
9
  "xctest"
10
10
  ],
11
- "version": "11.2.3",
11
+ "version": "11.2.4",
12
12
  "author": "Appium Contributors",
13
13
  "license": "Apache-2.0",
14
14
  "repository": {
@@ -143,7 +143,7 @@
143
143
  "appium": "^3.0.0-rc.2"
144
144
  },
145
145
  "devDependencies": {
146
- "@appium/docutils": "^2.0.0-rc.1",
146
+ "@appium/docutils": "^2.4.0",
147
147
  "@appium/eslint-config-appium-ts": "^3.0.0",
148
148
  "@appium/tsconfig": "^1.0.0-rc.1",
149
149
  "@appium/types": "^1.0.0-rc.1",
@@ -41,6 +41,8 @@ class TunnelCreator {
41
41
  this._tunnelRegistryPort = 42314;
42
42
  /** @type {import('appium-ios-remotexpc').TunnelRegistry | null} */
43
43
  this._registry = null;
44
+ /** @type {import('appium-ios-remotexpc').TunnelRegistryServer | null} */
45
+ this._registryServer = null;
44
46
  /** @type {Map<string, import('appium-ios-remotexpc').UsbmuxDevice>} */
45
47
  this._usbDevices = new Map();
46
48
  /** @type {Map<string, Promise<void>>} */
@@ -75,6 +77,10 @@ class TunnelCreator {
75
77
  return this._registry;
76
78
  }
77
79
 
80
+ get registryServer() {
81
+ return this._registryServer;
82
+ }
83
+
78
84
  set packetStreamBasePort(port) {
79
85
  this._packetStreamBasePort = port;
80
86
  }
@@ -97,6 +103,13 @@ class TunnelCreator {
97
103
  this._registry = value;
98
104
  }
99
105
 
106
+ /**
107
+ * @param {import('appium-ios-remotexpc').TunnelRegistryServer | null} value
108
+ */
109
+ set registryServer(value) {
110
+ this._registryServer = value;
111
+ }
112
+
100
113
  /**
101
114
  * @param {number | null} maxAttempts - null disables retries; 0 means unlimited retries
102
115
  * @param {number} intervalMs
@@ -171,12 +184,29 @@ class TunnelCreator {
171
184
  async cleanup() {
172
185
  this._isCleaningUp = true;
173
186
  log.warn('Cleaning up tunnel resources...');
187
+ /** @type {Error[]} */
188
+ const cleanupErrors = [];
189
+ const recordCleanupError = (message, err) => {
190
+ const wrapped = err instanceof Error ? err : new Error(String(err));
191
+ cleanupErrors.push(new Error(message, {cause: wrapped}));
192
+ log.warn(`${message}: ${wrapped.message}`);
193
+ };
194
+
174
195
  while (this._registryWatcherStops.length > 0) {
175
196
  const stop = this._registryWatcherStops.pop();
176
197
  try {
177
198
  await stop?.();
178
199
  } catch (err) {
179
- log.warn(`Failed to stop tunnel registry watcher: ${err}`);
200
+ recordCleanupError('Failed to stop tunnel registry watcher', err);
201
+ }
202
+ }
203
+ if (this._registryServer) {
204
+ try {
205
+ await this._registryServer.stop();
206
+ } catch (err) {
207
+ recordCleanupError('Failed to stop tunnel registry server', err);
208
+ } finally {
209
+ this._registryServer = null;
180
210
  }
181
211
  }
182
212
 
@@ -194,7 +224,7 @@ class TunnelCreator {
194
224
  await server.stop();
195
225
  log.info(`Closed packet stream server for device ${udid}`);
196
226
  } catch (err) {
197
- log.warn(`Failed to close packet stream server for device ${udid}: ${err}`);
227
+ recordCleanupError(`Failed to close packet stream server for device ${udid}`, err);
198
228
  }
199
229
  }),
200
230
  );
@@ -216,9 +246,18 @@ class TunnelCreator {
216
246
  })();
217
247
 
218
248
  await Promise.allSettled([closeUsbPacketStreamServers, closeAppleTVTunnels]);
249
+ try {
250
+ await TunnelManager.closeAllTunnels();
251
+ } catch (err) {
252
+ recordCleanupError('Failed to close managed tunnel(s)', err);
253
+ }
219
254
  await Promise.allSettled([...this._reconnectTasks.values()]);
220
255
 
221
- log.info('Cleanup completed.');
256
+ if (cleanupErrors.length > 0) {
257
+ throw new AggregateError(cleanupErrors, 'Tunnel cleanup encountered errors');
258
+ } else {
259
+ log.info('Cleanup completed.');
260
+ }
222
261
  }
223
262
 
224
263
  /**
@@ -914,6 +953,9 @@ function setupCleanupHandlers(tunnelCreator) {
914
953
  await tunnelCreator.cleanup();
915
954
  } catch (err) {
916
955
  log.warn(`Error during tunnel cleanup: ${err?.message ?? err}`);
956
+ if (!process.exitCode) {
957
+ process.exitCode = 1;
958
+ }
917
959
  }
918
960
  };
919
961
 
@@ -923,7 +965,8 @@ function setupCleanupHandlers(tunnelCreator) {
923
965
  if (process.exitCode == null) {
924
966
  // Follow conventional POSIX exit codes for signals where possible.
925
967
  if (signal === 'SIGINT') {
926
- process.exitCode = 130;
968
+ // SIGINT is typically sent by Ctrl+C, so we exit with code 0 to indicate success.
969
+ process.exitCode = 0;
927
970
  } else if (signal === 'SIGTERM') {
928
971
  process.exitCode = 143;
929
972
  } else {
@@ -1093,7 +1136,10 @@ async function main() {
1093
1136
  return;
1094
1137
  }
1095
1138
 
1096
- await startTunnelRegistryServer(registry, tunnelCreator.tunnelRegistryPort);
1139
+ tunnelCreator.registryServer = await startTunnelRegistryServer(
1140
+ registry,
1141
+ tunnelCreator.tunnelRegistryPort,
1142
+ );
1097
1143
  tunnelCreator._attachTunnelRegistryLifecycleWatch(watchTunnelRegistrySockets, usbResults, {
1098
1144
  onTunnelDead: async ({udid}) => {
1099
1145
  tunnelCreator._reconnectTunnelByUdid(udid);