micro-generate 1.3.11 → 1.3.12

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 (80) hide show
  1. package/README.md +83 -9
  2. package/dist/cli/generators/add-mongo-generator.d.ts +4 -0
  3. package/dist/cli/generators/add-mongo-generator.js +212 -0
  4. package/dist/cli/generators/add-mongo-generator.js.map +1 -0
  5. package/dist/cli/generators/add-mysql-generator.d.ts +4 -0
  6. package/dist/cli/generators/add-mysql-generator.js +221 -0
  7. package/dist/cli/generators/add-mysql-generator.js.map +1 -0
  8. package/dist/cli/generators/add-redis-generator.d.ts +1 -0
  9. package/dist/cli/generators/add-redis-generator.js +100 -0
  10. package/dist/cli/generators/add-redis-generator.js.map +1 -0
  11. package/dist/cli/generators/feature-generator.js +26 -338
  12. package/dist/cli/generators/feature-generator.js.map +1 -1
  13. package/dist/cli/generators/init-generator.js +31 -649
  14. package/dist/cli/generators/init-generator.js.map +1 -1
  15. package/dist/cli/generators/model-generator.d.ts +6 -0
  16. package/dist/cli/generators/model-generator.js +50 -0
  17. package/dist/cli/generators/model-generator.js.map +1 -0
  18. package/dist/cli/index.js +71 -0
  19. package/dist/cli/index.js.map +1 -1
  20. package/dist/cli/templates/feature/mongoModel.template.d.ts +6 -0
  21. package/dist/cli/templates/feature/mongoModel.template.js +57 -0
  22. package/dist/cli/templates/feature/mongoModel.template.js.map +1 -0
  23. package/dist/cli/templates/feature/mysqlModel.template.d.ts +6 -0
  24. package/dist/cli/templates/feature/mysqlModel.template.js +62 -0
  25. package/dist/cli/templates/feature/mysqlModel.template.js.map +1 -0
  26. package/dist/cli/templates/feature/resolvers.template.d.ts +1 -0
  27. package/dist/cli/templates/feature/resolvers.template.js +21 -0
  28. package/dist/cli/templates/feature/resolvers.template.js.map +1 -0
  29. package/dist/cli/templates/feature/service.template.d.ts +11 -0
  30. package/dist/cli/templates/feature/service.template.js +68 -0
  31. package/dist/cli/templates/feature/service.template.js.map +1 -0
  32. package/dist/cli/templates/feature/typeDefs.template.d.ts +1 -0
  33. package/dist/cli/templates/feature/typeDefs.template.js +24 -0
  34. package/dist/cli/templates/feature/typeDefs.template.js.map +1 -0
  35. package/dist/cli/templates/project/api.template.d.ts +1 -0
  36. package/dist/cli/templates/project/api.template.js +40 -0
  37. package/dist/cli/templates/project/api.template.js.map +1 -0
  38. package/dist/cli/templates/project/config.template.d.ts +1 -0
  39. package/dist/cli/templates/project/config.template.js +12 -0
  40. package/dist/cli/templates/project/config.template.js.map +1 -0
  41. package/dist/cli/templates/project/featuresIndex.template.d.ts +1 -0
  42. package/dist/cli/templates/project/featuresIndex.template.js +4 -0
  43. package/dist/cli/templates/project/featuresIndex.template.js.map +1 -0
  44. package/dist/cli/templates/project/index.template.d.ts +8 -0
  45. package/dist/cli/templates/project/index.template.js +104 -0
  46. package/dist/cli/templates/project/index.template.js.map +1 -0
  47. package/dist/cli/templates/project/mongo.template.d.ts +1 -0
  48. package/dist/cli/templates/project/mongo.template.js +51 -0
  49. package/dist/cli/templates/project/mongo.template.js.map +1 -0
  50. package/dist/cli/templates/project/mongoClient.template.d.ts +1 -0
  51. package/dist/cli/templates/project/mongoClient.template.js +21 -0
  52. package/dist/cli/templates/project/mongoClient.template.js.map +1 -0
  53. package/dist/cli/templates/project/mysqlClient.template.d.ts +1 -0
  54. package/dist/cli/templates/project/mysqlClient.template.js +18 -0
  55. package/dist/cli/templates/project/mysqlClient.template.js.map +1 -0
  56. package/dist/cli/templates/project/redis.template.d.ts +1 -0
  57. package/dist/cli/templates/project/redis.template.js +255 -0
  58. package/dist/cli/templates/project/redis.template.js.map +1 -0
  59. package/dist/cli/templates/project/sanitize.template.d.ts +1 -0
  60. package/dist/cli/templates/project/sanitize.template.js +11 -0
  61. package/dist/cli/templates/project/sanitize.template.js.map +1 -0
  62. package/dist/cli/templates/project/skill.template.d.ts +1 -0
  63. package/dist/cli/templates/project/skill.template.js +147 -0
  64. package/dist/cli/templates/project/skill.template.js.map +1 -0
  65. package/dist/cli/templates/project/tsconfig.template.d.ts +1 -0
  66. package/dist/cli/templates/project/tsconfig.template.js +17 -0
  67. package/dist/cli/templates/project/tsconfig.template.js.map +1 -0
  68. package/dist/core/MicroserviceServer.d.ts +4 -0
  69. package/dist/core/MicroserviceServer.js +13 -0
  70. package/dist/core/MicroserviceServer.js.map +1 -1
  71. package/dist/database/mysql.d.ts +23 -0
  72. package/dist/database/mysql.js +68 -0
  73. package/dist/database/mysql.js.map +1 -0
  74. package/dist/database/redis.d.ts +1 -1
  75. package/dist/database/redis.js +6 -8
  76. package/dist/database/redis.js.map +1 -1
  77. package/dist/index.d.ts +1 -0
  78. package/dist/index.js +1 -0
  79. package/dist/index.js.map +1 -1
  80. package/package.json +5 -1
@@ -1,6 +1,17 @@
1
1
  import fs from 'fs-extra';
2
2
  import path from 'path';
3
3
  import chalk from 'chalk';
4
+ import { apiTemplate } from '../templates/project/api.template.js';
5
+ import { sanitizeTemplate } from '../templates/project/sanitize.template.js';
6
+ import { configTemplate } from '../templates/project/config.template.js';
7
+ import { redisTemplate } from '../templates/project/redis.template.js';
8
+ import { mongoTemplate } from '../templates/project/mongo.template.js';
9
+ import { mongoClientTemplate } from '../templates/project/mongoClient.template.js';
10
+ import { mysqlClientTemplate } from '../templates/project/mysqlClient.template.js';
11
+ import { getIndexTemplate } from '../templates/project/index.template.js';
12
+ import { featuresIndexTemplate } from '../templates/project/featuresIndex.template.js';
13
+ import { tsConfigTemplate } from '../templates/project/tsconfig.template.js';
14
+ import { skillTemplate } from '../templates/project/skill.template.js';
4
15
  export const generateInit = async (options) => {
5
16
  const { name, useMongo = true, useRedis = true, useMySQL = false, dbNames = [], mysqlDbNames = [] } = options;
6
17
  const projectPath = path.join(process.cwd(), name);
@@ -27,591 +38,31 @@ export const generateInit = async (options) => {
27
38
  await fs.ensureDir(dir);
28
39
  }
29
40
  // 2. src/services/api.ts
30
- const apiContent = `import axios from 'axios';
31
-
32
- export default class ApiClient {
33
- public baseUrl: string;
34
- public timeout: number;
35
-
36
- constructor(url: string) {
37
- this.baseUrl = url;
38
- this.timeout = 600000; // 10 minutes
39
- }
40
-
41
- private getHeaders(token?: string) {
42
- const headers: Record<string, string> = {
43
- 'Content-Type': 'application/json',
44
- };
45
- if (token) {
46
- headers['Authorization'] = token;
47
- }
48
- return headers;
49
- }
50
-
51
- protected async get<T>(endpoint: string, params: Record<string, any> = {}, token?: string): Promise<T> {
52
- const response = await axios.get(\`\${this.baseUrl}/\${endpoint}\`, {
53
- headers: this.getHeaders(token),
54
- params,
55
- timeout: this.timeout,
56
- });
57
- return response.data;
58
- }
59
-
60
- protected async post<T>(endpoint: string, data: Record<string, any>, token?: string): Promise<T> {
61
- const response = await axios.post(\`\${this.baseUrl}/\${endpoint}\`, data, {
62
- headers: this.getHeaders(token),
63
- timeout: this.timeout,
64
- });
65
- return response.data;
66
- }
67
- }
68
- `;
69
- await fs.writeFile(path.join(projectPath, 'src', 'services', 'api.ts'), apiContent);
41
+ await fs.writeFile(path.join(projectPath, 'src', 'services', 'api.ts'), apiTemplate);
70
42
  // 3. src/utils/sanitize.ts
71
- const sanitizeContent = `import DOMPurify from 'dompurify';
72
- import { JSDOM } from 'jsdom';
73
-
74
- const window = new JSDOM('').window;
75
- const purify = DOMPurify(window as any);
76
-
77
- export function sanitize(dirty: string): string {
78
- return purify.sanitize(dirty, { ALLOWED_TAGS: [], ALLOWED_ATTR: [] });
79
- }
80
- `;
81
- await fs.writeFile(path.join(projectPath, 'src', 'utils', 'sanitize.ts'), sanitizeContent);
43
+ await fs.writeFile(path.join(projectPath, 'src', 'utils', 'sanitize.ts'), sanitizeTemplate);
82
44
  // 4. src/utils/config.ts
83
- const configUtilContent = `import * as dotenv from 'dotenv';
84
- dotenv.config();
85
-
86
- export function getEnv(name: string): string {
87
- const value = process.env[name];
88
- if (!value) {
89
- throw new Error(\`❌ Variable de entorno requerida no definida: \${name}\`);
90
- }
91
- return value;
92
- }
93
- `;
94
- await fs.writeFile(path.join(projectPath, 'src', 'utils', 'config.ts'), configUtilContent);
45
+ await fs.writeFile(path.join(projectPath, 'src', 'utils', 'config.ts'), configTemplate);
95
46
  // 5. src/database/redis.ts
96
47
  if (useRedis) {
97
- const redisContent = `import { Redis, RedisOptions } from 'ioredis';
98
- import { logger } from 'micro-generate';
99
-
100
- export class RedisConnector {
101
- private defaultClient: Redis | null = null;
102
- private clients: Map<number, Redis> = new Map();
103
- private options: RedisOptions = {};
104
- private defaultDb: number = 0;
105
- private host?: string;
106
-
107
- constructor(optionsOrUrl: RedisOptions | string) {
108
- if (typeof optionsOrUrl === 'string') {
109
- this.options = {
110
- retryStrategy: (times: number) => Math.min(times * 50, 2000)
111
- };
112
- this.host = undefined;
113
- (this as any).url = optionsOrUrl;
114
- } else {
115
- this.options = {
116
- retryStrategy: (times: number) => Math.min(times * 50, 2000),
117
- ...optionsOrUrl
118
- };
119
- this.defaultDb = optionsOrUrl.db || 0;
120
- this.host = optionsOrUrl.host;
121
- }
122
- }
123
-
124
- async connect(): Promise<void> {
125
- if (this.defaultClient) {
126
- logger.info('Redis default client already connected');
127
- return;
128
- }
129
- try {
130
- this.defaultClient = this.createClient(this.defaultDb);
131
- this.clients.set(this.defaultDb, this.defaultClient);
132
- await this.defaultClient.connect();
133
- } catch (error) {
134
- logger.error(\`Failed to connect to Redis: \${error}\`);
135
- throw error;
136
- }
137
- }
138
-
139
- private createClient(db: number): Redis {
140
- let client: Redis;
141
- const url = (this as any).url;
142
-
143
- if (url) {
144
- client = new Redis(url, { ...this.options, db, lazyConnect: true });
145
- } else {
146
- client = new Redis({ ...this.options, db, lazyConnect: true });
147
- }
148
-
149
- client.on('connect', () => logger.info(\`🔴 Redis connected to db \${db}\`));
150
- client.on('error', (err) => logger.error(\`Redis error on db \${db}: \${err}\`));
151
- return client;
152
- }
153
-
154
- async disconnect(): Promise<void> {
155
- const disconnectPromises: Promise<void>[] = [];
156
- for (const [db, client] of this.clients.entries()) {
157
- disconnectPromises.push(client.quit().then(() => {}).catch(() => client.disconnect()));
158
- }
159
- await Promise.all(disconnectPromises);
160
- this.clients.clear();
161
- this.defaultClient = null;
162
- }
163
-
164
- getClient(): Redis {
165
- if (!this.defaultClient) throw new Error('Redis not connected');
166
- return this.defaultClient;
167
- }
168
-
169
- async getConnection(db: number): Promise<Redis> {
170
- if (db === this.defaultDb) {
171
- if (!this.defaultClient) await this.connect();
172
- return this.defaultClient!;
173
- }
174
- if (this.clients.has(db)) {
175
- const client = this.clients.get(db)!;
176
- if (client.status === 'wait') await client.connect();
177
- return client;
178
- }
179
- const newClient = this.createClient(db);
180
- this.clients.set(db, newClient);
181
- await newClient.connect();
182
- return newClient;
183
- }
184
- }
185
-
186
- export let redisConnectorInstance: RedisConnector | null = null;
187
-
188
- export const setRedisConnectorInstance = (connector: RedisConnector) => {
189
- redisConnectorInstance = connector;
190
- };
191
-
192
- export const getRedisConnector = (): RedisConnector => {
193
- if (!redisConnectorInstance) {
194
- throw new Error('Redis connector not initialized.');
195
- }
196
- return redisConnectorInstance;
197
- };
198
-
199
- export const createRedisRepository = (getDb: () => (Redis | Promise<Redis>), keyPrefix: string) => {
200
- const promiseFunct = (err: any, response: any, resolve: (value: any) => void, reject: (reason?: any) => void) => {
201
- if (err) reject(err);
202
- else resolve(response);
203
- };
204
-
205
- const resolveDb = async (): Promise<Redis> => {
206
- const dbOrPromise = getDb();
207
- return dbOrPromise instanceof Promise ? await dbOrPromise : dbOrPromise;
208
- };
209
-
210
- return {
211
- find: async (_id: string) => {
212
- const db = await resolveDb();
213
- return new Promise((resolve, reject) => {
214
- db.get(_id, (err, response) => promiseFunct(err, response, resolve, reject));
215
- });
216
- },
217
- saveTTL: async (_id: string, _data: any, ttl: number) => {
218
- const db = await resolveDb();
219
- return new Promise((resolve, reject) => {
220
- db.set(_id, _data, (err, response) => {
221
- if (err) reject(err);
222
- else {
223
- db.expire(_id, ttl);
224
- resolve(response);
225
- }
226
- });
227
- });
228
- },
229
- findKeys: async (_id: string) => {
230
- const db = await resolveDb();
231
- return new Promise((resolve, reject) => {
232
- db.keys(_id, (err, response) => {
233
- if (response && response.length > 0) {
234
- promiseFunct(err, response, resolve, reject);
235
- } else {
236
- promiseFunct(null, ['No genero datos'], resolve, reject);
237
- }
238
- });
239
- });
240
- },
241
-
242
- findAll: async () => {
243
- const db = await resolveDb();
244
- return new Promise((resolve, reject) => {
245
- db.keys(keyPrefix + '*', (err, response) => {
246
- if (response && response.length > 0) {
247
- db.mget(response, (err, response2) => {
248
- promiseFunct(err, response2, resolve, reject);
249
- });
250
- } else {
251
- promiseFunct(null, ['No genero datos'], resolve, reject);
252
- }
253
- });
254
- });
255
- },
256
-
257
- save: async (_id: string, _data: any) => {
258
- const db = await resolveDb();
259
- return new Promise((resolve, reject) => {
260
- db.set(_id, _data, (err, response) => {
261
- promiseFunct(err, response, resolve, reject);
262
- });
263
- });
264
- },
265
-
266
- addTTL: async (_id: string, ttl: number) => {
267
- const db = await resolveDb();
268
- return db.expire(_id, ttl);
269
- },
270
-
271
- getTTL: async (_id: string) => {
272
- const db = await resolveDb();
273
- return new Promise((resolve, reject) => {
274
- db.ttl(_id, (err, response) => {
275
- promiseFunct(err, response, resolve, reject);
276
- });
277
- });
278
- },
279
-
280
- incr: async (_id: string) => {
281
- const db = await resolveDb();
282
- return new Promise((resolve, reject) => {
283
- db.incr(_id, (err, response) => {
284
- promiseFunct(err, response, resolve, reject);
285
- });
286
- });
287
- },
288
-
289
- sadd: async (_id: string, _data: any) => {
290
- const db = await resolveDb();
291
- return new Promise((resolve, reject) => {
292
- db.sadd(_id, _data, (err, response) => {
293
- promiseFunct(err, response, resolve, reject);
294
- });
295
- });
296
- },
297
-
298
- sismember: async (_id: string, _data: any) => {
299
- const db = await resolveDb();
300
- return new Promise((resolve, reject) => {
301
- db.sismember(_id, _data, (err, response) => {
302
- promiseFunct(err, response, resolve, reject);
303
- });
304
- });
305
- },
306
-
307
- sisremove: async (_id: string, _data: any) => {
308
- const db = await resolveDb();
309
- return new Promise((resolve, reject) => {
310
- db.srem(_id, _data, (err, response) => {
311
- promiseFunct(err, response, resolve, reject);
312
- });
313
- });
314
- },
315
-
316
- smembers: async (_id: string) => {
317
- const db = await resolveDb();
318
- return new Promise((resolve, reject) => {
319
- db.smembers(_id, (err, response) => {
320
- promiseFunct(err, response, resolve, reject);
321
- });
322
- });
323
- },
324
-
325
- sdiff: async (_id: string) => {
326
- return new Promise((resolve, reject) => {
327
- console.log('sdiff called with', _id);
328
- resolve([]);
329
- });
330
- },
331
-
332
- clear: async (key: string) => {
333
- const db = await resolveDb();
334
- return new Promise((resolve, reject) => {
335
- db.del(key, (err, response) => {
336
- promiseFunct(err, response, resolve, reject);
337
- });
338
- });
339
- }
340
- };
341
- };
342
-
343
- export function createRedisConnector(urlOrOptions: string | RedisOptions): RedisConnector {
344
- const connector = typeof urlOrOptions === 'string'
345
- ? new RedisConnector(urlOrOptions)
346
- : new RedisConnector(urlOrOptions);
347
- setRedisConnectorInstance(connector);
348
- return connector;
349
- }
350
- `;
351
- await fs.writeFile(path.join(projectPath, 'src', 'database', 'redis.ts'), redisContent);
48
+ await fs.writeFile(path.join(projectPath, 'src', 'database', 'redis.ts'), redisTemplate);
352
49
  }
353
50
  // src/database/mongo.ts
354
51
  if (useMongo) {
355
- const mongoContent = `import mongoose from 'mongoose';
356
-
357
- export interface MongoDBOptions {
358
- uri: string;
359
- options?: mongoose.ConnectOptions;
360
- secondaryConnections?: Record<string, string>;
361
- }
362
-
363
- export class MongoDBConnector {
364
- private uri: string;
365
- private options: mongoose.ConnectOptions;
366
- private secondaryConnectionsConfig: Record<string, string> = {};
367
- private isConnected = false;
368
- private secondaryConnections: Map<string, mongoose.Connection> = new Map();
369
-
370
- constructor(config: MongoDBOptions) {
371
- this.uri = config.uri;
372
- this.options = config.options || {};
373
- this.secondaryConnectionsConfig = config.secondaryConnections || {};
374
- }
375
-
376
- async connect(): Promise<void> {
377
- if (this.isConnected) return;
378
- try {
379
- await mongoose.connect(this.uri, this.options);
380
- this.isConnected = true;
381
- console.log('✅ Primary MongoDB connected');
382
-
383
- const secondaryPromises = Object.entries(this.secondaryConnectionsConfig).map(async ([name, uri]) => {
384
- const conn = mongoose.createConnection(uri, this.options);
385
- await conn.asPromise();
386
- this.secondaryConnections.set(name, conn);
387
- console.log(\`✅ Secondary MongoDB '\${name}' connected\`);
388
- });
389
- await Promise.all(secondaryPromises);
390
- } catch (error) {
391
- console.error('MongoDB connection error:', error);
392
- throw error;
393
- }
394
- }
395
-
396
- getSecondaryConnection(name: string): mongoose.Connection | undefined {
397
- return this.secondaryConnections.get(name);
398
- }
399
- }
400
-
401
- export function createMongoDBConnector(uri: string, secondaryConnections?: Record<string, string>): MongoDBConnector {
402
- return new MongoDBConnector({ uri, secondaryConnections });
403
- }
404
- `;
405
- await fs.writeFile(path.join(projectPath, 'src', 'database', 'mongo.ts'), mongoContent);
52
+ await fs.writeFile(path.join(projectPath, 'src', 'database', 'mongo.ts'), mongoTemplate);
406
53
  // src/database/mongo/client.ts (Legacy/Helper for Feature Generator)
407
- const mongoClientContent = `import { MongoDBConnector } from '../mongo.js';
408
- import mongoose from 'mongoose';
409
-
410
- let mongoConnector: MongoDBConnector | null = null;
411
-
412
- export function setMongoDBConnector(connector: MongoDBConnector): void {
413
- mongoConnector = connector;
414
- }
415
-
416
- export function getMongoDBConnector(): MongoDBConnector {
417
- if (!mongoConnector) {
418
- throw new Error('MongoDB connector not initialized. Make sure to connect in main.ts');
419
- }
420
- return mongoConnector;
421
- }
422
-
423
- export function getSecondaryConnection(name: string): mongoose.Connection | undefined {
424
- return getMongoDBConnector().getSecondaryConnection(name);
425
- }
426
- `;
427
54
  await fs.ensureDir(path.join(projectPath, 'src', 'database', 'mongo'));
428
- await fs.writeFile(path.join(projectPath, 'src', 'database', 'mongo', 'client.ts'), mongoClientContent);
55
+ await fs.writeFile(path.join(projectPath, 'src', 'database', 'mongo', 'client.ts'), mongoClientTemplate);
429
56
  }
430
57
  // 5.2 src/database/mysql/client.ts (Only if MySQL is enabled)
431
58
  if (useMySQL) {
432
- const mysqlClientContent = `import { Sequelize } from 'sequelize';
433
-
434
- export interface MySQLConfig {
435
- name?: string; // 'default' or others
436
- database: string;
437
- user: string;
438
- password?: string;
439
- host: string;
440
- port: number;
441
- }
442
-
443
- export class MySQLConnector {
444
- private connections: Map<string, Sequelize> = new Map();
445
- private configs: MySQLConfig[];
446
-
447
- constructor(configs: MySQLConfig[]) {
448
- this.configs = configs;
449
- }
450
-
451
- public async connect(): Promise<void> {
452
- for (const config of this.configs) {
453
- const sequelize = new Sequelize(config.database, config.user, config.password, {
454
- host: config.host,
455
- port: config.port,
456
- dialect: 'mysql',
457
- logging: process.env.NODE_ENV === 'development' ? console.log : false,
458
- });
459
-
460
- try {
461
- await sequelize.authenticate();
462
- console.log(\`MySQL Connection (\${config.name || 'default'}) established successfully.\`);
463
- this.connections.set(config.name || 'default', sequelize);
464
- } catch (error) {
465
- console.error(\`Unable to connect to the MySQL database (\${config.name || 'default'}):\`, error);
466
- }
467
- }
468
- }
469
-
470
- public getConnection(name: string = 'default'): Sequelize | undefined {
471
- return this.connections.get(name);
472
- }
473
-
474
- public getSecondaryConnection(name: string): Sequelize | undefined {
475
- return this.connections.get(name);
476
- }
477
- }
478
-
479
- let mysqlConnector: MySQLConnector | null = null;
480
-
481
- export const setMySQLConnector = (connector: MySQLConnector) => {
482
- mysqlConnector = connector;
483
- };
484
-
485
- export const getMySQLConnector = (): MySQLConnector => {
486
- if (!mysqlConnector) throw new Error('MySQL Connector not initialized');
487
- return mysqlConnector;
488
- };
489
-
490
- export const getSecondaryMySQLConnection = (name: string): Sequelize | undefined => {
491
- return getMySQLConnector().getSecondaryConnection(name);
492
- };
493
-
494
- export default () => {
495
- try {
496
- return getMySQLConnector().getConnection('default');
497
- } catch (e) {
498
- // Fallback for single DB scenarios or before init
499
- return null;
500
- }
501
- };
502
- `;
503
- await fs.writeFile(path.join(projectPath, 'src', 'database', 'mysql', 'client.ts'), mysqlClientContent);
59
+ await fs.writeFile(path.join(projectPath, 'src', 'database', 'mysql', 'client.ts'), mysqlClientTemplate);
504
60
  }
505
61
  // 6. src/index.ts (Entry Point)
506
- let indexImports = `import { MicroserviceServer } from 'micro-generate';
507
- import { typeDefs, resolvers } from './features/index.js';
508
- import * as dotenv from 'dotenv';\n`;
509
- if (useMongo) {
510
- indexImports += `import { createMongoDBConnector } from './database/mongo.js';\n`;
511
- indexImports += `import { setMongoDBConnector } from './database/mongo/client.js';\n`;
512
- }
513
- if (useRedis) {
514
- indexImports += `import { createRedisConnector } from './database/redis.js';\n`;
515
- }
516
- if (useMySQL) {
517
- indexImports += `import { MySQLConnector, setMySQLConnector } from './database/mysql/client.js';\n`;
518
- }
519
- const indexConfig = [];
520
- indexConfig.push(`port: parseInt(process.env.PORT || '4000')`);
521
- if (useMongo) {
522
- indexConfig.push(`mongoUri: process.env.MONGO_URI || ''`);
523
- }
524
- let redisConnectorInit = '';
525
- if (useRedis) {
526
- redisConnectorInit = `
527
- const redisConnector = createRedisConnector({
528
- host: process.env.REDIS_HOST || 'localhost',
529
- port: parseInt(process.env.REDIS_PORT || '6379'),
530
- password: process.env.REDIS_PASSWORD,
531
- db: parseInt(process.env.REDIS_DB || '0')
532
- });
533
- `;
534
- indexConfig.push(`redisConnector: redisConnector`);
535
- }
536
- if (useMongo && dbNames.length > 0) {
537
- const secondaryConfig = dbNames.map(name => {
538
- const envVar = `MONGODB_URI_${name.toUpperCase().replace(/-/g, '_')}`;
539
- return `${name}: process.env.${envVar} || ''`;
540
- }).join(',\\n ');
541
- indexConfig.push(`secondaryConnections: {
542
- ${secondaryConfig}
543
- }`);
544
- }
545
- indexConfig.push(`playground: process.env.GRAPHQL_PLAYGROUND === 'true'`);
546
- indexConfig.push(`introspection: process.env.GRAPHQL_INTROSPECTION === 'true'`);
547
- indexConfig.push(`graphqlPath: process.env.GRAPHQL_PATH || '/graphql'`);
548
- const indexContent = `${indexImports}
549
- dotenv.config();
550
-
551
- ${redisConnectorInit}
552
-
553
- const server = new MicroserviceServer({
554
- ${indexConfig.join(',\n ')},
555
- typeDefs,
556
- resolvers,
557
- });
558
-
559
- ${useMySQL ? `
560
- // MySQL Configuration
561
- const mysqlConfigs = [
562
- {
563
- name: 'default',
564
- database: process.env.MYSQL_DB || '',
565
- user: process.env.MYSQL_USER || '',
566
- password: process.env.MYSQL_PASSWORD,
567
- host: process.env.MYSQL_HOST || 'localhost',
568
- port: parseInt(process.env.MYSQL_PORT || '3306'),
569
- },
570
- ${mysqlDbNames.map(name => {
571
- const upper = name.toUpperCase().replace(/-/g, '_');
572
- return `{
573
- name: '${name}',
574
- database: process.env.MYSQL_DB_${upper} || '',
575
- user: process.env.MYSQL_USER_${upper} || '',
576
- password: process.env.MYSQL_PASSWORD_${upper},
577
- host: process.env.MYSQL_HOST_${upper} || 'localhost',
578
- port: parseInt(process.env.MYSQL_PORT_${upper} || '3306'),
579
- }`;
580
- }).join(',\n ')}
581
- ];
582
-
583
- const mysqlConnector = new MySQLConnector(mysqlConfigs);
584
- setMySQLConnector(mysqlConnector);
585
- ` : ''}
586
-
587
- server.start().then(async () => {
588
- ${useMongo ? `if (server.getMongoDBConnector()) {
589
- setMongoDBConnector(server.getMongoDBConnector()! as any);
590
- }` : ''}
591
-
592
- ${useRedis ? `await redisConnector.connect();` : ''}
593
-
594
- ${useMySQL ? `await mysqlConnector.connect();` : ''}
595
-
596
- console.log('Server initialized');
597
- });
598
-
599
- const gracefulShutdown = async () => {
600
- console.log('Starting graceful shutdown...');
601
- await server.stop();
602
- console.log('Graceful shutdown complete.');
603
- process.exit(0);
604
- };
605
-
606
- process.on('SIGINT', gracefulShutdown);
607
- process.on('SIGTERM', gracefulShutdown);
608
- `;
62
+ const indexContent = getIndexTemplate({ useMongo, useRedis, useMySQL, dbNames, mysqlDbNames });
609
63
  await fs.writeFile(path.join(projectPath, 'src', 'index.ts'), indexContent);
610
64
  // 7. src/features/index.ts
611
- const featuresIndexContent = `export const typeDefs = ['type Query { status: String }'];
612
- export const resolvers = [{ Query: { status: () => 'Functioning' } }];
613
- `;
614
- await fs.writeFile(path.join(projectPath, 'src', 'features', 'index.ts'), featuresIndexContent);
65
+ await fs.writeFile(path.join(projectPath, 'src', 'features', 'index.ts'), featuresIndexTemplate);
615
66
  // 8. .env
616
67
  let envContent = `PORT=4000
617
68
  NODE_ENV=development
@@ -668,16 +119,20 @@ LOG_LEVEL=info
668
119
  'jsdom': '^24.0.0',
669
120
  'zod': '^3.22.4',
670
121
  'graphql': '^16.12.0',
122
+ "express": "^4.18.2",
671
123
  '@apollo/server': '^5.2.0',
672
124
  '@as-integrations/express4': '^1.0.0',
673
125
  'pino': '^10.2.0',
674
126
  'pino-pretty': '^10.3.1'
675
127
  };
128
+ if (useMongo) {
129
+ dependencies['mongoose'] = '^8.1.1';
130
+ }
676
131
  if (useRedis) {
677
132
  dependencies['ioredis'] = '^5.3.2';
678
133
  }
679
134
  if (useMySQL) {
680
- dependencies['sequelize'] = '^6.37.0';
135
+ dependencies['sequelize'] = '^6.37.8';
681
136
  dependencies['mysql2'] = '^3.9.0';
682
137
  }
683
138
  const packageJson = {
@@ -696,95 +151,22 @@ LOG_LEVEL=info
696
151
  '@types/dompurify': '^3.0.0',
697
152
  '@types/jsdom': '^21.1.0',
698
153
  '@types/node': '^20.11.0',
154
+ "@types/express": "^4.17.21",
699
155
  'tsx': '^4.7.0',
700
156
  'typescript': '^5.3.3',
701
157
  'pino-pretty': '^10.3.1'
158
+ },
159
+ "overrides": {
160
+ "uuid": "^11.1.1"
702
161
  }
703
162
  };
704
163
  await fs.writeFile(path.join(projectPath, 'package.json'), JSON.stringify(packageJson, null, 2));
705
164
  // 10. tsconfig.json
706
- const tsConfigContent = `{
707
- "compilerOptions": {
708
- "target": "ES2020",
709
- "module": "NodeNext",
710
- "moduleResolution": "NodeNext",
711
- "outDir": "./dist",
712
- "rootDir": "./src",
713
- "strict": true,
714
- "esModuleInterop": true,
715
- "skipLibCheck": true,
716
- "forceConsistentCasingInFileNames": true
717
- },
718
- "include": ["src/**/*"],
719
- "exclude": ["node_modules", "**/*.spec.ts"]
720
- }
721
- `;
722
- await fs.writeFile(path.join(projectPath, 'tsconfig.json'), tsConfigContent);
165
+ await fs.writeFile(path.join(projectPath, 'tsconfig.json'), tsConfigTemplate);
723
166
  // 11. Add Antigravity Skill
724
167
  const skillPath = path.join(projectPath, '.agent', 'skills', 'micro-generate');
725
168
  await fs.ensureDir(skillPath);
726
- const skillContent = `---
727
- name: micro-generate-helper
728
- description: Use the micro-generate CLI non-interactively to generate features, queries, and mutations.
729
- ---
730
-
731
- # Micro-Generate Skill
732
-
733
- This skill allows you to programmatically invoke the \`micro-generate\` CLI tools to create features, GraphQL operations, and initialize projects without user interaction.
734
-
735
- ## Usage
736
-
737
- You should use the \`run_command\` tool to execute the \`npx micro-generate\` command directly. The CLI has been updated to support headless execution via flags.
738
-
739
- ### 1. Generate Feature (\`feature\`)
740
-
741
- Creates a new feature (Vertical Slice) with optional database support.
742
-
743
- **Options:**
744
- - \`--name <string>\`: (Required) Name of the feature (e.g., "users", "orders").
745
- - \`--mongo\`: Enable MongoDB support.
746
- - \`--no-mongo\`: Disable MongoDB support.
747
- - \`--mysql\`: Enable MySQL support.
748
- - \`--no-mysql\`: Disable MySQL support.
749
- - \`--redis\`: Enable Redis support.
750
- - \`--no-redis\`: Disable Redis support.
751
- - \`--db-connection <string>\`: (Optional) Name of the specific MongoDB connection to use (for Multi-DB).
752
- - \`--mysql-connection <string>\`: (Optional) Name of the specific MySQL connection to use (for Multi-DB).
753
-
754
- **Example:**
755
- \`\`\`bash
756
- npx micro-generate feature --name "notifications" --mongo --redis --db-connection "logs_db"
757
- \`\`\`
758
-
759
- ### 2. Generate GraphQL Query (\`query\`)
760
-
761
- Adds a new Query to an existing feature.
762
-
763
- **Options:**
764
- - \`--feature <string>\`: (Required) Name of the existing feature to add the query to.
765
- - \`--name <string>\`: (Required) Name of the query (e.g., "getUser").
766
- - \`--return-type <string>\`: (Optional) GraphQL return type (default: "String").
767
-
768
- **Example:**
769
- \`\`\`bash
770
- npx micro-generate query --feature "users" --name "getUserByEmail" --return-type "User"
771
- \`\`\`
772
-
773
- ### 3. Generate GraphQL Mutation (\`mutation\`)
774
-
775
- Adds a new Mutation to an existing feature.
776
-
777
- **Options:**
778
- - \`--feature <string>\`: (Required) Name of the existing feature.
779
- - \`--name <string>\`: (Required) Name of the mutation (e.g., "updateUser").
780
- - \`--return-type <string>\`: (Optional) GraphQL return type (default: "String").
781
-
782
- **Example:**
783
- \`\`\`bash
784
- npx micro-generate mutation --feature "users" --name "banUser" --return-type "UserResponse"
785
- \`\`\`
786
- `;
787
- await fs.writeFile(path.join(skillPath, 'SKILL.md'), skillContent);
169
+ await fs.writeFile(path.join(skillPath, 'SKILL.md'), skillTemplate);
788
170
  console.log(chalk.green("Project " + name + " initialized successfully in " + projectPath + "!"));
789
171
  if (useMongo)
790
172
  console.log(chalk.blue("- MongoDB: Enabled"));