nitronjs 0.1.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 (87) hide show
  1. package/README.md +429 -0
  2. package/cli/create.js +260 -0
  3. package/cli/njs.js +164 -0
  4. package/lib/Auth/Manager.js +111 -0
  5. package/lib/Build/Manager.js +1232 -0
  6. package/lib/Console/Commands/BuildCommand.js +25 -0
  7. package/lib/Console/Commands/DevCommand.js +385 -0
  8. package/lib/Console/Commands/MakeCommand.js +110 -0
  9. package/lib/Console/Commands/MigrateCommand.js +98 -0
  10. package/lib/Console/Commands/MigrateFreshCommand.js +97 -0
  11. package/lib/Console/Commands/SeedCommand.js +92 -0
  12. package/lib/Console/Commands/StorageLinkCommand.js +31 -0
  13. package/lib/Console/Stubs/controller.js +19 -0
  14. package/lib/Console/Stubs/middleware.js +9 -0
  15. package/lib/Console/Stubs/migration.js +23 -0
  16. package/lib/Console/Stubs/model.js +7 -0
  17. package/lib/Console/Stubs/page-hydration.tsx +54 -0
  18. package/lib/Console/Stubs/seeder.js +9 -0
  19. package/lib/Console/Stubs/vendor.tsx +11 -0
  20. package/lib/Core/Config.js +86 -0
  21. package/lib/Core/Environment.js +21 -0
  22. package/lib/Core/Paths.js +188 -0
  23. package/lib/Database/Connection.js +61 -0
  24. package/lib/Database/DB.js +84 -0
  25. package/lib/Database/Drivers/MySQLDriver.js +234 -0
  26. package/lib/Database/Manager.js +162 -0
  27. package/lib/Database/Model.js +161 -0
  28. package/lib/Database/QueryBuilder.js +714 -0
  29. package/lib/Database/QueryValidation.js +62 -0
  30. package/lib/Database/Schema/Blueprint.js +126 -0
  31. package/lib/Database/Schema/Manager.js +116 -0
  32. package/lib/Date/DateTime.js +108 -0
  33. package/lib/Date/Locale.js +68 -0
  34. package/lib/Encryption/Manager.js +47 -0
  35. package/lib/Filesystem/Manager.js +49 -0
  36. package/lib/Hashing/Manager.js +25 -0
  37. package/lib/Http/Server.js +317 -0
  38. package/lib/Logging/Manager.js +153 -0
  39. package/lib/Mail/Manager.js +120 -0
  40. package/lib/Route/Loader.js +81 -0
  41. package/lib/Route/Manager.js +265 -0
  42. package/lib/Runtime/Entry.js +11 -0
  43. package/lib/Session/File.js +299 -0
  44. package/lib/Session/Manager.js +259 -0
  45. package/lib/Session/Memory.js +67 -0
  46. package/lib/Session/Session.js +196 -0
  47. package/lib/Support/Str.js +100 -0
  48. package/lib/Translation/Manager.js +49 -0
  49. package/lib/Validation/MimeTypes.js +39 -0
  50. package/lib/Validation/Validator.js +691 -0
  51. package/lib/View/Manager.js +544 -0
  52. package/lib/View/Templates/default/Home.tsx +262 -0
  53. package/lib/View/Templates/default/MainLayout.tsx +44 -0
  54. package/lib/View/Templates/errors/404.tsx +13 -0
  55. package/lib/View/Templates/errors/500.tsx +13 -0
  56. package/lib/View/Templates/errors/ErrorLayout.tsx +112 -0
  57. package/lib/View/Templates/messages/Maintenance.tsx +17 -0
  58. package/lib/View/Templates/messages/MessageLayout.tsx +136 -0
  59. package/lib/index.js +57 -0
  60. package/package.json +48 -0
  61. package/skeleton/.env.example +26 -0
  62. package/skeleton/app/Controllers/HomeController.js +9 -0
  63. package/skeleton/app/Kernel.js +11 -0
  64. package/skeleton/app/Middlewares/Authentication.js +9 -0
  65. package/skeleton/app/Middlewares/Guest.js +9 -0
  66. package/skeleton/app/Middlewares/VerifyCsrf.js +24 -0
  67. package/skeleton/app/Models/User.js +7 -0
  68. package/skeleton/config/app.js +4 -0
  69. package/skeleton/config/auth.js +16 -0
  70. package/skeleton/config/database.js +27 -0
  71. package/skeleton/config/hash.js +3 -0
  72. package/skeleton/config/server.js +28 -0
  73. package/skeleton/config/session.js +21 -0
  74. package/skeleton/database/migrations/2025_01_01_00_00_users.js +20 -0
  75. package/skeleton/database/seeders/UserSeeder.js +15 -0
  76. package/skeleton/globals.d.ts +1 -0
  77. package/skeleton/package.json +24 -0
  78. package/skeleton/public/.gitkeep +0 -0
  79. package/skeleton/resources/css/.gitkeep +0 -0
  80. package/skeleton/resources/langs/.gitkeep +0 -0
  81. package/skeleton/resources/views/Site/Home.tsx +66 -0
  82. package/skeleton/routes/web.js +4 -0
  83. package/skeleton/storage/app/private/.gitkeep +0 -0
  84. package/skeleton/storage/app/public/.gitkeep +0 -0
  85. package/skeleton/storage/framework/sessions/.gitkeep +0 -0
  86. package/skeleton/storage/logs/.gitkeep +0 -0
  87. package/skeleton/tsconfig.json +33 -0
package/README.md ADDED
@@ -0,0 +1,429 @@
1
+ # NitronJS
2
+
3
+ A modern and extensible Node.js MVC framework built on Fastify. NitronJS focuses on clean architecture, modular structure, and developer productivity, offering built-in routing, middleware, configuration management, CLI tooling, and native React integration for scalable full-stack applications.
4
+
5
+ ## Features
6
+
7
+ - **MVC Architecture** - Clean separation of concerns with Models, Views, and Controllers
8
+ - **React SSR** - Built-in React server-side rendering with TypeScript support
9
+ - **Fast & Lightweight** - Built on Fastify for high performance
10
+ - **CLI Tools** - Powerful command-line interface for scaffolding and development
11
+ - **Database ORM** - Intuitive query builder and model system for MySQL
12
+ - **Hot Reload** - Development mode with automatic reloading
13
+ - **Middleware System** - Flexible middleware pipeline with route-specific middleware
14
+ - **Session Management** - Built-in session support with multiple drivers
15
+ - **Security** - CSRF protection, authentication, and input validation
16
+ - **Modern Build System** - esbuild + PostCSS + Tailwind CSS integration
17
+
18
+ ## Installation
19
+
20
+ Create a new NitronJS project:
21
+
22
+ ```bash
23
+ npx nitronjs my-app
24
+ cd my-app
25
+ ```
26
+
27
+ Dependencies are installed automatically during project creation.
28
+
29
+ ## Quick Start
30
+
31
+ 1. **Configure your database** in `config/database.js`
32
+
33
+ 2. **Run migrations**:
34
+ ```bash
35
+ npx njs migrate --seed
36
+ ```
37
+
38
+ 3. **Start development server**:
39
+ ```bash
40
+ npm run dev
41
+ ```
42
+
43
+ Your application will be running at `http://localhost:3000`
44
+
45
+ ## CLI Commands
46
+
47
+ NitronJS comes with a powerful CLI tool (`njs`):
48
+
49
+ ### Development & Build
50
+ ```bash
51
+ njs dev # Start development server with hot reload
52
+ njs build # Build views for production
53
+ njs start # Start production server
54
+ ```
55
+
56
+ ### Database
57
+ ```bash
58
+ njs migrate # Run pending migrations
59
+ njs migrate:fresh # Drop all tables and re-run migrations
60
+ njs migrate:fresh --seed # Drop, migrate, and seed
61
+ njs seed # Run database seeders
62
+ ```
63
+
64
+ ### Code Generation
65
+ ```bash
66
+ njs make:controller <name> # Generate a new controller
67
+ njs make:model <name> # Generate a new model
68
+ njs make:middleware <name> # Generate a new middleware
69
+ njs make:migration <name> # Generate a new migration
70
+ njs make:seeder <name> # Generate a new seeder
71
+ ```
72
+
73
+ ### Utilities
74
+ ```bash
75
+ njs storage:link # Create symbolic link for storage
76
+ ```
77
+
78
+ ## Project Structure
79
+
80
+ ```
81
+ my-app/
82
+ ├── app/
83
+ │ ├── Controllers/ # Request handlers
84
+ │ ├── Middlewares/ # Custom middleware
85
+ │ └── Models/ # Database models
86
+ ├── config/ # Configuration files
87
+ │ ├── app.js
88
+ │ ├── database.js
89
+ │ └── server.js
90
+ ├── database/
91
+ │ ├── migrations/ # Database migrations
92
+ │ └── seeders/ # Database seeders
93
+ ├── public/ # Static assets
94
+ ├── resources/
95
+ │ ├── css/ # Stylesheets
96
+ │ └── views/ # React components (TSX)
97
+ ├── routes/
98
+ │ └── web.js # Route definitions
99
+ └── storage/ # File storage
100
+ ```
101
+
102
+ ## Routing
103
+
104
+ Define routes in `routes/web.js`:
105
+
106
+ ```javascript
107
+ import { Route } from 'nitronjs';
108
+ import HomeController from '#app/Controllers/HomeController.js';
109
+
110
+ Route.get('/', HomeController.index).name('home');
111
+ Route.get('/about', HomeController.about);
112
+ Route.post('/contact', HomeController.contact);
113
+ ```
114
+
115
+ ### Route Groups & Middleware
116
+
117
+ ```javascript
118
+ Route.prefix('/admin').middleware('auth').group(() => {
119
+ Route.get('/dashboard', AdminController.dashboard);
120
+ Route.get('/users', AdminController.users);
121
+ });
122
+ ```
123
+
124
+ ## Controllers
125
+
126
+ Create controllers with `njs make:controller`:
127
+
128
+ ```javascript
129
+ class HomeController {
130
+ static async index(request, reply) {
131
+ return reply.view('Site/Home', {
132
+ title: 'Welcome'
133
+ });
134
+ }
135
+
136
+ static async contact(request, reply) {
137
+ const { name, email } = request.body;
138
+ // Handle contact form
139
+ return reply.redirect('/thank-you');
140
+ }
141
+ }
142
+
143
+ export default HomeController;
144
+ ```
145
+
146
+ ## Views (React SSR)
147
+
148
+ Create React views in `resources/views/`:
149
+
150
+ ```tsx
151
+ // resources/views/Site/Home.tsx
152
+ export default function Home({ title, items }) {
153
+ return (
154
+ <html>
155
+ <head>
156
+ <title>{title}</title>
157
+ <link rel="stylesheet" href="/css/site_style.css" />
158
+ </head>
159
+ <body>
160
+ <h1>{title}</h1>
161
+ <ul>
162
+ {items.map(item => (
163
+ <li key={item.id}>{item.name}</li>
164
+ ))}
165
+ </ul>
166
+ </body>
167
+ </html>
168
+ );
169
+ }
170
+ ```
171
+
172
+ Views are automatically compiled and bundled with your application.
173
+
174
+ ## Models
175
+
176
+ Create models with `njs make:model`:
177
+
178
+ ```javascript
179
+ import { Model } from 'nitronjs';
180
+
181
+ export default class User extends Model {
182
+ static table = 'users';
183
+ static primaryKey = 'id';
184
+ }
185
+ ```
186
+
187
+ ### Query Examples
188
+
189
+ ```javascript
190
+ // Find all users
191
+ const users = await User.get();
192
+
193
+ // Find by ID
194
+ const user = await User.find(1);
195
+
196
+ // Where clauses
197
+ const admins = await User.where('role', '=', 'admin').get();
198
+
199
+ // Create new record
200
+ const user = new User();
201
+ user.name = 'John';
202
+ user.email = 'john@example.com';
203
+ await user.save();
204
+
205
+ // Update
206
+ await User.where('id', '=', 1).update({
207
+ name: 'Jane'
208
+ });
209
+
210
+ // Delete
211
+ await User.where('id', '=', 1).delete();
212
+ ```
213
+
214
+ ## Middleware
215
+
216
+ Create middleware with `njs make:middleware`:
217
+
218
+ ```javascript
219
+ class CheckAge {
220
+ static async handler(req, res) {
221
+ const age = req.query.age;
222
+
223
+ if (age < 18) {
224
+ return res.status(403).send('Access denied');
225
+ }
226
+
227
+ // If no return, continues to next middleware/handler
228
+ }
229
+ }
230
+
231
+ export default CheckAge;
232
+ ```
233
+
234
+ Register middleware in `app/Kernel.js`:
235
+
236
+ ```javascript
237
+ export default {
238
+ routeMiddlewares: {
239
+ "check-age": CheckAge,
240
+ }
241
+ };
242
+ ```
243
+
244
+ Apply to routes:
245
+
246
+ ```javascript
247
+ Route.middleware('check-age').get('/restricted', Controller.method);
248
+ ```
249
+
250
+ ## Database Migrations
251
+
252
+ Create migrations with `njs make:migration`:
253
+
254
+ ```javascript
255
+ import { Schema } from 'nitronjs';
256
+
257
+ class CreateUsersTable {
258
+ static async up() {
259
+ await Schema.create('users', (table) => {
260
+ table.id();
261
+ table.string('name');
262
+ table.string('email').unique();
263
+ table.string('password');
264
+ table.timestamp('created_at');
265
+ table.timestamp('updated_at').nullable();
266
+ });
267
+ }
268
+
269
+ static async down() {
270
+ await Schema.dropIfExists('users');
271
+ }
272
+ }
273
+
274
+ export default CreateUsersTable;
275
+ ```
276
+
277
+ ## Configuration
278
+
279
+ All configuration files are in the `config/` directory:
280
+
281
+ - **app.js** - Application settings (name, env, debug mode)
282
+ - **database.js** - Database connections
283
+ - **server.js** - Server configuration (port, host, CORS)
284
+ - **session.js** - Session management
285
+ - **auth.js** - Authentication settings
286
+ - **hash.js** - Hashing algorithm configuration
287
+
288
+ Access config values:
289
+
290
+ ```javascript
291
+ import { Config } from 'nitronjs';
292
+
293
+ const appName = Config.get('app.name');
294
+ const dbHost = Config.get('database.host');
295
+ ```
296
+
297
+ ## Session Management
298
+
299
+ ```javascript
300
+ // Set session data
301
+ req.session.set('user', { id: 1, name: 'John' });
302
+
303
+ // Get session data
304
+ const user = req.session.get('user');
305
+
306
+ // Check if session has value
307
+ if (req.session.get('user')) {
308
+ // User is logged in
309
+ }
310
+
311
+ // Remove session data
312
+ req.session.set('user', null);
313
+
314
+ // Get all session data
315
+ const allData = req.session.all();
316
+
317
+ // Regenerate session (security - after login)
318
+ req.session.regenerate();
319
+
320
+ // Flash messages (one-time)
321
+ req.session.flash('message', 'Success!');
322
+ const message = req.session.getFlash('message');
323
+
324
+ // CSRF token
325
+ const token = req.session.getCsrfToken();
326
+ ```
327
+
328
+ ## Authentication
329
+
330
+ Built-in authentication system (request-based):
331
+
332
+ ```javascript
333
+ // Attempt login (inside controller or middleware)
334
+ const success = await req.auth.attempt({
335
+ email: 'admin@example.com',
336
+ password: 'secret'
337
+ });
338
+ // veya belirli bir guard ile:
339
+ // const success = await req.auth.guard('user').attempt({ email, password });
340
+
341
+ // Kullanıcıya erişim
342
+ const user = await req.auth.user();
343
+ // veya
344
+ // const user = await req.auth.guard('user').user();
345
+
346
+ // Giriş yapmış mı?
347
+ if (req.auth.check()) {
348
+ // Authenticated
349
+ }
350
+
351
+ // Çıkış
352
+ await req.auth.logout();
353
+ // veya
354
+ // await req.auth.guard('user').logout();
355
+ ```
356
+
357
+ ## Validation
358
+
359
+ ```javascript
360
+ import { Validator } from 'nitronjs';
361
+
362
+ const validation = Validator.make(req.body, {
363
+ email: 'required|email',
364
+ password: 'required|string|min:8',
365
+ age: 'required|numeric|min:18'
366
+ });
367
+
368
+ if (validation.fails()) {
369
+ return res.status(422).send({
370
+ errors: validation.errors()
371
+ });
372
+ }
373
+ ```
374
+
375
+ ## Environment Variables
376
+
377
+ Create a `.env` file in your project root:
378
+
379
+ ```env
380
+ APP_NAME=nitronjs
381
+ APP_DEV=true
382
+ APP_DEBUG=true
383
+ APP_PORT=3000
384
+ APP_URL=http://localhost
385
+
386
+ DATABASE_DRIVER=mysql
387
+ DATABASE_HOST=127.0.0.1
388
+ DATABASE_PORT=3306
389
+ DATABASE_NAME=nitronjs
390
+ DATABASE_USERNAME=root
391
+ DATABASE_PASSWORD=
392
+ ```
393
+
394
+ ## Response Methods
395
+
396
+ ```javascript
397
+ // Render view
398
+ return res.view('Site/Home', { title: 'Welcome' });
399
+
400
+ // JSON response
401
+ return res.json({ success: true, data: users });
402
+
403
+ // Redirect
404
+ return res.redirect('/dashboard');
405
+
406
+ // Status code
407
+ return res.status(404).send('Not Found');
408
+
409
+ // Download file
410
+ return res.download('/path/to/file.pdf');
411
+ ```
412
+
413
+ ## Testing Your Application
414
+
415
+ Build and run in production mode:
416
+
417
+ ```bash
418
+ npm run build
419
+ npm run start
420
+ ```
421
+
422
+ ## Requirements
423
+
424
+ - Node.js 18.x or higher
425
+ - MySQL 5.7+ or MariaDB 10.3+
426
+
427
+ ## License
428
+
429
+ ISC
package/cli/create.js ADDED
@@ -0,0 +1,260 @@
1
+ #!/usr/bin/env node
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import { fileURLToPath } from "url";
5
+ import crypto from "crypto";
6
+ import { spawn } from "child_process";
7
+
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+ const SKELETON_DIR = path.join(__dirname, "..", "skeleton");
10
+
11
+ const COLORS = {
12
+ reset: "\x1b[0m",
13
+ bold: "\x1b[1m",
14
+ dim: "\x1b[2m",
15
+ red: "\x1b[31m",
16
+ green: "\x1b[32m",
17
+ yellow: "\x1b[33m",
18
+ cyan: "\x1b[36m"
19
+ };
20
+
21
+ function log(message, color = COLORS.reset) {
22
+ console.log(`${color}${message}${COLORS.reset}`);
23
+ }
24
+
25
+ function logStep(message, status = "pending") {
26
+ const icons = {
27
+ pending: `${COLORS.dim}○${COLORS.reset}`,
28
+ running: `${COLORS.yellow}◐${COLORS.reset}`,
29
+ success: `${COLORS.green}✓${COLORS.reset}`,
30
+ error: `${COLORS.red}✗${COLORS.reset}`
31
+ };
32
+ console.log(` ${icons[status]} ${message}`);
33
+ }
34
+
35
+ function printBanner() {
36
+ console.log();
37
+ log("███╗ ██╗██╗████████╗██████╗ ██████╗ ███╗ ██╗ ██╗███████╗", COLORS.cyan);
38
+ log("████╗ ██║██║╚══██╔══╝██╔══██╗██╔═══██╗████╗ ██║ ██║██╔════╝", COLORS.cyan);
39
+ log("██╔██╗ ██║██║ ██║ ██████╔╝██║ ██║██╔██╗ ██║ ██║███████╗", COLORS.cyan);
40
+ log("██║╚██╗██║██║ ██║ ██╔══██╗██║ ██║██║╚██╗██║██ ██║╚════██║", COLORS.cyan);
41
+ log("██║ ╚████║██║ ██║ ██║ ██║╚██████╔╝██║ ╚████║╚█████╔╝███████║", COLORS.cyan);
42
+ log("╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚════╝ ╚══════╝", COLORS.cyan);
43
+ console.log();
44
+ }
45
+
46
+ function printHelp() {
47
+ console.log(`
48
+ ${COLORS.bold}Usage:${COLORS.reset}
49
+ npx nitronjs <project-name>
50
+
51
+ ${COLORS.bold}Arguments:${COLORS.reset}
52
+ project-name Name of the project directory to create
53
+
54
+ ${COLORS.bold}Examples:${COLORS.reset}
55
+ ${COLORS.cyan}npx nitronjs my-app${COLORS.reset}
56
+ ${COLORS.cyan}npx nitronjs blog${COLORS.reset}
57
+ ${COLORS.cyan}npx nitronjs e-commerce${COLORS.reset}
58
+
59
+ ${COLORS.bold}Project name rules:${COLORS.reset}
60
+ - Can contain letters, numbers, hyphens, and underscores
61
+ - Cannot start with a number
62
+ - Cannot contain spaces or special characters
63
+ `);
64
+ }
65
+
66
+ function validateProjectName(name) {
67
+ if (!name) {
68
+ return { valid: false, error: "Project name is required" };
69
+ }
70
+
71
+ if (/^\d/.test(name)) {
72
+ return { valid: false, error: "Project name cannot start with a number" };
73
+ }
74
+
75
+ if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(name)) {
76
+ return { valid: false, error: "Project name can only contain letters, numbers, hyphens, and underscores" };
77
+ }
78
+
79
+ if (name.length < 2) {
80
+ return { valid: false, error: "Project name must be at least 2 characters" };
81
+ }
82
+
83
+ if (name.length > 50) {
84
+ return { valid: false, error: "Project name cannot exceed 50 characters" };
85
+ }
86
+
87
+ return { valid: true };
88
+ }
89
+
90
+ function copyDir(src, dest) {
91
+ if (!fs.existsSync(dest)) {
92
+ fs.mkdirSync(dest, { recursive: true });
93
+ }
94
+
95
+ const entries = fs.readdirSync(src, { withFileTypes: true });
96
+ let fileCount = 0;
97
+
98
+ for (const entry of entries) {
99
+ const srcPath = path.join(src, entry.name);
100
+ const destPath = path.join(dest, entry.name);
101
+
102
+ if (entry.isDirectory()) {
103
+ fileCount += copyDir(srcPath, destPath);
104
+ } else {
105
+ fs.copyFileSync(srcPath, destPath);
106
+ fileCount++;
107
+ }
108
+ }
109
+
110
+ return fileCount;
111
+ }
112
+
113
+ function generateAppKey() {
114
+ return crypto.randomBytes(32).toString("base64");
115
+ }
116
+
117
+ function updatePackageJson(projectPath, projectName) {
118
+ const pkgPath = path.join(projectPath, "package.json");
119
+
120
+ if (fs.existsSync(pkgPath)) {
121
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
122
+ pkg.name = projectName;
123
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 4));
124
+ }
125
+ }
126
+
127
+ function updateEnvFile(projectPath) {
128
+ const envPath = path.join(projectPath, ".env");
129
+
130
+ if (fs.existsSync(envPath)) {
131
+ let content = fs.readFileSync(envPath, "utf-8");
132
+ const appKey = generateAppKey();
133
+ content = content.replace(/APP_KEY=.*/, `APP_KEY=${appKey}`);
134
+ fs.writeFileSync(envPath, content);
135
+ }
136
+ }
137
+
138
+ function runNpmInstall(projectPath) {
139
+ return new Promise((resolve, reject) => {
140
+ const isWindows = process.platform === "win32";
141
+ const npm = isWindows ? "npm.cmd" : "npm";
142
+
143
+ const child = spawn(npm, ["install"], {
144
+ cwd: projectPath,
145
+ stdio: ["pipe", "pipe", "pipe"]
146
+ });
147
+
148
+ let output = "";
149
+
150
+ child.stdout.on("data", (data) => {
151
+ output += data.toString();
152
+ });
153
+
154
+ child.stderr.on("data", (data) => {
155
+ output += data.toString();
156
+ });
157
+
158
+ child.on("close", (code) => {
159
+ if (code === 0) {
160
+ resolve(output);
161
+ } else {
162
+ reject(new Error(`npm install failed with code ${code}`));
163
+ }
164
+ });
165
+
166
+ child.on("error", (err) => {
167
+ reject(err);
168
+ });
169
+ });
170
+ }
171
+
172
+ function printSuccess(projectName) {
173
+ console.log();
174
+ log("╔══════════════════════════════════════════════════════════════╗", COLORS.green);
175
+ log("║ ║", COLORS.green);
176
+ log("║ ✓ Project created successfully! ║", COLORS.green);
177
+ log("║ ║", COLORS.green);
178
+ log("╚══════════════════════════════════════════════════════════════╝", COLORS.green);
179
+ console.log();
180
+
181
+ log(`${COLORS.bold}Next steps:${COLORS.reset}`);
182
+ console.log();
183
+ log(` ${COLORS.dim}1.${COLORS.reset} ${COLORS.cyan}cd ${projectName}${COLORS.reset}`);
184
+ log(` ${COLORS.dim}2.${COLORS.reset} Configure your ${COLORS.yellow}.env${COLORS.reset} file`);
185
+ log(` ${COLORS.dim}3.${COLORS.reset} ${COLORS.cyan}njs migrate${COLORS.reset}`);
186
+ log(` ${COLORS.dim}4.${COLORS.reset} ${COLORS.cyan}njs dev${COLORS.reset}`);
187
+ console.log();
188
+
189
+ log(`${COLORS.bold}Useful commands:${COLORS.reset}`);
190
+ console.log();
191
+ log(` ${COLORS.cyan}njs dev${COLORS.reset} ${COLORS.dim}Start development server${COLORS.reset}`);
192
+ log(` ${COLORS.cyan}njs build${COLORS.reset} ${COLORS.dim}Build for production${COLORS.reset}`);
193
+ log(` ${COLORS.cyan}njs start${COLORS.reset} ${COLORS.dim}Start production server${COLORS.reset}`);
194
+ log(` ${COLORS.cyan}njs migrate${COLORS.reset} ${COLORS.dim}Run database migrations${COLORS.reset}`);
195
+ log(` ${COLORS.cyan}njs seed${COLORS.reset} ${COLORS.dim}Run database seeders${COLORS.reset}`);
196
+ log(` ${COLORS.cyan}njs make:controller${COLORS.reset} ${COLORS.dim}Create a new controller${COLORS.reset}`);
197
+ log(` ${COLORS.cyan}njs make:model${COLORS.reset} ${COLORS.dim}Create a new model${COLORS.reset}`);
198
+ console.log();
199
+
200
+ log(`${COLORS.dim}Documentation: https://nitronjs.dev/docs${COLORS.reset}`);
201
+ console.log();
202
+ }
203
+
204
+ export default async function create(projectName, options = {}) {
205
+ if (options.help || projectName === "--help" || projectName === "-h") {
206
+ printHelp();
207
+ return;
208
+ }
209
+
210
+ printBanner();
211
+
212
+ const validation = validateProjectName(projectName);
213
+ if (!validation.valid) {
214
+ log(`${COLORS.red}Error: ${validation.error}${COLORS.reset}`);
215
+ console.log();
216
+ log(`${COLORS.dim}Run 'npx nitronjs --help' for usage information${COLORS.reset}`);
217
+ process.exit(1);
218
+ }
219
+
220
+ const projectPath = path.resolve(process.cwd(), projectName);
221
+
222
+ if (fs.existsSync(projectPath)) {
223
+ log(`${COLORS.red}Error: Directory "${projectName}" already exists${COLORS.reset}`);
224
+ console.log();
225
+ log(`${COLORS.dim}Please choose a different project name or remove the existing directory${COLORS.reset}`);
226
+ process.exit(1);
227
+ }
228
+
229
+ if (!fs.existsSync(SKELETON_DIR)) {
230
+ log(`${COLORS.red}Error: Skeleton directory not found${COLORS.reset}`);
231
+ log(`${COLORS.dim}This may indicate a corrupted installation. Try reinstalling NitronJS.${COLORS.reset}`);
232
+ process.exit(1);
233
+ }
234
+
235
+ log(`${COLORS.bold}Creating project: ${COLORS.cyan}${projectName}${COLORS.reset}`);
236
+ console.log();
237
+
238
+ logStep("Copying project files...", "running");
239
+ const fileCount = copyDir(SKELETON_DIR, projectPath);
240
+ logStep(`Copied ${fileCount} files`, "success");
241
+
242
+ logStep("Configuring package.json...", "running");
243
+ updatePackageJson(projectPath, projectName);
244
+ logStep("Package configured", "success");
245
+
246
+ logStep("Generating APP_KEY...", "running");
247
+ updateEnvFile(projectPath);
248
+ logStep("APP_KEY generated", "success");
249
+
250
+ logStep("Installing dependencies (this may take a moment)...", "running");
251
+ try {
252
+ await runNpmInstall(projectPath);
253
+ logStep("Dependencies installed", "success");
254
+ } catch (error) {
255
+ logStep("Failed to install dependencies", "error");
256
+ log(`${COLORS.yellow}Please run 'npm install' manually in the project directory${COLORS.reset}`);
257
+ }
258
+
259
+ printSuccess(projectName);
260
+ }