quapp 1.0.0 → 1.0.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/package.json +1 -1
- package/server.js +114 -70
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
1
3
|
import { spawn } from "child_process";
|
|
2
4
|
import os from "os";
|
|
3
5
|
import qrcode from "qrcode-terminal";
|
|
4
|
-
import fs from "fs";
|
|
6
|
+
import fs from "fs/promises";
|
|
7
|
+
import { existsSync } from "fs";
|
|
5
8
|
import path from "path";
|
|
6
9
|
import open from "open";
|
|
10
|
+
import { fileURLToPath } from "url";
|
|
11
|
+
import { spawnSync } from "child_process";
|
|
12
|
+
|
|
13
|
+
// __dirname replacement in ES modules
|
|
14
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
15
|
+
const __dirname = path.dirname(__filename);
|
|
7
16
|
|
|
8
|
-
//
|
|
17
|
+
// Default config
|
|
9
18
|
let config = {
|
|
10
19
|
server: {
|
|
11
20
|
qr: true,
|
|
@@ -15,30 +24,35 @@ let config = {
|
|
|
15
24
|
https: false,
|
|
16
25
|
openBrowser: false,
|
|
17
26
|
autoRetry: true,
|
|
18
|
-
strictPort: false
|
|
19
|
-
}
|
|
27
|
+
strictPort: false,
|
|
28
|
+
},
|
|
20
29
|
};
|
|
21
30
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
// Load user config
|
|
32
|
+
const loadUserConfig = async () => {
|
|
33
|
+
try {
|
|
34
|
+
const configPath = path.resolve("quapp.config.json");
|
|
35
|
+
if (existsSync(configPath)) {
|
|
36
|
+
const data = await fs.readFile(configPath, "utf-8");
|
|
37
|
+
const userConfig = JSON.parse(data);
|
|
38
|
+
config = {
|
|
39
|
+
...config,
|
|
40
|
+
...userConfig,
|
|
41
|
+
server: { ...config.server, ...userConfig.server },
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
} catch (err) {
|
|
45
|
+
console.warn("⚠️ Failed to read quapp.config.json. Using default config.");
|
|
46
|
+
console.warn(err.message);
|
|
31
47
|
}
|
|
32
|
-
}
|
|
33
|
-
console.warn("⚠️ Failed to read quapp.config.json. Using default config.");
|
|
34
|
-
}
|
|
48
|
+
};
|
|
35
49
|
|
|
36
|
-
// Get
|
|
37
|
-
|
|
50
|
+
// Get IP address
|
|
51
|
+
const getIP = (networkType = "local") => {
|
|
38
52
|
if (networkType === "private") {
|
|
39
53
|
const interfaces = os.networkInterfaces();
|
|
40
54
|
for (const key in interfaces) {
|
|
41
|
-
for (const iface of interfaces[key]
|
|
55
|
+
for (const iface of interfaces[key] ?? []) {
|
|
42
56
|
if (!iface.internal && iface.family === "IPv4") {
|
|
43
57
|
return iface.address;
|
|
44
58
|
}
|
|
@@ -46,83 +60,113 @@ function getIP(networkType = "local") {
|
|
|
46
60
|
}
|
|
47
61
|
}
|
|
48
62
|
return "localhost";
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Check if Vite is installed
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
function isViteInstalled() {
|
|
69
|
+
const result = spawnSync(
|
|
70
|
+
process.platform === "win32" ? "npx.cmd" : "npx",
|
|
71
|
+
["vite", "--version"],
|
|
72
|
+
{ stdio: "ignore" }
|
|
73
|
+
);
|
|
74
|
+
return result.status === 0;
|
|
49
75
|
}
|
|
50
76
|
|
|
51
|
-
|
|
52
|
-
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
// Install Vite
|
|
80
|
+
const installVite = () => {
|
|
81
|
+
return new Promise((resolve, reject) => {
|
|
82
|
+
console.log("📦 Installing Vite...");
|
|
83
|
+
const install = spawn("npm", ["install", "vite", "-D"], {
|
|
84
|
+
stdio: "inherit",
|
|
85
|
+
shell: true,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
install.on("exit", (code) => {
|
|
89
|
+
if (code === 0) {
|
|
90
|
+
console.log("✅ Vite installed.");
|
|
91
|
+
resolve();
|
|
92
|
+
} else {
|
|
93
|
+
reject(new Error("Failed to install Vite"));
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// Start Vite server
|
|
100
|
+
const startVite = (port, attempt = 0) => {
|
|
53
101
|
const host = config.server.network === "private" ? getIP("private") : "localhost";
|
|
54
|
-
const
|
|
102
|
+
const protocol = config.server.https ? "https" : "http";
|
|
103
|
+
const url = `${protocol}://${host}:${port}`;
|
|
55
104
|
|
|
56
105
|
const viteArgs = [
|
|
57
106
|
"--host",
|
|
58
107
|
host,
|
|
59
108
|
"--port",
|
|
60
109
|
port,
|
|
61
|
-
// 🛠 Automatically enable strictPort if autoRetry is false
|
|
62
110
|
...(config.server.strictPort || !config.server.autoRetry ? ["--strictPort"] : []),
|
|
63
|
-
...(config.server.https ? ["--https"] : [])
|
|
111
|
+
...(config.server.https ? ["--https"] : []),
|
|
64
112
|
];
|
|
65
113
|
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const output = data.toString();
|
|
114
|
+
const viteBinary = path.resolve(
|
|
115
|
+
"node_modules",
|
|
116
|
+
".bin",
|
|
117
|
+
process.platform === "win32" ? "vite.cmd" : "vite"
|
|
118
|
+
);
|
|
72
119
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
120
|
+
if (!existsSync(viteBinary)) {
|
|
121
|
+
console.error("❌ vite binary not found. Try running `npm install vite`.");
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
77
124
|
|
|
78
|
-
|
|
79
|
-
if (config.server.qr) {
|
|
80
|
-
console.log(`\n📱 Scan the QR code below to open on any device:\n`);
|
|
81
|
-
qrcode.generate(finalUrl, { small: true });
|
|
82
|
-
}
|
|
125
|
+
const vite = spawn(viteBinary, viteArgs, { shell: true });
|
|
83
126
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
127
|
+
vite.stdout.on("data", (data) => process.stdout.write(data));
|
|
128
|
+
vite.stderr.on("data", (data) => process.stderr.write(data));
|
|
87
129
|
|
|
88
|
-
|
|
130
|
+
setTimeout(() => {
|
|
131
|
+
console.log(`\n🌍 Access your app from LAN at: ${url}`);
|
|
132
|
+
if (config.server.qr) {
|
|
133
|
+
console.log(`\n📱 Scan the QR code below:\n`);
|
|
134
|
+
qrcode.generate(url, { small: true });
|
|
89
135
|
}
|
|
136
|
+
if (config.server.openBrowser) {
|
|
137
|
+
open(url);
|
|
138
|
+
}
|
|
139
|
+
}, 1500);
|
|
90
140
|
|
|
91
|
-
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
viteProcess.stderr.on("data", (data) => {
|
|
95
|
-
process.stderr.write(data);
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
viteProcess.on("exit", (code) => {
|
|
141
|
+
vite.on("exit", (code) => {
|
|
99
142
|
if (
|
|
100
143
|
code !== 0 &&
|
|
101
144
|
config.server.fallbackPort &&
|
|
102
145
|
config.server.autoRetry &&
|
|
103
146
|
attempt < 10
|
|
104
147
|
) {
|
|
105
|
-
console.log(`⚠️ Port ${port}
|
|
148
|
+
console.log(`⚠️ Port ${port} in use. Trying port ${port + 1}...`);
|
|
106
149
|
startVite(port + 1, attempt + 1);
|
|
107
|
-
} else {
|
|
108
|
-
console.
|
|
150
|
+
} else if (code !== 0) {
|
|
151
|
+
console.error(`❌ Vite exited with code ${code}`);
|
|
109
152
|
}
|
|
110
153
|
});
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
// Main
|
|
157
|
+
const main = async () => {
|
|
158
|
+
await loadUserConfig();
|
|
159
|
+
|
|
160
|
+
if (!isViteInstalled()) {
|
|
161
|
+
try {
|
|
162
|
+
await installVite();
|
|
163
|
+
} catch (err) {
|
|
164
|
+
console.error("❌ Failed to install Vite automatically. Please install it manually.");
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
119
167
|
}
|
|
120
|
-
}
|
|
121
|
-
// Check if Vite is installed
|
|
122
|
-
if (checkViteInstalled()) {
|
|
123
|
-
console.error("❌ Vite is not installed. Please install it globally or in your project.");
|
|
124
|
-
process.exit(1);
|
|
125
|
-
}
|
|
126
168
|
|
|
127
|
-
|
|
128
|
-
|
|
169
|
+
startVite(config.server.port);
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
main();
|