webspresso 0.0.9 → 0.0.11

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.
package/README.md CHANGED
@@ -73,9 +73,70 @@ webspresso new my-app --no-tailwind
73
73
  - Asks if you want to install in the current directory
74
74
  - If current directory is not empty, shows a warning
75
75
  - Prompts for project name (defaults to current folder name)
76
+ - Asks if you will use a database (SQLite, PostgreSQL, or MySQL)
77
+ - If yes, adds the appropriate driver to `package.json` and creates `webspresso.db.js` config
78
+ - After project creation, asks if you want to install dependencies
79
+ - If yes, runs `npm install` and `npm run build:css`
80
+ - Then asks if you want to start the development server
81
+ - If yes, starts `npm run dev` automatically
82
+
83
+ **Auto Installation:**
84
+ ```bash
85
+ # With --install flag (semi-interactive)
86
+ webspresso new my-app --install
87
+ # → Automatically runs: npm install && npm run build:css
88
+ # → Then prompts: "Start development server?" [Y/n]
89
+ # → If yes: starts npm run dev (with watch:css if Tailwind enabled)
90
+
91
+ # Without --install flag (fully interactive)
92
+ webspresso new my-app
93
+ # → Prompts: "Install dependencies and build CSS now?" [Y/n]
94
+ # → If yes: runs npm install && npm run build:css
95
+ # → Then: "Start development server?" [Y/n]
96
+ # → If yes: starts npm run dev (with watch:css if Tailwind enabled)
97
+ ```
98
+
99
+ **Note:** When dev server starts with Tailwind CSS, it automatically runs `watch:css` in the background to watch for CSS changes.
100
+
101
+ **Database Selection:**
102
+ During project creation, you'll be asked if you want to use a database:
103
+ - **SQLite** (better-sqlite3) - Recommended for development and small projects
104
+ - **PostgreSQL** (pg) - For production applications
105
+ - **MySQL** (mysql2) - Alternative SQL database
106
+
107
+ If you select a database:
108
+ - The appropriate driver is added to `package.json` dependencies
109
+ - `webspresso.db.js` config file is created with proper settings
110
+ - `migrations/` directory is created
111
+ - `models/` directory is created
112
+ - `DATABASE_URL` is added to `.env.example` with a template
113
+
114
+ **Seed Data Generation:**
115
+ After selecting a database, you'll be asked if you want to generate seed data:
116
+ - If yes, `@faker-js/faker` is added to dependencies
117
+ - `seeds/` directory is created with `seeds/index.js`
118
+ - `npm run seed` script is added to `package.json`
119
+ - The seed script automatically detects models in `models/` directory and generates fake data based on their schemas
120
+
121
+ To run seeds after creating models:
122
+ ```bash
123
+ npm run seed
124
+ ```
125
+
126
+ The seed script will:
127
+ - Load all models from `models/` directory
128
+ - Generate 10 fake records per model (by default)
129
+ - Use smart field detection based on column names (email, name, title, etc.)
130
+
131
+ You can always add database support later by:
132
+ 1. Installing the driver: `npm install better-sqlite3` (or `pg`, `mysql2`)
133
+ 2. Creating `webspresso.db.js` config file
134
+ 3. Adding `DATABASE_URL` to your `.env` file
135
+ 4. Creating `models/` directory and defining your models
136
+ 5. Optionally adding seed support: `npm install @faker-js/faker` and creating `seeds/index.js`
76
137
 
77
138
  Options:
78
- - `-i, --install` - Auto run `npm install` and `npm run build:css`
139
+ - `-i, --install` - Auto run `npm install` and `npm run build:css` (non-interactive)
79
140
  - `--no-tailwind` - Skip Tailwind CSS setup
80
141
 
81
142
  The project includes:
@@ -1018,6 +1079,32 @@ npm install better-sqlite3
1018
1079
 
1019
1080
  ### Database Seeding
1020
1081
 
1082
+ **CLI Command:**
1083
+
1084
+ The easiest way to seed your database is using the CLI command:
1085
+
1086
+ ```bash
1087
+ # Run seeds (requires seeds/index.js)
1088
+ webspresso seed
1089
+
1090
+ # Setup seed files if they don't exist
1091
+ webspresso seed --setup
1092
+
1093
+ # Use custom database config
1094
+ webspresso seed --config ./custom-db-config.js
1095
+
1096
+ # Use different environment
1097
+ webspresso seed --env production
1098
+ ```
1099
+
1100
+ The `webspresso seed` command:
1101
+ - Automatically loads all models from `models/` directory
1102
+ - Generates fake data based on model schemas
1103
+ - Creates 10 records per model by default
1104
+ - Uses smart field detection for appropriate fake data
1105
+
1106
+ **Manual Setup:**
1107
+
1021
1108
  Generate fake data for testing and development using `@faker-js/faker`:
1022
1109
 
1023
1110
  ```bash
package/bin/webspresso.js CHANGED
@@ -121,6 +121,43 @@ program
121
121
 
122
122
  console.log(`\n🚀 Creating new Webspresso project: ${projectName}\n`);
123
123
 
124
+ // Ask about database
125
+ const { useDatabase, databaseType } = await inquirer.prompt([
126
+ {
127
+ type: 'confirm',
128
+ name: 'useDatabase',
129
+ message: 'Will you use a database?',
130
+ default: false
131
+ },
132
+ {
133
+ type: 'list',
134
+ name: 'databaseType',
135
+ message: 'Which database?',
136
+ choices: [
137
+ { name: 'SQLite (better-sqlite3)', value: 'better-sqlite3' },
138
+ { name: 'PostgreSQL (pg)', value: 'pg' },
139
+ { name: 'MySQL (mysql2)', value: 'mysql2' },
140
+ { name: 'None', value: null }
141
+ ],
142
+ default: 'better-sqlite3',
143
+ when: (answers) => answers.useDatabase
144
+ }
145
+ ]);
146
+
147
+ // Ask about seed data if database is selected
148
+ let useSeed = false;
149
+ if (useDatabase && databaseType) {
150
+ const { generateSeed } = await inquirer.prompt([
151
+ {
152
+ type: 'confirm',
153
+ name: 'generateSeed',
154
+ message: 'Generate seed data based on existing models?',
155
+ default: false
156
+ }
157
+ ]);
158
+ useSeed = generateSeed;
159
+ }
160
+
124
161
  // Create directory structure (skip root if using current dir)
125
162
  if (!useCurrentDir) {
126
163
  fs.mkdirSync(projectPath, { recursive: true });
@@ -130,6 +167,11 @@ program
130
167
  fs.mkdirSync(path.join(projectPath, 'views'), { recursive: true });
131
168
  fs.mkdirSync(path.join(projectPath, 'public'), { recursive: true });
132
169
 
170
+ // Create models directory if database is selected
171
+ if (useDatabase && databaseType) {
172
+ fs.mkdirSync(path.join(projectPath, 'models'), { recursive: true });
173
+ }
174
+
133
175
  // Create package.json
134
176
  const packageJson = {
135
177
  name: projectName,
@@ -146,6 +188,23 @@ program
146
188
  }
147
189
  };
148
190
 
191
+ // Add database driver if selected
192
+ if (useDatabase && databaseType) {
193
+ const dbDrivers = {
194
+ 'better-sqlite3': '^9.0.0',
195
+ 'pg': '^8.0.0',
196
+ 'mysql2': '^3.0.0'
197
+ };
198
+
199
+ packageJson.dependencies[databaseType] = dbDrivers[databaseType];
200
+ }
201
+
202
+ // Add faker if seed is selected
203
+ if (useSeed) {
204
+ packageJson.dependencies['@faker-js/faker'] = '^8.0.0';
205
+ packageJson.scripts.seed = 'node seeds/index.js';
206
+ }
207
+
149
208
  fs.writeFileSync(
150
209
  path.join(projectPath, 'package.json'),
151
210
  JSON.stringify(packageJson, null, 2) + '\n'
@@ -172,15 +231,186 @@ app.listen(PORT, () => {
172
231
  fs.writeFileSync(path.join(projectPath, 'server.js'), serverJs);
173
232
 
174
233
  // Create .env.example
175
- const envExample = `PORT=3000
234
+ let envExample = `PORT=3000
176
235
  NODE_ENV=development
177
236
  DEFAULT_LOCALE=en
178
237
  SUPPORTED_LOCALES=en,tr
179
238
  BASE_URL=http://localhost:3000
180
239
  `;
181
240
 
241
+ if (useDatabase && databaseType) {
242
+ if (databaseType === 'better-sqlite3') {
243
+ envExample += `DATABASE_URL=sqlite:./database.sqlite
244
+ `;
245
+ } else if (databaseType === 'pg') {
246
+ envExample += `DATABASE_URL=postgresql://user:password@localhost:5432/dbname
247
+ `;
248
+ } else if (databaseType === 'mysql2') {
249
+ envExample += `DATABASE_URL=mysql://user:password@localhost:3306/dbname
250
+ `;
251
+ }
252
+ }
253
+
182
254
  fs.writeFileSync(path.join(projectPath, '.env.example'), envExample);
183
255
 
256
+ // Create database config if database is selected
257
+ if (useDatabase && databaseType) {
258
+ let dbConfig = '';
259
+
260
+ if (databaseType === 'better-sqlite3') {
261
+ dbConfig = `module.exports = {
262
+ client: 'better-sqlite3',
263
+ connection: {
264
+ filename: process.env.DATABASE_URL?.replace('sqlite:', '') || './database.sqlite'
265
+ },
266
+ migrations: {
267
+ directory: './migrations',
268
+ tableName: 'knex_migrations',
269
+ },
270
+ useNullAsDefault: true
271
+ };
272
+ `;
273
+ } else if (databaseType === 'pg') {
274
+ dbConfig = `module.exports = {
275
+ client: 'pg',
276
+ connection: process.env.DATABASE_URL,
277
+ migrations: {
278
+ directory: './migrations',
279
+ tableName: 'knex_migrations',
280
+ },
281
+ pool: {
282
+ min: 2,
283
+ max: 10
284
+ }
285
+ };
286
+ `;
287
+ } else if (databaseType === 'mysql2') {
288
+ dbConfig = `module.exports = {
289
+ client: 'mysql2',
290
+ connection: process.env.DATABASE_URL,
291
+ migrations: {
292
+ directory: './migrations',
293
+ tableName: 'knex_migrations',
294
+ },
295
+ pool: {
296
+ min: 2,
297
+ max: 10
298
+ }
299
+ };
300
+ `;
301
+ }
302
+
303
+ fs.writeFileSync(path.join(projectPath, 'webspresso.db.js'), dbConfig);
304
+
305
+ // Create migrations directory
306
+ fs.mkdirSync(path.join(projectPath, 'migrations'), { recursive: true });
307
+ }
308
+
309
+ // Create seed files if seed is selected
310
+ if (useSeed) {
311
+ fs.mkdirSync(path.join(projectPath, 'seeds'), { recursive: true });
312
+
313
+ const seedIndex = `require('dotenv').config();
314
+ const { faker } = require('@faker-js/faker');
315
+ const path = require('path');
316
+ const fs = require('fs');
317
+ const { createDatabase, getAllModels } = require('webspresso/orm');
318
+ const dbConfig = require('./webspresso.db.js');
319
+
320
+ const db = createDatabase(dbConfig);
321
+ const seeder = db.seeder(faker);
322
+
323
+ /**
324
+ * Load all models from models/ directory
325
+ */
326
+ function loadModels() {
327
+ const modelsDir = path.join(__dirname, 'models');
328
+
329
+ if (!fs.existsSync(modelsDir)) {
330
+ return [];
331
+ }
332
+
333
+ const modelFiles = fs.readdirSync(modelsDir)
334
+ .filter(file => file.endsWith('.js') && !file.startsWith('_'));
335
+
336
+ const loadedModels = [];
337
+ for (const file of modelFiles) {
338
+ try {
339
+ require(path.join(modelsDir, file));
340
+ loadedModels.push(file);
341
+ } catch (error) {
342
+ console.warn(\`⚠️ Failed to load model from \${file}:\`, error.message);
343
+ }
344
+ }
345
+
346
+ return loadedModels;
347
+ }
348
+
349
+ /**
350
+ * Seed database with fake data
351
+ * This script automatically detects models in the models/ directory
352
+ * and generates seed data based on their schemas.
353
+ */
354
+ async function runSeeds() {
355
+ try {
356
+ console.log('🌱 Starting seed process...');
357
+
358
+ // Load all models
359
+ const loadedFiles = loadModels();
360
+
361
+ if (loadedFiles.length === 0) {
362
+ console.log('⚠️ No model files found in models/ directory.');
363
+ console.log(' Create models first, then run: npm run seed');
364
+ await db.knex.destroy();
365
+ return;
366
+ }
367
+
368
+ // Get all registered models
369
+ const models = getAllModels();
370
+
371
+ if (models.size === 0) {
372
+ console.log('⚠️ No models registered. Make sure your model files export models using defineModel().');
373
+ await db.knex.destroy();
374
+ return;
375
+ }
376
+
377
+ console.log(\`📦 Found \${models.size} model(s):\`);
378
+ for (const [name] of models) {
379
+ console.log(\` - \${name}\`);
380
+ }
381
+
382
+ // Seed each model
383
+ const results = {};
384
+ for (const [modelName, model] of models) {
385
+ console.log(\`\\n🌱 Seeding \${modelName}...\`);
386
+
387
+ // Default count: 10 records per model
388
+ const count = 10;
389
+ const records = await seeder.seed(modelName, count);
390
+ results[modelName] = records.length;
391
+
392
+ console.log(\`✅ Created \${records.length} \${modelName} record(s)\`);
393
+ }
394
+
395
+ console.log(\`\\n✨ Seed completed! Created:\`);
396
+ for (const [modelName, count] of Object.entries(results)) {
397
+ console.log(\` - \${count} \${modelName} record(s)\`);
398
+ }
399
+
400
+ await db.knex.destroy();
401
+ } catch (error) {
402
+ console.error('❌ Seed failed:', error);
403
+ await db.knex.destroy().catch(() => {});
404
+ process.exit(1);
405
+ }
406
+ }
407
+
408
+ runSeeds();
409
+ `;
410
+
411
+ fs.writeFileSync(path.join(projectPath, 'seeds', 'index.js'), seedIndex);
412
+ }
413
+
184
414
  // Create .gitignore
185
415
  const gitignore = `node_modules/
186
416
  .env
@@ -429,8 +659,8 @@ module.exports = {
429
659
  console.log('✅ Tailwind CSS setup complete!');
430
660
  }
431
661
 
432
- // Auto install if requested
433
- if (autoInstall) {
662
+ // Helper function to run installation
663
+ async function runInstallation(projectPath, useTailwind) {
434
664
  console.log('\n📦 Installing dependencies...\n');
435
665
  const { execSync } = require('child_process');
436
666
  try {
@@ -447,27 +677,137 @@ module.exports = {
447
677
  });
448
678
  }
449
679
 
450
- console.log('\n✅ Project ready!\n');
680
+ console.log('\n✅ Installation complete!\n');
681
+ } catch (err) {
682
+ console.error('❌ Installation failed:', err.message);
683
+ process.exit(1);
684
+ }
685
+ }
686
+
687
+ // Helper function to start dev server
688
+ function startDevServer(projectPath, useTailwind) {
689
+ console.log('\n🚀 Starting development server...\n');
690
+ console.log('Press Ctrl+C to stop\n');
691
+
692
+ const { spawn } = require('child_process');
693
+
694
+ if (useTailwind) {
695
+ // Start CSS watch and server together
696
+ const cssWatch = spawn('npm', ['run', 'watch:css'], {
697
+ stdio: 'inherit',
698
+ shell: true,
699
+ cwd: projectPath
700
+ });
701
+
702
+ const server = spawn('node', ['--watch', 'server.js'], {
703
+ stdio: 'inherit',
704
+ shell: true,
705
+ cwd: projectPath,
706
+ env: { ...process.env, PORT: process.env.PORT || '3000', NODE_ENV: 'development' }
707
+ });
708
+
709
+ // Handle exit
710
+ const cleanup = () => {
711
+ cssWatch.kill();
712
+ server.kill();
713
+ process.exit(0);
714
+ };
715
+
716
+ process.on('SIGINT', cleanup);
717
+ process.on('SIGTERM', cleanup);
718
+
719
+ cssWatch.on('exit', cleanup);
720
+ server.on('exit', cleanup);
721
+ } else {
722
+ // Just start server
723
+ const server = spawn('node', ['--watch', 'server.js'], {
724
+ stdio: 'inherit',
725
+ shell: true,
726
+ cwd: projectPath,
727
+ env: { ...process.env, PORT: process.env.PORT || '3000', NODE_ENV: 'development' }
728
+ });
729
+
730
+ server.on('exit', (code) => {
731
+ process.exit(code || 0);
732
+ });
733
+
734
+ process.on('SIGINT', () => {
735
+ server.kill();
736
+ process.exit(0);
737
+ });
738
+ }
739
+ }
740
+
741
+ // Auto install if requested or ask interactively
742
+ if (autoInstall) {
743
+ await runInstallation(projectPath, useTailwind);
744
+
745
+ // Ask if user wants to start dev server
746
+ const { shouldStartDev } = await inquirer.prompt([
747
+ {
748
+ type: 'confirm',
749
+ name: 'shouldStartDev',
750
+ message: 'Start development server?',
751
+ default: true
752
+ }
753
+ ]);
754
+
755
+ if (shouldStartDev) {
756
+ startDevServer(projectPath, useTailwind);
757
+ } else {
758
+ console.log('✅ Project ready!\n');
451
759
  console.log('Start developing:');
452
760
  if (!useCurrentDir) {
453
761
  console.log(` cd ${projectName}`);
454
762
  }
455
763
  console.log(' npm run dev\n');
456
- } catch (err) {
457
- console.error('❌ Installation failed:', err.message);
458
- process.exit(1);
459
764
  }
460
765
  } else {
461
- console.log('\n✅ Project created successfully!\n');
462
- console.log('Next steps:');
463
- if (!useCurrentDir) {
464
- console.log(` cd ${projectName}`);
465
- }
466
- console.log(' npm install');
467
- if (useTailwind) {
468
- console.log(' npm run build:css');
766
+ // Ask if user wants to install dependencies
767
+ const { shouldInstall } = await inquirer.prompt([
768
+ {
769
+ type: 'confirm',
770
+ name: 'shouldInstall',
771
+ message: 'Install dependencies and build CSS now?',
772
+ default: true
773
+ }
774
+ ]);
775
+
776
+ if (shouldInstall) {
777
+ await runInstallation(projectPath, useTailwind);
778
+
779
+ // Ask if user wants to start dev server
780
+ const { shouldStartDev } = await inquirer.prompt([
781
+ {
782
+ type: 'confirm',
783
+ name: 'shouldStartDev',
784
+ message: 'Start development server?',
785
+ default: true
786
+ }
787
+ ]);
788
+
789
+ if (shouldStartDev) {
790
+ startDevServer(projectPath, useTailwind);
791
+ } else {
792
+ console.log('\n✅ Project ready!\n');
793
+ console.log('Start developing:');
794
+ if (!useCurrentDir) {
795
+ console.log(` cd ${projectName}`);
796
+ }
797
+ console.log(' npm run dev\n');
798
+ }
799
+ } else {
800
+ console.log('\n✅ Project created successfully!\n');
801
+ console.log('Next steps:');
802
+ if (!useCurrentDir) {
803
+ console.log(` cd ${projectName}`);
804
+ }
805
+ console.log(' npm install');
806
+ if (useTailwind) {
807
+ console.log(' npm run build:css');
808
+ }
809
+ console.log(' npm run dev\n');
469
810
  }
470
- console.log(' npm run dev\n');
471
811
  }
472
812
  });
473
813
 
@@ -1132,6 +1472,174 @@ exports.down = function(knex) {
1132
1472
  `;
1133
1473
  }
1134
1474
 
1475
+ // seed command
1476
+ program
1477
+ .command('seed')
1478
+ .description('Run database seeders to populate database with fake data')
1479
+ .option('-c, --config <path>', 'Path to database config file')
1480
+ .option('-e, --env <environment>', 'Environment (development, production)', 'development')
1481
+ .option('--setup', 'Setup seed files if they don\'t exist')
1482
+ .action(async (options) => {
1483
+ // Check if it's a Webspresso project
1484
+ if (!fs.existsSync(path.join(process.cwd(), 'server.js')) &&
1485
+ !fs.existsSync(path.join(process.cwd(), 'pages'))) {
1486
+ console.error('❌ Not a Webspresso project! Run this command in your project directory.');
1487
+ process.exit(1);
1488
+ }
1489
+
1490
+ // Check for faker
1491
+ let faker;
1492
+ try {
1493
+ faker = require('@faker-js/faker');
1494
+ } catch {
1495
+ console.error('❌ @faker-js/faker not installed.');
1496
+ console.log(' Install it with: npm install @faker-js/faker');
1497
+ process.exit(1);
1498
+ }
1499
+
1500
+ // Load database config
1501
+ const { config, path: configPath } = loadDbConfig(options.config);
1502
+ console.log(`\n📦 Using config: ${configPath}`);
1503
+ console.log(` Environment: ${options.env}\n`);
1504
+
1505
+ // Check if models directory exists
1506
+ const modelsDir = path.join(process.cwd(), 'models');
1507
+ if (!fs.existsSync(modelsDir)) {
1508
+ console.error('❌ models/ directory not found.');
1509
+ console.log(' Create models first, then run: webspresso seed');
1510
+ process.exit(1);
1511
+ }
1512
+
1513
+ // Check if seeds directory exists
1514
+ const seedsDir = path.join(process.cwd(), 'seeds');
1515
+ const seedIndexPath = path.join(seedsDir, 'index.js');
1516
+
1517
+ if (!fs.existsSync(seedsDir) || !fs.existsSync(seedIndexPath)) {
1518
+ if (options.setup) {
1519
+ console.log('📝 Setting up seed files...\n');
1520
+
1521
+ // Create seeds directory
1522
+ if (!fs.existsSync(seedsDir)) {
1523
+ fs.mkdirSync(seedsDir, { recursive: true });
1524
+ }
1525
+
1526
+ // Create seed index file
1527
+ const seedIndex = `require('dotenv').config();
1528
+ const { faker } = require('@faker-js/faker');
1529
+ const path = require('path');
1530
+ const fs = require('fs');
1531
+ const { createDatabase, getAllModels } = require('webspresso/orm');
1532
+ const dbConfig = require('../webspresso.db.js');
1533
+
1534
+ const db = createDatabase(dbConfig);
1535
+ const seeder = db.seeder(faker);
1536
+
1537
+ /**
1538
+ * Load all models from models/ directory
1539
+ */
1540
+ function loadModels() {
1541
+ const modelsDir = path.join(__dirname, '..', 'models');
1542
+
1543
+ if (!fs.existsSync(modelsDir)) {
1544
+ return [];
1545
+ }
1546
+
1547
+ const modelFiles = fs.readdirSync(modelsDir)
1548
+ .filter(file => file.endsWith('.js') && !file.startsWith('_'));
1549
+
1550
+ const loadedModels = [];
1551
+ for (const file of modelFiles) {
1552
+ try {
1553
+ require(path.join(modelsDir, file));
1554
+ loadedModels.push(file);
1555
+ } catch (error) {
1556
+ console.warn(\`⚠️ Failed to load model from \${file}:\`, error.message);
1557
+ }
1558
+ }
1559
+
1560
+ return loadedModels;
1561
+ }
1562
+
1563
+ /**
1564
+ * Seed database with fake data
1565
+ * This script automatically detects models in the models/ directory
1566
+ * and generates seed data based on their schemas.
1567
+ */
1568
+ async function runSeeds() {
1569
+ try {
1570
+ console.log('🌱 Starting seed process...');
1571
+
1572
+ // Load all models
1573
+ const loadedFiles = loadModels();
1574
+
1575
+ if (loadedFiles.length === 0) {
1576
+ console.log('⚠️ No model files found in models/ directory.');
1577
+ console.log(' Create models first, then run: webspresso seed');
1578
+ await db.knex.destroy();
1579
+ return;
1580
+ }
1581
+
1582
+ // Get all registered models
1583
+ const models = getAllModels();
1584
+
1585
+ if (models.size === 0) {
1586
+ console.log('⚠️ No models registered. Make sure your model files export models using defineModel().');
1587
+ await db.knex.destroy();
1588
+ return;
1589
+ }
1590
+
1591
+ console.log(\`📦 Found \${models.size} model(s):\`);
1592
+ for (const [name] of models) {
1593
+ console.log(\` - \${name}\`);
1594
+ }
1595
+
1596
+ // Seed each model
1597
+ const results = {};
1598
+ for (const [modelName, model] of models) {
1599
+ console.log(\`\\n🌱 Seeding \${modelName}...\`);
1600
+
1601
+ // Default count: 10 records per model
1602
+ const count = 10;
1603
+ const records = await seeder.seed(modelName, count);
1604
+ results[modelName] = records.length;
1605
+
1606
+ console.log(\`✅ Created \${records.length} \${modelName} record(s)\`);
1607
+ }
1608
+
1609
+ console.log(\`\\n✨ Seed completed! Created:\`);
1610
+ for (const [modelName, count] of Object.entries(results)) {
1611
+ console.log(\` - \${count} \${modelName} record(s)\`);
1612
+ }
1613
+
1614
+ await db.knex.destroy();
1615
+ } catch (error) {
1616
+ console.error('❌ Seed failed:', error);
1617
+ await db.knex.destroy().catch(() => {});
1618
+ process.exit(1);
1619
+ }
1620
+ }
1621
+
1622
+ runSeeds();
1623
+ `;
1624
+
1625
+ fs.writeFileSync(seedIndexPath, seedIndex);
1626
+ console.log('✅ Seed files created!\n');
1627
+ } else {
1628
+ console.error('❌ seeds/index.js not found.');
1629
+ console.log(' Run with --setup flag to create seed files: webspresso seed --setup');
1630
+ process.exit(1);
1631
+ }
1632
+ }
1633
+
1634
+ // Run the seed script
1635
+ try {
1636
+ require(seedIndexPath);
1637
+ } catch (error) {
1638
+ console.error('❌ Failed to run seed:', error.message);
1639
+ process.exit(1);
1640
+ }
1641
+ });
1642
+
1135
1643
  // Parse arguments
1136
1644
  program.parse();
1137
1645
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webspresso",
3
- "version": "0.0.9",
3
+ "version": "0.0.11",
4
4
  "description": "Minimal, production-ready SSR framework for Node.js with file-based routing, Nunjucks templating, built-in i18n, and CLI tooling",
5
5
  "main": "index.js",
6
6
  "bin": {