@coherent.js/cli 1.0.0-beta.5 → 1.0.0-beta.7

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 (3) hide show
  1. package/dist/index.cjs +11656 -2145
  2. package/dist/index.js +876 -322
  3. package/package.json +5 -1
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/index.js
2
2
  import { Command as Command6 } from "commander";
3
- import { readFileSync as readFileSync7 } from "fs";
3
+ import { readFileSync as readFileSync8 } from "fs";
4
4
  import { fileURLToPath as fileURLToPath4 } from "url";
5
5
  import { dirname as dirname3, join as join8 } from "path";
6
6
  import picocolors6 from "picocolors";
@@ -12,9 +12,10 @@ import ora from "ora";
12
12
  import picocolors from "picocolors";
13
13
  import { existsSync as existsSync2, mkdirSync as mkdirSync2 } from "fs";
14
14
  import { resolve as resolve2 } from "path";
15
+ import { spawn } from "child_process";
15
16
 
16
17
  // src/generators/project-scaffold.js
17
- import { writeFileSync, mkdirSync } from "node:fs";
18
+ import { writeFileSync, mkdirSync, copyFileSync, constants, readFileSync as readFileSync2, appendFileSync } from "node:fs";
18
19
  import { join as join2, dirname as dirname2 } from "node:path";
19
20
  import { execSync } from "node:child_process";
20
21
 
@@ -22,6 +23,7 @@ import { execSync } from "node:child_process";
22
23
  import { readFileSync } from "fs";
23
24
  import { join, dirname } from "path";
24
25
  import { fileURLToPath } from "url";
26
+ import { env } from "node:process";
25
27
  var cachedVersion = null;
26
28
  function getCLIVersion() {
27
29
  if (cachedVersion) {
@@ -35,7 +37,7 @@ function getCLIVersion() {
35
37
  cachedVersion = packageJson.version;
36
38
  return cachedVersion;
37
39
  } catch {
38
- cachedVersion = process.env.COHERENT_CLI_VERSION || "1.0.0-beta.3";
40
+ cachedVersion = env.COHERENT_CLI_VERSION || "1.0.0-beta.5";
39
41
  return cachedVersion;
40
42
  }
41
43
  }
@@ -45,7 +47,9 @@ var cliVersion = getCLIVersion();
45
47
  function generateBuiltInServer(options = {}) {
46
48
  const { port = 3e3, hasApi = false, hasDatabase = false, hasAuth = false } = options;
47
49
  const imports = [
48
- `import http from 'http';`,
50
+ `import http from 'node:http';`,
51
+ `import fs from 'node:fs';`,
52
+ `import path from 'node:path';`,
49
53
  `import { render } from '@coherent.js/core';`
50
54
  ];
51
55
  if (hasApi) imports.push(`import { setupRoutes } from './api/routes.js';`);
@@ -79,11 +83,42 @@ ${hasApi || hasAuth ? ` // Handle API routes
79
83
  }
80
84
  }
81
85
 
82
- ` : ""} // Serve static files
86
+ ` : ""} // Serve components for hydration
87
+ if (url.pathname.startsWith('/components/')) {
88
+ const filePath = path.join(process.cwd(), 'src', url.pathname);
89
+ try {
90
+ const content = await fs.promises.readFile(filePath);
91
+ res.writeHead(200, { 'Content-Type': 'text/javascript' });
92
+ return res.end(content);
93
+ } catch (err) {
94
+ res.writeHead(404);
95
+ return res.end('Not Found');
96
+ }
97
+ }
98
+
99
+ // Serve static files
83
100
  if (url.pathname.startsWith('/public')) {
84
- // Add your static file serving logic here
85
- res.writeHead(404);
86
- return res.end('Not Found');
101
+ const filePath = path.join(process.cwd(), url.pathname);
102
+ try {
103
+ const content = await fs.promises.readFile(filePath);
104
+ const ext = path.extname(filePath).toLowerCase();
105
+ const contentTypes = {
106
+ '.html': 'text/html',
107
+ '.js': 'text/javascript',
108
+ '.css': 'text/css',
109
+ '.json': 'application/json',
110
+ '.png': 'image/png',
111
+ '.jpg': 'image/jpeg',
112
+ '.gif': 'image/gif',
113
+ '.svg': 'image/svg+xml',
114
+ '.ico': 'image/x-icon'
115
+ };
116
+ res.writeHead(200, { 'Content-Type': contentTypes[ext] || 'application/octet-stream' });
117
+ return res.end(content);
118
+ } catch (err) {
119
+ res.writeHead(404);
120
+ return res.end('Not Found');
121
+ }
87
122
  }
88
123
 
89
124
  // Render page
@@ -114,23 +149,23 @@ function matchRoute(routePattern, urlPath, requestMethod, routeMethod) {
114
149
  if (requestMethod !== routeMethod) {
115
150
  return null;
116
151
  }
117
-
152
+
118
153
  // Split paths into segments
119
154
  const routeSegments = routePattern.split('/').filter(Boolean);
120
155
  const urlSegments = urlPath.split('/').filter(Boolean);
121
-
156
+
122
157
  // Check if lengths match
123
158
  if (routeSegments.length !== urlSegments.length) {
124
159
  return null;
125
160
  }
126
-
161
+
127
162
  const params = {};
128
-
163
+
129
164
  // Match each segment
130
165
  for (let i = 0; i < routeSegments.length; i++) {
131
166
  const routeSegment = routeSegments[i];
132
167
  const urlSegment = urlSegments[i];
133
-
168
+
134
169
  // Check for parameter (e.g., :id)
135
170
  if (routeSegment.startsWith(':')) {
136
171
  const paramName = routeSegment.substring(1);
@@ -140,7 +175,7 @@ function matchRoute(routePattern, urlPath, requestMethod, routeMethod) {
140
175
  return null;
141
176
  }
142
177
  }
143
-
178
+
144
179
  return { params };
145
180
  }
146
181
 
@@ -154,7 +189,7 @@ function generateExpressServer(options = {}) {
154
189
  const { port = 3e3, hasApi = false, hasDatabase = false, hasAuth = false } = options;
155
190
  const imports = [
156
191
  `import express from 'express';`,
157
- `import { setupCoherent } from '@coherent.js/express';`
192
+ `import { render } from '@coherent.js/core';`
158
193
  ];
159
194
  if (hasApi) imports.push(`import apiRoutes from './api/routes.js';`);
160
195
  if (hasDatabase) imports.push(`import { initDatabase } from './db/index.js';`);
@@ -175,15 +210,25 @@ ${hasDatabase ? `// Initialize database
175
210
  await initDatabase();
176
211
  ` : ""}${hasAuth ? `// Setup authentication
177
212
  app.use(authMiddleware);
178
- ` : ""}// Setup Coherent.js
179
- setupCoherent(app);
180
-
181
- ${hasApi ? `// API routes
182
- app.use('/api', apiRoutes);
183
213
  ` : ""}
184
- // Main route
214
+ ${hasApi ? `// API routes - convert Coherent.js router to Express middleware
215
+ app.use('/api', apiRoutes.toExpressRouter(express));
216
+ ` : ""}
217
+ // Main route - render Coherent.js component to HTML
185
218
  app.get('/', (req, res) => {
186
- res.render(HomePage({}));
219
+ const content = render(HomePage({}));
220
+ const html = \`<!DOCTYPE html>
221
+ <html lang="en">
222
+ <head>
223
+ <meta charset="UTF-8">
224
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
225
+ <title>Coherent.js App</title>
226
+ </head>
227
+ <body>
228
+ \${content}
229
+ </body>
230
+ </html>\`;
231
+ res.type('html').send(html);
187
232
  });
188
233
 
189
234
  // Error handling
@@ -232,9 +277,9 @@ await fastify.register(import('@fastify/static'), {
232
277
  ${hasApi ? `// API routes
233
278
  await fastify.register(apiRoutes, { prefix: '/api' });
234
279
  ` : ""}
235
- // Main route
280
+ // Main route - return Coherent.js component (auto-rendered by plugin)
236
281
  fastify.get('/', async (request, reply) => {
237
- return reply.render(HomePage({}));
282
+ return HomePage({});
238
283
  });
239
284
 
240
285
  // Start server
@@ -282,9 +327,9 @@ setupCoherent(app);
282
327
  ${hasApi ? `// API routes
283
328
  apiRoutes(router);
284
329
  ` : ""}
285
- // Main route
330
+ // Main route - set body to Coherent.js component (auto-rendered by middleware)
286
331
  router.get('/', async (ctx) => {
287
- ctx.render(HomePage({}));
332
+ ctx.body = HomePage({});
288
333
  });
289
334
 
290
335
  app.use(router.routes());
@@ -350,9 +395,12 @@ export const dbConfig = {
350
395
  user: process.env.DB_USER || 'postgres',
351
396
  password: process.env.DB_PASSWORD || 'postgres',
352
397
  // Connection pool settings
353
- max: 20,
354
- idleTimeoutMillis: 30000,
355
- connectionTimeoutMillis: 2000,
398
+ pool: {
399
+ min: 2,
400
+ max: 20,
401
+ idleTimeoutMillis: 30000,
402
+ connectionTimeoutMillis: 2000,
403
+ }
356
404
  };
357
405
  `,
358
406
  mysql: `
@@ -363,9 +411,12 @@ export const dbConfig = {
363
411
  user: process.env.DB_USER || 'root',
364
412
  password: process.env.DB_PASSWORD || 'password',
365
413
  // Connection pool settings
366
- connectionLimit: 10,
367
- waitForConnections: true,
368
- queueLimit: 0
414
+ pool: {
415
+ max: 10,
416
+ min: 0,
417
+ waitForConnections: true,
418
+ queueLimit: 0
419
+ }
369
420
  };
370
421
  `,
371
422
  sqlite: `
@@ -389,22 +440,33 @@ export const dbConfig = {
389
440
  };
390
441
  return configs[dbType] || "";
391
442
  }
392
- function generateDatabaseInit(dbType) {
443
+ function generateDatabaseInit(dbType, language = "javascript") {
444
+ const isTypeScript = language === "typescript";
445
+ const typeAnnotation = isTypeScript ? ": any" : "";
446
+ const returnType = isTypeScript ? ": Promise<any>" : "";
393
447
  const inits = {
394
448
  postgres: `
395
449
  import { setupDatabase } from '@coherent.js/database';
396
450
  import { dbConfig } from './config.js';
397
451
 
398
- let db;
452
+ let db${typeAnnotation};
399
453
 
400
- export async function initDatabase() {
454
+ export async function initDatabase()${returnType} {
401
455
  try {
402
456
  // Setup database with Coherent.js
403
457
  db = setupDatabase({
404
- type: 'postgres',
405
- ...dbConfig
458
+ type: 'postgresql',
459
+ host: dbConfig.host,
460
+ port: dbConfig.port,
461
+ database: dbConfig.database,
462
+ username: dbConfig.user,
463
+ password: dbConfig.password,
464
+ pool: dbConfig.pool
406
465
  });
407
466
 
467
+ // Wait for connection
468
+ await db.connect();
469
+
408
470
  console.log('\u2713 Connected to PostgreSQL database');
409
471
 
410
472
  return db;
@@ -414,7 +476,7 @@ export async function initDatabase() {
414
476
  }
415
477
  }
416
478
 
417
- export function getDatabase() {
479
+ export function getDatabase()${typeAnnotation} {
418
480
  if (!db) {
419
481
  throw new Error('Database not initialized. Call initDatabase() first.');
420
482
  }
@@ -434,16 +496,24 @@ process.on('SIGINT', async () => {
434
496
  import { setupDatabase } from '@coherent.js/database';
435
497
  import { dbConfig } from './config.js';
436
498
 
437
- let db;
499
+ let db${typeAnnotation};
438
500
 
439
- export async function initDatabase() {
501
+ export async function initDatabase()${returnType} {
440
502
  try {
441
503
  // Setup database with Coherent.js
442
504
  db = setupDatabase({
443
505
  type: 'mysql',
444
- ...dbConfig
506
+ host: dbConfig.host,
507
+ port: dbConfig.port,
508
+ database: dbConfig.database,
509
+ username: dbConfig.user,
510
+ password: dbConfig.password,
511
+ pool: dbConfig.pool
445
512
  });
446
513
 
514
+ // Wait for connection
515
+ await db.connect();
516
+
447
517
  console.log('\u2713 Connected to MySQL database');
448
518
 
449
519
  return db;
@@ -453,7 +523,7 @@ export async function initDatabase() {
453
523
  }
454
524
  }
455
525
 
456
- export function getDatabase() {
526
+ export function getDatabase()${typeAnnotation} {
457
527
  if (!db) {
458
528
  throw new Error('Database not initialized. Call initDatabase() first.');
459
529
  }
@@ -475,21 +545,24 @@ import { dbConfig } from './config.js';
475
545
  import { mkdirSync } from 'fs';
476
546
  import { dirname } from 'path';
477
547
 
478
- let db;
548
+ let db${typeAnnotation};
479
549
 
480
- export async function initDatabase() {
550
+ export async function initDatabase()${returnType} {
481
551
  try {
482
- // Ensure directory exists
483
- if (dbConfig.filename) {
552
+ // Ensure directory exists for SQLite file
553
+ if (dbConfig.filename && dbConfig.filename !== ':memory:') {
484
554
  mkdirSync(dirname(dbConfig.filename), { recursive: true });
485
555
  }
486
556
 
487
557
  // Setup database with Coherent.js
488
558
  db = setupDatabase({
489
559
  type: 'sqlite',
490
- ...dbConfig
560
+ database: dbConfig.filename || ':memory:'
491
561
  });
492
562
 
563
+ // Wait for connection
564
+ await db.connect();
565
+
493
566
  console.log('\u2713 Connected to SQLite database');
494
567
 
495
568
  return db;
@@ -499,7 +572,7 @@ export async function initDatabase() {
499
572
  }
500
573
  }
501
574
 
502
- export function getDatabase() {
575
+ export function getDatabase()${typeAnnotation} {
503
576
  if (!db) {
504
577
  throw new Error('Database not initialized. Call initDatabase() first.');
505
578
  }
@@ -507,9 +580,9 @@ export function getDatabase() {
507
580
  }
508
581
 
509
582
  // Graceful shutdown
510
- process.on('SIGINT', () => {
583
+ process.on('SIGINT', async () => {
511
584
  if (db) {
512
- db.close();
585
+ await db.disconnect();
513
586
  console.log('Database closed');
514
587
  }
515
588
  process.exit(0);
@@ -519,16 +592,20 @@ process.on('SIGINT', () => {
519
592
  import { setupDatabase } from '@coherent.js/database';
520
593
  import { dbConfig } from './config.js';
521
594
 
522
- let db;
595
+ let db${typeAnnotation};
523
596
 
524
- export async function initDatabase() {
597
+ export async function initDatabase()${returnType} {
525
598
  try {
526
599
  // Setup database with Coherent.js
527
600
  db = setupDatabase({
528
601
  type: 'mongodb',
529
- ...dbConfig
602
+ database: dbConfig.uri,
603
+ ...dbConfig.options
530
604
  });
531
605
 
606
+ // Wait for connection
607
+ await db.connect();
608
+
532
609
  console.log('\u2713 Connected to MongoDB database');
533
610
 
534
611
  return db;
@@ -538,7 +615,7 @@ export async function initDatabase() {
538
615
  }
539
616
  }
540
617
 
541
- export function getDatabase() {
618
+ export function getDatabase()${typeAnnotation} {
542
619
  if (!db) {
543
620
  throw new Error('Database not initialized. Call initDatabase() first.');
544
621
  }
@@ -557,47 +634,57 @@ process.on('SIGINT', async () => {
557
634
  };
558
635
  return inits[dbType] || "";
559
636
  }
560
- function generateExampleModel(dbType) {
637
+ function generateExampleModel(dbType, language = "javascript") {
638
+ const isTypeScript = language === "typescript";
639
+ const typeAnnotation = isTypeScript ? ": Promise<any>" : "";
640
+ const interfaceDef = isTypeScript ? `
641
+ interface UserData {
642
+ email: string;
643
+ name: string;
644
+ }` : "";
561
645
  const models = {
562
646
  postgres: `
563
647
  import { getDatabase } from '../index.js';
564
648
 
649
+ ${interfaceDef}
650
+
565
651
  export class UserModel {
566
- static async createTable() {
652
+ static async createTable()${typeAnnotation} {
567
653
  const db = getDatabase();
568
654
  await db.query(\`
569
655
  CREATE TABLE IF NOT EXISTS users (
570
656
  id SERIAL PRIMARY KEY,
571
657
  email VARCHAR(255) UNIQUE NOT NULL,
572
658
  name VARCHAR(255) NOT NULL,
659
+ password_hash VARCHAR(255),
573
660
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
574
661
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
575
662
  )
576
663
  \`);
577
664
  }
578
665
 
579
- static async create(data) {
666
+ static async create(userData)${typeAnnotation} {
580
667
  const db = getDatabase();
581
668
  const result = await db.query(
582
669
  'INSERT INTO users (email, name) VALUES ($1, $2) RETURNING *',
583
- [data.email, data.name]
670
+ [userData.email, userData.name]
584
671
  );
585
672
  return result.rows[0];
586
673
  }
587
674
 
588
- static async findById(id) {
675
+ static async findById(id)${typeAnnotation} {
589
676
  const db = getDatabase();
590
677
  const result = await db.query('SELECT * FROM users WHERE id = $1', [id]);
591
678
  return result.rows[0];
592
679
  }
593
680
 
594
- static async findByEmail(email) {
681
+ static async findByEmail(email)${typeAnnotation} {
595
682
  const db = getDatabase();
596
683
  const result = await db.query('SELECT * FROM users WHERE email = $1', [email]);
597
684
  return result.rows[0];
598
685
  }
599
686
 
600
- static async update(id, data) {
687
+ static async update(id, data)${typeAnnotation} {
601
688
  const db = getDatabase();
602
689
  const result = await db.query(
603
690
  'UPDATE users SET email = $1, name = $2, updated_at = CURRENT_TIMESTAMP WHERE id = $3 RETURNING *',
@@ -606,7 +693,7 @@ export class UserModel {
606
693
  return result.rows[0];
607
694
  }
608
695
 
609
- static async delete(id) {
696
+ static async delete(id)${typeAnnotation} {
610
697
  const db = getDatabase();
611
698
  await db.query('DELETE FROM users WHERE id = $1', [id]);
612
699
  }
@@ -615,61 +702,66 @@ export class UserModel {
615
702
  mysql: `
616
703
  import { getDatabase } from '../index.js';
617
704
 
705
+ ${interfaceDef}
706
+
618
707
  export class UserModel {
619
- static async createTable() {
708
+ static async createTable()${typeAnnotation} {
620
709
  const db = getDatabase();
621
- await db.execute(\`
710
+ await db.query(\`
622
711
  CREATE TABLE IF NOT EXISTS users (
623
712
  id INT AUTO_INCREMENT PRIMARY KEY,
624
713
  email VARCHAR(255) UNIQUE NOT NULL,
625
714
  name VARCHAR(255) NOT NULL,
715
+ password_hash VARCHAR(255),
626
716
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
627
717
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
628
718
  )
629
719
  \`);
630
720
  }
631
721
 
632
- static async create(data) {
722
+ static async create(userData)${typeAnnotation} {
633
723
  const db = getDatabase();
634
- const [result] = await db.execute(
724
+ const result = await db.query(
635
725
  'INSERT INTO users (email, name) VALUES (?, ?)',
636
- [data.email, data.name]
726
+ [userData.email, userData.name]
637
727
  );
638
- return { id: result.insertId, ...data };
728
+ return result[0];
639
729
  }
640
730
 
641
- static async findById(id) {
731
+ static async findById(id)${typeAnnotation} {
642
732
  const db = getDatabase();
643
- const [rows] = await db.execute('SELECT * FROM users WHERE id = ?', [id]);
644
- return rows[0];
733
+ const result = await db.query('SELECT * FROM users WHERE id = ?', [id]);
734
+ return result[0];
645
735
  }
646
736
 
647
- static async findByEmail(email) {
737
+ static async findByEmail(email)${typeAnnotation} {
648
738
  const db = getDatabase();
649
- const [rows] = await db.execute('SELECT * FROM users WHERE email = ?', [email]);
650
- return rows[0];
739
+ const result = await db.query('SELECT * FROM users WHERE email = ?', [email]);
740
+ return result[0];
651
741
  }
652
742
 
653
- static async update(id, data) {
743
+ static async update(id, data)${typeAnnotation} {
654
744
  const db = getDatabase();
655
- await db.execute(
656
- 'UPDATE users SET email = ?, name = ? WHERE id = ?',
745
+ const result = await db.query(
746
+ 'UPDATE users SET email = ?, name = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?',
657
747
  [data.email, data.name, id]
658
748
  );
659
- return { id, ...data };
749
+ return result[0];
660
750
  }
661
751
 
662
- static async delete(id) {
752
+ static async delete(id)${typeAnnotation} {
663
753
  const db = getDatabase();
664
- await db.execute('DELETE FROM users WHERE id = ?', [id]);
754
+ await db.query('DELETE FROM users WHERE id = ?', [id]);
665
755
  }
666
756
  }
667
757
  `,
668
758
  sqlite: `
669
759
  import { getDatabase } from '../index.js';
670
760
 
761
+ ${interfaceDef}
762
+
671
763
  export class UserModel {
672
- static createTable() {
764
+ static createTable()${typeAnnotation} {
673
765
  const db = getDatabase();
674
766
  db.exec(\`
675
767
  CREATE TABLE IF NOT EXISTS users (
@@ -682,94 +774,82 @@ export class UserModel {
682
774
  \`);
683
775
  }
684
776
 
685
- static create(data) {
777
+ static create(data)${typeAnnotation} {
686
778
  const db = getDatabase();
687
779
  const stmt = db.prepare('INSERT INTO users (email, name) VALUES (?, ?)');
688
780
  const result = stmt.run(data.email, data.name);
689
781
  return { id: result.lastInsertRowid, ...data };
690
782
  }
691
783
 
692
- static findById(id) {
784
+ static findById(id)${typeAnnotation} {
693
785
  const db = getDatabase();
694
786
  const stmt = db.prepare('SELECT * FROM users WHERE id = ?');
695
787
  return stmt.get(id);
696
788
  }
697
789
 
698
- static findByEmail(email) {
790
+ static findByEmail(email)${typeAnnotation} {
699
791
  const db = getDatabase();
700
792
  const stmt = db.prepare('SELECT * FROM users WHERE email = ?');
701
793
  return stmt.get(email);
702
794
  }
703
795
 
704
- static update(id, data) {
796
+ static update(id, data)${typeAnnotation} {
705
797
  const db = getDatabase();
706
798
  const stmt = db.prepare('UPDATE users SET email = ?, name = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?');
707
799
  stmt.run(data.email, data.name, id);
708
- return { id, ...data };
800
+ return this.findById(id);
709
801
  }
710
802
 
711
- static delete(id) {
803
+ static delete(id)${typeAnnotation} {
712
804
  const db = getDatabase();
713
805
  const stmt = db.prepare('DELETE FROM users WHERE id = ?');
714
- stmt.run(id);
806
+ return stmt.run(id);
715
807
  }
716
808
  }
717
809
  `,
718
810
  mongodb: `
719
811
  import { getDatabase } from '../index.js';
720
812
 
721
- export class UserModel {
722
- static collectionName = 'users';
813
+ ${interfaceDef}
723
814
 
724
- static getCollection() {
815
+ export class UserModel {
816
+ static async createCollection()${typeAnnotation} {
725
817
  const db = getDatabase();
726
- return db.collection(this.collectionName);
818
+ await db.createCollection('users');
819
+
820
+ // Create index for email uniqueness
821
+ await db.collection('users').createIndex({ email: 1 }, { unique: true });
727
822
  }
728
823
 
729
- static async create(data) {
730
- const collection = this.getCollection();
731
- const result = await collection.insertOne({
732
- email: data.email,
733
- name: data.name,
734
- createdAt: new Date(),
735
- updatedAt: new Date()
736
- });
737
- return { _id: result.insertedId, ...data };
824
+ static async create(userData)${typeAnnotation} {
825
+ const db = getDatabase();
826
+ const result = await db.collection('users').insertOne(userData);
827
+ return { _id: result.insertedId, ...userData };
738
828
  }
739
829
 
740
- static async findById(id) {
741
- const collection = this.getCollection();
742
- return await collection.findOne({ _id: id });
830
+ static async findById(id)${typeAnnotation} {
831
+ const db = getDatabase();
832
+ return await db.collection('users').findOne({ _id: id });
743
833
  }
744
834
 
745
- static async findByEmail(email) {
746
- const collection = this.getCollection();
747
- return await collection.findOne({ email });
835
+ static async findByEmail(email)${typeAnnotation} {
836
+ const db = getDatabase();
837
+ return await db.collection('users').findOne({ email });
748
838
  }
749
839
 
750
- static async update(id, data) {
751
- const collection = this.getCollection();
752
- await collection.updateOne(
840
+ static async update(id, data)${typeAnnotation} {
841
+ const db = getDatabase();
842
+ const result = await db.collection('users').updateOne(
753
843
  { _id: id },
754
- {
755
- $set: {
756
- email: data.email,
757
- name: data.name,
758
- updatedAt: new Date()
759
- }
760
- }
844
+ { $set: { ...data, updatedAt: new Date() } }
761
845
  );
762
- return { _id: id, ...data };
763
- }
764
-
765
- static async delete(id) {
766
- const collection = this.getCollection();
767
- await collection.deleteOne({ _id: id });
846
+ return result.modifiedCount > 0 ? this.findById(id) : null;
768
847
  }
769
848
 
770
- static async createIndexes() {
771
- const collection = this.getCollection();
772
- await collection.createIndex({ email: 1 }, { unique: true });
849
+ static async delete(id)${typeAnnotation} {
850
+ const db = getDatabase();
851
+ const result = await db.collection('users').deleteOne({ _id: id });
852
+ return result.deletedCount > 0;
773
853
  }
774
854
  }
775
855
  `
@@ -822,11 +902,11 @@ function getDatabaseDependencies(dbType) {
822
902
  };
823
903
  return deps[dbType] || {};
824
904
  }
825
- function generateDatabaseScaffolding(dbType) {
905
+ function generateDatabaseScaffolding(dbType, language = "javascript") {
826
906
  return {
827
907
  config: generateDatabaseConfig(dbType),
828
- init: generateDatabaseInit(dbType),
829
- model: generateExampleModel(dbType),
908
+ init: generateDatabaseInit(dbType, language),
909
+ model: generateExampleModel(dbType, language),
830
910
  env: generateEnvExample(dbType),
831
911
  dependencies: getDatabaseDependencies(dbType)
832
912
  };
@@ -1122,7 +1202,7 @@ function generateAuthRoutes(runtime, authType) {
1122
1202
  const jwtRoutes = {
1123
1203
  express: `
1124
1204
  import express from 'express';
1125
- import { generateToken } from '../middleware/auth.js';
1205
+ import { generateToken, authMiddleware } from '../middleware/auth.js';
1126
1206
  import { UserModel } from '../db/models/User.js';
1127
1207
 
1128
1208
  const router = express.Router();
@@ -1522,11 +1602,7 @@ router.get('/me', authMiddleware, async (ctx) => {
1522
1602
  }
1523
1603
  });
1524
1604
 
1525
- export default function registerAuthRoutes(router) {
1526
- router.post('/auth/register', registerHandler);
1527
- router.post('/auth/login', loginHandler);
1528
- router.get('/auth/me', authMiddleware, meHandler);
1529
- }
1605
+ export default router;
1530
1606
  `
1531
1607
  };
1532
1608
  const sessionRoutes = {
@@ -1666,6 +1742,312 @@ function generateAuthScaffolding(authType, runtime) {
1666
1742
  };
1667
1743
  }
1668
1744
 
1745
+ // src/generators/docker-scaffold.js
1746
+ var _cliVersion = getCLIVersion();
1747
+ function generateDockerScaffolding(dbType, dockerConfig) {
1748
+ const { port, name, user, password } = dockerConfig;
1749
+ const dockerCompose = generateDockerCompose(dbType, port, name, user, password);
1750
+ const dockerfile = generateDockerfile();
1751
+ const dockerignore = generateDockerignore();
1752
+ const envConfig = generateDockerEnvConfig(dbType, port, name, user, password);
1753
+ return {
1754
+ "docker-compose.yml": dockerCompose,
1755
+ "Dockerfile": dockerfile,
1756
+ ".dockerignore": dockerignore,
1757
+ envConfig
1758
+ };
1759
+ }
1760
+ function generateDockerCompose(dbType, port, dbName, dbUser, dbPassword) {
1761
+ const configs = {
1762
+ postgres: `version: '3.8'
1763
+
1764
+ services:
1765
+ postgres:
1766
+ image: postgres:16-alpine
1767
+ container_name: coherent-postgres
1768
+ restart: unless-stopped
1769
+ environment:
1770
+ POSTGRES_DB: ${dbName}
1771
+ POSTGRES_USER: ${dbUser}
1772
+ POSTGRES_PASSWORD: ${dbPassword}
1773
+ ports:
1774
+ - "${port}:5432"
1775
+ volumes:
1776
+ - postgres_data:/var/lib/postgresql/data
1777
+ networks:
1778
+ - coherent-network
1779
+
1780
+ volumes:
1781
+ postgres_data:
1782
+
1783
+ networks:
1784
+ coherent-network:
1785
+ driver: bridge`,
1786
+ mysql: `version: '3.8'
1787
+
1788
+ services:
1789
+ mysql:
1790
+ image: mysql:8
1791
+ container_name: coherent-mysql
1792
+ restart: unless-stopped
1793
+ environment:
1794
+ MYSQL_DATABASE: ${dbName}
1795
+ MYSQL_USER: ${dbUser}
1796
+ MYSQL_PASSWORD: ${dbPassword}
1797
+ MYSQL_ROOT_PASSWORD: ${dbPassword}_root
1798
+ ports:
1799
+ - "${port}:3306"
1800
+ volumes:
1801
+ - mysql_data:/var/lib/mysql
1802
+ networks:
1803
+ - coherent-network
1804
+
1805
+ volumes:
1806
+ mysql_data:
1807
+
1808
+ networks:
1809
+ coherent-network:
1810
+ driver: bridge`,
1811
+ mongodb: `version: '3.8'
1812
+
1813
+ services:
1814
+ mongodb:
1815
+ image: mongo:7
1816
+ container_name: coherent-mongodb
1817
+ restart: unless-stopped
1818
+ environment:
1819
+ MONGO_INITDB_ROOT_USERNAME: ${dbUser}
1820
+ MONGO_INITDB_ROOT_PASSWORD: ${dbPassword}
1821
+ MONGO_INITDB_DATABASE: ${dbName}
1822
+ ports:
1823
+ - "${port}:27017"
1824
+ volumes:
1825
+ - mongodb_data:/data/db
1826
+ networks:
1827
+ - coherent-network
1828
+
1829
+ volumes:
1830
+ mongodb_data:
1831
+
1832
+ networks:
1833
+ coherent-network:
1834
+ driver: bridge`
1835
+ };
1836
+ return configs[dbType] || configs.postgres;
1837
+ }
1838
+ function generateDockerfile() {
1839
+ return `# Use Node.js 18 Alpine as base image
1840
+ FROM node:18-alpine
1841
+
1842
+ # Set working directory
1843
+ WORKDIR /app
1844
+
1845
+ # Copy package files
1846
+ COPY package*.json ./
1847
+
1848
+ # Install dependencies
1849
+ RUN npm ci --only=production
1850
+
1851
+ # Copy application code
1852
+ COPY . .
1853
+
1854
+ # Create non-root user
1855
+ RUN addgroup -g 1001 -S nodejs
1856
+ RUN adduser -S nodejs -u 1001
1857
+
1858
+ # Change ownership of the app directory
1859
+ RUN chown -R nodejs:nodejs /app
1860
+ USER nodejs
1861
+
1862
+ # Expose port
1863
+ EXPOSE 3000
1864
+
1865
+ # Health check
1866
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \\
1867
+ CMD node healthcheck.js || exit 1
1868
+
1869
+ # Start the application
1870
+ CMD ["npm", "start"]`;
1871
+ }
1872
+ function generateDockerignore() {
1873
+ return `# Dependencies
1874
+ node_modules
1875
+ npm-debug.log*
1876
+ yarn-debug.log*
1877
+ yarn-error.log*
1878
+
1879
+ # Runtime data
1880
+ pids
1881
+ *.pid
1882
+ *.seed
1883
+ *.pid.lock
1884
+
1885
+ # Coverage directory used by tools like istanbul
1886
+ coverage
1887
+
1888
+ # nyc test coverage
1889
+ .nyc_output
1890
+
1891
+ # Grunt intermediate storage
1892
+ .grunt
1893
+
1894
+ # Bower dependency directory
1895
+ bower_components
1896
+
1897
+ # node-waf configuration
1898
+ .lock-wscript
1899
+
1900
+ # Compiled binary addons
1901
+ build/Release
1902
+
1903
+ # Dependency directories
1904
+ jspm_packages/
1905
+
1906
+ # TypeScript cache
1907
+ *.tsbuildinfo
1908
+
1909
+ # Optional npm cache directory
1910
+ .npm
1911
+
1912
+ # Optional eslint cache
1913
+ .eslintcache
1914
+
1915
+ # Microbundle cache
1916
+ .rpt2_cache/
1917
+ .rts2_cache_cjs/
1918
+ .rts2_cache_es/
1919
+ .rts2_cache_umd/
1920
+
1921
+ # Optional REPL history
1922
+ .node_repl_history
1923
+
1924
+ # Output of 'npm pack'
1925
+ *.tgz
1926
+
1927
+ # Yarn Integrity file
1928
+ .yarn-integrity
1929
+
1930
+ # dotenv environment variables file
1931
+ .env
1932
+ .env.test
1933
+ .env.local
1934
+ .env.production
1935
+
1936
+ # parcel-bundler cache
1937
+ .cache
1938
+ .parcel-cache
1939
+
1940
+ # Next.js build output
1941
+ .next
1942
+
1943
+ # Nuxt.js build / generate output
1944
+ .nuxt
1945
+ dist
1946
+
1947
+ # Gatsby files
1948
+ .cache/
1949
+ public
1950
+
1951
+ # Storybook build outputs
1952
+ .out
1953
+ .storybook-out
1954
+
1955
+ # Temporary folders
1956
+ tmp/
1957
+ temp/
1958
+
1959
+ # Logs
1960
+ logs
1961
+ *.log
1962
+
1963
+ # Runtime data
1964
+ pids
1965
+ *.pid
1966
+ *.seed
1967
+
1968
+ # Coverage directory used by tools like istanbul
1969
+ coverage
1970
+
1971
+ # Grunt intermediate storage
1972
+ .grunt
1973
+
1974
+ # Compiled binary addons
1975
+ build/Release
1976
+
1977
+ # Users Environment Variables
1978
+ .lock-wscript
1979
+
1980
+ # IDE files
1981
+ .vscode/
1982
+ .idea/
1983
+ *.swp
1984
+ *.swo
1985
+
1986
+ # OS generated files
1987
+ .DS_Store
1988
+ .DS_Store?
1989
+ ._*
1990
+ .Spotlight-V100
1991
+ .Trashes
1992
+ ehthumbs.db
1993
+ Thumbs.db`;
1994
+ }
1995
+ function generateDockerEnvConfig(dbType, port, dbName, dbUser, dbPassword) {
1996
+ const configs = {
1997
+ postgres: {
1998
+ DB_HOST: "postgres",
1999
+ DB_PORT: port,
2000
+ DB_NAME: dbName,
2001
+ DB_USER: dbUser,
2002
+ DB_PASSWORD: dbPassword,
2003
+ DATABASE_URL: `postgresql://${dbUser}:${dbPassword}@postgres:${port}/${dbName}`
2004
+ },
2005
+ mysql: {
2006
+ DB_HOST: "mysql",
2007
+ DB_PORT: port,
2008
+ DB_NAME: dbName,
2009
+ DB_USER: dbUser,
2010
+ DB_PASSWORD: dbPassword,
2011
+ DATABASE_URL: `mysql://${dbUser}:${dbPassword}@mysql:${port}/${dbName}`
2012
+ },
2013
+ mongodb: {
2014
+ DB_HOST: "mongodb",
2015
+ DB_PORT: port,
2016
+ DB_NAME: dbName,
2017
+ DB_USER: dbUser,
2018
+ DB_PASSWORD: dbPassword,
2019
+ DATABASE_URL: `mongodb://${dbUser}:${dbPassword}@mongodb:${port}/${dbName}`
2020
+ }
2021
+ };
2022
+ return configs[dbType] || configs.postgres;
2023
+ }
2024
+ function generateHealthCheck() {
2025
+ return `import http from 'http';
2026
+
2027
+ const options = {
2028
+ host: 'localhost',
2029
+ port: process.env.PORT || 3000,
2030
+ path: '/health',
2031
+ timeout: 2000
2032
+ };
2033
+
2034
+ const request = http.request(options, (res) => {
2035
+ console.log(\`Health check status: \${res.statusCode}\`);
2036
+ if (res.statusCode === 200) {
2037
+ process.exit(0);
2038
+ } else {
2039
+ process.exit(1);
2040
+ }
2041
+ });
2042
+
2043
+ request.on('error', (err) => {
2044
+ console.log('Health check failed:', err.message);
2045
+ process.exit(1);
2046
+ });
2047
+
2048
+ request.end();`;
2049
+ }
2050
+
1669
2051
  // src/generators/package-scaffold.js
1670
2052
  var cliVersion3 = getCLIVersion();
1671
2053
  function generateApiScaffolding() {
@@ -1674,41 +2056,42 @@ import { createRouter } from '@coherent.js/api';
1674
2056
 
1675
2057
  const router = createRouter();
1676
2058
 
1677
- // Example route with validation
2059
+ // Business Logic
2060
+ async function getUserById(id) {
2061
+ return { id, name: 'Example User', email: 'user@example.com' };
2062
+ }
2063
+
2064
+ async function createUser(data) {
2065
+ return { id: 1, ...data };
2066
+ }
2067
+
2068
+ // Router Definitions (for Express/Fastify/Koa usage)
1678
2069
  router.get('/users/:id', {
1679
2070
  params: {
1680
2071
  id: { type: 'number', required: true }
1681
2072
  },
1682
2073
  handler: async (req, res) => {
1683
2074
  const { id } = req.params;
1684
- // Fetch user logic here
1685
- return { id, name: 'Example User', email: 'user@example.com' };
2075
+ return getUserById(id);
1686
2076
  }
1687
2077
  });
1688
2078
 
1689
- // Example POST route with body validation
1690
2079
  router.post('/users', {
1691
2080
  body: {
1692
2081
  name: { type: 'string', required: true, minLength: 2 },
1693
2082
  email: { type: 'string', required: true, pattern: /^[^@]+@[^@]+\\.[^@]+$/ }
1694
2083
  },
1695
2084
  handler: async (req, res) => {
1696
- const { name, email } = req.body;
1697
- // Create user logic here
1698
- return { id: 1, name, email };
2085
+ return createUser(req.body);
1699
2086
  }
1700
2087
  });
1701
2088
 
1702
- // Handler for GET /api/users/:id
2089
+ // Handler for GET /api/users/:id (Built-in Server)
1703
2090
  export async function getUsersByIdHandler(req, res) {
1704
2091
  try {
1705
- // Extract ID from URL parameters
1706
2092
  const { id } = req.params;
1707
-
1708
- // Call the original handler
1709
- const result = await router.handle('GET', '/users/:id', { params: { id } }, {});
1710
-
1711
- // Send JSON response
2093
+ const result = await getUserById(id);
2094
+
1712
2095
  res.writeHead(200, { 'Content-Type': 'application/json' });
1713
2096
  res.end(JSON.stringify(result));
1714
2097
  } catch (error) {
@@ -1718,23 +2101,19 @@ export async function getUsersByIdHandler(req, res) {
1718
2101
  }
1719
2102
  }
1720
2103
 
1721
- // Handler for POST /api/users
2104
+ // Handler for POST /api/users (Built-in Server)
1722
2105
  export async function postUsersHandler(req, res) {
1723
2106
  try {
1724
- // Parse JSON body
1725
2107
  let body = '';
1726
2108
  req.on('data', chunk => {
1727
2109
  body += chunk.toString();
1728
2110
  });
1729
-
2111
+
1730
2112
  req.on('end', async () => {
1731
2113
  try {
1732
2114
  const parsedBody = JSON.parse(body);
1733
-
1734
- // Call the original handler
1735
- const result = await router.handle('POST', '/users', { body: parsedBody }, {});
1736
-
1737
- // Send JSON response
2115
+ const result = await createUser(parsedBody);
2116
+
1738
2117
  res.writeHead(200, { 'Content-Type': 'application/json' });
1739
2118
  res.end(JSON.stringify(result));
1740
2119
  } catch (error) {
@@ -1789,7 +2168,7 @@ document.addEventListener('DOMContentLoaded', () => {
1789
2168
 
1790
2169
  try {
1791
2170
  // Dynamically import component
1792
- const module = await import(\`../components/\${componentName}.js\`);
2171
+ const module = await import(\`/components/\${componentName}.js\`);
1793
2172
  const Component = module.default || module[componentName];
1794
2173
 
1795
2174
  // Hydrate component
@@ -2271,7 +2650,9 @@ async function scaffoldProject(projectPath, options) {
2271
2650
  auth = null,
2272
2651
  packages = [],
2273
2652
  language = "javascript",
2274
- packageManager = "npm"
2653
+ packageManager = "npm",
2654
+ onProgress = () => {
2655
+ }
2275
2656
  } = options;
2276
2657
  const isTypeScript = language === "typescript";
2277
2658
  const fileExtension = isTypeScript ? ".ts" : ".js";
@@ -2302,8 +2683,10 @@ async function scaffoldProject(projectPath, options) {
2302
2683
  dirs.forEach((dir) => {
2303
2684
  mkdirSync(join2(projectPath, dir), { recursive: true });
2304
2685
  });
2686
+ onProgress("Created project structure");
2305
2687
  const packageJson = generatePackageJson(name, { template, runtime, database, auth, packages, language, packageManager });
2306
2688
  writeFileSync(join2(projectPath, "package.json"), JSON.stringify(packageJson, null, 2));
2689
+ onProgress("Generated package.json");
2307
2690
  if (isTypeScript) {
2308
2691
  const tsConfig = generateTsConfig();
2309
2692
  writeFileSync(join2(projectPath, "tsconfig.json"), JSON.stringify(tsConfig, null, 2));
@@ -2311,6 +2694,7 @@ async function scaffoldProject(projectPath, options) {
2311
2694
  const jsConfig = generateJsConfig();
2312
2695
  writeFileSync(join2(projectPath, "jsconfig.json"), JSON.stringify(jsConfig, null, 2));
2313
2696
  }
2697
+ onProgress("Created configuration files");
2314
2698
  const serverContent = generateServerFile(runtime, {
2315
2699
  port: 3e3,
2316
2700
  hasApi: packages.includes("api") || auth,
@@ -2318,23 +2702,54 @@ async function scaffoldProject(projectPath, options) {
2318
2702
  hasAuth: !!auth
2319
2703
  });
2320
2704
  writeFileSync(join2(projectPath, `src/index${fileExtension}`), serverContent);
2705
+ onProgress("Set up server");
2321
2706
  await generateHomePageComponent(projectPath, name, isTypeScript, fileExtension);
2707
+ onProgress("Created components");
2322
2708
  if (database) {
2323
- const dbScaffolding = generateDatabaseScaffolding(database);
2324
- writeFileSync(join2(projectPath, "src/db/config.js"), dbScaffolding.config);
2325
- writeFileSync(join2(projectPath, "src/db/index.js"), dbScaffolding.init);
2326
- writeFileSync(join2(projectPath, "src/db/models/User.js"), dbScaffolding.model);
2327
- const existingEnv = "";
2328
- writeFileSync(join2(projectPath, ".env.example"), existingEnv + dbScaffolding.env);
2709
+ const dbScaffolding = generateDatabaseScaffolding(database, language);
2710
+ writeFileSync(join2(projectPath, `src/db/config${fileExtension}`), dbScaffolding.config);
2711
+ writeFileSync(join2(projectPath, `src/db/index${fileExtension}`), dbScaffolding.init);
2712
+ writeFileSync(join2(projectPath, `src/db/models/User${fileExtension}`), dbScaffolding.model);
2713
+ if (options.dockerConfig && database !== "sqlite") {
2714
+ const dockerScaffolding = generateDockerScaffolding(database, options.dockerConfig);
2715
+ writeFileSync(join2(projectPath, "docker-compose.yml"), dockerScaffolding["docker-compose.yml"]);
2716
+ writeFileSync(join2(projectPath, "Dockerfile"), dockerScaffolding["Dockerfile"]);
2717
+ writeFileSync(join2(projectPath, ".dockerignore"), dockerScaffolding[".dockerignore"]);
2718
+ writeFileSync(join2(projectPath, `healthcheck${fileExtension}`), generateHealthCheck());
2719
+ let envContent = "";
2720
+ for (const [key, value] of Object.entries(dockerScaffolding.envConfig)) {
2721
+ envContent += `${key}=${value}
2722
+ `;
2723
+ }
2724
+ writeFileSync(join2(projectPath, ".env.example"), envContent);
2725
+ onProgress("Created Docker configuration");
2726
+ } else {
2727
+ const existingEnv = "";
2728
+ writeFileSync(join2(projectPath, ".env.example"), existingEnv + dbScaffolding.env);
2729
+ }
2730
+ try {
2731
+ copyFileSync(join2(projectPath, ".env.example"), join2(projectPath, ".env"), constants.COPYFILE_EXCL);
2732
+ } catch {
2733
+ }
2734
+ onProgress("Configured database");
2329
2735
  }
2330
2736
  if (auth) {
2331
2737
  const authScaffolding = generateAuthScaffolding(auth, runtime);
2332
2738
  const authDir = runtime === "fastify" ? "plugins" : "middleware";
2333
- writeFileSync(join2(projectPath, `src/${authDir}/auth.js`), authScaffolding.middleware);
2334
- writeFileSync(join2(projectPath, "src/api/auth.js"), authScaffolding.routes);
2739
+ writeFileSync(join2(projectPath, `src/${authDir}/auth${fileExtension}`), authScaffolding.middleware);
2740
+ writeFileSync(join2(projectPath, `src/api/auth${fileExtension}`), authScaffolding.routes);
2335
2741
  const envPath = join2(projectPath, ".env.example");
2336
2742
  const existingEnv = "";
2337
2743
  writeFileSync(envPath, existingEnv + authScaffolding.env);
2744
+ try {
2745
+ const envContent = readFileSync2(join2(projectPath, ".env"), "utf8");
2746
+ if (!envContent.includes("JWT_SECRET") && !envContent.includes("SESSION_SECRET")) {
2747
+ appendFileSync(join2(projectPath, ".env"), authScaffolding.env);
2748
+ }
2749
+ } catch {
2750
+ writeFileSync(join2(projectPath, ".env"), authScaffolding.env);
2751
+ }
2752
+ onProgress("Set up authentication");
2338
2753
  }
2339
2754
  if (packages.length > 0) {
2340
2755
  const { files } = generatePackageScaffolding(packages);
@@ -2405,6 +2820,9 @@ function generatePackageJson(name, options) {
2405
2820
  const tsDeps = getTypeScriptDependencies();
2406
2821
  Object.assign(base.devDependencies, tsDeps);
2407
2822
  base.devDependencies.tsx = "^4.19.2";
2823
+ if (auth) {
2824
+ base.devDependencies["@types/jsonwebtoken"] = "^9.0.7";
2825
+ }
2408
2826
  }
2409
2827
  if (packageManager === "pnpm") {
2410
2828
  base.packageManager = "pnpm@9.0.0";
@@ -2414,7 +2832,7 @@ function generatePackageJson(name, options) {
2414
2832
  const runtimeDeps = getRuntimeDependencies(runtime);
2415
2833
  Object.assign(base.dependencies, runtimeDeps);
2416
2834
  if (database) {
2417
- const { dependencies: dbDeps } = generateDatabaseScaffolding(database);
2835
+ const { dependencies: dbDeps } = generateDatabaseScaffolding(database, language);
2418
2836
  Object.assign(base.dependencies, dbDeps);
2419
2837
  }
2420
2838
  if (auth) {
@@ -2744,7 +3162,15 @@ function validateComponentName(name) {
2744
3162
  }
2745
3163
 
2746
3164
  // src/commands/create.js
2747
- var createCommand = new Command("create").description("Create a new Coherent.js project").argument("[name]", "project name").option("-t, --template <template>", "project template", "basic").option("--skip-install", "skip npm install").option("--skip-git", "skip git initialization").action(async (name, options) => {
3165
+ function getDefaultDockerPort(database) {
3166
+ const ports = {
3167
+ postgres: 5432,
3168
+ mysql: 3306,
3169
+ mongodb: 27017
3170
+ };
3171
+ return ports[database] || 5432;
3172
+ }
3173
+ var createCommand = new Command("create").description("Create a new Coherent.js project").argument("[name]", "project name").option("-t, --template <template>", "project template", "basic").option("--runtime <runtime>", "runtime framework", "koa").option("--database <database>", "database type").option("--auth <auth>", "authentication type").option("--language <language>", "language", "javascript").option("--skip-install", "skip npm install").option("--skip-git", "skip git initialization").option("--skip-prompts", "skip interactive prompts").option("--use-docker", "include Docker configuration for database").option("--docker-db-port <port>", "Docker database port").option("--docker-db-name <name>", "Docker database name").option("--docker-db-user <user>", "Docker database user").option("--docker-db-password <password>", "Docker database password").action(async (name, options) => {
2748
3174
  let projectName = name;
2749
3175
  if (!projectName) {
2750
3176
  const response = await prompts({
@@ -2776,48 +3202,48 @@ var createCommand = new Command("create").description("Create a new Coherent.js
2776
3202
  console.log(picocolors.gray("\u{1F4CD} Location:"), projectPath);
2777
3203
  console.log();
2778
3204
  let template = options.template;
2779
- if (!template || template === "basic") {
2780
- const response = await prompts({
3205
+ if (!template || template === "basic" && !options.skipPrompts) {
3206
+ if (!options.skipPrompts) {
3207
+ const response = await prompts({
3208
+ type: "select",
3209
+ name: "template",
3210
+ message: "Which template would you like to use?",
3211
+ choices: [
3212
+ { title: "\u{1F3C3}\u200D\u2642\uFE0F Basic App", value: "basic", description: "Simple SSR app with routing" },
3213
+ { title: "\u{1F310} Full Stack", value: "fullstack", description: "API + SSR with database and auth options" }
3214
+ ],
3215
+ initial: 0
3216
+ });
3217
+ if (!response.template) {
3218
+ console.log(picocolors.yellow("\u{1F44B} Project creation cancelled"));
3219
+ process.exit(0);
3220
+ }
3221
+ template = response.template;
3222
+ }
3223
+ }
3224
+ let runtime = options.runtime || "built-in";
3225
+ let database = options.database || null;
3226
+ let auth = options.auth || null;
3227
+ let packages = [];
3228
+ let language = options.language || "javascript";
3229
+ if (!options.skipPrompts) {
3230
+ const languageResponse = await prompts({
2781
3231
  type: "select",
2782
- name: "template",
2783
- message: "Which template would you like to use?",
3232
+ name: "language",
3233
+ message: "Would you like to use TypeScript or JavaScript?",
2784
3234
  choices: [
2785
- { title: "\u{1F3C3}\u200D\u2642\uFE0F Basic App", value: "basic", description: "Simple Coherent.js app with routing" },
2786
- { title: "\u{1F310} Full Stack", value: "fullstack", description: "API + SSR with database integration" },
2787
- { title: "\u26A1 Express Integration", value: "express", description: "Coherent.js with Express.js" },
2788
- { title: "\u{1F680} Fastify Integration", value: "fastify", description: "Coherent.js with Fastify" },
2789
- { title: "\u{1F4F1} Component Library", value: "components", description: "Reusable component library" },
2790
- { title: "\u{1F3A8} Custom Setup", value: "custom", description: "Choose your own runtime and packages" }
3235
+ { title: "\u{1F4D8} JavaScript", value: "javascript", description: "JavaScript with JSDoc type hints (recommended)" },
3236
+ { title: "\u{1F4D5} TypeScript", value: "typescript", description: "Full TypeScript with static type checking" }
2791
3237
  ],
2792
3238
  initial: 0
2793
3239
  });
2794
- if (!response.template) {
3240
+ if (!languageResponse.language) {
2795
3241
  console.log(picocolors.yellow("\u{1F44B} Project creation cancelled"));
2796
3242
  process.exit(0);
2797
3243
  }
2798
- template = response.template;
2799
- }
2800
- let runtime = "built-in";
2801
- let database = null;
2802
- let auth = null;
2803
- let packages = [];
2804
- let language = "javascript";
2805
- const languageResponse = await prompts({
2806
- type: "select",
2807
- name: "language",
2808
- message: "Would you like to use TypeScript or JavaScript?",
2809
- choices: [
2810
- { title: "\u{1F4D8} JavaScript", value: "javascript", description: "JavaScript with JSDoc type hints (recommended)" },
2811
- { title: "\u{1F4D5} TypeScript", value: "typescript", description: "Full TypeScript with static type checking" }
2812
- ],
2813
- initial: 0
2814
- });
2815
- if (!languageResponse.language) {
2816
- console.log(picocolors.yellow("\u{1F44B} Project creation cancelled"));
2817
- process.exit(0);
3244
+ language = languageResponse.language;
2818
3245
  }
2819
- language = languageResponse.language;
2820
- if (template === "custom" || template === "basic" || template === "fullstack" || template === "components") {
3246
+ if ((template === "basic" || template === "fullstack") && !options.skipPrompts) {
2821
3247
  const runtimeResponse = await prompts({
2822
3248
  type: "select",
2823
3249
  name: "runtime",
@@ -2835,46 +3261,50 @@ var createCommand = new Command("create").description("Create a new Coherent.js
2835
3261
  process.exit(0);
2836
3262
  }
2837
3263
  runtime = runtimeResponse.runtime;
2838
- } else if (template === "express") {
2839
- runtime = "express";
2840
- } else if (template === "fastify") {
2841
- runtime = "fastify";
2842
3264
  }
2843
- if (template === "fullstack" || template === "custom") {
2844
- const dbResponse = await prompts({
2845
- type: "select",
2846
- name: "database",
2847
- message: "Which database would you like to use?",
2848
- choices: [
2849
- { title: "\u{1F418} PostgreSQL", value: "postgres", description: "Powerful, open source relational database" },
2850
- { title: "\u{1F42C} MySQL", value: "mysql", description: "Popular open source relational database" },
2851
- { title: "\u{1F4E6} SQLite", value: "sqlite", description: "Lightweight, file-based database" },
2852
- { title: "\u{1F343} MongoDB", value: "mongodb", description: "NoSQL document database" },
2853
- { title: "\u274C None", value: "none", description: "Skip database setup" }
2854
- ],
2855
- initial: 0
2856
- });
2857
- if (!dbResponse.database) {
2858
- console.log(picocolors.yellow("\u{1F44B} Project creation cancelled"));
2859
- process.exit(0);
3265
+ if (template === "fullstack") {
3266
+ if (!options.skipPrompts) {
3267
+ const dbResponse = await prompts({
3268
+ type: "select",
3269
+ name: "database",
3270
+ message: "Which database would you like to use?",
3271
+ choices: [
3272
+ { title: "\u{1F418} PostgreSQL", value: "postgres", description: "Powerful, open source relational database" },
3273
+ { title: "\u{1F42C} MySQL", value: "mysql", description: "Popular open source relational database" },
3274
+ { title: "\u{1F4E6} SQLite", value: "sqlite", description: "Lightweight, file-based database" },
3275
+ { title: "\u{1F343} MongoDB", value: "mongodb", description: "NoSQL document database" },
3276
+ { title: "\u274C None", value: "none", description: "Skip database setup" }
3277
+ ],
3278
+ initial: 0
3279
+ });
3280
+ if (!dbResponse.database) {
3281
+ console.log(picocolors.yellow("\u{1F44B} Project creation cancelled"));
3282
+ process.exit(0);
3283
+ }
3284
+ database = dbResponse.database === "none" ? null : dbResponse.database;
3285
+ } else {
3286
+ database = options.database || null;
2860
3287
  }
2861
- database = dbResponse.database === "none" ? null : dbResponse.database;
2862
- const pkgResponse = await prompts({
2863
- type: "multiselect",
2864
- name: "packages",
2865
- message: "Select optional packages (space to select, enter to confirm):",
2866
- choices: [
2867
- { title: "@coherent.js/api", value: "api", description: "API framework with validation & OpenAPI", selected: template === "fullstack" },
2868
- { title: "@coherent.js/client", value: "client", description: "Client-side hydration & progressive enhancement" },
2869
- { title: "@coherent.js/i18n", value: "i18n", description: "Internationalization utilities" },
2870
- { title: "@coherent.js/forms", value: "forms", description: "Form handling utilities" },
2871
- { title: "@coherent.js/devtools", value: "devtools", description: "Development tools & debugging" },
2872
- { title: "@coherent.js/seo", value: "seo", description: "SEO optimization utilities" },
2873
- { title: "@coherent.js/testing", value: "testing", description: "Testing utilities & helpers" }
2874
- ]
2875
- });
2876
- packages = pkgResponse.packages || [];
2877
- if (packages.includes("api") || database) {
3288
+ if (!options.skipPrompts) {
3289
+ const pkgResponse = await prompts({
3290
+ type: "multiselect",
3291
+ name: "packages",
3292
+ message: "Select optional packages (space to select, enter to confirm):",
3293
+ choices: [
3294
+ { title: "@coherent.js/api", value: "api", description: "API framework with validation & OpenAPI", selected: template === "fullstack" },
3295
+ { title: "@coherent.js/client", value: "client", description: "Client-side hydration & progressive enhancement" },
3296
+ { title: "@coherent.js/i18n", value: "i18n", description: "Internationalization utilities" },
3297
+ { title: "@coherent.js/forms", value: "forms", description: "Form handling utilities" },
3298
+ { title: "@coherent.js/devtools", value: "devtools", description: "Development tools & debugging" },
3299
+ { title: "@coherent.js/seo", value: "seo", description: "SEO optimization utilities" },
3300
+ { title: "@coherent.js/testing", value: "testing", description: "Testing utilities & helpers" }
3301
+ ]
3302
+ });
3303
+ packages = pkgResponse.packages || [];
3304
+ } else {
3305
+ packages = template === "fullstack" ? ["api"] : [];
3306
+ }
3307
+ if (!options.skipPrompts && (packages.includes("api") || database)) {
2878
3308
  const authResponse = await prompts({
2879
3309
  type: "select",
2880
3310
  name: "auth",
@@ -2888,7 +3318,7 @@ var createCommand = new Command("create").description("Create a new Coherent.js
2888
3318
  });
2889
3319
  auth = authResponse.auth === "none" ? null : authResponse.auth;
2890
3320
  }
2891
- } else if (template === "basic" || template === "components") {
3321
+ } else if (template === "basic" && !options.skipPrompts) {
2892
3322
  const pkgResponse = await prompts({
2893
3323
  type: "multiselect",
2894
3324
  name: "packages",
@@ -2903,7 +3333,7 @@ var createCommand = new Command("create").description("Create a new Coherent.js
2903
3333
  packages = pkgResponse.packages || [];
2904
3334
  }
2905
3335
  let packageManager = "npm";
2906
- if (!options.skipInstall) {
3336
+ if (!options.skipInstall && !options.skipPrompts) {
2907
3337
  const pmResponse = await prompts({
2908
3338
  type: "select",
2909
3339
  name: "packageManager",
@@ -2921,6 +3351,56 @@ var createCommand = new Command("create").description("Create a new Coherent.js
2921
3351
  }
2922
3352
  packageManager = pmResponse.packageManager;
2923
3353
  }
3354
+ let dockerConfig = null;
3355
+ if (database && database !== "sqlite" && !options.skipPrompts) {
3356
+ const dockerResponse = await prompts({
3357
+ type: "confirm",
3358
+ name: "useDocker",
3359
+ message: "Would you like to include Docker configuration for the database?",
3360
+ initial: true
3361
+ });
3362
+ if (dockerResponse.useDocker) {
3363
+ const dockerDetailsResponse = await prompts([
3364
+ {
3365
+ type: "number",
3366
+ name: "dbPort",
3367
+ message: "What port should the database use?",
3368
+ initial: getDefaultDockerPort(database)
3369
+ },
3370
+ {
3371
+ type: "text",
3372
+ name: "dbName",
3373
+ message: "What should the database be named?",
3374
+ initial: "coherent_db"
3375
+ },
3376
+ {
3377
+ type: "text",
3378
+ name: "dbUser",
3379
+ message: "What should the database user be?",
3380
+ initial: "coherent_user"
3381
+ },
3382
+ {
3383
+ type: "text",
3384
+ name: "dbPassword",
3385
+ message: "What should the database password be?",
3386
+ initial: "coherent_pass"
3387
+ }
3388
+ ]);
3389
+ dockerConfig = {
3390
+ port: dockerDetailsResponse.dbPort || getDefaultDockerPort(database),
3391
+ name: dockerDetailsResponse.dbName,
3392
+ user: dockerDetailsResponse.dbUser,
3393
+ password: dockerDetailsResponse.dbPassword
3394
+ };
3395
+ }
3396
+ } else if (database && database !== "sqlite" && options.useDocker) {
3397
+ dockerConfig = {
3398
+ port: options.dockerDbPort || getDefaultDockerPort(database),
3399
+ name: options.dockerDbName || "coherent_db",
3400
+ user: options.dockerDbUser || "coherent_user",
3401
+ password: options.dockerDbPassword || "coherent_pass"
3402
+ };
3403
+ }
2924
3404
  const spinner = ora("Scaffolding project...").start();
2925
3405
  try {
2926
3406
  mkdirSync2(projectPath, { recursive: true });
@@ -2933,30 +3413,77 @@ var createCommand = new Command("create").description("Create a new Coherent.js
2933
3413
  packages,
2934
3414
  language,
2935
3415
  packageManager,
3416
+ dockerConfig,
2936
3417
  skipInstall: options.skipInstall,
2937
- skipGit: options.skipGit
3418
+ skipGit: options.skipGit,
3419
+ onProgress: (msg) => {
3420
+ spinner.text = msg;
3421
+ }
2938
3422
  });
2939
3423
  spinner.succeed("Project created successfully!");
2940
3424
  console.log();
2941
- console.log(picocolors.green("\u2705 Project created successfully!"));
3425
+ console.log(picocolors.green("Project created successfully!"));
2942
3426
  console.log();
2943
- console.log(picocolors.cyan("\u{1F4CB} Project Configuration:"));
2944
- console.log(picocolors.gray(" Language:"), picocolors.bold(language === "typescript" ? "TypeScript" : "JavaScript"));
2945
- console.log(picocolors.gray(" Runtime:"), picocolors.bold(runtime));
3427
+ console.log(picocolors.cyan("Configuration:"));
3428
+ console.log(picocolors.gray(" Template:"), picocolors.white(template === "fullstack" ? "Full Stack" : "Basic"));
3429
+ console.log(picocolors.gray(" Language:"), picocolors.white(language === "typescript" ? "TypeScript" : "JavaScript"));
3430
+ console.log(picocolors.gray(" Runtime:"), picocolors.white(runtime));
2946
3431
  if (database) {
2947
- console.log(picocolors.gray(" Database:"), picocolors.bold(database));
3432
+ console.log(picocolors.gray(" Database:"), picocolors.white(database));
2948
3433
  }
2949
3434
  if (auth) {
2950
- console.log(picocolors.gray(" Authentication:"), picocolors.bold(auth.toUpperCase()));
3435
+ console.log(picocolors.gray(" Auth:"), picocolors.white(auth.toUpperCase()));
2951
3436
  }
2952
3437
  if (packages.length > 0) {
2953
- console.log(picocolors.gray(" Packages:"), picocolors.bold(packages.join(", ")));
3438
+ const formattedPackages = packages.map((p) => `@coherent.js/${p}`).join(", ");
3439
+ console.log(picocolors.gray(" Packages:"), picocolors.white(formattedPackages));
2954
3440
  }
2955
3441
  console.log();
2956
- console.log(picocolors.cyan("Next steps:"));
2957
- console.log(picocolors.gray(" cd"), picocolors.bold(projectName));
3442
+ const fileExt = language === "typescript" ? ".ts" : ".js";
3443
+ console.log(picocolors.cyan("Project structure:"));
3444
+ console.log(picocolors.white(` ${projectName}/`));
3445
+ console.log(picocolors.gray(` src/`));
3446
+ console.log(picocolors.gray(` index${fileExt}`));
3447
+ console.log(picocolors.gray(` components/`));
3448
+ if (database) {
3449
+ console.log(picocolors.gray(` db/`));
3450
+ }
3451
+ if (auth || packages.includes("api")) {
3452
+ console.log(picocolors.gray(` api/`));
3453
+ }
3454
+ console.log(picocolors.gray(` public/`));
3455
+ console.log(picocolors.gray(` package.json`));
2958
3456
  if (database) {
2959
- console.log(picocolors.gray(" # Configure database in .env.example"));
3457
+ console.log(picocolors.gray(` .env.example`), picocolors.yellow("<-- Configure this!"));
3458
+ }
3459
+ console.log();
3460
+ const needsEnvConfig = database && database !== "sqlite";
3461
+ const envVars = [];
3462
+ if (needsEnvConfig) {
3463
+ if (database === "mongodb") {
3464
+ envVars.push("MONGODB_URI");
3465
+ } else {
3466
+ envVars.push("DB_HOST", "DB_PORT", "DB_NAME", "DB_USER", "DB_PASSWORD");
3467
+ }
3468
+ }
3469
+ if (auth === "jwt") {
3470
+ envVars.push("JWT_SECRET");
3471
+ }
3472
+ if (auth === "session") {
3473
+ envVars.push("SESSION_SECRET");
3474
+ }
3475
+ if (envVars.length > 0) {
3476
+ console.log(picocolors.yellow("Environment variables to configure:"));
3477
+ envVars.forEach((v) => console.log(picocolors.gray(` ${v}`)));
3478
+ console.log();
3479
+ }
3480
+ console.log(picocolors.cyan("Next steps:"));
3481
+ let stepNum = 1;
3482
+ console.log(picocolors.white(` ${stepNum}.`), picocolors.gray(`cd ${projectName}`));
3483
+ stepNum++;
3484
+ if (needsEnvConfig) {
3485
+ console.log(picocolors.white(` ${stepNum}.`), picocolors.gray("Edit .env with your database credentials"));
3486
+ stepNum++;
2960
3487
  }
2961
3488
  const pmCommands = {
2962
3489
  npm: { install: "npm install", dev: "npm run dev" },
@@ -2964,14 +3491,41 @@ var createCommand = new Command("create").description("Create a new Coherent.js
2964
3491
  pnpm: { install: "pnpm install", dev: "pnpm dev" }
2965
3492
  };
2966
3493
  const commands = pmCommands[packageManager] || pmCommands.npm;
2967
- if (!options.skipInstall) {
2968
- console.log(picocolors.gray(` ${commands.dev}`));
2969
- } else {
2970
- console.log(picocolors.gray(` ${commands.install}`));
2971
- console.log(picocolors.gray(` ${commands.dev}`));
3494
+ if (options.skipInstall) {
3495
+ console.log(picocolors.white(` ${stepNum}.`), picocolors.gray(commands.install));
3496
+ stepNum++;
2972
3497
  }
3498
+ console.log(picocolors.white(` ${stepNum}.`), picocolors.gray(commands.dev));
2973
3499
  console.log();
2974
- console.log(picocolors.gray("Happy coding! \u{1F389}"));
3500
+ if (!options.skipPrompts && !options.skipInstall) {
3501
+ const startResponse = await prompts({
3502
+ type: "confirm",
3503
+ name: "startDev",
3504
+ message: "Start development server now?",
3505
+ initial: true
3506
+ });
3507
+ if (startResponse.startDev) {
3508
+ console.log();
3509
+ console.log(picocolors.cyan("Starting development server..."));
3510
+ console.log(picocolors.gray(` ${commands.dev}`));
3511
+ console.log();
3512
+ try {
3513
+ const devProcess = spawn(commands.dev, [], {
3514
+ cwd: projectPath,
3515
+ stdio: "inherit",
3516
+ shell: true,
3517
+ detached: true
3518
+ });
3519
+ devProcess.unref();
3520
+ return;
3521
+ } catch {
3522
+ console.log(picocolors.yellow("Could not start development server automatically."));
3523
+ console.log(picocolors.gray(` Run manually: cd ${projectName} && ${commands.dev}`));
3524
+ console.log();
3525
+ }
3526
+ }
3527
+ }
3528
+ console.log(picocolors.gray("Happy coding!"));
2975
3529
  } catch (_error) {
2976
3530
  spinner.fail("Failed to create project");
2977
3531
  console.error(picocolors.red("\u274C Error:"), _error.message);
@@ -4579,7 +5133,7 @@ import { Command as Command3 } from "commander";
4579
5133
  import ora3 from "ora";
4580
5134
  import picocolors3 from "picocolors";
4581
5135
  import { execSync as execSync2 } from "child_process";
4582
- import { existsSync as existsSync6, readFileSync as readFileSync2 } from "fs";
5136
+ import { existsSync as existsSync6, readFileSync as readFileSync3 } from "fs";
4583
5137
  import { join as join6 } from "path";
4584
5138
  var buildCommand = new Command3("build").description("Build the project for production").option("-w, --watch", "watch for changes").option("--analyze", "analyze bundle size").option("--no-minify", "disable minification").option("--no-optimize", "disable optimizations").action(async (options) => {
4585
5139
  console.log(picocolors3.cyan("\u{1F3D7}\uFE0F Building Coherent.js project..."));
@@ -4591,7 +5145,7 @@ var buildCommand = new Command3("build").description("Build the project for prod
4591
5145
  }
4592
5146
  let packageJson;
4593
5147
  try {
4594
- packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf-8"));
5148
+ packageJson = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
4595
5149
  } catch {
4596
5150
  console.error(picocolors3.red("\u274C Failed to read package.json"));
4597
5151
  process.exit(1);
@@ -4685,8 +5239,8 @@ var buildCommand = new Command3("build").description("Build the project for prod
4685
5239
  import { Command as Command4 } from "commander";
4686
5240
  import ora4 from "ora";
4687
5241
  import picocolors4 from "picocolors";
4688
- import { spawn } from "child_process";
4689
- import { existsSync as existsSync7, readFileSync as readFileSync3 } from "fs";
5242
+ import { spawn as spawn2 } from "child_process";
5243
+ import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
4690
5244
  import { join as join7 } from "path";
4691
5245
  var devCommand = new Command4("dev").description("Start development server with hot reload").option("-p, --port <port>", "port number", "3000").option("-h, --host <host>", "host address", "localhost").option("--open", "open browser automatically").option("--no-hmr", "disable hot module replacement").action(async (options) => {
4692
5246
  console.log(picocolors4.cyan("\u{1F680} Starting Coherent.js development server..."));
@@ -4698,7 +5252,7 @@ var devCommand = new Command4("dev").description("Start development server with
4698
5252
  }
4699
5253
  let packageJson;
4700
5254
  try {
4701
- packageJson = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
5255
+ packageJson = JSON.parse(readFileSync4(packageJsonPath, "utf-8"));
4702
5256
  } catch {
4703
5257
  console.error(picocolors4.red("\u274C Failed to read package.json"));
4704
5258
  process.exit(1);
@@ -4708,7 +5262,7 @@ var devCommand = new Command4("dev").description("Start development server with
4708
5262
  let devProcess;
4709
5263
  if (packageJson.scripts && packageJson.scripts.dev) {
4710
5264
  spinner.text = "Running dev script...";
4711
- devProcess = spawn("npm", ["run", "dev"], {
5265
+ devProcess = spawn2("npm", ["run", "dev"], {
4712
5266
  stdio: "inherit",
4713
5267
  cwd: process.cwd(),
4714
5268
  shell: true,
@@ -4721,19 +5275,19 @@ var devCommand = new Command4("dev").description("Start development server with
4721
5275
  } else {
4722
5276
  spinner.text = "Starting default dev server...";
4723
5277
  if (existsSync7("vite.config.js") || existsSync7("vite.config.ts")) {
4724
- devProcess = spawn("npx", ["vite", "--port", options.port, "--host", options.host], {
5278
+ devProcess = spawn2("npx", ["vite", "--port", options.port, "--host", options.host], {
4725
5279
  stdio: "inherit",
4726
5280
  cwd: process.cwd(),
4727
5281
  shell: true
4728
5282
  });
4729
5283
  } else if (existsSync7("webpack.config.js")) {
4730
- devProcess = spawn("npx", ["webpack", "serve", "--port", options.port, "--host", options.host], {
5284
+ devProcess = spawn2("npx", ["webpack", "serve", "--port", options.port, "--host", options.host], {
4731
5285
  stdio: "inherit",
4732
5286
  cwd: process.cwd(),
4733
5287
  shell: true
4734
5288
  });
4735
5289
  } else if (packageJson.type === "module" || existsSync7("src/index.js")) {
4736
- devProcess = spawn("npx", ["nodemon", "src/index.js"], {
5290
+ devProcess = spawn2("npx", ["nodemon", "src/index.js"], {
4737
5291
  stdio: "inherit",
4738
5292
  cwd: process.cwd(),
4739
5293
  shell: true,
@@ -4798,11 +5352,12 @@ import { Command as Command5 } from "commander";
4798
5352
  import prompts3 from "prompts";
4799
5353
  import ora5 from "ora";
4800
5354
  import picocolors5 from "picocolors";
4801
- import { existsSync as existsSync10, readFileSync as readFileSync6 } from "fs";
5355
+ import process2, { env as env2 } from "node:process";
5356
+ import { existsSync as existsSync10, readFileSync as readFileSync7 } from "fs";
4802
5357
  import { resolve as resolve5 } from "path";
4803
5358
 
4804
5359
  // src/analyzers/component-analyzer.js
4805
- import { readFileSync as readFileSync4, existsSync as existsSync8 } from "fs";
5360
+ import { readFileSync as readFileSync5, existsSync as existsSync8 } from "fs";
4806
5361
  import { resolve as resolve3 } from "path";
4807
5362
 
4808
5363
  // ../../node_modules/.pnpm/@isaacs+balanced-match@4.0.1/node_modules/@isaacs/balanced-match/dist/esm/index.js
@@ -5693,7 +6248,7 @@ var path = {
5693
6248
  };
5694
6249
  var sep = defaultPlatform === "win32" ? path.win32.sep : path.posix.sep;
5695
6250
  minimatch.sep = sep;
5696
- var GLOBSTAR = Symbol("globstar **");
6251
+ var GLOBSTAR = /* @__PURE__ */ Symbol("globstar **");
5697
6252
  minimatch.GLOBSTAR = GLOBSTAR;
5698
6253
  var qmark2 = "[^/]";
5699
6254
  var star2 = qmark2 + "*?";
@@ -6404,7 +6959,6 @@ if (typeof AC === "undefined") {
6404
6959
  };
6405
6960
  }
6406
6961
  var shouldWarn = (code) => !warned.has(code);
6407
- var TYPE = Symbol("type");
6408
6962
  var isPosInt = (n) => n && n === Math.floor(n) && n > 0 && isFinite(n);
6409
6963
  var getUintArray = (max) => !isPosInt(max) ? null : max <= Math.pow(2, 8) ? Uint8Array : max <= Math.pow(2, 16) ? Uint16Array : max <= Math.pow(2, 32) ? Uint32Array : max <= Number.MAX_SAFE_INTEGER ? ZeroArray : null;
6410
6964
  var ZeroArray = class extends Array {
@@ -7780,37 +8334,37 @@ var isStream = (s) => !!s && typeof s === "object" && (s instanceof Minipass ||
7780
8334
  var isReadable = (s) => !!s && typeof s === "object" && s instanceof EventEmitter && typeof s.pipe === "function" && // node core Writable streams have a pipe() method, but it throws
7781
8335
  s.pipe !== Stream.Writable.prototype.pipe;
7782
8336
  var isWritable = (s) => !!s && typeof s === "object" && s instanceof EventEmitter && typeof s.write === "function" && typeof s.end === "function";
7783
- var EOF = Symbol("EOF");
7784
- var MAYBE_EMIT_END = Symbol("maybeEmitEnd");
7785
- var EMITTED_END = Symbol("emittedEnd");
7786
- var EMITTING_END = Symbol("emittingEnd");
7787
- var EMITTED_ERROR = Symbol("emittedError");
7788
- var CLOSED = Symbol("closed");
7789
- var READ = Symbol("read");
7790
- var FLUSH = Symbol("flush");
7791
- var FLUSHCHUNK = Symbol("flushChunk");
7792
- var ENCODING = Symbol("encoding");
7793
- var DECODER = Symbol("decoder");
7794
- var FLOWING = Symbol("flowing");
7795
- var PAUSED = Symbol("paused");
7796
- var RESUME = Symbol("resume");
7797
- var BUFFER = Symbol("buffer");
7798
- var PIPES = Symbol("pipes");
7799
- var BUFFERLENGTH = Symbol("bufferLength");
7800
- var BUFFERPUSH = Symbol("bufferPush");
7801
- var BUFFERSHIFT = Symbol("bufferShift");
7802
- var OBJECTMODE = Symbol("objectMode");
7803
- var DESTROYED = Symbol("destroyed");
7804
- var ERROR = Symbol("error");
7805
- var EMITDATA = Symbol("emitData");
7806
- var EMITEND = Symbol("emitEnd");
7807
- var EMITEND2 = Symbol("emitEnd2");
7808
- var ASYNC = Symbol("async");
7809
- var ABORT = Symbol("abort");
7810
- var ABORTED = Symbol("aborted");
7811
- var SIGNAL = Symbol("signal");
7812
- var DATALISTENERS = Symbol("dataListeners");
7813
- var DISCARDED = Symbol("discarded");
8337
+ var EOF = /* @__PURE__ */ Symbol("EOF");
8338
+ var MAYBE_EMIT_END = /* @__PURE__ */ Symbol("maybeEmitEnd");
8339
+ var EMITTED_END = /* @__PURE__ */ Symbol("emittedEnd");
8340
+ var EMITTING_END = /* @__PURE__ */ Symbol("emittingEnd");
8341
+ var EMITTED_ERROR = /* @__PURE__ */ Symbol("emittedError");
8342
+ var CLOSED = /* @__PURE__ */ Symbol("closed");
8343
+ var READ = /* @__PURE__ */ Symbol("read");
8344
+ var FLUSH = /* @__PURE__ */ Symbol("flush");
8345
+ var FLUSHCHUNK = /* @__PURE__ */ Symbol("flushChunk");
8346
+ var ENCODING = /* @__PURE__ */ Symbol("encoding");
8347
+ var DECODER = /* @__PURE__ */ Symbol("decoder");
8348
+ var FLOWING = /* @__PURE__ */ Symbol("flowing");
8349
+ var PAUSED = /* @__PURE__ */ Symbol("paused");
8350
+ var RESUME = /* @__PURE__ */ Symbol("resume");
8351
+ var BUFFER = /* @__PURE__ */ Symbol("buffer");
8352
+ var PIPES = /* @__PURE__ */ Symbol("pipes");
8353
+ var BUFFERLENGTH = /* @__PURE__ */ Symbol("bufferLength");
8354
+ var BUFFERPUSH = /* @__PURE__ */ Symbol("bufferPush");
8355
+ var BUFFERSHIFT = /* @__PURE__ */ Symbol("bufferShift");
8356
+ var OBJECTMODE = /* @__PURE__ */ Symbol("objectMode");
8357
+ var DESTROYED = /* @__PURE__ */ Symbol("destroyed");
8358
+ var ERROR = /* @__PURE__ */ Symbol("error");
8359
+ var EMITDATA = /* @__PURE__ */ Symbol("emitData");
8360
+ var EMITEND = /* @__PURE__ */ Symbol("emitEnd");
8361
+ var EMITEND2 = /* @__PURE__ */ Symbol("emitEnd2");
8362
+ var ASYNC = /* @__PURE__ */ Symbol("async");
8363
+ var ABORT = /* @__PURE__ */ Symbol("abort");
8364
+ var ABORTED = /* @__PURE__ */ Symbol("aborted");
8365
+ var SIGNAL = /* @__PURE__ */ Symbol("signal");
8366
+ var DATALISTENERS = /* @__PURE__ */ Symbol("dataListeners");
8367
+ var DISCARDED = /* @__PURE__ */ Symbol("discarded");
7814
8368
  var defer = (fn) => Promise.resolve().then(fn);
7815
8369
  var nodefer = (fn) => fn();
7816
8370
  var isEndish = (ev) => ev === "end" || ev === "finish" || ev === "prefinish";
@@ -8723,7 +9277,7 @@ var ChildrenCache = class extends LRUCache {
8723
9277
  });
8724
9278
  }
8725
9279
  };
8726
- var setAsCwd = Symbol("PathScurry setAsCwd");
9280
+ var setAsCwd = /* @__PURE__ */ Symbol("PathScurry setAsCwd");
8727
9281
  var PathBase = class {
8728
9282
  /**
8729
9283
  * the basename of this path
@@ -10190,7 +10744,7 @@ var PathScurryBase = class {
10190
10744
  const dirs = /* @__PURE__ */ new Set();
10191
10745
  const queue = [entry];
10192
10746
  let processing = 0;
10193
- const process2 = () => {
10747
+ const process3 = () => {
10194
10748
  let paused = false;
10195
10749
  while (!paused) {
10196
10750
  const dir = queue.shift();
@@ -10231,9 +10785,9 @@ var PathScurryBase = class {
10231
10785
  }
10232
10786
  }
10233
10787
  if (paused && !results.flowing) {
10234
- results.once("drain", process2);
10788
+ results.once("drain", process3);
10235
10789
  } else if (!sync2) {
10236
- process2();
10790
+ process3();
10237
10791
  }
10238
10792
  };
10239
10793
  let sync2 = true;
@@ -10241,7 +10795,7 @@ var PathScurryBase = class {
10241
10795
  sync2 = false;
10242
10796
  }
10243
10797
  };
10244
- process2();
10798
+ process3();
10245
10799
  return results;
10246
10800
  }
10247
10801
  streamSync(entry = this.cwd, opts = {}) {
@@ -10259,7 +10813,7 @@ var PathScurryBase = class {
10259
10813
  }
10260
10814
  const queue = [entry];
10261
10815
  let processing = 0;
10262
- const process2 = () => {
10816
+ const process3 = () => {
10263
10817
  let paused = false;
10264
10818
  while (!paused) {
10265
10819
  const dir = queue.shift();
@@ -10293,9 +10847,9 @@ var PathScurryBase = class {
10293
10847
  }
10294
10848
  }
10295
10849
  if (paused && !results.flowing)
10296
- results.once("drain", process2);
10850
+ results.once("drain", process3);
10297
10851
  };
10298
- process2();
10852
+ process3();
10299
10853
  return results;
10300
10854
  }
10301
10855
  chdir(path2 = this.cwd) {
@@ -11548,7 +12102,7 @@ async function analyzeComponentFile(filePath, _options = {}) {
11548
12102
  });
11549
12103
  return analysis;
11550
12104
  }
11551
- const content = readFileSync4(resolve3(filePath), "utf-8");
12105
+ const content = readFileSync5(resolve3(filePath), "utf-8");
11552
12106
  analysis.size = Buffer.byteLength(content, "utf8");
11553
12107
  analysis.lines = content.split("\n").length;
11554
12108
  const syntaxAnalysis = analyzeSyntax(content, filePath);
@@ -11909,7 +12463,7 @@ async function analyzeHydration(options = {}) {
11909
12463
  }
11910
12464
 
11911
12465
  // src/validators/project-validator.js
11912
- import { existsSync as existsSync9, readFileSync as readFileSync5 } from "fs";
12466
+ import { existsSync as existsSync9, readFileSync as readFileSync6 } from "fs";
11913
12467
  import { resolve as resolve4 } from "path";
11914
12468
  async function validateProject(_options = {}) {
11915
12469
  const validation = {
@@ -11976,7 +12530,7 @@ function validatePackageJson() {
11976
12530
  const issues = [];
11977
12531
  const recommendations = [];
11978
12532
  try {
11979
- const packageJson = JSON.parse(readFileSync5("package.json", "utf-8"));
12533
+ const packageJson = JSON.parse(readFileSync6("package.json", "utf-8"));
11980
12534
  const requiredFields = ["name", "version", "description"];
11981
12535
  requiredFields.forEach((field) => {
11982
12536
  const hasField = packageJson[field];
@@ -12132,7 +12686,7 @@ var debugCommand = new Command5("debug").description("Debug and analyze Coherent
12132
12686
  });
12133
12687
  if (!response.target) {
12134
12688
  console.log(picocolors5.yellow("\u{1F44B} Debug cancelled"));
12135
- process.exit(0);
12689
+ process2.exit(0);
12136
12690
  }
12137
12691
  debugTarget = response.target;
12138
12692
  }
@@ -12174,14 +12728,14 @@ var debugCommand = new Command5("debug").description("Debug and analyze Coherent
12174
12728
  console.log();
12175
12729
  console.log(picocolors5.red("\u274C Debug Error:"));
12176
12730
  console.log(picocolors5.gray(` ${error.message}`));
12177
- if (process.env.DEBUG) {
12731
+ if (env2.DEBUG) {
12178
12732
  console.log();
12179
12733
  console.log(picocolors5.gray("Stack trace:"));
12180
12734
  console.log(picocolors5.gray(error.stack));
12181
12735
  } else {
12182
12736
  console.log(picocolors5.gray(" Run with DEBUG=1 for detailed error information"));
12183
12737
  }
12184
- process.exit(1);
12738
+ process2.exit(1);
12185
12739
  }
12186
12740
  });
12187
12741
  debugCommand.command("component [name]").description("Analyze component structure and performance").option("-f, --file <file>", "component file path").option("--props <props>", "test component with specific props (JSON)").option("--deep", "perform deep structural analysis").action(async (name, options) => {
@@ -12260,7 +12814,7 @@ async function analyzeConfiguration(_options = {}) {
12260
12814
  };
12261
12815
  if (existsSync10("package.json")) {
12262
12816
  try {
12263
- const packageJson = JSON.parse(readFileSync6("package.json", "utf-8"));
12817
+ const packageJson = JSON.parse(readFileSync7("package.json", "utf-8"));
12264
12818
  const hasCoherentDeps = Object.keys(packageJson.dependencies || {}).some((dep) => dep.startsWith("@coherent.js/"));
12265
12819
  if (!hasCoherentDeps) {
12266
12820
  analysis.summary.issues.push("No Coherent.js dependencies found");
@@ -12369,12 +12923,12 @@ async function generateHTMLReport(result) {
12369
12923
  <h1>\u{1F50D} Coherent.js Debug Report</h1>
12370
12924
  <p>Generated: ${(/* @__PURE__ */ new Date()).toLocaleString()}</p>
12371
12925
  </div>
12372
-
12926
+
12373
12927
  <div class="section">
12374
12928
  <h2>Summary</h2>
12375
12929
  <pre>${JSON.stringify(result.summary, null, 2)}</pre>
12376
12930
  </div>
12377
-
12931
+
12378
12932
  ${result.issues ? `
12379
12933
  <div class="section">
12380
12934
  <h2>Issues</h2>
@@ -12383,7 +12937,7 @@ async function generateHTMLReport(result) {
12383
12937
  `).join("")}
12384
12938
  </div>
12385
12939
  ` : ""}
12386
-
12940
+
12387
12941
  ${result.recommendations ? `
12388
12942
  <div class="section">
12389
12943
  <h2>Recommendations</h2>
@@ -12409,7 +12963,7 @@ var __dirname = dirname3(__filename);
12409
12963
  var version = "1.0.1";
12410
12964
  try {
12411
12965
  const packagePath = join8(__dirname, "..", "package.json");
12412
- const packageJson = JSON.parse(readFileSync7(packagePath, "utf-8"));
12966
+ const packageJson = JSON.parse(readFileSync8(packagePath, "utf-8"));
12413
12967
  version = packageJson.version;
12414
12968
  } catch {
12415
12969
  }