appium-xcuitest-driver 12.17.2 → 12.17.3

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
+ ## [12.17.3](https://github.com/appium/appium-xcuitest-driver/compare/v12.17.2...v12.17.3) (2026-10-12)
2
+
3
+ ### Bug Fixes
4
+
5
+ * make tunnel-creation exit on Ctrl+C ([#3033](https://github.com/appium/appium-xcuitest-driver/issues/3033)) ([1dde1ec](https://github.com/appium/appium-xcuitest-driver/commit/1dde1ec4589b416205729d943c7cf5ab9d286617))
6
+
1
7
  ## [12.17.2](https://github.com/appium/appium-xcuitest-driver/compare/v12.17.1...v12.17.2) (2026-10-12)
2
8
 
3
9
  ### Bug Fixes
@@ -28,6 +28,10 @@ require('bare-url/global')
28
28
 
29
29
  See the [`bare-url` reference](https://docs.pears.com/reference/bare/modules/bare-url).
30
30
 
31
+ ## Threat model
32
+
33
+ `bare-url` is one of the addons Bare compiles into its binary, so it inherits [Bare's threat model](https://github.com/holepunchto/bare/blob/main/docs/threat-model.md). See [`docs/threat-model.md`](docs/threat-model.md) for where this addon sits in it.
34
+
31
35
  ## License
32
36
 
33
37
  Apache-2.0
@@ -87,6 +87,9 @@ declare namespace URL {
87
87
  /**
88
88
  * Convert a platform-specific file path to a `file:` URL.
89
89
  * @param pathname - The platform-specific file path to convert.
90
+ * @throws {INVALID_ARG_VALUE} (Windows) the path is a UNC path with an empty server name or
91
+ * no resource path.
92
+ * @throws {INVALID_URL} the path does not form a valid `file:` URL.
90
93
  */
91
94
  export function pathToFileURL(pathname: string): URL
92
95
 
@@ -494,6 +494,26 @@ function encodePath(value) {
494
494
  return value.replace(pathDelimiterAll, (match) => escapes[match])
495
495
  }
496
496
 
497
+ function encodeFilePath(value) {
498
+ // Paths hardly ever contain any of these, so one pass to rule them out is
499
+ // cheaper than the six or seven replacements it stands in for.
500
+ if (!reserved.test(value)) return value
501
+
502
+ value = value
503
+ .replaceAll('%', '%25') // Must be first
504
+ .replaceAll('#', '%23')
505
+ .replaceAll('?', '%3f')
506
+ .replaceAll('\n', '%0a')
507
+ .replaceAll('\r', '%0d')
508
+ .replaceAll('\t', '%09')
509
+
510
+ if (!isWindows) {
511
+ value = value.replaceAll('\\', '%5c')
512
+ }
513
+
514
+ return value
515
+ }
516
+
497
517
  function encodeQuery(value) {
498
518
  if (value.indexOf('#') === -1) return value
499
519
 
@@ -600,7 +620,27 @@ exports.fileURLToPath = function fileURLToPath(url) {
600
620
  }
601
621
 
602
622
  exports.pathToFileURL = function pathToFileURL(pathname) {
603
- let resolved = path.resolve(pathname)
623
+ const isUNC = isWindows && pathname.startsWith('\\\\')
624
+
625
+ let resolved = isUNC ? pathname : path.resolve(pathname)
626
+
627
+ if (isUNC || (isWindows && resolved.startsWith('\\\\'))) {
628
+ // https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation
629
+ const hostStart = resolved.startsWith('\\\\?\\UNC\\') ? 8 : 2
630
+ const hostEnd = resolved.indexOf('\\', hostStart)
631
+
632
+ if (hostEnd === -1) {
633
+ throw errors.INVALID_ARG_VALUE('Missing UNC resource path')
634
+ }
635
+
636
+ if (hostEnd === 2) {
637
+ throw errors.INVALID_ARG_VALUE('Empty UNC servername')
638
+ }
639
+
640
+ const hostname = truncateHost('file', resolved.slice(hostStart, hostEnd))
641
+
642
+ return new URL('file://' + hostname + encodeFilePath(resolved.slice(hostEnd)))
643
+ }
604
644
 
605
645
  if (pathname[pathname.length - 1] === '/') {
606
646
  resolved += '/'
@@ -608,23 +648,7 @@ exports.pathToFileURL = function pathToFileURL(pathname) {
608
648
  resolved += '\\'
609
649
  }
610
650
 
611
- // Paths hardly ever contain any of these, so one pass to rule them out is
612
- // cheaper than the six or seven replacements it stands in for.
613
- if (reserved.test(resolved)) {
614
- resolved = resolved
615
- .replaceAll('%', '%25') // Must be first
616
- .replaceAll('#', '%23')
617
- .replaceAll('?', '%3f')
618
- .replaceAll('\n', '%0a')
619
- .replaceAll('\r', '%0d')
620
- .replaceAll('\t', '%09')
621
-
622
- if (!isWindows) {
623
- resolved = resolved.replaceAll('\\', '%5c')
624
- }
625
- }
626
-
627
- return new URL('file:' + resolved)
651
+ return new URL('file:' + encodeFilePath(resolved))
628
652
  }
629
653
 
630
654
  exports.format = function format(parts) {
@@ -30,4 +30,8 @@ module.exports = class URLError extends Error {
30
30
  static INVALID_FILE_URL_PATH(msg = 'Invalid file: URL path') {
31
31
  return new URLError(msg, URLError.INVALID_FILE_URL_PATH)
32
32
  }
33
+
34
+ static INVALID_ARG_VALUE(msg = 'Invalid argument value') {
35
+ return new URLError(msg, URLError.INVALID_ARG_VALUE)
36
+ }
33
37
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bare-url",
3
- "version": "2.5.4",
3
+ "version": "2.5.5",
4
4
  "description": "WHATWG URL implementation for JavaScript",
5
5
  "exports": {
6
6
  "./package": "./package.json",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium-xcuitest-driver",
3
- "version": "12.17.2",
3
+ "version": "12.17.3",
4
4
  "description": "Appium driver for iOS using XCUITest for backend",
5
5
  "keywords": [
6
6
  "appium",
@@ -863,7 +863,8 @@ function collectStringValues(value, previous = []) {
863
863
 
864
864
  /**
865
865
  * Sets up signal and error handlers to ensure tunnels are cleaned up exactly once
866
- * and an appropriate process exit code is set on shutdown.
866
+ * and the process exits with an appropriate code on shutdown. A repeated shutdown
867
+ * signal during cleanup forces an immediate exit.
867
868
  *
868
869
  * @param {TunnelCreator} tunnelCreator
869
870
  * @returns {() => Promise<void>} cleanup function that can be awaited in a finally block
@@ -892,6 +893,10 @@ function setupCleanupHandlers(tunnelCreator) {
892
893
  const shutdownSignals = ['SIGINT', 'SIGTERM', 'SIGHUP'];
893
894
  for (const signal of shutdownSignals) {
894
895
  process.on(signal, () => {
896
+ if (shuttingDown) {
897
+ log.warn(`Received ${signal} during cleanup, forcing exit`);
898
+ process.exit(process.exitCode || 1);
899
+ }
895
900
  if (process.exitCode == null) {
896
901
  if (signal === 'SIGINT') {
897
902
  process.exitCode = 0;
@@ -901,7 +906,7 @@ function setupCleanupHandlers(tunnelCreator) {
901
906
  process.exitCode = 1;
902
907
  }
903
908
  }
904
- void cleanupOnce();
909
+ void cleanupAndExit();
905
910
  });
906
911
  }
907
912