expo-release-it 0.7.0 → 1.0.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/README.md +30 -1
- package/build/CredentialVault-DJK55Brb.js +297 -0
- package/build/CredentialVault-DJK55Brb.js.map +1 -0
- package/build/{EnvUtil-D5sfaKZs.js → EnvUtil-bT6jh2Up.js} +1 -1
- package/build/{EnvUtil-D5sfaKZs.js.map → EnvUtil-bT6jh2Up.js.map} +1 -1
- package/build/{FastlaneOption-y0DYOkjC.js → FastlaneOption-D4A4hWrQ.js} +7 -6
- package/build/FastlaneOption-D4A4hWrQ.js.map +1 -0
- package/build/{FileUtil-B9JnWobK.js → FileUtil-Dq8PORna.js} +4 -4
- package/build/FileUtil-Dq8PORna.js.map +1 -0
- package/build/{InqueryInputs-CyW-i_4N.js → InqueryInputs-C7bgU4_P.js} +2 -2
- package/build/{InqueryInputs-CyW-i_4N.js.map → InqueryInputs-C7bgU4_P.js.map} +1 -1
- package/build/{MetadataSyncUtil-BqWEE06B.js → MetadataSyncUtil-D8LnTqSH.js} +4 -4
- package/build/{MetadataSyncUtil-BqWEE06B.js.map → MetadataSyncUtil-D8LnTqSH.js.map} +1 -1
- package/build/{NativeEnvironment-BAohR8aj.js → NativeEnvironment-CQn7erIC.js} +5 -5
- package/build/{NativeEnvironment-BAohR8aj.js.map → NativeEnvironment-CQn7erIC.js.map} +1 -1
- package/build/{OptionHolder-ooRZtG0l.js → OptionHolder-DCm-Anf0.js} +3 -4
- package/build/OptionHolder-DCm-Anf0.js.map +1 -0
- package/build/{RubyEnvironment-CqupQjgn.js → RubyEnvironment-CPq_9yPd.js} +7 -6
- package/build/RubyEnvironment-CPq_9yPd.js.map +1 -0
- package/build/{RubyEnvironment-K1nIGrMJ.d.ts → RubyEnvironment-DZ8FuUEh.d.ts} +2 -2
- package/build/{VersionUtil-CttA4ATC.js → VersionUtil-Io9Zx_Fc.js} +4 -4
- package/build/{VersionUtil-CttA4ATC.js.map → VersionUtil-Io9Zx_Fc.js.map} +1 -1
- package/build/{build-R29EBnOC.js → build-DPBOtXRM.js} +15 -16
- package/build/build-DPBOtXRM.js.map +1 -0
- package/build/{bump-NbU_02fP.js → bump-BoN6SXri.js} +10 -10
- package/build/bump-BoN6SXri.js.map +1 -0
- package/build/command/build.js +19 -19
- package/build/command/bump.js +12 -12
- package/build/command/init.js +11 -11
- package/build/command/pull.js +16 -16
- package/build/command/submit.js +16 -16
- package/build/command/upload.js +16 -16
- package/build/{execShellScript-ZLVCvae2.js → execShellScript-5FcHM7dZ.js} +8 -2
- package/build/execShellScript-5FcHM7dZ.js.map +1 -0
- package/build/generateAppStoreConnectApiKeyFile-Deww9U-5.js +16 -0
- package/build/generateAppStoreConnectApiKeyFile-Deww9U-5.js.map +1 -0
- package/build/index.js +34 -31
- package/build/index.js.map +1 -1
- package/build/{init-DwlkVt7G.js → init-BKcVizS6.js} +31 -20
- package/build/init-BKcVizS6.js.map +1 -0
- package/build/{iterateAllFiles-Yx59MXv2.js → iterateAllFiles-Cofs0nGH.js} +2 -2
- package/build/{iterateAllFiles-Yx59MXv2.js.map → iterateAllFiles-Cofs0nGH.js.map} +1 -1
- package/build/{logger-CSZA77Zt.js → logger-BLZBLDnp.js} +15 -4
- package/build/logger-BLZBLDnp.js.map +1 -0
- package/build/{parseConfigFile-DTkIYMK1.js → parseConfigFile-BGBx_tJj.js} +3 -3
- package/build/{parseConfigFile-DTkIYMK1.js.map → parseConfigFile-BGBx_tJj.js.map} +1 -1
- package/build/{prepareAndroid-BQBbb44J.js → prepareAndroid-4S_Vq9Zn.js} +6 -6
- package/build/prepareAndroid-4S_Vq9Zn.js.map +1 -0
- package/build/{prepareFastlane-BmFwr96S.js → prepareFastlane-ns6kCOjb.js} +5 -5
- package/build/{prepareFastlane-BmFwr96S.js.map → prepareFastlane-ns6kCOjb.js.map} +1 -1
- package/build/{prepareIos-CGc-nhwf.js → prepareIos-CXqNQ40Q.js} +6 -3
- package/build/prepareIos-CXqNQ40Q.js.map +1 -0
- package/build/{pull-COg4G-1u.js → pull-BiLvHoN9.js} +13 -11
- package/build/pull-BiLvHoN9.js.map +1 -0
- package/build/setup-q_SlIP_M.js +25 -0
- package/build/setup-q_SlIP_M.js.map +1 -0
- package/build/{submit-BaL5kRHE.js → submit-BLq6epKd.js} +7 -7
- package/build/{submit-BaL5kRHE.js.map → submit-BLq6epKd.js.map} +1 -1
- package/build/{throwError-ebp_0a_3.js → throwError-CjtFnSTp.js} +3 -3
- package/build/{throwError-ebp_0a_3.js.map → throwError-CjtFnSTp.js.map} +1 -1
- package/build/{upload-BY1mGc-G.js → upload-DyMky8Rn.js} +7 -7
- package/build/{upload-BY1mGc-G.js.map → upload-DyMky8Rn.js.map} +1 -1
- package/build/util/CredentialVault.d.ts +33 -0
- package/build/util/CredentialVault.js +6 -0
- package/build/util/EnvUtil.js +1 -1
- package/build/util/FastlaneOption.d.ts +1 -1
- package/build/util/FastlaneOption.js +5 -3
- package/build/util/FileUtil.js +1 -1
- package/build/util/MetadataSyncUtil.js +4 -4
- package/build/util/OptionHolder.d.ts +1 -1
- package/build/util/OptionHolder.js +2 -2
- package/build/util/generateAppStoreConnectApiKeyFile.js +5 -3
- package/build/util/injectTemplatePlaceHolders.js +3 -3
- package/build/util/input/InqueryInputs.js +3 -3
- package/build/util/iterateAllFiles.js +2 -2
- package/build/util/logger.d.ts +2 -1
- package/build/util/logger.js +4 -4
- package/build/util/parseConfigFile.js +3 -3
- package/build/util/setup/NativeEnvironment.js +6 -5
- package/build/util/setup/RubyEnvironment.d.ts +1 -1
- package/build/util/setup/RubyEnvironment.js +6 -5
- package/build/util/setup/VersionUtil.js +6 -6
- package/build/util/setup/execShellScript.d.ts +5 -2
- package/build/util/setup/execShellScript.js +5 -4
- package/build/util/setup/prepareAndroid.js +5 -3
- package/build/util/setup/prepareFastlane.d.ts +1 -1
- package/build/util/setup/prepareFastlane.js +8 -7
- package/build/util/setup/prepareIos.d.ts +1 -1
- package/build/util/setup/prepareIos.js +5 -3
- package/build/util/setup/setup.d.ts +6 -3
- package/build/util/setup/setup.js +10 -10
- package/build/util/throwError.js +5 -5
- package/package.json +1 -1
- package/build/FastlaneOption-y0DYOkjC.js.map +0 -1
- package/build/FileUtil-B9JnWobK.js.map +0 -1
- package/build/OptionHolder-ooRZtG0l.js.map +0 -1
- package/build/RubyEnvironment-CqupQjgn.js.map +0 -1
- package/build/build-R29EBnOC.js.map +0 -1
- package/build/bump-NbU_02fP.js.map +0 -1
- package/build/execShellScript-ZLVCvae2.js.map +0 -1
- package/build/generateAppStoreConnectApiKeyFile-Bt2nK7lP.js +0 -18
- package/build/generateAppStoreConnectApiKeyFile-Bt2nK7lP.js.map +0 -1
- package/build/hydrateKeyholderFileValues-Cwmc5iwo.js +0 -11
- package/build/hydrateKeyholderFileValues-Cwmc5iwo.js.map +0 -1
- package/build/init-DwlkVt7G.js.map +0 -1
- package/build/logger-CSZA77Zt.js.map +0 -1
- package/build/prepareAndroid-BQBbb44J.js.map +0 -1
- package/build/prepareIos-CGc-nhwf.js.map +0 -1
- package/build/pull-COg4G-1u.js.map +0 -1
- package/build/setup-Be5UwL9d.js +0 -25
- package/build/setup-Be5UwL9d.js.map +0 -1
- package/build/util/setup/hydrateKeyholderFileValues.d.ts +0 -5
- package/build/util/setup/hydrateKeyholderFileValues.js +0 -5
package/README.md
CHANGED
|
@@ -13,13 +13,42 @@ Visit our [Documentation Site](https://expo-release-it.mjstudio.net)
|
|
|
13
13
|
- 🎉 No **EAS**
|
|
14
14
|
- 🩵 No headaches when understanding and managing **keys and credentials**
|
|
15
15
|
- 🧩 Manage and sync **store metadata** easily
|
|
16
|
-
- 🌍 Works with [Expo CNG](https://docs.expo.dev/workflow/continuous-native-generation/)
|
|
16
|
+
- 🌍 Works with [Expo CNG](https://docs.expo.dev/workflow/continuous-native-generation/)
|
|
17
17
|
- 📦 Build artifacts **locally** (`apk`, `aab`, `ipa`)
|
|
18
18
|
- 🚀 Upload artifacts to Google Play Console Internal Testing Track and iOS TestFlight
|
|
19
19
|
- ✅ Submit releases for store review
|
|
20
20
|
|
|
21
|
+
# Support
|
|
22
|
+
|
|
23
|
+
| Area | Supported scope |
|
|
24
|
+
| ------------------- | --------------------------------------------------------------------------------------------- |
|
|
25
|
+
| Workflow | Expo CNG only; native customizations belong in app configuration or config plugins |
|
|
26
|
+
| Expo / React Native | Expo SDK 52 and newer with each SDK's official React Native version; no upper SDK version cap |
|
|
27
|
+
| Ruby | MRI Ruby 3.3, 3.4, or 4.0; latest Ruby 3.3 patch recommended |
|
|
28
|
+
| Managed tools | Bundler 2.5.22, Fastlane 2.227.1, and CocoaPods 1.16.2 for iOS builds |
|
|
29
|
+
| Platforms | macOS for iOS and Android; Linux for Android |
|
|
30
|
+
|
|
31
|
+
CI currently checks Ruby 3.3 and 4.0 on macOS/Linux, plus SDK 58 Android AAB and unsigned iOS builds with Xcode 27.0. Ruby 3.4, SDK 57 examples, and APK builds remain available for manual verification. The CI matrix is a verification baseline, not the full support range.
|
|
32
|
+
|
|
33
|
+
Prepare Ruby and the pinned Bundler yourself; the CLI installs its managed gems in `expo-release-it/.ruby`. See [Ruby setup and dependency maintenance](https://expo-release-it.mjstudio.net/ruby).
|
|
34
|
+
|
|
35
|
+
Credentials are encrypted by default in `expo-release-it/credentials.enc.json`. Every command, including `init`, `bump`, and unsigned builds, requires `EXPO_RELEASE_IT_ENCRYPTION_KEY` from your environment, `.env`, or GitHub Actions secrets. A missing key stops the command before any project changes or legacy migration. Existing commands handle encryption and temporary decryption automatically once the key is provided. See [Credential encryption and migration](https://expo-release-it.mjstudio.net/security).
|
|
36
|
+
|
|
21
37
|
The CLI owns release orchestration, integration with Expo-generated projects, and its managed Ruby toolchain. Prepare a toolchain supported by your project's Expo and React Native versions. Upstream native dependency or compiler incompatibilities are outside this library's scope; it does not patch Expo/RN, Pods source, or Xcode to repair them.
|
|
22
38
|
|
|
39
|
+
# Development
|
|
40
|
+
|
|
41
|
+
Install [mise](https://mise.jdx.dev/getting-started.html), then run from the repository root:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
mise trust
|
|
45
|
+
mise install node pnpm
|
|
46
|
+
mise exec -- pnpm install --frozen-lockfile
|
|
47
|
+
mise exec -- pnpm run t
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Local development and CI use the Node.js and pnpm versions pinned in `mise.toml`.
|
|
51
|
+
|
|
23
52
|
# Licenses
|
|
24
53
|
|
|
25
54
|
- See [LICENSE](/LICENSE)
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { OptionHolder } from "./OptionHolder-DCm-Anf0.js";
|
|
2
|
+
import { logger, registerSecrets } from "./logger-BLZBLDnp.js";
|
|
3
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
4
|
+
import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from "node:crypto";
|
|
5
|
+
import { appendFileSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, renameSync, rmSync, rmdirSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
7
|
+
import * as util from "node:util";
|
|
8
|
+
|
|
9
|
+
//#region src/util/CredentialVault.ts
|
|
10
|
+
const encryptionKeyEnvironment = "EXPO_RELEASE_IT_ENCRYPTION_KEY";
|
|
11
|
+
const credentialVaultFilename = "credentials.enc.json";
|
|
12
|
+
const appStoreApiFilename = "app_store_connect_api.json";
|
|
13
|
+
const credentialFilenames = {
|
|
14
|
+
androidKeystore: "android_release.keystore",
|
|
15
|
+
androidServiceAccount: "android_play_console_service_account.json",
|
|
16
|
+
iosApiKey: "ios_app_store_connect_api_key.p8"
|
|
17
|
+
};
|
|
18
|
+
const fileMode = 384;
|
|
19
|
+
const directoryMode = 448;
|
|
20
|
+
const algorithm = "aes-256-gcm";
|
|
21
|
+
const formatVersion = 1;
|
|
22
|
+
const authenticationTagLength = 16;
|
|
23
|
+
const saltLength = 16;
|
|
24
|
+
const ivLength = 12;
|
|
25
|
+
const keyLength = 32;
|
|
26
|
+
const minimumKeyLength = 16;
|
|
27
|
+
const scryptOptions = {
|
|
28
|
+
N: 131072,
|
|
29
|
+
r: 8,
|
|
30
|
+
p: 1,
|
|
31
|
+
maxmem: 256 * 1024 * 1024
|
|
32
|
+
};
|
|
33
|
+
const associatedData = Buffer.from("expo-release-it:credentials:v1");
|
|
34
|
+
const decryptionError = `Cannot decrypt credentials. Check ${encryptionKeyEnvironment}; the encrypted file may also be damaged.`;
|
|
35
|
+
let activeFiles;
|
|
36
|
+
let temporaryDirectory;
|
|
37
|
+
function isRecord(value) {
|
|
38
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
39
|
+
}
|
|
40
|
+
function isStringRecord(value) {
|
|
41
|
+
return isRecord(value) && Object.values(value).every((entry) => typeof entry === "string");
|
|
42
|
+
}
|
|
43
|
+
function decodeBase64(value, length) {
|
|
44
|
+
if (typeof value !== "string") throw new Error(decryptionError);
|
|
45
|
+
const bytes = Buffer.from(value, "base64");
|
|
46
|
+
if (bytes.toString("base64") !== value || length !== void 0 && bytes.length !== length) throw new Error(decryptionError);
|
|
47
|
+
return bytes;
|
|
48
|
+
}
|
|
49
|
+
function validateData(value) {
|
|
50
|
+
if (!isRecord(value) || !isStringRecord(value.keyholder) || !isStringRecord(value.files)) throw new Error("Invalid credential data.");
|
|
51
|
+
for (const [name, contents] of Object.entries(value.files)) {
|
|
52
|
+
if (!name || isAbsolute(name) || name.split(/[\\/]/).some((part) => !part || part === ".." || part === ".")) throw new Error("Invalid credential filename.");
|
|
53
|
+
decodeBase64(contents);
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
keyholder: value.keyholder,
|
|
57
|
+
files: value.files
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function warnPlaintextCredentials() {
|
|
61
|
+
const found = existsSync(OptionHolder.keyholderFilePath) || existsSync(OptionHolder.keyDir) && readdirSync(OptionHolder.keyDir).length > 0 || existsSync(join(OptionHolder.tempDir, appStoreApiFilename));
|
|
62
|
+
if (found) logger.warn("Legacy plaintext credentials found in keyholder.json, key/, or .temp/app_store_connect_api.json. They will be encrypted when release credentials are loaded; init can also migrate them.");
|
|
63
|
+
return found;
|
|
64
|
+
}
|
|
65
|
+
function getEncryptionKey() {
|
|
66
|
+
let key = process.env[encryptionKeyEnvironment];
|
|
67
|
+
const envFile = resolve(OptionHolder.projectDir, OptionHolder.input.envFile ?? ".env");
|
|
68
|
+
if (key === void 0 && (OptionHolder.input.envFile || existsSync(envFile))) {
|
|
69
|
+
if (typeof util.parseEnv !== "function") throw new Error(`Reading .env files requires Node.js 20.12 or newer. Alternatively set ${encryptionKeyEnvironment} in the process environment.`);
|
|
70
|
+
try {
|
|
71
|
+
const values = util.parseEnv(readFileSync(envFile, "utf8"));
|
|
72
|
+
if (encryptionKeyEnvironment in values && typeof values[encryptionKeyEnvironment] === "string") key = values[encryptionKeyEnvironment];
|
|
73
|
+
} catch {
|
|
74
|
+
throw new Error("Cannot read the encryption-key env file. Check --env-file and file permissions.");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (key !== void 0) registerSecrets([key]);
|
|
78
|
+
if (key === void 0 || key.length < minimumKeyLength) throw new Error(`${encryptionKeyEnvironment} is required for every command. Set a key of at least ${minimumKeyLength} characters in the process environment or an env file before running this command. Use --env-file to select another file.`);
|
|
79
|
+
return key;
|
|
80
|
+
}
|
|
81
|
+
function readCredentialVault(key, file = join(OptionHolder.resourcesDir, credentialVaultFilename)) {
|
|
82
|
+
let derived;
|
|
83
|
+
try {
|
|
84
|
+
if (!lstatSync(file).isFile()) throw new Error(decryptionError);
|
|
85
|
+
const envelope = JSON.parse(readFileSync(file, "utf8"));
|
|
86
|
+
if (!isRecord(envelope) || envelope.version !== formatVersion || envelope.algorithm !== algorithm) throw new Error(decryptionError);
|
|
87
|
+
const salt = decodeBase64(envelope.salt, saltLength);
|
|
88
|
+
const iv = decodeBase64(envelope.iv, ivLength);
|
|
89
|
+
const tag = decodeBase64(envelope.tag, authenticationTagLength);
|
|
90
|
+
const ciphertext = decodeBase64(envelope.ciphertext);
|
|
91
|
+
derived = scryptSync(key, salt, keyLength, scryptOptions);
|
|
92
|
+
const decipher = createDecipheriv(algorithm, derived, iv, { authTagLength: authenticationTagLength });
|
|
93
|
+
decipher.setAAD(associatedData);
|
|
94
|
+
decipher.setAuthTag(tag);
|
|
95
|
+
const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
96
|
+
try {
|
|
97
|
+
return validateData(JSON.parse(plaintext.toString("utf8")));
|
|
98
|
+
} finally {
|
|
99
|
+
plaintext.fill(0);
|
|
100
|
+
}
|
|
101
|
+
} catch {
|
|
102
|
+
throw new Error(decryptionError);
|
|
103
|
+
} finally {
|
|
104
|
+
derived?.fill(0);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function readLegacyCredentials() {
|
|
108
|
+
const data = {
|
|
109
|
+
keyholder: {},
|
|
110
|
+
files: {}
|
|
111
|
+
};
|
|
112
|
+
const originals = [];
|
|
113
|
+
if (existsSync(OptionHolder.keyholderFilePath)) {
|
|
114
|
+
const contents = readPlaintext(OptionHolder.keyholderFilePath);
|
|
115
|
+
try {
|
|
116
|
+
const keyholder = JSON.parse(contents.toString("utf8"));
|
|
117
|
+
if (!isStringRecord(keyholder)) throw new Error();
|
|
118
|
+
data.keyholder = keyholder;
|
|
119
|
+
} catch {
|
|
120
|
+
throw new Error("Cannot read legacy keyholder.json. Expected an object with string values.");
|
|
121
|
+
}
|
|
122
|
+
originals.push(OptionHolder.keyholderFilePath);
|
|
123
|
+
registerSecrets(Object.values(data.keyholder));
|
|
124
|
+
}
|
|
125
|
+
if (existsSync(OptionHolder.keyDir)) visit(OptionHolder.keyDir);
|
|
126
|
+
const legacyApiFile = join(OptionHolder.tempDir, appStoreApiFilename);
|
|
127
|
+
if (existsSync(legacyApiFile)) {
|
|
128
|
+
const name = `legacy/${appStoreApiFilename}`;
|
|
129
|
+
const contents = readPlaintext(legacyApiFile);
|
|
130
|
+
data.files[name] = contents.toString("base64");
|
|
131
|
+
originals.push(legacyApiFile);
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
data,
|
|
135
|
+
originals
|
|
136
|
+
};
|
|
137
|
+
function visit(directory) {
|
|
138
|
+
if (!lstatSync(directory).isDirectory()) throw new Error("Credential directories must not be symbolic links.");
|
|
139
|
+
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
140
|
+
const path = join(directory, entry.name);
|
|
141
|
+
if (entry.isDirectory()) visit(path);
|
|
142
|
+
else {
|
|
143
|
+
const contents = readPlaintext(path);
|
|
144
|
+
data.files[relative(OptionHolder.keyDir, path).split(sep).join("/")] = contents.toString("base64");
|
|
145
|
+
originals.push(path);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function readPlaintext(file) {
|
|
151
|
+
if (!lstatSync(file).isFile()) throw new Error("Credential inputs must be regular files, not symbolic links.");
|
|
152
|
+
return readFileSync(file);
|
|
153
|
+
}
|
|
154
|
+
function writeCredentialVault(data, key, originals = []) {
|
|
155
|
+
const salt = randomBytes(saltLength);
|
|
156
|
+
const iv = randomBytes(ivLength);
|
|
157
|
+
const derived = scryptSync(key, salt, keyLength, scryptOptions);
|
|
158
|
+
const plaintext = Buffer.from(JSON.stringify(data));
|
|
159
|
+
let encoded;
|
|
160
|
+
try {
|
|
161
|
+
const cipher = createCipheriv(algorithm, derived, iv, { authTagLength: authenticationTagLength });
|
|
162
|
+
cipher.setAAD(associatedData);
|
|
163
|
+
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
164
|
+
encoded = JSON.stringify({
|
|
165
|
+
version: formatVersion,
|
|
166
|
+
algorithm,
|
|
167
|
+
salt: salt.toString("base64"),
|
|
168
|
+
iv: iv.toString("base64"),
|
|
169
|
+
tag: cipher.getAuthTag().toString("base64"),
|
|
170
|
+
ciphertext: ciphertext.toString("base64")
|
|
171
|
+
});
|
|
172
|
+
} finally {
|
|
173
|
+
derived.fill(0);
|
|
174
|
+
plaintext.fill(0);
|
|
175
|
+
}
|
|
176
|
+
mkdirSync(OptionHolder.resourcesDir, {
|
|
177
|
+
recursive: true,
|
|
178
|
+
mode: directoryMode
|
|
179
|
+
});
|
|
180
|
+
const pending = join(OptionHolder.resourcesDir, `.credentials-${randomBytes(8).toString("hex")}.tmp`);
|
|
181
|
+
try {
|
|
182
|
+
writeFileSync(pending, encoded, {
|
|
183
|
+
flag: "wx",
|
|
184
|
+
mode: fileMode
|
|
185
|
+
});
|
|
186
|
+
if (JSON.stringify(readCredentialVault(key, pending)) !== JSON.stringify(data)) throw new Error("Encrypted credential verification failed. Plaintext files were retained.");
|
|
187
|
+
renameSync(pending, join(OptionHolder.resourcesDir, credentialVaultFilename));
|
|
188
|
+
protectSecretPaths();
|
|
189
|
+
for (const original of originals) rmSync(original);
|
|
190
|
+
if (existsSync(OptionHolder.keyDir)) removeEmptyDirectories(OptionHolder.keyDir);
|
|
191
|
+
} finally {
|
|
192
|
+
rmSync(pending, { force: true });
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function removeEmptyDirectories(directory) {
|
|
196
|
+
for (const entry of readdirSync(directory, { withFileTypes: true })) if (entry.isDirectory()) removeEmptyDirectories(join(directory, entry.name));
|
|
197
|
+
if (readdirSync(directory).length === 0) rmdirSync(directory);
|
|
198
|
+
}
|
|
199
|
+
function protectSecretPaths() {
|
|
200
|
+
appendIgnores(join(OptionHolder.resourcesDir, ".gitignore"), [
|
|
201
|
+
"/keyholder.json",
|
|
202
|
+
"/key/",
|
|
203
|
+
"/.ruby/",
|
|
204
|
+
"/.temp/"
|
|
205
|
+
]);
|
|
206
|
+
const envFile = relative(OptionHolder.projectDir, resolve(OptionHolder.projectDir, OptionHolder.input.envFile ?? ".env"));
|
|
207
|
+
if (envFile && !envFile.startsWith(`..${sep}`) && !isAbsolute(envFile)) appendIgnores(join(OptionHolder.projectDir, ".gitignore"), [`/${envFile.split(sep).join("/")}`]);
|
|
208
|
+
function appendIgnores(file, entries) {
|
|
209
|
+
if (existsSync(file) && !lstatSync(file).isFile()) throw new Error("Cannot protect secret paths: .gitignore must be a regular file.");
|
|
210
|
+
const previous = existsSync(file) ? readFileSync(file, "utf8") : "";
|
|
211
|
+
const missing = entries.filter((entry) => !previous.split(/\r?\n/).includes(entry));
|
|
212
|
+
if (missing.length) appendFileSync(file, `${previous && !previous.endsWith("\n") ? "\n" : ""}${missing.join("\n")}\n`, { mode: fileMode });
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
function loadRuntimeCredentials(key) {
|
|
216
|
+
const hasPlaintext = warnPlaintextCredentials();
|
|
217
|
+
const hasVault = existsSync(join(OptionHolder.resourcesDir, credentialVaultFilename));
|
|
218
|
+
if (!hasVault && !hasPlaintext) throw new Error("Encrypted credentials are missing. Run expo-release-it init.");
|
|
219
|
+
let data = hasVault ? readCredentialVault(key) : {
|
|
220
|
+
keyholder: {},
|
|
221
|
+
files: {}
|
|
222
|
+
};
|
|
223
|
+
if (hasPlaintext) {
|
|
224
|
+
const legacy = readLegacyCredentials();
|
|
225
|
+
data = {
|
|
226
|
+
keyholder: {
|
|
227
|
+
...data.keyholder,
|
|
228
|
+
...legacy.data.keyholder
|
|
229
|
+
},
|
|
230
|
+
files: {
|
|
231
|
+
...data.files,
|
|
232
|
+
...legacy.data.files
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
writeCredentialVault(data, key, legacy.originals);
|
|
236
|
+
logger.info("Plaintext credentials migrated to encrypted storage.");
|
|
237
|
+
}
|
|
238
|
+
Object.assign(OptionHolder.keyholderMap, data.keyholder);
|
|
239
|
+
activeFiles = data.files;
|
|
240
|
+
registerSecrets(Object.values(data.keyholder));
|
|
241
|
+
}
|
|
242
|
+
function credentialProcessEnvironment(environment = process.env) {
|
|
243
|
+
return {
|
|
244
|
+
...environment,
|
|
245
|
+
[encryptionKeyEnvironment]: ""
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
function credentialKeyPath(name) {
|
|
249
|
+
return writeCredentialTemporaryFile(name, readCredentialFile(name));
|
|
250
|
+
}
|
|
251
|
+
function readCredentialFile(name) {
|
|
252
|
+
const contents = activeFiles?.[name];
|
|
253
|
+
if (contents === void 0) throw new Error(`Credential file ${name} is missing. Import it with init.`);
|
|
254
|
+
const decoded = Buffer.from(contents, "base64");
|
|
255
|
+
registerSecrets([decoded.toString("utf8")]);
|
|
256
|
+
return decoded;
|
|
257
|
+
}
|
|
258
|
+
function writeCredentialTemporaryFile(name, contents) {
|
|
259
|
+
if (!temporaryDirectory) {
|
|
260
|
+
temporaryDirectory = mkdtempSync(join(tmpdir(), "expo-release-it-credentials-"));
|
|
261
|
+
process.once("exit", cleanupCredentials);
|
|
262
|
+
process.once("SIGINT", interruptCredentials);
|
|
263
|
+
process.once("SIGTERM", terminateCredentials);
|
|
264
|
+
}
|
|
265
|
+
const file = join(temporaryDirectory, name);
|
|
266
|
+
mkdirSync(dirname(file), {
|
|
267
|
+
recursive: true,
|
|
268
|
+
mode: directoryMode
|
|
269
|
+
});
|
|
270
|
+
writeFileSync(file, contents, { mode: fileMode });
|
|
271
|
+
registerSecrets([contents.toString("utf8")]);
|
|
272
|
+
contents.fill(0);
|
|
273
|
+
return file;
|
|
274
|
+
}
|
|
275
|
+
function cleanupCredentials() {
|
|
276
|
+
if (temporaryDirectory) rmSync(temporaryDirectory, {
|
|
277
|
+
recursive: true,
|
|
278
|
+
force: true
|
|
279
|
+
});
|
|
280
|
+
temporaryDirectory = void 0;
|
|
281
|
+
activeFiles = void 0;
|
|
282
|
+
process.off("exit", cleanupCredentials);
|
|
283
|
+
process.off("SIGINT", interruptCredentials);
|
|
284
|
+
process.off("SIGTERM", terminateCredentials);
|
|
285
|
+
}
|
|
286
|
+
function interruptCredentials() {
|
|
287
|
+
cleanupCredentials();
|
|
288
|
+
process.exit(130);
|
|
289
|
+
}
|
|
290
|
+
function terminateCredentials() {
|
|
291
|
+
cleanupCredentials();
|
|
292
|
+
process.exit(143);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
//#endregion
|
|
296
|
+
export { appStoreApiFilename, cleanupCredentials, credentialFilenames, credentialKeyPath, credentialProcessEnvironment, credentialVaultFilename, encryptionKeyEnvironment, getEncryptionKey, loadRuntimeCredentials, readCredentialFile, readCredentialVault, readLegacyCredentials, warnPlaintextCredentials, writeCredentialTemporaryFile, writeCredentialVault };
|
|
297
|
+
//# sourceMappingURL=CredentialVault-DJK55Brb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CredentialVault-DJK55Brb.js","names":["activeFiles: Record<string, string> | undefined","temporaryDirectory: string | undefined","value: unknown","length?: number","key: string","derived: Buffer | undefined","envelope: unknown","data: CredentialData","originals: string[]","keyholder: unknown","directory: string","file: string","encoded: string","entries: string[]","environment: NodeJS.ProcessEnv","name: string","contents: Buffer"],"sources":["../src/util/CredentialVault.ts"],"sourcesContent":["import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'node:crypto';\nimport {\n appendFileSync,\n existsSync,\n lstatSync,\n mkdirSync,\n mkdtempSync,\n readFileSync,\n readdirSync,\n renameSync,\n rmdirSync,\n rmSync,\n writeFileSync,\n} from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';\nimport * as util from 'node:util';\n\nimport { logger, registerSecrets } from './logger';\nimport { OptionHolder } from './OptionHolder';\n\nexport const encryptionKeyEnvironment = 'EXPO_RELEASE_IT_ENCRYPTION_KEY';\nexport const credentialVaultFilename = 'credentials.enc.json';\nexport const appStoreApiFilename = 'app_store_connect_api.json';\nexport const credentialFilenames = {\n androidKeystore: 'android_release.keystore',\n androidServiceAccount: 'android_play_console_service_account.json',\n iosApiKey: 'ios_app_store_connect_api_key.p8',\n};\nconst fileMode = 0o600;\nconst directoryMode = 0o700;\nconst algorithm = 'aes-256-gcm';\nconst formatVersion = 1;\nconst authenticationTagLength = 16;\nconst saltLength = 16;\nconst ivLength = 12;\nconst keyLength = 32;\nconst minimumKeyLength = 16;\nconst scryptOptions = { N: 131072, r: 8, p: 1, maxmem: 256 * 1024 * 1024 };\nconst associatedData = Buffer.from('expo-release-it:credentials:v1');\nconst decryptionError = `Cannot decrypt credentials. Check ${encryptionKeyEnvironment}; the encrypted file may also be damaged.`;\n\ntype CredentialData = {\n keyholder: Record<string, string>;\n files: Record<string, string>;\n};\nlet activeFiles: Record<string, string> | undefined;\nlet temporaryDirectory: string | undefined;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isStringRecord(value: unknown): value is Record<string, string> {\n return isRecord(value) && Object.values(value).every((entry) => typeof entry === 'string');\n}\n\nfunction decodeBase64(value: unknown, length?: number) {\n if (typeof value !== 'string') throw new Error(decryptionError);\n const bytes = Buffer.from(value, 'base64');\n if (bytes.toString('base64') !== value || (length !== undefined && bytes.length !== length))\n throw new Error(decryptionError);\n return bytes;\n}\n\nfunction validateData(value: unknown): CredentialData {\n if (!isRecord(value) || !isStringRecord(value.keyholder) || !isStringRecord(value.files))\n throw new Error('Invalid credential data.');\n for (const [name, contents] of Object.entries(value.files)) {\n if (\n !name ||\n isAbsolute(name) ||\n name.split(/[\\\\/]/).some((part) => !part || part === '..' || part === '.')\n )\n throw new Error('Invalid credential filename.');\n decodeBase64(contents);\n }\n return { keyholder: value.keyholder, files: value.files };\n}\n\nexport function warnPlaintextCredentials() {\n const found =\n existsSync(OptionHolder.keyholderFilePath) ||\n (existsSync(OptionHolder.keyDir) && readdirSync(OptionHolder.keyDir).length > 0) ||\n existsSync(join(OptionHolder.tempDir, appStoreApiFilename));\n if (found)\n logger.warn(\n 'Legacy plaintext credentials found in keyholder.json, key/, or .temp/app_store_connect_api.json. They will be encrypted when release credentials are loaded; init can also migrate them.',\n );\n return found;\n}\n\nexport function getEncryptionKey() {\n let key = process.env[encryptionKeyEnvironment];\n const envFile = resolve(OptionHolder.projectDir, OptionHolder.input.envFile ?? '.env');\n if (key === undefined && (OptionHolder.input.envFile || existsSync(envFile))) {\n if (typeof util.parseEnv !== 'function')\n throw new Error(\n `Reading .env files requires Node.js 20.12 or newer. Alternatively set ${encryptionKeyEnvironment} in the process environment.`,\n );\n try {\n const values = util.parseEnv(readFileSync(envFile, 'utf8'));\n if (\n encryptionKeyEnvironment in values &&\n typeof values[encryptionKeyEnvironment] === 'string'\n )\n key = values[encryptionKeyEnvironment];\n } catch {\n throw new Error(\n 'Cannot read the encryption-key env file. Check --env-file and file permissions.',\n );\n }\n }\n if (key !== undefined) registerSecrets([key]);\n if (key === undefined || key.length < minimumKeyLength)\n throw new Error(\n `${encryptionKeyEnvironment} is required for every command. Set a key of at least ${minimumKeyLength} characters in the process environment or an env file before running this command. Use --env-file to select another file.`,\n );\n return key;\n}\n\nexport function readCredentialVault(\n key: string,\n file = join(OptionHolder.resourcesDir, credentialVaultFilename),\n) {\n let derived: Buffer | undefined;\n try {\n if (!lstatSync(file).isFile()) throw new Error(decryptionError);\n const envelope: unknown = JSON.parse(readFileSync(file, 'utf8'));\n if (\n !isRecord(envelope) ||\n envelope.version !== formatVersion ||\n envelope.algorithm !== algorithm\n )\n throw new Error(decryptionError);\n const salt = decodeBase64(envelope.salt, saltLength);\n const iv = decodeBase64(envelope.iv, ivLength);\n const tag = decodeBase64(envelope.tag, authenticationTagLength);\n const ciphertext = decodeBase64(envelope.ciphertext);\n derived = scryptSync(key, salt, keyLength, scryptOptions);\n const decipher = createDecipheriv(algorithm, derived, iv, {\n authTagLength: authenticationTagLength,\n });\n decipher.setAAD(associatedData);\n decipher.setAuthTag(tag);\n const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);\n try {\n return validateData(JSON.parse(plaintext.toString('utf8')));\n } finally {\n plaintext.fill(0);\n }\n } catch {\n throw new Error(decryptionError);\n } finally {\n derived?.fill(0);\n }\n}\n\nexport function readLegacyCredentials() {\n const data: CredentialData = { keyholder: {}, files: {} };\n const originals: string[] = [];\n if (existsSync(OptionHolder.keyholderFilePath)) {\n const contents = readPlaintext(OptionHolder.keyholderFilePath);\n try {\n const keyholder: unknown = JSON.parse(contents.toString('utf8'));\n if (!isStringRecord(keyholder)) throw new Error();\n data.keyholder = keyholder;\n } catch {\n throw new Error('Cannot read legacy keyholder.json. Expected an object with string values.');\n }\n originals.push(OptionHolder.keyholderFilePath);\n registerSecrets(Object.values(data.keyholder));\n }\n if (existsSync(OptionHolder.keyDir)) visit(OptionHolder.keyDir);\n const legacyApiFile = join(OptionHolder.tempDir, appStoreApiFilename);\n if (existsSync(legacyApiFile)) {\n const name = `legacy/${appStoreApiFilename}`;\n const contents = readPlaintext(legacyApiFile);\n data.files[name] = contents.toString('base64');\n originals.push(legacyApiFile);\n }\n return { data, originals };\n\n function visit(directory: string) {\n if (!lstatSync(directory).isDirectory())\n throw new Error('Credential directories must not be symbolic links.');\n for (const entry of readdirSync(directory, { withFileTypes: true })) {\n const path = join(directory, entry.name);\n if (entry.isDirectory()) visit(path);\n else {\n const contents = readPlaintext(path);\n data.files[relative(OptionHolder.keyDir, path).split(sep).join('/')] =\n contents.toString('base64');\n originals.push(path);\n }\n }\n }\n}\n\nfunction readPlaintext(file: string) {\n if (!lstatSync(file).isFile())\n throw new Error('Credential inputs must be regular files, not symbolic links.');\n return readFileSync(file);\n}\n\nexport function writeCredentialVault(data: CredentialData, key: string, originals: string[] = []) {\n const salt = randomBytes(saltLength);\n const iv = randomBytes(ivLength);\n const derived = scryptSync(key, salt, keyLength, scryptOptions);\n const plaintext = Buffer.from(JSON.stringify(data));\n let encoded: string;\n try {\n const cipher = createCipheriv(algorithm, derived, iv, {\n authTagLength: authenticationTagLength,\n });\n cipher.setAAD(associatedData);\n const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);\n encoded = JSON.stringify({\n version: formatVersion,\n algorithm,\n salt: salt.toString('base64'),\n iv: iv.toString('base64'),\n tag: cipher.getAuthTag().toString('base64'),\n ciphertext: ciphertext.toString('base64'),\n });\n } finally {\n derived.fill(0);\n plaintext.fill(0);\n }\n mkdirSync(OptionHolder.resourcesDir, { recursive: true, mode: directoryMode });\n const pending = join(\n OptionHolder.resourcesDir,\n `.credentials-${randomBytes(8).toString('hex')}.tmp`,\n );\n try {\n writeFileSync(pending, encoded, { flag: 'wx', mode: fileMode });\n if (JSON.stringify(readCredentialVault(key, pending)) !== JSON.stringify(data))\n throw new Error('Encrypted credential verification failed. Plaintext files were retained.');\n renameSync(pending, join(OptionHolder.resourcesDir, credentialVaultFilename));\n protectSecretPaths();\n for (const original of originals) rmSync(original);\n if (existsSync(OptionHolder.keyDir)) removeEmptyDirectories(OptionHolder.keyDir);\n } finally {\n rmSync(pending, { force: true });\n }\n}\n\nfunction removeEmptyDirectories(directory: string) {\n for (const entry of readdirSync(directory, { withFileTypes: true }))\n if (entry.isDirectory()) removeEmptyDirectories(join(directory, entry.name));\n if (readdirSync(directory).length === 0) rmdirSync(directory);\n}\n\nfunction protectSecretPaths() {\n appendIgnores(join(OptionHolder.resourcesDir, '.gitignore'), [\n '/keyholder.json',\n '/key/',\n '/.ruby/',\n '/.temp/',\n ]);\n const envFile = relative(\n OptionHolder.projectDir,\n resolve(OptionHolder.projectDir, OptionHolder.input.envFile ?? '.env'),\n );\n if (envFile && !envFile.startsWith(`..${sep}`) && !isAbsolute(envFile))\n appendIgnores(join(OptionHolder.projectDir, '.gitignore'), [\n `/${envFile.split(sep).join('/')}`,\n ]);\n\n function appendIgnores(file: string, entries: string[]) {\n if (existsSync(file) && !lstatSync(file).isFile())\n throw new Error('Cannot protect secret paths: .gitignore must be a regular file.');\n const previous = existsSync(file) ? readFileSync(file, 'utf8') : '';\n const missing = entries.filter((entry) => !previous.split(/\\r?\\n/).includes(entry));\n if (missing.length)\n appendFileSync(\n file,\n `${previous && !previous.endsWith('\\n') ? '\\n' : ''}${missing.join('\\n')}\\n`,\n { mode: fileMode },\n );\n }\n}\n\nexport function loadRuntimeCredentials(key: string) {\n const hasPlaintext = warnPlaintextCredentials();\n const hasVault = existsSync(join(OptionHolder.resourcesDir, credentialVaultFilename));\n if (!hasVault && !hasPlaintext)\n throw new Error('Encrypted credentials are missing. Run expo-release-it init.');\n let data: CredentialData = hasVault ? readCredentialVault(key) : { keyholder: {}, files: {} };\n if (hasPlaintext) {\n const legacy = readLegacyCredentials();\n data = {\n keyholder: { ...data.keyholder, ...legacy.data.keyholder },\n files: { ...data.files, ...legacy.data.files },\n };\n writeCredentialVault(data, key, legacy.originals);\n logger.info('Plaintext credentials migrated to encrypted storage.');\n }\n Object.assign(OptionHolder.keyholderMap, data.keyholder);\n activeFiles = data.files;\n registerSecrets(Object.values(data.keyholder));\n}\n\nexport function credentialProcessEnvironment(environment: NodeJS.ProcessEnv = process.env) {\n return { ...environment, [encryptionKeyEnvironment]: '' };\n}\n\nexport function credentialKeyPath(name: string) {\n return writeCredentialTemporaryFile(name, readCredentialFile(name));\n}\n\nexport function readCredentialFile(name: string) {\n const contents = activeFiles?.[name];\n if (contents === undefined)\n throw new Error(`Credential file ${name} is missing. Import it with init.`);\n const decoded = Buffer.from(contents, 'base64');\n registerSecrets([decoded.toString('utf8')]);\n return decoded;\n}\n\nexport function writeCredentialTemporaryFile(name: string, contents: Buffer) {\n if (!temporaryDirectory) {\n temporaryDirectory = mkdtempSync(join(tmpdir(), 'expo-release-it-credentials-'));\n process.once('exit', cleanupCredentials);\n process.once('SIGINT', interruptCredentials);\n process.once('SIGTERM', terminateCredentials);\n }\n const file = join(temporaryDirectory, name);\n mkdirSync(dirname(file), { recursive: true, mode: directoryMode });\n writeFileSync(file, contents, { mode: fileMode });\n registerSecrets([contents.toString('utf8')]);\n contents.fill(0);\n return file;\n}\n\nexport function cleanupCredentials() {\n if (temporaryDirectory) rmSync(temporaryDirectory, { recursive: true, force: true });\n temporaryDirectory = undefined;\n activeFiles = undefined;\n process.off('exit', cleanupCredentials);\n process.off('SIGINT', interruptCredentials);\n process.off('SIGTERM', terminateCredentials);\n}\n\nfunction interruptCredentials() {\n cleanupCredentials();\n process.exit(130);\n}\n\nfunction terminateCredentials() {\n cleanupCredentials();\n process.exit(143);\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EnvUtil-
|
|
1
|
+
{"version":3,"file":"EnvUtil-bT6jh2Up.js","names":[],"sources":["../src/util/EnvUtil.ts"],"sourcesContent":["export const isDev = process.env.NODE_ENV === 'development';\nexport const isWin = process.platform.startsWith('win');\nexport const isTest = process.env.NODE_ENV === 'test';\n"],"mappings":";AAAA,MAAa,QAAQ,QAAQ,IAAI,aAAa;AAC9C,MAAa,QAAQ,QAAQ,SAAS,WAAW,MAAM;AACvD,MAAa,SAAS,QAAQ,IAAI,aAAa"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { OptionHolder } from "./OptionHolder-DCm-Anf0.js";
|
|
2
|
+
import { resolve } from "./FileUtil-Dq8PORna.js";
|
|
3
|
+
import { credentialFilenames, credentialKeyPath } from "./CredentialVault-DJK55Brb.js";
|
|
3
4
|
|
|
4
5
|
//#region src/util/FastlaneOption.ts
|
|
5
6
|
async function runFastlane(ruby, lane) {
|
|
6
|
-
const { keyholderMap: keys, input, resourcesDir
|
|
7
|
+
const { keyholderMap: keys, input, resourcesDir } = OptionHolder;
|
|
7
8
|
const options = {
|
|
8
9
|
version_name: OptionHolder.versionName,
|
|
9
10
|
version_code: OptionHolder.versionCode,
|
|
@@ -15,7 +16,7 @@ async function runFastlane(ruby, lane) {
|
|
|
15
16
|
ios_match_git_url: keys.ios_match_git_url,
|
|
16
17
|
ios_app_store_connect_api_key_id: keys.ios_app_store_connect_api_key_id,
|
|
17
18
|
ios_app_store_connect_api_key_issuer_id: keys.ios_app_store_connect_api_key_issuer_id,
|
|
18
|
-
api_key_filepath:
|
|
19
|
+
api_key_filepath: input.sign === false ? void 0 : credentialKeyPath(credentialFilenames.iosApiKey),
|
|
19
20
|
project: input.iosProject,
|
|
20
21
|
target: input.iosTarget,
|
|
21
22
|
scheme: input.iosScheme,
|
|
@@ -27,7 +28,7 @@ async function runFastlane(ruby, lane) {
|
|
|
27
28
|
archive_path: resolve(resourcesDir, "output", "ios", "app.xcarchive")
|
|
28
29
|
} : {
|
|
29
30
|
android_package_name: keys.android_package_name,
|
|
30
|
-
json_key:
|
|
31
|
+
json_key: credentialKeyPath(credentialFilenames.androidServiceAccount),
|
|
31
32
|
aab_path: resolve(resourcesDir, "output", "android", "aab", "app-release.aab"),
|
|
32
33
|
apk_path: resolve(resourcesDir, "output", "android", "apk", "app-release.apk"),
|
|
33
34
|
skip_upload_apk: input.androidOutput !== "apk",
|
|
@@ -47,4 +48,4 @@ async function runFastlane(ruby, lane) {
|
|
|
47
48
|
|
|
48
49
|
//#endregion
|
|
49
50
|
export { runFastlane };
|
|
50
|
-
//# sourceMappingURL=FastlaneOption-
|
|
51
|
+
//# sourceMappingURL=FastlaneOption-D4A4hWrQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FastlaneOption-D4A4hWrQ.js","names":["ruby: RubyEnvironment","lane: 'build' | 'upload' | 'submit'"],"sources":["../src/util/FastlaneOption.ts"],"sourcesContent":["import { credentialFilenames, credentialKeyPath } from './CredentialVault';\nimport { resolve } from './FileUtil';\nimport { OptionHolder } from './OptionHolder';\nimport type { RubyEnvironment } from './setup/RubyEnvironment';\n\nexport async function runFastlane(ruby: RubyEnvironment, lane: 'build' | 'upload' | 'submit') {\n const { keyholderMap: keys, input, resourcesDir } = OptionHolder;\n const options = {\n version_name: OptionHolder.versionName,\n version_code: OptionHolder.versionCode,\n upload_metadata: input.uploadMetadata,\n upload_screenshot: input.uploadScreenshot,\n ...(input.platform === 'ios'\n ? {\n ios_app_identifier: keys.ios_app_identifier,\n ios_developer_team_id: keys.ios_developer_team_id,\n ios_match_git_url: keys.ios_match_git_url,\n ios_app_store_connect_api_key_id: keys.ios_app_store_connect_api_key_id,\n ios_app_store_connect_api_key_issuer_id: keys.ios_app_store_connect_api_key_issuer_id,\n api_key_filepath:\n input.sign === false ? undefined : credentialKeyPath(credentialFilenames.iosApiKey),\n project: input.iosProject,\n target: input.iosTarget,\n scheme: input.iosScheme,\n workspace: input.iosWorkspace,\n no_sign: input.sign === false,\n ipa_path: resolve(resourcesDir, 'output', 'ios', 'app.ipa'),\n ipa_dir: resolve(resourcesDir, 'output', 'ios'),\n ipa_name: 'app.ipa',\n archive_path: resolve(resourcesDir, 'output', 'ios', 'app.xcarchive'),\n }\n : {\n android_package_name: keys.android_package_name,\n json_key: credentialKeyPath(credentialFilenames.androidServiceAccount),\n aab_path: resolve(resourcesDir, 'output', 'android', 'aab', 'app-release.aab'),\n apk_path: resolve(resourcesDir, 'output', 'android', 'apk', 'app-release.apk'),\n skip_upload_apk: input.androidOutput !== 'apk',\n skip_upload_aab: input.androidOutput !== 'aab',\n }),\n };\n await ruby.bundle(['exec', 'fastlane', input.platform, lane], {\n env: {\n EXPO_RELEASE_IT_OPTIONS: JSON.stringify(options),\n MATCH_PASSWORD:\n lane === 'build' && input.sign !== false ? (keys.ios_match_password ?? '') : '',\n },\n });\n}\n"],"mappings":";;;;;AAKA,eAAsB,YAAYA,MAAuBC,MAAqC;CAC5F,MAAM,EAAE,cAAc,MAAM,OAAO,cAAc,GAAG;CACpD,MAAM,UAAU;EACd,cAAc,aAAa;EAC3B,cAAc,aAAa;EAC3B,iBAAiB,MAAM;EACvB,mBAAmB,MAAM;EACzB,GAAI,MAAM,aAAa,QACnB;GACE,oBAAoB,KAAK;GACzB,uBAAuB,KAAK;GAC5B,mBAAmB,KAAK;GACxB,kCAAkC,KAAK;GACvC,yCAAyC,KAAK;GAC9C,kBACE,MAAM,SAAS,iBAAoB,kBAAkB,oBAAoB,UAAU;GACrF,SAAS,MAAM;GACf,QAAQ,MAAM;GACd,QAAQ,MAAM;GACd,WAAW,MAAM;GACjB,SAAS,MAAM,SAAS;GACxB,UAAU,QAAQ,cAAc,UAAU,OAAO,UAAU;GAC3D,SAAS,QAAQ,cAAc,UAAU,MAAM;GAC/C,UAAU;GACV,cAAc,QAAQ,cAAc,UAAU,OAAO,gBAAgB;EACtE,IACD;GACE,sBAAsB,KAAK;GAC3B,UAAU,kBAAkB,oBAAoB,sBAAsB;GACtE,UAAU,QAAQ,cAAc,UAAU,WAAW,OAAO,kBAAkB;GAC9E,UAAU,QAAQ,cAAc,UAAU,WAAW,OAAO,kBAAkB;GAC9E,iBAAiB,MAAM,kBAAkB;GACzC,iBAAiB,MAAM,kBAAkB;EAC1C;CACN;AACD,OAAM,KAAK,OAAO;EAAC;EAAQ;EAAY,MAAM;EAAU;CAAK,GAAE,EAC5D,KAAK;EACH,yBAAyB,KAAK,UAAU,QAAQ;EAChD,gBACE,SAAS,WAAW,MAAM,SAAS,QAAS,KAAK,sBAAsB,KAAM;CAChF,EACF,EAAC;AACH"}
|
|
@@ -2,8 +2,8 @@ import * as path from "node:path";
|
|
|
2
2
|
import fs from "fs-extra";
|
|
3
3
|
|
|
4
4
|
//#region src/util/FileUtil.ts
|
|
5
|
-
const join = path.join;
|
|
6
|
-
const resolve = path.resolve;
|
|
5
|
+
const join$1 = path.join;
|
|
6
|
+
const resolve$1 = path.resolve;
|
|
7
7
|
function exist(path$1) {
|
|
8
8
|
return fs.existsSync(path$1);
|
|
9
9
|
}
|
|
@@ -53,5 +53,5 @@ async function iterateDir(path$1, fn) {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
//#endregion
|
|
56
|
-
export { copy, exist, isDir, isFile, iterateDir, join, move, read, readJsonSlow, readdir, relativePath, remove, resolve, write, writeJson };
|
|
57
|
-
//# sourceMappingURL=FileUtil-
|
|
56
|
+
export { copy, exist, isDir, isFile, iterateDir, join$1 as join, move, read, readJsonSlow, readdir, relativePath, remove, resolve$1 as resolve, write, writeJson };
|
|
57
|
+
//# sourceMappingURL=FileUtil-Dq8PORna.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileUtil-Dq8PORna.js","names":["join","resolve","path: string","path","from: string","to: string","p: string","content: string","src: string","dest: string","options?: fs.CopyOptionsSync","options?: fs.MoveOptions","json: any","fn: (file: string) => Promise<void> | void"],"sources":["../src/util/FileUtil.ts"],"sourcesContent":["import * as path from 'node:path';\n\nimport fs from 'fs-extra';\n\nexport const join = path.join;\nexport const resolve = path.resolve;\n\nexport function exist(path: string) {\n return fs.existsSync(path);\n}\n\nexport function isDir(path: string) {\n return exist(path) && fs.lstatSync(path).isDirectory();\n}\n\nexport function relativePath(from: string, to: string) {\n return path.relative(from, to);\n}\n\nexport function isFile(path: string) {\n return exist(path) && fs.lstatSync(path).isFile();\n}\n\nexport function read(path: string) {\n return fs.readFileSync(path, { encoding: 'utf8' });\n}\n\nexport function readdir(path: string) {\n return fs.readdirSync(path);\n}\n\n// you should require when possible(optimized in js)\nexport function readJsonSlow(path: string) {\n return fs.readJSONSync(path);\n}\n\nexport function write(p: string, content: string) {\n const dir = path.dirname(p);\n if (!exist(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n return fs.writeFileSync(p, content);\n}\nexport function copy(src: string, dest: string, options?: fs.CopyOptionsSync) {\n fs.copySync(src, dest, options);\n}\nexport function move(src: string, dest: string, options?: fs.MoveOptions) {\n fs.moveSync(src, dest, options);\n}\n\nexport function writeJson(path: string, json: any) {\n return write(path, JSON.stringify(json, null, 2));\n}\n\nexport function remove(path: string) {\n if (!exist(path)) {\n return;\n }\n\n if (fs.lstatSync(path).isDirectory()) {\n return fs.rmSync(path, { force: true, recursive: true });\n } else {\n return fs.rmSync(path, { force: true });\n }\n}\n\nexport async function iterateDir(path: string, fn: (file: string) => Promise<void> | void) {\n if (!isDir(path)) {\n return;\n }\n\n for (const file of fs.readdirSync(path)) {\n await fn(file);\n }\n}\n"],"mappings":";;;;AAIA,MAAaA,SAAO,KAAK;AACzB,MAAaC,YAAU,KAAK;AAE5B,SAAgB,MAAMC,QAAc;AAClC,QAAO,GAAG,WAAWC,OAAK;AAC3B;AAED,SAAgB,MAAMD,QAAc;AAClC,QAAO,MAAMC,OAAK,IAAI,GAAG,UAAUA,OAAK,CAAC,aAAa;AACvD;AAED,SAAgB,aAAaC,MAAcC,IAAY;AACrD,QAAO,KAAK,SAAS,MAAM,GAAG;AAC/B;AAED,SAAgB,OAAOH,QAAc;AACnC,QAAO,MAAMC,OAAK,IAAI,GAAG,UAAUA,OAAK,CAAC,QAAQ;AAClD;AAED,SAAgB,KAAKD,QAAc;AACjC,QAAO,GAAG,aAAaC,QAAM,EAAE,UAAU,OAAQ,EAAC;AACnD;AAED,SAAgB,QAAQD,QAAc;AACpC,QAAO,GAAG,YAAYC,OAAK;AAC5B;AAGD,SAAgB,aAAaD,QAAc;AACzC,QAAO,GAAG,aAAaC,OAAK;AAC7B;AAED,SAAgB,MAAMG,GAAWC,SAAiB;CAChD,MAAM,MAAM,KAAK,QAAQ,EAAE;AAC3B,MAAK,MAAM,IAAI,CACb,IAAG,UAAU,KAAK,EAAE,WAAW,KAAM,EAAC;AAGxC,QAAO,GAAG,cAAc,GAAG,QAAQ;AACpC;AACD,SAAgB,KAAKC,KAAaC,MAAcC,SAA8B;AAC5E,IAAG,SAAS,KAAK,MAAM,QAAQ;AAChC;AACD,SAAgB,KAAKF,KAAaC,MAAcE,SAA0B;AACxE,IAAG,SAAS,KAAK,MAAM,QAAQ;AAChC;AAED,SAAgB,UAAUT,QAAcU,MAAW;AACjD,QAAO,MAAMT,QAAM,KAAK,UAAU,MAAM,MAAM,EAAE,CAAC;AAClD;AAED,SAAgB,OAAOD,QAAc;AACnC,MAAK,MAAMC,OAAK,CACd;AAGF,KAAI,GAAG,UAAUA,OAAK,CAAC,aAAa,CAClC,QAAO,GAAG,OAAOA,QAAM;EAAE,OAAO;EAAM,WAAW;CAAM,EAAC;KAExD,QAAO,GAAG,OAAOA,QAAM,EAAE,OAAO,KAAM,EAAC;AAE1C;AAED,eAAsB,WAAWD,QAAcW,IAA4C;AACzF,MAAK,MAAMV,OAAK,CACd;AAGF,MAAK,MAAM,QAAQ,GAAG,YAAYA,OAAK,CACrC,OAAM,GAAG,KAAK;AAEjB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { OptionHolder } from "./OptionHolder-
|
|
1
|
+
import { OptionHolder } from "./OptionHolder-DCm-Anf0.js";
|
|
2
2
|
import chalk from "chalk";
|
|
3
3
|
import { is } from "@mj-studio/js-util";
|
|
4
4
|
import { select } from "@inquirer/prompts";
|
|
@@ -95,4 +95,4 @@ function constructInquirerFormattedMessage({ example, explanation, referUrl, nam
|
|
|
95
95
|
|
|
96
96
|
//#endregion
|
|
97
97
|
export { InqueryInputs, constructInquirerFormattedMessage };
|
|
98
|
-
//# sourceMappingURL=InqueryInputs-
|
|
98
|
+
//# sourceMappingURL=InqueryInputs-C7bgU4_P.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InqueryInputs-
|
|
1
|
+
{"version":3,"file":"InqueryInputs-C7bgU4_P.js","names":[],"sources":["../src/util/input/InqueryInputs.ts"],"sourcesContent":["import { select } from '@inquirer/prompts';\nimport { is } from '@mj-studio/js-util';\nimport chalk from 'chalk';\n\nimport { OptionHolder } from '../OptionHolder';\n\nexport const InqueryInputs = {\n platform: async () => {\n if (!OptionHolder.input.platform) {\n OptionHolder.input.platform = await select({\n message: constructInquirerFormattedMessage({\n name: 'Platform',\n explanation: 'Platform to run action',\n }),\n choices: [\n { name: 'ios', value: 'ios', description: 'Release ios' },\n { name: 'android', value: 'android', description: 'Release android' },\n ],\n });\n }\n },\n androidBuildOutput: async () => {\n if (OptionHolder.input.platform === 'android') {\n if (!OptionHolder.input.androidOutput) {\n OptionHolder.input.androidOutput = await select({\n message: constructInquirerFormattedMessage({\n name: 'Android output artifact type',\n }),\n choices: [\n { name: 'aab', value: 'aab', description: 'Build as App bundle' },\n { name: 'apk', value: 'apk', description: 'Build as APK' },\n ],\n });\n }\n }\n },\n uploadMetadata: async () => {\n if (!is.boolean(OptionHolder.input.uploadMetadata)) {\n OptionHolder.input.uploadMetadata = await select({\n message: constructInquirerFormattedMessage({\n name: 'Upload Text Metadata(title, description, ...)',\n }),\n choices: [\n { name: 'yes', value: true, description: 'Upload' },\n { name: 'no', value: false, description: \"Don't Upload\" },\n ],\n });\n }\n },\n uploadScreenshot: async () => {\n if (!is.boolean(OptionHolder.input.uploadScreenshot)) {\n OptionHolder.input.uploadScreenshot = await select({\n message: constructInquirerFormattedMessage({\n name: 'Upload Screenshots & Images',\n }),\n choices: [\n { name: 'yes', value: true, description: 'Upload' },\n { name: 'no', value: false, description: \"Don't Upload\" },\n ],\n });\n }\n },\n useLiveVersionIos: async () => {\n if (\n !is.boolean(OptionHolder.input.useLiveVersionIos) &&\n OptionHolder.input.platform === 'ios'\n ) {\n OptionHolder.input.useLiveVersionIos = await select({\n message: constructInquirerFormattedMessage({\n name: 'Download metadatas from live version rather than draft',\n }),\n choices: [\n { name: 'yes', value: true, description: 'Download from live version' },\n { name: 'no', value: false, description: 'Download from draft' },\n ],\n });\n }\n },\n};\n\nexport function constructInquirerFormattedMessage({\n example,\n explanation,\n referUrl,\n name,\n}: {\n name: string;\n explanation?: string;\n example?: string;\n referUrl?: string;\n}) {\n let ret = `${chalk.bold(name)}`;\n if (explanation) {\n ret += `\\n\\n${chalk.italic.blue(explanation)}`;\n }\n if (example) {\n ret += `\\n${chalk.italic(`${chalk.greenBright('example :')} ${example}`)}`;\n }\n if (referUrl) {\n ret += `\\n${chalk.italic(`${chalk.greenBright('references :')} ${chalk.underline.blue(referUrl)}`)}`;\n }\n\n if (explanation) {\n ret += '\\n';\n if (example || referUrl) {\n ret += '\\n';\n }\n }\n\n return ret;\n}\n"],"mappings":";;;;;;AAMA,MAAa,gBAAgB;CAC3B,UAAU,YAAY;AACpB,OAAK,aAAa,MAAM,SACtB,cAAa,MAAM,WAAW,MAAM,OAAO;GACzC,SAAS,kCAAkC;IACzC,MAAM;IACN,aAAa;GACd,EAAC;GACF,SAAS,CACP;IAAE,MAAM;IAAO,OAAO;IAAO,aAAa;GAAe,GACzD;IAAE,MAAM;IAAW,OAAO;IAAW,aAAa;GAAmB,CACtE;EACF,EAAC;CAEL;CACD,oBAAoB,YAAY;AAC9B,MAAI,aAAa,MAAM,aAAa,WAClC;QAAK,aAAa,MAAM,cACtB,cAAa,MAAM,gBAAgB,MAAM,OAAO;IAC9C,SAAS,kCAAkC,EACzC,MAAM,+BACP,EAAC;IACF,SAAS,CACP;KAAE,MAAM;KAAO,OAAO;KAAO,aAAa;IAAuB,GACjE;KAAE,MAAM;KAAO,OAAO;KAAO,aAAa;IAAgB,CAC3D;GACF,EAAC;EACH;CAEJ;CACD,gBAAgB,YAAY;AAC1B,OAAK,GAAG,QAAQ,aAAa,MAAM,eAAe,CAChD,cAAa,MAAM,iBAAiB,MAAM,OAAO;GAC/C,SAAS,kCAAkC,EACzC,MAAM,gDACP,EAAC;GACF,SAAS,CACP;IAAE,MAAM;IAAO,OAAO;IAAM,aAAa;GAAU,GACnD;IAAE,MAAM;IAAM,OAAO;IAAO,aAAa;GAAgB,CAC1D;EACF,EAAC;CAEL;CACD,kBAAkB,YAAY;AAC5B,OAAK,GAAG,QAAQ,aAAa,MAAM,iBAAiB,CAClD,cAAa,MAAM,mBAAmB,MAAM,OAAO;GACjD,SAAS,kCAAkC,EACzC,MAAM,8BACP,EAAC;GACF,SAAS,CACP;IAAE,MAAM;IAAO,OAAO;IAAM,aAAa;GAAU,GACnD;IAAE,MAAM;IAAM,OAAO;IAAO,aAAa;GAAgB,CAC1D;EACF,EAAC;CAEL;CACD,mBAAmB,YAAY;AAC7B,OACG,GAAG,QAAQ,aAAa,MAAM,kBAAkB,IACjD,aAAa,MAAM,aAAa,MAEhC,cAAa,MAAM,oBAAoB,MAAM,OAAO;GAClD,SAAS,kCAAkC,EACzC,MAAM,yDACP,EAAC;GACF,SAAS,CACP;IAAE,MAAM;IAAO,OAAO;IAAM,aAAa;GAA8B,GACvE;IAAE,MAAM;IAAM,OAAO;IAAO,aAAa;GAAuB,CACjE;EACF,EAAC;CAEL;AACF;AAED,SAAgB,kCAAkC,EAChD,SACA,aACA,UACA,MAMD,EAAE;CACD,IAAI,OAAO,EAAE,MAAM,KAAK,KAAK,CAAC;AAC9B,KAAI,YACF,SAAQ,MAAM,MAAM,OAAO,KAAK,YAAY,CAAC;AAE/C,KAAI,QACF,SAAQ,IAAI,MAAM,QAAQ,EAAE,MAAM,YAAY,eAAe,CAAC,GAAG,QAAQ,EAAE,CAAC;AAE9E,KAAI,SACF,SAAQ,IAAI,MAAM,QAAQ,EAAE,MAAM,YAAY,eAAe,CAAC,GAAG,MAAM,UAAU,KAAK,SAAS,CAAC,EAAE,CAAC;AAGrG,KAAI,aAAa;AACf,SAAO;AACP,MAAI,WAAW,SACb,QAAO;CAEV;AAED,QAAO;AACR"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { logger } from "./logger-
|
|
1
|
+
import { OptionHolder } from "./OptionHolder-DCm-Anf0.js";
|
|
2
|
+
import { copy, exist, join, relativePath } from "./FileUtil-Dq8PORna.js";
|
|
3
|
+
import { logger } from "./logger-BLZBLDnp.js";
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
|
|
6
6
|
//#region src/util/MetadataSyncUtil.ts
|
|
@@ -39,4 +39,4 @@ function copyAndroidMetadata(to, workspace) {
|
|
|
39
39
|
|
|
40
40
|
//#endregion
|
|
41
41
|
export { copyAndroidMetadata, copyIosMetadata };
|
|
42
|
-
//# sourceMappingURL=MetadataSyncUtil-
|
|
42
|
+
//# sourceMappingURL=MetadataSyncUtil-D8LnTqSH.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MetadataSyncUtil-
|
|
1
|
+
{"version":3,"file":"MetadataSyncUtil-D8LnTqSH.js","names":["to: 'resources' | 'workspace'","workspace: string"],"sources":["../src/util/MetadataSyncUtil.ts"],"sourcesContent":["import chalk from 'chalk';\n\nimport { copy, exist, join, relativePath } from './FileUtil';\nimport { logger } from './logger';\nimport { OptionHolder } from './OptionHolder';\n\nexport function copyIosMetadata(to: 'resources' | 'workspace', workspace: string) {\n const iosDir = workspace;\n\n const nativeDir = join(iosDir, 'fastlane');\n const metadataNativeDir = join(nativeDir, 'metadata');\n const screenshotsNativeDir = join(nativeDir, 'screenshots');\n\n const resourcesDir = join(OptionHolder.resourcesDir, 'metadata/ios');\n const metadataResourcesDir = join(resourcesDir, 'metadata');\n const screenshotsResourcesDir = join(resourcesDir, 'screenshots');\n\n if (to === 'resources') {\n if (exist(metadataNativeDir) && exist(screenshotsNativeDir)) {\n copy(metadataNativeDir, metadataResourcesDir);\n copy(screenshotsNativeDir, screenshotsResourcesDir);\n\n logger.done(\n `iOS Metadata saved in ${chalk.inverse(relativePath(OptionHolder.projectDir, resourcesDir))}. You can edit inside contents.`,\n );\n } else {\n logger.warn(\n `iOS Metadata not found in ${chalk.inverse(relativePath(OptionHolder.projectDir, nativeDir))}`,\n );\n }\n } else {\n if (exist(metadataResourcesDir) && exist(screenshotsResourcesDir)) {\n copy(metadataResourcesDir, metadataNativeDir);\n copy(screenshotsResourcesDir, screenshotsNativeDir);\n\n logger.done(\n `iOS Metadata copyed to ${chalk.inverse(relativePath(OptionHolder.projectDir, nativeDir))}`,\n );\n } else {\n logger.warn(\n `iOS Metadata not found in ${chalk.inverse(relativePath(OptionHolder.projectDir, resourcesDir))}`,\n );\n }\n }\n}\n\nexport function copyAndroidMetadata(to: 'resources' | 'workspace', workspace: string) {\n const androidDir = workspace;\n\n const nativeDir = join(androidDir, 'fastlane/metadata/android');\n const resourcesDir = join(OptionHolder.resourcesDir, 'metadata/android');\n\n if (to === 'resources') {\n if (exist(nativeDir)) {\n copy(nativeDir, resourcesDir);\n logger.done(\n `Android Metadata saved in ${chalk.inverse(relativePath(OptionHolder.projectDir, resourcesDir))}. You can edit inside contents.`,\n );\n } else {\n logger.warn(\n `Android Metadata not found in ${chalk.inverse(relativePath(OptionHolder.projectDir, nativeDir))}`,\n );\n }\n } else {\n if (exist(resourcesDir)) {\n copy(resourcesDir, nativeDir);\n logger.done(\n `Android Metadata copyed to ${chalk.inverse(relativePath(OptionHolder.projectDir, nativeDir))}`,\n );\n } else {\n logger.warn(\n `Android Metadata not found in ${chalk.inverse(relativePath(OptionHolder.projectDir, resourcesDir))}`,\n );\n }\n }\n}\n"],"mappings":";;;;;;AAMA,SAAgB,gBAAgBA,IAA+BC,WAAmB;CAChF,MAAM,SAAS;CAEf,MAAM,YAAY,KAAK,QAAQ,WAAW;CAC1C,MAAM,oBAAoB,KAAK,WAAW,WAAW;CACrD,MAAM,uBAAuB,KAAK,WAAW,cAAc;CAE3D,MAAM,eAAe,KAAK,aAAa,cAAc,eAAe;CACpE,MAAM,uBAAuB,KAAK,cAAc,WAAW;CAC3D,MAAM,0BAA0B,KAAK,cAAc,cAAc;AAEjE,KAAI,OAAO,YACT,KAAI,MAAM,kBAAkB,IAAI,MAAM,qBAAqB,EAAE;AAC3D,OAAK,mBAAmB,qBAAqB;AAC7C,OAAK,sBAAsB,wBAAwB;AAEnD,SAAO,MACJ,wBAAwB,MAAM,QAAQ,aAAa,aAAa,YAAY,aAAa,CAAC,CAAC,iCAC7F;CACF,MACC,QAAO,MACJ,4BAA4B,MAAM,QAAQ,aAAa,aAAa,YAAY,UAAU,CAAC,CAAC,EAC9F;UAGC,MAAM,qBAAqB,IAAI,MAAM,wBAAwB,EAAE;AACjE,OAAK,sBAAsB,kBAAkB;AAC7C,OAAK,yBAAyB,qBAAqB;AAEnD,SAAO,MACJ,yBAAyB,MAAM,QAAQ,aAAa,aAAa,YAAY,UAAU,CAAC,CAAC,EAC3F;CACF,MACC,QAAO,MACJ,4BAA4B,MAAM,QAAQ,aAAa,aAAa,YAAY,aAAa,CAAC,CAAC,EACjG;AAGN;AAED,SAAgB,oBAAoBD,IAA+BC,WAAmB;CACpF,MAAM,aAAa;CAEnB,MAAM,YAAY,KAAK,YAAY,4BAA4B;CAC/D,MAAM,eAAe,KAAK,aAAa,cAAc,mBAAmB;AAExE,KAAI,OAAO,YACT,KAAI,MAAM,UAAU,EAAE;AACpB,OAAK,WAAW,aAAa;AAC7B,SAAO,MACJ,4BAA4B,MAAM,QAAQ,aAAa,aAAa,YAAY,aAAa,CAAC,CAAC,iCACjG;CACF,MACC,QAAO,MACJ,gCAAgC,MAAM,QAAQ,aAAa,aAAa,YAAY,UAAU,CAAC,CAAC,EAClG;UAGC,MAAM,aAAa,EAAE;AACvB,OAAK,cAAc,UAAU;AAC7B,SAAO,MACJ,6BAA6B,MAAM,QAAQ,aAAa,aAAa,YAAY,UAAU,CAAC,CAAC,EAC/F;CACF,MACC,QAAO,MACJ,gCAAgC,MAAM,QAAQ,aAAa,aAAa,YAAY,aAAa,CAAC,CAAC,EACrG;AAGN"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { logger } from "./logger-
|
|
4
|
-
import { exe } from "./execShellScript-
|
|
1
|
+
import { OptionHolder } from "./OptionHolder-DCm-Anf0.js";
|
|
2
|
+
import { exist, readJsonSlow, resolve } from "./FileUtil-Dq8PORna.js";
|
|
3
|
+
import { logger } from "./logger-BLZBLDnp.js";
|
|
4
|
+
import { exe } from "./execShellScript-5FcHM7dZ.js";
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
6
|
import { dirname } from "node:path";
|
|
7
7
|
import semver from "semver";
|
|
@@ -47,4 +47,4 @@ async function inspectNativeEnvironment() {
|
|
|
47
47
|
|
|
48
48
|
//#endregion
|
|
49
49
|
export { inspectNativeEnvironment };
|
|
50
|
-
//# sourceMappingURL=NativeEnvironment-
|
|
50
|
+
//# sourceMappingURL=NativeEnvironment-CQn7erIC.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NativeEnvironment-
|
|
1
|
+
{"version":3,"file":"NativeEnvironment-CQn7erIC.js","names":["expoPackage: string","nativePackage: string"],"sources":["../src/util/setup/NativeEnvironment.ts"],"sourcesContent":["import { createRequire } from 'node:module';\nimport { dirname } from 'node:path';\n\nimport semver from 'semver';\n\nimport { exist, readJsonSlow, resolve } from '../FileUtil';\nimport { logger } from '../logger';\nimport { OptionHolder } from '../OptionHolder';\nimport { exe } from './execShellScript';\n\nexport async function inspectNativeEnvironment() {\n const platform = OptionHolder.input.platform;\n if (platform === 'ios' && process.platform !== 'darwin') {\n throw new Error('Local iOS builds require macOS and Xcode.');\n }\n const require = createRequire(resolve(OptionHolder.projectDir, 'package.json'));\n let expoPackage: string;\n let nativePackage: string;\n try {\n expoPackage = require.resolve('expo/package.json');\n nativePackage = require.resolve('react-native/package.json');\n } catch {\n throw new Error(\n 'Install Expo and React Native in the target project before building. CNG projects with Expo SDK 52 or newer are supported.',\n );\n }\n const native = readJsonSlow(nativePackage) as { engines?: { node?: string } };\n if (native.engines?.node && !semver.satisfies(process.version, native.engines.node)) {\n throw new Error(\n `Node ${process.version} at ${process.execPath} does not meet this React Native version's requirement: ${native.engines.node}. Activate a compatible Node before rerunning.`,\n );\n }\n const expoCli = resolve(dirname(expoPackage), 'bin', 'cli');\n if (!exist(expoCli)) throw new Error(`Project-local Expo CLI not found: ${expoCli}`);\n await exe(platform === 'ios' ? 'xcodebuild' : 'java', ['-version'], {\n cwd: OptionHolder.projectDir,\n });\n logger.info(`Node ${process.version}: ${process.execPath}; Expo CLI: ${expoCli}`);\n const env = {\n CI: '1',\n PATH: `${dirname(process.execPath)}:${process.env.PATH ?? ''}`,\n };\n return async function prebuild() {\n await exe(\n process.execPath,\n [expoCli, 'prebuild', '--clean', '--platform', platform, '--no-install'],\n {\n cwd: OptionHolder.projectDir,\n env,\n },\n );\n logger.done('Expo CNG prebuild');\n };\n}\n"],"mappings":";;;;;;;;;AAUA,eAAsB,2BAA2B;CAC/C,MAAM,WAAW,aAAa,MAAM;AACpC,KAAI,aAAa,SAAS,QAAQ,aAAa,SAC7C,OAAM,IAAI,MAAM;CAElB,MAAM,UAAU,cAAc,QAAQ,aAAa,YAAY,eAAe,CAAC;CAC/E,IAAIA;CACJ,IAAIC;AACJ,KAAI;AACF,gBAAc,QAAQ,QAAQ,oBAAoB;AAClD,kBAAgB,QAAQ,QAAQ,4BAA4B;CAC7D,QAAO;AACN,QAAM,IAAI,MACR;CAEH;CACD,MAAM,SAAS,aAAa,cAAc;AAC1C,KAAI,OAAO,SAAS,SAAS,OAAO,UAAU,QAAQ,SAAS,OAAO,QAAQ,KAAK,CACjF,OAAM,IAAI,OACP,OAAO,QAAQ,QAAQ,MAAM,QAAQ,SAAS,0DAA0D,OAAO,QAAQ,KAAK;CAGjI,MAAM,UAAU,QAAQ,QAAQ,YAAY,EAAE,OAAO,MAAM;AAC3D,MAAK,MAAM,QAAQ,CAAE,OAAM,IAAI,OAAO,oCAAoC,QAAQ;AAClF,OAAM,IAAI,aAAa,QAAQ,eAAe,QAAQ,CAAC,UAAW,GAAE,EAClE,KAAK,aAAa,WACnB,EAAC;AACF,QAAO,MAAM,OAAO,QAAQ,QAAQ,IAAI,QAAQ,SAAS,cAAc,QAAQ,EAAE;CACjF,MAAM,MAAM;EACV,IAAI;EACJ,OAAO,EAAE,QAAQ,QAAQ,SAAS,CAAC,GAAG,QAAQ,IAAI,QAAQ,GAAG;CAC9D;AACD,QAAO,eAAe,WAAW;AAC/B,QAAM,IACJ,QAAQ,UACR;GAAC;GAAS;GAAY;GAAW;GAAc;GAAU;EAAe,GACxE;GACE,KAAK,aAAa;GAClB;EACD,EACF;AACD,SAAO,KAAK,oBAAoB;CACjC;AACF"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { resolve } from "./FileUtil-
|
|
1
|
+
import { resolve } from "./FileUtil-Dq8PORna.js";
|
|
2
2
|
import { fileURLToPath } from "url";
|
|
3
3
|
|
|
4
4
|
//#region package.json
|
|
5
5
|
var name = "expo-release-it";
|
|
6
|
-
var version = "0.
|
|
6
|
+
var version = "1.0.0";
|
|
7
7
|
var homepage = "https://expo-release-it.mjstudio.net/";
|
|
8
8
|
var license = "MIT";
|
|
9
9
|
var repository = "https://github.com/mym0404/expo-release-it";
|
|
@@ -90,7 +90,6 @@ const OptionHolder = {
|
|
|
90
90
|
},
|
|
91
91
|
input: { git: {} },
|
|
92
92
|
keyholderMap: {},
|
|
93
|
-
templateDirNames: ["key"],
|
|
94
93
|
projectDir: "",
|
|
95
94
|
resourcesDir: "",
|
|
96
95
|
keyDir: "",
|
|
@@ -102,4 +101,4 @@ const OptionHolder = {
|
|
|
102
101
|
|
|
103
102
|
//#endregion
|
|
104
103
|
export { OptionHolder };
|
|
105
|
-
//# sourceMappingURL=OptionHolder-
|
|
104
|
+
//# sourceMappingURL=OptionHolder-DCm-Anf0.js.map
|