voltjs-framework 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.
Files changed (60) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1265 -0
  3. package/bin/volt.js +139 -0
  4. package/package.json +56 -0
  5. package/src/api/graphql.js +399 -0
  6. package/src/api/rest.js +204 -0
  7. package/src/api/websocket.js +285 -0
  8. package/src/cli/build.js +111 -0
  9. package/src/cli/create.js +371 -0
  10. package/src/cli/db.js +106 -0
  11. package/src/cli/dev.js +114 -0
  12. package/src/cli/generate.js +278 -0
  13. package/src/cli/lint.js +172 -0
  14. package/src/cli/routes.js +118 -0
  15. package/src/cli/start.js +42 -0
  16. package/src/cli/test.js +138 -0
  17. package/src/core/app.js +701 -0
  18. package/src/core/config.js +232 -0
  19. package/src/core/middleware.js +133 -0
  20. package/src/core/plugins.js +88 -0
  21. package/src/core/react-renderer.js +244 -0
  22. package/src/core/renderer.js +337 -0
  23. package/src/core/router.js +183 -0
  24. package/src/database/index.js +461 -0
  25. package/src/database/migration.js +192 -0
  26. package/src/database/model.js +285 -0
  27. package/src/database/query.js +394 -0
  28. package/src/database/seeder.js +89 -0
  29. package/src/index.js +156 -0
  30. package/src/security/auth.js +425 -0
  31. package/src/security/cors.js +80 -0
  32. package/src/security/csrf.js +125 -0
  33. package/src/security/encryption.js +110 -0
  34. package/src/security/helmet.js +103 -0
  35. package/src/security/index.js +75 -0
  36. package/src/security/rateLimit.js +119 -0
  37. package/src/security/sanitizer.js +113 -0
  38. package/src/security/xss.js +110 -0
  39. package/src/ui/component.js +224 -0
  40. package/src/ui/reactive.js +503 -0
  41. package/src/ui/template.js +448 -0
  42. package/src/utils/cache.js +216 -0
  43. package/src/utils/collection.js +772 -0
  44. package/src/utils/cron.js +213 -0
  45. package/src/utils/date.js +223 -0
  46. package/src/utils/events.js +181 -0
  47. package/src/utils/excel.js +482 -0
  48. package/src/utils/form.js +547 -0
  49. package/src/utils/hash.js +121 -0
  50. package/src/utils/http.js +461 -0
  51. package/src/utils/logger.js +186 -0
  52. package/src/utils/mail.js +347 -0
  53. package/src/utils/paginator.js +179 -0
  54. package/src/utils/pdf.js +417 -0
  55. package/src/utils/queue.js +199 -0
  56. package/src/utils/schema.js +985 -0
  57. package/src/utils/sms.js +243 -0
  58. package/src/utils/storage.js +348 -0
  59. package/src/utils/string.js +236 -0
  60. package/src/utils/validation.js +318 -0
@@ -0,0 +1,278 @@
1
+ /**
2
+ * VoltJS CLI — `volt generate <type> <name>`
3
+ * Generate pages, API routes, components, models, middleware, migrations.
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+
11
+ const c = {
12
+ reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m',
13
+ red: '\x1b[31m', green: '\x1b[32m', cyan: '\x1b[36m',
14
+ };
15
+
16
+ const generators = {
17
+ page(name, cwd) {
18
+ const filePath = path.join(cwd, 'pages', `${name}.js`);
19
+ const content = `/**
20
+ * Page: /${name}
21
+ * Auto-discovered by VoltJS file-based routing.
22
+ */
23
+
24
+ module.exports = {
25
+ // GET /${name}
26
+ async get(req, res) {
27
+ res.render('${name}', {
28
+ title: '${capitalize(name)}',
29
+ });
30
+ },
31
+
32
+ // POST /${name}
33
+ // async post(req, res) {
34
+ // res.json({ message: '${name} created' });
35
+ // },
36
+ };
37
+ `;
38
+ writeFile(filePath, content);
39
+
40
+ // Also create the view
41
+ const viewPath = path.join(cwd, 'views', `${name}.volt`);
42
+ if (!fs.existsSync(viewPath)) {
43
+ const viewContent = `{#layout layouts/main}
44
+
45
+ {#block content}
46
+ <div style="padding: 2rem; max-width: 800px; margin: 0 auto;">
47
+ <h1>{{ title }}</h1>
48
+ <p>This is the ${name} page.</p>
49
+ </div>
50
+ {/block}
51
+ `;
52
+ writeFile(viewPath, viewContent);
53
+ }
54
+ },
55
+
56
+ api(name, cwd) {
57
+ const filePath = path.join(cwd, 'api', `${name}.js`);
58
+ const modelName = capitalize(singularize(name));
59
+ const content = `/**
60
+ * API: /api/${name}
61
+ * Auto-discovered by VoltJS.
62
+ */
63
+
64
+ module.exports = {
65
+ // GET /api/${name}
66
+ async get(req, res) {
67
+ // const items = await ${modelName}.all();
68
+ res.json({ data: [], message: 'List ${name}' });
69
+ },
70
+
71
+ // POST /api/${name}
72
+ async post(req, res) {
73
+ // const item = await ${modelName}.create(req.body);
74
+ res.json({ data: req.body, message: '${modelName} created' }, 201);
75
+ },
76
+
77
+ // GET /api/${name}/:id
78
+ async show(req, res) {
79
+ const { id } = req.params;
80
+ // const item = await ${modelName}.find(id);
81
+ res.json({ data: { id }, message: '${modelName} details' });
82
+ },
83
+
84
+ // PUT /api/${name}/:id
85
+ async update(req, res) {
86
+ const { id } = req.params;
87
+ // const item = await ${modelName}.updateById(id, req.body);
88
+ res.json({ data: { id, ...req.body }, message: '${modelName} updated' });
89
+ },
90
+
91
+ // DELETE /api/${name}/:id
92
+ async destroy(req, res) {
93
+ const { id } = req.params;
94
+ // await ${modelName}.deleteById(id);
95
+ res.json({ message: '${modelName} deleted' });
96
+ },
97
+ };
98
+ `;
99
+ writeFile(filePath, content);
100
+ },
101
+
102
+ component(name, cwd) {
103
+ const filePath = path.join(cwd, 'components', `${name}.js`);
104
+ const className = capitalize(name);
105
+ const content = `const { Component } = require('voltjs');
106
+
107
+ class ${className} extends Component {
108
+ setup() {
109
+ this.state = {};
110
+ }
111
+
112
+ render() {
113
+ return \`
114
+ <div class="${name.toLowerCase()}" data-component="${className}">
115
+ <h2>\${this.props.title || '${className}'}</h2>
116
+ \${this.children}
117
+ </div>
118
+ \`;
119
+ }
120
+ }
121
+
122
+ module.exports = ${className};
123
+ `;
124
+ writeFile(filePath, content);
125
+ },
126
+
127
+ model(name, cwd) {
128
+ const filePath = path.join(cwd, 'models', `${capitalize(name)}.js`);
129
+ const className = capitalize(name);
130
+ const tableName = name.toLowerCase() + 's';
131
+ const content = `const { Model } = require('voltjs');
132
+
133
+ class ${className} extends Model {
134
+ static table = '${tableName}';
135
+
136
+ static schema = {
137
+ name: { type: 'string', required: true, maxLength: 255 },
138
+ email: { type: 'string', required: true },
139
+ // Add more fields here
140
+ };
141
+
142
+ // Custom methods
143
+ fullName() {
144
+ return this.name;
145
+ }
146
+ }
147
+
148
+ module.exports = ${className};
149
+ `;
150
+ writeFile(filePath, content);
151
+ },
152
+
153
+ middleware(name, cwd) {
154
+ const filePath = path.join(cwd, 'middleware', `${name}.js`);
155
+ const content = `/**
156
+ * Middleware: ${name}
157
+ *
158
+ * Usage in app.js:
159
+ * const ${name} = require('./middleware/${name}');
160
+ * app.use(${name});
161
+ * // or on specific routes:
162
+ * app.get('/protected', ${name}, handler);
163
+ */
164
+
165
+ module.exports = function ${name}(req, res) {
166
+ // Your middleware logic here
167
+ // Return false to stop the request
168
+ // Return nothing (undefined) to continue to next middleware
169
+
170
+ console.log('[${name}]', req.method, req.url);
171
+ };
172
+ `;
173
+ writeFile(filePath, content);
174
+ },
175
+
176
+ migration(name, cwd) {
177
+ const timestamp = Date.now();
178
+ const filePath = path.join(cwd, 'database', 'migrations', `${timestamp}_${name}.js`);
179
+ const tableName = name.replace(/^create_/, '').replace(/_table$/, '');
180
+ const content = `/**
181
+ * Migration: ${name}
182
+ * Created: ${new Date().toISOString()}
183
+ */
184
+
185
+ module.exports = {
186
+ async up(db) {
187
+ await db.query(\`
188
+ CREATE TABLE IF NOT EXISTS ${tableName} (
189
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
190
+ name VARCHAR(255) NOT NULL,
191
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
192
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
193
+ )
194
+ \`);
195
+ },
196
+
197
+ async down(db) {
198
+ await db.query('DROP TABLE IF EXISTS ${tableName}');
199
+ },
200
+ };
201
+ `;
202
+ writeFile(filePath, content);
203
+ },
204
+
205
+ seeder(name, cwd) {
206
+ const filePath = path.join(cwd, 'database', 'seeders', `${name}.js`);
207
+ const content = `/**
208
+ * Seeder: ${name}
209
+ * Run: volt db:seed
210
+ */
211
+
212
+ module.exports = {
213
+ async run(db) {
214
+ // await db.query("INSERT INTO table_name (col) VALUES (?)", ['value']);
215
+ console.log('Seeder ${name} executed');
216
+ },
217
+ };
218
+ `;
219
+ writeFile(filePath, content);
220
+ },
221
+ };
222
+
223
+ module.exports = function generate(args) {
224
+ const type = args[0];
225
+ const name = args[1];
226
+
227
+ if (!type) {
228
+ console.log(`${c.bold}Usage:${c.reset} volt generate <type> <name>\n`);
229
+ console.log(`${c.bold}Types:${c.reset}`);
230
+ console.log(` ${c.cyan}page${c.reset} Generate a page with view`);
231
+ console.log(` ${c.cyan}api${c.reset} Generate an API route`);
232
+ console.log(` ${c.cyan}component${c.reset} Generate a component`);
233
+ console.log(` ${c.cyan}model${c.reset} Generate a database model`);
234
+ console.log(` ${c.cyan}middleware${c.reset} Generate middleware`);
235
+ console.log(` ${c.cyan}migration${c.reset} Generate a database migration`);
236
+ console.log(` ${c.cyan}seeder${c.reset} Generate a database seeder`);
237
+ process.exit(0);
238
+ }
239
+
240
+ if (!name) {
241
+ console.error(`${c.red}Error: Please specify a name.${c.reset}`);
242
+ console.log(` ${c.cyan}volt generate ${type} <name>${c.reset}`);
243
+ process.exit(1);
244
+ }
245
+
246
+ const generator = generators[type];
247
+ if (!generator) {
248
+ console.error(`${c.red}Error: Unknown generator type "${type}".${c.reset}`);
249
+ console.log(`Available: ${Object.keys(generators).join(', ')}`);
250
+ process.exit(1);
251
+ }
252
+
253
+ generator(name, process.cwd());
254
+ };
255
+
256
+ function writeFile(filePath, content) {
257
+ const dir = path.dirname(filePath);
258
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
259
+
260
+ if (fs.existsSync(filePath)) {
261
+ console.log(` ${c.yellow}⚠ Already exists:${c.reset} ${path.relative(process.cwd(), filePath)}`);
262
+ return;
263
+ }
264
+
265
+ fs.writeFileSync(filePath, content);
266
+ console.log(` ${c.green}✓ Created:${c.reset} ${path.relative(process.cwd(), filePath)}`);
267
+ }
268
+
269
+ function capitalize(str) {
270
+ return str.charAt(0).toUpperCase() + str.slice(1);
271
+ }
272
+
273
+ function singularize(str) {
274
+ if (str.endsWith('ies')) return str.slice(0, -3) + 'y';
275
+ if (str.endsWith('ses') || str.endsWith('xes')) return str.slice(0, -2);
276
+ if (str.endsWith('s') && !str.endsWith('ss')) return str.slice(0, -1);
277
+ return str;
278
+ }
@@ -0,0 +1,172 @@
1
+ /**
2
+ * VoltJS CLI — `volt lint`
3
+ * Basic linting for VoltJS projects.
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+
11
+ const c = {
12
+ reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m',
13
+ red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m', cyan: '\x1b[36m',
14
+ };
15
+
16
+ module.exports = function lint(args) {
17
+ const cwd = process.cwd();
18
+ console.log(`${c.cyan}${c.bold}⚡ VoltJS Lint${c.reset}\n`);
19
+
20
+ const issues = [];
21
+ const scannedFiles = [];
22
+ const dirs = ['pages', 'api', 'models', 'middleware', 'components'];
23
+
24
+ // Scan root JS files
25
+ for (const file of ['app.js', 'index.js', 'server.js']) {
26
+ const filePath = path.join(cwd, file);
27
+ if (fs.existsSync(filePath)) {
28
+ lintFile(filePath, issues, scannedFiles);
29
+ }
30
+ }
31
+
32
+ // Scan directories
33
+ for (const dir of dirs) {
34
+ const dirPath = path.join(cwd, dir);
35
+ if (fs.existsSync(dirPath)) {
36
+ scanAndLint(dirPath, issues, scannedFiles);
37
+ }
38
+ }
39
+
40
+ // Check config
41
+ checkConfig(cwd, issues);
42
+
43
+ // Report
44
+ if (issues.length === 0) {
45
+ console.log(` ${c.green}✓ No issues found!${c.reset} (${scannedFiles.length} files scanned)`);
46
+ } else {
47
+ const warnings = issues.filter(i => i.severity === 'warning');
48
+ const errors = issues.filter(i => i.severity === 'error');
49
+
50
+ for (const issue of issues) {
51
+ const icon = issue.severity === 'error' ? `${c.red}✗` : `${c.yellow}⚠`;
52
+ const relative = path.relative(cwd, issue.file);
53
+ console.log(` ${icon} ${relative}${issue.line ? `:${issue.line}` : ''}${c.reset} — ${issue.message}`);
54
+ }
55
+
56
+ console.log(`\n ${c.dim}${scannedFiles.length} files scanned${c.reset}`);
57
+ if (errors.length > 0) console.log(` ${c.red}${errors.length} error(s)${c.reset}`);
58
+ if (warnings.length > 0) console.log(` ${c.yellow}${warnings.length} warning(s)${c.reset}`);
59
+ }
60
+ };
61
+
62
+ function scanAndLint(dir, issues, scannedFiles) {
63
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
64
+ for (const entry of entries) {
65
+ const fullPath = path.join(dir, entry.name);
66
+ if (entry.isDirectory()) {
67
+ scanAndLint(fullPath, issues, scannedFiles);
68
+ } else if (entry.name.endsWith('.js')) {
69
+ lintFile(fullPath, issues, scannedFiles);
70
+ }
71
+ }
72
+ }
73
+
74
+ function lintFile(filePath, issues, scannedFiles) {
75
+ const content = fs.readFileSync(filePath, 'utf-8');
76
+ const lines = content.split('\n');
77
+ scannedFiles.push(filePath);
78
+
79
+ // Check for syntax errors
80
+ try {
81
+ new Function(content);
82
+ } catch (err) {
83
+ if (err instanceof SyntaxError) {
84
+ issues.push({
85
+ file: filePath,
86
+ line: null,
87
+ severity: 'error',
88
+ message: `Syntax error: ${err.message}`,
89
+ });
90
+ }
91
+ }
92
+
93
+ for (let i = 0; i < lines.length; i++) {
94
+ const line = lines[i];
95
+ const lineNum = i + 1;
96
+
97
+ // console.log in production code
98
+ if (line.match(/console\.(log|dir|table)\s*\(/) && !filePath.includes('test')) {
99
+ issues.push({
100
+ file: filePath,
101
+ line: lineNum,
102
+ severity: 'warning',
103
+ message: 'Consider removing console.log in production code',
104
+ });
105
+ }
106
+
107
+ // eval usage
108
+ if (line.match(/\beval\s*\(/)) {
109
+ issues.push({
110
+ file: filePath,
111
+ line: lineNum,
112
+ severity: 'error',
113
+ message: 'Avoid using eval() — security risk',
114
+ });
115
+ }
116
+
117
+ // Hardcoded secrets
118
+ if (line.match(/(password|secret|api_key|apikey|token)\s*[:=]\s*['"][^'"]{8,}['"]/i)) {
119
+ if (!line.includes('process.env') && !filePath.includes('.env')) {
120
+ issues.push({
121
+ file: filePath,
122
+ line: lineNum,
123
+ severity: 'error',
124
+ message: 'Possible hardcoded secret detected — use environment variables',
125
+ });
126
+ }
127
+ }
128
+
129
+ // Very long lines
130
+ if (line.length > 200) {
131
+ issues.push({
132
+ file: filePath,
133
+ line: lineNum,
134
+ severity: 'warning',
135
+ message: `Line too long (${line.length} chars)`,
136
+ });
137
+ }
138
+ }
139
+ }
140
+
141
+ function checkConfig(cwd, issues) {
142
+ // Missing .env
143
+ if (!fs.existsSync(path.join(cwd, '.env'))) {
144
+ issues.push({
145
+ file: path.join(cwd, '.env'),
146
+ severity: 'warning',
147
+ message: 'No .env file found — create one for environment variables',
148
+ });
149
+ }
150
+
151
+ // .env in .gitignore
152
+ const gitignore = path.join(cwd, '.gitignore');
153
+ if (fs.existsSync(gitignore)) {
154
+ const content = fs.readFileSync(gitignore, 'utf-8');
155
+ if (!content.includes('.env')) {
156
+ issues.push({
157
+ file: gitignore,
158
+ severity: 'error',
159
+ message: '.env is not in .gitignore — secrets may be committed',
160
+ });
161
+ }
162
+ }
163
+
164
+ // Missing volt.config.js
165
+ if (!fs.existsSync(path.join(cwd, 'volt.config.js'))) {
166
+ issues.push({
167
+ file: path.join(cwd, 'volt.config.js'),
168
+ severity: 'warning',
169
+ message: 'No volt.config.js — using defaults',
170
+ });
171
+ }
172
+ }
@@ -0,0 +1,118 @@
1
+ /**
2
+ * VoltJS CLI — `volt routes`
3
+ * Lists all registered routes in the application.
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const path = require('path');
9
+ const fs = require('fs');
10
+
11
+ const c = {
12
+ reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m',
13
+ red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m', cyan: '\x1b[36m',
14
+ magenta: '\x1b[35m',
15
+ };
16
+
17
+ const METHOD_COLORS = {
18
+ GET: c.green,
19
+ POST: c.cyan,
20
+ PUT: c.yellow,
21
+ PATCH: c.yellow,
22
+ DELETE: c.red,
23
+ };
24
+
25
+ module.exports = function routes(args) {
26
+ const cwd = process.cwd();
27
+
28
+ console.log(`${c.cyan}${c.bold}⚡ VoltJS Routes${c.reset}\n`);
29
+
30
+ const allRoutes = [];
31
+
32
+ // Scan pages directory
33
+ const pagesDir = path.join(cwd, 'pages');
34
+ if (fs.existsSync(pagesDir)) {
35
+ scanDir(pagesDir, pagesDir, '', allRoutes, 'page');
36
+ }
37
+
38
+ // Scan api directory
39
+ const apiDir = path.join(cwd, 'api');
40
+ if (fs.existsSync(apiDir)) {
41
+ scanDir(apiDir, apiDir, '/api', allRoutes, 'api');
42
+ }
43
+
44
+ // Try to load app and discover programmatic routes
45
+ try {
46
+ // We'll just display file-based routes since loading the app might start the server
47
+ } catch { }
48
+
49
+ if (allRoutes.length === 0) {
50
+ console.log(` ${c.dim}No routes found. Create files in pages/ or api/ directories.${c.reset}`);
51
+ return;
52
+ }
53
+
54
+ // Print table header
55
+ const methodWidth = 8;
56
+ const pathWidth = 40;
57
+ const sourceWidth = 30;
58
+
59
+ console.log(
60
+ ` ${c.bold}${'METHOD'.padEnd(methodWidth)}${'PATH'.padEnd(pathWidth)}${'SOURCE'.padEnd(sourceWidth)}${c.reset}`
61
+ );
62
+ console.log(` ${'─'.repeat(methodWidth + pathWidth + sourceWidth)}`);
63
+
64
+ for (const route of allRoutes) {
65
+ const methodColor = METHOD_COLORS[route.method] || c.dim;
66
+ console.log(
67
+ ` ${methodColor}${route.method.padEnd(methodWidth)}${c.reset}${route.path.padEnd(pathWidth)}${c.dim}${route.source.padEnd(sourceWidth)}${c.reset}`
68
+ );
69
+ }
70
+
71
+ console.log(`\n ${c.dim}Total: ${allRoutes.length} routes${c.reset}\n`);
72
+ };
73
+
74
+ function scanDir(baseDir, currentDir, prefix, routes, type) {
75
+ const entries = fs.readdirSync(currentDir, { withFileTypes: true });
76
+
77
+ for (const entry of entries) {
78
+ if (entry.isDirectory()) {
79
+ scanDir(baseDir, path.join(currentDir, entry.name), `${prefix}/${entry.name}`, routes, type);
80
+ } else if (entry.name.endsWith('.js')) {
81
+ const routeName = entry.name.replace('.js', '');
82
+ const routePath = routeName === 'index'
83
+ ? (prefix || '/')
84
+ : `${prefix}/${routeName}`;
85
+
86
+ const relativePath = path.relative(process.cwd(), path.join(currentDir, entry.name));
87
+
88
+ try {
89
+ const mod = require(path.join(currentDir, entry.name));
90
+ const methods = ['get', 'post', 'put', 'patch', 'delete'];
91
+
92
+ for (const method of methods) {
93
+ if (mod[method] || mod[method.toUpperCase()]) {
94
+ routes.push({
95
+ method: method.toUpperCase(),
96
+ path: routePath,
97
+ source: relativePath,
98
+ });
99
+ }
100
+ }
101
+
102
+ // If it exports show/update/destroy, add /:id routes
103
+ if (mod.show) {
104
+ routes.push({ method: 'GET', path: `${routePath}/:id`, source: relativePath });
105
+ }
106
+ if (mod.update) {
107
+ routes.push({ method: 'PUT', path: `${routePath}/:id`, source: relativePath });
108
+ }
109
+ if (mod.destroy) {
110
+ routes.push({ method: 'DELETE', path: `${routePath}/:id`, source: relativePath });
111
+ }
112
+ } catch {
113
+ // If we can't load the module, assume GET
114
+ routes.push({ method: 'GET', path: routePath, source: relativePath });
115
+ }
116
+ }
117
+ }
118
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * VoltJS CLI — `volt start`
3
+ * Starts the production server.
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+
11
+ const c = {
12
+ reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m',
13
+ red: '\x1b[31m', green: '\x1b[32m', cyan: '\x1b[36m',
14
+ };
15
+
16
+ module.exports = function start(args) {
17
+ const cwd = process.cwd();
18
+ const entry = findEntry(cwd);
19
+
20
+ if (!entry) {
21
+ console.error(`${c.red}Error: No app entry point found (app.js, index.js, or server.js).${c.reset}`);
22
+ process.exit(1);
23
+ }
24
+
25
+ console.log(`${c.cyan}${c.bold}⚡ VoltJS Production Server${c.reset}`);
26
+ console.log(`${c.dim}Starting ${path.basename(entry)}...${c.reset}\n`);
27
+
28
+ // Set production environment
29
+ process.env.NODE_ENV = process.env.NODE_ENV || 'production';
30
+
31
+ // Load the app
32
+ require(entry);
33
+ };
34
+
35
+ function findEntry(cwd) {
36
+ const candidates = ['app.js', 'index.js', 'server.js', 'src/app.js', 'src/index.js'];
37
+ for (const file of candidates) {
38
+ const fullPath = path.join(cwd, file);
39
+ if (fs.existsSync(fullPath)) return fullPath;
40
+ }
41
+ return null;
42
+ }