@limrun/api 0.22.1 → 0.23.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 +8 -0
- package/exec-client.d.mts.map +1 -1
- package/exec-client.d.ts.map +1 -1
- package/exec-client.js +3 -5
- package/exec-client.js.map +1 -1
- package/exec-client.mjs +3 -5
- package/exec-client.mjs.map +1 -1
- package/folder-sync-ignore.d.mts +7 -0
- package/folder-sync-ignore.d.mts.map +1 -0
- package/folder-sync-ignore.d.ts +7 -0
- package/folder-sync-ignore.d.ts.map +1 -0
- package/folder-sync-ignore.js +56 -0
- package/folder-sync-ignore.js.map +1 -0
- package/folder-sync-ignore.mjs +52 -0
- package/folder-sync-ignore.mjs.map +1 -0
- package/folder-sync-watcher.d.mts +2 -0
- package/folder-sync-watcher.d.mts.map +1 -1
- package/folder-sync-watcher.d.ts +2 -0
- package/folder-sync-watcher.d.ts.map +1 -1
- package/folder-sync-watcher.js +10 -62
- package/folder-sync-watcher.js.map +1 -1
- package/folder-sync-watcher.mjs +10 -62
- package/folder-sync-watcher.mjs.map +1 -1
- package/folder-sync.d.mts +16 -16
- package/folder-sync.d.mts.map +1 -1
- package/folder-sync.d.ts +16 -16
- package/folder-sync.d.ts.map +1 -1
- package/folder-sync.js +22 -65
- package/folder-sync.js.map +1 -1
- package/folder-sync.mjs +21 -64
- package/folder-sync.mjs.map +1 -1
- package/instance-client.d.mts +1 -1
- package/instance-client.d.mts.map +1 -1
- package/instance-client.d.ts +1 -1
- package/instance-client.d.ts.map +1 -1
- package/ios-client.d.mts +24 -0
- package/ios-client.d.mts.map +1 -1
- package/ios-client.d.ts +24 -0
- package/ios-client.d.ts.map +1 -1
- package/ios-client.js +108 -8
- package/ios-client.js.map +1 -1
- package/ios-client.mjs +109 -9
- package/ios-client.mjs.map +1 -1
- package/package.json +11 -1
- package/sandbox-client.d.mts +20 -15
- package/sandbox-client.d.mts.map +1 -1
- package/sandbox-client.d.ts +20 -15
- package/sandbox-client.d.ts.map +1 -1
- package/sandbox-client.js +49 -40
- package/sandbox-client.js.map +1 -1
- package/sandbox-client.mjs +48 -40
- package/sandbox-client.mjs.map +1 -1
- package/src/exec-client.ts +3 -5
- package/src/folder-sync-ignore.ts +65 -0
- package/src/folder-sync-watcher.ts +11 -66
- package/src/folder-sync.ts +39 -89
- package/src/instance-client.ts +1 -1
- package/src/ios-client.ts +138 -9
- package/src/sandbox-client.ts +72 -62
- package/src/version.ts +1 -1
- package/version.d.mts +1 -1
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/version.mjs +1 -1
package/src/ios-client.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { WebSocket, Data } from 'ws';
|
|
2
2
|
import fs from 'fs';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import crypto from 'crypto';
|
|
3
6
|
import { EventEmitter } from 'events';
|
|
7
|
+
import { Readable } from 'stream';
|
|
8
|
+
import { pipeline } from 'stream/promises';
|
|
4
9
|
import { isNonRetryableError } from './tunnel';
|
|
5
|
-
import {
|
|
10
|
+
import { type SyncFolderResult, type FolderSyncOptions, syncFolder } from './folder-sync';
|
|
11
|
+
import { createIgnoreFn } from './folder-sync-ignore';
|
|
6
12
|
|
|
7
13
|
/**
|
|
8
14
|
* Connection state of the instance client
|
|
@@ -14,6 +20,46 @@ export type ConnectionState = 'connecting' | 'connected' | 'disconnected' | 'rec
|
|
|
14
20
|
*/
|
|
15
21
|
export type ConnectionStateCallback = (state: ConnectionState) => void;
|
|
16
22
|
|
|
23
|
+
function generateRecordingFilename(): string {
|
|
24
|
+
const rand = Math.random().toString(36).slice(2, 5).padEnd(3, '0');
|
|
25
|
+
const now = new Date();
|
|
26
|
+
const formattedDate = now.toISOString().replace(/[-:]/g, '_').replace('T', '_').replace(/\..+/, '');
|
|
27
|
+
|
|
28
|
+
// Example: 20240602_17_45_30 for June 2, 2024 17:45:30 UTC
|
|
29
|
+
return `ios_video_${formattedDate}_${rand}.mp4`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function downloadFileToLocalPath(url: string, token: string, localPath: string): Promise<void> {
|
|
33
|
+
const maxRetries = 3;
|
|
34
|
+
|
|
35
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
36
|
+
const response = await fetch(url, {
|
|
37
|
+
method: 'GET',
|
|
38
|
+
headers: {
|
|
39
|
+
Authorization: `Bearer ${token}`,
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
if (!response.ok) {
|
|
43
|
+
const errorBody = await response.text();
|
|
44
|
+
const isRetriable = response.status >= 500 && response.status < 600;
|
|
45
|
+
if (isRetriable && attempt < maxRetries) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
throw new Error(`Download failed: ${response.status} ${errorBody}`);
|
|
49
|
+
}
|
|
50
|
+
if (!response.body) {
|
|
51
|
+
throw new Error('Download failed: response body is missing');
|
|
52
|
+
}
|
|
53
|
+
await fs.promises.mkdir(path.dirname(localPath), { recursive: true });
|
|
54
|
+
await pipeline(Readable.fromWeb(response.body as any), fs.createWriteStream(localPath));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function buildDownloadUrl(apiUrl: string, filename: string): string {
|
|
60
|
+
return `${apiUrl}/files?name=${encodeURIComponent(filename)}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
17
63
|
/**
|
|
18
64
|
* Events emitted by a simctl execution
|
|
19
65
|
*/
|
|
@@ -295,13 +341,36 @@ export type InstanceClient = {
|
|
|
295
341
|
options?: { coordinate?: [number, number]; momentum?: number },
|
|
296
342
|
) => Promise<void>;
|
|
297
343
|
|
|
344
|
+
/**
|
|
345
|
+
* Start recording simulator video. Use stopRecording() to stop the recording.
|
|
346
|
+
*/
|
|
347
|
+
startRecording: () => Promise<void>;
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Stop the active recording for this client instance.
|
|
351
|
+
* If `saveTo.presignedUrl` is provided, the server uploads the completed file there before resolving.
|
|
352
|
+
* If `saveTo.localPath` is provided, the client downloads the completed file to that path.
|
|
353
|
+
* If both are provided, both are performed.
|
|
354
|
+
* Returns a download URL for the completed recording that can be used to download using the token.
|
|
355
|
+
* Note that the download URL is only valid while the instance is running.
|
|
356
|
+
*/
|
|
357
|
+
stopRecording: (saveTo: { presignedUrl?: string; localPath?: string }) => Promise<string>;
|
|
358
|
+
|
|
298
359
|
/**
|
|
299
360
|
* Sync an iOS app bundle folder to the server and (optionally) install/launch it.
|
|
361
|
+
* @param localAppBundlePath The path to the local app bundle folder
|
|
362
|
+
* @param opts Optional sync options
|
|
363
|
+
* @param opts.install If true, install the app after syncing. Defaults to true.
|
|
364
|
+
* @param opts.basisCacheDir Directory for the client-side folder-sync cache.
|
|
365
|
+
* @param opts.maxPatchBytes Max patch size (bytes) to send as delta before falling back to full upload. Defaults to 4MB.
|
|
366
|
+
* @param opts.launchMode Launch mode after installation: "ForegroundIfRunning" (default): bring to foreground if already running, otherwise launch, "RelaunchIfRunning": kill and relaunch if already running
|
|
367
|
+
* @param opts.watch If true, watch the folder and re-sync on any changes (debounced, single-flight).
|
|
300
368
|
*/
|
|
301
369
|
syncApp: (
|
|
302
370
|
localAppBundlePath: string,
|
|
303
371
|
opts?: {
|
|
304
372
|
install?: boolean;
|
|
373
|
+
basisCacheDir?: string;
|
|
305
374
|
maxPatchBytes?: number;
|
|
306
375
|
launchMode?: 'ForegroundIfRunning' | 'RelaunchIfRunning';
|
|
307
376
|
watch?: boolean;
|
|
@@ -513,6 +582,7 @@ type ServerResponse = {
|
|
|
513
582
|
elementType?: string;
|
|
514
583
|
apps?: string;
|
|
515
584
|
url?: string;
|
|
585
|
+
filename?: string;
|
|
516
586
|
bundleId?: string;
|
|
517
587
|
files?: LsofEntry[];
|
|
518
588
|
// Device info fields
|
|
@@ -850,6 +920,7 @@ export async function createInstanceClient(options: InstanceClientOptions): Prom
|
|
|
850
920
|
let reconnectTimeout: NodeJS.Timeout | undefined;
|
|
851
921
|
let intentionalDisconnect = false;
|
|
852
922
|
let lastError: string | undefined;
|
|
923
|
+
let activeRecordingFilename: string | undefined;
|
|
853
924
|
|
|
854
925
|
// Centralized pending requests map - handles all request/response patterns
|
|
855
926
|
const pendingRequests: Map<string, PendingRequest<any>> = new Map();
|
|
@@ -1028,6 +1099,10 @@ export async function createInstanceClient(options: InstanceClientOptions): Prom
|
|
|
1028
1099
|
url: msg.url || '',
|
|
1029
1100
|
bundleId: msg.bundleId || '',
|
|
1030
1101
|
}),
|
|
1102
|
+
startVideoRecordingResult: () => undefined,
|
|
1103
|
+
stopVideoRecordingResult: (msg) => ({
|
|
1104
|
+
filename: msg.filename || '',
|
|
1105
|
+
}),
|
|
1031
1106
|
setOrientationResult: () => undefined,
|
|
1032
1107
|
scrollResult: () => undefined,
|
|
1033
1108
|
xcrunResult: (msg): CommandResult => ({
|
|
@@ -1061,7 +1136,7 @@ export async function createInstanceClient(options: InstanceClientOptions): Prom
|
|
|
1061
1136
|
if (message.type === 'simctlStream') {
|
|
1062
1137
|
const execution = simctlExecutions.get(message.id);
|
|
1063
1138
|
if (!execution) {
|
|
1064
|
-
logger.
|
|
1139
|
+
logger.debug(`Received simctl stream for unknown execution: ${message.id}`);
|
|
1065
1140
|
return;
|
|
1066
1141
|
}
|
|
1067
1142
|
|
|
@@ -1200,6 +1275,8 @@ export async function createInstanceClient(options: InstanceClientOptions): Prom
|
|
|
1200
1275
|
installApp,
|
|
1201
1276
|
setOrientation,
|
|
1202
1277
|
scroll,
|
|
1278
|
+
startRecording,
|
|
1279
|
+
stopRecording,
|
|
1203
1280
|
syncApp,
|
|
1204
1281
|
disconnect,
|
|
1205
1282
|
getConnectionState,
|
|
@@ -1341,22 +1418,74 @@ export async function createInstanceClient(options: InstanceClientOptions): Prom
|
|
|
1341
1418
|
});
|
|
1342
1419
|
};
|
|
1343
1420
|
|
|
1421
|
+
const startRecording = async (): Promise<void> => {
|
|
1422
|
+
if (activeRecordingFilename) {
|
|
1423
|
+
throw new Error(`A recording is already active for this client: ${activeRecordingFilename}`);
|
|
1424
|
+
}
|
|
1425
|
+
const finalFilename = generateRecordingFilename();
|
|
1426
|
+
activeRecordingFilename = finalFilename;
|
|
1427
|
+
try {
|
|
1428
|
+
await sendRequest<void>('startVideoRecording', { filename: finalFilename });
|
|
1429
|
+
} catch (error) {
|
|
1430
|
+
if (activeRecordingFilename === finalFilename) {
|
|
1431
|
+
activeRecordingFilename = undefined;
|
|
1432
|
+
}
|
|
1433
|
+
throw error;
|
|
1434
|
+
}
|
|
1435
|
+
};
|
|
1436
|
+
|
|
1437
|
+
const stopRecording = async (saveTo: { presignedUrl?: string; localPath?: string }): Promise<string> => {
|
|
1438
|
+
const filename = activeRecordingFilename;
|
|
1439
|
+
if (!filename) {
|
|
1440
|
+
throw new Error('No active recording for this client. Call startRecording() first.');
|
|
1441
|
+
}
|
|
1442
|
+
const result = await sendRequest<{ filename: string }>('stopVideoRecording', {
|
|
1443
|
+
filename,
|
|
1444
|
+
upload: saveTo.presignedUrl ? { presignedUrl: saveTo.presignedUrl } : undefined,
|
|
1445
|
+
});
|
|
1446
|
+
const finalFilename = result.filename || filename;
|
|
1447
|
+
const downloadUrl = buildDownloadUrl(options.apiUrl, finalFilename);
|
|
1448
|
+
if (saveTo.localPath) {
|
|
1449
|
+
try {
|
|
1450
|
+
await downloadFileToLocalPath(downloadUrl, options.token, saveTo.localPath);
|
|
1451
|
+
} finally {
|
|
1452
|
+
activeRecordingFilename = undefined;
|
|
1453
|
+
}
|
|
1454
|
+
} else {
|
|
1455
|
+
activeRecordingFilename = undefined;
|
|
1456
|
+
}
|
|
1457
|
+
return downloadUrl;
|
|
1458
|
+
};
|
|
1459
|
+
|
|
1344
1460
|
const syncApp = async (
|
|
1345
1461
|
localAppBundlePath: string,
|
|
1346
1462
|
opts?: {
|
|
1347
1463
|
install?: boolean;
|
|
1464
|
+
basisCacheDir?: string;
|
|
1348
1465
|
maxPatchBytes?: number;
|
|
1349
1466
|
launchMode?: 'ForegroundIfRunning' | 'RelaunchIfRunning';
|
|
1350
1467
|
watch?: boolean;
|
|
1351
1468
|
},
|
|
1352
1469
|
): Promise<SyncFolderResult> => {
|
|
1470
|
+
const infoPlistPath = path.join(localAppBundlePath, 'Info.plist');
|
|
1471
|
+
const infoPlistStat = await fs.promises.stat(infoPlistPath).catch(() => null);
|
|
1472
|
+
if (!infoPlistStat?.isFile()) {
|
|
1473
|
+
throw new Error(`The folder is not a valid app bundle: missing Info.plist at ${infoPlistPath}`);
|
|
1474
|
+
}
|
|
1353
1475
|
if (!cachedDeviceInfo) {
|
|
1354
1476
|
throw new Error('Device info not available yet; wait for client connection to be established.');
|
|
1355
1477
|
}
|
|
1356
|
-
const
|
|
1478
|
+
const resolvedPath = path.resolve(localAppBundlePath);
|
|
1479
|
+
const folderName = path.basename(resolvedPath);
|
|
1480
|
+
const hash = crypto.createHash('sha1').update(resolvedPath).digest('hex').slice(0, 8);
|
|
1481
|
+
const cacheKey = `limsync-cache-${folderName}-${hash}`;
|
|
1482
|
+
const basisCacheDir = opts?.basisCacheDir ?? path.join(os.tmpdir(), cacheKey);
|
|
1483
|
+
const folderSyncOpts: FolderSyncOptions = {
|
|
1357
1484
|
apiUrl: options.apiUrl,
|
|
1358
1485
|
token: options.token,
|
|
1359
|
-
udid:
|
|
1486
|
+
udid: cacheKey,
|
|
1487
|
+
ignoreFn: await createIgnoreFn(localAppBundlePath, { basisCacheDir }),
|
|
1488
|
+
basisCacheDir,
|
|
1360
1489
|
log: (level, msg) => {
|
|
1361
1490
|
switch (level) {
|
|
1362
1491
|
case 'debug':
|
|
@@ -1376,12 +1505,12 @@ export async function createInstanceClient(options: InstanceClientOptions): Prom
|
|
|
1376
1505
|
break;
|
|
1377
1506
|
}
|
|
1378
1507
|
},
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1508
|
+
install: opts?.install ?? true,
|
|
1509
|
+
maxPatchBytes: opts?.maxPatchBytes ?? 4 * 1024 * 1024,
|
|
1510
|
+
launchMode: opts?.launchMode ?? 'ForegroundIfRunning',
|
|
1511
|
+
watch: opts?.watch ?? true,
|
|
1383
1512
|
};
|
|
1384
|
-
return await
|
|
1513
|
+
return await syncFolder(localAppBundlePath, folderSyncOpts);
|
|
1385
1514
|
};
|
|
1386
1515
|
|
|
1387
1516
|
const lsof = (): Promise<LsofEntry[]> => {
|
package/src/sandbox-client.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import os from 'os';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { syncFolder as syncFolderImpl, type FolderSyncOptions } from './folder-sync';
|
|
2
4
|
import { exec, ExecChildProcess } from './exec-client';
|
|
5
|
+
import { createIgnoreFn } from './folder-sync-ignore';
|
|
6
|
+
import crypto from 'crypto';
|
|
3
7
|
|
|
4
8
|
export type LogLevel = 'none' | 'error' | 'warn' | 'info' | 'debug';
|
|
5
9
|
|
|
@@ -27,32 +31,37 @@ export type SimulatorConfig = {
|
|
|
27
31
|
*/
|
|
28
32
|
export type SyncOptions = {
|
|
29
33
|
/**
|
|
30
|
-
*
|
|
31
|
-
* This is not sent to the server.
|
|
34
|
+
* If true, watch the folder and re-sync on any changes. Defaults to true.
|
|
32
35
|
*/
|
|
33
|
-
|
|
34
|
-
basisCacheDir?: string;
|
|
35
|
-
maxPatchBytes?: number;
|
|
36
|
+
watch?: boolean;
|
|
36
37
|
/**
|
|
37
|
-
*
|
|
38
|
+
* Directory for the client-side folder-sync cache.
|
|
39
|
+
* Used to store the last-synced “basis” copies of files (and related sync metadata) so we can compute xdelta patches
|
|
40
|
+
* on subsequent syncs without re-downloading server state.
|
|
41
|
+
*
|
|
42
|
+
* Defaults to a temporary directory under the OS temp directory.
|
|
38
43
|
*/
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
basisCacheDir?: string;
|
|
45
|
+
/** Max patch size (bytes) to send as delta before falling back to full upload. */
|
|
46
|
+
maxPatchBytes?: number;
|
|
47
|
+
/** If true, install the app after syncing. Defaults to true. */
|
|
48
|
+
install?: boolean;
|
|
41
49
|
/**
|
|
42
|
-
* Optional
|
|
50
|
+
* Optional predicate for ignoring files and directories during sync.
|
|
51
|
+
* Applied in addition to built-in sync and Xcode-specific ignore rules.
|
|
43
52
|
* Called with the relative path from the sync root (using forward slashes).
|
|
44
53
|
* For directories, the path ends with '/'.
|
|
45
|
-
* Return true to
|
|
54
|
+
* Return true to ignore, false to keep.
|
|
46
55
|
*
|
|
47
56
|
* @example
|
|
48
|
-
* //
|
|
49
|
-
*
|
|
57
|
+
* // Ignore build folder
|
|
58
|
+
* ignore: (path) => path.startsWith('build/')
|
|
50
59
|
*
|
|
51
60
|
* @example
|
|
52
|
-
* //
|
|
53
|
-
*
|
|
61
|
+
* // Ignore anything outside src/ and JSON files
|
|
62
|
+
* ignore: (path) => !(path.startsWith('src/') || path.endsWith('.json'))
|
|
54
63
|
*/
|
|
55
|
-
|
|
64
|
+
ignore?: (relativePath: string) => boolean;
|
|
56
65
|
};
|
|
57
66
|
|
|
58
67
|
/**
|
|
@@ -150,7 +159,7 @@ export async function createXCodeSandboxClient(
|
|
|
150
159
|
},
|
|
151
160
|
};
|
|
152
161
|
|
|
153
|
-
const
|
|
162
|
+
const log = (level: 'debug' | 'info' | 'warn' | 'error', msg: string) => {
|
|
154
163
|
switch (level) {
|
|
155
164
|
case 'debug':
|
|
156
165
|
logger.debug(msg);
|
|
@@ -196,54 +205,55 @@ export async function createXCodeSandboxClient(
|
|
|
196
205
|
|
|
197
206
|
return {
|
|
198
207
|
async sync(localCodePath: string, opts?: SyncOptions): Promise<SyncResult> {
|
|
208
|
+
// Use folder name and hash of absolute path to scope basisCacheDir uniquely for each sync root
|
|
209
|
+
const resolvedPath = path.resolve(localCodePath);
|
|
210
|
+
const folderName = path.basename(resolvedPath);
|
|
211
|
+
const hash = crypto.createHash('sha1').update(resolvedPath).digest('hex').slice(0, 8);
|
|
212
|
+
const cacheKey = `limsync-cache-${folderName}-${hash}`;
|
|
213
|
+
const basisCacheDir = opts?.basisCacheDir ?? path.join(os.tmpdir(), cacheKey);
|
|
199
214
|
const codeSyncOpts: FolderSyncOptions = {
|
|
200
215
|
apiUrl: options.apiUrl,
|
|
201
216
|
token: options.token,
|
|
202
|
-
udid:
|
|
203
|
-
install:
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
217
|
+
udid: cacheKey,
|
|
218
|
+
install: opts?.install ?? true,
|
|
219
|
+
ignoreFn: await createIgnoreFn(localCodePath, {
|
|
220
|
+
basisCacheDir,
|
|
221
|
+
additional: (relativePath: string) => {
|
|
222
|
+
if (
|
|
223
|
+
relativePath.startsWith('build/') ||
|
|
224
|
+
relativePath.startsWith('.build/') ||
|
|
225
|
+
relativePath.startsWith('DerivedData/') ||
|
|
226
|
+
relativePath.startsWith('Index.noindex/') ||
|
|
227
|
+
relativePath.startsWith('ModuleCache.noindex/') ||
|
|
228
|
+
relativePath.startsWith('.index-build/')
|
|
229
|
+
) {
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
if (
|
|
233
|
+
relativePath.startsWith('.swiftpm/') ||
|
|
234
|
+
relativePath.startsWith('Pods/') ||
|
|
235
|
+
relativePath.startsWith('Carthage/Build/')
|
|
236
|
+
) {
|
|
237
|
+
return true;
|
|
238
|
+
}
|
|
239
|
+
if (relativePath.includes('/xcuserdata/')) {
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
if (relativePath.includes('.dSYM/')) {
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
// User-provided ignores
|
|
246
|
+
if (opts?.ignore?.(relativePath)) {
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
213
249
|
return false;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
if (
|
|
223
|
-
relativePath.startsWith('.git/') ||
|
|
224
|
-
relativePath.startsWith('.limsync-cache/') ||
|
|
225
|
-
relativePath === '.DS_Store' ||
|
|
226
|
-
relativePath.endsWith('/.DS_Store')
|
|
227
|
-
) {
|
|
228
|
-
return false;
|
|
229
|
-
}
|
|
230
|
-
if (relativePath.includes('/xcuserdata/')) {
|
|
231
|
-
return false;
|
|
232
|
-
}
|
|
233
|
-
if (relativePath.includes('.dSYM/')) {
|
|
234
|
-
return false;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// User-provided filter
|
|
238
|
-
if (opts?.filter && !opts.filter(relativePath)) {
|
|
239
|
-
return false;
|
|
240
|
-
}
|
|
241
|
-
return true;
|
|
242
|
-
},
|
|
243
|
-
...(opts?.basisCacheDir ? { basisCacheDir: opts.basisCacheDir } : {}),
|
|
244
|
-
...(opts?.maxPatchBytes !== undefined ? { maxPatchBytes: opts.maxPatchBytes } : {}),
|
|
245
|
-
...(opts?.watch !== undefined ? { watch: opts.watch } : {}),
|
|
246
|
-
log: opts?.log ?? logFn,
|
|
250
|
+
},
|
|
251
|
+
}),
|
|
252
|
+
basisCacheDir,
|
|
253
|
+
watch: opts?.watch ?? true,
|
|
254
|
+
maxPatchBytes: opts?.maxPatchBytes ?? 4 * 1024 * 1024,
|
|
255
|
+
launchMode: 'ForegroundIfRunning',
|
|
256
|
+
log,
|
|
247
257
|
};
|
|
248
258
|
|
|
249
259
|
const result = await syncFolderImpl(localCodePath, codeSyncOpts);
|
|
@@ -259,7 +269,7 @@ export async function createXCodeSandboxClient(
|
|
|
259
269
|
{
|
|
260
270
|
apiUrl: options.apiUrl,
|
|
261
271
|
token: options.token,
|
|
262
|
-
log
|
|
272
|
+
log,
|
|
263
273
|
},
|
|
264
274
|
);
|
|
265
275
|
},
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = '0.
|
|
1
|
+
export const VERSION = '0.23.0'; // x-release-please-version
|
package/version.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.
|
|
1
|
+
export declare const VERSION = "0.23.0";
|
|
2
2
|
//# sourceMappingURL=version.d.mts.map
|
package/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.
|
|
1
|
+
export declare const VERSION = "0.23.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/version.js
CHANGED
package/version.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const VERSION = '0.
|
|
1
|
+
export const VERSION = '0.23.0'; // x-release-please-version
|
|
2
2
|
//# sourceMappingURL=version.mjs.map
|