appium-ios-remotexpc 0.9.0 → 0.10.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.
- package/CHANGELOG.md +6 -0
- package/README.md +1 -0
- package/build/src/services/index.d.ts +2 -1
- package/build/src/services/index.d.ts.map +1 -1
- package/build/src/services/index.js +2 -1
- package/build/src/services/ios/afc/codec.d.ts +46 -0
- package/build/src/services/ios/afc/codec.d.ts.map +1 -0
- package/build/src/services/ios/afc/codec.js +263 -0
- package/build/src/services/ios/afc/constants.d.ts +11 -0
- package/build/src/services/ios/afc/constants.d.ts.map +1 -0
- package/build/src/services/ios/afc/constants.js +22 -0
- package/build/src/services/ios/afc/enums.d.ts +66 -0
- package/build/src/services/ios/afc/enums.d.ts.map +1 -0
- package/build/src/services/ios/afc/enums.js +70 -0
- package/build/src/services/ios/afc/index.d.ts +72 -0
- package/build/src/services/ios/afc/index.d.ts.map +1 -0
- package/build/src/services/ios/afc/index.js +385 -0
- package/build/src/services/ios/afc/stream-utils.d.ts +14 -0
- package/build/src/services/ios/afc/stream-utils.d.ts.map +1 -0
- package/build/src/services/ios/afc/stream-utils.js +60 -0
- package/build/src/services.d.ts +6 -0
- package/build/src/services.d.ts.map +1 -1
- package/build/src/services.js +13 -0
- package/package.json +2 -1
- package/src/services/index.ts +2 -0
- package/src/services/ios/afc/codec.ts +365 -0
- package/src/services/ios/afc/constants.ts +29 -0
- package/src/services/ios/afc/enums.ts +70 -0
- package/src/services/ios/afc/index.ts +511 -0
- package/src/services/ios/afc/stream-utils.ts +102 -0
- package/src/services.ts +15 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## [0.10.0](https://github.com/appium/appium-ios-remotexpc/compare/v0.9.0...v0.10.0) (2025-10-27)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* **afc:** add Apple File Conduit (AFC) service implementation ([#84](https://github.com/appium/appium-ios-remotexpc/issues/84)) ([07306c6](https://github.com/appium/appium-ios-remotexpc/commit/07306c611756c206ac07fed6917c70bfc9032757))
|
|
6
|
+
|
|
1
7
|
## [0.9.0](https://github.com/appium/appium-ios-remotexpc/compare/v0.8.0...v0.9.0) (2025-10-27)
|
|
2
8
|
|
|
3
9
|
### Features
|
package/README.md
CHANGED
|
@@ -38,6 +38,7 @@ npm install appium-ios-remotexpc
|
|
|
38
38
|
- System Log Service: Access device logs
|
|
39
39
|
- Tunnel Service: Network tunneling to/from iOS devices
|
|
40
40
|
- Diagnostic Service: Device diagnostics
|
|
41
|
+
- AFC Service: File system operations on iOS devices
|
|
41
42
|
- **Pair Record Management**: Read and write device pairing records.
|
|
42
43
|
- **Packet Streaming**: Stream packets between host and device for service communication.
|
|
43
44
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { TunnelRegistryServer, startTunnelRegistryServer } from '../lib/tunnel/tunnel-registry-server.js';
|
|
2
|
+
import * as afc from './ios/afc/index.js';
|
|
2
3
|
import * as diagnostics from './ios/diagnostic-service/index.js';
|
|
3
4
|
import * as mobileImageMounter from './ios/mobile-image-mounter/index.js';
|
|
4
5
|
import * as powerAssertion from './ios/power-assertion/index.js';
|
|
5
6
|
import * as syslog from './ios/syslog-service/index.js';
|
|
6
7
|
import * as tunnel from './ios/tunnel-service/index.js';
|
|
7
8
|
import * as webinspector from './ios/webinspector/index.js';
|
|
8
|
-
export { diagnostics, mobileImageMounter, powerAssertion, syslog, tunnel, webinspector, TunnelRegistryServer, startTunnelRegistryServer, };
|
|
9
|
+
export { diagnostics, mobileImageMounter, powerAssertion, syslog, tunnel, afc, webinspector, TunnelRegistryServer, startTunnelRegistryServer, };
|
|
9
10
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,yBAAyB,EAC1B,MAAM,yCAAyC,CAAC;AACjD,OAAO,KAAK,WAAW,MAAM,mCAAmC,CAAC;AACjE,OAAO,KAAK,kBAAkB,MAAM,qCAAqC,CAAC;AAC1E,OAAO,KAAK,cAAc,MAAM,gCAAgC,CAAC;AACjE,OAAO,KAAK,MAAM,MAAM,+BAA+B,CAAC;AACxD,OAAO,KAAK,MAAM,MAAM,+BAA+B,CAAC;AACxD,OAAO,KAAK,YAAY,MAAM,6BAA6B,CAAC;AAE5D,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,cAAc,EACd,MAAM,EACN,MAAM,EACN,YAAY,EACZ,oBAAoB,EACpB,yBAAyB,GAC1B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,yBAAyB,EAC1B,MAAM,yCAAyC,CAAC;AACjD,OAAO,KAAK,GAAG,MAAM,oBAAoB,CAAC;AAC1C,OAAO,KAAK,WAAW,MAAM,mCAAmC,CAAC;AACjE,OAAO,KAAK,kBAAkB,MAAM,qCAAqC,CAAC;AAC1E,OAAO,KAAK,cAAc,MAAM,gCAAgC,CAAC;AACjE,OAAO,KAAK,MAAM,MAAM,+BAA+B,CAAC;AACxD,OAAO,KAAK,MAAM,MAAM,+BAA+B,CAAC;AACxD,OAAO,KAAK,YAAY,MAAM,6BAA6B,CAAC;AAE5D,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,cAAc,EACd,MAAM,EACN,MAAM,EACN,GAAG,EACH,YAAY,EACZ,oBAAoB,EACpB,yBAAyB,GAC1B,CAAC"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { TunnelRegistryServer, startTunnelRegistryServer, } from '../lib/tunnel/tunnel-registry-server.js';
|
|
2
|
+
import * as afc from './ios/afc/index.js';
|
|
2
3
|
import * as diagnostics from './ios/diagnostic-service/index.js';
|
|
3
4
|
import * as mobileImageMounter from './ios/mobile-image-mounter/index.js';
|
|
4
5
|
import * as powerAssertion from './ios/power-assertion/index.js';
|
|
5
6
|
import * as syslog from './ios/syslog-service/index.js';
|
|
6
7
|
import * as tunnel from './ios/tunnel-service/index.js';
|
|
7
8
|
import * as webinspector from './ios/webinspector/index.js';
|
|
8
|
-
export { diagnostics, mobileImageMounter, powerAssertion, syslog, tunnel, webinspector, TunnelRegistryServer, startTunnelRegistryServer, };
|
|
9
|
+
export { diagnostics, mobileImageMounter, powerAssertion, syslog, tunnel, afc, webinspector, TunnelRegistryServer, startTunnelRegistryServer, };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import net from 'node:net';
|
|
2
|
+
import { AfcError, AfcFopenMode, AfcOpcode } from './enums.js';
|
|
3
|
+
export interface AfcHeader {
|
|
4
|
+
magic: Buffer;
|
|
5
|
+
entireLength: bigint;
|
|
6
|
+
thisLength: bigint;
|
|
7
|
+
packetNum: bigint;
|
|
8
|
+
operation: bigint;
|
|
9
|
+
}
|
|
10
|
+
export interface AfcResponse {
|
|
11
|
+
status: AfcError;
|
|
12
|
+
data: Buffer;
|
|
13
|
+
operation: AfcOpcode;
|
|
14
|
+
rawHeader: AfcHeader;
|
|
15
|
+
}
|
|
16
|
+
export declare function writeUInt64LE(value: bigint | number): Buffer;
|
|
17
|
+
export declare function readUInt64LE(buf: Buffer, offset?: number): bigint;
|
|
18
|
+
export declare function cstr(str: string): Buffer;
|
|
19
|
+
export declare function encodeHeader(op: AfcOpcode, packetNum: bigint, payloadLen: number, thisLenOverride?: number): Buffer;
|
|
20
|
+
export declare function readExact(socket: net.Socket, n: number, timeoutMs?: number): Promise<Buffer>;
|
|
21
|
+
export declare function readAfcHeader(socket: net.Socket): Promise<AfcHeader>;
|
|
22
|
+
export declare function readAfcResponse(socket: net.Socket): Promise<AfcResponse>;
|
|
23
|
+
export declare function sendAfcPacket(socket: net.Socket, op: AfcOpcode, packetNum: bigint, payload?: Buffer, thisLenOverride?: number): Promise<void>;
|
|
24
|
+
export declare function parseCStringArray(buf: Buffer): string[];
|
|
25
|
+
export declare function parseKeyValueNullList(buf: Buffer): Record<string, string>;
|
|
26
|
+
export declare function buildFopenPayload(mode: AfcFopenMode, path: string): Buffer;
|
|
27
|
+
export declare function buildReadPayload(handle: bigint | number, size: bigint | number): Buffer;
|
|
28
|
+
export declare function buildClosePayload(handle: bigint | number): Buffer;
|
|
29
|
+
export declare function buildRemovePayload(path: string): Buffer;
|
|
30
|
+
export declare function buildMkdirPayload(path: string): Buffer;
|
|
31
|
+
export declare function buildStatPayload(path: string): Buffer;
|
|
32
|
+
export declare function buildRenamePayload(src: string, dst: string): Buffer;
|
|
33
|
+
export declare function buildLinkPayload(type: number, target: string, source: string): Buffer;
|
|
34
|
+
/**
|
|
35
|
+
* Receive a single length-prefixed plist from the socket
|
|
36
|
+
*/
|
|
37
|
+
export declare function recvOnePlist(socket: net.Socket): Promise<any>;
|
|
38
|
+
export declare function rsdHandshakeForRawService(socket: net.Socket): Promise<void>;
|
|
39
|
+
export declare function nextReadChunkSize(left: bigint | number): number;
|
|
40
|
+
/**
|
|
41
|
+
* Convert nanoseconds to milliseconds for Date construction
|
|
42
|
+
* @param nanoseconds - Time value in nanoseconds as a string
|
|
43
|
+
* @returns Time value in milliseconds
|
|
44
|
+
*/
|
|
45
|
+
export declare function nanosecondsToMilliseconds(nanoseconds: string): number;
|
|
46
|
+
//# sourceMappingURL=codec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codec.d.ts","sourceRoot":"","sources":["../../../../../src/services/ios/afc/codec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import net from 'node:net';
|
|
2
|
+
import { createPlist } from '../../../lib/plist/plist-creator.js';
|
|
3
|
+
import { parsePlist } from '../../../lib/plist/unified-plist-parser.js';
|
|
4
|
+
import { AFCMAGIC, AFC_HEADER_SIZE, NULL_BYTE } from './constants.js';
|
|
5
|
+
import { AfcError, AfcFopenMode, AfcOpcode } from './enums.js';
|
|
6
|
+
export function writeUInt64LE(value) {
|
|
7
|
+
const buf = Buffer.alloc(8);
|
|
8
|
+
buf.writeBigUInt64LE(BigInt(value), 0);
|
|
9
|
+
return buf;
|
|
10
|
+
}
|
|
11
|
+
export function readUInt64LE(buf, offset = 0) {
|
|
12
|
+
return buf.readBigUInt64LE(offset);
|
|
13
|
+
}
|
|
14
|
+
export function cstr(str) {
|
|
15
|
+
const s = Buffer.from(str, 'utf8');
|
|
16
|
+
return Buffer.concat([s, NULL_BYTE]);
|
|
17
|
+
}
|
|
18
|
+
export function encodeHeader(op, packetNum, payloadLen, thisLenOverride) {
|
|
19
|
+
const entireLen = BigInt(AFC_HEADER_SIZE + payloadLen);
|
|
20
|
+
const thisLen = BigInt(thisLenOverride ?? AFC_HEADER_SIZE + payloadLen);
|
|
21
|
+
const header = Buffer.alloc(AFC_HEADER_SIZE);
|
|
22
|
+
// magic
|
|
23
|
+
AFCMAGIC.copy(header, 0);
|
|
24
|
+
// entire_length
|
|
25
|
+
writeUInt64LE(entireLen).copy(header, 8);
|
|
26
|
+
// this_length
|
|
27
|
+
writeUInt64LE(thisLen).copy(header, 16);
|
|
28
|
+
// packet_num
|
|
29
|
+
writeUInt64LE(packetNum).copy(header, 24);
|
|
30
|
+
// operation
|
|
31
|
+
writeUInt64LE(BigInt(op)).copy(header, 32);
|
|
32
|
+
return header;
|
|
33
|
+
}
|
|
34
|
+
const SOCKET_STATES = new WeakMap();
|
|
35
|
+
function cleanupSocketState(socket, error) {
|
|
36
|
+
const state = SOCKET_STATES.get(socket);
|
|
37
|
+
if (!state) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
// Remove all event listeners to prevent memory leaks
|
|
41
|
+
socket.removeListener('data', state.onData);
|
|
42
|
+
socket.removeListener('error', state.onError);
|
|
43
|
+
socket.removeListener('close', state.onClose);
|
|
44
|
+
socket.removeListener('end', state.onClose);
|
|
45
|
+
// Reject any pending waiters
|
|
46
|
+
const err = error || new Error('Socket closed');
|
|
47
|
+
while (state.waiters.length) {
|
|
48
|
+
const w = state.waiters.shift();
|
|
49
|
+
if (w.timer) {
|
|
50
|
+
clearTimeout(w.timer);
|
|
51
|
+
}
|
|
52
|
+
w.reject(err);
|
|
53
|
+
}
|
|
54
|
+
// Remove from WeakMap
|
|
55
|
+
SOCKET_STATES.delete(socket);
|
|
56
|
+
}
|
|
57
|
+
function ensureSocketState(socket) {
|
|
58
|
+
let state = SOCKET_STATES.get(socket);
|
|
59
|
+
if (state) {
|
|
60
|
+
return state;
|
|
61
|
+
}
|
|
62
|
+
state = {
|
|
63
|
+
buffer: Buffer.alloc(0),
|
|
64
|
+
waiters: [],
|
|
65
|
+
onData: (chunk) => {
|
|
66
|
+
const st = SOCKET_STATES.get(socket);
|
|
67
|
+
if (!st) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
st.buffer = Buffer.concat([st.buffer, chunk]);
|
|
71
|
+
while (st.waiters.length && st.buffer.length >= st.waiters[0].n) {
|
|
72
|
+
const w = st.waiters.shift();
|
|
73
|
+
const out = st.buffer.subarray(0, w.n);
|
|
74
|
+
st.buffer = st.buffer.subarray(w.n);
|
|
75
|
+
if (w.timer) {
|
|
76
|
+
clearTimeout(w.timer);
|
|
77
|
+
}
|
|
78
|
+
w.resolve(out);
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
onError: (err) => {
|
|
82
|
+
cleanupSocketState(socket, err);
|
|
83
|
+
},
|
|
84
|
+
onClose: () => {
|
|
85
|
+
cleanupSocketState(socket);
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
socket.on('data', state.onData);
|
|
89
|
+
socket.once('error', state.onError);
|
|
90
|
+
socket.once('close', state.onClose);
|
|
91
|
+
socket.once('end', state.onClose);
|
|
92
|
+
SOCKET_STATES.set(socket, state);
|
|
93
|
+
return state;
|
|
94
|
+
}
|
|
95
|
+
export async function readExact(socket, n, timeoutMs = 30000) {
|
|
96
|
+
const state = ensureSocketState(socket);
|
|
97
|
+
if (state.buffer.length >= n) {
|
|
98
|
+
const out = state.buffer.subarray(0, n);
|
|
99
|
+
state.buffer = state.buffer.subarray(n);
|
|
100
|
+
return out;
|
|
101
|
+
}
|
|
102
|
+
return await new Promise((resolve, reject) => {
|
|
103
|
+
const waiter = { n, resolve, reject };
|
|
104
|
+
state.waiters.push(waiter);
|
|
105
|
+
waiter.timer = setTimeout(() => {
|
|
106
|
+
const idx = state.waiters.indexOf(waiter);
|
|
107
|
+
if (idx >= 0) {
|
|
108
|
+
state.waiters.splice(idx, 1);
|
|
109
|
+
reject(new Error(`readExact timeout after ${timeoutMs}ms`));
|
|
110
|
+
}
|
|
111
|
+
}, timeoutMs);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
export async function readAfcHeader(socket) {
|
|
115
|
+
const buf = await readExact(socket, AFC_HEADER_SIZE);
|
|
116
|
+
const magic = buf.subarray(0, 8);
|
|
117
|
+
if (!magic.equals(AFCMAGIC)) {
|
|
118
|
+
throw new Error(`Invalid AFC magic: ${magic.toString('hex')}`);
|
|
119
|
+
}
|
|
120
|
+
const entireLength = readUInt64LE(buf, 8);
|
|
121
|
+
const thisLength = readUInt64LE(buf, 16);
|
|
122
|
+
const packetNum = readUInt64LE(buf, 24);
|
|
123
|
+
const operation = readUInt64LE(buf, 32);
|
|
124
|
+
return {
|
|
125
|
+
magic,
|
|
126
|
+
entireLength,
|
|
127
|
+
thisLength,
|
|
128
|
+
packetNum,
|
|
129
|
+
operation,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
export async function readAfcResponse(socket) {
|
|
133
|
+
const header = await readAfcHeader(socket);
|
|
134
|
+
const payloadLen = Number(header.entireLength - BigInt(AFC_HEADER_SIZE));
|
|
135
|
+
const payload = payloadLen > 0 ? await readExact(socket, payloadLen) : Buffer.alloc(0);
|
|
136
|
+
const op = Number(header.operation);
|
|
137
|
+
if (op === AfcOpcode.STATUS) {
|
|
138
|
+
const status = Number(readUInt64LE(payload.subarray(0, 8)));
|
|
139
|
+
return { status, data: Buffer.alloc(0), operation: op, rawHeader: header };
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
status: AfcError.SUCCESS,
|
|
143
|
+
data: payload,
|
|
144
|
+
operation: op,
|
|
145
|
+
rawHeader: header,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
export async function sendAfcPacket(socket, op, packetNum, payload = Buffer.alloc(0), thisLenOverride) {
|
|
149
|
+
const header = encodeHeader(op, packetNum, payload.length, thisLenOverride);
|
|
150
|
+
await new Promise((resolve, reject) => {
|
|
151
|
+
socket.write(header, (err) => {
|
|
152
|
+
if (err) {
|
|
153
|
+
return reject(err);
|
|
154
|
+
}
|
|
155
|
+
if (payload.length) {
|
|
156
|
+
socket.write(payload, (err2) => {
|
|
157
|
+
if (err2) {
|
|
158
|
+
return reject(err2);
|
|
159
|
+
}
|
|
160
|
+
resolve();
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
resolve();
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
export function parseCStringArray(buf) {
|
|
170
|
+
const parts = [];
|
|
171
|
+
let start = 0;
|
|
172
|
+
for (let i = 0; i < buf.length; i++) {
|
|
173
|
+
if (buf[i] === 0x00) {
|
|
174
|
+
const slice = buf.subarray(start, i);
|
|
175
|
+
parts.push(slice.toString('utf8'));
|
|
176
|
+
start = i + 1;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (start < buf.length) {
|
|
180
|
+
parts.push(buf.subarray(start).toString('utf8'));
|
|
181
|
+
}
|
|
182
|
+
while (parts.length && parts[parts.length - 1] === '') {
|
|
183
|
+
parts.pop();
|
|
184
|
+
}
|
|
185
|
+
return parts;
|
|
186
|
+
}
|
|
187
|
+
export function parseKeyValueNullList(buf) {
|
|
188
|
+
const arr = parseCStringArray(buf);
|
|
189
|
+
if (arr.length % 2 !== 0) {
|
|
190
|
+
throw new Error('Invalid key/value AFC list (odd number of entries)');
|
|
191
|
+
}
|
|
192
|
+
return Object.fromEntries(Array.from({ length: arr.length / 2 }, (_, i) => [
|
|
193
|
+
arr[i * 2],
|
|
194
|
+
arr[i * 2 + 1],
|
|
195
|
+
]));
|
|
196
|
+
}
|
|
197
|
+
export function buildFopenPayload(mode, path) {
|
|
198
|
+
return Buffer.concat([writeUInt64LE(mode), cstr(path)]);
|
|
199
|
+
}
|
|
200
|
+
export function buildReadPayload(handle, size) {
|
|
201
|
+
return Buffer.concat([writeUInt64LE(handle), writeUInt64LE(BigInt(size))]);
|
|
202
|
+
}
|
|
203
|
+
export function buildClosePayload(handle) {
|
|
204
|
+
return writeUInt64LE(handle);
|
|
205
|
+
}
|
|
206
|
+
export function buildRemovePayload(path) {
|
|
207
|
+
return cstr(path);
|
|
208
|
+
}
|
|
209
|
+
export function buildMkdirPayload(path) {
|
|
210
|
+
return cstr(path);
|
|
211
|
+
}
|
|
212
|
+
export function buildStatPayload(path) {
|
|
213
|
+
return cstr(path);
|
|
214
|
+
}
|
|
215
|
+
export function buildRenamePayload(src, dst) {
|
|
216
|
+
return Buffer.concat([cstr(src), cstr(dst)]);
|
|
217
|
+
}
|
|
218
|
+
export function buildLinkPayload(type, target, source) {
|
|
219
|
+
return Buffer.concat([writeUInt64LE(type), cstr(target), cstr(source)]);
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Receive a single length-prefixed plist from the socket
|
|
223
|
+
*/
|
|
224
|
+
export async function recvOnePlist(socket) {
|
|
225
|
+
const lenBuf = await readExact(socket, 4);
|
|
226
|
+
const respLen = lenBuf.readUInt32BE(0);
|
|
227
|
+
const respBody = await readExact(socket, respLen);
|
|
228
|
+
return parsePlist(respBody);
|
|
229
|
+
}
|
|
230
|
+
export async function rsdHandshakeForRawService(socket) {
|
|
231
|
+
const request = {
|
|
232
|
+
Label: 'appium-internal',
|
|
233
|
+
ProtocolVersion: '2',
|
|
234
|
+
Request: 'RSDCheckin',
|
|
235
|
+
};
|
|
236
|
+
const xml = createPlist(request);
|
|
237
|
+
const body = Buffer.from(xml, 'utf8');
|
|
238
|
+
const header = Buffer.alloc(4);
|
|
239
|
+
header.writeUInt32BE(body.length, 0);
|
|
240
|
+
await new Promise((resolve, reject) => {
|
|
241
|
+
socket.write(Buffer.concat([header, body]), (err) => err ? reject(err) : resolve());
|
|
242
|
+
});
|
|
243
|
+
const first = await recvOnePlist(socket);
|
|
244
|
+
if (!first || first.Request !== 'RSDCheckin') {
|
|
245
|
+
throw new Error(`Invalid RSDCheckin response: ${JSON.stringify(first)}`);
|
|
246
|
+
}
|
|
247
|
+
const second = await recvOnePlist(socket);
|
|
248
|
+
if (!second || second.Request !== 'StartService') {
|
|
249
|
+
throw new Error(`Invalid StartService response: ${JSON.stringify(second)}`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
export function nextReadChunkSize(left) {
|
|
253
|
+
const leftNum = typeof left === 'bigint' ? Number(left) : left;
|
|
254
|
+
return leftNum;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Convert nanoseconds to milliseconds for Date construction
|
|
258
|
+
* @param nanoseconds - Time value in nanoseconds as a string
|
|
259
|
+
* @returns Time value in milliseconds
|
|
260
|
+
*/
|
|
261
|
+
export function nanosecondsToMilliseconds(nanoseconds) {
|
|
262
|
+
return Number(BigInt(nanoseconds) / 1000000n);
|
|
263
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AfcFopenMode } from './enums.js';
|
|
2
|
+
/**
|
|
3
|
+
* AFC protocol constants
|
|
4
|
+
*/
|
|
5
|
+
export declare const AFCMAGIC: Buffer<ArrayBuffer>;
|
|
6
|
+
export declare const MAXIMUM_READ_SIZE: number;
|
|
7
|
+
export declare const AFC_FOPEN_TEXTUAL_MODES: Record<string, AfcFopenMode>;
|
|
8
|
+
export declare const AFC_HEADER_SIZE = 40;
|
|
9
|
+
export declare const AFC_WRITE_THIS_LENGTH = 48;
|
|
10
|
+
export declare const NULL_BYTE: Buffer<ArrayBuffer>;
|
|
11
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../../src/services/ios/afc/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C;;GAEG;AAGH,eAAO,MAAM,QAAQ,qBAAmC,CAAC;AAGzD,eAAO,MAAM,iBAAiB,QAAkB,CAAC;AAGjD,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAOhE,CAAC;AAGF,eAAO,MAAM,eAAe,KAAK,CAAC;AAGlC,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC,eAAO,MAAM,SAAS,qBAAmB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { AfcFopenMode } from './enums.js';
|
|
2
|
+
/**
|
|
3
|
+
* AFC protocol constants
|
|
4
|
+
*/
|
|
5
|
+
// Magic bytes at start of every AFC header
|
|
6
|
+
export const AFCMAGIC = Buffer.from('CFA6LPAA', 'ascii');
|
|
7
|
+
// IO chunk sizes
|
|
8
|
+
export const MAXIMUM_READ_SIZE = 4 * 1024 * 1024; // 4 MiB
|
|
9
|
+
// Mapping of textual fopen modes to AFC modes
|
|
10
|
+
export const AFC_FOPEN_TEXTUAL_MODES = {
|
|
11
|
+
r: AfcFopenMode.RDONLY,
|
|
12
|
+
'r+': AfcFopenMode.RW,
|
|
13
|
+
w: AfcFopenMode.WRONLY,
|
|
14
|
+
'w+': AfcFopenMode.WR,
|
|
15
|
+
a: AfcFopenMode.APPEND,
|
|
16
|
+
'a+': AfcFopenMode.RDAPPEND,
|
|
17
|
+
};
|
|
18
|
+
// Header size: magic (8) + entire_length (8) + this_length (8) + packet_num (8) + operation (8)
|
|
19
|
+
export const AFC_HEADER_SIZE = 40;
|
|
20
|
+
// Override for WRITE packets' this_length
|
|
21
|
+
export const AFC_WRITE_THIS_LENGTH = 48;
|
|
22
|
+
export const NULL_BYTE = Buffer.from([0]);
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enums for AFC protocol as defined by Apple's AFC service
|
|
3
|
+
*/
|
|
4
|
+
export declare enum AfcOpcode {
|
|
5
|
+
STATUS = 1,
|
|
6
|
+
DATA = 2,
|
|
7
|
+
READ_DIR = 3,
|
|
8
|
+
REMOVE_PATH = 8,
|
|
9
|
+
MAKE_DIR = 9,
|
|
10
|
+
GET_FILE_INFO = 10,
|
|
11
|
+
GET_DEVINFO = 11,
|
|
12
|
+
FILE_OPEN = 13,
|
|
13
|
+
READ = 15,
|
|
14
|
+
WRITE = 16,
|
|
15
|
+
FILE_CLOSE = 20,
|
|
16
|
+
RENAME_PATH = 24,
|
|
17
|
+
MAKE_LINK = 28
|
|
18
|
+
}
|
|
19
|
+
export declare enum AfcError {
|
|
20
|
+
SUCCESS = 0,
|
|
21
|
+
UNKNOWN_ERROR = 1,
|
|
22
|
+
OP_HEADER_INVALID = 2,
|
|
23
|
+
NO_RESOURCES = 3,
|
|
24
|
+
READ_ERROR = 4,
|
|
25
|
+
WRITE_ERROR = 5,
|
|
26
|
+
UNKNOWN_PACKET_TYPE = 6,
|
|
27
|
+
INVALID_ARG = 7,
|
|
28
|
+
OBJECT_NOT_FOUND = 8,
|
|
29
|
+
OBJECT_IS_DIR = 9,
|
|
30
|
+
PERM_DENIED = 10,
|
|
31
|
+
SERVICE_NOT_CONNECTED = 11,
|
|
32
|
+
OP_TIMEOUT = 12,
|
|
33
|
+
TOO_MUCH_DATA = 13,
|
|
34
|
+
END_OF_DATA = 14,
|
|
35
|
+
OP_NOT_SUPPORTED = 15,
|
|
36
|
+
OBJECT_EXISTS = 16,
|
|
37
|
+
OBJECT_BUSY = 17,
|
|
38
|
+
NO_SPACE_LEFT = 18,
|
|
39
|
+
OP_WOULD_BLOCK = 19,
|
|
40
|
+
IO_ERROR = 20,
|
|
41
|
+
OP_INTERRUPTED = 21,
|
|
42
|
+
OP_IN_PROGRESS = 22,
|
|
43
|
+
INTERNAL_ERROR = 23,
|
|
44
|
+
MUX_ERROR = 30,
|
|
45
|
+
NO_MEM = 31,
|
|
46
|
+
NOT_ENOUGH_DATA = 32,
|
|
47
|
+
DIR_NOT_EMPTY = 33
|
|
48
|
+
}
|
|
49
|
+
export declare enum AfcLinkType {
|
|
50
|
+
HARDLINK = 1,
|
|
51
|
+
SYMLINK = 2
|
|
52
|
+
}
|
|
53
|
+
export declare enum AfcFopenMode {
|
|
54
|
+
RDONLY = 1,// 'r'
|
|
55
|
+
RW = 2,// 'r+'
|
|
56
|
+
WRONLY = 3,// 'w'
|
|
57
|
+
WR = 4,// 'w+'
|
|
58
|
+
APPEND = 5,// 'a'
|
|
59
|
+
RDAPPEND = 6
|
|
60
|
+
}
|
|
61
|
+
export declare enum AfcFileMode {
|
|
62
|
+
S_IFDIR = "S_IFDIR",
|
|
63
|
+
S_IFREG = "S_IFREG",
|
|
64
|
+
S_IFLNK = "S_IFLNK"
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=enums.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enums.d.ts","sourceRoot":"","sources":["../../../../../src/services/ios/afc/enums.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,oBAAY,SAAS;IACnB,MAAM,IAAa;IACnB,IAAI,IAAa;IACjB,QAAQ,IAAa;IACrB,WAAW,IAAa;IACxB,QAAQ,IAAa;IACrB,aAAa,KAAa;IAC1B,WAAW,KAAa;IACxB,SAAS,KAAa;IACtB,IAAI,KAAa;IACjB,KAAK,KAAa;IAClB,UAAU,KAAa;IACvB,WAAW,KAAa;IACxB,SAAS,KAAa;CACvB;AAED,oBAAY,QAAQ;IAClB,OAAO,IAAI;IACX,aAAa,IAAI;IACjB,iBAAiB,IAAI;IACrB,YAAY,IAAI;IAChB,UAAU,IAAI;IACd,WAAW,IAAI;IACf,mBAAmB,IAAI;IACvB,WAAW,IAAI;IACf,gBAAgB,IAAI;IACpB,aAAa,IAAI;IACjB,WAAW,KAAK;IAChB,qBAAqB,KAAK;IAC1B,UAAU,KAAK;IACf,aAAa,KAAK;IAClB,WAAW,KAAK;IAChB,gBAAgB,KAAK;IACrB,aAAa,KAAK;IAClB,WAAW,KAAK;IAChB,aAAa,KAAK;IAClB,cAAc,KAAK;IACnB,QAAQ,KAAK;IACb,cAAc,KAAK;IACnB,cAAc,KAAK;IACnB,cAAc,KAAK;IACnB,SAAS,KAAK;IACd,MAAM,KAAK;IACX,eAAe,KAAK;IACpB,aAAa,KAAK;CACnB;AAED,oBAAY,WAAW;IACrB,QAAQ,IAAI;IACZ,OAAO,IAAI;CACZ;AAED,oBAAY,YAAY;IACtB,MAAM,IAAa,CAAE,MAAM;IAC3B,EAAE,IAAa,CAAE,OAAO;IACxB,MAAM,IAAa,CAAE,MAAM;IAC3B,EAAE,IAAa,CAAE,OAAO;IACxB,MAAM,IAAa,CAAE,MAAM;IAC3B,QAAQ,IAAa;CACtB;AAED,oBAAY,WAAW;IACrB,OAAO,YAAY;IACnB,OAAO,YAAY;IACnB,OAAO,YAAY;CACpB"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enums for AFC protocol as defined by Apple's AFC service
|
|
3
|
+
*/
|
|
4
|
+
export var AfcOpcode;
|
|
5
|
+
(function (AfcOpcode) {
|
|
6
|
+
AfcOpcode[AfcOpcode["STATUS"] = 1] = "STATUS";
|
|
7
|
+
AfcOpcode[AfcOpcode["DATA"] = 2] = "DATA";
|
|
8
|
+
AfcOpcode[AfcOpcode["READ_DIR"] = 3] = "READ_DIR";
|
|
9
|
+
AfcOpcode[AfcOpcode["REMOVE_PATH"] = 8] = "REMOVE_PATH";
|
|
10
|
+
AfcOpcode[AfcOpcode["MAKE_DIR"] = 9] = "MAKE_DIR";
|
|
11
|
+
AfcOpcode[AfcOpcode["GET_FILE_INFO"] = 10] = "GET_FILE_INFO";
|
|
12
|
+
AfcOpcode[AfcOpcode["GET_DEVINFO"] = 11] = "GET_DEVINFO";
|
|
13
|
+
AfcOpcode[AfcOpcode["FILE_OPEN"] = 13] = "FILE_OPEN";
|
|
14
|
+
AfcOpcode[AfcOpcode["READ"] = 15] = "READ";
|
|
15
|
+
AfcOpcode[AfcOpcode["WRITE"] = 16] = "WRITE";
|
|
16
|
+
AfcOpcode[AfcOpcode["FILE_CLOSE"] = 20] = "FILE_CLOSE";
|
|
17
|
+
AfcOpcode[AfcOpcode["RENAME_PATH"] = 24] = "RENAME_PATH";
|
|
18
|
+
AfcOpcode[AfcOpcode["MAKE_LINK"] = 28] = "MAKE_LINK";
|
|
19
|
+
})(AfcOpcode || (AfcOpcode = {}));
|
|
20
|
+
export var AfcError;
|
|
21
|
+
(function (AfcError) {
|
|
22
|
+
AfcError[AfcError["SUCCESS"] = 0] = "SUCCESS";
|
|
23
|
+
AfcError[AfcError["UNKNOWN_ERROR"] = 1] = "UNKNOWN_ERROR";
|
|
24
|
+
AfcError[AfcError["OP_HEADER_INVALID"] = 2] = "OP_HEADER_INVALID";
|
|
25
|
+
AfcError[AfcError["NO_RESOURCES"] = 3] = "NO_RESOURCES";
|
|
26
|
+
AfcError[AfcError["READ_ERROR"] = 4] = "READ_ERROR";
|
|
27
|
+
AfcError[AfcError["WRITE_ERROR"] = 5] = "WRITE_ERROR";
|
|
28
|
+
AfcError[AfcError["UNKNOWN_PACKET_TYPE"] = 6] = "UNKNOWN_PACKET_TYPE";
|
|
29
|
+
AfcError[AfcError["INVALID_ARG"] = 7] = "INVALID_ARG";
|
|
30
|
+
AfcError[AfcError["OBJECT_NOT_FOUND"] = 8] = "OBJECT_NOT_FOUND";
|
|
31
|
+
AfcError[AfcError["OBJECT_IS_DIR"] = 9] = "OBJECT_IS_DIR";
|
|
32
|
+
AfcError[AfcError["PERM_DENIED"] = 10] = "PERM_DENIED";
|
|
33
|
+
AfcError[AfcError["SERVICE_NOT_CONNECTED"] = 11] = "SERVICE_NOT_CONNECTED";
|
|
34
|
+
AfcError[AfcError["OP_TIMEOUT"] = 12] = "OP_TIMEOUT";
|
|
35
|
+
AfcError[AfcError["TOO_MUCH_DATA"] = 13] = "TOO_MUCH_DATA";
|
|
36
|
+
AfcError[AfcError["END_OF_DATA"] = 14] = "END_OF_DATA";
|
|
37
|
+
AfcError[AfcError["OP_NOT_SUPPORTED"] = 15] = "OP_NOT_SUPPORTED";
|
|
38
|
+
AfcError[AfcError["OBJECT_EXISTS"] = 16] = "OBJECT_EXISTS";
|
|
39
|
+
AfcError[AfcError["OBJECT_BUSY"] = 17] = "OBJECT_BUSY";
|
|
40
|
+
AfcError[AfcError["NO_SPACE_LEFT"] = 18] = "NO_SPACE_LEFT";
|
|
41
|
+
AfcError[AfcError["OP_WOULD_BLOCK"] = 19] = "OP_WOULD_BLOCK";
|
|
42
|
+
AfcError[AfcError["IO_ERROR"] = 20] = "IO_ERROR";
|
|
43
|
+
AfcError[AfcError["OP_INTERRUPTED"] = 21] = "OP_INTERRUPTED";
|
|
44
|
+
AfcError[AfcError["OP_IN_PROGRESS"] = 22] = "OP_IN_PROGRESS";
|
|
45
|
+
AfcError[AfcError["INTERNAL_ERROR"] = 23] = "INTERNAL_ERROR";
|
|
46
|
+
AfcError[AfcError["MUX_ERROR"] = 30] = "MUX_ERROR";
|
|
47
|
+
AfcError[AfcError["NO_MEM"] = 31] = "NO_MEM";
|
|
48
|
+
AfcError[AfcError["NOT_ENOUGH_DATA"] = 32] = "NOT_ENOUGH_DATA";
|
|
49
|
+
AfcError[AfcError["DIR_NOT_EMPTY"] = 33] = "DIR_NOT_EMPTY";
|
|
50
|
+
})(AfcError || (AfcError = {}));
|
|
51
|
+
export var AfcLinkType;
|
|
52
|
+
(function (AfcLinkType) {
|
|
53
|
+
AfcLinkType[AfcLinkType["HARDLINK"] = 1] = "HARDLINK";
|
|
54
|
+
AfcLinkType[AfcLinkType["SYMLINK"] = 2] = "SYMLINK";
|
|
55
|
+
})(AfcLinkType || (AfcLinkType = {}));
|
|
56
|
+
export var AfcFopenMode;
|
|
57
|
+
(function (AfcFopenMode) {
|
|
58
|
+
AfcFopenMode[AfcFopenMode["RDONLY"] = 1] = "RDONLY";
|
|
59
|
+
AfcFopenMode[AfcFopenMode["RW"] = 2] = "RW";
|
|
60
|
+
AfcFopenMode[AfcFopenMode["WRONLY"] = 3] = "WRONLY";
|
|
61
|
+
AfcFopenMode[AfcFopenMode["WR"] = 4] = "WR";
|
|
62
|
+
AfcFopenMode[AfcFopenMode["APPEND"] = 5] = "APPEND";
|
|
63
|
+
AfcFopenMode[AfcFopenMode["RDAPPEND"] = 6] = "RDAPPEND";
|
|
64
|
+
})(AfcFopenMode || (AfcFopenMode = {}));
|
|
65
|
+
export var AfcFileMode;
|
|
66
|
+
(function (AfcFileMode) {
|
|
67
|
+
AfcFileMode["S_IFDIR"] = "S_IFDIR";
|
|
68
|
+
AfcFileMode["S_IFREG"] = "S_IFREG";
|
|
69
|
+
AfcFileMode["S_IFLNK"] = "S_IFLNK";
|
|
70
|
+
})(AfcFileMode || (AfcFileMode = {}));
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Readable, Writable } from 'node:stream';
|
|
2
|
+
import { AFC_FOPEN_TEXTUAL_MODES } from './constants.js';
|
|
3
|
+
import { AfcFileMode } from './enums.js';
|
|
4
|
+
export interface StatInfo {
|
|
5
|
+
st_ifmt: AfcFileMode;
|
|
6
|
+
st_size: bigint;
|
|
7
|
+
st_blocks: number;
|
|
8
|
+
st_mtime: Date;
|
|
9
|
+
st_birthtime: Date;
|
|
10
|
+
st_nlink: number;
|
|
11
|
+
LinkTarget?: string;
|
|
12
|
+
[k: string]: any;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* AFC client over RSD (Remote XPC shim).
|
|
16
|
+
* After RSDCheckin, speaks raw AFC protocol on the same socket.
|
|
17
|
+
*/
|
|
18
|
+
export declare class AfcService {
|
|
19
|
+
private readonly address;
|
|
20
|
+
static readonly RSD_SERVICE_NAME = "com.apple.afc.shim.remote";
|
|
21
|
+
private socket;
|
|
22
|
+
private packetNum;
|
|
23
|
+
private silent;
|
|
24
|
+
constructor(address: [string, number], silent?: boolean);
|
|
25
|
+
/**
|
|
26
|
+
* List directory entries. Returned entries do not include '.' and '..'
|
|
27
|
+
*/
|
|
28
|
+
listdir(dirPath: string): Promise<string[]>;
|
|
29
|
+
stat(filePath: string): Promise<StatInfo>;
|
|
30
|
+
isdir(filePath: string): Promise<boolean>;
|
|
31
|
+
exists(filePath: string): Promise<boolean>;
|
|
32
|
+
fopen(filePath: string, mode?: keyof typeof AFC_FOPEN_TEXTUAL_MODES): Promise<bigint>;
|
|
33
|
+
fclose(handle: bigint): Promise<void>;
|
|
34
|
+
createReadStream(handle: bigint, size: bigint): Readable;
|
|
35
|
+
createWriteStream(handle: bigint, chunkSize?: number): Writable;
|
|
36
|
+
fread(handle: bigint, size: bigint): Promise<Buffer>;
|
|
37
|
+
fwrite(handle: bigint, data: Buffer, chunkSize?: number): Promise<void>;
|
|
38
|
+
getFileContents(filePath: string): Promise<Buffer>;
|
|
39
|
+
setFileContents(filePath: string, data: Buffer): Promise<void>;
|
|
40
|
+
readToStream(filePath: string): Promise<Readable>;
|
|
41
|
+
writeFromStream(filePath: string, stream: Readable): Promise<void>;
|
|
42
|
+
pull(remoteSrc: string, localDst: string): Promise<void>;
|
|
43
|
+
rmSingle(filePath: string, force?: boolean): Promise<boolean>;
|
|
44
|
+
rm(filePath: string, force?: boolean): Promise<string[]>;
|
|
45
|
+
rename(src: string, dst: string): Promise<void>;
|
|
46
|
+
push(localSrc: string, remoteDst: string): Promise<void>;
|
|
47
|
+
walk(root: string): Promise<Array<{
|
|
48
|
+
dir: string;
|
|
49
|
+
dirs: string[];
|
|
50
|
+
files: string[];
|
|
51
|
+
}>>;
|
|
52
|
+
/**
|
|
53
|
+
* Close the underlying socket
|
|
54
|
+
*/
|
|
55
|
+
close(): void;
|
|
56
|
+
/**
|
|
57
|
+
* Connect to RSD port and perform RSDCheckin.
|
|
58
|
+
* Keeps the underlying socket for raw AFC I/O.
|
|
59
|
+
*/
|
|
60
|
+
private _connect;
|
|
61
|
+
private _resolvePath;
|
|
62
|
+
private _dispatch;
|
|
63
|
+
private _receive;
|
|
64
|
+
/**
|
|
65
|
+
* Send a single-operation request and parse result.
|
|
66
|
+
* Throws if status != SUCCESS.
|
|
67
|
+
* Returns response DATA buffer when applicable.
|
|
68
|
+
*/
|
|
69
|
+
private _doOperation;
|
|
70
|
+
}
|
|
71
|
+
export default AfcService;
|
|
72
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/services/ios/afc/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAmBjD,OAAO,EAAE,uBAAuB,EAAyB,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAY,WAAW,EAAa,MAAM,YAAY,CAAC;AAO9D,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,WAAW,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,IAAI,CAAC;IACf,YAAY,EAAE,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,CAAC,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;CAClB;AAED;;;GAGG;AACH,qBAAa,UAAU;IAQnB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAP1B,MAAM,CAAC,QAAQ,CAAC,gBAAgB,+BAA+B;IAE/D,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,MAAM,CAAkB;gBAGb,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAC1C,MAAM,CAAC,EAAE,OAAO;IAKlB;;OAEG;IACG,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAS3C,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IA8BzC,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKzC,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS1C,KAAK,CACT,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,MAAM,OAAO,uBAA6B,GAC/C,OAAO,CAAC,MAAM,CAAC;IAiCZ,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3C,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ;IASxD,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,QAAQ;IASzD,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAYpD,MAAM,CACV,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,SAAS,SAAc,GACtB,OAAO,CAAC,IAAI,CAAC;IAoCV,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAsBlD,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAc9D,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAajD,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAelE,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQxD,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,UAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAwB3D,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,UAAQ,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAwCtD,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB/C,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOxD,IAAI,CACR,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IAoBnE;;OAEG;IACH,KAAK,IAAI,IAAI;IAUb;;;OAGG;YACW,QAAQ;YAyBR,YAAY;YAYZ,SAAS;YAST,QAAQ;IAMtB;;;;OAIG;YACW,YAAY;CA2B3B;AAED,eAAe,UAAU,CAAC"}
|