appium 3.0.0-beta.1 → 3.0.0-rc.2

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.
Files changed (66) hide show
  1. package/README.md +10 -0
  2. package/build/lib/appium.d.ts +9 -5
  3. package/build/lib/appium.d.ts.map +1 -1
  4. package/build/lib/appium.js +12 -25
  5. package/build/lib/appium.js.map +1 -1
  6. package/build/lib/bidi-commands.js +2 -2
  7. package/build/lib/bidi-commands.js.map +1 -1
  8. package/build/lib/cli/driver-command.js +1 -1
  9. package/build/lib/cli/driver-command.js.map +1 -1
  10. package/build/lib/cli/extension-command.d.ts.map +1 -1
  11. package/build/lib/cli/extension-command.js +32 -5
  12. package/build/lib/cli/extension-command.js.map +1 -1
  13. package/build/lib/cli/parser.js +1 -1
  14. package/build/lib/cli/plugin-command.js +1 -1
  15. package/build/lib/cli/plugin-command.js.map +1 -1
  16. package/build/lib/constants.d.ts +4 -0
  17. package/build/lib/constants.d.ts.map +1 -1
  18. package/build/lib/constants.js +5 -1
  19. package/build/lib/constants.js.map +1 -1
  20. package/build/lib/extension/driver-config.d.ts.map +1 -1
  21. package/build/lib/extension/driver-config.js +12 -14
  22. package/build/lib/extension/driver-config.js.map +1 -1
  23. package/build/lib/extension/extension-config.d.ts.map +1 -1
  24. package/build/lib/extension/extension-config.js +5 -7
  25. package/build/lib/extension/extension-config.js.map +1 -1
  26. package/build/lib/extension/manifest.d.ts.map +1 -1
  27. package/build/lib/extension/manifest.js +5 -7
  28. package/build/lib/extension/manifest.js.map +1 -1
  29. package/build/lib/insecure-features.d.ts +18 -0
  30. package/build/lib/insecure-features.d.ts.map +1 -0
  31. package/build/lib/insecure-features.js +116 -0
  32. package/build/lib/insecure-features.js.map +1 -0
  33. package/build/lib/logsink.d.ts +10 -0
  34. package/build/lib/logsink.d.ts.map +1 -1
  35. package/build/lib/logsink.js +17 -18
  36. package/build/lib/logsink.js.map +1 -1
  37. package/build/lib/main.d.ts +1 -1
  38. package/build/lib/main.d.ts.map +1 -1
  39. package/build/lib/main.js +3 -1
  40. package/build/lib/main.js.map +1 -1
  41. package/build/lib/schema/cli-args.d.ts +1 -1
  42. package/build/lib/schema/cli-args.js +1 -1
  43. package/build/lib/schema/cli-args.js.map +1 -1
  44. package/build/lib/schema/schema.d.ts +1 -1
  45. package/build/lib/schema/schema.js +1 -1
  46. package/build/lib/utils.d.ts +12 -9
  47. package/build/lib/utils.d.ts.map +1 -1
  48. package/build/lib/utils.js +28 -39
  49. package/build/lib/utils.js.map +1 -1
  50. package/lib/appium.js +15 -37
  51. package/lib/bidi-commands.ts +2 -2
  52. package/lib/cli/driver-command.js +1 -1
  53. package/lib/cli/extension-command.js +36 -6
  54. package/lib/cli/parser.js +1 -1
  55. package/lib/cli/plugin-command.js +1 -1
  56. package/lib/constants.js +5 -0
  57. package/lib/extension/driver-config.js +11 -13
  58. package/lib/extension/extension-config.js +11 -14
  59. package/lib/extension/manifest.js +10 -12
  60. package/lib/insecure-features.ts +129 -0
  61. package/lib/logsink.js +17 -18
  62. package/lib/main.js +4 -1
  63. package/lib/schema/cli-args.js +2 -2
  64. package/lib/schema/schema.js +1 -1
  65. package/lib/utils.js +27 -39
  66. package/package.json +19 -19
@@ -84,20 +84,18 @@ export class DriverConfig extends ExtensionConfig {
84
84
  err: 'Missing or incorrect supported platformNames list.',
85
85
  val: platformNames,
86
86
  });
87
+ } else if (_.isEmpty(platformNames)) {
88
+ problems.push({
89
+ err: 'Empty platformNames list.',
90
+ val: platformNames,
91
+ });
87
92
  } else {
88
- if (_.isEmpty(platformNames)) {
89
- problems.push({
90
- err: 'Empty platformNames list.',
91
- val: platformNames,
92
- });
93
- } else {
94
- for (const pName of platformNames) {
95
- if (!_.isString(pName)) {
96
- problems.push({
97
- err: 'Incorrectly formatted platformName.',
98
- val: pName,
99
- });
100
- }
93
+ for (const pName of platformNames) {
94
+ if (!_.isString(pName)) {
95
+ problems.push({
96
+ err: 'Incorrectly formatted platformName.',
97
+ val: pName,
98
+ });
101
99
  }
102
100
  }
103
101
  }
@@ -240,20 +240,17 @@ export class ExtensionConfig {
240
240
  for (const summary of errorSummaries) {
241
241
  log.error(summary);
242
242
  }
243
- } else {
243
+ } else if (!_.isEmpty(warningSummaries)) {
244
244
  // only display warnings if there are no errors!
245
-
246
- if (!_.isEmpty(warningSummaries)) {
247
- log.warn(
248
- `Appium encountered ${util.pluralize(
249
- 'warning',
250
- warningMap.size,
251
- true
252
- )} while validating ${this.extensionType}s found in manifest ${this.manifestPath}`
253
- );
254
- for (const summary of warningSummaries) {
255
- log.warn(summary);
256
- }
245
+ log.warn(
246
+ `Appium encountered ${util.pluralize(
247
+ 'warning',
248
+ warningMap.size,
249
+ true
250
+ )} while validating ${this.extensionType}s found in manifest ${this.manifestPath}`
251
+ );
252
+ for (const summary of warningSummaries) {
253
+ log.warn(summary);
257
254
  }
258
255
  }
259
256
  return exts;
@@ -464,7 +461,7 @@ export class ExtensionConfig {
464
461
  */
465
462
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
466
463
  getConfigProblems(extManifest, extName) {
467
- // shoud override this method if special validation is necessary for this extension type
464
+ // should override this method if special validation is necessary for this extension type
468
465
  return [];
469
466
  }
470
467
 
@@ -390,19 +390,17 @@ export class Manifest {
390
390
  if (err.code === 'ENOENT') {
391
391
  data = _.cloneDeep(INITIAL_MANIFEST_DATA);
392
392
  shouldWrite = true;
393
+ } else if (this.#manifestPath) {
394
+ throw new Error(
395
+ `Appium had trouble loading the extension installation ` +
396
+ `cache file (${this.#manifestPath}). It may be invalid YAML. Specific error: ${
397
+ err.message
398
+ }`
399
+ );
393
400
  } else {
394
- if (this.#manifestPath) {
395
- throw new Error(
396
- `Appium had trouble loading the extension installation ` +
397
- `cache file (${this.#manifestPath}). It may be invalid YAML. Specific error: ${
398
- err.message
399
- }`
400
- );
401
- } else {
402
- throw new Error(
403
- `Appium encountered an unknown problem. Specific error: ${err.message}`
404
- );
405
- }
401
+ throw new Error(
402
+ `Appium encountered an unknown problem. Specific error: ${err.message}`
403
+ );
406
404
  }
407
405
  }
408
406
 
@@ -0,0 +1,129 @@
1
+ import _ from 'lodash';
2
+ import logger from './logger';
3
+
4
+ import type {AppiumDriver} from './appium';
5
+ import type {ExternalDriver} from '@appium/types';
6
+
7
+ const ALL_DRIVERS_MATCH = '*';
8
+ const FEATURE_NAME_SEPARATOR = ':';
9
+
10
+ /**
11
+ * Configures insecure features according to the values in `args.relaxedSecurityEnabled`,
12
+ * `args.allowInsecure`, and `args.denyInsecure`, and informs the user about any
13
+ * globally-applied features.
14
+ * Uses `logger` instead of `this.log` to reduce user confusion.
15
+ */
16
+ export function configureGlobalFeatures(this: AppiumDriver) {
17
+ if (this.args.relaxedSecurityEnabled) {
18
+ logger.info(
19
+ `Enabling relaxed security. All insecure features will be ` +
20
+ `enabled unless explicitly disabled by --deny-insecure`,
21
+ );
22
+ this.relaxedSecurityEnabled = true;
23
+ } else if (!_.isEmpty(this.args.allowInsecure)) {
24
+ this.allowInsecure = validateFeatures(this.args.allowInsecure);
25
+ const globalAllowedFeatures = filterInsecureFeatures(this.allowInsecure);
26
+ if (!_.isEmpty(globalAllowedFeatures)) {
27
+ logger.info('Explicitly enabling insecure features:');
28
+ globalAllowedFeatures.forEach((a) => logger.info(` ${a}`));
29
+ }
30
+ }
31
+ if (_.isEmpty(this.args.denyInsecure)) {
32
+ return;
33
+ }
34
+ this.denyInsecure = validateFeatures(this.args.denyInsecure);
35
+ const globalDeniedFeatures = filterInsecureFeatures(this.denyInsecure);
36
+ if (_.isEmpty(globalDeniedFeatures)) {
37
+ return;
38
+ }
39
+ logger.info('Explicitly disabling insecure features:');
40
+ globalDeniedFeatures.forEach((a) => logger.info(` ${a}`));
41
+ }
42
+
43
+ /**
44
+ * If anything in the umbrella driver's insecure feature configuration applies to this driver,
45
+ * assign it to the driver instance
46
+ *
47
+ * @param driver
48
+ * @param driverName
49
+ */
50
+ export function configureDriverFeatures(
51
+ this: AppiumDriver,
52
+ driver: ExternalDriver,
53
+ driverName: string,
54
+ ) {
55
+ if (this.relaxedSecurityEnabled) {
56
+ this.log.info(
57
+ `Enabling relaxed security for this session as per the server configuration. ` +
58
+ `All insecure features will be enabled unless explicitly disabled by --deny-insecure`,
59
+ );
60
+ driver.relaxedSecurityEnabled = true;
61
+ }
62
+ const allowedDriverFeatures = filterInsecureFeatures(this.allowInsecure, driverName);
63
+ if (!_.isEmpty(allowedDriverFeatures)) {
64
+ this.log.info('Explicitly enabling insecure features for this session ' +
65
+ 'as per the server configuration:',
66
+ );
67
+ allowedDriverFeatures.forEach((a) => this.log.info(` ${a}`));
68
+ driver.allowInsecure = allowedDriverFeatures;
69
+ }
70
+ const deniedDriverFeatures = filterInsecureFeatures(this.denyInsecure, driverName);
71
+ if (_.isEmpty(deniedDriverFeatures)) {
72
+ return;
73
+ }
74
+ this.log.info('Explicitly disabling insecure features for this session ' +
75
+ 'as per the server configuration:',
76
+ );
77
+ deniedDriverFeatures.forEach((a) => this.log.info(` ${a}`));
78
+ driver.denyInsecure = deniedDriverFeatures;
79
+ }
80
+
81
+ /**
82
+ * Validates the list of allowed/denied server features
83
+ *
84
+ * @param features
85
+ */
86
+ function validateFeatures(features: string[]): string[] {
87
+ const validator = (fullName: string) => {
88
+ const errMsg = `The full feature name must include both the destination automation name or the ` +
89
+ `'${ALL_DRIVERS_MATCH}' wildcard to apply the feature to all installed drivers, and ` +
90
+ `the feature name split by a colon. Got '${fullName}' instead`;
91
+
92
+ const separatorPos = fullName.indexOf(FEATURE_NAME_SEPARATOR);
93
+ if (separatorPos < 0) {
94
+ throw new Error(errMsg);
95
+ }
96
+ const [automationName, featureName] = [
97
+ fullName.substring(0, separatorPos),
98
+ fullName.substring(separatorPos + 1)
99
+ ];
100
+ if (!automationName || !featureName) {
101
+ throw new Error(errMsg);
102
+ }
103
+ return fullName;
104
+ };
105
+ return features.map(validator);
106
+ }
107
+
108
+ /**
109
+ * Filters the list of insecure features to only those that are
110
+ * applicable to the given driver name.
111
+ * Assumes that all feature names have already been validated
112
+ *
113
+ * @param features
114
+ * @param driverName
115
+ */
116
+ function filterInsecureFeatures(
117
+ features: string[],
118
+ driverName: string = ALL_DRIVERS_MATCH
119
+ ): string[] {
120
+ const filterFn = (fullName: string) => {
121
+ const separatorPos = fullName.indexOf(FEATURE_NAME_SEPARATOR);
122
+ if (separatorPos <= 0) {
123
+ return false;
124
+ }
125
+ const automationName = fullName.substring(0, separatorPos);
126
+ return [driverName, ALL_DRIVERS_MATCH].includes(automationName);
127
+ };
128
+ return features.filter(filterFn);
129
+ }
package/lib/logsink.js CHANGED
@@ -61,6 +61,8 @@ export async function init(args) {
61
61
  log = createLogger({
62
62
  transports,
63
63
  levels: LEVELS_MAP,
64
+ handleExceptions: true,
65
+ exitOnError: false
64
66
  });
65
67
 
66
68
  const reportedLoggerErrors = new Set();
@@ -131,12 +133,9 @@ const stripColorFormat = format(function stripColor(info) {
131
133
  * @returns {transports.ConsoleTransportInstance}
132
134
  */
133
135
  function createConsoleTransport(args, logLvl) {
134
- return new transports.Console({
135
- // @ts-expect-error The 'name' property should exist
136
+ /** @type {AppiumConsoleTransportOptions} */
137
+ const opt = {
136
138
  name: 'console',
137
- handleExceptions: true,
138
- exitOnError: false,
139
- json: false,
140
139
  level: logLvl,
141
140
  stderrLevels: ['error'],
142
141
  format: format.combine(
@@ -144,7 +143,8 @@ function createConsoleTransport(args, logLvl) {
144
143
  isLogColorEnabled(args) ? colorizeFormat : stripColorFormat,
145
144
  formatLog(args, true),
146
145
  ),
147
- });
146
+ };
147
+ return new transports.Console(opt);
148
148
  }
149
149
 
150
150
  /**
@@ -154,21 +154,19 @@ function createConsoleTransport(args, logLvl) {
154
154
  * @returns {transports.FileTransportInstance}
155
155
  */
156
156
  function createFileTransport(args, logLvl) {
157
- return new transports.File({
158
- // @ts-expect-error The 'name' property should exist
157
+ /** @type {AppiumFileTransportOptions} */
158
+ const opt = {
159
159
  name: 'file',
160
160
  filename: args.logFile,
161
161
  maxFiles: 1,
162
- handleExceptions: true,
163
- exitOnError: false,
164
- json: false,
165
162
  level: logLvl,
166
163
  format: format.combine(
167
164
  stripColorFormat,
168
165
  formatTimestamp(args),
169
166
  formatLog(args, false),
170
167
  ),
171
- });
168
+ };
169
+ return new transports.File(opt);
172
170
  }
173
171
 
174
172
  /**
@@ -187,21 +185,19 @@ function createHttpTransport(args, logLvl) {
187
185
  port = parseInt(hostAndPort[1], 10);
188
186
  }
189
187
 
190
- return new transports.Http({
191
- // @ts-expect-error The 'name' property should exist
188
+ /** @type {AppiumHttpTransportOptions} */
189
+ const opt = {
192
190
  name: 'http',
193
191
  host,
194
192
  port,
195
193
  path: '/',
196
- handleExceptions: true,
197
- exitOnError: false,
198
- json: false,
199
194
  level: logLvl,
200
195
  format: format.combine(
201
196
  stripColorFormat,
202
197
  formatLog(args, false),
203
198
  ),
204
- });
199
+ };
200
+ return new transports.Http(opt);
205
201
  }
206
202
 
207
203
  /**
@@ -362,4 +358,7 @@ export default init;
362
358
  /**
363
359
  * @typedef {import('appium/types').ParsedArgs} ParsedArgs
364
360
  * @typedef {import('@appium/logger').MessageObject} MessageObject
361
+ * @typedef {transports.ConsoleTransportOptions & {name: string}} AppiumConsoleTransportOptions
362
+ * @typedef {transports.FileTransportOptions & {name: string}} AppiumFileTransportOptions
363
+ * @typedef {transports.HttpTransportOptions & {name: string}} AppiumHttpTransportOptions
365
364
  */
package/lib/main.js CHANGED
@@ -177,7 +177,7 @@ function determineAppiumHomeSource(appiumHomeFromArgs) {
177
177
  *
178
178
  * @template {CliCommand} [Cmd=ServerCommand]
179
179
  * @template {CliExtensionSubcommand|void} [SubCmd=void]
180
- * @param {Args<Cmd, SubCmd>} [args] - Partial args (progammatic usage only)
180
+ * @param {Args<Cmd, SubCmd>} [args] - Partial args (programmatic usage only)
181
181
  * @returns {Promise<InitResult<Cmd>>}
182
182
  * @example
183
183
  * import {init, getSchema} from 'appium';
@@ -375,6 +375,9 @@ async function main(args) {
375
375
 
376
376
  await logStartupInfo(parsedArgs);
377
377
 
378
+ // handle the insecure feature configuration since some features may apply globally
379
+ appiumDriver.configureGlobalFeatures();
380
+
378
381
  const appiumHomeSourceName = determineAppiumHomeSource(args?.appiumHome);
379
382
  logger.debug(`The ${appiumHomeSourceName}: ${appiumHome}`);
380
383
 
@@ -1,6 +1,6 @@
1
1
  import {ArgumentTypeError} from 'argparse';
2
2
  import _ from 'lodash';
3
- import {formatErrors as formatErrors} from '../config-file';
3
+ import {formatErrors} from '../config-file';
4
4
  import {flattenSchema, validate} from './schema';
5
5
  import {transformers, parseCsvLine} from './cli-transformers';
6
6
 
@@ -225,7 +225,7 @@ function subSchemaToArgDef(subSchema, argSpec) {
225
225
  * ArgumentDefinitions for handoff to `argparse`.
226
226
  *
227
227
  * @throws If schema has not been added to ajv (via `finalizeSchema()`)
228
- * @returns {import('../cli/args').ArgumentDefinitions} A map of arryas of
228
+ * @returns {import('../cli/args').ArgumentDefinitions} A map of arrays of
229
229
  * aliases to `argparse` arguments; empty if no schema found
230
230
  */
231
231
  export function toParserArgs() {
@@ -421,7 +421,7 @@ class AppiumSchema {
421
421
  * name. Used when translating to `argparse` options or getting the list of
422
422
  * default values (see {@link AppiumSchema.getDefaults}) for CLI or otherwise.
423
423
  *
424
- * The return value is an intermediate reprsentation used by `cli-args`
424
+ * The return value is an intermediate representation used by `cli-args`
425
425
  * module's `toParserArgs`, which converts the finalized schema to parameters
426
426
  * used by `argparse`.
427
427
  * @throws If {@link AppiumSchema.finalize} has not been called yet.
package/lib/utils.js CHANGED
@@ -17,8 +17,6 @@ const STANDARD_CAPS_LOWERCASE = new Set([...STANDARD_CAPS].map((cap) => cap.toLo
17
17
  export const V4_BROADCAST_IP = '0.0.0.0';
18
18
  export const V6_BROADCAST_IP = '::';
19
19
  export const npmPackage = fs.readPackageJsonFrom(__dirname);
20
- const ALL_DRIVERS_MATCH = '*';
21
- const FEATURE_NAME_SEPARATOR = ':';
22
20
 
23
21
  /**
24
22
  *
@@ -191,19 +189,37 @@ export function getPackageVersion(pkgName) {
191
189
  return pkgInfo.version;
192
190
  }
193
191
 
192
+ /**
193
+ * Returns the root directory of the Appium module.
194
+ *
195
+ * @returns {string} - The absolute path to the Appium module root directory.
196
+ * @throws {Error} - If the Appium module root cannot be determined.
197
+ */
198
+ export const getAppiumModuleRoot = _.memoize(function getAppiumModuleRoot() {
199
+ const selfRoot = node.getModuleRootSync('appium', __filename);
200
+ if (!selfRoot) {
201
+ throw new Error('Cannot find the appium module root. This is likely a bug in Appium.');
202
+ }
203
+ return selfRoot;
204
+ });
205
+
194
206
  /**
195
207
  * Adjusts NODE_PATH environment variable,
196
- * so drivers and plugins could load their peer dependencies.
208
+ * so CJS drivers and plugins could load their peer dependencies.
197
209
  * Read https://nodejs.org/api/modules.html#loading-from-the-global-folders
198
210
  * for more details.
211
+ *
212
+ * Unfortunately this hack does not work with ESM modules,
199
213
  * @returns {void}
200
214
  */
201
215
  export function adjustNodePath() {
202
- const selfRoot = node.getModuleRootSync('appium', __filename);
203
- if (!selfRoot || path.dirname(selfRoot).length >= selfRoot.length) {
216
+ let appiumModuleSearchRoot;
217
+ try {
218
+ appiumModuleSearchRoot = path.dirname(getAppiumModuleRoot());
219
+ } catch (error) {
220
+ logger.warn(error.message);
204
221
  return;
205
222
  }
206
- const nodeModulesRoot = path.dirname(selfRoot);
207
223
 
208
224
  const refreshRequirePaths = () => {
209
225
  try {
@@ -221,7 +237,7 @@ export function adjustNodePath() {
221
237
  };
222
238
 
223
239
  if (!process.env.NODE_PATH) {
224
- process.env.NODE_PATH = nodeModulesRoot;
240
+ process.env.NODE_PATH = appiumModuleSearchRoot;
225
241
  if (refreshRequirePaths()) {
226
242
  process.env.APPIUM_OMIT_PEER_DEPS = '1';
227
243
  } else {
@@ -231,17 +247,17 @@ export function adjustNodePath() {
231
247
  }
232
248
 
233
249
  const nodePathParts = process.env.NODE_PATH.split(path.delimiter);
234
- if (nodePathParts.includes(nodeModulesRoot)) {
250
+ if (nodePathParts.includes(appiumModuleSearchRoot)) {
235
251
  process.env.APPIUM_OMIT_PEER_DEPS = '1';
236
252
  return;
237
253
  }
238
254
 
239
- nodePathParts.push(nodeModulesRoot);
255
+ nodePathParts.push(appiumModuleSearchRoot);
240
256
  process.env.NODE_PATH = nodePathParts.join(path.delimiter);
241
257
  if (refreshRequirePaths()) {
242
258
  process.env.APPIUM_OMIT_PEER_DEPS = '1';
243
259
  } else {
244
- process.env.NODE_PATH = _.without(nodePathParts, nodeModulesRoot).join(path.delimiter);
260
+ process.env.NODE_PATH = _.without(nodePathParts, appiumModuleSearchRoot).join(path.delimiter);
245
261
  }
246
262
  }
247
263
 
@@ -346,7 +362,7 @@ export function isPluginCommandArgs(args) {
346
362
  *
347
363
  * @param {4|6|null} family Either 4 to include ipv4 addresses only,
348
364
  * 6 to include ipv6 addresses only, or null to include all of them
349
- * @returns {os.NetworkInterfaceInfo[]} The list of matched interfcaes
365
+ * @returns {os.NetworkInterfaceInfo[]} The list of matched interfaces
350
366
  */
351
367
  export function fetchInterfaces (family = null) {
352
368
  let familyValue = null;
@@ -427,34 +443,6 @@ export function isBroadcastIp(address) {
427
443
  return [V4_BROADCAST_IP, V6_BROADCAST_IP, `[${V6_BROADCAST_IP}]`].includes(address);
428
444
  }
429
445
 
430
- /**
431
- * Validates the list of allowed/denied server features
432
- *
433
- * @param {string[]} features
434
- * @returns {string[]}
435
- */
436
- export function validateFeatures(features) {
437
- const validator = (/** @type {string} */ fullName) => {
438
- const errMsg = `The full feature name must include both the destination automation name or the ` +
439
- `'${ALL_DRIVERS_MATCH}' wildcard to apply the feature to all installed drivers, and ` +
440
- `the feature name split by a colon. Got '${fullName}' instead`;
441
-
442
- const separatorPos = fullName.indexOf(FEATURE_NAME_SEPARATOR);
443
- if (separatorPos < 0) {
444
- throw new Error(errMsg);
445
- }
446
- const [automationName, featureName] = [
447
- fullName.substring(0, separatorPos),
448
- fullName.substring(separatorPos + 1)
449
- ];
450
- if (!automationName || !featureName) {
451
- throw new Error(errMsg);
452
- }
453
- return fullName;
454
- };
455
- return features.map(validator);
456
- }
457
-
458
446
  /**
459
447
  * @typedef {import('@appium/types').StringRecord} StringRecord
460
448
  * @typedef {import('@appium/types').BaseDriverCapConstraints} BaseDriverCapConstraints
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium",
3
- "version": "3.0.0-beta.1",
3
+ "version": "3.0.0-rc.2",
4
4
  "description": "Automation for Apps.",
5
5
  "keywords": [
6
6
  "automation",
@@ -60,43 +60,43 @@
60
60
  "test:unit": "mocha \"./test/unit/**/*.spec.js\""
61
61
  },
62
62
  "dependencies": {
63
- "@appium/base-driver": "^10.0.0-beta.2",
64
- "@appium/base-plugin": "^3.0.0-beta.2",
65
- "@appium/docutils": "^1.1.0",
66
- "@appium/logger": "^1.7.0",
67
- "@appium/schema": "^0.8.1",
68
- "@appium/support": "^6.1.0",
69
- "@appium/types": "^0.25.3",
70
- "@sidvind/better-ajv-errors": "3.0.1",
63
+ "@appium/base-driver": "^10.0.0-rc.2",
64
+ "@appium/base-plugin": "^3.0.0-rc.2",
65
+ "@appium/docutils": "^2.0.0-rc.1",
66
+ "@appium/logger": "^2.0.0-rc.1",
67
+ "@appium/schema": "^1.0.0-rc.1",
68
+ "@appium/support": "^7.0.0-rc.1",
69
+ "@appium/types": "^1.0.0-rc.1",
70
+ "@sidvind/better-ajv-errors": "4.0.0",
71
71
  "ajv": "8.17.1",
72
72
  "ajv-formats": "3.0.1",
73
73
  "argparse": "2.0.1",
74
74
  "async-lock": "1.4.1",
75
75
  "asyncbox": "3.0.0",
76
- "axios": "1.9.0",
76
+ "axios": "1.11.0",
77
77
  "bluebird": "3.7.2",
78
78
  "lilconfig": "3.1.3",
79
79
  "lodash": "4.17.21",
80
- "lru-cache": "10.4.3",
80
+ "lru-cache": "11.1.0",
81
81
  "ora": "5.4.1",
82
82
  "package-changed": "3.0.0",
83
83
  "resolve-from": "5.0.0",
84
- "semver": "7.7.1",
84
+ "semver": "7.7.2",
85
85
  "source-map-support": "0.5.21",
86
- "teen_process": "2.3.1",
87
- "type-fest": "4.40.0",
86
+ "teen_process": "2.3.3",
87
+ "type-fest": "4.41.0",
88
88
  "winston": "3.17.0",
89
89
  "wrap-ansi": "7.0.0",
90
- "ws": "8.18.1",
91
- "yaml": "2.7.1"
90
+ "ws": "8.18.3",
91
+ "yaml": "2.8.1"
92
92
  },
93
93
  "engines": {
94
- "node": "^20.9.0 || >=22.11.0",
94
+ "node": "^20.19.0 || ^22.12.0 || >=24.0.0",
95
95
  "npm": ">=10"
96
96
  },
97
97
  "publishConfig": {
98
98
  "access": "public",
99
- "tag": "beta"
99
+ "tag": "rc"
100
100
  },
101
- "gitHead": "dc5ef8d5f62c8a0775131305107a4037cd9ec9c9"
101
+ "gitHead": "157425ce6aa01c009533f5bf6a56b14570222b00"
102
102
  }