appium-ios-remotexpc 0.7.0 → 0.9.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.
@@ -0,0 +1,286 @@
1
+ import { logger } from '@appium/support';
2
+ import { randomUUID } from 'crypto';
3
+ import { EventEmitter } from 'events';
4
+ import { ServiceConnection } from '../../../service-connection.js';
5
+ import { BaseService } from '../base-service.js';
6
+ const log = logger.getLogger('WebInspectorService');
7
+ /**
8
+ * WebInspectorService provides an API to:
9
+ * - Send messages to webinspectord
10
+ * - Listen to messages from webinspectord
11
+ * - Communicate with web views and Safari on iOS devices
12
+ *
13
+ * This service is used for web automation, inspection, and debugging.
14
+ */
15
+ export class WebInspectorService extends BaseService {
16
+ static RSD_SERVICE_NAME = 'com.apple.webinspector.shim.remote';
17
+ // RPC method selectors
18
+ static RPC_REPORT_IDENTIFIER = '_rpc_reportIdentifier:';
19
+ static RPC_REQUEST_APPLICATION_LAUNCH = '_rpc_requestApplicationLaunch:';
20
+ static RPC_GET_CONNECTED_APPLICATIONS = '_rpc_getConnectedApplications:';
21
+ static RPC_FORWARD_GET_LISTING = '_rpc_forwardGetListing:';
22
+ static RPC_FORWARD_AUTOMATION_SESSION_REQUEST = '_rpc_forwardAutomationSessionRequest:';
23
+ static RPC_FORWARD_SOCKET_SETUP = '_rpc_forwardSocketSetup:';
24
+ static RPC_FORWARD_SOCKET_DATA = '_rpc_forwardSocketData:';
25
+ static RPC_FORWARD_INDICATE_WEB_VIEW = '_rpc_forwardIndicateWebView:';
26
+ connection = null;
27
+ messageEmitter = new EventEmitter();
28
+ isReceiving = false;
29
+ connectionId;
30
+ receivePromise = null;
31
+ constructor(address) {
32
+ super(address);
33
+ this.connectionId = randomUUID().toUpperCase();
34
+ }
35
+ /**
36
+ * Send a message to the WebInspector service
37
+ * @param selector The RPC selector (e.g., '_rpc_reportIdentifier:')
38
+ * @param args The arguments dictionary for the message
39
+ * @returns Promise that resolves when the message is sent
40
+ */
41
+ async sendMessage(selector, args = {}) {
42
+ const connection = await this.connectToWebInspectorService();
43
+ // Add connection identifier to all messages
44
+ const message = {
45
+ __selector: selector,
46
+ __argument: {
47
+ ...args,
48
+ WIRConnectionIdentifierKey: this.connectionId,
49
+ },
50
+ };
51
+ log.debug(`Sending WebInspector message: ${selector}`);
52
+ connection.sendPlist(message);
53
+ }
54
+ /**
55
+ * Listen to messages from the WebInspector service using async generator
56
+ * @yields PlistMessage - Messages received from the WebInspector service
57
+ */
58
+ async *listenMessage() {
59
+ await this.connectToWebInspectorService();
60
+ // Start receiving messages in background if not already started
61
+ if (!this.isReceiving) {
62
+ this.startMessageReceiver();
63
+ }
64
+ const queue = [];
65
+ let resolveNext = null;
66
+ let stopped = false;
67
+ const messageHandler = (message) => {
68
+ if (resolveNext) {
69
+ resolveNext({ value: message, done: false });
70
+ resolveNext = null;
71
+ }
72
+ else {
73
+ queue.push(message);
74
+ }
75
+ };
76
+ const stopHandler = () => {
77
+ stopped = true;
78
+ if (resolveNext) {
79
+ resolveNext({ value: undefined, done: true });
80
+ resolveNext = null;
81
+ }
82
+ };
83
+ this.messageEmitter.on('message', messageHandler);
84
+ this.messageEmitter.once('stop', stopHandler);
85
+ try {
86
+ while (!stopped) {
87
+ if (queue.length > 0) {
88
+ yield queue.shift();
89
+ }
90
+ else {
91
+ const message = await new Promise((resolve) => {
92
+ if (stopped) {
93
+ resolve(null);
94
+ return;
95
+ }
96
+ resolveNext = (result) => {
97
+ resolve(result.done ? null : result.value);
98
+ };
99
+ });
100
+ if (message === null) {
101
+ break;
102
+ }
103
+ yield message;
104
+ }
105
+ }
106
+ }
107
+ finally {
108
+ this.messageEmitter.off('message', messageHandler);
109
+ this.messageEmitter.off('stop', stopHandler);
110
+ }
111
+ }
112
+ /**
113
+ * Stop listening to messages
114
+ */
115
+ stopListening() {
116
+ this.isReceiving = false;
117
+ this.messageEmitter.emit('stop');
118
+ }
119
+ /**
120
+ * Close the connection and clean up resources
121
+ */
122
+ async close() {
123
+ this.stopListening();
124
+ if (this.connection) {
125
+ await this.connection.close();
126
+ this.connection = null;
127
+ log.debug('WebInspector connection closed');
128
+ }
129
+ if (this.receivePromise) {
130
+ await this.receivePromise;
131
+ }
132
+ }
133
+ /**
134
+ * Get the connection ID being used for this service
135
+ * @returns The connection identifier
136
+ */
137
+ getConnectionId() {
138
+ return this.connectionId;
139
+ }
140
+ /**
141
+ * Request application launch
142
+ * @param bundleId The bundle identifier of the application to launch
143
+ */
144
+ async requestApplicationLaunch(bundleId) {
145
+ await this.sendMessage(WebInspectorService.RPC_REQUEST_APPLICATION_LAUNCH, {
146
+ WIRApplicationBundleIdentifierKey: bundleId,
147
+ });
148
+ }
149
+ /**
150
+ * Get connected applications
151
+ */
152
+ async getConnectedApplications() {
153
+ await this.sendMessage(WebInspectorService.RPC_GET_CONNECTED_APPLICATIONS, {});
154
+ }
155
+ /**
156
+ * Forward get listing for an application
157
+ * @param appId The application identifier
158
+ */
159
+ async forwardGetListing(appId) {
160
+ await this.sendMessage(WebInspectorService.RPC_FORWARD_GET_LISTING, {
161
+ WIRApplicationIdentifierKey: appId,
162
+ });
163
+ }
164
+ /**
165
+ * Forward automation session request
166
+ * @param sessionId The session identifier
167
+ * @param appId The application identifier
168
+ * @param capabilities Optional session capabilities
169
+ */
170
+ async forwardAutomationSessionRequest(sessionId, appId, capabilities) {
171
+ const defaultCapabilities = {
172
+ 'org.webkit.webdriver.webrtc.allow-insecure-media-capture': true,
173
+ 'org.webkit.webdriver.webrtc.suppress-ice-candidate-filtering': false,
174
+ };
175
+ await this.sendMessage(WebInspectorService.RPC_FORWARD_AUTOMATION_SESSION_REQUEST, {
176
+ WIRApplicationIdentifierKey: appId,
177
+ WIRSessionIdentifierKey: sessionId,
178
+ WIRSessionCapabilitiesKey: {
179
+ ...defaultCapabilities,
180
+ ...(capabilities ?? {}),
181
+ },
182
+ });
183
+ }
184
+ /**
185
+ * Forward socket setup for inspector connection
186
+ * @param sessionId The session identifier
187
+ * @param appId The application identifier
188
+ * @param pageId The page identifier
189
+ * @param automaticallyPause Whether to automatically pause (defaults to true)
190
+ */
191
+ async forwardSocketSetup(sessionId, appId, pageId, automaticallyPause = true) {
192
+ const message = {
193
+ WIRApplicationIdentifierKey: appId,
194
+ WIRPageIdentifierKey: pageId,
195
+ WIRSenderKey: sessionId,
196
+ WIRMessageDataTypeChunkSupportedKey: 0,
197
+ };
198
+ if (!automaticallyPause) {
199
+ message.WIRAutomaticallyPause = false;
200
+ }
201
+ await this.sendMessage(WebInspectorService.RPC_FORWARD_SOCKET_SETUP, message);
202
+ }
203
+ /**
204
+ * Forward socket data to a page
205
+ * @param sessionId The session identifier
206
+ * @param appId The application identifier
207
+ * @param pageId The page identifier
208
+ * @param data The data to send (will be JSON stringified)
209
+ */
210
+ async forwardSocketData(sessionId, appId, pageId, data) {
211
+ const socketData = typeof data === 'string' ? data : JSON.stringify(data);
212
+ await this.sendMessage(WebInspectorService.RPC_FORWARD_SOCKET_DATA, {
213
+ WIRApplicationIdentifierKey: appId,
214
+ WIRPageIdentifierKey: pageId,
215
+ WIRSessionIdentifierKey: sessionId,
216
+ WIRSenderKey: sessionId,
217
+ WIRSocketDataKey: Buffer.from(socketData, 'utf-8'),
218
+ });
219
+ }
220
+ /**
221
+ * Forward indicate web view
222
+ * @param appId The application identifier
223
+ * @param pageId The page identifier
224
+ * @param enable Whether to enable indication
225
+ */
226
+ async forwardIndicateWebView(appId, pageId, enable) {
227
+ await this.sendMessage(WebInspectorService.RPC_FORWARD_INDICATE_WEB_VIEW, {
228
+ WIRApplicationIdentifierKey: appId,
229
+ WIRPageIdentifierKey: pageId,
230
+ WIRIndicateEnabledKey: enable,
231
+ });
232
+ }
233
+ /**
234
+ * Connect to the WebInspector service
235
+ * @returns Promise resolving to the ServiceConnection instance
236
+ */
237
+ async connectToWebInspectorService() {
238
+ if (this.connection) {
239
+ return this.connection;
240
+ }
241
+ const service = {
242
+ serviceName: WebInspectorService.RSD_SERVICE_NAME,
243
+ port: this.address[1].toString(),
244
+ };
245
+ this.connection = await this.startLockdownService(service);
246
+ // Consume the StartService response from RSDCheckin
247
+ const startServiceResponse = await this.connection.receive();
248
+ if (startServiceResponse?.Request !== 'StartService') {
249
+ log.warn(`Expected StartService response, got: ${JSON.stringify(startServiceResponse)}`);
250
+ }
251
+ // Send initial identifier report
252
+ await this.sendMessage(WebInspectorService.RPC_REPORT_IDENTIFIER, {});
253
+ log.debug('Connected to WebInspector service');
254
+ return this.connection;
255
+ }
256
+ /**
257
+ * Start receiving messages from the WebInspector service in the background
258
+ */
259
+ startMessageReceiver() {
260
+ if (this.isReceiving || !this.connection) {
261
+ return;
262
+ }
263
+ this.isReceiving = true;
264
+ this.receivePromise = (async () => {
265
+ try {
266
+ while (this.isReceiving && this.connection) {
267
+ try {
268
+ const message = await this.connection.receive();
269
+ this.messageEmitter.emit('message', message);
270
+ }
271
+ catch (error) {
272
+ if (this.isReceiving) {
273
+ log.error('Error receiving message:', error);
274
+ this.messageEmitter.emit('error', error);
275
+ }
276
+ break;
277
+ }
278
+ }
279
+ }
280
+ finally {
281
+ this.isReceiving = false;
282
+ }
283
+ })();
284
+ }
285
+ }
286
+ export default WebInspectorService;
@@ -1,11 +1,13 @@
1
1
  import { RemoteXpcConnection } from './lib/remote-xpc/remote-xpc-connection.js';
2
- import type { DiagnosticsServiceWithConnection, MobileConfigServiceWithConnection, MobileImageMounterServiceWithConnection, NotificationProxyServiceWithConnection, SpringboardServiceWithConnection, SyslogService as SyslogServiceType } from './lib/types.js';
2
+ import type { DiagnosticsServiceWithConnection, MobileConfigServiceWithConnection, MobileImageMounterServiceWithConnection, NotificationProxyServiceWithConnection, PowerAssertionServiceWithConnection, SpringboardServiceWithConnection, SyslogService as SyslogServiceType, WebInspectorServiceWithConnection } from './lib/types.js';
3
3
  export declare function startDiagnosticsService(udid: string): Promise<DiagnosticsServiceWithConnection>;
4
4
  export declare function startNotificationProxyService(udid: string): Promise<NotificationProxyServiceWithConnection>;
5
5
  export declare function startMobileConfigService(udid: string): Promise<MobileConfigServiceWithConnection>;
6
6
  export declare function startMobileImageMounterService(udid: string): Promise<MobileImageMounterServiceWithConnection>;
7
7
  export declare function startSpringboardService(udid: string): Promise<SpringboardServiceWithConnection>;
8
+ export declare function startPowerAssertionService(udid: string): Promise<PowerAssertionServiceWithConnection>;
8
9
  export declare function startSyslogService(udid: string): Promise<SyslogServiceType>;
10
+ export declare function startWebInspectorService(udid: string): Promise<WebInspectorServiceWithConnection>;
9
11
  export declare function createRemoteXPCConnection(udid: string): Promise<{
10
12
  remoteXPC: RemoteXpcConnection;
11
13
  tunnelConnection: {
@@ -1 +1 @@
1
- {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/services.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,2CAA2C,CAAC;AAGhF,OAAO,KAAK,EACV,gCAAgC,EAChC,iCAAiC,EACjC,uCAAuC,EACvC,sCAAsC,EACtC,gCAAgC,EAChC,aAAa,IAAI,iBAAiB,EACnC,MAAM,gBAAgB,CAAC;AAWxB,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,gCAAgC,CAAC,CAY3C;AAED,wBAAsB,6BAA6B,CACjD,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,sCAAsC,CAAC,CAYjD;AAED,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,iCAAiC,CAAC,CAY5C;AACD,wBAAsB,8BAA8B,CAClD,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,uCAAuC,CAAC,CAYlD;AAED,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,gCAAgC,CAAC,CAY3C;AAED,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,iBAAiB,CAAC,CAG5B;AAED,wBAAsB,yBAAyB,CAAC,IAAI,EAAE,MAAM;;;;;;;;GAO3D"}
1
+ {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/services.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,2CAA2C,CAAC;AAGhF,OAAO,KAAK,EACV,gCAAgC,EAChC,iCAAiC,EACjC,uCAAuC,EACvC,sCAAsC,EACtC,mCAAmC,EACnC,gCAAgC,EAChC,aAAa,IAAI,iBAAiB,EAClC,iCAAiC,EAClC,MAAM,gBAAgB,CAAC;AAaxB,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,gCAAgC,CAAC,CAY3C;AAED,wBAAsB,6BAA6B,CACjD,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,sCAAsC,CAAC,CAYjD;AAED,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,iCAAiC,CAAC,CAY5C;AACD,wBAAsB,8BAA8B,CAClD,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,uCAAuC,CAAC,CAYlD;AAED,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,gCAAgC,CAAC,CAY3C;AAED,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,mCAAmC,CAAC,CAY9C;AAED,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,iBAAiB,CAAC,CAG5B;AAED,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,iCAAiC,CAAC,CAY5C;AAED,wBAAsB,yBAAyB,CAAC,IAAI,EAAE,MAAM;;;;;;;;GAO3D"}
@@ -6,8 +6,10 @@ import DiagnosticsService from './services/ios/diagnostic-service/index.js';
6
6
  import { MobileConfigService } from './services/ios/mobile-config/index.js';
7
7
  import MobileImageMounterService from './services/ios/mobile-image-mounter/index.js';
8
8
  import { NotificationProxyService } from './services/ios/notification-proxy/index.js';
9
+ import { PowerAssertionService } from './services/ios/power-assertion/index.js';
9
10
  import { SpringBoardService } from './services/ios/springboard-service/index.js';
10
11
  import SyslogService from './services/ios/syslog-service/index.js';
12
+ import { WebInspectorService } from './services/ios/webinspector/index.js';
11
13
  const APPIUM_XCUITEST_DRIVER_NAME = 'appium-xcuitest-driver';
12
14
  const TUNNEL_REGISTRY_PORT = 'tunnelRegistryPort';
13
15
  export async function startDiagnosticsService(udid) {
@@ -65,10 +67,32 @@ export async function startSpringboardService(udid) {
65
67
  ]),
66
68
  };
67
69
  }
70
+ export async function startPowerAssertionService(udid) {
71
+ const { remoteXPC, tunnelConnection } = await createRemoteXPCConnection(udid);
72
+ const powerAssertionService = remoteXPC.findService(PowerAssertionService.RSD_SERVICE_NAME);
73
+ return {
74
+ remoteXPC: remoteXPC,
75
+ powerAssertionService: new PowerAssertionService([
76
+ tunnelConnection.host,
77
+ parseInt(powerAssertionService.port, 10),
78
+ ]),
79
+ };
80
+ }
68
81
  export async function startSyslogService(udid) {
69
82
  const { tunnelConnection } = await createRemoteXPCConnection(udid);
70
83
  return new SyslogService([tunnelConnection.host, tunnelConnection.port]);
71
84
  }
85
+ export async function startWebInspectorService(udid) {
86
+ const { remoteXPC, tunnelConnection } = await createRemoteXPCConnection(udid);
87
+ const webInspectorService = remoteXPC.findService(WebInspectorService.RSD_SERVICE_NAME);
88
+ return {
89
+ remoteXPC: remoteXPC,
90
+ webInspectorService: new WebInspectorService([
91
+ tunnelConnection.host,
92
+ parseInt(webInspectorService.port, 10),
93
+ ]),
94
+ };
95
+ }
72
96
  export async function createRemoteXPCConnection(udid) {
73
97
  const tunnelConnection = await getTunnelInformation(udid);
74
98
  const remoteXPC = await startService(tunnelConnection.host, tunnelConnection.port);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium-ios-remotexpc",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "main": "build/src/index.js",
5
5
  "types": "build/src/index.d.ts",
6
6
  "type": "module",
@@ -32,6 +32,8 @@
32
32
  "test:image-mounter": "mocha test/integration/mobile-image-mounter-test.ts --exit --timeout 1m",
33
33
  "test:mobile-config": "mocha test/integration/mobile-config-test.ts --exit --timeout 1m",
34
34
  "test:springboard": "mocha test/integration/springboard-service-test.ts --exit --timeout 1m",
35
+ "test:webinspector": "mocha test/integration/webinspector-test.ts --exit --timeout 1m",
36
+ "test:power-assertion": "mocha test/integration/power-assertion-test.ts --exit --timeout 1m",
35
37
  "test:unit": "mocha 'test/unit/**/*.ts' --exit --timeout 2m",
36
38
  "test:tunnel-creation": "sudo tsx scripts/test-tunnel-creation.ts",
37
39
  "test:tunnel-creation:lsof": "sudo tsx scripts/test-tunnel-creation.ts --keep-open"
package/src/index.ts CHANGED
@@ -17,7 +17,10 @@ export type {
17
17
  MobileImageMounterService,
18
18
  NotificationProxyService,
19
19
  MobileConfigService,
20
+ PowerAssertionService,
21
+ PowerAssertionOptions,
20
22
  SpringboardService,
23
+ WebInspectorService,
21
24
  SyslogService,
22
25
  SocketInfo,
23
26
  TunnelResult,
@@ -27,8 +30,11 @@ export type {
27
30
  MobileImageMounterServiceWithConnection,
28
31
  NotificationProxyServiceWithConnection,
29
32
  MobileConfigServiceWithConnection,
33
+ PowerAssertionServiceWithConnection,
30
34
  SpringboardServiceWithConnection,
35
+ WebInspectorServiceWithConnection,
31
36
  } from './lib/types.js';
37
+ export { PowerAssertionType } from './lib/types.js';
32
38
  export {
33
39
  createUsbmux,
34
40
  Services,
package/src/lib/types.ts CHANGED
@@ -6,10 +6,15 @@ import { EventEmitter } from 'events';
6
6
 
7
7
  import type { ServiceConnection } from '../service-connection.js';
8
8
  import type { BaseService, Service } from '../services/ios/base-service.js';
9
+ import type { PowerAssertionOptions } from '../services/ios/power-assertion/index.js';
10
+ import { PowerAssertionType } from '../services/ios/power-assertion/index.js';
9
11
  import type { InterfaceOrientation } from '../services/ios/springboard-service/index.js';
10
12
  import type { RemoteXpcConnection } from './remote-xpc/remote-xpc-connection.js';
11
13
  import type { Device } from './usbmux/index.js';
12
14
 
15
+ export type { PowerAssertionOptions };
16
+ export { PowerAssertionType };
17
+
13
18
  /**
14
19
  * Represents a value that can be stored in a plist
15
20
  */
@@ -213,6 +218,24 @@ export interface NotificationProxyService extends BaseService {
213
218
  expectNotification(timeout?: number): Promise<PlistMessage>;
214
219
  }
215
220
 
221
+ /**
222
+ * Represents the PowerAssertionService for preventing system sleep
223
+ */
224
+ export interface PowerAssertionService extends BaseService {
225
+ /**
226
+ * Create a power assertion to prevent system sleep
227
+ * @param options Options for creating the power assertion
228
+ * @returns Promise that resolves when the assertion is created
229
+ */
230
+ createPowerAssertion(options: PowerAssertionOptions): Promise<void>;
231
+
232
+ /**
233
+ * Close the connection to the power assertion service
234
+ * @returns Promise that resolves when the connection is closed
235
+ */
236
+ close(): Promise<void>;
237
+ }
238
+
216
239
  /**
217
240
  * Represents the static side of MobileConfigService
218
241
  */
@@ -312,6 +335,132 @@ export interface MobileConfigServiceWithConnection {
312
335
  remoteXPC: RemoteXpcConnection;
313
336
  }
314
337
 
338
+ /**
339
+ * Represents a PowerAssertionService instance with its associated RemoteXPC connection
340
+ * This allows callers to properly manage the connection lifecycle
341
+ */
342
+ export interface PowerAssertionServiceWithConnection {
343
+ /** The PowerAssertionService instance */
344
+ powerAssertionService: PowerAssertionService;
345
+ /** The RemoteXPC connection that can be used to close the connection */
346
+ remoteXPC: RemoteXpcConnection;
347
+ }
348
+
349
+ /**
350
+ * Represents the WebInspectorService
351
+ */
352
+ export interface WebInspectorService extends BaseService {
353
+ /**
354
+ * Send a message to the WebInspector service
355
+ * @param selector The RPC selector (e.g., '_rpc_reportIdentifier:')
356
+ * @param args The arguments dictionary for the message
357
+ * @returns Promise that resolves when the message is sent
358
+ */
359
+ sendMessage(selector: string, args?: PlistDictionary): Promise<void>;
360
+
361
+ /**
362
+ * Listen to messages from the WebInspector service using async generator
363
+ * @yields PlistMessage - Messages received from the WebInspector service
364
+ */
365
+ listenMessage(): AsyncGenerator<PlistMessage, void, unknown>;
366
+
367
+ /**
368
+ * Stop listening to messages
369
+ */
370
+ stopListening(): void;
371
+
372
+ /**
373
+ * Close the connection and clean up resources
374
+ */
375
+ close(): Promise<void>;
376
+
377
+ /**
378
+ * Get the connection ID being used for this service
379
+ * @returns The connection identifier
380
+ */
381
+ getConnectionId(): string;
382
+
383
+ /**
384
+ * Request application launch
385
+ * @param bundleId The bundle identifier of the application to launch
386
+ */
387
+ requestApplicationLaunch(bundleId: string): Promise<void>;
388
+
389
+ /**
390
+ * Get connected applications
391
+ */
392
+ getConnectedApplications(): Promise<void>;
393
+
394
+ /**
395
+ * Forward get listing for an application
396
+ * @param appId The application identifier
397
+ */
398
+ forwardGetListing(appId: string): Promise<void>;
399
+
400
+ /**
401
+ * Forward automation session request
402
+ * @param sessionId The session identifier
403
+ * @param appId The application identifier
404
+ * @param capabilities Optional session capabilities
405
+ */
406
+ forwardAutomationSessionRequest(
407
+ sessionId: string,
408
+ appId: string,
409
+ capabilities?: PlistDictionary,
410
+ ): Promise<void>;
411
+
412
+ /**
413
+ * Forward socket setup for inspector connection
414
+ * @param sessionId The session identifier
415
+ * @param appId The application identifier
416
+ * @param pageId The page identifier
417
+ * @param automaticallyPause Whether to automatically pause (defaults to true)
418
+ */
419
+ forwardSocketSetup(
420
+ sessionId: string,
421
+ appId: string,
422
+ pageId: number,
423
+ automaticallyPause?: boolean,
424
+ ): Promise<void>;
425
+
426
+ /**
427
+ * Forward socket data to a page
428
+ * @param sessionId The session identifier
429
+ * @param appId The application identifier
430
+ * @param pageId The page identifier
431
+ * @param data The data to send (will be JSON stringified)
432
+ */
433
+ forwardSocketData(
434
+ sessionId: string,
435
+ appId: string,
436
+ pageId: number,
437
+ data: any,
438
+ ): Promise<void>;
439
+
440
+ /**
441
+ * Forward indicate web view
442
+ * @param appId The application identifier
443
+ * @param pageId The page identifier
444
+ * @param enable Whether to enable indication
445
+ */
446
+ forwardIndicateWebView(
447
+ appId: string,
448
+ pageId: number,
449
+ enable: boolean,
450
+ ): Promise<void>;
451
+ }
452
+
453
+ /**
454
+ * Represents a WebInspectorService instance with its associated RemoteXPC connection
455
+ * This allows callers to properly manage the connection lifecycle
456
+ */
457
+ export interface WebInspectorServiceWithConnection {
458
+ /** The WebInspectorService instance */
459
+ webInspectorService: WebInspectorService;
460
+ /** The RemoteXPC connection that can be used to close the connection */
461
+ remoteXPC: RemoteXpcConnection;
462
+ }
463
+
315
464
  /**
316
465
  * Options for configuring syslog capture
317
466
  */
@@ -60,6 +60,15 @@ export class ServiceConnection extends BasePlistService {
60
60
  return this.sendAndReceive(requestObj, timeout);
61
61
  }
62
62
 
63
+ /**
64
+ * Sends a plist message without waiting for a response
65
+ * This is useful for fire-and-forget style communication
66
+ * @param message The message to send
67
+ */
68
+ sendPlist(message: PlistDictionary): void {
69
+ this.send(message);
70
+ }
71
+
63
72
  /**
64
73
  * Gets the underlying socket
65
74
  * @returns The socket used by this service
@@ -4,14 +4,18 @@ import {
4
4
  } from '../lib/tunnel/tunnel-registry-server.js';
5
5
  import * as diagnostics from './ios/diagnostic-service/index.js';
6
6
  import * as mobileImageMounter from './ios/mobile-image-mounter/index.js';
7
+ import * as powerAssertion from './ios/power-assertion/index.js';
7
8
  import * as syslog from './ios/syslog-service/index.js';
8
9
  import * as tunnel from './ios/tunnel-service/index.js';
10
+ import * as webinspector from './ios/webinspector/index.js';
9
11
 
10
12
  export {
11
13
  diagnostics,
12
14
  mobileImageMounter,
15
+ powerAssertion,
13
16
  syslog,
14
17
  tunnel,
18
+ webinspector,
15
19
  TunnelRegistryServer,
16
20
  startTunnelRegistryServer,
17
21
  };