@hapico/cli 0.0.19 → 0.0.21
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/index.js +213 -56
- package/dist/index.js +213 -56
- package/index.ts +288 -68
- package/package.json +1 -1
- package/test.tsx +0 -0
package/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
-
import { isEqual, find } from "lodash";
|
|
3
|
+
import { isEqual, find, map } from "lodash";
|
|
4
4
|
import { program } from "commander";
|
|
5
5
|
import axios from "axios";
|
|
6
6
|
import * as fs from "fs";
|
|
@@ -15,7 +15,7 @@ import { randomUUID } from "crypto";
|
|
|
15
15
|
import { exec } from "child_process";
|
|
16
16
|
import { promisify } from "util";
|
|
17
17
|
import chalk from "chalk";
|
|
18
|
-
import pako from
|
|
18
|
+
import pako from "pako";
|
|
19
19
|
|
|
20
20
|
// Promisify exec for async usage
|
|
21
21
|
const execPromise = promisify(exec);
|
|
@@ -74,14 +74,25 @@ const saveProjectId = (projectDir: string, id: string) => {
|
|
|
74
74
|
};
|
|
75
75
|
|
|
76
76
|
// Function to get stored project ID
|
|
77
|
-
const getStoredProjectId = (
|
|
77
|
+
const getStoredProjectId = (
|
|
78
|
+
projectDir: string
|
|
79
|
+
): {
|
|
80
|
+
projectId: string | null;
|
|
81
|
+
replicate?: string[];
|
|
82
|
+
} => {
|
|
78
83
|
const configFile = path.join(projectDir, "hapico.config.json");
|
|
79
84
|
if (fs.existsSync(configFile)) {
|
|
80
85
|
const data = fs.readFileSync(configFile, { encoding: "utf8" });
|
|
81
86
|
const json = JSON.parse(data);
|
|
82
|
-
return
|
|
87
|
+
return {
|
|
88
|
+
projectId: json.projectId || null,
|
|
89
|
+
replicate: json.replicate || [],
|
|
90
|
+
};
|
|
83
91
|
}
|
|
84
|
-
return
|
|
92
|
+
return {
|
|
93
|
+
projectId: null,
|
|
94
|
+
replicate: [],
|
|
95
|
+
};
|
|
85
96
|
};
|
|
86
97
|
|
|
87
98
|
// Khởi tạo cache bằng Map để lưu trữ kết quả compile
|
|
@@ -95,7 +106,7 @@ interface FileContent {
|
|
|
95
106
|
|
|
96
107
|
interface ApiResponse {
|
|
97
108
|
data: {
|
|
98
|
-
|
|
109
|
+
code: string;
|
|
99
110
|
type: "view" | "zalominiapp" | string;
|
|
100
111
|
dbCode: string;
|
|
101
112
|
db_code: string;
|
|
@@ -111,6 +122,14 @@ interface WebSocketMessage {
|
|
|
111
122
|
state?: RoomStateData;
|
|
112
123
|
}
|
|
113
124
|
|
|
125
|
+
export const tryJSONParse = (str: string): any => {
|
|
126
|
+
try {
|
|
127
|
+
return JSON.parse(str);
|
|
128
|
+
} catch {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
114
133
|
export const compileES5 = (code: string, filePath?: string) => {
|
|
115
134
|
if (filePath && !filePath.endsWith(".ts") && !filePath.endsWith(".tsx")) {
|
|
116
135
|
return code;
|
|
@@ -131,7 +150,8 @@ export const compileES5 = (code: string, filePath?: string) => {
|
|
|
131
150
|
|
|
132
151
|
compileCache.set(code, result.code || "");
|
|
133
152
|
return result.code;
|
|
134
|
-
} catch (error) {
|
|
153
|
+
} catch (error: any) {
|
|
154
|
+
console.log(chalk.red(`Error compiling code: ${error?.message}`));
|
|
135
155
|
return "";
|
|
136
156
|
}
|
|
137
157
|
};
|
|
@@ -303,12 +323,10 @@ class RoomState {
|
|
|
303
323
|
clearTimeout(this.reconnectTimeout);
|
|
304
324
|
}
|
|
305
325
|
|
|
306
|
-
this.ws = new WebSocket(
|
|
307
|
-
`wss://ws3.myworkbeast.com/ws?room=${this.roomId}`
|
|
308
|
-
);
|
|
326
|
+
this.ws = new WebSocket(`wss://ws3.myworkbeast.com/ws?room=${this.roomId}`);
|
|
309
327
|
|
|
310
328
|
// Set binaryType to 'arraybuffer' to handle binary data
|
|
311
|
-
this.ws.binaryType =
|
|
329
|
+
this.ws.binaryType = "arraybuffer";
|
|
312
330
|
|
|
313
331
|
this.ws.on("open", () => {
|
|
314
332
|
console.log(chalk.green(`Connected to room: ${this.roomId}`));
|
|
@@ -337,11 +355,11 @@ class RoomState {
|
|
|
337
355
|
try {
|
|
338
356
|
let jsonStr: string;
|
|
339
357
|
if (data instanceof ArrayBuffer) {
|
|
340
|
-
jsonStr = pako.inflate(data, { to:
|
|
358
|
+
jsonStr = pako.inflate(data, { to: "string" });
|
|
341
359
|
} else if (typeof data === "string") {
|
|
342
360
|
jsonStr = data;
|
|
343
361
|
} else if (Buffer.isBuffer(data)) {
|
|
344
|
-
jsonStr = pako.inflate(data, { to:
|
|
362
|
+
jsonStr = pako.inflate(data, { to: "string" });
|
|
345
363
|
} else {
|
|
346
364
|
jsonStr = data.toString(); // Fallback nếu không nén
|
|
347
365
|
}
|
|
@@ -429,7 +447,7 @@ class RoomState {
|
|
|
429
447
|
}
|
|
430
448
|
}
|
|
431
449
|
|
|
432
|
-
program.version("0.0.
|
|
450
|
+
program.version("0.0.21").description("Hapico CLI for project management");
|
|
433
451
|
|
|
434
452
|
program
|
|
435
453
|
.command("clone <id>")
|
|
@@ -455,7 +473,12 @@ program
|
|
|
455
473
|
const response: ApiResponse = await axios.get(
|
|
456
474
|
`https://base.myworkbeast.com/api/views/${id}`
|
|
457
475
|
);
|
|
458
|
-
|
|
476
|
+
const code = response?.data?.code;
|
|
477
|
+
const decompressedCode = pako.inflate(
|
|
478
|
+
Uint8Array.from(atob(code), (c) => c.charCodeAt(0)),
|
|
479
|
+
{ to: "string" }
|
|
480
|
+
);
|
|
481
|
+
files = tryJSONParse(decompressedCode)?.files || [];
|
|
459
482
|
apiSpinner.succeed(chalk.green("Project data fetched successfully!"));
|
|
460
483
|
|
|
461
484
|
const templateSpinner: Ora = ora(
|
|
@@ -518,7 +541,8 @@ program
|
|
|
518
541
|
program
|
|
519
542
|
.command("dev")
|
|
520
543
|
.description("Start the project in development mode")
|
|
521
|
-
.
|
|
544
|
+
.option('--zversion <version>', 'Zalo version for QR code', '75')
|
|
545
|
+
.action((options) => {
|
|
522
546
|
const { accessToken } = getStoredToken();
|
|
523
547
|
if (!accessToken) {
|
|
524
548
|
console.error(
|
|
@@ -578,7 +602,7 @@ program
|
|
|
578
602
|
const info = JSON.stringify({
|
|
579
603
|
id: sessionId,
|
|
580
604
|
createdAt: new Date().toISOString(),
|
|
581
|
-
viewId: getStoredProjectId(pwd),
|
|
605
|
+
viewId: getStoredProjectId(pwd)?.projectId,
|
|
582
606
|
});
|
|
583
607
|
|
|
584
608
|
// Convert info to base64
|
|
@@ -596,12 +620,47 @@ program
|
|
|
596
620
|
const room = new RoomState(`view_${projectId}`, []);
|
|
597
621
|
const fileManager = new FileManager(srcDir);
|
|
598
622
|
const initialFiles = fileManager.listFiles();
|
|
599
|
-
|
|
623
|
+
// get tsconfig.json
|
|
624
|
+
const tsconfigPath = path.join(srcDir, "..", "tsconfig.json");
|
|
625
|
+
if (fs.existsSync(tsconfigPath)) {
|
|
626
|
+
const content = fs.readFileSync(tsconfigPath, { encoding: "utf8" });
|
|
627
|
+
initialFiles.push({
|
|
628
|
+
path: "./tsconfig.json",
|
|
629
|
+
content,
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
// Remove All binary files
|
|
633
|
+
const supportExtensions = [
|
|
634
|
+
".ts",
|
|
635
|
+
".tsx",
|
|
636
|
+
".js",
|
|
637
|
+
".jsx",
|
|
638
|
+
".json",
|
|
639
|
+
".css",
|
|
640
|
+
".html",
|
|
641
|
+
".env",
|
|
642
|
+
".env.local",
|
|
643
|
+
".env.development",
|
|
644
|
+
".env.production",
|
|
645
|
+
".jsonc",
|
|
646
|
+
".yml",
|
|
647
|
+
".yaml",
|
|
648
|
+
".md",
|
|
649
|
+
".markdown",
|
|
650
|
+
".txt",
|
|
651
|
+
".xml",
|
|
652
|
+
".config",
|
|
653
|
+
];
|
|
654
|
+
const filteredFiles = initialFiles.filter((file) => {
|
|
655
|
+
return supportExtensions.some((ext) => file.path.endsWith(ext));
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
room.files = filteredFiles;
|
|
600
659
|
|
|
601
660
|
room.connect(async () => {
|
|
602
661
|
devSpinner.succeed(chalk.green("Project started in development mode!"));
|
|
603
662
|
|
|
604
|
-
room.updateState("view",
|
|
663
|
+
room.updateState("view", filteredFiles);
|
|
605
664
|
|
|
606
665
|
fileManager.setOnFileChange((filePath, content) => {
|
|
607
666
|
const es5 = compileES5(content, filePath) ?? "";
|
|
@@ -619,8 +678,8 @@ program
|
|
|
619
678
|
});
|
|
620
679
|
|
|
621
680
|
// Fetch project info
|
|
622
|
-
const
|
|
623
|
-
if (!
|
|
681
|
+
const store = getStoredProjectId(pwd);
|
|
682
|
+
if (!store.projectId) {
|
|
624
683
|
console.error(
|
|
625
684
|
chalk.red(
|
|
626
685
|
"✗ Project ID not found. Please ensure hapico.config.json exists in the project directory."
|
|
@@ -629,7 +688,7 @@ program
|
|
|
629
688
|
return;
|
|
630
689
|
}
|
|
631
690
|
const project = await axios.get(
|
|
632
|
-
`https://base.myworkbeast.com/api/views/${
|
|
691
|
+
`https://base.myworkbeast.com/api/views/${store.projectId}`,
|
|
633
692
|
{
|
|
634
693
|
headers: {
|
|
635
694
|
Authorization: `Bearer ${accessToken}`,
|
|
@@ -646,10 +705,11 @@ program
|
|
|
646
705
|
}
|
|
647
706
|
|
|
648
707
|
const projectType = project.data.type || "view";
|
|
708
|
+
const zversion = options.zversion || '75';
|
|
649
709
|
|
|
650
710
|
if (projectType === "zalominiapp") {
|
|
651
711
|
QRCode.generate(
|
|
652
|
-
`https://zalo.me/s/3218692650896662017/player/${projectId}?env=TESTING&version
|
|
712
|
+
`https://zalo.me/s/3218692650896662017/player/${projectId}?env=TESTING&version=${zversion}`,
|
|
653
713
|
{ small: true },
|
|
654
714
|
(qrcode) => {
|
|
655
715
|
console.log(
|
|
@@ -672,23 +732,16 @@ program
|
|
|
672
732
|
});
|
|
673
733
|
|
|
674
734
|
// Hàm tái sử dụng để push mã nguồn lên server
|
|
675
|
-
async function pushProject(spinner: Ora): Promise<boolean> {
|
|
735
|
+
async function pushProject(spinner: Ora, projectId: string): Promise<boolean> {
|
|
676
736
|
const data = getStoredToken();
|
|
677
737
|
const { accessToken } = data || {};
|
|
678
738
|
if (!accessToken) {
|
|
679
|
-
spinner.fail(chalk.red("✗ You need to login first. Use 'hapico login' command."));
|
|
680
|
-
return false;
|
|
681
|
-
}
|
|
682
|
-
const pwd = process.cwd();
|
|
683
|
-
const projectId = getStoredProjectId(pwd);
|
|
684
|
-
if (!projectId) {
|
|
685
739
|
spinner.fail(
|
|
686
|
-
chalk.red(
|
|
687
|
-
"✗ Project ID not found. Please ensure hapico.config.json exists in the project directory."
|
|
688
|
-
)
|
|
740
|
+
chalk.red("✗ You need to login first. Use 'hapico login' command.")
|
|
689
741
|
);
|
|
690
742
|
return false;
|
|
691
743
|
}
|
|
744
|
+
const pwd = process.cwd();
|
|
692
745
|
const srcDir: string = path.join(pwd, "src");
|
|
693
746
|
if (!fs.existsSync(srcDir)) {
|
|
694
747
|
spinner.fail(
|
|
@@ -701,17 +754,35 @@ async function pushProject(spinner: Ora): Promise<boolean> {
|
|
|
701
754
|
const fileManager = new FileManager(srcDir);
|
|
702
755
|
const files = fileManager.listFiles();
|
|
703
756
|
|
|
704
|
-
//
|
|
705
|
-
const
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
757
|
+
// Supported files
|
|
758
|
+
const SUPPORT_FILES = [
|
|
759
|
+
"./.env",
|
|
760
|
+
"./.env.local",
|
|
761
|
+
"./.env.development",
|
|
762
|
+
"./.env.production",
|
|
763
|
+
"./package.json",
|
|
764
|
+
"./tsconfig.json",
|
|
765
|
+
];
|
|
766
|
+
|
|
767
|
+
// Include supported files
|
|
768
|
+
SUPPORT_FILES.forEach((relativePath) => {
|
|
769
|
+
const fullPath = path.join(pwd, relativePath);
|
|
770
|
+
if (fs.existsSync(fullPath)) {
|
|
771
|
+
console.log(
|
|
772
|
+
chalk.green(
|
|
773
|
+
`Including ${relativePath} in push for project ${projectId}.`
|
|
774
|
+
)
|
|
775
|
+
);
|
|
776
|
+
const content = fs.readFileSync(fullPath, { encoding: "utf8" });
|
|
777
|
+
files.push({
|
|
778
|
+
path: relativePath,
|
|
779
|
+
content,
|
|
780
|
+
es5: compileES5(content, fullPath) ?? "",
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
});
|
|
784
|
+
spinner.text = `Pushing project source code to server for project ${projectId}...`;
|
|
785
|
+
|
|
715
786
|
const apiUrl = `https://base.myworkbeast.com/api/views/${projectId}`;
|
|
716
787
|
try {
|
|
717
788
|
await axios.put(
|
|
@@ -730,7 +801,11 @@ async function pushProject(spinner: Ora): Promise<boolean> {
|
|
|
730
801
|
);
|
|
731
802
|
return true;
|
|
732
803
|
} catch (error) {
|
|
733
|
-
spinner.fail(
|
|
804
|
+
spinner.fail(
|
|
805
|
+
chalk.red(
|
|
806
|
+
`✗ Error saving project ${projectId}: ${(error as Error).message}`
|
|
807
|
+
)
|
|
808
|
+
);
|
|
734
809
|
return false;
|
|
735
810
|
}
|
|
736
811
|
}
|
|
@@ -742,10 +817,49 @@ program
|
|
|
742
817
|
const saveSpinner: Ora = ora(
|
|
743
818
|
chalk.blue("Saving project source code...")
|
|
744
819
|
).start();
|
|
745
|
-
const
|
|
746
|
-
|
|
820
|
+
const pwd = process.cwd();
|
|
821
|
+
const { projectId, replicate } = getStoredProjectId(pwd);
|
|
822
|
+
|
|
823
|
+
if (!projectId) {
|
|
824
|
+
saveSpinner.fail(
|
|
825
|
+
chalk.red(
|
|
826
|
+
"✗ Project ID not found. Please ensure hapico.config.json exists in the project directory."
|
|
827
|
+
)
|
|
828
|
+
);
|
|
829
|
+
return;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
// Push to the main project
|
|
833
|
+
const mainSuccess = await pushProject(saveSpinner, projectId);
|
|
834
|
+
let allSuccess = mainSuccess;
|
|
835
|
+
|
|
836
|
+
// Push to replicated projects if replicate array exists
|
|
837
|
+
if (replicate && Array.isArray(replicate) && replicate.length > 0) {
|
|
838
|
+
saveSpinner.text = chalk.blue("Pushing to replicated projects...");
|
|
839
|
+
for (const repId of replicate) {
|
|
840
|
+
const success = await pushProject(saveSpinner, repId);
|
|
841
|
+
if (!success) {
|
|
842
|
+
allSuccess = false;
|
|
843
|
+
console.warn(
|
|
844
|
+
chalk.yellow(
|
|
845
|
+
`⚠ Failed to push to replicated project ${repId}. Continuing...`
|
|
846
|
+
)
|
|
847
|
+
);
|
|
848
|
+
} else {
|
|
849
|
+
console.log(
|
|
850
|
+
chalk.green(`✓ Successfully pushed to replicated project ${repId}.`)
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
if (allSuccess) {
|
|
747
857
|
saveSpinner.succeed(
|
|
748
|
-
chalk.green("Project source code saved successfully!")
|
|
858
|
+
chalk.green("Project source code saved successfully to all projects!")
|
|
859
|
+
);
|
|
860
|
+
} else {
|
|
861
|
+
saveSpinner.warn(
|
|
862
|
+
chalk.yellow("Project source code saved with some errors.")
|
|
749
863
|
);
|
|
750
864
|
}
|
|
751
865
|
});
|
|
@@ -838,7 +952,7 @@ program
|
|
|
838
952
|
return;
|
|
839
953
|
}
|
|
840
954
|
const pwd: string = process.cwd();
|
|
841
|
-
const projectId = getStoredProjectId(pwd);
|
|
955
|
+
const { projectId } = getStoredProjectId(pwd);
|
|
842
956
|
if (!projectId) {
|
|
843
957
|
console.error(
|
|
844
958
|
chalk.red(
|
|
@@ -852,15 +966,22 @@ program
|
|
|
852
966
|
).start();
|
|
853
967
|
try {
|
|
854
968
|
const response: ApiResponse = await axios.get(
|
|
855
|
-
`https://base.myworkbeast.com/api/views/${projectId}`,
|
|
969
|
+
`https://base.myworkbeast.com/api/views/v3/${projectId}`,
|
|
856
970
|
{
|
|
857
971
|
headers: {
|
|
858
|
-
Authorization: `Bearer ${token}`,
|
|
972
|
+
Authorization: `Bearer ${token.accessToken}`,
|
|
859
973
|
"Content-Type": "application/json",
|
|
860
974
|
},
|
|
861
975
|
}
|
|
862
976
|
);
|
|
863
|
-
|
|
977
|
+
|
|
978
|
+
const code = response?.data?.code;
|
|
979
|
+
const decompressedCode = pako.inflate(
|
|
980
|
+
Uint8Array.from(atob(code), (c) => c.charCodeAt(0)),
|
|
981
|
+
{ to: "string" }
|
|
982
|
+
);
|
|
983
|
+
|
|
984
|
+
const files: FileContent[] = tryJSONParse(decompressedCode)?.files || [];
|
|
864
985
|
const fileManager = new FileManager(path.join(pwd, "src"));
|
|
865
986
|
fileManager.syncFiles(files);
|
|
866
987
|
apiSpinner.succeed(chalk.green("Project files updated successfully!"));
|
|
@@ -999,7 +1120,9 @@ program
|
|
|
999
1120
|
migrationsDir,
|
|
1000
1121
|
`${index + 1}_migration_${timestamp}.sql`
|
|
1001
1122
|
);
|
|
1002
|
-
fs.writeFileSync(filename, (migration as any).sql, {
|
|
1123
|
+
fs.writeFileSync(filename, (migration as any).sql, {
|
|
1124
|
+
encoding: "utf8",
|
|
1125
|
+
});
|
|
1003
1126
|
});
|
|
1004
1127
|
|
|
1005
1128
|
console.log(chalk.green("✓ Migrations saved successfully!"));
|
|
@@ -1011,7 +1134,6 @@ program
|
|
|
1011
1134
|
).start();
|
|
1012
1135
|
|
|
1013
1136
|
try {
|
|
1014
|
-
files = response.data.files || [];
|
|
1015
1137
|
apiSpinner.succeed(chalk.green("Project data fetched successfully!"));
|
|
1016
1138
|
|
|
1017
1139
|
const saveSpinner: Ora = ora(
|
|
@@ -1232,17 +1354,12 @@ program
|
|
|
1232
1354
|
|
|
1233
1355
|
// hapico publish
|
|
1234
1356
|
program.command("publish").action(async () => {
|
|
1235
|
-
const publishSpinner: Ora = ora(
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
if (!pushSuccess) {
|
|
1239
|
-
return; // Dừng nếu push thất bại
|
|
1240
|
-
}
|
|
1241
|
-
|
|
1242
|
-
// Bước 2: Gọi API để publish
|
|
1243
|
-
const { accessToken } = getStoredToken();
|
|
1357
|
+
const publishSpinner: Ora = ora(
|
|
1358
|
+
chalk.blue("Publishing to Hapico...")
|
|
1359
|
+
).start();
|
|
1244
1360
|
const pwd = process.cwd();
|
|
1245
|
-
const projectId = getStoredProjectId(pwd);
|
|
1361
|
+
const { projectId, replicate } = getStoredProjectId(pwd);
|
|
1362
|
+
|
|
1246
1363
|
if (!projectId) {
|
|
1247
1364
|
publishSpinner.fail(
|
|
1248
1365
|
chalk.red(
|
|
@@ -1251,11 +1368,42 @@ program.command("publish").action(async () => {
|
|
|
1251
1368
|
);
|
|
1252
1369
|
return;
|
|
1253
1370
|
}
|
|
1371
|
+
|
|
1372
|
+
// Step 1: Push source code to main project and replicas
|
|
1373
|
+
const pushSuccess = await pushProject(publishSpinner, projectId);
|
|
1374
|
+
if (!pushSuccess) {
|
|
1375
|
+
return; // Stop if push to main project fails
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
// Push to replicated projects
|
|
1379
|
+
let allPushSuccess = true;
|
|
1380
|
+
if (replicate && Array.isArray(replicate) && replicate.length > 0) {
|
|
1381
|
+
publishSpinner.text = chalk.blue("Pushing to replicated projects...");
|
|
1382
|
+
for (const repId of replicate) {
|
|
1383
|
+
const success = await pushProject(publishSpinner, repId);
|
|
1384
|
+
if (!success) {
|
|
1385
|
+
allPushSuccess = false;
|
|
1386
|
+
console.warn(
|
|
1387
|
+
chalk.yellow(
|
|
1388
|
+
`⚠ Failed to push to replicated project ${repId}. Continuing...`
|
|
1389
|
+
)
|
|
1390
|
+
);
|
|
1391
|
+
} else {
|
|
1392
|
+
console.log(
|
|
1393
|
+
chalk.green(`✓ Successfully pushed to replicated project ${repId}.`)
|
|
1394
|
+
);
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
// Step 2: Publish main project
|
|
1400
|
+
const { accessToken } = getStoredToken();
|
|
1254
1401
|
const apiUrl = "https://base.myworkbeast.com/api/views/publish";
|
|
1402
|
+
let allPublishSuccess = true;
|
|
1255
1403
|
try {
|
|
1256
1404
|
await axios.post(
|
|
1257
1405
|
apiUrl,
|
|
1258
|
-
{ view_id: parseInt(projectId, 10) },
|
|
1406
|
+
{ view_id: parseInt(projectId, 10) },
|
|
1259
1407
|
{
|
|
1260
1408
|
headers: {
|
|
1261
1409
|
Authorization: `Bearer ${accessToken}`,
|
|
@@ -1263,11 +1411,83 @@ program.command("publish").action(async () => {
|
|
|
1263
1411
|
},
|
|
1264
1412
|
}
|
|
1265
1413
|
);
|
|
1266
|
-
publishSpinner.succeed(
|
|
1414
|
+
publishSpinner.succeed(
|
|
1415
|
+
chalk.green(`Project ${projectId} published successfully!`)
|
|
1416
|
+
);
|
|
1267
1417
|
} catch (error) {
|
|
1268
|
-
|
|
1269
|
-
publishSpinner.fail(
|
|
1418
|
+
allPublishSuccess = false;
|
|
1419
|
+
publishSpinner.fail(
|
|
1420
|
+
chalk.red(
|
|
1421
|
+
`✗ Error publishing project ${projectId}: ${(error as Error).message}`
|
|
1422
|
+
)
|
|
1423
|
+
);
|
|
1270
1424
|
}
|
|
1425
|
+
|
|
1426
|
+
// Step 3: Publish replicated projects
|
|
1427
|
+
if (replicate && Array.isArray(replicate) && replicate.length > 0) {
|
|
1428
|
+
publishSpinner.text = chalk.blue("Publishing replicated projects...");
|
|
1429
|
+
for (const repId of replicate) {
|
|
1430
|
+
try {
|
|
1431
|
+
await axios.post(
|
|
1432
|
+
apiUrl,
|
|
1433
|
+
{ view_id: parseInt(repId, 10) },
|
|
1434
|
+
{
|
|
1435
|
+
headers: {
|
|
1436
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1437
|
+
"Content-Type": "application/json",
|
|
1438
|
+
},
|
|
1439
|
+
}
|
|
1440
|
+
);
|
|
1441
|
+
console.log(
|
|
1442
|
+
chalk.green(`✓ Successfully published replicated project ${repId}.`)
|
|
1443
|
+
);
|
|
1444
|
+
} catch (error) {
|
|
1445
|
+
allPublishSuccess = false;
|
|
1446
|
+
console.warn(
|
|
1447
|
+
chalk.yellow(
|
|
1448
|
+
`⚠ Error publishing replicated project ${repId}: ${(error as Error).message}`
|
|
1449
|
+
)
|
|
1450
|
+
);
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
if (allPushSuccess && allPublishSuccess) {
|
|
1456
|
+
publishSpinner.succeed(chalk.green("All projects published successfully!"));
|
|
1457
|
+
} else {
|
|
1458
|
+
publishSpinner.warn(chalk.yellow("Publishing completed with some errors."));
|
|
1459
|
+
}
|
|
1460
|
+
});
|
|
1461
|
+
|
|
1462
|
+
program.command("mirror").action(() => {
|
|
1463
|
+
console.log(chalk.cyan("🌐 Starting mirror mode..."));
|
|
1464
|
+
const pwd = process.cwd();
|
|
1465
|
+
const srcDir = path.join(pwd, "src");
|
|
1466
|
+
if (!fs.existsSync(srcDir)) {
|
|
1467
|
+
console.error(
|
|
1468
|
+
chalk.red(
|
|
1469
|
+
"✗ Source directory 'src' does not exist. Please clone a project first."
|
|
1470
|
+
)
|
|
1471
|
+
);
|
|
1472
|
+
return;
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
const fileManager = new FileManager(srcDir);
|
|
1476
|
+
const initialFiles = fileManager.listFiles();
|
|
1477
|
+
|
|
1478
|
+
// Lấy danh sách file và viết ra 1 file .txt
|
|
1479
|
+
let content = ``;
|
|
1480
|
+
map(initialFiles, (file) => {
|
|
1481
|
+
content += `\`\`\`typescript
|
|
1482
|
+
// Path: ${file.path}
|
|
1483
|
+
${file.content}
|
|
1484
|
+
|
|
1485
|
+
\`\`\`
|
|
1486
|
+
`;
|
|
1487
|
+
});
|
|
1488
|
+
const outputFile = path.join(pwd, "hapico_files.txt");
|
|
1489
|
+
fs.writeFileSync(outputFile, content, { encoding: "utf8" });
|
|
1490
|
+
console.log(chalk.green(`✓ File list saved to ${outputFile}`));
|
|
1271
1491
|
});
|
|
1272
1492
|
|
|
1273
1493
|
program.parse(process.argv);
|
package/package.json
CHANGED
package/test.tsx
ADDED
|
File without changes
|