appium-ios-remotexpc 0.0.3 → 0.0.4

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 (192) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/build/src/base-plist-service.d.ts +51 -0
  3. package/build/src/base-plist-service.d.ts.map +1 -0
  4. package/build/src/base-plist-service.js +61 -0
  5. package/build/src/base-socket-service.d.ts +15 -0
  6. package/build/src/base-socket-service.d.ts.map +1 -0
  7. package/build/src/base-socket-service.js +46 -0
  8. package/build/src/index.d.ts +9 -0
  9. package/build/src/index.d.ts.map +1 -0
  10. package/build/src/index.js +7 -0
  11. package/build/src/lib/apple-tv/constants.d.ts +49 -0
  12. package/build/src/lib/apple-tv/constants.d.ts.map +1 -0
  13. package/build/src/lib/apple-tv/constants.js +71 -0
  14. package/build/src/lib/apple-tv/errors.d.ts +17 -0
  15. package/build/src/lib/apple-tv/errors.d.ts.map +1 -0
  16. package/build/src/lib/apple-tv/errors.js +30 -0
  17. package/build/src/lib/apple-tv/tlv/decoder.d.ts +19 -0
  18. package/build/src/lib/apple-tv/tlv/decoder.d.ts.map +1 -0
  19. package/build/src/lib/apple-tv/tlv/decoder.js +49 -0
  20. package/build/src/lib/apple-tv/tlv/encoder.d.ts +10 -0
  21. package/build/src/lib/apple-tv/tlv/encoder.d.ts.map +1 -0
  22. package/build/src/lib/apple-tv/tlv/encoder.js +20 -0
  23. package/build/src/lib/apple-tv/tlv/index.d.ts +4 -0
  24. package/build/src/lib/apple-tv/tlv/index.d.ts.map +1 -0
  25. package/build/src/lib/apple-tv/tlv/index.js +3 -0
  26. package/build/src/lib/apple-tv/tlv/pairing-tlv.d.ts +14 -0
  27. package/build/src/lib/apple-tv/tlv/pairing-tlv.d.ts.map +1 -0
  28. package/build/src/lib/apple-tv/tlv/pairing-tlv.js +27 -0
  29. package/build/src/lib/apple-tv/types.d.ts +36 -0
  30. package/build/src/lib/apple-tv/types.d.ts.map +1 -0
  31. package/build/src/lib/apple-tv/types.js +1 -0
  32. package/build/src/lib/apple-tv/utils/buffer-utils.d.ts +40 -0
  33. package/build/src/lib/apple-tv/utils/buffer-utils.d.ts.map +1 -0
  34. package/build/src/lib/apple-tv/utils/buffer-utils.js +76 -0
  35. package/build/src/lib/apple-tv/utils/index.d.ts +3 -0
  36. package/build/src/lib/apple-tv/utils/index.d.ts.map +1 -0
  37. package/build/src/lib/apple-tv/utils/index.js +2 -0
  38. package/build/src/lib/apple-tv/utils/uuid-generator.d.ts +9 -0
  39. package/build/src/lib/apple-tv/utils/uuid-generator.d.ts.map +1 -0
  40. package/build/src/lib/apple-tv/utils/uuid-generator.js +36 -0
  41. package/build/src/lib/lockdown/index.d.ts +87 -0
  42. package/build/src/lib/lockdown/index.d.ts.map +1 -0
  43. package/build/src/lib/lockdown/index.js +324 -0
  44. package/build/src/lib/pair-record/index.d.ts +3 -0
  45. package/build/src/lib/pair-record/index.d.ts.map +1 -0
  46. package/build/src/lib/pair-record/index.js +2 -0
  47. package/build/src/lib/pair-record/pair-record.d.ts +48 -0
  48. package/build/src/lib/pair-record/pair-record.d.ts.map +1 -0
  49. package/build/src/lib/pair-record/pair-record.js +85 -0
  50. package/build/src/lib/plist/binary-plist-creator.d.ts +14 -0
  51. package/build/src/lib/plist/binary-plist-creator.d.ts.map +1 -0
  52. package/build/src/lib/plist/binary-plist-creator.js +475 -0
  53. package/build/src/lib/plist/binary-plist-parser.d.ts +14 -0
  54. package/build/src/lib/plist/binary-plist-parser.d.ts.map +1 -0
  55. package/build/src/lib/plist/binary-plist-parser.js +449 -0
  56. package/build/src/lib/plist/constants.d.ts +36 -0
  57. package/build/src/lib/plist/constants.d.ts.map +1 -0
  58. package/build/src/lib/plist/constants.js +43 -0
  59. package/build/src/lib/plist/index.d.ts +14 -0
  60. package/build/src/lib/plist/index.d.ts.map +1 -0
  61. package/build/src/lib/plist/index.js +16 -0
  62. package/build/src/lib/plist/length-based-splitter.d.ts +43 -0
  63. package/build/src/lib/plist/length-based-splitter.d.ts.map +1 -0
  64. package/build/src/lib/plist/length-based-splitter.js +228 -0
  65. package/build/src/lib/plist/plist-creator.d.ts +8 -0
  66. package/build/src/lib/plist/plist-creator.d.ts.map +1 -0
  67. package/build/src/lib/plist/plist-creator.js +33 -0
  68. package/build/src/lib/plist/plist-decoder.d.ts +25 -0
  69. package/build/src/lib/plist/plist-decoder.d.ts.map +1 -0
  70. package/build/src/lib/plist/plist-decoder.js +103 -0
  71. package/build/src/lib/plist/plist-encoder.d.ts +10 -0
  72. package/build/src/lib/plist/plist-encoder.d.ts.map +1 -0
  73. package/build/src/lib/plist/plist-encoder.js +27 -0
  74. package/build/src/lib/plist/plist-parser.d.ts +9 -0
  75. package/build/src/lib/plist/plist-parser.d.ts.map +1 -0
  76. package/build/src/lib/plist/plist-parser.js +109 -0
  77. package/build/src/lib/plist/plist-service.d.ts +86 -0
  78. package/build/src/lib/plist/plist-service.d.ts.map +1 -0
  79. package/build/src/lib/plist/plist-service.js +180 -0
  80. package/build/src/lib/plist/unified-plist-creator.d.ts +9 -0
  81. package/build/src/lib/plist/unified-plist-creator.d.ts.map +1 -0
  82. package/build/src/lib/plist/unified-plist-creator.js +14 -0
  83. package/build/src/lib/plist/unified-plist-parser.d.ts +8 -0
  84. package/build/src/lib/plist/unified-plist-parser.d.ts.map +1 -0
  85. package/build/src/lib/plist/unified-plist-parser.js +23 -0
  86. package/build/src/lib/plist/utils.d.ts +97 -0
  87. package/build/src/lib/plist/utils.d.ts.map +1 -0
  88. package/build/src/lib/plist/utils.js +287 -0
  89. package/build/src/lib/remote-xpc/constants.d.ts +20 -0
  90. package/build/src/lib/remote-xpc/constants.d.ts.map +1 -0
  91. package/build/src/lib/remote-xpc/constants.js +21 -0
  92. package/build/src/lib/remote-xpc/handshake-frames.d.ts +74 -0
  93. package/build/src/lib/remote-xpc/handshake-frames.d.ts.map +1 -0
  94. package/build/src/lib/remote-xpc/handshake-frames.js +285 -0
  95. package/build/src/lib/remote-xpc/handshake.d.ts +14 -0
  96. package/build/src/lib/remote-xpc/handshake.d.ts.map +1 -0
  97. package/build/src/lib/remote-xpc/handshake.js +95 -0
  98. package/build/src/lib/remote-xpc/remote-xpc-connection.d.ts +55 -0
  99. package/build/src/lib/remote-xpc/remote-xpc-connection.d.ts.map +1 -0
  100. package/build/src/lib/remote-xpc/remote-xpc-connection.js +365 -0
  101. package/build/src/lib/remote-xpc/xpc-protocol.d.ts +22 -0
  102. package/build/src/lib/remote-xpc/xpc-protocol.d.ts.map +1 -0
  103. package/build/src/lib/remote-xpc/xpc-protocol.js +368 -0
  104. package/build/src/lib/tunnel/index.d.ts +69 -0
  105. package/build/src/lib/tunnel/index.d.ts.map +1 -0
  106. package/build/src/lib/tunnel/index.js +205 -0
  107. package/build/src/lib/tunnel/packet-stream-client.d.ts +46 -0
  108. package/build/src/lib/tunnel/packet-stream-client.d.ts.map +1 -0
  109. package/build/src/lib/tunnel/packet-stream-client.js +152 -0
  110. package/build/src/lib/tunnel/packet-stream-server.d.ts +37 -0
  111. package/build/src/lib/tunnel/packet-stream-server.d.ts.map +1 -0
  112. package/build/src/lib/tunnel/packet-stream-server.js +109 -0
  113. package/build/src/lib/tunnel/tunnel-api-client.d.ts +85 -0
  114. package/build/src/lib/tunnel/tunnel-api-client.d.ts.map +1 -0
  115. package/build/src/lib/tunnel/tunnel-api-client.js +207 -0
  116. package/build/src/lib/tunnel/tunnel-registry-server.d.ts +68 -0
  117. package/build/src/lib/tunnel/tunnel-registry-server.d.ts.map +1 -0
  118. package/build/src/lib/tunnel/tunnel-registry-server.js +351 -0
  119. package/build/src/lib/types.d.ts +238 -0
  120. package/build/src/lib/types.d.ts.map +1 -0
  121. package/build/src/lib/types.js +4 -0
  122. package/build/src/lib/usbmux/index.d.ts +177 -0
  123. package/build/src/lib/usbmux/index.d.ts.map +1 -0
  124. package/build/src/lib/usbmux/index.js +490 -0
  125. package/build/src/lib/usbmux/usbmux-decoder.d.ts +19 -0
  126. package/build/src/lib/usbmux/usbmux-decoder.d.ts.map +1 -0
  127. package/build/src/lib/usbmux/usbmux-decoder.js +38 -0
  128. package/build/src/lib/usbmux/usbmux-encoder.d.ts +12 -0
  129. package/build/src/lib/usbmux/usbmux-encoder.d.ts.map +1 -0
  130. package/build/src/lib/usbmux/usbmux-encoder.js +32 -0
  131. package/build/src/service-connection.d.ts +34 -0
  132. package/build/src/service-connection.d.ts.map +1 -0
  133. package/build/src/service-connection.js +51 -0
  134. package/build/src/services/index.d.ts +6 -0
  135. package/build/src/services/index.d.ts.map +1 -0
  136. package/build/src/services/index.js +5 -0
  137. package/build/src/services/ios/base-service.d.ts +35 -0
  138. package/build/src/services/ios/base-service.d.ts.map +1 -0
  139. package/build/src/services/ios/base-service.js +55 -0
  140. package/build/src/services/ios/diagnostic-service/index.d.ts +46 -0
  141. package/build/src/services/ios/diagnostic-service/index.d.ts.map +1 -0
  142. package/build/src/services/ios/diagnostic-service/index.js +169 -0
  143. package/build/src/services/ios/diagnostic-service/keys.d.ts +5 -0
  144. package/build/src/services/ios/diagnostic-service/keys.d.ts.map +1 -0
  145. package/build/src/services/ios/diagnostic-service/keys.js +770 -0
  146. package/build/src/services/ios/syslog-service/index.d.ts +91 -0
  147. package/build/src/services/ios/syslog-service/index.d.ts.map +1 -0
  148. package/build/src/services/ios/syslog-service/index.js +323 -0
  149. package/build/src/services/ios/tunnel-service/index.d.ts +17 -0
  150. package/build/src/services/ios/tunnel-service/index.d.ts.map +1 -0
  151. package/build/src/services/ios/tunnel-service/index.js +57 -0
  152. package/build/src/services.d.ts +14 -0
  153. package/build/src/services.d.ts.map +1 -0
  154. package/build/src/services.js +48 -0
  155. package/package.json +12 -3
  156. package/.github/dependabot.yml +0 -38
  157. package/.github/workflows/format-check.yml +0 -43
  158. package/.github/workflows/lint-and-build.yml +0 -40
  159. package/.github/workflows/pr-title.yml +0 -16
  160. package/.github/workflows/publish.js.yml +0 -43
  161. package/.github/workflows/test-validation.yml +0 -40
  162. package/.mocharc.json +0 -8
  163. package/.prettierignore +0 -3
  164. package/.prettierrc +0 -17
  165. package/.releaserc +0 -48
  166. package/assets/images/ios-arch.png +0 -0
  167. package/eslint.config.js +0 -45
  168. package/npm-shrinkwrap.json +0 -2711
  169. package/test/integration/diagnostics-test.ts +0 -44
  170. package/test/integration/read-pair-record-test.ts +0 -39
  171. package/test/integration/tunnel-test.ts +0 -104
  172. package/test/unit/apple-tv/tlv/decoder.spec.ts +0 -144
  173. package/test/unit/apple-tv/tlv/encoder.spec.ts +0 -91
  174. package/test/unit/apple-tv/tlv/pairing-tlv.spec.ts +0 -101
  175. package/test/unit/apple-tv/tlv/tlv-integration.spec.ts +0 -146
  176. package/test/unit/apple-tv/utils/buffer-utils.spec.ts +0 -74
  177. package/test/unit/apple-tv/utils/uuid-generator.spec.ts +0 -39
  178. package/test/unit/fixtures/index.ts +0 -88
  179. package/test/unit/fixtures/usbmuxconnectmessage.bin +0 -0
  180. package/test/unit/fixtures/usbmuxlistdevicemessage.bin +0 -0
  181. package/test/unit/plist/error-handling.spec.ts +0 -101
  182. package/test/unit/plist/fixtures/sample.binary.plist +0 -0
  183. package/test/unit/plist/fixtures/sample.xml.plist +0 -38
  184. package/test/unit/plist/plist-parser.spec.ts +0 -283
  185. package/test/unit/plist/plist.spec.ts +0 -205
  186. package/test/unit/plist/tag-position-handling.spec.ts +0 -90
  187. package/test/unit/plist/unified-plist-parser.spec.ts +0 -227
  188. package/test/unit/plist/utils.spec.ts +0 -249
  189. package/test/unit/plist/xml-cleaning.spec.ts +0 -60
  190. package/test/unit/tunnel/tunnel-registry-server.spec.ts +0 -194
  191. package/test/unit/usbmux/usbmux-specs.ts +0 -71
  192. package/tsconfig.json +0 -36
@@ -0,0 +1,365 @@
1
+ import { logger } from '@appium/support';
2
+ import net from 'node:net';
3
+ import Handshake from './handshake.js';
4
+ const log = logger.getLogger('RemoteXpcConnection');
5
+ // Timeout constants
6
+ const CONNECTION_TIMEOUT_MS = 30000; // 30 seconds
7
+ const SERVICE_EXTRACTION_TIMEOUT_MS = 5000; // 5 seconds
8
+ const HANDSHAKE_DELAY_MS = 100; // 100 milliseconds
9
+ const SERVICE_AFTER_HANDSHAKE_TIMEOUT_MS = 10000; // 10 seconds
10
+ const SOCKET_CLOSE_TIMEOUT_MS = 1000; // 1 second
11
+ const SOCKET_END_TIMEOUT_MS = 500; // 0.5 seconds
12
+ const SOCKET_WRITE_TIMEOUT_MS = 500; // 0.5 seconds
13
+ class RemoteXpcConnection {
14
+ _address;
15
+ _socket;
16
+ _handshake;
17
+ _isConnected;
18
+ _services;
19
+ constructor(address) {
20
+ this._address = address;
21
+ this._socket = undefined;
22
+ this._handshake = undefined;
23
+ this._isConnected = false;
24
+ this._services = undefined;
25
+ }
26
+ /**
27
+ * Connect to the remote device and perform handshake
28
+ * @returns Promise that resolves with the list of available services
29
+ */
30
+ async connect() {
31
+ if (this._isConnected) {
32
+ throw new Error('Already connected');
33
+ }
34
+ return new Promise((resolve, reject) => {
35
+ // Set a timeout for the entire connection process
36
+ const connectionTimeout = setTimeout(() => {
37
+ if (this._socket) {
38
+ this._socket.destroy();
39
+ }
40
+ reject(new Error(`Connection timed out after ${CONNECTION_TIMEOUT_MS / 1000} seconds`));
41
+ }, CONNECTION_TIMEOUT_MS);
42
+ // Set a timeout for service extraction
43
+ let serviceExtractionTimeout;
44
+ const clearTimeouts = () => {
45
+ clearTimeout(connectionTimeout);
46
+ if (serviceExtractionTimeout) {
47
+ clearTimeout(serviceExtractionTimeout);
48
+ }
49
+ };
50
+ try {
51
+ this._socket = net.connect({
52
+ host: this._address[0],
53
+ port: this._address[1],
54
+ family: 6,
55
+ });
56
+ this._socket.setNoDelay(true);
57
+ this._socket.setKeepAlive(true);
58
+ // Buffer to accumulate data
59
+ let accumulatedData = Buffer.alloc(0);
60
+ this._socket.once('error', (error) => {
61
+ log.error(`Connection error: ${error}`);
62
+ this._isConnected = false;
63
+ clearTimeouts();
64
+ reject(error);
65
+ });
66
+ // Handle incoming data
67
+ this._socket.on('data', (data) => {
68
+ if (Buffer.isBuffer(data) || typeof data === 'string') {
69
+ const buffer = Buffer.isBuffer(data)
70
+ ? data
71
+ : Buffer.from(data, 'hex');
72
+ // Accumulate data
73
+ accumulatedData = Buffer.concat([accumulatedData, buffer]);
74
+ // Check if we have enough data to extract services
75
+ // Don't rely solely on buffer length, also check for service patterns
76
+ const dataStr = accumulatedData.toString('utf8');
77
+ if (dataStr.includes('com.apple') && dataStr.includes('Port')) {
78
+ try {
79
+ const servicesResponse = extractServices(dataStr);
80
+ // Only resolve if we found at least one service
81
+ if (servicesResponse.services.length > 0) {
82
+ this._services = servicesResponse.services;
83
+ log.info(`Extracted ${servicesResponse.services.length} services`);
84
+ clearTimeouts();
85
+ resolve(servicesResponse);
86
+ }
87
+ else if (!serviceExtractionTimeout) {
88
+ // Set a timeout to resolve with whatever we have if no more data comes
89
+ serviceExtractionTimeout = setTimeout(() => {
90
+ log.warn('Service extraction timeout reached, resolving with current data');
91
+ const finalResponse = extractServices(accumulatedData.toString('utf8'));
92
+ this._services = finalResponse.services;
93
+ clearTimeouts();
94
+ resolve(finalResponse);
95
+ }, SERVICE_EXTRACTION_TIMEOUT_MS);
96
+ }
97
+ }
98
+ catch (error) {
99
+ log.warn(`Error extracting services: ${error}, continuing to collect data`);
100
+ }
101
+ }
102
+ }
103
+ });
104
+ this._socket.on('close', () => {
105
+ log.info('Socket closed');
106
+ this._isConnected = false;
107
+ clearTimeouts();
108
+ // If we haven't resolved yet, reject with an error
109
+ if (this._services === undefined) {
110
+ reject(new Error('Connection closed before services were extracted'));
111
+ }
112
+ });
113
+ this._socket.once('connect', async () => {
114
+ try {
115
+ this._isConnected = true;
116
+ if (this._socket) {
117
+ this._handshake = new Handshake(this._socket);
118
+ // Add a small delay before performing handshake to ensure socket is ready
119
+ await new Promise((resolve) => setTimeout(resolve, HANDSHAKE_DELAY_MS));
120
+ // Once handshake is successful we can get
121
+ // peer-info and get ports for lockdown in RSD
122
+ await this._handshake.perform();
123
+ // Set a timeout for service extraction
124
+ setTimeout(async () => {
125
+ if (this._services === undefined) {
126
+ log.warn('No services received after handshake, closing connection');
127
+ try {
128
+ await this.close();
129
+ }
130
+ catch (err) {
131
+ log.error(`Error closing connection: ${err}`);
132
+ }
133
+ reject(new Error('No services received after handshake'));
134
+ }
135
+ }, SERVICE_AFTER_HANDSHAKE_TIMEOUT_MS);
136
+ }
137
+ }
138
+ catch (error) {
139
+ log.error(`Handshake failed: ${error}`);
140
+ clearTimeouts();
141
+ await this.close();
142
+ reject(error);
143
+ }
144
+ });
145
+ }
146
+ catch (error) {
147
+ log.error(`Failed to create connection: ${error}`);
148
+ clearTimeouts();
149
+ reject(error);
150
+ }
151
+ });
152
+ }
153
+ /**
154
+ * Close the connection
155
+ */
156
+ async close() {
157
+ if (!this._socket) {
158
+ return Promise.resolve();
159
+ }
160
+ // Immediately mark as disconnected to prevent further operations
161
+ this._isConnected = false;
162
+ return new Promise((resolve) => {
163
+ // Set a shorter timeout for socket closing
164
+ const closeTimeout = setTimeout(() => {
165
+ log.warn('Socket close timed out, destroying socket');
166
+ this.forceCleanup();
167
+ resolve();
168
+ }, SOCKET_CLOSE_TIMEOUT_MS);
169
+ // Listen for the close event
170
+ if (this._socket) {
171
+ this._socket.once('close', () => {
172
+ log.debug('Socket closed successfully');
173
+ clearTimeout(closeTimeout);
174
+ this.cleanupResources();
175
+ resolve();
176
+ });
177
+ // Add an error handler specifically for the close operation
178
+ this._socket.once('error', (err) => {
179
+ log.error(`Socket error during close: ${err.message}`);
180
+ // Don't wait for timeout, force cleanup immediately
181
+ clearTimeout(closeTimeout);
182
+ this.forceCleanup();
183
+ resolve();
184
+ });
185
+ }
186
+ try {
187
+ // First remove all data listeners to prevent parsing during close
188
+ this.cleanupSocket();
189
+ if (this._socket) {
190
+ // Set a small write timeout to prevent hanging
191
+ this._socket.setTimeout(SOCKET_WRITE_TIMEOUT_MS);
192
+ // End the socket with a small empty buffer to flush any pending data
193
+ this._socket.end(Buffer.alloc(0), () => {
194
+ // If end completes successfully, the 'close' event will handle cleanup
195
+ // But set a short timeout just in case 'close' doesn't fire
196
+ setTimeout(() => {
197
+ if (this._socket) {
198
+ log.debug('Socket end completed but close event not fired, forcing cleanup');
199
+ clearTimeout(closeTimeout);
200
+ this.forceCleanup();
201
+ resolve();
202
+ }
203
+ }, SOCKET_END_TIMEOUT_MS);
204
+ });
205
+ }
206
+ else {
207
+ clearTimeout(closeTimeout);
208
+ this.cleanupResources();
209
+ resolve();
210
+ }
211
+ }
212
+ catch (error) {
213
+ log.error(`Unexpected error during close: ${error instanceof Error ? error.message : String(error)}`);
214
+ clearTimeout(closeTimeout);
215
+ this.forceCleanup();
216
+ resolve();
217
+ }
218
+ });
219
+ }
220
+ /**
221
+ * Get the list of available services
222
+ * @returns Array of available services
223
+ */
224
+ getServices() {
225
+ if (!this._services) {
226
+ throw new Error('Not connected or services not available');
227
+ }
228
+ return this._services;
229
+ }
230
+ /**
231
+ * List all available services
232
+ * @returns Array of all available services
233
+ */
234
+ listAllServices() {
235
+ return this.getServices();
236
+ }
237
+ /**
238
+ * Find a service by name
239
+ * @param serviceName The name of the service to find
240
+ * @returns The service or throws an error if not found
241
+ */
242
+ findService(serviceName) {
243
+ const services = this.getServices();
244
+ const service = services.find((service) => service.serviceName === serviceName);
245
+ if (!service) {
246
+ throw new Error(`Service ${serviceName} not found,
247
+ Check if the device is locked.`);
248
+ }
249
+ return service;
250
+ }
251
+ /**
252
+ * Remove all listeners from the socket to prevent memory leaks
253
+ */
254
+ cleanupSocket() {
255
+ if (this._socket) {
256
+ try {
257
+ // Store references to the listeners we want to keep
258
+ const closeListeners = this._socket.listeners('close');
259
+ const errorListeners = this._socket.listeners('error');
260
+ // Remove all listeners
261
+ this._socket.removeAllListeners();
262
+ // Re-add only the close and error listeners we need for cleanup
263
+ for (const listener of closeListeners) {
264
+ this._socket.once('close', listener);
265
+ }
266
+ for (const listener of errorListeners) {
267
+ this._socket.once('error', listener);
268
+ }
269
+ log.debug('Successfully removed socket data listeners');
270
+ }
271
+ catch (error) {
272
+ log.error(`Error removing socket listeners: ${error instanceof Error ? error.message : String(error)}`);
273
+ }
274
+ }
275
+ }
276
+ /**
277
+ * Clean up all resources
278
+ */
279
+ cleanupResources() {
280
+ this._socket = undefined;
281
+ this._isConnected = false;
282
+ this._handshake = undefined;
283
+ this._services = undefined;
284
+ }
285
+ /**
286
+ * Force cleanup by destroying the socket and cleaning up resources
287
+ */
288
+ forceCleanup() {
289
+ try {
290
+ if (this._socket) {
291
+ // Destroy the socket forcefully
292
+ this._socket.destroy();
293
+ log.debug('Socket forcefully destroyed');
294
+ }
295
+ }
296
+ catch (error) {
297
+ log.error(`Error destroying socket: ${error instanceof Error ? error.message : String(error)}`);
298
+ }
299
+ finally {
300
+ this.cleanupResources();
301
+ }
302
+ }
303
+ }
304
+ /**
305
+ * Extract services from the response
306
+ * @param response The response string to parse
307
+ * @returns Object containing the extracted services
308
+ */
309
+ function extractServices(response) {
310
+ // More robust regex that handles various formats of service names and port specifications
311
+ const serviceRegex = /com\.apple(?:\.[\w-]+)+/g;
312
+ const portRegex = /Port[^0-9]*(\d+)/g;
313
+ // First, collect all service names
314
+ const serviceMatches = [];
315
+ let match;
316
+ while ((match = serviceRegex.exec(response)) !== null) {
317
+ serviceMatches.push({ value: match[0], index: match.index });
318
+ }
319
+ // Then, collect all port numbers
320
+ const portMatches = [];
321
+ while ((match = portRegex.exec(response)) !== null) {
322
+ if (match[1]) {
323
+ // Ensure we have a captured port number
324
+ portMatches.push({ value: match[1], index: match.index });
325
+ }
326
+ }
327
+ // Sort both arrays by index to maintain order
328
+ serviceMatches.sort((a, b) => a.index - b.index);
329
+ portMatches.sort((a, b) => a.index - b.index);
330
+ // Log the extracted data for debugging
331
+ log.debug(`Found ${serviceMatches.length} services and ${portMatches.length} ports`);
332
+ // Create a mapping of services to ports
333
+ const services = [];
334
+ // Assign a port to each service based on proximity in the response
335
+ for (let i = 0; i < serviceMatches.length; i++) {
336
+ const serviceName = serviceMatches[i].value;
337
+ const serviceIndex = serviceMatches[i].index;
338
+ // Find the closest port after this service
339
+ let closestPort = '';
340
+ let closestDistance = Number.MAX_SAFE_INTEGER;
341
+ for (const portMatch of portMatches) {
342
+ // Only consider ports that come after the service in the response
343
+ if (portMatch.index > serviceIndex) {
344
+ const distance = portMatch.index - serviceIndex;
345
+ // If this port is closer than the current closest, update
346
+ if (distance < closestDistance) {
347
+ closestDistance = distance;
348
+ closestPort = portMatch.value;
349
+ // If the port is very close (within 200 chars), we can be confident it's the right one
350
+ if (distance < 200) {
351
+ break;
352
+ }
353
+ }
354
+ }
355
+ }
356
+ // Add the service with its port (or empty string if no port found)
357
+ services.push({
358
+ serviceName,
359
+ port: closestPort || '',
360
+ });
361
+ }
362
+ return { services };
363
+ }
364
+ export default RemoteXpcConnection;
365
+ export {};
@@ -0,0 +1,22 @@
1
+ import type { XPCDictionary } from '../types.js';
2
+ export declare const XPC_TYPES: {
3
+ [key: string]: number;
4
+ };
5
+ export interface XPCMessage {
6
+ flags: number;
7
+ id?: bigint | number;
8
+ body?: XPCDictionary | null;
9
+ size?: number;
10
+ }
11
+ /**
12
+ * Encodes a message object into an XPC Buffer.
13
+ * A message is an object like:
14
+ * { flags: Number, id: bigint, body: Object|null }
15
+ */
16
+ export declare function encodeMessage(message: XPCMessage): Buffer;
17
+ /**
18
+ * Decodes an XPC Buffer into a message object.
19
+ * (Keep this function if you plan to handle incoming messages.)
20
+ */
21
+ export declare function decodeMessage(buffer: Buffer): XPCMessage;
22
+ //# sourceMappingURL=xpc-protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xpc-protocol.d.ts","sourceRoot":"","sources":["../../../../src/lib/remote-xpc/xpc-protocol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAY,aAAa,EAAY,MAAM,aAAa,CAAC;AAOrE,eAAO,MAAM,SAAS,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAa9C,CAAC;AA4GF,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,CAkCzD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAoCxD"}