free-framework 4.6.1 → 4.6.4

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.
@@ -48,13 +48,6 @@ module.exports = function (name) {
48
48
  });
49
49
 
50
50
  // Wrap up
51
- console.log("\nšŸ“¦ Installing dependencies... (This may take a minute)");
52
- try {
53
- execSync("npm install", { cwd: targetDir, stdio: "inherit" });
54
- console.log("\nāœ… Enterprise Project Scaffolded Successfully!");
55
- console.log(`\nTo get started, run:\n cd ${name}\n free serve\n`);
56
- } catch (err) {
57
- console.log("\nāš ļø Scaffolding complete, but npm install failed. Please run 'npm install' manually.");
58
- console.log(`\nTo get started, run:\n cd ${name}\n npm install\n free serve\n`);
59
- }
51
+ console.log("\nāœ… Enterprise Project Scaffolded Successfully!");
52
+ console.log(`\nTo get started, run:\n cd ${name}\n npm install\n free serve\n`);
60
53
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "free-framework",
3
- "version": "4.6.1",
3
+ "version": "4.6.4",
4
4
  "description": "Professional Node.js engine for the .free language. Blazing-fast SSR, Islands Architecture, and built-in ORM.",
5
5
  "main": "index.js",
6
6
  "bin": {
package/runtime/server.js CHANGED
@@ -15,26 +15,38 @@ const { LRUCache } = require('lru-cache');
15
15
 
16
16
  class FreeServer {
17
17
  constructor() {
18
+ console.log(`[Free Engine] āš™ļø Runtime Core v4.6.3 initializing...`);
18
19
  this.app = new HyperExpress.Server();
20
+ this.viewsPath = process.env.VIEWS_PATH || nodePath.join(process.cwd(), 'views');
19
21
  this.namedMiddlewares = {};
20
22
  this.errorViews = {};
21
23
  this.plugins = [];
22
- this.viewsPath = process.env.VIEWS_PATH || nodePath.join(process.cwd(), 'views');
24
+
25
+ // Global Request Logger & Error Handler Initialization
26
+ this.app.set_error_handler((req, res, error) => {
27
+ console.error(`[Free Engine] šŸ”„ Global Uncaught Error:`, error);
28
+ this.handleError(req, res, error);
29
+ });
30
+
31
+ this.app.use((req, res, next) => {
32
+ console.log(`[Free Engine] šŸ“„ Request: ${req.method} ${req.url}`);
33
+ if (next) next();
34
+ });
23
35
 
24
36
  // Static Asset Serving Middleware
25
37
  const publicPath = nodePath.join(process.cwd(), 'public');
26
38
  this.app.use((req, res, next) => {
27
39
  const lookupPath = req.path.startsWith('/') ? req.path.substring(1) : req.path;
28
- if (!lookupPath) return next();
40
+ if (!lookupPath) return next ? next() : null;
29
41
 
30
42
  const fullPath = nodePath.join(publicPath, lookupPath);
31
43
  if (fs.existsSync(fullPath) && fs.statSync(fullPath).isFile()) {
32
- const content = fs.readFileSync(fullPath);
33
44
  const ext = nodePath.extname(fullPath);
34
- const mimes = { '.js': 'application/javascript', '.css': 'text/css', '.png': 'image/png' };
35
- return res.type(mimes[ext] || 'application/javascript').send(content);
45
+ const mimes = { '.js': 'application/javascript', '.css': 'text/css', '.png': 'image/png', '.jpg': 'image/jpeg', '.svg': 'image/svg+xml' };
46
+ res.type(mimes[ext] || 'text/plain');
47
+ return res.send(fs.readFileSync(fullPath));
36
48
  }
37
- next();
49
+ if (next) next();
38
50
  });
39
51
 
40
52
  this.app.get('/test-static', (req, res) => res.send('Static serving test'));
@@ -56,17 +68,17 @@ class FreeServer {
56
68
  this.app.use(securityMiddleware);
57
69
 
58
70
  this.app.use((req, res, next) => {
59
- const ip = req.ip || req.headers['x-forwarded-for'] || 'unknown';
71
+ const ip = req.ip || req.headers['x-forwarded-for'] || '127.0.0.1';
60
72
  const reqCount = this.rateLimits.get(ip) || 0;
61
73
 
62
74
  if (reqCount >= 5000) {
63
75
  res.status(429);
64
76
  res.setHeader('Retry-After', '60');
65
- return res.send('Too Many Requests - Under DDoS Protection');
77
+ return res.send('Too Many Requests');
66
78
  }
67
79
 
68
80
  this.rateLimits.set(ip, reqCount + 1);
69
- next();
81
+ if (next) next();
70
82
  });
71
83
  }
72
84
 
@@ -98,58 +110,7 @@ class FreeServer {
98
110
 
99
111
  await handler(req, res);
100
112
  } catch (e) {
101
- if (process.env.NODE_ENV === 'production') {
102
- console.error(`[Free Engine] Error ${method} ${path}:`, e);
103
- res.status(e.status || 500).header('Content-Type', 'text/html').send('Internal Error');
104
- } else {
105
- // Premium Debug Page (Ignition Style)
106
- const os = require('os');
107
- const pkg = require('../package.json');
108
- const debugTplPath = nodePath.join(__dirname, 'views/debug.html');
109
-
110
- if (fs.existsSync(debugTplPath)) {
111
- let html = fs.readFileSync(debugTplPath, 'utf8');
112
-
113
- // Error Details
114
- html = html.replace('{{errorName}}', e.name || 'Error');
115
- html = html.replace('{{errorMessage}}', e.message || 'No message provided');
116
-
117
- // Stack Trace with highlighting
118
- const stack = (e.stack || '').split('\n').map(line => {
119
- const isUserFile = line.includes(process.cwd()) && !line.includes('node_modules');
120
- return `<span class="stack-line ${isUserFile ? 'highlight' : ''}">${line.replace(/&/g, '&amp;').replace(/</g, '&lt;')}</span>`;
121
- }).join('');
122
- html = html.replace('{{stackTrace}}', stack);
123
-
124
- // Request Details
125
- let reqHtml = `<tr><th>Method</th><td class="val-text">${req.method}</td></tr>`;
126
- reqHtml += `<tr><th>URL</th><td class="val-text">${req.url}</td></tr>`;
127
- Object.keys(req.headers).forEach(k => {
128
- reqHtml += `<tr><th>Header: ${k}</th><td class="val-text">${req.headers[k]}</td></tr>`;
129
- });
130
- html = html.replace('{{requestDetails}}', reqHtml);
131
-
132
- // Env details (Mask secrets)
133
- let envHtml = '';
134
- Object.keys(process.env).forEach(k => {
135
- const isSecret = k.includes('KEY') || k.includes('SECRET') || k.includes('PASS');
136
- const val = isSecret ? '********' : process.env[k];
137
- envHtml += `<tr><th>${k}</th><td class="val-text">${val}</td></tr>`;
138
- });
139
- html = html.replace('{{envDetails}}', envHtml);
140
-
141
- // Engine Stats
142
- html = html.replace('{{version}}', pkg.version);
143
- html = html.replace('{{nodeVersion}}', process.version);
144
- html = html.replace('{{osInfo}}', `${os.type()} ${os.release()} (${os.arch()})`);
145
- const mem = process.memoryUsage();
146
- html = html.replace('{{memoryUsage}}', `${Math.round(mem.heapUsed / 1024 / 1024)}MB / ${Math.round(mem.heapTotal / 1024 / 1024)}MB`);
147
-
148
- res.status(500).header('Content-Type', 'text/html').send(html);
149
- } else {
150
- res.status(500).send(`<h1>${e.name || 'Error'}</h1><pre>${e.stack}</pre>`);
151
- }
152
- }
113
+ this.handleError(req, res, e);
153
114
  }
154
115
  };
155
116
 
@@ -157,6 +118,54 @@ class FreeServer {
157
118
  if (routeMethod === 'get') this.app.head(path, ...mwFns, routeHandler);
158
119
  }
159
120
 
121
+ handleError(req, res, e) {
122
+ if (process.env.NODE_ENV === 'production') {
123
+ res.status(500).header('Content-Type', 'text/html').send('Internal Error');
124
+ } else {
125
+ // Premium Debug Page (Ignition Style) logic moved here
126
+ const os = require('os');
127
+ const pkg = require('../package.json');
128
+ const debugTplPath = nodePath.join(__dirname, 'views/debug.html');
129
+
130
+ if (fs.existsSync(debugTplPath)) {
131
+ let html = fs.readFileSync(debugTplPath, 'utf8');
132
+ html = html.replace('{{errorName}}', e.name || 'Error');
133
+ html = html.replace('{{errorMessage}}', e.message || 'No message provided');
134
+
135
+ const stack = (e.stack || '').split('\n').map(line => {
136
+ const isUserFile = line.includes(process.cwd()) && !line.includes('node_modules');
137
+ return `<span class="stack-line ${isUserFile ? 'highlight' : ''}">${line.replace(/&/g, '&amp;').replace(/</g, '&lt;')}</span>`;
138
+ }).join('');
139
+ html = html.replace('{{stackTrace}}', stack);
140
+
141
+ let reqHtml = `<tr><th>Method</th><td class="val-text">${req.method}</td></tr>`;
142
+ reqHtml += `<tr><th>URL</th><td class="val-text">${req.url}</td></tr>`;
143
+ Object.keys(req.headers).forEach(k => {
144
+ reqHtml += `<tr><th>Header: ${k}</th><td class="val-text">${req.headers[k]}</td></tr>`;
145
+ });
146
+ html = html.replace('{{requestDetails}}', reqHtml);
147
+
148
+ let envHtml = '';
149
+ Object.keys(process.env).forEach(k => {
150
+ const isSecret = k.includes('KEY') || k.includes('SECRET') || k.includes('PASS');
151
+ const val = isSecret ? '********' : process.env[k];
152
+ envHtml += `<tr><th>${k}</th><td class="val-text">${val}</td></tr>`;
153
+ });
154
+ html = html.replace('{{envDetails}}', envHtml);
155
+
156
+ html = html.replace('{{version}}', pkg.version);
157
+ html = html.replace('{{nodeVersion}}', process.version);
158
+ html = html.replace('{{osInfo}}', `${os.type()} ${os.release()} (${os.arch()})`);
159
+ const mem = process.memoryUsage();
160
+ html = html.replace('{{memoryUsage}}', `${Math.round(mem.heapUsed / 1024 / 1024)}MB / ${Math.round(mem.heapTotal / 1024 / 1024)}MB`);
161
+
162
+ res.status(500).header('Content-Type', 'text/html').send(html);
163
+ } else {
164
+ res.status(500).send(`<h1>${e.name || 'Error'}</h1><pre>${e.stack}</pre>`);
165
+ }
166
+ }
167
+ }
168
+
160
169
  middleware(fn) { this.app.use(fn); }
161
170
  registerMiddleware(name, fn) { this.namedMiddlewares[name] = fn; }
162
171
  use(plugin) { plugin.install(this); this.plugins.push(plugin); }
@@ -171,7 +180,7 @@ class FreeServer {
171
180
 
172
181
  start(port = 3000) {
173
182
  this.app.get('/health', (req, res) => res.send('OK'));
174
- this.app.listen(port).then(() => {
183
+ this.app.listen(port, '0.0.0.0').then(() => {
175
184
  const blueUnderline = "\x1b[34m\x1b[4m";
176
185
  const reset = "\x1b[0m";
177
186
  console.log(`⚔ Free Engine Ignite: ${blueUnderline}http://localhost:${port}${reset}`);