@solidstarters/solid-core 1.2.192 → 1.2.200

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 (376) hide show
  1. package/dist/commands/mcp.command.d.ts +20 -0
  2. package/dist/commands/mcp.command.d.ts.map +1 -0
  3. package/dist/commands/mcp.command.js +208 -0
  4. package/dist/commands/mcp.command.js.map +1 -0
  5. package/dist/commands/refresh-model.command.d.ts +8 -5
  6. package/dist/commands/refresh-model.command.d.ts.map +1 -1
  7. package/dist/commands/refresh-model.command.js +32 -0
  8. package/dist/commands/refresh-model.command.js.map +1 -1
  9. package/dist/commands/remove-fields.command.js +1 -1
  10. package/dist/commands/remove-fields.command.js.map +1 -1
  11. package/dist/commands/seed.command.d.ts +2 -0
  12. package/dist/commands/seed.command.d.ts.map +1 -1
  13. package/dist/commands/seed.command.js +28 -1
  14. package/dist/commands/seed.command.js.map +1 -1
  15. package/dist/controllers/authentication.controller.js +1 -1
  16. package/dist/controllers/authentication.controller.js.map +1 -1
  17. package/dist/controllers/email-template.controller.js +1 -1
  18. package/dist/controllers/email-template.controller.js.map +1 -1
  19. package/dist/controllers/field-metadata.controller.d.ts +136 -4
  20. package/dist/controllers/field-metadata.controller.d.ts.map +1 -1
  21. package/dist/controllers/field-metadata.controller.js +14 -1
  22. package/dist/controllers/field-metadata.controller.js.map +1 -1
  23. package/dist/controllers/media-storage-provider-metadata.controller.js +1 -1
  24. package/dist/controllers/media-storage-provider-metadata.controller.js.map +1 -1
  25. package/dist/controllers/model-metadata.controller.js +1 -1
  26. package/dist/controllers/model-metadata.controller.js.map +1 -1
  27. package/dist/controllers/module-metadata.controller.js +1 -1
  28. package/dist/controllers/module-metadata.controller.js.map +1 -1
  29. package/dist/controllers/otp-authentication.controller.js +1 -1
  30. package/dist/controllers/otp-authentication.controller.js.map +1 -1
  31. package/dist/controllers/service.controller.js +1 -1
  32. package/dist/controllers/service.controller.js.map +1 -1
  33. package/dist/controllers/sms-template.controller.js +1 -1
  34. package/dist/controllers/sms-template.controller.js.map +1 -1
  35. package/dist/controllers/test-queue.controller.js +1 -1
  36. package/dist/controllers/test-queue.controller.js.map +1 -1
  37. package/dist/controllers/test.controller.js +1 -1
  38. package/dist/controllers/test.controller.js.map +1 -1
  39. package/dist/dtos/create-ai-interaction.dto.d.ts +2 -0
  40. package/dist/dtos/create-ai-interaction.dto.d.ts.map +1 -1
  41. package/dist/dtos/create-ai-interaction.dto.js +14 -1
  42. package/dist/dtos/create-ai-interaction.dto.js.map +1 -1
  43. package/dist/dtos/create-field-metadata.dto.d.ts +22 -5
  44. package/dist/dtos/create-field-metadata.dto.d.ts.map +1 -1
  45. package/dist/dtos/create-field-metadata.dto.js +33 -7
  46. package/dist/dtos/create-field-metadata.dto.js.map +1 -1
  47. package/dist/dtos/create-import-transaction.dto.d.ts +0 -1
  48. package/dist/dtos/create-import-transaction.dto.d.ts.map +1 -1
  49. package/dist/dtos/create-import-transaction.dto.js +1 -7
  50. package/dist/dtos/create-import-transaction.dto.js.map +1 -1
  51. package/dist/dtos/create-model-metadata.dto.d.ts +2 -0
  52. package/dist/dtos/create-model-metadata.dto.d.ts.map +1 -1
  53. package/dist/dtos/create-model-metadata.dto.js +13 -1
  54. package/dist/dtos/create-model-metadata.dto.js.map +1 -1
  55. package/dist/dtos/create-role-metadata.dto.d.ts.map +1 -1
  56. package/dist/dtos/create-role-metadata.dto.js +5 -1
  57. package/dist/dtos/create-role-metadata.dto.js.map +1 -1
  58. package/dist/dtos/resolve-s3-url.dto.d.ts +10 -0
  59. package/dist/dtos/resolve-s3-url.dto.d.ts.map +1 -0
  60. package/dist/dtos/resolve-s3-url.dto.js +49 -0
  61. package/dist/dtos/resolve-s3-url.dto.js.map +1 -0
  62. package/dist/dtos/update-ai-interaction.dto.d.ts +2 -0
  63. package/dist/dtos/update-ai-interaction.dto.d.ts.map +1 -1
  64. package/dist/dtos/update-ai-interaction.dto.js +13 -1
  65. package/dist/dtos/update-ai-interaction.dto.js.map +1 -1
  66. package/dist/dtos/update-field-metadata.dto.d.ts.map +1 -1
  67. package/dist/dtos/update-field-metadata.dto.js.map +1 -1
  68. package/dist/dtos/update-import-transaction.dto.d.ts +0 -1
  69. package/dist/dtos/update-import-transaction.dto.d.ts.map +1 -1
  70. package/dist/dtos/update-import-transaction.dto.js +1 -7
  71. package/dist/dtos/update-import-transaction.dto.js.map +1 -1
  72. package/dist/entities/action-metadata.entity.js +4 -4
  73. package/dist/entities/action-metadata.entity.js.map +1 -1
  74. package/dist/entities/ai-interaction.entity.d.ts +2 -0
  75. package/dist/entities/ai-interaction.entity.d.ts.map +1 -1
  76. package/dist/entities/ai-interaction.entity.js +15 -6
  77. package/dist/entities/ai-interaction.entity.js.map +1 -1
  78. package/dist/entities/chatter-message-details.entity.d.ts.map +1 -1
  79. package/dist/entities/chatter-message-details.entity.js +1 -1
  80. package/dist/entities/chatter-message-details.entity.js.map +1 -1
  81. package/dist/entities/chatter-message.entity.js +1 -1
  82. package/dist/entities/chatter-message.entity.js.map +1 -1
  83. package/dist/entities/common.entity.d.ts +2 -3
  84. package/dist/entities/common.entity.d.ts.map +1 -1
  85. package/dist/entities/common.entity.js +9 -11
  86. package/dist/entities/common.entity.js.map +1 -1
  87. package/dist/entities/dashboard-question-sql-dataset-config.entity.js +2 -2
  88. package/dist/entities/dashboard-question-sql-dataset-config.entity.js.map +1 -1
  89. package/dist/entities/dashboard-question.entity.js +3 -3
  90. package/dist/entities/dashboard-question.entity.js.map +1 -1
  91. package/dist/entities/dashboard-variable.entity.js +3 -3
  92. package/dist/entities/dashboard-variable.entity.js.map +1 -1
  93. package/dist/entities/dashboard.entity.js +1 -1
  94. package/dist/entities/dashboard.entity.js.map +1 -1
  95. package/dist/entities/email-template.entity.d.ts.map +1 -1
  96. package/dist/entities/email-template.entity.js +4 -3
  97. package/dist/entities/email-template.entity.js.map +1 -1
  98. package/dist/entities/export-template.entity.js +2 -2
  99. package/dist/entities/export-template.entity.js.map +1 -1
  100. package/dist/entities/export-transaction.entity.js +2 -2
  101. package/dist/entities/export-transaction.entity.js.map +1 -1
  102. package/dist/entities/field-metadata.entity.d.ts +1 -0
  103. package/dist/entities/field-metadata.entity.d.ts.map +1 -1
  104. package/dist/entities/field-metadata.entity.js +8 -4
  105. package/dist/entities/field-metadata.entity.js.map +1 -1
  106. package/dist/entities/import-transaction-error-log.entity.js +1 -1
  107. package/dist/entities/import-transaction-error-log.entity.js.map +1 -1
  108. package/dist/entities/import-transaction.entity.d.ts +0 -1
  109. package/dist/entities/import-transaction.entity.d.ts.map +1 -1
  110. package/dist/entities/import-transaction.entity.js +2 -7
  111. package/dist/entities/import-transaction.entity.js.map +1 -1
  112. package/dist/entities/legacy-common-with-id.entity.d.ts +5 -0
  113. package/dist/entities/legacy-common-with-id.entity.d.ts.map +1 -0
  114. package/dist/entities/legacy-common-with-id.entity.js +32 -0
  115. package/dist/entities/legacy-common-with-id.entity.js.map +1 -0
  116. package/dist/entities/legacy-common.entity.d.ts +13 -0
  117. package/dist/entities/legacy-common.entity.d.ts.map +1 -0
  118. package/dist/entities/legacy-common.entity.js +67 -0
  119. package/dist/entities/legacy-common.entity.js.map +1 -0
  120. package/dist/entities/list-of-values.entity.js +2 -2
  121. package/dist/entities/list-of-values.entity.js.map +1 -1
  122. package/dist/entities/locale.entity.js +1 -1
  123. package/dist/entities/locale.entity.js.map +1 -1
  124. package/dist/entities/media.entity.d.ts.map +1 -1
  125. package/dist/entities/media.entity.js +3 -3
  126. package/dist/entities/media.entity.js.map +1 -1
  127. package/dist/entities/menu-item-metadata.entity.js +4 -4
  128. package/dist/entities/menu-item-metadata.entity.js.map +1 -1
  129. package/dist/entities/model-metadata.entity.d.ts +2 -0
  130. package/dist/entities/model-metadata.entity.d.ts.map +1 -1
  131. package/dist/entities/model-metadata.entity.js +11 -3
  132. package/dist/entities/model-metadata.entity.js.map +1 -1
  133. package/dist/entities/mq-message-queue.entity.js +1 -1
  134. package/dist/entities/mq-message-queue.entity.js.map +1 -1
  135. package/dist/entities/mq-message.entity.d.ts +3 -3
  136. package/dist/entities/mq-message.entity.d.ts.map +1 -1
  137. package/dist/entities/mq-message.entity.js +10 -10
  138. package/dist/entities/mq-message.entity.js.map +1 -1
  139. package/dist/entities/saved-filters.entity.js +4 -4
  140. package/dist/entities/saved-filters.entity.js.map +1 -1
  141. package/dist/entities/scheduled-job.entity.js +4 -4
  142. package/dist/entities/scheduled-job.entity.js.map +1 -1
  143. package/dist/entities/security-rule.entity.js +2 -2
  144. package/dist/entities/security-rule.entity.js.map +1 -1
  145. package/dist/entities/setting.entity.js +2 -2
  146. package/dist/entities/setting.entity.js.map +1 -1
  147. package/dist/entities/sms-template.entity.js +2 -2
  148. package/dist/entities/sms-template.entity.js.map +1 -1
  149. package/dist/entities/user-activity-history.entity.d.ts.map +1 -1
  150. package/dist/entities/user-activity-history.entity.js +1 -1
  151. package/dist/entities/user-activity-history.entity.js.map +1 -1
  152. package/dist/entities/user-view-metadata.entity.js +2 -2
  153. package/dist/entities/user-view-metadata.entity.js.map +1 -1
  154. package/dist/entities/user.entity.js +13 -15
  155. package/dist/entities/user.entity.js.map +1 -1
  156. package/dist/entities/view-metadata.entity.js +3 -3
  157. package/dist/entities/view-metadata.entity.js.map +1 -1
  158. package/dist/helpers/date.helper.d.ts +1 -1
  159. package/dist/helpers/date.helper.d.ts.map +1 -1
  160. package/dist/helpers/date.helper.js +24 -2
  161. package/dist/helpers/date.helper.js.map +1 -1
  162. package/dist/helpers/model-metadata-helper.service.d.ts +4 -1
  163. package/dist/helpers/model-metadata-helper.service.d.ts.map +1 -1
  164. package/dist/helpers/model-metadata-helper.service.js +48 -30
  165. package/dist/helpers/model-metadata-helper.service.js.map +1 -1
  166. package/dist/helpers/module.helper.d.ts.map +1 -1
  167. package/dist/helpers/module.helper.js +1 -3
  168. package/dist/helpers/module.helper.js.map +1 -1
  169. package/dist/helpers/schematic.service.d.ts +9 -3
  170. package/dist/helpers/schematic.service.d.ts.map +1 -1
  171. package/dist/helpers/schematic.service.js +49 -32
  172. package/dist/helpers/schematic.service.js.map +1 -1
  173. package/dist/helpers/solid-registry.d.ts +3 -2
  174. package/dist/helpers/solid-registry.d.ts.map +1 -1
  175. package/dist/helpers/solid-registry.js +10 -0
  176. package/dist/helpers/solid-registry.js.map +1 -1
  177. package/dist/helpers/typeorm-db-helper.d.ts +3 -0
  178. package/dist/helpers/typeorm-db-helper.d.ts.map +1 -0
  179. package/dist/helpers/typeorm-db-helper.js +24 -0
  180. package/dist/helpers/typeorm-db-helper.js.map +1 -0
  181. package/dist/index.d.ts +5 -1
  182. package/dist/index.d.ts.map +1 -1
  183. package/dist/index.js +5 -1
  184. package/dist/index.js.map +1 -1
  185. package/dist/interfaces.d.ts +3 -0
  186. package/dist/interfaces.d.ts.map +1 -1
  187. package/dist/interfaces.js.map +1 -1
  188. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.d.ts.map +1 -1
  189. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.js +6 -1
  190. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.js.map +1 -1
  191. package/dist/seeders/module-metadata-seeder.service.d.ts +1 -1
  192. package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
  193. package/dist/seeders/module-metadata-seeder.service.js +39 -17
  194. package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
  195. package/dist/seeders/seed-data/solid-core-metadata.json +53 -468
  196. package/dist/seeders/system-fields-seeder.service.d.ts.map +1 -1
  197. package/dist/seeders/system-fields-seeder.service.js +1 -1
  198. package/dist/seeders/system-fields-seeder.service.js.map +1 -1
  199. package/dist/services/ai-interaction.service.js +1 -1
  200. package/dist/services/ai-interaction.service.js.map +1 -1
  201. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.d.ts.map +1 -1
  202. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js +6 -4
  203. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js.map +1 -1
  204. package/dist/services/crud-helper.service.d.ts +8 -0
  205. package/dist/services/crud-helper.service.d.ts.map +1 -1
  206. package/dist/services/crud-helper.service.js +28 -5
  207. package/dist/services/crud-helper.service.js.map +1 -1
  208. package/dist/services/crud.service.d.ts +4 -1
  209. package/dist/services/crud.service.d.ts.map +1 -1
  210. package/dist/services/crud.service.js +87 -7
  211. package/dist/services/crud.service.js.map +1 -1
  212. package/dist/services/field-metadata.service.d.ts +143 -6
  213. package/dist/services/field-metadata.service.d.ts.map +1 -1
  214. package/dist/services/field-metadata.service.js +211 -56
  215. package/dist/services/field-metadata.service.js.map +1 -1
  216. package/dist/services/menu-item-metadata.service.d.ts +3 -1
  217. package/dist/services/menu-item-metadata.service.d.ts.map +1 -1
  218. package/dist/services/menu-item-metadata.service.js +31 -11
  219. package/dist/services/menu-item-metadata.service.js.map +1 -1
  220. package/dist/services/model-metadata.service.d.ts.map +1 -1
  221. package/dist/services/model-metadata.service.js +14 -3
  222. package/dist/services/model-metadata.service.js.map +1 -1
  223. package/dist/services/mq-message.service.d.ts.map +1 -1
  224. package/dist/services/mq-message.service.js +3 -4
  225. package/dist/services/mq-message.service.js.map +1 -1
  226. package/dist/services/queues/publisher-factory.service.d.ts.map +1 -1
  227. package/dist/services/queues/publisher-factory.service.js +4 -0
  228. package/dist/services/queues/publisher-factory.service.js.map +1 -1
  229. package/dist/{providers → services/selection-providers}/list-of-values-selection-providers.service.d.ts +2 -2
  230. package/dist/services/selection-providers/list-of-values-selection-providers.service.d.ts.map +1 -0
  231. package/dist/{providers → services/selection-providers}/list-of-values-selection-providers.service.js +3 -3
  232. package/dist/services/selection-providers/list-of-values-selection-providers.service.js.map +1 -0
  233. package/dist/services/selection-providers/pseudo-foreign-key-selection-provider.service.d.ts +20 -0
  234. package/dist/services/selection-providers/pseudo-foreign-key-selection-provider.service.d.ts.map +1 -0
  235. package/dist/services/selection-providers/pseudo-foreign-key-selection-provider.service.js +87 -0
  236. package/dist/services/selection-providers/pseudo-foreign-key-selection-provider.service.js.map +1 -0
  237. package/dist/services/setting.service.d.ts.map +1 -1
  238. package/dist/services/setting.service.js +2 -1
  239. package/dist/services/setting.service.js.map +1 -1
  240. package/dist/services/solid-introspect.service.d.ts +19 -3
  241. package/dist/services/solid-introspect.service.d.ts.map +1 -1
  242. package/dist/services/solid-introspect.service.js +83 -11
  243. package/dist/services/solid-introspect.service.js.map +1 -1
  244. package/dist/services/view-metadata.service.d.ts +3 -1
  245. package/dist/services/view-metadata.service.d.ts.map +1 -1
  246. package/dist/services/view-metadata.service.js +31 -5
  247. package/dist/services/view-metadata.service.js.map +1 -1
  248. package/dist/solid-core.module.d.ts.map +1 -1
  249. package/dist/solid-core.module.js +5 -1
  250. package/dist/solid-core.module.js.map +1 -1
  251. package/dist/subscribers/audit.subscriber.d.ts +3 -2
  252. package/dist/subscribers/audit.subscriber.d.ts.map +1 -1
  253. package/dist/subscribers/audit.subscriber.js +6 -12
  254. package/dist/subscribers/audit.subscriber.js.map +1 -1
  255. package/dist/subscribers/computed-entity-field.subscriber.d.ts +3 -2
  256. package/dist/subscribers/computed-entity-field.subscriber.d.ts.map +1 -1
  257. package/dist/subscribers/computed-entity-field.subscriber.js +7 -9
  258. package/dist/subscribers/computed-entity-field.subscriber.js.map +1 -1
  259. package/dist/subscribers/created-by-updated-by.subscriber.d.ts +4 -2
  260. package/dist/subscribers/created-by-updated-by.subscriber.d.ts.map +1 -1
  261. package/dist/subscribers/created-by-updated-by.subscriber.js +10 -8
  262. package/dist/subscribers/created-by-updated-by.subscriber.js.map +1 -1
  263. package/dist/subscribers/field-metadata.subscriber.d.ts.map +1 -1
  264. package/dist/subscribers/field-metadata.subscriber.js +0 -1
  265. package/dist/subscribers/field-metadata.subscriber.js.map +1 -1
  266. package/dist/subscribers/model-metadata.subscriber.d.ts.map +1 -1
  267. package/dist/subscribers/model-metadata.subscriber.js +3 -2
  268. package/dist/subscribers/model-metadata.subscriber.js.map +1 -1
  269. package/dist/subscribers/soft-delete-aware-event.subscriber.d.ts +3 -2
  270. package/dist/subscribers/soft-delete-aware-event.subscriber.d.ts.map +1 -1
  271. package/dist/subscribers/soft-delete-aware-event.subscriber.js +6 -11
  272. package/dist/subscribers/soft-delete-aware-event.subscriber.js.map +1 -1
  273. package/dist/tsconfig.tsbuildinfo +1 -1
  274. package/package.json +1 -1
  275. package/sql/mssql/proc_CleanupModelMetadata.sql +175 -0
  276. package/sql/mssql/proc_CleanupModuleMetadata.sql +78 -0
  277. package/sql/mssql/scratchpad.sql +10 -0
  278. package/sql/postgres/proc_CleanupModelMetadata.sql +148 -0
  279. package/sql/postgres/proc_CleanupModuleMetadata.sql +50 -0
  280. package/sql/postgres/scratchpad.sql +12 -0
  281. package/sql-server-changes.txt +88 -0
  282. package/src/commands/mcp.command.ts +215 -0
  283. package/src/commands/refresh-model.command.ts +37 -5
  284. package/src/commands/remove-fields.command.ts +1 -1
  285. package/src/commands/seed.command.ts +34 -15
  286. package/src/controllers/authentication.controller.ts +1 -1
  287. package/src/controllers/email-template.controller.ts +1 -1
  288. package/src/controllers/field-metadata.controller.ts +7 -1
  289. package/src/controllers/media-storage-provider-metadata.controller.ts +1 -1
  290. package/src/controllers/model-metadata.controller.ts +1 -1
  291. package/src/controllers/module-metadata.controller.ts +1 -1
  292. package/src/controllers/otp-authentication.controller.ts +1 -1
  293. package/src/controllers/service.controller.ts +1 -1
  294. package/src/controllers/sms-template.controller.ts +1 -1
  295. package/src/controllers/test-queue.controller.ts +1 -1
  296. package/src/controllers/test.controller.ts +1 -1
  297. package/src/dtos/create-ai-interaction.dto.ts +16 -9
  298. package/src/dtos/create-field-metadata.dto.ts +42 -12
  299. package/src/dtos/create-import-transaction.dto.ts +0 -4
  300. package/src/dtos/create-model-metadata.dto.ts +10 -0
  301. package/src/dtos/create-role-metadata.dto.ts +8 -2
  302. package/src/dtos/resolve-s3-url.dto.ts +33 -0
  303. package/src/dtos/update-ai-interaction.dto.ts +16 -9
  304. package/src/dtos/update-field-metadata.dto.ts +1 -2
  305. package/src/dtos/update-import-transaction.dto.ts +0 -4
  306. package/src/entities/action-metadata.entity.ts +4 -4
  307. package/src/entities/ai-interaction.entity.ts +16 -12
  308. package/src/entities/chatter-message-details.entity.ts +18 -18
  309. package/src/entities/chatter-message.entity.ts +2 -2
  310. package/src/entities/common.entity.ts +19 -10
  311. package/src/entities/dashboard-question-sql-dataset-config.entity.ts +2 -2
  312. package/src/entities/dashboard-question.entity.ts +3 -3
  313. package/src/entities/dashboard-variable.entity.ts +3 -3
  314. package/src/entities/dashboard.entity.ts +1 -1
  315. package/src/entities/email-template.entity.ts +4 -3
  316. package/src/entities/export-template.entity.ts +2 -2
  317. package/src/entities/export-transaction.entity.ts +2 -2
  318. package/src/entities/field-metadata.entity.ts +6 -3
  319. package/src/entities/import-transaction-error-log.entity.ts +2 -2
  320. package/src/entities/import-transaction.entity.ts +2 -5
  321. package/src/entities/legacy-common-with-id.entity.ts +11 -0
  322. package/src/entities/legacy-common.entity.ts +57 -0
  323. package/src/entities/list-of-values.entity.ts +2 -2
  324. package/src/entities/locale.entity.ts +1 -1
  325. package/src/entities/media.entity.ts +25 -25
  326. package/src/entities/menu-item-metadata.entity.ts +4 -4
  327. package/src/entities/model-metadata.entity.ts +9 -2
  328. package/src/entities/mq-message-queue.entity.ts +1 -1
  329. package/src/entities/mq-message.entity.ts +34 -34
  330. package/src/entities/saved-filters.entity.ts +5 -5
  331. package/src/entities/scheduled-job.entity.ts +4 -4
  332. package/src/entities/security-rule.entity.ts +2 -2
  333. package/src/entities/setting.entity.ts +2 -2
  334. package/src/entities/sms-template.entity.ts +2 -2
  335. package/src/entities/user-activity-history.entity.ts +14 -14
  336. package/src/entities/user-view-metadata.entity.ts +2 -2
  337. package/src/entities/user.entity.ts +15 -15
  338. package/src/entities/view-metadata.entity.ts +3 -3
  339. package/src/helpers/date.helper.ts +31 -10
  340. package/src/helpers/model-metadata-helper.service.ts +63 -32
  341. package/src/helpers/module.helper.ts +4 -3
  342. package/src/helpers/schematic.service.ts +72 -46
  343. package/src/helpers/solid-registry.ts +14 -2
  344. package/src/helpers/typeorm-db-helper.ts +26 -0
  345. package/src/index.ts +5 -1
  346. package/src/interfaces.ts +3 -0
  347. package/src/jobs/database/trigger-mcp-client-subscriber-database.service.ts +17 -21
  348. package/src/seeders/module-metadata-seeder.service.ts +73 -29
  349. package/src/seeders/seed-data/solid-core-metadata.json +55 -470
  350. package/src/seeders/system-fields-seeder.service.ts +34 -35
  351. package/src/services/ai-interaction.service.ts +1 -1
  352. package/src/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.ts +13 -9
  353. package/src/services/crud-helper.service.ts +32 -4
  354. package/src/services/crud.service.ts +158 -10
  355. package/src/services/field-metadata.service.ts +272 -67
  356. package/src/services/menu-item-metadata.service.ts +81 -50
  357. package/src/services/model-metadata.service.ts +18 -3
  358. package/src/services/mq-message.service.ts +16 -15
  359. package/src/services/queues/publisher-factory.service.ts +2 -1
  360. package/src/{providers → services/selection-providers}/list-of-values-selection-providers.service.ts +2 -2
  361. package/src/services/selection-providers/pseudo-foreign-key-selection-provider.service.ts +94 -0
  362. package/src/services/setting.service.ts +13 -10
  363. package/src/services/solid-introspect.service.ts +110 -10
  364. package/src/services/view-metadata.service.ts +48 -18
  365. package/src/solid-core.module.ts +5 -1
  366. package/src/subscribers/audit.subscriber.ts +12 -8
  367. package/src/subscribers/computed-entity-field.subscriber.ts +13 -7
  368. package/src/subscribers/created-by-updated-by.subscriber.ts +14 -8
  369. package/src/subscribers/field-metadata.subscriber.ts +1 -1
  370. package/src/subscribers/model-metadata.subscriber.ts +4 -2
  371. package/src/subscribers/soft-delete-aware-event.subscriber.ts +12 -6
  372. package/dist/providers/list-of-values-selection-providers.service.d.ts.map +0 -1
  373. package/dist/providers/list-of-values-selection-providers.service.js.map +0 -1
  374. package/src/commands/ingest-rag-chunking-strategy-for.md +0 -224
  375. package/src/entities/user.entity.ts.bkp +0 -144
  376. package/src/services/docker exec -it mssql //" +0 -8
@@ -9,46 +9,45 @@ import { ModelMetadataRepository } from "src/repository/model-metadata.repositor
9
9
 
10
10
  @Injectable()
11
11
  export class SystemFieldsSeederService {
12
- // This service is responsible for seeding the system fields metadata for all models.
13
- // It will check if the system fields are already present in the field-metadata table.
14
- // If not, it will add them.
15
- constructor(
16
- private readonly modelHelperService: ModelMetadataHelperService,
12
+ // This service is responsible for seeding the system fields metadata for all models.
13
+ // It will check if the system fields are already present in the field-metadata table.
14
+ // If not, it will add them.
15
+ constructor(
16
+ private readonly modelHelperService: ModelMetadataHelperService,
17
17
  // @InjectRepository(ModelMetadata)
18
18
  // private readonly modelRepository: Repository<ModelMetadata>, // Replace with actual model repository type
19
- private readonly modelRepository: ModelMetadataRepository, // Replace with actual model repository type
20
- private readonly fieldMetadataRepository: FieldMetadataRepository, // Replace with actual field repository type
21
- ) {}
22
-
23
- async seed() {
24
- // Get the model repo
25
- const models = await this.modelRepository.find({
26
- relations: ['fields'], // Assuming 'fields' is the relation to field metadata
27
- });
19
+ private readonly modelRepository: ModelMetadataRepository, // Replace with actual model repository type
20
+ private readonly fieldMetadataRepository: FieldMetadataRepository, // Replace with actual field repository type
21
+ ) { }
28
22
 
29
- for (const model of models) {
30
- // Check if the system fields are already present
31
- await this.seedMissingSystemFields(model);
32
- }
33
- }
23
+ async seed() {
24
+ // Get the model repo
25
+ const models = await this.modelRepository.find({
26
+ relations: ['fields'], // Assuming 'fields' is the relation to field metadata
27
+ });
34
28
 
35
- private async seedMissingSystemFields(model: ModelMetadata) {
36
- const existingSystemFields = model.fields.filter(field => field.isSystem);
37
- const systemFieldsMetadata = this.modelHelperService.getSystemFieldsMetadata();
29
+ for (const model of models) {
30
+ // Check if the system fields are already present
31
+ await this.seedMissingSystemFields(model);
32
+ }
33
+ }
34
+
35
+ private async seedMissingSystemFields(model: ModelMetadata) {
36
+ const existingSystemFields = model.fields.filter(field => field.isSystem);
37
+ const systemFieldsMetadata = this.modelHelperService.getSystemFieldsMetadata(model.isLegacyTable, model.isLegacyTableWithId);
38
38
 
39
- // Find out which system fields are missing
40
- const missingFields = systemFieldsMetadata.filter(
41
- sysField => !existingSystemFields.some(field => field.name === sysField.name)
42
- );
39
+ // Find out which system fields are missing
40
+ const missingFields = systemFieldsMetadata.filter(
41
+ sysField => !existingSystemFields.some(field => field.name === sysField.name)
42
+ );
43
43
 
44
- // If there are missing fields, add them
45
- if (missingFields.length > 0) {
46
- const newFields = missingFields.map(field => ({
47
- ...field,
48
- model: model, // Associate the field with the current model
49
- }));
50
- await this.fieldMetadataRepository.save(newFields);
51
- }
44
+ // If there are missing fields, add them
45
+ if (missingFields.length > 0) {
46
+ const newFields = missingFields.map(field => ({
47
+ ...field,
48
+ model: model, // Associate the field with the current model
49
+ }));
50
+ await this.fieldMetadataRepository.save(newFields);
52
51
  }
52
+ }
53
53
  }
54
-
@@ -219,7 +219,7 @@ export class AiInteractionService extends CRUDService<AiInteraction> {
219
219
  throw new Error(`Invalid metadata JSON: ${e}`);
220
220
  }
221
221
 
222
- const toolsInvoked = metadata['toolsInvoked'];
222
+ const toolsInvoked = metadata['tools_invoked'];
223
223
  if (!toolsInvoked) {
224
224
  // TODO: RESPONSE SHAPE ALERT Check if we want to control the shape of the response....
225
225
  throw new Error(ERROR_MESSAGES.UNABLE_TO_RESOLVE_SOLID_COMMAND);
@@ -14,8 +14,7 @@ export interface AlphaNumExternalIdContext {
14
14
 
15
15
  @ComputedFieldProvider()
16
16
  @Injectable()
17
- export class AlphaNumExternalIdComputationProvider<T extends CommonEntity> implements IEntityPreComputeFieldProvider<T, AlphaNumExternalIdContext>
18
- {
17
+ export class AlphaNumExternalIdComputationProvider<T extends CommonEntity> implements IEntityPreComputeFieldProvider<T, AlphaNumExternalIdContext> {
19
18
  constructor(
20
19
  @InjectEntityManager()
21
20
  private readonly entityManager: EntityManager
@@ -29,8 +28,8 @@ export class AlphaNumExternalIdComputationProvider<T extends CommonEntity> imple
29
28
  return 'Provider used to compute external ID for a CommonEntity with support for static or dynamic prefix.';
30
29
  }
31
30
 
32
- async preComputeValue( triggerEntity: T, computedFieldMetadata: ComputedFieldMetadata<AlphaNumExternalIdContext>
33
- ) {
31
+ async preComputeValue(triggerEntity: T, computedFieldMetadata: ComputedFieldMetadata<AlphaNumExternalIdContext>
32
+ ) {
34
33
  const { prefix, length, dynamicFieldPrefix } =
35
34
  computedFieldMetadata.computedFieldValueProviderCtxt;
36
35
 
@@ -46,8 +45,10 @@ export class AlphaNumExternalIdComputationProvider<T extends CommonEntity> imple
46
45
  }
47
46
  }
48
47
 
49
- const uniqueCode = await this.generateUniqueExternalId( codeLength, triggerEntity, computedFieldMetadata.fieldName );
50
- triggerEntity[computedFieldMetadata.fieldName] = resolvedPrefix ? `${resolvedPrefix}-${uniqueCode}` : uniqueCode;
48
+ const uniqueCode = await this.generateUniqueExternalId(resolvedPrefix, codeLength, triggerEntity, computedFieldMetadata.fieldName);
49
+ const finalExternalId = resolvedPrefix ? `${resolvedPrefix}-${uniqueCode}` : uniqueCode;
50
+
51
+ triggerEntity[computedFieldMetadata.fieldName] = finalExternalId;
51
52
  }
52
53
 
53
54
  private generateRandomCode(length = 5): string {
@@ -59,7 +60,7 @@ export class AlphaNumExternalIdComputationProvider<T extends CommonEntity> imple
59
60
  return result;
60
61
  }
61
62
 
62
- private async isExternalIdUnique( externalId: string, triggerEntity: T, fieldName: string ): Promise<boolean> {
63
+ private async isExternalIdUnique(externalId: string, triggerEntity: T, fieldName: string): Promise<boolean> {
63
64
  const count = await this.entityManager.count(triggerEntity.constructor as any,
64
65
  {
65
66
  where: { [fieldName]: externalId },
@@ -68,13 +69,16 @@ export class AlphaNumExternalIdComputationProvider<T extends CommonEntity> imple
68
69
  return count === 0;
69
70
  }
70
71
 
71
- private async generateUniqueExternalId(codeLength: number, triggerEntity: T, fieldName: string): Promise<string> {
72
+ private async generateUniqueExternalId(resolvedPrefix: string, codeLength: number, triggerEntity: T, fieldName: string): Promise<string> {
72
73
  const maxAttempts = 10;
73
74
 
74
75
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
76
+
75
77
  const newId = this.generateRandomCode(codeLength);
76
78
 
77
- const isUnique = await this.isExternalIdUnique(newId,triggerEntity,fieldName);
79
+ const fullId = resolvedPrefix ? `${resolvedPrefix}-${newId}` : newId;
80
+
81
+ const isUnique = await this.isExternalIdUnique(fullId, triggerEntity, fieldName);
78
82
 
79
83
  if (isUnique) {
80
84
  return newId;
@@ -11,6 +11,11 @@ export enum FilterCombinator {
11
11
  OR = '$or'
12
12
  }
13
13
 
14
+ export enum UserIdFields {
15
+ CREATED_BY = 'createdBy',
16
+ UPDATED_BY = 'updatedBy'
17
+ }
18
+
14
19
  export class CrudHelperService {
15
20
  constructor(
16
21
  ) { }
@@ -154,6 +159,17 @@ export class CrudHelperService {
154
159
  return Array.isArray(value) ? value : [value]; // if the value is an array, return it as is, otherwise return it as an array
155
160
  }
156
161
 
162
+ private normalizeAndFilterPopulateAttributes(value: string | string[]): string[] {
163
+ // Normalize and remove the userId fields from the populate filter, since they are handled separately
164
+ const normalized = this.normalize(value);
165
+ return normalized.filter(item => item !== UserIdFields.CREATED_BY && item !== UserIdFields.UPDATED_BY);
166
+ }
167
+
168
+ extractUserIdFieldsFromPopulate(value: string | string[]): UserIdFields[] {
169
+ const normalized = this.normalize(value);
170
+ return normalized.filter(item => item === UserIdFields.CREATED_BY || item === UserIdFields.UPDATED_BY);
171
+ }
172
+
157
173
  private isRelationJoined(queryBuilder: SelectQueryBuilder<any>, joinProperty: string): boolean {
158
174
  return queryBuilder.expressionMap.joinAttributes.some(join => join.entityOrProperty === joinProperty);
159
175
  }
@@ -176,13 +192,13 @@ export class CrudHelperService {
176
192
 
177
193
  // Normalize the fields, sort, groupBy and populate options i.e (since they can be either a string or an array of strings, when coming from the request)
178
194
  const normalizedFields = this.normalize(fields);
179
- const normalizedPopulate = this.normalize(populate);
195
+ const normalizedAndFilteredPopulateAttributes = this.normalizeAndFilterPopulateAttributes(populate);
180
196
  const normalizedPopulateMedia = this.normalize(populateMedia);
181
197
 
182
198
  // if normalizedPopulateMedia, has any nested media paths, then add then to populate excluding the last part
183
199
  const additionalPopulate = this.additionalRelationsRequiredForMediaPopulation(normalizedPopulateMedia);
184
200
  // Add the additional populate relations to the normalizedPopulate, if they are not already present
185
- normalizedPopulate.push(...additionalPopulate.filter((relation) => !normalizedPopulate.includes(relation)));
201
+ normalizedAndFilteredPopulateAttributes.push(...additionalPopulate.filter((relation) => !normalizedAndFilteredPopulateAttributes.includes(relation)));
186
202
 
187
203
  const normalizedSort = this.normalize(sort);
188
204
  const normalizedGroupBy = this.normalize(groupBy);
@@ -191,8 +207,8 @@ export class CrudHelperService {
191
207
  }
192
208
 
193
209
  // Depending upon the populate option, apply the join clause
194
- if (normalizedPopulate && normalizedPopulate.length) {
195
- this.buildPopulateQuery(normalizedPopulate, entityAlias, qb);
210
+ if (normalizedAndFilteredPopulateAttributes && normalizedAndFilteredPopulateAttributes.length) {
211
+ this.buildPopulateQuery(normalizedAndFilteredPopulateAttributes, entityAlias, qb);
196
212
  }
197
213
 
198
214
  if (filters) {
@@ -419,6 +435,18 @@ export class CrudHelperService {
419
435
  return matchingPermssions.length > 0
420
436
  }
421
437
 
438
+ hasPublishPermissionOnModel = (activeUser: ActiveUserData, modelName: string) => {
439
+ const permissionNames = [`${classify(modelName)}Controller.publish`];
440
+ const matchingPermssions = activeUser.permissions.filter((p) => permissionNames.includes(p));
441
+ return matchingPermssions.length > 0
442
+ }
443
+
444
+ hasUnpublishPermissionOnModel = (activeUser: ActiveUserData, modelName: string) => {
445
+ const permissionNames = [`${classify(modelName)}Controller.publish`];
446
+ const matchingPermssions = activeUser.permissions.filter((p) => permissionNames.includes(p));
447
+ return matchingPermssions.length > 0
448
+ }
449
+
422
450
  hasDeletePermissionOnModel = (activeUser: ActiveUserData, modelName: string) => {
423
451
  const permissionNames = [`${classify(modelName)}Controller.delete`, `${classify(modelName)}Controller.deleteMany`];
424
452
  const matchingPermssions = activeUser.permissions.filter((p) => permissionNames.includes(p));
@@ -2,7 +2,7 @@ import { BadRequestException, NotFoundException } from "@nestjs/common";
2
2
  import { ConfigService } from "@nestjs/config";
3
3
  import { DiscoveryService, ModuleRef } from "@nestjs/core";
4
4
  import { isArray } from "class-validator";
5
- import { CommonEntity, SolidBaseRepository } from "src";
5
+ import { CommonEntity, SolidBaseRepository, User } from "src";
6
6
  import { ERROR_MESSAGES } from "src/constants/error-messages";
7
7
  import { SUCCESS_MESSAGES } from "src/constants/success-messages";
8
8
  import { EntityManager, FindOptionsWhere, In, IsNull, Not, QueryFailedError, SelectQueryBuilder } from "typeorm";
@@ -33,7 +33,7 @@ import { SelectionStaticFieldCrudManager } from "../helpers/field-crud-managers/
33
33
  import { ShortTextFieldCrudManager } from "../helpers/field-crud-managers/ShortTextFieldCrudManager";
34
34
  import { UUIDFieldCrudManager } from "../helpers/field-crud-managers/UUIDFieldCrudManager";
35
35
  import { FieldCrudManager, MediaWithFullUrl } from "../interfaces";
36
- import { CrudHelperService } from "./crud-helper.service";
36
+ import { CrudHelperService, UserIdFields } from "./crud-helper.service";
37
37
  import { FileService } from "./file.service";
38
38
  import { HashingService } from "./hashing.service";
39
39
  import { getMediaStorageProvider } from "./mediaStorageProviders";
@@ -178,6 +178,10 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
178
178
  throw new Error(`Entity [${this.moduleName}.${this.modelName}] with id ${id} not found`);
179
179
  }
180
180
 
181
+ if (model.draftPublishWorkflow === true && entity.publishedAt) {
182
+ throw new BadRequestException(`Cannot update a published record for model ${this.modelName}. Unpublish it first.`
183
+ );
184
+ }
181
185
  updateDto.id = id;
182
186
  // This class will be extended by the generated service class i.e PersonService
183
187
  // The data required to identify the model and module name will be passed from the generate CrudService subclass
@@ -239,6 +243,10 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
239
243
  throw new Error(`Entity [${this.moduleName}.${this.modelName}] with id ${id} not found`);
240
244
  }
241
245
 
246
+ if (model.draftPublishWorkflow === true && entity.publishedAt) {
247
+ throw new BadRequestException(`Cannot update a published record for model ${this.modelName}, Unpublish it first.`);
248
+ }
249
+
242
250
  // If the model has internationalisation enabled, delete children with defaultEntityLocaleId === this entity's id
243
251
  if (model.internationalisation) {
244
252
  // Find all child entities where defaultEntityLocaleId === this entity's id
@@ -430,6 +438,8 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
430
438
  const alias = 'entity';
431
439
  // Extract the required keys from the input query
432
440
  let { limit, offset, populateMedia, populateGroup, groupFilter } = basicFilterDto;
441
+ const populateUserIdFields = this.crudHelperService.extractUserIdFieldsFromPopulate(basicFilterDto.populate);
442
+
433
443
  const { singularName, internationalisation, draftPublishWorkflow } = await this.loadModel();
434
444
  // Check wheather user has update permission for model
435
445
  if (solidRequestContext.activeUser) {
@@ -445,16 +455,19 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
445
455
 
446
456
  // Create above query on pincode table using query builder
447
457
  var qb: SelectQueryBuilder<T> = await this.repo.createSecurityRuleAwareQueryBuilder(alias)
448
- qb = this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias);
458
+ // qb = this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias);
449
459
  if (internationalisation && draftPublishWorkflow) {
450
460
  qb = this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias, internationalisation, draftPublishWorkflow, this.moduleRef);
451
461
  }
462
+ else {
463
+ qb = this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias);
464
+ }
452
465
 
453
466
  if (basicFilterDto.groupBy) {
454
467
  // Get the records and the count
455
- const { groupMeta, groupRecords } = await this.handleGroupFind(qb, groupFilter, populateGroup, alias, populateMedia);
468
+ const { groupMeta, groupRecords } = await this.handleGroupFind(qb, groupFilter, populateGroup, alias, populateUserIdFields, populateMedia);
456
469
  const totalGroups = await this.crudHelperService.countGroupedRecords(qb, basicFilterDto, alias);
457
- qb = this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias);
470
+ // qb = this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias);
458
471
 
459
472
  return {
460
473
  meta: {
@@ -466,7 +479,7 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
466
479
  }
467
480
  else {
468
481
  // Get the records and the count
469
- const { meta, records } = await this.handleNonGroupFind(qb, populateMedia, offset, limit, alias);
482
+ const { meta, records } = await this.handleNonGroupFind(qb, populateUserIdFields, populateMedia, offset, limit, alias);
470
483
  return {
471
484
  meta,
472
485
  records,
@@ -474,9 +487,14 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
474
487
  }
475
488
  }
476
489
 
477
- private async handleNonGroupFind(qb: SelectQueryBuilder<T>, populateMedia: string[], offset: number, limit: number, alias: string) {
490
+ private async handleNonGroupFind(qb: SelectQueryBuilder<T>, populateUserIdFields: UserIdFields[], populateMedia: string[], offset: number, limit: number, alias: string) {
478
491
  const [entities, count] = await qb.getManyAndCount();
479
492
 
493
+ // Populate the entity with the userId fields
494
+ if (populateUserIdFields && populateUserIdFields.length > 0) {
495
+ await this.handlePopulateUserIdFields(populateUserIdFields, entities);
496
+ }
497
+
480
498
  // Populate the entity with the media
481
499
  if (populateMedia && populateMedia.length > 0) {
482
500
  await this.handlePopulateMedia(populateMedia, entities);
@@ -485,7 +503,7 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
485
503
  return this.wrapFindResponse(offset, limit, count, entities);
486
504
  }
487
505
 
488
- private async handleGroupFind(qb: SelectQueryBuilder<T>, groupFilter: BasicFilterDto, populateGroup: boolean, alias: string, populateMedia: string[]) {
506
+ private async handleGroupFind(qb: SelectQueryBuilder<T>, groupFilter: BasicFilterDto, populateGroup: boolean, alias: string, populateUserIdFields: UserIdFields[], populateMedia: string[]) {
489
507
  const groupByResult = await qb.getRawMany();
490
508
 
491
509
  const groupMeta = [];
@@ -498,6 +516,11 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
498
516
  groupByQb = this.crudHelperService.buildGroupByRecordsQuery(groupByQb, group, alias);
499
517
  const [entities, count] = await groupByQb.getManyAndCount();
500
518
 
519
+ // Populate the entity with the userId fields
520
+ if (populateUserIdFields && populateUserIdFields.length > 0) {
521
+ await this.handlePopulateUserIdFields(populateUserIdFields, entities);
522
+ }
523
+
501
524
  // Populate the entity with the media
502
525
  if (populateMedia && populateMedia.length > 0) {
503
526
  await this.handlePopulateMedia(populateMedia, entities);
@@ -531,6 +554,25 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
531
554
  return r;
532
555
  }
533
556
 
557
+ // entities is an array of T
558
+ // T can contain createdBy and updatedBy fields
559
+ // We need to populate the createdBy and updatedBy fields with the User entity
560
+ private async handlePopulateUserIdFields(userIdFields: UserIdFields[], entities: T[]) {
561
+ const userRepository = this.entityManager.getRepository(User);
562
+ for (const entity of entities) {
563
+ for (const userFieldPath of userIdFields) {
564
+ const userId = entity[userFieldPath as keyof T] as unknown as number;
565
+ if (userId) {
566
+ const user = await userRepository.findOne({
567
+ where: { id: userId },
568
+ });
569
+ // @ts-ignore
570
+ entity[userFieldPath] = user;
571
+ }
572
+ }
573
+ }
574
+ }
575
+
534
576
  private async handlePopulateMedia(populateMedia: string[], entities: T[]) {
535
577
  const model = await this.entityManager.getRepository(ModelMetadata).findOne({
536
578
  where: {
@@ -615,7 +657,7 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
615
657
  return mediaDetails as MediaWithFullUrl[];
616
658
  }
617
659
 
618
- async findOne(id: number, query: any, solidRequestContext: any = {}) {
660
+ async findOne(id: number, query: any={}, solidRequestContext: any = {}) {
619
661
  const { populate = [], fields = [], populateMedia = [] } = query;
620
662
 
621
663
  // const normalizedFields = this.crudHelperService.normalize(fields);
@@ -731,8 +773,30 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
731
773
  id: id,
732
774
  } as unknown as FindOptionsWhere<T>,
733
775
  });
776
+
734
777
  removedEntities.push(entity);
735
778
  }
779
+
780
+
781
+ // entity-level flag
782
+ const isDraftPublishEnabled = model?.draftPublishWorkflow === true;
783
+
784
+ let publishedEntitiesExists: T[] = [];
785
+
786
+ if (isDraftPublishEnabled) {
787
+ publishedEntitiesExists = removedEntities.filter(
788
+ (x) => !!x?.publishedAt
789
+ );
790
+ }
791
+
792
+ if (publishedEntitiesExists.length > 0) {
793
+ const publishedEntitiesExistsID = publishedEntitiesExists.map(x => x.id);
794
+
795
+ throw new BadRequestException(
796
+ `Cannot delete published record(s) for model ${this.modelName} with Ids ${publishedEntitiesExistsID.join(', ')}. Unpublish them first.`
797
+ );
798
+ }
799
+
736
800
  if (model.enableSoftDelete === true) {
737
801
  await this.repo.softRemove(removedEntities);
738
802
  return this.repo.save(removedEntities);
@@ -767,7 +831,7 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
767
831
  await this.repo.update(id, {
768
832
  deletedAt: null, deletedTracker: "not-deleted"
769
833
  } as unknown as QueryDeepPartialEntity<T>
770
- );
834
+ );
771
835
 
772
836
  return { message: SUCCESS_MESSAGES.RECORD_RECOVERED, data: softDeletedRows };
773
837
  } catch (error) {
@@ -868,5 +932,89 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
868
932
  }
869
933
  return model.userKeyField?.name || '';
870
934
  }
935
+
936
+ /* Publish a record - sets publishedAt timestamp */
937
+ async publishRecord(id: number, solidRequestContext: any = {}): Promise<T> {
938
+
939
+ const model = await this.loadModel();
940
+
941
+ // Check if publish workflow is enabled for this model
942
+ if (!model.draftPublishWorkflow) {
943
+ throw new BadRequestException(
944
+ `Publish workflow is not enabled for ${this.modelName}`
945
+ );
946
+ }
947
+
948
+ // Check user permissions
949
+ if (solidRequestContext.activeUser) {
950
+ const hasPermission = this.crudHelperService.hasPublishPermissionOnModel(
951
+ solidRequestContext.activeUser,
952
+ model.singularName
953
+ );
954
+ if (!hasPermission) {
955
+ throw new BadRequestException(ERROR_MESSAGES.FORBIDDEN);
956
+ }
957
+ }
958
+
959
+ // Find the entity
960
+ const entity = await this.repo.findOne({ where: { id } as any });
961
+ if (!entity) {
962
+ throw new NotFoundException(`${this.modelName} with id ${id} not found`);
963
+ }
964
+
965
+ // Check if already published
966
+ if (entity.publishedAt) {
967
+ throw new BadRequestException(
968
+ `${this.modelName} with id ${id} is already published`
969
+ );
970
+ }
971
+
972
+ // Update publish status
973
+ const updatedEntity = await this.repo.save({ ...entity, publishedAt: new Date() });
974
+
975
+ return updatedEntity
976
+ }
977
+
978
+ /* Unpublish a record - clears publishedAt timestamp */
979
+ async unpublishRecord(id: number, solidRequestContext: any = {}): Promise<T> {
980
+
981
+ const model = await this.loadModel();
982
+
983
+ // Check if publish workflow is enabled for this model
984
+ if (!model.draftPublishWorkflow) {
985
+ throw new BadRequestException(
986
+ `Publish workflow is not enabled for ${this.modelName}`
987
+ );
988
+ }
989
+
990
+ // Check user permissions
991
+ if (solidRequestContext.activeUser) {
992
+ const hasPermission = this.crudHelperService.hasUnpublishPermissionOnModel(
993
+ solidRequestContext.activeUser,
994
+ model.singularName
995
+ );
996
+ if (!hasPermission) {
997
+ throw new BadRequestException(ERROR_MESSAGES.FORBIDDEN);
998
+ }
999
+ }
1000
+
1001
+ // Find the entity
1002
+ const entity = await this.repo.findOne({ where: { id } as any });
1003
+ if (!entity) {
1004
+ throw new NotFoundException(`${this.modelName} with id ${id} not found`);
1005
+ }
1006
+
1007
+ // Check if already unpublished
1008
+ if (!entity.publishedAt) {
1009
+ throw new BadRequestException(
1010
+ `${this.modelName} with id ${id} is already unpublished`
1011
+ );
1012
+ }
1013
+
1014
+ // Update unpublish status
1015
+ const updatedEntity = await this.repo.save({ ...entity, publishedAt: null });
1016
+
1017
+ return updatedEntity
1018
+ }
871
1019
  }
872
1020