appium 2.0.0-beta.5 → 2.0.0-beta.52

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 (199) hide show
  1. package/README.md +156 -63
  2. package/build/lib/appium.d.ts +226 -0
  3. package/build/lib/appium.d.ts.map +1 -0
  4. package/build/lib/appium.js +694 -439
  5. package/build/lib/appium.js.map +1 -0
  6. package/build/lib/cli/args.d.ts +17 -0
  7. package/build/lib/cli/args.d.ts.map +1 -0
  8. package/build/lib/cli/args.js +253 -319
  9. package/build/lib/cli/args.js.map +1 -0
  10. package/build/lib/cli/driver-command.d.ts +102 -0
  11. package/build/lib/cli/driver-command.d.ts.map +1 -0
  12. package/build/lib/cli/driver-command.js +126 -81
  13. package/build/lib/cli/driver-command.js.map +1 -0
  14. package/build/lib/cli/extension-command.d.ts +385 -0
  15. package/build/lib/cli/extension-command.d.ts.map +1 -0
  16. package/build/lib/cli/extension-command.js +731 -383
  17. package/build/lib/cli/extension-command.js.map +1 -0
  18. package/build/lib/cli/extension.d.ts +23 -0
  19. package/build/lib/cli/extension.d.ts.map +1 -0
  20. package/build/lib/cli/extension.js +71 -54
  21. package/build/lib/cli/extension.js.map +1 -0
  22. package/build/lib/cli/parser.d.ts +84 -0
  23. package/build/lib/cli/parser.d.ts.map +1 -0
  24. package/build/lib/cli/parser.js +240 -128
  25. package/build/lib/cli/parser.js.map +1 -0
  26. package/build/lib/cli/plugin-command.d.ts +99 -0
  27. package/build/lib/cli/plugin-command.d.ts.map +1 -0
  28. package/build/lib/cli/plugin-command.js +120 -81
  29. package/build/lib/cli/plugin-command.js.map +1 -0
  30. package/build/lib/cli/utils.d.ts +29 -0
  31. package/build/lib/cli/utils.d.ts.map +1 -0
  32. package/build/lib/cli/utils.js +72 -51
  33. package/build/lib/cli/utils.js.map +1 -0
  34. package/build/lib/config-file.d.ts +100 -0
  35. package/build/lib/config-file.d.ts.map +1 -0
  36. package/build/lib/config-file.js +207 -0
  37. package/build/lib/config-file.js.map +1 -0
  38. package/build/lib/config.d.ts +49 -0
  39. package/build/lib/config.d.ts.map +1 -0
  40. package/build/lib/config.js +265 -201
  41. package/build/lib/config.js.map +1 -0
  42. package/build/lib/constants.d.ts +49 -0
  43. package/build/lib/constants.d.ts.map +1 -0
  44. package/build/lib/constants.js +66 -0
  45. package/build/lib/constants.js.map +1 -0
  46. package/build/lib/extension/driver-config.d.ts +82 -0
  47. package/build/lib/extension/driver-config.d.ts.map +1 -0
  48. package/build/lib/extension/driver-config.js +212 -0
  49. package/build/lib/extension/driver-config.js.map +1 -0
  50. package/build/lib/extension/extension-config.d.ts +249 -0
  51. package/build/lib/extension/extension-config.d.ts.map +1 -0
  52. package/build/lib/extension/extension-config.js +581 -0
  53. package/build/lib/extension/extension-config.js.map +1 -0
  54. package/build/lib/extension/index.d.ts +48 -0
  55. package/build/lib/extension/index.d.ts.map +1 -0
  56. package/build/lib/extension/index.js +105 -0
  57. package/build/lib/extension/index.js.map +1 -0
  58. package/build/lib/extension/manifest-migrations.d.ts +27 -0
  59. package/build/lib/extension/manifest-migrations.d.ts.map +1 -0
  60. package/build/lib/extension/manifest-migrations.js +118 -0
  61. package/build/lib/extension/manifest-migrations.js.map +1 -0
  62. package/build/lib/extension/manifest.d.ts +145 -0
  63. package/build/lib/extension/manifest.d.ts.map +1 -0
  64. package/build/lib/extension/manifest.js +521 -0
  65. package/build/lib/extension/manifest.js.map +1 -0
  66. package/build/lib/extension/package-changed.d.ts +11 -0
  67. package/build/lib/extension/package-changed.d.ts.map +1 -0
  68. package/build/lib/extension/package-changed.js +62 -0
  69. package/build/lib/extension/package-changed.js.map +1 -0
  70. package/build/lib/extension/plugin-config.d.ts +56 -0
  71. package/build/lib/extension/plugin-config.d.ts.map +1 -0
  72. package/build/lib/extension/plugin-config.js +102 -0
  73. package/build/lib/extension/plugin-config.js.map +1 -0
  74. package/build/lib/grid-register.d.ts +10 -0
  75. package/build/lib/grid-register.d.ts.map +1 -0
  76. package/build/lib/grid-register.js +122 -144
  77. package/build/lib/grid-register.js.map +1 -0
  78. package/build/lib/logger.d.ts +3 -0
  79. package/build/lib/logger.d.ts.map +1 -0
  80. package/build/lib/logger.js +5 -17
  81. package/build/lib/logger.js.map +1 -0
  82. package/build/lib/logsink.d.ts +4 -0
  83. package/build/lib/logsink.d.ts.map +1 -0
  84. package/build/lib/logsink.js +190 -187
  85. package/build/lib/logsink.js.map +1 -0
  86. package/build/lib/main.d.ts +62 -0
  87. package/build/lib/main.d.ts.map +1 -0
  88. package/build/lib/main.js +348 -228
  89. package/build/lib/main.js.map +1 -0
  90. package/build/lib/schema/arg-spec.d.ts +143 -0
  91. package/build/lib/schema/arg-spec.d.ts.map +1 -0
  92. package/build/lib/schema/arg-spec.js +164 -0
  93. package/build/lib/schema/arg-spec.js.map +1 -0
  94. package/build/lib/schema/cli-args.d.ts +19 -0
  95. package/build/lib/schema/cli-args.d.ts.map +1 -0
  96. package/build/lib/schema/cli-args.js +217 -0
  97. package/build/lib/schema/cli-args.js.map +1 -0
  98. package/build/lib/schema/cli-transformers.d.ts +5 -0
  99. package/build/lib/schema/cli-transformers.d.ts.map +1 -0
  100. package/build/lib/schema/cli-transformers.js +124 -0
  101. package/build/lib/schema/cli-transformers.js.map +1 -0
  102. package/build/lib/schema/index.d.ts +3 -0
  103. package/build/lib/schema/index.d.ts.map +1 -0
  104. package/build/lib/schema/index.js +19 -0
  105. package/build/lib/schema/index.js.map +1 -0
  106. package/build/lib/schema/keywords.d.ts +24 -0
  107. package/build/lib/schema/keywords.d.ts.map +1 -0
  108. package/build/lib/schema/keywords.js +128 -0
  109. package/build/lib/schema/keywords.js.map +1 -0
  110. package/build/lib/schema/schema.d.ts +259 -0
  111. package/build/lib/schema/schema.d.ts.map +1 -0
  112. package/build/lib/schema/schema.js +615 -0
  113. package/build/lib/schema/schema.js.map +1 -0
  114. package/build/lib/utils.d.ts +121 -0
  115. package/build/lib/utils.d.ts.map +1 -0
  116. package/build/lib/utils.js +351 -273
  117. package/build/lib/utils.js.map +1 -0
  118. package/build/tsconfig.tsbuildinfo +1 -0
  119. package/build/types/cli.d.ts +134 -0
  120. package/build/types/cli.d.ts.map +1 -0
  121. package/build/types/cli.js +3 -0
  122. package/build/types/cli.js.map +1 -0
  123. package/build/types/index.d.ts +15 -0
  124. package/build/types/index.d.ts.map +1 -0
  125. package/build/types/index.js +19 -0
  126. package/build/types/index.js.map +1 -0
  127. package/build/types/manifest/base.d.ts +135 -0
  128. package/build/types/manifest/base.d.ts.map +1 -0
  129. package/build/types/manifest/base.js +3 -0
  130. package/build/types/manifest/base.js.map +1 -0
  131. package/build/types/manifest/index.d.ts +19 -0
  132. package/build/types/manifest/index.d.ts.map +1 -0
  133. package/build/types/manifest/index.js +40 -0
  134. package/build/types/manifest/index.js.map +1 -0
  135. package/build/types/manifest/v3.d.ts +139 -0
  136. package/build/types/manifest/v3.d.ts.map +1 -0
  137. package/build/types/manifest/v3.js +3 -0
  138. package/build/types/manifest/v3.js.map +1 -0
  139. package/driver.d.ts +1 -0
  140. package/driver.js +14 -0
  141. package/index.js +11 -0
  142. package/lib/appium.js +535 -186
  143. package/lib/cli/args.js +267 -422
  144. package/lib/cli/driver-command.js +126 -23
  145. package/lib/cli/extension-command.js +679 -271
  146. package/lib/cli/extension.js +48 -17
  147. package/lib/cli/parser.js +263 -83
  148. package/lib/cli/plugin-command.js +115 -20
  149. package/lib/cli/utils.js +24 -10
  150. package/lib/config-file.js +220 -0
  151. package/lib/config.js +244 -110
  152. package/lib/constants.js +71 -0
  153. package/lib/extension/driver-config.js +250 -0
  154. package/lib/extension/extension-config.js +682 -0
  155. package/lib/extension/index.js +116 -0
  156. package/lib/extension/manifest-migrations.js +120 -0
  157. package/lib/extension/manifest.js +573 -0
  158. package/lib/extension/package-changed.js +64 -0
  159. package/lib/extension/plugin-config.js +112 -0
  160. package/lib/grid-register.js +49 -35
  161. package/lib/logger.js +1 -2
  162. package/lib/logsink.js +64 -38
  163. package/lib/main.js +321 -101
  164. package/lib/schema/arg-spec.js +229 -0
  165. package/lib/schema/cli-args.js +238 -0
  166. package/lib/schema/cli-transformers.js +119 -0
  167. package/lib/schema/index.js +2 -0
  168. package/lib/schema/keywords.js +136 -0
  169. package/lib/schema/schema.js +722 -0
  170. package/lib/utils.js +291 -167
  171. package/package.json +83 -84
  172. package/plugin.d.ts +1 -0
  173. package/plugin.js +13 -0
  174. package/scripts/autoinstall-extensions.js +237 -0
  175. package/support.d.ts +1 -0
  176. package/support.js +13 -0
  177. package/tsconfig.json +25 -0
  178. package/types/cli.ts +189 -0
  179. package/types/index.ts +20 -0
  180. package/types/manifest/README.md +30 -0
  181. package/types/manifest/base.ts +158 -0
  182. package/types/manifest/index.ts +27 -0
  183. package/types/manifest/v3.ts +161 -0
  184. package/CHANGELOG.md +0 -3515
  185. package/bin/ios-webkit-debug-proxy-launcher.js +0 -71
  186. package/build/lib/cli/npm.js +0 -208
  187. package/build/lib/cli/parser-helpers.js +0 -82
  188. package/build/lib/driver-config.js +0 -77
  189. package/build/lib/drivers.js +0 -96
  190. package/build/lib/extension-config.js +0 -253
  191. package/build/lib/plugin-config.js +0 -59
  192. package/build/lib/plugins.js +0 -14
  193. package/lib/cli/npm.js +0 -184
  194. package/lib/cli/parser-helpers.js +0 -79
  195. package/lib/driver-config.js +0 -46
  196. package/lib/drivers.js +0 -81
  197. package/lib/extension-config.js +0 -209
  198. package/lib/plugin-config.js +0 -34
  199. package/lib/plugins.js +0 -10
package/lib/main.js CHANGED
@@ -1,42 +1,62 @@
1
1
  #!/usr/bin/env node
2
- // transpile:main
3
2
 
4
- import { init as logsinkInit } from './logsink';
5
- import logger from './logger'; // logger needs to remain first of imports
3
+ import {init as logsinkInit} from './logsink'; // this import needs to come first since it sets up global npmlog
4
+ import logger from './logger'; // logger needs to remain second
5
+ // @ts-ignore
6
+ import {routeConfiguringFunction as makeRouter, server as baseServer} from '@appium/base-driver';
7
+ import {logger as logFactory, util, env} from '@appium/support';
8
+ import {asyncify} from 'asyncbox';
6
9
  import _ from 'lodash';
7
- import { server as baseServer, routeConfiguringFunction as makeRouter } from 'appium-base-driver';
8
- import { asyncify } from 'asyncbox';
9
- import { default as getParser, getDefaultServerArgs } from './cli/parser';
10
- import { USE_ALL_PLUGINS } from './cli/args';
11
- import { logger as logFactory, util } from 'appium-support';
10
+ import {AppiumDriver} from './appium';
11
+ import {runExtensionCommand} from './cli/extension';
12
+ import {getParser} from './cli/parser';
12
13
  import {
13
- showConfig, checkNodeOk, validateServerArgs,
14
- warnNodeDeprecations, validateTmpDir, getNonDefaultArgs,
15
- getGitRev, APPIUM_VER
14
+ APPIUM_VER,
15
+ checkNodeOk,
16
+ getGitRev,
17
+ getNonDefaultServerArgs,
18
+ showConfig,
19
+ showBuildInfo,
20
+ validateTmpDir,
21
+ warnNodeDeprecations,
22
+ checkNpmOk,
16
23
  } from './config';
17
- import DriverConfig from './driver-config';
18
- import PluginConfig from './plugin-config';
19
- import { DRIVER_TYPE, PLUGIN_TYPE } from './extension-config';
20
- import { runExtensionCommand } from './cli/extension';
21
- import { AppiumDriver } from './appium';
24
+ import {readConfigFile} from './config-file';
25
+ import {loadExtensions, getActivePlugins, getActiveDrivers} from './extension';
26
+ import {SERVER_SUBCOMMAND} from './constants';
22
27
  import registerNode from './grid-register';
23
- import { inspectObject } from './utils';
28
+ import {getDefaultsForSchema, validate} from './schema/schema';
29
+ import {
30
+ inspect,
31
+ adjustNodePath,
32
+ isDriverCommandArgs,
33
+ isExtensionCommandArgs,
34
+ isPluginCommandArgs,
35
+ isServerCommandArgs,
36
+ } from './utils';
24
37
 
38
+ const {resolveAppiumHome} = env;
25
39
 
26
- async function preflightChecks ({parser, args, driverConfig, pluginConfig, throwInsteadOfExit = false}) {
40
+ /**
41
+ *
42
+ * @param {ParsedArgs} args
43
+ * @param {boolean} [throwInsteadOfExit]
44
+ */
45
+ async function preflightChecks(args, throwInsteadOfExit = false) {
27
46
  try {
28
47
  checkNodeOk();
48
+ await checkNpmOk();
29
49
  if (args.longStacktrace) {
30
50
  require('longjohn').async_trace_limit = -1;
31
51
  }
32
- if (args.showConfig) {
33
- await showConfig();
52
+ if (args.showBuildInfo) {
53
+ await showBuildInfo();
34
54
  process.exit(0);
35
55
  }
36
56
  warnNodeDeprecations();
37
- validateServerArgs(parser, args);
38
- await driverConfig.read();
39
- await pluginConfig.read();
57
+
58
+ validate(args);
59
+
40
60
  if (args.tmpDir) {
41
61
  await validateTmpDir(args.tmpDir);
42
62
  }
@@ -50,18 +70,29 @@ async function preflightChecks ({parser, args, driverConfig, pluginConfig, throw
50
70
  }
51
71
  }
52
72
 
53
- function logNonDefaultArgsWarning (args) {
73
+ /**
74
+ * @param {Args} args
75
+ */
76
+ function logNonDefaultArgsWarning(args) {
54
77
  logger.info('Non-default server args:');
55
- inspectObject(args);
78
+ inspect(args);
56
79
  }
57
80
 
58
- function logDefaultCapabilitiesWarning (caps) {
59
- logger.info('Default capabilities, which will be added to each request ' +
60
- 'unless overridden by desired capabilities:');
61
- inspectObject(caps);
81
+ /**
82
+ * @param {Args['defaultCapabilities']} caps
83
+ */
84
+ function logDefaultCapabilitiesWarning(caps) {
85
+ logger.info(
86
+ 'Default capabilities, which will be added to each request ' +
87
+ 'unless overridden by desired capabilities:'
88
+ );
89
+ inspect(caps);
62
90
  }
63
91
 
64
- async function logStartupInfo (parser, args) {
92
+ /**
93
+ * @param {ParsedArgs} args
94
+ */
95
+ async function logStartupInfo(args) {
65
96
  let welcome = `Welcome to Appium v${APPIUM_VER}`;
66
97
  let appiumRev = await getGitRev();
67
98
  if (appiumRev) {
@@ -69,7 +100,7 @@ async function logStartupInfo (parser, args) {
69
100
  }
70
101
  logger.info(welcome);
71
102
 
72
- let showArgs = getNonDefaultArgs(parser, args);
103
+ let showArgs = getNonDefaultServerArgs(args);
73
104
  if (_.size(showArgs)) {
74
105
  logNonDefaultArgsWarning(showArgs);
75
106
  }
@@ -83,20 +114,72 @@ async function logStartupInfo (parser, args) {
83
114
  // }
84
115
  }
85
116
 
86
- function logServerPort (address, port) {
87
- let logMessage = `Appium REST http interface listener started on ` +
88
- `${address}:${port}`;
117
+ /**
118
+ * Logs the address and port the server is listening on
119
+ * @param {string} address - Address
120
+ * @param {number} port - Port
121
+ * @returns {void}
122
+ */
123
+ function logServerPort(address, port) {
124
+ let logMessage = `Appium REST http interface listener started on ` + `${address}:${port}`;
89
125
  logger.info(logMessage);
90
126
  }
91
127
 
92
- async function main (args = null) {
93
- let parser = getParser();
128
+ /**
129
+ * Gets a list of `updateServer` functions from all extensions
130
+ * @param {DriverNameMap} driverClasses
131
+ * @param {PluginNameMap} pluginClasses
132
+ * @returns {import('@appium/types').UpdateServerCallback[]}
133
+ */
134
+ function getServerUpdaters(driverClasses, pluginClasses) {
135
+ return _.compact(_.map([...driverClasses.keys(), ...pluginClasses.keys()], 'updateServer'));
136
+ }
137
+
138
+ /**
139
+ * Makes a big `MethodMap` from all the little `MethodMap`s in the extensions
140
+ * @param {DriverNameMap} driverClasses
141
+ * @param {PluginNameMap} pluginClasses
142
+ * @returns {import('@appium/types').MethodMap}
143
+ */
144
+ function getExtraMethodMap(driverClasses, pluginClasses) {
145
+ return [...driverClasses.keys(), ...pluginClasses.keys()].reduce(
146
+ (map, klass) => ({
147
+ ...map,
148
+ ...(klass.newMethodMap ?? {}),
149
+ }),
150
+ {}
151
+ );
152
+ }
153
+ /**
154
+ * Initializes Appium, but does not start the server.
155
+ *
156
+ * Use this to get at the configuration schema.
157
+ *
158
+ * If `args` contains a non-empty `subcommand` which is not `server`, this function will return an empty object.
159
+ *
160
+ * @template {CliCommand} [Cmd=ServerCommand]
161
+ * @template {CliExtensionSubcommand|void} [SubCmd=void]
162
+ * @param {Args<Cmd, SubCmd>} [args] - Partial args (progammatic usage only)
163
+ * @returns {Promise<InitResult<Cmd>>}
164
+ * @example
165
+ * import {init, getSchema} from 'appium';
166
+ * const options = {}; // config object
167
+ * await init(options);
168
+ * const schema = getSchema(); // entire config schema including plugins and drivers
169
+ */
170
+ async function init(args) {
171
+ const appiumHome = args?.appiumHome ?? (await resolveAppiumHome());
172
+
173
+ adjustNodePath();
174
+
175
+ const {driverConfig, pluginConfig} = await loadExtensions(appiumHome);
176
+
177
+ const parser = getParser();
94
178
  let throwInsteadOfExit = false;
95
- if (args) {
96
- // a containing package passed in their own args, let's fill them out
97
- // with defaults
98
- args = Object.assign({}, getDefaultServerArgs(), args);
179
+ /** @type {Args<Cmd, SubCmd>} */
180
+ let preConfigArgs;
99
181
 
182
+ if (args) {
100
183
  // if we have a containing package instead of running as a CLI process,
101
184
  // that package might not appreciate us calling 'process.exit' willy-
102
185
  // nilly, so give it the option to have us throw instead of exit
@@ -105,80 +188,166 @@ async function main (args = null) {
105
188
  // but remove it since it's not a real server arg per se
106
189
  delete args.throwInsteadOfExit;
107
190
  }
191
+ preConfigArgs = {...args, subcommand: args.subcommand ?? SERVER_SUBCOMMAND};
108
192
  } else {
109
193
  // otherwise parse from CLI
110
- args = parser.parseArgs();
194
+ preConfigArgs = /** @type {Args<Cmd, SubCmd>} */ (parser.parseArgs());
111
195
  }
112
- await logsinkInit(args);
113
196
 
114
- // if the user has requested the 'driver' CLI, don't run the normal server,
115
- // but instead pass control to the driver CLI
116
- if (args.subcommand === DRIVER_TYPE || args.subcommand === PLUGIN_TYPE) {
117
- await runExtensionCommand(args, args.subcommand);
118
- process.exit();
197
+ const configResult = await readConfigFile(preConfigArgs.configFile);
198
+
199
+ if (!_.isEmpty(configResult.errors)) {
200
+ throw new Error(
201
+ `Errors in config file ${configResult.filepath}:\n ${
202
+ configResult.reason ?? configResult.errors
203
+ }`
204
+ );
119
205
  }
120
206
 
121
- if (args.logFilters) {
122
- const {issues, rules} = await logFactory.loadSecureValuesPreprocessingRules(args.logFilters);
123
- if (!_.isEmpty(issues)) {
124
- throw new Error(`The log filtering rules config '${args.logFilters}' has issues: ` +
125
- JSON.stringify(issues, null, 2));
207
+ // merge config and apply defaults.
208
+ // the order of precendece is:
209
+ // 1. command line args
210
+ // 2. config file
211
+ // 3. defaults from config file.
212
+ if (isServerCommandArgs(preConfigArgs)) {
213
+ const defaults = getDefaultsForSchema(false);
214
+
215
+ /** @type {ParsedArgs} */
216
+ const serverArgs = _.defaultsDeep({}, preConfigArgs, configResult.config?.server, defaults);
217
+
218
+ if (preConfigArgs.showConfig) {
219
+ showConfig(getNonDefaultServerArgs(preConfigArgs), configResult, defaults, serverArgs);
220
+ return /** @type {InitResult<Cmd>} */ ({});
126
221
  }
127
- if (_.isEmpty(rules)) {
128
- logger.warn(`Found no log filtering rules in '${args.logFilters}'. Is that expected?`);
129
- } else {
130
- logger.info(`Loaded ${util.pluralize('filtering rule', rules.length, true)} from '${args.logFilters}'`);
222
+
223
+ await logsinkInit(serverArgs);
224
+
225
+ if (serverArgs.logFilters) {
226
+ const {issues, rules} = await logFactory.loadSecureValuesPreprocessingRules(
227
+ serverArgs.logFilters
228
+ );
229
+ if (!_.isEmpty(issues)) {
230
+ throw new Error(
231
+ `The log filtering rules config '${serverArgs.logFilters}' has issues: ` +
232
+ JSON.stringify(issues, null, 2)
233
+ );
234
+ }
235
+ if (_.isEmpty(rules)) {
236
+ logger.warn(
237
+ `Found no log filtering rules in '${serverArgs.logFilters}'. Is that expected?`
238
+ );
239
+ } else {
240
+ logger.info(
241
+ `Loaded ${util.pluralize('filtering rule', rules.length, true)} from '${
242
+ serverArgs.logFilters
243
+ }'`
244
+ );
245
+ }
246
+ }
247
+
248
+ const appiumDriver = new AppiumDriver(serverArgs);
249
+ // set the config on the umbrella driver so it can match drivers to caps
250
+ appiumDriver.driverConfig = driverConfig;
251
+ await preflightChecks(serverArgs, throwInsteadOfExit);
252
+
253
+ return /** @type {InitResult<Cmd>} */ ({
254
+ appiumDriver,
255
+ parsedArgs: serverArgs,
256
+ driverConfig,
257
+ pluginConfig,
258
+ });
259
+ } else {
260
+ if (isExtensionCommandArgs(preConfigArgs)) {
261
+ // if the user has requested the 'driver' CLI, don't run the normal server,
262
+ // but instead pass control to the driver CLI
263
+ if (isDriverCommandArgs(preConfigArgs)) {
264
+ await runExtensionCommand(preConfigArgs, driverConfig);
265
+ }
266
+ if (isPluginCommandArgs(preConfigArgs)) {
267
+ await runExtensionCommand(preConfigArgs, pluginConfig);
268
+ }
131
269
  }
270
+ return /** @type {InitResult<Cmd>} */ ({});
132
271
  }
272
+ }
273
+
274
+ /**
275
+ * Initializes Appium's config. Starts server if appropriate and resolves the
276
+ * server instance if so; otherwise resolves w/ `undefined`.
277
+ * @template {CliCommand} [Cmd=ServerCommand]
278
+ * @template {CliExtensionSubcommand|void} [SubCmd=void]
279
+ * @param {Args<Cmd, SubCmd>} [args] - Arguments from CLI or otherwise
280
+ * @returns {Promise<Cmd extends ServerCommand ? import('@appium/types').AppiumServer : void>}
281
+ */
282
+ async function main(args) {
283
+ const initResult = await init(args);
133
284
 
134
- let appiumDriver = new AppiumDriver(args);
135
- const driverConfig = new DriverConfig(args.appiumHome);
136
- const pluginConfig = new PluginConfig(args.appiumHome);
137
- appiumDriver.driverConfig = driverConfig;
138
- await preflightChecks({parser, args, driverConfig, pluginConfig, throwInsteadOfExit});
139
- await logStartupInfo(parser, args);
285
+ if (_.isEmpty(initResult)) {
286
+ // if this branch is taken, we've run a different subcommand, so there's nothing
287
+ // left to do here.
288
+ return /** @type {Cmd extends ServerCommand ? import('@appium/types').AppiumServer : void} */ (
289
+ undefined
290
+ );
291
+ }
292
+
293
+ const {appiumDriver, pluginConfig, driverConfig, parsedArgs} =
294
+ /** @type {InitResult<ServerCommand>} */ (initResult);
295
+
296
+ const pluginClasses = getActivePlugins(pluginConfig, parsedArgs.usePlugins);
297
+ // set the active plugins on the umbrella driver so it can use them for commands
298
+ appiumDriver.pluginClasses = pluginClasses;
299
+
300
+ await logStartupInfo(parsedArgs);
140
301
  let routeConfiguringFunction = makeRouter(appiumDriver);
141
302
 
142
- // find any plugin name which has been installed, and which has been requested for activation by
143
- // using the --plugins flag, and turn each one into an instantiated plugin object, so we can send
144
- // them as objects to the server init. we also want to send/assign them to the umbrella driver so
145
- // it can use them to wrap command execution
146
- const plugins = Object.keys(pluginConfig.installedExtensions).filter((pluginName) =>
147
- _.includes(args.plugins, pluginName) ||
148
- (args.plugins.length === 1 && args.plugins[0] === USE_ALL_PLUGINS)
149
- ).map((pluginName) => {
150
- try {
151
- const PluginClass = pluginConfig.require(pluginName);
152
- return new PluginClass(pluginName);
153
- } catch (err) {
154
- logger.error(`Could not load plugin '${pluginName}', so it will not be available. Error ` +
155
- `in loading the plugin was: ${err}`);
156
- return false;
157
- }
158
- }).filter(Boolean);
159
- appiumDriver.plugins = plugins;
303
+ const driverClasses = getActiveDrivers(driverConfig, parsedArgs.useDrivers);
304
+ const serverUpdaters = getServerUpdaters(driverClasses, pluginClasses);
305
+ const extraMethodMap = getExtraMethodMap(driverClasses, pluginClasses);
160
306
 
161
- let server = await baseServer({
307
+ /** @type {import('@appium/base-driver').ServerOpts} */
308
+ const serverOpts = {
162
309
  routeConfiguringFunction,
163
- port: args.port,
164
- hostname: args.address,
165
- allowCors: args.allowCors,
166
- basePath: args.basePath,
167
- plugins,
168
- });
169
- if (args.allowCors) {
170
- logger.warn('You have enabled CORS requests from any host. Be careful not ' +
171
- 'to visit sites which could maliciously try to start Appium ' +
172
- 'sessions on your machine');
310
+ port: parsedArgs.port,
311
+ hostname: parsedArgs.address,
312
+ allowCors: parsedArgs.allowCors,
313
+ basePath: parsedArgs.basePath,
314
+ serverUpdaters,
315
+ extraMethodMap,
316
+ cliArgs: parsedArgs,
317
+ };
318
+ if (parsedArgs.keepAliveTimeout) {
319
+ serverOpts.keepAliveTimeout = parsedArgs.keepAliveTimeout * 1000;
173
320
  }
174
- appiumDriver.server = server;
321
+ let server;
175
322
  try {
176
- // TODO prelaunch if args.launch is set
177
- // TODO: startAlertSocket(server, appiumServer);
323
+ server = await baseServer(serverOpts);
324
+ } catch (err) {
325
+ logger.error(
326
+ `Could not configure Appium server. It's possible that a driver or plugin tried ` +
327
+ `to update the server and failed. Original error: ${err.message}`
328
+ );
329
+ logger.debug(err.stack);
330
+ return process.exit(1);
331
+ }
178
332
 
333
+ if (parsedArgs.allowCors) {
334
+ logger.warn(
335
+ 'You have enabled CORS requests from any host. Be careful not ' +
336
+ 'to visit sites which could maliciously try to start Appium ' +
337
+ 'sessions on your machine'
338
+ );
339
+ }
340
+ appiumDriver.server = server;
341
+ try {
179
342
  // configure as node on grid, if necessary
180
- if (args.nodeconfig !== null) {
181
- await registerNode(args.nodeconfig, args.address, args.port, args.basePath);
343
+ // falsy values should not cause this to run
344
+ if (parsedArgs.nodeconfig) {
345
+ await registerNode(
346
+ parsedArgs.nodeconfig,
347
+ parsedArgs.address,
348
+ parsedArgs.port,
349
+ parsedArgs.basePath
350
+ );
182
351
  }
183
352
  } catch (err) {
184
353
  await server.close();
@@ -186,7 +355,7 @@ async function main (args = null) {
186
355
  }
187
356
 
188
357
  for (const signal of ['SIGINT', 'SIGTERM']) {
189
- process.once(signal, async function onSignal () {
358
+ process.once(signal, async function onSignal() {
190
359
  logger.info(`Received ${signal} - shutting down`);
191
360
  try {
192
361
  await appiumDriver.deleteAllSessions({
@@ -202,15 +371,66 @@ async function main (args = null) {
202
371
  });
203
372
  }
204
373
 
205
- logServerPort(args.address, args.port);
374
+ logServerPort(parsedArgs.address, parsedArgs.port);
206
375
  driverConfig.print();
207
- pluginConfig.print(plugins);
376
+ pluginConfig.print([...pluginClasses.values()]);
208
377
 
209
- return server;
378
+ return /** @type {Cmd extends ServerCommand ? import('@appium/types').AppiumServer : void} */ (
379
+ server
380
+ );
210
381
  }
211
382
 
383
+ // NOTE: this is here for backwards compat for any scripts referencing `main.js` directly
384
+ // (more specifically, `build/lib/main.js`)
385
+ // the executable is now `../index.js`, so that module will typically be `require.main`.
212
386
  if (require.main === module) {
213
387
  asyncify(main);
214
388
  }
215
389
 
216
- export { main };
390
+ // everything below here is intended to be a public API.
391
+ export {readConfigFile} from './config-file';
392
+ export {finalizeSchema, getSchema, validate} from './schema/schema';
393
+ export {main, init, resolveAppiumHome};
394
+
395
+ /**
396
+ * @typedef {import('@appium/types').DriverType} DriverType
397
+ * @typedef {import('@appium/types').PluginType} PluginType
398
+ * @typedef {import('@appium/types').DriverClass} DriverClass
399
+ * @typedef {import('@appium/types').PluginClass} PluginClass
400
+ * @typedef {import('appium/types').CliCommand} CliCommand
401
+ * @typedef {import('appium/types').CliExtensionSubcommand} CliExtensionSubcommand
402
+ * @typedef {import('appium/types').CliExtensionCommand} CliExtensionCommand
403
+ * @typedef {import('appium/types').ServerCommand} ServerCommand
404
+ * @typedef {import('appium/types').DriverCommand} DriverCommand
405
+ * @typedef {import('appium/types').PluginCommand} PluginCommand
406
+ * @typedef {import('./extension').DriverNameMap} DriverNameMap
407
+ * @typedef {import('./extension').PluginNameMap} PluginNameMap
408
+ */
409
+
410
+ /**
411
+ * Literally an empty object
412
+ * @typedef { {} } ExtCommandInitResult
413
+ */
414
+
415
+ /**
416
+ * @typedef ServerInitData
417
+ * @property {import('./appium').AppiumDriver} appiumDriver - The Appium driver
418
+ * @property {import('appium/types').ParsedArgs} parsedArgs - The parsed arguments
419
+ */
420
+
421
+ /**
422
+ * @template {CliCommand} Cmd
423
+ * @typedef {Cmd extends ServerCommand ? ServerInitData & import('./extension').ExtensionConfigs : ExtCommandInitResult} InitResult
424
+ */
425
+
426
+ /**
427
+ * @template {CliCommand} [Cmd=ServerCommand]
428
+ * @template {CliExtensionSubcommand|void} [SubCmd=void]
429
+ * @typedef {import('appium/types').Args<Cmd, SubCmd>} Args
430
+ */
431
+
432
+ /**
433
+ * @template {CliCommand} [Cmd=ServerCommand]
434
+ * @template {CliExtensionSubcommand|void} [SubCmd=void]
435
+ * @typedef {import('appium/types').ParsedArgs<Cmd, SubCmd>} ParsedArgs
436
+ */