4bnode 4.1.5 → 4.1.6

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.
Files changed (68) hide show
  1. package/add-api.js +5 -3
  2. package/add-email.js +118 -28
  3. package/add-login.js +35 -16
  4. package/add-mongo-schema.js +13 -5
  5. package/lib/codegen.js +191 -57
  6. package/lib/codegen.test.js +87 -15
  7. package/lib/names.js +1 -1
  8. package/package.json +1 -1
  9. package/skeleton/.4bnode/assets/js/pages/ApiTesterPage.js +54 -9
  10. package/skeleton/.4bnode/assets/js/pages/LogsPage.js +49 -16
  11. package/skeleton/.4bnode/assets/js/pages/MailPage.js +110 -50
  12. package/skeleton/.4bnode/codegen.js +191 -57
  13. package/skeleton/.4bnode/dev-api.js +284 -56
  14. package/skeleton/.env.example +17 -3
  15. package/skeleton/_gitignore +1 -0
  16. package/skeleton/index.js +7 -2
  17. package/skeleton/src/middleware/apiKey.js +14 -1
  18. package/skeleton/src/middleware/errorHandler.js +7 -2
  19. package/app-1/.4bnode/.passkey +0 -1
  20. package/app-1/.4bnode/assets/fonts/NotoSans-Bold.woff2 +0 -0
  21. package/app-1/.4bnode/assets/fonts/NotoSans-Light.woff2 +0 -0
  22. package/app-1/.4bnode/assets/fonts/NotoSans-Medium.woff2 +0 -0
  23. package/app-1/.4bnode/assets/fonts/NotoSans-Regular.woff2 +0 -0
  24. package/app-1/.4bnode/assets/fonts/NotoSans-SemiBold.woff2 +0 -0
  25. package/app-1/.4bnode/assets/images/mongo.png +0 -0
  26. package/app-1/.4bnode/assets/js/App.js +0 -139
  27. package/app-1/.4bnode/assets/js/Root.js +0 -40
  28. package/app-1/.4bnode/assets/js/components/Modal.js +0 -52
  29. package/app-1/.4bnode/assets/js/components/Sidebar.js +0 -73
  30. package/app-1/.4bnode/assets/js/components/ToastContainer.js +0 -15
  31. package/app-1/.4bnode/assets/js/context.js +0 -7
  32. package/app-1/.4bnode/assets/js/lib.js +0 -113
  33. package/app-1/.4bnode/assets/js/main.js +0 -5
  34. package/app-1/.4bnode/assets/js/pages/AiBuilderPage.js +0 -268
  35. package/app-1/.4bnode/assets/js/pages/ApiTesterPage.js +0 -1879
  36. package/app-1/.4bnode/assets/js/pages/DashboardPage.js +0 -435
  37. package/app-1/.4bnode/assets/js/pages/DatabasePage.js +0 -300
  38. package/app-1/.4bnode/assets/js/pages/DocsPage.js +0 -150
  39. package/app-1/.4bnode/assets/js/pages/EnvironmentPage.js +0 -103
  40. package/app-1/.4bnode/assets/js/pages/LogsPage.js +0 -205
  41. package/app-1/.4bnode/assets/js/pages/MailPage.js +0 -224
  42. package/app-1/.4bnode/assets/js/pages/RealtimePage.js +0 -186
  43. package/app-1/.4bnode/assets/js/pages/RoutesPage.js +0 -1485
  44. package/app-1/.4bnode/assets/js/pages/SchemasPage.js +0 -838
  45. package/app-1/.4bnode/assets/js/pages/SecurityPage.js +0 -74
  46. package/app-1/.4bnode/assets/js/pages/SerialPortPage.js +0 -170
  47. package/app-1/.4bnode/assets/js/screens/PasskeyScreen.js +0 -105
  48. package/app-1/.4bnode/codegen.js +0 -1440
  49. package/app-1/.4bnode/dev-api.js +0 -3747
  50. package/app-1/.4bnode/ui.html +0 -1578
  51. package/app-1/.env.example +0 -11
  52. package/app-1/README.md +0 -47
  53. package/app-1/ecosystem.config.cjs +0 -25
  54. package/app-1/index.js +0 -188
  55. package/app-1/package.json +0 -37
  56. package/app-1/public/index.html +0 -292
  57. package/app-1/src/db.js +0 -13
  58. package/app-1/src/docs.js +0 -84
  59. package/app-1/src/middleware/apiKey.js +0 -36
  60. package/app-1/src/middleware/auth.js +0 -17
  61. package/app-1/src/middleware/errorHandler.js +0 -15
  62. package/app-1/src/middleware/roles.js +0 -14
  63. package/app-1/src/middleware/validate.js +0 -20
  64. package/app-1/src/models/user.js +0 -11
  65. package/app-1/src/openapi.json +0 -80
  66. package/app-1/src/routes/upload-resume.js +0 -21
  67. package/app-1/src/services/mailer.js +0 -52
  68. package/app-1/src/validators/upload-resume.js +0 -8
@@ -1,11 +0,0 @@
1
- # Copy this file to .env and fill in real values.
2
- # cp .env.example .env
3
-
4
- # Port the server listens on
5
- PORT=3000
6
-
7
- # Rate limiting (only enforced when NODE_ENV=production)
8
- # RATE_LIMIT_WINDOW_MS = window length in ms (900000 = 15 minutes)
9
- # RATE_LIMIT_MAX = max requests per IP per window
10
- RATE_LIMIT_WINDOW_MS=900000
11
- RATE_LIMIT_MAX=500
package/app-1/README.md DELETED
@@ -1,47 +0,0 @@
1
- # node-skeleton-app
2
-
3
- Express 5 + Dotenv + CORS app, scaffolded by [4bnode](https://github.com/pawan-4brains/4bnode).
4
-
5
- ## Getting started
6
-
7
- ### 1. Install dependencies
8
-
9
- ```bash
10
- npm install
11
- ```
12
-
13
- ### 2. Configure environment
14
-
15
- Edit `.env` in the project root and fill in the values your app needs:
16
-
17
- ```bash
18
- PORT=3000
19
- # Add DATABASE_URL, API keys, etc. here
20
- ```
21
-
22
- ### 3. Run it
23
-
24
- ```bash
25
- npm run dev
26
- ```
27
-
28
- The app starts at `http://localhost:PORT` and the dev dashboard at `http://localhost:PORT/_dev`.
29
-
30
- ## Project structure
31
-
32
- ```
33
- .
34
- ├── index.js # Express app entry point
35
- ├── package.json
36
- ├── .env # Environment variables
37
- ├── .4bnode/ # Dashboard engine & data (managed by 4bnode)
38
- ├── public/ # Static files
39
- └── src/
40
- ├── db.js # MongoDB connection (after `4bnode add mongo`)
41
- ├── models/ # Mongoose schemas
42
- └── routes/ # API route files
43
- ```
44
-
45
- ## Extending with 4bnode
46
-
47
- Run `4bnode add` inside this project to scaffold MongoDB, CRUD, login, sockets, and more. See the [4bnode README](https://github.com/pawan-4brains/4bnode) for the full feature list.
@@ -1,25 +0,0 @@
1
- // PM2 process config for production.
2
- //
3
- // pm2 start ecosystem.config.cjs # start (NODE_ENV=production)
4
- // pm2 save # remember across reboots
5
- // pm2 startup # enable boot startup (run the printed command)
6
- // pm2 logs / pm2 restart / pm2 status
7
- //
8
- // NODE_ENV=production keeps the /_dev dashboard OFF and security on. Other config
9
- // (PORT, MONGO_URI, secrets) comes from your .env. CommonJS (.cjs) on purpose —
10
- // the app itself is an ES module.
11
- const pkg = require("./package.json");
12
-
13
- module.exports = {
14
- apps: [
15
- {
16
- name: pkg.name || "app",
17
- script: "index.js",
18
- instances: 1,
19
- autorestart: true,
20
- env: {
21
- NODE_ENV: "production",
22
- },
23
- },
24
- ],
25
- };
package/app-1/index.js DELETED
@@ -1,188 +0,0 @@
1
- import express from "express";
2
- import dotenv from "dotenv";
3
- import path from "path";
4
- import fs from "fs";
5
- import cors from "cors";
6
- import os from "os";
7
- import helmet from "helmet";
8
- import rateLimit from "express-rate-limit";
9
- import { createInterface } from "readline";
10
- import { notFound, errorHandler } from "./src/middleware/errorHandler.js";
11
- import connectDB from './src/db.js';
12
- import docsRouter from './src/docs.js';
13
- import uploadResumeRouter from './src/routes/upload-resume.js';
14
-
15
- // ── Environment ─────────────────────────────────────
16
- dotenv.config();
17
-
18
- connectDB();
19
- const app = express();
20
- // Behind reverse proxies (e.g. nginx → load balancer). Lets Express read the real
21
- // client IP from X-Forwarded-For so rate limiting and req.ip are correct. The number
22
- // is how many proxy hops to trust — adjust to your infrastructure.
23
- app.set("trust proxy", 2);
24
- const port = process.env.PORT || 3000;
25
- const __dirname = path.resolve();
26
-
27
- // ── Middleware ───────────────────────────────────────
28
- app.use(express.json({ limit: "50mb" }));
29
- app.use(express.urlencoded({ extended: true, limit: "50mb" }));
30
- app.use(cors({ origin: "*" }));
31
-
32
- // ── Dev Dashboard (local development only) ───────────
33
- // The dashboard at /_dev can write files and run shell commands — it is a
34
- // remote-code-execution surface and must NEVER be reachable in production.
35
- // In production it is not even imported. It additionally restricts itself to
36
- // loopback requests and requires a passkey (see .4bnode/dev-api.js).
37
- // • production (NODE_ENV=production): OFF — set _4BNODE_DASHBOARD=on to force.
38
- // • non-production: ON — set _4BNODE_DASHBOARD=off to disable.
39
- const dashboardEnabled =
40
- process.env._4BNODE_DASHBOARD === "on" ||
41
- (process.env.NODE_ENV !== "production" && process.env._4BNODE_DASHBOARD !== "off");
42
- if (dashboardEnabled) {
43
- try {
44
- const devApi = await import("./.4bnode/dev-api.js");
45
- app.use("/_dev", devApi.default);
46
- } catch {}
47
- }
48
-
49
- // ── Security (built-in by default) ───────────────────
50
- // Mounted AFTER the /_dev dashboard so its CDN/inline scripts aren't blocked by
51
- // helmet's CSP and the dashboard isn't throttled by the rate limiter.
52
- // helmet() defaults to a strict Content-Security-Policy (script-src 'self',
53
- // etc.) that blocks CDN-loaded scripts, inline <script> blocks, and cross-origin
54
- // assets. We widen the policy so a typical frontend/docs page works while keeping
55
- // the rest of helmet's protections. Tighten these directives for production.
56
- app.use(helmet({
57
- contentSecurityPolicy: {
58
- directives: {
59
- defaultSrc: ["'self'"],
60
- scriptSrc: ["'self'", 'https:', "'unsafe-inline'"],
61
- styleSrc: ["'self'", 'https:', "'unsafe-inline'"],
62
- imgSrc: ["'self'", 'data:', 'https:'],
63
- connectSrc: ["'self'"],
64
- },
65
- },
66
- crossOriginEmbedderPolicy: false,
67
- // Allow other origins (e.g. a separate frontend host) to load assets served
68
- // by this app. Default is 'same-origin'. Tighten to 'same-site' for production.
69
- crossOriginResourcePolicy: { policy: 'cross-origin' },
70
- }));
71
-
72
- // ── Rate limiting ────────────────────────────────────
73
- // Window + cap are read from .env (RATE_LIMIT_WINDOW_MS / RATE_LIMIT_MAX) so the
74
- // dashboard's Security page can tune them; fall back to 15 min / 500 requests.
75
- const apiLimiter = rateLimit({
76
- windowMs: Number(process.env.RATE_LIMIT_WINDOW_MS) || 15 * 60 * 1000,
77
- max: Number(process.env.RATE_LIMIT_MAX) || 500,
78
- standardHeaders: true,
79
- legacyHeaders: false,
80
- });
81
- // Strict cap for authentication routes — defends against password brute-forcing.
82
- // Point this at your real auth routes (login / signup / password-reset).
83
- const authLimiter = rateLimit({
84
- windowMs: 15 * 60 * 1000, // 15 minutes
85
- max: 10, // 10 attempts per IP per window
86
- standardHeaders: true,
87
- legacyHeaders: false,
88
- });
89
- // Only throttle in production — in dev, repeated/hot-reload requests shouldn't hit 429.
90
- if (process.env.NODE_ENV === 'production') {
91
- app.use('/api/auth', authLimiter); // strict limiter first, on auth routes
92
- app.use(apiLimiter); // generous global limiter for everything else
93
- }
94
-
95
- // ── Static Files ────────────────────────────────────
96
- app.use(express.static(path.join(__dirname, "public")));
97
-
98
- // ── Helpers ─────────────────────────────────────────
99
- function getLocalNetworkIp() {
100
- const interfaces = os.networkInterfaces();
101
- for (const name of Object.keys(interfaces)) {
102
- for (const iface of interfaces[name]) {
103
- if (iface.family === "IPv4" && !iface.internal) {
104
- return iface.address;
105
- }
106
- }
107
- }
108
- return null;
109
- }
110
-
111
- function updateEnvPort(newPort) {
112
- try {
113
- if (fs.existsSync(".env")) {
114
- let content = fs.readFileSync(".env", "utf8");
115
- if (content.match(/^PORT=.*/m)) {
116
- content = content.replace(/^PORT=.*/m, `PORT=${newPort}`);
117
- } else {
118
- content += `\nPORT=${newPort}`;
119
- }
120
- fs.writeFileSync(".env", content, "utf8");
121
- }
122
- } catch {}
123
- }
124
-
125
- function askPort(busyPort) {
126
- return new Promise((resolve) => {
127
- const rl = createInterface({ input: process.stdin, output: process.stdout });
128
- console.log(`\nPort ${busyPort} is already in use.`);
129
- rl.question(`Press Enter to use ${busyPort + 1}, or type a port number: `, (answer) => {
130
- rl.close();
131
- const custom = parseInt(answer.trim(), 10);
132
- resolve(custom && custom > 0 ? custom : busyPort + 1);
133
- });
134
- });
135
- }
136
-
137
-
138
-
139
- app.use('/docs', docsRouter);
140
-
141
-
142
-
143
-
144
-
145
-
146
-
147
-
148
-
149
-
150
-
151
-
152
- app.use('/api/upload-resume', uploadResumeRouter);
153
-
154
- // ── Error handling (must be last) ──
155
- app.use(notFound);
156
- app.use(errorHandler);
157
-
158
- // ── Start Server ────────────────────────────────────
159
- async function startServer(tryPort) {
160
- const listener = app.listen(tryPort);
161
- listener.on("listening", () => {
162
- const localIp = getLocalNetworkIp();
163
- console.log(`App is running on http://localhost:${tryPort}`);
164
- if (localIp) {
165
- console.log(`App is also accessible on your local network at http://${localIp}:${tryPort}`);
166
- }
167
- if (tryPort !== Number(port)) {
168
- updateEnvPort(tryPort);
169
- console.log(`Updated .env with PORT=${tryPort}`);
170
- }
171
- });
172
- listener.on("error", async (err) => {
173
- if (err.code === "EADDRINUSE") {
174
- if (!process.stdin.isTTY) {
175
- // Running under pm2 / systemd / IntraApp — no terminal to prompt.
176
- console.error(`Port ${tryPort} is in use and no TTY is available. Exiting.`);
177
- process.exit(1);
178
- }
179
- const nextPort = await askPort(tryPort);
180
- startServer(nextPort);
181
- } else {
182
- console.error(err);
183
- process.exit(1);
184
- }
185
- });
186
- }
187
-
188
- startServer(Number(port));
@@ -1,37 +0,0 @@
1
- {
2
- "name": "app-1",
3
- "version": "1.0.0",
4
- "main": "index.js",
5
- "type": "module",
6
- "scripts": {
7
- "start": "node index.js",
8
- "dev": "nodemon index.js"
9
- },
10
- "nodemonConfig": {
11
- "watch": [
12
- "."
13
- ],
14
- "ext": "js,mjs,cjs",
15
- "ignore": [
16
- "node_modules/",
17
- "package.json",
18
- "package-lock.json",
19
- ".4bnode/"
20
- ]
21
- },
22
- "dependencies": {
23
- "cors": "^2.8.6",
24
- "dotenv": "^17.3.1",
25
- "express": "^5.2.1",
26
- "express-rate-limit": "^7.4.0",
27
- "helmet": "^8.0.0",
28
- "jsonwebtoken": "^9.0.3",
29
- "mongoose": "^8.24.0",
30
- "multer": "^1.4.5-lts.1",
31
- "nodemailer": "^6.10.1",
32
- "zod": "^3.23.0"
33
- },
34
- "devDependencies": {
35
- "nodemon": "^3.1.14"
36
- }
37
- }
@@ -1,292 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>4bnode App</title>
7
- <style>
8
- * { margin: 0; padding: 0; box-sizing: border-box; }
9
-
10
- @font-face { font-family: "Noto Sans"; src: url("/_dev/assets/fonts/NotoSans-Light.woff2") format("woff2"); font-weight: 300; font-style: normal; font-display: swap; }
11
- @font-face { font-family: "Noto Sans"; src: url("/_dev/assets/fonts/NotoSans-Regular.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
12
- @font-face { font-family: "Noto Sans"; src: url("/_dev/assets/fonts/NotoSans-Medium.woff2") format("woff2"); font-weight: 500; font-style: normal; font-display: swap; }
13
- @font-face { font-family: "Noto Sans"; src: url("/_dev/assets/fonts/NotoSans-SemiBold.woff2") format("woff2"); font-weight: 600; font-style: normal; font-display: swap; }
14
- @font-face { font-family: "Noto Sans"; src: url("/_dev/assets/fonts/NotoSans-Bold.woff2") format("woff2"); font-weight: 700; font-style: normal; font-display: swap; }
15
-
16
- body {
17
- font-family: "Noto Sans", -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
18
- background: #0a0b10;
19
- color: #e2e8f0;
20
- min-height: 100vh;
21
- display: flex;
22
- align-items: center;
23
- justify-content: center;
24
- overflow: hidden;
25
- }
26
-
27
- .scene {
28
- position: fixed;
29
- inset: 0;
30
- z-index: 0;
31
- }
32
-
33
- /* Animated grid floor */
34
- .grid {
35
- position: absolute;
36
- bottom: 0;
37
- left: 50%;
38
- transform: translateX(-50%) perspective(600px) rotateX(55deg);
39
- width: 200%;
40
- height: 70vh;
41
- background-image:
42
- linear-gradient(rgba(0,114,255,0.08) 1px, transparent 1px),
43
- linear-gradient(90deg, rgba(0,114,255,0.08) 1px, transparent 1px);
44
- background-size: 60px 60px;
45
- animation: gridScroll 12s linear infinite;
46
- mask-image: linear-gradient(to top, rgba(0,0,0,0.4) 0%, transparent 80%);
47
- -webkit-mask-image: linear-gradient(to top, rgba(0,0,0,0.4) 0%, transparent 80%);
48
- }
49
-
50
- @keyframes gridScroll {
51
- 0% { background-position: 0 0; }
52
- 100% { background-position: 0 60px; }
53
- }
54
-
55
- /* Floating orbs */
56
- .orb {
57
- position: absolute;
58
- border-radius: 50%;
59
- filter: blur(80px);
60
- opacity: 0.35;
61
- animation: float 8s ease-in-out infinite;
62
- }
63
- .orb-1 {
64
- width: 400px; height: 400px;
65
- background: radial-gradient(circle, #0072ff, transparent 70%);
66
- top: 10%; left: 15%;
67
- animation-delay: 0s;
68
- }
69
- .orb-2 {
70
- width: 350px; height: 350px;
71
- background: radial-gradient(circle, #7b2ff7, transparent 70%);
72
- top: 30%; right: 10%;
73
- animation-delay: -3s;
74
- animation-duration: 10s;
75
- }
76
- .orb-3 {
77
- width: 300px; height: 300px;
78
- background: radial-gradient(circle, #00c6ff, transparent 70%);
79
- bottom: 15%; left: 40%;
80
- animation-delay: -5s;
81
- animation-duration: 12s;
82
- }
83
-
84
- @keyframes float {
85
- 0%, 100% { transform: translate(0, 0) scale(1); }
86
- 33% { transform: translate(30px, -20px) scale(1.05); }
87
- 66% { transform: translate(-20px, 15px) scale(0.95); }
88
- }
89
-
90
- /* Content */
91
- .container {
92
- position: relative;
93
- z-index: 1;
94
- text-align: center;
95
- padding: 40px;
96
- animation: fadeUp 1s ease-out;
97
- }
98
-
99
- @keyframes fadeUp {
100
- from { opacity: 0; transform: translateY(30px); }
101
- to { opacity: 1; transform: translateY(0); }
102
- }
103
-
104
- /* Animated node SVG */
105
- .node-graphic {
106
- width: 120px;
107
- height: 120px;
108
- margin: 0 auto 32px;
109
- }
110
-
111
- .node-ring {
112
- fill: none;
113
- stroke: url(#ringGrad);
114
- stroke-width: 1.5;
115
- stroke-dasharray: 8 6;
116
- transform-origin: 60px 60px;
117
- animation: spin 20s linear infinite;
118
- }
119
- .node-ring-2 {
120
- animation: spin 15s linear infinite reverse;
121
- stroke-dasharray: 12 8;
122
- }
123
- .node-ring-3 {
124
- animation: spin 25s linear infinite;
125
- stroke-dasharray: 4 10;
126
- }
127
-
128
- @keyframes spin {
129
- to { transform: rotate(360deg); }
130
- }
131
-
132
- .node-dot {
133
- fill: #0072ff;
134
- animation: pulse 2s ease-in-out infinite;
135
- }
136
- .node-dot:nth-child(2) { animation-delay: 0.3s; fill: #7b2ff7; }
137
- .node-dot:nth-child(3) { animation-delay: 0.6s; fill: #00c6ff; }
138
- .node-dot:nth-child(4) { animation-delay: 0.9s; fill: #0072ff; }
139
- .node-dot:nth-child(5) { animation-delay: 1.2s; fill: #7b2ff7; }
140
- .node-dot:nth-child(6) { animation-delay: 1.5s; fill: #00c6ff; }
141
-
142
- @keyframes pulse {
143
- 0%, 100% { opacity: 0.5; r: 3; }
144
- 50% { opacity: 1; r: 5; }
145
- }
146
-
147
- .node-line {
148
- stroke: url(#lineGrad);
149
- stroke-width: 0.8;
150
- opacity: 0.4;
151
- }
152
-
153
- .node-center {
154
- fill: url(#centerGrad);
155
- filter: drop-shadow(0 0 8px rgba(0,114,255,0.4));
156
- }
157
-
158
- h1 {
159
- font-size: 36px;
160
- font-weight: 800;
161
- letter-spacing: -0.5px;
162
- margin-bottom: 12px;
163
- background: linear-gradient(135deg, #ffffff 0%, #94a3b8 100%);
164
- -webkit-background-clip: text;
165
- -webkit-text-fill-color: transparent;
166
- }
167
-
168
- .tagline {
169
- font-size: 15px;
170
- color: #64748b;
171
- font-weight: 400;
172
- letter-spacing: 0.3px;
173
- margin-bottom: 32px;
174
- }
175
-
176
- .status {
177
- display: inline-flex;
178
- align-items: center;
179
- gap: 8px;
180
- padding: 8px 20px;
181
- border-radius: 100px;
182
- background: rgba(16, 185, 129, 0.08);
183
- border: 1px solid rgba(16, 185, 129, 0.2);
184
- font-size: 13px;
185
- color: #10b981;
186
- font-weight: 500;
187
- animation: fadeUp 1s ease-out 0.3s both;
188
- }
189
-
190
- .status-dot {
191
- width: 8px;
192
- height: 8px;
193
- border-radius: 50%;
194
- background: #10b981;
195
- animation: blink 2s ease-in-out infinite;
196
- box-shadow: 0 0 8px rgba(16, 185, 129, 0.5);
197
- }
198
-
199
- @keyframes blink {
200
- 0%, 100% { opacity: 1; }
201
- 50% { opacity: 0.4; }
202
- }
203
-
204
- .powered {
205
- position: fixed;
206
- bottom: 28px;
207
- left: 0;
208
- right: 0;
209
- text-align: center;
210
- font-size: 12px;
211
- color: #334155;
212
- letter-spacing: 0.3px;
213
- animation: fadeUp 1s ease-out 0.6s both;
214
- }
215
- .powered a {
216
- text-decoration: none;
217
- }
218
- .powered span {
219
- font-weight: 600;
220
- background: linear-gradient(135deg, #00c6ff, #7b2ff7);
221
- -webkit-background-clip: text;
222
- -webkit-text-fill-color: transparent;
223
- transition: opacity 0.2s;
224
- }
225
- .powered a:hover span {
226
- opacity: 0.75;
227
- }
228
- </style>
229
- </head>
230
- <body>
231
-
232
- <div class="scene">
233
- <div class="orb orb-1"></div>
234
- <div class="orb orb-2"></div>
235
- <div class="orb orb-3"></div>
236
- <div class="grid"></div>
237
- </div>
238
-
239
- <div class="container">
240
- <svg class="node-graphic" viewBox="0 0 120 120">
241
- <defs>
242
- <linearGradient id="ringGrad" x1="0%" y1="0%" x2="100%" y2="100%">
243
- <stop offset="0%" stop-color="#0072ff" />
244
- <stop offset="100%" stop-color="#7b2ff7" />
245
- </linearGradient>
246
- <linearGradient id="lineGrad" x1="0%" y1="0%" x2="100%" y2="100%">
247
- <stop offset="0%" stop-color="#0072ff" stop-opacity="0.6" />
248
- <stop offset="100%" stop-color="#7b2ff7" stop-opacity="0.2" />
249
- </linearGradient>
250
- <radialGradient id="centerGrad" cx="50%" cy="50%" r="50%">
251
- <stop offset="0%" stop-color="#0072ff" />
252
- <stop offset="100%" stop-color="#7b2ff7" />
253
- </radialGradient>
254
- </defs>
255
-
256
- <!-- Connection lines -->
257
- <line class="node-line" x1="60" y1="60" x2="60" y2="14" />
258
- <line class="node-line" x1="60" y1="60" x2="100" y2="37" />
259
- <line class="node-line" x1="60" y1="60" x2="100" y2="83" />
260
- <line class="node-line" x1="60" y1="60" x2="60" y2="106" />
261
- <line class="node-line" x1="60" y1="60" x2="20" y2="83" />
262
- <line class="node-line" x1="60" y1="60" x2="20" y2="37" />
263
-
264
- <!-- Rotating rings -->
265
- <circle class="node-ring" cx="60" cy="60" r="50" />
266
- <circle class="node-ring node-ring-2" cx="60" cy="60" r="38" />
267
- <circle class="node-ring node-ring-3" cx="60" cy="60" r="26" />
268
-
269
- <!-- Orbiting dots -->
270
- <circle class="node-dot" cx="60" cy="14" r="4" />
271
- <circle class="node-dot" cx="100" cy="37" r="4" />
272
- <circle class="node-dot" cx="100" cy="83" r="4" />
273
- <circle class="node-dot" cx="60" cy="106" r="4" />
274
- <circle class="node-dot" cx="20" cy="83" r="4" />
275
- <circle class="node-dot" cx="20" cy="37" r="4" />
276
-
277
- <!-- Center node -->
278
- <circle class="node-center" cx="60" cy="60" r="8" />
279
- </svg>
280
-
281
- <h1>Your app is running</h1>
282
- <p class="tagline">Server is live and ready to accept requests</p>
283
- <div class="status">
284
- <span class="status-dot"></span>
285
- All systems operational
286
- </div>
287
- </div>
288
-
289
- <div class="powered">Powered by <a href="https://www.npmjs.com/package/4bnode" target="_blank" rel="noopener noreferrer"><span>4bnode</span></a></div>
290
-
291
- </body>
292
- </html>
package/app-1/src/db.js DELETED
@@ -1,13 +0,0 @@
1
- import mongoose from 'mongoose';
2
-
3
- const connectDB = async () => {
4
- try {
5
- const conn = await mongoose.connect(process.env.MONGO_URI);
6
- console.log(`MongoDB connected: ${conn.connection.host}`);
7
- } catch (err) {
8
- console.error('MongoDB connection error:', err.message);
9
- console.error('Check your MONGO_URI in .env and ensure MongoDB is running.');
10
- }
11
- };
12
-
13
- export default connectDB;