@sitepong/fastnode 0.1.0 → 0.1.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/dist/actions/index.cjs +227 -27
- package/dist/actions/index.cjs.map +1 -1
- package/dist/actions/index.mjs +227 -27
- package/dist/actions/index.mjs.map +1 -1
- package/dist/cli/index.cjs +227 -27
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.mjs +227 -27
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index-D6zjGlPL.d.cts +158 -0
- package/dist/index-DHw08dUc.d.ts +158 -0
- package/dist/index.cjs +228 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +228 -28
- package/dist/index.mjs.map +1 -1
- package/dist/lane/index.cjs +227 -27
- package/dist/lane/index.cjs.map +1 -1
- package/dist/lane/index.mjs +227 -27
- package/dist/lane/index.mjs.map +1 -1
- package/dist/pilot/index.cjs +190 -12
- package/dist/pilot/index.cjs.map +1 -1
- package/dist/pilot/index.d.cts +1 -1
- package/dist/pilot/index.d.ts +1 -1
- package/dist/pilot/index.mjs +186 -14
- package/dist/pilot/index.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/index-DkvinY7_.d.ts +0 -54
- package/dist/index-HRiaaX-Q.d.cts +0 -54
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { A as AppStoreConnectClient, j as Build } from './index-BLubSlgK.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shared types for the pilot module's upload backends.
|
|
5
|
+
*/
|
|
6
|
+
type UploadBackend = "altool" | "transporter";
|
|
7
|
+
interface PilotUploadOptions {
|
|
8
|
+
ipaPath: string;
|
|
9
|
+
apiKeyId: string;
|
|
10
|
+
apiIssuerId: string;
|
|
11
|
+
apiPrivateKey: string;
|
|
12
|
+
/** Apple target platform. Defaults to "ios". */
|
|
13
|
+
platform?: "ios" | "osx" | "appletvos";
|
|
14
|
+
/** Upload timeout in ms. Defaults to 30 min. */
|
|
15
|
+
timeout?: number;
|
|
16
|
+
/** Stream callback for upload progress / log lines. */
|
|
17
|
+
onOutput?: (chunk: string) => void;
|
|
18
|
+
/**
|
|
19
|
+
* Which backend to use. Defaults to "auto":
|
|
20
|
+
* - altool on macOS (requires Xcode CLI)
|
|
21
|
+
* - transporter on Linux (requires Java + iTMSTransporter)
|
|
22
|
+
*/
|
|
23
|
+
backend?: UploadBackend | "auto";
|
|
24
|
+
}
|
|
25
|
+
interface UploadResult {
|
|
26
|
+
success: boolean;
|
|
27
|
+
output: string;
|
|
28
|
+
/** Which backend actually ran. Useful for logs/metrics. */
|
|
29
|
+
backend: UploadBackend;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Upload a build to TestFlight via Apple's `altool` (macOS only).
|
|
34
|
+
*
|
|
35
|
+
* altool ships with Xcode command-line tools. It provides richer error
|
|
36
|
+
* output than iTMSTransporter but is only available on macOS.
|
|
37
|
+
*/
|
|
38
|
+
declare function uploadWithAltool(options: PilotUploadOptions): Promise<UploadResult>;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Upload a build to TestFlight via Apple's iTMSTransporter (Java).
|
|
42
|
+
*
|
|
43
|
+
* This path works on Linux (and macOS) and does NOT require Xcode.
|
|
44
|
+
* It is the primary upload path for the ship worker LXC.
|
|
45
|
+
*
|
|
46
|
+
* iTMSTransporter reads the ASC API private key from a directory
|
|
47
|
+
* named by API_PRIVATE_KEYS_DIR, looking for the file `AuthKey_<keyId>.p8`.
|
|
48
|
+
*/
|
|
49
|
+
declare function uploadWithTransporter(options: PilotUploadOptions): Promise<UploadResult>;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Classify upload failures into transient vs. permanent buckets.
|
|
53
|
+
*
|
|
54
|
+
* Apple's App Store Connect / iTMSTransporter backend is flaky:
|
|
55
|
+
* the finalize step ("CHANGE UPLOAD STATE TO COMPLETE") periodically
|
|
56
|
+
* returns 500, and the Java transporter surfaces various connection
|
|
57
|
+
* errors during long uploads. These are all safe to retry — the IPA
|
|
58
|
+
* is deterministic and Apple deduplicates on build number.
|
|
59
|
+
*
|
|
60
|
+
* Non-transient errors (invalid binary, duplicate build number, auth
|
|
61
|
+
* failure) should NOT be retried — they will never succeed without
|
|
62
|
+
* the caller taking some action.
|
|
63
|
+
*/
|
|
64
|
+
type TransientUploadError = "apple_5xx" | "finalize_failed" | "network_timeout" | "connection_reset" | "transporter_jvm_error";
|
|
65
|
+
/**
|
|
66
|
+
* Returns the transient-error kind if the output matches any known
|
|
67
|
+
* retry-worthy pattern, or `null` if the error is non-transient.
|
|
68
|
+
*/
|
|
69
|
+
declare function classifyUploadError(output: string): TransientUploadError | null;
|
|
70
|
+
/**
|
|
71
|
+
* Convenience: `true` if the upload should be retried.
|
|
72
|
+
*/
|
|
73
|
+
declare function isTransientUploadError(output: string): boolean;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Locate the iTMSTransporter binary on this host.
|
|
77
|
+
*
|
|
78
|
+
* Apple ships iTMSTransporter as a Java-based tool bundled with Xcode
|
|
79
|
+
* on macOS, and as a standalone Linux distribution used by media
|
|
80
|
+
* publishers for CI. Either works for uploading IPAs — same protocol,
|
|
81
|
+
* same ASC API key format.
|
|
82
|
+
*
|
|
83
|
+
* Resolution order:
|
|
84
|
+
* 1. ITMSTRANSPORTER_BIN env var (pinning for prod deployments)
|
|
85
|
+
* 2. Well-known system paths for the host OS
|
|
86
|
+
* 3. Throw with a clear install hint
|
|
87
|
+
*
|
|
88
|
+
* We deliberately do NOT auto-download Transporter. Apple's download
|
|
89
|
+
* URL is not versioned and the license/redistribution story is fuzzy.
|
|
90
|
+
* Prod hosts should install it once via apt/brew/manual, then pin via
|
|
91
|
+
* env var so CI is reproducible.
|
|
92
|
+
*/
|
|
93
|
+
declare function resolveTransporter(): Promise<string>;
|
|
94
|
+
/**
|
|
95
|
+
* Verify that Java is available on PATH. iTMSTransporter is a Java
|
|
96
|
+
* application and won't run without a JRE.
|
|
97
|
+
*/
|
|
98
|
+
declare function verifyJava(): Promise<{
|
|
99
|
+
version: string;
|
|
100
|
+
}>;
|
|
101
|
+
|
|
102
|
+
interface PilotDistributeOptions {
|
|
103
|
+
client: AppStoreConnectClient;
|
|
104
|
+
buildId: string;
|
|
105
|
+
groupNames?: string[];
|
|
106
|
+
changelog?: string;
|
|
107
|
+
locale?: string;
|
|
108
|
+
expirePreviousBuilds?: boolean;
|
|
109
|
+
submitForReview?: boolean;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Upload a build to TestFlight.
|
|
113
|
+
*
|
|
114
|
+
* Selects the upload backend based on the host OS:
|
|
115
|
+
* - macOS → altool (ships with Xcode CLI)
|
|
116
|
+
* - Linux → iTMSTransporter (standalone Java tool from Apple)
|
|
117
|
+
*
|
|
118
|
+
* Pass `backend` to force a specific path, e.g. for testing the
|
|
119
|
+
* Linux path on a mac dev machine.
|
|
120
|
+
*/
|
|
121
|
+
declare function uploadToTestFlight(options: PilotUploadOptions): Promise<UploadResult>;
|
|
122
|
+
declare function waitForProcessing(client: AppStoreConnectClient, params: {
|
|
123
|
+
bundleId: string;
|
|
124
|
+
buildNumber: string;
|
|
125
|
+
appVersion: string;
|
|
126
|
+
timeout?: number;
|
|
127
|
+
pollInterval?: number;
|
|
128
|
+
}): Promise<Build>;
|
|
129
|
+
declare function distributeToGroups(options: PilotDistributeOptions): Promise<string[]>;
|
|
130
|
+
declare function setChangelog(options: {
|
|
131
|
+
client: AppStoreConnectClient;
|
|
132
|
+
buildId: string;
|
|
133
|
+
changelog: string;
|
|
134
|
+
locale?: string;
|
|
135
|
+
}): Promise<void>;
|
|
136
|
+
declare function expireBuild(client: AppStoreConnectClient, buildId: string): Promise<void>;
|
|
137
|
+
|
|
138
|
+
type index_PilotDistributeOptions = PilotDistributeOptions;
|
|
139
|
+
type index_PilotUploadOptions = PilotUploadOptions;
|
|
140
|
+
type index_TransientUploadError = TransientUploadError;
|
|
141
|
+
type index_UploadBackend = UploadBackend;
|
|
142
|
+
type index_UploadResult = UploadResult;
|
|
143
|
+
declare const index_classifyUploadError: typeof classifyUploadError;
|
|
144
|
+
declare const index_distributeToGroups: typeof distributeToGroups;
|
|
145
|
+
declare const index_expireBuild: typeof expireBuild;
|
|
146
|
+
declare const index_isTransientUploadError: typeof isTransientUploadError;
|
|
147
|
+
declare const index_resolveTransporter: typeof resolveTransporter;
|
|
148
|
+
declare const index_setChangelog: typeof setChangelog;
|
|
149
|
+
declare const index_uploadToTestFlight: typeof uploadToTestFlight;
|
|
150
|
+
declare const index_uploadWithAltool: typeof uploadWithAltool;
|
|
151
|
+
declare const index_uploadWithTransporter: typeof uploadWithTransporter;
|
|
152
|
+
declare const index_verifyJava: typeof verifyJava;
|
|
153
|
+
declare const index_waitForProcessing: typeof waitForProcessing;
|
|
154
|
+
declare namespace index {
|
|
155
|
+
export { type index_PilotDistributeOptions as PilotDistributeOptions, type index_PilotUploadOptions as PilotUploadOptions, type index_TransientUploadError as TransientUploadError, type index_UploadBackend as UploadBackend, type index_UploadResult as UploadResult, index_classifyUploadError as classifyUploadError, index_distributeToGroups as distributeToGroups, index_expireBuild as expireBuild, index_isTransientUploadError as isTransientUploadError, index_resolveTransporter as resolveTransporter, index_setChangelog as setChangelog, index_uploadToTestFlight as uploadToTestFlight, index_uploadWithAltool as uploadWithAltool, index_uploadWithTransporter as uploadWithTransporter, index_verifyJava as verifyJava, index_waitForProcessing as waitForProcessing };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export { type PilotDistributeOptions as P, type TransientUploadError as T, type UploadBackend as U, type PilotUploadOptions as a, type UploadResult as b, uploadWithAltool as c, distributeToGroups as d, expireBuild as e, uploadWithTransporter as f, classifyUploadError as g, isTransientUploadError as h, index as i, resolveTransporter as r, setChangelog as s, uploadToTestFlight as u, verifyJava as v, waitForProcessing as w };
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { A as AppStoreConnectClient, j as Build } from './index-D1Izm7qt.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shared types for the pilot module's upload backends.
|
|
5
|
+
*/
|
|
6
|
+
type UploadBackend = "altool" | "transporter";
|
|
7
|
+
interface PilotUploadOptions {
|
|
8
|
+
ipaPath: string;
|
|
9
|
+
apiKeyId: string;
|
|
10
|
+
apiIssuerId: string;
|
|
11
|
+
apiPrivateKey: string;
|
|
12
|
+
/** Apple target platform. Defaults to "ios". */
|
|
13
|
+
platform?: "ios" | "osx" | "appletvos";
|
|
14
|
+
/** Upload timeout in ms. Defaults to 30 min. */
|
|
15
|
+
timeout?: number;
|
|
16
|
+
/** Stream callback for upload progress / log lines. */
|
|
17
|
+
onOutput?: (chunk: string) => void;
|
|
18
|
+
/**
|
|
19
|
+
* Which backend to use. Defaults to "auto":
|
|
20
|
+
* - altool on macOS (requires Xcode CLI)
|
|
21
|
+
* - transporter on Linux (requires Java + iTMSTransporter)
|
|
22
|
+
*/
|
|
23
|
+
backend?: UploadBackend | "auto";
|
|
24
|
+
}
|
|
25
|
+
interface UploadResult {
|
|
26
|
+
success: boolean;
|
|
27
|
+
output: string;
|
|
28
|
+
/** Which backend actually ran. Useful for logs/metrics. */
|
|
29
|
+
backend: UploadBackend;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Upload a build to TestFlight via Apple's `altool` (macOS only).
|
|
34
|
+
*
|
|
35
|
+
* altool ships with Xcode command-line tools. It provides richer error
|
|
36
|
+
* output than iTMSTransporter but is only available on macOS.
|
|
37
|
+
*/
|
|
38
|
+
declare function uploadWithAltool(options: PilotUploadOptions): Promise<UploadResult>;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Upload a build to TestFlight via Apple's iTMSTransporter (Java).
|
|
42
|
+
*
|
|
43
|
+
* This path works on Linux (and macOS) and does NOT require Xcode.
|
|
44
|
+
* It is the primary upload path for the ship worker LXC.
|
|
45
|
+
*
|
|
46
|
+
* iTMSTransporter reads the ASC API private key from a directory
|
|
47
|
+
* named by API_PRIVATE_KEYS_DIR, looking for the file `AuthKey_<keyId>.p8`.
|
|
48
|
+
*/
|
|
49
|
+
declare function uploadWithTransporter(options: PilotUploadOptions): Promise<UploadResult>;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Classify upload failures into transient vs. permanent buckets.
|
|
53
|
+
*
|
|
54
|
+
* Apple's App Store Connect / iTMSTransporter backend is flaky:
|
|
55
|
+
* the finalize step ("CHANGE UPLOAD STATE TO COMPLETE") periodically
|
|
56
|
+
* returns 500, and the Java transporter surfaces various connection
|
|
57
|
+
* errors during long uploads. These are all safe to retry — the IPA
|
|
58
|
+
* is deterministic and Apple deduplicates on build number.
|
|
59
|
+
*
|
|
60
|
+
* Non-transient errors (invalid binary, duplicate build number, auth
|
|
61
|
+
* failure) should NOT be retried — they will never succeed without
|
|
62
|
+
* the caller taking some action.
|
|
63
|
+
*/
|
|
64
|
+
type TransientUploadError = "apple_5xx" | "finalize_failed" | "network_timeout" | "connection_reset" | "transporter_jvm_error";
|
|
65
|
+
/**
|
|
66
|
+
* Returns the transient-error kind if the output matches any known
|
|
67
|
+
* retry-worthy pattern, or `null` if the error is non-transient.
|
|
68
|
+
*/
|
|
69
|
+
declare function classifyUploadError(output: string): TransientUploadError | null;
|
|
70
|
+
/**
|
|
71
|
+
* Convenience: `true` if the upload should be retried.
|
|
72
|
+
*/
|
|
73
|
+
declare function isTransientUploadError(output: string): boolean;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Locate the iTMSTransporter binary on this host.
|
|
77
|
+
*
|
|
78
|
+
* Apple ships iTMSTransporter as a Java-based tool bundled with Xcode
|
|
79
|
+
* on macOS, and as a standalone Linux distribution used by media
|
|
80
|
+
* publishers for CI. Either works for uploading IPAs — same protocol,
|
|
81
|
+
* same ASC API key format.
|
|
82
|
+
*
|
|
83
|
+
* Resolution order:
|
|
84
|
+
* 1. ITMSTRANSPORTER_BIN env var (pinning for prod deployments)
|
|
85
|
+
* 2. Well-known system paths for the host OS
|
|
86
|
+
* 3. Throw with a clear install hint
|
|
87
|
+
*
|
|
88
|
+
* We deliberately do NOT auto-download Transporter. Apple's download
|
|
89
|
+
* URL is not versioned and the license/redistribution story is fuzzy.
|
|
90
|
+
* Prod hosts should install it once via apt/brew/manual, then pin via
|
|
91
|
+
* env var so CI is reproducible.
|
|
92
|
+
*/
|
|
93
|
+
declare function resolveTransporter(): Promise<string>;
|
|
94
|
+
/**
|
|
95
|
+
* Verify that Java is available on PATH. iTMSTransporter is a Java
|
|
96
|
+
* application and won't run without a JRE.
|
|
97
|
+
*/
|
|
98
|
+
declare function verifyJava(): Promise<{
|
|
99
|
+
version: string;
|
|
100
|
+
}>;
|
|
101
|
+
|
|
102
|
+
interface PilotDistributeOptions {
|
|
103
|
+
client: AppStoreConnectClient;
|
|
104
|
+
buildId: string;
|
|
105
|
+
groupNames?: string[];
|
|
106
|
+
changelog?: string;
|
|
107
|
+
locale?: string;
|
|
108
|
+
expirePreviousBuilds?: boolean;
|
|
109
|
+
submitForReview?: boolean;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Upload a build to TestFlight.
|
|
113
|
+
*
|
|
114
|
+
* Selects the upload backend based on the host OS:
|
|
115
|
+
* - macOS → altool (ships with Xcode CLI)
|
|
116
|
+
* - Linux → iTMSTransporter (standalone Java tool from Apple)
|
|
117
|
+
*
|
|
118
|
+
* Pass `backend` to force a specific path, e.g. for testing the
|
|
119
|
+
* Linux path on a mac dev machine.
|
|
120
|
+
*/
|
|
121
|
+
declare function uploadToTestFlight(options: PilotUploadOptions): Promise<UploadResult>;
|
|
122
|
+
declare function waitForProcessing(client: AppStoreConnectClient, params: {
|
|
123
|
+
bundleId: string;
|
|
124
|
+
buildNumber: string;
|
|
125
|
+
appVersion: string;
|
|
126
|
+
timeout?: number;
|
|
127
|
+
pollInterval?: number;
|
|
128
|
+
}): Promise<Build>;
|
|
129
|
+
declare function distributeToGroups(options: PilotDistributeOptions): Promise<string[]>;
|
|
130
|
+
declare function setChangelog(options: {
|
|
131
|
+
client: AppStoreConnectClient;
|
|
132
|
+
buildId: string;
|
|
133
|
+
changelog: string;
|
|
134
|
+
locale?: string;
|
|
135
|
+
}): Promise<void>;
|
|
136
|
+
declare function expireBuild(client: AppStoreConnectClient, buildId: string): Promise<void>;
|
|
137
|
+
|
|
138
|
+
type index_PilotDistributeOptions = PilotDistributeOptions;
|
|
139
|
+
type index_PilotUploadOptions = PilotUploadOptions;
|
|
140
|
+
type index_TransientUploadError = TransientUploadError;
|
|
141
|
+
type index_UploadBackend = UploadBackend;
|
|
142
|
+
type index_UploadResult = UploadResult;
|
|
143
|
+
declare const index_classifyUploadError: typeof classifyUploadError;
|
|
144
|
+
declare const index_distributeToGroups: typeof distributeToGroups;
|
|
145
|
+
declare const index_expireBuild: typeof expireBuild;
|
|
146
|
+
declare const index_isTransientUploadError: typeof isTransientUploadError;
|
|
147
|
+
declare const index_resolveTransporter: typeof resolveTransporter;
|
|
148
|
+
declare const index_setChangelog: typeof setChangelog;
|
|
149
|
+
declare const index_uploadToTestFlight: typeof uploadToTestFlight;
|
|
150
|
+
declare const index_uploadWithAltool: typeof uploadWithAltool;
|
|
151
|
+
declare const index_uploadWithTransporter: typeof uploadWithTransporter;
|
|
152
|
+
declare const index_verifyJava: typeof verifyJava;
|
|
153
|
+
declare const index_waitForProcessing: typeof waitForProcessing;
|
|
154
|
+
declare namespace index {
|
|
155
|
+
export { type index_PilotDistributeOptions as PilotDistributeOptions, type index_PilotUploadOptions as PilotUploadOptions, type index_TransientUploadError as TransientUploadError, type index_UploadBackend as UploadBackend, type index_UploadResult as UploadResult, index_classifyUploadError as classifyUploadError, index_distributeToGroups as distributeToGroups, index_expireBuild as expireBuild, index_isTransientUploadError as isTransientUploadError, index_resolveTransporter as resolveTransporter, index_setChangelog as setChangelog, index_uploadToTestFlight as uploadToTestFlight, index_uploadWithAltool as uploadWithAltool, index_uploadWithTransporter as uploadWithTransporter, index_verifyJava as verifyJava, index_waitForProcessing as waitForProcessing };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export { type PilotDistributeOptions as P, type TransientUploadError as T, type UploadBackend as U, type PilotUploadOptions as a, type UploadResult as b, uploadWithAltool as c, distributeToGroups as d, expireBuild as e, uploadWithTransporter as f, classifyUploadError as g, isTransientUploadError as h, index as i, resolveTransporter as r, setChangelog as s, uploadToTestFlight as u, verifyJava as v, waitForProcessing as w };
|
package/dist/index.cjs
CHANGED
|
@@ -3029,8 +3029,8 @@ async function revokeExpiredCertificates(options) {
|
|
|
3029
3029
|
return count;
|
|
3030
3030
|
}
|
|
3031
3031
|
async function importToKeychain(certData, keychainPath, keychainPassword) {
|
|
3032
|
-
const { tmpdir:
|
|
3033
|
-
const tempCertPath = path.join(
|
|
3032
|
+
const { tmpdir: tmpdir10 } = await import('os');
|
|
3033
|
+
const tempCertPath = path.join(tmpdir10(), `fastnode-cert-${Date.now()}.cer`);
|
|
3034
3034
|
await promises.writeFile(tempCertPath, certData);
|
|
3035
3035
|
try {
|
|
3036
3036
|
const args = [
|
|
@@ -4019,23 +4019,13 @@ var init_produce = __esm({
|
|
|
4019
4019
|
};
|
|
4020
4020
|
}
|
|
4021
4021
|
});
|
|
4022
|
-
|
|
4023
|
-
// src/pilot/index.ts
|
|
4024
|
-
var pilot_exports = {};
|
|
4025
|
-
__export(pilot_exports, {
|
|
4026
|
-
distributeToGroups: () => distributeToGroups,
|
|
4027
|
-
expireBuild: () => expireBuild,
|
|
4028
|
-
setChangelog: () => setChangelog,
|
|
4029
|
-
uploadToTestFlight: () => uploadToTestFlight,
|
|
4030
|
-
waitForProcessing: () => waitForProcessing
|
|
4031
|
-
});
|
|
4032
|
-
async function uploadToTestFlight(options) {
|
|
4022
|
+
async function uploadWithAltool(options) {
|
|
4033
4023
|
if (!fs.existsSync(options.ipaPath)) {
|
|
4034
4024
|
throw new Error(`File not found: ${options.ipaPath}`);
|
|
4035
4025
|
}
|
|
4036
4026
|
const platform = options.platform ?? "ios";
|
|
4037
4027
|
const timeout = options.timeout ?? 18e5;
|
|
4038
|
-
const keyDir = await promises.mkdtemp(path.join(os.tmpdir(), "fastnode-
|
|
4028
|
+
const keyDir = await promises.mkdtemp(path.join(os.tmpdir(), "fastnode-altool-"));
|
|
4039
4029
|
const keyPath = path.join(keyDir, `AuthKey_${options.apiKeyId}.p8`);
|
|
4040
4030
|
await promises.writeFile(keyPath, options.apiPrivateKey);
|
|
4041
4031
|
return new Promise((resolve4) => {
|
|
@@ -4059,24 +4049,228 @@ async function uploadToTestFlight(options) {
|
|
|
4059
4049
|
const timer = setTimeout(() => {
|
|
4060
4050
|
child.kill("SIGTERM");
|
|
4061
4051
|
}, timeout);
|
|
4062
|
-
|
|
4052
|
+
const onData = (data) => {
|
|
4063
4053
|
const chunk = data.toString();
|
|
4064
4054
|
output += chunk;
|
|
4065
4055
|
options.onOutput?.(chunk);
|
|
4056
|
+
};
|
|
4057
|
+
child.stdout.on("data", onData);
|
|
4058
|
+
child.stderr.on("data", onData);
|
|
4059
|
+
child.on("close", async (code) => {
|
|
4060
|
+
clearTimeout(timer);
|
|
4061
|
+
await promises.unlink(keyPath).catch(() => {
|
|
4062
|
+
});
|
|
4063
|
+
await promises.rm(keyDir, { recursive: true, force: true }).catch(() => {
|
|
4064
|
+
});
|
|
4065
|
+
resolve4({ success: code === 0, output, backend: "altool" });
|
|
4066
4066
|
});
|
|
4067
|
-
|
|
4067
|
+
});
|
|
4068
|
+
}
|
|
4069
|
+
var init_upload_altool = __esm({
|
|
4070
|
+
"src/pilot/upload-altool.ts"() {
|
|
4071
|
+
}
|
|
4072
|
+
});
|
|
4073
|
+
async function resolveTransporter() {
|
|
4074
|
+
const override = process.env.ITMSTRANSPORTER_BIN;
|
|
4075
|
+
if (override) {
|
|
4076
|
+
if (!fs.existsSync(override)) {
|
|
4077
|
+
throw new Error(
|
|
4078
|
+
`ITMSTRANSPORTER_BIN is set to "${override}" but that path does not exist.`
|
|
4079
|
+
);
|
|
4080
|
+
}
|
|
4081
|
+
return override;
|
|
4082
|
+
}
|
|
4083
|
+
const candidates = process.platform === "darwin" ? [
|
|
4084
|
+
// Xcode 15+: Transporter.app bundled with Xcode
|
|
4085
|
+
"/Applications/Xcode.app/Contents/SharedFrameworks/ContentDeliveryServices.framework/Versions/A/itms/bin/iTMSTransporter",
|
|
4086
|
+
// Standalone Transporter.app from the Mac App Store
|
|
4087
|
+
"/Applications/Transporter.app/Contents/itms/bin/iTMSTransporter"
|
|
4088
|
+
] : [
|
|
4089
|
+
"/usr/local/itms/bin/iTMSTransporter",
|
|
4090
|
+
"/opt/itms/bin/iTMSTransporter",
|
|
4091
|
+
"/usr/local/bin/iTMSTransporter"
|
|
4092
|
+
];
|
|
4093
|
+
for (const path of candidates) {
|
|
4094
|
+
if (fs.existsSync(path)) return path;
|
|
4095
|
+
}
|
|
4096
|
+
throw new Error(
|
|
4097
|
+
[
|
|
4098
|
+
"iTMSTransporter not found.",
|
|
4099
|
+
"",
|
|
4100
|
+
"Install options:",
|
|
4101
|
+
process.platform === "darwin" ? " - Install Xcode (includes Transporter)" : " - Download Apple's standalone iTMSTransporter package for Linux",
|
|
4102
|
+
" - Or set ITMSTRANSPORTER_BIN to the absolute path of the binary",
|
|
4103
|
+
"",
|
|
4104
|
+
`Searched: ${candidates.join(", ")}`
|
|
4105
|
+
].join("\n")
|
|
4106
|
+
);
|
|
4107
|
+
}
|
|
4108
|
+
async function verifyJava() {
|
|
4109
|
+
return new Promise((resolve4, reject) => {
|
|
4110
|
+
const child = child_process.spawn("java", ["-version"], { stdio: ["ignore", "pipe", "pipe"] });
|
|
4111
|
+
let stderr = "";
|
|
4112
|
+
child.stderr.on("data", (d) => {
|
|
4113
|
+
stderr += d.toString();
|
|
4114
|
+
});
|
|
4115
|
+
child.on("error", (err) => {
|
|
4116
|
+
reject(
|
|
4117
|
+
new Error(
|
|
4118
|
+
`java not found on PATH (${err.message}). Install Java 17 LTS and ensure it is on PATH.`
|
|
4119
|
+
)
|
|
4120
|
+
);
|
|
4121
|
+
});
|
|
4122
|
+
child.on("close", (code) => {
|
|
4123
|
+
if (code !== 0) {
|
|
4124
|
+
reject(new Error(`java -version exited ${code}: ${stderr}`));
|
|
4125
|
+
return;
|
|
4126
|
+
}
|
|
4127
|
+
const match = stderr.match(/version "([^"]+)"/);
|
|
4128
|
+
resolve4({ version: match?.[1] ?? "unknown" });
|
|
4129
|
+
});
|
|
4130
|
+
});
|
|
4131
|
+
}
|
|
4132
|
+
var init_transporter_install = __esm({
|
|
4133
|
+
"src/pilot/transporter-install.ts"() {
|
|
4134
|
+
}
|
|
4135
|
+
});
|
|
4136
|
+
async function uploadWithTransporter(options) {
|
|
4137
|
+
if (!fs.existsSync(options.ipaPath)) {
|
|
4138
|
+
throw new Error(`File not found: ${options.ipaPath}`);
|
|
4139
|
+
}
|
|
4140
|
+
await verifyJava();
|
|
4141
|
+
const transporterBin = await resolveTransporter();
|
|
4142
|
+
const platform = options.platform ?? "ios";
|
|
4143
|
+
const timeout = options.timeout ?? 18e5;
|
|
4144
|
+
const keyDir = await promises.mkdtemp(path.join(os.tmpdir(), "fastnode-itms-"));
|
|
4145
|
+
const keyPath = path.join(keyDir, `AuthKey_${options.apiKeyId}.p8`);
|
|
4146
|
+
await promises.writeFile(keyPath, options.apiPrivateKey);
|
|
4147
|
+
return new Promise((resolve4) => {
|
|
4148
|
+
const args = [
|
|
4149
|
+
"-m",
|
|
4150
|
+
"upload",
|
|
4151
|
+
"-assetFile",
|
|
4152
|
+
options.ipaPath,
|
|
4153
|
+
"-apiKey",
|
|
4154
|
+
options.apiKeyId,
|
|
4155
|
+
"-apiIssuer",
|
|
4156
|
+
options.apiIssuerId,
|
|
4157
|
+
// WONoPause prevents the JVM from waiting on stdin in non-TTY
|
|
4158
|
+
// environments (CI, LaunchAgent) where it would hang forever.
|
|
4159
|
+
"-WONoPause",
|
|
4160
|
+
"true"
|
|
4161
|
+
];
|
|
4162
|
+
if (platform !== "ios") {
|
|
4163
|
+
args.push("-bundleType", platform);
|
|
4164
|
+
}
|
|
4165
|
+
const child = child_process.spawn(transporterBin, args, {
|
|
4166
|
+
env: {
|
|
4167
|
+
...process.env,
|
|
4168
|
+
API_PRIVATE_KEYS_DIR: keyDir
|
|
4169
|
+
},
|
|
4170
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
4171
|
+
});
|
|
4172
|
+
let output = "";
|
|
4173
|
+
const timer = setTimeout(() => {
|
|
4174
|
+
child.kill("SIGTERM");
|
|
4175
|
+
}, timeout);
|
|
4176
|
+
const onData = (data) => {
|
|
4068
4177
|
const chunk = data.toString();
|
|
4069
4178
|
output += chunk;
|
|
4070
4179
|
options.onOutput?.(chunk);
|
|
4071
|
-
}
|
|
4180
|
+
};
|
|
4181
|
+
child.stdout.on("data", onData);
|
|
4182
|
+
child.stderr.on("data", onData);
|
|
4072
4183
|
child.on("close", async (code) => {
|
|
4073
4184
|
clearTimeout(timer);
|
|
4074
|
-
await promises.
|
|
4185
|
+
await promises.rm(keyDir, { recursive: true, force: true }).catch(() => {
|
|
4186
|
+
});
|
|
4187
|
+
resolve4({ success: code === 0, output, backend: "transporter" });
|
|
4188
|
+
});
|
|
4189
|
+
child.on("error", async (err) => {
|
|
4190
|
+
clearTimeout(timer);
|
|
4191
|
+
await promises.rm(keyDir, { recursive: true, force: true }).catch(() => {
|
|
4192
|
+
});
|
|
4193
|
+
resolve4({
|
|
4194
|
+
success: false,
|
|
4195
|
+
output: output + `
|
|
4196
|
+
Process error: ${err.message}`,
|
|
4197
|
+
backend: "transporter"
|
|
4075
4198
|
});
|
|
4076
|
-
resolve4({ success: code === 0, output });
|
|
4077
4199
|
});
|
|
4078
4200
|
});
|
|
4079
4201
|
}
|
|
4202
|
+
var init_upload_transporter = __esm({
|
|
4203
|
+
"src/pilot/upload-transporter.ts"() {
|
|
4204
|
+
init_transporter_install();
|
|
4205
|
+
}
|
|
4206
|
+
});
|
|
4207
|
+
|
|
4208
|
+
// src/pilot/classify.ts
|
|
4209
|
+
function classifyUploadError(output) {
|
|
4210
|
+
for (const { pattern, kind } of RULES) {
|
|
4211
|
+
if (pattern.test(output)) return kind;
|
|
4212
|
+
}
|
|
4213
|
+
return null;
|
|
4214
|
+
}
|
|
4215
|
+
function isTransientUploadError(output) {
|
|
4216
|
+
return classifyUploadError(output) !== null;
|
|
4217
|
+
}
|
|
4218
|
+
var RULES;
|
|
4219
|
+
var init_classify = __esm({
|
|
4220
|
+
"src/pilot/classify.ts"() {
|
|
4221
|
+
RULES = [
|
|
4222
|
+
// Apple's finalize-upload call returning 5xx — the most common transient
|
|
4223
|
+
// failure we see in practice. Example:
|
|
4224
|
+
// "CHANGE UPLOAD STATE TO COMPLETE (UPLOADING ASSET DESCRIPTION):
|
|
4225
|
+
// received status code 500; internal server error."
|
|
4226
|
+
{ pattern: /CHANGE UPLOAD STATE TO COMPLETE/i, kind: "finalize_failed" },
|
|
4227
|
+
// Generic 5xx from ASC backend services
|
|
4228
|
+
{ pattern: /status code 5\d\d/i, kind: "apple_5xx" },
|
|
4229
|
+
{ pattern: /internal server error/i, kind: "apple_5xx" },
|
|
4230
|
+
{ pattern: /Service Unavailable/i, kind: "apple_5xx" },
|
|
4231
|
+
{ pattern: /Bad Gateway/i, kind: "apple_5xx" },
|
|
4232
|
+
// Network-level interruptions during the upload body transfer
|
|
4233
|
+
{ pattern: /Connection reset/i, kind: "connection_reset" },
|
|
4234
|
+
{ pattern: /SocketException/i, kind: "connection_reset" },
|
|
4235
|
+
{ pattern: /Broken pipe/i, kind: "connection_reset" },
|
|
4236
|
+
// Timeouts — distinct from resets because the other side may have
|
|
4237
|
+
// actually processed the request, so dedupe logic may matter.
|
|
4238
|
+
{ pattern: /Read timed out/i, kind: "network_timeout" },
|
|
4239
|
+
{ pattern: /SocketTimeoutException/i, kind: "network_timeout" },
|
|
4240
|
+
{ pattern: /Operation timed out/i, kind: "network_timeout" },
|
|
4241
|
+
// JVM-internal errors from iTMSTransporter (OOM, thread interruption, etc.)
|
|
4242
|
+
{ pattern: /java\.lang\.OutOfMemoryError/i, kind: "transporter_jvm_error" },
|
|
4243
|
+
{ pattern: /EOFException/i, kind: "transporter_jvm_error" }
|
|
4244
|
+
];
|
|
4245
|
+
}
|
|
4246
|
+
});
|
|
4247
|
+
|
|
4248
|
+
// src/pilot/index.ts
|
|
4249
|
+
var pilot_exports = {};
|
|
4250
|
+
__export(pilot_exports, {
|
|
4251
|
+
classifyUploadError: () => classifyUploadError,
|
|
4252
|
+
distributeToGroups: () => distributeToGroups,
|
|
4253
|
+
expireBuild: () => expireBuild,
|
|
4254
|
+
isTransientUploadError: () => isTransientUploadError,
|
|
4255
|
+
resolveTransporter: () => resolveTransporter,
|
|
4256
|
+
setChangelog: () => setChangelog,
|
|
4257
|
+
uploadToTestFlight: () => uploadToTestFlight,
|
|
4258
|
+
uploadWithAltool: () => uploadWithAltool,
|
|
4259
|
+
uploadWithTransporter: () => uploadWithTransporter,
|
|
4260
|
+
verifyJava: () => verifyJava,
|
|
4261
|
+
waitForProcessing: () => waitForProcessing
|
|
4262
|
+
});
|
|
4263
|
+
async function uploadToTestFlight(options) {
|
|
4264
|
+
const backend = selectBackend(options.backend ?? "auto");
|
|
4265
|
+
if (backend === "altool") {
|
|
4266
|
+
return uploadWithAltool(options);
|
|
4267
|
+
}
|
|
4268
|
+
return uploadWithTransporter(options);
|
|
4269
|
+
}
|
|
4270
|
+
function selectBackend(pref) {
|
|
4271
|
+
if (pref !== "auto") return pref;
|
|
4272
|
+
return process.platform === "darwin" ? "altool" : "transporter";
|
|
4273
|
+
}
|
|
4080
4274
|
async function waitForProcessing(client, params) {
|
|
4081
4275
|
const timeout = params.timeout ?? 18e5;
|
|
4082
4276
|
const pollInterval = params.pollInterval ?? 3e4;
|
|
@@ -4197,6 +4391,12 @@ function sleep2(ms) {
|
|
|
4197
4391
|
var init_pilot = __esm({
|
|
4198
4392
|
"src/pilot/index.ts"() {
|
|
4199
4393
|
init_request();
|
|
4394
|
+
init_upload_altool();
|
|
4395
|
+
init_upload_transporter();
|
|
4396
|
+
init_upload_altool();
|
|
4397
|
+
init_upload_transporter();
|
|
4398
|
+
init_classify();
|
|
4399
|
+
init_transporter_install();
|
|
4200
4400
|
}
|
|
4201
4401
|
});
|
|
4202
4402
|
async function loadMetadata(metadataPath) {
|
|
@@ -4300,9 +4500,9 @@ var init_platform = __esm({
|
|
|
4300
4500
|
// src/xcode/upload.ts
|
|
4301
4501
|
var upload_exports = {};
|
|
4302
4502
|
__export(upload_exports, {
|
|
4303
|
-
uploadWithAltool: () =>
|
|
4503
|
+
uploadWithAltool: () => uploadWithAltool2
|
|
4304
4504
|
});
|
|
4305
|
-
async function
|
|
4505
|
+
async function uploadWithAltool2(options) {
|
|
4306
4506
|
requireMacOS("altool upload");
|
|
4307
4507
|
let keyDir;
|
|
4308
4508
|
if (options.apiPrivateKey && !options.apiKeyPath) {
|
|
@@ -4411,8 +4611,8 @@ async function uploadToAppStore(options) {
|
|
|
4411
4611
|
if (!options.skipBinaryUpload) {
|
|
4412
4612
|
const binaryPath = options.ipaPath ?? options.pkgPath;
|
|
4413
4613
|
if (binaryPath && options.apiKeyId && options.apiIssuerId) {
|
|
4414
|
-
const { uploadWithAltool:
|
|
4415
|
-
await
|
|
4614
|
+
const { uploadWithAltool: uploadWithAltool3 } = await Promise.resolve().then(() => (init_upload(), upload_exports));
|
|
4615
|
+
await uploadWithAltool3({
|
|
4416
4616
|
filePath: binaryPath,
|
|
4417
4617
|
apiKeyId: options.apiKeyId,
|
|
4418
4618
|
apiIssuerId: options.apiIssuerId,
|
|
@@ -5388,8 +5588,8 @@ async function captureScreenshots(options) {
|
|
|
5388
5588
|
const outputDir = options.outputDirectory ?? path.join(process.cwd(), "screenshots");
|
|
5389
5589
|
const retries = options.numberOfRetries ?? 1;
|
|
5390
5590
|
if (options.clearPreviousScreenshots && fs.existsSync(outputDir)) {
|
|
5391
|
-
const { rm:
|
|
5392
|
-
await
|
|
5591
|
+
const { rm: rm5 } = await import('fs/promises');
|
|
5592
|
+
await rm5(outputDir, { recursive: true, force: true });
|
|
5393
5593
|
}
|
|
5394
5594
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
5395
5595
|
const screenshots = {};
|
|
@@ -6768,14 +6968,14 @@ var init_building = __esm({
|
|
|
6768
6968
|
name: "clean_build_artifacts",
|
|
6769
6969
|
description: "Remove build artifacts (IPA, dSYM, etc.)",
|
|
6770
6970
|
async run(params, ctx) {
|
|
6771
|
-
const { rm:
|
|
6971
|
+
const { rm: rm5 } = await import('fs/promises');
|
|
6772
6972
|
const paths = [
|
|
6773
6973
|
ctx.get("IPA_OUTPUT_PATH"),
|
|
6774
6974
|
ctx.get("PKG_OUTPUT_PATH"),
|
|
6775
6975
|
ctx.get("DSYM_OUTPUT_PATH")
|
|
6776
6976
|
].filter(Boolean);
|
|
6777
6977
|
for (const p of paths) {
|
|
6778
|
-
await
|
|
6978
|
+
await rm5(p, { force: true }).catch(() => {
|
|
6779
6979
|
});
|
|
6780
6980
|
}
|
|
6781
6981
|
return { cleaned: paths };
|
|
@@ -7812,7 +8012,7 @@ __export(xcode_exports, {
|
|
|
7812
8012
|
setBuildNumber: () => setBuildNumber,
|
|
7813
8013
|
setVersionNumber: () => setVersionNumber,
|
|
7814
8014
|
updateSigningSettings: () => updateSigningSettings,
|
|
7815
|
-
uploadWithAltool: () =>
|
|
8015
|
+
uploadWithAltool: () => uploadWithAltool2
|
|
7816
8016
|
});
|
|
7817
8017
|
init_platform();
|
|
7818
8018
|
|