swiftpatch-cli 1.1.3 → 1.1.4
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/index.js +242 -198
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -57,16 +57,26 @@ __export(api_exports, {
|
|
|
57
57
|
api: () => api
|
|
58
58
|
});
|
|
59
59
|
import axios from "axios";
|
|
60
|
-
|
|
60
|
+
import { readFileSync } from "fs";
|
|
61
|
+
import { dirname, join } from "path";
|
|
62
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
63
|
+
function rejectIfInsecure(url) {
|
|
61
64
|
if (url.startsWith("http://") && !url.includes("localhost") && !url.includes("127.0.0.1")) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
if (process.env.SWIFTPATCH_ALLOW_INSECURE === "1") {
|
|
66
|
+
console.warn(
|
|
67
|
+
"\x1B[33m\u26A0 Warning: API URL uses HTTP instead of HTTPS. Credentials will be sent in plaintext.\x1B[0m"
|
|
68
|
+
);
|
|
69
|
+
} else {
|
|
70
|
+
throw new Error(
|
|
71
|
+
"API URL uses HTTP instead of HTTPS. This is insecure and credentials would be sent in plaintext.\nSet SWIFTPATCH_ALLOW_INSECURE=1 to bypass this check (not recommended for production)."
|
|
72
|
+
);
|
|
73
|
+
}
|
|
65
74
|
}
|
|
66
75
|
}
|
|
67
|
-
function normalizeIds(obj) {
|
|
76
|
+
function normalizeIds(obj, depth = 0) {
|
|
77
|
+
if (depth > 20) return obj;
|
|
68
78
|
if (obj === null || obj === void 0) return obj;
|
|
69
|
-
if (Array.isArray(obj)) return obj.map(normalizeIds);
|
|
79
|
+
if (Array.isArray(obj)) return obj.map((item) => normalizeIds(item, depth + 1));
|
|
70
80
|
if (typeof obj === "object") {
|
|
71
81
|
const result = {};
|
|
72
82
|
for (const [key, value] of Object.entries(obj)) {
|
|
@@ -75,14 +85,14 @@ function normalizeIds(obj) {
|
|
|
75
85
|
} else if (key === "__v") {
|
|
76
86
|
continue;
|
|
77
87
|
} else {
|
|
78
|
-
result[key] = normalizeIds(value);
|
|
88
|
+
result[key] = normalizeIds(value, depth + 1);
|
|
79
89
|
}
|
|
80
90
|
}
|
|
81
91
|
return result;
|
|
82
92
|
}
|
|
83
93
|
return obj;
|
|
84
94
|
}
|
|
85
|
-
var API_BASE_URL, ApiClient, api;
|
|
95
|
+
var API_BASE_URL, __dirname2, CLI_VERSION, ApiClient, api;
|
|
86
96
|
var init_api = __esm({
|
|
87
97
|
"src/lib/api.ts"() {
|
|
88
98
|
"use strict";
|
|
@@ -90,17 +100,24 @@ var init_api = __esm({
|
|
|
90
100
|
init_auth();
|
|
91
101
|
init_config();
|
|
92
102
|
API_BASE_URL = process.env.SWIFTPATCH_API_URL || "https://api.blendapp.ae/api/v1";
|
|
103
|
+
__dirname2 = dirname(fileURLToPath2(import.meta.url));
|
|
104
|
+
CLI_VERSION = "1.0.0";
|
|
105
|
+
try {
|
|
106
|
+
const pkg = JSON.parse(readFileSync(join(__dirname2, "../package.json"), "utf-8"));
|
|
107
|
+
CLI_VERSION = pkg.version;
|
|
108
|
+
} catch {
|
|
109
|
+
}
|
|
93
110
|
ApiClient = class {
|
|
94
111
|
client;
|
|
95
112
|
constructor() {
|
|
96
113
|
const baseURL = config.get("apiUrl") || API_BASE_URL;
|
|
97
|
-
|
|
114
|
+
rejectIfInsecure(baseURL);
|
|
98
115
|
this.client = axios.create({
|
|
99
116
|
baseURL,
|
|
100
117
|
timeout: 3e4,
|
|
101
118
|
headers: {
|
|
102
119
|
"Content-Type": "application/json",
|
|
103
|
-
"User-Agent":
|
|
120
|
+
"User-Agent": `swiftpatch-cli/${CLI_VERSION}`
|
|
104
121
|
}
|
|
105
122
|
});
|
|
106
123
|
this.client.interceptors.request.use((reqConfig) => {
|
|
@@ -475,9 +492,9 @@ init_esm_shims();
|
|
|
475
492
|
init_esm_shims();
|
|
476
493
|
import { Command as Command47 } from "commander";
|
|
477
494
|
import chalk45 from "chalk";
|
|
478
|
-
import { readFileSync as
|
|
479
|
-
import { fileURLToPath as
|
|
480
|
-
import { dirname as
|
|
495
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
496
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
497
|
+
import { dirname as dirname3, join as join3 } from "path";
|
|
481
498
|
|
|
482
499
|
// src/commands/login.ts
|
|
483
500
|
init_esm_shims();
|
|
@@ -520,7 +537,7 @@ var logger = {
|
|
|
520
537
|
};
|
|
521
538
|
|
|
522
539
|
// src/commands/login.ts
|
|
523
|
-
var loginCommand = new Command("login").description("Authenticate with SwiftPatch").option("-k, --api-key <key>", "Login with API key (for CI/CD)").option("-e, --email <email>", "Login with email and password").option("-
|
|
540
|
+
var loginCommand = new Command("login").description("Authenticate with SwiftPatch").option("-k, --api-key <key>", "Login with API key (for CI/CD)").option("-e, --email <email>", "Login with email and password").option("-i, --interactive", "Force interactive login").action(async (options) => {
|
|
524
541
|
const existingToken = auth.getToken();
|
|
525
542
|
if (existingToken && !options.interactive && !options.apiKey && !options.email) {
|
|
526
543
|
const user = await api.getCurrentUser().catch(() => null);
|
|
@@ -556,7 +573,7 @@ var loginCommand = new Command("login").description("Authenticate with SwiftPatc
|
|
|
556
573
|
return;
|
|
557
574
|
}
|
|
558
575
|
if (options.email) {
|
|
559
|
-
await emailLogin(options.email
|
|
576
|
+
await emailLogin(options.email);
|
|
560
577
|
return;
|
|
561
578
|
}
|
|
562
579
|
const { method } = await inquirer.prompt([
|
|
@@ -579,19 +596,17 @@ var loginCommand = new Command("login").description("Authenticate with SwiftPatc
|
|
|
579
596
|
await apiKeyLogin();
|
|
580
597
|
}
|
|
581
598
|
});
|
|
582
|
-
async function emailLogin(email
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
password = answers.password;
|
|
594
|
-
}
|
|
599
|
+
async function emailLogin(email) {
|
|
600
|
+
const answers = await inquirer.prompt([
|
|
601
|
+
{
|
|
602
|
+
type: "password",
|
|
603
|
+
name: "password",
|
|
604
|
+
message: "Password:",
|
|
605
|
+
mask: "*",
|
|
606
|
+
validate: (input) => input ? true : "Password is required"
|
|
607
|
+
}
|
|
608
|
+
]);
|
|
609
|
+
const password = answers.password;
|
|
595
610
|
const spinner = ora("Logging in...").start();
|
|
596
611
|
try {
|
|
597
612
|
const result = await api.loginWithCredentials(email, password);
|
|
@@ -615,26 +630,19 @@ async function emailLogin(email, password) {
|
|
|
615
630
|
}
|
|
616
631
|
}
|
|
617
632
|
async function emailLoginInteractive() {
|
|
618
|
-
const { email
|
|
633
|
+
const { email } = await inquirer.prompt([
|
|
619
634
|
{
|
|
620
635
|
type: "input",
|
|
621
636
|
name: "email",
|
|
622
637
|
message: "Email:",
|
|
623
638
|
validate: (input) => {
|
|
624
639
|
if (!input) return "Email is required";
|
|
625
|
-
if (
|
|
640
|
+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input)) return "Invalid email format";
|
|
626
641
|
return true;
|
|
627
642
|
}
|
|
628
|
-
},
|
|
629
|
-
{
|
|
630
|
-
type: "password",
|
|
631
|
-
name: "password",
|
|
632
|
-
message: "Password:",
|
|
633
|
-
mask: "*",
|
|
634
|
-
validate: (input) => input ? true : "Password is required"
|
|
635
643
|
}
|
|
636
644
|
]);
|
|
637
|
-
await emailLogin(email
|
|
645
|
+
await emailLogin(email);
|
|
638
646
|
}
|
|
639
647
|
async function browserLogin() {
|
|
640
648
|
const spinner = ora("Opening browser...").start();
|
|
@@ -1150,7 +1158,6 @@ import { Command as Command10 } from "commander";
|
|
|
1150
1158
|
import chalk12 from "chalk";
|
|
1151
1159
|
import inquirer6 from "inquirer";
|
|
1152
1160
|
import ora7 from "ora";
|
|
1153
|
-
import path4 from "path";
|
|
1154
1161
|
import fs6 from "fs-extra";
|
|
1155
1162
|
|
|
1156
1163
|
// src/lib/bundler.ts
|
|
@@ -1168,8 +1175,7 @@ var bundler = {
|
|
|
1168
1175
|
minify = true,
|
|
1169
1176
|
sourcemap = false
|
|
1170
1177
|
} = options;
|
|
1171
|
-
const tempDir = path2.join(os2.tmpdir(),
|
|
1172
|
-
await fs.ensureDir(tempDir);
|
|
1178
|
+
const tempDir = await fs.mkdtemp(path2.join(os2.tmpdir(), "swiftpatch-bundle-"));
|
|
1173
1179
|
const bundlePath = path2.join(tempDir, `index.${platform}.bundle`);
|
|
1174
1180
|
const sourcemapPath = sourcemap ? path2.join(tempDir, `index.${platform}.bundle.map`) : void 0;
|
|
1175
1181
|
const args = [
|
|
@@ -1206,8 +1212,7 @@ var bundler = {
|
|
|
1206
1212
|
function runCommand(command, args) {
|
|
1207
1213
|
return new Promise((resolve, reject) => {
|
|
1208
1214
|
const child = spawn(command, args, {
|
|
1209
|
-
stdio: ["inherit", "pipe", "pipe"]
|
|
1210
|
-
shell: true
|
|
1215
|
+
stdio: ["inherit", "pipe", "pipe"]
|
|
1211
1216
|
});
|
|
1212
1217
|
let stderr = "";
|
|
1213
1218
|
child.stdout?.on("data", () => {
|
|
@@ -1232,9 +1237,13 @@ function runCommand(command, args) {
|
|
|
1232
1237
|
init_esm_shims();
|
|
1233
1238
|
import axios2 from "axios";
|
|
1234
1239
|
import fs2 from "fs-extra";
|
|
1240
|
+
var MAX_UPLOAD_SIZE = 500 * 1024 * 1024;
|
|
1235
1241
|
var uploader = {
|
|
1236
1242
|
async uploadBundle(uploadUrl, bundlePath, onProgress) {
|
|
1237
1243
|
const fileSize = (await fs2.stat(bundlePath)).size;
|
|
1244
|
+
if (fileSize > MAX_UPLOAD_SIZE) {
|
|
1245
|
+
throw new Error(`Bundle size (${(fileSize / 1024 / 1024).toFixed(1)}MB) exceeds maximum upload size of ${MAX_UPLOAD_SIZE / 1024 / 1024}MB`);
|
|
1246
|
+
}
|
|
1238
1247
|
const fileStream = fs2.createReadStream(bundlePath);
|
|
1239
1248
|
let uploadedBytes = 0;
|
|
1240
1249
|
fileStream.on("data", (chunk) => {
|
|
@@ -1256,6 +1265,9 @@ var uploader = {
|
|
|
1256
1265
|
*/
|
|
1257
1266
|
async uploadZip(uploadUrl, zipPath, onProgress) {
|
|
1258
1267
|
const fileSize = (await fs2.stat(zipPath)).size;
|
|
1268
|
+
if (fileSize > MAX_UPLOAD_SIZE) {
|
|
1269
|
+
throw new Error(`ZIP size (${(fileSize / 1024 / 1024).toFixed(1)}MB) exceeds maximum upload size of ${MAX_UPLOAD_SIZE / 1024 / 1024}MB`);
|
|
1270
|
+
}
|
|
1259
1271
|
const fileStream = fs2.createReadStream(zipPath);
|
|
1260
1272
|
let uploadedBytes = 0;
|
|
1261
1273
|
fileStream.on("data", (chunk) => {
|
|
@@ -1296,7 +1308,7 @@ function sleep2(ms) {
|
|
|
1296
1308
|
init_esm_shims();
|
|
1297
1309
|
import crypto2 from "crypto";
|
|
1298
1310
|
import fs3 from "fs-extra";
|
|
1299
|
-
import { readFileSync } from "fs";
|
|
1311
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
1300
1312
|
async function hashBundle(bundlePath) {
|
|
1301
1313
|
return new Promise((resolve, reject) => {
|
|
1302
1314
|
const hash = crypto2.createHash("sha256");
|
|
@@ -1308,7 +1320,7 @@ async function hashBundle(bundlePath) {
|
|
|
1308
1320
|
}
|
|
1309
1321
|
function calculateZipHash(filePath) {
|
|
1310
1322
|
try {
|
|
1311
|
-
const fileBuffer =
|
|
1323
|
+
const fileBuffer = readFileSync2(filePath);
|
|
1312
1324
|
return crypto2.createHash("sha256").update(fileBuffer).digest("hex");
|
|
1313
1325
|
} catch {
|
|
1314
1326
|
return null;
|
|
@@ -1677,14 +1689,13 @@ var releaseCommand = new Command10("release").description("Bundle and publish a
|
|
|
1677
1689
|
});
|
|
1678
1690
|
async function detectAppFromConfig() {
|
|
1679
1691
|
const configPaths = [
|
|
1680
|
-
"./swiftpatch.config.js",
|
|
1681
1692
|
"./swiftpatch.config.json",
|
|
1682
1693
|
"./.swiftpatchrc"
|
|
1683
1694
|
];
|
|
1684
1695
|
for (const configPath of configPaths) {
|
|
1685
1696
|
if (await fs6.pathExists(configPath)) {
|
|
1686
1697
|
try {
|
|
1687
|
-
const config2 =
|
|
1698
|
+
const config2 = await fs6.readJson(configPath);
|
|
1688
1699
|
return config2.appId || config2.app;
|
|
1689
1700
|
} catch {
|
|
1690
1701
|
continue;
|
|
@@ -2794,7 +2805,7 @@ init_esm_shims();
|
|
|
2794
2805
|
import { Command as Command34 } from "commander";
|
|
2795
2806
|
import chalk32 from "chalk";
|
|
2796
2807
|
import ora27 from "ora";
|
|
2797
|
-
import
|
|
2808
|
+
import path4 from "path";
|
|
2798
2809
|
import fs7 from "fs-extra";
|
|
2799
2810
|
|
|
2800
2811
|
// src/lib/claude.ts
|
|
@@ -2954,7 +2965,7 @@ async function collectDiagnostics(projectRoot) {
|
|
|
2954
2965
|
gradleDeps: [],
|
|
2955
2966
|
warnings: []
|
|
2956
2967
|
};
|
|
2957
|
-
const pkgPath =
|
|
2968
|
+
const pkgPath = path4.join(projectRoot, "package.json");
|
|
2958
2969
|
if (await fs7.pathExists(pkgPath)) {
|
|
2959
2970
|
try {
|
|
2960
2971
|
diag.packageJson = await fs7.readJson(pkgPath);
|
|
@@ -2985,13 +2996,13 @@ async function collectDiagnostics(projectRoot) {
|
|
|
2985
2996
|
}
|
|
2986
2997
|
const assetDirs = ["assets", "src/assets", "app/assets", "src/images"];
|
|
2987
2998
|
for (const dir of assetDirs) {
|
|
2988
|
-
const fullDir =
|
|
2999
|
+
const fullDir = path4.join(projectRoot, dir);
|
|
2989
3000
|
if (await fs7.pathExists(fullDir)) {
|
|
2990
3001
|
try {
|
|
2991
3002
|
const files = await fs7.readdir(fullDir);
|
|
2992
3003
|
for (const file of files.slice(0, 50)) {
|
|
2993
3004
|
try {
|
|
2994
|
-
const stat = await fs7.stat(
|
|
3005
|
+
const stat = await fs7.stat(path4.join(fullDir, file));
|
|
2995
3006
|
if (stat.isFile() && stat.size > 100 * 1024) {
|
|
2996
3007
|
diag.assets.push({ name: `${dir}/${file}`, sizeKB: Math.round(stat.size / 1024) });
|
|
2997
3008
|
}
|
|
@@ -3002,7 +3013,7 @@ async function collectDiagnostics(projectRoot) {
|
|
|
3002
3013
|
}
|
|
3003
3014
|
}
|
|
3004
3015
|
}
|
|
3005
|
-
const gradlePath =
|
|
3016
|
+
const gradlePath = path4.join(projectRoot, "android/app/build.gradle");
|
|
3006
3017
|
if (await fs7.pathExists(gradlePath)) {
|
|
3007
3018
|
try {
|
|
3008
3019
|
const gradle = await fs7.readFile(gradlePath, "utf-8");
|
|
@@ -3014,7 +3025,7 @@ async function collectDiagnostics(projectRoot) {
|
|
|
3014
3025
|
} catch {
|
|
3015
3026
|
}
|
|
3016
3027
|
}
|
|
3017
|
-
const gradlePropsPath =
|
|
3028
|
+
const gradlePropsPath = path4.join(projectRoot, "android/gradle.properties");
|
|
3018
3029
|
if (await fs7.pathExists(gradlePropsPath)) {
|
|
3019
3030
|
try {
|
|
3020
3031
|
const props = await fs7.readFile(gradlePropsPath, "utf-8");
|
|
@@ -3025,9 +3036,9 @@ async function collectDiagnostics(projectRoot) {
|
|
|
3025
3036
|
}
|
|
3026
3037
|
}
|
|
3027
3038
|
const signingPaths = [
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3039
|
+
path4.join(projectRoot, "swiftpatch-private.pem"),
|
|
3040
|
+
path4.join(projectRoot, ".swiftpatch/private.pem"),
|
|
3041
|
+
path4.join(projectRoot, "keys/swiftpatch-private.pem")
|
|
3031
3042
|
];
|
|
3032
3043
|
for (const p of signingPaths) {
|
|
3033
3044
|
if (await fs7.pathExists(p)) {
|
|
@@ -3035,7 +3046,7 @@ async function collectDiagnostics(projectRoot) {
|
|
|
3035
3046
|
break;
|
|
3036
3047
|
}
|
|
3037
3048
|
}
|
|
3038
|
-
const podfileLock =
|
|
3049
|
+
const podfileLock = path4.join(projectRoot, "ios/Podfile.lock");
|
|
3039
3050
|
if (await fs7.pathExists(podfileLock)) {
|
|
3040
3051
|
try {
|
|
3041
3052
|
const stat = await fs7.stat(podfileLock);
|
|
@@ -3046,8 +3057,8 @@ async function collectDiagnostics(projectRoot) {
|
|
|
3046
3057
|
return diag;
|
|
3047
3058
|
}
|
|
3048
3059
|
var aiDoctorCommand = new Command34("doctor").description("AI-powered pre-publish diagnostics for your React Native project").option("-d, --dir <path>", "Project root directory", process.cwd()).option("-y, --yes", "Skip consent prompt (for CI/CD)").option("--json", "Output raw diagnostics as JSON").action(async (options) => {
|
|
3049
|
-
const projectRoot =
|
|
3050
|
-
if (!await fs7.pathExists(
|
|
3060
|
+
const projectRoot = path4.resolve(options.dir);
|
|
3061
|
+
if (!await fs7.pathExists(path4.join(projectRoot, "package.json"))) {
|
|
3051
3062
|
logger.error("No package.json found. Run this from your React Native project root.");
|
|
3052
3063
|
process.exit(1);
|
|
3053
3064
|
}
|
|
@@ -3809,7 +3820,7 @@ init_api();
|
|
|
3809
3820
|
import { Command as Command39 } from "commander";
|
|
3810
3821
|
import chalk37 from "chalk";
|
|
3811
3822
|
import ora31 from "ora";
|
|
3812
|
-
import
|
|
3823
|
+
import path8 from "path";
|
|
3813
3824
|
import fs11 from "fs-extra";
|
|
3814
3825
|
import os3 from "os";
|
|
3815
3826
|
|
|
@@ -3817,10 +3828,10 @@ import os3 from "os";
|
|
|
3817
3828
|
init_esm_shims();
|
|
3818
3829
|
import archiver from "archiver";
|
|
3819
3830
|
import fs8 from "fs";
|
|
3820
|
-
import
|
|
3831
|
+
import path5 from "path";
|
|
3821
3832
|
function createZip(inputPath, outputPath) {
|
|
3822
3833
|
return new Promise((resolve, reject) => {
|
|
3823
|
-
const zipPath =
|
|
3834
|
+
const zipPath = path5.join(outputPath, "build.zip");
|
|
3824
3835
|
const output = fs8.createWriteStream(zipPath);
|
|
3825
3836
|
const archive = archiver("zip", { zlib: { level: 9 } });
|
|
3826
3837
|
output.on("close", () => resolve());
|
|
@@ -3834,25 +3845,25 @@ function createZip(inputPath, outputPath) {
|
|
|
3834
3845
|
// src/lib/artifacts.ts
|
|
3835
3846
|
init_esm_shims();
|
|
3836
3847
|
import fs9 from "fs-extra";
|
|
3837
|
-
import
|
|
3848
|
+
import path6 from "path";
|
|
3838
3849
|
async function keepArtifacts(contentRootPath, platform, variant) {
|
|
3839
|
-
const artifactsDir =
|
|
3850
|
+
const artifactsDir = path6.join(process.cwd(), "swiftpatch-artifacts", platform, variant);
|
|
3840
3851
|
await fs9.ensureDir(artifactsDir);
|
|
3841
|
-
const bundlesDir =
|
|
3842
|
-
const sourcemapsDir =
|
|
3852
|
+
const bundlesDir = path6.join(contentRootPath, "bundles");
|
|
3853
|
+
const sourcemapsDir = path6.join(contentRootPath, "sourcemaps");
|
|
3843
3854
|
if (await fs9.pathExists(bundlesDir)) {
|
|
3844
|
-
await copyDirRecursive(bundlesDir,
|
|
3855
|
+
await copyDirRecursive(bundlesDir, path6.join(artifactsDir, "bundles"));
|
|
3845
3856
|
}
|
|
3846
3857
|
if (await fs9.pathExists(sourcemapsDir)) {
|
|
3847
|
-
await copyDirRecursive(sourcemapsDir,
|
|
3858
|
+
await copyDirRecursive(sourcemapsDir, path6.join(artifactsDir, "sourcemaps"));
|
|
3848
3859
|
}
|
|
3849
3860
|
}
|
|
3850
3861
|
async function copyDirRecursive(srcDir, destDir) {
|
|
3851
3862
|
await fs9.ensureDir(destDir);
|
|
3852
3863
|
const entries = await fs9.readdir(srcDir);
|
|
3853
3864
|
for (const entry of entries) {
|
|
3854
|
-
const srcPath =
|
|
3855
|
-
const destPath =
|
|
3865
|
+
const srcPath = path6.join(srcDir, entry);
|
|
3866
|
+
const destPath = path6.join(destDir, entry);
|
|
3856
3867
|
const stat = await fs9.stat(srcPath);
|
|
3857
3868
|
if (stat.isDirectory()) {
|
|
3858
3869
|
await copyDirRecursive(srcPath, destPath);
|
|
@@ -3864,16 +3875,16 @@ async function copyDirRecursive(srcDir, destDir) {
|
|
|
3864
3875
|
|
|
3865
3876
|
// src/lib/react-native-utils.ts
|
|
3866
3877
|
init_esm_shims();
|
|
3867
|
-
import * as
|
|
3878
|
+
import * as path7 from "path";
|
|
3868
3879
|
import * as fs10 from "fs";
|
|
3869
3880
|
import * as childProcess from "child_process";
|
|
3870
3881
|
import { coerce, compare } from "semver";
|
|
3871
3882
|
function findUpwardReactNativePackageJson(startDir = process.cwd()) {
|
|
3872
3883
|
let current = startDir;
|
|
3873
|
-
while (current !==
|
|
3874
|
-
const candidate =
|
|
3884
|
+
while (current !== path7.parse(current).root) {
|
|
3885
|
+
const candidate = path7.join(current, "node_modules", "react-native", "package.json");
|
|
3875
3886
|
if (fs10.existsSync(candidate)) return candidate;
|
|
3876
|
-
current =
|
|
3887
|
+
current = path7.dirname(current);
|
|
3877
3888
|
}
|
|
3878
3889
|
return null;
|
|
3879
3890
|
}
|
|
@@ -3883,9 +3894,9 @@ function getReactNativeVersion() {
|
|
|
3883
3894
|
const rnPackageJson = JSON.parse(fs10.readFileSync(rnPackageJsonPath, "utf-8"));
|
|
3884
3895
|
return rnPackageJson.version;
|
|
3885
3896
|
}
|
|
3886
|
-
function directoryExistsSync(
|
|
3897
|
+
function directoryExistsSync(dirname4) {
|
|
3887
3898
|
try {
|
|
3888
|
-
return fs10.statSync(
|
|
3899
|
+
return fs10.statSync(dirname4).isDirectory();
|
|
3889
3900
|
} catch (err) {
|
|
3890
3901
|
if (err.code !== "ENOENT") throw err;
|
|
3891
3902
|
}
|
|
@@ -3893,14 +3904,14 @@ function directoryExistsSync(dirname3) {
|
|
|
3893
3904
|
}
|
|
3894
3905
|
function getReactNativePackagePath() {
|
|
3895
3906
|
const rnPackageJsonPath = findUpwardReactNativePackageJson();
|
|
3896
|
-
if (rnPackageJsonPath) return
|
|
3907
|
+
if (rnPackageJsonPath) return path7.dirname(rnPackageJsonPath);
|
|
3897
3908
|
const result = childProcess.spawnSync("node", [
|
|
3898
3909
|
"--print",
|
|
3899
3910
|
"require.resolve('react-native/package.json')"
|
|
3900
3911
|
]);
|
|
3901
|
-
const packagePath =
|
|
3912
|
+
const packagePath = path7.dirname(result.stdout.toString().trim());
|
|
3902
3913
|
if (result.status === 0 && directoryExistsSync(packagePath)) return packagePath;
|
|
3903
|
-
return
|
|
3914
|
+
return path7.join("node_modules", "react-native");
|
|
3904
3915
|
}
|
|
3905
3916
|
function resolvePackageDirFromCwd(packageName) {
|
|
3906
3917
|
const result = childProcess.spawnSync("node", [
|
|
@@ -3910,7 +3921,7 @@ function resolvePackageDirFromCwd(packageName) {
|
|
|
3910
3921
|
if (result.status !== 0) return null;
|
|
3911
3922
|
const resolved = result.stdout.toString().trim();
|
|
3912
3923
|
if (!resolved) return null;
|
|
3913
|
-
const packageDir =
|
|
3924
|
+
const packageDir = path7.dirname(resolved);
|
|
3914
3925
|
return directoryExistsSync(packageDir) ? packageDir : null;
|
|
3915
3926
|
}
|
|
3916
3927
|
function isValidPlatform(platform) {
|
|
@@ -3924,12 +3935,12 @@ function fileExists(filePath) {
|
|
|
3924
3935
|
}
|
|
3925
3936
|
}
|
|
3926
3937
|
function getCliPath() {
|
|
3927
|
-
return
|
|
3938
|
+
return path7.join(getReactNativePackagePath(), "cli.js");
|
|
3928
3939
|
}
|
|
3929
3940
|
async function runReactNativeBundleCommand(bundleName, entryFile, outputFolder, platform, sourcemap, devMode) {
|
|
3930
|
-
fs10.mkdirSync(
|
|
3941
|
+
fs10.mkdirSync(path7.join(outputFolder, "bundles"), { recursive: true });
|
|
3931
3942
|
if (sourcemap) {
|
|
3932
|
-
fs10.mkdirSync(
|
|
3943
|
+
fs10.mkdirSync(path7.join(outputFolder, "sourcemaps"), { recursive: true });
|
|
3933
3944
|
}
|
|
3934
3945
|
const reactNativeBundleArgs = [
|
|
3935
3946
|
getCliPath(),
|
|
@@ -3937,14 +3948,14 @@ async function runReactNativeBundleCommand(bundleName, entryFile, outputFolder,
|
|
|
3937
3948
|
"--dev",
|
|
3938
3949
|
devMode,
|
|
3939
3950
|
"--assets-dest",
|
|
3940
|
-
|
|
3951
|
+
path7.join(outputFolder, "bundles"),
|
|
3941
3952
|
"--bundle-output",
|
|
3942
|
-
|
|
3953
|
+
path7.join(outputFolder, "bundles", bundleName),
|
|
3943
3954
|
"--entry-file",
|
|
3944
3955
|
entryFile,
|
|
3945
3956
|
"--platform",
|
|
3946
3957
|
platform,
|
|
3947
|
-
...sourcemap ? ["--sourcemap-output",
|
|
3958
|
+
...sourcemap ? ["--sourcemap-output", path7.join(outputFolder, "sourcemaps", bundleName + ".map")] : []
|
|
3948
3959
|
];
|
|
3949
3960
|
logger.info('Running "react-native bundle" command');
|
|
3950
3961
|
const reactNativeBundleProcess = childProcess.spawn("node", reactNativeBundleArgs);
|
|
@@ -3970,17 +3981,27 @@ async function runHermesEmitBinaryCommand(bundleName, outputFolder, hermesLogs =
|
|
|
3970
3981
|
...sourcemap ? ["--output-source-map"] : [],
|
|
3971
3982
|
"--emit-binary",
|
|
3972
3983
|
"--out",
|
|
3973
|
-
|
|
3974
|
-
|
|
3984
|
+
path7.join(outputFolder, bundleName + ".hbc"),
|
|
3985
|
+
path7.join(outputFolder, "bundles", bundleName)
|
|
3975
3986
|
];
|
|
3976
3987
|
logger.info("Converting JS bundle to Hermes bytecode");
|
|
3977
3988
|
const hermesCommand = await getHermesCommand();
|
|
3978
|
-
|
|
3979
|
-
|
|
3989
|
+
const resolvedHermesPath = hermescPath || hermesCommand;
|
|
3990
|
+
if (hermescPath) {
|
|
3991
|
+
const binaryName = path7.basename(hermescPath).replace(/\.exe$/, "");
|
|
3992
|
+
if (!["hermesc", "hermes"].includes(binaryName)) {
|
|
3993
|
+
throw new Error(
|
|
3994
|
+
`Invalid hermesc path: binary must be named "hermesc" or "hermes", got "${path7.basename(hermescPath)}"`
|
|
3995
|
+
);
|
|
3996
|
+
}
|
|
3997
|
+
}
|
|
3998
|
+
logger.info(`Hermesc path: ${resolvedHermesPath}`);
|
|
3999
|
+
const hermesProcess = childProcess.spawn(resolvedHermesPath, hermesArgs);
|
|
3980
4000
|
let logFile = null;
|
|
4001
|
+
const logFilePath = path7.join(outputFolder, "hermes-output.log");
|
|
3981
4002
|
let isWarned = false;
|
|
3982
4003
|
if (hermesLogs) {
|
|
3983
|
-
logFile = fs10.createWriteStream(
|
|
4004
|
+
logFile = fs10.createWriteStream(logFilePath, { flags: "a" });
|
|
3984
4005
|
}
|
|
3985
4006
|
return new Promise((resolve, reject) => {
|
|
3986
4007
|
hermesProcess.stdout.on("data", (data) => {
|
|
@@ -3996,15 +4017,15 @@ async function runHermesEmitBinaryCommand(bundleName, outputFolder, hermesLogs =
|
|
|
3996
4017
|
});
|
|
3997
4018
|
hermesProcess.on("close", (exitCode, signal) => {
|
|
3998
4019
|
if (hermesLogs && logFile) {
|
|
3999
|
-
logger.success(
|
|
4020
|
+
logger.success(`Done writing logs to ${logFilePath}`);
|
|
4000
4021
|
logFile.end();
|
|
4001
4022
|
}
|
|
4002
4023
|
if (exitCode !== 0) {
|
|
4003
4024
|
reject(new Error(`"hermes" command failed (exitCode=${exitCode}, signal=${signal}).`));
|
|
4004
4025
|
return;
|
|
4005
4026
|
}
|
|
4006
|
-
const source =
|
|
4007
|
-
const destination =
|
|
4027
|
+
const source = path7.join(outputFolder, bundleName + ".hbc");
|
|
4028
|
+
const destination = path7.join(outputFolder, "bundles", bundleName);
|
|
4008
4029
|
fs10.copyFile(source, destination, (err) => {
|
|
4009
4030
|
if (err) {
|
|
4010
4031
|
reject(new Error(`Copying Hermes output failed: ${err.message}`));
|
|
@@ -4041,7 +4062,7 @@ function getHermesOSExe() {
|
|
|
4041
4062
|
return process.platform === "win32" ? hermesExecutableName + ".exe" : hermesExecutableName;
|
|
4042
4063
|
}
|
|
4043
4064
|
async function getHermesCommand() {
|
|
4044
|
-
const bundledHermesEngine =
|
|
4065
|
+
const bundledHermesEngine = path7.join(
|
|
4045
4066
|
getReactNativePackagePath(),
|
|
4046
4067
|
"sdks",
|
|
4047
4068
|
"hermesc",
|
|
@@ -4051,23 +4072,23 @@ async function getHermesCommand() {
|
|
|
4051
4072
|
if (fileExists(bundledHermesEngine)) return bundledHermesEngine;
|
|
4052
4073
|
const hermesEnginePackageDir = resolvePackageDirFromCwd("hermes-engine");
|
|
4053
4074
|
if (hermesEnginePackageDir) {
|
|
4054
|
-
const hermesEngine2 =
|
|
4075
|
+
const hermesEngine2 = path7.join(hermesEnginePackageDir, getHermesOSBin(), getHermesOSExe());
|
|
4055
4076
|
if (fileExists(hermesEngine2)) return hermesEngine2;
|
|
4056
4077
|
}
|
|
4057
|
-
const hermesEngine =
|
|
4078
|
+
const hermesEngine = path7.join("node_modules", "hermes-engine", getHermesOSBin(), getHermesOSExe());
|
|
4058
4079
|
if (fileExists(hermesEngine)) return hermesEngine;
|
|
4059
4080
|
const hermesCompilerPackageDir = resolvePackageDirFromCwd("hermes-compiler");
|
|
4060
4081
|
if (hermesCompilerPackageDir) {
|
|
4061
|
-
const hermesCompiler2 =
|
|
4082
|
+
const hermesCompiler2 = path7.join(hermesCompilerPackageDir, "hermesc", getHermesOSBin(), getHermesOSExe());
|
|
4062
4083
|
if (fileExists(hermesCompiler2)) return hermesCompiler2;
|
|
4063
4084
|
}
|
|
4064
|
-
const hermesCompiler =
|
|
4085
|
+
const hermesCompiler = path7.join("node_modules", "hermes-compiler", "hermesc", getHermesOSBin(), getHermesOSExe());
|
|
4065
4086
|
if (fileExists(hermesCompiler)) return hermesCompiler;
|
|
4066
4087
|
const hermesVmPackageDir = resolvePackageDirFromCwd("hermesvm");
|
|
4067
4088
|
if (hermesVmPackageDir) {
|
|
4068
|
-
return
|
|
4089
|
+
return path7.join(hermesVmPackageDir, getHermesOSBin(), "hermes");
|
|
4069
4090
|
}
|
|
4070
|
-
return
|
|
4091
|
+
return path7.join("node_modules", "hermesvm", getHermesOSBin(), "hermes");
|
|
4071
4092
|
}
|
|
4072
4093
|
|
|
4073
4094
|
// src/commands/publish-bundle.ts
|
|
@@ -4116,8 +4137,7 @@ var publishBundleCommand = new Command39("publish-bundle").description("Bundle,
|
|
|
4116
4137
|
const uploadPath = appSlug || resolvedAppId || "";
|
|
4117
4138
|
const entryFile = options.entryFile || "index.js";
|
|
4118
4139
|
const bundleName = platform === "ios" ? "main.jsbundle" : "index.android.bundle";
|
|
4119
|
-
const contentRootPath =
|
|
4120
|
-
await fs11.ensureDir(contentRootPath);
|
|
4140
|
+
const contentRootPath = await fs11.mkdtemp(path8.join(os3.tmpdir(), "swiftpatch-publish-"));
|
|
4121
4141
|
try {
|
|
4122
4142
|
const spinner = ora31("Bundling JavaScript...").start();
|
|
4123
4143
|
try {
|
|
@@ -4159,7 +4179,7 @@ var publishBundleCommand = new Command39("publish-bundle").description("Bundle,
|
|
|
4159
4179
|
if (options.privateKey) {
|
|
4160
4180
|
const signSpinner = ora31("Signing bundle...").start();
|
|
4161
4181
|
try {
|
|
4162
|
-
const bundlesDir2 =
|
|
4182
|
+
const bundlesDir2 = path8.join(contentRootPath, "bundles");
|
|
4163
4183
|
await signBundleDirectory(bundlesDir2, options.privateKey);
|
|
4164
4184
|
signSpinner.succeed("Bundle signed with JWT RS256");
|
|
4165
4185
|
} catch (error) {
|
|
@@ -4168,9 +4188,9 @@ var publishBundleCommand = new Command39("publish-bundle").description("Bundle,
|
|
|
4168
4188
|
}
|
|
4169
4189
|
}
|
|
4170
4190
|
const zipSpinner = ora31("Creating ZIP archive...").start();
|
|
4171
|
-
const bundlesDir =
|
|
4191
|
+
const bundlesDir = path8.join(contentRootPath, "bundles");
|
|
4172
4192
|
await createZip(bundlesDir, contentRootPath);
|
|
4173
|
-
const zipPath =
|
|
4193
|
+
const zipPath = path8.join(contentRootPath, "build.zip");
|
|
4174
4194
|
if (!await fs11.pathExists(zipPath)) {
|
|
4175
4195
|
zipSpinner.fail("ZIP creation failed: build.zip not found");
|
|
4176
4196
|
process.exit(1);
|
|
@@ -4186,7 +4206,7 @@ var publishBundleCommand = new Command39("publish-bundle").description("Bundle,
|
|
|
4186
4206
|
hashSpinner.succeed(`ZIP hash: ${chalk37.gray(hash.slice(0, 16))}...`);
|
|
4187
4207
|
let bundleSignature;
|
|
4188
4208
|
if (options.privateKey) {
|
|
4189
|
-
const bundlesDir2 =
|
|
4209
|
+
const bundlesDir2 = path8.join(contentRootPath, "bundles");
|
|
4190
4210
|
const sig = await readBundleSignature(bundlesDir2);
|
|
4191
4211
|
if (sig) bundleSignature = sig;
|
|
4192
4212
|
}
|
|
@@ -4234,6 +4254,7 @@ var publishBundleCommand = new Command39("publish-bundle").description("Bundle,
|
|
|
4234
4254
|
}
|
|
4235
4255
|
} finally {
|
|
4236
4256
|
await fs11.remove(contentRootPath).catch(() => {
|
|
4257
|
+
logger.warning(`Failed to clean up temp directory: ${contentRootPath}`);
|
|
4237
4258
|
});
|
|
4238
4259
|
}
|
|
4239
4260
|
});
|
|
@@ -4359,12 +4380,12 @@ init_esm_shims();
|
|
|
4359
4380
|
import { Command as Command42 } from "commander";
|
|
4360
4381
|
import chalk40 from "chalk";
|
|
4361
4382
|
import ora34 from "ora";
|
|
4362
|
-
import
|
|
4383
|
+
import path9 from "path";
|
|
4363
4384
|
var generateKeyPairCommand = new Command42("generate-key-pair").description("Generate RSA 2048-bit key pair for bundle signing").option("-o, --output <dir>", "Output directory for key files", ".").action(async (options) => {
|
|
4364
4385
|
console.log("");
|
|
4365
4386
|
logger.info(chalk40.bold("SwiftPatch Generate Key Pair"));
|
|
4366
4387
|
console.log("");
|
|
4367
|
-
const outputDir =
|
|
4388
|
+
const outputDir = path9.resolve(options.output || ".");
|
|
4368
4389
|
const spinner = ora34("Generating RSA 2048-bit key pair...").start();
|
|
4369
4390
|
try {
|
|
4370
4391
|
const { publicKeyPath, privateKeyPath } = await generateKeyPair(outputDir);
|
|
@@ -4398,7 +4419,8 @@ import chalk41 from "chalk";
|
|
|
4398
4419
|
import inquirer21 from "inquirer";
|
|
4399
4420
|
import ora35 from "ora";
|
|
4400
4421
|
import fs12 from "fs-extra";
|
|
4401
|
-
import
|
|
4422
|
+
import path10 from "path";
|
|
4423
|
+
import os4 from "os";
|
|
4402
4424
|
var deployCommand = new Command43("deploy").description("Bundle, publish, and release in one step").option("-p, --platform <platform>", "Target platform (ios or android)").option("-a, --app <app-id>", "App ID or slug").option("-o, --org <org-id>", "Organization ID").option("--app-version <version>", "Target app version (semver)").option("-n, --release-note <note>", "Release notes").option("-m, --mandatory", "Mark as mandatory update").option("--paused", "Create release in paused state").option("--hermes", "Compile to Hermes bytecode").option("--ci-token <token>", "CI token for authentication").option("-e, --entry-file <path>", "Entry file (default: index.js)").option("--dev", "Dev bundle").option("--sourcemap", "Generate sourcemaps").option("-k, --private-key <path>", "Private key path for signing").option("-y, --yes", "Skip confirmations").action(async (options) => {
|
|
4403
4425
|
const ciToken = options.ciToken || process.env.SWIFTPATCH_CI_TOKEN;
|
|
4404
4426
|
if (!ciToken) {
|
|
@@ -4469,94 +4491,99 @@ var deployCommand = new Command43("deploy").description("Bundle, publish, and re
|
|
|
4469
4491
|
console.log(chalk41.bold(" Deploy"));
|
|
4470
4492
|
console.log(chalk41.gray(` Platform: ${platform} \xB7 Version: ${appVersion}`));
|
|
4471
4493
|
console.log("");
|
|
4472
|
-
const
|
|
4494
|
+
const tmpRoot = await fs12.mkdtemp(path10.join(os4.tmpdir(), "swiftpatch-deploy-"));
|
|
4473
4495
|
try {
|
|
4474
|
-
const
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
bundleName
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4496
|
+
const bundleSpinner = ora35("Bundling JavaScript...").start();
|
|
4497
|
+
try {
|
|
4498
|
+
const entryFile = options.entryFile || "index.js";
|
|
4499
|
+
const outputDir = path10.join(tmpRoot, platform);
|
|
4500
|
+
await fs12.ensureDir(outputDir);
|
|
4501
|
+
const bundleName = platform === "ios" ? "main.jsbundle" : "index.android.bundle";
|
|
4502
|
+
await runReactNativeBundleCommand(
|
|
4503
|
+
bundleName,
|
|
4504
|
+
entryFile,
|
|
4505
|
+
outputDir,
|
|
4506
|
+
platform,
|
|
4507
|
+
options.sourcemap || false,
|
|
4508
|
+
options.dev || false
|
|
4509
|
+
);
|
|
4510
|
+
if (options.hermes) {
|
|
4511
|
+
bundleSpinner.text = "Compiling to Hermes bytecode...";
|
|
4512
|
+
}
|
|
4513
|
+
bundleSpinner.succeed("Bundle created");
|
|
4514
|
+
} catch (error) {
|
|
4515
|
+
bundleSpinner.fail(`Bundle failed: ${error.message}`);
|
|
4516
|
+
process.exit(1);
|
|
4488
4517
|
}
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
process.exit(1);
|
|
4493
|
-
}
|
|
4494
|
-
const archiveSpinner = ora35("Creating archive...").start();
|
|
4495
|
-
let zipPath;
|
|
4496
|
-
let bundleHash;
|
|
4497
|
-
try {
|
|
4498
|
-
const outputDir = path11.join(".swiftpatch-tmp", platform);
|
|
4499
|
-
const zipOutputDir = path11.join(".swiftpatch-tmp", "zip");
|
|
4500
|
-
await fs12.ensureDir(zipOutputDir);
|
|
4501
|
-
await createZip(outputDir, zipOutputDir);
|
|
4502
|
-
zipPath = path11.join(zipOutputDir, "build.zip");
|
|
4503
|
-
bundleHash = calculateZipHash(zipPath);
|
|
4504
|
-
if (!bundleHash) throw new Error("Failed to compute bundle hash");
|
|
4505
|
-
archiveSpinner.succeed(`Archive created (hash: ${bundleHash.slice(0, 12)}...)`);
|
|
4506
|
-
} catch (error) {
|
|
4507
|
-
archiveSpinner.fail(`Archive failed: ${error.message}`);
|
|
4508
|
-
process.exit(1);
|
|
4509
|
-
}
|
|
4510
|
-
const uploadSpinner = ora35("Uploading bundle...").start();
|
|
4511
|
-
try {
|
|
4512
|
-
const { url } = await api.generateSignedUrl(
|
|
4513
|
-
{ hash: bundleHash, uploadPath, platform, releaseNote },
|
|
4514
|
-
ciToken
|
|
4515
|
-
);
|
|
4516
|
-
await uploader.uploadZip(url, zipPath, (progress) => {
|
|
4517
|
-
uploadSpinner.text = `Uploading bundle... ${progress}%`;
|
|
4518
|
-
});
|
|
4519
|
-
uploadSpinner.succeed("Bundle uploaded");
|
|
4520
|
-
} catch (error) {
|
|
4521
|
-
uploadSpinner.fail(`Upload failed: ${error.message}`);
|
|
4522
|
-
process.exit(1);
|
|
4523
|
-
}
|
|
4524
|
-
if (!ciToken) {
|
|
4525
|
-
console.log("");
|
|
4526
|
-
logger.warning("Deploy requires a CI token to create the release.");
|
|
4527
|
-
console.log(chalk41.gray(" Bundle was uploaded. Promote it manually:"));
|
|
4528
|
-
console.log(chalk41.cyan(` $ swiftpatch release-bundle --hash ${bundleHash} --app-version ${appVersion} --ci-token <token>`));
|
|
4529
|
-
console.log("");
|
|
4530
|
-
} else {
|
|
4531
|
-
const releaseSpinner = ora35("Creating release...").start();
|
|
4518
|
+
const archiveSpinner = ora35("Creating archive...").start();
|
|
4519
|
+
let zipPath;
|
|
4520
|
+
let bundleHash;
|
|
4532
4521
|
try {
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4522
|
+
const outputDir = path10.join(tmpRoot, platform);
|
|
4523
|
+
const zipOutputDir = path10.join(tmpRoot, "zip");
|
|
4524
|
+
await fs12.ensureDir(zipOutputDir);
|
|
4525
|
+
await createZip(outputDir, zipOutputDir);
|
|
4526
|
+
zipPath = path10.join(zipOutputDir, "build.zip");
|
|
4527
|
+
bundleHash = calculateZipHash(zipPath);
|
|
4528
|
+
if (!bundleHash) throw new Error("Failed to compute bundle hash");
|
|
4529
|
+
archiveSpinner.succeed(`Archive created (hash: ${bundleHash.slice(0, 12)}...)`);
|
|
4530
|
+
} catch (error) {
|
|
4531
|
+
archiveSpinner.fail(`Archive failed: ${error.message}`);
|
|
4532
|
+
process.exit(1);
|
|
4533
|
+
}
|
|
4534
|
+
const uploadSpinner = ora35("Uploading bundle...").start();
|
|
4535
|
+
try {
|
|
4536
|
+
const { url } = await api.generateSignedUrl(
|
|
4537
|
+
{ hash: bundleHash, uploadPath, platform, releaseNote },
|
|
4542
4538
|
ciToken
|
|
4543
4539
|
);
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
console.log(` Version: ${chalk41.cyan(appVersion)}`);
|
|
4549
|
-
console.log(` Platform: ${platform}`);
|
|
4550
|
-
console.log(` Mandatory: ${options.mandatory ? chalk41.yellow("Yes") : "No"}`);
|
|
4551
|
-
console.log(` Status: ${options.paused ? chalk41.yellow("Paused") : chalk41.green("Released")}`);
|
|
4552
|
-
console.log("");
|
|
4540
|
+
await uploader.uploadZip(url, zipPath, (progress) => {
|
|
4541
|
+
uploadSpinner.text = `Uploading bundle... ${progress}%`;
|
|
4542
|
+
});
|
|
4543
|
+
uploadSpinner.succeed("Bundle uploaded");
|
|
4553
4544
|
} catch (error) {
|
|
4554
|
-
|
|
4545
|
+
uploadSpinner.fail(`Upload failed: ${error.message}`);
|
|
4555
4546
|
process.exit(1);
|
|
4556
4547
|
}
|
|
4548
|
+
if (!ciToken) {
|
|
4549
|
+
console.log("");
|
|
4550
|
+
logger.warning("Deploy requires a CI token to create the release.");
|
|
4551
|
+
console.log(chalk41.gray(" Bundle was uploaded. Promote it manually:"));
|
|
4552
|
+
console.log(chalk41.cyan(` $ swiftpatch release-bundle --hash ${bundleHash} --app-version ${appVersion} --ci-token <token>`));
|
|
4553
|
+
console.log("");
|
|
4554
|
+
} else {
|
|
4555
|
+
const releaseSpinner = ora35("Creating release...").start();
|
|
4556
|
+
try {
|
|
4557
|
+
await api.promoteBundle(
|
|
4558
|
+
{
|
|
4559
|
+
projectId: uploadPath,
|
|
4560
|
+
hash: bundleHash,
|
|
4561
|
+
appVersion,
|
|
4562
|
+
releaseNote,
|
|
4563
|
+
isMandatory: options.mandatory || false,
|
|
4564
|
+
isPaused: options.paused || false
|
|
4565
|
+
},
|
|
4566
|
+
ciToken
|
|
4567
|
+
);
|
|
4568
|
+
releaseSpinner.succeed("Release created!");
|
|
4569
|
+
console.log("");
|
|
4570
|
+
console.log(chalk41.bold(" Deploy Complete"));
|
|
4571
|
+
console.log(` Hash: ${chalk41.gray(bundleHash)}`);
|
|
4572
|
+
console.log(` Version: ${chalk41.cyan(appVersion)}`);
|
|
4573
|
+
console.log(` Platform: ${platform}`);
|
|
4574
|
+
console.log(` Mandatory: ${options.mandatory ? chalk41.yellow("Yes") : "No"}`);
|
|
4575
|
+
console.log(` Status: ${options.paused ? chalk41.yellow("Paused") : chalk41.green("Released")}`);
|
|
4576
|
+
console.log("");
|
|
4577
|
+
} catch (error) {
|
|
4578
|
+
releaseSpinner.fail(`Release failed: ${error.message}`);
|
|
4579
|
+
process.exit(1);
|
|
4580
|
+
}
|
|
4581
|
+
}
|
|
4582
|
+
} finally {
|
|
4583
|
+
await fs12.remove(tmpRoot).catch((err) => {
|
|
4584
|
+
logger.warning(`Failed to clean up temp directory: ${tmpRoot}`);
|
|
4585
|
+
});
|
|
4557
4586
|
}
|
|
4558
|
-
await fs12.remove(".swiftpatch-tmp").catch(() => {
|
|
4559
|
-
});
|
|
4560
4587
|
});
|
|
4561
4588
|
|
|
4562
4589
|
// src/commands/status.ts
|
|
@@ -4654,7 +4681,7 @@ import chalk43 from "chalk";
|
|
|
4654
4681
|
import inquirer23 from "inquirer";
|
|
4655
4682
|
import ora37 from "ora";
|
|
4656
4683
|
import fs13 from "fs-extra";
|
|
4657
|
-
import
|
|
4684
|
+
import path11 from "path";
|
|
4658
4685
|
var initCommand = new Command45("init").description("Initialize SwiftPatch in your React Native project").option("-y, --yes", "Accept defaults").action(async (options) => {
|
|
4659
4686
|
console.log("");
|
|
4660
4687
|
console.log(chalk43.bold(" SwiftPatch Setup"));
|
|
@@ -4745,13 +4772,30 @@ var initCommand = new Command45("init").description("Initialize SwiftPatch in yo
|
|
|
4745
4772
|
platform: defaultPlatform || (selectedApp.platform === "BOTH" ? void 0 : selectedApp.platform.toLowerCase()),
|
|
4746
4773
|
deploymentKey: selectedApp.deploymentKey
|
|
4747
4774
|
};
|
|
4748
|
-
const rcPath =
|
|
4775
|
+
const rcPath = path11.resolve(".swiftpatchrc");
|
|
4749
4776
|
await fs13.writeJson(rcPath, rcConfig, { spaces: 2 });
|
|
4750
4777
|
logger.success("Created .swiftpatchrc");
|
|
4751
4778
|
config.set("defaultOrg", orgId);
|
|
4752
4779
|
config.set("defaultApp", selectedApp.id);
|
|
4753
4780
|
if (defaultPlatform) config.set("defaultPlatform", defaultPlatform);
|
|
4754
4781
|
logger.success("Saved defaults to CLI config");
|
|
4782
|
+
const gitignorePath = path11.resolve(".gitignore");
|
|
4783
|
+
const swiftpatchIgnores = [
|
|
4784
|
+
"# SwiftPatch",
|
|
4785
|
+
".swiftpatch-tmp/",
|
|
4786
|
+
"swiftpatch-artifacts/",
|
|
4787
|
+
"swiftpatch-private.pem"
|
|
4788
|
+
];
|
|
4789
|
+
try {
|
|
4790
|
+
let gitignore = await fs13.pathExists(gitignorePath) ? await fs13.readFile(gitignorePath, "utf-8") : "";
|
|
4791
|
+
const missing = swiftpatchIgnores.filter((line) => !gitignore.includes(line));
|
|
4792
|
+
if (missing.length > 0) {
|
|
4793
|
+
const addition = (gitignore.endsWith("\n") || gitignore === "" ? "" : "\n") + missing.join("\n") + "\n";
|
|
4794
|
+
await fs13.appendFile(gitignorePath, addition);
|
|
4795
|
+
logger.success("Updated .gitignore with SwiftPatch entries");
|
|
4796
|
+
}
|
|
4797
|
+
} catch {
|
|
4798
|
+
}
|
|
4755
4799
|
console.log("");
|
|
4756
4800
|
console.log(chalk43.bold(" Setup Complete"));
|
|
4757
4801
|
console.log("");
|
|
@@ -4772,7 +4816,7 @@ async function createApp(orgId, pkg, platforms) {
|
|
|
4772
4816
|
type: "input",
|
|
4773
4817
|
name: "name",
|
|
4774
4818
|
message: "App name:",
|
|
4775
|
-
default: pkg.name ||
|
|
4819
|
+
default: pkg.name || path11.basename(process.cwd())
|
|
4776
4820
|
}
|
|
4777
4821
|
]);
|
|
4778
4822
|
let platform;
|
|
@@ -4926,10 +4970,10 @@ var doctorCommand = new Command46("doctor").description("Diagnose your SwiftPatc
|
|
|
4926
4970
|
});
|
|
4927
4971
|
|
|
4928
4972
|
// src/cli.ts
|
|
4929
|
-
var
|
|
4973
|
+
var __dirname3 = dirname3(fileURLToPath3(import.meta.url));
|
|
4930
4974
|
var version = "1.0.0";
|
|
4931
4975
|
try {
|
|
4932
|
-
const pkg = JSON.parse(
|
|
4976
|
+
const pkg = JSON.parse(readFileSync4(join3(__dirname3, "../package.json"), "utf-8"));
|
|
4933
4977
|
version = pkg.version;
|
|
4934
4978
|
} catch {
|
|
4935
4979
|
}
|
|
@@ -5003,12 +5047,12 @@ function checkForUpdates() {
|
|
|
5003
5047
|
try {
|
|
5004
5048
|
import("update-notifier").then(({ default: updateNotifier }) => {
|
|
5005
5049
|
import("fs-extra").then(({ default: fs15 }) => {
|
|
5006
|
-
import("url").then(({ fileURLToPath:
|
|
5007
|
-
import("path").then(({ dirname:
|
|
5050
|
+
import("url").then(({ fileURLToPath: fileURLToPath4 }) => {
|
|
5051
|
+
import("path").then(({ dirname: dirname4, join: join4 }) => {
|
|
5008
5052
|
try {
|
|
5009
|
-
const
|
|
5053
|
+
const __dirname4 = dirname4(fileURLToPath4(import.meta.url));
|
|
5010
5054
|
const pkg = JSON.parse(
|
|
5011
|
-
fs15.readFileSync(
|
|
5055
|
+
fs15.readFileSync(join4(__dirname4, "../../package.json"), "utf-8")
|
|
5012
5056
|
);
|
|
5013
5057
|
const notifier = updateNotifier({ pkg, updateCheckInterval: 1e3 * 60 * 60 * 24 });
|
|
5014
5058
|
notifier.notify();
|