@limrun/api 0.39.0 → 0.39.2
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 +34 -0
- package/exec-client.d.mts.map +1 -1
- package/exec-client.d.ts +34 -0
- package/exec-client.d.ts.map +1 -1
- package/exec-client.js +25 -1
- package/exec-client.js.map +1 -1
- package/exec-client.mjs +25 -1
- package/exec-client.mjs.map +1 -1
- package/folder-sync.d.mts +6 -0
- package/folder-sync.d.mts.map +1 -1
- package/folder-sync.d.ts +6 -0
- package/folder-sync.d.ts.map +1 -1
- package/folder-sync.js +2 -1
- package/folder-sync.js.map +1 -1
- package/folder-sync.mjs +2 -1
- package/folder-sync.mjs.map +1 -1
- package/index.d.mts +1 -1
- package/index.d.mts.map +1 -1
- package/index.d.ts +1 -1
- package/index.d.ts.map +1 -1
- package/index.js.map +1 -1
- package/index.mjs.map +1 -1
- package/package.json +1 -1
- package/resources/xcode-instances-helpers.d.mts +15 -1
- package/resources/xcode-instances-helpers.d.mts.map +1 -1
- package/resources/xcode-instances-helpers.d.ts +15 -1
- package/resources/xcode-instances-helpers.d.ts.map +1 -1
- package/resources/xcode-instances-helpers.js +7 -2
- package/resources/xcode-instances-helpers.js.map +1 -1
- package/resources/xcode-instances-helpers.mjs +7 -2
- package/resources/xcode-instances-helpers.mjs.map +1 -1
- package/src/exec-client.ts +58 -1
- package/src/folder-sync.ts +8 -1
- package/src/index.ts +2 -0
- package/src/resources/xcode-instances-helpers.ts +23 -3
- 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/exec-client.ts
CHANGED
|
@@ -30,6 +30,7 @@ export type ExecRequest = {
|
|
|
30
30
|
certificatePassword?: string;
|
|
31
31
|
provisioningProfileBase64?: string;
|
|
32
32
|
};
|
|
33
|
+
testflight?: TestflightUploadConfig;
|
|
33
34
|
buildSettings?: Record<string, string>;
|
|
34
35
|
signedUploadUrl?: string;
|
|
35
36
|
additionalMetadata?: {
|
|
@@ -48,6 +49,40 @@ export type ExecResult = {
|
|
|
48
49
|
execId: string;
|
|
49
50
|
status: 'SUCCEEDED' | 'FAILED' | 'CANCELLED';
|
|
50
51
|
signedDownloadUrl?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Last TestFlight state streamed by the server. Absent when the build ran
|
|
54
|
+
* without a testflight request, or when the server predates the feature.
|
|
55
|
+
*/
|
|
56
|
+
testflight?: TestflightEvent;
|
|
57
|
+
/**
|
|
58
|
+
* True when the client gave up waiting for the build's event stream. The
|
|
59
|
+
* exit code is fabricated in that case; the remote build may still be
|
|
60
|
+
* running and may yet succeed.
|
|
61
|
+
*/
|
|
62
|
+
timedOut?: boolean;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export type TestflightEvent = {
|
|
66
|
+
/** 'unknown' means a testflight event arrived but its payload was unreadable. */
|
|
67
|
+
state: 'uploading' | 'processing' | 'accepted' | 'failed' | 'unknown';
|
|
68
|
+
uploadId?: string;
|
|
69
|
+
buildId?: string;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export type TestflightUploadConfig = {
|
|
73
|
+
/** App Store Connect API key ID, e.g. 2X9R4HXF34. */
|
|
74
|
+
apiKeyId: string;
|
|
75
|
+
/** Issuer ID for team API keys. Omit for individual API keys. */
|
|
76
|
+
apiIssuerId?: string;
|
|
77
|
+
/** Base64-encoded content of the .p8 private key file. */
|
|
78
|
+
apiPrivateKeyBase64: string;
|
|
79
|
+
/**
|
|
80
|
+
* How long the server watches for App Store Connect's processing verdict
|
|
81
|
+
* after the upload. A FAILED verdict within the window fails the build;
|
|
82
|
+
* expiry without a verdict succeeds with the build still processing on
|
|
83
|
+
* Apple's side. 0 skips the watch. Defaults to 120.
|
|
84
|
+
*/
|
|
85
|
+
waitTimeoutSeconds?: number;
|
|
51
86
|
};
|
|
52
87
|
|
|
53
88
|
type DataListener = (chunk: string) => void;
|
|
@@ -121,6 +156,7 @@ export class ExecChildProcess implements PromiseLike<ExecResult> {
|
|
|
121
156
|
private abortController = new AbortController();
|
|
122
157
|
private sseConnection: EventSourceClient | null = null;
|
|
123
158
|
private killed = false;
|
|
159
|
+
private testflightEvent: TestflightEvent | null = null;
|
|
124
160
|
private readonly options: ExecOptions;
|
|
125
161
|
private readonly log: (level: 'debug' | 'info' | 'warn' | 'error', msg: string) => void;
|
|
126
162
|
|
|
@@ -228,8 +264,15 @@ export class ExecChildProcess implements PromiseLike<ExecResult> {
|
|
|
228
264
|
// 2. Stream logs via SSE and wait for exit code
|
|
229
265
|
const eventsUrl = `${apiUrl}/exec/${this.execId}/events`;
|
|
230
266
|
|
|
231
|
-
|
|
267
|
+
// 1 hour max for the build itself; a TestFlight request extends the
|
|
268
|
+
// budget by its server-side verdict watch plus upload headroom so a long
|
|
269
|
+
// build is not force-failed client-side while the server still succeeds.
|
|
270
|
+
let timeoutMs = 3600 * 1000;
|
|
271
|
+
if (request.testflight) {
|
|
272
|
+
timeoutMs += (Math.max(0, request.testflight.waitTimeoutSeconds ?? 120) + 900) * 1000;
|
|
273
|
+
}
|
|
232
274
|
let exitCode: number;
|
|
275
|
+
let timedOut = false;
|
|
233
276
|
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
|
234
277
|
try {
|
|
235
278
|
exitCode = await Promise.race([
|
|
@@ -243,8 +286,11 @@ export class ExecChildProcess implements PromiseLike<ExecResult> {
|
|
|
243
286
|
log('debug', 'Build killed');
|
|
244
287
|
exitCode = -1;
|
|
245
288
|
} else {
|
|
289
|
+
// The client stopped waiting; the remote build may still be running.
|
|
290
|
+
// The fabricated exit code must not read as a build failure.
|
|
246
291
|
log('warn', 'SSE completion timeout');
|
|
247
292
|
exitCode = 1;
|
|
293
|
+
timedOut = true;
|
|
248
294
|
}
|
|
249
295
|
} finally {
|
|
250
296
|
clearTimeout(timeoutId);
|
|
@@ -275,6 +321,8 @@ export class ExecChildProcess implements PromiseLike<ExecResult> {
|
|
|
275
321
|
execId: this.execId!,
|
|
276
322
|
status,
|
|
277
323
|
...(request.additionalMetadata ?? {}),
|
|
324
|
+
...(this.testflightEvent ? { testflight: this.testflightEvent } : {}),
|
|
325
|
+
...(timedOut ? { timedOut } : {}),
|
|
278
326
|
};
|
|
279
327
|
|
|
280
328
|
this.log('debug', `Build finished: ${result.status} (exit ${result.exitCode})`);
|
|
@@ -307,6 +355,15 @@ export class ExecChildProcess implements PromiseLike<ExecResult> {
|
|
|
307
355
|
this.stdout.emit('data', data);
|
|
308
356
|
} else if (eventType === 'stderr') {
|
|
309
357
|
this.stderr.emit('data', data);
|
|
358
|
+
} else if (eventType === 'testflight') {
|
|
359
|
+
try {
|
|
360
|
+
this.testflightEvent = JSON.parse(data) as TestflightEvent;
|
|
361
|
+
} catch {
|
|
362
|
+
// The event itself proves the server ran the TestFlight step,
|
|
363
|
+
// so never let a payload glitch look like a missing feature.
|
|
364
|
+
this.testflightEvent = { state: 'unknown' };
|
|
365
|
+
this.log('warn', `SSE testflight event has invalid data: ${data}`);
|
|
366
|
+
}
|
|
310
367
|
} else if (eventType === 'exitCode') {
|
|
311
368
|
const exitCode = parseInt(data, 10);
|
|
312
369
|
if (Number.isNaN(exitCode)) {
|
package/src/folder-sync.ts
CHANGED
|
@@ -59,6 +59,12 @@ export type FolderSyncOptions = {
|
|
|
59
59
|
export type SyncFolderResult = {
|
|
60
60
|
installedAppPath?: string;
|
|
61
61
|
installedBundleId?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Number of bytes transmitted to the server for this sync (full uploads plus
|
|
64
|
+
* delta patches, before transport compression). In watch mode, this reflects
|
|
65
|
+
* the initial sync only.
|
|
66
|
+
*/
|
|
67
|
+
bytesSent?: number;
|
|
62
68
|
/** Present only when watch=true; call to stop watching. */
|
|
63
69
|
stopWatching?: () => Promise<void>;
|
|
64
70
|
};
|
|
@@ -703,6 +709,7 @@ async function syncFolderOnce(
|
|
|
703
709
|
},
|
|
704
710
|
filePath: entry.absPath,
|
|
705
711
|
});
|
|
712
|
+
bytesSentFull += entry.size;
|
|
706
713
|
}
|
|
707
714
|
if (retryPayloads.length > 0) {
|
|
708
715
|
slog('debug', `server requested full for ${retryPayloads.length} files; retrying once`);
|
|
@@ -747,7 +754,7 @@ async function syncFolderOnce(
|
|
|
747
754
|
syncWorkMs,
|
|
748
755
|
)} total=${fmtMs(tookMs)}`,
|
|
749
756
|
);
|
|
750
|
-
const out: SyncFolderResult = {};
|
|
757
|
+
const out: SyncFolderResult = { bytesSent: totalBytes };
|
|
751
758
|
if (resp.installedAppPath) {
|
|
752
759
|
out.installedAppPath = resp.installedAppPath;
|
|
753
760
|
}
|
package/src/index.ts
CHANGED
|
@@ -4,7 +4,9 @@ import crypto from 'crypto';
|
|
|
4
4
|
|
|
5
5
|
import { XcodeInstances as GeneratedXcodeInstances, type XcodeInstance } from './xcode-instances';
|
|
6
6
|
import { type IosInstance } from './ios-instances';
|
|
7
|
-
import { exec, type ExecChildProcess, type ExecRequest } from '../exec-client';
|
|
7
|
+
import { exec, type ExecChildProcess, type ExecRequest, type TestflightUploadConfig } from '../exec-client';
|
|
8
|
+
|
|
9
|
+
export type { TestflightUploadConfig } from '../exec-client';
|
|
8
10
|
import {
|
|
9
11
|
syncFolder as syncFolderImpl,
|
|
10
12
|
type AdditionalFileSyncEntry,
|
|
@@ -50,6 +52,12 @@ export type SyncOptions = {
|
|
|
50
52
|
};
|
|
51
53
|
|
|
52
54
|
export type SyncResult = {
|
|
55
|
+
/**
|
|
56
|
+
* Number of bytes transmitted to the server for this sync (full uploads plus
|
|
57
|
+
* delta patches, before transport compression). In watch mode, this reflects
|
|
58
|
+
* the initial sync only.
|
|
59
|
+
*/
|
|
60
|
+
bytesSent?: number;
|
|
53
61
|
/** Present only when watch=true; call to stop watching */
|
|
54
62
|
stopWatching?: () => Promise<void>;
|
|
55
63
|
};
|
|
@@ -93,6 +101,13 @@ export type ReactNativeBuildConfig = {
|
|
|
93
101
|
export type XcodeBuildOptions = {
|
|
94
102
|
upload?: { assetName: string } | { signedUploadUrl: string };
|
|
95
103
|
signing?: XcodeSigningConfig;
|
|
104
|
+
/**
|
|
105
|
+
* Upload the signed device IPA to TestFlight after the build. Requires
|
|
106
|
+
* signing and sdk=iphoneos. Check ExecResult.testflight on completion: it is
|
|
107
|
+
* absent when the instance's limbuild predates the feature (old servers
|
|
108
|
+
* silently ignore this option).
|
|
109
|
+
*/
|
|
110
|
+
testflight?: TestflightUploadConfig;
|
|
96
111
|
reactNative?: ReactNativeBuildConfig;
|
|
97
112
|
buildSettings?: Record<string, string>;
|
|
98
113
|
};
|
|
@@ -619,10 +634,14 @@ export class XcodeInstances extends GeneratedXcodeInstances {
|
|
|
619
634
|
};
|
|
620
635
|
|
|
621
636
|
const result = await syncFolderImpl(localCodePath, codeSyncOpts);
|
|
637
|
+
const out: SyncResult = {};
|
|
638
|
+
if (result.bytesSent !== undefined) {
|
|
639
|
+
out.bytesSent = result.bytesSent;
|
|
640
|
+
}
|
|
622
641
|
if (result.stopWatching) {
|
|
623
|
-
|
|
642
|
+
out.stopWatching = result.stopWatching;
|
|
624
643
|
}
|
|
625
|
-
return
|
|
644
|
+
return out;
|
|
626
645
|
},
|
|
627
646
|
|
|
628
647
|
xcodebuild(settings?: XcodeProjectConfig, options?: XcodeBuildOptions): ExecChildProcess {
|
|
@@ -637,6 +656,7 @@ export class XcodeInstances extends GeneratedXcodeInstances {
|
|
|
637
656
|
...(settings && { xcodebuild: settings }),
|
|
638
657
|
...(options?.reactNative && { reactNative: options.reactNative }),
|
|
639
658
|
...(options?.signing && { signing: options.signing }),
|
|
659
|
+
...(options?.testflight && { testflight: options.testflight }),
|
|
640
660
|
...(options?.buildSettings && { buildSettings: options.buildSettings }),
|
|
641
661
|
};
|
|
642
662
|
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = '0.39.
|
|
1
|
+
export const VERSION = '0.39.2'; // x-release-please-version
|
package/version.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.39.
|
|
1
|
+
export declare const VERSION = "0.39.2";
|
|
2
2
|
//# sourceMappingURL=version.d.mts.map
|
package/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.39.
|
|
1
|
+
export declare const VERSION = "0.39.2";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/version.js
CHANGED
package/version.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const VERSION = '0.39.
|
|
1
|
+
export const VERSION = '0.39.2'; // x-release-please-version
|
|
2
2
|
//# sourceMappingURL=version.mjs.map
|