@dbcube/cli 5.2.4 → 5.2.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dbcube/cli",
3
- "version": "5.2.4",
3
+ "version": "5.2.6",
4
4
  "main": "src/index.js",
5
5
  "scripts": {
6
6
  "dbcube": "node src/index.js"
@@ -28,11 +28,11 @@
28
28
  "access": "public"
29
29
  },
30
30
  "dependencies": {
31
- "@dbcube/schema-builder": "^5.2.4",
31
+ "@dbcube/schema-builder": "^5.2.6",
32
32
  "@inquirer/prompts": "^8.5.2",
33
33
  "alwait": "^1.0.0",
34
34
  "chalk": "4.1.2",
35
- "dbcube": "^5.2.4",
35
+ "dbcube": "^5.2.6",
36
36
  "dotenv": "^17.4.2",
37
37
  "fs-extra": "^11.3.5",
38
38
  "glob": "^13.0.6",
@@ -1,6 +1,7 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const chalk = require('chalk');
4
+ const ui = require('../utils/ui');
4
5
  const { execSync } = require('child_process');
5
6
 
6
7
  /**
@@ -66,18 +67,15 @@ function onChange(filename) {
66
67
  async function main() {
67
68
  const cubesDir = path.join(process.cwd(), 'dbcube');
68
69
  if (!fs.existsSync(cubesDir)) {
69
- console.error(`${chalk.red('❌')} dbcube/ directory not found — run: npx dbcube init`);
70
+ ui.error('dbcube/ directory not found.', ['Run: npx dbcube init']);
70
71
  process.exit(1);
71
72
  }
72
73
 
73
- console.log(`\n${chalk.green.bold('🚀 DBCube dev mode')}`);
74
- console.log(`${chalk.gray('Save a .cube file and the change applies automatically.')}\n`);
75
- console.log(`${chalk.green('👀 watching dbcube/ ...')} ${chalk.gray('(Ctrl+C to stop)')}`);
74
+ ui.header('DBCube dev mode', '🛰️');
75
+ ui.dim('Save a .cube file and the change applies automatically.');
76
+ console.log(`${chalk.green('›')} watching dbcube/ ... ${chalk.gray('(Ctrl+C to stop)')}\n`);
76
77
 
77
78
  fs.watch(cubesDir, { recursive: true }, (_event, filename) => onChange(filename));
78
79
  }
79
80
 
80
- main().catch(error => {
81
- console.error('Error fatal:', error);
82
- process.exit(1);
83
- });
81
+ main().catch(ui.handleError);
@@ -2,6 +2,7 @@ const fs = require('fs');
2
2
  const path = require('path');
3
3
  const chalk = require('chalk');
4
4
  const ConfigFileUtils = require('../utils/ConfigFileUtils');
5
+ const ui = require('../utils/ui');
5
6
  const { Engine } = require('@dbcube/schema-builder');
6
7
 
7
8
  /**
@@ -13,7 +14,7 @@ const warn = (msg) => console.log(` ${chalk.yellow('⚠')} ${msg}`);
13
14
  const fail = (msg) => console.log(` ${chalk.red('✗')} ${msg}`);
14
15
 
15
16
  async function main() {
16
- console.log(`\n🩺 ${chalk.green.bold('DBCube Doctor')}\n`);
17
+ ui.header('DBCube Doctor', '🩺');
17
18
  let problems = 0;
18
19
 
19
20
  // 1. Node version
@@ -21,13 +22,14 @@ async function main() {
21
22
  if (major >= 16) ok(`Node.js ${process.versions.node}`);
22
23
  else { fail(`Node.js ${process.versions.node} — DBCube requires >= 16`); problems++; }
23
24
 
24
- // 2. Config file
25
- const configPath = path.join(process.cwd(), 'dbcube.config.js');
25
+ // 2. Config file (.js o .cjs — getConfigPath prefiere .cjs en proyectos ESM)
26
+ const configPath = ConfigFileUtils.getConfigPath();
27
+ const configName = path.basename(configPath);
26
28
  if (!fs.existsSync(configPath)) {
27
- fail('dbcube.config.js not found — run: npx dbcube init');
29
+ fail(`${configName} not found — run: npx dbcube init`);
28
30
  problems++;
29
31
  } else {
30
- ok('dbcube.config.js found');
32
+ ok(`${configName} found`);
31
33
  }
32
34
 
33
35
  // 3. Configured databases
@@ -93,7 +95,4 @@ async function main() {
93
95
  process.exit(0);
94
96
  }
95
97
 
96
- main().catch(error => {
97
- console.error('Error fatal:', error);
98
- process.exit(1);
99
- });
98
+ main().catch(ui.handleError);
@@ -1,6 +1,7 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const chalk = require('chalk');
4
+ const ui = require('../utils/ui');
4
5
 
5
6
  /**
6
7
  * dbcube generate — Generates TypeScript interfaces from .table.cube files.
@@ -154,7 +155,4 @@ async function main() {
154
155
  console.log(` const rows = await db.table('${schemaEntries[0] ? schemaEntries[0].tableName : 'users'}').get() as ${schemaEntries[0] ? schemaEntries[0].ifaceName : 'User'}[];\n`);
155
156
  }
156
157
 
157
- main().catch(error => {
158
- console.error('Error fatal:', error);
159
- process.exit(1);
160
- });
158
+ main().catch(ui.handleError);
@@ -1,13 +1,14 @@
1
1
  const chalk = require('chalk');
2
+ const ui = require('../utils/ui');
2
3
 
3
4
  /**
4
5
  * Shows help information with all available Dbcube CLI commands
5
6
  */
6
7
  async function showHelp() {
7
8
  try {
8
- console.log(`\n${chalk.green('🚀 Dbcube CLI - Command Reference')}`);
9
- console.log(`${chalk.gray('A powerful database toolkit for modern applications')}\n`);
10
-
9
+ ui.banner();
10
+ console.log('');
11
+
11
12
  console.log(`${chalk.cyan.bold('USAGE:')}`);
12
13
  console.log(` ${chalk.white('npx dbcube')} ${chalk.yellow('<command>')} ${chalk.gray('[options]')}\n`);
13
14
 
@@ -97,13 +98,9 @@ async function showHelp() {
97
98
  console.log(` ${chalk.white('Issues:')} ${chalk.blue('https://github.com/Dbcube/query-builder/issues')}\n`);
98
99
 
99
100
  } catch (error) {
100
- console.error('❌ Error showing help:', error.message);
101
- process.exit(1);
101
+ ui.handleError(error);
102
102
  }
103
103
  }
104
104
 
105
105
  // Ejecutar función
106
- showHelp().catch(error => {
107
- console.error('Error fatal:', error);
108
- process.exit(1);
109
- });
106
+ showHelp().catch(ui.handleError);
@@ -2,6 +2,7 @@ const fs = require('fs');
2
2
  const path = require('path');
3
3
  const chalk = require('chalk');
4
4
  const ConfigFileUtils = require('../utils/ConfigFileUtils');
5
+ const ui = require('../utils/ui');
5
6
 
6
7
  /**
7
8
  * dbcube init — Scaffolds a new DBCube project:
@@ -9,15 +10,17 @@ const ConfigFileUtils = require('../utils/ConfigFileUtils');
9
10
  */
10
11
  async function main() {
11
12
  const root = process.cwd();
12
- console.log(`\n💚 ${chalk.green('Initializing DBCube project...')}\n`);
13
+ ui.header('Initializing DBCube project', '📦');
14
+ console.log('');
13
15
 
14
- // 1. dbcube.config.js
15
- const configPath = path.join(root, 'dbcube.config.js');
16
+ // 1. dbcube.config.(js|cjs) — getConfigPath elige .cjs en proyectos ESM
17
+ const configPath = ConfigFileUtils.getConfigPath();
18
+ const configName = path.basename(configPath);
16
19
  if (fs.existsSync(configPath)) {
17
- console.log(` ${chalk.yellow('•')} dbcube.config.js already exists — skipped`);
20
+ console.log(` ${chalk.yellow('•')} ${configName} already exists — skipped`);
18
21
  } else {
19
22
  ConfigFileUtils.crearArchivoConfig(configPath);
20
- console.log(` ${chalk.green('✓')} dbcube.config.js created`);
23
+ console.log(` ${chalk.green('✓')} ${configName} created`);
21
24
  }
22
25
 
23
26
  // 2. dbcube/ directory
@@ -76,7 +79,4 @@ async function main() {
76
79
  console.log(` 4. ${chalk.white('npx dbcube generate')} ${chalk.gray('— generate TypeScript types')}\n`);
77
80
  }
78
81
 
79
- main().catch(error => {
80
- console.error('Error fatal:', error);
81
- process.exit(1);
82
- });
82
+ main().catch(ui.handleError);
@@ -3,6 +3,7 @@ const path = require('path');
3
3
  const chalk = require('chalk');
4
4
  const { Schema } = require('@dbcube/schema-builder');
5
5
  const ConfigFileUtils = require('../../utils/ConfigFileUtils');
6
+ const ui = require('../../utils/ui');
6
7
  const { loadHistory, saveHistory } = require('./lib');
7
8
 
8
9
  /**
@@ -66,7 +67,4 @@ async function main() {
66
67
  }
67
68
  }
68
69
 
69
- main().catch(error => {
70
- console.error(`${chalk.red('❌ Rollback failed:')}`, error.message);
71
- process.exit(1);
72
- });
70
+ main().catch(ui.handleError);
@@ -1,5 +1,6 @@
1
1
  const path = require('path');
2
2
  const chalk = require('chalk');
3
+ const ui = require('../../utils/ui');
3
4
  const { loadHistory, hashFile, collectAlterFiles } = require('./lib');
4
5
 
5
6
  /**
@@ -49,7 +50,4 @@ async function main() {
49
50
  console.log('');
50
51
  }
51
52
 
52
- main().catch(error => {
53
- console.error('Error fatal:', error);
54
- process.exit(1);
55
- });
53
+ main().catch(ui.handleError);
@@ -21,8 +21,7 @@ async function addDatabaseConfiguration(databaseName = null, motor = null) {
21
21
  databaseName = await input({
22
22
  message: 'Nombre de referencia a la base de datos:',
23
23
  validate: (value) => {
24
- const rootPath = path.resolve(process.cwd());
25
- const configPath = path.join(rootPath, 'dbcube.config.js');
24
+ const configPath = ConfigFileUtils.getConfigPath();
26
25
  const getconfig = require(configPath);
27
26
  const config = new Config();
28
27
  getconfig(config);
@@ -63,13 +63,13 @@ async function main() {
63
63
 
64
64
  await createDatabasePhysically(parsedArgs.name);
65
65
  } catch (error) {
66
- console.error('Error inesperado:', error);
66
+ console.error(`\n${chalk.red('')} ${error.message || error}`);
67
67
  process.exit(1);
68
68
  }
69
69
  }
70
70
 
71
71
  // Ejecutar el comando
72
72
  main().catch(error => {
73
- console.error('Error fatal:', error);
73
+ console.error(`\n${chalk.red('')} ${error.message || error}`);
74
74
  process.exit(1);
75
75
  });
@@ -10,22 +10,15 @@ const path = require('path');
10
10
  * Función para crear una nueva base de datos con configuración (Proceso completo en dos fases)
11
11
  */
12
12
  async function createNewDatabase() {
13
- console.clear();
14
13
  try {
15
- console.log(`\n💚 ${chalk.green("Proceso de creación de base de datos...")}`);
16
- console.log('📋 Fase 1: Configuración');
17
- console.log('🏗️ Fase 2: Creación física\n');
18
-
19
- // Fase 1: Ejecutar addDatabaseConfig.js
20
- console.log('🔧 Iniciando configuración de base de datos...');
21
-
14
+ // Fase 1: configuración interactiva (addDatabaseConfig.js trae su propia UI)
22
15
  try {
23
16
  execFileSync(process.execPath, [path.join(__dirname, 'addDatabaseConfig.js')], {
24
17
  stdio: 'inherit',
25
18
  cwd: process.cwd()
26
19
  });
27
20
  } catch (error) {
28
- console.error(' Error en la fase de configuración:', error.message);
21
+ console.error(`\n${chalk.red('✖')} No se pudo completar la configuración.`);
29
22
  process.exit(1);
30
23
  }
31
24
 
@@ -37,32 +30,24 @@ async function createNewDatabase() {
37
30
  try {
38
31
  databaseName = fs.readFileSync(tempFile, 'utf8');
39
32
  } catch (error) {
40
- console.error(' Error: No se pudo obtener el nombre de la base de datos configurada');
33
+ console.error(`\n${chalk.red('✖')} No se pudo obtener el nombre de la base de datos configurada.`);
41
34
  process.exit(1);
42
35
  } finally {
43
- // Limpiar el archivo temporal pase lo que pase
44
36
  try { fs.unlinkSync(tempFile); } catch { /* ya no existe */ }
45
37
  }
46
38
 
47
- console.log('\n🏗️ Iniciando creación física de la base de datos...');
48
-
49
- // Fase 2: Ejecutar createDatabase.js. execFileSync con array de
50
- // argumentos: el nombre no pasa por el shell (sin inyección de comandos)
39
+ // Fase 2: creación física (createDatabase.js trae su propia UI de resumen)
51
40
  try {
52
41
  execFileSync(process.execPath, [path.join(__dirname, 'createDatabase.js'), `--name=${databaseName}`], {
53
42
  stdio: 'inherit',
54
43
  cwd: process.cwd()
55
44
  });
56
45
  } catch (error) {
57
- console.error('❌ Error en la fase de creación:', error.message);
46
+ // createDatabase.js ya imprimió el detalle del error
58
47
  process.exit(1);
59
48
  }
60
-
61
- console.log(`\n🎉 ${chalk.green("¡Base de datos creada exitosamente!")}`);
62
- console.log(`✅ Configuración y creación de '${databaseName}' completadas\n`);
63
-
64
49
  } catch (error) {
65
- console.error('Error al crear la base de datos:', error);
50
+ console.error(`\n${chalk.red('')} ${error.message}`);
66
51
  process.exit(1);
67
52
  }
68
53
  }
@@ -81,12 +66,12 @@ async function useExistingDatabase(databaseName) {
81
66
  cwd: process.cwd()
82
67
  });
83
68
  } catch (error) {
84
- console.error('❌ Error al crear la base de datos:', error.message);
69
+ // createDatabase.js ya imprimió el detalle del error
85
70
  process.exit(1);
86
71
  }
87
72
 
88
73
  } catch (error) {
89
- console.log('❌ Error al crear la base de datos:', error);
74
+ console.error(`\n${chalk.red('')} ${error.message}`);
90
75
  process.exit(1);
91
76
  }
92
77
  }
@@ -134,12 +119,19 @@ async function main() {
134
119
  await useExistingDatabase(selected);
135
120
  }
136
121
  } catch (error) {
137
- console.error('Error inesperado:', error);
122
+ // Ctrl+C / cierre del prompt interactivo: salir en silencio, sin stack.
123
+ if (error && (error.name === 'ExitPromptError' || /force closed/i.test(error.message || ''))) {
124
+ console.log(`\n${chalk.gray('Cancelado.')}`);
125
+ process.exit(0);
126
+ }
127
+ // Errores de config ya vienen con mensaje claro y accionable.
128
+ console.error(`\n${chalk.red('✖')} ${error.message}`);
129
+ process.exit(1);
138
130
  }
139
131
  }
140
132
 
141
133
  // Ejecutar el ejemplo
142
134
  main().catch(error => {
143
- console.error('Error fatal:', error);
135
+ console.error(`\n${chalk.red('')} ${error.message}`);
144
136
  process.exit(1);
145
137
  });
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  const chalk = require('chalk');
3
+ const ui = require('../../utils/ui');
3
4
  const { select } = require('@inquirer/prompts');
4
5
  const path = require('path');
5
6
  const fs = require('fs');
@@ -292,7 +293,4 @@ async function main() {
292
293
  }
293
294
  }
294
295
 
295
- main().catch(err => {
296
- console.error(chalk.red('\n❌ Error inesperado:'), err.message);
297
- process.exit(1);
298
- });
296
+ main().catch(ui.handleError);
@@ -2,6 +2,7 @@ const fs = require('fs');
2
2
  const path = require('path');
3
3
  const chalk = require('chalk');
4
4
  const ConfigFileUtils = require('../../utils/ConfigFileUtils');
5
+ const ui = require('../../utils/ui');
5
6
  const { Engine } = require('@dbcube/schema-builder');
6
7
 
7
8
  /**
@@ -211,7 +212,11 @@ async function main() {
211
212
  const dbs = targetDb ? configured.filter(d => d.name === targetDb) : configured;
212
213
 
213
214
  if (dbs.length === 0) {
214
- console.error(`${chalk.red('❌')} ${targetDb ? `Database '${targetDb}' is not configured` : 'No databases configured'} in dbcube.config.js`);
215
+ ui.error(
216
+ targetDb ? `Database '${targetDb}' is not configured in dbcube.config.js`
217
+ : 'No databases configured in dbcube.config.js',
218
+ ['Run: npx dbcube run database:create']
219
+ );
215
220
  process.exit(1);
216
221
  }
217
222
 
@@ -247,7 +252,4 @@ async function main() {
247
252
  process.exit(0);
248
253
  }
249
254
 
250
- main().catch(error => {
251
- console.error(`${chalk.red('❌ Pull failed:')}`, error.message);
252
- process.exit(1);
253
- });
255
+ main().catch(ui.handleError);
@@ -1,33 +1,21 @@
1
- const { Schema } = require('@dbcube/schema-builder');
2
- const ConfigFileUtils = require('./../../../utils/ConfigFileUtils');
3
-
4
- async function main() {
5
- try {
6
- const args = process.argv.slice(2);
7
- const seederName = args.find(a => !a.startsWith('--'));
8
-
9
- const configuredDatabases = await ConfigFileUtils.getConfiguredDatabases();
10
-
11
- for (const config of configuredDatabases) {
12
- const schema = new Schema(config.name);
13
- await schema.executeSeeders(seederName);
14
- }
15
- } catch (error) {
16
- if (error.message.includes("reading 'init'")) {
17
- console.error('❌ Configuracion de base de datos no encontrada\n');
18
- console.error('Ejecute el comando para crear una nueva base de datos:');
19
- console.error(`\tnpx dbcube run database:create`);
20
- console.error('\nO verifique que la base de datos este configurada en el archivo dbcube.config.js\n');
21
- process.exit(1);
22
- } else if (error.message.includes("reading 'getDatabase'")) {
23
- console.error('- Se sugiere cambiar el linea o crear la base de datos a la que se hace referencia.');
24
- } else {
25
- console.error(`❌ ${error.message}`);
26
- if (process.env.DEBUG) console.error(error);
27
- process.exit(1);
28
- }
29
- }
30
- }
31
-
32
- // Ejecutar el ejemplo
33
- main().catch(console.error);
1
+ const { Schema } = require('@dbcube/schema-builder');
2
+ const ConfigFileUtils = require('./../../../utils/ConfigFileUtils');
3
+ const ui = require('./../../../utils/ui');
4
+
5
+ async function main() {
6
+ try {
7
+ const args = process.argv.slice(2);
8
+ const seederName = args.find(a => !a.startsWith('--'));
9
+
10
+ const configuredDatabases = await ConfigFileUtils.getConfiguredDatabases();
11
+
12
+ for (const config of configuredDatabases) {
13
+ const schema = new Schema(config.name);
14
+ await schema.executeSeeders(seederName);
15
+ }
16
+ } catch (error) {
17
+ ui.handleError(error);
18
+ }
19
+ }
20
+
21
+ main().catch(ui.handleError);
@@ -2,6 +2,7 @@ const fs = require('fs');
2
2
  const path = require('path');
3
3
  const { Schema } = require('@dbcube/schema-builder');
4
4
  const ConfigFileUtils = require('./../../../utils/ConfigFileUtils');
5
+ const ui = require('./../../../utils/ui');
5
6
  const { loadHistory, saveHistory, hashFile, collectAlterFiles, buildReverse } = require('../../migrate/lib');
6
7
 
7
8
  /**
@@ -73,33 +74,21 @@ async function main() {
73
74
  console.log(' Status: npx dbcube migrate:status · Rollback: npx dbcube migrate:rollback\n');
74
75
  }
75
76
  } catch (error) {
76
- if (error.message.includes("reading 'init'")) {
77
- console.error(' Configuracion de base de datos no encontrada\n');
78
- console.error('Ejecute el comando para crear una nueva base de datos:');
79
- console.error(`\tdbcube run database:create`);
80
- console.error('\nO verifique que la base de datos este configurada en el archivo dbcube.config.js\n');
81
- process.exit(1);
82
- } else if (error.message.includes("There are no .alter.cube files")) {
83
- console.error('❌ No se encontraron archivos .alter.cube en la carpeta dbcube/\n');
84
- console.error('Crea un archivo .alter.cube con la siguiente estructura:');
85
- console.error('');
86
- console.error(' @database("nombre_db");');
87
- console.error(' @table("nombre_tabla");');
88
- console.error('');
89
- console.error(' @addColumn({');
90
- console.error(' nueva_columna: {');
91
- console.error(' type: "varchar";');
92
- console.error(' length: "255";');
93
- console.error(' options: ["not null"];');
94
- console.error(' };');
95
- console.error(' });');
96
- console.error('');
97
- process.exit(1);
98
- } else {
99
- console.error('Error:', error.message);
77
+ if (error.message && error.message.includes("There are no .alter.cube files")) {
78
+ ui.error('No .alter.cube files found in dbcube/.', [
79
+ 'Create one, e.g. dbcube/add_email.alter.cube:',
80
+ ]);
81
+ console.error(ui.chalk.gray([
82
+ ' @database("my_db");',
83
+ ' @table("users");',
84
+ ' @addColumn({',
85
+ ' email: { type: "varchar"; length: "255"; options: ["not null"]; };',
86
+ ' });',
87
+ ].join('\n')) + '\n');
100
88
  process.exit(1);
101
89
  }
90
+ ui.handleError(error);
102
91
  }
103
92
  }
104
93
 
105
- main().catch(console.error);
94
+ main().catch(ui.handleError);
@@ -1,6 +1,7 @@
1
1
  const chalk = require('chalk');
2
2
  const { Schema } = require('@dbcube/schema-builder');
3
3
  const ConfigFileUtils = require('./../../../utils/ConfigFileUtils');
4
+ const ui = require('./../../../utils/ui');
4
5
 
5
6
  /**
6
7
  * dbcube run table:fresh [--seeder] [--force]
@@ -63,19 +64,8 @@ async function main() {
63
64
  console.log(`\n${chalk.yellow('Aborted.')} ${chalk.gray('No changes were made.')}\n`);
64
65
  process.exit(0);
65
66
  }
66
- if (error.message.includes("reading 'init'")) {
67
- console.error('❌ Configuracion de base de datos no encontrada\n');
68
- console.error('Ejecute el comando para crear una nueva base de datos:');
69
- console.error(`\tdbcube run database:create`);
70
- console.error('\nO verifique que la base de datos este configurada en el archivo dbcube.config.js\n');
71
- process.exit(1);
72
- } else if (error.message.includes("reading 'getDatabase'")) {
73
- console.error('- Se sugiere cambiar el linea o crear la base de datos a la que se hace referencia.');
74
- } else {
75
- console.error('Error:', error.message);
76
- process.exit(1);
77
- }
67
+ ui.handleError(error);
78
68
  }
79
69
  }
80
70
 
81
- main().catch(console.error);
71
+ main().catch(ui.handleError);
@@ -1,30 +1,17 @@
1
- const { Schema } = require('@dbcube/schema-builder');
2
- const ConfigFileUtils = require('./../../../utils/ConfigFileUtils');
3
-
4
- async function main() {
5
- try {
6
- const configuredDatabases = await ConfigFileUtils.getConfiguredDatabases();
7
- // Recorrer cada archivo y mostrar su contenido
8
- for (const config of configuredDatabases) {
9
- const schema = new Schema(config.name);
10
- await schema.refreshTables();
11
- }
12
- } catch (error) {
13
- if (error.message.includes("reading 'init'")) {
14
- console.error('❌ Configuracion de base de datos no encontrada\n');
15
- console.error('Ejecute el comando para crear una nueva base de datos:');
16
- console.error(`\tnpx dbcube run database:create`);
17
- console.error('\nO verifique que la base de datos este configurada en el archivo dbcube.config.js\n');
18
- process.exit(1);
19
- } else if (error.message.includes("reading 'getDatabase'")) {
20
- console.error('- Se sugiere cambiar el linea o crear la base de datos a la que se hace referencia.');
21
- } else {
22
- console.error(`❌ ${error.message}`);
23
- if (process.env.DEBUG) console.error(error);
24
- process.exit(1);
25
- }
26
- }
27
- }
28
-
29
- // Ejecutar el ejemplo
30
- main().catch(console.error);
1
+ const { Schema } = require('@dbcube/schema-builder');
2
+ const ConfigFileUtils = require('./../../../utils/ConfigFileUtils');
3
+ const ui = require('./../../../utils/ui');
4
+
5
+ async function main() {
6
+ try {
7
+ const configuredDatabases = await ConfigFileUtils.getConfiguredDatabases();
8
+ for (const config of configuredDatabases) {
9
+ const schema = new Schema(config.name);
10
+ await schema.refreshTables();
11
+ }
12
+ } catch (error) {
13
+ ui.handleError(error);
14
+ }
15
+ }
16
+
17
+ main().catch(ui.handleError);
@@ -1,32 +1,18 @@
1
- const { Schema } = require('@dbcube/schema-builder');
2
- const ConfigFileUtils = require('./../../../utils/ConfigFileUtils');
3
-
4
- async function main() {
5
- try {
6
- const configuredDatabases = await ConfigFileUtils.getConfiguredDatabases();
7
-
8
- // Recorrer cada archivo y mostrar su contenido
9
- for (const config of configuredDatabases) {
10
- const schema = new Schema(config.name);
11
- await schema.executeTriggers();
12
- }
13
- } catch (error) {
14
- if (error.message.includes("reading 'init'")) {
15
- console.error('❌ Configuracion de base de datos no encontrada\n');
16
- console.error('Ejecute el comando para crear una nueva base de datos:');
17
- console.error(`\tnpx dbcube run database:create`);
18
- console.error('\nO verifique que la base de datos este configurada en el archivo dbcube.config.js\n');
19
- process.exit(1);
20
- } else if (error.message.includes("reading 'getDatabase'")) {
21
- console.error('- Se sugiere cambiar el linea o crear la base de datos a la que se hace referencia.');
22
- } else {
23
- console.error(`❌ ${error.message}`);
24
- if (process.env.DEBUG) console.error(error);
25
- process.exit(1);
26
- }
27
- }
28
- console.log('\n');
29
- }
30
-
31
- // Ejecutar el ejemplo
32
- main().catch(console.error);
1
+ const { Schema } = require('@dbcube/schema-builder');
2
+ const ConfigFileUtils = require('./../../../utils/ConfigFileUtils');
3
+ const ui = require('./../../../utils/ui');
4
+
5
+ async function main() {
6
+ try {
7
+ const configuredDatabases = await ConfigFileUtils.getConfiguredDatabases();
8
+
9
+ for (const config of configuredDatabases) {
10
+ const schema = new Schema(config.name);
11
+ await schema.executeTriggers();
12
+ }
13
+ } catch (error) {
14
+ ui.handleError(error);
15
+ }
16
+ }
17
+
18
+ main().catch(ui.handleError);
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  const chalk = require('chalk');
3
+ const ui = require('../utils/ui');
3
4
  const ora = require('ora');
4
5
  const path = require('path');
5
6
  const fs = require('fs');
@@ -409,7 +410,4 @@ async function main() {
409
410
  }
410
411
  }
411
412
 
412
- main().catch(err => {
413
- console.error(chalk.red('\n❌ Unexpected error:'), err.message);
414
- process.exit(1);
415
- });
413
+ main().catch(ui.handleError);
@@ -1,6 +1,7 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const chalk = require('chalk');
4
+ const ui = require('../utils/ui');
4
5
  const { CubeValidator } = require('@dbcube/schema-builder');
5
6
 
6
7
  /**
@@ -64,7 +65,4 @@ async function main() {
64
65
  console.log(`${chalk.green('✓')} All cube files are valid\n`);
65
66
  }
66
67
 
67
- main().catch(error => {
68
- console.error('Error fatal:', error);
69
- process.exit(1);
70
- });
68
+ main().catch(ui.handleError);
@@ -1,6 +1,7 @@
1
1
  const path = require('path');
2
2
  const fs = require('fs');
3
3
  const chalk = require('chalk');
4
+ const ui = require('../utils/ui');
4
5
 
5
6
  /**
6
7
  * dbcube version — CLI, packages, engine binaries, and environment info.
@@ -32,7 +33,7 @@ async function showVersion() {
32
33
  console.log(` ${chalk.gray(label.padEnd(16))} ${dim ? chalk.gray(value) : chalk.white(value)}`);
33
34
 
34
35
  console.log('');
35
- console.log(` ${chalk.green.bold(' DBCube CLI')} ${chalk.bold('v' + cliVersion)}`);
36
+ console.log(` ${ui.brand(' DBCube CLI')} ${chalk.bold('v' + cliVersion)}`);
36
37
  console.log(` ${chalk.gray('─'.repeat(40))}`);
37
38
 
38
39
  // Local package versions (when resolvable from the project)
@@ -55,12 +56,8 @@ async function showVersion() {
55
56
  row('platform', `${process.platform}-${process.arch}`, true);
56
57
  console.log('');
57
58
  } catch (error) {
58
- console.error('❌ Error al obtener la versión:', error.message);
59
- process.exit(1);
59
+ ui.handleError(error);
60
60
  }
61
61
  }
62
62
 
63
- showVersion().catch(error => {
64
- console.error('Error fatal:', error);
65
- process.exit(1);
66
- });
63
+ showVersion().catch(ui.handleError);
@@ -1,5 +1,22 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
+ const EnvLoader = require('./EnvLoader');
4
+
5
+ /**
6
+ * Detecta si el proyecto está marcado como ESM ("type": "module" en
7
+ * package.json), lo que hace que dbcube.config.js (CommonJS) no se pueda
8
+ * cargar con require(). Devuelve true si es ESM.
9
+ */
10
+ function projectIsESM() {
11
+ try {
12
+ const pkgPath = path.resolve(process.cwd(), 'package.json');
13
+ if (!fs.existsSync(pkgPath)) return false;
14
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
15
+ return pkg.type === 'module';
16
+ } catch {
17
+ return false;
18
+ }
19
+ }
3
20
 
4
21
  /**
5
22
  * Clase para manejar operaciones sobre el archivo de configuración
@@ -10,10 +27,15 @@ class ConfigFileUtils {
10
27
  * @returns {string} - Ruta al archivo de configuración
11
28
  */
12
29
  static getConfigPath() {
13
- // Usar la ruta raíz del proyecto
14
30
  const rootPath = path.resolve(process.cwd());
15
- const configPath = path.join(rootPath, 'dbcube.config.js');
16
- return configPath;
31
+ const cjsPath = path.join(rootPath, 'dbcube.config.cjs');
32
+ const jsPath = path.join(rootPath, 'dbcube.config.js');
33
+ // Si ya existe alguno, ese manda (preferimos .cjs).
34
+ if (fs.existsSync(cjsPath)) return cjsPath;
35
+ if (fs.existsSync(jsPath)) return jsPath;
36
+ // Si no existe ninguno (se va a crear): en proyectos ESM
37
+ // ("type": "module") debe ser .cjs para poder cargarse con require().
38
+ return projectIsESM() ? cjsPath : jsPath;
17
39
  }
18
40
 
19
41
  /**
@@ -21,19 +43,16 @@ class ConfigFileUtils {
21
43
  * @returns {Promise<Array<string>>} - Array con los nombres de las bases de datos
22
44
  */
23
45
  static async getConfiguredDatabases() {
24
- try {
25
- // Ruta al archivo de configuración
26
- const configPath = this.getConfigPath();
27
-
28
- // Comprobar si el archivo existe
29
- if (!fs.existsSync(configPath)) {
30
- ConfigFileUtils.crearArchivoConfig(configPath);
31
- }
32
-
33
- return this.loadDatabasesFromPath(configPath);
34
- } catch (error) {
35
- throw new Error('Error al obtener las bases de datos configuradas:', error);
46
+ // Sin try/catch que oculte el error: loadDatabasesFromPath ya lanza
47
+ // mensajes explícitos y accionables. (Antes, `new Error('msg', error)`
48
+ // descartaba el segundo argumento y se perdía la causa real.)
49
+ const configPath = this.getConfigPath();
50
+
51
+ if (!fs.existsSync(configPath)) {
52
+ ConfigFileUtils.crearArchivoConfig(configPath);
36
53
  }
54
+
55
+ return this.loadDatabasesFromPath(configPath);
37
56
  }
38
57
 
39
58
  /**
@@ -42,46 +61,91 @@ class ConfigFileUtils {
42
61
  * @returns {Array<string>} - Nombres de las bases de datos
43
62
  */
44
63
  static loadDatabasesFromPath(configPath) {
64
+ // Carga automática de .env (cargador propio de DBCube): el usuario no
65
+ // necesita instalar dotenv ni escribir require("dotenv") en su config.
66
+ EnvLoader.load();
67
+
68
+ let config;
45
69
  try {
46
70
  // Borrar la caché del módulo para asegurarnos de cargar la versión más reciente
47
71
  delete require.cache[require.resolve(configPath)];
48
-
49
72
  // Cargar el archivo de configuración
50
- const config = require(configPath);
51
-
52
- // Crear una instancia temporal de Config para obtener los datos
53
- const tempConfig = {
54
- databases: {},
55
- data: {},
56
- set: function(configData) {
57
- this.data = configData;
58
- if (configData.databases) {
59
- this.databases = configData.databases;
60
- }
61
- },
62
- getAllDatabases: function() {
63
- return this.databases;
73
+ config = require(configPath);
74
+ } catch (error) {
75
+ const missing = (error.message.match(/Cannot find module '([^']+)'/) || [])[1];
76
+ // ¿El módulo que no se encuentra es el PROPIO config? Entonces el
77
+ // problema es de carga (típicamente ESM). Si es OTRO módulo, es una
78
+ // dependencia del config que falta (p. ej. dotenv).
79
+ const missingIsConfig = missing && (configPath.includes(missing) || missing.includes('dbcube.config'));
80
+
81
+ // Caso 1: falta una dependencia que el config requiere.
82
+ if (error.code === 'MODULE_NOT_FOUND' && missing && !missingIsConfig) {
83
+ throw new Error(
84
+ `dbcube.config.js requiere un módulo que no está instalado: "${missing}".\n` +
85
+ ` Instálalo (p. ej. npm install ${missing}).\n` +
86
+ ` Nota: DBCube ya carga el .env automáticamente — puedes quitar require("dotenv") de tu config.`
87
+ );
88
+ }
89
+ // Caso 2: proyecto ESM ("type": "module") → require() del config falla
90
+ // o el .js se interpreta como módulo ES y `module.exports` no aplica.
91
+ if (projectIsESM() || error.code === 'ERR_REQUIRE_ESM') {
92
+ throw new Error(
93
+ `No se pudo cargar dbcube.config.js porque el proyecto está marcado como ESM ` +
94
+ `("type": "module" en package.json), pero la configuración usa CommonJS (module.exports).\n` +
95
+ ` Solución: renombra el archivo a "dbcube.config.cjs", o quita "type": "module" de package.json.`
96
+ );
97
+ }
98
+ // Cualquier otro error de carga: mostrarlo tal cual.
99
+ throw new Error(`No se pudo cargar la configuración desde ${configPath}:\n ${error.message}`);
100
+ }
101
+
102
+ // Validar que la config exporte una función (firma esperada).
103
+ if (typeof config !== 'function') {
104
+ const hint = projectIsESM()
105
+ ? ` El proyecto es ESM ("type": "module"): renombra el archivo a "dbcube.config.cjs" o quita "type": "module".`
106
+ : ` Debe exportar una función: module.exports = function (config) { config.set({ databases: {...} }); }.`;
107
+ throw new Error(`dbcube.config.js no exporta una configuración válida.${hint}`);
108
+ }
109
+
110
+ // Crear una instancia temporal de Config para obtener los datos
111
+ const tempConfig = {
112
+ databases: {},
113
+ data: {},
114
+ set: function(configData) {
115
+ this.data = configData;
116
+ if (configData.databases) {
117
+ this.databases = configData.databases;
64
118
  }
65
- };
66
-
67
- // Ejecutar la función de configuración
68
- config(tempConfig);
69
-
70
- // Obtener los nombres de las bases de datos
71
- const databaseNames = Object.keys(tempConfig.getAllDatabases());
72
- const arrayDatabases = [];
73
- for (const database of databaseNames) {
74
- arrayDatabases.push({
75
- name: database,
76
- type: tempConfig.getAllDatabases()[database].type
77
- });
119
+ },
120
+ getAllDatabases: function() {
121
+ return this.databases;
78
122
  }
79
- return arrayDatabases;
123
+ };
124
+
125
+ // Ejecutar la función de configuración
126
+ try {
127
+ config(tempConfig);
80
128
  } catch (error) {
81
- // Fallar claro: devolver una DB inventada ocultaría el problema
82
- // y haría que los comandos operen contra una base inexistente
83
- throw new Error(`No se pudo cargar la configuración desde ${configPath}: ${error.message}`);
129
+ throw new Error(`dbcube.config.js lanzó un error al evaluarse:\n ${error.message}`);
130
+ }
131
+
132
+ const allDatabases = tempConfig.getAllDatabases();
133
+ if (!allDatabases || Object.keys(allDatabases).length === 0) {
134
+ throw new Error(
135
+ `dbcube.config.js no define ninguna base de datos.\n` +
136
+ ` Añade al menos una en config.set({ databases: { miBase: { type, config } } }).`
137
+ );
84
138
  }
139
+
140
+ const databaseNames = Object.keys(allDatabases);
141
+ const arrayDatabases = [];
142
+ for (const database of databaseNames) {
143
+ arrayDatabases.push({
144
+ name: database,
145
+ type: allDatabases[database].type
146
+ });
147
+ }
148
+ return arrayDatabases;
85
149
  }
86
150
 
87
151
  /**
@@ -271,15 +335,16 @@ class ConfigFileUtils {
271
335
  * @param {string} rutaDestino - Ruta completa donde se debe crear el archivo.
272
336
  */
273
337
  static crearArchivoConfig(rutaDestino) {
274
- const contenido = `require('dotenv').config({ quiet: true });
275
-
276
- module.exports = function (config) {
277
- config.set({
278
- databases: {
279
- }
280
- });
281
- };
282
- `;
338
+ // DBCube carga el .env automáticamente, así que el template ya NO
339
+ // necesita require('dotenv') (que además requeriría instalar el paquete).
340
+ const contenido = `// DBCube carga .env automáticamente — usa process.env.MI_VAR sin dotenv.
341
+ module.exports = function (config) {
342
+ config.set({
343
+ databases: {
344
+ }
345
+ });
346
+ };
347
+ `;
283
348
 
284
349
  // Asegurarse de que el directorio existe
285
350
  const dir = path.dirname(rutaDestino);
@@ -0,0 +1,94 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ /**
5
+ * Cargador de variables de entorno propio de DBCube.
6
+ *
7
+ * Evita que el usuario tenga que instalar `dotenv` y escribir
8
+ * `require("dotenv").config()` al inicio de su dbcube.config.js. DBCube carga
9
+ * el `.env` del proyecto automáticamente ANTES de evaluar la configuración.
10
+ *
11
+ * Estrategia:
12
+ * 1. `process.loadEnvFile()` — nativo de Node 20.6+ (cero dependencias).
13
+ * 2. Fallback: parser propio mínimo (KEY=VALUE, comillas, comentarios, export).
14
+ *
15
+ * No sobrescribe variables ya presentes en process.env (las del shell mandan).
16
+ */
17
+ class EnvLoader {
18
+ /**
19
+ * Carga el archivo .env indicado (o ./.env del cwd) en process.env.
20
+ * Silencioso si el archivo no existe. Devuelve true si cargó algo.
21
+ * @param {string} [envPath]
22
+ * @returns {boolean}
23
+ */
24
+ static load(envPath) {
25
+ const file = envPath || path.resolve(process.cwd(), '.env');
26
+ if (!fs.existsSync(file)) return false;
27
+
28
+ // Camino preferido: cargador nativo de Node (20.6+).
29
+ if (typeof process.loadEnvFile === 'function') {
30
+ try {
31
+ process.loadEnvFile(file);
32
+ return true;
33
+ } catch {
34
+ // Cae al parser propio si el nativo falla por algún motivo.
35
+ }
36
+ }
37
+
38
+ try {
39
+ const content = fs.readFileSync(file, 'utf8');
40
+ const parsed = EnvLoader.parse(content);
41
+ for (const [key, value] of Object.entries(parsed)) {
42
+ if (process.env[key] === undefined) {
43
+ process.env[key] = value;
44
+ }
45
+ }
46
+ return true;
47
+ } catch {
48
+ return false;
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Parser mínimo de formato .env. Soporta:
54
+ * KEY=value · KEY="value con espacios" · KEY='literal' · export KEY=value
55
+ * comentarios con # · líneas en blanco · \n \t en comillas dobles.
56
+ * @param {string} content
57
+ * @returns {Record<string,string>}
58
+ */
59
+ static parse(content) {
60
+ const out = {};
61
+ for (let rawLine of content.split(/\r?\n/)) {
62
+ const line = rawLine.trim();
63
+ if (!line || line.startsWith('#')) continue;
64
+
65
+ // Permite el prefijo `export` (estilo shell).
66
+ const withoutExport = line.startsWith('export ') ? line.slice(7).trim() : line;
67
+
68
+ const eq = withoutExport.indexOf('=');
69
+ if (eq === -1) continue;
70
+
71
+ const key = withoutExport.slice(0, eq).trim();
72
+ if (!key) continue;
73
+
74
+ let value = withoutExport.slice(eq + 1).trim();
75
+
76
+ // Comillas dobles: interpreta escapes. Comillas simples: literal.
77
+ if (value.length >= 2 && value[0] === '"' && value[value.length - 1] === '"') {
78
+ value = value.slice(1, -1).replace(/\\n/g, '\n').replace(/\\t/g, '\t').replace(/\\"/g, '"');
79
+ } else if (value.length >= 2 && value[0] === "'" && value[value.length - 1] === "'") {
80
+ value = value.slice(1, -1);
81
+ } else {
82
+ // Sin comillas: corta un comentario en línea (espacio + #).
83
+ const hash = value.indexOf(' #');
84
+ if (hash !== -1) value = value.slice(0, hash).trim();
85
+ }
86
+
87
+ out[key] = value;
88
+ }
89
+ return out;
90
+ }
91
+ }
92
+
93
+ module.exports = EnvLoader;
94
+ module.exports.EnvLoader = EnvLoader;
@@ -0,0 +1,89 @@
1
+ const chalk = require('chalk');
2
+
3
+ /**
4
+ * UI compartida del CLI de DBCube. Un solo lugar para el estilo visual:
5
+ * colores de marca, símbolos de estado y el manejo de errores consistente.
6
+ * Así todos los comandos se ven como parte del mismo producto.
7
+ */
8
+
9
+ // Verde de marca DBCube (con fallback si la terminal no soporta truecolor).
10
+ const brandGreen = (t) => (chalk.level >= 2 ? chalk.hex('#22C55E') : chalk.green)(t);
11
+
12
+ const ui = {
13
+ chalk,
14
+ brand: (t) => brandGreen(chalk.bold(t)),
15
+
16
+ /** Banner de marca para el header del CLI/help. */
17
+ banner(subtitle = 'Database toolkit powered by Rust') {
18
+ const line = chalk.gray('─'.repeat(54));
19
+ console.log('');
20
+ console.log(` ${brandGreen('◆')} ${ui.brand('DBCube')} ${chalk.gray('CLI')}`);
21
+ console.log(` ${chalk.gray(subtitle)}`);
22
+ console.log(` ${line}`);
23
+ },
24
+
25
+ /** Cabecera de comando: ícono + título + línea separadora. */
26
+ header(title, icon = '🧊') {
27
+ console.log(`\n${icon} ${ui.brand(title.toUpperCase())}`);
28
+ console.log(chalk.gray('─'.repeat(54)));
29
+ },
30
+
31
+ /** Línea de detalle bajo una cabecera (clave: valor). */
32
+ item(label, value) {
33
+ if (value === undefined) {
34
+ console.log(`${chalk.gray('│')} ${label}`);
35
+ } else {
36
+ console.log(`${chalk.gray('│')} ${chalk.gray(label + ':')} ${chalk.white(value)}`);
37
+ }
38
+ },
39
+
40
+ success(message) { console.log(`${chalk.green('✔')} ${message}`); },
41
+ info(message) { console.log(`${chalk.cyan('ℹ')} ${message}`); },
42
+ warn(message) { console.log(`${chalk.yellow('⚠')} ${message}`); },
43
+ dim(message) { console.log(chalk.gray(message)); },
44
+ step(message) { console.log(`${chalk.cyan('›')} ${message}`); },
45
+
46
+ /** Error con título en rojo y pistas opcionales (→ ...). */
47
+ error(message, hints = []) {
48
+ console.error(`\n${chalk.red('✖')} ${chalk.red(message)}`);
49
+ for (const h of hints) console.error(` ${chalk.gray('→')} ${chalk.gray(h)}`);
50
+ console.error('');
51
+ },
52
+
53
+ /** "Cancelado." silencioso (Ctrl+C / prompt cerrado). */
54
+ cancelled() {
55
+ console.log(`\n${chalk.gray('Cancelled.')}`);
56
+ },
57
+
58
+ /**
59
+ * Manejador central de errores de comando. Llamar desde cada catch.
60
+ * Traduce los fallos comunes a mensajes claros y accionables, sin stacks
61
+ * (salvo DBCUBE_DEBUG=1), y cierra el proceso con el código adecuado.
62
+ */
63
+ handleError(error) {
64
+ // Ctrl+C / cierre del prompt interactivo.
65
+ if (error && (error.name === 'ExitPromptError' || /force closed/i.test(error.message || ''))) {
66
+ ui.cancelled();
67
+ process.exit(0);
68
+ }
69
+
70
+ const msg = (error && error.message) || String(error);
71
+
72
+ // Base de datos/config no inicializada (errores internos típicos).
73
+ if (msg.includes("reading 'init'") || msg.includes("reading 'getDatabase'") || msg.includes("reading 'type'")) {
74
+ ui.error('Database configuration not found.', [
75
+ 'Run: npx dbcube run database:create',
76
+ 'Or check that the database is configured in dbcube.config.js',
77
+ ]);
78
+ process.exit(1);
79
+ }
80
+
81
+ ui.error(msg);
82
+ if (process.env.DBCUBE_DEBUG === '1' || process.env.DBCUBE_DEBUG === 'true') {
83
+ console.error(error);
84
+ }
85
+ process.exit(1);
86
+ },
87
+ };
88
+
89
+ module.exports = ui;