appium 2.0.0-beta.4 → 2.0.0-beta.40

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