appium-remote-debugger 10.0.3 → 10.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/build/index.js +18 -33
  3. package/build/lib/atoms.d.ts +17 -0
  4. package/build/lib/atoms.d.ts.map +1 -0
  5. package/build/lib/atoms.js +75 -50
  6. package/build/lib/atoms.js.map +1 -1
  7. package/build/lib/logger.d.ts +3 -0
  8. package/build/lib/logger.d.ts.map +1 -0
  9. package/build/lib/logger.js +5 -11
  10. package/build/lib/logger.js.map +1 -1
  11. package/build/lib/mixins/connect.d.ts +125 -0
  12. package/build/lib/mixins/connect.d.ts.map +1 -0
  13. package/build/lib/mixins/connect.js +299 -202
  14. package/build/lib/mixins/connect.js.map +1 -1
  15. package/build/lib/mixins/events.d.ts +7 -0
  16. package/build/lib/mixins/events.d.ts.map +1 -0
  17. package/build/lib/mixins/events.js +7 -12
  18. package/build/lib/mixins/events.js.map +1 -1
  19. package/build/lib/mixins/execute.d.ts +38 -0
  20. package/build/lib/mixins/execute.d.ts.map +1 -0
  21. package/build/lib/mixins/execute.js +162 -122
  22. package/build/lib/mixins/execute.js.map +1 -1
  23. package/build/lib/mixins/index.d.ts +5 -0
  24. package/build/lib/mixins/index.d.ts.map +1 -0
  25. package/build/lib/mixins/index.js +14 -23
  26. package/build/lib/mixins/index.js.map +1 -1
  27. package/build/lib/mixins/message-handlers.d.ts +92 -0
  28. package/build/lib/mixins/message-handlers.d.ts.map +1 -0
  29. package/build/lib/mixins/message-handlers.js +160 -97
  30. package/build/lib/mixins/message-handlers.js.map +1 -1
  31. package/build/lib/mixins/navigate.d.ts +92 -0
  32. package/build/lib/mixins/navigate.d.ts.map +1 -0
  33. package/build/lib/mixins/navigate.js +199 -141
  34. package/build/lib/mixins/navigate.js.map +1 -1
  35. package/build/lib/protocol/index.d.ts +14 -0
  36. package/build/lib/protocol/index.d.ts.map +1 -0
  37. package/build/lib/protocol/index.js +192 -118
  38. package/build/lib/protocol/index.js.map +1 -1
  39. package/build/lib/remote-debugger-real-device.d.ts +6 -0
  40. package/build/lib/remote-debugger-real-device.d.ts.map +1 -0
  41. package/build/lib/remote-debugger-real-device.js +29 -32
  42. package/build/lib/remote-debugger-real-device.js.map +1 -1
  43. package/build/lib/remote-debugger.d.ts +119 -0
  44. package/build/lib/remote-debugger.d.ts.map +1 -0
  45. package/build/lib/remote-debugger.js +256 -226
  46. package/build/lib/remote-debugger.js.map +1 -1
  47. package/build/lib/rpc/index.d.ts +4 -0
  48. package/build/lib/rpc/index.d.ts.map +1 -0
  49. package/build/lib/rpc/index.js +10 -21
  50. package/build/lib/rpc/index.js.map +1 -1
  51. package/build/lib/rpc/remote-messages.d.ts +51 -0
  52. package/build/lib/rpc/remote-messages.d.ts.map +1 -0
  53. package/build/lib/rpc/remote-messages.js +203 -224
  54. package/build/lib/rpc/remote-messages.js.map +1 -1
  55. package/build/lib/rpc/rpc-client-real-device.d.ts +6 -0
  56. package/build/lib/rpc/rpc-client-real-device.d.ts.map +1 -0
  57. package/build/lib/rpc/rpc-client-real-device.js +43 -49
  58. package/build/lib/rpc/rpc-client-real-device.js.map +1 -1
  59. package/build/lib/rpc/rpc-client-simulator.d.ts +15 -0
  60. package/build/lib/rpc/rpc-client-simulator.d.ts.map +1 -0
  61. package/build/lib/rpc/rpc-client-simulator.js +138 -125
  62. package/build/lib/rpc/rpc-client-simulator.js.map +1 -1
  63. package/build/lib/rpc/rpc-client.d.ts +142 -0
  64. package/build/lib/rpc/rpc-client.d.ts.map +1 -0
  65. package/build/lib/rpc/rpc-client.js +559 -418
  66. package/build/lib/rpc/rpc-client.js.map +1 -1
  67. package/build/lib/rpc/rpc-message-handler.d.ts +13 -0
  68. package/build/lib/rpc/rpc-message-handler.d.ts.map +1 -0
  69. package/build/lib/rpc/rpc-message-handler.js +181 -166
  70. package/build/lib/rpc/rpc-message-handler.js.map +1 -1
  71. package/build/lib/utils.d.ts +61 -0
  72. package/build/lib/utils.d.ts.map +1 -0
  73. package/build/lib/utils.js +241 -155
  74. package/build/lib/utils.js.map +1 -1
  75. package/lib/atoms.js +25 -4
  76. package/lib/mixins/connect.js +102 -7
  77. package/lib/mixins/execute.js +46 -13
  78. package/lib/mixins/message-handlers.js +44 -1
  79. package/lib/mixins/navigate.js +55 -3
  80. package/lib/remote-debugger.js +112 -0
  81. package/lib/rpc/rpc-client-real-device.js +1 -6
  82. package/lib/rpc/rpc-client-simulator.js +7 -1
  83. package/lib/rpc/rpc-client.js +106 -6
  84. package/lib/rpc/rpc-message-handler.js +1 -1
  85. package/lib/utils.js +31 -1
  86. package/package.json +25 -15
@@ -7,6 +7,7 @@ import _ from 'lodash';
7
7
  import B from 'bluebird';
8
8
  import path from 'path';
9
9
  import AsyncLock from 'async-lock';
10
+ import RpcClient from './rpc/rpc-client';
10
11
 
11
12
  const REMOTE_DEBUGGER_PORT = 27753;
12
13
  const SAFARI_BUNDLE_ID = 'com.apple.mobilesafari';
@@ -20,6 +21,76 @@ const GARBAGE_COLLECT_TIMEOUT = 5000;
20
21
 
21
22
 
22
23
  class RemoteDebugger extends EventEmitter {
24
+ // properties
25
+ /** @type {any[]|undefined} */
26
+ _skippedApps;
27
+ /** @type {Record<string, any>} */
28
+ _clientEventListeners;
29
+ /** @type {Record<string, any>} */
30
+ appDict;
31
+ /** @type {Record<string, any>[]|undefined} */
32
+ connectedDrivers;
33
+ /** @type {Record<string, any>[]|undefined} */
34
+ currentState;
35
+ /** @type {boolean|undefined} */
36
+ connected;
37
+ /** @type {B<void>} */
38
+ pageLoadDelay;
39
+ /** @type {B<void>} */
40
+ navigationDelay;
41
+ /** @type {RpcClient?} */
42
+ rpcClient;
43
+
44
+ // events
45
+ /** @type {string} */
46
+ static EVENT_PAGE_CHANGE;
47
+ /** @type {string} */
48
+ static EVENT_DISCONNECT;
49
+
50
+ // methods
51
+ /** @type {() => Promise<void>} */
52
+ setConnectionKey;
53
+ /** @type {() => Promise<void>} */
54
+ disconnect;
55
+ /** @type {(currentUrl: string?, maxTries: number, ignoreAboutBlankUrl: boolean) => Promise<Record<string, any>>} */
56
+ searchForApp;
57
+ /** @type {(appsDict:Record<string, any>, currentUrl: string?, ignoreAboutBlankUrl: boolean) => import('./mixins/connect').AppPages?} */
58
+ searchForPage;
59
+ /** @type {() => Promise<void>} */
60
+ pageUnload;
61
+ /** @type {() => Promise<boolean>} */
62
+ checkPageIsReady;
63
+ /** @type {(dict: Record<string, any>) => void} */
64
+ updateAppsWithDict;
65
+ /** @type {(startPageLoadTimer?: import('@appium/support').timing.Timer, pageLoadVerifyHook?: import('./mixins/navigate').TPageLoadVerifyHook) => Promise<void>} */
66
+ waitForDom;
67
+ /** @type {(startPageLoadTimer?: import('@appium/support').timing.Timer?, pageLoadVerifyHook?: import('./mixins/navigate').TPageLoadVerifyHook) => Promise<void>} */
68
+ pageLoad;
69
+ /** @type {(command: string, override?: boolean) => Promise<any>} */
70
+ execute;
71
+ /** @type {() => Promise<any>} */
72
+ waitForFrameNavigated;
73
+ /** @type {(atom: string, args?: any[], frames?: string[]) => Promise<string>} */
74
+ executeAtom;
75
+
76
+ // Callbacks
77
+ /** @type {(err: Error?, appIdKey: string, pageDict: Record<string, any>) => Promise<void>} */
78
+ onPageChange;
79
+ /** @type {(err: Error?, apps: Record<string, any>) => Promise<void>} */
80
+ onConnectedApplicationList;
81
+ /** @type {(err: Error?, dict: Record<string, any>) => Promise<void>} */
82
+ onAppConnect;
83
+ /** @type {(err: Error?, dict: Record<string, any>) => void} */
84
+ onAppDisconnect;
85
+ /** @type {(err: Error?, dict: Record<string, any>) => Promise<void>} */
86
+ onAppUpdate;
87
+ /** @type {(err: Error?, drivers: Record<string, any>) => void} */
88
+ onConnectedDriverList;
89
+ /** @type {(err: Error?, state: Record<string, any>) => void} */
90
+ onCurrentState;
91
+ /** @type {(err: Error?, state: Record<string, any>) => void} */
92
+ frameDetached;
93
+
23
94
  /*
24
95
  * The constructor takes an opts hash with the following properties:
25
96
  * - bundleId - id of the app being connected to
@@ -39,6 +110,7 @@ class RemoteDebugger extends EventEmitter {
39
110
  constructor (opts = {}) {
40
111
  super();
41
112
 
113
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
42
114
  log.info(`Remote Debugger version ${require(path.resolve(getModuleRoot(), 'package.json')).version}`);
43
115
 
44
116
  const {
@@ -141,12 +213,20 @@ class RemoteDebugger extends EventEmitter {
141
213
  }
142
214
 
143
215
  async launchSafari () {
216
+ if (!this.rpcClient) {
217
+ throw new Error(`rpcClient is undefined. Has 'initRpcClient' been called before?`);
218
+ }
219
+
144
220
  await this.rpcClient.send('launchApplication', {
145
221
  bundleId: SAFARI_BUNDLE_ID
146
222
  });
147
223
  }
148
224
 
149
225
  async startTimeline (fn) {
226
+ if (!this.rpcClient) {
227
+ throw new Error(`rpcClient is undefined. Has 'initRpcClient' been called before?`);
228
+ }
229
+
150
230
  log.debug('Starting to record the timeline');
151
231
  this.rpcClient.on('Timeline.eventRecorded', fn);
152
232
  return await this.rpcClient.send('Timeline.start', {
@@ -156,6 +236,10 @@ class RemoteDebugger extends EventEmitter {
156
236
  }
157
237
 
158
238
  async stopTimeline () {
239
+ if (!this.rpcClient) {
240
+ throw new Error(`rpcClient is undefined. Has 'initRpcClient' been called before?`);
241
+ }
242
+
159
243
  log.debug('Stopping to record the timeline');
160
244
  await this.rpcClient.send('Timeline.stop', {
161
245
  appIdKey: this.appIdKey,
@@ -167,12 +251,20 @@ class RemoteDebugger extends EventEmitter {
167
251
  * Keep track of the client event listeners so they can be removed
168
252
  */
169
253
  addClientEventListener (eventName, listener) {
254
+ if (!this.rpcClient) {
255
+ throw new Error(`rpcClient is undefined. Has 'initRpcClient' been called before?`);
256
+ }
257
+
170
258
  this._clientEventListeners[eventName] = this._clientEventListeners[eventName] || [];
171
259
  this._clientEventListeners[eventName].push(listener);
172
260
  this.rpcClient.on(eventName, listener);
173
261
  }
174
262
 
175
263
  removeClientEventListener (eventName) {
264
+ if (!this.rpcClient) {
265
+ throw new Error(`rpcClient is undefined. Has 'initRpcClient' been called before?`);
266
+ }
267
+
176
268
  for (const listener of (this._clientEventListeners[eventName] || [])) {
177
269
  this.rpcClient.off(eventName, listener);
178
270
  }
@@ -211,6 +303,10 @@ class RemoteDebugger extends EventEmitter {
211
303
  // Potentially this does not work for mobile safari
212
304
  async overrideUserAgent (value) {
213
305
  log.debug('Setting overrideUserAgent');
306
+ if (!this.rpcClient) {
307
+ throw new Error(`rpcClient is undefined. Has 'initRpcClient' been called before?`);
308
+ }
309
+
214
310
  return await this.rpcClient.send('Page.overrideUserAgent', {
215
311
  appIdKey: this.appIdKey,
216
312
  pageIdKey: this.pageIdKey,
@@ -220,6 +316,10 @@ class RemoteDebugger extends EventEmitter {
220
316
 
221
317
  async getCookies () {
222
318
  log.debug('Getting cookies');
319
+ if (!this.rpcClient) {
320
+ throw new Error(`rpcClient is undefined. Has 'initRpcClient' been called before?`);
321
+ }
322
+
223
323
  return await this.rpcClient.send('Page.getCookies', {
224
324
  appIdKey: this.appIdKey,
225
325
  pageIdKey: this.pageIdKey
@@ -228,6 +328,10 @@ class RemoteDebugger extends EventEmitter {
228
328
 
229
329
  async setCookie (cookie) {
230
330
  log.debug('Setting cookie');
331
+ if (!this.rpcClient) {
332
+ throw new Error(`rpcClient is undefined. Has 'initRpcClient' been called before?`);
333
+ }
334
+
231
335
  return await this.rpcClient.send('Page.setCookie', {
232
336
  appIdKey: this.appIdKey,
233
337
  pageIdKey: this.pageIdKey,
@@ -237,6 +341,10 @@ class RemoteDebugger extends EventEmitter {
237
341
 
238
342
  async deleteCookie (cookieName, url) {
239
343
  log.debug(`Deleting cookie '${cookieName}' on '${url}'`);
344
+ if (!this.rpcClient) {
345
+ throw new Error(`rpcClient is undefined. Has 'initRpcClient' been called before?`);
346
+ }
347
+
240
348
  return await this.rpcClient.send('Page.deleteCookie', {
241
349
  appIdKey: this.appIdKey,
242
350
  pageIdKey: this.pageIdKey,
@@ -247,6 +355,10 @@ class RemoteDebugger extends EventEmitter {
247
355
 
248
356
  async garbageCollect (timeoutMs = GARBAGE_COLLECT_TIMEOUT) {
249
357
  log.debug(`Garbage collecting with ${timeoutMs}ms timeout`);
358
+ if (!this.rpcClient) {
359
+ throw new Error(`rpcClient is undefined. Has 'initRpcClient' been called before?`);
360
+ }
361
+
250
362
  try {
251
363
  checkParams({appIdKey: this.appIdKey, pageIdKey: this.pageIdKey});
252
364
  } catch (err) {
@@ -8,12 +8,6 @@ export default class RpcClientRealDevice extends RpcClient {
8
8
  super(Object.assign({
9
9
  shouldCheckForTarget: false,
10
10
  }, opts));
11
-
12
- const {
13
- udid,
14
- } = opts;
15
-
16
- this.udid = udid;
17
11
  }
18
12
 
19
13
  async connect () {
@@ -49,6 +43,7 @@ export default class RpcClientRealDevice extends RpcClient {
49
43
  if (!this.isConnected) {
50
44
  return;
51
45
  }
46
+ // @ts-ignore messageHandler must be defined here
52
47
  await this.messageHandler.handleMessage(data);
53
48
  }
54
49
  }
@@ -39,6 +39,7 @@ export default class RpcClientSimulator extends RpcClient {
39
39
  // Forward the actual socketPath to the proxy
40
40
  this.socket.once('connect', () => {
41
41
  log.debug(`Forwarding the actual web inspector socket to the proxy: '${this.socketPath}'`);
42
+ // @ts-ignore socket must be efined here
42
43
  this.socket.write(JSON.stringify({
43
44
  socketPath: this.socketPath
44
45
  }));
@@ -57,7 +58,7 @@ export default class RpcClientSimulator extends RpcClient {
57
58
 
58
59
  // tcp socket
59
60
  log.debug(`Connecting to remote debugger ${this.messageProxy ? 'via proxy ' : ''}through TCP: ${this.host}:${this.port}`);
60
- this.socket = new net.Socket({type: 'tcp6'});
61
+ this.socket = new net.Socket();
61
62
  this.socket.connect(this.port, this.host);
62
63
  }
63
64
 
@@ -86,12 +87,14 @@ export default class RpcClientSimulator extends RpcClient {
86
87
  // connect the socket
87
88
  return await new B((resolve, reject) => {
88
89
  // only resolve this function when we are actually connected
90
+ // @ts-ignore socket must be defined here
89
91
  this.socket.on('connect', () => {
90
92
  log.debug(`Debugger socket connected`);
91
93
  this.isConnected = true;
92
94
 
93
95
  resolve();
94
96
  });
97
+ // @ts-ignore socket must be defined here
95
98
  this.socket.on('error', (err) => {
96
99
  if (this.isConnected) {
97
100
  log.error(`Socket error: ${err.message}`);
@@ -127,6 +130,7 @@ export default class RpcClientSimulator extends RpcClient {
127
130
  reject(err);
128
131
  };
129
132
 
133
+ // @ts-ignore socket must be defined
130
134
  this.socket.on('error', onSocketError);
131
135
  this.service.sendMessage(cmd);
132
136
  resolve();
@@ -134,6 +138,7 @@ export default class RpcClientSimulator extends RpcClient {
134
138
  .finally(() => {
135
139
  // remove this listener, so we don't exhaust the system
136
140
  try {
141
+ // @ts-ignore socket must be defined
137
142
  this.socket.removeListener('error', onSocketError);
138
143
  } catch (ign) {}
139
144
  });
@@ -153,6 +158,7 @@ export default class RpcClientSimulator extends RpcClient {
153
158
  data[key] = data[key].toString('utf8');
154
159
  }
155
160
  }
161
+ // @ts-ignore messageHandler must be defined
156
162
  await this.messageHandler.handleMessage(data);
157
163
  }
158
164
  }
@@ -28,6 +28,15 @@ function isTargetBased (isSafari, platformVersion) {
28
28
  }
29
29
 
30
30
  export default class RpcClient {
31
+ /** @type {RpcMessageHandler|undefined} */
32
+ messageHandler;
33
+
34
+ /** @type {RemoteMessages|undefined} */
35
+ remoteMessages;
36
+
37
+ /** @type {boolean} */
38
+ connected;
39
+
31
40
  constructor (opts = {}) {
32
41
  this._targets = [];
33
42
  this._shouldCheckForTarget = !!opts.shouldCheckForTarget;
@@ -41,6 +50,7 @@ export default class RpcClient {
41
50
  webInspectorMaxFrameLength,
42
51
  socketChunkSize,
43
52
  fullPageInitialization = false,
53
+ udid,
44
54
  } = opts;
45
55
 
46
56
  this.isSafari = isSafari;
@@ -50,6 +60,8 @@ export default class RpcClient {
50
60
  this.senderId = util.uuidV4();
51
61
  this.msgId = 0;
52
62
 
63
+ this.udid = udid;
64
+
53
65
  this.logAllCommunication = logAllCommunication;
54
66
  this.logAllCommunicationHexDump = logAllCommunicationHexDump;
55
67
  this.socketChunkSize = socketChunkSize;
@@ -96,16 +108,19 @@ export default class RpcClient {
96
108
  }
97
109
 
98
110
  on (event, listener) {
111
+ // @ts-ignore messageHandler must be defined here
99
112
  this.messageHandler.on(event, listener);
100
113
  return this;
101
114
  }
102
115
 
103
116
  once (event, listener) {
117
+ // @ts-ignore messageHandler must be defined here
104
118
  this.messageHandler.once(event, listener);
105
119
  return this;
106
120
  }
107
121
 
108
122
  off (event, listener) {
123
+ // @ts-ignore messageHandler must be defined here
109
124
  this.messageHandler.off(event, listener);
110
125
  return this;
111
126
  }
@@ -138,6 +153,13 @@ export default class RpcClient {
138
153
  return this._isTargetBased;
139
154
  }
140
155
 
156
+ /**
157
+ *
158
+ * @param {string} appIdKey
159
+ * @param {string} pageIdKey
160
+ * @param {boolean} [force]
161
+ * @returns {Promise<void>}
162
+ */
141
163
  async waitForTarget (appIdKey, pageIdKey, force = false) {
142
164
  if (!force && !this.needsTarget) {
143
165
  return;
@@ -162,6 +184,13 @@ export default class RpcClient {
162
184
  }
163
185
  }
164
186
 
187
+ /**
188
+ *
189
+ * @param {string} command
190
+ * @param {Record<string, any>} [opts]
191
+ * @param {boolean} [waitForResponse]
192
+ * @returns {Promise<any>}
193
+ */
165
194
  async send (command, opts = {}, waitForResponse = true) {
166
195
  const timer = new timing.Timer().start();
167
196
  const {
@@ -194,6 +223,13 @@ export default class RpcClient {
194
223
  }
195
224
  }
196
225
 
226
+ /**
227
+ *
228
+ * @param {string} command
229
+ * @param {Record<string, any>} opts
230
+ * @param {boolean} [waitForResponse]
231
+ * @returns {Promise<any>}
232
+ */
197
233
  async sendToDevice (command, opts = {}, waitForResponse = true) {
198
234
  return await new B(async (resolve, reject) => {
199
235
  // promise to be resolved whenever remote debugger
@@ -206,6 +242,7 @@ export default class RpcClient {
206
242
  // for target-base communication, everything is wrapped up
207
243
  wrapperMsgId = this.msgId++;
208
244
  // acknowledge wrapper message
245
+ // @ts-ignore messageHandler must be defined
209
246
  this.messageHandler.on(wrapperMsgId.toString(), function (err) {
210
247
  if (err) {
211
248
  reject(err);
@@ -224,6 +261,7 @@ export default class RpcClient {
224
261
  targetId,
225
262
  id: msgId,
226
263
  }, opts);
264
+ // @ts-ignore remoteMessages must be defined
227
265
  const cmd = this.remoteMessages.getRemoteCommand(command, fullOpts);
228
266
 
229
267
  if (cmd?.__argument?.WIRSocketDataKey) {
@@ -240,6 +278,7 @@ export default class RpcClient {
240
278
  // the promise will be resolved as soon as the socket has been sent
241
279
  messageHandled = false;
242
280
  // do not log receipts
281
+ // @ts-ignore messageHandler must be defined
243
282
  this.messageHandler.once(msgId.toString(), function (err) {
244
283
  if (err) {
245
284
  // we are not waiting for this, and if it errors it is most likely
@@ -251,7 +290,9 @@ export default class RpcClient {
251
290
  reject(err);
252
291
  }
253
292
  });
293
+ // @ts-ignore messageHandler must be defined
254
294
  } else if (this.messageHandler.listeners(cmd.__selector).length) {
295
+ // @ts-ignore messageHandler must be defined
255
296
  this.messageHandler.prependOnceListener(cmd.__selector, function (err, ...args) {
256
297
  if (err) {
257
298
  return reject(err);
@@ -260,6 +301,7 @@ export default class RpcClient {
260
301
  resolve(args);
261
302
  });
262
303
  } else if (cmd?.__argument?.WIRSocketDataKey) {
304
+ // @ts-ignore messageHandler must be defined
263
305
  this.messageHandler.once(msgId.toString(), function (err, value) {
264
306
  if (err) {
265
307
  return reject(new Error(`Remote debugger error with code '${err.code}': ${err.message}`));
@@ -273,8 +315,8 @@ export default class RpcClient {
273
315
  }
274
316
 
275
317
  const msg = `Sending '${cmd.__selector}' message` +
276
- (fullOpts.appIdKey ? ` to app '${fullOpts.appIdKey}'` : '') +
277
- (fullOpts.pageIdKey ? `, page '${fullOpts.pageIdKey}'` : '') +
318
+ (appIdKey ? ` to app '${appIdKey}'` : '') +
319
+ (pageIdKey ? `, page '${pageIdKey}'` : '') +
278
320
  (this.needsTarget && targetId ? `, target '${targetId}'` : '') +
279
321
  ` (id: ${msgId}): '${command}'`;
280
322
  log.debug(msg);
@@ -296,10 +338,11 @@ export default class RpcClient {
296
338
  }
297
339
 
298
340
  async disconnect () { // eslint-disable-line require-await
299
- this.messageHandler.removeAllListeners();
341
+ this.messageHandler?.removeAllListeners();
300
342
  }
301
343
 
302
- async sendMessage (/* command */) { // eslint-disable-line require-await
344
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
345
+ async sendMessage (command) { // eslint-disable-line require-await
303
346
  throw new Error(`Sub-classes need to implement a 'sendMessage' function`);
304
347
  }
305
348
 
@@ -307,6 +350,13 @@ export default class RpcClient {
307
350
  throw new Error(`Sub-classes need to implement a 'receive' function`);
308
351
  }
309
352
 
353
+ /**
354
+ *
355
+ * @param {Error?} err
356
+ * @param {string} app
357
+ * @param {Record<string, any>} targetInfo
358
+ * @returns {void}
359
+ */
310
360
  addTarget (err, app, targetInfo) {
311
361
  if (_.isNil(targetInfo?.targetId)) {
312
362
  log.warn(`Received 'Target.targetCreated' event for app '${app}' with no target. Skipping`);
@@ -322,6 +372,7 @@ export default class RpcClient {
322
372
  return;
323
373
  }
324
374
 
375
+ // @ts-ignore this.pendingTargetNotification must be defined here
325
376
  const [appIdKey, pageIdKey] = this.pendingTargetNotification;
326
377
 
327
378
  log.debug(`Target created for app '${appIdKey}' and page '${pageIdKey}': ${JSON.stringify(targetInfo)}`);
@@ -332,6 +383,14 @@ export default class RpcClient {
332
383
  this.targets[appIdKey][pageIdKey] = targetInfo.targetId;
333
384
  }
334
385
 
386
+ /**
387
+ *
388
+ * @param {Error?} err
389
+ * @param {string} app
390
+ * @param {string} oldTargetId
391
+ * @param {string} newTargetId
392
+ * @returns {void}
393
+ */
335
394
  updateTarget (err, app, oldTargetId, newTargetId) {
336
395
  log.debug(`Target updated for app '${app}'. Old target: '${oldTargetId}', new target: '${newTargetId}'`);
337
396
  if (!this.targets[app]) {
@@ -345,6 +404,13 @@ export default class RpcClient {
345
404
  };
346
405
  }
347
406
 
407
+ /**
408
+ *
409
+ * @param {Error?} err
410
+ * @param {string} app
411
+ * @param {Record<string, any>} targetInfo
412
+ * @returns {void}
413
+ */
348
414
  removeTarget (err, app, targetInfo) {
349
415
  if (_.isNil(targetInfo?.targetId)) {
350
416
  log.debug(`Received 'Target.targetDestroyed' event with no target. Skipping`);
@@ -382,11 +448,22 @@ export default class RpcClient {
382
448
  log.debug(`Target '${targetInfo.targetId}' deleted for app '${app}', but no such target exists`);
383
449
  }
384
450
 
451
+ /**
452
+ * @param {string} appIdKey
453
+ * @param {string} pageIdKey
454
+ * @returns {any}
455
+ */
385
456
  getTarget (appIdKey, pageIdKey) {
386
457
  return (this.targets[appIdKey] || {})[pageIdKey];
387
458
  }
388
459
 
460
+ /**
461
+ * @param {string} appIdKey
462
+ * @param {string} pageIdKey
463
+ * @returns {Promise<void>}
464
+ */
389
465
  async selectPage (appIdKey, pageIdKey) {
466
+ /** @type {[string, string]} */
390
467
  this.pendingTargetNotification = [appIdKey, pageIdKey];
391
468
  this.shouldCheckForTarget = false;
392
469
 
@@ -421,8 +498,11 @@ export default class RpcClient {
421
498
  }
422
499
  }
423
500
 
424
- /*
501
+ /**
425
502
  * Perform the minimal initialization to get the Web Inspector working
503
+ * @param {string} appIdKey
504
+ * @param {string} pageIdKey
505
+ * @returns {Promise<void>}
426
506
  */
427
507
  async initializePage (appIdKey, pageIdKey) {
428
508
  const sendOpts = {
@@ -442,9 +522,13 @@ export default class RpcClient {
442
522
  await this.send('Inspector.initialized', sendOpts, false);
443
523
  }
444
524
 
445
- /*
525
+ /**
446
526
  * Mimic every step that Desktop Safari Develop tools uses to initialize a
447
527
  * Web Inspector session
528
+ *
529
+ * @param {string} appIdKey
530
+ * @param {string} pageIdKey
531
+ * @returns {Promise<void>}
448
532
  */
449
533
  async initializePageFull (appIdKey, pageIdKey) {
450
534
  const sendOpts = {
@@ -509,6 +593,11 @@ export default class RpcClient {
509
593
  await this.send('Inspector.initialized', sendOpts, false);
510
594
  }
511
595
 
596
+ /**
597
+ *
598
+ * @param {string} appIdKey
599
+ * @returns {Promise<[string, Record<string, any>]>}
600
+ */
512
601
  async selectApp (appIdKey) {
513
602
  return await new B((resolve, reject) => {
514
603
  // local callback, temporarily added as callback to
@@ -531,6 +620,7 @@ export default class RpcClient {
531
620
 
532
621
  reject(new Error('New application has connected'));
533
622
  };
623
+ // @ts-ignore messageHandler must be defined
534
624
  this.messageHandler.prependOnceListener('_rpc_applicationConnected:', onAppChange);
535
625
 
536
626
  // do the actual connecting to the app
@@ -558,6 +648,11 @@ export default class RpcClient {
558
648
  });
559
649
  }
560
650
 
651
+ /**
652
+ *
653
+ * @param {Error?} err
654
+ * @param {Record<string, any>} context
655
+ */
561
656
  onExecutionContextCreated (err, context) {
562
657
  // { id: 2, isPageContext: true, name: '', frameId: '0.1' }
563
658
  // right now we have no way to map contexts to apps/pages
@@ -570,6 +665,11 @@ export default class RpcClient {
570
665
  log.debug(`Web Inspector garbage collected`);
571
666
  }
572
667
 
668
+ /**
669
+ *
670
+ * @param {Error?} err
671
+ * @param {Record<string, any>} scriptInfo
672
+ */
573
673
  onScriptParsed (err, scriptInfo) {
574
674
  // { scriptId: '13', url: '', startLine: 0, startColumn: 0, endLine: 82, endColumn: 3 }
575
675
  log.debug(`Script parsed: ${JSON.stringify(scriptInfo)}`);
@@ -190,7 +190,7 @@ export default class RpcMessageHandler extends EventEmitters {
190
190
  // if this happens then some aspect of the protocol is missing to us
191
191
  // so print the entire message to get visibiity into what is going on
192
192
  log.error(`Unexpected message format from Web Inspector:`);
193
- this.warn(util.jsonStringify(plist));
193
+ log.warn(util.jsonStringify(plist, null));
194
194
  throw err;
195
195
  }
196
196
  } else {
package/lib/utils.js CHANGED
@@ -23,9 +23,31 @@ const ACCEPTED_PAGE_TYPES = [
23
23
 
24
24
  const RESPONSE_LOG_LENGTH = 100;
25
25
 
26
- /*
26
+ /**
27
+ * @typedef {Object} DeferredPromise
28
+ * @property {B<any>} promise
29
+ * @property {(...args: any[]) => void} resolve
30
+ * @property {(err?: Error) => void} reject
31
+ */
32
+
33
+ /**
34
+ * @typedef {Object} AppInfo
35
+ * @property {string} id
36
+ * @property {boolean} isProxy
37
+ * @property {string} name
38
+ * @property {string} bundleId
39
+ * @property {string} hostId
40
+ * @property {boolean} isActive
41
+ * @property {boolean|string} isAutomationEnabled
42
+ * @property {any[]|undefined|DeferredPromise} [pageArray]
43
+ */
44
+
45
+ /**
27
46
  * Takes a dictionary from the remote debugger and makes a more manageable
28
47
  * dictionary whose keys are understandable
48
+ *
49
+ * @param {Record<string, any>} dict
50
+ * @returns {[string, AppInfo]}
29
51
  */
30
52
  function appInfoFromDict (dict) {
31
53
  const id = dict.WIRApplicationIdentifierKey;
@@ -35,6 +57,7 @@ function appInfoFromDict (dict) {
35
57
  // automation enabled can be either from the keys
36
58
  // - WIRRemoteAutomationEnabledKey (boolean)
37
59
  // - WIRAutomationAvailabilityKey (string or boolean)
60
+ /** @type {boolean|string} */
38
61
  let isAutomationEnabled = !!dict.WIRRemoteAutomationEnabledKey;
39
62
  if (_.has(dict, 'WIRAutomationAvailabilityKey')) {
40
63
  if (_.isString(dict.WIRAutomationAvailabilityKey)) {
@@ -189,9 +212,14 @@ function simpleStringify (value, multiline = false) {
189
212
  return multiline ? JSON.stringify(cleanValue, null, 2) : JSON.stringify(cleanValue);
190
213
  }
191
214
 
215
+ /**
216
+ * @returns {DeferredPromise}
217
+ */
192
218
  function deferredPromise () {
193
219
  // http://bluebirdjs.com/docs/api/deferred-migration.html
220
+ /** @type {(...args: any[]) => void} */
194
221
  let resolve;
222
+ /** @type {(err?: Error) => void} */
195
223
  let reject;
196
224
  const promise = new B((res, rej) => { // eslint-disable-line promise/param-names
197
225
  resolve = res;
@@ -199,7 +227,9 @@ function deferredPromise () {
199
227
  });
200
228
  return {
201
229
  promise,
230
+ // @ts-ignore It will be assigned eventually
202
231
  resolve,
232
+ // @ts-ignore It will be assigned eventually
203
233
  reject
204
234
  };
205
235
  }