4bnode 3.5.3 → 4.0.2
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 +144 -109
- package/add-api.js +288 -156
- package/add-crud.js +226 -0
- package/add-login.js +152 -319
- package/add-mongo-delete.js +67 -138
- package/add-mongo-insert.js +87 -204
- package/add-mongo-read.js +100 -216
- package/add-mongo-schema.js +431 -199
- package/add-mongo-update.js +89 -202
- package/add-mongo.js +125 -218
- package/add-serialport.js +53 -98
- package/add-socket.js +43 -66
- package/add-websocket.js +68 -140
- package/index.js +341 -156
- package/lib/env.js +18 -0
- package/lib/indexFile.js +134 -0
- package/lib/names.js +21 -0
- package/lib/project.js +122 -0
- package/lib/routeFile.js +56 -0
- package/lib/ui.js +161 -0
- package/package.json +9 -16
- package/skeleton/.4bnode/assets/fonts/NotoSans-Bold.woff2 +0 -0
- package/skeleton/.4bnode/assets/fonts/NotoSans-Light.woff2 +0 -0
- package/skeleton/.4bnode/assets/fonts/NotoSans-Medium.woff2 +0 -0
- package/skeleton/.4bnode/assets/fonts/NotoSans-Regular.woff2 +0 -0
- package/skeleton/.4bnode/assets/fonts/NotoSans-SemiBold.woff2 +0 -0
- package/skeleton/.4bnode/assets/images/mongo.png +0 -0
- package/skeleton/.4bnode/assets/images/mysql.png +0 -0
- package/skeleton/.4bnode/assets/images/postgresql.png +0 -0
- package/skeleton/.4bnode/assets/images/sqlite.png +0 -0
- package/skeleton/.4bnode/assets/js/App.js +115 -0
- package/skeleton/.4bnode/assets/js/Root.js +44 -0
- package/skeleton/.4bnode/assets/js/components/Modal.js +52 -0
- package/skeleton/.4bnode/assets/js/components/Sidebar.js +68 -0
- package/skeleton/.4bnode/assets/js/components/ToastContainer.js +15 -0
- package/skeleton/.4bnode/assets/js/context.js +7 -0
- package/skeleton/.4bnode/assets/js/lib.js +83 -0
- package/skeleton/.4bnode/assets/js/main.js +5 -0
- package/skeleton/.4bnode/assets/js/pages/ApiTesterPage.js +1594 -0
- package/skeleton/.4bnode/assets/js/pages/DashboardPage.js +435 -0
- package/skeleton/.4bnode/assets/js/pages/DatabasePage.js +461 -0
- package/skeleton/.4bnode/assets/js/pages/EnvironmentPage.js +141 -0
- package/skeleton/.4bnode/assets/js/pages/RealtimePage.js +186 -0
- package/skeleton/.4bnode/assets/js/pages/RoutesPage.js +1656 -0
- package/skeleton/.4bnode/assets/js/pages/SchemasPage.js +901 -0
- package/skeleton/.4bnode/assets/js/pages/SerialPortPage.js +170 -0
- package/skeleton/.4bnode/assets/js/screens/PasskeyScreen.js +105 -0
- package/skeleton/.4bnode/assets/js/screens/SplashScreen.js +66 -0
- package/skeleton/.4bnode/dev-api.js +2930 -0
- package/skeleton/.4bnode/ui.html +1556 -0
- package/skeleton/index.js +70 -17
- package/skeleton/package.json +9 -5
- package/skeleton/public/index.html +288 -86
- package/README_4bnode.md +0 -197
- package/src/auth/passport.js +0 -21
- package/src/db.js +0 -13
- package/test-server/.env.development +0 -1
- package/test-server/.env.production +0 -1
- package/test-server/index.js +0 -82
- package/test-server/package-lock.json +0 -1267
- package/test-server/package.json +0 -20
- package/test-server/public/index.html +0 -90
package/add-socket.js
CHANGED
|
@@ -1,33 +1,42 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
3
|
+
import { input } from "@inquirer/prompts";
|
|
4
|
+
import {
|
|
5
|
+
addImport,
|
|
6
|
+
insertBeforeRoutes,
|
|
7
|
+
replaceAppListen,
|
|
8
|
+
} from "./lib/indexFile.js";
|
|
9
|
+
import {
|
|
10
|
+
showHeader,
|
|
11
|
+
showTaskDone,
|
|
12
|
+
showError,
|
|
13
|
+
showFileAction,
|
|
14
|
+
installDeps,
|
|
15
|
+
} from "./lib/ui.js";
|
|
16
|
+
|
|
17
|
+
async function main() {
|
|
18
|
+
showHeader("add-socket", "Add Socket.IO real-time support");
|
|
19
|
+
|
|
20
|
+
const ipAddresses = await input({
|
|
21
|
+
message: "CORS origins (comma-separated, or * for all):",
|
|
22
|
+
default: "*",
|
|
23
|
+
});
|
|
17
24
|
|
|
18
|
-
|
|
19
|
-
const httpImport = `import http from "http";\n`;
|
|
25
|
+
console.log();
|
|
20
26
|
|
|
21
27
|
let corsOrigins;
|
|
22
|
-
|
|
23
28
|
if (ipAddresses.trim() === "*") {
|
|
24
|
-
corsOrigins =
|
|
29
|
+
corsOrigins = '["*"]';
|
|
25
30
|
} else {
|
|
26
31
|
const ipArray = ipAddresses.split(",").map((ip) => ip.trim());
|
|
27
32
|
corsOrigins = `[${ipArray.map((ip) => `"http://${ip}"`).join(", ")}]`;
|
|
28
33
|
}
|
|
29
34
|
|
|
30
|
-
|
|
35
|
+
addImport('import { Server } from "socket.io";');
|
|
36
|
+
addImport('import http from "http";');
|
|
37
|
+
showFileAction("updated", "index.js");
|
|
38
|
+
|
|
39
|
+
const socketSetup = `
|
|
31
40
|
const server = http.createServer(app);
|
|
32
41
|
const io = new Server(server, {
|
|
33
42
|
cors: {
|
|
@@ -44,40 +53,14 @@ io.on("connection", (socket) => {
|
|
|
44
53
|
});
|
|
45
54
|
});
|
|
46
55
|
|
|
47
|
-
// Middleware to pass io instance to routes
|
|
48
56
|
app.use((req, res, next) => {
|
|
49
57
|
req.io = io;
|
|
50
58
|
next();
|
|
51
|
-
})
|
|
52
|
-
`;
|
|
53
|
-
|
|
54
|
-
let indexContent = fs.readFileSync(indexPath, "utf8");
|
|
59
|
+
});`;
|
|
55
60
|
|
|
56
|
-
|
|
57
|
-
if (!indexContent.includes(socketIoImport)) {
|
|
58
|
-
indexContent = socketIoImport + indexContent;
|
|
59
|
-
}
|
|
60
|
-
if (!indexContent.includes(httpImport)) {
|
|
61
|
-
indexContent = httpImport + indexContent;
|
|
62
|
-
}
|
|
61
|
+
insertBeforeRoutes(socketSetup);
|
|
63
62
|
|
|
64
|
-
|
|
65
|
-
const routesStart = indexContent.indexOf("app.use(");
|
|
66
|
-
if (routesStart !== -1) {
|
|
67
|
-
indexContent =
|
|
68
|
-
indexContent.slice(0, routesStart) +
|
|
69
|
-
socketIoSetup +
|
|
70
|
-
indexContent.slice(routesStart);
|
|
71
|
-
} else {
|
|
72
|
-
indexContent += socketIoSetup;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Replace existing app.listen if it exists
|
|
76
|
-
indexContent = indexContent.replace(/app\.listen\(port,.*\);/s, "");
|
|
77
|
-
|
|
78
|
-
// Append server.listen at the end if not already present
|
|
79
|
-
if (!indexContent.includes("server.listen(port")) {
|
|
80
|
-
indexContent += `
|
|
63
|
+
replaceAppListen(`
|
|
81
64
|
server.listen(port, () => {
|
|
82
65
|
const localIp = getLocalNetworkIp();
|
|
83
66
|
console.log(\`App is running on http://localhost:\${port}\`);
|
|
@@ -86,25 +69,19 @@ server.listen(port, () => {
|
|
|
86
69
|
\`App is also accessible on your local network at http://\${localIp}:\${port}\`
|
|
87
70
|
);
|
|
88
71
|
}
|
|
89
|
-
});
|
|
90
|
-
`;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
fs.writeFileSync(indexPath, indexContent, "utf8");
|
|
72
|
+
});`);
|
|
94
73
|
|
|
95
|
-
|
|
96
|
-
console.log(chalk.green("Installing socket.io..."));
|
|
97
|
-
execSync("npm install socket.io", { stdio: "inherit" });
|
|
74
|
+
await installDeps("socket.io");
|
|
98
75
|
|
|
99
|
-
|
|
76
|
+
showTaskDone("Socket.IO integration complete", [
|
|
77
|
+
`CORS: ${ipAddresses.trim()}`,
|
|
78
|
+
"Access via req.io in routes",
|
|
79
|
+
"Events: connection, disconnect",
|
|
80
|
+
]);
|
|
100
81
|
}
|
|
101
82
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
)
|
|
106
|
-
|
|
107
|
-
addSocketIo(ipAddresses);
|
|
108
|
-
rl.close();
|
|
109
|
-
}
|
|
110
|
-
);
|
|
83
|
+
main().catch((err) => {
|
|
84
|
+
if (err.name === "ExitPromptError") process.exit(0);
|
|
85
|
+
showError(err.message);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
});
|
package/add-websocket.js
CHANGED
|
@@ -1,54 +1,63 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import fs from "fs";
|
|
4
3
|
import path from "path";
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
4
|
+
import { confirm, input } from "@inquirer/prompts";
|
|
5
|
+
import { getProjectRoot } from "./lib/project.js";
|
|
6
|
+
import { updateEnvFile } from "./lib/env.js";
|
|
7
|
+
import {
|
|
8
|
+
addImport,
|
|
9
|
+
insertBeforeRoutes,
|
|
10
|
+
replaceAppListen,
|
|
11
|
+
} from "./lib/indexFile.js";
|
|
12
|
+
import {
|
|
13
|
+
showHeader,
|
|
14
|
+
showTaskDone,
|
|
15
|
+
showError,
|
|
16
|
+
showFileAction,
|
|
17
|
+
installDeps,
|
|
18
|
+
} from "./lib/ui.js";
|
|
19
|
+
|
|
20
|
+
async function main() {
|
|
21
|
+
showHeader("add-websocket", "Add native WebSocket support");
|
|
22
|
+
|
|
23
|
+
const samePort = await confirm({
|
|
24
|
+
message: "Use the server port for WebSocket?",
|
|
25
|
+
default: true,
|
|
26
|
+
});
|
|
18
27
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
let wsPort = null;
|
|
29
|
+
if (!samePort) {
|
|
30
|
+
const serverPort = process.env.PORT || 3000;
|
|
31
|
+
wsPort = await input({
|
|
32
|
+
message: "Enter WebSocket port:",
|
|
33
|
+
default: "3001",
|
|
34
|
+
validate: (v) => {
|
|
35
|
+
const num = parseInt(v, 10);
|
|
36
|
+
if (isNaN(num) || num < 1 || num > 65535) return "Enter a valid port.";
|
|
37
|
+
if (num === Number(serverPort))
|
|
38
|
+
return "Cannot be the same as the server port.";
|
|
39
|
+
return true;
|
|
40
|
+
},
|
|
41
|
+
});
|
|
29
42
|
}
|
|
30
|
-
}
|
|
31
43
|
|
|
32
|
-
|
|
33
|
-
const projectRoot = process.cwd();
|
|
34
|
-
const indexPath = path.join(projectRoot, "index.js");
|
|
44
|
+
console.log();
|
|
35
45
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
46
|
+
addImport("import { WebSocketServer } from 'ws';");
|
|
47
|
+
if (samePort) {
|
|
48
|
+
addImport("import http from 'http';");
|
|
49
|
+
}
|
|
50
|
+
showFileAction("updated", "index.js");
|
|
39
51
|
|
|
40
|
-
// Define WebSocket setup based on `samePort`
|
|
41
52
|
const websocketSetup = samePort
|
|
42
53
|
? `
|
|
43
54
|
const server = http.createServer(app);
|
|
44
55
|
const wsServer = new WebSocketServer({ server });
|
|
45
|
-
console.log(\`WebSocket server is running on the same port as the server (\${port})\`)
|
|
46
|
-
`
|
|
56
|
+
console.log(\`WebSocket server is running on the same port as the server (\${port})\`);`
|
|
47
57
|
: `
|
|
48
58
|
const wsPort = process.env.WS_PORT || ${wsPort};
|
|
49
59
|
const wsServer = new WebSocketServer({ port: wsPort });
|
|
50
|
-
console.log(\`WebSocket server is running on WebSocket port \${wsPort}\`)
|
|
51
|
-
`;
|
|
60
|
+
console.log(\`WebSocket server is running on WebSocket port \${wsPort}\`);`;
|
|
52
61
|
|
|
53
62
|
const wsLogic = `
|
|
54
63
|
wsServer.on('connection', (ws) => {
|
|
@@ -58,8 +67,7 @@ wsServer.on('connection', (ws) => {
|
|
|
58
67
|
try {
|
|
59
68
|
const parsedMessage = JSON.parse(message);
|
|
60
69
|
console.log('Received:', parsedMessage);
|
|
61
|
-
|
|
62
|
-
// Broadcast to all clients except sender
|
|
70
|
+
|
|
63
71
|
wsServer.clients.forEach((client) => {
|
|
64
72
|
if (client !== ws && client.readyState === ws.OPEN) {
|
|
65
73
|
client.send(JSON.stringify(parsedMessage));
|
|
@@ -78,12 +86,12 @@ wsServer.on('connection', (ws) => {
|
|
|
78
86
|
app.use((req, res, next) => {
|
|
79
87
|
req.wss = wsServer;
|
|
80
88
|
next();
|
|
81
|
-
})
|
|
82
|
-
`;
|
|
89
|
+
});`;
|
|
83
90
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
91
|
+
insertBeforeRoutes(websocketSetup + "\n" + wsLogic);
|
|
92
|
+
|
|
93
|
+
if (samePort) {
|
|
94
|
+
replaceAppListen(`
|
|
87
95
|
server.listen(port, () => {
|
|
88
96
|
const localIp = getLocalNetworkIp();
|
|
89
97
|
console.log(\`App is running on http://localhost:\${port}\`);
|
|
@@ -92,108 +100,28 @@ server.listen(port, () => {
|
|
|
92
100
|
\`App is also accessible on your local network at http://\${localIp}:\${port}\`
|
|
93
101
|
);
|
|
94
102
|
}
|
|
95
|
-
});
|
|
96
|
-
`
|
|
97
|
-
: `
|
|
98
|
-
app.listen(port, () => {
|
|
99
|
-
const localIp = getLocalNetworkIp();
|
|
100
|
-
console.log(\`App is running on http://localhost:\${port}\`);
|
|
101
|
-
if (localIp) {
|
|
102
|
-
console.log(
|
|
103
|
-
\`App is also accessible on your local network at http://\${localIp}:\${port}\`
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
`;
|
|
108
|
-
|
|
109
|
-
// Add imports if they don't already exist
|
|
110
|
-
if (!indexContent.includes(wsImport)) {
|
|
111
|
-
indexContent = wsImport + indexContent;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Remove existing `app.listen()` or `server.listen()`
|
|
115
|
-
indexContent = indexContent.replace(/server\.listen\(port.*\);/s, "");
|
|
116
|
-
indexContent = indexContent.replace(/app\.listen\(port.*\);/s, "");
|
|
117
|
-
|
|
118
|
-
// Ensure WebSocket setup is placed before routes
|
|
119
|
-
if (!indexContent.includes("const wsServer = new WebSocketServer({")) {
|
|
120
|
-
const routesStart = indexContent.indexOf("app.use(");
|
|
121
|
-
if (routesStart !== -1) {
|
|
122
|
-
indexContent =
|
|
123
|
-
indexContent.slice(0, routesStart) +
|
|
124
|
-
websocketSetup +
|
|
125
|
-
wsLogic +
|
|
126
|
-
indexContent.slice(routesStart);
|
|
127
|
-
} else {
|
|
128
|
-
indexContent += websocketSetup + wsLogic;
|
|
129
|
-
}
|
|
103
|
+
});`);
|
|
130
104
|
}
|
|
131
105
|
|
|
132
|
-
// Append the correct `listen()` function
|
|
133
|
-
if (
|
|
134
|
-
!indexContent.includes("app.listen(port)") &&
|
|
135
|
-
!indexContent.includes("server.listen(port)")
|
|
136
|
-
) {
|
|
137
|
-
indexContent += listenSetup;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
fs.writeFileSync(indexPath, indexContent, "utf8");
|
|
141
|
-
|
|
142
|
-
// Update `.env` files only if using a separate WebSocket port
|
|
143
106
|
if (!samePort) {
|
|
144
|
-
|
|
145
|
-
updateEnvFile(path.join(projectRoot, ".env.
|
|
107
|
+
const projectRoot = getProjectRoot();
|
|
108
|
+
updateEnvFile(path.join(projectRoot, ".env.development"), "WS_PORT", wsPort);
|
|
109
|
+
updateEnvFile(path.join(projectRoot, ".env.production"), "WS_PORT", wsPort);
|
|
110
|
+
showFileAction("updated", ".env.development");
|
|
111
|
+
showFileAction("updated", ".env.production");
|
|
146
112
|
}
|
|
147
113
|
|
|
148
|
-
|
|
149
|
-
console.log(chalk.green("Installing ws..."));
|
|
150
|
-
execSync("npm install ws", { stdio: "inherit" });
|
|
114
|
+
await installDeps("ws");
|
|
151
115
|
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
function askWebSocketPort() {
|
|
159
|
-
rl.question(
|
|
160
|
-
chalk.yellow("Enter a different WebSocket port (default: 3001): "),
|
|
161
|
-
(wsPortInput) => {
|
|
162
|
-
let wsPort = parseInt(wsPortInput.trim()) || 3001;
|
|
163
|
-
|
|
164
|
-
if (wsPort === serverPort) {
|
|
165
|
-
console.log(
|
|
166
|
-
chalk.red("WebSocket port cannot be the same as the server port.")
|
|
167
|
-
);
|
|
168
|
-
askWebSocketPort(); // Re-prompt if user enters the same port
|
|
169
|
-
} else {
|
|
170
|
-
addWebSocket(false, wsPort); // samePort = false, pass wsPort
|
|
171
|
-
rl.close();
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
);
|
|
116
|
+
showTaskDone("WebSocket integration complete", [
|
|
117
|
+
samePort ? "Sharing server port" : `WebSocket port: ${wsPort}`,
|
|
118
|
+
"Access via req.wss in routes",
|
|
119
|
+
"Auto-broadcasts to all clients",
|
|
120
|
+
]);
|
|
175
121
|
}
|
|
176
122
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
(useSamePort) => {
|
|
183
|
-
const answer = useSamePort.trim().toLowerCase();
|
|
184
|
-
|
|
185
|
-
if (answer === "y" || answer === "yes") {
|
|
186
|
-
addWebSocket(true); // samePort = true, no wsPort needed
|
|
187
|
-
rl.close();
|
|
188
|
-
} else if (answer === "n" || answer === "no") {
|
|
189
|
-
askWebSocketPort(); // Ask for a different WebSocket port
|
|
190
|
-
} else {
|
|
191
|
-
console.log(chalk.red("Invalid input. Please enter Yes or No."));
|
|
192
|
-
askUseSamePort(); // Re-prompt if invalid input
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Start asking user input
|
|
199
|
-
askUseSamePort();
|
|
123
|
+
main().catch((err) => {
|
|
124
|
+
if (err.name === "ExitPromptError") process.exit(0);
|
|
125
|
+
showError(err.message);
|
|
126
|
+
process.exit(1);
|
|
127
|
+
});
|