@mpgd/cli 0.34.0 → 0.36.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/dist/android-bundle-signer.d.ts +2 -0
- package/dist/android-bundle-signer.js +38 -0
- package/dist/android-signing-session.d.ts +22 -0
- package/dist/android-signing-session.js +198 -0
- package/dist/artifact-inspection-environment.d.ts +2 -0
- package/dist/artifact-inspection-environment.js +31 -0
- package/dist/asc-pin.json +26 -0
- package/dist/capacitor-shell-starter.d.ts +1 -0
- package/dist/capacitor-shell-starter.js +9 -6
- package/dist/deploy-planning.d.ts +64 -0
- package/dist/deploy-planning.js +471 -0
- package/dist/deploy-process.d.ts +28 -0
- package/dist/deploy-process.js +197 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +483 -13
- package/dist/ios-ipa-inspection.js +151 -0
- package/dist/ios-keychain-import.swift +92 -0
- package/dist/ios-plist.d.ts +2 -0
- package/dist/ios-plist.js +75 -0
- package/dist/ios-signing-profile.d.ts +12 -0
- package/dist/ios-signing-profile.js +60 -0
- package/dist/ios-signing-session.d.ts +22 -0
- package/dist/ios-signing-session.js +256 -0
- package/dist/kit-upgrade-target-readiness.d.ts +8 -0
- package/dist/kit-upgrade-target-readiness.js +119 -0
- package/dist/kit-upgrade.d.ts +41 -0
- package/dist/kit-upgrade.js +489 -0
- package/dist/native-build-info.json +5 -0
- package/dist/native-build-target.js +12032 -0
- package/dist/native-deploy-run.d.ts +35 -0
- package/dist/native-deploy-run.js +462 -0
- package/dist/native-deploy-submission.d.ts +40 -0
- package/dist/native-deploy-submission.js +244 -0
- package/dist/native-deploy-workflow.d.ts +11 -0
- package/dist/native-deploy-workflow.js +328 -0
- package/dist/play-internal-submission.d.ts +32 -0
- package/dist/play-internal-submission.js +247 -0
- package/dist/play-publisher-port.d.ts +30 -0
- package/dist/play-publisher-port.js +1 -0
- package/dist/play-sdk-adapter.js +78 -0
- package/dist/release-state.d.ts +140 -0
- package/dist/release-state.js +1046 -0
- package/dist/release-workspace.d.ts +61 -0
- package/dist/release-workspace.js +504 -0
- package/dist/testflight-submission.d.ts +49 -0
- package/dist/testflight-submission.js +462 -0
- package/package.json +20 -13
- package/templates/phaser-game/README.md +23 -8
- package/templates/phaser-game/src/main.ts +34 -33
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { runReleaseProcess } from './deploy-process.js';
|
|
3
|
+
import { artifactInspectionEnvironment } from './artifact-inspection-environment.js';
|
|
4
|
+
const signerPattern = /\bSHA256:\s*((?:[A-Fa-f0-9]{2}:){31}[A-Fa-f0-9]{2})/u;
|
|
5
|
+
const timeoutMs = 60_000;
|
|
6
|
+
const maxOutputBytes = 1024 * 1024;
|
|
7
|
+
/** Recheck the signer of these AAB bytes before persisting or submitting them. */
|
|
8
|
+
export async function inspectAndroidBundleSigner(aabFile) {
|
|
9
|
+
const bundle = path.resolve(aabFile);
|
|
10
|
+
const options = {
|
|
11
|
+
cwd: path.dirname(bundle),
|
|
12
|
+
timeoutMs,
|
|
13
|
+
maxOutputBytes,
|
|
14
|
+
environment: artifactInspectionEnvironment(),
|
|
15
|
+
};
|
|
16
|
+
const verified = await runReleaseProcess({
|
|
17
|
+
...options,
|
|
18
|
+
command: 'jarsigner',
|
|
19
|
+
args: ['-verify', '-verbose', bundle],
|
|
20
|
+
});
|
|
21
|
+
if (verified.truncated || !/\bjar verified\./u.test(verified.output)
|
|
22
|
+
|| /jar is unsigned|contains unsigned entries|has expired/iu.test(verified.output)) {
|
|
23
|
+
throw new Error('Android App Bundle JAR signature verification failed.');
|
|
24
|
+
}
|
|
25
|
+
const certificate = await runReleaseProcess({
|
|
26
|
+
...options,
|
|
27
|
+
command: 'keytool',
|
|
28
|
+
args: ['-J-Duser.language=en', '-printcert', '-jarfile', bundle],
|
|
29
|
+
});
|
|
30
|
+
const signer = /\bSigner #1:/u.test(certificate.output)
|
|
31
|
+
? signerPattern.exec(certificate.output)?.[1]
|
|
32
|
+
: undefined;
|
|
33
|
+
if (certificate.truncated || /\bSigner #2:/u.test(certificate.output)
|
|
34
|
+
|| signer === undefined) {
|
|
35
|
+
throw new Error('Android App Bundle must have exactly one inspectable signer.');
|
|
36
|
+
}
|
|
37
|
+
return signer.replaceAll(':', '').toLowerCase();
|
|
38
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface AndroidUploadSigningInput {
|
|
2
|
+
readonly keystoreFile: string;
|
|
3
|
+
readonly storePassword: string;
|
|
4
|
+
readonly keyAlias: string;
|
|
5
|
+
readonly keyPassword: string;
|
|
6
|
+
readonly expectedCertSha256: string;
|
|
7
|
+
readonly environment?: NodeJS.ProcessEnv;
|
|
8
|
+
readonly signal?: AbortSignal;
|
|
9
|
+
readonly temporaryParent?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface AndroidUploadSigningSession {
|
|
12
|
+
readonly environment: NodeJS.ProcessEnv;
|
|
13
|
+
readonly expectedCertSha256: string;
|
|
14
|
+
readonly temporaryKeystore: string;
|
|
15
|
+
readonly gradleInitScript: string;
|
|
16
|
+
readonly secretValues: readonly string[];
|
|
17
|
+
dispose(): void;
|
|
18
|
+
}
|
|
19
|
+
/** Restore one upload key to an owned temporary path and preflight its identity. */
|
|
20
|
+
export declare function prepareAndroidUploadSigningSession(input: AndroidUploadSigningInput): Promise<AndroidUploadSigningSession>;
|
|
21
|
+
/** Always remove the restored key after a build, failure, or cancellation. */
|
|
22
|
+
export declare function withAndroidUploadSigningSession<T>(input: AndroidUploadSigningInput, action: (session: AndroidUploadSigningSession) => Promise<T>): Promise<T>;
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { chmodSync, copyFileSync, mkdtempSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { runReleaseProcess } from './deploy-process.js';
|
|
5
|
+
const fingerprintPattern = /^[0-9A-F]{64}$/u;
|
|
6
|
+
const maximumKeystoreBytes = 64 * 1024 * 1024;
|
|
7
|
+
const initScript = `gradle.beforeProject { project ->
|
|
8
|
+
if (project.path != ':app') return
|
|
9
|
+
project.pluginManager.withPlugin('com.android.application') {
|
|
10
|
+
def android = project.extensions.getByName('android')
|
|
11
|
+
def signing = android.signingConfigs.findByName('mpgdUpload')
|
|
12
|
+
?: android.signingConfigs.create('mpgdUpload')
|
|
13
|
+
signing.storeFile = project.file(System.getenv('MPGD_ANDROID_SIGNING_KEYSTORE'))
|
|
14
|
+
signing.storePassword = System.getenv('MPGD_ANDROID_SIGNING_STORE_PASSWORD')
|
|
15
|
+
signing.keyAlias = System.getenv('MPGD_ANDROID_SIGNING_KEY_ALIAS')
|
|
16
|
+
signing.keyPassword = System.getenv('MPGD_ANDROID_SIGNING_KEY_PASSWORD')
|
|
17
|
+
android.buildTypes.getByName('release').signingConfig = signing
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
gradle.projectsEvaluated {
|
|
21
|
+
def app = gradle.rootProject.findProject(':app')
|
|
22
|
+
if (app == null || app.extensions.findByName('android') == null
|
|
23
|
+
|| app.extensions.getByName('android').buildTypes.getByName('release').signingConfig?.name
|
|
24
|
+
!= 'mpgdUpload') {
|
|
25
|
+
throw new GradleException('The game shell did not accept mpgd upload signing.')
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
`;
|
|
29
|
+
/** Restore one upload key to an owned temporary path and preflight its identity. */
|
|
30
|
+
export async function prepareAndroidUploadSigningSession(input) {
|
|
31
|
+
const expectedCertSha256 = input.expectedCertSha256.replace(/:/gu, '').toUpperCase();
|
|
32
|
+
const keyAlias = input.keyAlias.trim();
|
|
33
|
+
if (!fingerprintPattern.test(expectedCertSha256) || keyAlias === ''
|
|
34
|
+
|| input.storePassword === '' || input.keyPassword === '') {
|
|
35
|
+
throw new Error('Android upload signing requires an alias, passwords and SHA-256 certificate.');
|
|
36
|
+
}
|
|
37
|
+
const source = path.resolve(input.keystoreFile);
|
|
38
|
+
let sourceStat;
|
|
39
|
+
try {
|
|
40
|
+
sourceStat = statSync(source);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
throw new Error(`Android upload keystore is missing or unreadable: ${source}`);
|
|
44
|
+
}
|
|
45
|
+
if (!sourceStat.isFile() || sourceStat.size < 1 || sourceStat.size > maximumKeystoreBytes) {
|
|
46
|
+
throw new Error('Android upload keystore must be a nonempty regular file under 64 MiB.');
|
|
47
|
+
}
|
|
48
|
+
const parent = input.temporaryParent ?? tmpdir();
|
|
49
|
+
const ownedRoot = mkdtempSync(path.join(parent, 'mpgd-android-upload-'));
|
|
50
|
+
const temporaryKeystore = path.join(ownedRoot, 'upload-keystore');
|
|
51
|
+
const gradleInitScript = path.join(ownedRoot, 'upload-signing.init.gradle');
|
|
52
|
+
const environment = {
|
|
53
|
+
...(input.environment ?? process.env),
|
|
54
|
+
MPGD_ANDROID_SIGNING_KEYSTORE: temporaryKeystore,
|
|
55
|
+
MPGD_ANDROID_SIGNING_STORE_PASSWORD: input.storePassword,
|
|
56
|
+
MPGD_ANDROID_SIGNING_KEY_ALIAS: keyAlias,
|
|
57
|
+
MPGD_ANDROID_SIGNING_KEY_PASSWORD: input.keyPassword,
|
|
58
|
+
MPGD_ANDROID_SIGNING_INIT_SCRIPT: gradleInitScript,
|
|
59
|
+
MPGD_ANDROID_UPLOAD_CERT_SHA256: expectedCertSha256,
|
|
60
|
+
};
|
|
61
|
+
delete environment.MPGD_ANDROID_UPLOAD_KEYSTORE;
|
|
62
|
+
const secretValues = [input.storePassword, input.keyPassword];
|
|
63
|
+
try {
|
|
64
|
+
if (process.platform !== 'win32') {
|
|
65
|
+
chmodSync(ownedRoot, 0o700);
|
|
66
|
+
}
|
|
67
|
+
copyFileSync(source, temporaryKeystore);
|
|
68
|
+
chmodSync(temporaryKeystore, 0o600);
|
|
69
|
+
const javaHome = environment.JAVA_HOME?.trim();
|
|
70
|
+
const keytoolExecutable = process.platform === 'win32' ? 'keytool.exe' : 'keytool';
|
|
71
|
+
const keytool = javaHome === undefined || javaHome === ''
|
|
72
|
+
? keytoolExecutable
|
|
73
|
+
: path.join(javaHome, 'bin', keytoolExecutable);
|
|
74
|
+
const listed = await runReleaseProcess({
|
|
75
|
+
command: keytool,
|
|
76
|
+
args: [
|
|
77
|
+
'-J-Duser.language=en',
|
|
78
|
+
'-list',
|
|
79
|
+
'-v',
|
|
80
|
+
'-keystore',
|
|
81
|
+
temporaryKeystore,
|
|
82
|
+
'-alias',
|
|
83
|
+
keyAlias,
|
|
84
|
+
'-storepass:env',
|
|
85
|
+
'MPGD_ANDROID_SIGNING_STORE_PASSWORD',
|
|
86
|
+
],
|
|
87
|
+
cwd: ownedRoot,
|
|
88
|
+
environment,
|
|
89
|
+
timeoutMs: 30_000,
|
|
90
|
+
signal: input.signal,
|
|
91
|
+
secretValues,
|
|
92
|
+
captureMachineStdout: true,
|
|
93
|
+
});
|
|
94
|
+
if (listed.truncated || listed.machineStdout === undefined) {
|
|
95
|
+
throw new Error('Android upload certificate inspection output was truncated.');
|
|
96
|
+
}
|
|
97
|
+
const observed = /\bSHA256:\s*((?:[0-9A-Fa-f]{2}:){31}[0-9A-Fa-f]{2})/u
|
|
98
|
+
.exec(listed.machineStdout)?.[1]?.replace(/:/gu, '').toUpperCase();
|
|
99
|
+
if (observed !== expectedCertSha256) {
|
|
100
|
+
throw new Error('Android upload keystore certificate does not match the expected SHA-256.');
|
|
101
|
+
}
|
|
102
|
+
const typeListing = await runReleaseProcess({
|
|
103
|
+
command: keytool,
|
|
104
|
+
args: [
|
|
105
|
+
'-J-Duser.language=en',
|
|
106
|
+
'-list',
|
|
107
|
+
'-keystore',
|
|
108
|
+
temporaryKeystore,
|
|
109
|
+
'-storepass:env',
|
|
110
|
+
'MPGD_ANDROID_SIGNING_STORE_PASSWORD',
|
|
111
|
+
],
|
|
112
|
+
cwd: ownedRoot,
|
|
113
|
+
environment,
|
|
114
|
+
timeoutMs: 30_000,
|
|
115
|
+
signal: input.signal,
|
|
116
|
+
secretValues,
|
|
117
|
+
captureMachineStdout: true,
|
|
118
|
+
});
|
|
119
|
+
if (typeListing.truncated || typeListing.machineStdout === undefined) {
|
|
120
|
+
throw new Error('Android upload keystore type inspection output was truncated.');
|
|
121
|
+
}
|
|
122
|
+
// -list -v with -alias omits the keystore type. PKCS12 ignores a distinct
|
|
123
|
+
// key password during -certreq, so Gradle must receive the store password.
|
|
124
|
+
if (/^Keystore type:\s*PKCS12\s*$/imu.test(typeListing.machineStdout)
|
|
125
|
+
&& input.keyPassword !== input.storePassword) {
|
|
126
|
+
throw new Error('PKCS12 upload signing requires the key password to equal the store password.');
|
|
127
|
+
}
|
|
128
|
+
await runReleaseProcess({
|
|
129
|
+
command: keytool,
|
|
130
|
+
args: [
|
|
131
|
+
'-J-Duser.language=en',
|
|
132
|
+
'-certreq',
|
|
133
|
+
'-keystore',
|
|
134
|
+
temporaryKeystore,
|
|
135
|
+
'-alias',
|
|
136
|
+
keyAlias,
|
|
137
|
+
'-file',
|
|
138
|
+
path.join(ownedRoot, 'upload.csr'),
|
|
139
|
+
'-storepass:env',
|
|
140
|
+
'MPGD_ANDROID_SIGNING_STORE_PASSWORD',
|
|
141
|
+
'-keypass:env',
|
|
142
|
+
'MPGD_ANDROID_SIGNING_KEY_PASSWORD',
|
|
143
|
+
],
|
|
144
|
+
cwd: ownedRoot,
|
|
145
|
+
environment,
|
|
146
|
+
timeoutMs: 30_000,
|
|
147
|
+
signal: input.signal,
|
|
148
|
+
secretValues,
|
|
149
|
+
});
|
|
150
|
+
writeFileSync(gradleInitScript, initScript, { flag: 'wx', mode: 0o600 });
|
|
151
|
+
return {
|
|
152
|
+
environment,
|
|
153
|
+
expectedCertSha256,
|
|
154
|
+
temporaryKeystore,
|
|
155
|
+
gradleInitScript,
|
|
156
|
+
secretValues,
|
|
157
|
+
dispose() {
|
|
158
|
+
removeOwnedSigningRoot(ownedRoot);
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
try {
|
|
164
|
+
removeOwnedSigningRoot(ownedRoot);
|
|
165
|
+
}
|
|
166
|
+
catch (cleanupError) {
|
|
167
|
+
throw new AggregateError([error, cleanupError], 'Android upload signing preparation and cleanup both failed.');
|
|
168
|
+
}
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/** Always remove the restored key after a build, failure, or cancellation. */
|
|
173
|
+
export async function withAndroidUploadSigningSession(input, action) {
|
|
174
|
+
const session = await prepareAndroidUploadSigningSession(input);
|
|
175
|
+
let outcome;
|
|
176
|
+
try {
|
|
177
|
+
outcome = { ok: true, value: await action(session) };
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
outcome = { ok: false, error };
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
session.dispose();
|
|
184
|
+
}
|
|
185
|
+
catch (cleanupError) {
|
|
186
|
+
if (!outcome.ok) {
|
|
187
|
+
throw new AggregateError([outcome.error, cleanupError], 'Android upload signing action and cleanup both failed.');
|
|
188
|
+
}
|
|
189
|
+
throw cleanupError;
|
|
190
|
+
}
|
|
191
|
+
if (!outcome.ok) {
|
|
192
|
+
throw outcome.error;
|
|
193
|
+
}
|
|
194
|
+
return outcome.value;
|
|
195
|
+
}
|
|
196
|
+
function removeOwnedSigningRoot(root) {
|
|
197
|
+
rmSync(root, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
198
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const allowedInspectionEnvironmentNames = [
|
|
2
|
+
'PATH',
|
|
3
|
+
'Path',
|
|
4
|
+
'HOME',
|
|
5
|
+
'TMPDIR',
|
|
6
|
+
'TMP',
|
|
7
|
+
'TEMP',
|
|
8
|
+
'LANG',
|
|
9
|
+
'LC_ALL',
|
|
10
|
+
'LC_CTYPE',
|
|
11
|
+
'JAVA_HOME',
|
|
12
|
+
'ANDROID_HOME',
|
|
13
|
+
'ANDROID_SDK_ROOT',
|
|
14
|
+
'DEVELOPER_DIR',
|
|
15
|
+
'SDKROOT',
|
|
16
|
+
'SystemRoot',
|
|
17
|
+
'windir',
|
|
18
|
+
'PATHEXT',
|
|
19
|
+
'USERPROFILE',
|
|
20
|
+
];
|
|
21
|
+
/** Artifact inspectors need tool locations, never release-state or signing credentials. */
|
|
22
|
+
export function artifactInspectionEnvironment(source = process.env) {
|
|
23
|
+
const result = {};
|
|
24
|
+
for (const name of allowedInspectionEnvironmentNames) {
|
|
25
|
+
const value = source[name];
|
|
26
|
+
if (value !== undefined) {
|
|
27
|
+
result[name] = value;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"repository": "rorkai/App-Store-Connect-CLI",
|
|
3
|
+
"version": "5.5.0",
|
|
4
|
+
"assets": {
|
|
5
|
+
"darwin-arm64": {
|
|
6
|
+
"name": "asc_5.5.0_macOS_arm64",
|
|
7
|
+
"sha256": "8d0c38ad9c7e3094d2fc9b7b5a86d7c9a08fd2b36a3df081aefbf60503035b29"
|
|
8
|
+
},
|
|
9
|
+
"darwin-x64": {
|
|
10
|
+
"name": "asc_5.5.0_macOS_amd64",
|
|
11
|
+
"sha256": "296553af9cd63f9f93782f22dc12077c3d6678ee57cf52e05aee7e850fe13f63"
|
|
12
|
+
},
|
|
13
|
+
"linux-arm64": {
|
|
14
|
+
"name": "asc_5.5.0_linux_arm64",
|
|
15
|
+
"sha256": "c8f6d0adf7ca3ad41391adda3c83ff2023b921f4f9b077c6498c6d18b39aaebd"
|
|
16
|
+
},
|
|
17
|
+
"linux-x64": {
|
|
18
|
+
"name": "asc_5.5.0_linux_amd64",
|
|
19
|
+
"sha256": "712b29762c7ad8c2624bccc9752a30ff3c1d4c5b4cb689a00680f45081939239"
|
|
20
|
+
},
|
|
21
|
+
"win32-x64": {
|
|
22
|
+
"name": "asc_5.5.0_windows_amd64.exe",
|
|
23
|
+
"sha256": "52d1eb290139570b377b8fca439c84be7275934209dd342bb2a8b44f14e00c89"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -24,6 +24,7 @@ export interface CapacitorShellStarterPlan {
|
|
|
24
24
|
* never rewritten by this initializer.
|
|
25
25
|
*/
|
|
26
26
|
export declare function planCapacitorShellStarter(input: CapacitorShellStarterInput): CapacitorShellStarterPlan;
|
|
27
|
+
export declare function assertCapacitorAppId(appId: string): void;
|
|
27
28
|
export declare function applyCapacitorShellStarter(plan: CapacitorShellStarterPlan, installStagedFile?: (temporary: string, destination: string) => void): void;
|
|
28
29
|
export interface CapacitorShellCommandRunner {
|
|
29
30
|
run(command: string, args: readonly string[], cwd: string): void;
|
|
@@ -31,12 +31,7 @@ export function planCapacitorShellStarter(input) {
|
|
|
31
31
|
if (!lstatSync(gameRoot).isDirectory()) {
|
|
32
32
|
throw new Error('Capacitor shell game root must be a directory.');
|
|
33
33
|
}
|
|
34
|
-
|
|
35
|
-
throw new Error('Capacitor app ID must be a lowercase reverse-domain identifier.');
|
|
36
|
-
}
|
|
37
|
-
if (input.appId.split('.').some((segment) => javaKeywords.has(segment))) {
|
|
38
|
-
throw new Error('Capacitor app ID cannot contain Java keyword segments.');
|
|
39
|
-
}
|
|
34
|
+
assertCapacitorAppId(input.appId);
|
|
40
35
|
if (input.displayName.trim() !== input.displayName
|
|
41
36
|
|| input.displayName.length === 0 || input.displayName.length > 80) {
|
|
42
37
|
throw new Error('Capacitor display name must be 1-80 characters without outer whitespace.');
|
|
@@ -349,6 +344,14 @@ export function planCapacitorShellStarter(input) {
|
|
|
349
344
|
nativePlatformsToAdd,
|
|
350
345
|
};
|
|
351
346
|
}
|
|
347
|
+
export function assertCapacitorAppId(appId) {
|
|
348
|
+
if (!appIdPattern.test(appId)) {
|
|
349
|
+
throw new Error('Capacitor app ID must be a lowercase reverse-domain identifier.');
|
|
350
|
+
}
|
|
351
|
+
if (appId.split('.').some((segment) => javaKeywords.has(segment))) {
|
|
352
|
+
throw new Error('Capacitor app ID cannot contain Java keyword segments.');
|
|
353
|
+
}
|
|
354
|
+
}
|
|
352
355
|
export function applyCapacitorShellStarter(plan, installStagedFile = renameSync) {
|
|
353
356
|
const staged = plan.files.filter((file) => !plan.nativePlatformsToAdd.some((platform) => file.path.startsWith(`${shellPath}/${platform}/`))).map((file) => {
|
|
354
357
|
const destination = safeDestination(plan.gameRoot, file.path);
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export type NativeDeployTarget = 'android' | 'ios';
|
|
2
|
+
export interface CredentialReference {
|
|
3
|
+
readonly env: string;
|
|
4
|
+
}
|
|
5
|
+
export interface DeployTargetProfile {
|
|
6
|
+
readonly destination: 'play-internal' | 'testflight';
|
|
7
|
+
readonly signingCredential: CredentialReference;
|
|
8
|
+
readonly submissionCredential: CredentialReference;
|
|
9
|
+
readonly testGroup?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface DeployProfile {
|
|
12
|
+
readonly buildProfile: 'production';
|
|
13
|
+
readonly approval: 'manual' | 'preapproved-internal-test';
|
|
14
|
+
readonly targets: Partial<Record<NativeDeployTarget, DeployTargetProfile>>;
|
|
15
|
+
}
|
|
16
|
+
export interface DeployConfig {
|
|
17
|
+
readonly schemaVersion: 1;
|
|
18
|
+
readonly profiles: Record<string, DeployProfile>;
|
|
19
|
+
}
|
|
20
|
+
export interface PlannedDeployTarget {
|
|
21
|
+
readonly target: NativeDeployTarget;
|
|
22
|
+
readonly destination: 'play-internal' | 'testflight';
|
|
23
|
+
readonly appId: string;
|
|
24
|
+
readonly testGroup?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface NativeDeploymentPlan {
|
|
27
|
+
readonly schemaVersion: 1;
|
|
28
|
+
readonly gameRoot: string;
|
|
29
|
+
readonly profile: string;
|
|
30
|
+
readonly buildProfile: 'production';
|
|
31
|
+
readonly approval: DeployProfile['approval'];
|
|
32
|
+
readonly targetConfigSha256: string;
|
|
33
|
+
readonly deployConfigSha256: string;
|
|
34
|
+
readonly targets: readonly PlannedDeployTarget[];
|
|
35
|
+
}
|
|
36
|
+
export interface DeployDoctorCheck {
|
|
37
|
+
readonly name: string;
|
|
38
|
+
readonly status: 'ok' | 'missing' | 'warning';
|
|
39
|
+
readonly detail: string;
|
|
40
|
+
}
|
|
41
|
+
export interface DeployDoctorResult {
|
|
42
|
+
readonly checks: readonly DeployDoctorCheck[];
|
|
43
|
+
readonly healthy: boolean;
|
|
44
|
+
}
|
|
45
|
+
export declare function initializeDeployConfig(game: string): string;
|
|
46
|
+
export declare function planNativeDeployment(input: {
|
|
47
|
+
readonly game: string;
|
|
48
|
+
readonly profile: string;
|
|
49
|
+
readonly targets?: readonly NativeDeployTarget[];
|
|
50
|
+
}): NativeDeploymentPlan;
|
|
51
|
+
export declare function writeNativeDeploymentPlan(file: string, plan: NativeDeploymentPlan): void;
|
|
52
|
+
/** Load a saved plan only if it still equals the game-owned current configuration. */
|
|
53
|
+
export declare function readNativeDeploymentPlan(file: string, gameRootOverride?: string): NativeDeploymentPlan;
|
|
54
|
+
/** Resolve credential references from the one authoritative game-owned profile. */
|
|
55
|
+
export declare function readNativeDeployTargetProfile(plan: NativeDeploymentPlan, target: NativeDeployTarget): DeployTargetProfile;
|
|
56
|
+
/** Credential names across every configured profile, including unselected targets. */
|
|
57
|
+
export declare function readNativeDeployCredentialNames(plan: NativeDeploymentPlan): readonly string[];
|
|
58
|
+
export declare function doctorNativeDeployment(input: {
|
|
59
|
+
readonly game: string;
|
|
60
|
+
readonly profile: string;
|
|
61
|
+
readonly targets?: readonly NativeDeployTarget[];
|
|
62
|
+
readonly environment?: NodeJS.ProcessEnv;
|
|
63
|
+
}): DeployDoctorResult;
|
|
64
|
+
export declare function parseDeployTargets(value: string | undefined): readonly NativeDeployTarget[] | undefined;
|