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.
- package/CHANGELOG.md +7 -0
- package/build/index.js +18 -33
- package/build/lib/atoms.d.ts +17 -0
- package/build/lib/atoms.d.ts.map +1 -0
- package/build/lib/atoms.js +75 -50
- package/build/lib/atoms.js.map +1 -1
- package/build/lib/logger.d.ts +3 -0
- package/build/lib/logger.d.ts.map +1 -0
- package/build/lib/logger.js +5 -11
- package/build/lib/logger.js.map +1 -1
- package/build/lib/mixins/connect.d.ts +125 -0
- package/build/lib/mixins/connect.d.ts.map +1 -0
- package/build/lib/mixins/connect.js +299 -202
- package/build/lib/mixins/connect.js.map +1 -1
- package/build/lib/mixins/events.d.ts +7 -0
- package/build/lib/mixins/events.d.ts.map +1 -0
- package/build/lib/mixins/events.js +7 -12
- package/build/lib/mixins/events.js.map +1 -1
- package/build/lib/mixins/execute.d.ts +38 -0
- package/build/lib/mixins/execute.d.ts.map +1 -0
- package/build/lib/mixins/execute.js +162 -122
- package/build/lib/mixins/execute.js.map +1 -1
- package/build/lib/mixins/index.d.ts +5 -0
- package/build/lib/mixins/index.d.ts.map +1 -0
- package/build/lib/mixins/index.js +14 -23
- package/build/lib/mixins/index.js.map +1 -1
- package/build/lib/mixins/message-handlers.d.ts +92 -0
- package/build/lib/mixins/message-handlers.d.ts.map +1 -0
- package/build/lib/mixins/message-handlers.js +160 -97
- package/build/lib/mixins/message-handlers.js.map +1 -1
- package/build/lib/mixins/navigate.d.ts +92 -0
- package/build/lib/mixins/navigate.d.ts.map +1 -0
- package/build/lib/mixins/navigate.js +199 -141
- package/build/lib/mixins/navigate.js.map +1 -1
- package/build/lib/protocol/index.d.ts +14 -0
- package/build/lib/protocol/index.d.ts.map +1 -0
- package/build/lib/protocol/index.js +192 -118
- package/build/lib/protocol/index.js.map +1 -1
- package/build/lib/remote-debugger-real-device.d.ts +6 -0
- package/build/lib/remote-debugger-real-device.d.ts.map +1 -0
- package/build/lib/remote-debugger-real-device.js +29 -32
- package/build/lib/remote-debugger-real-device.js.map +1 -1
- package/build/lib/remote-debugger.d.ts +119 -0
- package/build/lib/remote-debugger.d.ts.map +1 -0
- package/build/lib/remote-debugger.js +256 -226
- package/build/lib/remote-debugger.js.map +1 -1
- package/build/lib/rpc/index.d.ts +4 -0
- package/build/lib/rpc/index.d.ts.map +1 -0
- package/build/lib/rpc/index.js +10 -21
- package/build/lib/rpc/index.js.map +1 -1
- package/build/lib/rpc/remote-messages.d.ts +51 -0
- package/build/lib/rpc/remote-messages.d.ts.map +1 -0
- package/build/lib/rpc/remote-messages.js +203 -224
- package/build/lib/rpc/remote-messages.js.map +1 -1
- package/build/lib/rpc/rpc-client-real-device.d.ts +6 -0
- package/build/lib/rpc/rpc-client-real-device.d.ts.map +1 -0
- package/build/lib/rpc/rpc-client-real-device.js +43 -49
- package/build/lib/rpc/rpc-client-real-device.js.map +1 -1
- package/build/lib/rpc/rpc-client-simulator.d.ts +15 -0
- package/build/lib/rpc/rpc-client-simulator.d.ts.map +1 -0
- package/build/lib/rpc/rpc-client-simulator.js +138 -125
- package/build/lib/rpc/rpc-client-simulator.js.map +1 -1
- package/build/lib/rpc/rpc-client.d.ts +142 -0
- package/build/lib/rpc/rpc-client.d.ts.map +1 -0
- package/build/lib/rpc/rpc-client.js +559 -418
- package/build/lib/rpc/rpc-client.js.map +1 -1
- package/build/lib/rpc/rpc-message-handler.d.ts +13 -0
- package/build/lib/rpc/rpc-message-handler.d.ts.map +1 -0
- package/build/lib/rpc/rpc-message-handler.js +181 -166
- package/build/lib/rpc/rpc-message-handler.js.map +1 -1
- package/build/lib/utils.d.ts +61 -0
- package/build/lib/utils.d.ts.map +1 -0
- package/build/lib/utils.js +241 -155
- package/build/lib/utils.js.map +1 -1
- package/lib/atoms.js +25 -4
- package/lib/mixins/connect.js +102 -7
- package/lib/mixins/execute.js +46 -13
- package/lib/mixins/message-handlers.js +44 -1
- package/lib/mixins/navigate.js +55 -3
- package/lib/remote-debugger.js +112 -0
- package/lib/rpc/rpc-client-real-device.js +1 -6
- package/lib/rpc/rpc-client-simulator.js +7 -1
- package/lib/rpc/rpc-client.js +106 -6
- package/lib/rpc/rpc-message-handler.js +1 -1
- package/lib/utils.js +31 -1
- package/package.json +25 -15
package/lib/remote-debugger.js
CHANGED
|
@@ -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(
|
|
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
|
}
|
package/lib/rpc/rpc-client.js
CHANGED
|
@@ -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
|
-
(
|
|
277
|
-
(
|
|
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
|
|
341
|
+
this.messageHandler?.removeAllListeners();
|
|
300
342
|
}
|
|
301
343
|
|
|
302
|
-
|
|
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
|
-
|
|
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
|
}
|