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,177 @@
1
+ import { Socket } from 'node:net';
2
+ import { BaseSocketService } from '../../base-socket-service.js';
3
+ import { type PairRecord } from '../pair-record/index.js';
4
+ /**
5
+ * Interface for device properties
6
+ */
7
+ export interface DeviceProperties {
8
+ ConnectionSpeed: number;
9
+ ConnectionType: string;
10
+ DeviceID: number;
11
+ LocationID: number;
12
+ ProductID: number;
13
+ SerialNumber: string;
14
+ USBSerialNumber: string;
15
+ }
16
+ /**
17
+ * Interface for a device
18
+ */
19
+ export interface Device {
20
+ DeviceID: number;
21
+ MessageType: string;
22
+ Properties: DeviceProperties;
23
+ }
24
+ export declare const USBMUXD_PORT = 27015;
25
+ export declare const DEFAULT_USBMUXD_SOCKET = "/var/run/usbmuxd";
26
+ export declare const DEFAULT_USBMUXD_HOST = "127.0.0.1";
27
+ export declare const MAX_FRAME_SIZE: number;
28
+ export declare const USBMUX_RESULT: {
29
+ OK: number;
30
+ BADCOMMAND: number;
31
+ BADDEV: number;
32
+ CONNREFUSED: number;
33
+ };
34
+ /**
35
+ * Function to swap bytes for a 16-bit value
36
+ * Used for usbmuxd port numbers
37
+ */
38
+ export declare function byteSwap16(value: number): number;
39
+ /**
40
+ * Socket options for connecting to usbmuxd
41
+ */
42
+ export interface SocketOptions {
43
+ socketPath?: string;
44
+ socketPort?: number;
45
+ socketHost?: string;
46
+ timeout?: number;
47
+ }
48
+ /**
49
+ * Connects a socket to usbmuxd service
50
+ * @param opts - Connection options
51
+ * @returns Promise that resolves with a socket connected to usbmuxd
52
+ */
53
+ export declare function getDefaultSocket(opts?: Partial<SocketOptions>): Promise<Socket>;
54
+ /**
55
+ * usbmux class for communicating with usbmuxd
56
+ */
57
+ export declare class Usbmux extends BaseSocketService {
58
+ private readonly _decoder;
59
+ private readonly _splitter;
60
+ private readonly _encoder;
61
+ private _tag;
62
+ private readonly _responseCallbacks;
63
+ /**
64
+ * Creates a new usbmux instance
65
+ * @param socketClient - Connected socket to usbmuxd
66
+ */
67
+ constructor(socketClient: Socket);
68
+ /**
69
+ * Returns the BUID of the host computer from usbmuxd
70
+ * @param timeout - Timeout in milliseconds
71
+ * @returns Promise that resolves with the BUID
72
+ */
73
+ readBUID(timeout?: number): Promise<string>;
74
+ /**
75
+ * Reads the pair record of a device, checking local cache first
76
+ * @param udid - Device UDID
77
+ * @param timeout - Timeout in milliseconds
78
+ * @returns Promise that resolves with the pair record or null if not found
79
+ */
80
+ readPairRecord(udid: string, timeout?: number): Promise<PairRecord | null>;
81
+ /**
82
+ * Lists all devices connected to the host
83
+ * @param timeout - Timeout in milliseconds
84
+ * @returns Promise that resolves with the device list
85
+ */
86
+ listDevices(timeout?: number): Promise<Device[]>;
87
+ /**
88
+ * Looks for a device with the passed udid
89
+ * @param udid - Device UDID
90
+ * @param timeout - Timeout in milliseconds
91
+ * @returns Promise that resolves with the device or undefined if not found
92
+ */
93
+ findDevice(udid: string, timeout?: number): Promise<Device | undefined>;
94
+ /**
95
+ * Connects to a certain port on the device
96
+ * @param deviceID - Device ID
97
+ * @param port - Port to connect to
98
+ * @param timeout - Timeout in milliseconds
99
+ * @returns Promise that resolves with the connected socket
100
+ */
101
+ connect(deviceID: string | number, port: number, timeout?: number): Promise<Socket>;
102
+ /**
103
+ * Closes the current USBMUX connection gracefully.
104
+ * For non-tunnel commands, call this after the operation is complete.
105
+ * For Connect commands (which consume the connection),
106
+ * the caller is responsible for closing the returned socket.
107
+ *
108
+ * @returns Promise that resolves when the socket is closed.
109
+ */
110
+ close(): Promise<void>;
111
+ /**
112
+ * Handles incoming data from the decoder
113
+ * @param data - Decoded data
114
+ * @private
115
+ */
116
+ private _handleData;
117
+ /**
118
+ * Sends a plist to usbmuxd
119
+ * @param json - JSON object with tag and payload
120
+ * @private
121
+ */
122
+ private _sendPlist;
123
+ /**
124
+ * Sets up a promise to receive and process a plist response
125
+ * @param timeout - Timeout in milliseconds
126
+ * @param responseCallback - Callback to process the response
127
+ * @returns Object with tag and promise
128
+ * @private
129
+ */
130
+ private _receivePlistPromise;
131
+ }
132
+ /**
133
+ * Creates a new usbmux instance
134
+ * @param opts - Socket options
135
+ * @returns Promise that resolves with a usbmux instance
136
+ */
137
+ export declare function createUsbmux(opts?: Partial<SocketOptions>): Promise<Usbmux>;
138
+ /**
139
+ * RelayService class for tunneling connections through a local TCP server
140
+ */
141
+ export declare class RelayService {
142
+ private readonly deviceID;
143
+ private readonly devicePort;
144
+ private readonly relayPort;
145
+ private usbmuxClient;
146
+ private server;
147
+ /**
148
+ * Creates a new RelayService instance
149
+ * @param deviceID - The device ID to connect to
150
+ * @param devicePort - The port on the device to connect to
151
+ * @param relayPort - The local port to use for the relay server
152
+ */
153
+ constructor(deviceID: string | number, devicePort: number, relayPort?: number);
154
+ /**
155
+ * Starts the relay service
156
+ * @returns Promise that resolves when the relay is set up
157
+ */
158
+ start(): Promise<void>;
159
+ /**
160
+ * Connects to the relay service
161
+ * @returns Promise that resolves with a socket connected to the relay
162
+ */
163
+ connect(): Promise<Socket>;
164
+ /**
165
+ * Stops the relay service
166
+ */
167
+ stop(): Promise<void>;
168
+ }
169
+ /**
170
+ * Connects to a device and sets up a relay service in one operation
171
+ * @param deviceID - The device ID to connect to
172
+ * @param port - The port on the device to connect to
173
+ * @param relayPort - The local port to use for the relay server
174
+ * @returns Promise that resolves with a connected socket
175
+ */
176
+ export declare function connectAndRelay(deviceID: string | number, port: number, relayPort?: number): Promise<Socket>;
177
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/usbmux/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,490 @@
1
+ import { logger } from '@appium/support';
2
+ import { Server, Socket, createConnection, createServer } from 'node:net';
3
+ import { release } from 'node:os';
4
+ import { BaseSocketService } from '../../base-socket-service.js';
5
+ import { processPlistResponse } from '../pair-record/index.js';
6
+ import {} from '../pair-record/pair-record.js';
7
+ import { LengthBasedSplitter, parsePlist } from '../plist/index.js';
8
+ import { UsbmuxDecoder } from '../usbmux/usbmux-decoder.js';
9
+ import { UsbmuxEncoder } from '../usbmux/usbmux-encoder.js';
10
+ const log = logger.getLogger('Usbmux');
11
+ export const USBMUXD_PORT = 27015;
12
+ export const DEFAULT_USBMUXD_SOCKET = '/var/run/usbmuxd';
13
+ export const DEFAULT_USBMUXD_HOST = '127.0.0.1';
14
+ export const MAX_FRAME_SIZE = 100 * 1024 * 1024; // 1MB
15
+ // Result codes from usbmuxd
16
+ export const USBMUX_RESULT = {
17
+ OK: 0,
18
+ BADCOMMAND: 1,
19
+ BADDEV: 2,
20
+ CONNREFUSED: 3,
21
+ };
22
+ // Package info for client identification
23
+ const PROG_NAME = 'appium-internal';
24
+ const CLIENT_VERSION_STRING = 'appium-internal-1.0.0';
25
+ /**
26
+ * Function to swap bytes for a 16-bit value
27
+ * Used for usbmuxd port numbers
28
+ */
29
+ export function byteSwap16(value) {
30
+ return ((value & 0xff) << 8) | ((value >> 8) & 0xff);
31
+ }
32
+ /**
33
+ * Helper function to check if a file exists
34
+ * @param path - Path to check
35
+ * @returns Boolean indicating if the file exists
36
+ */
37
+ async function fileExists(path) {
38
+ try {
39
+ await import('fs').then((fs) => fs.promises.access(path));
40
+ return true;
41
+ }
42
+ catch {
43
+ return false;
44
+ }
45
+ }
46
+ /**
47
+ * Connects a socket to usbmuxd service
48
+ * @param opts - Connection options
49
+ * @returns Promise that resolves with a socket connected to usbmuxd
50
+ */
51
+ export async function getDefaultSocket(opts = {}) {
52
+ const defaults = {
53
+ socketPath: DEFAULT_USBMUXD_SOCKET,
54
+ socketPort: USBMUXD_PORT,
55
+ socketHost: DEFAULT_USBMUXD_HOST,
56
+ timeout: 5000,
57
+ };
58
+ if (process.env.USBMUXD_SOCKET_ADDRESS &&
59
+ !opts.socketPath &&
60
+ !opts.socketPort &&
61
+ !opts.socketHost) {
62
+ log.debug(`Using USBMUXD_SOCKET_ADDRESS environment variable as default socket: ${process.env.USBMUXD_SOCKET_ADDRESS}`);
63
+ // "unix:" or "UNIX:" prefix is optional for unix socket paths.
64
+ const usbmuxdSocketAddress = process.env.USBMUXD_SOCKET_ADDRESS.replace(/^(unix):/i, '');
65
+ const [ip, port] = usbmuxdSocketAddress.split(':');
66
+ if (ip && port) {
67
+ defaults.socketHost = ip;
68
+ defaults.socketPort = parseInt(port, 10);
69
+ }
70
+ else {
71
+ defaults.socketPath = usbmuxdSocketAddress;
72
+ }
73
+ }
74
+ const { socketPath, socketPort, socketHost, timeout } = {
75
+ ...defaults,
76
+ ...opts,
77
+ };
78
+ let socket;
79
+ if (await fileExists(socketPath ?? '')) {
80
+ socket = createConnection(socketPath ?? '');
81
+ }
82
+ else if (process.platform === 'win32' ||
83
+ (process.platform === 'linux' && /microsoft/i.test(release()))) {
84
+ // Connect to usbmuxd when running on WSL1
85
+ socket = createConnection({
86
+ port: socketPort,
87
+ host: socketHost,
88
+ });
89
+ }
90
+ else {
91
+ throw new Error(`The usbmuxd socket at '${socketPath}' does not exist or is not accessible`);
92
+ }
93
+ return await new Promise((resolve, reject) => {
94
+ const timeoutId = setTimeout(() => {
95
+ socket.removeAllListeners();
96
+ reject(new Error(`Connection timed out after ${timeout}ms`));
97
+ }, timeout ?? 5000);
98
+ socket.once('error', (err) => {
99
+ clearTimeout(timeoutId);
100
+ reject(err);
101
+ });
102
+ socket.once('connect', () => {
103
+ clearTimeout(timeoutId);
104
+ resolve(socket);
105
+ });
106
+ });
107
+ }
108
+ /**
109
+ * usbmux class for communicating with usbmuxd
110
+ */
111
+ export class Usbmux extends BaseSocketService {
112
+ _decoder;
113
+ _splitter;
114
+ _encoder;
115
+ _tag;
116
+ _responseCallbacks;
117
+ /**
118
+ * Creates a new usbmux instance
119
+ * @param socketClient - Connected socket to usbmuxd
120
+ */
121
+ constructor(socketClient) {
122
+ super(socketClient);
123
+ this._decoder = new UsbmuxDecoder();
124
+ this._splitter = new LengthBasedSplitter({
125
+ readableStream: socketClient,
126
+ littleEndian: true,
127
+ maxFrameLength: MAX_FRAME_SIZE,
128
+ lengthFieldOffset: 0,
129
+ lengthFieldLength: 4,
130
+ lengthAdjustment: 0,
131
+ });
132
+ this._socketClient.pipe(this._decoder);
133
+ this._encoder = new UsbmuxEncoder();
134
+ this._encoder.pipe(this._socketClient);
135
+ this._assignClientFailureHandlers(this._encoder);
136
+ this._tag = 0;
137
+ this._responseCallbacks = {};
138
+ this._decoder.on('data', this._handleData.bind(this));
139
+ }
140
+ /**
141
+ * Returns the BUID of the host computer from usbmuxd
142
+ * @param timeout - Timeout in milliseconds
143
+ * @returns Promise that resolves with the BUID
144
+ */
145
+ async readBUID(timeout = 5000) {
146
+ const { tag, receivePromise } = this._receivePlistPromise(timeout, (data) => {
147
+ if (data.payload.BUID) {
148
+ return data.payload.BUID;
149
+ }
150
+ throw new Error(`Unexpected data: ${JSON.stringify(data)}`);
151
+ });
152
+ this._sendPlist({
153
+ tag,
154
+ payload: {
155
+ MessageType: 'ReadBUID',
156
+ ProgName: PROG_NAME,
157
+ ClientVersionString: CLIENT_VERSION_STRING,
158
+ },
159
+ });
160
+ return await receivePromise;
161
+ }
162
+ /**
163
+ * Reads the pair record of a device, checking local cache first
164
+ * @param udid - Device UDID
165
+ * @param timeout - Timeout in milliseconds
166
+ * @returns Promise that resolves with the pair record or null if not found
167
+ */
168
+ async readPairRecord(udid, timeout = 5000) {
169
+ // Request from usbmuxd if not found in cache
170
+ const { tag, receivePromise } = this._receivePlistPromise(timeout, (data) => {
171
+ if (!data.payload.PairRecordData) {
172
+ return null;
173
+ }
174
+ try {
175
+ // Parse the pair record and assert the type
176
+ return processPlistResponse(parsePlist(data.payload.PairRecordData));
177
+ }
178
+ catch (e) {
179
+ throw new Error(`Failed to parse pair record data: ${e}`);
180
+ }
181
+ });
182
+ this._sendPlist({
183
+ tag,
184
+ payload: {
185
+ MessageType: 'ReadPairRecord',
186
+ PairRecordID: udid,
187
+ ProgName: PROG_NAME,
188
+ ClientVersionString: CLIENT_VERSION_STRING,
189
+ },
190
+ });
191
+ return await receivePromise;
192
+ }
193
+ /**
194
+ * Lists all devices connected to the host
195
+ * @param timeout - Timeout in milliseconds
196
+ * @returns Promise that resolves with the device list
197
+ */
198
+ async listDevices(timeout = 5000) {
199
+ const { tag, receivePromise } = this._receivePlistPromise(timeout, (data) => {
200
+ if (data.payload.DeviceList) {
201
+ return data.payload.DeviceList;
202
+ }
203
+ throw new Error(`Unexpected data: ${JSON.stringify(data)}`);
204
+ });
205
+ this._sendPlist({
206
+ tag,
207
+ payload: {
208
+ MessageType: 'ListDevices',
209
+ ProgName: PROG_NAME,
210
+ ClientVersionString: CLIENT_VERSION_STRING,
211
+ },
212
+ });
213
+ return await receivePromise;
214
+ }
215
+ /**
216
+ * Looks for a device with the passed udid
217
+ * @param udid - Device UDID
218
+ * @param timeout - Timeout in milliseconds
219
+ * @returns Promise that resolves with the device or undefined if not found
220
+ */
221
+ async findDevice(udid, timeout = 5000) {
222
+ const devices = await this.listDevices(timeout);
223
+ return devices.find((device) => device.Properties.SerialNumber === udid);
224
+ }
225
+ /**
226
+ * Connects to a certain port on the device
227
+ * @param deviceID - Device ID
228
+ * @param port - Port to connect to
229
+ * @param timeout - Timeout in milliseconds
230
+ * @returns Promise that resolves with the connected socket
231
+ */
232
+ async connect(deviceID, port, timeout = 5000) {
233
+ const { tag, receivePromise } = this._receivePlistPromise(timeout, (data) => {
234
+ if (data.payload.MessageType !== 'Result') {
235
+ throw new Error(`Unexpected data: ${JSON.stringify(data)}`);
236
+ }
237
+ if (data.payload.Number === USBMUX_RESULT.OK) {
238
+ this._splitter.shutdown();
239
+ this._socketClient.unpipe(this._splitter);
240
+ this._splitter.unpipe(this._decoder);
241
+ return this._socketClient;
242
+ }
243
+ else if (data.payload.Number === USBMUX_RESULT.CONNREFUSED) {
244
+ throw new Error(`Connection was refused to port ${port}`);
245
+ }
246
+ else {
247
+ throw new Error(`Connection failed with code ${data.payload.Number}`);
248
+ }
249
+ });
250
+ this._sendPlist({
251
+ tag,
252
+ payload: {
253
+ MessageType: 'Connect',
254
+ ProgName: PROG_NAME,
255
+ ClientVersionString: CLIENT_VERSION_STRING,
256
+ DeviceID: deviceID,
257
+ PortNumber: byteSwap16(port),
258
+ },
259
+ });
260
+ return await receivePromise;
261
+ }
262
+ /**
263
+ * Closes the current USBMUX connection gracefully.
264
+ * For non-tunnel commands, call this after the operation is complete.
265
+ * For Connect commands (which consume the connection),
266
+ * the caller is responsible for closing the returned socket.
267
+ *
268
+ * @returns Promise that resolves when the socket is closed.
269
+ */
270
+ close() {
271
+ return new Promise((resolve, reject) => {
272
+ // If the socket is still open, end it gracefully.
273
+ if (!this._socketClient.destroyed) {
274
+ // End the connection and then destroy it once closed.
275
+ this._socketClient.end((err) => {
276
+ if (err) {
277
+ log.error(`Error closing usbmux socket: ${err}`);
278
+ this._socketClient.destroy();
279
+ reject(err);
280
+ }
281
+ else {
282
+ this._socketClient.destroy();
283
+ resolve();
284
+ }
285
+ });
286
+ }
287
+ else {
288
+ resolve();
289
+ }
290
+ });
291
+ }
292
+ /**
293
+ * Handles incoming data from the decoder
294
+ * @param data - Decoded data
295
+ * @private
296
+ */
297
+ _handleData(data) {
298
+ const cb = this._responseCallbacks[data.header.tag];
299
+ if (cb) {
300
+ cb(data);
301
+ }
302
+ }
303
+ /**
304
+ * Sends a plist to usbmuxd
305
+ * @param json - JSON object with tag and payload
306
+ * @private
307
+ */
308
+ _sendPlist(json) {
309
+ this._encoder.write(json);
310
+ }
311
+ /**
312
+ * Sets up a promise to receive and process a plist response
313
+ * @param timeout - Timeout in milliseconds
314
+ * @param responseCallback - Callback to process the response
315
+ * @returns Object with tag and promise
316
+ * @private
317
+ */
318
+ _receivePlistPromise(timeout = 5000, responseCallback) {
319
+ const tag = this._tag++;
320
+ let timeoutId;
321
+ const receivePromise = new Promise((resolve, reject) => {
322
+ this._responseCallbacks[tag] = (data) => {
323
+ try {
324
+ // Clear the timeout to prevent it from triggering
325
+ if (timeoutId) {
326
+ clearTimeout(timeoutId);
327
+ }
328
+ // Process the response
329
+ resolve(responseCallback(data));
330
+ }
331
+ catch (e) {
332
+ reject(e);
333
+ }
334
+ finally {
335
+ delete this._responseCallbacks[tag];
336
+ }
337
+ };
338
+ // Set the timeout handler
339
+ timeoutId = setTimeout(() => {
340
+ if (this._responseCallbacks[tag]) {
341
+ delete this._responseCallbacks[tag];
342
+ log.warn(`Timeout waiting for response with tag ${tag} after ${timeout}ms`);
343
+ reject(new Error(`Failed to receive any data within the timeout: ${timeout}ms - The device might be busy or unresponsive`));
344
+ }
345
+ }, timeout);
346
+ });
347
+ // Add cleanup handler when promise is settled
348
+ receivePromise
349
+ .catch(() => { })
350
+ .finally(() => {
351
+ if (this._responseCallbacks[tag]) {
352
+ delete this._responseCallbacks[tag];
353
+ }
354
+ });
355
+ return { tag, receivePromise };
356
+ }
357
+ }
358
+ /**
359
+ * Creates a new usbmux instance
360
+ * @param opts - Socket options
361
+ * @returns Promise that resolves with a usbmux instance
362
+ */
363
+ export async function createUsbmux(opts = {}) {
364
+ const socket = await getDefaultSocket(opts);
365
+ return new Usbmux(socket);
366
+ }
367
+ /**
368
+ * RelayService class for tunneling connections through a local TCP server
369
+ */
370
+ export class RelayService {
371
+ deviceID;
372
+ devicePort;
373
+ relayPort;
374
+ usbmuxClient;
375
+ server;
376
+ /**
377
+ * Creates a new RelayService instance
378
+ * @param deviceID - The device ID to connect to
379
+ * @param devicePort - The port on the device to connect to
380
+ * @param relayPort - The local port to use for the relay server
381
+ */
382
+ constructor(deviceID, devicePort, relayPort = 2222) {
383
+ this.deviceID = deviceID;
384
+ this.devicePort = devicePort;
385
+ this.relayPort = relayPort;
386
+ this.usbmuxClient = null;
387
+ this.server = null;
388
+ }
389
+ /**
390
+ * Starts the relay service
391
+ * @returns Promise that resolves when the relay is set up
392
+ */
393
+ async start() {
394
+ log.info(`Starting relay to device ${this.deviceID} on port ${this.devicePort}...`);
395
+ // Create a usbmux instance and connect to the device
396
+ const usbmux = await createUsbmux();
397
+ this.usbmuxClient = await usbmux.connect(this.deviceID, this.devicePort);
398
+ // Set up the relay server
399
+ this.server = createServer((localSocket) => {
400
+ log.debug('🔌 Local client connected to relay!');
401
+ // Set up the bidirectional pipe between local socket and usbmux connection
402
+ if (this.usbmuxClient) {
403
+ localSocket.pipe(this.usbmuxClient).pipe(localSocket);
404
+ }
405
+ // Handle socket events
406
+ localSocket.on('close', () => {
407
+ log.debug('Local connection closed (tunnel remains open).');
408
+ });
409
+ localSocket.on('error', (err) => {
410
+ log.error(`Local socket error: ${err}`);
411
+ });
412
+ });
413
+ // Start the server
414
+ await new Promise((resolve, reject) => {
415
+ if (!this.server) {
416
+ return reject(new Error('Server not initialized'));
417
+ }
418
+ this.server.listen(this.relayPort, () => {
419
+ log.info(`Relay server running on localhost:${this.relayPort}`);
420
+ resolve();
421
+ });
422
+ this.server.on('error', (err) => {
423
+ reject(err);
424
+ });
425
+ });
426
+ }
427
+ /**
428
+ * Connects to the relay service
429
+ * @returns Promise that resolves with a socket connected to the relay
430
+ */
431
+ async connect() {
432
+ return new Promise((resolve, reject) => {
433
+ const socket = createConnection({ host: '127.0.0.1', port: this.relayPort }, () => {
434
+ log.debug('Connected to service via local relay.');
435
+ resolve(socket);
436
+ });
437
+ socket.on('error', (err) => {
438
+ reject(err);
439
+ });
440
+ });
441
+ }
442
+ /**
443
+ * Stops the relay service
444
+ */
445
+ async stop() {
446
+ return new Promise((resolve, reject) => {
447
+ if (this.server) {
448
+ this.server.close((err) => {
449
+ if (err) {
450
+ log.error(`Error stopping relay server: ${err}`);
451
+ reject(err);
452
+ }
453
+ else {
454
+ log.info('Relay server stopped');
455
+ resolve();
456
+ }
457
+ });
458
+ }
459
+ else {
460
+ resolve();
461
+ }
462
+ });
463
+ }
464
+ }
465
+ /**
466
+ * Connects to a device and sets up a relay service in one operation
467
+ * @param deviceID - The device ID to connect to
468
+ * @param port - The port on the device to connect to
469
+ * @param relayPort - The local port to use for the relay server
470
+ * @returns Promise that resolves with a connected socket
471
+ */
472
+ export async function connectAndRelay(deviceID, port, relayPort = 2222) {
473
+ // Create and start the relay service
474
+ const relay = new RelayService(deviceID, port, relayPort);
475
+ let socket;
476
+ try {
477
+ // Start the relay
478
+ await relay.start();
479
+ // Connect to the relay
480
+ socket = await relay.connect();
481
+ return socket;
482
+ }
483
+ finally {
484
+ if (!socket) {
485
+ await relay
486
+ .stop()
487
+ .catch((err) => log.error(`Error stopping relay: ${err}`));
488
+ }
489
+ }
490
+ }
@@ -0,0 +1,19 @@
1
+ import { Transform, type TransformCallback } from 'stream';
2
+ import type { PlistDictionary } from '../types.js';
3
+ export interface UsbmuxHeader {
4
+ length: number;
5
+ version: number;
6
+ type: number;
7
+ tag: number;
8
+ }
9
+ export interface DecodedUsbmux {
10
+ header: UsbmuxHeader;
11
+ payload: PlistDictionary;
12
+ }
13
+ export declare class UsbmuxDecoder extends Transform {
14
+ private _buffer;
15
+ constructor();
16
+ _transform(chunk: Buffer, encoding: BufferEncoding, callback: TransformCallback): void;
17
+ private _decode;
18
+ }
19
+ //# sourceMappingURL=usbmux-decoder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usbmux-decoder.d.ts","sourceRoot":"","sources":["../../../../src/lib/usbmux/usbmux-decoder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAG3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAInD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,eAAe,CAAC;CAC1B;AAED,qBAAa,aAAc,SAAQ,SAAS;IAC1C,OAAO,CAAC,OAAO,CAA2B;;IAM1C,UAAU,CACR,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,iBAAiB,GAC1B,IAAI;IAwBP,OAAO,CAAC,OAAO;CAWhB"}