@solidstarters/solid-core 1.2.1 → 1.2.3

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 (45) hide show
  1. package/.env +114 -0
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +17 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/decorators/active-user.decorator.d.ts +1 -1
  7. package/dist/dtos/basic-filters.dto.d.ts +1 -0
  8. package/dist/dtos/basic-filters.dto.d.ts.map +1 -1
  9. package/dist/dtos/basic-filters.dto.js +6 -1
  10. package/dist/dtos/basic-filters.dto.js.map +1 -1
  11. package/dist/index.d.ts +1 -0
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +1 -0
  14. package/dist/index.js.map +1 -1
  15. package/dist/services/crud.service.js +5 -9
  16. package/dist/services/crud.service.js.map +1 -1
  17. package/dist/solid-core-cli-db.module.d.ts +3 -0
  18. package/dist/solid-core-cli-db.module.d.ts.map +1 -0
  19. package/dist/solid-core-cli-db.module.js +44 -0
  20. package/dist/solid-core-cli-db.module.js.map +1 -0
  21. package/dist/solid-core-cli.module.d.ts +3 -0
  22. package/dist/solid-core-cli.module.d.ts.map +1 -0
  23. package/dist/solid-core-cli.module.js +45 -0
  24. package/dist/solid-core-cli.module.js.map +1 -0
  25. package/dist/solid-core.module.d.ts.map +1 -1
  26. package/dist/solid-core.module.js +7 -5
  27. package/dist/solid-core.module.js.map +1 -1
  28. package/dist/tsconfig.tsbuildinfo +1 -1
  29. package/dist/winston.logger.d.ts +19 -0
  30. package/dist/winston.logger.d.ts.map +1 -0
  31. package/dist/winston.logger.js +106 -0
  32. package/dist/winston.logger.js.map +1 -0
  33. package/logs/application.log +1855 -0
  34. package/logs/error.log +0 -0
  35. package/package.json +44 -22
  36. package/rebuild.sh +6 -0
  37. package/solidstarters-solid-core-1.2.5.tgz +0 -0
  38. package/src/cli.ts +34 -0
  39. package/src/dtos/basic-filters.dto.ts +5 -1
  40. package/src/index.ts +3 -1
  41. package/src/services/crud.service.ts +28 -28
  42. package/src/solid-core-cli-db.module.ts +62 -0
  43. package/src/solid-core-cli.module.ts +40 -0
  44. package/src/solid-core.module.ts +7 -5
  45. package/src/winston.logger.ts +70 -0
package/logs/error.log ADDED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidstarters/solid-core",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "description": "This module is a NestJS module containing all the required core providers required by a Solid application",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -8,6 +8,9 @@
8
8
  "publishConfig": {
9
9
  "access": "public"
10
10
  },
11
+ "bin": {
12
+ "solidCore": "dist/cli.js"
13
+ },
11
14
  "scripts": {
12
15
  "build": "nest build",
13
16
  "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
@@ -30,20 +33,6 @@
30
33
  "@aws-sdk/client-s3": "^3.637.0",
31
34
  "@elasticemail/elasticemail-client": "^4.0.23",
32
35
  "@hapi/joi": "^17.1.1",
33
- "@nestjs/axios": "^3.0.2",
34
- "@nestjs/cache-manager": "^2.2.2",
35
- "@nestjs/common": "^10.0.0",
36
- "@nestjs/core": "^10.0.0",
37
- "@nestjs/event-emitter": "^2.0.4",
38
- "@nestjs/jwt": "^10.2.0",
39
- "@nestjs/mapped-types": "^2.0.4",
40
- "@nestjs/mongoose": "^10.0.10",
41
- "@nestjs/passport": "^10.0.3",
42
- "@nestjs/platform-express": "^10.0.0",
43
- "@nestjs/serve-static": "^4.0.2",
44
- "@nestjs/swagger": "^7.2.0",
45
- "@nestjs/typeorm": "^10.0.1",
46
- "@types/luxon": "^3.4.2",
47
36
  "amqplib": "^0.10.4",
48
37
  "axios": "^1.7.0",
49
38
  "bcrypt": "^5.1.1",
@@ -57,8 +46,6 @@
57
46
  "luxon": "^3.4.4",
58
47
  "mailgen": "^2.0.28",
59
48
  "mongoose": "^8.7.0",
60
- "nest-commander": "^3.12.5",
61
- "nest-winston": "^1.9.7",
62
49
  "nodemailer": "^6.9.13",
63
50
  "passport": "^0.7.0",
64
51
  "passport-google-oauth2": "^0.2.0",
@@ -70,22 +57,53 @@
70
57
  "reflect-metadata": "^0.1.13",
71
58
  "rxjs": "^7.8.1",
72
59
  "swagger-ui-express": "^5.0.0",
73
- "typeorm": "^0.3.20",
74
- "typeorm-naming-strategies": "^4.1.0",
75
60
  "uuid": "^9.0.1",
76
- "winston": "^3.17.0",
77
61
  "xlsx": "^0.18.5"
78
62
  },
79
63
  "peerDependencies": {
80
- "@nestjs/config": "^3.2.0"
64
+ "@nestjs/axios": "^3.0.2",
65
+ "@nestjs/cache-manager": "^2.2.2",
66
+ "@nestjs/common": "^10.0.0",
67
+ "@nestjs/config": "^3.2.0",
68
+ "@nestjs/core": "^10.0.0",
69
+ "@nestjs/event-emitter": "^2.0.4",
70
+ "@nestjs/jwt": "^10.2.0",
71
+ "@nestjs/mapped-types": "^2.0.4",
72
+ "@nestjs/mongoose": "^10.0.10",
73
+ "@nestjs/passport": "^10.0.3",
74
+ "@nestjs/platform-express": "^10.0.0",
75
+ "@nestjs/serve-static": "^4.0.2",
76
+ "@nestjs/swagger": "^7.2.0",
77
+ "@nestjs/typeorm": "^10.0.1",
78
+ "nest-commander": "^3.12.5",
79
+ "nest-winston": "^1.9.7",
80
+ "typeorm": "^0.3.20",
81
+ "typeorm-naming-strategies": "^4.1.0",
82
+ "winston": "^3.17.0"
81
83
  },
82
84
  "devDependencies": {
85
+ "@nestjs/axios": "^3.0.2",
86
+ "@nestjs/cache-manager": "^2.2.2",
83
87
  "@nestjs/cli": "^10.0.0",
88
+ "@nestjs/common": "^10.0.0",
84
89
  "@nestjs/config": "^3.2.0",
90
+ "@nestjs/core": "^10.0.0",
91
+ "@nestjs/event-emitter": "^2.0.4",
92
+ "@nestjs/jwt": "^10.2.0",
93
+ "@nestjs/mapped-types": "^2.0.4",
94
+ "@nestjs/mongoose": "^10.0.10",
95
+ "@nestjs/passport": "^10.0.3",
96
+ "@nestjs/platform-express": "^10.0.0",
97
+ "@nestjs/serve-static": "^4.0.2",
98
+ "@nestjs/swagger": "^7.2.0",
85
99
  "@nestjs/testing": "^10.0.0",
100
+ "@nestjs/typeorm": "^10.0.1",
101
+ "nest-commander": "^3.12.5",
102
+ "nest-winston": "^1.9.7",
86
103
  "@types/express": "^4.17.17",
87
104
  "@types/hapi__joi": "^17.1.12",
88
105
  "@types/jest": "^29.5.2",
106
+ "@types/luxon": "^3.4.2",
89
107
  "@types/mongoose": "^5.11.97",
90
108
  "@types/multer": "^1.4.11",
91
109
  "@types/node": "^20.3.1",
@@ -110,7 +128,11 @@
110
128
  "ts-loader": "^9.4.3",
111
129
  "ts-node": "^10.9.1",
112
130
  "tsconfig-paths": "^4.2.0",
113
- "typescript": "^5.1.3"
131
+ "typeorm": "^0.3.20",
132
+ "typeorm-naming-strategies": "^4.1.0",
133
+ "typescript": "^5.1.3",
134
+ "winston": "^3.17.0",
135
+ "@solidstarters/solid-code-builder": "^1.0.2"
114
136
  },
115
137
  "jest": {
116
138
  "moduleFileExtensions": [
package/rebuild.sh ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ npm i
3
+ npm run build
4
+ #rm /Users/oswald/.nvm/versions/node/v21.7.3/bin/solid
5
+ npm i -g
6
+ chmod +x dist/cli.js
package/src/cli.ts ADDED
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { CommandFactory } from "nest-commander";
4
+ import { SolidCoreCliModule } from "./solid-core-cli.module";
5
+
6
+ async function bootstrap() {
7
+
8
+ // const app = await NestFactory.create(appModule);
9
+
10
+ // Create an instance of the application, capture the application context so we can inject it into a service in itself.
11
+ // @ts-ignore
12
+ const app = await CommandFactory.createWithoutRunning(SolidCoreCliModule, ['debug', 'error', 'fatal', 'log', 'verbose', 'warn']);
13
+ // const app = await CommandFactory.createWithoutRunning(AppModule, ['debug', 'error', 'fatal', 'log', 'verbose', 'warn']);
14
+ // const app = await CommandFactory.createWithoutRunning(AppModule, ['error', 'fatal']);
15
+
16
+ // Now run the command factory.
17
+ try {
18
+ await CommandFactory.runApplication(app);
19
+ }
20
+ catch (e) {
21
+ process.exit(1);
22
+ }
23
+
24
+ // Exit explicitly, make sure that any commands you have created and are using Promises, you do not keep them orphan/dangling.
25
+ process.exit(0);
26
+ }
27
+
28
+ // https://github.com/typeorm/typeorm/issues/8583
29
+ // const types = require('pg').types;
30
+ // types.setTypeParser(types.builtins.INT8, function(val) {
31
+ // return parseInt(val)
32
+ // });
33
+
34
+ bootstrap();
@@ -18,7 +18,7 @@ export class BasicFilterDto extends PaginationQueryDto {
18
18
  @ApiProperty({ description: "groupBy" })
19
19
  readonly groupBy?: string[];
20
20
 
21
-
21
+
22
22
  @IsOptional()
23
23
  @ApiProperty({ description: "populate" })
24
24
  readonly populate?: string[];
@@ -44,4 +44,8 @@ export class BasicFilterDto extends PaginationQueryDto {
44
44
  @IsOptional()
45
45
  @ApiProperty({ description: "populateGroup" })
46
46
  readonly populateGroup?: boolean;
47
+
48
+ @IsOptional()
49
+ @ApiProperty({ description: "groupFilter" })
50
+ groupFilter?: BasicFilterDto
47
51
  }
package/src/index.ts CHANGED
@@ -222,4 +222,6 @@ export * from './validators/is-parsable-int'
222
222
 
223
223
  export * from './constants'
224
224
  export * from './interfaces'
225
- export * from './solid-core.module'
225
+ export * from './solid-core.module'
226
+
227
+ export * from './winston.logger'
@@ -163,7 +163,7 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
163
163
 
164
164
  //TODO: Will the updates be partial i.e PATCH or full i.e PUT
165
165
  async update(id: number, updateDto: any, files: Express.Multer.File[] = [], isPartialUpdate: boolean = false): Promise<T> {
166
- if (!id) {
166
+ if (!id) {
167
167
  throw new Error('Id is required for update');
168
168
  }
169
169
  const entity = await this.repo.findOne({
@@ -239,7 +239,7 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
239
239
  }
240
240
  }
241
241
 
242
- private fieldCrudManager(fieldMetadata: FieldMetadata, entityManager: EntityManager, isPartialUpdate: boolean=false): FieldCrudManager {
242
+ private fieldCrudManager(fieldMetadata: FieldMetadata, entityManager: EntityManager, isPartialUpdate: boolean = false): FieldCrudManager {
243
243
  const commonOptions = { required: fieldMetadata.required && !isPartialUpdate, fieldName: fieldMetadata.name };
244
244
  switch (fieldMetadata.type) {
245
245
  case SolidFieldType.shortText: {
@@ -262,11 +262,11 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
262
262
  const options = { ...commonOptions };
263
263
  return new JsonFieldCrudManager(options);
264
264
  }
265
- case SolidFieldType.int:{
265
+ case SolidFieldType.int: {
266
266
  const options = { ...commonOptions, min: fieldMetadata.min, max: fieldMetadata.max };
267
267
  return new IntFieldCrudManager(options);
268
268
  }
269
- case SolidFieldType.decimal:{
269
+ case SolidFieldType.decimal: {
270
270
  const options = { ...commonOptions, min: fieldMetadata.min, max: fieldMetadata.max };
271
271
  return new DecimalFieldCrudManager(options);
272
272
  }
@@ -274,21 +274,21 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
274
274
  const options = { ...commonOptions, min: fieldMetadata.min, max: fieldMetadata.max };
275
275
  return new BigIntFieldCrudManager(options);
276
276
  }
277
- case SolidFieldType.email:{
278
- const options = { ...commonOptions, max: fieldMetadata.max?? MAX_EMAIL_LENGTH, regexPattern: fieldMetadata.regexPattern };
277
+ case SolidFieldType.email: {
278
+ const options = { ...commonOptions, max: fieldMetadata.max ?? MAX_EMAIL_LENGTH, regexPattern: fieldMetadata.regexPattern };
279
279
  return new EmailFieldCrudManager(options);
280
280
  }
281
281
  case SolidFieldType.date:
282
- case SolidFieldType.datetime:{
282
+ case SolidFieldType.datetime: {
283
283
  const options = { ...commonOptions };
284
284
  return new DateFieldCrudManager(options);
285
285
  }
286
- case SolidFieldType.password:{
286
+ case SolidFieldType.password: {
287
287
  const options = { ...commonOptions, min: fieldMetadata.min, max: fieldMetadata.max, regexPattern: fieldMetadata.regexPattern };
288
288
  return new PasswordFieldCrudManager(options);
289
289
  }
290
290
  case SolidFieldType.mediaSingle:
291
- case SolidFieldType.mediaMultiple:{
291
+ case SolidFieldType.mediaMultiple: {
292
292
  // update will need to delete the existing media and save the new media
293
293
  // case 'mediaSingle':
294
294
  // Use the EntityController to extract uploaded content & pass to the entity service.
@@ -357,13 +357,13 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
357
357
  }
358
358
  }
359
359
  else throw new Error('Relation type not supported in crud service');
360
- // return (fieldMetadata.relationType === 'many-to-one') ? new ManyToOneRelationFieldCrudManager(fieldMetadata, entityManager) : new ManyToManyRelationFieldCrudManager(fieldMetadata, entityManager); //FIXME many-to-many pending
361
- // ManyToOne -> fieldId. The value is saved as is. No transformation is required
362
- // OneToMany -> fieldIds. Get the value of the oneToMany field side. No transformation is required (While saving special provision to be made)
363
- // ManyToMany
364
- // break;
360
+ // return (fieldMetadata.relationType === 'many-to-one') ? new ManyToOneRelationFieldCrudManager(fieldMetadata, entityManager) : new ManyToManyRelationFieldCrudManager(fieldMetadata, entityManager); //FIXME many-to-many pending
361
+ // ManyToOne -> fieldId. The value is saved as is. No transformation is required
362
+ // OneToMany -> fieldIds. Get the value of the oneToMany field side. No transformation is required (While saving special provision to be made)
363
+ // ManyToMany
364
+ // break;
365
365
  }
366
- case SolidFieldType.selectionStatic:{
366
+ case SolidFieldType.selectionStatic: {
367
367
 
368
368
  // Validation against the selectionStatic values. No transformation is required
369
369
  // If the value is not in the selectionStatic values, then throw
@@ -380,12 +380,12 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
380
380
  const options = { ...commonOptions, selectionDynamicProvider: fieldMetadata.selectionDynamicProvider, selectionDynamicProviderCtxt: fieldMetadata.selectionDynamicProviderCtxt, selectionValueType: fieldMetadata.selectionValueType as SelectionValueType, discoveryService: this.discoveryService };
381
381
  return new SelectionDynamicFieldCrudManager(options);
382
382
  }
383
- case SolidFieldType.uuid:{
383
+ case SolidFieldType.uuid: {
384
384
  const options = { ...commonOptions };
385
385
  // If no value is provided, then generate a uuid. Add to the dto
386
386
  return new UUIDFieldCrudManager(options);
387
387
  }
388
- case SolidFieldType.computed:{
388
+ case SolidFieldType.computed: {
389
389
 
390
390
  // The value will be computed by the computed provider
391
391
  // Invoke the appropriate computed provider, get the value and add to the dto
@@ -401,7 +401,7 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
401
401
  async find(basicFilterDto: BasicFilterDto) {
402
402
  const alias = 'entity';
403
403
  // Extract the required keys from the input query
404
- let { limit, offset, populateMedia, populateGroup } = basicFilterDto;
404
+ let { limit, offset, populateMedia, populateGroup,groupFilter } = basicFilterDto;
405
405
 
406
406
  // Create above query on pincode table using query builder
407
407
  var qb: SelectQueryBuilder<T> = this.repo.createQueryBuilder(alias)
@@ -409,7 +409,7 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
409
409
 
410
410
  if (basicFilterDto.groupBy) {
411
411
  // Get the records and the count
412
- const { groupMeta, groupRecords } = await this.handleGroupFind(qb, populateGroup, alias, populateMedia);
412
+ const { groupMeta, groupRecords } = await this.handleGroupFind(qb, groupFilter,populateGroup, alias, populateMedia);
413
413
  return {
414
414
  groupMeta,
415
415
  groupRecords,
@@ -417,7 +417,7 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
417
417
  }
418
418
  else {
419
419
  // Get the records and the count
420
- const {meta, records} = await this.handleNonGroupFind(qb, populateMedia, offset, limit);
420
+ const { meta, records } = await this.handleNonGroupFind(qb, populateMedia, offset, limit);
421
421
  return {
422
422
  meta,
423
423
  records,
@@ -433,10 +433,10 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
433
433
  await this.handlePopulateMedia(populateMedia, entities);
434
434
  }
435
435
 
436
- return this.wrapFindResponse(offset, limit, count, entities);
436
+ return this.wrapFindResponse(offset, limit, count, entities);
437
437
  }
438
438
 
439
- private async handleGroupFind(qb: SelectQueryBuilder<T>, populateGroup: boolean, alias: string, populateMedia: string[]) {
439
+ private async handleGroupFind(qb: SelectQueryBuilder<T>, groupFilter: BasicFilterDto,populateGroup: boolean, alias: string, populateMedia: string[]) {
440
440
  const groupByResult = await qb.getRawMany();
441
441
 
442
442
  const groupMeta = [];
@@ -446,11 +446,11 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
446
446
  if (populateGroup) {
447
447
  let groupByQb: SelectQueryBuilder<T> = this.repo.createQueryBuilder(alias);
448
448
  // For the group by records, apply the basic filter
449
- const basicFilterDto = {
450
- limit: DEFAULT_LIMIT,
451
- offset: DEFAULT_OFFSET,
452
- };
453
- groupByQb = this.crudHelperService.buildFilterQuery(groupByQb, basicFilterDto, alias);
449
+ // const basicFilterDto = {
450
+ // limit: DEFAULT_LIMIT,
451
+ // offset: DEFAULT_OFFSET,
452
+ // };
453
+ groupByQb = this.crudHelperService.buildFilterQuery(groupByQb, groupFilter, alias);
454
454
  groupByQb = this.crudHelperService.buildGroupByRecordsQuery(groupByQb, group, alias);
455
455
  const [entities, count] = await groupByQb.getManyAndCount();
456
456
 
@@ -459,7 +459,7 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
459
459
  if (populateMedia && populateMedia.length > 0) {
460
460
  await this.handlePopulateMedia(populateMedia, entities);
461
461
  }
462
- const groupData = this.wrapFindResponse(basicFilterDto.offset, basicFilterDto.limit, count, entities);
462
+ const groupData = this.wrapFindResponse(groupFilter.offset, groupFilter.limit, count, entities);
463
463
  groupRecords.push(this.crudHelperService.createGroupRecords(group, alias, groupData));
464
464
  }
465
465
  groupMeta.push(this.crudHelperService.createGroupMeta(group, alias));
@@ -0,0 +1,62 @@
1
+ import { Module } from '@nestjs/common';
2
+ import { TypeOrmModule } from '@nestjs/typeorm';
3
+ import { join } from 'path';
4
+ import { SnakeNamingStrategy } from 'typeorm-naming-strategies';
5
+ import { WinstonTypeORMLogger } from './winston.logger';
6
+ import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
7
+
8
+ @Module({
9
+ imports: [
10
+ TypeOrmModule.forRootAsync({
11
+ // This becomes the default by default.
12
+ // name: 'default',
13
+ useFactory: (logger: Logger) => {
14
+
15
+ const entities = [
16
+ join(__dirname, './entities/*.entity.{ts,js}'),
17
+ ];
18
+
19
+ // DO NOT REMOVE BELOW COMMENT
20
+ // We no longer register subscribers on the TypeORM datasource.
21
+ // instead we register them directly as NestJS providers, and they register themselves as subscribers on the data source during service instantiation in their respective constructor.
22
+ // check ModelSubscriber for a reference.
23
+ // Steps are
24
+ // 1. Create the subscriber like a NestJS injectable service.
25
+ // 2. Register the subscriber in the respective module like you would any other NestJS service.
26
+ // 3. Make sure to not provide the subscribers array below.
27
+ // const subscribers = [
28
+ // join(__dirname, './app-builder/subscribers/*.subscriber.{ts,js}'),
29
+ // join(__dirname, './common/subscribers/*.subscriber.{ts,js}'),
30
+ // join(__dirname, './iam/subscribers/*.subscriber.{ts,js}'),
31
+ // join(__dirname, './queues/subscribers/*.subscriber.{ts,js}'),
32
+ // ...enabledModules.map(module =>
33
+ // join(__dirname, `./${module}/subscribers/*.subscriber.{ts,js}`)
34
+ // ),
35
+ // ];
36
+
37
+ return {
38
+ // type of our database.
39
+ type: 'postgres',
40
+ host: process.env.DEFAULT_DATABASE_HOST,
41
+ port: +process.env.DEFAULT_DATABASE_PORT,
42
+ username: process.env.DEFAULT_DATABASE_USER,
43
+ password: process.env.DEFAULT_DATABASE_PASSWORD,
44
+ // name of our database
45
+ database: process.env.DEFAULT_DATABASE_NAME,
46
+ // models will be loaded automatically
47
+ // autoLoadEntities: true,
48
+ entities: entities,
49
+ // your entities will be synced with the database (recommended: disable in prod)
50
+ synchronize: Boolean(process.env.DEFAULT_DATABASE_SYNCHRONIZE),
51
+ logging: Boolean(process.env.DEFAULT_DATABASE_LOGGING),
52
+ // logger: new WinstonTypeORMLogger(logger), // Pass in the custom WinstonLogger
53
+ namingStrategy: new SnakeNamingStrategy(),
54
+ // subscribers: subscribers
55
+ }
56
+ },
57
+ inject: [WINSTON_MODULE_PROVIDER]
58
+ }),
59
+ ],
60
+ })
61
+ export class SolidCoreCliDBModule{
62
+ }
@@ -0,0 +1,40 @@
1
+ import { Module } from '@nestjs/common';
2
+ import { SolidCoreCliDBModule } from './solid-core-cli-db.module';
3
+ import { SolidCoreModule } from './solid-core.module'; // Import main module
4
+ import { WinstonLoggerConfig } from './winston.logger';
5
+ import { WinstonModule } from 'nest-winston';
6
+ import { CacheModule } from '@nestjs/cache-manager';
7
+ import { EventEmitterModule } from '@nestjs/event-emitter';
8
+ import { RedisOptions } from './config/redis.options';
9
+ import { ConfigModule } from '@nestjs/config';
10
+ import Joi from '@hapi/joi';
11
+
12
+ @Module({
13
+ imports: [
14
+ WinstonModule.forRoot(WinstonLoggerConfig),
15
+ ConfigModule.forRoot({
16
+ isGlobal: true,
17
+ // Here we are specifying the path of the environment file.
18
+ // If not specified then it assumes a file named .env
19
+ // envFilePath: '.environment'
20
+
21
+ // This we do in live environments, where these variables should ideally come
22
+ // from the OS provided environment.
23
+ // ignoreEnvFile: true
24
+
25
+ validationSchema: Joi.object({
26
+ DEFAULT_DATABASE_HOST: Joi.required(),
27
+ DEFAULT_DATABASE_PORT: Joi.number().default(5432),
28
+ }),
29
+
30
+ // load: [appConfig],
31
+ }),
32
+
33
+ SolidCoreCliDBModule,
34
+ CacheModule.registerAsync(RedisOptions),
35
+ EventEmitterModule.forRoot(),
36
+ SolidCoreModule, // Import main module without exposing forRoot()
37
+ ],
38
+ exports: [SolidCoreModule], // Ensure CLI can use all exports
39
+ })
40
+ export class SolidCoreCliModule{}
@@ -121,17 +121,17 @@ import { Msg91SMSService } from './services/sms/Msg91SMSService';
121
121
  import { Msg91WhatsappService } from './services/whatsapp/Msg91WhatsappService';
122
122
  import { SoftDeleteAwareEventSubscriber } from './subscribers/softDeleteAwareEventSubscriber.subscriber';
123
123
 
124
+ import { PermissionMetadataController } from './controllers/permission-metadata.controller';
124
125
  import { PermissionMetadata } from './entities/permission-metadata.entity';
125
126
  import { PermissionMetadataService } from './services/permission-metadata.service';
126
- import { PermissionMetadataController } from './controllers/permission-metadata.controller';
127
127
 
128
- import { RoleMetadata } from './entities/role-metadata.entity';
129
- import { RoleMetadataService } from './services/role-metadata.service';
130
128
  import { RoleMetadataController } from './controllers/role-metadata.controller';
131
- import { PermissionMetadataSeederService } from './seeders/permission-metadata-seeder.service';
129
+ import { UserController } from './controllers/user.controller';
130
+ import { RoleMetadata } from './entities/role-metadata.entity';
132
131
  import { User } from './entities/user.entity';
132
+ import { PermissionMetadataSeederService } from './seeders/permission-metadata-seeder.service';
133
+ import { RoleMetadataService } from './services/role-metadata.service';
133
134
  import { UserService } from './services/user.service';
134
- import { UserController } from './controllers/user.controller';
135
135
 
136
136
 
137
137
  @Global()
@@ -311,6 +311,8 @@ import { UserController } from './controllers/user.controller';
311
311
  AuthenticationService,
312
312
  MqMessageQueueService,
313
313
  MqMessageService,
314
+ RefreshModelCommand,
315
+ RefreshModuleCommand,
314
316
  ],
315
317
  })
316
318
  export class SolidCoreModule { }
@@ -0,0 +1,70 @@
1
+
2
+ import { Logger as TypeORMLogger, QueryRunner } from 'typeorm';
3
+ import { Logger } from 'winston';
4
+ import { Inject } from '@nestjs/common';
5
+ import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
6
+ import * as winston from 'winston';
7
+
8
+ export const WinstonLoggerConfig = {
9
+ level: 'debug', // Allow all log levels for debugging
10
+ format: winston.format.combine(
11
+ winston.format.timestamp(),
12
+ winston.format.errors({ stack: true }),
13
+ winston.format.printf(({ level, message, timestamp }) => {
14
+ if (!message) {
15
+ return `[${timestamp}] ${level.toUpperCase()}: (No message provided)`;
16
+ }
17
+ return `[${timestamp}] ${level.toUpperCase()}: ${message}`;
18
+ }),
19
+ ),
20
+ transports: [
21
+ new winston.transports.Console({
22
+ format: winston.format.combine(
23
+ // winston.format.colorize(),
24
+ // winston.format.timestamp(),
25
+ winston.format.printf(({ level, message, timestamp }) => {
26
+ return `[${timestamp}] ${level.toUpperCase()}: ${message}`;
27
+ }),
28
+ ),
29
+ }),
30
+ new winston.transports.File({
31
+ filename: 'logs/application.log',
32
+ // format: winston.format.json(),
33
+ }),
34
+ new winston.transports.File({
35
+ filename: 'logs/error.log',
36
+ level: 'error',
37
+ // format: winston.format.json(),
38
+ }),
39
+ ],
40
+ };
41
+
42
+ export class WinstonTypeORMLogger implements TypeORMLogger {
43
+ constructor(@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger) { }
44
+
45
+ logQuery(query: string, parameters?: any[], queryRunner?: QueryRunner): void {
46
+ if (Boolean(process.env.DEFAULT_DATABASE_LOGGING)) {
47
+ this.logger.info(`Query: ${query} Parameters: ${parameters}`);
48
+ }
49
+ }
50
+
51
+ logQueryError(error: string, query: string, parameters?: any[], queryRunner?: QueryRunner): void {
52
+ this.logger.error(`Query failed: ${error} | Query: ${query} | Parameters: ${parameters}`);
53
+ }
54
+
55
+ logQuerySlow(time: number, query: string, parameters?: any[], queryRunner?: QueryRunner): void {
56
+ this.logger.warn(`Slow query: ${time}ms | Query: ${query} | Parameters: ${parameters}`);
57
+ }
58
+
59
+ logSchemaBuild(message: string, queryRunner?: QueryRunner): void {
60
+ this.logger.info(`Schema Build: ${message}`);
61
+ }
62
+
63
+ logMigration(message: string, queryRunner?: QueryRunner): void {
64
+ this.logger.info(`Migration: ${message}`);
65
+ }
66
+
67
+ log(level: 'log' | 'info' | 'warn' | 'error', message: any): void {
68
+ this.logger[level](message);
69
+ }
70
+ }