free-framework 4.4.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.
Files changed (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +198 -0
  3. package/bin/free.js +118 -0
  4. package/cli/commands/build.js +124 -0
  5. package/cli/commands/deploy.js +143 -0
  6. package/cli/commands/devtools.js +210 -0
  7. package/cli/commands/doctor.js +72 -0
  8. package/cli/commands/install.js +28 -0
  9. package/cli/commands/make.js +74 -0
  10. package/cli/commands/migrate.js +67 -0
  11. package/cli/commands/new.js +54 -0
  12. package/cli/commands/serve.js +73 -0
  13. package/cli/commands/test.js +57 -0
  14. package/compiler/analyzer.js +102 -0
  15. package/compiler/generator.js +386 -0
  16. package/compiler/lexer.js +166 -0
  17. package/compiler/parser.js +410 -0
  18. package/database/model.js +6 -0
  19. package/database/orm.js +379 -0
  20. package/database/query-builder.js +179 -0
  21. package/index.js +51 -0
  22. package/package.json +80 -0
  23. package/plugins/auth.js +212 -0
  24. package/plugins/cache.js +85 -0
  25. package/plugins/chat.js +32 -0
  26. package/plugins/mail.js +53 -0
  27. package/plugins/metrics.js +126 -0
  28. package/plugins/payments.js +59 -0
  29. package/plugins/queue.js +139 -0
  30. package/plugins/search.js +51 -0
  31. package/plugins/storage.js +123 -0
  32. package/plugins/upload.js +62 -0
  33. package/router/router.js +57 -0
  34. package/runtime/app.js +14 -0
  35. package/runtime/client.js +254 -0
  36. package/runtime/cluster.js +35 -0
  37. package/runtime/edge.js +62 -0
  38. package/runtime/middleware/maintenance.js +54 -0
  39. package/runtime/middleware/security.js +30 -0
  40. package/runtime/server.js +130 -0
  41. package/runtime/validator.js +102 -0
  42. package/runtime/views/error.free +104 -0
  43. package/runtime/views/maintenance.free +0 -0
  44. package/template-engine/renderer.js +24 -0
  45. package/templates/app-template/.env +23 -0
  46. package/templates/app-template/app/Exceptions/Handler.js +65 -0
  47. package/templates/app-template/app/Http/Controllers/AuthController.free +91 -0
  48. package/templates/app-template/app/Http/Middleware/AuthGuard.js +46 -0
  49. package/templates/app-template/app/Services/Storage.js +75 -0
  50. package/templates/app-template/app/Services/Validator.js +91 -0
  51. package/templates/app-template/app/controllers/AuthController.free +42 -0
  52. package/templates/app-template/app/middleware/auth.js +25 -0
  53. package/templates/app-template/app/models/User.free +32 -0
  54. package/templates/app-template/app/routes.free +12 -0
  55. package/templates/app-template/app/styles.css +23 -0
  56. package/templates/app-template/app/views/counter.free +23 -0
  57. package/templates/app-template/app/views/header.free +13 -0
  58. package/templates/app-template/config/app.js +32 -0
  59. package/templates/app-template/config/auth.js +39 -0
  60. package/templates/app-template/config/database.js +54 -0
  61. package/templates/app-template/package.json +28 -0
  62. package/templates/app-template/resources/css/app.css +11 -0
  63. package/templates/app-template/resources/views/dashboard.free +25 -0
  64. package/templates/app-template/resources/views/home.free +26 -0
  65. package/templates/app-template/routes/api.free +22 -0
  66. package/templates/app-template/routes/web.free +25 -0
  67. package/templates/app-template/tailwind.config.js +21 -0
  68. package/templates/app-template/views/about.ejs +47 -0
  69. package/templates/app-template/views/home.ejs +52 -0
  70. package/templates/auth/login.html +144 -0
  71. package/templates/auth/register.html +146 -0
  72. package/utils/logger.js +20 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Dev Omar Tolba
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,198 @@
1
+ # Free Framework
2
+
3
+ > The blazing-fast, full-stack web framework with its own `.free` language syntax.
4
+ > Build modern production apps in a fraction of the time — with **zero boilerplate**.
5
+
6
+ [![NPM Version](https://img.shields.io/npm/v/free-framework.svg)](https://www.npmjs.com/package/free-framework)
7
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
8
+ [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18-green.svg)](https://nodejs.org)
9
+
10
+ ---
11
+
12
+ ## ⚔ Why Free Framework?
13
+
14
+ | Feature | Free | Next.js | Laravel |
15
+ |---|---|---|---|
16
+ | Custom DSL Syntax | āœ… `.free` | āŒ JSX | āŒ Blade |
17
+ | Performance Engine | āœ… uWebSockets | āš ļø Node HTTP | āš ļø PHP-FPM |
18
+ | Built-in ORM | āœ… Yes | āŒ No | āœ… Eloquent |
19
+ | Server Actions | āœ… `action {}` | āœ… Yes | āŒ No |
20
+ | Real-Time Sockets | āœ… Built-in | āŒ Manual | āŒ Manual |
21
+ | Edge Runtime | āœ… Yes | āœ… Yes | āŒ No |
22
+ | Islands Architecture | āœ… Native | āš ļø Extra | āŒ No |
23
+ | CLI DevTools | āœ… `free devtools` | āŒ No | āš ļø Artisan |
24
+
25
+ ---
26
+
27
+ ## šŸš€ Quick Start
28
+
29
+ ```bash
30
+ npx free-framework new my-app
31
+ cd my-app
32
+ free serve
33
+ ```
34
+
35
+ ---
36
+
37
+ ## 🧩 The `.free` Syntax
38
+
39
+ **Routing:**
40
+ ```
41
+ route GET "/" {
42
+ view "Home"
43
+ }
44
+
45
+ route GET "/dashboard" {
46
+ middleware auth
47
+ view "Dashboard"
48
+ }
49
+ ```
50
+
51
+ **Components with Reactive State:**
52
+ ```
53
+ component Counter {
54
+ state count = 0
55
+
56
+ button {
57
+ text "Clicked {count} times!"
58
+ on-click { count++ }
59
+ }
60
+ }
61
+ ```
62
+
63
+ **Server Actions (no API routes needed):**
64
+ ```
65
+ action createPost {
66
+ const post = await Post.create({ title: body.title, content: body.content });
67
+ return post;
68
+ }
69
+ ```
70
+
71
+ **Database Models:**
72
+ ```
73
+ model Post {
74
+ title string
75
+ content string
76
+ likes number
77
+ }
78
+ ```
79
+
80
+ **Authentication:**
81
+ ```
82
+ auth {
83
+ login "/login"
84
+ register "/register"
85
+ }
86
+ ```
87
+
88
+ **File Uploads:**
89
+ ```
90
+ upload avatar {
91
+ path "public/uploads"
92
+ maxSize "10mb"
93
+ }
94
+ ```
95
+
96
+ **Error Pages:**
97
+ ```
98
+ error 404 {
99
+ view "NotFound"
100
+ }
101
+ ```
102
+
103
+ ---
104
+
105
+ ## šŸ› ļø CLI Commands
106
+
107
+ | Command | Description |
108
+ |---|---|
109
+ | `free new <name>` | Create a new Free project |
110
+ | `free serve` | Start the development server |
111
+ | `free build` | Build for production (minified) |
112
+ | `free devtools` | Launch the DevTools Dashboard |
113
+ | `free test` | Run the test suite with Vitest |
114
+ | `free install <pkg>` | Install ecosystem plugins |
115
+ | `free make:model <name>` | Scaffold a new model |
116
+
117
+ ---
118
+
119
+ ## šŸ—ļø Architecture
120
+
121
+ ```
122
+ my-app/
123
+ ā”œā”€ā”€ app/
124
+ │ ā”œā”€ā”€ routes.free # Route definitions
125
+ │ ā”œā”€ā”€ config.free # Auth, Uploads, Error pages
126
+ │ ā”œā”€ā”€ models.free # ORM Models
127
+ │ ā”œā”€ā”€ actions.free # Server Actions
128
+ │ └── *.free # Pages & Components
129
+ ā”œā”€ā”€ public/ # Static assets
130
+ ā”œā”€ā”€ views/ # EJS fallback views
131
+ ā”œā”€ā”€ .env # Environment config
132
+ └── .free/ # Compiled output
133
+ └── app.js
134
+ ```
135
+
136
+ ---
137
+
138
+ ## ⚔ Performance
139
+
140
+ Powered by **HyperExpress (uWebSockets.js)** — the fastest HTTP/WebSocket server for Node.js:
141
+
142
+ - **Multi-core clustering** via built-in `ClusterManager`
143
+ - **LRU page cache** for instant SSR delivery
144
+ - **Zero-copy streaming** for file uploads
145
+ - **Native pub/sub** WebSocket rooms
146
+ - **Minified HTML/CSS/JS** output at build time
147
+
148
+ ---
149
+
150
+ ## šŸ”Œ Built-in Plugins
151
+
152
+ ```js
153
+ const { AuthPlugin, UploadPlugin, ChatPlugin } = require('free-framework');
154
+
155
+ server.use(AuthPlugin({ login: '/login', register: '/register' }));
156
+ server.use(UploadPlugin('avatar', { path: 'uploads', maxSize: '10mb' }));
157
+ server.use(ChatPlugin());
158
+ ```
159
+
160
+ ---
161
+
162
+ ## šŸ”’ Security Built-in
163
+
164
+ - Zero-config **security headers** (CSP, X-Frame-Options, HSTS)
165
+ - **DDoS & Rate limiting** (1000 req/min per IP by default)
166
+ - **CSRF token injection** on every page
167
+ - **bcrypt** password hashing in `AuthPlugin`
168
+ - **XSS-safe** template interpolation (auto-escaped)
169
+
170
+ ---
171
+
172
+ ## 🌐 Edge Runtime
173
+
174
+ Deploy anywhere — Cloudflare Workers, Bun, or standard Node.js:
175
+
176
+ ```js
177
+ const { EdgeRuntime } = require('free-framework');
178
+ const edge = new EdgeRuntime(myFreeApp);
179
+
180
+ // Cloudflare Workers / Bun compatible
181
+ export default { fetch: edge.fetch.bind(edge) };
182
+ ```
183
+
184
+ ---
185
+
186
+ ## šŸ“¦ Ecosystem
187
+
188
+ ```bash
189
+ free install free-auth
190
+ free install free-mail
191
+ free install free-payments
192
+ ```
193
+
194
+ ---
195
+
196
+ ## License
197
+
198
+ MIT Ā© [Dev Omar Tolba](https://github.com/dev-omartolba)
package/bin/free.js ADDED
@@ -0,0 +1,118 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * bin/free.js
5
+ * CLI entry point for the Free framework.
6
+ */
7
+
8
+ const { program } = require("commander");
9
+ const path = require("path");
10
+
11
+ // Load Environment variables globally
12
+ require('dotenv').config();
13
+
14
+ program
15
+ .version("1.0.0")
16
+ .description("Free Framework CLI");
17
+
18
+ program
19
+ .command("new <name>")
20
+ .description("Create a new Free project")
21
+ .action((name) => {
22
+ require("../cli/commands/new")(name);
23
+ });
24
+
25
+ program
26
+ .command("serve")
27
+ .description("Start the development server")
28
+ .option("-p, --port <port>", "Port to run on", "3000")
29
+ .option("--cluster", "Run in Enterprise Cluster Mode")
30
+ .action((options) => {
31
+ require("../cli/commands/serve")(options);
32
+ });
33
+
34
+ program
35
+ .command("build")
36
+ .description("Build the project for production")
37
+ .action(() => {
38
+ require("../cli/commands/build")();
39
+ });
40
+
41
+ program
42
+ .command("make:model <name>")
43
+ .description("Scaffold a new model")
44
+ .action((name) => { require("../cli/commands/make").model(name); });
45
+
46
+ program
47
+ .command("make:controller <name>")
48
+ .description("Scaffold route file for a controller")
49
+ .action((name) => { require("../cli/commands/make").controller(name); });
50
+
51
+ program
52
+ .command("make:page <name>")
53
+ .description("Scaffold a new .free page")
54
+ .action((name) => { require("../cli/commands/make").page(name); });
55
+
56
+ program
57
+ .command("make:component <name>")
58
+ .description("Scaffold a new .free component")
59
+ .action((name) => { require("../cli/commands/make").component(name); });
60
+
61
+ program
62
+ .command("make:middleware <name>")
63
+ .description("Scaffold a new middleware file")
64
+ .action((name) => { require("../cli/commands/make").middleware(name); });
65
+
66
+ program
67
+ .command("make:plugin <name>")
68
+ .description("Scaffold a new plugin file")
69
+ .action((name) => { require("../cli/commands/make").plugin(name); });
70
+
71
+ program
72
+ .command("make:migration <name>")
73
+ .description("Scaffold a new database migration")
74
+ .action((name) => { require("../cli/commands/make").migration(name); });
75
+
76
+ program
77
+ .command("migrate")
78
+ .description("Run pending database migrations")
79
+ .action(() => {
80
+ require("../cli/commands/migrate")();
81
+ });
82
+
83
+ program
84
+ .command("devtools")
85
+ .description("Open Free DevTools Dashboard")
86
+ .action(() => {
87
+ require("../cli/commands/devtools")();
88
+ });
89
+
90
+ program
91
+ .command("test")
92
+ .description("Run Vitest Testing Suite")
93
+ .action(() => {
94
+ require("../cli/commands/test")();
95
+ });
96
+
97
+ program
98
+ .command("install [packages...]")
99
+ .description("Install ecosystem NPM plugins")
100
+ .action((packages) => {
101
+ require("../cli/commands/install")(packages);
102
+ });
103
+
104
+ program
105
+ .command("deploy")
106
+ .description("Generate Docker + PM2 deployment files")
107
+ .action(() => {
108
+ require("../cli/commands/deploy")();
109
+ });
110
+
111
+ program
112
+ .command("doctor")
113
+ .description("Run project health diagnostics")
114
+ .action(() => {
115
+ require("../cli/commands/doctor")();
116
+ });
117
+
118
+ program.parse(process.argv);
@@ -0,0 +1,124 @@
1
+ /**
2
+ * cli/commands/build.js
3
+ * Implementation of 'free build' command.
4
+ */
5
+
6
+ const fs = require("fs-extra");
7
+ const path = require("path");
8
+ const { tokenize } = require("../../compiler/lexer");
9
+ const { parse } = require("../../compiler/parser");
10
+ const { generate } = require("../../compiler/generator");
11
+ const { analyze, printAnalysis } = require("../../compiler/analyzer");
12
+
13
+ module.exports = function () {
14
+ const baseDir = process.cwd();
15
+ const outputDir = path.join(baseDir, ".free");
16
+
17
+ if (!fs.existsSync(path.join(baseDir, "app"))) {
18
+ console.error("Error: 'app' directory not found. Are you in a Free Enterprise project?");
19
+ process.exit(1);
20
+ }
21
+
22
+ if (!fs.existsSync(outputDir)) {
23
+ fs.mkdirSync(outputDir);
24
+ }
25
+
26
+ console.log("šŸ”Ø Building Enterprise Project...");
27
+
28
+ const freeFiles = [];
29
+ function scanDir(dir) {
30
+ if (!fs.existsSync(dir)) return;
31
+ const files = fs.readdirSync(dir);
32
+ files.forEach(file => {
33
+ const filePath = path.join(dir, file);
34
+ if (fs.statSync(filePath).isDirectory()) {
35
+ scanDir(filePath);
36
+ } else if (file.endsWith(".free")) {
37
+ freeFiles.push(filePath);
38
+ }
39
+ });
40
+ }
41
+
42
+ // Scan all enterprise directories for .free files
43
+ scanDir(path.join(baseDir, "app"));
44
+ scanDir(path.join(baseDir, "routes"));
45
+ scanDir(path.join(baseDir, "resources", "views"));
46
+ let combinedAST = [];
47
+
48
+ console.log(`šŸ” Found ${freeFiles.length} files to process.`);
49
+ freeFiles.forEach(filePath => {
50
+ const file = path.basename(filePath);
51
+ console.log(` šŸ“„ Processing ${file}...`);
52
+ const code = fs.readFileSync(filePath, "utf-8");
53
+
54
+ try {
55
+ const tokens = tokenize(code, file);
56
+ const ast = parse(tokens, file, code);
57
+ console.log(` āœ… Parsed ${ast.length} nodes from ${file}`);
58
+ combinedAST = combinedAST.concat(ast);
59
+ } catch (err) {
60
+ if (err.name === 'FreeSyntaxError') {
61
+ console.error(err.toString());
62
+ } else {
63
+ console.error(`Error in ${filePath}: ${err.message}`);
64
+ }
65
+ process.exit(1);
66
+ }
67
+ });
68
+
69
+ // ── Static Analysis ──────────────────────────────────────────────────────
70
+ console.log("šŸ” Running static analysis...");
71
+ const analysis = analyze(combinedAST, 'app/');
72
+ printAnalysis(analysis, 'app/');
73
+ if (!analysis.clean) {
74
+ console.error("āŒ Build aborted due to errors.");
75
+ process.exit(1);
76
+ }
77
+
78
+ const jsCode = generate(combinedAST);
79
+ const outputPath = path.join(outputDir, "app.js");
80
+
81
+ fs.writeFileSync(outputPath, jsCode);
82
+
83
+ // Bundle client runtime
84
+ console.log("šŸ“¦ Bundling client assets...");
85
+ const { buildSync } = require("esbuild");
86
+
87
+ try {
88
+ const publicDir = path.join(process.cwd(), "public");
89
+ fs.ensureDirSync(publicDir);
90
+
91
+ buildSync({
92
+ entryPoints: [path.join(__dirname, "../../runtime/client.js")],
93
+ bundle: true,
94
+ minify: true,
95
+ outfile: path.join(publicDir, "free-runtime.js"),
96
+ });
97
+ console.log("āœ… Client runtime bundled to public/free-runtime.js");
98
+ } catch (err) {
99
+ console.error("Bundling failed:", err.message || err);
100
+ }
101
+
102
+ // ── CSS Build (Tailwind) ──────────────────────────────────────────────────
103
+ console.log("šŸŽØ Compiling Tailwind CSS...");
104
+ const { execSync } = require("child_process");
105
+ try {
106
+ const publicCssDir = path.join(process.cwd(), "public/css");
107
+ fs.ensureDirSync(publicCssDir);
108
+
109
+ let tailwindInput = "./resources/css/app.css";
110
+ // Fallback for older projects
111
+ if (!fs.existsSync(path.join(process.cwd(), "resources/css/app.css"))) {
112
+ if (fs.existsSync(path.join(process.cwd(), "app/styles.css"))) {
113
+ tailwindInput = "./app/styles.css";
114
+ }
115
+ }
116
+
117
+ execSync(`npx tailwindcss -i ${tailwindInput} -o ./public/css/app.css --minify`, { stdio: "inherit" });
118
+ console.log("āœ… Tailwind CSS compiled to public/css/app.css");
119
+ } catch (err) {
120
+ console.error("Tailwind compilation failed:", err);
121
+ }
122
+
123
+ console.log(`āœ… Build complete! Compiled to ${outputPath}`);
124
+ };
@@ -0,0 +1,143 @@
1
+ /**
2
+ * cli/commands/deploy.js
3
+ * Free Framework Deployment Generator.
4
+ * Generates: Dockerfile, docker-compose.yml, .dockerignore, deploy.sh
5
+ */
6
+
7
+ const fs = require("fs-extra");
8
+ const path = require("path");
9
+
10
+ module.exports = function deploy(options = {}) {
11
+ const cwd = process.cwd();
12
+ const appName = require(path.join(cwd, "package.json")).name || "free-app";
13
+ const port = process.env.PORT || 3000;
14
+
15
+ console.log(`\nšŸš€ Generating deployment files for "${appName}"...\n`);
16
+
17
+ // ── Dockerfile ────────────────────────────────────────────────────────────
18
+ fs.writeFileSync(path.join(cwd, "Dockerfile"), `# Free Framework — Production Dockerfile
19
+ FROM node:20-alpine AS base
20
+ WORKDIR /app
21
+
22
+ # Install dependencies
23
+ COPY package*.json ./
24
+ RUN npm ci --only=production
25
+
26
+ # Copy source
27
+ COPY . .
28
+
29
+ # Build
30
+ RUN node bin/free.js build 2>/dev/null || true
31
+
32
+ EXPOSE ${port}
33
+
34
+ # Use clustered production start
35
+ CMD ["node", ".free/app.js"]
36
+ `);
37
+
38
+ // ── docker-compose.yml ────────────────────────────────────────────────────
39
+ fs.writeFileSync(path.join(cwd, "docker-compose.yml"), `version: "3.9"
40
+
41
+ services:
42
+ app:
43
+ build: .
44
+ container_name: ${appName}
45
+ restart: unless-stopped
46
+ ports:
47
+ - "${port}:${port}"
48
+ environment:
49
+ NODE_ENV: production
50
+ PORT: ${port}
51
+ # Add your .env values here or use --env-file .env
52
+ volumes:
53
+ - ./storage:/app/storage # persist file uploads
54
+ - ./database.sqlite:/app/database.sqlite # persist SQLite DB
55
+
56
+ # Uncomment for Redis cache support
57
+ # redis:
58
+ # image: redis:7-alpine
59
+ # restart: unless-stopped
60
+ # ports:
61
+ # - "6379:6379"
62
+
63
+ # Uncomment for PostgreSQL support
64
+ # postgres:
65
+ # image: postgres:16-alpine
66
+ # restart: unless-stopped
67
+ # environment:
68
+ # POSTGRES_DB: free_db
69
+ # POSTGRES_USER: postgres
70
+ # POSTGRES_PASSWORD: changeme
71
+ # ports:
72
+ # - "5432:5432"
73
+ # volumes:
74
+ # - pgdata:/var/lib/postgresql/data
75
+
76
+ # volumes:
77
+ # pgdata:
78
+ `);
79
+
80
+ // ── .dockerignore ─────────────────────────────────────────────────────────
81
+ fs.writeFileSync(path.join(cwd, ".dockerignore"), `node_modules
82
+ .free
83
+ *.log
84
+ .env
85
+ .git
86
+ coverage
87
+ demo-app
88
+ free-social-app
89
+ `);
90
+
91
+ // ── deploy.sh (VPS quick deploy) ──────────────────────────────────────────
92
+ fs.writeFileSync(path.join(cwd, "deploy.sh"), `#!/bin/bash
93
+ # Quick VPS deployment script for ${appName}
94
+ set -e
95
+
96
+ echo "šŸ“¦ Pulling latest changes..."
97
+ git pull origin main
98
+
99
+ echo "šŸ“„ Installing dependencies..."
100
+ npm ci --only=production
101
+
102
+ echo "šŸ”Ø Building..."
103
+ node bin/free.js build
104
+
105
+ echo "šŸš€ Restarting with PM2..."
106
+ pm2 restart ${appName} || pm2 start .free/app.js --name ${appName} --instances max
107
+
108
+ echo "āœ… Deployed successfully!"
109
+ `);
110
+ fs.chmodSync(path.join(cwd, "deploy.sh"), "755");
111
+
112
+ // ── PM2 ecosystem config ──────────────────────────────────────────────────
113
+ fs.writeFileSync(path.join(cwd, "ecosystem.config.js"), `// PM2 Ecosystem Config for ${appName}
114
+ module.exports = {
115
+ apps: [{
116
+ name: "${appName}",
117
+ script: ".free/app.js",
118
+ instances: "max", // Use all CPU cores
119
+ exec_mode: "cluster",
120
+ env_production: {
121
+ NODE_ENV: "production",
122
+ PORT: ${port},
123
+ },
124
+ max_memory_restart: "500M",
125
+ error_file: "logs/err.log",
126
+ out_file: "logs/out.log",
127
+ }],
128
+ };
129
+ `);
130
+
131
+ console.log("āœ… Deployment files generated:");
132
+ console.log(" šŸ“„ Dockerfile");
133
+ console.log(" šŸ“„ docker-compose.yml");
134
+ console.log(" šŸ“„ .dockerignore");
135
+ console.log(" šŸ“„ deploy.sh");
136
+ console.log(" šŸ“„ ecosystem.config.js (PM2)\n");
137
+ console.log("🐳 Docker:");
138
+ console.log(" docker build -t " + appName + " .");
139
+ console.log(" docker-compose up -d\n");
140
+ console.log("šŸ–„ļø VPS (with PM2):");
141
+ console.log(" npm install -g pm2");
142
+ console.log(" bash deploy.sh\n");
143
+ };