crypt-express-app 1.0.0

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.
@@ -0,0 +1,715 @@
1
+ // generate-module.ts
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+
5
+ // get module name from command line
6
+ const args = process.argv.slice(2);
7
+
8
+ // Check that exactly **one argument** is provided
9
+ if (args.length !== 1) {
10
+ console.error('Invalid module name: provide exactly one module name without spaces.');
11
+ console.error('Example: npm run generate-module clientRole');
12
+ process.exit(1);
13
+ }
14
+
15
+ const moduleInput = args[0];
16
+
17
+ // Reject if input contains spaces
18
+ if (/\s/.test(moduleInput)) {
19
+ console.error('Invalid module name: spaces are not allowed. Use camelCase, kebab-case or snake_case.');
20
+ process.exit(1);
21
+ }
22
+
23
+ if (!moduleInput) {
24
+ console.error('Please provide a module name: npm run generate-module <module-name>');
25
+ process.exit(1);
26
+ }
27
+
28
+ // Convert any input to camelCase
29
+ const moduleName = moduleInput.includes('-') || moduleInput.includes('_') || moduleInput.includes(' ')
30
+ ? moduleInput
31
+ .toLowerCase()
32
+ .replace(/[-_\s]+(.)/g, (_, c) => c.toUpperCase())
33
+ : moduleInput; // preserve existing camelCase
34
+
35
+ console.log("moduleName: ", moduleName)
36
+
37
+ // Convert any input (camelCase, PascalCase, snake_case, spaces) to kebab-case
38
+ const fileName = moduleName
39
+ .replace(/([a-z])([A-Z])/g, '$1-$2') // add dash before uppercase letters
40
+ .toLowerCase(); // lowercase everything
41
+
42
+ console.log("fileName: ", fileName)
43
+
44
+
45
+ // const basePath = path.join(__dirname, '..', 'src', 'modules', fileName);
46
+ // const basePath = path.join(__dirname, '..', 'src', 'modules', fileName);
47
+ const projectRoot = process.cwd();
48
+ const modulesRoot = path.join(projectRoot, "src", "modules");
49
+ const basePath = path.join(modulesRoot, fileName);
50
+
51
+ // ensure modules directory exists
52
+ if (!fs.existsSync(modulesRoot)) {
53
+ fs.mkdirSync(modulesRoot, { recursive: true });
54
+ }
55
+
56
+ // prevent overwrite
57
+ if (fs.existsSync(basePath)) {
58
+ console.error(`❌ Module '${fileName}' already exists.`);
59
+ process.exit(1);
60
+ }
61
+
62
+ fs.mkdirSync(basePath, { recursive: true });
63
+
64
+
65
+ // Create folder
66
+ if (!fs.existsSync(basePath)) {
67
+ fs.mkdirSync(basePath, { recursive: true });
68
+ }
69
+
70
+ // Capitalize first letter
71
+ const ModuleClassName = moduleName.charAt(0).toUpperCase() + moduleName.slice(1);
72
+
73
+ // Service
74
+ const serviceContent = `import { Create${ModuleClassName}Dto, Update${ModuleClassName}Dto, Create${ModuleClassName}Response, Update${ModuleClassName}Response, Get${ModuleClassName}Response, List${ModuleClassName}Response } from "./${fileName}.dto";
75
+ import { Prisma } from "@prisma/client";
76
+ import prisma from '../../prisma/client';
77
+ import { PaginationRequestDto } from "../common/common.dto";
78
+
79
+
80
+ export class ${ModuleClassName}Service {
81
+ constructor() {}
82
+
83
+ async create(payload: Create${ModuleClassName}Dto): Promise<Create${ModuleClassName}Response> {
84
+ try {
85
+ // TODO: create ${ModuleClassName} in database
86
+ return {
87
+ ${moduleName}Id: "generated-${moduleName}Id",
88
+ ...payload,
89
+ createdAt: new Date().toISOString(),
90
+ updatedAt: new Date().toISOString(),
91
+ };
92
+ } catch (error) {
93
+ throw error;
94
+ }
95
+ }
96
+
97
+ async update(${moduleName}Id: string, payload: Update${ModuleClassName}Dto): Promise<Update${ModuleClassName}Response> {
98
+ try {
99
+ // TODO: update ${ModuleClassName} by ${moduleName}Id
100
+ return {
101
+ ${moduleName}Id,
102
+ ...payload,
103
+ updatedAt: new Date().toISOString(),
104
+ };
105
+ } catch (error) {
106
+ throw error;
107
+ }
108
+ }
109
+
110
+ async getById(${moduleName}Id: string): Promise<Get${ModuleClassName}Response> {
111
+ try {
112
+ // TODO: fetch ${ModuleClassName} by ${moduleName}Id
113
+ return {
114
+ ${moduleName}Id,
115
+ name: "Sample ${ModuleClassName}",
116
+ createdAt: new Date().toISOString(),
117
+ updatedAt: new Date().toISOString(),
118
+ };
119
+ } catch (error) {
120
+ throw error;
121
+ }
122
+ }
123
+
124
+ async list({
125
+ offset = 0,
126
+ limit = 20,
127
+ search,
128
+ sortBy = "createdAt",
129
+ sortOrder = "desc",
130
+ }: PaginationRequestDto): Promise<{ items: List${ModuleClassName}Response; total: number }> {
131
+ try {
132
+ // TODO: fetch list of ${ModuleClassName}
133
+ return {
134
+ total: 1,
135
+ items: [
136
+ {
137
+ ${moduleName}Id: "1",
138
+ name: "Sample ${ModuleClassName} 1",
139
+ createdAt: new Date().toISOString(),
140
+ updatedAt: new Date().toISOString(),
141
+ },
142
+ ]
143
+ }
144
+ } catch (error) {
145
+ throw error;
146
+ }
147
+ }
148
+
149
+ async delete(${moduleName}Id: string): Promise<void> {
150
+ try {
151
+ // TODO: delete ${ModuleClassName} by ${moduleName}Id
152
+ return;
153
+ } catch (error) {
154
+ throw error;
155
+ }
156
+ }
157
+ }
158
+
159
+ export default new ${ModuleClassName}Service()
160
+ `;
161
+
162
+ fs.writeFileSync(path.join(basePath, `${fileName}.service.ts`), serviceContent);
163
+
164
+ // Controller
165
+ const controllerContent = `
166
+ import { Request, Response } from 'express';
167
+ import { ${ModuleClassName}Service } from './${fileName}.service';
168
+ import {
169
+ Create${ModuleClassName}Dto,
170
+ Update${ModuleClassName}Dto,
171
+ Create${ModuleClassName}ResponseDto,
172
+ Update${ModuleClassName}ResponseDto,
173
+ Get${ModuleClassName}ResponseDto,
174
+ List${ModuleClassName}ResponseDto
175
+ } from './${fileName}.dto';
176
+ import { PaginationRequestDto } from '../common/common.dto';
177
+
178
+ export class ${ModuleClassName}Controller {
179
+ constructor(private ${moduleName}Service: ${ModuleClassName}Service) {}
180
+
181
+ async create(req: Request, res: Response) {
182
+ try {
183
+ const payload: Create${ModuleClassName}Dto = req.body;
184
+ const data = await this.${moduleName}Service.create(payload);
185
+ const response: Create${ModuleClassName}ResponseDto = {
186
+ success: true,
187
+ status: 201,
188
+ message: '${ModuleClassName} created successfully',
189
+ data,
190
+ };
191
+ res.status(201).json(response);
192
+ } catch (error: any) {
193
+ res.status(500).json({ success: false, status: 500, message: error.message });
194
+ }
195
+ }
196
+
197
+ async update(req: Request, res: Response) {
198
+ try {
199
+ const ${moduleName}Id = req.params.${moduleName}Id as string;
200
+ const payload: Update${ModuleClassName}Dto = req.body;
201
+ const data = await this.${moduleName}Service.update(${moduleName}Id, payload);
202
+ const response: Update${ModuleClassName}ResponseDto = {
203
+ success: true,
204
+ status: 200,
205
+ message: '${ModuleClassName} updated successfully',
206
+ data,
207
+ };
208
+ res.json(response);
209
+ } catch (error: any) {
210
+ res.status(500).json({ success: false, status: 500, message: error.message });
211
+ }
212
+ }
213
+
214
+ async getById(req: Request, res: Response) {
215
+ try {
216
+ const ${moduleName}Id = req.params.${moduleName}Id as string;
217
+ const data = await this.${moduleName}Service.getById(${moduleName}Id);
218
+ const response: Get${ModuleClassName}ResponseDto = {
219
+ success: true,
220
+ status: 200,
221
+ message: '${ModuleClassName} fetched successfully',
222
+ data,
223
+ };
224
+ res.json(response);
225
+ } catch (error: any) {
226
+ res.status(404).json({ success: false, status: 404, message: error.message });
227
+ }
228
+ }
229
+
230
+ async list(req: Request, res: Response) {
231
+ try {
232
+ const query = req.query as PaginationRequestDto;
233
+
234
+ const offset = query.offset ? Number(query.offset) : 0;
235
+ const limit = query.limit ? Number(query.limit) : 20;
236
+ const search = query.search;
237
+ const sortBy = query.sortBy || "createdAt";
238
+ const sortOrder = query.sortOrder || "desc";
239
+ const { items, total } =
240
+ await this.${moduleName}Service.list({
241
+ offset,
242
+ limit,
243
+ search,
244
+ sortBy,
245
+ sortOrder,
246
+ });
247
+
248
+ const response: List${ModuleClassName}ResponseDto = {
249
+ success: true,
250
+ status: 200,
251
+ message: "${ModuleClassName} list fetched successfully",
252
+ data: {
253
+ items,
254
+ total,
255
+ offset,
256
+ limit,
257
+ },
258
+ };
259
+ res.json(response);
260
+ } catch (error: any) {
261
+ res.status(500).json({ success: false, status: 500, message: error.message });
262
+ }
263
+ }
264
+
265
+ async delete(req: Request, res: Response) {
266
+ try {
267
+ const ${moduleName}Id = req.params.${moduleName}Id as string;
268
+ await this.${moduleName}Service.delete(${moduleName}Id);
269
+ res.json({
270
+ success: true,
271
+ status: 200,
272
+ message: '${ModuleClassName} deleted successfully',
273
+ });
274
+ } catch (error: any) {
275
+ res.status(500).json({ success: false, status: 500, message: error.message });
276
+ }
277
+ }
278
+ }
279
+ `;
280
+
281
+ fs.writeFileSync(path.join(basePath, `${fileName}.controller.ts`), controllerContent);
282
+
283
+ // Routes
284
+ const routesContent = `
285
+ import express, { Router } from 'express';
286
+ import { ${ModuleClassName}Controller } from './${fileName}.controller';
287
+ import { ${moduleName}Middleware } from './${fileName}.middlewares';
288
+ import { authMiddleware } from '../../middlewares/auth.middleware';
289
+ import ${moduleName}Service from './${fileName}.service';
290
+ import { ActionsType, Resource, ResourceType } from '../../utils/consts';
291
+ import { authorizationMiddleware } from '../../middlewares/authorization.middleware';
292
+
293
+ const router: Router = express.Router();
294
+ const controller = new ${ModuleClassName}Controller(${moduleName}Service);
295
+ router.use(authMiddleware);
296
+ const guard = (actions: ActionsType[]) => authorizationMiddleware({ resource: Resource.COMMON, actions, resourceType: ResourceType.API_ENDPOINT });
297
+
298
+ /**
299
+ * @openapi
300
+ * tags:
301
+ * - name: ${ModuleClassName}
302
+ * description: ${ModuleClassName} management and operations
303
+ */
304
+
305
+ /**
306
+ * @openapi
307
+ * /api/${moduleName}:
308
+ * post:
309
+ * tags: [${ModuleClassName}]
310
+ * summary: Create a new ${ModuleClassName}
311
+ * requestBody:
312
+ * required: true
313
+ * content:
314
+ * application/json:
315
+ * schema:
316
+ * $ref: '#/components/schemas/Create${ModuleClassName}Dto'
317
+ * responses:
318
+ * 201:
319
+ * description: ${ModuleClassName} created successfully
320
+ * content:
321
+ * application/json:
322
+ * schema:
323
+ * $ref: '#/components/schemas/Create${ModuleClassName}ResponseDto'
324
+ */
325
+ router.post('/', ${moduleName}Middleware, guard([ActionsType.CREATE]), controller.create.bind(controller));
326
+
327
+ /**
328
+ * @openapi
329
+ * /api/${moduleName}/{${moduleName}Id}:
330
+ * get:
331
+ * tags: [${ModuleClassName}]
332
+ * summary: Get a ${ModuleClassName} by ID
333
+ * parameters:
334
+ * - name: ${moduleName}Id
335
+ * in: path
336
+ * required: true
337
+ * schema:
338
+ * type: string
339
+ * responses:
340
+ * 200:
341
+ * description: ${ModuleClassName} fetched successfully
342
+ * content:
343
+ * application/json:
344
+ * schema:
345
+ * $ref: '#/components/schemas/Get${ModuleClassName}ResponseDto'
346
+ */
347
+ router.get('/:${moduleName}Id', ${moduleName}Middleware, guard([ActionsType.READ]), controller.getById.bind(controller));
348
+
349
+ /**
350
+ * @openapi
351
+ * /api/${moduleName}/{${moduleName}Id}:
352
+ * put:
353
+ * tags: [${ModuleClassName}]
354
+ * summary: Update a ${ModuleClassName} by ID
355
+ * parameters:
356
+ * - name: ${moduleName}Id
357
+ * in: path
358
+ * required: true
359
+ * schema:
360
+ * type: string
361
+ * requestBody:
362
+ * required: true
363
+ * content:
364
+ * application/json:
365
+ * schema:
366
+ * $ref: '#/components/schemas/Update${ModuleClassName}Dto'
367
+ * responses:
368
+ * 200:
369
+ * description: ${ModuleClassName} updated successfully
370
+ * content:
371
+ * application/json:
372
+ * schema:
373
+ * $ref: '#/components/schemas/Update${ModuleClassName}ResponseDto'
374
+ */
375
+ router.put('/:${moduleName}Id', ${moduleName}Middleware, guard([ActionsType.UPDATE]), controller.update.bind(controller));
376
+
377
+ /**
378
+ * @openapi
379
+ * /api/${moduleName}/{${moduleName}Id}:
380
+ * delete:
381
+ * tags: [${ModuleClassName}]
382
+ * summary: Delete a ${ModuleClassName} by ID
383
+ * parameters:
384
+ * - name: ${moduleName}Id
385
+ * in: path
386
+ * required: true
387
+ * schema:
388
+ * type: string
389
+ * responses:
390
+ * 200:
391
+ * description: ${ModuleClassName} deleted successfully
392
+ * content:
393
+ * application/json:
394
+ * schema:
395
+ * type: object
396
+ * properties:
397
+ * success:
398
+ * type: boolean
399
+ * status:
400
+ * type: integer
401
+ * message:
402
+ * type: string
403
+ */
404
+ router.delete('/:${moduleName}Id', ${moduleName}Middleware, guard([ActionsType.DELETE]), controller.delete.bind(controller));
405
+
406
+ /**
407
+ * @openapi
408
+ * /api/${moduleName}:
409
+ * get:
410
+ * tags: [${ModuleClassName}]
411
+ * summary: List all ${ModuleClassName}s with pagination
412
+ * parameters:
413
+ * - in: query
414
+ * name: offset
415
+ * schema:
416
+ * type: integer
417
+ * description: Offset for pagination
418
+ * - in: query
419
+ * name: limit
420
+ * schema:
421
+ * type: integer
422
+ * description: Limit for pagination
423
+ * - in: query
424
+ * name: search
425
+ * schema:
426
+ * type: string
427
+ * description: Search keyword
428
+ * - in: query
429
+ * name: sortBy
430
+ * schema:
431
+ * type: string
432
+ * description: Field to sort by
433
+ * - in: query
434
+ * name: sortOrder
435
+ * schema:
436
+ * type: string
437
+ * enum: [asc, desc]
438
+ * description: Sort order
439
+ * responses:
440
+ * 200:
441
+ * description: List of ${ModuleClassName}s
442
+ * content:
443
+ * application/json:
444
+ * schema:
445
+ * $ref: '#/components/schemas/List${ModuleClassName}ResponseDto'
446
+ */
447
+ router.get('/', ${moduleName}Middleware, guard([ActionsType.READ_ALL]), controller.list.bind(controller));
448
+
449
+ /**
450
+ * ======================================================
451
+ * Optional: Health Check
452
+ * ======================================================
453
+ */
454
+ router.get('/health/check', (_req, res) => {
455
+ res.json({
456
+ success: true,
457
+ status: 200,
458
+ message: "${ModuleClassName} module is healthy",
459
+ });
460
+ });
461
+
462
+ export default router;
463
+ `;
464
+
465
+
466
+ fs.writeFileSync(path.join(basePath, `${fileName}.routes.ts`), routesContent);
467
+ const dtoContent = `import { ApiResponse, PaginatedData } from "../common/common.dto";
468
+
469
+ /**
470
+ * Main ${ModuleClassName} entity
471
+ *
472
+ * @openapi
473
+ * components:
474
+ * schemas:
475
+ * ${ModuleClassName}:
476
+ * type: object
477
+ * required:
478
+ * - name
479
+ * properties:
480
+ * ${moduleName}Id:
481
+ * type: string
482
+ * example: "c3f2a9b4-8d21-4f3b-a91c-1a2b3c4d5e6f"
483
+ * description: Unique identifier of the ${ModuleClassName}
484
+ * name:
485
+ * type: string
486
+ * example: Sample ${ModuleClassName}
487
+ * description: Name of the ${ModuleClassName}
488
+ * description:
489
+ * type: string
490
+ * example: Optional description
491
+ * nullable: true
492
+ * description: Description of the ${ModuleClassName}
493
+ * createdAt:
494
+ * type: string
495
+ * format: date-time
496
+ * example: "2025-01-01T10:00:00.000Z"
497
+ * description: Creation timestamp
498
+ * updatedAt:
499
+ * type: string
500
+ * format: date-time
501
+ * example: "2025-01-02T12:00:00.000Z"
502
+ * description: Last update timestamp
503
+ */
504
+ export interface ${ModuleClassName} {
505
+ ${moduleName}Id: string;
506
+ name: string;
507
+ description?: string;
508
+ createdAt: string;
509
+ updatedAt: string;
510
+ }
511
+
512
+ /**
513
+ * @openapi
514
+ * components:
515
+ * schemas:
516
+ * Create${ModuleClassName}Dto:
517
+ * type: object
518
+ * required:
519
+ * - name
520
+ * properties:
521
+ * name:
522
+ * type: string
523
+ * example: Sample ${ModuleClassName}
524
+ * description: Name of the ${ModuleClassName}
525
+ * description:
526
+ * type: string
527
+ * example: Sample description
528
+ */
529
+ export interface Create${ModuleClassName}Dto {
530
+ name: string;
531
+ description?: string;
532
+ }
533
+
534
+ /**
535
+ * @openapi
536
+ * components:
537
+ * schemas:
538
+ * Update${ModuleClassName}Dto:
539
+ * type: object
540
+ * properties:
541
+ * name:
542
+ * type: string
543
+ * example: Updated ${ModuleClassName} Name
544
+ * description:
545
+ * type: string
546
+ * example: Updated description
547
+ */
548
+ export interface Update${ModuleClassName}Dto {
549
+ name?: string;
550
+ description?: string;
551
+ }
552
+
553
+ /**
554
+ * ======================================================
555
+ * Service return types (data only, controller wraps response)
556
+ * ======================================================
557
+ */
558
+
559
+ // data returned from service
560
+ export type Create${ModuleClassName}Response = Partial<${ModuleClassName}>;
561
+ export type Update${ModuleClassName}Response = Partial<${ModuleClassName}>;
562
+ export type Get${ModuleClassName}Response = Partial<${ModuleClassName}>;
563
+ export type List${ModuleClassName}Response = Partial<${ModuleClassName}>[];
564
+
565
+ /**
566
+ * ======================================================
567
+ * API Response DTOs (Swagger documented)
568
+ * ======================================================
569
+ */
570
+
571
+ /**
572
+ * @openapi
573
+ * components:
574
+ * schemas:
575
+ * Create${ModuleClassName}ResponseDto:
576
+ * allOf:
577
+ * - $ref: '#/components/schemas/ApiResponse'
578
+ * - type: object
579
+ * properties:
580
+ * data:
581
+ * $ref: '#/components/schemas/${ModuleClassName}'
582
+ */
583
+ export interface Create${ModuleClassName}ResponseDto
584
+ extends ApiResponse<Partial<${ModuleClassName}>> {}
585
+
586
+ /**
587
+ * @openapi
588
+ * components:
589
+ * schemas:
590
+ * Update${ModuleClassName}ResponseDto:
591
+ * allOf:
592
+ * - $ref: '#/components/schemas/ApiResponse'
593
+ * - type: object
594
+ * properties:
595
+ * data:
596
+ * $ref: '#/components/schemas/${ModuleClassName}'
597
+ */
598
+ export interface Update${ModuleClassName}ResponseDto
599
+ extends ApiResponse<Partial<${ModuleClassName}>> {}
600
+
601
+ /**
602
+ * @openapi
603
+ * components:
604
+ * schemas:
605
+ * Get${ModuleClassName}ResponseDto:
606
+ * allOf:
607
+ * - $ref: '#/components/schemas/ApiResponse'
608
+ * - type: object
609
+ * properties:
610
+ * data:
611
+ * $ref: '#/components/schemas/${ModuleClassName}'
612
+ */
613
+ export interface Get${ModuleClassName}ResponseDto
614
+ extends ApiResponse<Partial<${ModuleClassName}>> {}
615
+
616
+ /**
617
+ * @openapi
618
+ * components:
619
+ * schemas:
620
+ * List${ModuleClassName}ResponseDto:
621
+ * allOf:
622
+ * - $ref: '#/components/schemas/ApiResponse'
623
+ * - type: object
624
+ * properties:
625
+ * data:
626
+ * type: object
627
+ * properties:
628
+ * items:
629
+ * type: array
630
+ * items:
631
+ * $ref: '#/components/schemas/${ModuleClassName}'
632
+ * total:
633
+ * type: integer
634
+ * offset:
635
+ * type: integer
636
+ * limit:
637
+ * type: integer
638
+ */
639
+ export interface List${ModuleClassName}ResponseDto
640
+ extends ApiResponse<PaginatedData<Partial<${ModuleClassName}>>> {}
641
+ `;
642
+
643
+
644
+ fs.writeFileSync(path.join(basePath, `${fileName}.dto.ts`), dtoContent);
645
+
646
+ // Middleware
647
+ const middlewareContent = `
648
+ import { Request, Response, NextFunction } from "express";
649
+ import { cacheService } from "../../utils/redis";
650
+ import { CachedUserProfilePermissionDto } from "../../utils/redis.dto";
651
+
652
+ export async function ${moduleName}Middleware(req: Request, res: Response, next: NextFunction) {
653
+ try {
654
+ const { userId } = req.user!
655
+ const profile = await cacheService.get<CachedUserProfilePermissionDto>(\`user:\${userId}:permissions\`);
656
+ if(!profile) throw new Error("No permission found")
657
+ const userPermissions = profile;
658
+
659
+ const method = req.method;
660
+ const url = req.originalUrl;
661
+ const path = req.path;
662
+ const ${moduleName}Id = req?.params?.${moduleName}Id
663
+
664
+ console.log("---- REALM MIDDLEWARE ----");
665
+ console.log("Method:", method);
666
+ console.log("URL:", url);
667
+ console.log("Path:", path);
668
+
669
+ // Example condition checking
670
+ if (method === "POST" && path === "/") {
671
+ console.log("👉 Creating new realm");
672
+ }
673
+
674
+ if (method === "GET" && path === "/") {
675
+ console.log("👉 Listing realms");
676
+ }
677
+
678
+ if (method === "GET" && ${moduleName}Id) {
679
+ console.log("👉 Getting realm by ID:", ${moduleName}Id);
680
+ }
681
+
682
+ if (method === "PUT") {
683
+ console.log("👉 Updating realm");
684
+ }
685
+
686
+ if (method === "DELETE") {
687
+ console.log("👉 Deleting realm");
688
+ }
689
+
690
+ next();
691
+ } catch (error) {
692
+ return res.status(500).json({
693
+ message: "Authorization error",
694
+ });
695
+ }
696
+ }
697
+ `;
698
+
699
+ fs.writeFileSync(path.join(basePath, `${fileName}.middlewares.ts`), middlewareContent);
700
+
701
+ const routerIndexPath = path.join(projectRoot, "src", "routes.ts");
702
+
703
+ if (fs.existsSync(routerIndexPath)) {
704
+ fs.appendFileSync(
705
+ routerIndexPath,
706
+ `\nimport ${moduleName}Routes from "./modules/${fileName}/${fileName}.routes";`
707
+ );
708
+
709
+ fs.appendFileSync(
710
+ routerIndexPath,
711
+ `\nrouter.use("/${moduleName}", ${moduleName}Routes);\n`
712
+ );
713
+ }
714
+
715
+ console.log(`Module '${moduleName}' generated successfully at ${basePath}`);