appium-remote-debugger 15.2.13 → 15.3.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 (45) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/build/lib/protocol/index.d.ts +13 -8
  3. package/build/lib/protocol/index.d.ts.map +1 -1
  4. package/build/lib/protocol/index.js +17 -12
  5. package/build/lib/protocol/index.js.map +1 -1
  6. package/build/lib/rpc/index.d.ts +2 -3
  7. package/build/lib/rpc/index.d.ts.map +1 -1
  8. package/build/lib/rpc/index.js +2 -2
  9. package/build/lib/rpc/index.js.map +1 -1
  10. package/build/lib/rpc/remote-messages.d.ts +62 -41
  11. package/build/lib/rpc/remote-messages.d.ts.map +1 -1
  12. package/build/lib/rpc/remote-messages.js +56 -41
  13. package/build/lib/rpc/remote-messages.js.map +1 -1
  14. package/build/lib/rpc/rpc-client-real-device.d.ts +26 -8
  15. package/build/lib/rpc/rpc-client-real-device.d.ts.map +1 -1
  16. package/build/lib/rpc/rpc-client-real-device.js +21 -16
  17. package/build/lib/rpc/rpc-client-real-device.js.map +1 -1
  18. package/build/lib/rpc/rpc-client-simulator.d.ts +36 -28
  19. package/build/lib/rpc/rpc-client-simulator.d.ts.map +1 -1
  20. package/build/lib/rpc/rpc-client-simulator.js +39 -36
  21. package/build/lib/rpc/rpc-client-simulator.js.map +1 -1
  22. package/build/lib/rpc/rpc-client.d.ts +278 -189
  23. package/build/lib/rpc/rpc-client.d.ts.map +1 -1
  24. package/build/lib/rpc/rpc-client.js +222 -178
  25. package/build/lib/rpc/rpc-client.js.map +1 -1
  26. package/build/lib/rpc/rpc-message-handler.d.ts +32 -39
  27. package/build/lib/rpc/rpc-message-handler.d.ts.map +1 -1
  28. package/build/lib/rpc/rpc-message-handler.js +39 -53
  29. package/build/lib/rpc/rpc-message-handler.js.map +1 -1
  30. package/build/lib/types.d.ts +28 -0
  31. package/build/lib/types.d.ts.map +1 -1
  32. package/build/test/functional/safari-e2e-specs.js +5 -1
  33. package/build/test/functional/safari-e2e-specs.js.map +1 -1
  34. package/build/tsconfig.tsbuildinfo +1 -1
  35. package/lib/protocol/{index.js → index.ts} +29 -17
  36. package/lib/rpc/index.ts +2 -0
  37. package/lib/rpc/{remote-messages.js → remote-messages.ts} +73 -59
  38. package/lib/rpc/rpc-client-real-device.ts +68 -0
  39. package/lib/rpc/{rpc-client-simulator.js → rpc-client-simulator.ts} +54 -57
  40. package/lib/rpc/{rpc-client.js → rpc-client.ts} +368 -284
  41. package/lib/rpc/{rpc-message-handler.js → rpc-message-handler.ts} +73 -64
  42. package/lib/types.ts +31 -0
  43. package/package.json +1 -1
  44. package/lib/rpc/index.js +0 -4
  45. package/lib/rpc/rpc-client-real-device.js +0 -64
@@ -1,7 +1,10 @@
1
+ import type { StringRecord } from '@appium/types';
2
+ import type { RemoteCommandOpts, ProtocolCommandOpts } from '../types';
3
+
1
4
  const OBJECT_GROUP = 'console';
2
5
 
3
6
  // See https://github.com/WebKit/webkit/tree/master/Source/JavaScriptCore/inspector/protocol
4
- const COMMANDS = /** @type {const} */ ({
7
+ const COMMANDS = {
5
8
  // https://github.com/WebKit/WebKit/blob/main/Source/JavaScriptCore/inspector/protocol/Animation.json
6
9
  //#region ANIMATION DOMAIN
7
10
  'Animation.enable': [], // Enables Canvas domain events
@@ -196,28 +199,39 @@ const COMMANDS = /** @type {const} */ ({
196
199
  'Worker.initialized': ['workerId'],
197
200
  'Worker.sendMessageToWorker': ['workerId', 'message']
198
201
  //#endregion
199
- });
202
+ } as const;
200
203
 
201
204
  /**
205
+ * Generates a protocol command object based on the command name and options.
206
+ * Extracts only the parameters that are defined for the specific command in the
207
+ * WebKit Inspector protocol specification.
202
208
  *
203
- * @param {string} id
204
- * @param {string} method
205
- * @param {import('../types').RemoteCommandOpts} opts
206
- * @param {boolean} [direct=false] - if set to false then the resulting command params
207
- * will be patched with default values
208
- * @returns {import('../types').ProtocolCommandOpts}
209
+ * @param id - The command identifier.
210
+ * @param method - The protocol method name (e.g., 'Page.navigate', 'Runtime.evaluate').
211
+ * @param opts - Options containing parameters for the command.
212
+ * @param direct - If false (default), the resulting command params will be patched
213
+ * with default values (objectGroup, includeCommandLineAPI, etc.).
214
+ * If true, only the specified parameters are included.
215
+ * @returns A ProtocolCommandOpts object with id, method, and params.
216
+ * @throws Error if the command method is unknown.
209
217
  */
210
- export function getProtocolCommand (id, method, opts, direct = false) {
211
- const paramNames = COMMANDS[method];
218
+ export function getProtocolCommand(
219
+ id: string,
220
+ method: string,
221
+ opts: RemoteCommandOpts,
222
+ direct: boolean = false
223
+ ): ProtocolCommandOpts {
224
+ const paramNames = COMMANDS[method as keyof typeof COMMANDS];
212
225
  if (!paramNames) {
213
226
  throw new Error(`Unknown command: '${method}'`);
214
227
  }
215
228
 
216
- const params = paramNames.reduce(function (params, name) {
217
- params[name] = opts[name];
218
- return params;
219
- }, {});
220
- const result = {
229
+ const params: StringRecord = (paramNames as readonly string[])
230
+ .reduce(function (acc: StringRecord, name: string) {
231
+ acc[name] = opts[name];
232
+ return acc;
233
+ }, {} as StringRecord);
234
+ const result: ProtocolCommandOpts = {
221
235
  id,
222
236
  method,
223
237
  params,
@@ -235,5 +249,3 @@ export function getProtocolCommand (id, method, opts, direct = false) {
235
249
  }
236
250
  return result;
237
251
  }
238
-
239
- export default getProtocolCommand;
@@ -0,0 +1,2 @@
1
+ export { RpcClientSimulator } from './rpc-client-simulator';
2
+ export { RpcClientRealDevice } from './rpc-client-real-device';
@@ -1,6 +1,6 @@
1
1
  import _ from 'lodash';
2
2
  import { getProtocolCommand } from '../protocol';
3
-
3
+ import type { RawRemoteCommand, RemoteCommandOpts, ProtocolCommandOpts, AppIdKey, PageIdKey, RemoteCommandId } from '../types';
4
4
 
5
5
  const OBJECT_GROUP = 'console';
6
6
 
@@ -10,7 +10,7 @@ const DIRECT_COMMAND = 'getDirectCommand';
10
10
 
11
11
  // mapping of commands to the function for getting the command
12
12
  // defaults to `getMinimalCommand`, so no need to have those listed here
13
- const COMMANDS = /** @type {const} */ ({
13
+ const COMMANDS = {
14
14
  'Page.getCookies': FULL_COMMAND,
15
15
  'Page.navigate': FULL_COMMAND,
16
16
 
@@ -24,17 +24,23 @@ const COMMANDS = /** @type {const} */ ({
24
24
 
25
25
  'Timeline.start': FULL_COMMAND,
26
26
  'Timeline.stop': FULL_COMMAND,
27
- });
27
+ } as const;
28
28
 
29
- export class RemoteMessages {
30
- // #region Connection functions
29
+ type CommandBuilderFunction = typeof MINIMAL_COMMAND | typeof FULL_COMMAND | typeof DIRECT_COMMAND;
31
30
 
31
+ /**
32
+ * Generates remote commands for communicating with the Web Inspector.
33
+ * Provides methods for creating various types of commands including connection
34
+ * setup, application management, and protocol commands.
35
+ */
36
+ export class RemoteMessages {
32
37
  /**
38
+ * Creates a command to set the connection key for the Web Inspector session.
33
39
  *
34
- * @param {string} connId
35
- * @returns {import('../types').RawRemoteCommand}
40
+ * @param connId - The connection identifier.
41
+ * @returns A RawRemoteCommand for setting the connection key.
36
42
  */
37
- setConnectionKey (connId) {
43
+ setConnectionKey(connId: string): RawRemoteCommand {
38
44
  return {
39
45
  __argument: {
40
46
  WIRConnectionIdentifierKey: connId
@@ -44,12 +50,13 @@ export class RemoteMessages {
44
50
  }
45
51
 
46
52
  /**
53
+ * Creates a command to connect to a specific application.
47
54
  *
48
- * @param {string} connId
49
- * @param {import('../types').AppIdKey} appIdKey
50
- * @returns {import('../types').RawRemoteCommand}
55
+ * @param connId - The connection identifier.
56
+ * @param appIdKey - The application identifier key.
57
+ * @returns A RawRemoteCommand for connecting to the application.
51
58
  */
52
- connectToApp (connId, appIdKey) {
59
+ connectToApp(connId: string, appIdKey: AppIdKey): RawRemoteCommand {
53
60
  return {
54
61
  __argument: {
55
62
  WIRConnectionIdentifierKey: connId,
@@ -60,14 +67,15 @@ export class RemoteMessages {
60
67
  }
61
68
 
62
69
  /**
70
+ * Creates a command to set the sender key for message routing.
63
71
  *
64
- * @param {string} connId
65
- * @param {string} senderId
66
- * @param {import('../types').AppIdKey} appIdKey
67
- * @param {import('../types').PageIdKey} [pageIdKey]
68
- * @returns {import('../types').RawRemoteCommand}
72
+ * @param connId - The connection identifier.
73
+ * @param senderId - The sender identifier.
74
+ * @param appIdKey - The application identifier key.
75
+ * @param pageIdKey - Optional page identifier key.
76
+ * @returns A RawRemoteCommand for setting the sender key.
69
77
  */
70
- setSenderKey (connId, senderId, appIdKey, pageIdKey) {
78
+ setSenderKey(connId: string, senderId: string, appIdKey: AppIdKey, pageIdKey?: PageIdKey): RawRemoteCommand {
71
79
  return {
72
80
  __argument: {
73
81
  WIRApplicationIdentifierKey: appIdKey,
@@ -81,14 +89,15 @@ export class RemoteMessages {
81
89
  }
82
90
 
83
91
  /**
92
+ * Creates a command to indicate web view status.
84
93
  *
85
- * @param {string} connId
86
- * @param {import('../types').AppIdKey} appIdKey
87
- * @param {import('../types').PageIdKey} [pageIdKey]
88
- * @param {boolean} [enabled]
89
- * @returns {import('../types').RawRemoteCommand}
94
+ * @param connId - The connection identifier.
95
+ * @param appIdKey - The application identifier key.
96
+ * @param pageIdKey - Optional page identifier key.
97
+ * @param enabled - Whether the web view indication is enabled. Defaults to true if not provided.
98
+ * @returns A RawRemoteCommand for indicating web view status.
90
99
  */
91
- indicateWebView (connId, appIdKey, pageIdKey, enabled) {
100
+ indicateWebView(connId: string, appIdKey: AppIdKey, pageIdKey?: PageIdKey, enabled?: boolean): RawRemoteCommand {
92
101
  return {
93
102
  __argument: {
94
103
  WIRApplicationIdentifierKey: appIdKey,
@@ -101,11 +110,12 @@ export class RemoteMessages {
101
110
  }
102
111
 
103
112
  /**
113
+ * Creates a command to launch an application.
104
114
  *
105
- * @param {string} bundleId
106
- * @returns {import('../types').RawRemoteCommand}
115
+ * @param bundleId - The bundle identifier of the application to launch.
116
+ * @returns A RawRemoteCommand for launching the application.
107
117
  */
108
- launchApplication (bundleId) {
118
+ launchApplication(bundleId: string): RawRemoteCommand {
109
119
  return {
110
120
  __argument: {
111
121
  WIRApplicationBundleIdentifierKey: bundleId
@@ -115,11 +125,13 @@ export class RemoteMessages {
115
125
  }
116
126
 
117
127
  /**
128
+ * Creates a full command with all default parameters included.
129
+ * This includes objectGroup, includeCommandLineAPI, and other runtime options.
118
130
  *
119
- * @param {import('../types').RemoteCommandOpts & import('../types').ProtocolCommandOpts} opts
120
- * @returns {import('../types').RawRemoteCommand}
131
+ * @param opts - Options combining RemoteCommandOpts and ProtocolCommandOpts.
132
+ * @returns A RawRemoteCommand with full parameter set.
121
133
  */
122
- getFullCommand (opts) {
134
+ getFullCommand(opts: RemoteCommandOpts & ProtocolCommandOpts): RawRemoteCommand {
123
135
  const {
124
136
  method,
125
137
  params,
@@ -143,7 +155,7 @@ export class RemoteMessages {
143
155
  const realParams = {
144
156
  targetId,
145
157
  message: JSON.stringify({
146
- id,
158
+ id: parseInt(id, 10),
147
159
  method,
148
160
  params: Object.assign({
149
161
  objectGroup: OBJECT_GROUP,
@@ -169,23 +181,24 @@ export class RemoteMessages {
169
181
  },
170
182
  __selector: '_rpc_forwardSocketData:',
171
183
  };
172
- // @ts-ignore This is ok
173
- return _.omitBy(plist, _.isNil);
184
+ return _.omitBy(plist, _.isNil) as RawRemoteCommand;
174
185
  }
175
186
 
176
187
  /**
188
+ * Creates a minimal command with only the essential parameters.
189
+ * This is the default command type for most operations.
177
190
  *
178
- * @param {import('../types').RemoteCommandOpts & import('../types').ProtocolCommandOpts} opts
179
- * @returns {import('../types').RawRemoteCommand}
191
+ * @param opts - Options combining RemoteCommandOpts and ProtocolCommandOpts.
192
+ * @returns A RawRemoteCommand with minimal parameter set.
180
193
  */
181
- getMinimalCommand (opts) {
194
+ getMinimalCommand(opts: RemoteCommandOpts & ProtocolCommandOpts): RawRemoteCommand {
182
195
  const {method, params, connId, senderId, appIdKey, pageIdKey, targetId, id} = opts;
183
196
 
184
197
  const realMethod = 'Target.sendMessageToTarget';
185
198
  const realParams = {
186
199
  targetId,
187
200
  message: JSON.stringify({
188
- id,
201
+ id: parseInt(id, 10),
189
202
  method,
190
203
  params,
191
204
  }),
@@ -204,22 +217,23 @@ export class RemoteMessages {
204
217
  },
205
218
  __selector: '_rpc_forwardSocketData:'
206
219
  };
207
- // @ts-ignore This is ok
208
- return _.omitBy(plist, _.isNil);
220
+ return _.omitBy(plist, _.isNil) as RawRemoteCommand;
209
221
  }
210
222
 
211
223
  /**
224
+ * Creates a direct command that bypasses the Target.sendMessageToTarget wrapper.
225
+ * Used for certain Target domain commands.
212
226
  *
213
- * @param {import('../types').RemoteCommandOpts & import('../types').ProtocolCommandOpts} opts
214
- * @returns {import('../types').RawRemoteCommand}
227
+ * @param opts - Options combining RemoteCommandOpts and ProtocolCommandOpts.
228
+ * @returns A RawRemoteCommand for direct protocol communication.
215
229
  */
216
- getDirectCommand (opts) {
230
+ getDirectCommand(opts: RemoteCommandOpts & ProtocolCommandOpts): RawRemoteCommand {
217
231
  const {method, params, connId, senderId, appIdKey, pageIdKey, id} = opts;
218
232
 
219
233
  const plist = {
220
234
  __argument: {
221
235
  WIRSocketDataKey: {
222
- id,
236
+ id: parseInt(id, 10),
223
237
  method,
224
238
  params,
225
239
  },
@@ -230,17 +244,19 @@ export class RemoteMessages {
230
244
  },
231
245
  __selector: '_rpc_forwardSocketData:'
232
246
  };
233
- // @ts-ignore This is ok
234
- return _.omitBy(plist, _.isNil);
247
+ return _.omitBy(plist, _.isNil) as RawRemoteCommand;
235
248
  }
236
249
 
237
250
  /**
251
+ * Gets a remote command based on the command name and options.
252
+ * Handles both Safari Web Inspector commands and WebKit protocol commands.
238
253
  *
239
- * @param {string} command
240
- * @param {import('../types').RemoteCommandOpts} opts
241
- * @returns {import('../types').RawRemoteCommand}
254
+ * @param command - The command name (e.g., 'setConnectionKey', 'Page.navigate').
255
+ * @param opts - Options for the command.
256
+ * @returns A RawRemoteCommand appropriate for the given command.
257
+ * @throws Error if required parameters are missing for specific commands.
242
258
  */
243
- getRemoteCommand (command, opts) {
259
+ getRemoteCommand(command: string, opts: RemoteCommandOpts & RemoteCommandId): RawRemoteCommand {
244
260
  const {
245
261
  id,
246
262
  connId,
@@ -280,9 +296,9 @@ export class RemoteMessages {
280
296
  }
281
297
 
282
298
  // deal with WebKit commands
283
- const builderFunction = COMMANDS[command] || MINIMAL_COMMAND;
299
+ const builderFunction = (COMMANDS[command as keyof typeof COMMANDS] || MINIMAL_COMMAND) as CommandBuilderFunction;
284
300
  const commonOpts = getProtocolCommand(
285
- /** @type {string} */ (id),
301
+ id,
286
302
  command,
287
303
  opts,
288
304
  isDirectCommand(command),
@@ -296,17 +312,15 @@ export class RemoteMessages {
296
312
  targetId,
297
313
  });
298
314
  }
299
-
300
- // #endregion
301
315
  }
302
316
 
303
317
  /**
318
+ * Checks if a command should use the direct command format.
319
+ * Direct commands bypass the Target.sendMessageToTarget wrapper.
304
320
  *
305
- * @param {string} command
306
- * @returns {boolean}
321
+ * @param command - The command name to check.
322
+ * @returns True if the command should use direct format, false otherwise.
307
323
  */
308
- export function isDirectCommand (command) {
309
- return COMMANDS[command] === DIRECT_COMMAND;
324
+ export function isDirectCommand(command: string): boolean {
325
+ return COMMANDS[command as keyof typeof COMMANDS] === DIRECT_COMMAND;
310
326
  }
311
-
312
- export default RemoteMessages;
@@ -0,0 +1,68 @@
1
+ import { log } from '../logger';
2
+ import { RpcClient } from './rpc-client';
3
+ import { services } from 'appium-ios-device';
4
+ import type { RemoteCommand } from '../types';
5
+
6
+ /**
7
+ * RPC client implementation for real iOS devices.
8
+ * Extends RpcClient to provide device-specific connection handling.
9
+ */
10
+ export class RpcClientRealDevice extends RpcClient {
11
+ protected service?: any;
12
+
13
+ /**
14
+ * Connects to the Web Inspector service on a real iOS device.
15
+ * Starts the Web Inspector service and sets up message listening.
16
+ */
17
+ override async connect(): Promise<void> {
18
+ this.service = await services.startWebInspectorService(this.udid, {
19
+ osVersion: this.platformVersion,
20
+ isSimulator: false,
21
+ verbose: this.logAllCommunication,
22
+ verboseHexDump: this.logAllCommunicationHexDump,
23
+ socketChunkSize: this.socketChunkSize,
24
+ maxFrameLength: this.webInspectorMaxFrameLength,
25
+ });
26
+
27
+ this.service.listenMessage(this.receive.bind(this));
28
+ this.isConnected = true;
29
+ }
30
+
31
+ /**
32
+ * Disconnects from the Web Inspector service on the real device.
33
+ * Closes the service connection and cleans up resources.
34
+ */
35
+ override async disconnect(): Promise<void> {
36
+ if (!this.isConnected) {
37
+ return;
38
+ }
39
+
40
+ log.debug('Disconnecting from remote debugger');
41
+ await super.disconnect();
42
+ this.service?.close();
43
+ this.isConnected = false;
44
+ }
45
+
46
+ /**
47
+ * Sends a command message to the Web Inspector service.
48
+ *
49
+ * @param cmd - The command to send to the device.
50
+ */
51
+ override async sendMessage(cmd: RemoteCommand): Promise<void> {
52
+ if (!this.service) {
53
+ throw new Error('RPC service is not initialized. Is the client connected?');
54
+ }
55
+ this.service.sendMessage(cmd);
56
+ }
57
+
58
+ /**
59
+ * Receives data from the Web Inspector service and handles it.
60
+ *
61
+ * @param data - The data received from the service.
62
+ */
63
+ override async receive(data: any): Promise<void> {
64
+ if (this.isConnected) {
65
+ await this.messageHandler.handleMessage(data);
66
+ }
67
+ }
68
+ }
@@ -4,27 +4,26 @@ import B from 'bluebird';
4
4
  import net from 'net';
5
5
  import { RpcClient } from './rpc-client';
6
6
  import { services } from 'appium-ios-device';
7
+ import type { RpcClientOptions, RpcClientSimulatorOptions, RemoteCommand } from '../types';
7
8
 
9
+ /**
10
+ * RPC client implementation for iOS simulators.
11
+ * Extends RpcClient to provide simulator-specific connection handling
12
+ * via TCP sockets or Unix domain sockets.
13
+ */
8
14
  export class RpcClientSimulator extends RpcClient {
9
- /** @type {string|undefined} */
10
- host;
11
-
12
- /** @type {number|undefined} */
13
- port;
14
-
15
- /** @type {any} */
16
- messageProxy;
17
-
18
- /** @type {import('node:net').Socket|null} */
19
- socket;
20
-
21
- /** @type {string|undefined} */
22
- socketPath;
15
+ protected readonly host?: string;
16
+ protected port?: number;
17
+ protected readonly messageProxy?: any;
18
+ protected socket: net.Socket | null;
19
+ protected readonly socketPath?: string;
20
+ protected service?: any;
23
21
 
24
22
  /**
25
- * @param {import('./rpc-client').RpcClientOptions & RpcClientSimulatorOptions} [opts={}]
23
+ * @param opts - Options for configuring the RPC client, including
24
+ * simulator-specific options like socketPath, host, and port.
26
25
  */
27
- constructor (opts = {}) {
26
+ constructor(opts: RpcClientOptions & RpcClientSimulatorOptions = {}) {
28
27
  super(opts);
29
28
 
30
29
  const {
@@ -44,9 +43,10 @@ export class RpcClientSimulator extends RpcClient {
44
43
  }
45
44
 
46
45
  /**
47
- * @override
46
+ * Connects to the Web Inspector service on an iOS simulator.
47
+ * Supports both Unix domain sockets and TCP connections, with optional proxy support.
48
48
  */
49
- async connect () {
49
+ override async connect(): Promise<void> {
50
50
  // create socket and handle its messages
51
51
  if (this.socketPath) {
52
52
  if (this.messageProxy) {
@@ -57,10 +57,11 @@ export class RpcClientSimulator extends RpcClient {
57
57
  // Forward the actual socketPath to the proxy
58
58
  this.socket.once('connect', () => {
59
59
  log.debug(`Forwarding the actual web inspector socket to the proxy: '${this.socketPath}'`);
60
- // @ts-ignore socket must be efined here
61
- this.socket.write(JSON.stringify({
62
- socketPath: this.socketPath
63
- }));
60
+ if (this.socket) {
61
+ this.socket.write(JSON.stringify({
62
+ socketPath: this.socketPath
63
+ }));
64
+ }
64
65
  });
65
66
 
66
67
  } else {
@@ -77,7 +78,11 @@ export class RpcClientSimulator extends RpcClient {
77
78
  // tcp socket
78
79
  log.debug(`Connecting to remote debugger ${this.messageProxy ? 'via proxy ' : ''}through TCP: ${this.host}:${this.port}`);
79
80
  this.socket = new net.Socket();
80
- this.socket.connect(/** @type {number} */ (this.port), /** @type {String} */ (this.host));
81
+ if (this.port && this.host) {
82
+ this.socket.connect(this.port, this.host);
83
+ } else {
84
+ throw new Error('Both port and host must be defined for TCP connection');
85
+ }
81
86
  }
82
87
 
83
88
  this.socket.setNoDelay(true);
@@ -103,16 +108,17 @@ export class RpcClientSimulator extends RpcClient {
103
108
  this.service.listenMessage(this.receive.bind(this));
104
109
 
105
110
  // connect the socket
106
- return await new B((resolve, reject) => {
111
+ return await new B<void>((resolve, reject) => {
107
112
  // only resolve this function when we are actually connected
108
- // @ts-ignore socket must be defined here
113
+ if (!this.socket) {
114
+ return reject(new Error('RPC socket is not connected. Please contact developers'));
115
+ }
109
116
  this.socket.on('connect', () => {
110
117
  log.debug(`Debugger socket connected`);
111
118
  this.isConnected = true;
112
119
 
113
120
  resolve();
114
121
  });
115
- // @ts-ignore socket must be defined here
116
122
  this.socket.on('error', (err) => {
117
123
  if (this.isConnected) {
118
124
  log.error(`Socket error: ${err.message}`);
@@ -126,37 +132,41 @@ export class RpcClientSimulator extends RpcClient {
126
132
  }
127
133
 
128
134
  /**
129
- * @override
135
+ * Disconnects from the Web Inspector service on the simulator.
136
+ * Closes the socket and service connection, and cleans up resources.
130
137
  */
131
- async disconnect () {
138
+ override async disconnect(): Promise<void> {
132
139
  if (!this.isConnected) {
133
140
  return;
134
141
  }
135
142
 
136
143
  log.debug('Disconnecting from remote debugger');
137
144
  await super.disconnect();
138
- this.service.close();
145
+ this.service?.close();
139
146
  this.isConnected = false;
140
147
  }
141
148
 
142
149
  /**
143
- * @override
150
+ * Sends a command message to the Web Inspector service via the socket.
151
+ * Handles socket errors and ensures the socket is available before sending.
152
+ *
153
+ * @param cmd - The command to send to the simulator.
144
154
  */
145
- async sendMessage (cmd) {
146
- let onSocketError;
155
+ override async sendMessage(cmd: RemoteCommand): Promise<void> {
156
+ let onSocketError: ((err: Error) => void) | undefined;
147
157
 
148
- return await new B((resolve, reject) => {
158
+ return await new B<void>((resolve, reject) => {
149
159
  // handle socket problems
150
- onSocketError = (err) => {
160
+ onSocketError = (err: Error) => {
151
161
  log.error(`Socket error: ${err.message}`);
152
162
 
153
163
  // the connection was refused, so reject the connect promise
154
164
  reject(err);
155
165
  };
156
166
 
157
- if (!this.socket) {
167
+ if (!this.socket || !this.service) {
158
168
  return reject(
159
- new Error('The RPC socket is not defined. Have you called `connect()` before sending a message?')
169
+ new Error('The RPC client is not connected. Have you called `connect()` before sending a message?')
160
170
  );
161
171
  }
162
172
  this.socket.on('error', onSocketError);
@@ -165,22 +175,20 @@ export class RpcClientSimulator extends RpcClient {
165
175
  })
166
176
  .finally(() => {
167
177
  // remove this listener, so we don't exhaust the system
168
- try {
169
- // @ts-ignore socket must be defined
178
+ if (this.socket && onSocketError) {
170
179
  this.socket.removeListener('error', onSocketError);
171
- } catch {}
180
+ }
172
181
  });
173
182
  }
174
183
 
175
184
  /**
176
- * @override
185
+ * Receives data from the Web Inspector service and handles it.
186
+ * Converts Buffer data to strings for certain message keys.
187
+ *
188
+ * @param data - The data received from the service.
177
189
  */
178
- async receive (data) {
179
- if (!this.isConnected) {
180
- return;
181
- }
182
-
183
- if (!data) {
190
+ override async receive(data: any): Promise<void> {
191
+ if (!this.isConnected || !data) {
184
192
  return;
185
193
  }
186
194
 
@@ -189,17 +197,6 @@ export class RpcClientSimulator extends RpcClient {
189
197
  data[key] = data[key].toString('utf8');
190
198
  }
191
199
  }
192
- // @ts-ignore messageHandler must be defined
193
200
  await this.messageHandler.handleMessage(data);
194
201
  }
195
202
  }
196
-
197
- export default RpcClientSimulator;
198
-
199
- /**
200
- * @typedef {Object} RpcClientSimulatorOptions
201
- * @property {string} [socketPath]
202
- * @property {string} [host='::1']
203
- * @property {number} [port]
204
- * @property {any} [messageProxy]
205
- */