quapp 1.0.0

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 ADDED
@@ -0,0 +1,29 @@
1
+ # Quapp CLI ๐Ÿงช
2
+
3
+ **Quapp CLI** is a developer-friendly CLI tool to serve and Build quapps in a quick and Easy manner
4
+
5
+ ---
6
+
7
+ ## ๐Ÿš€ Features
8
+
9
+ - โšก Create Quapp's Quickly and Efficently
10
+ - ๐Ÿ“ฑ Serve locally and share via LAN QR code
11
+ - ๐Ÿ“ Lightweight and extensible project setup
12
+
13
+ ---
14
+
15
+ ## ๐Ÿ“ฆ Installation
16
+
17
+ ```bash
18
+ npm install quapp
19
+
20
+ ```
21
+ ## ๐Ÿ”ง Usage
22
+
23
+ ```bash
24
+ quapp serve
25
+
26
+ quapp build
27
+
28
+ quapp
29
+ ```
package/bin/cli.js ADDED
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { spawn } from "child_process";
4
+ import path from "path";
5
+ import { fileURLToPath } from "url";
6
+
7
+ // Resolve __dirname in ESM
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
10
+
11
+ // Get user command
12
+ const args = process.argv.slice(2);
13
+ const command = args[0];
14
+
15
+ // Path to files inside your package
16
+ const buildPath = path.join(__dirname, "../build.js");
17
+ const servePath = path.join(__dirname, "../server.js");
18
+
19
+ // Helper to run a file with Node
20
+ function runScript(scriptPath) {
21
+ const child = spawn("node", [scriptPath], { stdio: "inherit" });
22
+ child.on("close", (code) => process.exit(code));
23
+ }
24
+
25
+ switch (command) {
26
+ case "build":
27
+ runScript(buildPath);
28
+ break;
29
+ case "serve":
30
+ runScript(servePath);
31
+ break;
32
+ default:
33
+ console.log(`
34
+ \x1b[1m\x1b[34mQuapp CLI\x1b[0m
35
+
36
+ Usage:
37
+ quapp build Run production build and compress to dist.quapp
38
+ quapp serve Start local server for testing your app
39
+
40
+ Options:
41
+ -h, --help Show this help message
42
+
43
+ Examples:
44
+ quapp build
45
+ quapp serve
46
+ `);
47
+ break;
48
+ }
package/build.js ADDED
@@ -0,0 +1,87 @@
1
+ import { execSync } from "child_process";
2
+ import fs from "fs";
3
+ import { rm } from "fs/promises";
4
+ import path from "path";
5
+ import archiver from "archiver";
6
+ import { fileURLToPath } from "url";
7
+
8
+ // ASCII color codes for console
9
+ const c = {
10
+ blue: "\x1b[34m",
11
+ red: "\x1b[31m",
12
+ green: "\x1b[32m",
13
+ yellow: "\x1b[33m",
14
+ reset: "\x1b[0m",
15
+ bold: "\x1b[1m",
16
+ };
17
+
18
+ // __dirname workaround for ESM
19
+ const __filename = fileURLToPath(import.meta.url);
20
+ const __dirname = path.dirname(__filename);
21
+
22
+ // Paths
23
+ const projectRoot = process.cwd();
24
+ const distFolder = path.join(projectRoot, "dist");
25
+ const outputQpp = path.join(projectRoot, "dist.qpp");
26
+
27
+ console.log(`${c.blue}\n๐Ÿ“ฆ Starting production build...${c.reset}`);
28
+
29
+ try {
30
+ // Step 1: Run build
31
+ try {
32
+ execSync("npm run build", { stdio: "inherit" });
33
+ } catch (err) {
34
+ console.error(`${c.red}โŒ Build process failed. Please check your build script.${c.reset}`);
35
+ process.exit(1);
36
+ }
37
+
38
+ // Step 2: Verify dist/ exists
39
+ if (!fs.existsSync(distFolder)) {
40
+ console.error(`${c.red}โŒ Build folder 'dist/' not found!${c.reset}`);
41
+ process.exit(1);
42
+ }
43
+
44
+ // Step 3: Compress dist/ into dist.qpp using archiver
45
+ await new Promise((resolve, reject) => {
46
+ const output = fs.createWriteStream(outputQpp);
47
+ const archive = archiver("zip", { zlib: { level: 9 } });
48
+
49
+ output.on("close", () => {
50
+ console.log(`${c.green}\nโœ… Project built and compressed โ†’ ${c.bold}dist.qpp${c.reset}`);
51
+ resolve();
52
+ });
53
+
54
+ output.on("error", (err) => {
55
+ console.error(`${c.red}โŒ Failed to write output file: ${err.message}${c.reset}`);
56
+ reject(err);
57
+ });
58
+
59
+ archive.on("warning", (err) => {
60
+ if (err.code === "ENOENT") {
61
+ console.warn(`${c.yellow}โš ๏ธ Archive warning: ${err.message}${c.reset}`);
62
+ } else {
63
+ reject(err);
64
+ }
65
+ });
66
+
67
+ archive.on("error", (err) => {
68
+ console.error(`${c.red}โŒ Archiving failed: ${err.message}${c.reset}`);
69
+ reject(err);
70
+ });
71
+
72
+ archive.pipe(output);
73
+ archive.directory(distFolder, false);
74
+ archive.finalize();
75
+ });
76
+
77
+ // Step 4: Remove dist folder
78
+ try {
79
+ await rm(distFolder, { recursive: true, force: true });
80
+ } catch (err) {
81
+ console.warn(`${c.yellow}โš ๏ธ Could not remove dist/: ${err.message}${c.reset}`);
82
+ }
83
+
84
+ } catch (err) {
85
+ console.error(`${c.red}\nโŒ Unexpected failure: ${err.message}${c.reset}`);
86
+ process.exit(1);
87
+ }
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "quapp",
3
+ "version": "1.0.0",
4
+ "main": "index.js",
5
+ "scripts": {
6
+ "test": "echo \"Error: no test specified\" && exit 1"
7
+ },
8
+ "type": "module",
9
+ "author": "",
10
+ "bin": {
11
+ "quapp": "./bin/cli.js"
12
+ },
13
+ "license": "ISC",
14
+ "description": "",
15
+ "dependencies": {
16
+ "archiver": "^7.0.1",
17
+ "open": "^10.1.2",
18
+ "qrcode-terminal": "^0.12.0"
19
+ }
20
+ }
package/server.js ADDED
@@ -0,0 +1,128 @@
1
+ import { spawn } from "child_process";
2
+ import os from "os";
3
+ import qrcode from "qrcode-terminal";
4
+ import fs from "fs";
5
+ import path from "path";
6
+ import open from "open";
7
+
8
+ // Load config
9
+ let config = {
10
+ server: {
11
+ qr: true,
12
+ network: "private",
13
+ port: 5173,
14
+ fallbackPort: true,
15
+ https: false,
16
+ openBrowser: false,
17
+ autoRetry: true,
18
+ strictPort: false
19
+ }
20
+ };
21
+
22
+ try {
23
+ const configPath = path.resolve("quapp.config.json");
24
+ if (fs.existsSync(configPath)) {
25
+ const userConfig = JSON.parse(fs.readFileSync(configPath, "utf-8"));
26
+ config = {
27
+ ...config,
28
+ ...userConfig,
29
+ server: { ...config.server, ...userConfig.server }
30
+ };
31
+ }
32
+ } catch (err) {
33
+ console.warn("โš ๏ธ Failed to read quapp.config.json. Using default config.");
34
+ }
35
+
36
+ // Get local or LAN IP
37
+ function getIP(networkType = "local") {
38
+ if (networkType === "private") {
39
+ const interfaces = os.networkInterfaces();
40
+ for (const key in interfaces) {
41
+ for (const iface of interfaces[key] || []) {
42
+ if (!iface.internal && iface.family === "IPv4") {
43
+ return iface.address;
44
+ }
45
+ }
46
+ }
47
+ }
48
+ return "localhost";
49
+ }
50
+
51
+ // Start Vite with fallback logic
52
+ function startVite(port, attempt = 0) {
53
+ const host = config.server.network === "private" ? getIP("private") : "localhost";
54
+ const url = `${config.server.https ? "https" : "http"}://${host}:${port}`;
55
+
56
+ const viteArgs = [
57
+ "--host",
58
+ host,
59
+ "--port",
60
+ port,
61
+ // ๐Ÿ›  Automatically enable strictPort if autoRetry is false
62
+ ...(config.server.strictPort || !config.server.autoRetry ? ["--strictPort"] : []),
63
+ ...(config.server.https ? ["--https"] : [])
64
+ ];
65
+
66
+ const viteProcess = spawn("vite", viteArgs, { shell: true });
67
+
68
+ let shown = false;
69
+
70
+ viteProcess.stdout.on("data", (data) => {
71
+ const output = data.toString();
72
+
73
+ const portMatch = output.match(/http[s]?:\/\/.*:(\d+)/);
74
+ if (portMatch && !shown) {
75
+ const usedPort = parseInt(portMatch[1]);
76
+ const finalUrl = `${config.server.https ? "https" : "http"}://${host}:${usedPort}`;
77
+
78
+ console.log(`\n\n๐ŸŒ Access your app from LAN at: ${finalUrl}`);
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
+ }
83
+
84
+ if (config.server.openBrowser) {
85
+ open(finalUrl); // โœ… Uses external open package
86
+ }
87
+
88
+ shown = true;
89
+ }
90
+
91
+ process.stdout.write(data);
92
+ });
93
+
94
+ viteProcess.stderr.on("data", (data) => {
95
+ process.stderr.write(data);
96
+ });
97
+
98
+ viteProcess.on("exit", (code) => {
99
+ if (
100
+ code !== 0 &&
101
+ config.server.fallbackPort &&
102
+ config.server.autoRetry &&
103
+ attempt < 10
104
+ ) {
105
+ console.log(`โš ๏ธ Port ${port} might be in use. Retrying on port ${port + 1}...`);
106
+ startVite(port + 1, attempt + 1);
107
+ } else {
108
+ console.log(`โŒ Vite exited with code ${code}`);
109
+ }
110
+ });
111
+ }
112
+ // Check if Vite is installed
113
+ function checkViteInstalled() {
114
+ try {
115
+ require.resolve("vite");
116
+ return true;
117
+ } catch (err) {
118
+ return false;
119
+ }
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
+
127
+ // Kickoff
128
+ startVite(config.server.port);