langaro-api 1.2.5 → 1.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.
@@ -74,23 +74,23 @@ function confirm(question) {
74
74
 
75
75
  // ── Command runners ──
76
76
 
77
- function runGenerateTypes() {
77
+ async function runGenerateTypes() {
78
78
  const { generateTypes } = require('../lib/index');
79
79
  const config = loadConfig();
80
- generateTypes(config);
80
+ await generateTypes(config);
81
81
  console.log('[langaro-api] Types + JSDoc annotations generated.');
82
82
  }
83
83
 
84
- function runWatch() {
84
+ async function runWatch() {
85
85
  const { generateTypes, getWatchDirs } = require('../lib/index');
86
86
 
87
- function generate() {
87
+ async function generate() {
88
88
  const config = loadConfig();
89
- generateTypes(config);
89
+ await generateTypes(config);
90
90
  console.log('[langaro-api] Types + JSDoc annotations generated.');
91
91
  }
92
92
 
93
- generate();
93
+ await generate();
94
94
 
95
95
  const config = loadConfig();
96
96
  const dirs = getWatchDirs(config);
@@ -102,7 +102,7 @@ function runWatch() {
102
102
  if (filename && filename.endsWith('.js')) {
103
103
  if (debounceTimer) clearTimeout(debounceTimer);
104
104
  debounceTimer = setTimeout(() => {
105
- try { generate(); } catch (err) { console.error('[langaro-api] Error:', err.message); }
105
+ generate().catch((err) => console.error('[langaro-api] Error:', err.message));
106
106
  }, 300);
107
107
  }
108
108
  });
@@ -153,13 +153,13 @@ async function main() {
153
153
  if (command === 'update-docs') { runUpdateDocs(); return process.exit(0); }
154
154
  if (command === '--watch') return runWatch();
155
155
  if (command === 'generate' || command === 'types') {
156
- runGenerateTypes();
156
+ await runGenerateTypes();
157
157
  return process.exit(0);
158
158
  }
159
159
 
160
160
  // No args + non-TTY (e.g. piped, CI): just generate types
161
161
  if (!process.stdin.isTTY) {
162
- runGenerateTypes();
162
+ await runGenerateTypes();
163
163
  return process.exit(0);
164
164
  }
165
165
 
@@ -176,7 +176,7 @@ async function main() {
176
176
 
177
177
  console.log('');
178
178
 
179
- if (choice === 'types') { runGenerateTypes(); process.exit(0); }
179
+ if (choice === 'types') { await runGenerateTypes(); process.exit(0); }
180
180
  if (choice === 'new') return runNew();
181
181
  if (choice === 'migrate') return runMigrate();
182
182
  if (choice === 'init') return runInit();
package/lib/cli/new.js CHANGED
@@ -2,6 +2,7 @@ const fs = require('fs');
2
2
  const path = require('path');
3
3
  const readline = require('readline');
4
4
  const { pascalCase } = require('../utils');
5
+ const { fetchTablesFromDatabase } = require('../db');
5
6
 
6
7
  const DEFAULTS = {
7
8
  services: 'src/database/services',
@@ -181,44 +182,6 @@ function singleSelect(question, allOptions) {
181
182
  });
182
183
  }
183
184
 
184
- async function fetchTablesFromDatabase() {
185
- try {
186
- // Resolve modules from the project's node_modules, not langaro-api's
187
- const projectRoot = process.cwd();
188
- const resolveFrom = (mod) => require(require.resolve(mod, { paths: [projectRoot] }));
189
-
190
- resolveFrom('dotenv').config({ path: path.join(projectRoot, '.env') });
191
-
192
- const {
193
- DB_HOST, DB_USER, DB_PASSWORD, DB_NAME, DB_PORT,
194
- } = process.env;
195
-
196
- if (!DB_NAME) {
197
- console.log('\x1b[33m Could not connect to database. DB_NAME not found in .env\x1b[0m');
198
- return null;
199
- }
200
-
201
- const knex = resolveFrom('knex')({
202
- client: 'mysql2',
203
- connection: {
204
- host: DB_HOST, user: DB_USER, password: DB_PASSWORD, database: DB_NAME, port: DB_PORT,
205
- },
206
- });
207
-
208
- const results = await knex.raw(
209
- 'SELECT table_name FROM information_schema.tables WHERE table_schema = ?',
210
- [DB_NAME],
211
- );
212
-
213
- const tables = results[0].map((row) => row.TABLE_NAME).sort();
214
- await knex.destroy();
215
- return tables;
216
- } catch (err) {
217
- console.log(`\x1b[33m Could not connect to database: ${err.message}\x1b[0m`);
218
- return null;
219
- }
220
- }
221
-
222
185
  function multiSelect(rl, question, options) {
223
186
  return new Promise((resolve) => {
224
187
  const selected = new Set(options.map((_, i) => i));
@@ -393,7 +356,7 @@ async function run(config = {}) {
393
356
  if (created.length > 0) {
394
357
  // Auto-regenerate types so the new resource gets IntelliSense immediately
395
358
  const { generateTypes } = require('../index');
396
- generateTypes(cfg);
359
+ await generateTypes(cfg);
397
360
  console.log(`\n\x1b[32mDone!\x1b[0m Created ${created.length} file(s). Types regenerated.\n`);
398
361
  } else {
399
362
  console.log('\nNo files created (all already exist).\n');
package/lib/db.js ADDED
@@ -0,0 +1,41 @@
1
+ const path = require('path');
2
+
3
+ async function fetchTablesFromDatabase() {
4
+ try {
5
+ // Resolve modules from the project's node_modules, not langaro-api's
6
+ const projectRoot = process.cwd();
7
+ const resolveFrom = (mod) => require(require.resolve(mod, { paths: [projectRoot] }));
8
+
9
+ resolveFrom('dotenv').config({ path: path.join(projectRoot, '.env') });
10
+
11
+ const {
12
+ DB_HOST, DB_USER, DB_PASSWORD, DB_NAME, DB_PORT,
13
+ } = process.env;
14
+
15
+ if (!DB_NAME) {
16
+ console.log('\x1b[33m Could not connect to database. DB_NAME not found in .env\x1b[0m');
17
+ return null;
18
+ }
19
+
20
+ const knex = resolveFrom('knex')({
21
+ client: 'mysql2',
22
+ connection: {
23
+ host: DB_HOST, user: DB_USER, password: DB_PASSWORD, database: DB_NAME, port: DB_PORT,
24
+ },
25
+ });
26
+
27
+ const results = await knex.raw(
28
+ 'SELECT table_name FROM information_schema.tables WHERE table_schema = ?',
29
+ [DB_NAME],
30
+ );
31
+
32
+ const tables = results[0].map((row) => row.TABLE_NAME).sort();
33
+ await knex.destroy();
34
+ return tables;
35
+ } catch (err) {
36
+ console.log(`\x1b[33m Could not connect to database: ${err.message}\x1b[0m`);
37
+ return null;
38
+ }
39
+ }
40
+
41
+ module.exports = { fetchTablesFromDatabase };
@@ -3,7 +3,7 @@ const path = require('path');
3
3
  const { pascalCase, extractMethodsWithLocations, isCustomService } = require('../utils');
4
4
  const { generateSourceMap } = require('../sourcemap');
5
5
 
6
- module.exports = function generateServicesDts(servicesDir, modelsDir, outputDir) {
6
+ module.exports = function generateServicesDts(servicesDir, modelsDir, outputDir, dbTableNames = []) {
7
7
  const lines = ['// Auto-generated by langaro-api — DO NOT EDIT', ''];
8
8
  const serviceEntries = [];
9
9
  const mappings = [];
@@ -89,6 +89,22 @@ module.exports = function generateServicesDts(servicesDir, modelsDir, outputDir)
89
89
  });
90
90
  }
91
91
 
92
+ // DB tables discovered via introspection — pure CRUD (no file on disk)
93
+ dbTableNames
94
+ .sort()
95
+ .forEach((tableName) => {
96
+ const serviceName = `${pascalCase(tableName)}Services`;
97
+ if (serviceEntries.find((e) => e.serviceName === serviceName)) return;
98
+ const interfaceName = `I${serviceName}`;
99
+ lines.push(`declare interface ${interfaceName} extends CRUD {}`, '');
100
+ serviceEntries.push({
101
+ interfaceName,
102
+ serviceName,
103
+ tableName,
104
+ custom: false,
105
+ });
106
+ });
107
+
92
108
  // ServicesMap
93
109
  lines.push('declare interface ServicesMap {');
94
110
  serviceEntries
package/lib/index.js CHANGED
@@ -27,7 +27,7 @@ const DEFAULTS = {
27
27
  middlewares: 'src/middlewares',
28
28
  };
29
29
 
30
- function generateTypes(userConfig = {}) {
30
+ async function generateTypes(userConfig = {}) {
31
31
  const config = { ...DEFAULTS, ...userConfig };
32
32
  const root = config.root;
33
33
 
@@ -51,7 +51,11 @@ function generateTypes(userConfig = {}) {
51
51
  fs.writeFileSync(path.join(outputDir, 'crud.d.ts.map'), crud.sourceMap);
52
52
  }
53
53
 
54
- const services = generateServicesDts(servicesDir, modelsDir, outputDir);
54
+ // Discover DB tables via introspection (same as loadModels does at runtime)
55
+ const { fetchTablesFromDatabase } = require('./db');
56
+ const dbTableNames = await fetchTablesFromDatabase() || [];
57
+
58
+ const services = generateServicesDts(servicesDir, modelsDir, outputDir, dbTableNames);
55
59
  fs.writeFileSync(path.join(outputDir, 'services.d.ts'), services.content);
56
60
  fs.writeFileSync(path.join(outputDir, 'services.d.ts.map'), services.sourceMap);
57
61
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langaro-api",
3
- "version": "1.2.5",
3
+ "version": "1.2.6",
4
4
  "description": "Auto-generate TypeScript types, JSDoc annotations, and boilerplate loaders for knex-extended-crud projects",
5
5
  "main": "lib/index.js",
6
6
  "bin": {