@solidstarters/solid-core 1.2.200 → 1.2.201

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 (371) hide show
  1. package/dist/commands/fixtures/fixtures-setup.command.d.ts +15 -0
  2. package/dist/commands/fixtures/fixtures-setup.command.d.ts.map +1 -0
  3. package/dist/commands/fixtures/fixtures-setup.command.js +58 -0
  4. package/dist/commands/fixtures/fixtures-setup.command.js.map +1 -0
  5. package/dist/commands/fixtures/fixtures-tear-down.command.d.ts +16 -0
  6. package/dist/commands/fixtures/fixtures-tear-down.command.d.ts.map +1 -0
  7. package/dist/commands/fixtures/fixtures-tear-down.command.js +59 -0
  8. package/dist/commands/fixtures/fixtures-tear-down.command.js.map +1 -0
  9. package/dist/commands/refresh-model.command.d.ts.map +1 -1
  10. package/dist/commands/refresh-model.command.js +4 -0
  11. package/dist/commands/refresh-model.command.js.map +1 -1
  12. package/dist/constants/error-messages.d.ts +2 -0
  13. package/dist/constants/error-messages.d.ts.map +1 -1
  14. package/dist/constants/error-messages.js +4 -0
  15. package/dist/constants/error-messages.js.map +1 -1
  16. package/dist/controllers/model-sequence.controller.d.ts +43 -0
  17. package/dist/controllers/model-sequence.controller.d.ts.map +1 -0
  18. package/dist/controllers/model-sequence.controller.js +179 -0
  19. package/dist/controllers/model-sequence.controller.js.map +1 -0
  20. package/dist/controllers/setting.controller.d.ts +1 -0
  21. package/dist/controllers/setting.controller.d.ts.map +1 -1
  22. package/dist/controllers/setting.controller.js +15 -0
  23. package/dist/controllers/setting.controller.js.map +1 -1
  24. package/dist/dtos/basic-filters.dto.d.ts +3 -1
  25. package/dist/dtos/basic-filters.dto.d.ts.map +1 -1
  26. package/dist/dtos/basic-filters.dto.js +8 -2
  27. package/dist/dtos/basic-filters.dto.js.map +1 -1
  28. package/dist/dtos/basic-group-filters.dto.d.ts +6 -0
  29. package/dist/dtos/basic-group-filters.dto.d.ts.map +1 -0
  30. package/dist/dtos/basic-group-filters.dto.js +46 -0
  31. package/dist/dtos/basic-group-filters.dto.js.map +1 -0
  32. package/dist/dtos/create-field-metadata.dto.js +2 -2
  33. package/dist/dtos/create-field-metadata.dto.js.map +1 -1
  34. package/dist/dtos/create-model-sequence.dto.d.ts +14 -0
  35. package/dist/dtos/create-model-sequence.dto.d.ts.map +1 -0
  36. package/dist/dtos/create-model-sequence.dto.js +90 -0
  37. package/dist/dtos/create-model-sequence.dto.js.map +1 -0
  38. package/dist/dtos/create-role-metadata.dto.d.ts.map +1 -1
  39. package/dist/dtos/create-role-metadata.dto.js +1 -0
  40. package/dist/dtos/create-role-metadata.dto.js.map +1 -1
  41. package/dist/dtos/get-mcp-url.dto.d.ts +5 -0
  42. package/dist/dtos/get-mcp-url.dto.d.ts.map +1 -0
  43. package/dist/dtos/get-mcp-url.dto.js +31 -0
  44. package/dist/dtos/get-mcp-url.dto.js.map +1 -0
  45. package/dist/dtos/resolve-s3-url.dto.d.ts +5 -5
  46. package/dist/dtos/resolve-s3-url.dto.d.ts.map +1 -1
  47. package/dist/dtos/resolve-s3-url.dto.js +7 -7
  48. package/dist/dtos/resolve-s3-url.dto.js.map +1 -1
  49. package/dist/dtos/update-model-sequence.dto.d.ts +15 -0
  50. package/dist/dtos/update-model-sequence.dto.d.ts.map +1 -0
  51. package/dist/dtos/update-model-sequence.dto.js +94 -0
  52. package/dist/dtos/update-model-sequence.dto.js.map +1 -0
  53. package/dist/entities/common.entity.d.ts.map +1 -1
  54. package/dist/entities/common.entity.js +1 -0
  55. package/dist/entities/common.entity.js.map +1 -1
  56. package/dist/entities/legacy-common.entity.d.ts.map +1 -1
  57. package/dist/entities/legacy-common.entity.js +1 -0
  58. package/dist/entities/legacy-common.entity.js.map +1 -1
  59. package/dist/entities/model-sequence.entity.d.ts +15 -0
  60. package/dist/entities/model-sequence.entity.d.ts.map +1 -0
  61. package/dist/entities/model-sequence.entity.js +67 -0
  62. package/dist/entities/model-sequence.entity.js.map +1 -0
  63. package/dist/helpers/field-crud-managers/BigIntFieldCrudManager.d.ts.map +1 -1
  64. package/dist/helpers/field-crud-managers/BigIntFieldCrudManager.js +13 -2
  65. package/dist/helpers/field-crud-managers/BigIntFieldCrudManager.js.map +1 -1
  66. package/dist/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.d.ts +0 -1
  67. package/dist/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.d.ts.map +1 -1
  68. package/dist/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.js +4 -9
  69. package/dist/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.js.map +1 -1
  70. package/dist/helpers/field-crud-managers/ManyToOneRelationFieldCrudManager.d.ts +0 -1
  71. package/dist/helpers/field-crud-managers/ManyToOneRelationFieldCrudManager.d.ts.map +1 -1
  72. package/dist/helpers/field-crud-managers/ManyToOneRelationFieldCrudManager.js +7 -8
  73. package/dist/helpers/field-crud-managers/ManyToOneRelationFieldCrudManager.js.map +1 -1
  74. package/dist/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.d.ts +0 -1
  75. package/dist/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.d.ts.map +1 -1
  76. package/dist/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.js +4 -9
  77. package/dist/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.js.map +1 -1
  78. package/dist/helpers/model-metadata-helper.service.d.ts.map +1 -1
  79. package/dist/helpers/model-metadata-helper.service.js +6 -2
  80. package/dist/helpers/model-metadata-helper.service.js.map +1 -1
  81. package/dist/helpers/module-metadata-helper.service.d.ts +1 -0
  82. package/dist/helpers/module-metadata-helper.service.d.ts.map +1 -1
  83. package/dist/helpers/module-metadata-helper.service.js +9 -0
  84. package/dist/helpers/module-metadata-helper.service.js.map +1 -1
  85. package/dist/helpers/module.helper.d.ts +1 -0
  86. package/dist/helpers/module.helper.d.ts.map +1 -1
  87. package/dist/helpers/module.helper.js +29 -3
  88. package/dist/helpers/module.helper.js.map +1 -1
  89. package/dist/helpers/solid-registry.d.ts +11 -0
  90. package/dist/helpers/solid-registry.d.ts.map +1 -1
  91. package/dist/helpers/solid-registry.js.map +1 -1
  92. package/dist/index.d.ts +3 -1
  93. package/dist/index.d.ts.map +1 -1
  94. package/dist/index.js +4 -2
  95. package/dist/index.js.map +1 -1
  96. package/dist/jobs/computed-field-evaluation-subscriber.service.d.ts +1 -0
  97. package/dist/jobs/computed-field-evaluation-subscriber.service.d.ts.map +1 -1
  98. package/dist/jobs/computed-field-evaluation-subscriber.service.js +16 -4
  99. package/dist/jobs/computed-field-evaluation-subscriber.service.js.map +1 -1
  100. package/dist/repository/media.repository.d.ts.map +1 -1
  101. package/dist/repository/media.repository.js +4 -0
  102. package/dist/repository/media.repository.js.map +1 -1
  103. package/dist/repository/model-sequence.repository.d.ts +14 -0
  104. package/dist/repository/model-sequence.repository.d.ts.map +1 -0
  105. package/dist/repository/model-sequence.repository.js +103 -0
  106. package/dist/repository/model-sequence.repository.js.map +1 -0
  107. package/dist/seeders/module-metadata-seeder.service.d.ts +7 -12
  108. package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
  109. package/dist/seeders/module-metadata-seeder.service.js +64 -26
  110. package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
  111. package/dist/seeders/seed-data/solid-core-metadata.json +343 -27
  112. package/dist/seeders/system-fields-seeder.service.d.ts +1 -0
  113. package/dist/seeders/system-fields-seeder.service.d.ts.map +1 -1
  114. package/dist/seeders/system-fields-seeder.service.js +11 -2
  115. package/dist/seeders/system-fields-seeder.service.js.map +1 -1
  116. package/dist/services/action-metadata.service.d.ts.map +1 -1
  117. package/dist/services/action-metadata.service.js +1 -0
  118. package/dist/services/action-metadata.service.js.map +1 -1
  119. package/dist/services/ai-interaction.service.d.ts.map +1 -1
  120. package/dist/services/ai-interaction.service.js +1 -0
  121. package/dist/services/ai-interaction.service.js.map +1 -1
  122. package/dist/services/authentication.service.d.ts.map +1 -1
  123. package/dist/services/authentication.service.js +22 -14
  124. package/dist/services/authentication.service.js.map +1 -1
  125. package/dist/services/chatter-message-details.service.d.ts.map +1 -1
  126. package/dist/services/chatter-message-details.service.js +1 -0
  127. package/dist/services/chatter-message-details.service.js.map +1 -1
  128. package/dist/services/chatter-message.service.d.ts.map +1 -1
  129. package/dist/services/chatter-message.service.js +7 -3
  130. package/dist/services/chatter-message.service.js.map +1 -1
  131. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.d.ts.map +1 -1
  132. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js +7 -5
  133. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js.map +1 -1
  134. package/dist/services/computed-fields/entity/sequence-num-computed-field-provider.d.ts +15 -0
  135. package/dist/services/computed-fields/entity/sequence-num-computed-field-provider.d.ts.map +1 -0
  136. package/dist/services/computed-fields/entity/sequence-num-computed-field-provider.js +72 -0
  137. package/dist/services/computed-fields/entity/sequence-num-computed-field-provider.js.map +1 -0
  138. package/dist/services/crud-helper.service.d.ts +23 -6
  139. package/dist/services/crud-helper.service.d.ts.map +1 -1
  140. package/dist/services/crud-helper.service.js +257 -45
  141. package/dist/services/crud-helper.service.js.map +1 -1
  142. package/dist/services/crud.service.d.ts +3 -1
  143. package/dist/services/crud.service.d.ts.map +1 -1
  144. package/dist/services/crud.service.js +53 -24
  145. package/dist/services/crud.service.js.map +1 -1
  146. package/dist/services/database/database-bootstrap.service.d.ts +12 -0
  147. package/dist/services/database/database-bootstrap.service.d.ts.map +1 -0
  148. package/dist/services/database/database-bootstrap.service.js +115 -0
  149. package/dist/services/database/database-bootstrap.service.js.map +1 -0
  150. package/dist/services/email-template.service.d.ts +7 -7
  151. package/dist/services/email-template.service.d.ts.map +1 -1
  152. package/dist/services/email-template.service.js +8 -7
  153. package/dist/services/email-template.service.js.map +1 -1
  154. package/dist/services/excel.service.d.ts +10 -0
  155. package/dist/services/excel.service.d.ts.map +1 -1
  156. package/dist/services/excel.service.js +100 -0
  157. package/dist/services/excel.service.js.map +1 -1
  158. package/dist/services/field-metadata.service.d.ts +4 -1
  159. package/dist/services/field-metadata.service.d.ts.map +1 -1
  160. package/dist/services/field-metadata.service.js +35 -30
  161. package/dist/services/field-metadata.service.js.map +1 -1
  162. package/dist/services/file.service.d.ts +1 -0
  163. package/dist/services/file.service.d.ts.map +1 -1
  164. package/dist/services/file.service.js +9 -0
  165. package/dist/services/file.service.js.map +1 -1
  166. package/dist/services/fixtures.service.d.ts +13 -0
  167. package/dist/services/fixtures.service.d.ts.map +1 -0
  168. package/dist/services/fixtures.service.js +95 -0
  169. package/dist/services/fixtures.service.js.map +1 -0
  170. package/dist/services/genai/ingest-metadata.service.d.ts.map +1 -1
  171. package/dist/services/genai/ingest-metadata.service.js +1 -1
  172. package/dist/services/genai/ingest-metadata.service.js.map +1 -1
  173. package/dist/services/import-transaction-error-log.service.d.ts.map +1 -1
  174. package/dist/services/import-transaction-error-log.service.js +1 -0
  175. package/dist/services/import-transaction-error-log.service.js.map +1 -1
  176. package/dist/services/import-transaction.service.d.ts.map +1 -1
  177. package/dist/services/import-transaction.service.js +7 -1
  178. package/dist/services/import-transaction.service.js.map +1 -1
  179. package/dist/services/list-of-values.service.d.ts +2 -2
  180. package/dist/services/list-of-values.service.d.ts.map +1 -1
  181. package/dist/services/list-of-values.service.js +2 -1
  182. package/dist/services/list-of-values.service.js.map +1 -1
  183. package/dist/services/locale.service.d.ts.map +1 -1
  184. package/dist/services/locale.service.js +1 -0
  185. package/dist/services/locale.service.js.map +1 -1
  186. package/dist/services/mail/smtp-email.service.js +0 -1
  187. package/dist/services/mail/smtp-email.service.js.map +1 -1
  188. package/dist/services/media.service.d.ts +3 -3
  189. package/dist/services/media.service.d.ts.map +1 -1
  190. package/dist/services/media.service.js +6 -4
  191. package/dist/services/media.service.js.map +1 -1
  192. package/dist/services/mediaStorageProviders/file-s3-storage-provider.d.ts.map +1 -1
  193. package/dist/services/mediaStorageProviders/file-s3-storage-provider.js +17 -6
  194. package/dist/services/mediaStorageProviders/file-s3-storage-provider.js.map +1 -1
  195. package/dist/services/mediaStorageProviders/file-storage-provider.d.ts.map +1 -1
  196. package/dist/services/mediaStorageProviders/file-storage-provider.js +0 -13
  197. package/dist/services/mediaStorageProviders/file-storage-provider.js.map +1 -1
  198. package/dist/services/menu-item-metadata.service.d.ts.map +1 -1
  199. package/dist/services/menu-item-metadata.service.js +4 -0
  200. package/dist/services/menu-item-metadata.service.js.map +1 -1
  201. package/dist/services/model-metadata.service.d.ts.map +1 -1
  202. package/dist/services/model-metadata.service.js +2 -42
  203. package/dist/services/model-metadata.service.js.map +1 -1
  204. package/dist/services/model-sequence.service.d.ts +23 -0
  205. package/dist/services/model-sequence.service.d.ts.map +1 -0
  206. package/dist/services/model-sequence.service.js +55 -0
  207. package/dist/services/model-sequence.service.js.map +1 -0
  208. package/dist/services/module-metadata.service.d.ts +1 -0
  209. package/dist/services/module-metadata.service.d.ts.map +1 -1
  210. package/dist/services/module-metadata.service.js +35 -1
  211. package/dist/services/module-metadata.service.js.map +1 -1
  212. package/dist/services/permission-metadata.service.d.ts +5 -5
  213. package/dist/services/permission-metadata.service.d.ts.map +1 -1
  214. package/dist/services/permission-metadata.service.js +6 -5
  215. package/dist/services/permission-metadata.service.js.map +1 -1
  216. package/dist/services/queues/database-subscriber.service.d.ts.map +1 -1
  217. package/dist/services/queues/database-subscriber.service.js +2 -1
  218. package/dist/services/queues/database-subscriber.service.js.map +1 -1
  219. package/dist/services/queues/rabbitmq-subscriber.service.d.ts.map +1 -1
  220. package/dist/services/queues/rabbitmq-subscriber.service.js +2 -2
  221. package/dist/services/queues/rabbitmq-subscriber.service.js.map +1 -1
  222. package/dist/services/role-metadata.service.d.ts.map +1 -1
  223. package/dist/services/role-metadata.service.js +1 -0
  224. package/dist/services/role-metadata.service.js.map +1 -1
  225. package/dist/services/scheduled-job.service.d.ts +6 -6
  226. package/dist/services/scheduled-job.service.d.ts.map +1 -1
  227. package/dist/services/scheduled-job.service.js +8 -8
  228. package/dist/services/scheduled-job.service.js.map +1 -1
  229. package/dist/services/scheduled-jobs/scheduler.service.d.ts.map +1 -1
  230. package/dist/services/scheduled-jobs/scheduler.service.js +4 -0
  231. package/dist/services/scheduled-jobs/scheduler.service.js.map +1 -1
  232. package/dist/services/security-rule.service.d.ts.map +1 -1
  233. package/dist/services/security-rule.service.js +1 -0
  234. package/dist/services/security-rule.service.js.map +1 -1
  235. package/dist/services/selection-providers/list-of-models-selection-provider.service.d.ts.map +1 -1
  236. package/dist/services/selection-providers/list-of-models-selection-provider.service.js +4 -0
  237. package/dist/services/selection-providers/list-of-models-selection-provider.service.js.map +1 -1
  238. package/dist/services/setting.service.d.ts +7 -5
  239. package/dist/services/setting.service.d.ts.map +1 -1
  240. package/dist/services/setting.service.js +26 -4
  241. package/dist/services/setting.service.js.map +1 -1
  242. package/dist/services/sms-template.service.d.ts +7 -7
  243. package/dist/services/sms-template.service.d.ts.map +1 -1
  244. package/dist/services/sms-template.service.js +8 -7
  245. package/dist/services/sms-template.service.js.map +1 -1
  246. package/dist/services/solid-introspect.service.d.ts +4 -13
  247. package/dist/services/solid-introspect.service.d.ts.map +1 -1
  248. package/dist/services/solid-introspect.service.js +4 -22
  249. package/dist/services/solid-introspect.service.js.map +1 -1
  250. package/dist/services/solid-ts-morph.service.js +2 -2
  251. package/dist/services/solid-ts-morph.service.js.map +1 -1
  252. package/dist/services/user-activity-history.service.d.ts.map +1 -1
  253. package/dist/services/user-activity-history.service.js +1 -0
  254. package/dist/services/user-activity-history.service.js.map +1 -1
  255. package/dist/services/user-view-metadata.service.d.ts.map +1 -1
  256. package/dist/services/user-view-metadata.service.js +3 -2
  257. package/dist/services/user-view-metadata.service.js.map +1 -1
  258. package/dist/services/user.service.d.ts.map +1 -1
  259. package/dist/services/user.service.js +1 -0
  260. package/dist/services/user.service.js.map +1 -1
  261. package/dist/services/view-metadata.service.d.ts +1 -1
  262. package/dist/services/view-metadata.service.d.ts.map +1 -1
  263. package/dist/services/view-metadata.service.js +3 -1
  264. package/dist/services/view-metadata.service.js.map +1 -1
  265. package/dist/solid-core-cli-db.module.d.ts.map +1 -1
  266. package/dist/solid-core-cli-db.module.js +5 -2
  267. package/dist/solid-core-cli-db.module.js.map +1 -1
  268. package/dist/solid-core.module.d.ts.map +1 -1
  269. package/dist/solid-core.module.js +18 -0
  270. package/dist/solid-core.module.js.map +1 -1
  271. package/dist/subscribers/audit.subscriber.d.ts.map +1 -1
  272. package/dist/subscribers/audit.subscriber.js +5 -1
  273. package/dist/subscribers/audit.subscriber.js.map +1 -1
  274. package/dist/subscribers/computed-entity-field.subscriber.d.ts +4 -2
  275. package/dist/subscribers/computed-entity-field.subscriber.d.ts.map +1 -1
  276. package/dist/subscribers/computed-entity-field.subscriber.js +53 -12
  277. package/dist/subscribers/computed-entity-field.subscriber.js.map +1 -1
  278. package/dist/transformers/typeorm/local-date-time-transformer.d.ts +5 -0
  279. package/dist/transformers/typeorm/local-date-time-transformer.d.ts.map +1 -0
  280. package/dist/transformers/typeorm/local-date-time-transformer.js +26 -0
  281. package/dist/transformers/typeorm/local-date-time-transformer.js.map +1 -0
  282. package/dist/tsconfig.tsbuildinfo +1 -1
  283. package/docs/grouping-enhancements.md +89 -0
  284. package/package.json +1 -1
  285. package/src/commands/fixtures/fixtures-setup.command.ts +44 -0
  286. package/src/commands/fixtures/fixtures-tear-down.command.ts +45 -0
  287. package/src/commands/refresh-model.command.ts +3 -1
  288. package/src/constants/error-messages.ts +7 -1
  289. package/src/controllers/model-sequence.controller.ts +93 -0
  290. package/src/controllers/setting.controller.ts +33 -21
  291. package/src/dtos/basic-filters.dto.ts +6 -1
  292. package/src/dtos/basic-group-filters.dto.ts +23 -0
  293. package/src/dtos/create-field-metadata.dto.ts +1 -1
  294. package/src/dtos/create-model-sequence.dto.ts +51 -0
  295. package/src/dtos/create-role-metadata.dto.ts +16 -3
  296. package/src/dtos/get-mcp-url.dto.ts +13 -0
  297. package/src/dtos/resolve-s3-url.dto.ts +9 -11
  298. package/src/dtos/update-model-sequence.dto.ts +53 -0
  299. package/src/entities/common.entity.ts +2 -2
  300. package/src/entities/legacy-common.entity.ts +2 -1
  301. package/src/entities/model-sequence.entity.ts +32 -0
  302. package/src/helpers/field-crud-managers/BigIntFieldCrudManager.ts +18 -5
  303. package/src/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.ts +9 -9
  304. package/src/helpers/field-crud-managers/ManyToOneRelationFieldCrudManager.ts +16 -8
  305. package/src/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.ts +9 -9
  306. package/src/helpers/model-metadata-helper.service.ts +6 -4
  307. package/src/helpers/module-metadata-helper.service.ts +18 -1
  308. package/src/helpers/module.helper.ts +40 -5
  309. package/src/helpers/solid-registry.ts +14 -0
  310. package/src/index.ts +3 -1
  311. package/src/jobs/computed-field-evaluation-subscriber.service.ts +15 -4
  312. package/src/repository/media.repository.ts +3 -2
  313. package/src/repository/model-sequence.repository.ts +97 -0
  314. package/src/seeders/module-metadata-seeder.service.ts +103 -29
  315. package/src/seeders/seed-data/solid-core-metadata.json +343 -27
  316. package/src/seeders/system-fields-seeder.service.ts +6 -2
  317. package/src/services/action-metadata.service.ts +3 -2
  318. package/src/services/ai-interaction.service.ts +2 -1
  319. package/src/services/authentication.service.ts +46 -14
  320. package/src/services/chatter-message-details.service.ts +2 -1
  321. package/src/services/chatter-message.service.ts +10 -4
  322. package/src/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.ts +8 -7
  323. package/src/services/computed-fields/entity/sequence-num-computed-field-provider.ts +86 -0
  324. package/src/services/crud-helper.service.ts +287 -49
  325. package/src/services/crud.service.ts +83 -32
  326. package/src/services/database/database-bootstrap.service.ts +91 -0
  327. package/src/services/email-template.service.ts +11 -13
  328. package/src/services/excel.service.ts +146 -3
  329. package/src/services/field-metadata.service.ts +102 -55
  330. package/src/services/file.service.ts +9 -0
  331. package/src/services/fixtures.service.ts +108 -0
  332. package/src/services/genai/ingest-metadata.service.ts +4 -3
  333. package/src/services/import-transaction-error-log.service.ts +2 -1
  334. package/src/services/import-transaction.service.ts +8 -4
  335. package/src/services/list-of-values.service.ts +4 -4
  336. package/src/services/locale.service.ts +2 -1
  337. package/src/services/mail/smtp-email.service.ts +1 -1
  338. package/src/services/media.service.ts +10 -11
  339. package/src/services/mediaStorageProviders/file-s3-storage-provider.ts +22 -7
  340. package/src/services/mediaStorageProviders/file-storage-provider.ts +18 -13
  341. package/src/services/menu-item-metadata.service.ts +6 -2
  342. package/src/services/model-metadata.service.ts +50 -44
  343. package/src/services/model-sequence.service.ts +33 -0
  344. package/src/services/module-metadata.service.ts +49 -2
  345. package/src/services/permission-metadata.service.ts +8 -9
  346. package/src/services/queues/database-subscriber.service.ts +3 -1
  347. package/src/services/queues/rabbitmq-subscriber.service.ts +4 -2
  348. package/src/services/role-metadata.service.ts +1 -0
  349. package/src/services/scheduled-job.service.ts +9 -9
  350. package/src/services/scheduled-jobs/scheduler.service.ts +5 -0
  351. package/src/services/security-rule.service.ts +1 -0
  352. package/src/services/selection-providers/list-of-models-selection-provider.service.ts +5 -2
  353. package/src/services/setting.service.ts +33 -6
  354. package/src/services/sms-template.service.ts +11 -13
  355. package/src/services/solid-introspect.service.ts +6 -19
  356. package/src/services/solid-ts-morph.service.ts +2 -2
  357. package/src/services/user-activity-history.service.ts +3 -2
  358. package/src/services/user-view-metadata.service.ts +4 -3
  359. package/src/services/user.service.ts +2 -1
  360. package/src/services/view-metadata.service.ts +5 -4
  361. package/src/solid-core-cli-db.module.ts +5 -4
  362. package/src/solid-core.module.ts +18 -0
  363. package/src/subscribers/audit.subscriber.ts +3 -2
  364. package/src/subscribers/computed-entity-field.subscriber.ts +60 -17
  365. package/src/transformers/typeorm/local-date-time-transformer.ts +30 -0
  366. /package/sql/{mssql → default/mssql}/proc_CleanupModelMetadata.sql +0 -0
  367. /package/sql/{mssql → default/mssql}/proc_CleanupModuleMetadata.sql +0 -0
  368. /package/sql/{mssql/scratchpad.sql → default/mssql/scratchpad.sql.txt} +0 -0
  369. /package/sql/{postgres → default/postgres}/proc_CleanupModelMetadata.sql +0 -0
  370. /package/sql/{postgres → default/postgres}/proc_CleanupModuleMetadata.sql +0 -0
  371. /package/sql/{postgres/scratchpad.sql → default/postgres/scratchpad.sql.txt} +0 -0
@@ -1,4 +1,4 @@
1
- import { BadRequestException, NotFoundException } from "@nestjs/common";
1
+ import { BadRequestException, Inject, 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";
@@ -33,13 +33,14 @@ 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, UserIdFields } from "./crud-helper.service";
36
+ import { CrudHelperService, FilterCombinator, 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";
40
40
  import { ModelMetadataService } from "./model-metadata.service";
41
41
  import { ModuleMetadataService } from "./module-metadata.service";
42
42
  import { RequestContextService } from "./request-context.service";
43
+ import { BasicGroupFilterDto } from "src/dtos/basic-group-filters.dto";
43
44
 
44
45
  export class CRUDService<T extends CommonEntity> { // Add two generic value i.e Person,CreatePersonDto, so we get the proper types in our service
45
46
 
@@ -55,6 +56,8 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
55
56
  readonly modelName: string,
56
57
  readonly moduleName: string,
57
58
  readonly moduleRef: ModuleRef,
59
+ readonly defaultEntityManager? : EntityManager
60
+
58
61
  //We can just have the Model Entity here
59
62
  ) { }
60
63
 
@@ -182,7 +185,12 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
182
185
  throw new BadRequestException(`Cannot update a published record for model ${this.modelName}. Unpublish it first.`
183
186
  );
184
187
  }
185
- updateDto.id = id;
188
+
189
+ // // In some instances for legacy tables sometimes id is mapped as a bigint.
190
+ // // in these cases the update method ends up attempting to insert records due to some type orm type mismatch issue.
191
+ // const idFieldMetadata = model.fields.find(f => f.name === 'id');
192
+ // updateDto.id = idFieldMetadata?.type === 'bigint' ? BigInt(id) : id;
193
+
186
194
  // This class will be extended by the generated service class i.e PersonService
187
195
  // The data required to identify the model and module name will be passed from the generate CrudService subclass
188
196
  //TODO: Algorithm to create the entity
@@ -455,19 +463,34 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
455
463
 
456
464
  // Create above query on pincode table using query builder
457
465
  var qb: SelectQueryBuilder<T> = await this.repo.createSecurityRuleAwareQueryBuilder(alias)
458
- // qb = this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias);
459
- if (internationalisation && draftPublishWorkflow) {
460
- qb = this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias, internationalisation, draftPublishWorkflow, this.moduleRef);
461
- }
462
- else {
463
- qb = this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias);
464
- }
465
466
 
466
467
  if (basicFilterDto.groupBy) {
467
- // Get the records and the count
468
- const { groupMeta, groupRecords } = await this.handleGroupFind(qb, groupFilter, populateGroup, alias, populateUserIdFields, populateMedia);
469
- const totalGroups = await this.crudHelperService.countGroupedRecords(qb, basicFilterDto, alias);
470
- // qb = this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias);
468
+ const groupFilterQb = (internationalisation && draftPublishWorkflow)
469
+ ? this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias, internationalisation, draftPublishWorkflow, this.moduleRef, FilterCombinator.AND, false, false)
470
+ : this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias, undefined, undefined, undefined, FilterCombinator.AND, false, false);
471
+
472
+ const groupByFields = this.crudHelperService.normalize(basicFilterDto.groupBy);
473
+ if (!groupByFields.length) {
474
+ throw new BadRequestException(ERROR_MESSAGES.INVALID_GROUP_BY_COUNT);
475
+ }
476
+
477
+ if (basicFilterDto.populateGroup) {
478
+ const hasRelationGroup = groupByFields.some(field => field.includes('.'));
479
+ if (hasRelationGroup) {
480
+ throw new BadRequestException('populateGroup is not supported when grouping on relation fields. Fetch group metadata first and retrieve records in a separate call.');
481
+ }
482
+ }
483
+
484
+ const { aliasMap: groupAliasMap, formatMap: groupFormatMap, expressionMap: groupExpressionMap } = this.crudHelperService.applyGroupBySelections(groupFilterQb, groupByFields, alias);
485
+ const aggregateAliasMap = this.crudHelperService.applyAggregates(groupFilterQb, basicFilterDto.aggregates, alias);
486
+ const sortAliasMap = { ...groupAliasMap, ...aggregateAliasMap };
487
+ this.crudHelperService.applyGroupSortingAndPagination(groupFilterQb, basicFilterDto.sort, sortAliasMap, limit, offset);
488
+
489
+ const groupByResult = await groupFilterQb.getRawMany();
490
+ const totalGroups = await this.crudHelperService.countGroups(groupFilterQb);
491
+
492
+ const groupByFieldsOrdered = this.crudHelperService.normalize(basicFilterDto.groupBy || []);
493
+ const { groupMeta, groupRecords } = await this.handleGroupFind(groupByResult, groupFilter, populateGroup, alias, populateUserIdFields, populateMedia, basicFilterDto, groupAliasMap, aggregateAliasMap, groupByFieldsOrdered, groupFormatMap, groupExpressionMap);
471
494
 
472
495
  return {
473
496
  meta: {
@@ -478,7 +501,9 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
478
501
  }
479
502
  }
480
503
  else {
481
- // Get the records and the count
504
+ qb = (internationalisation && draftPublishWorkflow)
505
+ ? this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias, internationalisation, draftPublishWorkflow, this.moduleRef)
506
+ : this.crudHelperService.buildFilterQuery(qb, basicFilterDto, alias);
482
507
  const { meta, records } = await this.handleNonGroupFind(qb, populateUserIdFields, populateMedia, offset, limit, alias);
483
508
  return {
484
509
  meta,
@@ -503,17 +528,38 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
503
528
  return this.wrapFindResponse(offset, limit, count, entities);
504
529
  }
505
530
 
506
- private async handleGroupFind(qb: SelectQueryBuilder<T>, groupFilter: BasicFilterDto, populateGroup: boolean, alias: string, populateUserIdFields: UserIdFields[], populateMedia: string[]) {
507
- const groupByResult = await qb.getRawMany();
508
-
531
+ private async handleGroupFind(
532
+ groupByResult: any[],
533
+ groupFilter: BasicGroupFilterDto | undefined,
534
+ populateGroup: boolean,
535
+ alias: string,
536
+ populateUserIdFields: UserIdFields[],
537
+ populateMedia: string[],
538
+ baseFilterDto: BasicFilterDto,
539
+ groupAliasMap: Record<string, string>,
540
+ aggregateAliasMap: Record<string, string>,
541
+ groupByFieldsOrdered: string[],
542
+ groupFormatMap: Record<string, string | undefined>,
543
+ groupExpressionMap: Record<string, string>
544
+ ) {
509
545
  const groupMeta = [];
510
546
  const groupRecords = [];
547
+ const aggregateAliasSet = new Set(Object.values(aggregateAliasMap));
511
548
  // For each group, get the records and the count
512
549
  for (const group of groupByResult) {
513
550
  if (populateGroup) {
514
551
  let groupByQb: SelectQueryBuilder<T> = await this.repo.createSecurityRuleAwareQueryBuilder(alias);
515
- groupByQb = this.crudHelperService.buildFilterQuery(groupByQb, groupFilter, alias);
516
- groupByQb = this.crudHelperService.buildGroupByRecordsQuery(groupByQb, group, alias);
552
+ const groupFilterDto: BasicFilterDto = {
553
+ ...baseFilterDto,
554
+ ...groupFilter,
555
+ groupBy: undefined,
556
+ aggregates: undefined,
557
+ // Only use explicit groupFilter.sort for record ordering; group-level sorts can contain
558
+ // group expressions (e.g. createdAt:day) that are invalid on record queries.
559
+ sort: groupFilter?.sort,
560
+ };
561
+ groupByQb = this.crudHelperService.buildFilterQuery(groupByQb, groupFilterDto, alias);
562
+ groupByQb = this.crudHelperService.buildGroupByRecordsQuery(groupByQb, group, alias, groupAliasMap, aggregateAliasMap, groupExpressionMap);
517
563
  const [entities, count] = await groupByQb.getManyAndCount();
518
564
 
519
565
  // Populate the entity with the userId fields
@@ -525,20 +571,22 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
525
571
  if (populateMedia && populateMedia.length > 0) {
526
572
  await this.handlePopulateMedia(populateMedia, entities);
527
573
  }
528
- const groupData = this.wrapFindResponse(groupFilter.offset, groupFilter.limit, count, entities);
529
- groupRecords.push(this.crudHelperService.createGroupRecords(group, alias, groupData));
574
+ const groupData = this.wrapFindResponse(groupFilter?.offset, groupFilter?.limit, count, entities);
575
+ groupRecords.push(this.crudHelperService.createGroupRecords(group, aggregateAliasSet, groupData, groupByFieldsOrdered, groupAliasMap, groupFormatMap));
530
576
  }
531
- groupMeta.push(this.crudHelperService.createGroupMeta(group, alias));
577
+ groupMeta.push(this.crudHelperService.createGroupMeta(group, aggregateAliasSet, groupByFieldsOrdered, groupAliasMap, groupFormatMap));
532
578
  }
533
579
  return { groupMeta, groupRecords };
534
580
  }
535
581
 
536
- private wrapFindResponse(offset: number, limit: number, count: number, entities: T[]) {
537
- const currentPage = Math.floor(offset / limit) + 1;
538
- const totalPages = Math.ceil(count / limit);
582
+ private wrapFindResponse(offset: number | undefined, limit: number | undefined, count: number, entities: T[]) {
583
+ const safeLimit = limit ?? count ?? 0;
584
+ const safeOffset = offset ?? 0;
585
+ const currentPage = safeLimit ? Math.floor(safeOffset / safeLimit) + 1 : 1;
586
+ const totalPages = safeLimit ? Math.ceil(count / safeLimit) : 1;
539
587
 
540
- const nextPage = currentPage < totalPages ? currentPage + 1 : null;
541
- const prevPage = currentPage > 1 ? currentPage - 1 : null;
588
+ const nextPage = safeLimit && currentPage < totalPages ? currentPage + 1 : null;
589
+ const prevPage = safeLimit && currentPage > 1 ? currentPage - 1 : null;
542
590
 
543
591
  const r = {
544
592
  meta: {
@@ -547,7 +595,7 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
547
595
  nextPage: nextPage,
548
596
  prevPage: prevPage,
549
597
  totalPages: totalPages,
550
- perPage: +limit,
598
+ perPage: safeLimit ? +safeLimit : 0,
551
599
  },
552
600
  records: entities
553
601
  };
@@ -574,7 +622,7 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
574
622
  }
575
623
 
576
624
  private async handlePopulateMedia(populateMedia: string[], entities: T[]) {
577
- const model = await this.entityManager.getRepository(ModelMetadata).findOne({
625
+ const model = await this.getDefaultEntityManager().getRepository(ModelMetadata).findOne({
578
626
  where: {
579
627
  singularName: this.modelName,
580
628
  },
@@ -913,7 +961,7 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
913
961
  throw new BadRequestException(`Field ${field.name} does not define a relationCoModelSingularName`);
914
962
  }
915
963
 
916
- const relationCoModel = await this.entityManager.getRepository(ModelMetadata).findOne({
964
+ const relationCoModel = await this.getDefaultEntityManager().getRepository(ModelMetadata).findOne({
917
965
  where: { singularName: field.relationCoModelSingularName },
918
966
  relations: ['fields', 'fields.mediaStorageProvider', 'fields.model'],
919
967
  });
@@ -1016,5 +1064,8 @@ export class CRUDService<T extends CommonEntity> { // Add two generic value i.e
1016
1064
 
1017
1065
  return updatedEntity
1018
1066
  }
1019
- }
1020
1067
 
1068
+ private getDefaultEntityManager(){
1069
+ return this.defaultEntityManager ?? this.entityManager;
1070
+ }
1071
+ }
@@ -0,0 +1,91 @@
1
+ import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
2
+ import { DataSource } from 'typeorm';
3
+ import { readdir, readFile } from 'fs/promises';
4
+ import * as path from 'path';
5
+ import { InjectDataSource } from '@nestjs/typeorm';
6
+
7
+ @Injectable()
8
+ export class DatabaseBootstrapService implements OnModuleInit {
9
+ private readonly logger = new Logger(DatabaseBootstrapService.name);
10
+
11
+ constructor(
12
+ @InjectDataSource()
13
+ private readonly dataSource: DataSource,
14
+ ) { }
15
+
16
+ async onModuleInit() {
17
+ if (!this.dataSource.isInitialized) {
18
+ this.logger.warn(`[${this.dataSource.name}] DataSource not initialized. Skipping SQL bootstrap.`);
19
+ return;
20
+ }
21
+
22
+ this.logger.debug(`[${this.dataSource.name}] Bootstrapping stored procedures...`);
23
+
24
+ await this.applyAllSqlFiles();
25
+
26
+ this.logger.debug(`[${this.dataSource.name}] SQL bootstrap completed`);
27
+ }
28
+
29
+ private resolveSqlDirectory(): string {
30
+ const datasourceName = this.dataSource.name || 'default';
31
+ const dbType = this.dataSource.options.type;
32
+
33
+ const sqlFilePath = path.resolve(__dirname, `../../../sql/${datasourceName}/${dbType}`);
34
+
35
+ return sqlFilePath
36
+ }
37
+
38
+ private async applyAllSqlFiles() {
39
+ const sqlDir = this.resolveSqlDirectory();
40
+
41
+ this.logger.debug(`[${this.dataSource.name}] SQL directory: ${sqlDir}`);
42
+
43
+ let files: string[];
44
+ try {
45
+ files = await readdir(sqlDir);
46
+ } catch {
47
+ this.logger.warn(
48
+ `[${this.dataSource.name}] No SQL directory found. Skipping.`,
49
+ );
50
+ return;
51
+ }
52
+
53
+ const sqlFiles = files
54
+ .filter(file => file.endsWith('.sql'))
55
+ .sort();
56
+
57
+ if (!sqlFiles.length) {
58
+ this.logger.warn(
59
+ `[${this.dataSource.name}] No SQL files found`,
60
+ );
61
+ return;
62
+ }
63
+
64
+ for (const file of sqlFiles) {
65
+ await this.applySqlFileSafely(
66
+ path.join(sqlDir, file),
67
+ file,
68
+ );
69
+ }
70
+ }
71
+
72
+ private async applySqlFileSafely(
73
+ filePath: string,
74
+ fileName: string,
75
+ ) {
76
+ this.logger.debug(`[${this.dataSource.name}] Applying ${fileName}`);
77
+
78
+ try {
79
+ const sql = await readFile(filePath, 'utf8');
80
+ await this.dataSource.query(sql);
81
+
82
+ this.logger.debug(`[${this.dataSource.name}] Applied ${fileName}`);
83
+ } catch (error) {
84
+ // DO NOT THROW — continue with next file
85
+ this.logger.error(
86
+ `[${this.dataSource.name}] Failed ${fileName}`,
87
+ error instanceof Error ? error.stack : String(error),
88
+ );
89
+ }
90
+ }
91
+ }
@@ -1,25 +1,23 @@
1
- import { Injectable, NotFoundException } from '@nestjs/common';
1
+ import { forwardRef, Inject, Injectable } from '@nestjs/common';
2
2
 
3
- import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm';
4
- import { EntityManager, Repository } from 'typeorm';
5
- import { PaginationQueryDto } from 'src/dtos/pagination-query.dto';
3
+ import { ConfigService } from '@nestjs/config';
4
+ import { DiscoveryService, ModuleRef } from '@nestjs/core';
5
+ import { InjectEntityManager } from '@nestjs/typeorm';
6
+ import { EmailTemplateRepository } from 'src/repository/email-template.repository';
7
+ import { EntityManager } from 'typeorm';
6
8
  import { EmailTemplate } from '../entities/email-template.entity';
7
- import { CreateEmailTemplateDto } from '../dtos/create-email-template.dto';
8
- import { UpdateEmailTemplateDto } from '../dtos/update-email-template.dto';
9
+ import { CrudHelperService } from './crud-helper.service';
9
10
  import { CRUDService } from './crud.service';
10
- import { ModelMetadataService } from './model-metadata.service';
11
- import { ModuleMetadataService } from './module-metadata.service';
12
- import { MediaStorageProviderMetadataService } from './media-storage-provider-metadata.service';
13
- import { ConfigService } from '@nestjs/config';
14
11
  import { FileService } from './file.service';
12
+ import { MediaStorageProviderMetadataService } from './media-storage-provider-metadata.service';
15
13
  import { MediaService } from './media.service';
16
- import { DiscoveryService, ModuleRef } from '@nestjs/core';
17
- import { CrudHelperService } from './crud-helper.service';
18
- import { EmailTemplateRepository } from 'src/repository/email-template.repository';
14
+ import { ModelMetadataService } from './model-metadata.service';
15
+ import { ModuleMetadataService } from './module-metadata.service';
19
16
 
20
17
  @Injectable()
21
18
  export class EmailTemplateService extends CRUDService<EmailTemplate>{
22
19
  constructor(
20
+ @Inject(forwardRef(() => ModelMetadataService))
23
21
  readonly modelMetadataService: ModelMetadataService,
24
22
  readonly moduleMetadataService: ModuleMetadataService,
25
23
  readonly mediaStorageProviderService: MediaStorageProviderMetadataService,
@@ -3,7 +3,6 @@ import * as ExcelJS from 'exceljs';
3
3
  import { ERROR_MESSAGES } from 'src/constants/error-messages';
4
4
  import { PassThrough, Readable } from 'stream';
5
5
 
6
-
7
6
  export interface ExcelReadOptions {
8
7
  pageSize?: number; // Number of records per page
9
8
  hasHeaderRow?: boolean; // Whether the first row contains headers
@@ -17,6 +16,11 @@ export interface ExcelReadResult {
17
16
  data: Record<string, any>[]; // Data records in the current page
18
17
  }
19
18
 
19
+ export interface ExcelReadAllResult {
20
+ headers: string[];
21
+ rows: Record<string, any>[];
22
+ }
23
+
20
24
  @Injectable()
21
25
  export class ExcelService {
22
26
  private logger = new Logger(ExcelService.name);
@@ -59,7 +63,7 @@ export class ExcelService {
59
63
  // headers.reduce((acc, header) => ({ ...acc, [header]: '' }), {})
60
64
  // ).commit(); // Write a dummy record with headers
61
65
 
62
- workbook.commit();
66
+ workbook.commit();
63
67
  return passThrough;
64
68
  }
65
69
 
@@ -86,7 +90,7 @@ export class ExcelService {
86
90
  this.logger.debug(`✅ Chunk ${chunkIndex} written to Excel`);
87
91
  }
88
92
 
89
- workbook.commit();
93
+ workbook.commit();
90
94
  // passThrough.end(); // ✅ Properly close the stream
91
95
  } catch (error) {
92
96
  this.logger.error(`❌ Error writing Excel: ${error.message}`);
@@ -159,4 +163,143 @@ export class ExcelService {
159
163
  }
160
164
  }
161
165
 
166
+ private cleanString(value: any): string {
167
+ return (value === null || value === undefined ? '' : String(value))
168
+ .replace(/\uFEFF/g, '') // BOM
169
+ .replace(/\u00A0/g, ' ') // NBSP
170
+ .replace(/\s+/g, ' ')
171
+ .trim();
172
+ }
173
+
174
+ private normalizeCellValue(value: any, sharedStrings?: any[]): any {
175
+ if (value === undefined || value === null) return null;
176
+
177
+ // ExcelJS streaming shared string ref: { sharedString: number }
178
+ if (typeof value === 'object' && value && 'sharedString' in value) {
179
+ const idx = (value as any).sharedString;
180
+ const resolved = sharedStrings?.[idx];
181
+ // sharedStrings may store objects or plain strings depending on ExcelJS internals
182
+ if (resolved === undefined || resolved === null) return null;
183
+ if (typeof resolved === 'string') return resolved;
184
+ if (typeof resolved === 'object') {
185
+ if ('text' in resolved && typeof (resolved as any).text === 'string') return (resolved as any).text;
186
+ if ('richText' in resolved && Array.isArray((resolved as any).richText)) {
187
+ return (resolved as any).richText.map((item: any) => item?.text ?? '').join('');
188
+ }
189
+ if ('value' in resolved) return (resolved as any).value;
190
+ }
191
+ return resolved;
192
+ }
193
+
194
+ // ExcelJS can return rich objects for styled cells; unwrap to plain text/primitive
195
+ if (typeof value === 'object' && value) {
196
+ // Plain rich cell: { text: '...' }
197
+ if ('text' in value && typeof (value as any).text === 'string') return (value as any).text;
198
+
199
+ // Rich text: { richText: [{text:'a'}, ...] }
200
+ if ('richText' in value && Array.isArray((value as any).richText)) {
201
+ return (value as any).richText.map((item: any) => item?.text ?? '').join('');
202
+ }
203
+
204
+ // Formula cells: { formula: '...', result: ... }
205
+ if ('result' in value) return (value as any).result;
206
+ if ('formula' in value) return (value as any).formula;
207
+
208
+ // Hyperlinks: { text: '...', hyperlink: '...' }
209
+ if ('hyperlink' in value && typeof (value as any).hyperlink === 'string') {
210
+ return (value as any).text ?? (value as any).hyperlink;
211
+ }
212
+
213
+ // Sometimes primitive nested under .value
214
+ if ('value' in value) return this.normalizeCellValue((value as any).value, sharedStrings);
215
+ }
216
+
217
+ return value;
218
+ }
219
+
220
+ public async readExcelFromStreamNonStreaming(
221
+ stream: Readable,
222
+ options?: ExcelReadOptions & { worksheetIndex?: number; maxRows?: number }
223
+ ): Promise<ExcelReadAllResult> {
224
+ const {
225
+ hasHeaderRow = true,
226
+ providedHeaders = [],
227
+ worksheetIndex = 0, // 0-based
228
+ maxRows,
229
+ } = options || {};
230
+
231
+ // 1) Read entire stream into a Buffer
232
+ const chunks: Buffer[] = [];
233
+ for await (const chunk of stream) {
234
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
235
+ }
236
+ const buffer = Buffer.concat(chunks);
237
+
238
+ // 2) Load workbook (non-streaming)
239
+ const workbook = new ExcelJS.Workbook();
240
+ // @ts-ignore
241
+ await workbook.xlsx.load(buffer);
242
+
243
+ const worksheet = workbook.worksheets?.[worksheetIndex];
244
+ if (!worksheet) {
245
+ return { headers: [], rows: [] };
246
+ }
247
+
248
+ // 3) Determine headers
249
+ let headers: string[] = [];
250
+
251
+ const firstRow = worksheet.getRow(1);
252
+ const firstRowValues = Array.isArray(firstRow.values) ? (firstRow.values as any[]).slice(1) : [];
253
+
254
+ const normalizeNonStreamingCell = (v: any) => {
255
+ // In non-streaming ExcelJS, cell.value can be:
256
+ // - string/number/boolean/date
257
+ // - {richText}, {text}, {hyperlink}, {formula,result}, etc.
258
+ // We'll reuse your normalizeCellValue but without sharedStrings
259
+ return this.normalizeCellValue(v);
260
+ };
261
+
262
+ if (hasHeaderRow) {
263
+ headers = firstRowValues.map((v) => this.cleanString(normalizeNonStreamingCell(v)));
264
+ } else if (providedHeaders.length) {
265
+ headers = providedHeaders.map((h) => this.cleanString(h));
266
+ } else {
267
+ headers = firstRowValues.map((_, idx) => `${idx}`);
268
+ }
269
+
270
+ // If headers are all blank and hasHeaderRow=true, treat as no headers (avoid mapping everything to "")
271
+ if (hasHeaderRow && headers.length > 0 && headers.every((h) => !h)) {
272
+ this.logger.warn(`ExcelService.readExcelFromStreamNonStreaming: header row appears blank`);
273
+ }
274
+
275
+ // 4) Read rows
276
+ const rows: Record<string, any>[] = [];
277
+
278
+ const startRowNumber = hasHeaderRow ? 2 : 1;
279
+ const lastRowNumber = worksheet.rowCount || 0;
280
+
281
+ for (let r = startRowNumber; r <= lastRowNumber; r++) {
282
+ if (maxRows && rows.length >= maxRows) break;
283
+
284
+ const row = worksheet.getRow(r);
285
+ const rawValues = Array.isArray(row.values) ? (row.values as any[]).slice(1) : [];
286
+ const values = rawValues.map((v) => normalizeNonStreamingCell(v));
287
+
288
+ // Align row width to header width
289
+ while (values.length < headers.length) values.push(null);
290
+ if (values.length > headers.length) values.length = headers.length;
291
+
292
+ const record = headers.reduce((acc, key, i) => {
293
+ acc[key] = values[i] ?? null;
294
+ return acc;
295
+ }, {} as Record<string, any>);
296
+
297
+ // Skip fully empty rows
298
+ if (Object.values(record).every((v) => v === null || this.cleanString(v) === '')) continue;
299
+
300
+ rows.push(record);
301
+ }
302
+
303
+ return { headers, rows };
304
+ }
162
305
  }