@solidxai/core 0.1.13-beta.2 → 0.1.13-beta.21

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 (517) hide show
  1. package/CHANGELOG.md +10107 -0
  2. package/CLAUDE.md +5 -6
  3. package/README.md +19 -0
  4. package/dist/commands/run-tests.command.d.ts +9 -1
  5. package/dist/commands/run-tests.command.d.ts.map +1 -1
  6. package/dist/commands/run-tests.command.js +69 -6
  7. package/dist/commands/run-tests.command.js.map +1 -1
  8. package/dist/commands/seed.command.d.ts +2 -0
  9. package/dist/commands/seed.command.d.ts.map +1 -1
  10. package/dist/commands/seed.command.js +21 -0
  11. package/dist/commands/seed.command.js.map +1 -1
  12. package/dist/config/cache.options.d.ts.map +1 -1
  13. package/dist/config/cache.options.js +2 -2
  14. package/dist/config/cache.options.js.map +1 -1
  15. package/dist/constants/chatter-message.constants.d.ts +1 -0
  16. package/dist/constants/chatter-message.constants.d.ts.map +1 -1
  17. package/dist/constants/chatter-message.constants.js +3 -1
  18. package/dist/constants/chatter-message.constants.js.map +1 -1
  19. package/dist/constants/draft-publish-fields.d.ts +2 -0
  20. package/dist/constants/draft-publish-fields.d.ts.map +1 -0
  21. package/dist/constants/draft-publish-fields.js +5 -0
  22. package/dist/constants/draft-publish-fields.js.map +1 -0
  23. package/dist/constants/error-messages.d.ts +7 -0
  24. package/dist/constants/error-messages.d.ts.map +1 -1
  25. package/dist/constants/error-messages.js +7 -0
  26. package/dist/constants/error-messages.js.map +1 -1
  27. package/dist/constants/media-file-types.d.ts +12 -0
  28. package/dist/constants/media-file-types.d.ts.map +1 -1
  29. package/dist/constants/media-file-types.js +66 -1
  30. package/dist/constants/media-file-types.js.map +1 -1
  31. package/dist/constants/success-messages.d.ts +3 -0
  32. package/dist/constants/success-messages.d.ts.map +1 -1
  33. package/dist/constants/success-messages.js +3 -0
  34. package/dist/constants/success-messages.js.map +1 -1
  35. package/dist/constants/user.constants.d.ts +2 -0
  36. package/dist/constants/user.constants.d.ts.map +1 -0
  37. package/dist/constants/user.constants.js +5 -0
  38. package/dist/constants/user.constants.js.map +1 -0
  39. package/dist/controllers/action-metadata.controller.d.ts +1 -1
  40. package/dist/controllers/action-metadata.controller.js +1 -1
  41. package/dist/controllers/agent-event.controller.d.ts +1 -1
  42. package/dist/controllers/agent-event.controller.js +1 -1
  43. package/dist/controllers/agent-session.controller.d.ts +1 -1
  44. package/dist/controllers/agent-session.controller.js +1 -1
  45. package/dist/controllers/authentication.controller.d.ts +1 -1
  46. package/dist/controllers/authentication.controller.d.ts.map +1 -1
  47. package/dist/controllers/authentication.controller.js +4 -3
  48. package/dist/controllers/authentication.controller.js.map +1 -1
  49. package/dist/controllers/chatter-message.controller.d.ts +5 -0
  50. package/dist/controllers/chatter-message.controller.d.ts.map +1 -1
  51. package/dist/controllers/chatter-message.controller.js +14 -0
  52. package/dist/controllers/chatter-message.controller.js.map +1 -1
  53. package/dist/controllers/dashboard-user-layout.controller.d.ts +1 -1
  54. package/dist/controllers/dashboard-user-layout.controller.js +1 -1
  55. package/dist/controllers/email-template.controller.d.ts +1 -1
  56. package/dist/controllers/email-template.controller.js +1 -1
  57. package/dist/controllers/export-template.controller.d.ts +1 -1
  58. package/dist/controllers/export-template.controller.d.ts.map +1 -1
  59. package/dist/controllers/export-template.controller.js +6 -4
  60. package/dist/controllers/export-template.controller.js.map +1 -1
  61. package/dist/controllers/export-transaction.controller.d.ts +1 -1
  62. package/dist/controllers/export-transaction.controller.js +1 -1
  63. package/dist/controllers/field-metadata.controller.d.ts +2 -2
  64. package/dist/controllers/import-transaction-error-log.controller.d.ts +1 -1
  65. package/dist/controllers/import-transaction-error-log.controller.js +1 -1
  66. package/dist/controllers/import-transaction.controller.d.ts +1 -1
  67. package/dist/controllers/import-transaction.controller.d.ts.map +1 -1
  68. package/dist/controllers/import-transaction.controller.js +7 -7
  69. package/dist/controllers/import-transaction.controller.js.map +1 -1
  70. package/dist/controllers/list-of-values.controller.d.ts +1 -1
  71. package/dist/controllers/list-of-values.controller.js +1 -1
  72. package/dist/controllers/locale.controller.d.ts +1 -1
  73. package/dist/controllers/locale.controller.js +1 -1
  74. package/dist/controllers/mcp-audit-log.controller.d.ts +1 -1
  75. package/dist/controllers/mcp-audit-log.controller.js +1 -1
  76. package/dist/controllers/media.controller.d.ts +2 -2
  77. package/dist/controllers/media.controller.d.ts.map +1 -1
  78. package/dist/controllers/media.controller.js +13 -8
  79. package/dist/controllers/media.controller.js.map +1 -1
  80. package/dist/controllers/menu-item-metadata.controller.d.ts +1 -1
  81. package/dist/controllers/menu-item-metadata.controller.js +1 -1
  82. package/dist/controllers/model-sequence.controller.d.ts +1 -1
  83. package/dist/controllers/model-sequence.controller.js +1 -1
  84. package/dist/controllers/module-package.controller.d.ts.map +1 -1
  85. package/dist/controllers/module-package.controller.js +2 -3
  86. package/dist/controllers/module-package.controller.js.map +1 -1
  87. package/dist/controllers/mpin-authentication.controller.d.ts +44 -0
  88. package/dist/controllers/mpin-authentication.controller.d.ts.map +1 -0
  89. package/dist/controllers/mpin-authentication.controller.js +102 -0
  90. package/dist/controllers/mpin-authentication.controller.js.map +1 -0
  91. package/dist/controllers/mq-message-queue.controller.d.ts +1 -1
  92. package/dist/controllers/mq-message-queue.controller.js +1 -1
  93. package/dist/controllers/mq-message.controller.d.ts +1 -1
  94. package/dist/controllers/mq-message.controller.js +1 -1
  95. package/dist/controllers/permission-metadata.controller.d.ts +1 -1
  96. package/dist/controllers/permission-metadata.controller.js +1 -1
  97. package/dist/controllers/role-metadata.controller.d.ts +1 -1
  98. package/dist/controllers/role-metadata.controller.js +1 -1
  99. package/dist/controllers/saved-filters.controller.d.ts +1 -1
  100. package/dist/controllers/saved-filters.controller.js +1 -1
  101. package/dist/controllers/scheduled-job.controller.d.ts +1 -1
  102. package/dist/controllers/scheduled-job.controller.js +1 -1
  103. package/dist/controllers/security-rule.controller.d.ts +1 -1
  104. package/dist/controllers/security-rule.controller.js +1 -1
  105. package/dist/controllers/sms-template.controller.d.ts +1 -1
  106. package/dist/controllers/sms-template.controller.js +1 -1
  107. package/dist/controllers/user-activity-history.controller.d.ts +1 -1
  108. package/dist/controllers/user-activity-history.controller.js +1 -1
  109. package/dist/controllers/user-view-metadata.controller.d.ts +1 -1
  110. package/dist/controllers/user-view-metadata.controller.js +1 -1
  111. package/dist/controllers/user.controller.d.ts +2 -2
  112. package/dist/controllers/user.controller.js +2 -2
  113. package/dist/controllers/view-metadata.controller.d.ts +2 -2
  114. package/dist/controllers/view-metadata.controller.js +1 -1
  115. package/dist/controllers/workflow-definition.controller.d.ts +1 -1
  116. package/dist/controllers/workflow-definition.controller.js +1 -1
  117. package/dist/controllers/workflow-execution-artifact.controller.d.ts +1 -1
  118. package/dist/controllers/workflow-execution-artifact.controller.js +1 -1
  119. package/dist/controllers/workflow-execution-log.controller.d.ts +1 -1
  120. package/dist/controllers/workflow-execution-log.controller.js +1 -1
  121. package/dist/controllers/workflow-execution.controller.d.ts +1 -1
  122. package/dist/controllers/workflow-execution.controller.js +1 -1
  123. package/dist/controllers/workflow-secret.controller.d.ts +1 -1
  124. package/dist/controllers/workflow-secret.controller.js +1 -1
  125. package/dist/controllers/workflow-step-execution.controller.d.ts +1 -1
  126. package/dist/controllers/workflow-step-execution.controller.js +1 -1
  127. package/dist/controllers/workflow-trigger-execution.controller.d.ts +1 -1
  128. package/dist/controllers/workflow-trigger-execution.controller.js +1 -1
  129. package/dist/dtos/basic-filters.dto.d.ts +0 -1
  130. package/dist/dtos/basic-filters.dto.d.ts.map +1 -1
  131. package/dist/dtos/basic-filters.dto.js +1 -6
  132. package/dist/dtos/basic-filters.dto.js.map +1 -1
  133. package/dist/dtos/change-mpin.dto.d.ts +6 -0
  134. package/dist/dtos/change-mpin.dto.d.ts.map +1 -0
  135. package/dist/dtos/change-mpin.dto.js +39 -0
  136. package/dist/dtos/change-mpin.dto.js.map +1 -0
  137. package/dist/dtos/create-field-metadata.dto.d.ts +3 -6
  138. package/dist/dtos/create-field-metadata.dto.d.ts.map +1 -1
  139. package/dist/dtos/create-field-metadata.dto.js +15 -10
  140. package/dist/dtos/create-field-metadata.dto.js.map +1 -1
  141. package/dist/dtos/create-model-sequence.dto.d.ts +1 -1
  142. package/dist/dtos/create-model-sequence.dto.d.ts.map +1 -1
  143. package/dist/dtos/create-model-sequence.dto.js +1 -1
  144. package/dist/dtos/create-model-sequence.dto.js.map +1 -1
  145. package/dist/dtos/mpin-login.dto.d.ts +5 -0
  146. package/dist/dtos/mpin-login.dto.d.ts.map +1 -0
  147. package/dist/dtos/mpin-login.dto.js +33 -0
  148. package/dist/dtos/mpin-login.dto.js.map +1 -0
  149. package/dist/dtos/setup-mpin.dto.d.ts +7 -0
  150. package/dist/dtos/setup-mpin.dto.d.ts.map +1 -0
  151. package/dist/dtos/setup-mpin.dto.js +47 -0
  152. package/dist/dtos/setup-mpin.dto.js.map +1 -0
  153. package/dist/entities/common.entity.d.ts +4 -0
  154. package/dist/entities/common.entity.d.ts.map +1 -1
  155. package/dist/entities/common.entity.js +25 -1
  156. package/dist/entities/common.entity.js.map +1 -1
  157. package/dist/entities/dashboard-user-layout.entity.js +2 -2
  158. package/dist/entities/dashboard-user-layout.entity.js.map +1 -1
  159. package/dist/entities/field-metadata.entity.d.ts +1 -0
  160. package/dist/entities/field-metadata.entity.d.ts.map +1 -1
  161. package/dist/entities/field-metadata.entity.js +5 -1
  162. package/dist/entities/field-metadata.entity.js.map +1 -1
  163. package/dist/entities/saved-filters.entity.js +3 -3
  164. package/dist/entities/saved-filters.entity.js.map +1 -1
  165. package/dist/entities/user-device-credential.entity.d.ts +18 -0
  166. package/dist/entities/user-device-credential.entity.d.ts.map +1 -0
  167. package/dist/entities/user-device-credential.entity.js +91 -0
  168. package/dist/entities/user-device-credential.entity.js.map +1 -0
  169. package/dist/entities/user.entity.d.ts.map +1 -1
  170. package/dist/entities/user.entity.js +36 -0
  171. package/dist/entities/user.entity.js.map +1 -1
  172. package/dist/entities/view-metadata.entity.js.map +1 -1
  173. package/dist/entities/workflow-execution-artifact.entity.d.ts.map +1 -1
  174. package/dist/entities/workflow-execution-artifact.entity.js +4 -3
  175. package/dist/entities/workflow-execution-artifact.entity.js.map +1 -1
  176. package/dist/entities/workflow-execution-log.entity.d.ts.map +1 -1
  177. package/dist/entities/workflow-execution-log.entity.js +4 -3
  178. package/dist/entities/workflow-execution-log.entity.js.map +1 -1
  179. package/dist/entities/workflow-execution.entity.d.ts.map +1 -1
  180. package/dist/entities/workflow-execution.entity.js +3 -2
  181. package/dist/entities/workflow-execution.entity.js.map +1 -1
  182. package/dist/entities/workflow-secret.entity.d.ts.map +1 -1
  183. package/dist/entities/workflow-secret.entity.js +3 -2
  184. package/dist/entities/workflow-secret.entity.js.map +1 -1
  185. package/dist/entities/workflow-step-execution.entity.d.ts.map +1 -1
  186. package/dist/entities/workflow-step-execution.entity.js +3 -2
  187. package/dist/entities/workflow-step-execution.entity.js.map +1 -1
  188. package/dist/entities/workflow-trigger-execution.entity.d.ts.map +1 -1
  189. package/dist/entities/workflow-trigger-execution.entity.js +7 -6
  190. package/dist/entities/workflow-trigger-execution.entity.js.map +1 -1
  191. package/dist/factories/mail.factory.d.ts.map +1 -1
  192. package/dist/factories/mail.factory.js +4 -0
  193. package/dist/factories/mail.factory.js.map +1 -1
  194. package/dist/filters/http-exception.filter.d.ts.map +1 -1
  195. package/dist/filters/http-exception.filter.js +5 -1
  196. package/dist/filters/http-exception.filter.js.map +1 -1
  197. package/dist/helpers/bootstrap.helper.d.ts +5 -2
  198. package/dist/helpers/bootstrap.helper.d.ts.map +1 -1
  199. package/dist/helpers/bootstrap.helper.js +7 -3
  200. package/dist/helpers/bootstrap.helper.js.map +1 -1
  201. package/dist/helpers/field-crud-managers/MediaFieldCrudManager.d.ts +7 -0
  202. package/dist/helpers/field-crud-managers/MediaFieldCrudManager.d.ts.map +1 -1
  203. package/dist/helpers/field-crud-managers/MediaFieldCrudManager.js +66 -32
  204. package/dist/helpers/field-crud-managers/MediaFieldCrudManager.js.map +1 -1
  205. package/dist/helpers/file-download.helper.d.ts +9 -0
  206. package/dist/helpers/file-download.helper.d.ts.map +1 -0
  207. package/dist/helpers/file-download.helper.js +19 -0
  208. package/dist/helpers/file-download.helper.js.map +1 -0
  209. package/dist/helpers/model-metadata-helper.service.d.ts.map +1 -1
  210. package/dist/helpers/model-metadata-helper.service.js +30 -1
  211. package/dist/helpers/model-metadata-helper.service.js.map +1 -1
  212. package/dist/helpers/security.helper.d.ts +5 -1
  213. package/dist/helpers/security.helper.d.ts.map +1 -1
  214. package/dist/helpers/security.helper.js +15 -4
  215. package/dist/helpers/security.helper.js.map +1 -1
  216. package/dist/helpers/solid-core-error-codes-provider.service.d.ts.map +1 -1
  217. package/dist/helpers/solid-core-error-codes-provider.service.js +45 -0
  218. package/dist/helpers/solid-core-error-codes-provider.service.js.map +1 -1
  219. package/dist/helpers/solid-microservice-adapter.service.d.ts.map +1 -1
  220. package/dist/helpers/solid-microservice-adapter.service.js +1 -1
  221. package/dist/helpers/solid-microservice-adapter.service.js.map +1 -1
  222. package/dist/helpers/solid-registry.js +1 -1
  223. package/dist/helpers/solid-registry.js.map +1 -1
  224. package/dist/helpers/typeorm-db-helper.d.ts.map +1 -1
  225. package/dist/helpers/typeorm-db-helper.js +9 -0
  226. package/dist/helpers/typeorm-db-helper.js.map +1 -1
  227. package/dist/index.d.ts +10 -0
  228. package/dist/index.d.ts.map +1 -1
  229. package/dist/index.js +10 -0
  230. package/dist/index.js.map +1 -1
  231. package/dist/interfaces/active-user-data.interface.d.ts +1 -0
  232. package/dist/interfaces/active-user-data.interface.d.ts.map +1 -1
  233. package/dist/interfaces/active-user-data.interface.js.map +1 -1
  234. package/dist/interfaces.d.ts +1 -0
  235. package/dist/interfaces.d.ts.map +1 -1
  236. package/dist/interfaces.js.map +1 -1
  237. package/dist/repository/user-device-credential.repository.d.ts +12 -0
  238. package/dist/repository/user-device-credential.repository.d.ts.map +1 -0
  239. package/dist/repository/user-device-credential.repository.js +34 -0
  240. package/dist/repository/user-device-credential.repository.js.map +1 -0
  241. package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
  242. package/dist/seeders/module-metadata-seeder.service.js +51 -30
  243. package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
  244. package/dist/seeders/module-test-data.service.d.ts +3 -1
  245. package/dist/seeders/module-test-data.service.d.ts.map +1 -1
  246. package/dist/seeders/module-test-data.service.js +8 -2
  247. package/dist/seeders/module-test-data.service.js.map +1 -1
  248. package/dist/seeders/seed-data/solid-core-metadata.json +290 -78
  249. package/dist/services/api-key.service.d.ts.map +1 -1
  250. package/dist/services/api-key.service.js +1 -1
  251. package/dist/services/api-key.service.js.map +1 -1
  252. package/dist/services/authentication.service.d.ts +9 -5
  253. package/dist/services/authentication.service.d.ts.map +1 -1
  254. package/dist/services/authentication.service.js +102 -23
  255. package/dist/services/authentication.service.js.map +1 -1
  256. package/dist/services/chatter-message.service.d.ts +16 -1
  257. package/dist/services/chatter-message.service.d.ts.map +1 -1
  258. package/dist/services/chatter-message.service.js +100 -16
  259. package/dist/services/chatter-message.service.js.map +1 -1
  260. package/dist/services/crud-helper.service.d.ts +6 -4
  261. package/dist/services/crud-helper.service.d.ts.map +1 -1
  262. package/dist/services/crud-helper.service.js +32 -48
  263. package/dist/services/crud-helper.service.js.map +1 -1
  264. package/dist/services/crud.service.d.ts +13 -1
  265. package/dist/services/crud.service.d.ts.map +1 -1
  266. package/dist/services/crud.service.js +94 -68
  267. package/dist/services/crud.service.js.map +1 -1
  268. package/dist/services/datasource-introspection.service.d.ts.map +1 -1
  269. package/dist/services/datasource-introspection.service.js.map +1 -1
  270. package/dist/services/draft-publish-helper.service.d.ts +53 -0
  271. package/dist/services/draft-publish-helper.service.d.ts.map +1 -0
  272. package/dist/services/draft-publish-helper.service.js +402 -0
  273. package/dist/services/draft-publish-helper.service.js.map +1 -0
  274. package/dist/services/field-metadata.service.d.ts +2 -2
  275. package/dist/services/field-metadata.service.d.ts.map +1 -1
  276. package/dist/services/field-metadata.service.js +4 -1
  277. package/dist/services/field-metadata.service.js.map +1 -1
  278. package/dist/services/internationalisation-helper.service.d.ts +19 -0
  279. package/dist/services/internationalisation-helper.service.d.ts.map +1 -0
  280. package/dist/services/internationalisation-helper.service.js +107 -0
  281. package/dist/services/internationalisation-helper.service.js.map +1 -0
  282. package/dist/services/locale.service.d.ts +1 -1
  283. package/dist/services/media-storage.utils.d.ts +1 -0
  284. package/dist/services/media-storage.utils.d.ts.map +1 -1
  285. package/dist/services/media-storage.utils.js +12 -1
  286. package/dist/services/media-storage.utils.js.map +1 -1
  287. package/dist/services/media.service.d.ts +3 -2
  288. package/dist/services/media.service.d.ts.map +1 -1
  289. package/dist/services/media.service.js +45 -29
  290. package/dist/services/media.service.js.map +1 -1
  291. package/dist/services/metadata-validation.service.d.ts +7 -0
  292. package/dist/services/metadata-validation.service.d.ts.map +1 -0
  293. package/dist/services/metadata-validation.service.js +42 -0
  294. package/dist/services/metadata-validation.service.js.map +1 -0
  295. package/dist/services/model-metadata.service.d.ts.map +1 -1
  296. package/dist/services/model-metadata.service.js +2 -1
  297. package/dist/services/model-metadata.service.js.map +1 -1
  298. package/dist/services/module-metadata.service.d.ts.map +1 -1
  299. package/dist/services/module-metadata.service.js +9 -1
  300. package/dist/services/module-metadata.service.js.map +1 -1
  301. package/dist/services/mpin.service.d.ts +67 -0
  302. package/dist/services/mpin.service.d.ts.map +1 -0
  303. package/dist/services/mpin.service.js +282 -0
  304. package/dist/services/mpin.service.js.map +1 -0
  305. package/dist/services/object.utils.d.ts +2 -0
  306. package/dist/services/object.utils.d.ts.map +1 -0
  307. package/dist/services/object.utils.js +11 -0
  308. package/dist/services/object.utils.js.map +1 -0
  309. package/dist/services/refresh-token-ids-storage.service.d.ts +25 -6
  310. package/dist/services/refresh-token-ids-storage.service.d.ts.map +1 -1
  311. package/dist/services/refresh-token-ids-storage.service.js +80 -42
  312. package/dist/services/refresh-token-ids-storage.service.js.map +1 -1
  313. package/dist/services/setting.service.d.ts.map +1 -1
  314. package/dist/services/setting.service.js +6 -1
  315. package/dist/services/setting.service.js.map +1 -1
  316. package/dist/services/settings/default-settings-provider.service.d.ts +248 -12
  317. package/dist/services/settings/default-settings-provider.service.d.ts.map +1 -1
  318. package/dist/services/settings/default-settings-provider.service.js +143 -6
  319. package/dist/services/settings/default-settings-provider.service.js.map +1 -1
  320. package/dist/services/user.service.d.ts +2 -2
  321. package/dist/services/user.service.d.ts.map +1 -1
  322. package/dist/services/user.service.js +9 -3
  323. package/dist/services/user.service.js.map +1 -1
  324. package/dist/services/view-metadata.service.d.ts +1 -2
  325. package/dist/services/view-metadata.service.d.ts.map +1 -1
  326. package/dist/services/view-metadata.service.js +3 -55
  327. package/dist/services/view-metadata.service.js.map +1 -1
  328. package/dist/services/workflow/nodes/execution-fail.node.d.ts +6 -0
  329. package/dist/services/workflow/nodes/execution-fail.node.d.ts.map +1 -0
  330. package/dist/services/workflow/nodes/execution-fail.node.js +81 -0
  331. package/dist/services/workflow/nodes/execution-fail.node.js.map +1 -0
  332. package/dist/services/workflow/nodes/for-each.node.d.ts +2 -0
  333. package/dist/services/workflow/nodes/for-each.node.d.ts.map +1 -1
  334. package/dist/services/workflow/nodes/for-each.node.js +114 -5
  335. package/dist/services/workflow/nodes/for-each.node.js.map +1 -1
  336. package/dist/services/workflow/nodes/if.node.d.ts.map +1 -1
  337. package/dist/services/workflow/nodes/if.node.js +7 -0
  338. package/dist/services/workflow/nodes/if.node.js.map +1 -1
  339. package/dist/services/workflow/nodes/log-write.node.d.ts.map +1 -1
  340. package/dist/services/workflow/nodes/log-write.node.js +2 -0
  341. package/dist/services/workflow/nodes/log-write.node.js.map +1 -1
  342. package/dist/services/workflow/nodes/loop-until.node.d.ts +12 -0
  343. package/dist/services/workflow/nodes/loop-until.node.d.ts.map +1 -0
  344. package/dist/services/workflow/nodes/loop-until.node.js +281 -0
  345. package/dist/services/workflow/nodes/loop-until.node.js.map +1 -0
  346. package/dist/services/workflow/nodes/parallel.node.d.ts.map +1 -1
  347. package/dist/services/workflow/nodes/parallel.node.js +7 -0
  348. package/dist/services/workflow/nodes/parallel.node.js.map +1 -1
  349. package/dist/services/workflow/nodes/sequential.node.d.ts.map +1 -1
  350. package/dist/services/workflow/nodes/sequential.node.js +7 -0
  351. package/dist/services/workflow/nodes/sequential.node.js.map +1 -1
  352. package/dist/services/workflow/nodes/switch.node.d.ts.map +1 -1
  353. package/dist/services/workflow/nodes/switch.node.js +7 -0
  354. package/dist/services/workflow/nodes/switch.node.js.map +1 -1
  355. package/dist/services/workflow/workflow-definition-validator.service.d.ts.map +1 -1
  356. package/dist/services/workflow/workflow-definition-validator.service.js +5 -2
  357. package/dist/services/workflow/workflow-definition-validator.service.js.map +1 -1
  358. package/dist/services/workflow/workflow-expression.service.d.ts.map +1 -1
  359. package/dist/services/workflow/workflow-expression.service.js +5 -0
  360. package/dist/services/workflow/workflow-expression.service.js.map +1 -1
  361. package/dist/services/workflow/workflow-node-registry.service.d.ts +2 -1
  362. package/dist/services/workflow/workflow-node-registry.service.d.ts.map +1 -1
  363. package/dist/services/workflow/workflow-node-registry.service.js +7 -0
  364. package/dist/services/workflow/workflow-node-registry.service.js.map +1 -1
  365. package/dist/services/workflow/workflow-runtime.service.d.ts +8 -0
  366. package/dist/services/workflow/workflow-runtime.service.d.ts.map +1 -1
  367. package/dist/services/workflow/workflow-runtime.service.js +197 -32
  368. package/dist/services/workflow/workflow-runtime.service.js.map +1 -1
  369. package/dist/services/workflow-definition.service.d.ts +1 -1
  370. package/dist/solid-core.module.d.ts +1 -3
  371. package/dist/solid-core.module.d.ts.map +1 -1
  372. package/dist/solid-core.module.js +28 -40
  373. package/dist/solid-core.module.js.map +1 -1
  374. package/dist/testing/adapters/ui/playwright-adapter.d.ts +5 -0
  375. package/dist/testing/adapters/ui/playwright-adapter.d.ts.map +1 -1
  376. package/dist/testing/adapters/ui/playwright-adapter.js +17 -1
  377. package/dist/testing/adapters/ui/playwright-adapter.js.map +1 -1
  378. package/dist/testing/adapters/ui/ui.types.d.ts +2 -0
  379. package/dist/testing/adapters/ui/ui.types.d.ts.map +1 -1
  380. package/dist/testing/adapters/ui/ui.types.js.map +1 -1
  381. package/dist/testing/reporter/console-reporter.d.ts +3 -0
  382. package/dist/testing/reporter/console-reporter.d.ts.map +1 -1
  383. package/dist/testing/reporter/console-reporter.js +2 -0
  384. package/dist/testing/reporter/console-reporter.js.map +1 -1
  385. package/dist/testing/reporter/progress-reporter.d.ts +64 -0
  386. package/dist/testing/reporter/progress-reporter.d.ts.map +1 -0
  387. package/dist/testing/reporter/progress-reporter.js +224 -0
  388. package/dist/testing/reporter/progress-reporter.js.map +1 -0
  389. package/dist/testing/reporter/reporter.types.d.ts +3 -0
  390. package/dist/testing/reporter/reporter.types.d.ts.map +1 -1
  391. package/dist/testing/reporter/reporter.types.js.map +1 -1
  392. package/dist/testing/runner/run-from-metadata.d.ts.map +1 -1
  393. package/dist/testing/runner/run-from-metadata.js +1 -0
  394. package/dist/testing/runner/run-from-metadata.js.map +1 -1
  395. package/dist/testing/steps/ui/actions.step.d.ts.map +1 -1
  396. package/dist/testing/steps/ui/actions.step.js +6 -2
  397. package/dist/testing/steps/ui/actions.step.js.map +1 -1
  398. package/dist/testing/steps/ui/assertions.step.d.ts.map +1 -1
  399. package/dist/testing/steps/ui/assertions.step.js +11 -3
  400. package/dist/testing/steps/ui/assertions.step.js.map +1 -1
  401. package/dist/testing/steps/ui/form.step.d.ts.map +1 -1
  402. package/dist/testing/steps/ui/form.step.js +9 -3
  403. package/dist/testing/steps/ui/form.step.js.map +1 -1
  404. package/dist/testing/steps/ui/manual.step.js +1 -1
  405. package/dist/testing/steps/ui/manual.step.js.map +1 -1
  406. package/dist/testing/steps/ui/navigation.step.d.ts.map +1 -1
  407. package/dist/testing/steps/ui/navigation.step.js +3 -1
  408. package/dist/testing/steps/ui/navigation.step.js.map +1 -1
  409. package/dist/theme/theme-registry.d.ts +14 -0
  410. package/dist/theme/theme-registry.d.ts.map +1 -0
  411. package/dist/theme/theme-registry.js +147 -0
  412. package/dist/theme/theme-registry.js.map +1 -0
  413. package/dist/types/workflow-dsl.types.d.ts +14 -0
  414. package/dist/types/workflow-dsl.types.d.ts.map +1 -1
  415. package/dist/types/workflow-dsl.types.js.map +1 -1
  416. package/package.json +2 -2
  417. package/src/commands/run-tests.command.ts +64 -4
  418. package/src/commands/seed.command.ts +19 -0
  419. package/src/config/cache.options.ts +9 -1
  420. package/src/constants/chatter-message.constants.ts +12 -0
  421. package/src/constants/draft-publish-fields.ts +5 -0
  422. package/src/constants/error-messages.ts +14 -0
  423. package/src/constants/media-file-types.ts +128 -0
  424. package/src/constants/success-messages.ts +5 -0
  425. package/src/constants/user.constants.ts +13 -0
  426. package/src/controllers/authentication.controller.ts +5 -2
  427. package/src/controllers/chatter-message.controller.ts +8 -0
  428. package/src/controllers/export-template.controller.ts +5 -3
  429. package/src/controllers/import-transaction.controller.ts +6 -6
  430. package/src/controllers/media.controller.ts +17 -6
  431. package/src/controllers/module-package.controller.ts +2 -3
  432. package/src/controllers/mpin-authentication.controller.ts +67 -0
  433. package/src/dtos/basic-filters.dto.ts +0 -4
  434. package/src/dtos/change-mpin.dto.ts +18 -0
  435. package/src/dtos/create-field-metadata.dto.ts +17 -9
  436. package/src/dtos/create-model-sequence.dto.ts +1 -1
  437. package/src/dtos/mpin-login.dto.ts +24 -0
  438. package/src/dtos/setup-mpin.dto.ts +51 -0
  439. package/src/entities/common.entity.ts +24 -0
  440. package/src/entities/dashboard-user-layout.entity.ts +2 -2
  441. package/src/entities/field-metadata.entity.ts +3 -0
  442. package/src/entities/saved-filters.entity.ts +3 -3
  443. package/src/entities/user-device-credential.entity.ts +130 -0
  444. package/src/entities/user.entity.ts +53 -36
  445. package/src/entities/view-metadata.entity.ts +2 -2
  446. package/src/entities/workflow-execution-artifact.entity.ts +4 -3
  447. package/src/entities/workflow-execution-log.entity.ts +4 -3
  448. package/src/entities/workflow-execution.entity.ts +3 -2
  449. package/src/entities/workflow-secret.entity.ts +3 -2
  450. package/src/entities/workflow-step-execution.entity.ts +3 -2
  451. package/src/entities/workflow-trigger-execution.entity.ts +7 -6
  452. package/src/factories/mail.factory.ts +7 -1
  453. package/src/filters/http-exception.filter.ts +11 -1
  454. package/src/helpers/bootstrap.helper.ts +43 -6
  455. package/src/helpers/field-crud-managers/MediaFieldCrudManager.ts +90 -37
  456. package/src/helpers/file-download.helper.ts +45 -0
  457. package/src/helpers/model-metadata-helper.service.ts +32 -1
  458. package/src/helpers/security.helper.ts +35 -8
  459. package/src/helpers/solid-core-error-codes-provider.service.ts +53 -0
  460. package/src/helpers/solid-microservice-adapter.service.ts +6 -1
  461. package/src/helpers/solid-registry.ts +1 -1
  462. package/src/helpers/typeorm-db-helper.ts +12 -1
  463. package/src/index.ts +10 -0
  464. package/src/interfaces/active-user-data.interface.ts +9 -0
  465. package/src/interfaces.ts +1 -0
  466. package/src/repository/user-device-credential.repository.ts +17 -0
  467. package/src/seeders/module-metadata-seeder.service.ts +61 -39
  468. package/src/seeders/module-test-data.service.ts +6 -0
  469. package/src/seeders/seed-data/solid-core-metadata.json +290 -78
  470. package/src/services/api-key.service.ts +13 -1
  471. package/src/services/authentication.service.ts +203 -41
  472. package/src/services/chatter-message.service.ts +180 -19
  473. package/src/services/crud-helper.service.ts +35 -50
  474. package/src/services/crud.service.ts +132 -105
  475. package/src/services/datasource-introspection.service.ts +5 -0
  476. package/src/services/draft-publish-helper.service.ts +581 -0
  477. package/src/services/field-metadata.service.ts +5 -2
  478. package/src/services/internationalisation-helper.service.ts +148 -0
  479. package/src/services/media-storage.utils.ts +26 -1
  480. package/src/services/media.service.ts +68 -36
  481. package/src/services/metadata-validation.service.ts +39 -0
  482. package/src/services/model-metadata.service.ts +4 -1
  483. package/src/services/module-metadata.service.ts +10 -1
  484. package/src/services/mpin.service.ts +447 -0
  485. package/src/services/object.utils.ts +10 -0
  486. package/src/services/refresh-token-ids-storage.service.ts +229 -90
  487. package/src/services/setting.service.ts +8 -1
  488. package/src/services/settings/default-settings-provider.service.ts +154 -6
  489. package/src/services/user.service.ts +18 -3
  490. package/src/services/view-metadata.service.ts +5 -145
  491. package/src/services/workflow/nodes/execution-fail.node.ts +82 -0
  492. package/src/services/workflow/nodes/for-each.node.ts +140 -6
  493. package/src/services/workflow/nodes/if.node.ts +7 -0
  494. package/src/services/workflow/nodes/log-write.node.ts +2 -0
  495. package/src/services/workflow/nodes/loop-until.node.ts +343 -0
  496. package/src/services/workflow/nodes/parallel.node.ts +7 -0
  497. package/src/services/workflow/nodes/sequential.node.ts +7 -0
  498. package/src/services/workflow/nodes/switch.node.ts +7 -0
  499. package/src/services/workflow/workflow-definition-validator.service.ts +5 -2
  500. package/src/services/workflow/workflow-expression.service.ts +5 -0
  501. package/src/services/workflow/workflow-node-registry.service.ts +11 -0
  502. package/src/services/workflow/workflow-runtime.service.ts +274 -39
  503. package/src/solid-core.module.ts +46 -15
  504. package/src/testing/README.md +75 -3
  505. package/src/testing/adapters/ui/playwright-adapter.ts +25 -0
  506. package/src/testing/adapters/ui/ui.types.ts +2 -0
  507. package/src/testing/reporter/console-reporter.ts +4 -0
  508. package/src/testing/reporter/progress-reporter.ts +251 -0
  509. package/src/testing/reporter/reporter.types.ts +3 -0
  510. package/src/testing/runner/run-from-metadata.ts +1 -0
  511. package/src/testing/steps/ui/actions.step.ts +8 -4
  512. package/src/testing/steps/ui/assertions.step.ts +18 -5
  513. package/src/testing/steps/ui/form.step.ts +16 -6
  514. package/src/testing/steps/ui/manual.step.ts +1 -1
  515. package/src/testing/steps/ui/navigation.step.ts +4 -2
  516. package/src/theme/theme-registry.ts +181 -0
  517. package/src/types/workflow-dsl.types.ts +43 -0
@@ -0,0 +1,581 @@
1
+ import { BadRequestException, NotFoundException } from "@nestjs/common";
2
+ import { EntityManager, FindOptionsWhere, In, SelectQueryBuilder } from "typeorm";
3
+ import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity";
4
+ import { DRAFT_PUBLISH_VERSIONING_FIELD_NAMES } from "../constants/draft-publish-fields";
5
+ import { RelationType, SolidFieldType } from "../dtos/create-field-metadata.dto";
6
+ import { CommonEntity } from "../entities/common.entity";
7
+ import { FieldMetadata } from "../entities/field-metadata.entity";
8
+ import { Media } from "../entities/media.entity";
9
+ import { ModelMetadata } from "../entities/model-metadata.entity";
10
+ import { SolidBaseRepository } from "../repository/solid-base.repository";
11
+ import { normalizeObjectKeys } from "./object.utils";
12
+
13
+ type TransformDtoResult = {
14
+ dto: any;
15
+ hasMediaFields: boolean;
16
+ };
17
+
18
+ type DraftPublishCrudContext<T extends CommonEntity> = {
19
+ repo: SolidBaseRepository<T>;
20
+ modelName: string;
21
+ moduleName: string;
22
+ validateAndTransformDto: (
23
+ field: FieldMetadata,
24
+ dto: any,
25
+ files: Express.Multer.File[],
26
+ hasMediaFields: boolean,
27
+ isPartialUpdate?: boolean,
28
+ isUpdate?: boolean,
29
+ entityId?: number,
30
+ ) => Promise<TransformDtoResult>;
31
+ saveMedia: (model: ModelMetadata, files: Express.Multer.File[], savedEntity: T) => Promise<void>;
32
+ getDatasourceDefaultEntityManager: () => EntityManager;
33
+ getColumnDatabaseName: (propertyName: string) => string;
34
+ escapeDatabaseName: (databaseName: string) => string;
35
+ };
36
+
37
+ export class DraftPublishHelperService {
38
+ isDraftPublishEnabled(model: ModelMetadata): boolean {
39
+ return model?.draftPublishWorkflow === true;
40
+ }
41
+
42
+ assertDraftPublishWorkflowEnabled(model: ModelMetadata, modelName: string): void {
43
+ if (!this.isDraftPublishEnabled(model)) {
44
+ throw new BadRequestException(`Publish workflow is not enabled for ${modelName}`);
45
+ }
46
+ }
47
+
48
+ assertUpdateAllowed<T extends CommonEntity>(model: ModelMetadata, entity: T, modelName: string): void {
49
+ if (!this.isDraftPublishEnabled(model)) return;
50
+ if (entity.isLatest === false) {
51
+ throw new BadRequestException(`Only the latest version of ${modelName} can be updated.`);
52
+ }
53
+ }
54
+
55
+ shouldCopyPublishedVersionForUpdate<T extends CommonEntity>(model: ModelMetadata, entity: T): boolean {
56
+ return this.isDraftPublishEnabled(model) && entity.isPublished === true;
57
+ }
58
+
59
+ applyCreateDefaults(model: ModelMetadata, createDto: any): void {
60
+ if (!this.isDraftPublishEnabled(model)) return;
61
+ createDto.isLatest = true;
62
+ createDto.isPublished = false;
63
+ createDto.publishedAt = null;
64
+ createDto.publishedTracker = "na";
65
+ }
66
+
67
+ async ensureInitialEntityVersionId<T extends CommonEntity>(
68
+ model: ModelMetadata,
69
+ repo: SolidBaseRepository<T>,
70
+ savedEntity: T,
71
+ ): Promise<T> {
72
+ if (!this.isDraftPublishEnabled(model) || savedEntity.initialEntityVersionId) return savedEntity;
73
+ savedEntity.initialEntityVersionId = savedEntity.id;
74
+ return repo.save(savedEntity) as Promise<T>;
75
+ }
76
+
77
+ applyDraftPublishFilterDefaults(
78
+ qb: SelectQueryBuilder<any>,
79
+ filters: any,
80
+ entityAlias: string,
81
+ ): void {
82
+ const hasIsLatestFilter = this.filtersContainField(filters, 'isLatest');
83
+ const hasInitialVersionFilter = this.filtersContainField(filters, 'initialEntityVersionId');
84
+ const isPublishedViewRequested = this.filtersContainBooleanValue(filters, 'isPublished', true);
85
+ const shouldApplyDefaultLatestFilter = !isPublishedViewRequested && !hasIsLatestFilter && !hasInitialVersionFilter;
86
+
87
+ if (shouldApplyDefaultLatestFilter) {
88
+ // OR in deletedAt IS NOT NULL so soft-deleted rows — always isLatest: false
89
+ // once deleted, see markDeletedDraftPublishVersionsAsNotLatest — stay visible
90
+ // when showSoftDeleted=inclusive/exclusive calls qb.withDeleted() to bypass
91
+ // TypeORM's automatic deletedAt-IS-NULL exclusion. Under the default query
92
+ // (no withDeleted()), deletedAt IS NOT NULL rows are already excluded by
93
+ // TypeORM itself, so this OR has no effect there.
94
+ qb.andWhere(
95
+ `(${entityAlias}.isLatest = :defaultIsLatest OR ${entityAlias}.deletedAt IS NOT NULL)`,
96
+ { defaultIsLatest: true },
97
+ );
98
+ }
99
+ }
100
+
101
+ filtersContainField(filters: any, fieldName: string): boolean {
102
+ return this.someFilterLeaf(filters, fieldName, () => true);
103
+ }
104
+
105
+ async copyPublishedVersionAndUpdate<T extends CommonEntity>(
106
+ context: DraftPublishCrudContext<T>,
107
+ id: number,
108
+ updateDto: any,
109
+ files: Express.Multer.File[],
110
+ isPartialUpdate: boolean,
111
+ model: ModelMetadata,
112
+ ): Promise<T> {
113
+ const relationNames = this.getVersionedRelationNames(model);
114
+ const sourceEntity = await context.repo.findOne({
115
+ where: { id } as unknown as FindOptionsWhere<T>,
116
+ relations: relationNames as any,
117
+ });
118
+
119
+ if (!sourceEntity) {
120
+ throw new Error(`Entity [${context.moduleName}.${context.modelName}] with id ${id} not found`);
121
+ }
122
+
123
+ let hasMediaFields = false;
124
+ // Snapshot of what the caller actually submitted, used only for hasOwnProperty checks
125
+ // below; the transform pipeline works off its own copy (transformedDto) so this
126
+ // reference never needs to be cloned.
127
+ const submittedDto = updateDto;
128
+ let transformedDto = { ...updateDto };
129
+
130
+ for (const field of model.fields) {
131
+ const transformed = await context.validateAndTransformDto(field, transformedDto, files, hasMediaFields, isPartialUpdate, false);
132
+ transformedDto = transformed.dto;
133
+ hasMediaFields = transformed.hasMediaFields;
134
+ }
135
+
136
+ const newVersionPayload = this.buildNewVersionPayload(context.repo, sourceEntity, relationNames);
137
+
138
+ for (const field of model.fields) {
139
+ if (this.wasFieldSubmitted(submittedDto, field) && Object.prototype.hasOwnProperty.call(transformedDto, field.name)) {
140
+ newVersionPayload[field.name] = transformedDto[field.name];
141
+ }
142
+ }
143
+
144
+ const chainId = sourceEntity.initialEntityVersionId || sourceEntity.id;
145
+ newVersionPayload.initialEntityVersionId = chainId;
146
+ newVersionPayload.isLatest = true;
147
+ newVersionPayload.isPublished = false;
148
+ newVersionPayload.publishedAt = null;
149
+ newVersionPayload.publishedTracker = this.createTemporaryPublishedVersionTracker();
150
+
151
+ const savedVersion = await context.repo.manager.transaction(async (manager) => {
152
+ const transactionalRepo = manager.getRepository(context.repo.metadata.target);
153
+
154
+ await manager
155
+ .createQueryBuilder()
156
+ .update(context.repo.metadata.target)
157
+ .set({ isLatest: false } as any)
158
+ .where(`${context.escapeDatabaseName(context.getColumnDatabaseName('isLatest'))} = :isLatest`, { isLatest: true })
159
+ .andWhere(`(${context.escapeDatabaseName(context.getColumnDatabaseName('initialEntityVersionId'))} = :chainId OR ${context.escapeDatabaseName(context.getColumnDatabaseName('id'))} = :chainId)`, { chainId })
160
+ .callListeners(false)
161
+ .execute();
162
+
163
+ const newVersion = transactionalRepo.create(newVersionPayload);
164
+ let persistedVersion = await transactionalRepo.save(newVersion) as unknown as T;
165
+ persistedVersion.publishedTracker = this.createPublishedVersionTracker(persistedVersion.id);
166
+ persistedVersion = await transactionalRepo.save(persistedVersion as any) as unknown as T;
167
+
168
+ await this.cloneMediaForVersion(context, model, sourceEntity.id, persistedVersion, files, manager);
169
+
170
+ return persistedVersion;
171
+ });
172
+
173
+ if (hasMediaFields) {
174
+ await context.saveMedia(model, files, savedVersion);
175
+ }
176
+
177
+ return savedVersion;
178
+ }
179
+
180
+ assertDraftPublishDeleteAllowed<T extends CommonEntity>(
181
+ modelName: string,
182
+ entities: T[],
183
+ ): void {
184
+ // The caller just loaded these entities, so their isPublished flags are already
185
+ // current — no need to re-query the DB for the same rows.
186
+ const currentPublishedEntityIds = entities
187
+ .filter(entity => entity.isPublished === true)
188
+ .map(entity => entity.id);
189
+
190
+ if (currentPublishedEntityIds.length > 0) {
191
+ throw new BadRequestException(
192
+ `Published ${modelName} record cannot be deleted. Publish another draft or unpublish it before deleting. Invalid Ids ${currentPublishedEntityIds.join(', ')}.`
193
+ );
194
+ }
195
+ }
196
+
197
+ markDeletedDraftPublishVersionsAsNotLatest<T extends CommonEntity>(model: ModelMetadata, entities: T[]): void {
198
+ if (!this.isDraftPublishEnabled(model)) return;
199
+ for (const entity of entities) {
200
+ if (entity.isLatest === true) {
201
+ entity.isLatest = false;
202
+ }
203
+ }
204
+ }
205
+
206
+ getLatestDraftPublishChainIds<T extends CommonEntity>(entities: T[]): number[] {
207
+ return Array.from(new Set(
208
+ entities
209
+ .filter(entity => entity.isLatest === true)
210
+ .map(entity => entity.initialEntityVersionId || entity.id)
211
+ ));
212
+ }
213
+
214
+ getEntityIds<T extends CommonEntity>(entities: T[]): number[] {
215
+ return entities.map(entity => entity.id).filter(Boolean);
216
+ }
217
+
218
+ async promoteLatestDraftPublishVersionAfterDelete<T extends CommonEntity>(
219
+ repo: SolidBaseRepository<T>,
220
+ deletedLatestChainIds: number[],
221
+ deletedIds: number[],
222
+ ): Promise<void> {
223
+ if (deletedLatestChainIds.length === 0) return;
224
+
225
+ // Chains are independent of one another, so promote replacements concurrently
226
+ // rather than awaiting one chain at a time.
227
+ await Promise.all(deletedLatestChainIds.map(chainId =>
228
+ this.promoteReplacementForChain(repo, chainId, deletedIds)
229
+ ));
230
+ }
231
+
232
+ private async promoteReplacementForChain<T extends CommonEntity>(
233
+ repo: SolidBaseRepository<T>,
234
+ chainId: number,
235
+ deletedIds: number[],
236
+ ): Promise<void> {
237
+ const replacementQuery = repo.manager
238
+ .createQueryBuilder(repo.metadata.target, 'entity')
239
+ .where('(entity.initialEntityVersionId = :chainId OR entity.id = :chainId)', { chainId })
240
+ .orderBy('entity.createdAt', 'DESC')
241
+ .addOrderBy('entity.id', 'DESC');
242
+
243
+ if (deletedIds.length > 0) {
244
+ replacementQuery.andWhere('entity.id NOT IN (:...deletedIds)', { deletedIds });
245
+ }
246
+
247
+ const replacement = await replacementQuery.getOne() as T | null;
248
+ if (!replacement) return;
249
+
250
+ await repo.manager
251
+ .createQueryBuilder()
252
+ .update(repo.metadata.target)
253
+ .set({ isLatest: false } as any)
254
+ .where('(initial_entity_version_id = :chainId OR id = :chainId)', { chainId })
255
+ .execute();
256
+
257
+ await repo.update(replacement.id, { isLatest: true } as unknown as QueryDeepPartialEntity<T>);
258
+ }
259
+
260
+ async promoteRecoveredDraftPublishVersion<T extends CommonEntity>(
261
+ repo: SolidBaseRepository<T>,
262
+ recoveredEntity: T,
263
+ ): Promise<void> {
264
+ const chainId = recoveredEntity.initialEntityVersionId || recoveredEntity.id;
265
+
266
+ await repo.manager
267
+ .createQueryBuilder()
268
+ .update(repo.metadata.target)
269
+ .set({ isLatest: false } as any)
270
+ .where('(initial_entity_version_id = :chainId OR id = :chainId)', { chainId })
271
+ .execute();
272
+
273
+ await repo.update(recoveredEntity.id, { isLatest: true } as unknown as QueryDeepPartialEntity<T>);
274
+ recoveredEntity.isLatest = true;
275
+ }
276
+
277
+ async publishRecord<T extends CommonEntity>(
278
+ repo: SolidBaseRepository<T>,
279
+ model: ModelMetadata,
280
+ modelName: string,
281
+ id: number,
282
+ activeUser?: any,
283
+ ): Promise<T> {
284
+ const entity = await this.loadLatestEntityForPublishAction(repo, model, modelName, id, 'published');
285
+
286
+ if (entity.isPublished) {
287
+ throw new BadRequestException(`${modelName} with id ${id} is already published`);
288
+ }
289
+
290
+ const chainId = entity.initialEntityVersionId || entity.id;
291
+
292
+ return repo.manager.transaction(async (manager) => {
293
+ const transactionalRepo = manager.getRepository(repo.metadata.target);
294
+ const chainVersions = await transactionalRepo.find({
295
+ where: [
296
+ { initialEntityVersionId: chainId },
297
+ { id: chainId },
298
+ ] as any,
299
+ }) as unknown as T[];
300
+ const archivedVersions = chainVersions
301
+ .filter(version => version.id !== entity.id)
302
+ .map(version => ({
303
+ ...version,
304
+ isPublished: false,
305
+ publishedTracker: this.createPublishedVersionTracker(version.id),
306
+ }));
307
+
308
+ if (archivedVersions.length > 0) {
309
+ await transactionalRepo.save(archivedVersions as any);
310
+ }
311
+
312
+ return transactionalRepo.save({
313
+ ...entity,
314
+ initialEntityVersionId: chainId,
315
+ isPublished: true,
316
+ publishedAt: new Date(),
317
+ publishedTracker: "na",
318
+ updatedBy: activeUser?.sub ?? entity.updatedBy,
319
+ } as any) as Promise<T>;
320
+ });
321
+ }
322
+
323
+ async unpublishRecord<T extends CommonEntity>(
324
+ repo: SolidBaseRepository<T>,
325
+ model: ModelMetadata,
326
+ modelName: string,
327
+ id: number,
328
+ activeUser?: any,
329
+ ): Promise<T> {
330
+ const entity = await this.loadLatestEntityForPublishAction(repo, model, modelName, id, 'unpublished');
331
+
332
+ if (!entity.isPublished) {
333
+ throw new BadRequestException(`${modelName} with id ${id} is already unpublished`);
334
+ }
335
+
336
+ const chainId = entity.initialEntityVersionId || entity.id;
337
+
338
+ return repo.manager.transaction(async (manager) => {
339
+ const transactionalRepo = manager.getRepository(repo.metadata.target);
340
+
341
+ // Release the "na" published tracker before anything else can claim it, mirroring
342
+ // publishRecord's archive-others-then-publish ordering in reverse. unpublishRecord
343
+ // only ever acts on the latest version (see loadLatestEntityForPublishAction), so
344
+ // this always becomes a Draft rather than an Archived version — clear publishedAt
345
+ // to match applyCreateDefaults' Draft convention instead of leaving a stale date.
346
+ const unpublishedEntity = await transactionalRepo.save({
347
+ ...entity,
348
+ isPublished: false,
349
+ publishedAt: null,
350
+ publishedTracker: this.createPublishedVersionTracker(entity.id),
351
+ updatedBy: activeUser?.sub ?? entity.updatedBy,
352
+ } as any) as unknown as T;
353
+
354
+ const chainVersions = await transactionalRepo.find({
355
+ where: [
356
+ { initialEntityVersionId: chainId },
357
+ { id: chainId },
358
+ ] as any,
359
+ }) as unknown as T[];
360
+
361
+ const versionToRestore = this.pickMostRecentlyPublishedVersion(
362
+ chainVersions.filter(version => version.id !== entity.id),
363
+ );
364
+
365
+ if (versionToRestore) {
366
+ await transactionalRepo.save({
367
+ ...versionToRestore,
368
+ isPublished: true,
369
+ publishedAt: new Date(),
370
+ publishedTracker: "na",
371
+ } as any);
372
+ }
373
+
374
+ return unpublishedEntity;
375
+ });
376
+ }
377
+
378
+ /**
379
+ * Among the other versions in a chain, find the one that was live most recently before
380
+ * being superseded (i.e. the "Archived" version unpublishRecord should restore). Ties on
381
+ * publishedAt fall back to the highest id, matching pickCurrentLocaleRecord's ordering.
382
+ */
383
+ private pickMostRecentlyPublishedVersion<T extends CommonEntity>(versions: T[]): T | null {
384
+ const previouslyPublished = versions.filter(version => Boolean(version.publishedAt));
385
+ if (previouslyPublished.length === 0) return null;
386
+
387
+ return previouslyPublished.sort((a, b) => {
388
+ const aPublishedAt = new Date(a.publishedAt as any).getTime();
389
+ const bPublishedAt = new Date(b.publishedAt as any).getTime();
390
+ if (aPublishedAt !== bPublishedAt) return bPublishedAt - aPublishedAt;
391
+ return Number(b.id) - Number(a.id);
392
+ })[0];
393
+ }
394
+
395
+ /**
396
+ * Load the latest version of a draft/publish-enabled record for a publish/unpublish
397
+ * action, applying the two checks both actions share (workflow enabled, version is latest).
398
+ */
399
+ private async loadLatestEntityForPublishAction<T extends CommonEntity>(
400
+ repo: SolidBaseRepository<T>,
401
+ model: ModelMetadata,
402
+ modelName: string,
403
+ id: number,
404
+ action: 'published' | 'unpublished',
405
+ ): Promise<T> {
406
+ this.assertDraftPublishWorkflowEnabled(model, modelName);
407
+
408
+ const entity = await repo.findOne({ where: { id } as any });
409
+ if (!entity) {
410
+ throw new NotFoundException(`${modelName} with id ${id} not found`);
411
+ }
412
+
413
+ if (entity.isLatest === false) {
414
+ throw new BadRequestException(`Only the latest version of ${modelName} can be ${action}.`);
415
+ }
416
+
417
+ return entity;
418
+ }
419
+
420
+ /**
421
+ * Walk a (possibly nested, $and/$or-combined) filters object looking for any leaf keyed
422
+ * by `fieldName`, delegating the leaf test to the caller. Shared by filtersContainField
423
+ * (any occurrence counts) and filtersContainBooleanValue (occurrence must match a value).
424
+ */
425
+ private someFilterLeaf(filters: any, fieldName: string, matchesLeaf: (value: any) => boolean): boolean {
426
+ if (!filters || typeof filters !== 'object') return false;
427
+ const normalizedFilters = normalizeObjectKeys(filters);
428
+
429
+ return Object.keys(normalizedFilters).some(key => {
430
+ const [rawField] = key.split(':');
431
+ const value = normalizedFilters[key];
432
+ if (rawField === fieldName) return matchesLeaf(value);
433
+ if (key === '$and' || key === '$or') {
434
+ return Array.isArray(value) && value.some((nestedFilter: any) => this.someFilterLeaf(nestedFilter, fieldName, matchesLeaf));
435
+ }
436
+ return value && typeof value === 'object' && this.someFilterLeaf(value, fieldName, matchesLeaf);
437
+ });
438
+ }
439
+
440
+ private normalizeBooleanFilterValue(value: boolean | string | undefined): boolean | undefined {
441
+ if (value === undefined || value === null || value === '') return undefined;
442
+ if (typeof value === 'boolean') return value;
443
+ if (typeof value === 'string') {
444
+ const normalized = value.toLowerCase();
445
+ if (normalized === 'true') return true;
446
+ if (normalized === 'false') return false;
447
+ }
448
+ return undefined;
449
+ }
450
+
451
+ private filtersContainBooleanValue(filters: any, fieldName: string, expectedValue: boolean): boolean {
452
+ return this.someFilterLeaf(filters, fieldName, value => this.extractBooleanFilterValues(value).includes(expectedValue));
453
+ }
454
+
455
+ private extractBooleanFilterValues(filterValue: any): boolean[] {
456
+ if (filterValue === undefined || filterValue === null) return [];
457
+ const directValue = this.normalizeBooleanFilterValue(filterValue);
458
+ if (directValue !== undefined) return [directValue];
459
+ if (Array.isArray(filterValue)) {
460
+ return filterValue
461
+ .map(value => this.normalizeBooleanFilterValue(value))
462
+ .filter((value): value is boolean => value !== undefined);
463
+ }
464
+ if (typeof filterValue !== 'object') return [];
465
+
466
+ const normalizedValue = normalizeObjectKeys(filterValue);
467
+ return Object.keys(normalizedValue)
468
+ .filter(operator => operator === '$eq' || operator === '$in')
469
+ .flatMap(operator => this.extractBooleanFilterValues(normalizedValue[operator]));
470
+ }
471
+
472
+ private getVersionedRelationNames(model: ModelMetadata): string[] {
473
+ return model.fields
474
+ .filter(field => field.type === SolidFieldType.relation && field.relationType !== RelationType.oneToMany)
475
+ .map(field => field.name);
476
+ }
477
+
478
+ private wasFieldSubmitted(dto: any, field: FieldMetadata): boolean {
479
+ if (!dto) return false;
480
+ if (Object.prototype.hasOwnProperty.call(dto, field.name)) return true;
481
+ if (field.type !== SolidFieldType.relation) return false;
482
+ if (Object.prototype.hasOwnProperty.call(dto, `${field.name}Id`)) return true;
483
+ if (Object.prototype.hasOwnProperty.call(dto, `${field.name}Ids`)) return true;
484
+ if (Object.prototype.hasOwnProperty.call(dto, `${field.name}UserKey`)) return true;
485
+ if (Object.prototype.hasOwnProperty.call(dto, `${field.name}Command`)) return true;
486
+ if (field.relationCoModelFieldName) {
487
+ if (Object.prototype.hasOwnProperty.call(dto, `${field.relationCoModelFieldName}Ids`)) return true;
488
+ if (Object.prototype.hasOwnProperty.call(dto, `${field.relationCoModelFieldName}Command`)) return true;
489
+ }
490
+ return false;
491
+ }
492
+
493
+ private buildNewVersionPayload<T extends CommonEntity>(
494
+ repo: SolidBaseRepository<T>,
495
+ sourceEntity: T,
496
+ relationNames: string[],
497
+ ): any {
498
+ const newVersionPayload: any = {};
499
+ const excludedColumns = new Set([
500
+ 'id',
501
+ 'createdAt',
502
+ 'updatedAt',
503
+ 'deletedAt',
504
+ 'createdBy',
505
+ 'updatedBy',
506
+ 'publishedAt',
507
+ ...DRAFT_PUBLISH_VERSIONING_FIELD_NAMES,
508
+ ]);
509
+
510
+ repo.metadata.columns.forEach(column => {
511
+ if (!excludedColumns.has(column.propertyName)) {
512
+ newVersionPayload[column.propertyName] = sourceEntity[column.propertyName];
513
+ }
514
+ });
515
+
516
+ for (const relationName of relationNames) {
517
+ newVersionPayload[relationName] = sourceEntity[relationName];
518
+ }
519
+
520
+ return newVersionPayload;
521
+ }
522
+
523
+ private async cloneMediaForVersion<T extends CommonEntity>(
524
+ context: DraftPublishCrudContext<T>,
525
+ model: ModelMetadata,
526
+ sourceEntityId: number,
527
+ targetEntity: T,
528
+ files: Express.Multer.File[] = [],
529
+ entityManager?: EntityManager,
530
+ ): Promise<void> {
531
+ const mediaFields = model.fields.filter(field => field.type === SolidFieldType.mediaSingle || field.type === SolidFieldType.mediaMultiple);
532
+ if (mediaFields.length === 0) return;
533
+
534
+ const uploadedFieldNames = new Set(files.map(file => file.fieldname));
535
+ const clonableFieldIds = mediaFields
536
+ .filter(field => !uploadedFieldNames.has(field.name))
537
+ .map(field => field.id);
538
+ if (clonableFieldIds.length === 0) return;
539
+
540
+ const mediaRepository = (entityManager ?? context.getDatasourceDefaultEntityManager()).getRepository(Media);
541
+
542
+ // One query for every clonable media field instead of one query per field.
543
+ const sourceMedia = await mediaRepository.find({
544
+ where: {
545
+ entityId: sourceEntityId,
546
+ modelMetadata: { id: model.id },
547
+ fieldMetadata: { id: In(clonableFieldIds) },
548
+ } as any,
549
+ relations: {
550
+ modelMetadata: true,
551
+ mediaStorageProviderMetadata: true,
552
+ fieldMetadata: true,
553
+ } as any,
554
+ });
555
+ if (sourceMedia.length === 0) return;
556
+
557
+ // Reuse the same underlying file across versions instead of physically duplicating it
558
+ // in storage; MediaService.deletePhysicalFile guards against removing the file while
559
+ // another Media row still references it. Saved as a single batch instead of one insert
560
+ // per row.
561
+ const clonedMedia = sourceMedia.map(media => mediaRepository.create({
562
+ entityId: targetEntity.id,
563
+ relativeUri: media.relativeUri,
564
+ fileSize: media.fileSize,
565
+ mimeType: media.mimeType,
566
+ originalFileName: media.originalFileName,
567
+ modelMetadata: media.modelMetadata,
568
+ mediaStorageProviderMetadata: media.mediaStorageProviderMetadata,
569
+ fieldMetadata: media.fieldMetadata,
570
+ }));
571
+ await mediaRepository.save(clonedMedia);
572
+ }
573
+
574
+ private createPublishedVersionTracker(seed: number | string): string {
575
+ return `version:${seed}`;
576
+ }
577
+
578
+ private createTemporaryPublishedVersionTracker(): string {
579
+ return `version:pending:${Date.now()}:${Math.random().toString(36).slice(2)}`;
580
+ }
581
+ }
@@ -7,12 +7,13 @@ import { ComputedFieldMetadata, SolidRegistry } from 'src/helpers/solid-registry
7
7
  import { FieldMetadataRepository } from 'src/repository/field-metadata.repository';
8
8
  import { DataSource, Repository, SelectQueryBuilder } from 'typeorm';
9
9
  import { BasicFilterDto } from '../dtos/basic-filters.dto';
10
- import { CascadeType, ComputedFieldValueType, CreateFieldMetadataDto, DecryptWhenType, EncryptionType, MediaType, MSSQLType, PSQLType, RelationType, SelectionValueType, SolidFieldType } from '../dtos/create-field-metadata.dto';
10
+ import { CascadeType, ComputedFieldValueType, CreateFieldMetadataDto, DecryptWhenType, EncryptionType, MSSQLType, PSQLType, RelationType, SelectionValueType, SolidFieldType } from '../dtos/create-field-metadata.dto';
11
11
  import { SelectionDynamicQueryDto } from '../dtos/selection-dynamic-query.dto';
12
12
  import { UpdateFieldMetaDataDto } from '../dtos/update-field-metadata.dto';
13
13
  import { FieldMetadata } from '../entities/field-metadata.entity';
14
14
  import { ModelMetadata } from '../entities/model-metadata.entity';
15
15
  import { ISelectionProviderValues, MediaStorageProvider } from '../interfaces';
16
+ import { MEDIA_CATEGORIES } from '../constants/media-file-types';
16
17
  import { CrudHelperService } from './crud-helper.service';
17
18
  import { ERROR_MESSAGES } from 'src/constants/error-messages';
18
19
  import qs from 'qs';
@@ -414,7 +415,7 @@ export class FieldMetadataService implements OnApplicationBootstrap {
414
415
  encryptionTypes: enumToResponseArray(EncryptionType),
415
416
  ormType: ormFieldTypeForSolid,
416
417
  decryptWhenTypes: enumToResponseArray(DecryptWhenType),
417
- mediaTypes: enumToResponseArray(MediaType),
418
+ mediaTypes: MEDIA_CATEGORIES.map((value) => ({ label: value, value })),
418
419
  relationTypes: enumToResponseArray(RelationType),
419
420
  selectionDynamicProviders: sps,
420
421
  computedProviders: cps,
@@ -944,6 +945,7 @@ export class FieldMetadataService implements OnApplicationBootstrap {
944
945
  "isSystem",
945
946
  "mediaTypes",
946
947
  "mediaMaxSizeKb",
948
+ "mediaAllowedExtensions",
947
949
  "mediaStorageProviderId",
948
950
  "required",
949
951
  "unique",
@@ -965,6 +967,7 @@ export class FieldMetadataService implements OnApplicationBootstrap {
965
967
  "isSystem",
966
968
  "mediaTypes",
967
969
  "mediaMaxSizeKb",
970
+ "mediaAllowedExtensions",
968
971
  "mediaStorageProviderId",
969
972
  "required",
970
973
  "unique",