@solidstarters/solid-core 1.2.160 → 1.2.163

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 (62) hide show
  1. package/dist/commands/ingest.command.d.ts +16 -0
  2. package/dist/commands/ingest.command.d.ts.map +1 -0
  3. package/dist/commands/ingest.command.js +50 -0
  4. package/dist/commands/ingest.command.js.map +1 -0
  5. package/dist/commands/refresh-module.command.d.ts.map +1 -1
  6. package/dist/commands/refresh-module.command.js.map +1 -1
  7. package/dist/controllers/service.controller.d.ts +16 -1
  8. package/dist/controllers/service.controller.d.ts.map +1 -1
  9. package/dist/controllers/service.controller.js +55 -2
  10. package/dist/controllers/service.controller.js.map +1 -1
  11. package/dist/controllers/test.controller.d.ts +6 -1
  12. package/dist/controllers/test.controller.d.ts.map +1 -1
  13. package/dist/controllers/test.controller.js +21 -3
  14. package/dist/controllers/test.controller.js.map +1 -1
  15. package/dist/entities/common.entity.d.ts.map +1 -1
  16. package/dist/entities/common.entity.js +14 -2
  17. package/dist/entities/common.entity.js.map +1 -1
  18. package/dist/entities/user.entity.d.ts.map +1 -1
  19. package/dist/entities/user.entity.js +11 -1
  20. package/dist/entities/user.entity.js.map +1 -1
  21. package/dist/helpers/error-mapper.service.d.ts +8 -0
  22. package/dist/helpers/error-mapper.service.d.ts.map +1 -0
  23. package/dist/helpers/error-mapper.service.js +108 -0
  24. package/dist/helpers/error-mapper.service.js.map +1 -0
  25. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.d.ts.map +1 -1
  26. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.js +4 -2
  27. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.js.map +1 -1
  28. package/dist/seeders/seed-data/solid-core-metadata.json +21 -0
  29. package/dist/services/genai/ingest-metadata.service.d.ts +38 -0
  30. package/dist/services/genai/ingest-metadata.service.d.ts.map +1 -0
  31. package/dist/services/genai/ingest-metadata.service.js +530 -0
  32. package/dist/services/genai/ingest-metadata.service.js.map +1 -0
  33. package/dist/services/genai/r2r-helper.service.d.ts +7 -0
  34. package/dist/services/genai/r2r-helper.service.d.ts.map +1 -0
  35. package/dist/services/genai/r2r-helper.service.js +36 -0
  36. package/dist/services/genai/r2r-helper.service.js.map +1 -0
  37. package/dist/services/setting.service.d.ts.map +1 -1
  38. package/dist/services/setting.service.js +38 -20
  39. package/dist/services/setting.service.js.map +1 -1
  40. package/dist/solid-core.module.d.ts.map +1 -1
  41. package/dist/solid-core.module.js +8 -0
  42. package/dist/solid-core.module.js.map +1 -1
  43. package/dist/subscribers/security-rule.subscriber.d.ts.map +1 -1
  44. package/dist/subscribers/security-rule.subscriber.js +4 -0
  45. package/dist/subscribers/security-rule.subscriber.js.map +1 -1
  46. package/dist/tsconfig.tsbuildinfo +1 -1
  47. package/package.json +2 -1
  48. package/src/commands/ingest-rag-chunking-strategy-for.md +224 -0
  49. package/src/commands/ingest.command.ts +36 -0
  50. package/src/commands/refresh-module.command.ts +0 -1
  51. package/src/controllers/service.controller.ts +66 -3
  52. package/src/controllers/test.controller.ts +15 -3
  53. package/src/entities/common.entity.ts +10 -0
  54. package/src/entities/user.entity.ts +33 -1
  55. package/src/helpers/error-mapper.service.ts +214 -0
  56. package/src/jobs/database/trigger-mcp-client-subscriber-database.service.ts +4 -2
  57. package/src/seeders/seed-data/solid-core-metadata.json +21 -0
  58. package/src/services/genai/ingest-metadata.service.ts +695 -0
  59. package/src/services/genai/r2r-helper.service.ts +33 -0
  60. package/src/services/setting.service.ts +46 -22
  61. package/src/solid-core.module.ts +8 -0
  62. package/src/subscribers/security-rule.subscriber.ts +6 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidstarters/solid-core",
3
- "version": "1.2.160",
3
+ "version": "1.2.163",
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",
@@ -68,6 +68,7 @@
68
68
  "pg": "^8.11.3",
69
69
  "pluralize": "^8.0.0",
70
70
  "puppeteer": "^23.2.0",
71
+ "r2r-js": "^0.4.43",
71
72
  "reflect-metadata": "^0.1.13",
72
73
  "rxjs": "^7.8.1",
73
74
  "swagger-ui-express": "^5.0.0",
@@ -0,0 +1,224 @@
1
+ # Optimized RAG Chunking Strategy for Solid No-Code Platform Metadata
2
+
3
+ ## Executive Summary
4
+
5
+ This document outlines an intelligent chunking strategy for ingesting Solid no-code platform metadata into R2R vector database to enable effective retrieval for LLM-powered MCP tools.
6
+
7
+ ## System Architecture Context
8
+
9
+ **Platform**: Solid no-code platform with metadata-driven code generation
10
+ **RAG System**: R2R (https://r2r-docs.sciphi.ai/)
11
+ **Integration**: MCP client → MCP server → LLM tools (createModule, createModel, addField, etc.)
12
+ **Workflow**: User chat → tool call → RAG retrieval → LLM context → metadata JSON generation → database seeding → code generation
13
+
14
+ ## Chunking Strategy
15
+
16
+ ### 1. Hierarchical Semantic Chunking
17
+
18
+ **Primary Strategy**: Create chunks based on logical metadata boundaries while maintaining semantic relationships.
19
+
20
+ #### Level 1: Module-Level Chunks
21
+ ```
22
+ Chunk Type: "module_overview"
23
+ Content: Module metadata + high-level model summaries
24
+ Size: ~500-800 tokens
25
+ Purpose: Provide context for module-level operations
26
+ ```
27
+
28
+ #### Level 2: Model-Level Chunks
29
+ ```
30
+ Chunk Type: "model_definition"
31
+ Content: Complete model with all fields + relationships
32
+ Size: ~800-1200 tokens per model
33
+ Purpose: Support model creation/modification operations
34
+ ```
35
+
36
+ #### Level 3: Field-Level Chunks
37
+ ```
38
+ Chunk Type: "field_specification"
39
+ Content: Individual field + its configuration + usage patterns
40
+ Size: ~200-400 tokens per field
41
+ Purpose: Enable precise field-level modifications
42
+ ```
43
+
44
+ #### Level 4: Cross-Reference Chunks
45
+ ```
46
+ Chunk Type: "relationship_mapping"
47
+ Content: Relations between models + dependency chains
48
+ Size: ~300-600 tokens
49
+ Purpose: Maintain referential integrity during modifications
50
+ ```
51
+
52
+ ### 2. Functional Domain Chunks
53
+
54
+ #### UI/UX Configuration Chunks
55
+ ```
56
+ Chunk Type: "ui_configuration"
57
+ Content: Views + layouts + actions + menus (grouped by feature)
58
+ Size: ~600-1000 tokens
59
+ Purpose: Support UI generation and modification
60
+ ```
61
+
62
+ #### Security & Permissions Chunks
63
+ ```
64
+ Chunk Type: "security_rules"
65
+ Content: Roles + permissions + security rules (grouped)
66
+ Size: ~400-800 tokens
67
+ Purpose: Maintain security context during operations
68
+ ```
69
+
70
+ #### Integration Chunks
71
+ ```
72
+ Chunk Type: "system_integration"
73
+ Content: Email/SMS templates + media providers + scheduled jobs
74
+ Size: ~300-600 tokens per integration type
75
+ Purpose: Support system-level configurations
76
+ ```
77
+
78
+ ### 3. Chunk Metadata Enhancement
79
+
80
+ Each chunk should include structured metadata:
81
+
82
+ ```json
83
+ {
84
+ "chunk_id": "unique_identifier",
85
+ "chunk_type": "model_definition|field_specification|ui_configuration|etc",
86
+ "module_name": "fees-portal",
87
+ "model_name": "institute|feeType|etc",
88
+ "component_names": ["field1", "field2"],
89
+ "relationships": ["related_model1", "related_model2"],
90
+ "last_modified": "timestamp",
91
+ "version": "semantic_version",
92
+ "dependencies": ["required_chunks"],
93
+ "keywords": ["domain_specific_terms"]
94
+ }
95
+ ```
96
+
97
+ ### 4. Overlap Strategy for Context Preservation
98
+
99
+ - **Boundary Overlap**: 50-100 token overlap between related chunks
100
+ - **Reference Preservation**: Include parent/child context in each chunk
101
+ - **Relationship Chains**: Maintain connection information across chunk boundaries
102
+
103
+ ## R2R Integration Implementation
104
+
105
+ ### Document Ingestion API Usage
106
+
107
+ Based on R2R documentation, use these endpoints:
108
+
109
+ #### Initial Ingestion
110
+ ```bash
111
+ POST /v1/documents
112
+ Content-Type: multipart/form-data
113
+
114
+ # Ingest chunked documents with metadata
115
+ curl -X POST "http://localhost:7272/v1/documents" \
116
+ -H "Authorization: Bearer <token>" \
117
+ -F "file=@chunk_module_overview.json" \
118
+ -F "metadata={\"chunk_type\":\"module_overview\",\"module\":\"fees-portal\"}"
119
+ ```
120
+
121
+ #### Update Existing Documents
122
+ ```bash
123
+ PUT /v1/documents/{document_id}
124
+ Content-Type: multipart/form-data
125
+
126
+ # Update specific chunks when metadata changes
127
+ curl -X PUT "http://localhost:7272/v1/documents/{doc_id}" \
128
+ -H "Authorization: Bearer <token>" \
129
+ -F "file=@updated_chunk.json" \
130
+ -F "metadata={\"version\":\"1.1.0\",\"last_modified\":\"2025-01-15T10:30:00Z\"}"
131
+ ```
132
+
133
+ ### CLI Ingestion Command Structure
134
+
135
+ Create a CLI command for automated ingestion:
136
+
137
+ ```bash
138
+ # Initial ingestion
139
+ solid-cli rag:ingest --metadata-file ./metadata.json --strategy hierarchical
140
+
141
+ # Update ingestion (incremental)
142
+ solid-cli rag:update --changed-components "institute.fields,views" --strategy differential
143
+
144
+ # Full re-ingestion
145
+ solid-cli rag:reingest --metadata-file ./metadata.json --force
146
+ ```
147
+
148
+ ## Retrieval Optimization
149
+
150
+ ### Query Enhancement Strategies
151
+
152
+ 1. **Semantic Search**: Use embedding-based retrieval for concept matching
153
+ 2. **Hybrid Search**: Combine semantic + keyword search for precision
154
+ 3. **Contextual Filtering**: Apply metadata filters based on operation type
155
+
156
+ ### MCP Tool Integration
157
+
158
+ Each MCP tool should specify its retrieval requirements:
159
+
160
+ ```python
161
+ # Example for addField tool
162
+ def addField(model_name: str, field_spec: dict):
163
+ # Retrieve relevant chunks
164
+ query = f"model definition {model_name} field types relationships"
165
+
166
+ context_chunks = r2r_client.search(
167
+ query=query,
168
+ filters={
169
+ "chunk_type": ["model_definition", "field_specification"],
170
+ "model_name": model_name,
171
+ "module_name": "fees-portal"
172
+ },
173
+ limit=5
174
+ )
175
+
176
+ # Pass context to LLM for field generation
177
+ return generate_field_json(context_chunks, field_spec)
178
+ ```
179
+
180
+ ## Versioning & Change Management
181
+
182
+ ### Differential Updates
183
+ - Track changes at component level (model, field, view, etc.)
184
+ - Update only affected chunks + dependents
185
+ - Maintain version history for rollback capability
186
+
187
+ ### Consistency Checks
188
+ - Validate cross-references after updates
189
+ - Ensure relationship integrity
190
+ - Verify permission consistency
191
+
192
+ ## Performance Considerations
193
+
194
+ ### Chunk Size Optimization
195
+ - Target 200-1200 tokens per chunk for optimal retrieval
196
+ - Balance between context completeness and search precision
197
+ - Monitor retrieval latency and adjust sizes accordingly
198
+
199
+ ### Indexing Strategy
200
+ - Create composite indexes on frequently queried metadata fields
201
+ - Optimize for common query patterns (model + field combinations)
202
+ - Regular index maintenance and optimization
203
+
204
+ ## Implementation Checklist
205
+
206
+ - [ ] Implement hierarchical chunking algorithm
207
+ - [ ] Create metadata extraction and enhancement pipeline
208
+ - [ ] Set up R2R ingestion endpoints integration
209
+ - [ ] Build CLI commands for ingestion management
210
+ - [ ] Develop retrieval optimization for each MCP tool
211
+ - [ ] Implement versioning and change tracking
212
+ - [ ] Create monitoring and performance metrics
213
+ - [ ] Test with real metadata updates and tool operations
214
+
215
+ ## Success Metrics
216
+
217
+ 1. **Retrieval Accuracy**: >95% relevant context retrieval for tool operations
218
+ 2. **Update Efficiency**: <30s for incremental metadata updates
219
+ 3. **Context Quality**: LLM tools produce correct JSON with minimal hallucination
220
+ 4. **System Performance**: <200ms average retrieval time per tool operation
221
+
222
+ ---
223
+
224
+ *This strategy ensures your RAG pipeline provides precise, contextual information to your MCP tools while maintaining system performance and update efficiency.*
@@ -0,0 +1,36 @@
1
+ import { Logger } from '@nestjs/common';
2
+ import { Command, CommandRunner, Option } from 'nest-commander';
3
+ import { SolidRegistry } from 'src/helpers/solid-registry';
4
+ import { IngestMetadataService } from 'src/services/genai/ingest-metadata.service';
5
+
6
+ interface IngestCommandOptions {
7
+ module?: string;
8
+ // seeder?: string;
9
+ }
10
+
11
+ @Command({ name: 'ingest', description: 'Ingests solid metadata json for all modules deployed in the consuming project' })
12
+ export class IngestCommand extends CommandRunner {
13
+ private readonly logger = new Logger(IngestCommand.name);
14
+
15
+ constructor(
16
+ private readonly solidRegistry: SolidRegistry,
17
+ private readonly ingestMetadataService: IngestMetadataService,
18
+ ) {
19
+ super();
20
+ }
21
+
22
+ async run(passedParam: string[], options?: IngestCommandOptions): Promise<void> {
23
+ this.logger.log(`Running the solid ingest for module ${options.module} at ${new Date()}`);
24
+ await this.ingestMetadataService.ingest();
25
+ }
26
+
27
+ @Option({
28
+ flags: '-m, --module [module name]',
29
+ description: 'The seeder to run.',
30
+ required: false,
31
+ defaultValue: ''
32
+ })
33
+ parseString(val: string): string {
34
+ return val;
35
+ }
36
+ }
@@ -35,7 +35,6 @@ export class RefreshModuleCommand extends CommandRunner {
35
35
  await this.moduleMetadataService.generateCode(codeGenerationOptions);
36
36
  }
37
37
 
38
-
39
38
  @Option({
40
39
  flags: '-i, --id [module ID]',
41
40
  description: 'Module ID from the ss_module_metadata table',
@@ -1,20 +1,27 @@
1
1
  import { Body, Controller, Get, Logger, Post, UseGuards } from '@nestjs/common';
2
- import { DiscoveryService, MetadataScanner, Reflector } from '@nestjs/core';
3
2
  import { Public } from 'src/decorators/public.decorator';
4
3
  import { SolidRegistry } from '../helpers/solid-registry';
5
- import { ApiTags } from '@nestjs/swagger';
4
+ import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
6
5
  import { ThrottlerGuard, SkipThrottle } from '@nestjs/throttler';
6
+ import { ActiveUserData } from 'src/interfaces/active-user-data.interface';
7
+ import { ActiveUser } from 'src/decorators/active-user.decorator';
8
+ import { AiInteractionService } from 'src/services/ai-interaction.service';
9
+ import { MqMessageService } from 'src/services/mq-message.service';
10
+ import { ErrorMapperService } from 'src/helpers/error-mapper.service';
7
11
 
8
12
 
9
13
  @Controller('')
10
14
  @ApiTags("Common")
11
15
  @UseGuards(ThrottlerGuard)
12
- @SkipThrottle({ short: true, login: true, burst: true, sustained: true }) //Skip all
16
+ @SkipThrottle({ short: true, login: true, burst: true, sustained: true }) // Skip all
13
17
  export class ServiceController {
14
18
  private readonly logger = new Logger(ServiceController.name);
15
19
 
16
20
  constructor(
17
21
  private readonly solidRegistry: SolidRegistry,
22
+ private readonly aiInteractionService: AiInteractionService,
23
+ private readonly mqMessageService: MqMessageService,
24
+ private readonly errorMapper: ErrorMapperService
18
25
  ) { }
19
26
 
20
27
  @Public()
@@ -23,6 +30,62 @@ export class ServiceController {
23
30
  return { pong: 'v1.0.2' };
24
31
  }
25
32
 
33
+ @ApiBearerAuth("jwt")
34
+ @Get('mcp/ping')
35
+ async mcpPingPong(@ActiveUser() activeUser: ActiveUserData) {
36
+ // TODO: do a MCP client invocation, wait for response and return.
37
+ // If failure then decide shape to return.
38
+
39
+ const threadId = `pingPongTxn-${activeUser.sub}`;
40
+
41
+ const { queueMessageId, aiInteractionId } = await this.aiInteractionService.triggerMcpClientJob(
42
+ `Can you do 1 + 1`,
43
+ activeUser.sub,
44
+ true,
45
+ threadId
46
+ );
47
+
48
+ this.logger.debug(`mcp ping pong job triggered: queueMessageId=${queueMessageId}, aiInteractionId=${aiInteractionId}`);
49
+
50
+ // Wait up to 2 minutes, start at 500ms poll, back off to max 2s, throw if failed:
51
+ const result = await this.mqMessageService.waitForTerminalStatus(queueMessageId, {
52
+ timeoutMs: 2 * 60 * 1000,
53
+ intervalMs: 500,
54
+ maxIntervalMs: 2000,
55
+ throwOnFailure: false,
56
+ });
57
+
58
+ this.logger.debug(`mcp ping pong job finished with stage=${result.stage}`)
59
+
60
+ this.logger.debug(`mcp ping pong trying to find genai (child) interaction for aiInteraction for id=${aiInteractionId}`)
61
+
62
+ // @ts-ignore
63
+ const genAiInteractions = await this.aiInteractionService.find({
64
+ filters: {
65
+ parentInteraction: {
66
+ id: {
67
+ $eq: aiInteractionId
68
+ }
69
+ }
70
+ }
71
+ });
72
+
73
+ const genAiInteraction = genAiInteractions['records'][0];
74
+ this.logger.debug(genAiInteraction.message);
75
+
76
+ this.logger.debug(`identified gen-ai interaction with id=${genAiInteraction.id}`);
77
+ this.logger.debug(`proceeding with applying the gen-ai interaction`)
78
+
79
+ return {
80
+ mcpPong: 'v1.0.2',
81
+ genAiInteraction: {
82
+ status: genAiInteraction.status,
83
+ errorCode: genAiInteraction.status === 'failed' ? this.errorMapper.mapMessage(genAiInteraction.errorMessage, genAiInteraction.metadata) : '',
84
+ errorMessage: genAiInteraction.errorMessage,
85
+ }
86
+ };
87
+ }
88
+
26
89
  @Public()
27
90
  @SkipThrottle({ short: false, login: true, burst: true, sustained: true }) //Enable the short throttle only
28
91
  @Post('seed')
@@ -1,20 +1,23 @@
1
1
  import { Body, Controller, Logger, Post, UploadedFile, UploadedFiles, UseInterceptors } from "@nestjs/common";
2
2
  import { AnyFilesInterceptor, FileInterceptor } from "@nestjs/platform-express";
3
- import { ApiTags } from "@nestjs/swagger";
3
+ import { ApiBearerAuth, ApiTags } from "@nestjs/swagger";
4
4
  import { SolidRegistry } from "src/helpers/solid-registry";
5
5
  import { Auth } from "src/decorators/auth.decorator";
6
6
  import { AuthType } from "src/enums/auth-type.enum";
7
+ import { IngestMetadataService } from "src/services/genai/ingest-metadata.service";
7
8
 
8
9
  export class SeedData {
9
10
  seeder: string;
10
11
  }
11
12
 
12
- @Auth(AuthType.None)
13
13
  @Controller('test')
14
14
  @ApiTags("App Builder")
15
15
  export class TestController {
16
16
  private readonly logger = new Logger(TestController.name);
17
- constructor(private readonly solidRegistry: SolidRegistry) { }
17
+ constructor(
18
+ private readonly solidRegistry: SolidRegistry,
19
+ private readonly ingestMetadataService: IngestMetadataService,
20
+ ) { }
18
21
 
19
22
  @Auth(AuthType.None)
20
23
  @UseInterceptors(AnyFilesInterceptor())
@@ -23,6 +26,7 @@ export class TestController {
23
26
  return { message: 'file uploaded', fileNames: files.map(f => f.originalname), formData: body };
24
27
  }
25
28
 
29
+ @Auth(AuthType.None)
26
30
  @Post('upload')
27
31
  @UseInterceptors(FileInterceptor('file')) // 'file' here is the name of the field in the form
28
32
  uploadFile(@UploadedFile() file: Express.Multer.File, @Body() body: any) {
@@ -33,6 +37,14 @@ export class TestController {
33
37
  return { filename: file.originalname };
34
38
  }
35
39
 
40
+ @ApiBearerAuth("jwt")
41
+ @Post('mcp/ingest')
42
+ @UseInterceptors(FileInterceptor('file'))
43
+ async mcpIngest(@UploadedFile() file: Express.Multer.File, @Body() body: any) {
44
+ await this.ingestMetadataService.ingest();
45
+ return { ok: true };
46
+ }
47
+
36
48
  // @Public()
37
49
  // @Post('seed')
38
50
  // async seedData(@Body() seedData: any) {
@@ -1,7 +1,10 @@
1
1
  import { Column, CreateDateColumn, DeleteDateColumn, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm";
2
2
  import type { User } from "./user.entity";
3
+ import { Exclude, Expose, Type } from "class-transformer";
3
4
 
5
+ @Exclude()
4
6
  export abstract class CommonEntity {
7
+ @Expose()
5
8
  @PrimaryGeneratedColumn({ type: 'integer' })
6
9
  id: number
7
10
 
@@ -17,18 +20,25 @@ export abstract class CommonEntity {
17
20
  @Column({ name: "deletedTracker", default: "not-deleted" })
18
21
  deletedTracker: string;
19
22
 
23
+ @Expose()
20
24
  @Column({ type: "timestamp", name: 'published_at', default: null ,nullable: true})
21
25
  publishedAt: Date;
22
26
 
27
+ @Expose()
23
28
  @Column({ type: "varchar", name: 'locale_name', default: null })
24
29
  localeName: string;
25
30
 
31
+ @Expose()
26
32
  @Column({ type: "int", name: 'default_entity_locale_id', default: null })
27
33
  defaultEntityLocaleId: number;
28
34
 
35
+ @Expose()
36
+ @Type( () => require('./user.entity').User?.default ?? require('./user.entity').User )
29
37
  @ManyToOne(() => require('./user.entity').User?.default ?? require('./user.entity').User, { onDelete: 'SET NULL', nullable: true })
30
38
  createdBy: User;
31
39
 
40
+ @Expose()
41
+ @Type( () => require('./user.entity').User?.default ?? require('./user.entity').User )
32
42
  @ManyToOne(() => require('./user.entity').User?.default ?? require('./user.entity').User, { onDelete: 'SET NULL', nullable: true })
33
43
  updatedBy: User;
34
44
  }
@@ -2,72 +2,104 @@ import { CommonEntity } from "src/entities/common.entity"
2
2
  import { Entity, Column, Index, JoinTable, ManyToMany, OneToMany, TableInheritance } from "typeorm";
3
3
  import { RoleMetadata } from 'src/entities/role-metadata.entity';
4
4
  import { UserViewMetadata } from 'src/entities/user-view-metadata.entity'
5
+ import { Exclude, Expose } from "class-transformer";
5
6
 
6
7
  @Entity("ss_user")
7
8
  @TableInheritance({ column: { type: "varchar", name: "type", default: "User" } })
9
+ @Exclude()
8
10
  export class User extends CommonEntity {
9
11
  @Column({ type: "varchar", nullable: true })
10
- fullName: string;
12
+ @Expose()
13
+ fullName: string;
11
14
  @Index({ unique: true })
12
15
  @Column({ type: "varchar" })
16
+ @Expose()
13
17
  username: string;
14
18
  @Index({ unique: true })
15
19
  @Column({ type: "varchar", nullable: true })
20
+ @Expose()
16
21
  email: string;
17
22
  @Index({ unique: true })
18
23
  @Column({ type: "varchar", nullable: true })
24
+ @Expose()
19
25
  mobile: string;
20
26
  @Column({ type: "varchar", nullable: true })
27
+ // don't send to client
21
28
  password: string;
22
29
  @Column({ type: "boolean", nullable: true, default: true })
30
+ @Expose()
23
31
  forcePasswordChange: boolean = true;
24
32
  @Column({ type: "varchar", default: "local" })
33
+ // don't send to client
25
34
  lastLoginProvider: string = "local";
26
35
  @Column({ type: "varchar", nullable: true })
36
+ // don't send to client (test)
27
37
  accessCode: string;
28
38
  @Column({ type: "varchar", nullable: true })
39
+ // don't send to client
29
40
  googleAccessToken: string;
30
41
  @Column({ type: "varchar", nullable: true })
42
+ // don't send to client
31
43
  googleId: string;
32
44
  @Column({ type: "varchar", nullable: true })
45
+ // don't send to client
33
46
  googleProfilePicture: string;
34
47
  @Column({ type: "boolean", default: true })
48
+ @Expose()
35
49
  active: boolean = true;
36
50
  @Column({ type: "timestamp", nullable: true })
51
+ // don't send to client
37
52
  forgotPasswordConfirmedAt: Date;
38
53
  @Column({ type: "varchar", nullable: true })
54
+ // don't send to client
39
55
  verificationTokenOnForgotPassword: string;
40
56
  @Column({ type: "timestamp", nullable: true })
57
+ // don't send to client
41
58
  verificationTokenOnForgotPasswordExpiresAt: Date;
42
59
  @Column({ type: "timestamp", nullable: true })
60
+ // don't send to client
43
61
  emailVerifiedOnRegistrationAt: Date;
44
62
  @Column({ type: "varchar", nullable: true })
63
+ // don't send to client
45
64
  emailVerificationTokenOnRegistration: string;
46
65
  @Column({ type: "timestamp", nullable: true })
66
+ // don't send to client
47
67
  emailVerificationTokenOnRegistrationExpiresAt: Date;
48
68
  @Column({ type: "timestamp", nullable: true })
69
+ // don't send to client
49
70
  mobileVerifiedOnRegistrationAt: Date;
50
71
  @Column({ type: "varchar", nullable: true })
72
+ // don't send to client
51
73
  mobileVerificationTokenOnRegistration: string;
52
74
  @Column({ type: "timestamp", nullable: true })
75
+ // don't send to client
53
76
  mobileVerificationTokenOnRegistrationExpiresAt: Date;
54
77
  @Column({ type: "timestamp", nullable: true })
78
+ // don't send to client
55
79
  emailVerifiedOnLoginAt: Date;
56
80
  @Column({ type: "varchar", nullable: true })
81
+ // don't send to client
57
82
  emailVerificationTokenOnLogin: string;
58
83
  @Column({ type: "timestamp", nullable: true })
84
+ // don't send to client
59
85
  emailVerificationTokenOnLoginExpiresAt: Date;
60
86
  @Column({ type: "timestamp", nullable: true })
87
+ // don't send to client
61
88
  mobileVerifiedOnLoginAt: Date;
62
89
  @Column({ type: "varchar", nullable: true })
90
+ // don't send to client
63
91
  mobileVerificationTokenOnLogin: string;
64
92
  @Column({ type: "timestamp", nullable: true })
93
+ // don't send to client
65
94
  mobileVerificationTokenOnLoginExpiresAt: Date;
66
95
  @Column({ type: "varchar", nullable: true })
96
+ @Expose()
67
97
  customPayload: string;
68
98
  @ManyToMany(() => RoleMetadata, roleMetadata => roleMetadata.users, { cascade: true })
69
99
  @JoinTable()
100
+ @Expose()
70
101
  roles: RoleMetadata[];
71
102
  @OneToMany(() => UserViewMetadata, userViewMetadata => userViewMetadata.user, { cascade: true })
103
+ // don't send to client
72
104
  userViewMetadata: UserViewMetadata[];
73
105
  }