appium 2.0.0-beta.6 → 2.0.0-beta.60

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