appium-remote-debugger 15.2.9 → 15.2.11

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 (48) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/build/lib/mixins/connect.d.ts +47 -31
  3. package/build/lib/mixins/connect.d.ts.map +1 -1
  4. package/build/lib/mixins/connect.js +105 -86
  5. package/build/lib/mixins/connect.js.map +1 -1
  6. package/build/lib/mixins/cookies.d.ts +17 -13
  7. package/build/lib/mixins/cookies.d.ts.map +1 -1
  8. package/build/lib/mixins/cookies.js +12 -12
  9. package/build/lib/mixins/cookies.js.map +1 -1
  10. package/build/lib/mixins/events.d.ts +32 -31
  11. package/build/lib/mixins/events.d.ts.map +1 -1
  12. package/build/lib/mixins/events.js +21 -24
  13. package/build/lib/mixins/events.js.map +1 -1
  14. package/build/lib/mixins/execute.d.ts +35 -24
  15. package/build/lib/mixins/execute.d.ts.map +1 -1
  16. package/build/lib/mixins/execute.js +34 -26
  17. package/build/lib/mixins/execute.js.map +1 -1
  18. package/build/lib/mixins/message-handlers.d.ts +63 -43
  19. package/build/lib/mixins/message-handlers.d.ts.map +1 -1
  20. package/build/lib/mixins/message-handlers.js +74 -57
  21. package/build/lib/mixins/message-handlers.js.map +1 -1
  22. package/build/lib/mixins/misc.d.ts +34 -24
  23. package/build/lib/mixins/misc.d.ts.map +1 -1
  24. package/build/lib/mixins/misc.js +27 -21
  25. package/build/lib/mixins/misc.js.map +1 -1
  26. package/build/lib/mixins/navigate.d.ts +39 -27
  27. package/build/lib/mixins/navigate.d.ts.map +1 -1
  28. package/build/lib/mixins/navigate.js +31 -31
  29. package/build/lib/mixins/navigate.js.map +1 -1
  30. package/build/lib/mixins/screenshot.d.ts +21 -11
  31. package/build/lib/mixins/screenshot.d.ts.map +1 -1
  32. package/build/lib/mixins/screenshot.js +10 -14
  33. package/build/lib/mixins/screenshot.js.map +1 -1
  34. package/build/tsconfig.tsbuildinfo +1 -1
  35. package/lib/mixins/{connect.js → connect.ts} +153 -113
  36. package/lib/mixins/cookies.ts +61 -0
  37. package/lib/mixins/events.ts +91 -0
  38. package/lib/mixins/{execute.js → execute.ts} +59 -33
  39. package/lib/mixins/message-handlers.ts +272 -0
  40. package/lib/mixins/misc.ts +136 -0
  41. package/lib/mixins/{navigate.js → navigate.ts} +44 -41
  42. package/lib/mixins/screenshot.ts +52 -0
  43. package/package.json +1 -1
  44. package/lib/mixins/cookies.js +0 -53
  45. package/lib/mixins/events.js +0 -81
  46. package/lib/mixins/message-handlers.js +0 -224
  47. package/lib/mixins/misc.js +0 -121
  48. package/lib/mixins/screenshot.js +0 -43
@@ -19,6 +19,8 @@ import {
19
19
  getAdditionalBundleIds,
20
20
  } from './property-accessors';
21
21
  import { NEW_APP_CONNECTED_ERROR, EMPTY_PAGE_DICTIONARY_ERROR } from '../rpc/rpc-client';
22
+ import type { RemoteDebugger } from '../remote-debugger';
23
+ import type { AppDict, Page, AppIdKey, PageIdKey, AppPage } from '../types';
22
24
 
23
25
  const APP_CONNECT_TIMEOUT_MS = 0;
24
26
  const APP_CONNECT_INTERVAL_MS = 100;
@@ -32,11 +34,11 @@ const SAFARI_VIEW_BUNDLE_ID = 'com.apple.SafariViewService';
32
34
  const WILDCARD_BUNDLE_ID = '*';
33
35
 
34
36
  /**
35
- *
36
- * @this {RemoteDebugger}
37
- * @returns {Promise<void>}
37
+ * Sends a connection key request to the Web Inspector.
38
+ * This method only waits to ensure the socket connection works, as the response
39
+ * from Web Inspector can take a long time.
38
40
  */
39
- export async function setConnectionKey () {
41
+ export async function setConnectionKey(this: RemoteDebugger): Promise<void> {
40
42
  this.log.debug('Sending connection key request');
41
43
 
42
44
  // send but only wait to make sure the socket worked
@@ -45,12 +47,17 @@ export async function setConnectionKey () {
45
47
  }
46
48
 
47
49
  /**
50
+ * Establishes a connection to the remote debugger and initializes the RPC client.
51
+ * Sets up event listeners for debugger-level events and waits for applications
52
+ * to be reported if a timeout is specified.
48
53
  *
49
- * @this {RemoteDebugger}
50
- * @param {number} [timeout=APP_CONNECT_TIMEOUT_MS]
51
- * @returns {Promise<import('../types').AppDict>}
54
+ * @param timeout - Maximum time in milliseconds to wait for applications to be reported.
55
+ * Defaults to 0 (no waiting). If provided, the method will wait up to
56
+ * this duration for applications to appear in the app dictionary.
57
+ * @returns A promise that resolves to the application dictionary containing all
58
+ * connected applications.
52
59
  */
53
- export async function connect (timeout = APP_CONNECT_TIMEOUT_MS) {
60
+ export async function connect(this: RemoteDebugger, timeout: number = APP_CONNECT_TIMEOUT_MS): Promise<AppDict> {
54
61
  this.setup();
55
62
 
56
63
  // initialize the rpc client
@@ -91,7 +98,7 @@ export async function connect (timeout = APP_CONNECT_TIMEOUT_MS) {
91
98
  }
92
99
  }
93
100
  return this.appDict;
94
- } catch (err) {
101
+ } catch (err: any) {
95
102
  this.log.error(`Error setting connection key: ${err.message}`);
96
103
  await this.disconnect();
97
104
  throw err;
@@ -99,25 +106,36 @@ export async function connect (timeout = APP_CONNECT_TIMEOUT_MS) {
99
106
  }
100
107
 
101
108
  /**
102
- *
103
- * @this {RemoteDebugger}
104
- * @returns {Promise<void>}
109
+ * Disconnects from the remote debugger by closing the RPC client connection,
110
+ * emitting a disconnect event, and performing cleanup via teardown.
105
111
  */
106
- export async function disconnect () {
112
+ export async function disconnect(this: RemoteDebugger): Promise<void> {
107
113
  await getRcpClient(this)?.disconnect();
108
114
  this.emit(events.EVENT_DISCONNECT, true);
109
115
  this.teardown();
110
116
  }
111
117
 
112
118
  /**
119
+ * Selects an application from the available connected applications.
120
+ * Searches for an app matching the provided URL and bundle IDs, then returns
121
+ * all pages from the selected application.
113
122
  *
114
- * @this {RemoteDebugger}
115
- * @param {string?} [currentUrl=null]
116
- * @param {number} [maxTries=SELECT_APP_RETRIES]
117
- * @param {boolean} [ignoreAboutBlankUrl=false]
118
- * @returns {Promise<import('../types').Page[]>}
123
+ * @param currentUrl - Optional URL to match when selecting an application.
124
+ * If provided, the method will try to find an app containing
125
+ * a page with this URL.
126
+ * @param maxTries - Maximum number of retry attempts when searching for an app.
127
+ * Defaults to SELECT_APP_RETRIES (20).
128
+ * @param ignoreAboutBlankUrl - If true, pages with 'about:blank' URL will be
129
+ * excluded from the results. Defaults to false.
130
+ * @returns A promise that resolves to an array of Page objects from the selected
131
+ * application. Returns an empty array if no applications are connected.
119
132
  */
120
- export async function selectApp (currentUrl = null, maxTries = SELECT_APP_RETRIES, ignoreAboutBlankUrl = false) {
133
+ export async function selectApp(
134
+ this: RemoteDebugger,
135
+ currentUrl: string | null = null,
136
+ maxTries: number = SELECT_APP_RETRIES,
137
+ ignoreAboutBlankUrl: boolean = false
138
+ ): Promise<Page[]> {
121
139
  this.log.debug('Selecting application');
122
140
 
123
141
  const timer = new timing.Timer().start();
@@ -135,8 +153,7 @@ export async function selectApp (currentUrl = null, maxTries = SELECT_APP_RETRIE
135
153
  // translate the dictionary into a useful form, and return to sender
136
154
  this.log.debug(`Finally selecting app ${getAppIdKey(this)}`);
137
155
 
138
- /** @type {import('../types').Page[]} */
139
- const fullPageArray = [];
156
+ const fullPageArray: Page[] = [];
140
157
  for (const [app, info] of _.toPairs(getAppDict(this))) {
141
158
  if (!_.isArray(info.pageArray) || !info.isActive) {
142
159
  continue;
@@ -157,14 +174,22 @@ export async function selectApp (currentUrl = null, maxTries = SELECT_APP_RETRIE
157
174
  }
158
175
 
159
176
  /**
177
+ * Selects a specific page within an application and forwards socket setup.
178
+ * Optionally waits for the page to be ready based on the page load strategy.
160
179
  *
161
- * @this {RemoteDebugger}
162
- * @param {import('../types').AppIdKey} appIdKey
163
- * @param {import('../types').PageIdKey} pageIdKey
164
- * @param {boolean} [skipReadyCheck]
165
- * @returns {Promise<void>}
180
+ * @param appIdKey - The application identifier key. Will be prefixed with 'PID:'
181
+ * if not already present.
182
+ * @param pageIdKey - The page identifier key to select.
183
+ * @param skipReadyCheck - If true, skips the page readiness check. Defaults to false.
184
+ * When false, the method will wait for the page to be ready
185
+ * according to the configured page load strategy.
166
186
  */
167
- export async function selectPage (appIdKey, pageIdKey, skipReadyCheck = false) {
187
+ export async function selectPage(
188
+ this: RemoteDebugger,
189
+ appIdKey: AppIdKey,
190
+ pageIdKey: PageIdKey,
191
+ skipReadyCheck: boolean = false
192
+ ): Promise<void> {
168
193
  const fullAppIdKey = _.startsWith(`${appIdKey}`, 'PID:') ? `${appIdKey}` : `PID:${appIdKey}`;
169
194
  setAppIdKey(this, fullAppIdKey);
170
195
  setPageIdKey(this, pageIdKey);
@@ -175,7 +200,7 @@ export async function selectPage (appIdKey, pageIdKey, skipReadyCheck = false) {
175
200
 
176
201
  const pageReadinessDetector = skipReadyCheck ? undefined : {
177
202
  timeoutMs: this.pageLoadMs,
178
- readinessDetector: (/** @type {string} */ readyState) => this.isPageLoadingCompleted(readyState),
203
+ readinessDetector: (readyState: string) => this.isPageLoadingCompleted(readyState),
179
204
  };
180
205
  await this.requireRpcClient().selectPage(fullAppIdKey, pageIdKey, pageReadinessDetector);
181
206
 
@@ -183,16 +208,87 @@ export async function selectPage (appIdKey, pageIdKey, skipReadyCheck = false) {
183
208
  }
184
209
 
185
210
  /**
211
+ * Finds app keys based on assigned bundle IDs from the app dictionary.
212
+ * When bundleIds includes a wildcard ('*'), returns all app keys in the app dictionary.
213
+ * Also handles proxy applications that may act on behalf of other bundle IDs.
186
214
  *
187
- * @this {RemoteDebugger}
188
- * @param {string?} currentUrl
189
- * @param {number} maxTries
190
- * @param {boolean} ignoreAboutBlankUrl
191
- * @returns {Promise<import('../types').AppPage>}
215
+ * @param bundleIds - Array of bundle identifiers to match against. If the array
216
+ * contains a wildcard ('*'), all apps will be returned.
217
+ * @returns Array of application identifier keys that match the provided bundle IDs.
192
218
  */
193
- async function searchForApp (currentUrl, maxTries, ignoreAboutBlankUrl) {
194
- /** @type {string[]} */
195
- const bundleIds = _.compact(
219
+ export function getPossibleDebuggerAppKeys(this: RemoteDebugger, bundleIds: string[]): string[] {
220
+ const appDict = getAppDict(this);
221
+
222
+ if (bundleIds.includes(WILDCARD_BUNDLE_ID)) {
223
+ this.log.info(
224
+ 'Returning all apps because the list of matching bundle identifiers includes a wildcard'
225
+ );
226
+ return _.keys(appDict);
227
+ }
228
+
229
+ // go through the possible bundle identifiers
230
+ const possibleBundleIds = _.uniq([
231
+ WEB_CONTENT_BUNDLE_ID,
232
+ WEB_CONTENT_PROCESS_BUNDLE_ID,
233
+ SAFARI_VIEW_PROCESS_BUNDLE_ID,
234
+ SAFARI_VIEW_BUNDLE_ID,
235
+ ...bundleIds,
236
+ ]);
237
+ this.log.debug(
238
+ `Checking for apps with matching bundle identifiers: ${possibleBundleIds.join(', ')}`
239
+ );
240
+ const proxiedAppIds: string[] = [];
241
+ for (const bundleId of possibleBundleIds) {
242
+ // now we need to determine if we should pick a proxy for this instead
243
+ for (const appId of appIdsForBundle(bundleId, appDict)) {
244
+ if (proxiedAppIds.includes(appId)) {
245
+ continue;
246
+ }
247
+
248
+ proxiedAppIds.push(appId);
249
+ this.log.debug(`Found app id key '${appId}' for bundle '${bundleId}'`);
250
+ for (const [key, data] of _.toPairs(appDict)) {
251
+ if (data.isProxy && data.hostId === appId && !proxiedAppIds.includes(key)) {
252
+ this.log.debug(
253
+ `Found separate bundleId '${data.bundleId}' ` +
254
+ `acting as proxy for '${bundleId}', with app id '${key}'`
255
+ );
256
+ proxiedAppIds.push(key);
257
+ }
258
+ }
259
+ }
260
+ }
261
+
262
+ this.log.debug(
263
+ `You may also consider providing more values to 'additionalWebviewBundleIds' ` +
264
+ `capability to match other applications. Add a wildcard ('*') to match all apps.`
265
+ );
266
+
267
+ return _.uniq(proxiedAppIds);
268
+ }
269
+
270
+ /**
271
+ * Searches for an application matching the given criteria by retrying with
272
+ * exponential backoff. Attempts to connect to apps matching the bundle IDs
273
+ * and optionally filters by URL.
274
+ *
275
+ * @param currentUrl - Optional URL to match when searching for a page.
276
+ * If provided, only apps containing a page with this URL
277
+ * will be considered.
278
+ * @param maxTries - Maximum number of retry attempts.
279
+ * @param ignoreAboutBlankUrl - If true, pages with 'about:blank' URL will be
280
+ * ignored during the search.
281
+ * @returns A promise that resolves to an AppPage object containing the matched
282
+ * app ID key and page dictionary.
283
+ * @throws Error if no valid webapp can be connected after all retry attempts.
284
+ */
285
+ async function searchForApp(
286
+ this: RemoteDebugger,
287
+ currentUrl: string | null,
288
+ maxTries: number,
289
+ ignoreAboutBlankUrl: boolean
290
+ ): Promise<AppPage> {
291
+ const bundleIds: string[] = _.compact(
196
292
  [
197
293
  getBundleId(this),
198
294
  ...(getAdditionalBundleIds(this) ?? []),
@@ -200,9 +296,9 @@ async function searchForApp (currentUrl, maxTries, ignoreAboutBlankUrl) {
200
296
  ]
201
297
  );
202
298
  let retryCount = 0;
203
- return /** @type {import('../types').AppPage} */ (await retryInterval(maxTries, SELECT_APP_RETRY_SLEEP_MS, async () => {
299
+ return await retryInterval(maxTries, SELECT_APP_RETRY_SLEEP_MS, async () => {
204
300
  logApplicationDictionary.bind(this)();
205
- const possibleAppIds = getPossibleDebuggerAppKeys.bind(this)(/** @type {string[]} */ (bundleIds));
301
+ const possibleAppIds = getPossibleDebuggerAppKeys.bind(this)(bundleIds);
206
302
  this.log.debug(`Trying out the possible app ids: ${possibleAppIds.join(', ')} (try #${retryCount + 1} of ${maxTries})`);
207
303
  for (const attemptedAppIdKey of possibleAppIds) {
208
304
  const appInfo = getAppDict(this)[attemptedAppIdKey];
@@ -236,7 +332,7 @@ async function searchForApp (currentUrl, maxTries, ignoreAboutBlankUrl) {
236
332
  } else {
237
333
  this.log.debug('Received app, but no match was found. Trying again.');
238
334
  }
239
- } catch (err) {
335
+ } catch (err: any) {
240
336
  if (![NEW_APP_CONNECTED_ERROR, EMPTY_PAGE_DICTIONARY_ERROR].some((msg) => msg === err.message)) {
241
337
  this.log.debug(err.stack);
242
338
  }
@@ -247,18 +343,25 @@ async function searchForApp (currentUrl, maxTries, ignoreAboutBlankUrl) {
247
343
  throw new Error(
248
344
  `Could not connect to a valid webapp. Make sure it is debuggable and has at least one active page.`
249
345
  );
250
- }));
346
+ }) as Promise<AppPage>;
251
347
  }
252
348
 
253
349
  /**
350
+ * Searches through the application dictionary to find a page matching the given URL.
351
+ * Only considers active applications with non-empty page arrays.
254
352
  *
255
- * @this {RemoteDebugger}
256
- * @param {Record<string, import('../types').AppInfo>} appsDict
257
- * @param {string?} currentUrl
258
- * @param {boolean} [ignoreAboutBlankUrl]
259
- * @returns {import('../types').AppPage?}
353
+ * @param appsDict - The application dictionary to search through.
354
+ * @param currentUrl - Optional URL to match. If provided, only pages with this exact
355
+ * URL or with this URL followed by '/' will be considered.
356
+ * @param ignoreAboutBlankUrl - If true, pages with 'about:blank' URL will be ignored.
357
+ * @returns An AppPage object if a matching page is found, null otherwise.
260
358
  */
261
- function searchForPage (appsDict, currentUrl = null, ignoreAboutBlankUrl = false) {
359
+ function searchForPage(
360
+ this: RemoteDebugger,
361
+ appsDict: AppDict,
362
+ currentUrl: string | null = null,
363
+ ignoreAboutBlankUrl: boolean = false
364
+ ): AppPage | null {
262
365
  for (const appDict of _.values(appsDict)) {
263
366
  if (!appDict || !appDict.isActive || !appDict.pageArray || _.isEmpty(appDict.pageArray)) {
264
367
  continue;
@@ -278,10 +381,11 @@ function searchForPage (appsDict, currentUrl = null, ignoreAboutBlankUrl = false
278
381
  }
279
382
 
280
383
  /**
281
- * @this {RemoteDebugger}
282
- * @returns {void}
384
+ * Logs the current application dictionary to the debug log.
385
+ * Displays all applications, their properties, and their associated pages
386
+ * in a formatted structure.
283
387
  */
284
- function logApplicationDictionary () {
388
+ function logApplicationDictionary(this: RemoteDebugger): void {
285
389
  this.log.debug('Current applications available:');
286
390
  for (const [app, info] of _.toPairs(getAppDict(this))) {
287
391
  this.log.debug(` Application: "${app}"`);
@@ -302,67 +406,3 @@ function logApplicationDictionary () {
302
406
  }
303
407
  }
304
408
  }
305
-
306
- /**
307
- * Find app keys based on assigned bundleIds from appDict
308
- * When bundleIds includes a wildcard ('*'), returns all appKeys in appDict.
309
- *
310
- * @this {RemoteDebugger}
311
- * @param {string[]} bundleIds
312
- * @returns {string[]}
313
- */
314
- export function getPossibleDebuggerAppKeys(bundleIds) {
315
- const appDict = getAppDict(this);
316
-
317
- if (bundleIds.includes(WILDCARD_BUNDLE_ID)) {
318
- this.log.info(
319
- 'Returning all apps because the list of matching bundle identifiers includes a wildcard'
320
- );
321
- return _.keys(appDict);
322
- }
323
-
324
- // go through the possible bundle identifiers
325
- const possibleBundleIds = _.uniq([
326
- WEB_CONTENT_BUNDLE_ID,
327
- WEB_CONTENT_PROCESS_BUNDLE_ID,
328
- SAFARI_VIEW_PROCESS_BUNDLE_ID,
329
- SAFARI_VIEW_BUNDLE_ID,
330
- ...bundleIds,
331
- ]);
332
- this.log.debug(
333
- `Checking for apps with matching bundle identifiers: ${possibleBundleIds.join(', ')}`
334
- );
335
- /** @type {string[]} */
336
- const proxiedAppIds = [];
337
- for (const bundleId of possibleBundleIds) {
338
- // now we need to determine if we should pick a proxy for this instead
339
- for (const appId of appIdsForBundle(bundleId, appDict)) {
340
- if (proxiedAppIds.includes(appId)) {
341
- continue;
342
- }
343
-
344
- proxiedAppIds.push(appId);
345
- this.log.debug(`Found app id key '${appId}' for bundle '${bundleId}'`);
346
- for (const [key, data] of _.toPairs(appDict)) {
347
- if (data.isProxy && data.hostId === appId && !proxiedAppIds.includes(key)) {
348
- this.log.debug(
349
- `Found separate bundleId '${data.bundleId}' ` +
350
- `acting as proxy for '${bundleId}', with app id '${key}'`
351
- );
352
- proxiedAppIds.push(key);
353
- }
354
- }
355
- }
356
- }
357
-
358
- this.log.debug(
359
- `You may also consider providing more values to 'additionalWebviewBundleIds' ` +
360
- `capability to match other applications. Add a wildcard ('*') to match all apps.`
361
- );
362
-
363
- return _.uniq(proxiedAppIds);
364
- }
365
-
366
- /**
367
- * @typedef {import('../remote-debugger').RemoteDebugger} RemoteDebugger
368
- */
@@ -0,0 +1,61 @@
1
+ import {
2
+ getAppIdKey,
3
+ getPageIdKey,
4
+ } from './property-accessors';
5
+ import type { RemoteDebugger } from '../remote-debugger';
6
+ import type { StringRecord } from '@appium/types';
7
+
8
+ /**
9
+ * Retrieves all cookies for the current page by sending a Page.getCookies
10
+ * command to the remote debugger.
11
+ *
12
+ * @returns A promise that resolves to a dictionary containing the cookies.
13
+ */
14
+ export async function getCookies(this: RemoteDebugger): Promise<StringRecord> {
15
+ this.log.debug('Getting cookies');
16
+ return await this.requireRpcClient().send('Page.getCookies', {
17
+ appIdKey: getAppIdKey(this),
18
+ pageIdKey: getPageIdKey(this),
19
+ });
20
+ }
21
+
22
+ /**
23
+ * Sets a cookie on the current page by sending a Page.setCookie command
24
+ * to the remote debugger.
25
+ *
26
+ * @param cookie - Dictionary containing the cookie properties to set.
27
+ * @returns A promise that resolves when the cookie has been set.
28
+ */
29
+ export async function setCookie(
30
+ this: RemoteDebugger,
31
+ cookie: StringRecord
32
+ ): Promise<any> {
33
+ this.log.debug('Setting cookie');
34
+ return await this.requireRpcClient().send('Page.setCookie', {
35
+ appIdKey: getAppIdKey(this),
36
+ pageIdKey: getPageIdKey(this),
37
+ cookie,
38
+ });
39
+ }
40
+
41
+ /**
42
+ * Deletes a cookie from the current page by sending a Page.deleteCookie
43
+ * command to the remote debugger.
44
+ *
45
+ * @param cookieName - The name of the cookie to delete.
46
+ * @param url - The URL associated with the cookie to delete.
47
+ * @returns A promise that resolves when the cookie has been deleted.
48
+ */
49
+ export async function deleteCookie(
50
+ this: RemoteDebugger,
51
+ cookieName: string,
52
+ url: string
53
+ ): Promise<any> {
54
+ this.log.debug(`Deleting cookie '${cookieName}' on '${url}'`);
55
+ return await this.requireRpcClient().send('Page.deleteCookie', {
56
+ appIdKey: getAppIdKey(this),
57
+ pageIdKey: getPageIdKey(this),
58
+ cookieName,
59
+ url,
60
+ });
61
+ }
@@ -0,0 +1,91 @@
1
+ import {
2
+ getClientEventListeners,
3
+ } from './property-accessors';
4
+ import type { RemoteDebugger } from '../remote-debugger';
5
+ import type { EventListener } from '../types';
6
+
7
+ // event emitted publically
8
+ export const events = {
9
+ EVENT_PAGE_CHANGE: 'remote_debugger_page_change',
10
+ EVENT_FRAMES_DETACHED: 'remote_debugger_frames_detached',
11
+ EVENT_DISCONNECT: 'remote_debugger_disconnect',
12
+ } as const;
13
+
14
+ /**
15
+ * Adds a client event listener to the RPC client and tracks it for later removal.
16
+ * The listener will be called when the specified event is emitted by the remote debugger.
17
+ *
18
+ * @param eventName - The name of the event to listen for.
19
+ * @param listener - The event listener function to call when the event is emitted.
20
+ */
21
+ export function addClientEventListener(
22
+ this: RemoteDebugger,
23
+ eventName: string,
24
+ listener: EventListener
25
+ ): void {
26
+ getClientEventListeners(this)[eventName] ??= [];
27
+ getClientEventListeners(this)[eventName].push(listener);
28
+ this.requireRpcClient().on(eventName, listener);
29
+ }
30
+
31
+ /**
32
+ * Removes all client event listeners for the specified event name from the RPC client.
33
+ * This will stop listening for the event and clean up the tracked listeners.
34
+ *
35
+ * @param eventName - The name of the event to stop listening for.
36
+ */
37
+ export function removeClientEventListener(
38
+ this: RemoteDebugger,
39
+ eventName: string
40
+ ): void {
41
+ for (const listener of (getClientEventListeners(this)[eventName] || [])) {
42
+ this.requireRpcClient().off(eventName, listener);
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Starts listening for JavaScript console messages by registering listeners
48
+ * for Console.messageAdded and Console.messageRepeatCountUpdated events.
49
+ *
50
+ * @param listener - The event listener function to call when console messages are received.
51
+ */
52
+ export function startConsole(
53
+ this: RemoteDebugger,
54
+ listener: EventListener
55
+ ): void {
56
+ this.log.debug('Starting to listen for JavaScript console');
57
+ this.addClientEventListener('Console.messageAdded', listener);
58
+ this.addClientEventListener('Console.messageRepeatCountUpdated', listener);
59
+ }
60
+
61
+ /**
62
+ * Stops listening for JavaScript console messages by removing listeners
63
+ * for Console.messageAdded and Console.messageRepeatCountUpdated events.
64
+ */
65
+ export function stopConsole(this: RemoteDebugger): void {
66
+ this.log.debug('Stopping to listen for JavaScript console');
67
+ this.removeClientEventListener('Console.messageAdded');
68
+ this.removeClientEventListener('Console.messageRepeatCountUpdated');
69
+ }
70
+
71
+ /**
72
+ * Starts listening for network events by registering a listener for NetworkEvent.
73
+ * This aggregates all Network.* events into a single NetworkEvent.
74
+ *
75
+ * @param listener - The event listener function to call when network events are received.
76
+ */
77
+ export function startNetwork(
78
+ this: RemoteDebugger,
79
+ listener: EventListener
80
+ ): void {
81
+ this.log.debug('Starting to listen for network events');
82
+ this.addClientEventListener('NetworkEvent', listener);
83
+ }
84
+
85
+ /**
86
+ * Stops listening for network events by removing the listener for NetworkEvent.
87
+ */
88
+ export function stopNetwork(this: RemoteDebugger): void {
89
+ this.log.debug('Stopping to listen for network events');
90
+ this.removeClientEventListener('NetworkEvent');
91
+ }