appium-xcuitest-driver 12.2.0 → 12.3.0
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 +13 -0
- package/npm-shrinkwrap.json +80 -284
- package/package.json +3 -7
- package/scripts/lib/retry-policy.mjs +127 -0
- package/scripts/tunnel-creation.mjs +109 -25
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
## [12.3.0](https://github.com/appium/appium-xcuitest-driver/compare/v12.2.1...v12.3.0) (2026-08-08)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* 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))
|
|
6
|
+
|
|
7
|
+
## [12.2.1](https://github.com/appium/appium-xcuitest-driver/compare/v12.2.0...v12.2.1) (2026-08-07)
|
|
8
|
+
|
|
9
|
+
### Miscellaneous Chores
|
|
10
|
+
|
|
11
|
+
* Drop chai ([#2935](https://github.com/appium/appium-xcuitest-driver/issues/2935)) ([d31bba4](https://github.com/appium/appium-xcuitest-driver/commit/d31bba46420d816098de8acc4bb0a27060c80b81))
|
|
12
|
+
* rename safe occurrences of JWProxy ([#2937](https://github.com/appium/appium-xcuitest-driver/issues/2937)) ([b479f7b](https://github.com/appium/appium-xcuitest-driver/commit/b479f7b12ceb32eba97e08f0b6a1eb44b9652b81))
|
|
13
|
+
|
|
1
14
|
## [12.2.0](https://github.com/appium/appium-xcuitest-driver/compare/v12.1.4...v12.2.0) (2026-08-04)
|
|
2
15
|
|
|
3
16
|
### Features
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appium-xcuitest-driver",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.3.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "appium-xcuitest-driver",
|
|
9
|
-
"version": "12.
|
|
9
|
+
"version": "12.3.0",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@appium/css-locator-to-native": "^1.0.1",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"appium-ios-device": "^3.1.12",
|
|
16
16
|
"appium-ios-simulator": "^9.0.0",
|
|
17
17
|
"appium-remote-debugger": "^16.0.0",
|
|
18
|
-
"appium-webdriveragent": "^16.
|
|
18
|
+
"appium-webdriveragent": "^16.1.4",
|
|
19
19
|
"appium-xcode": "^7.0.0",
|
|
20
20
|
"async-lock": "^1.4.0",
|
|
21
21
|
"asyncbox": "^6.3.0",
|
|
@@ -39,15 +39,11 @@
|
|
|
39
39
|
"@appium/tsconfig": "^1.2.0",
|
|
40
40
|
"@appium/types": "^1.5.0",
|
|
41
41
|
"@types/async-lock": "1.4.2",
|
|
42
|
-
"@types/chai": "5.2.3",
|
|
43
|
-
"@types/chai-as-promised": "8.0.2",
|
|
44
42
|
"@types/node": "^26.0.0",
|
|
45
43
|
"@types/pem": "1.14.4",
|
|
46
44
|
"@types/portscanner": "^2.1.1",
|
|
47
|
-
"@types/semver": "7.
|
|
45
|
+
"@types/semver": "7.8.0",
|
|
48
46
|
"@types/sinon": "22.0.0",
|
|
49
|
-
"chai": "^6.0.0",
|
|
50
|
-
"chai-as-promised": "^8.0.0",
|
|
51
47
|
"pem": "^1.14.8",
|
|
52
48
|
"sharp": "^0.x",
|
|
53
49
|
"sinon": "^22.0.0",
|
|
@@ -482,13 +478,16 @@
|
|
|
482
478
|
}
|
|
483
479
|
},
|
|
484
480
|
"node_modules/ansi-styles": {
|
|
485
|
-
"version": "
|
|
486
|
-
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-
|
|
487
|
-
"integrity": "sha512-
|
|
488
|
-
"
|
|
481
|
+
"version": "4.3.0",
|
|
482
|
+
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
|
483
|
+
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
|
484
|
+
"extraneous": true,
|
|
489
485
|
"license": "MIT",
|
|
486
|
+
"dependencies": {
|
|
487
|
+
"color-convert": "^2.0.1"
|
|
488
|
+
},
|
|
490
489
|
"engines": {
|
|
491
|
-
"node": ">=
|
|
490
|
+
"node": ">=8"
|
|
492
491
|
},
|
|
493
492
|
"funding": {
|
|
494
493
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
|
@@ -513,9 +512,9 @@
|
|
|
513
512
|
}
|
|
514
513
|
},
|
|
515
514
|
"node_modules/appium-ios-remotexpc": {
|
|
516
|
-
"version": "5.13.
|
|
517
|
-
"resolved": "https://registry.npmjs.org/appium-ios-remotexpc/-/appium-ios-remotexpc-5.13.
|
|
518
|
-
"integrity": "sha512-
|
|
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==",
|
|
519
518
|
"license": "Apache-2.0",
|
|
520
519
|
"optional": true,
|
|
521
520
|
"dependencies": {
|
|
@@ -527,8 +526,7 @@
|
|
|
527
526
|
"axios": "^1.15.1",
|
|
528
527
|
"commander": "^14.0.1",
|
|
529
528
|
"minimatch": "^10.1.1",
|
|
530
|
-
"node-devicectl": "^
|
|
531
|
-
"npm-run-all2": "^8.0.4",
|
|
529
|
+
"node-devicectl": "^2.0.0",
|
|
532
530
|
"path-to-regexp": "^8.3.0"
|
|
533
531
|
},
|
|
534
532
|
"engines": {
|
|
@@ -536,21 +534,6 @@
|
|
|
536
534
|
"npm": ">=10"
|
|
537
535
|
}
|
|
538
536
|
},
|
|
539
|
-
"node_modules/appium-ios-remotexpc/node_modules/node-devicectl": {
|
|
540
|
-
"version": "1.4.3",
|
|
541
|
-
"resolved": "https://registry.npmjs.org/node-devicectl/-/node-devicectl-1.4.3.tgz",
|
|
542
|
-
"integrity": "sha512-AnyroE1FzGhQd5oJ9vo/IJl37XypMFFkTEU7PFcrSDpbJo0KCXdLd5twbgZyUyqtma1KgK7VuE6NsIoMpaBfGA==",
|
|
543
|
-
"license": "Apache-2.0",
|
|
544
|
-
"optional": true,
|
|
545
|
-
"dependencies": {
|
|
546
|
-
"@appium/logger": "^2.0.0-rc.1",
|
|
547
|
-
"teen_process": "^4.1.0"
|
|
548
|
-
},
|
|
549
|
-
"engines": {
|
|
550
|
-
"node": "^20.19.0 || ^22.12.0 || >=24.0.0",
|
|
551
|
-
"npm": ">=10"
|
|
552
|
-
}
|
|
553
|
-
},
|
|
554
537
|
"node_modules/appium-ios-simulator": {
|
|
555
538
|
"version": "9.1.2",
|
|
556
539
|
"resolved": "https://registry.npmjs.org/appium-ios-simulator/-/appium-ios-simulator-9.1.2.tgz",
|
|
@@ -589,9 +572,9 @@
|
|
|
589
572
|
}
|
|
590
573
|
},
|
|
591
574
|
"node_modules/appium-remote-debugger": {
|
|
592
|
-
"version": "16.0
|
|
593
|
-
"resolved": "https://registry.npmjs.org/appium-remote-debugger/-/appium-remote-debugger-16.0.
|
|
594
|
-
"integrity": "sha512-
|
|
575
|
+
"version": "16.4.0",
|
|
576
|
+
"resolved": "https://registry.npmjs.org/appium-remote-debugger/-/appium-remote-debugger-16.4.0.tgz",
|
|
577
|
+
"integrity": "sha512-Rr0u0CNZPte2aEBozGIUJxRclzyqNUkBBrDZLo4rxwwEfnalFcpWfTJa9/f1YtkdakMfTRysJA3YFwmGuVFQ8w==",
|
|
595
578
|
"license": "Apache-2.0",
|
|
596
579
|
"dependencies": {
|
|
597
580
|
"@appium/base-driver": "^10.0.0-rc.1",
|
|
@@ -610,9 +593,9 @@
|
|
|
610
593
|
}
|
|
611
594
|
},
|
|
612
595
|
"node_modules/appium-webdriveragent": {
|
|
613
|
-
"version": "16.1.
|
|
614
|
-
"resolved": "https://registry.npmjs.org/appium-webdriveragent/-/appium-webdriveragent-16.1.
|
|
615
|
-
"integrity": "sha512-
|
|
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==",
|
|
616
599
|
"license": "Apache-2.0",
|
|
617
600
|
"dependencies": {
|
|
618
601
|
"@appium/base-driver": "^10.3.0",
|
|
@@ -803,9 +786,9 @@
|
|
|
803
786
|
}
|
|
804
787
|
},
|
|
805
788
|
"node_modules/bare-url": {
|
|
806
|
-
"version": "2.
|
|
807
|
-
"resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.
|
|
808
|
-
"integrity": "sha512-
|
|
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==",
|
|
809
792
|
"license": "Apache-2.0",
|
|
810
793
|
"dependencies": {
|
|
811
794
|
"bare-path": "^3.0.0"
|
|
@@ -979,42 +962,6 @@
|
|
|
979
962
|
"url": "https://github.com/chalk/chalk?sponsor=1"
|
|
980
963
|
}
|
|
981
964
|
},
|
|
982
|
-
"node_modules/chalk/node_modules/ansi-styles": {
|
|
983
|
-
"version": "4.3.0",
|
|
984
|
-
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
|
985
|
-
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
|
986
|
-
"extraneous": true,
|
|
987
|
-
"license": "MIT",
|
|
988
|
-
"dependencies": {
|
|
989
|
-
"color-convert": "^2.0.1"
|
|
990
|
-
},
|
|
991
|
-
"engines": {
|
|
992
|
-
"node": ">=8"
|
|
993
|
-
},
|
|
994
|
-
"funding": {
|
|
995
|
-
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
|
996
|
-
}
|
|
997
|
-
},
|
|
998
|
-
"node_modules/chalk/node_modules/color-convert": {
|
|
999
|
-
"version": "2.0.1",
|
|
1000
|
-
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
|
1001
|
-
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
|
1002
|
-
"extraneous": true,
|
|
1003
|
-
"license": "MIT",
|
|
1004
|
-
"dependencies": {
|
|
1005
|
-
"color-name": "~1.1.4"
|
|
1006
|
-
},
|
|
1007
|
-
"engines": {
|
|
1008
|
-
"node": ">=7.0.0"
|
|
1009
|
-
}
|
|
1010
|
-
},
|
|
1011
|
-
"node_modules/chalk/node_modules/color-name": {
|
|
1012
|
-
"version": "1.1.4",
|
|
1013
|
-
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
|
1014
|
-
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
|
1015
|
-
"extraneous": true,
|
|
1016
|
-
"license": "MIT"
|
|
1017
|
-
},
|
|
1018
965
|
"node_modules/cliui": {
|
|
1019
966
|
"version": "9.0.1",
|
|
1020
967
|
"resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz",
|
|
@@ -1085,18 +1032,38 @@
|
|
|
1085
1032
|
}
|
|
1086
1033
|
},
|
|
1087
1034
|
"node_modules/color-convert": {
|
|
1088
|
-
"version": "
|
|
1089
|
-
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-
|
|
1090
|
-
"integrity": "sha512-
|
|
1035
|
+
"version": "2.0.1",
|
|
1036
|
+
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
|
1037
|
+
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
|
1038
|
+
"extraneous": true,
|
|
1091
1039
|
"license": "MIT",
|
|
1092
1040
|
"dependencies": {
|
|
1093
|
-
"color-name": "
|
|
1041
|
+
"color-name": "~1.1.4"
|
|
1094
1042
|
},
|
|
1095
1043
|
"engines": {
|
|
1096
|
-
"node": ">=
|
|
1044
|
+
"node": ">=7.0.0"
|
|
1097
1045
|
}
|
|
1098
1046
|
},
|
|
1099
1047
|
"node_modules/color-name": {
|
|
1048
|
+
"version": "1.1.4",
|
|
1049
|
+
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
|
1050
|
+
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
|
1051
|
+
"extraneous": true,
|
|
1052
|
+
"license": "MIT"
|
|
1053
|
+
},
|
|
1054
|
+
"node_modules/color-string": {
|
|
1055
|
+
"version": "2.1.4",
|
|
1056
|
+
"resolved": "https://registry.npmjs.org/color-string/-/color-string-2.1.4.tgz",
|
|
1057
|
+
"integrity": "sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==",
|
|
1058
|
+
"license": "MIT",
|
|
1059
|
+
"dependencies": {
|
|
1060
|
+
"color-name": "^2.0.0"
|
|
1061
|
+
},
|
|
1062
|
+
"engines": {
|
|
1063
|
+
"node": ">=18"
|
|
1064
|
+
}
|
|
1065
|
+
},
|
|
1066
|
+
"node_modules/color-string/node_modules/color-name": {
|
|
1100
1067
|
"version": "2.1.1",
|
|
1101
1068
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.1.tgz",
|
|
1102
1069
|
"integrity": "sha512-p2FdgwVx1a9yWBHP2wI0VgShkDpgN4kZISkxdNipGBJWpa5G6b04OINlVWCyJj0JmfvcPrgqt95E9k8yvaOJFg==",
|
|
@@ -1105,16 +1072,25 @@
|
|
|
1105
1072
|
"node": ">=12.20"
|
|
1106
1073
|
}
|
|
1107
1074
|
},
|
|
1108
|
-
"node_modules/color-
|
|
1109
|
-
"version": "
|
|
1110
|
-
"resolved": "https://registry.npmjs.org/color-
|
|
1111
|
-
"integrity": "sha512-
|
|
1075
|
+
"node_modules/color/node_modules/color-convert": {
|
|
1076
|
+
"version": "3.1.3",
|
|
1077
|
+
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-3.1.3.tgz",
|
|
1078
|
+
"integrity": "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==",
|
|
1112
1079
|
"license": "MIT",
|
|
1113
1080
|
"dependencies": {
|
|
1114
1081
|
"color-name": "^2.0.0"
|
|
1115
1082
|
},
|
|
1116
1083
|
"engines": {
|
|
1117
|
-
"node": ">=
|
|
1084
|
+
"node": ">=14.6"
|
|
1085
|
+
}
|
|
1086
|
+
},
|
|
1087
|
+
"node_modules/color/node_modules/color-name": {
|
|
1088
|
+
"version": "2.1.1",
|
|
1089
|
+
"resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.1.tgz",
|
|
1090
|
+
"integrity": "sha512-p2FdgwVx1a9yWBHP2wI0VgShkDpgN4kZISkxdNipGBJWpa5G6b04OINlVWCyJj0JmfvcPrgqt95E9k8yvaOJFg==",
|
|
1091
|
+
"license": "MIT",
|
|
1092
|
+
"engines": {
|
|
1093
|
+
"node": ">=12.20"
|
|
1118
1094
|
}
|
|
1119
1095
|
},
|
|
1120
1096
|
"node_modules/combined-stream": {
|
|
@@ -1239,44 +1215,6 @@
|
|
|
1239
1215
|
"node": ">=18"
|
|
1240
1216
|
}
|
|
1241
1217
|
},
|
|
1242
|
-
"node_modules/cross-spawn": {
|
|
1243
|
-
"version": "7.0.6",
|
|
1244
|
-
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
|
1245
|
-
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
|
|
1246
|
-
"license": "MIT",
|
|
1247
|
-
"optional": true,
|
|
1248
|
-
"dependencies": {
|
|
1249
|
-
"path-key": "^3.1.0",
|
|
1250
|
-
"shebang-command": "^2.0.0",
|
|
1251
|
-
"which": "^2.0.1"
|
|
1252
|
-
},
|
|
1253
|
-
"engines": {
|
|
1254
|
-
"node": ">= 8"
|
|
1255
|
-
}
|
|
1256
|
-
},
|
|
1257
|
-
"node_modules/cross-spawn/node_modules/isexe": {
|
|
1258
|
-
"version": "2.0.0",
|
|
1259
|
-
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
|
1260
|
-
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
|
1261
|
-
"license": "ISC",
|
|
1262
|
-
"optional": true
|
|
1263
|
-
},
|
|
1264
|
-
"node_modules/cross-spawn/node_modules/which": {
|
|
1265
|
-
"version": "2.0.2",
|
|
1266
|
-
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
|
1267
|
-
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
|
1268
|
-
"license": "ISC",
|
|
1269
|
-
"optional": true,
|
|
1270
|
-
"dependencies": {
|
|
1271
|
-
"isexe": "^2.0.0"
|
|
1272
|
-
},
|
|
1273
|
-
"bin": {
|
|
1274
|
-
"node-which": "bin/node-which"
|
|
1275
|
-
},
|
|
1276
|
-
"engines": {
|
|
1277
|
-
"node": ">= 8"
|
|
1278
|
-
}
|
|
1279
|
-
},
|
|
1280
1218
|
"node_modules/css-selector-parser": {
|
|
1281
1219
|
"version": "3.3.0",
|
|
1282
1220
|
"resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-3.3.0.tgz",
|
|
@@ -2112,16 +2050,6 @@
|
|
|
2112
2050
|
"ms": "^2.1.1"
|
|
2113
2051
|
}
|
|
2114
2052
|
},
|
|
2115
|
-
"node_modules/json-parse-even-better-errors": {
|
|
2116
|
-
"version": "4.0.0",
|
|
2117
|
-
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-4.0.0.tgz",
|
|
2118
|
-
"integrity": "sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==",
|
|
2119
|
-
"license": "MIT",
|
|
2120
|
-
"optional": true,
|
|
2121
|
-
"engines": {
|
|
2122
|
-
"node": "^18.17.0 || >=20.5.0"
|
|
2123
|
-
}
|
|
2124
|
-
},
|
|
2125
2053
|
"node_modules/json-schema": {
|
|
2126
2054
|
"version": "0.4.0",
|
|
2127
2055
|
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
|
|
@@ -2267,15 +2195,6 @@
|
|
|
2267
2195
|
"url": "https://opencollective.com/express"
|
|
2268
2196
|
}
|
|
2269
2197
|
},
|
|
2270
|
-
"node_modules/memorystream": {
|
|
2271
|
-
"version": "0.3.1",
|
|
2272
|
-
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
|
|
2273
|
-
"integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==",
|
|
2274
|
-
"optional": true,
|
|
2275
|
-
"engines": {
|
|
2276
|
-
"node": ">= 0.10.0"
|
|
2277
|
-
}
|
|
2278
|
-
},
|
|
2279
2198
|
"node_modules/merge-descriptors": {
|
|
2280
2199
|
"version": "2.0.0",
|
|
2281
2200
|
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
|
|
@@ -2510,82 +2429,6 @@
|
|
|
2510
2429
|
"node": ">=0.10.0"
|
|
2511
2430
|
}
|
|
2512
2431
|
},
|
|
2513
|
-
"node_modules/npm-normalize-package-bin": {
|
|
2514
|
-
"version": "4.0.0",
|
|
2515
|
-
"resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz",
|
|
2516
|
-
"integrity": "sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==",
|
|
2517
|
-
"license": "ISC",
|
|
2518
|
-
"optional": true,
|
|
2519
|
-
"engines": {
|
|
2520
|
-
"node": "^18.17.0 || >=20.5.0"
|
|
2521
|
-
}
|
|
2522
|
-
},
|
|
2523
|
-
"node_modules/npm-run-all2": {
|
|
2524
|
-
"version": "8.0.4",
|
|
2525
|
-
"resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-8.0.4.tgz",
|
|
2526
|
-
"integrity": "sha512-wdbB5My48XKp2ZfJUlhnLVihzeuA1hgBnqB2J9ahV77wLS+/YAJAlN8I+X3DIFIPZ3m5L7nplmlbhNiFDmXRDA==",
|
|
2527
|
-
"license": "MIT",
|
|
2528
|
-
"optional": true,
|
|
2529
|
-
"dependencies": {
|
|
2530
|
-
"ansi-styles": "^6.2.1",
|
|
2531
|
-
"cross-spawn": "^7.0.6",
|
|
2532
|
-
"memorystream": "^0.3.1",
|
|
2533
|
-
"picomatch": "^4.0.2",
|
|
2534
|
-
"pidtree": "^0.6.0",
|
|
2535
|
-
"read-package-json-fast": "^4.0.0",
|
|
2536
|
-
"shell-quote": "^1.7.3",
|
|
2537
|
-
"which": "^5.0.0"
|
|
2538
|
-
},
|
|
2539
|
-
"bin": {
|
|
2540
|
-
"npm-run-all": "bin/npm-run-all/index.js",
|
|
2541
|
-
"npm-run-all2": "bin/npm-run-all/index.js",
|
|
2542
|
-
"run-p": "bin/run-p/index.js",
|
|
2543
|
-
"run-s": "bin/run-s/index.js"
|
|
2544
|
-
},
|
|
2545
|
-
"engines": {
|
|
2546
|
-
"node": "^20.5.0 || >=22.0.0",
|
|
2547
|
-
"npm": ">= 10"
|
|
2548
|
-
}
|
|
2549
|
-
},
|
|
2550
|
-
"node_modules/npm-run-all2/node_modules/isexe": {
|
|
2551
|
-
"version": "3.1.5",
|
|
2552
|
-
"resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz",
|
|
2553
|
-
"integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==",
|
|
2554
|
-
"license": "BlueOak-1.0.0",
|
|
2555
|
-
"optional": true,
|
|
2556
|
-
"engines": {
|
|
2557
|
-
"node": ">=18"
|
|
2558
|
-
}
|
|
2559
|
-
},
|
|
2560
|
-
"node_modules/npm-run-all2/node_modules/picomatch": {
|
|
2561
|
-
"version": "4.0.5",
|
|
2562
|
-
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz",
|
|
2563
|
-
"integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
|
|
2564
|
-
"license": "MIT",
|
|
2565
|
-
"optional": true,
|
|
2566
|
-
"engines": {
|
|
2567
|
-
"node": ">=12"
|
|
2568
|
-
},
|
|
2569
|
-
"funding": {
|
|
2570
|
-
"url": "https://github.com/sponsors/jonschlinkert"
|
|
2571
|
-
}
|
|
2572
|
-
},
|
|
2573
|
-
"node_modules/npm-run-all2/node_modules/which": {
|
|
2574
|
-
"version": "5.0.0",
|
|
2575
|
-
"resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz",
|
|
2576
|
-
"integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==",
|
|
2577
|
-
"license": "ISC",
|
|
2578
|
-
"optional": true,
|
|
2579
|
-
"dependencies": {
|
|
2580
|
-
"isexe": "^3.1.1"
|
|
2581
|
-
},
|
|
2582
|
-
"bin": {
|
|
2583
|
-
"node-which": "bin/which.js"
|
|
2584
|
-
},
|
|
2585
|
-
"engines": {
|
|
2586
|
-
"node": "^18.17.0 || >=20.5.0"
|
|
2587
|
-
}
|
|
2588
|
-
},
|
|
2589
2432
|
"node_modules/object-inspect": {
|
|
2590
2433
|
"version": "1.13.4",
|
|
2591
2434
|
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
|
|
@@ -2682,16 +2525,6 @@
|
|
|
2682
2525
|
"node": ">= 0.8"
|
|
2683
2526
|
}
|
|
2684
2527
|
},
|
|
2685
|
-
"node_modules/path-key": {
|
|
2686
|
-
"version": "3.1.1",
|
|
2687
|
-
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
|
2688
|
-
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
|
2689
|
-
"license": "MIT",
|
|
2690
|
-
"optional": true,
|
|
2691
|
-
"engines": {
|
|
2692
|
-
"node": ">=8"
|
|
2693
|
-
}
|
|
2694
|
-
},
|
|
2695
2528
|
"node_modules/path-scurry": {
|
|
2696
2529
|
"version": "2.0.2",
|
|
2697
2530
|
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz",
|
|
@@ -2724,19 +2557,6 @@
|
|
|
2724
2557
|
"integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
|
|
2725
2558
|
"license": "MIT"
|
|
2726
2559
|
},
|
|
2727
|
-
"node_modules/pidtree": {
|
|
2728
|
-
"version": "0.6.1",
|
|
2729
|
-
"resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.1.tgz",
|
|
2730
|
-
"integrity": "sha512-e0F9AOF1JMrCfBsyJOwU9lNvQ0WtXTq0j/4jk0BQ5JSI9VAybPXmDpPRw/2FQ3e5d3ZFN1mLh7jW99m/jjaptw==",
|
|
2731
|
-
"license": "MIT",
|
|
2732
|
-
"optional": true,
|
|
2733
|
-
"bin": {
|
|
2734
|
-
"pidtree": "bin/pidtree.js"
|
|
2735
|
-
},
|
|
2736
|
-
"engines": {
|
|
2737
|
-
"node": ">=0.10"
|
|
2738
|
-
}
|
|
2739
|
-
},
|
|
2740
2560
|
"node_modules/plist": {
|
|
2741
2561
|
"version": "4.0.0",
|
|
2742
2562
|
"resolved": "https://registry.npmjs.org/plist/-/plist-4.0.0.tgz",
|
|
@@ -2863,20 +2683,6 @@
|
|
|
2863
2683
|
"node": ">= 0.10"
|
|
2864
2684
|
}
|
|
2865
2685
|
},
|
|
2866
|
-
"node_modules/read-package-json-fast": {
|
|
2867
|
-
"version": "4.0.0",
|
|
2868
|
-
"resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-4.0.0.tgz",
|
|
2869
|
-
"integrity": "sha512-qpt8EwugBWDw2cgE2W+/3oxC+KTez2uSVR8JU9Q36TXPAGCaozfQUs59v4j4GFpWTaw0i6hAZSvOmu1J0uOEUg==",
|
|
2870
|
-
"license": "ISC",
|
|
2871
|
-
"optional": true,
|
|
2872
|
-
"dependencies": {
|
|
2873
|
-
"json-parse-even-better-errors": "^4.0.0",
|
|
2874
|
-
"npm-normalize-package-bin": "^4.0.0"
|
|
2875
|
-
},
|
|
2876
|
-
"engines": {
|
|
2877
|
-
"node": "^18.17.0 || >=20.5.0"
|
|
2878
|
-
}
|
|
2879
|
-
},
|
|
2880
2686
|
"node_modules/readable-stream": {
|
|
2881
2687
|
"version": "4.7.0",
|
|
2882
2688
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
|
|
@@ -3162,29 +2968,6 @@
|
|
|
3162
2968
|
}
|
|
3163
2969
|
}
|
|
3164
2970
|
},
|
|
3165
|
-
"node_modules/shebang-command": {
|
|
3166
|
-
"version": "2.0.0",
|
|
3167
|
-
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
|
3168
|
-
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
|
3169
|
-
"license": "MIT",
|
|
3170
|
-
"optional": true,
|
|
3171
|
-
"dependencies": {
|
|
3172
|
-
"shebang-regex": "^3.0.0"
|
|
3173
|
-
},
|
|
3174
|
-
"engines": {
|
|
3175
|
-
"node": ">=8"
|
|
3176
|
-
}
|
|
3177
|
-
},
|
|
3178
|
-
"node_modules/shebang-regex": {
|
|
3179
|
-
"version": "3.0.0",
|
|
3180
|
-
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
|
3181
|
-
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
|
3182
|
-
"license": "MIT",
|
|
3183
|
-
"optional": true,
|
|
3184
|
-
"engines": {
|
|
3185
|
-
"node": ">=8"
|
|
3186
|
-
}
|
|
3187
|
-
},
|
|
3188
2971
|
"node_modules/shell-quote": {
|
|
3189
2972
|
"version": "1.10.0",
|
|
3190
2973
|
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.10.0.tgz",
|
|
@@ -3776,6 +3559,19 @@
|
|
|
3776
3559
|
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
|
3777
3560
|
}
|
|
3778
3561
|
},
|
|
3562
|
+
"node_modules/wrap-ansi/node_modules/ansi-styles": {
|
|
3563
|
+
"version": "6.2.3",
|
|
3564
|
+
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
|
|
3565
|
+
"integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
|
|
3566
|
+
"dev": true,
|
|
3567
|
+
"license": "MIT",
|
|
3568
|
+
"engines": {
|
|
3569
|
+
"node": ">=12"
|
|
3570
|
+
},
|
|
3571
|
+
"funding": {
|
|
3572
|
+
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
|
3573
|
+
}
|
|
3574
|
+
},
|
|
3779
3575
|
"node_modules/wrap-ansi/node_modules/emoji-regex": {
|
|
3780
3576
|
"version": "10.6.0",
|
|
3781
3577
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
|
|
@@ -3824,9 +3620,9 @@
|
|
|
3824
3620
|
"license": "ISC"
|
|
3825
3621
|
},
|
|
3826
3622
|
"node_modules/ws": {
|
|
3827
|
-
"version": "8.21.
|
|
3828
|
-
"resolved": "https://registry.npmjs.org/ws/-/ws-8.21.
|
|
3829
|
-
"integrity": "sha512-
|
|
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==",
|
|
3830
3626
|
"license": "MIT",
|
|
3831
3627
|
"engines": {
|
|
3832
3628
|
"node": ">=10.0.0"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appium-xcuitest-driver",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.3.0",
|
|
4
4
|
"description": "Appium driver for iOS using XCUITest for backend",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"appium",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"appium-ios-device": "^3.1.12",
|
|
75
75
|
"appium-ios-simulator": "^9.0.0",
|
|
76
76
|
"appium-remote-debugger": "^16.0.0",
|
|
77
|
-
"appium-webdriveragent": "^16.
|
|
77
|
+
"appium-webdriveragent": "^16.1.4",
|
|
78
78
|
"appium-xcode": "^7.0.0",
|
|
79
79
|
"async-lock": "^1.4.0",
|
|
80
80
|
"asyncbox": "^6.3.0",
|
|
@@ -98,15 +98,11 @@
|
|
|
98
98
|
"@appium/tsconfig": "^1.2.0",
|
|
99
99
|
"@appium/types": "^1.5.0",
|
|
100
100
|
"@types/async-lock": "1.4.2",
|
|
101
|
-
"@types/chai": "5.2.3",
|
|
102
|
-
"@types/chai-as-promised": "8.0.2",
|
|
103
101
|
"@types/node": "^26.0.0",
|
|
104
102
|
"@types/pem": "1.14.4",
|
|
105
103
|
"@types/portscanner": "^2.1.1",
|
|
106
|
-
"@types/semver": "7.
|
|
104
|
+
"@types/semver": "7.8.0",
|
|
107
105
|
"@types/sinon": "22.0.0",
|
|
108
|
-
"chai": "^6.0.0",
|
|
109
|
-
"chai-as-promised": "^8.0.0",
|
|
110
106
|
"pem": "^1.14.8",
|
|
111
107
|
"sharp": "^0.x",
|
|
112
108
|
"sinon": "^22.0.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 {
|
|
69
|
-
this.
|
|
70
|
-
|
|
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 {
|
|
87
|
-
* @param {number} intervalMs
|
|
96
|
+
* @param {import('./lib/retry-policy.mjs').RetryPolicy} policy
|
|
88
97
|
*/
|
|
89
|
-
setDisconnectRetryPolicy(
|
|
90
|
-
this.
|
|
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
|
-
|
|
594
|
+
const policy = this._disconnectRetryPolicy;
|
|
595
|
+
let attemptsMade = 0;
|
|
591
596
|
while (!this._isCleaningUp) {
|
|
592
|
-
if (
|
|
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
|
-
|
|
601
|
+
attemptsMade += 1;
|
|
602
|
+
const delayMs = policy.getDelayMs(attemptsMade);
|
|
597
603
|
log.warn(
|
|
598
|
-
`Retrying tunnel creation for ${udid} (attempt ${
|
|
604
|
+
`Retrying tunnel creation for ${udid} (attempt ${attemptsMade}${policy.maxAttempts === 0 ? ', unlimited' : `/${policy.maxAttempts}`}) in ${delayMs}ms...`,
|
|
599
605
|
);
|
|
600
|
-
await sleep(
|
|
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
|
|
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
|
-
|
|
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
|
|