appium-xcuitest-driver 12.2.1 → 12.3.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/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## [12.3.1](https://github.com/appium/appium-xcuitest-driver/compare/v12.3.0...v12.3.1) (2026-08-10)
2
+
3
+ ### Miscellaneous Chores
4
+
5
+ * Bump appium-remote-debugger to v17 ([#2940](https://github.com/appium/appium-xcuitest-driver/issues/2940)) ([d5522ea](https://github.com/appium/appium-xcuitest-driver/commit/d5522ea68e5f0faf70b9b3e744f327346529c20f))
6
+
7
+ ## [12.3.0](https://github.com/appium/appium-xcuitest-driver/compare/v12.2.1...v12.3.0) (2026-08-08)
8
+
9
+ ### Features
10
+
11
+ * Add customizable exponential backoff for tunnel reconnect retries ([#2936](https://github.com/appium/appium-xcuitest-driver/issues/2936)) ([84ed39d](https://github.com/appium/appium-xcuitest-driver/commit/84ed39dcaf274368f28fed85c980cf7d23ce470e))
12
+
1
13
  ## [12.2.1](https://github.com/appium/appium-xcuitest-driver/compare/v12.2.0...v12.2.1) (2026-08-07)
2
14
 
3
15
  ### Miscellaneous Chores
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "appium-xcuitest-driver",
3
- "version": "12.2.1",
3
+ "version": "12.3.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "appium-xcuitest-driver",
9
- "version": "12.2.1",
9
+ "version": "12.3.1",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
12
  "@appium/css-locator-to-native": "^1.0.1",
@@ -14,7 +14,7 @@
14
14
  "@colors/colors": "^1.6.0",
15
15
  "appium-ios-device": "^3.1.12",
16
16
  "appium-ios-simulator": "^9.0.0",
17
- "appium-remote-debugger": "^16.0.0",
17
+ "appium-remote-debugger": "^17.0.0",
18
18
  "appium-webdriveragent": "^16.1.4",
19
19
  "appium-xcode": "^7.0.0",
20
20
  "async-lock": "^1.4.0",
@@ -512,9 +512,9 @@
512
512
  }
513
513
  },
514
514
  "node_modules/appium-ios-remotexpc": {
515
- "version": "5.13.6",
516
- "resolved": "https://registry.npmjs.org/appium-ios-remotexpc/-/appium-ios-remotexpc-5.13.6.tgz",
517
- "integrity": "sha512-leWj0oCe/DgIPlMZc3FCLvSnyZF57uW+Gq4OkZeqqFojpY1tgTN6YGN3AFYSk/VfF/uvbYtNhT1fn+R6Lf8zow==",
515
+ "version": "5.14.0",
516
+ "resolved": "https://registry.npmjs.org/appium-ios-remotexpc/-/appium-ios-remotexpc-5.14.0.tgz",
517
+ "integrity": "sha512-KcFZPDRvj8Z3W17watauBAfD1A19kbG/1jxrTwPWkzg8VMuQR5GZyoBbnEjrAxjD3Nd8+FEibZx0PgN2QBAcDQ==",
518
518
  "license": "Apache-2.0",
519
519
  "optional": true,
520
520
  "dependencies": {
@@ -572,9 +572,9 @@
572
572
  }
573
573
  },
574
574
  "node_modules/appium-remote-debugger": {
575
- "version": "16.1.0",
576
- "resolved": "https://registry.npmjs.org/appium-remote-debugger/-/appium-remote-debugger-16.1.0.tgz",
577
- "integrity": "sha512-oKI3eOPpnmyGwaVgVAkcbkE8Jpdml1YqP2DOK28Uh28nuwxqEatWMOAhU/SMaHIcDib2oTUmHKXlKSlNzzbxXQ==",
575
+ "version": "17.0.0",
576
+ "resolved": "https://registry.npmjs.org/appium-remote-debugger/-/appium-remote-debugger-17.0.0.tgz",
577
+ "integrity": "sha512-6sGezJXG0H7STdRxwx/NTgTymvQb/mwDyCK3rx3+ypyq6T1nE2iaaAs04pT1EryL4VWdF/ML32FecKltu2DYdQ==",
578
578
  "license": "Apache-2.0",
579
579
  "dependencies": {
580
580
  "@appium/base-driver": "^10.0.0-rc.1",
@@ -593,9 +593,9 @@
593
593
  }
594
594
  },
595
595
  "node_modules/appium-webdriveragent": {
596
- "version": "16.1.5",
597
- "resolved": "https://registry.npmjs.org/appium-webdriveragent/-/appium-webdriveragent-16.1.5.tgz",
598
- "integrity": "sha512-R8SM8NEak5TAVbvnzBjTy9F5yJpgOE1d0kVahIcTvipFPU6g06Jg1moNPIZs0+nsykyRLIvED3zFZA0G/eNZCQ==",
596
+ "version": "16.1.6",
597
+ "resolved": "https://registry.npmjs.org/appium-webdriveragent/-/appium-webdriveragent-16.1.6.tgz",
598
+ "integrity": "sha512-Xyin/09D1C8qGXtWSU/V13sDgg11S15zaGaxjtZhhqVkoyxC0XNjmy2vE7lXhxKSovcTtGfTW5ZYdliKRsZvHA==",
599
599
  "license": "Apache-2.0",
600
600
  "dependencies": {
601
601
  "@appium/base-driver": "^10.3.0",
@@ -786,9 +786,9 @@
786
786
  }
787
787
  },
788
788
  "node_modules/bare-url": {
789
- "version": "2.4.7",
790
- "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.7.tgz",
791
- "integrity": "sha512-o8CRCiJtib+ycO3mE4A5UChtGX4dDP2XxsWVu9P+Zc3H8tcmKwNVEDoDTXmwN+uuMhfKeT7/i7Y26xS8W7ohoA==",
789
+ "version": "2.5.1",
790
+ "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.5.1.tgz",
791
+ "integrity": "sha512-cD5ciQuKlx+eumTCfqbfiL+fhQm+dHbVNB/cX4+d+I/nx4JsVop9VoFEPAs5RJ6I84QR6bZIBjpd2kjDOYeWcg==",
792
792
  "license": "Apache-2.0",
793
793
  "dependencies": {
794
794
  "bare-path": "^3.0.0"
@@ -3620,9 +3620,9 @@
3620
3620
  "license": "ISC"
3621
3621
  },
3622
3622
  "node_modules/ws": {
3623
- "version": "8.21.2",
3624
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.2.tgz",
3625
- "integrity": "sha512-54dMVAo4WIe6SKy3vBgN+9bJZqqQ8IMRevAkOLQALhi49qkkQDQfWdAZ8KQlXiEabw88ARXXdUrlvtbKQX+aKw==",
3623
+ "version": "8.21.3",
3624
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz",
3625
+ "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==",
3626
3626
  "license": "MIT",
3627
3627
  "engines": {
3628
3628
  "node": ">=10.0.0"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium-xcuitest-driver",
3
- "version": "12.2.1",
3
+ "version": "12.3.1",
4
4
  "description": "Appium driver for iOS using XCUITest for backend",
5
5
  "keywords": [
6
6
  "appium",
@@ -73,7 +73,7 @@
73
73
  "@colors/colors": "^1.6.0",
74
74
  "appium-ios-device": "^3.1.12",
75
75
  "appium-ios-simulator": "^9.0.0",
76
- "appium-remote-debugger": "^16.0.0",
76
+ "appium-remote-debugger": "^17.0.0",
77
77
  "appium-webdriveragent": "^16.1.4",
78
78
  "appium-xcode": "^7.0.0",
79
79
  "async-lock": "^1.4.0",
@@ -0,0 +1,127 @@
1
+ export const DEFAULT_DISCONNECT_RETRY_INTERVAL_MS = 1000;
2
+ export const DEFAULT_DISCONNECT_RETRY_BACKOFF_MULTIPLIER = 2;
3
+ export const DEFAULT_DISCONNECT_RETRY_BACKOFF_MAX_INTERVAL_MS = 30_000;
4
+ export const DEFAULT_DISCONNECT_RETRY_BACKOFF_JITTER = 0.5;
5
+
6
+ /**
7
+ * @abstract
8
+ * Common attempt-counting behavior shared by all retry policies. Subclasses only need to implement
9
+ * `getDelayMs()`.
10
+ */
11
+ export class RetryPolicy {
12
+ /**
13
+ * @param {{maxAttempts: number | null, intervalMs: number}} opts - maxAttempts: null disables
14
+ * retries entirely; 0 means unlimited retries
15
+ */
16
+ constructor({maxAttempts, intervalMs}) {
17
+ if (new.target === RetryPolicy) {
18
+ throw new TypeError('RetryPolicy is abstract and cannot be instantiated directly');
19
+ }
20
+ this.maxAttempts = maxAttempts;
21
+ this._intervalMs = intervalMs;
22
+ }
23
+
24
+ get isEnabled() {
25
+ return this.maxAttempts !== null;
26
+ }
27
+
28
+ /**
29
+ * @param {number} attemptsMade - number of attempts already made
30
+ * @returns {boolean}
31
+ */
32
+ hasAttemptsRemaining(attemptsMade) {
33
+ const {maxAttempts} = this;
34
+ if (maxAttempts === null) {
35
+ return false;
36
+ }
37
+ return maxAttempts === 0 || attemptsMade < maxAttempts;
38
+ }
39
+
40
+ /**
41
+ * @abstract
42
+ * @param {number} _attempt - 1-based number of the attempt about to be made
43
+ * @returns {number}
44
+ */
45
+ getDelayMs(_attempt) {
46
+ throw new Error('Not implemented');
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Fixed-interval retry policy: waits the same delay between every attempt.
52
+ */
53
+ export class FixedIntervalRetryPolicy extends RetryPolicy {
54
+ /**
55
+ * @param {number} _attempt - 1-based number of the attempt about to be made
56
+ * @returns {number}
57
+ */
58
+ getDelayMs(_attempt) {
59
+ return this._intervalMs;
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Exponential-backoff retry policy: the delay grows by a multiplier on each attempt, capped at a
65
+ * configured maximum.
66
+ */
67
+ export class ExponentialBackoffRetryPolicy extends RetryPolicy {
68
+ /**
69
+ * @param {{maxAttempts: number | null, intervalMs: number, backoffMultiplier: number, backoffMaxIntervalMs: number, jitter: number}} opts
70
+ * - jitter: fraction of the delay to randomize away, in [0, 1]. 0 always returns the exact
71
+ * computed delay; 1 returns a value uniformly distributed between 0 and the computed delay.
72
+ * Jitter spreads out devices that dropped together instead of having them retry in lockstep and
73
+ * stay synchronised once they reach the cap.
74
+ */
75
+ constructor({maxAttempts, intervalMs, backoffMultiplier, backoffMaxIntervalMs, jitter}) {
76
+ super({maxAttempts, intervalMs});
77
+ if (backoffMaxIntervalMs < intervalMs) {
78
+ throw new Error(
79
+ `Invalid disconnect retry backoff max interval: ${backoffMaxIntervalMs}. ` +
80
+ `Expected a value >= the initial interval (${intervalMs}).`,
81
+ );
82
+ }
83
+ if (jitter < 0 || jitter > 1) {
84
+ throw new Error(`Invalid disconnect retry backoff jitter: ${jitter}. Expected a value between 0 and 1.`);
85
+ }
86
+ this._backoffMultiplier = backoffMultiplier;
87
+ this._backoffMaxIntervalMs = backoffMaxIntervalMs;
88
+ this._jitter = jitter;
89
+ }
90
+
91
+ /**
92
+ * @param {number} attempt - 1-based number of the attempt about to be made
93
+ * @returns {number}
94
+ */
95
+ getDelayMs(attempt) {
96
+ const delayMs = this._intervalMs * this._backoffMultiplier ** (attempt - 1);
97
+ const cappedDelayMs = Math.min(delayMs, this._backoffMaxIntervalMs);
98
+ return Math.round(cappedDelayMs * (1 - this._jitter * Math.random()));
99
+ }
100
+ }
101
+
102
+ /**
103
+ * @param {{strategy: 'fixed' | 'exponential', maxAttempts: number | null, intervalMs: number, backoffMultiplier?: number, backoffMaxIntervalMs?: number, jitter?: number}} opts
104
+ * @returns {RetryPolicy}
105
+ */
106
+ export function createDisconnectRetryPolicy({
107
+ strategy,
108
+ maxAttempts,
109
+ intervalMs,
110
+ backoffMultiplier = DEFAULT_DISCONNECT_RETRY_BACKOFF_MULTIPLIER,
111
+ backoffMaxIntervalMs = DEFAULT_DISCONNECT_RETRY_BACKOFF_MAX_INTERVAL_MS,
112
+ jitter = DEFAULT_DISCONNECT_RETRY_BACKOFF_JITTER,
113
+ }) {
114
+ if (strategy === 'fixed') {
115
+ return new FixedIntervalRetryPolicy({maxAttempts, intervalMs});
116
+ }
117
+ if (strategy === 'exponential') {
118
+ return new ExponentialBackoffRetryPolicy({
119
+ maxAttempts,
120
+ intervalMs,
121
+ backoffMultiplier,
122
+ backoffMaxIntervalMs,
123
+ jitter,
124
+ });
125
+ }
126
+ throw new Error(`Invalid disconnect retry strategy: ${strategy}. Expected 'fixed' or 'exponential'.`);
127
+ }
@@ -27,6 +27,14 @@ import {Command} from 'commander';
27
27
 
28
28
  import {parsePositiveIntegerOption} from './lib/options.mjs';
29
29
  import {startTimeoutProgressLogger} from './lib/progress.mjs';
30
+ import {
31
+ createDisconnectRetryPolicy,
32
+ DEFAULT_DISCONNECT_RETRY_BACKOFF_JITTER,
33
+ DEFAULT_DISCONNECT_RETRY_BACKOFF_MAX_INTERVAL_MS,
34
+ DEFAULT_DISCONNECT_RETRY_BACKOFF_MULTIPLIER,
35
+ DEFAULT_DISCONNECT_RETRY_INTERVAL_MS,
36
+ FixedIntervalRetryPolicy,
37
+ } from './lib/retry-policy.mjs';
30
38
  import {assertRoot} from './lib/root.mjs';
31
39
 
32
40
  const log = logger.getLogger('TunnelCreation');
@@ -65,9 +73,11 @@ class TunnelCreator {
65
73
  /** @type {Map<string, import('appium-ios-remotexpc').AppleTVTunnelService>} */
66
74
  this._appletvTunnelServicesByUdid = new Map();
67
75
  this._isCleaningUp = false;
68
- /** @type {number | null} */
69
- this._disconnectRetryMaxAttempts = null;
70
- this._disconnectRetryIntervalMs = 1000;
76
+ /** @type {import('./lib/retry-policy.mjs').RetryPolicy} */
77
+ this._disconnectRetryPolicy = new FixedIntervalRetryPolicy({
78
+ maxAttempts: null,
79
+ intervalMs: DEFAULT_DISCONNECT_RETRY_INTERVAL_MS,
80
+ });
71
81
  }
72
82
 
73
83
  get tunnelRegistryPort() {
@@ -83,12 +93,10 @@ class TunnelCreator {
83
93
  }
84
94
 
85
95
  /**
86
- * @param {number | null} maxAttempts - null disables retries; 0 means unlimited retries
87
- * @param {number} intervalMs
96
+ * @param {import('./lib/retry-policy.mjs').RetryPolicy} policy
88
97
  */
89
- setDisconnectRetryPolicy(maxAttempts, intervalMs) {
90
- this._disconnectRetryMaxAttempts = maxAttempts;
91
- this._disconnectRetryIntervalMs = intervalMs;
98
+ setDisconnectRetryPolicy(policy) {
99
+ this._disconnectRetryPolicy = policy;
92
100
  }
93
101
 
94
102
  /**
@@ -576,10 +584,6 @@ class TunnelCreator {
576
584
  if (!this._isRetryEnabledForUdid(udid)) {
577
585
  return;
578
586
  }
579
- const maxAttempts = this._disconnectRetryMaxAttempts;
580
- if (maxAttempts === null) {
581
- return;
582
- }
583
587
 
584
588
  const device = this._usbDevicesByUdid.get(udid);
585
589
  const isAppleTV = this._appleTVDeviceIds.has(udid);
@@ -587,17 +591,19 @@ class TunnelCreator {
587
591
  return;
588
592
  }
589
593
 
590
- let attempt = 0;
594
+ const policy = this._disconnectRetryPolicy;
595
+ let attemptsMade = 0;
591
596
  while (!this._isCleaningUp) {
592
- if (maxAttempts !== 0 && attempt >= maxAttempts) {
597
+ if (!policy.hasAttemptsRemaining(attemptsMade)) {
593
598
  log.warn(`Retry limit reached for ${udid}; keeping it removed from the registry`);
594
599
  return;
595
600
  }
596
- attempt += 1;
601
+ attemptsMade += 1;
602
+ const delayMs = policy.getDelayMs(attemptsMade);
597
603
  log.warn(
598
- `Retrying tunnel creation for ${udid} (attempt ${attempt}${maxAttempts === 0 ? ', unlimited' : `/${maxAttempts}`}) in ${this._disconnectRetryIntervalMs}ms...`,
604
+ `Retrying tunnel creation for ${udid} (attempt ${attemptsMade}${policy.maxAttempts === 0 ? ', unlimited' : `/${policy.maxAttempts}`}) in ${delayMs}ms...`,
599
605
  );
600
- await sleep(this._disconnectRetryIntervalMs);
606
+ await sleep(delayMs);
601
607
 
602
608
  try {
603
609
  this._registryServer?.markTunnelPending(udid);
@@ -635,8 +641,7 @@ class TunnelCreator {
635
641
  */
636
642
  _isRetryEnabledForUdid(udid) {
637
643
  return (
638
- (this._usbDevicesByUdid.has(udid) || this._appleTVDeviceIds.has(udid)) &&
639
- this._disconnectRetryMaxAttempts !== null
644
+ (this._usbDevicesByUdid.has(udid) || this._appleTVDeviceIds.has(udid)) && this._disconnectRetryPolicy.isEnabled
640
645
  );
641
646
  }
642
647
 
@@ -800,6 +805,43 @@ function parseNonNegativeIntegerOption(value, label) {
800
805
  return count;
801
806
  }
802
807
 
808
+ /**
809
+ * @param {string} value
810
+ * @returns {'fixed' | 'exponential'}
811
+ */
812
+ function parseRetryStrategyOption(value) {
813
+ if (value !== 'fixed' && value !== 'exponential') {
814
+ throw new Error(`Invalid disconnect retry strategy: ${value}. Expected 'fixed' or 'exponential'.`);
815
+ }
816
+ return value;
817
+ }
818
+
819
+ /**
820
+ * @param {string} value
821
+ * @param {string} label
822
+ * @returns {number}
823
+ */
824
+ function parseRetryBackoffMultiplierOption(value, label) {
825
+ const multiplier = Number.parseFloat(value);
826
+ if (!Number.isFinite(multiplier) || multiplier <= 1) {
827
+ throw new Error(`Invalid ${label}: ${value}. Expected a number greater than 1.`);
828
+ }
829
+ return multiplier;
830
+ }
831
+
832
+ /**
833
+ * @param {string} value
834
+ * @param {string} label
835
+ * @returns {number}
836
+ */
837
+ function parseRetryBackoffJitterOption(value, label) {
838
+ const jitter = Number.parseFloat(value);
839
+ if (!Number.isFinite(jitter) || jitter < 0 || jitter > 1) {
840
+ throw new Error(`Invalid ${label}: ${value}. Expected a number between 0 and 1.`);
841
+ }
842
+ return jitter;
843
+ }
844
+
803
845
  /**
804
846
  * @param {string} value
805
847
  * @param {string[]} previous
@@ -906,11 +948,38 @@ async function main() {
906
948
  'Max tunnel recreation attempts after unexpected disconnect: 0 = unlimited; omit to disable retries',
907
949
  (value) => parseNonNegativeIntegerOption(value, 'disconnect retry max attempts'),
908
950
  )
951
+ .option(
952
+ '--disconnect-retry-strategy <strategy>',
953
+ "Delay strategy between tunnel recreation attempts: 'fixed' or 'exponential'",
954
+ (value) => parseRetryStrategyOption(value),
955
+ 'fixed',
956
+ )
909
957
  .option(
910
958
  '--disconnect-retry-interval-ms <ms>',
911
- 'Delay between tunnel recreation attempts in milliseconds (default 1000)',
959
+ 'Delay between tunnel recreation attempts in milliseconds. ' +
960
+ 'With --disconnect-retry-strategy exponential, this is the initial delay, before it starts growing',
912
961
  (value) => parsePositiveIntegerOption(value, 'disconnect retry interval'),
913
- 1000,
962
+ DEFAULT_DISCONNECT_RETRY_INTERVAL_MS,
963
+ )
964
+ .option(
965
+ '--disconnect-retry-backoff-multiplier <factor>',
966
+ 'Factor the delay grows by on each attempt when --disconnect-retry-strategy is exponential (must be > 1)',
967
+ (value) => parseRetryBackoffMultiplierOption(value, 'disconnect retry backoff multiplier'),
968
+ DEFAULT_DISCONNECT_RETRY_BACKOFF_MULTIPLIER,
969
+ )
970
+ .option(
971
+ '--disconnect-retry-backoff-max-interval-ms <ms>',
972
+ 'Upper bound on the delay between tunnel recreation attempts when --disconnect-retry-strategy is exponential',
973
+ (value) => parsePositiveIntegerOption(value, 'disconnect retry backoff max interval'),
974
+ DEFAULT_DISCONNECT_RETRY_BACKOFF_MAX_INTERVAL_MS,
975
+ )
976
+ .option(
977
+ '--disconnect-retry-backoff-jitter <factor>',
978
+ 'Fraction of the delay to randomize away on each attempt when --disconnect-retry-strategy is exponential, ' +
979
+ 'between 0 (no jitter) and 1 (full jitter). Spreads out devices that dropped together instead of having ' +
980
+ 'them retry in lockstep',
981
+ (value) => parseRetryBackoffJitterOption(value, 'disconnect retry backoff jitter'),
982
+ DEFAULT_DISCONNECT_RETRY_BACKOFF_JITTER,
914
983
  );
915
984
 
916
985
  program.parse(process.argv);
@@ -922,6 +991,24 @@ async function main() {
922
991
  const shouldRunUsbFlow = !hasRequestedAppleTVIds || hasRequestedUdids;
923
992
  const shouldRunAppleTVFlow = !hasRequestedUdids || hasRequestedAppleTVIds;
924
993
 
994
+ /** @type {import('./lib/retry-policy.mjs').RetryPolicy} */
995
+ let disconnectRetryPolicy;
996
+ try {
997
+ disconnectRetryPolicy = createDisconnectRetryPolicy({
998
+ strategy: options.disconnectRetryStrategy,
999
+ maxAttempts: options.disconnectRetryMaxAttempts ?? null,
1000
+ intervalMs: options.disconnectRetryIntervalMs,
1001
+ backoffMultiplier: options.disconnectRetryBackoffMultiplier,
1002
+ backoffMaxIntervalMs: options.disconnectRetryBackoffMaxIntervalMs,
1003
+ jitter: options.disconnectRetryBackoffJitter,
1004
+ });
1005
+ } catch (err) {
1006
+ // program.error() never returns (it exits the process); the throw below is unreachable and
1007
+ // only here so TS can see disconnectRetryPolicy is always assigned past this point.
1008
+ program.error(/** @type {Error} */ (err).message);
1009
+ throw err;
1010
+ }
1011
+
925
1012
  await assertRoot(path.parse(fileURLToPath(import.meta.url)).name);
926
1013
 
927
1014
  const tunnelCreator = new TunnelCreator({
@@ -953,10 +1040,7 @@ async function main() {
953
1040
  });
954
1041
  }
955
1042
 
956
- tunnelCreator.setDisconnectRetryPolicy(
957
- options.disconnectRetryMaxAttempts ?? null,
958
- options.disconnectRetryIntervalMs,
959
- );
1043
+ tunnelCreator.setDisconnectRetryPolicy(disconnectRetryPolicy);
960
1044
 
961
1045
  await tunnelCreator.startRegistryServer();
962
1046