@solidxai/core 0.1.10-beta.26 → 0.1.10-beta.27

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 (274) hide show
  1. package/.claude/settings.local.json +15 -0
  2. package/CLAUDE.md +26 -0
  3. package/ai-interaction-cleanup.sql +53 -0
  4. package/dist/controllers/service.controller.d.ts +1 -5
  5. package/dist/controllers/service.controller.d.ts.map +1 -1
  6. package/dist/controllers/service.controller.js +6 -11
  7. package/dist/controllers/service.controller.js.map +1 -1
  8. package/dist/controllers/test.controller.d.ts +1 -6
  9. package/dist/controllers/test.controller.d.ts.map +1 -1
  10. package/dist/controllers/test.controller.js +2 -20
  11. package/dist/controllers/test.controller.js.map +1 -1
  12. package/dist/dtos/create-permission-metadata.dto.d.ts.map +1 -1
  13. package/dist/dtos/create-permission-metadata.dto.js +2 -0
  14. package/dist/dtos/create-permission-metadata.dto.js.map +1 -1
  15. package/dist/dtos/create-role-metadata.dto.d.ts +2 -0
  16. package/dist/dtos/create-role-metadata.dto.d.ts.map +1 -1
  17. package/dist/dtos/create-role-metadata.dto.js +13 -1
  18. package/dist/dtos/create-role-metadata.dto.js.map +1 -1
  19. package/dist/dtos/import-instructions.dto.d.ts +2 -0
  20. package/dist/dtos/import-instructions.dto.d.ts.map +1 -1
  21. package/dist/dtos/import-instructions.dto.js +15 -1
  22. package/dist/dtos/import-instructions.dto.js.map +1 -1
  23. package/dist/dtos/update-permission-metadata.dto.d.ts.map +1 -1
  24. package/dist/dtos/update-permission-metadata.dto.js +3 -1
  25. package/dist/dtos/update-permission-metadata.dto.js.map +1 -1
  26. package/dist/dtos/update-role-metadata.dto.d.ts +2 -0
  27. package/dist/dtos/update-role-metadata.dto.d.ts.map +1 -1
  28. package/dist/dtos/update-role-metadata.dto.js +13 -1
  29. package/dist/dtos/update-role-metadata.dto.js.map +1 -1
  30. package/dist/entities/action-metadata.entity.d.ts.map +1 -1
  31. package/dist/entities/action-metadata.entity.js +1 -0
  32. package/dist/entities/action-metadata.entity.js.map +1 -1
  33. package/dist/entities/agent-event.entity.d.ts.map +1 -1
  34. package/dist/entities/agent-event.entity.js +1 -0
  35. package/dist/entities/agent-event.entity.js.map +1 -1
  36. package/dist/entities/agent-session.entity.d.ts.map +1 -1
  37. package/dist/entities/agent-session.entity.js +1 -0
  38. package/dist/entities/agent-session.entity.js.map +1 -1
  39. package/dist/entities/chatter-message.entity.d.ts.map +1 -1
  40. package/dist/entities/chatter-message.entity.js +2 -0
  41. package/dist/entities/chatter-message.entity.js.map +1 -1
  42. package/dist/entities/email-template.entity.d.ts.map +1 -1
  43. package/dist/entities/email-template.entity.js +1 -0
  44. package/dist/entities/email-template.entity.js.map +1 -1
  45. package/dist/entities/field-metadata.entity.d.ts.map +1 -1
  46. package/dist/entities/field-metadata.entity.js +4 -0
  47. package/dist/entities/field-metadata.entity.js.map +1 -1
  48. package/dist/entities/list-of-values.entity.d.ts.map +1 -1
  49. package/dist/entities/list-of-values.entity.js +4 -0
  50. package/dist/entities/list-of-values.entity.js.map +1 -1
  51. package/dist/entities/locale.entity.d.ts.map +1 -1
  52. package/dist/entities/locale.entity.js +1 -0
  53. package/dist/entities/locale.entity.js.map +1 -1
  54. package/dist/entities/media.entity.d.ts.map +1 -1
  55. package/dist/entities/media.entity.js +1 -0
  56. package/dist/entities/media.entity.js.map +1 -1
  57. package/dist/entities/menu-item-metadata.entity.d.ts.map +1 -1
  58. package/dist/entities/menu-item-metadata.entity.js +2 -0
  59. package/dist/entities/menu-item-metadata.entity.js.map +1 -1
  60. package/dist/entities/model-metadata.entity.d.ts.map +1 -1
  61. package/dist/entities/model-metadata.entity.js +3 -0
  62. package/dist/entities/model-metadata.entity.js.map +1 -1
  63. package/dist/entities/module-metadata.entity.d.ts.map +1 -1
  64. package/dist/entities/module-metadata.entity.js +2 -0
  65. package/dist/entities/module-metadata.entity.js.map +1 -1
  66. package/dist/entities/permission-metadata.entity.d.ts.map +1 -1
  67. package/dist/entities/permission-metadata.entity.js.map +1 -1
  68. package/dist/entities/role-metadata.entity.d.ts +2 -0
  69. package/dist/entities/role-metadata.entity.d.ts.map +1 -1
  70. package/dist/entities/role-metadata.entity.js +10 -2
  71. package/dist/entities/role-metadata.entity.js.map +1 -1
  72. package/dist/entities/saved-filters.entity.d.ts.map +1 -1
  73. package/dist/entities/saved-filters.entity.js +3 -0
  74. package/dist/entities/saved-filters.entity.js.map +1 -1
  75. package/dist/entities/scheduled-job.entity.d.ts.map +1 -1
  76. package/dist/entities/scheduled-job.entity.js +2 -0
  77. package/dist/entities/scheduled-job.entity.js.map +1 -1
  78. package/dist/entities/security-rule.entity.d.ts.map +1 -1
  79. package/dist/entities/security-rule.entity.js +1 -0
  80. package/dist/entities/security-rule.entity.js.map +1 -1
  81. package/dist/entities/sms-template.entity.d.ts.map +1 -1
  82. package/dist/entities/sms-template.entity.js +2 -0
  83. package/dist/entities/sms-template.entity.js.map +1 -1
  84. package/dist/entities/user-activity-history.entity.d.ts.map +1 -1
  85. package/dist/entities/user-activity-history.entity.js +1 -0
  86. package/dist/entities/user-activity-history.entity.js.map +1 -1
  87. package/dist/entities/user.entity.d.ts.map +1 -1
  88. package/dist/entities/user.entity.js +2 -0
  89. package/dist/entities/user.entity.js.map +1 -1
  90. package/dist/entities/view-metadata.entity.d.ts.map +1 -1
  91. package/dist/entities/view-metadata.entity.js +2 -0
  92. package/dist/entities/view-metadata.entity.js.map +1 -1
  93. package/dist/helpers/module.helper.js +0 -5
  94. package/dist/helpers/module.helper.js.map +1 -1
  95. package/dist/index.d.ts +0 -5
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.js +0 -5
  98. package/dist/index.js.map +1 -1
  99. package/dist/interfaces.d.ts +0 -8
  100. package/dist/interfaces.d.ts.map +1 -1
  101. package/dist/interfaces.js.map +1 -1
  102. package/dist/seeders/seed-data/solid-core-metadata.json +317 -814
  103. package/dist/services/crud-helper.service.d.ts.map +1 -1
  104. package/dist/services/crud-helper.service.js +11 -3
  105. package/dist/services/crud-helper.service.js.map +1 -1
  106. package/dist/services/import-transaction.service.d.ts.map +1 -1
  107. package/dist/services/import-transaction.service.js +6 -0
  108. package/dist/services/import-transaction.service.js.map +1 -1
  109. package/dist/solid-core.module.d.ts.map +1 -1
  110. package/dist/solid-core.module.js +0 -29
  111. package/dist/solid-core.module.js.map +1 -1
  112. package/dist/subscribers/scheduled-job.subscriber.js +1 -1
  113. package/dist/subscribers/scheduled-job.subscriber.js.map +1 -1
  114. package/dist/subscribers/security-rule.subscriber.js +1 -1
  115. package/dist/subscribers/security-rule.subscriber.js.map +1 -1
  116. package/package.json +4 -4
  117. package/src/controllers/service.controller.ts +4 -7
  118. package/src/controllers/test.controller.ts +0 -9
  119. package/src/dtos/create-permission-metadata.dto.ts +3 -0
  120. package/src/dtos/create-role-metadata.dto.ts +11 -1
  121. package/src/dtos/import-instructions.dto.ts +11 -1
  122. package/src/dtos/update-permission-metadata.dto.ts +4 -1
  123. package/src/dtos/update-role-metadata.dto.ts +21 -1
  124. package/src/entities/action-metadata.entity.ts +1 -0
  125. package/src/entities/agent-event.entity.ts +1 -0
  126. package/src/entities/agent-session.entity.ts +1 -0
  127. package/src/entities/chatter-message.entity.ts +2 -0
  128. package/src/entities/email-template.entity.ts +1 -0
  129. package/src/entities/field-metadata.entity.ts +4 -1
  130. package/src/entities/list-of-values.entity.ts +5 -1
  131. package/src/entities/locale.entity.ts +1 -0
  132. package/src/entities/media.entity.ts +1 -0
  133. package/src/entities/menu-item-metadata.entity.ts +2 -0
  134. package/src/entities/model-metadata.entity.ts +3 -0
  135. package/src/entities/module-metadata.entity.ts +2 -0
  136. package/src/entities/permission-metadata.entity.ts +2 -2
  137. package/src/entities/role-metadata.entity.ts +11 -3
  138. package/src/entities/saved-filters.entity.ts +3 -0
  139. package/src/entities/scheduled-job.entity.ts +2 -0
  140. package/src/entities/security-rule.entity.ts +1 -0
  141. package/src/entities/sms-template.entity.ts +2 -0
  142. package/src/entities/user-activity-history.entity.ts +1 -0
  143. package/src/entities/user.entity.ts +2 -0
  144. package/src/entities/view-metadata.entity.ts +2 -0
  145. package/src/helpers/module.helper.ts +5 -5
  146. package/src/index.ts +0 -5
  147. package/src/interfaces.ts +0 -8
  148. package/src/seeders/seed-data/solid-core-metadata.json +317 -814
  149. package/src/services/1.js +6 -0
  150. package/src/services/crud-helper.service.ts +9 -3
  151. package/src/services/import-transaction.service.ts +11 -1
  152. package/src/solid-core.module.ts +0 -31
  153. package/src/subscribers/scheduled-job.subscriber.ts +1 -1
  154. package/src/subscribers/security-rule.subscriber.ts +1 -1
  155. package/dist/commands/ingest.command.d.ts +0 -16
  156. package/dist/commands/ingest.command.d.ts.map +0 -1
  157. package/dist/commands/ingest.command.js +0 -50
  158. package/dist/commands/ingest.command.js.map +0 -1
  159. package/dist/controllers/ai-interaction.controller.d.ts +0 -29
  160. package/dist/controllers/ai-interaction.controller.d.ts.map +0 -1
  161. package/dist/controllers/ai-interaction.controller.js +0 -218
  162. package/dist/controllers/ai-interaction.controller.js.map +0 -1
  163. package/dist/dtos/create-ai-interaction.dto.d.ts +0 -23
  164. package/dist/dtos/create-ai-interaction.dto.d.ts.map +0 -1
  165. package/dist/dtos/create-ai-interaction.dto.js +0 -149
  166. package/dist/dtos/create-ai-interaction.dto.js.map +0 -1
  167. package/dist/dtos/invoke-ai-prompt.dto.d.ts +0 -5
  168. package/dist/dtos/invoke-ai-prompt.dto.d.ts.map +0 -1
  169. package/dist/dtos/invoke-ai-prompt.dto.js +0 -30
  170. package/dist/dtos/invoke-ai-prompt.dto.js.map +0 -1
  171. package/dist/dtos/update-ai-interaction.dto.d.ts +0 -24
  172. package/dist/dtos/update-ai-interaction.dto.d.ts.map +0 -1
  173. package/dist/dtos/update-ai-interaction.dto.js +0 -150
  174. package/dist/dtos/update-ai-interaction.dto.js.map +0 -1
  175. package/dist/entities/ai-interaction.entity.d.ts +0 -24
  176. package/dist/entities/ai-interaction.entity.d.ts.map +0 -1
  177. package/dist/entities/ai-interaction.entity.js +0 -116
  178. package/dist/entities/ai-interaction.entity.js.map +0 -1
  179. package/dist/jobs/database/trigger-mcp-client-publisher-database.service.d.ts +0 -11
  180. package/dist/jobs/database/trigger-mcp-client-publisher-database.service.d.ts.map +0 -1
  181. package/dist/jobs/database/trigger-mcp-client-publisher-database.service.js +0 -39
  182. package/dist/jobs/database/trigger-mcp-client-publisher-database.service.js.map +0 -1
  183. package/dist/jobs/database/trigger-mcp-client-queue-options.d.ts +0 -8
  184. package/dist/jobs/database/trigger-mcp-client-queue-options.d.ts.map +0 -1
  185. package/dist/jobs/database/trigger-mcp-client-queue-options.js +0 -10
  186. package/dist/jobs/database/trigger-mcp-client-queue-options.js.map +0 -1
  187. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.d.ts +0 -25
  188. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.d.ts.map +0 -1
  189. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.js +0 -222
  190. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.js.map +0 -1
  191. package/dist/jobs/rabbitmq/trigger-mcp-client-publisher.service.d.ts +0 -11
  192. package/dist/jobs/rabbitmq/trigger-mcp-client-publisher.service.d.ts.map +0 -1
  193. package/dist/jobs/rabbitmq/trigger-mcp-client-publisher.service.js +0 -39
  194. package/dist/jobs/rabbitmq/trigger-mcp-client-publisher.service.js.map +0 -1
  195. package/dist/jobs/rabbitmq/trigger-mcp-client-queue-options.d.ts +0 -8
  196. package/dist/jobs/rabbitmq/trigger-mcp-client-queue-options.d.ts.map +0 -1
  197. package/dist/jobs/rabbitmq/trigger-mcp-client-queue-options.js +0 -10
  198. package/dist/jobs/rabbitmq/trigger-mcp-client-queue-options.js.map +0 -1
  199. package/dist/jobs/rabbitmq/trigger-mcp-client-subscriber.service.d.ts +0 -18
  200. package/dist/jobs/rabbitmq/trigger-mcp-client-subscriber.service.d.ts.map +0 -1
  201. package/dist/jobs/rabbitmq/trigger-mcp-client-subscriber.service.js +0 -103
  202. package/dist/jobs/rabbitmq/trigger-mcp-client-subscriber.service.js.map +0 -1
  203. package/dist/jobs/redis/trigger-mcp-client-publisher-redis.service.d.ts +0 -11
  204. package/dist/jobs/redis/trigger-mcp-client-publisher-redis.service.d.ts.map +0 -1
  205. package/dist/jobs/redis/trigger-mcp-client-publisher-redis.service.js +0 -39
  206. package/dist/jobs/redis/trigger-mcp-client-publisher-redis.service.js.map +0 -1
  207. package/dist/jobs/redis/trigger-mcp-client-queue-options-redis.d.ts +0 -8
  208. package/dist/jobs/redis/trigger-mcp-client-queue-options-redis.d.ts.map +0 -1
  209. package/dist/jobs/redis/trigger-mcp-client-queue-options-redis.js +0 -10
  210. package/dist/jobs/redis/trigger-mcp-client-queue-options-redis.js.map +0 -1
  211. package/dist/jobs/redis/trigger-mcp-client-subscriber-redis.service.d.ts +0 -18
  212. package/dist/jobs/redis/trigger-mcp-client-subscriber-redis.service.d.ts.map +0 -1
  213. package/dist/jobs/redis/trigger-mcp-client-subscriber-redis.service.js +0 -103
  214. package/dist/jobs/redis/trigger-mcp-client-subscriber-redis.service.js.map +0 -1
  215. package/dist/repository/ai-interaction.repository.d.ts +0 -12
  216. package/dist/repository/ai-interaction.repository.d.ts.map +0 -1
  217. package/dist/repository/ai-interaction.repository.js +0 -34
  218. package/dist/repository/ai-interaction.repository.js.map +0 -1
  219. package/dist/services/ai-interaction.service.d.ts +0 -23
  220. package/dist/services/ai-interaction.service.d.ts.map +0 -1
  221. package/dist/services/ai-interaction.service.js +0 -217
  222. package/dist/services/ai-interaction.service.js.map +0 -1
  223. package/dist/services/genai/ingest-metadata.service.d.ts +0 -38
  224. package/dist/services/genai/ingest-metadata.service.d.ts.map +0 -1
  225. package/dist/services/genai/ingest-metadata.service.js +0 -542
  226. package/dist/services/genai/ingest-metadata.service.js.map +0 -1
  227. package/dist/services/genai/mcp-handlers/mcp-handler-factory.service.d.ts +0 -9
  228. package/dist/services/genai/mcp-handlers/mcp-handler-factory.service.d.ts.map +0 -1
  229. package/dist/services/genai/mcp-handlers/mcp-handler-factory.service.js +0 -39
  230. package/dist/services/genai/mcp-handlers/mcp-handler-factory.service.js.map +0 -1
  231. package/dist/services/genai/r2r-helper.service.d.ts +0 -9
  232. package/dist/services/genai/r2r-helper.service.d.ts.map +0 -1
  233. package/dist/services/genai/r2r-helper.service.js +0 -40
  234. package/dist/services/genai/r2r-helper.service.js.map +0 -1
  235. package/dist-tests/api/authenticate.spec.js +0 -119
  236. package/dist-tests/api/authenticate.spec.js.map +0 -1
  237. package/dist-tests/api/crud-service.findOne.cityMaster.spec.js +0 -97
  238. package/dist-tests/api/crud-service.findOne.cityMaster.spec.js.map +0 -1
  239. package/dist-tests/api/ping.spec.js +0 -21
  240. package/dist-tests/api/ping.spec.js.map +0 -1
  241. package/dist-tests/helpers/auth.js +0 -41
  242. package/dist-tests/helpers/auth.js.map +0 -1
  243. package/dist-tests/helpers/env.js +0 -11
  244. package/dist-tests/helpers/env.js.map +0 -1
  245. package/docs/dashboards/AGENTIC_DASHBOARD_IMPLEMENTATION_PLAN.md +0 -438
  246. package/docs/dashboards/dashboard-curl-smoke-tests.txt +0 -146
  247. package/docs/dashboards/delete-legacy-dashboard-metadata.sql +0 -172
  248. package/docs/grouping-enhancements.md +0 -89
  249. package/docs/java-spring/README.md +0 -3
  250. package/docs/java-spring/solid-core-module-deep-dive-report.md +0 -1317
  251. package/docs/module-package-import-handoff.md +0 -691
  252. package/docs/seed-changes.md +0 -65
  253. package/docs/test-data-workflow.md +0 -200
  254. package/docs/type-declaration-import-issue.md +0 -24
  255. package/src/commands/ingest.command.ts +0 -36
  256. package/src/controllers/ai-interaction.controller.ts +0 -112
  257. package/src/dtos/create-ai-interaction.dto.ts +0 -89
  258. package/src/dtos/invoke-ai-prompt.dto.ts +0 -10
  259. package/src/dtos/update-ai-interaction.dto.ts +0 -93
  260. package/src/entities/ai-interaction.entity.ts +0 -71
  261. package/src/jobs/database/trigger-mcp-client-publisher-database.service.ts +0 -22
  262. package/src/jobs/database/trigger-mcp-client-queue-options.ts +0 -9
  263. package/src/jobs/database/trigger-mcp-client-subscriber-database.service.ts +0 -278
  264. package/src/jobs/rabbitmq/trigger-mcp-client-publisher.service.ts +0 -22
  265. package/src/jobs/rabbitmq/trigger-mcp-client-queue-options.ts +0 -9
  266. package/src/jobs/rabbitmq/trigger-mcp-client-subscriber.service.ts +0 -104
  267. package/src/jobs/redis/trigger-mcp-client-publisher-redis.service.ts +0 -23
  268. package/src/jobs/redis/trigger-mcp-client-queue-options-redis.ts +0 -9
  269. package/src/jobs/redis/trigger-mcp-client-subscriber-redis.service.ts +0 -98
  270. package/src/repository/ai-interaction.repository.ts +0 -17
  271. package/src/services/ai-interaction.service.ts +0 -239
  272. package/src/services/genai/ingest-metadata.service.ts +0 -798
  273. package/src/services/genai/mcp-handlers/mcp-handler-factory.service.ts +0 -33
  274. package/src/services/genai/r2r-helper.service.ts +0 -37
@@ -1,798 +0,0 @@
1
- import { Injectable, Logger } from '@nestjs/common';
2
- import * as crypto from 'crypto';
3
- import * as fs from 'fs';
4
- import * as path from 'path';
5
-
6
- import { getDynamicModuleNames, getDynamicModuleNamesBasedOnMetadata } from 'src/helpers/module.helper';
7
- import { CreateModuleMetadataDto } from 'src/dtos/create-module-metadata.dto';
8
- import { R2RHelperService } from './r2r-helper.service';
9
- import { r2rClient } from 'r2r-js';
10
- import { CreateModelMetadataDto } from 'src/dtos/create-model-metadata.dto';
11
- import { CreateFieldMetadataDto } from 'src/dtos/create-field-metadata.dto';
12
-
13
- export type FieldIngestionInfo = {
14
- fieldName: string;
15
- fieldChunkId?: string;
16
- fieldHash?: string;
17
- };
18
-
19
- export type ModelIngestionInfo = {
20
- modelName: string;
21
- modelChunkId?: string;
22
- modelHash?: string;
23
- fields: FieldIngestionInfo[];
24
- };
25
-
26
- export type ModuleRAGIngestionInfo = {
27
- moduleName?: string;
28
- collectionId?: string;
29
-
30
- // Full json document is also uploaded so we track references...
31
- documentId?: string;
32
- documentHash?: string;
33
-
34
- // module references
35
- moduleChunkId?: string;
36
- // track a hash of module metadata to skip unchanged
37
- moduleHash?: string;
38
-
39
- // model references...
40
- models: ModelIngestionInfo[];
41
- };
42
-
43
- @Injectable()
44
- export class IngestMetadataService {
45
- private readonly logger = new Logger(IngestMetadataService.name);
46
- private ragClient: r2rClient;
47
-
48
- constructor(
49
- private readonly r2rService: R2RHelperService,
50
- ) { }
51
-
52
- // Stable stringify so hashes/ids don't flap
53
- // private stableStringify(obj: any): string {
54
- // return JSON.stringify(obj, Object.keys(obj).sort(), 2);
55
- // }
56
- // private sha256(input: string): string {
57
- // return crypto.createHash('sha256').update(input).digest('hex');
58
- // }
59
- // private hashSchema(obj: any): string {
60
- // return this.sha256(this.stableStringify(obj));
61
- // }
62
- private _sha256OfJson(obj: any): string {
63
- const s = JSON.stringify(obj);
64
- return crypto.createHash('sha256').update(s).digest('hex');
65
- }
66
- // // Small natural-language one-liners for relations
67
- // private relationSig(model: any): string[] {
68
- // const rels: string[] = [];
69
- // for (const f of model.fields ?? []) {
70
- // if (f.relation?.targetModel) {
71
- // rels.push(`${model.singularName}.${f.name} -> ${f.relation.targetModel}(${f.relation.targetField ?? 'id'})`);
72
- // }
73
- // }
74
- // return rels;
75
- // }
76
-
77
- private _oneLineBool(b?: boolean): 'yes' | 'no' {
78
- return b ? 'yes' : 'no';
79
- }
80
-
81
- private _shortList(arr?: string[] | null, max = 10): string {
82
- if (!Array.isArray(arr) || arr.length === 0) return 'none';
83
- const a = arr.slice(0, max);
84
- return `${a.join(', ')}${arr.length > max ? ', …' : ''}`;
85
- }
86
-
87
- async ingest() {
88
- // Create a new ragClient...
89
- this.ragClient = await this.r2rService.getClient();
90
-
91
- // const allModuleMetadataJson = [];
92
- this.logger.debug(`getting dynamics modules`);
93
- // const enabledModules = getDynamicModuleNames();
94
- const enabledModules = getDynamicModuleNamesBasedOnMetadata();
95
- this.logger.log(`ingesting metadata`);
96
-
97
- for (let i = 0; i < enabledModules.length; i++) {
98
- const enabledModule = enabledModules[i];
99
- const fileName = `${enabledModule}-metadata.json`;
100
- const enabledModuleSeedFile = `src/${enabledModule}/metadata/${fileName}`;
101
- const fullPath = path.join(process.cwd(), enabledModuleSeedFile);
102
- const overallMetadata: any = JSON.parse(fs.readFileSync(fullPath, 'utf-8').toString());
103
-
104
- const moduleMetadata: CreateModuleMetadataDto = overallMetadata.moduleMetadata;
105
-
106
- // Manage all the ingestion info file paths...
107
- const enabledModulIngestionInfoFile = `src/${enabledModule}/metadata/genai/${enabledModule}-ingested-info.json`;
108
- const enabledModulIngestionInfoFullPath = path.join(process.cwd(), enabledModulIngestionInfoFile);
109
- const ingestionInfo: ModuleRAGIngestionInfo = fs.existsSync(enabledModulIngestionInfoFullPath) ? JSON.parse(fs.readFileSync(enabledModulIngestionInfoFullPath, 'utf-8').toString()) : {};
110
- const enabledModulIngestionInfoDir = path.dirname(enabledModulIngestionInfoFullPath);
111
- if (!fs.existsSync(enabledModulIngestionInfoDir)) {
112
- fs.mkdirSync(enabledModulIngestionInfoDir, { recursive: true });
113
- }
114
-
115
- ingestionInfo.moduleName = enabledModule
116
-
117
- // Process module metadata first.
118
- this.logger.log(`[Start] Processing module metadata for ${moduleMetadata.name}`)
119
-
120
- // Create or use an existing collection...
121
- const collectionId = await this.resolveRagCollectionForModule(ingestionInfo, enabledModule)
122
- ingestionInfo.collectionId = collectionId;
123
-
124
- // Delete and re-insert a document representing the full json...
125
- // await this.deleteInsertRagDocumentForModuleMetadataJsonFile(ingestionInfo, fullPath, fileName)
126
-
127
- // Delete all metadata chunks.
128
- // const collectionName = `${enabledModule}-rag-collection`;
129
- // const deleteResult = await this.ragClient.documents.deleteByFilter({
130
- // filters: {
131
- // // AND semantics across fields:
132
- // "$and": [
133
- // { 'metadata.kind': { $eq: 'solidx-metadata' } },
134
- // { 'metadata.collectionName': { $eq: collectionName } },
135
- // { 'title': { $like: '%Ingested Chunks%' } },
136
- // ]
137
- // },
138
- // });
139
- // this.logger.log(`Deleted existing documents for collectionName: ${collectionName}. Got response:`, deleteResult);
140
-
141
- // Delete and re-insert a chunk representing the module.
142
- await this.deleteInsertRagChunkForModule(ingestionInfo, moduleMetadata);
143
-
144
- // Delete and re-insert chunks representing each model.
145
- for (const model of moduleMetadata.models) {
146
- await this.deleteInsertRagChunkForModel(ingestionInfo, enabledModule, model);
147
-
148
- // Disabling this for now...
149
- // for (const field of model.fields) {
150
- // await this.deleteInsertRagChunkForField(ingestionInfo, enabledModule, model.singularName, field);
151
- // }
152
- }
153
-
154
- // TODO: Delete and re-insert chunks representing roles
155
-
156
- // TODO: Delete and re-insert chunks representing menus
157
-
158
- // TODO: Delete and re-insert chunks representing actions
159
-
160
- // TODO: Delete and re-insert chunks representing list views
161
-
162
- // TODO: Delete and re-insert chunks representing kanban views
163
-
164
- // TODO: Delete and re-insert chunks representing form views
165
-
166
- // TODO: Delete and re-insert chunks representing security rules
167
-
168
- // TODO: Delete and re-insert chunks representing scheduled jobs
169
-
170
- // Save ingestion info to disk...
171
- fs.writeFileSync(enabledModulIngestionInfoFullPath, JSON.stringify({ ...ingestionInfo }, null, 2), 'utf8');
172
- }
173
- }
174
-
175
- private async resolveRagCollectionForModule(ingestionInfo: ModuleRAGIngestionInfo, moduleName: string): Promise<string> {
176
- this.logger.debug(`Resolving RAG collection for module: ${moduleName}`);
177
-
178
- const collectionName = `${moduleName}-rag-collection`;
179
-
180
- // delete and recreate
181
- // if (alwaysRecreate === true) {
182
- const existingCollection = await this.ragClient.collections.retrieveByName({
183
- name: collectionName
184
- });
185
-
186
- if (existingCollection) {
187
- try {
188
- await this.ragClient.collections.delete({ id: existingCollection.results.id });
189
- } catch (e) {
190
- this.logger.warn(`[Warn] Failed deleteByFilter for collection': ${String(e)}`);
191
- }
192
- }
193
- // }
194
-
195
- // let existingCollection: CollectionResponse = null;
196
- // if (ingestionInfo.collectionId) {
197
- // // See if collection already exists...
198
- // const r = await this.ragClient.collections.list({
199
- // ids: [
200
- // ingestionInfo.collectionId
201
- // ]
202
- // });
203
-
204
- // if (r) {
205
- // if (r.results.length === 1) {
206
- // existingCollection = r.results[0];
207
- // }
208
- // if (r.results.length > 1) {
209
- // // TODO: do something that will print a meaningful error on the console...
210
- // }
211
- // }
212
- // }
213
-
214
- // if (!existingCollection) {
215
- const r = await this.ragClient.collections.create({
216
- name: collectionName,
217
- description: `Collection created to group all documents, chunks related to module: ${moduleName}`
218
- });
219
-
220
- // TODO: for some reason if we are unable to create a collection then fail with a visible error message in the console...
221
- return r.results.id;
222
- // }
223
- // return existingCollection.id;
224
- }
225
-
226
- private async deleteInsertRagDocumentForModuleMetadataJsonFile(ingestionInfo: ModuleRAGIngestionInfo, fullPath: string, fileName: string): Promise<void> {
227
- this.logger.debug(`Ingesting file: ${fullPath}`);
228
-
229
- // 1) Compute hash of the entire JSON string (as-is)
230
- const jsonStr = fs.readFileSync(fullPath, 'utf-8');
231
- const contentHash = this._sha256OfJson(JSON.parse(jsonStr));
232
-
233
- // 2) Short-circuit if unchanged and we still have a documentId
234
- if (ingestionInfo.documentHash === contentHash && ingestionInfo.documentId) {
235
- this.logger.log(`[Skip] Unchanged: ${fileName} (hash=${contentHash.slice(0, 8)}…)`);
236
- return;
237
- // return ingestionInfo.documentId;
238
- }
239
-
240
- // 3) Delete the previous doc if present
241
- if (ingestionInfo.documentId) {
242
- try {
243
- await this.ragClient.documents.delete({ id: ingestionInfo.documentId });
244
- } catch (e) {
245
- this.logger.warn(
246
- `[Warn] Failed deleting prior document ${ingestionInfo.documentId}: ${String(e)}`
247
- );
248
- }
249
- }
250
-
251
- // 4) Create a fresh document; attach the hash into metadata for traceability
252
- const ingestResult = await this.ragClient.documents.create({
253
- file: {
254
- path: fullPath,
255
- name: fileName
256
- },
257
- collectionIds: [ingestionInfo.collectionId],
258
- metadata: {
259
- contentHash,
260
- fileName
261
- },
262
- });
263
- // console.log("file ingest result:", JSON.stringify(ingestResult, null, 2));
264
-
265
- const newId = ingestResult?.results?.documentId;
266
- if (!newId) {
267
- throw new Error(`R2R did not return a documentId for ${fileName}`);
268
- }
269
-
270
- // 5) Persist identifiers + hash on our side
271
- ingestionInfo.documentId = newId;
272
- ingestionInfo.documentHash = contentHash;
273
-
274
- this.logger.log(`[OK] Ingested ${fileName} → id=${newId}, hash=${contentHash.slice(0, 8)}…`);
275
- // return newId;
276
-
277
- }
278
-
279
- private async deleteInsertRagChunkForModule(ingestionInfo: ModuleRAGIngestionInfo, moduleMetadata: CreateModuleMetadataDto): Promise<void> {
280
- const moduleName: string = moduleMetadata?.name;
281
-
282
- // Hash the meaningful parts of the module to detect changes and skip re-ingest.
283
- const schemaHash = this._sha256OfJson({
284
- name: moduleMetadata?.name ?? null,
285
- description: moduleMetadata?.description ?? null,
286
-
287
- // Keep model names + brief shape so module-level hash changes when models change.
288
- models: (moduleMetadata?.models ?? []).map((m: any) => ({
289
- singularName: m?.singularName ?? null,
290
- description: m?.description ?? null,
291
-
292
- // Include field names to detect field-level changes at module granularity - maybe remove this later?
293
- // fields: Array.isArray(m?.fields) ? m.fields.map((f: any) => f?.name ?? null) : [],
294
- })),
295
- });
296
-
297
- // Skip unchanged module
298
- if (ingestionInfo.moduleHash === schemaHash && ingestionInfo.moduleChunkId) {
299
- this.logger.log(`[Skip] Module unchanged: ${moduleName}`);
300
- return;
301
- // return ingestionInfo.moduleChunkId;
302
- }
303
-
304
- const models: any[] = moduleMetadata?.models ?? [];
305
- const modelLines = models.map((m) => {
306
- const name = m?.singularName;
307
- const desc = m?.description ? `: ${m.description}` : '';
308
- return `- ${name}${desc}`;
309
- });
310
-
311
- const text = `SolidX Module: ${moduleName}
312
- Purpose: ${moduleMetadata?.description ?? 'N/A'}
313
-
314
- Models (${models.length}):
315
- ${modelLines.join('\n')}
316
-
317
- Usage: Use this chunk to choose the correct model/field chunks for code generation or metadata edits.`;
318
-
319
- // metadata has to be concise and queryable
320
- const metadata = {
321
- collectionName: `${moduleName}-rag-collection`,
322
- kind: 'solidx-metadata',
323
- type: 'module',
324
- moduleName,
325
- modelCount: models.length,
326
- schemaHash,
327
- models: models.map((m) => m?.singularName).filter(Boolean),
328
- };
329
-
330
- // Delete previous chunk if we have one
331
- // if (ingestionInfo.moduleChunkId) {
332
- // try {
333
- // await this.ragClient.documents.delete({ id: ingestionInfo.moduleChunkId });
334
- // } catch (e) {
335
- // this.logger.warn(`[Warn] Failed deleting old module chunk (${ingestionInfo.moduleChunkId}): ${String(e)}`);
336
- // }
337
- // }
338
-
339
- // We changed the approach to delete and re-create using metadata.
340
- // delete any existing module records by metadata (idempotent)
341
- try {
342
- const deleteResult = await this.ragClient.documents.deleteByFilter({
343
- filters: {
344
- // AND semantics across fields:
345
- "$and": [
346
- { 'metadata.kind': { $eq: 'solidx-metadata' } },
347
- { 'metadata.type': { $eq: 'module' } },
348
- { 'metadata.moduleName': { $eq: moduleName } },
349
- // (optional but nice to constrain tightly if you always set it)
350
- { 'metadata.collectionName': { $eq: `${moduleName}-rag-collection` } },
351
- ]
352
- },
353
- });
354
-
355
- this.logger.log(`Deleted existing module document for moduleName: ${moduleName}. Got response:`, deleteResult);
356
-
357
- } catch (e) {
358
- this.logger.warn(`[Warn] Failed deleteByFilter for module '${moduleName}': ${String(e)}`);
359
- // Non-fatal: we can still proceed to create; caller’s auth will limit scope anyway
360
- }
361
-
362
- const r = await this.ragClient.documents.create({
363
- chunks: [text],
364
- // raw_text: text,
365
- metadata: metadata,
366
- collectionIds: [ingestionInfo.collectionId],
367
- });
368
-
369
- const newId = r?.results?.documentId;
370
- if (!newId) {
371
- throw new Error(`R2R did not return a documentId while creating module chunk for module name ${moduleName}`);
372
- }
373
-
374
- // Update ingestion info for persistence by the caller
375
- ingestionInfo.moduleChunkId = r.results?.documentId;
376
- ingestionInfo.moduleHash = schemaHash;
377
-
378
- this.logger.log(`[OK] Ingested module ${moduleName} → id=${newId}, hash=${schemaHash.slice(0, 8)}…`);
379
-
380
- }
381
-
382
- private async deleteInsertRagChunkForModel(ingestionInfo: ModuleRAGIngestionInfo, moduleName: string, model: CreateModelMetadataDto): Promise<void> {
383
- const modelName: string = model?.singularName;
384
-
385
- // 1) Hash full JSON (as-is) to detect changes and skip re-ingest
386
- const schemaHash = this._sha256OfJson(model);
387
-
388
- // Ensure ingestionInfo.models[] has an entry for this model
389
- const modelsArr = ingestionInfo.models ?? (ingestionInfo.models = []);
390
- let modelEntry = modelsArr.find(m => m.modelName === modelName);
391
- if (!modelEntry) {
392
- modelEntry = { modelName, fields: [] };
393
- modelsArr.push(modelEntry);
394
- }
395
-
396
- // 2) Short-circuit if unchanged
397
- if (modelEntry.modelHash === schemaHash && modelEntry.modelChunkId) {
398
- this.logger.log(`[Skip] Model unchanged: ${moduleName}.${modelName}`);
399
- return;
400
- // return modelEntry.modelChunkId;
401
- }
402
-
403
- // 3) Build retrieval-friendly text (concise)
404
- const fields: CreateFieldMetadataDto[] = Array.isArray(model?.fields) ? model.fields : [];
405
- const userkey = fields.find((f: CreateFieldMetadataDto) => f?.isUserKey)?.name ?? 'id';
406
- const uniques = fields.filter((f: CreateFieldMetadataDto) => f?.unique).map((f: any) => f.name);
407
- const required = fields.filter((f: CreateFieldMetadataDto) => f?.required).map((f: any) => f.name);
408
- const rels = fields
409
- .filter((f: CreateFieldMetadataDto) => f.type === 'relation')
410
- .map((f: CreateFieldMetadataDto) => `${modelName}.${f.name} -> ${f.relationCoModelSingularName}.${f.relationCoModelColumnName ?? 'id'}`);
411
-
412
- const fieldSummaryLines = fields.slice(0, 30).map((f: CreateFieldMetadataDto) => {
413
- const bits = [
414
- `${f.name}:${f.type}`,
415
- f.required ? 'req' : '',
416
- f.unique ? 'unique' : '',
417
- f.isUserKey ? 'userkey' : '',
418
- f.relationCoModelSingularName ? `rel->${f.relationCoModelSingularName}` : '',
419
- ].filter(Boolean).join('|');
420
- return `- ${bits}`;
421
- });
422
-
423
- const text =
424
- `SolidX Model: ${modelName}
425
- Module: ${moduleName}
426
- Purpose: ${model?.description ?? 'N/A'}
427
-
428
- Signature:
429
- - Primary: ${userkey}
430
- - Unique: ${uniques.length ? uniques.join(', ') : 'none'}
431
- - Required (${required.length}): ${required.slice(0, 12).join(', ')}${required.length > 12 ? '…' : ''}
432
-
433
- Relations (${rels.length}):
434
- ${rels.length ? `- ${rels.join('\n- ')}` : 'None'}
435
-
436
- Fields (${fields.length}) [name:type|flags]:
437
- ${fieldSummaryLines.join('\n')}
438
-
439
- Usage: Use this chunk to generate DTOs, subscribers, custom service methods, and CRUD handlers for ${modelName}.
440
-
441
- Full model metadata json:
442
- ${JSON.stringify(model)}
443
-
444
- `;
445
-
446
- // 4) Metadata (concise & queryable)
447
- const metadata = {
448
- collectionName: `${moduleName}-rag-collection`,
449
- kind: 'solidx-metadata',
450
- type: 'model',
451
- moduleName,
452
- modelName,
453
- fieldCount: fields.length,
454
- requiredCount: required.length,
455
- relationCount: rels.length,
456
- userkey: userkey,
457
- uniqueFields: uniques,
458
- hasTimestamps: !!fields.find((f: CreateFieldMetadataDto) => ['time', 'date', 'datetime'].includes(f.type)),
459
- schemaHash,
460
- };
461
-
462
- // 5) Delete previous chunk if present
463
- // if (modelEntry.modelChunkId) {
464
- // try {
465
- // await this.ragClient.documents.delete({ id: modelEntry.modelChunkId });
466
- // } catch (e) {
467
- // this.logger.warn(`[Warn] Failed deleting old model chunk (${modelEntry.modelChunkId}): ${String(e)}`);
468
- // }
469
- // }
470
-
471
- // We changed the approach to delete and re-create using metadata.
472
- // delete any existing module records by metadata (idempotent)
473
- try {
474
- const deleteResult = await this.ragClient.documents.deleteByFilter({
475
- filters: {
476
- // AND semantics across fields:
477
- "$and": [
478
- { 'metadata.kind': { $eq: 'solidx-metadata' } },
479
- { 'metadata.type': { $eq: 'model' } },
480
- { 'metadata.moduleName': { $eq: moduleName } },
481
- { 'metadata.modelName': { $eq: modelName } },
482
- // (optional but nice to constrain tightly if you always set it)
483
- { 'metadata.collectionName': { $eq: `${moduleName}-rag-collection` } },
484
- ]
485
- },
486
- });
487
-
488
- this.logger.log(`Deleted existing model document for modelName: ${modelName}. Got response:`, deleteResult);
489
-
490
- } catch (e) {
491
- this.logger.warn(`[Warn] Failed deleteByFilter for module '${moduleName}': ${String(e)}`);
492
- // Non-fatal: we can still proceed to create; caller’s auth will limit scope anyway
493
- }
494
-
495
- // 6) Create new document (R2R auto-generates the ID)
496
- const r = await this.ragClient.documents.create({
497
- chunks: [text],
498
- metadata,
499
- collectionIds: [ingestionInfo.collectionId],
500
- });
501
-
502
- const newId = r?.results?.documentId;
503
- if (!newId) {
504
- throw new Error(`R2R did not return a documentId while creating model chunk for ${moduleName}.${modelName}`);
505
- }
506
-
507
- // 7) Update ingestionInfo for persistence
508
- modelEntry.modelChunkId = newId;
509
- modelEntry.modelHash = schemaHash;
510
-
511
- this.logger.log(`[OK] Ingested model ${moduleName}.${modelName} → id=${newId}, hash=${schemaHash.slice(0, 8)}…`);
512
- // return newId;
513
- }
514
-
515
- private _buildFieldTextAndMetadata(moduleName: string, modelName: string, f: CreateFieldMetadataDto) {
516
- // Identity
517
- const name = f?.name;
518
- const displayName = f?.displayName ?? name;
519
- const description = f?.description ?? 'N/A';
520
-
521
- // Types
522
- const type = f?.type;
523
- const ormType = f?.ormType ?? null;
524
-
525
- // Constraints / validation
526
- const required = !!f?.required;
527
- const unique = !!f?.unique;
528
- const index = !!f?.index;
529
- const length = f?.length ?? null;
530
- const min = f?.min ?? null;
531
- const max = f?.max ?? null;
532
- const defaultValue = f?.defaultValue ?? null;
533
- const regex = f?.regexPattern ?? null;
534
- const regexErr = f?.regexPatternNotMatchingErrorMsg ?? null;
535
-
536
- // Relation
537
- const relationType = f?.relationType ?? null; // e.g., many-to-one, many-to-many, one-to-many
538
- const relModule = f?.relationModelModuleName ?? null;
539
- const relModel = f?.relationCoModelSingularName ?? null;
540
- const relField = f?.relationCoModelFieldName ?? 'id';
541
- // const relOwner = f?.isRelationManyToManyOwner ?? null;
542
- // const relJoinTable = f?.relationJoinTableName ?? null;
543
- // const relCreateInverse = !!f?.relationCreateInverse;
544
- const relCascade = f?.relationCascade ?? null;
545
- const relFixedFilter = f?.relationFieldFixedFilter ?? null;
546
-
547
- // Selection (dropdowns)
548
- const selectionDynProvider = f?.selectionDynamicProvider ?? null;
549
- const selectionDynCtxt = f?.selectionDynamicProviderCtxt ?? null;
550
- const selectionStatic = Array.isArray(f?.selectionStaticValues) ? f.selectionStaticValues : null;
551
- const selectionValueType = f?.selectionValueType ?? null;
552
- const isMultiSelect = !!f?.isMultiSelect;
553
-
554
- // Media (uploads)
555
- const mediaTypes = Array.isArray(f?.mediaTypes) ? f.mediaTypes : null;
556
- const mediaMaxSizeKb = f?.mediaMaxSizeKb ?? null;
557
- const mediaStorageProvider = f?.mediaStorageProviderUserKey ?? null; // likely object/id in your JSON
558
-
559
- // Computed fields
560
- const computedProvider = f?.computedFieldValueProvider ?? null;
561
- const computedProviderCtxt = f?.computedFieldValueProviderCtxt ?? null;
562
- const computedValueType = f?.computedFieldValueType ?? null;
563
- const computedTriggerCfg = f?.computedFieldTriggerConfig ?? null;
564
-
565
- // Security / privacy / audit
566
- // const encrypt = !!f?.encrypt;
567
- // const encryptionType = f?.encryptionType ?? null;
568
- // const decryptWhen = f?.decryptWhen ?? null;
569
- const isPrivate = !!f?.private;
570
- const enableAuditTracking = !!f?.enableAuditTracking;
571
-
572
- // Keys / system flags / mapping
573
- const isUserKey = !!f?.isUserKey;
574
- const isSystem = !!f?.isSystem;
575
- const isMarkedForRemoval = !!f?.isMarkedForRemoval;
576
- const columnName = f?.columnName ?? null;
577
- const relCoModelColumn = f?.relationCoModelColumnName ?? null;
578
- const uuid = f?.uuid ?? null;
579
-
580
- const relationSummary = (() => {
581
- if (!relationType || !relModel) return 'none';
582
- const parts = [
583
- `type=${relationType}`,
584
- relModule ? `module=${relModule}` : null,
585
- `model=${relModel}`,
586
- relField ? `field=${relField}` : null,
587
- // relOwner !== null ? `m2mOwner=${relOwner}` : null,
588
- // relCreateInverse ? 'createInverse=yes' : null,
589
- relCascade ? `cascade=${relCascade}` : null,
590
- // relJoinTable ? `joinTable=${relJoinTable}` : null,
591
- relFixedFilter ? `fixedFilter=${relFixedFilter}` : null,
592
- ].filter(Boolean);
593
- return parts.join(', ');
594
- })();
595
-
596
- const selectionSummary = (() => {
597
- const parts: string[] = [];
598
- if (selectionDynProvider) parts.push(`dynamicProvider=${selectionDynProvider}`);
599
- if (selectionDynCtxt) parts.push(`dynamicCtxt=${selectionDynCtxt}`);
600
- if (selectionStatic?.length) parts.push(`static=[${this._shortList(selectionStatic, 12)}]`);
601
- if (selectionValueType) parts.push(`valueType=${selectionValueType}`);
602
- parts.push(`multiSelect=${this._oneLineBool(isMultiSelect)}`);
603
- return parts.length ? parts.join(', ') : 'none';
604
- })();
605
-
606
- const mediaSummary = (() => {
607
- const parts: string[] = [];
608
- if (mediaTypes?.length) parts.push(`types=[${this._shortList(mediaTypes, 12)}]`);
609
- if (mediaMaxSizeKb) parts.push(`maxSizeKb=${mediaMaxSizeKb}`);
610
- if (mediaStorageProvider) parts.push(`storageProvider=${typeof mediaStorageProvider === 'string' ? mediaStorageProvider : 'set'}`);
611
- return parts.length ? parts.join(', ') : 'none';
612
- })();
613
-
614
- const computedSummary = (() => {
615
- const parts: string[] = [];
616
- if (computedProvider) parts.push(`provider=${computedProvider}`);
617
- if (computedProviderCtxt) parts.push(`providerCtxt=${computedProviderCtxt}`);
618
- if (computedValueType) parts.push(`valueType=${computedValueType}`);
619
- if (computedTriggerCfg?.length) parts.push(`triggers=${computedTriggerCfg.length}`);
620
- return parts.length ? parts.join(', ') : 'none';
621
- })();
622
-
623
- const securitySummary = [
624
- // `encrypt=${this.oneLineBool(encrypt)}`,
625
- // encryptionType ? `encType=${encryptionType}` : null,
626
- // decryptWhen ? `decryptWhen=${decryptWhen}` : null,
627
- `private=${this._oneLineBool(isPrivate)}`,
628
- `auditTracking=${this._oneLineBool(enableAuditTracking)}`
629
- ].filter(Boolean).join(', ');
630
-
631
- const constraintSummary = [
632
- `required=${this._oneLineBool(required)}`,
633
- `unique=${this._oneLineBool(unique)}`,
634
- `index=${this._oneLineBool(index)}`,
635
- length !== null ? `length=${length}` : null,
636
- min !== null ? `min=${min}` : null,
637
- max !== null ? `max=${max}` : null,
638
- defaultValue !== null ? `default=${defaultValue}` : null,
639
- regex ? `regex=${regex}${regexErr ? ` (${regexErr})` : ''}` : null
640
- ].filter(Boolean).join(', ');
641
-
642
- const mappingSummary = [
643
- columnName ? `column=${columnName}` : null,
644
- relCoModelColumn ? `relColumn=${relCoModelColumn}` : null,
645
- uuid ? `uuid=${uuid}` : null,
646
- `userKey=${this._oneLineBool(isUserKey)}`,
647
- `system=${this._oneLineBool(isSystem)}`,
648
- `markedForRemoval=${this._oneLineBool(isMarkedForRemoval)}`
649
- ].filter(Boolean).join(', ');
650
-
651
- const text = [
652
- `SolidX Field: ${name} (${displayName})`,
653
- `Model: ${modelName}`,
654
- `Module: ${moduleName}`,
655
- ``,
656
- `Type: ${type}${ormType ? ` (orm=${ormType})` : ''}`,
657
- `Description: ${description}`,
658
- ``,
659
- `Constraints: ${constraintSummary || 'none'}`,
660
- `Relation: ${relationSummary}`,
661
- `Selection: ${selectionSummary}`,
662
- `Media: ${mediaSummary}`,
663
- `Computed: ${computedSummary}`,
664
- `Security/Privacy/Audit: ${securitySummary}`,
665
- `Mapping/Flags: ${mappingSummary || 'none'}`,
666
- ``,
667
- `Usage: Use this chunk to generate exact field contracts (DTO, form control, DB column), `,
668
- `validation rules, relation wiring, and UI widgets (selection/media/computed).`,
669
- ].join('\n');
670
-
671
- const metadata = {
672
- kind: 'solidx-metadata',
673
- type: 'field',
674
- moduleName,
675
- modelName,
676
- fieldName: name,
677
- displayName,
678
- description,
679
- dataType: type,
680
- ormType,
681
- required,
682
- unique,
683
- index,
684
- defaultValue,
685
- length,
686
- min,
687
- max,
688
- regexPattern: regex,
689
- regexPatternNotMatchingErrorMsg: regexErr,
690
-
691
- // relation
692
- relationType,
693
- relationModelModuleName: relModule,
694
- relationCoModelSingularName: relModel,
695
- relationCoModelFieldName: relField,
696
- // isRelationManyToManyOwner: relOwner,
697
- // relationJoinTableName: relJoinTable,
698
- // relationCreateInverse: relCreateInverse,
699
- relationCascade: relCascade,
700
- relationFieldFixedFilter: relFixedFilter,
701
-
702
- // selection
703
- selectionDynProvider,
704
- selectionDynCtxt,
705
- selectionStaticValues: selectionStatic,
706
- selectionValueType,
707
- isMultiSelect,
708
-
709
- // media
710
- mediaTypes,
711
- mediaMaxSizeKb,
712
- mediaStorageProvider: mediaStorageProvider ? (typeof mediaStorageProvider === 'string' ? mediaStorageProvider : 'set') : null,
713
-
714
- // computed
715
- computedFieldValueProvider: computedProvider,
716
- computedFieldValueProviderCtxt: computedProviderCtxt,
717
- computedFieldValueType: computedValueType,
718
- computedFieldTriggerConfigCount: Array.isArray(computedTriggerCfg) ? computedTriggerCfg.length : 0,
719
-
720
- // security/privacy/audit
721
- // encrypt,
722
- // encryptionType,
723
- // decryptWhen,
724
- private: isPrivate,
725
- enableAuditTracking,
726
-
727
- // mapping/flags
728
- columnName,
729
- relationCoModelColumnName: relCoModelColumn,
730
- isUserKey,
731
- isSystem,
732
- isMarkedForRemoval,
733
- };
734
-
735
- return { text, metadata };
736
- }
737
-
738
- private async deleteInsertRagChunkForField(ingestionInfo: ModuleRAGIngestionInfo, moduleName: string, modelName: string, field: CreateFieldMetadataDto,): Promise<string> {
739
- const fieldName: string = field?.name ?? 'unknown_field';
740
-
741
- // 1) Full JSON hash (as-is)
742
- const schemaHash = this._sha256OfJson(field);
743
-
744
- // 2) Ensure ingestionInfo entry for the model & field
745
- const modelsArr = ingestionInfo.models ?? (ingestionInfo.models = []);
746
- let modelEntry = modelsArr.find(m => m.modelName === modelName);
747
- if (!modelEntry) {
748
- modelEntry = { modelName, fields: [] };
749
- modelsArr.push(modelEntry);
750
- }
751
- const fieldsArr = modelEntry.fields ?? (modelEntry.fields = []);
752
- let fieldEntry = fieldsArr.find(f => f.fieldName === fieldName);
753
- if (!fieldEntry) {
754
- fieldEntry = { fieldName };
755
- fieldsArr.push(fieldEntry);
756
- }
757
-
758
- // 3) Skip if unchanged
759
- if (fieldEntry.fieldHash === schemaHash && fieldEntry.fieldChunkId) {
760
- this.logger.log(`[Skip] Field unchanged: ${moduleName}.${modelName}.${fieldName}`);
761
- return fieldEntry.fieldChunkId;
762
- }
763
-
764
- // 4) Build text + metadata tailored to FieldMetadata
765
- const { text, metadata } = this._buildFieldTextAndMetadata(moduleName, modelName, field);
766
-
767
- // also keep the hash in metadata for audit/debug
768
- (metadata as any).schemaHash = schemaHash;
769
-
770
- // 5) Delete previous chunk if present
771
- if (fieldEntry.fieldChunkId) {
772
- try {
773
- await this.ragClient.documents.delete({ id: fieldEntry.fieldChunkId });
774
- } catch (e) {
775
- this.logger.warn(`[Warn] Failed deleting old field chunk (${fieldEntry.fieldChunkId}): ${String(e)}`);
776
- }
777
- }
778
-
779
- // 6) Create new document (R2R auto-generates the ID)
780
- const r = await this.ragClient.documents.create({
781
- raw_text: text,
782
- metadata,
783
- collectionIds: [ingestionInfo.collectionId],
784
- });
785
-
786
- const newId = r?.results?.documentId;
787
- if (!newId) {
788
- throw new Error(`R2R did not return a documentId while creating field chunk for ${moduleName}.${modelName}.${fieldName}`);
789
- }
790
-
791
- // 7) Update ingestion info
792
- fieldEntry.fieldChunkId = newId;
793
- fieldEntry.fieldHash = schemaHash;
794
-
795
- this.logger.log(`[OK] Ingested field ${moduleName}.${modelName}.${fieldName} → id=${newId}, hash=${schemaHash.slice(0, 8)}…`);
796
- return newId;
797
- }
798
- }