catalyst-core 1.1.0 → 1.2.0-canary.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/bin/catalyst.js +54 -6
- package/changelog.md +27 -1
- package/dist/errors/registry.js +306 -18
- package/dist/errors-index.json +273 -70
- package/dist/native/androidProject/app/build.gradle.kts +53 -79
- package/dist/native/androidProject/app/src/main/AndroidManifest.xml +1 -1
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/CatalystConstants.kt +3 -1
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/MainActivity.kt +32 -4
- package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/KeyboardUtil.kt +5 -1
- package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/ConfigMappingTest.kt +25 -0
- package/dist/native/androidSetup.js +76 -170
- package/dist/native/androidToolchain.js +642 -0
- package/dist/native/appIcon.js +100 -0
- package/dist/native/buildAndroid/assets.js +29 -5
- package/dist/native/buildAndroid/build.js +110 -223
- package/dist/native/buildAndroid/config.js +57 -65
- package/dist/native/buildAndroid/devices.js +176 -0
- package/dist/native/buildAndroid/index.js +271 -46
- package/dist/native/buildAndroid/output.js +43 -0
- package/dist/native/buildAndroid/signing.js +456 -0
- package/dist/native/buildAppAndroid.js +27 -7
- package/dist/native/buildAppIos.js +139 -20
- package/dist/native/buildIos/assets.js +76 -4
- package/dist/native/buildIos/build.js +31 -181
- package/dist/native/buildIos/config.js +126 -11
- package/dist/native/buildIos/index.js +354 -34
- package/dist/native/buildIos/localhostCert.js +87 -0
- package/dist/native/buildIos/output.js +28 -0
- package/dist/native/buildIos/signing.js +596 -0
- package/dist/native/credentials.js +309 -0
- package/dist/native/exportCredentials.js +51 -0
- package/dist/native/iosToolchain.js +583 -0
- package/dist/native/iosnativeWebView/Configurations/Shared.xcconfig +1 -3
- package/dist/native/iosnativeWebView/iosnativeWebView/Info-Release.plist +2 -0
- package/dist/native/iosnativeWebView/iosnativeWebView/PrivacyInfo.xcprivacy +40 -0
- package/dist/native/iosnativeWebView/iosnativeWebView/iosnativeWebView.entitlements +0 -2
- package/dist/native/iosnativeWebView/iosnativeWebView.xcodeproj/project.pbxproj +4 -4
- package/dist/native/localState.js +148 -0
- package/dist/native/nativeConfig.js +621 -0
- package/dist/native/releaseOutput.js +53 -0
- package/dist/native/renameAndroidProject.js +154 -369
- package/dist/native/setupEmulatorIos.js +58 -275
- package/dist/native/setupServer.js +520 -124
- package/dist/native/utils.js +418 -115
- package/dist/vite/resolveDevServerConfig.js +21 -0
- package/mcp_v2/knowledge-base.json +13 -11
- package/mcp_v2/test/config.test.ts +40 -0
- package/mcp_v2/tools/build.js +80 -104
- package/mcp_v2/tools/config.js +181 -174
- package/package.json +1 -1
- package/test/cli/nativeFlags.test.ts +97 -0
- package/test/native/androidDevices.test.ts +230 -0
- package/test/native/androidElfAlignment.test.ts +148 -0
- package/test/native/androidSigning.test.ts +646 -0
- package/test/native/androidToolchain.test.ts +766 -0
- package/test/native/appIcon.test.ts +124 -0
- package/test/native/credentials.test.ts +241 -0
- package/test/native/interaction.test.ts +179 -0
- package/test/native/iosConfigPhase.test.ts +611 -0
- package/test/native/iosSigning.test.ts +1060 -0
- package/test/native/iosToolchain.test.ts +821 -0
- package/test/native/localState.test.ts +80 -0
- package/test/native/nativeConfig.test.ts +602 -0
- package/test/native/setupServer.test.ts +529 -0
- package/test/native/utils.test.ts +102 -127
- package/test/vite/resolveDevServerConfig.test.js +25 -0
- package/dist/native/androidProject/keystore/Untitled +0 -0
- package/dist/native/androidProject/keystore/release-key.jks +0 -0
- package/dist/native/iosnativeWebView/iosnativeWebView/localhost.p12 +0 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.MAX_CREDENTIALS_SECRET_BYTES = void 0;
|
|
7
|
+
exports.cleanupOnSignal = cleanupOnSignal;
|
|
8
|
+
exports.credentialsDir = credentialsDir;
|
|
9
|
+
exports.credentialsEnvName = credentialsEnvName;
|
|
10
|
+
exports.maskSecret = maskSecret;
|
|
11
|
+
exports.packCredentials = packCredentials;
|
|
12
|
+
exports.resolveCredentials = resolveCredentials;
|
|
13
|
+
exports.unpackCredentials = unpackCredentials;
|
|
14
|
+
var _child_process = require("child_process");
|
|
15
|
+
var _fs = _interopRequireDefault(require("fs"));
|
|
16
|
+
var _os = _interopRequireDefault(require("os"));
|
|
17
|
+
var _path = _interopRequireDefault(require("path"));
|
|
18
|
+
var _utils = require("./utils.js");
|
|
19
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
20
|
+
// Signing files live in git-ignored credentials/<platform>/ in the app. CI
|
|
21
|
+
// gets the same folder from one secret per platform, CATALYST_<PLATFORM>_CREDENTIALS:
|
|
22
|
+
// a base64 gzipped tar of that folder, made by `catalyst credentials:export`.
|
|
23
|
+
// Everything that reads credentials goes through resolveCredentials, so the
|
|
24
|
+
// folder and the secret behave the same.
|
|
25
|
+
|
|
26
|
+
const PLATFORMS = ["android", "ios"];
|
|
27
|
+
|
|
28
|
+
// GitHub's limit for one secret value.
|
|
29
|
+
const MAX_CREDENTIALS_SECRET_BYTES = exports.MAX_CREDENTIALS_SECRET_BYTES = 48 * 1024;
|
|
30
|
+
|
|
31
|
+
// macOS tar adds AppleDouble (._*) files for extended attributes unless told not to.
|
|
32
|
+
const TAR_ENV = {
|
|
33
|
+
...process.env,
|
|
34
|
+
COPYFILE_DISABLE: "1"
|
|
35
|
+
};
|
|
36
|
+
function assertPlatform(platform) {
|
|
37
|
+
if (!PLATFORMS.includes(platform)) {
|
|
38
|
+
throw new Error(`Unknown platform "${platform}": expected android or ios`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** @param {"android"|"ios"} platform */
|
|
43
|
+
function credentialsEnvName(platform) {
|
|
44
|
+
assertPlatform(platform);
|
|
45
|
+
return `CATALYST_${platform.toUpperCase()}_CREDENTIALS`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The project's credentials folder for a platform (it may not exist).
|
|
50
|
+
*
|
|
51
|
+
* @param {"android"|"ios"} platform
|
|
52
|
+
* @param {object} [options]
|
|
53
|
+
* @param {string} [options.cwd]
|
|
54
|
+
*/
|
|
55
|
+
function credentialsDir(platform, {
|
|
56
|
+
cwd = process.cwd()
|
|
57
|
+
} = {}) {
|
|
58
|
+
assertPlatform(platform);
|
|
59
|
+
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal - platform is one of two fixed names; cwd is the app root.
|
|
60
|
+
return _path.default.join(cwd, "credentials", platform);
|
|
61
|
+
}
|
|
62
|
+
function isDirectory(dir) {
|
|
63
|
+
try {
|
|
64
|
+
return _fs.default.statSync(dir).isDirectory();
|
|
65
|
+
} catch (error) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** GitHub Actions' escaping for workflow command data. */
|
|
71
|
+
function escapeCommandData(value) {
|
|
72
|
+
return String(value).replace(/%/g, "%25").replace(/\r/g, "%0D").replace(/\n/g, "%0A");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Hide a secret in GitHub Actions logs from here on. A no-op elsewhere.
|
|
77
|
+
* Call it for every password read from credentials before it can reach a
|
|
78
|
+
* log line or a child process's echoed output.
|
|
79
|
+
*
|
|
80
|
+
* @param {string} value
|
|
81
|
+
* @param {object} [options]
|
|
82
|
+
* @param {Record<string, string | undefined>} [options.env]
|
|
83
|
+
* @param {(text: string) => void} [options.write]
|
|
84
|
+
* @returns {boolean} whether a mask was printed
|
|
85
|
+
*/
|
|
86
|
+
function maskSecret(value, {
|
|
87
|
+
env = process.env,
|
|
88
|
+
write = text => process.stdout.write(text)
|
|
89
|
+
} = {}) {
|
|
90
|
+
if (env.GITHUB_ACTIONS !== "true" || value === undefined || value === null || value === "") return false;
|
|
91
|
+
write(`::add-mask::${escapeCommandData(value)}\n`);
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Pack credentials/<platform>/ into the CATALYST_<PLATFORM>_CREDENTIALS value.
|
|
97
|
+
*
|
|
98
|
+
* @param {"android"|"ios"} platform
|
|
99
|
+
* @param {object} [options]
|
|
100
|
+
* @param {string} [options.cwd]
|
|
101
|
+
* @returns {string} base64 of a gzipped tar of the folder's contents
|
|
102
|
+
*/
|
|
103
|
+
function packCredentials(platform, {
|
|
104
|
+
cwd = process.cwd()
|
|
105
|
+
} = {}) {
|
|
106
|
+
const dir = credentialsDir(platform, {
|
|
107
|
+
cwd
|
|
108
|
+
});
|
|
109
|
+
const files = isDirectory(dir) ? _fs.default.readdirSync(dir).filter(name => name !== ".DS_Store") : [];
|
|
110
|
+
if (files.length === 0) {
|
|
111
|
+
throw (0, _utils.nativeError)("NATIVE-008", `credentials/${platform}/ is missing or empty in ${cwd}`);
|
|
112
|
+
}
|
|
113
|
+
// nosemgrep: javascript.lang.security.detect-child-process.detect-child-process - fixed tar argv; dir is the app's own credentials folder.
|
|
114
|
+
const archive = (0, _child_process.execFileSync)("tar", ["-czf", "-", "--exclude", ".DS_Store", "-C", dir, "."], {
|
|
115
|
+
env: TAR_ENV,
|
|
116
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
117
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
118
|
+
});
|
|
119
|
+
const value = archive.toString("base64");
|
|
120
|
+
if (value.length > MAX_CREDENTIALS_SECRET_BYTES) {
|
|
121
|
+
throw (0, _utils.nativeError)("NATIVE-009", `credentials/${platform}/ packs to ${Math.ceil(value.length / 1024)} KB; the limit is 48 KB`);
|
|
122
|
+
}
|
|
123
|
+
return value;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Tar entries that could write outside the destination, or are links. */
|
|
127
|
+
function unsafeEntries(listing, verbose) {
|
|
128
|
+
const names = listing.split("\n").filter(Boolean);
|
|
129
|
+
const bad = names.filter(name => {
|
|
130
|
+
const clean = name.replace(/^\.\//, "");
|
|
131
|
+
return clean.startsWith("/") || clean.split("/").includes("..");
|
|
132
|
+
});
|
|
133
|
+
// Long listings start each line with the entry type: "-" file, "d" folder.
|
|
134
|
+
const links = verbose.split("\n").filter(Boolean).filter(line => !/^[-d]/.test(line));
|
|
135
|
+
return [...bad, ...links];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Unpack a CATALYST_<PLATFORM>_CREDENTIALS value into `destDir`.
|
|
140
|
+
* Only plain files and folders inside `destDir` are accepted.
|
|
141
|
+
*
|
|
142
|
+
* @param {string} value
|
|
143
|
+
* @param {string} destDir - created when missing
|
|
144
|
+
* @param {object} [options]
|
|
145
|
+
* @param {string} [options.envName] - for the error message
|
|
146
|
+
*/
|
|
147
|
+
function unpackCredentials(value, destDir, {
|
|
148
|
+
envName = "the credentials secret"
|
|
149
|
+
} = {}) {
|
|
150
|
+
const archive = Buffer.from(String(value || "").trim(), "base64");
|
|
151
|
+
if (archive.length < 2 || archive[0] !== 0x1f || archive[1] !== 0x8b) {
|
|
152
|
+
throw (0, _utils.nativeError)("NATIVE-007", `${envName} is not a base64 gzipped tar`);
|
|
153
|
+
}
|
|
154
|
+
const work = _fs.default.mkdtempSync(_path.default.join(_os.default.tmpdir(), "catalyst-credentials-archive-"));
|
|
155
|
+
try {
|
|
156
|
+
const file = _path.default.join(work, "credentials.tgz");
|
|
157
|
+
_fs.default.writeFileSync(file, archive, {
|
|
158
|
+
mode: 0o600
|
|
159
|
+
});
|
|
160
|
+
let listing;
|
|
161
|
+
let verbose;
|
|
162
|
+
try {
|
|
163
|
+
// nosemgrep: javascript.lang.security.detect-child-process.detect-child-process - fixed tar argv on a temp file.
|
|
164
|
+
listing = (0, _child_process.execFileSync)("tar", ["-tzf", file], {
|
|
165
|
+
encoding: "utf8",
|
|
166
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
167
|
+
});
|
|
168
|
+
// nosemgrep: javascript.lang.security.detect-child-process.detect-child-process - fixed tar argv on a temp file.
|
|
169
|
+
verbose = (0, _child_process.execFileSync)("tar", ["-tvzf", file], {
|
|
170
|
+
encoding: "utf8",
|
|
171
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
172
|
+
});
|
|
173
|
+
} catch (error) {
|
|
174
|
+
throw (0, _utils.nativeError)("NATIVE-007", `${envName} could not be read as a tar archive`);
|
|
175
|
+
}
|
|
176
|
+
const unsafe = unsafeEntries(listing, verbose);
|
|
177
|
+
if (unsafe.length) {
|
|
178
|
+
throw (0, _utils.nativeError)("NATIVE-007", `${envName} holds links or paths outside the folder`);
|
|
179
|
+
}
|
|
180
|
+
_fs.default.mkdirSync(destDir, {
|
|
181
|
+
recursive: true,
|
|
182
|
+
mode: 0o700
|
|
183
|
+
});
|
|
184
|
+
// nosemgrep: javascript.lang.security.detect-child-process.detect-child-process - fixed tar argv; entries were checked above.
|
|
185
|
+
(0, _child_process.execFileSync)("tar", ["-xzf", file, "-C", destDir], {
|
|
186
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
187
|
+
});
|
|
188
|
+
} finally {
|
|
189
|
+
_fs.default.rmSync(work, {
|
|
190
|
+
recursive: true,
|
|
191
|
+
force: true
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Run `cleanup` on SIGINT and SIGTERM too: a Ctrl+C ends the process
|
|
198
|
+
* without running any `finally`, which would leave unpacked secrets in the
|
|
199
|
+
* temp folder. After cleaning up it exits (130 or 143), unless another
|
|
200
|
+
* handler for the signal is still to run, in which case that one exits.
|
|
201
|
+
*
|
|
202
|
+
* @param {() => void} cleanup
|
|
203
|
+
* @param {object} [options]
|
|
204
|
+
* @param {{ once: Function, removeListener: Function, listenerCount?: Function }} [options.signals]
|
|
205
|
+
* @param {(code: number) => void} [options.exit]
|
|
206
|
+
* @returns {() => void} removes the handlers; call it from the normal cleanup
|
|
207
|
+
*/
|
|
208
|
+
function cleanupOnSignal(cleanup, {
|
|
209
|
+
signals = process,
|
|
210
|
+
exit = code => process.exit(code)
|
|
211
|
+
} = {}) {
|
|
212
|
+
const release = () => {
|
|
213
|
+
signals.removeListener("SIGINT", onSignal);
|
|
214
|
+
signals.removeListener("SIGTERM", onSignal);
|
|
215
|
+
};
|
|
216
|
+
function onSignal(signal) {
|
|
217
|
+
release();
|
|
218
|
+
cleanup();
|
|
219
|
+
const others = typeof signals.listenerCount === "function" ? signals.listenerCount(signal) : 0;
|
|
220
|
+
if (others === 0) exit(signal === "SIGINT" ? 130 : 143);
|
|
221
|
+
}
|
|
222
|
+
signals.once("SIGINT", onSignal);
|
|
223
|
+
signals.once("SIGTERM", onSignal);
|
|
224
|
+
return release;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Where this build reads its credentials for a platform.
|
|
229
|
+
*
|
|
230
|
+
* 1. credentials/<platform>/ in the app, when it exists.
|
|
231
|
+
* 2. Otherwise CATALYST_<PLATFORM>_CREDENTIALS, unpacked into a private temp
|
|
232
|
+
* folder that `cleanup()` removes, and that an interrupted build (Ctrl+C,
|
|
233
|
+
* SIGTERM) removes too. The project folder is never written.
|
|
234
|
+
* 3. Otherwise `source: "none"` and `dir` is the (missing) project folder,
|
|
235
|
+
* where a first-time setup should create it.
|
|
236
|
+
*
|
|
237
|
+
* The caller still masks each password it reads with maskSecret().
|
|
238
|
+
*
|
|
239
|
+
* @param {"android"|"ios"} platform
|
|
240
|
+
* @param {object} [options]
|
|
241
|
+
* @param {string} [options.cwd]
|
|
242
|
+
* @param {Record<string, string | undefined>} [options.env]
|
|
243
|
+
* @param {(message: string, type?: string) => void} [options.log]
|
|
244
|
+
* @param {object} [options.signals] - for tests; see cleanupOnSignal
|
|
245
|
+
* @param {(code: number) => void} [options.exit] - for tests
|
|
246
|
+
* @returns {{ dir: string, source: "folder" | "env" | "none", envName: string, cleanup: () => void }}
|
|
247
|
+
*/
|
|
248
|
+
function resolveCredentials(platform, {
|
|
249
|
+
cwd = process.cwd(),
|
|
250
|
+
env = process.env,
|
|
251
|
+
log = () => {},
|
|
252
|
+
signals,
|
|
253
|
+
exit
|
|
254
|
+
} = {}) {
|
|
255
|
+
const dir = credentialsDir(platform, {
|
|
256
|
+
cwd
|
|
257
|
+
});
|
|
258
|
+
const envName = credentialsEnvName(platform);
|
|
259
|
+
if (isDirectory(dir)) return {
|
|
260
|
+
dir,
|
|
261
|
+
source: "folder",
|
|
262
|
+
envName,
|
|
263
|
+
cleanup: () => {}
|
|
264
|
+
};
|
|
265
|
+
const value = env[envName];
|
|
266
|
+
if (value && String(value).trim()) {
|
|
267
|
+
const temp = _fs.default.mkdtempSync(_path.default.join(_os.default.tmpdir(), `catalyst-${platform}-credentials-`));
|
|
268
|
+
_fs.default.chmodSync(temp, 0o700);
|
|
269
|
+
try {
|
|
270
|
+
unpackCredentials(value, temp, {
|
|
271
|
+
envName
|
|
272
|
+
});
|
|
273
|
+
} catch (error) {
|
|
274
|
+
_fs.default.rmSync(temp, {
|
|
275
|
+
recursive: true,
|
|
276
|
+
force: true
|
|
277
|
+
});
|
|
278
|
+
throw error;
|
|
279
|
+
}
|
|
280
|
+
log(`Using ${platform} credentials from ${envName}`, "info");
|
|
281
|
+
const remove = () => _fs.default.rmSync(temp, {
|
|
282
|
+
recursive: true,
|
|
283
|
+
force: true
|
|
284
|
+
});
|
|
285
|
+
const releaseSignals = cleanupOnSignal(remove, {
|
|
286
|
+
...(signals ? {
|
|
287
|
+
signals
|
|
288
|
+
} : {}),
|
|
289
|
+
...(exit ? {
|
|
290
|
+
exit
|
|
291
|
+
} : {})
|
|
292
|
+
});
|
|
293
|
+
return {
|
|
294
|
+
dir: temp,
|
|
295
|
+
source: "env",
|
|
296
|
+
envName,
|
|
297
|
+
cleanup: () => {
|
|
298
|
+
releaseSignals();
|
|
299
|
+
remove();
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
return {
|
|
304
|
+
dir,
|
|
305
|
+
source: "none",
|
|
306
|
+
envName,
|
|
307
|
+
cleanup: () => {}
|
|
308
|
+
};
|
|
309
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.runExportCredentials = runExportCredentials;
|
|
7
|
+
var _credentials = require("./credentials.js");
|
|
8
|
+
// `catalyst credentials:export <android|ios>`: print credentials/<platform>/
|
|
9
|
+
// as the value of the CATALYST_<PLATFORM>_CREDENTIALS CI secret. The value
|
|
10
|
+
// goes to stdout alone (so it can be piped to pbcopy); the one line on where
|
|
11
|
+
// to paste it goes to stderr. The same value is the backup of the folder.
|
|
12
|
+
|
|
13
|
+
const GUTTER = " ";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {object} [options]
|
|
17
|
+
* @param {string[]} [options.argv]
|
|
18
|
+
* @param {string} [options.cwd]
|
|
19
|
+
* @param {(text: string) => void} [options.stdout]
|
|
20
|
+
* @param {(text: string) => void} [options.stderr]
|
|
21
|
+
* @returns {number} the exit code
|
|
22
|
+
*/
|
|
23
|
+
function runExportCredentials({
|
|
24
|
+
argv = process.argv.slice(2),
|
|
25
|
+
cwd = process.cwd(),
|
|
26
|
+
stdout = text => process.stdout.write(text),
|
|
27
|
+
stderr = text => process.stderr.write(text)
|
|
28
|
+
} = {}) {
|
|
29
|
+
const platform = argv.find(arg => !arg.startsWith("-"));
|
|
30
|
+
if (platform !== "android" && platform !== "ios") {
|
|
31
|
+
stderr(`\n${GUTTER}Usage: catalyst credentials:export <android|ios>\n\n`);
|
|
32
|
+
return 1;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const value = (0, _credentials.packCredentials)(platform, {
|
|
36
|
+
cwd
|
|
37
|
+
});
|
|
38
|
+
stdout(`${value}\n`);
|
|
39
|
+
stderr(`\n${GUTTER}Paste this into a GitHub Actions secret named ${(0, _credentials.credentialsEnvName)(platform)} ` + "(Settings > Secrets and variables > Actions), and keep a copy somewhere safe as your backup.\n\n");
|
|
40
|
+
return 0;
|
|
41
|
+
} catch (error) {
|
|
42
|
+
const lines = [`\n${GUTTER}error ${error.code ? `[${error.code}] ` : ""}${error.message}`];
|
|
43
|
+
if (error.hint) lines.push(`${GUTTER}hint ${error.hint}`);
|
|
44
|
+
if (error.docUrl) lines.push(`${GUTTER}docs ${error.docUrl}`);
|
|
45
|
+
stderr(`${lines.join("\n")}\n\n`);
|
|
46
|
+
return 1;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (typeof require !== "undefined" && typeof module !== "undefined" && require.main === module) {
|
|
50
|
+
process.exit(runExportCredentials());
|
|
51
|
+
}
|