comp-hub 0.27.19 → 0.28.1
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 +71 -86
- package/bin/cli.js +42 -76
- package/bin/lib/commands.js +147 -0
- package/bin/lib/constants.js +22 -0
- package/bin/lib/http.js +62 -0
- package/bin/lib/startup.js +183 -0
- package/bin/lib/utils.js +80 -0
- package/dist/index.js +16 -16
- package/dist/master.js +403 -0
- package/dist/website/container/assets/{index-CdaB9oWd.js → index-BTW7AmWY.js} +9 -9
- package/dist/website/container/assets/index-DqV5-Zk-.css +1 -0
- package/dist/website/container/index.html +31 -34
- package/dist/website/container/js/vue2-sfc-loader.js +1 -1
- package/dist/website/container/js/vue3-sfc-loader.js +1 -1
- package/dist/website/item/assets/index-DNn8L2ik.css +1 -0
- package/dist/website/item/assets/index-eJgZiYQR.js +40 -0
- package/dist/website/item/index.html +28 -30
- package/dist/website/main/assets/{AuthCodeSendBtn.vue_vue_type_script_setup_true_lang-CfufrKbA.js → AuthCodeSendBtn.vue_vue_type_script_setup_true_lang-C2LcEFL4.js} +1 -1
- package/dist/website/main/assets/{BaseDialog.vue_vue_type_script_setup_true_lang-B6WkXWm7.js → BaseDialog.vue_vue_type_script_setup_true_lang-CgV6_zzd.js} +1 -1
- package/dist/website/main/assets/BaseSegmented.vue_vue_type_script_setup_true_lang-CW16Y3Jx.js +1 -0
- package/dist/website/main/assets/{CanvasAnimation.vue_vue_type_script_setup_true_lang-BwtYEYU5.js → CanvasAnimation.vue_vue_type_script_setup_true_lang-BVY2XxV8.js} +1 -1
- package/dist/website/main/assets/{EmptyStatusContainer.vue_vue_type_script_setup_true_lang-DIgE9MGd.js → EmptyStatusContainer.vue_vue_type_script_setup_true_lang-CofI0Rvq.js} +1 -1
- package/dist/website/main/assets/{LoadingWrapper.vue_vue_type_script_setup_true_lang-5GxduB08.js → LoadingWrapper.vue_vue_type_script_setup_true_lang-bBtkKtmz.js} +1 -1
- package/dist/website/main/assets/{PanelBackground.vue_vue_type_script_setup_true_lang-CM6wkI5V.js → PanelBackground.vue_vue_type_script_setup_true_lang-DBIlZFl0.js} +1 -1
- package/dist/website/main/assets/{cloud-upload-CyIQfnxU.js → cloud-upload-BRjLuSi4.js} +1 -1
- package/dist/website/main/assets/{core-DE5-zGKf.js → core-B1GcTOER.js} +1 -1
- package/dist/website/main/assets/{el-table-column-BiqynxkD.js → el-table-column-8qfe8CVK.js} +1 -1
- package/dist/website/main/assets/{home-rounded-Dq-TBvLG.js → home-rounded-8qNxvN2I.js} +1 -1
- package/dist/website/main/assets/{index-CMvx8gm3.js → index-0Y9kW7YJ.js} +1 -1
- package/dist/website/main/assets/index-2LGHX46G.js +1 -0
- package/dist/website/main/assets/index-B2xvPCaB.js +1 -0
- package/dist/website/main/assets/{index-CGgS1tZ0.js → index-B3dAdOL_.js} +1 -1
- package/dist/website/main/assets/{index-Cf69_nzt.js → index-B5qe6yln.js} +15 -15
- package/dist/website/main/assets/index-BANn4H7f.css +1 -0
- package/dist/website/main/assets/{index-DvyE3TrH.js → index-ByKMTPW3.js} +2 -2
- package/dist/website/main/assets/index-CDnNjG3p.css +1 -0
- package/dist/website/main/assets/index-CEQStqDa.js +1 -0
- package/dist/website/main/assets/index-CP6sOfKF.css +1 -0
- package/dist/website/main/assets/index-Cf5sOeOs.js +1 -0
- package/dist/website/main/assets/index-CmSN0r9I.css +1 -0
- package/dist/website/main/assets/index-Cn8OtDDR.js +1 -0
- package/dist/website/main/assets/{index-BQWeT5qu.js → index-CoWWi7z-.js} +2 -2
- package/dist/website/main/assets/index-Cqi9_pkc.js +1 -0
- package/dist/website/main/assets/{index-vnzmxexj.js → index-CrzWpCC3.js} +1 -1
- package/dist/website/main/assets/index-CtzG8xUz.js +1 -0
- package/dist/website/main/assets/index-DANPdG90.js +1 -0
- package/dist/website/main/assets/index-DI0kvKsV.js +1 -0
- package/dist/website/main/assets/index-DJ4AvgpT.css +1 -0
- package/dist/website/main/assets/index-DSED2-Jv.js +1 -0
- package/dist/website/main/assets/index-DUr8uU-d.js +1 -0
- package/dist/website/main/assets/index-DW-M9dmc.js +1 -0
- package/dist/website/main/assets/{index-BGLjC3BV.js → index-D_jNsofk.js} +1 -1
- package/dist/website/main/assets/index-DffjEud2.js +1 -0
- package/dist/website/main/assets/{index-ctwb4cB7.js → index-DkTzdi1V.js} +1 -1
- package/dist/website/main/assets/index-DoTR7Juh.css +1 -0
- package/dist/website/main/assets/index-DxG4_1zN.js +1 -0
- package/dist/website/main/assets/{index-CTLlcQoM.js → index-DyEkv8OS.js} +1 -1
- package/dist/website/main/assets/{index-CCFHORqg.js → index-RlxCYKYM.js} +1 -1
- package/dist/website/main/assets/index-ZwJcoRf3.js +2 -0
- package/dist/website/main/assets/index-bJb3z37F.js +1 -0
- package/dist/website/main/assets/{index-gOTpUrNM.js → index-dC2trX5C.js} +1 -1
- package/dist/website/main/assets/{index-Cu1YAWdz.js → index-dhG9Kj5W.js} +1 -1
- package/dist/website/main/assets/{index-q4Z3Q7p4.js → index-feqY_hvF.js} +1 -1
- package/dist/website/main/assets/{index-cFhtMyBi.js → index-op0bdgFk.js} +2 -2
- package/dist/website/main/assets/index-xqKWYiCC.js +1 -0
- package/dist/website/main/assets/{index.vue_vue_type_script_setup_true_lang-BDhf8t5D.js → index.vue_vue_type_script_setup_true_lang-B_VrULUy.js} +1 -1
- package/dist/website/main/assets/index.vue_vue_type_script_setup_true_lang-D3xHCy9f.js +2 -0
- package/dist/website/main/assets/{index.vue_vue_type_script_setup_true_lang-B4echric.js → index.vue_vue_type_script_setup_true_lang-DCQMqfel.js} +1 -1
- package/dist/website/main/assets/index.vue_vue_type_script_setup_true_lang-DM_Wm4GD.js +1 -0
- package/dist/website/main/assets/{index.vue_vue_type_script_setup_true_lang-qhJpeu7a.js → index.vue_vue_type_script_setup_true_lang-DX9EV5b8.js} +1 -1
- package/dist/website/main/assets/{index.vue_vue_type_script_setup_true_lang-aO0L9Tak.js → index.vue_vue_type_script_setup_true_lang-RJnk970E.js} +1 -1
- package/dist/website/main/assets/index.vue_vue_type_script_setup_true_lang-rk3Yu4M8.js +1 -0
- package/dist/website/main/assets/{index.vue_vue_type_style_index_0_lang-C3U7f9Ma.js → index.vue_vue_type_style_index_0_lang-BQWxY2F1.js} +5 -5
- package/dist/website/main/assets/{index.vue_vue_type_style_index_0_lang-C4fELX8m.js → index.vue_vue_type_style_index_0_lang-DQhqVyhA.js} +1 -1
- package/dist/website/main/assets/{index.vue_vue_type_style_index_0_lang-D_eT-tA_.js → index.vue_vue_type_style_index_0_lang-xD-wMtaK.js} +1 -1
- package/dist/website/main/assets/{kid-star-CFLIpXDC.js → kid-star-Cr1NlTdT.js} +1 -1
- package/dist/website/main/assets/{md5-BZr8xhBN.js → md5-DzJRYP5-.js} +1 -1
- package/dist/website/main/assets/{settings-B3XnnICj.js → settings-BFJXTJ9K.js} +1 -1
- package/dist/website/main/assets/{supervised-user-circle-CEgKC7n7.js → supervised-user-circle-Bnx5icEm.js} +1 -1
- package/dist/website/main/assets/{sync-saved-locally-rounded-CmlRPNS9.js → sync-saved-locally-rounded-DtyOT0dw.js} +1 -1
- package/dist/website/main/assets/{terminal-DykiTSV6.js → terminal-D72IJB2N.js} +1 -1
- package/dist/website/main/assets/{useCacheOssStore-CU4a8b24.js → useCacheOssStore-DApHt9lQ.js} +1 -1
- package/dist/website/main/assets/{useCompEditStore-Du_-rNtX.css → useCompEditStore-B9HAj9va.css} +1 -1
- package/dist/website/main/assets/{useCompEditStore-B7KaUbOi.js → useCompEditStore-KBTFiinR.js} +94 -94
- package/dist/website/main/assets/{useCompMetaLocalStore-pb1Ikkq3.js → useCompMetaLocalStore-eE-CBcE9.js} +1 -1
- package/dist/website/main/assets/{useKeyword-D1qu8Tz-.js → useKeyword-CoagiMo1.js} +1 -1
- package/dist/website/main/assets/useMessage-CYVXvlqq.js +1 -0
- package/dist/website/main/assets/{useTeamHeaders-DELMIzHt.js → useTeamHeaders-Cc060CP0.js} +1 -1
- package/dist/website/main/assets/useVscodeOpen-Dx3IRL0P.js +1 -0
- package/dist/website/main/assets/{vendor-core-B-Si3WEf.js → vendor-core-CzvSW5ae.js} +3 -3
- package/dist/website/main/assets/{vendor-ui-D6wVBlls.js → vendor-ui-DXwyveTF.js} +12 -12
- package/dist/website/main/index.html +92 -92
- package/package.json +5 -3
- package/dist/website/container/assets/index-BnbvpvZL.css +0 -1
- package/dist/website/item/assets/index-B0s1uwsa.js +0 -39
- package/dist/website/item/assets/index-BIcNxYiU.css +0 -1
- package/dist/website/main/assets/BaseSegmented.vue_vue_type_script_setup_true_lang-D5yw_wF0.js +0 -1
- package/dist/website/main/assets/index-B6f_06zP.js +0 -1
- package/dist/website/main/assets/index-BIGvC1SM.js +0 -1
- package/dist/website/main/assets/index-BfPdLll-.js +0 -1
- package/dist/website/main/assets/index-BkUBwon5.css +0 -1
- package/dist/website/main/assets/index-C9t3Yhe9.js +0 -1
- package/dist/website/main/assets/index-CFH_ugiT.js +0 -1
- package/dist/website/main/assets/index-CWW1M_cy.js +0 -1
- package/dist/website/main/assets/index-CuHNNhtE.js +0 -1
- package/dist/website/main/assets/index-D6Fz5rH9.css +0 -1
- package/dist/website/main/assets/index-D7eOWAPr.js +0 -1
- package/dist/website/main/assets/index-D8WDrGkh.js +0 -1
- package/dist/website/main/assets/index-DBM1x91X.js +0 -1
- package/dist/website/main/assets/index-DC94GyXj.js +0 -1
- package/dist/website/main/assets/index-Dl-mwEbG.js +0 -1
- package/dist/website/main/assets/index-DmO0JQ56.css +0 -1
- package/dist/website/main/assets/index-DrUAgWBX.js +0 -1
- package/dist/website/main/assets/index-Oo11MKfd.js +0 -1
- package/dist/website/main/assets/index-YUZjR2Eq.js +0 -2
- package/dist/website/main/assets/index-tEU6GnSH.js +0 -1
- package/dist/website/main/assets/index-tWc_GbBW.css +0 -1
- package/dist/website/main/assets/index-uu5oSUvx.js +0 -1
- package/dist/website/main/assets/index-wgeiSlf-.css +0 -1
- package/dist/website/main/assets/index-y8GEzH-z.css +0 -1
- package/dist/website/main/assets/index.vue_vue_type_script_setup_true_lang-COryHg9c.js +0 -1
- package/dist/website/main/assets/index.vue_vue_type_script_setup_true_lang-D_7jZ1zo.js +0 -2
- package/dist/website/main/assets/index.vue_vue_type_script_setup_true_lang-Dtuk2wrA.js +0 -1
- package/dist/website/main/assets/useMessage-D7WAp245.js +0 -1
- package/dist/website/main/assets/useVscodeOpen-DIYbcP1e.js +0 -1
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const { spawn } = require("child_process");
|
|
4
|
+
const { httpPost } = require("./http");
|
|
5
|
+
const { computeHash, projectRoot, readMasterRuntime, loadComphubConfig, colors, apiUrl } = require("./utils");
|
|
6
|
+
const { cyan, green, white, yellow, red } = colors;
|
|
7
|
+
const { ADMIN_API, POLL_INTERVAL, MAX_RETRIES, DEFAULT_PORT } = require("./constants");
|
|
8
|
+
const getPort = require("get-port");
|
|
9
|
+
|
|
10
|
+
// ---- Config ----
|
|
11
|
+
|
|
12
|
+
function mergeConfig(opts, cwd) {
|
|
13
|
+
// 加载项目配置文件,作为命令行参数的 fallback
|
|
14
|
+
const fileConfig = loadComphubConfig(cwd);
|
|
15
|
+
// 优先级:命令行 > 配置文件 > 默认值
|
|
16
|
+
return {
|
|
17
|
+
dir: opts.dir || fileConfig.dir || "./",
|
|
18
|
+
api: opts.api || fileConfig.api,
|
|
19
|
+
allowDebug: opts.allowDebug ?? fileConfig.allowDebug ?? false,
|
|
20
|
+
proxy: opts.proxy || fileConfig.proxy,
|
|
21
|
+
port: opts.port
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// ---- Master lifecycle ----
|
|
26
|
+
|
|
27
|
+
async function waitForMasterRuntime() {
|
|
28
|
+
for (let i = 0; i < MAX_RETRIES; i++) {
|
|
29
|
+
const runtime = readMasterRuntime();
|
|
30
|
+
if (runtime) return runtime;
|
|
31
|
+
await new Promise(r => setTimeout(r, POLL_INTERVAL));
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function spawnMaster(publicPort, pkg, cwd) {
|
|
37
|
+
const masterEntry = path.join(projectRoot, "dist/master.js");
|
|
38
|
+
|
|
39
|
+
if (!fs.existsSync(masterEntry)) {
|
|
40
|
+
throw new Error("Master entry file not found, startup failed");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const masterArgs = ["--port", String(publicPort), "--public-port", String(publicPort)];
|
|
44
|
+
const child = spawn(process.execPath, [masterEntry, ...masterArgs], {
|
|
45
|
+
stdio: "ignore",
|
|
46
|
+
detached: true,
|
|
47
|
+
windowsHide: true,
|
|
48
|
+
cwd,
|
|
49
|
+
env: {
|
|
50
|
+
...process.env,
|
|
51
|
+
COMP_HUB_VERSION: pkg.version
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
child.unref();
|
|
56
|
+
|
|
57
|
+
const runtime = await waitForMasterRuntime();
|
|
58
|
+
if (!runtime) {
|
|
59
|
+
child.kill();
|
|
60
|
+
throw new Error("Master startup timeout");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return runtime;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 确保 master 在运行,返回运行时信息。
|
|
68
|
+
* 如果已在运行则复用,否则 spawn 新的 master 进程。
|
|
69
|
+
*/
|
|
70
|
+
async function ensureMasterRunning(opts, pkg) {
|
|
71
|
+
let portMismatch = false;
|
|
72
|
+
let runningPublicPort = 0;
|
|
73
|
+
|
|
74
|
+
const existingRuntime = readMasterRuntime();
|
|
75
|
+
|
|
76
|
+
if (existingRuntime) {
|
|
77
|
+
// Master 已在运行,检查用户指定的端口是否匹配
|
|
78
|
+
const expectedPort = opts.port ?? existingRuntime.publicPort;
|
|
79
|
+
if (opts.port != null && existingRuntime.publicPort !== expectedPort) {
|
|
80
|
+
portMismatch = true;
|
|
81
|
+
runningPublicPort = existingRuntime.publicPort;
|
|
82
|
+
}
|
|
83
|
+
return { runtime: existingRuntime, portMismatch, runningPublicPort };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 启动新 master
|
|
87
|
+
const portHint = opts.port ?? DEFAULT_PORT;
|
|
88
|
+
const publicPort = await getPort({ port: getPort.makeRange(portHint, portHint + 100) });
|
|
89
|
+
|
|
90
|
+
const runtime = await spawnMaster(publicPort, pkg, process.cwd());
|
|
91
|
+
return { runtime, portMismatch, runningPublicPort };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ---- Registration ----
|
|
95
|
+
|
|
96
|
+
async function registerProject(masterPort, hash, cwd, opts) {
|
|
97
|
+
const body = {
|
|
98
|
+
hash,
|
|
99
|
+
cwd,
|
|
100
|
+
dir: opts.dir || "./"
|
|
101
|
+
};
|
|
102
|
+
if (opts.api) body.api = opts.api;
|
|
103
|
+
if (opts.allowDebug) body.allowDebug = true;
|
|
104
|
+
if (opts.proxy) body.proxy = opts.proxy;
|
|
105
|
+
|
|
106
|
+
const res = await httpPost(apiUrl(masterPort, ADMIN_API.REGISTER), body);
|
|
107
|
+
if (!res.ok) {
|
|
108
|
+
throw new Error(res.error || "Registration failed");
|
|
109
|
+
}
|
|
110
|
+
console.log(`${green("✓")} Project registered (hash: ${hash})`);
|
|
111
|
+
return res;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ---- Banner ----
|
|
115
|
+
|
|
116
|
+
function printBanner(pkg, cwd, hash, displayPort, opts, { portMismatch, runningPublicPort }) {
|
|
117
|
+
const url = `http://localhost:${displayPort}/${hash}/main/`;
|
|
118
|
+
|
|
119
|
+
const lines = [
|
|
120
|
+
"",
|
|
121
|
+
cyan(" ██████╗ ██████╗ ███╗ ███╗ ██████╗ ██╗ ██╗ ██╗ ██╗ ██████╗ "),
|
|
122
|
+
cyan(" ██╔════╝ ██╔═══██╗ ████╗ ████║ ██╔══██╗ ██║ ██║ ██║ ██║ ██╔══██╗"),
|
|
123
|
+
cyan(" ██║ ██║ ██║ ██╔████╔██║ ██████╔╝ ███████║ ██║ ██║ ██████╔╝"),
|
|
124
|
+
cyan(" ██║ ██║ ██║ ██║╚██╔╝██║ ██╔═══╝ ██╔══██║ ██║ ██║ ██╔══██╗"),
|
|
125
|
+
cyan(" ╚██████╗ ╚██████╔╝ ██║ ╚═╝ ██║ ██║ ██║ ██║ ╚██████╔╝ ██████╔╝"),
|
|
126
|
+
cyan(" ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ "),
|
|
127
|
+
"",
|
|
128
|
+
"",
|
|
129
|
+
` ${green("Version")} ${pkg.version}`,
|
|
130
|
+
` ${green("Project")} ${cwd}`,
|
|
131
|
+
` ${green("Hash")} ${hash}`,
|
|
132
|
+
` ${green("Port")} ${displayPort}`,
|
|
133
|
+
"",
|
|
134
|
+
` ${yellow("URL")} ${cyan(url)}`,
|
|
135
|
+
"",
|
|
136
|
+
white(" ─────────────────────────────────────────────"),
|
|
137
|
+
"",
|
|
138
|
+
` ${"comphub status".padEnd(30)}View all projects`,
|
|
139
|
+
` ${`comphub stop ${hash}`.padEnd(30)}Stop current project`,
|
|
140
|
+
` ${"comphub stop --all".padEnd(30)}Stop all projects`,
|
|
141
|
+
` ${"comphub kill".padEnd(30)}Shutdown master`,
|
|
142
|
+
""
|
|
143
|
+
];
|
|
144
|
+
|
|
145
|
+
if (portMismatch) {
|
|
146
|
+
lines.push(
|
|
147
|
+
white(" ─────────────────────────────────────────────"),
|
|
148
|
+
"",
|
|
149
|
+
red(` ⚠ Master is already running on port ${runningPublicPort}, ignoring -p ${opts.port}`),
|
|
150
|
+
red(` To change port, please run comphub kill first`),
|
|
151
|
+
""
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
console.log(lines.join("\n"));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ---- Main ----
|
|
159
|
+
|
|
160
|
+
async function main(pkg, opts) {
|
|
161
|
+
if (!fs.existsSync(path.join(process.cwd(), "package.json"))) {
|
|
162
|
+
console.error(`${red("✗")} Current directory is not a Node.js project`);
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const cwd = process.cwd();
|
|
167
|
+
const hash = computeHash(cwd);
|
|
168
|
+
|
|
169
|
+
opts = mergeConfig(opts, cwd);
|
|
170
|
+
|
|
171
|
+
console.log(`${green("✓")} ${pkg.name} v${pkg.version}`);
|
|
172
|
+
|
|
173
|
+
const { runtime, portMismatch, runningPublicPort } = await ensureMasterRunning(opts, pkg);
|
|
174
|
+
|
|
175
|
+
const masterPort = runtime.managementPort;
|
|
176
|
+
const displayPort = runtime.publicPort;
|
|
177
|
+
|
|
178
|
+
await registerProject(masterPort, hash, cwd, opts);
|
|
179
|
+
|
|
180
|
+
printBanner(pkg, cwd, hash, displayPort, opts, { portMismatch, runningPublicPort });
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
module.exports = { main };
|
package/bin/lib/utils.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const crypto = require("crypto");
|
|
4
|
+
const { MASTER_RUNTIME_FILE } = require("./constants");
|
|
5
|
+
|
|
6
|
+
const projectRoot = path.resolve(__dirname, "../..");
|
|
7
|
+
|
|
8
|
+
function readJson(p) {
|
|
9
|
+
return JSON.parse(fs.readFileSync(p, "utf8"));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 加载项目根目录的 .comphub.json 或 .comphub.js
|
|
14
|
+
* 作为命令行参数的 fallback,优先级低于 CLI 选项
|
|
15
|
+
*/
|
|
16
|
+
function loadComphubConfig(cwd) {
|
|
17
|
+
const jsonPath = path.join(cwd, ".comphub.json");
|
|
18
|
+
const jsPath = path.join(cwd, ".comphub.js");
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
if (fs.existsSync(jsonPath)) {
|
|
22
|
+
return readJson(jsonPath);
|
|
23
|
+
}
|
|
24
|
+
} catch {
|
|
25
|
+
/* corrupted json, try js */
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
if (fs.existsSync(jsPath)) {
|
|
30
|
+
const mod = require(jsPath);
|
|
31
|
+
return mod.default || mod;
|
|
32
|
+
}
|
|
33
|
+
} catch {
|
|
34
|
+
/* ignore */
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return {};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function getLocalPkgInfo() {
|
|
41
|
+
const pkgPath = path.join(projectRoot, "package.json");
|
|
42
|
+
const pkg = readJson(pkgPath);
|
|
43
|
+
const entry = path.join(projectRoot, pkg.main || "dist/index.js");
|
|
44
|
+
return { pkg, entry };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function computeHash(dir) {
|
|
48
|
+
return crypto.createHash("sha256").update(dir).digest("hex").slice(0, 8);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function readMasterRuntime() {
|
|
52
|
+
try {
|
|
53
|
+
if (fs.existsSync(MASTER_RUNTIME_FILE)) {
|
|
54
|
+
const data = JSON.parse(fs.readFileSync(MASTER_RUNTIME_FILE, "utf8"));
|
|
55
|
+
try {
|
|
56
|
+
process.kill(data.pid, 0);
|
|
57
|
+
return data;
|
|
58
|
+
} catch {
|
|
59
|
+
fs.unlinkSync(MASTER_RUNTIME_FILE);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
} catch {
|
|
63
|
+
/* corrupted file */
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const colors = {
|
|
69
|
+
cyan: s => `\x1b[36m${s}\x1b[0m`,
|
|
70
|
+
green: s => `\x1b[32m${s}\x1b[0m`,
|
|
71
|
+
white: s => `\x1b[37m${s}\x1b[0m`,
|
|
72
|
+
yellow: s => `\x1b[33m${s}\x1b[0m`,
|
|
73
|
+
red: s => `\x1b[31m${s}\x1b[0m`
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
function apiUrl(port, pathname) {
|
|
77
|
+
return `http://localhost:${port}${pathname}`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
module.exports = { getLocalPkgInfo, computeHash, projectRoot, readMasterRuntime, loadComphubConfig, colors, apiUrl };
|