@limrun/api 0.46.14 → 0.47.1
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 +27 -0
- package/exec-client.d.mts +13 -1
- package/exec-client.d.mts.map +1 -1
- package/exec-client.d.ts +13 -1
- package/exec-client.d.ts.map +1 -1
- package/exec-client.js.map +1 -1
- package/exec-client.mjs.map +1 -1
- package/folder-sync-ignore.d.mts +4 -3
- package/folder-sync-ignore.d.mts.map +1 -1
- package/folder-sync-ignore.d.ts +4 -3
- package/folder-sync-ignore.d.ts.map +1 -1
- package/folder-sync-ignore.js +13 -7
- package/folder-sync-ignore.js.map +1 -1
- package/folder-sync-ignore.mjs +13 -7
- package/folder-sync-ignore.mjs.map +1 -1
- package/instance-client.d.mts +107 -1
- package/instance-client.d.mts.map +1 -1
- package/instance-client.d.ts +107 -1
- package/instance-client.d.ts.map +1 -1
- package/instance-client.js +75 -0
- package/instance-client.js.map +1 -1
- package/instance-client.mjs +75 -0
- package/instance-client.mjs.map +1 -1
- package/package.json +1 -1
- package/resources/daemon-client-shared.d.mts +9 -0
- package/resources/daemon-client-shared.d.mts.map +1 -1
- package/resources/daemon-client-shared.d.ts +9 -0
- package/resources/daemon-client-shared.d.ts.map +1 -1
- package/resources/daemon-client-shared.js +11 -1
- package/resources/daemon-client-shared.js.map +1 -1
- package/resources/daemon-client-shared.mjs +10 -1
- package/resources/daemon-client-shared.mjs.map +1 -1
- package/resources/gradle-instances-helpers.d.mts +8 -0
- package/resources/gradle-instances-helpers.d.mts.map +1 -1
- package/resources/gradle-instances-helpers.d.ts +8 -0
- package/resources/gradle-instances-helpers.d.ts.map +1 -1
- package/resources/gradle-instances-helpers.js +1 -1
- package/resources/gradle-instances-helpers.js.map +1 -1
- package/resources/gradle-instances-helpers.mjs +1 -1
- package/resources/gradle-instances-helpers.mjs.map +1 -1
- package/resources/xcode-instances-helpers.d.mts +46 -3
- package/resources/xcode-instances-helpers.d.mts.map +1 -1
- package/resources/xcode-instances-helpers.d.ts +46 -3
- package/resources/xcode-instances-helpers.d.ts.map +1 -1
- package/resources/xcode-instances-helpers.js +2 -1
- package/resources/xcode-instances-helpers.js.map +1 -1
- package/resources/xcode-instances-helpers.mjs +2 -1
- package/resources/xcode-instances-helpers.mjs.map +1 -1
- package/src/exec-client.ts +13 -1
- package/src/folder-sync-ignore.ts +12 -7
- package/src/instance-client.ts +227 -1
- package/src/resources/daemon-client-shared.ts +11 -1
- package/src/resources/gradle-instances-helpers.ts +22 -8
- package/src/resources/xcode-instances-helpers.ts +48 -4
- package/src/version.ts +1 -1
- package/version.d.mts +1 -1
- package/version.d.mts.map +1 -1
- package/version.d.ts +1 -1
- package/version.d.ts.map +1 -1
- package/version.js +1 -1
- package/version.js.map +1 -1
- package/version.mjs +1 -1
- package/version.mjs.map +1 -1
package/src/instance-client.ts
CHANGED
|
@@ -152,9 +152,76 @@ export type InstanceClient = {
|
|
|
152
152
|
/**
|
|
153
153
|
* Play an on-device WAV/MP3 file as microphone input.
|
|
154
154
|
*
|
|
155
|
-
* The file must already exist on the Android instance, for example after
|
|
155
|
+
* The file must already exist on the Android instance, for example after
|
|
156
|
+
* uploading it with {@link pushFile} or pushing it with ADB.
|
|
156
157
|
*/
|
|
157
158
|
playOnMicrophone: (path: string, options?: PlayOnMicrophoneOptions) => Promise<PlayOnMicrophoneResult>;
|
|
159
|
+
/**
|
|
160
|
+
* Upload a local file to the instance, without needing an ADB connection.
|
|
161
|
+
*
|
|
162
|
+
* With no destination, the instance stores the file under an internal name
|
|
163
|
+
* and returns its path. With a destination, behaves like `adb push`: the
|
|
164
|
+
* write is performed with the same permissions the ADB shell user has, so
|
|
165
|
+
* writable locations (e.g. `/data/local/tmp`, `/sdcard`) succeed and
|
|
166
|
+
* protected ones are rejected, exactly as they would be for `adb push`.
|
|
167
|
+
*
|
|
168
|
+
* @param path The path of the local file to upload.
|
|
169
|
+
* @param destination Optional absolute path on the instance to write to.
|
|
170
|
+
* @returns A promise that resolves to the absolute path of the file on the
|
|
171
|
+
* instance, usable with {@link playOnMicrophone}.
|
|
172
|
+
*/
|
|
173
|
+
pushFile: (path: string, destination?: string) => Promise<string>;
|
|
174
|
+
/**
|
|
175
|
+
* Play a local video file as the camera feed.
|
|
176
|
+
*
|
|
177
|
+
* Uploads the file to the instance and switches the virtual camera source
|
|
178
|
+
* to it, replacing the live WebRTC camera until {@link clearCameraVideo} is
|
|
179
|
+
* called. Apps see the video through their regular Camera2/CameraX
|
|
180
|
+
* pipeline, and the file's audio track (if any) plays through the
|
|
181
|
+
* microphone in sync.
|
|
182
|
+
*
|
|
183
|
+
* By default the video loops; with `loop: false` it plays once and the
|
|
184
|
+
* feed freezes on the last frame.
|
|
185
|
+
*
|
|
186
|
+
* @param path The path of the local video file to play as the camera.
|
|
187
|
+
* @param opts Playback options (currently just `loop`).
|
|
188
|
+
* @throws If the file has no decodable video track or the instance does not
|
|
189
|
+
* support camera injection (Android 14 and older).
|
|
190
|
+
*/
|
|
191
|
+
setCameraVideo: (path: string, opts?: CameraVideoOptions) => Promise<void>;
|
|
192
|
+
/**
|
|
193
|
+
* Stop video-file camera playback and restore the default WebRTC camera
|
|
194
|
+
* source. Safe to call when no video is playing.
|
|
195
|
+
*/
|
|
196
|
+
clearCameraVideo: () => Promise<void>;
|
|
197
|
+
/**
|
|
198
|
+
* Run a shell command on the instance, without needing `adb` installed
|
|
199
|
+
* locally. The command runs with the same permissions the ADB shell user
|
|
200
|
+
* has (exactly like `adb shell`), and its stdout, stderr, and exit code are
|
|
201
|
+
* returned separately.
|
|
202
|
+
*
|
|
203
|
+
* The command and each argument are safely quoted before being sent, so
|
|
204
|
+
* argument values cannot be interpreted as extra shell syntax (no injection
|
|
205
|
+
* from untrusted args), mirroring `child_process.execFile`:
|
|
206
|
+
*
|
|
207
|
+
* ```ts
|
|
208
|
+
* await client.adbShell('pm', ['list', 'packages', '-3']);
|
|
209
|
+
* await client.adbShell('getprop', ['ro.build.version.sdk']);
|
|
210
|
+
* ```
|
|
211
|
+
*
|
|
212
|
+
* To use shell features such as pipes or redirection, invoke a shell
|
|
213
|
+
* explicitly and pass the script as an argument:
|
|
214
|
+
*
|
|
215
|
+
* ```ts
|
|
216
|
+
* await client.adbShell('sh', ['-c', 'dumpsys battery | grep level']);
|
|
217
|
+
* ```
|
|
218
|
+
*
|
|
219
|
+
* @param command The executable or shell builtin to run.
|
|
220
|
+
* @param args Arguments passed to the command; each is individually quoted.
|
|
221
|
+
* @throws If the command times out or the ADB transport is unavailable. A
|
|
222
|
+
* non-zero `exitCode` is returned in the result, not thrown.
|
|
223
|
+
*/
|
|
224
|
+
adbShell: (command: string, args?: string[], options?: AdbShellOptions) => Promise<AdbShellResult>;
|
|
158
225
|
/**
|
|
159
226
|
* Set Android Wi-Fi bandwidth limits in Kbps. Omit a direction to leave it unchanged;
|
|
160
227
|
* pass `0` to clear that direction's limit.
|
|
@@ -443,6 +510,18 @@ export type PlayOnMicrophoneOptions = {
|
|
|
443
510
|
once?: boolean;
|
|
444
511
|
};
|
|
445
512
|
|
|
513
|
+
/**
|
|
514
|
+
* Options for playing a video file as the virtual camera feed.
|
|
515
|
+
*/
|
|
516
|
+
export type CameraVideoOptions = {
|
|
517
|
+
/**
|
|
518
|
+
* Whether to restart the video when it ends. When false the video
|
|
519
|
+
* plays once and the camera feed freezes on its last frame.
|
|
520
|
+
* @default true
|
|
521
|
+
*/
|
|
522
|
+
loop?: boolean;
|
|
523
|
+
};
|
|
524
|
+
|
|
446
525
|
export type PlayOnMicrophoneResult = {
|
|
447
526
|
/** Duration of the decoded audio in microseconds. */
|
|
448
527
|
duration: number;
|
|
@@ -455,6 +534,46 @@ export type WifiBandwidthOptions = {
|
|
|
455
534
|
upKbps?: number;
|
|
456
535
|
};
|
|
457
536
|
|
|
537
|
+
/**
|
|
538
|
+
* Quotes each token so the remote `sh -c` receives them as literal,
|
|
539
|
+
* separate arguments — values cannot inject extra shell syntax. Uses
|
|
540
|
+
* POSIX single-quoting: wrap in single quotes and escape embedded single
|
|
541
|
+
* quotes as `'\''`.
|
|
542
|
+
*/
|
|
543
|
+
function quoteShellArgs(tokens: string[]): string {
|
|
544
|
+
return tokens.map((token) => `'${token.replace(/'/g, `'\\''`)}'`).join(' ');
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Options for {@link InstanceClient.adbShell}.
|
|
549
|
+
*/
|
|
550
|
+
export type AdbShellOptions = {
|
|
551
|
+
/**
|
|
552
|
+
* Maximum time to wait for the command to finish, in milliseconds.
|
|
553
|
+
* @default 30000
|
|
554
|
+
*/
|
|
555
|
+
timeoutMs?: number;
|
|
556
|
+
/**
|
|
557
|
+
* Encoding used to decode stdout/stderr into strings.
|
|
558
|
+
* @default 'utf8'
|
|
559
|
+
*/
|
|
560
|
+
encoding?: BufferEncoding;
|
|
561
|
+
};
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Result of a shell command run via {@link InstanceClient.adbShell}.
|
|
565
|
+
*/
|
|
566
|
+
export type AdbShellResult = {
|
|
567
|
+
/** Standard output, decoded with the requested encoding. */
|
|
568
|
+
stdout: string;
|
|
569
|
+
/** Standard error, decoded with the requested encoding. */
|
|
570
|
+
stderr: string;
|
|
571
|
+
/** Process exit code (`-1` if the device reported no exit status). */
|
|
572
|
+
exitCode: number;
|
|
573
|
+
/** True if output exceeded the capture limit and was truncated. */
|
|
574
|
+
truncated: boolean;
|
|
575
|
+
};
|
|
576
|
+
|
|
458
577
|
type EmptyCommandResult = Record<string, never>;
|
|
459
578
|
|
|
460
579
|
type ScreenshotErrorResponse = {
|
|
@@ -589,6 +708,15 @@ type PlayOnMicrophoneResultMessage = {
|
|
|
589
708
|
error?: CommandError;
|
|
590
709
|
};
|
|
591
710
|
|
|
711
|
+
// The server sends camera control results "flat": fields at the top level and
|
|
712
|
+
// `error` as a plain string, with no payload envelope.
|
|
713
|
+
type CameraControlResultMessage = {
|
|
714
|
+
type: 'cameraControlResult';
|
|
715
|
+
id: string;
|
|
716
|
+
payload?: EmptyCommandResult;
|
|
717
|
+
error?: string;
|
|
718
|
+
};
|
|
719
|
+
|
|
592
720
|
type SetWifiBandwidthResultMessage = {
|
|
593
721
|
type: 'setWifiBandwidthResult';
|
|
594
722
|
id: string;
|
|
@@ -596,6 +724,19 @@ type SetWifiBandwidthResultMessage = {
|
|
|
596
724
|
error?: CommandError;
|
|
597
725
|
};
|
|
598
726
|
|
|
727
|
+
// The server sends adb shell results "flat": stdout/stderr (base64) and
|
|
728
|
+
// exitCode at the top level, with `error` as a plain string.
|
|
729
|
+
type AdbShellResultMessage = {
|
|
730
|
+
type: 'adbShellResult';
|
|
731
|
+
id: string;
|
|
732
|
+
stdout?: string;
|
|
733
|
+
stderr?: string;
|
|
734
|
+
exitCode?: number;
|
|
735
|
+
truncated?: boolean;
|
|
736
|
+
payload?: EmptyCommandResult;
|
|
737
|
+
error?: string;
|
|
738
|
+
};
|
|
739
|
+
|
|
599
740
|
type StartVideoRecordingResultMessage = {
|
|
600
741
|
type: 'startRecordingResult';
|
|
601
742
|
id: string;
|
|
@@ -625,6 +766,8 @@ type KnownCommandResultMessage =
|
|
|
625
766
|
| WatchAppResultMessage
|
|
626
767
|
| UnwatchAppResultMessage
|
|
627
768
|
| PlayOnMicrophoneResultMessage
|
|
769
|
+
| CameraControlResultMessage
|
|
770
|
+
| AdbShellResultMessage
|
|
628
771
|
| SetWifiBandwidthResultMessage
|
|
629
772
|
| StartVideoRecordingResultMessage
|
|
630
773
|
| StopVideoRecordingResultMessage;
|
|
@@ -651,6 +794,8 @@ type CommandRequestMap = {
|
|
|
651
794
|
watchApp: { packageName: string; execId: string };
|
|
652
795
|
unwatchApp: { execId: string };
|
|
653
796
|
playOnMicrophone: { path: string; once?: boolean };
|
|
797
|
+
cameraControl: { action: 'setSource'; source: 'video'; arg: string; loop?: boolean } | { action: 'reset' };
|
|
798
|
+
adbShell: { command: string; timeoutMs?: number };
|
|
654
799
|
setWifiBandwidth: WifiBandwidthOptions;
|
|
655
800
|
startRecording: { quality?: RecordingQuality };
|
|
656
801
|
stopRecording: { upload?: { presignedUrl: string } };
|
|
@@ -671,6 +816,8 @@ type CommandResultMap = {
|
|
|
671
816
|
watchApp: { packageName?: string };
|
|
672
817
|
unwatchApp: EmptyCommandResult;
|
|
673
818
|
playOnMicrophone: PlayOnMicrophoneResult;
|
|
819
|
+
cameraControl: EmptyCommandResult;
|
|
820
|
+
adbShell: AdbShellResultMessage;
|
|
674
821
|
setWifiBandwidth: EmptyCommandResult;
|
|
675
822
|
startRecording: EmptyCommandResult;
|
|
676
823
|
stopRecording: EmptyCommandResult;
|
|
@@ -812,6 +959,11 @@ export async function createInstanceClient(options: InstanceClientOptions): Prom
|
|
|
812
959
|
if ('message' in message && typeof message.message === 'string') {
|
|
813
960
|
return message.message;
|
|
814
961
|
}
|
|
962
|
+
// "Flat" results (e.g. cameraControlResult, playOnMicrophoneResult)
|
|
963
|
+
// carry the error as a plain string instead of a CommandError object.
|
|
964
|
+
if ('error' in message && typeof message.error === 'string' && message.error) {
|
|
965
|
+
return message.error;
|
|
966
|
+
}
|
|
815
967
|
if ('error' in message && message.error && typeof message.error === 'object') {
|
|
816
968
|
const obj = message.error as CommandError;
|
|
817
969
|
if (typeof obj.message === 'string' && obj.message) {
|
|
@@ -845,6 +997,8 @@ export async function createInstanceClient(options: InstanceClientOptions): Prom
|
|
|
845
997
|
case 'watchAppResult':
|
|
846
998
|
case 'unwatchAppResult':
|
|
847
999
|
case 'playOnMicrophoneResult':
|
|
1000
|
+
case 'cameraControlResult':
|
|
1001
|
+
case 'adbShellResult':
|
|
848
1002
|
case 'setWifiBandwidthResult':
|
|
849
1003
|
case 'startRecordingResult':
|
|
850
1004
|
case 'stopRecordingResult':
|
|
@@ -1116,6 +1270,10 @@ export async function createInstanceClient(options: InstanceClientOptions): Prom
|
|
|
1116
1270
|
terminateApp,
|
|
1117
1271
|
watchApp,
|
|
1118
1272
|
playOnMicrophone,
|
|
1273
|
+
pushFile,
|
|
1274
|
+
setCameraVideo,
|
|
1275
|
+
clearCameraVideo,
|
|
1276
|
+
adbShell,
|
|
1119
1277
|
setWifiBandwidth,
|
|
1120
1278
|
startRecording,
|
|
1121
1279
|
stopRecording,
|
|
@@ -1279,6 +1437,74 @@ export async function createInstanceClient(options: InstanceClientOptions): Prom
|
|
|
1279
1437
|
});
|
|
1280
1438
|
};
|
|
1281
1439
|
|
|
1440
|
+
const pushFile = async (filePath: string, destination?: string): Promise<string> => {
|
|
1441
|
+
const uploadUrl =
|
|
1442
|
+
destination === undefined ?
|
|
1443
|
+
`${options.apiUrl}/files`
|
|
1444
|
+
: `${options.apiUrl}/files?path=${encodeURIComponent(destination)}`;
|
|
1445
|
+
const fileStream = fs.createReadStream(filePath);
|
|
1446
|
+
// Node's fetch (undici) supports streaming request bodies but TS DOM types may not include
|
|
1447
|
+
// `duplex` and may not accept Node ReadStreams as BodyInit in some configs.
|
|
1448
|
+
const response = await nodeProxyTransport.fetch(uploadUrl, {
|
|
1449
|
+
method: 'PUT',
|
|
1450
|
+
headers: {
|
|
1451
|
+
'Content-Type': 'application/octet-stream',
|
|
1452
|
+
'Content-Length': fs.statSync(filePath).size.toString(),
|
|
1453
|
+
Authorization: `Bearer ${options.token}`,
|
|
1454
|
+
},
|
|
1455
|
+
body: fileStream as any,
|
|
1456
|
+
duplex: 'half' as any,
|
|
1457
|
+
} as any);
|
|
1458
|
+
if (!response.ok) {
|
|
1459
|
+
const errorBody = await response.text();
|
|
1460
|
+
logger.debug(`Upload failed: ${response.status} ${errorBody}`);
|
|
1461
|
+
throw new Error(`Upload failed: ${response.status} ${errorBody}`);
|
|
1462
|
+
}
|
|
1463
|
+
const result = (await response.json()) as { path: string };
|
|
1464
|
+
return result.path;
|
|
1465
|
+
};
|
|
1466
|
+
|
|
1467
|
+
const setCameraVideo = async (filePath: string, cameraOptions?: CameraVideoOptions): Promise<void> => {
|
|
1468
|
+
const remotePath = await pushFile(filePath);
|
|
1469
|
+
await sendRequest('cameraControl', {
|
|
1470
|
+
action: 'setSource',
|
|
1471
|
+
source: 'video',
|
|
1472
|
+
arg: remotePath,
|
|
1473
|
+
loop: cameraOptions?.loop ?? true,
|
|
1474
|
+
});
|
|
1475
|
+
};
|
|
1476
|
+
|
|
1477
|
+
const clearCameraVideo = async (): Promise<void> => {
|
|
1478
|
+
await sendRequest('cameraControl', { action: 'reset' });
|
|
1479
|
+
};
|
|
1480
|
+
|
|
1481
|
+
const adbShell = async (
|
|
1482
|
+
command: string,
|
|
1483
|
+
args: string[] = [],
|
|
1484
|
+
adbOptions?: AdbShellOptions,
|
|
1485
|
+
): Promise<AdbShellResult> => {
|
|
1486
|
+
if (!command) {
|
|
1487
|
+
throw new Error('command must be a non-empty string');
|
|
1488
|
+
}
|
|
1489
|
+
const commandLine = quoteShellArgs([command, ...args]);
|
|
1490
|
+
const timeoutMs = adbOptions?.timeoutMs;
|
|
1491
|
+
// Wait a little longer than the device-side timeout so the server's own
|
|
1492
|
+
// error surfaces instead of a generic client timeout.
|
|
1493
|
+
const requestTimeoutMs = (timeoutMs ?? 30000) + 15000;
|
|
1494
|
+
const result = await sendRequest(
|
|
1495
|
+
'adbShell',
|
|
1496
|
+
{ command: commandLine, ...(timeoutMs === undefined ? {} : { timeoutMs }) },
|
|
1497
|
+
requestTimeoutMs,
|
|
1498
|
+
);
|
|
1499
|
+
const encoding = adbOptions?.encoding ?? 'utf8';
|
|
1500
|
+
return {
|
|
1501
|
+
stdout: Buffer.from(result.stdout ?? '', 'base64').toString(encoding),
|
|
1502
|
+
stderr: Buffer.from(result.stderr ?? '', 'base64').toString(encoding),
|
|
1503
|
+
exitCode: typeof result.exitCode === 'number' ? result.exitCode : -1,
|
|
1504
|
+
truncated: result.truncated === true,
|
|
1505
|
+
};
|
|
1506
|
+
};
|
|
1507
|
+
|
|
1282
1508
|
const setWifiBandwidth = async (bandwidthOptions: WifiBandwidthOptions): Promise<void> => {
|
|
1283
1509
|
const request: CommandRequestMap['setWifiBandwidth'] = {};
|
|
1284
1510
|
if (bandwidthOptions.downKbps !== undefined) {
|
|
@@ -88,9 +88,19 @@ export type AssetUploadOptions = {
|
|
|
88
88
|
deeplink?: string;
|
|
89
89
|
};
|
|
90
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Default TTL for build-product uploads. Every build upload without an
|
|
93
|
+
* explicit ttl pushes the asset's expiry to 14 days from that upload, so
|
|
94
|
+
* abandoned build artifacts don't accumulate in Asset Storage forever.
|
|
95
|
+
* Assets uploaded through the general asset API keep no expiry by default.
|
|
96
|
+
*/
|
|
97
|
+
export const DEFAULT_BUILD_ASSET_TTL = '336h';
|
|
98
|
+
|
|
91
99
|
/**
|
|
92
100
|
* Mints presigned upload/download URLs for a named asset via assets.getOrCreate,
|
|
93
101
|
* wrapping failures with the asset name (and the original error as cause).
|
|
102
|
+
* All build-product upload paths (xcodebuild, gradlebuild, RBE) go through
|
|
103
|
+
* here, which is what scopes DEFAULT_BUILD_ASSET_TTL to build uploads.
|
|
94
104
|
*/
|
|
95
105
|
export function mintAssetUploadUrls(
|
|
96
106
|
assets: {
|
|
@@ -100,7 +110,7 @@ export function mintAssetUploadUrls(
|
|
|
100
110
|
ttl?: string,
|
|
101
111
|
uploadOptions?: AssetUploadOptions,
|
|
102
112
|
): Promise<AssetUploadUrls> {
|
|
103
|
-
return assets.getOrCreate({ name,
|
|
113
|
+
return assets.getOrCreate({ name, ttl: ttl || DEFAULT_BUILD_ASSET_TTL, ...uploadOptions }).catch((err) => {
|
|
104
114
|
const message = `Failed to create upload URL for asset '${name}': ${
|
|
105
115
|
err instanceof Error ? err.message : err
|
|
106
116
|
}`;
|
|
@@ -56,7 +56,19 @@ export type GradleBuildOptions = {
|
|
|
56
56
|
/** Relative path to the Gradle root when auto-discovery is ambiguous. */
|
|
57
57
|
projectPath?: string;
|
|
58
58
|
/** Upload the built artifact as a named org asset, or to a presigned URL. */
|
|
59
|
-
upload?:
|
|
59
|
+
upload?:
|
|
60
|
+
| {
|
|
61
|
+
assetName: string;
|
|
62
|
+
/**
|
|
63
|
+
* Asset TTL as a Go duration (e.g. "24h", "30m"; "1d" is invalid),
|
|
64
|
+
* forwarded to assets.getOrCreate. Defaults to 336h (14 days): each
|
|
65
|
+
* build upload without an explicit ttl pushes the asset's expiry to
|
|
66
|
+
* 14 days from that upload.
|
|
67
|
+
*/
|
|
68
|
+
ttl?: string;
|
|
69
|
+
signedUploadUrl?: never;
|
|
70
|
+
}
|
|
71
|
+
| { signedUploadUrl: string; assetName?: never; ttl?: never };
|
|
60
72
|
/** React Native / Expo tuning. */
|
|
61
73
|
reactNative?: GradleReactNativeConfig;
|
|
62
74
|
/** Release signing config; presence makes bundleRelease the default task. */
|
|
@@ -183,13 +195,15 @@ class GradleInstancesHelpers extends GradleInstances {
|
|
|
183
195
|
};
|
|
184
196
|
|
|
185
197
|
if (options?.upload && 'assetName' in options.upload) {
|
|
186
|
-
const requestPromise = mintAssetUploadUrls(
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
198
|
+
const requestPromise = mintAssetUploadUrls(
|
|
199
|
+
client.assets,
|
|
200
|
+
options.upload.assetName,
|
|
201
|
+
options.upload.ttl,
|
|
202
|
+
).then((asset) => {
|
|
203
|
+
request.signedUploadUrl = asset.signedUploadUrl;
|
|
204
|
+
request.additionalMetadata = { signedDownloadUrl: asset.signedDownloadUrl };
|
|
205
|
+
return request;
|
|
206
|
+
});
|
|
193
207
|
return exec(requestPromise, { apiUrl, token, log });
|
|
194
208
|
}
|
|
195
209
|
|
|
@@ -90,8 +90,12 @@ export type SyncOptions = {
|
|
|
90
90
|
export type XcodeRunOptions = {
|
|
91
91
|
/** Working directory relative to the synced workspace root. Defaults to ".". */
|
|
92
92
|
cwd?: string;
|
|
93
|
-
/**
|
|
94
|
-
|
|
93
|
+
/**
|
|
94
|
+
* Ordered KEY=VALUE entries added to limbuild's curated sandbox
|
|
95
|
+
* environment. Server-managed variables (PATH, HOME, ...) cannot be
|
|
96
|
+
* overridden; when a key repeats, the last entry wins.
|
|
97
|
+
*/
|
|
98
|
+
env?: string[];
|
|
95
99
|
/** Server-side timeout in seconds. Defaults to 3600; maximum 21600. */
|
|
96
100
|
timeoutSeconds?: number;
|
|
97
101
|
};
|
|
@@ -105,6 +109,14 @@ export type XcodeProjectConfig = {
|
|
|
105
109
|
* Debug for native Xcode builds and Release for React Native / Expo builds.
|
|
106
110
|
*/
|
|
107
111
|
configuration?: 'Debug' | 'Release';
|
|
112
|
+
/**
|
|
113
|
+
* Full filename of the built app bundle, including the .app extension
|
|
114
|
+
* (e.g. "MyApp-dev.app"). When set, limbuild takes the artifact from
|
|
115
|
+
* this name in the built products directory verbatim, skipping artifact
|
|
116
|
+
* discovery. Use when the scheme name differs from the product name and
|
|
117
|
+
* discovery picks the wrong bundle.
|
|
118
|
+
*/
|
|
119
|
+
artifactName?: string;
|
|
108
120
|
};
|
|
109
121
|
|
|
110
122
|
export type XcodeGenConfig = {
|
|
@@ -173,12 +185,28 @@ export type ReactNativeBuildConfig = {
|
|
|
173
185
|
* server URL you want opened.
|
|
174
186
|
*/
|
|
175
187
|
devServerURL?: string;
|
|
188
|
+
/**
|
|
189
|
+
* Run `expo prebuild` even when the synced workspace already contains the
|
|
190
|
+
* native ios/ tree, regenerating it in place. Use when the tree holds
|
|
191
|
+
* client-synced files the server treats as user-owned (for example
|
|
192
|
+
* committed Podfile customizations) while the Xcode project itself is
|
|
193
|
+
* generated and gitignored. Requires a detectable Expo project. Older
|
|
194
|
+
* limbuild servers silently ignore this option.
|
|
195
|
+
*/
|
|
196
|
+
expoForcePrebuild?: boolean;
|
|
176
197
|
};
|
|
177
198
|
|
|
178
199
|
export type XcodeBuildOptions = {
|
|
179
200
|
upload?:
|
|
180
201
|
| {
|
|
181
202
|
assetName: string;
|
|
203
|
+
/**
|
|
204
|
+
* Asset TTL as a Go duration (e.g. "24h", "30m"; "1d" is invalid),
|
|
205
|
+
* forwarded to assets.getOrCreate. Defaults to 336h (14 days): each
|
|
206
|
+
* build upload without an explicit ttl pushes the asset's expiry to
|
|
207
|
+
* 14 days from that upload.
|
|
208
|
+
*/
|
|
209
|
+
ttl?: string;
|
|
182
210
|
/**
|
|
183
211
|
* App metadata to record on the asset up front. limbuild extracts
|
|
184
212
|
* the same metadata from the built bundle after the build and
|
|
@@ -207,6 +235,16 @@ export type XcodeBuildOptions = {
|
|
|
207
235
|
*/
|
|
208
236
|
xcodegen?: XcodeGenConfig;
|
|
209
237
|
buildSettings?: Record<string, string>;
|
|
238
|
+
/**
|
|
239
|
+
* Ordered KEY=VALUE entries added to the environment of every build
|
|
240
|
+
* pipeline command (dependency installs, expo prebuild, pod install,
|
|
241
|
+
* xcodebuild and its script phases). Server-managed variables (PATH,
|
|
242
|
+
* HOME, ...) cannot be overridden; when a key repeats, the last entry
|
|
243
|
+
* wins. Dependency installs always include devDependencies, so
|
|
244
|
+
* NODE_ENV=production cannot break them. Older limbuild servers
|
|
245
|
+
* silently ignore this option.
|
|
246
|
+
*/
|
|
247
|
+
env?: string[];
|
|
210
248
|
/**
|
|
211
249
|
* Run `git init` in the synced workspace before project generation,
|
|
212
250
|
* dependency resolution, and xcodebuild.
|
|
@@ -323,7 +361,12 @@ export type RbeUploadOptions =
|
|
|
323
361
|
| {
|
|
324
362
|
/** Upload as a named asset: the SDK mints the presigned upload URL via assets.getOrCreate. */
|
|
325
363
|
assetName: string;
|
|
326
|
-
/**
|
|
364
|
+
/**
|
|
365
|
+
* Optional asset TTL as a Go duration (e.g. "24h", "30m"; "1d" is
|
|
366
|
+
* invalid), forwarded to assets.getOrCreate. Defaults to 336h (14
|
|
367
|
+
* days): each upload without an explicit ttl pushes the asset's
|
|
368
|
+
* expiry to 14 days from that upload.
|
|
369
|
+
*/
|
|
327
370
|
ttl?: string;
|
|
328
371
|
signedUploadUrl?: never;
|
|
329
372
|
}
|
|
@@ -813,6 +856,7 @@ export class XcodeInstances extends GeneratedXcodeInstances {
|
|
|
813
856
|
// testflight until the exec API is revised separately.
|
|
814
857
|
...(options?.appstore && { testflight: options.appstore }),
|
|
815
858
|
...(options?.buildSettings && { buildSettings: options.buildSettings }),
|
|
859
|
+
...(options?.env?.length && { env: options.env }),
|
|
816
860
|
...(options?.gitInit !== undefined && { gitInit: options.gitInit }),
|
|
817
861
|
...(options?.webhook && { webhook: options.webhook }),
|
|
818
862
|
};
|
|
@@ -821,7 +865,7 @@ export class XcodeInstances extends GeneratedXcodeInstances {
|
|
|
821
865
|
const requestPromise = mintAssetUploadUrls(
|
|
822
866
|
client.assets,
|
|
823
867
|
options.upload.assetName,
|
|
824
|
-
|
|
868
|
+
options.upload.ttl,
|
|
825
869
|
options.upload.uploadOptions,
|
|
826
870
|
).then((asset) => {
|
|
827
871
|
request.signedUploadUrl = asset.signedUploadUrl;
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = '0.
|
|
1
|
+
export const VERSION = '0.47.1'; // 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.47.1";
|
|
2
2
|
//# sourceMappingURL=version.d.mts.map
|
package/version.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.d.mts","sourceRoot":"","sources":["src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,
|
|
1
|
+
{"version":3,"file":"version.d.mts","sourceRoot":"","sources":["src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,WAAW,CAAC"}
|
package/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.
|
|
1
|
+
export declare const VERSION = "0.47.1";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/version.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,WAAW,CAAC"}
|
package/version.js
CHANGED
package/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["src/version.ts"],"names":[],"mappings":";;;AAAa,QAAA,OAAO,GAAG,
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["src/version.ts"],"names":[],"mappings":";;;AAAa,QAAA,OAAO,GAAG,QAAQ,CAAC,CAAC,2BAA2B"}
|
package/version.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const VERSION = '0.
|
|
1
|
+
export const VERSION = '0.47.1'; // x-release-please-version
|
|
2
2
|
//# sourceMappingURL=version.mjs.map
|
package/version.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.mjs","sourceRoot":"","sources":["src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,
|
|
1
|
+
{"version":3,"file":"version.mjs","sourceRoot":"","sources":["src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,2BAA2B"}
|