@solidxai/core 0.1.11-beta.0 → 0.1.11-beta.11

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 (226) hide show
  1. package/.claude/settings.local.json +2 -1
  2. package/CLAUDE.md +26 -0
  3. package/dist/commands/migrate-removed-fields.command.d.ts +19 -0
  4. package/dist/commands/migrate-removed-fields.command.d.ts.map +1 -0
  5. package/dist/commands/migrate-removed-fields.command.js +77 -0
  6. package/dist/commands/migrate-removed-fields.command.js.map +1 -0
  7. package/dist/controllers/datasource-introspection.controller.d.ts +46 -1
  8. package/dist/controllers/datasource-introspection.controller.d.ts.map +1 -1
  9. package/dist/controllers/datasource-introspection.controller.js +38 -0
  10. package/dist/controllers/datasource-introspection.controller.js.map +1 -1
  11. package/dist/controllers/service.controller.d.ts +1 -0
  12. package/dist/controllers/service.controller.d.ts.map +1 -1
  13. package/dist/controllers/service.controller.js +2 -2
  14. package/dist/controllers/service.controller.js.map +1 -1
  15. package/dist/dtos/datasource-introspection-mapping.dto.d.ts +5 -0
  16. package/dist/dtos/datasource-introspection-mapping.dto.d.ts.map +1 -1
  17. package/dist/dtos/datasource-introspection-mapping.dto.js +24 -2
  18. package/dist/dtos/datasource-introspection-mapping.dto.js.map +1 -1
  19. package/dist/entities/{legacy-common-with-id.entity.d.ts → legacy-common-with-generated-id.entity.d.ts} +2 -2
  20. package/dist/entities/legacy-common-with-generated-id.entity.d.ts.map +1 -0
  21. package/dist/entities/{legacy-common-with-id.entity.js → legacy-common-with-generated-id.entity.js} +4 -4
  22. package/dist/entities/legacy-common-with-generated-id.entity.js.map +1 -0
  23. package/dist/entities/{legacy-common.entity.d.ts → legacy-common.entity-with-existing-id.entity.d.ts} +1 -1
  24. package/dist/entities/legacy-common.entity-with-existing-id.entity.d.ts.map +1 -0
  25. package/dist/entities/{legacy-common.entity.js → legacy-common.entity-with-existing-id.entity.js} +1 -1
  26. package/dist/entities/legacy-common.entity-with-existing-id.entity.js.map +1 -0
  27. package/dist/helpers/command.service.d.ts +2 -0
  28. package/dist/helpers/command.service.d.ts.map +1 -1
  29. package/dist/helpers/command.service.js +6 -2
  30. package/dist/helpers/command.service.js.map +1 -1
  31. package/dist/helpers/environment.helper.d.ts +1 -0
  32. package/dist/helpers/environment.helper.d.ts.map +1 -1
  33. package/dist/helpers/environment.helper.js +4 -0
  34. package/dist/helpers/environment.helper.js.map +1 -1
  35. package/dist/helpers/field-crud-managers/IntFieldCrudManager.d.ts.map +1 -1
  36. package/dist/helpers/field-crud-managers/IntFieldCrudManager.js +4 -1
  37. package/dist/helpers/field-crud-managers/IntFieldCrudManager.js.map +1 -1
  38. package/dist/helpers/model-metadata-helper.service.d.ts +2 -1
  39. package/dist/helpers/model-metadata-helper.service.d.ts.map +1 -1
  40. package/dist/helpers/model-metadata-helper.service.js +9 -5
  41. package/dist/helpers/model-metadata-helper.service.js.map +1 -1
  42. package/dist/helpers/nodemon-heartbeat.d.ts +5 -0
  43. package/dist/helpers/nodemon-heartbeat.d.ts.map +1 -0
  44. package/dist/helpers/nodemon-heartbeat.js +67 -0
  45. package/dist/helpers/nodemon-heartbeat.js.map +1 -0
  46. package/dist/helpers/solid-registry.d.ts +2 -1
  47. package/dist/helpers/solid-registry.d.ts.map +1 -1
  48. package/dist/helpers/solid-registry.js.map +1 -1
  49. package/dist/helpers/typeorm-db-helper.d.ts +1 -0
  50. package/dist/helpers/typeorm-db-helper.d.ts.map +1 -1
  51. package/dist/helpers/typeorm-db-helper.js +12 -0
  52. package/dist/helpers/typeorm-db-helper.js.map +1 -1
  53. package/dist/index.d.ts +3 -2
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +3 -2
  56. package/dist/index.js.map +1 -1
  57. package/dist/interfaces/datasource-introspection-provider.interface.d.ts +1 -0
  58. package/dist/interfaces/datasource-introspection-provider.interface.d.ts.map +1 -1
  59. package/dist/interfaces/datasource-introspection-provider.interface.js.map +1 -1
  60. package/dist/interfaces.d.ts +1 -0
  61. package/dist/interfaces.d.ts.map +1 -1
  62. package/dist/interfaces.js.map +1 -1
  63. package/dist/repository/scheduled-job.repository.d.ts +5 -2
  64. package/dist/repository/scheduled-job.repository.d.ts.map +1 -1
  65. package/dist/repository/scheduled-job.repository.js +66 -3
  66. package/dist/repository/scheduled-job.repository.js.map +1 -1
  67. package/dist/repository/security-rule.repository.d.ts +2 -2
  68. package/dist/repository/security-rule.repository.d.ts.map +1 -1
  69. package/dist/repository/security-rule.repository.js +6 -3
  70. package/dist/repository/security-rule.repository.js.map +1 -1
  71. package/dist/seeders/module-metadata-seeder.service.d.ts +43 -2
  72. package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
  73. package/dist/seeders/module-metadata-seeder.service.js +1173 -232
  74. package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
  75. package/dist/seeders/seed-data/solid-core-metadata.json +128 -34
  76. package/dist/services/action-metadata.service.d.ts +7 -0
  77. package/dist/services/action-metadata.service.d.ts.map +1 -1
  78. package/dist/services/action-metadata.service.js +76 -3
  79. package/dist/services/action-metadata.service.js.map +1 -1
  80. package/dist/services/api-key.service.d.ts.map +1 -1
  81. package/dist/services/api-key.service.js.map +1 -1
  82. package/dist/services/authentication.service.d.ts +2 -0
  83. package/dist/services/authentication.service.d.ts.map +1 -1
  84. package/dist/services/authentication.service.js +32 -11
  85. package/dist/services/authentication.service.js.map +1 -1
  86. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.d.ts.map +1 -1
  87. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js +7 -5
  88. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js.map +1 -1
  89. package/dist/services/computed-fields/entity/concat-entity-computed-field-provider.service.d.ts +4 -0
  90. package/dist/services/computed-fields/entity/concat-entity-computed-field-provider.service.d.ts.map +1 -1
  91. package/dist/services/computed-fields/entity/concat-entity-computed-field-provider.service.js +18 -1
  92. package/dist/services/computed-fields/entity/concat-entity-computed-field-provider.service.js.map +1 -1
  93. package/dist/services/crud-helper.service.d.ts.map +1 -1
  94. package/dist/services/crud-helper.service.js +25 -12
  95. package/dist/services/crud-helper.service.js.map +1 -1
  96. package/dist/services/crud.service.d.ts +1 -0
  97. package/dist/services/crud.service.d.ts.map +1 -1
  98. package/dist/services/crud.service.js +27 -0
  99. package/dist/services/crud.service.js.map +1 -1
  100. package/dist/services/datasource-introspection/mssql-datasource-introspection-provider.service.d.ts.map +1 -1
  101. package/dist/services/datasource-introspection/mssql-datasource-introspection-provider.service.js +12 -0
  102. package/dist/services/datasource-introspection/mssql-datasource-introspection-provider.service.js.map +1 -1
  103. package/dist/services/datasource-introspection/mysql-datasource-introspection-provider.service.d.ts.map +1 -1
  104. package/dist/services/datasource-introspection/mysql-datasource-introspection-provider.service.js +2 -0
  105. package/dist/services/datasource-introspection/mysql-datasource-introspection-provider.service.js.map +1 -1
  106. package/dist/services/datasource-introspection/postgres-datasource-introspection-provider.service.d.ts.map +1 -1
  107. package/dist/services/datasource-introspection/postgres-datasource-introspection-provider.service.js +28 -15
  108. package/dist/services/datasource-introspection/postgres-datasource-introspection-provider.service.js.map +1 -1
  109. package/dist/services/datasource-introspection.service.d.ts +62 -2
  110. package/dist/services/datasource-introspection.service.d.ts.map +1 -1
  111. package/dist/services/datasource-introspection.service.js +654 -186
  112. package/dist/services/datasource-introspection.service.js.map +1 -1
  113. package/dist/services/import-transaction.service.d.ts.map +1 -1
  114. package/dist/services/import-transaction.service.js +3 -0
  115. package/dist/services/import-transaction.service.js.map +1 -1
  116. package/dist/services/locale.service.d.ts +14 -0
  117. package/dist/services/locale.service.d.ts.map +1 -1
  118. package/dist/services/locale.service.js +83 -0
  119. package/dist/services/locale.service.js.map +1 -1
  120. package/dist/services/mediaStorageProviders/file-s3-storage-provider.js +10 -10
  121. package/dist/services/mediaStorageProviders/file-s3-storage-provider.js.map +1 -1
  122. package/dist/services/menu-item-metadata.service.d.ts.map +1 -1
  123. package/dist/services/menu-item-metadata.service.js +1 -0
  124. package/dist/services/menu-item-metadata.service.js.map +1 -1
  125. package/dist/services/model-metadata.service.d.ts +3 -0
  126. package/dist/services/model-metadata.service.d.ts.map +1 -1
  127. package/dist/services/model-metadata.service.js +78 -0
  128. package/dist/services/model-metadata.service.js.map +1 -1
  129. package/dist/services/module-metadata.service.d.ts.map +1 -1
  130. package/dist/services/module-metadata.service.js +28 -0
  131. package/dist/services/module-metadata.service.js.map +1 -1
  132. package/dist/services/removed-field-migration.service.d.ts +30 -0
  133. package/dist/services/removed-field-migration.service.d.ts.map +1 -0
  134. package/dist/services/removed-field-migration.service.js +319 -0
  135. package/dist/services/removed-field-migration.service.js.map +1 -0
  136. package/dist/services/role-metadata.service.d.ts +5 -0
  137. package/dist/services/role-metadata.service.d.ts.map +1 -1
  138. package/dist/services/role-metadata.service.js +95 -33
  139. package/dist/services/role-metadata.service.js.map +1 -1
  140. package/dist/services/settings/default-settings-provider.service.d.ts +244 -0
  141. package/dist/services/settings/default-settings-provider.service.d.ts.map +1 -1
  142. package/dist/services/settings/default-settings-provider.service.js +120 -0
  143. package/dist/services/settings/default-settings-provider.service.js.map +1 -1
  144. package/dist/services/solid-ts-morph.service.d.ts +6 -0
  145. package/dist/services/solid-ts-morph.service.d.ts.map +1 -1
  146. package/dist/services/solid-ts-morph.service.js +43 -0
  147. package/dist/services/solid-ts-morph.service.js.map +1 -1
  148. package/dist/services/view-metadata.service.d.ts +6 -0
  149. package/dist/services/view-metadata.service.d.ts.map +1 -1
  150. package/dist/services/view-metadata.service.js +70 -8
  151. package/dist/services/view-metadata.service.js.map +1 -1
  152. package/dist/solid-core.module.d.ts.map +1 -1
  153. package/dist/solid-core.module.js +4 -0
  154. package/dist/solid-core.module.js.map +1 -1
  155. package/dist/subscribers/audit.subscriber.d.ts +5 -1
  156. package/dist/subscribers/audit.subscriber.d.ts.map +1 -1
  157. package/dist/subscribers/audit.subscriber.js +76 -12
  158. package/dist/subscribers/audit.subscriber.js.map +1 -1
  159. package/dist/subscribers/computed-entity-field.subscriber.d.ts +9 -1
  160. package/dist/subscribers/computed-entity-field.subscriber.d.ts.map +1 -1
  161. package/dist/subscribers/computed-entity-field.subscriber.js +45 -11
  162. package/dist/subscribers/computed-entity-field.subscriber.js.map +1 -1
  163. package/dist/subscribers/created-by-updated-by.subscriber.d.ts.map +1 -1
  164. package/dist/subscribers/created-by-updated-by.subscriber.js.map +1 -1
  165. package/dist/subscribers/field-metadata.subscriber.d.ts.map +1 -1
  166. package/dist/subscribers/field-metadata.subscriber.js.map +1 -1
  167. package/dist/subscribers/scheduled-job.subscriber.d.ts.map +1 -1
  168. package/dist/subscribers/scheduled-job.subscriber.js +3 -2
  169. package/dist/subscribers/scheduled-job.subscriber.js.map +1 -1
  170. package/dist/subscribers/security-rule.subscriber.d.ts.map +1 -1
  171. package/dist/subscribers/security-rule.subscriber.js +5 -3
  172. package/dist/subscribers/security-rule.subscriber.js.map +1 -1
  173. package/package.json +1 -1
  174. package/src/commands/migrate-removed-fields.command.ts +81 -0
  175. package/src/controllers/datasource-introspection.controller.ts +27 -1
  176. package/src/controllers/service.controller.ts +3 -2
  177. package/src/dtos/datasource-introspection-mapping.dto.ts +15 -0
  178. package/src/entities/{legacy-common-with-id.entity.ts → legacy-common-with-generated-id.entity.ts} +1 -1
  179. package/src/helpers/command.service.ts +10 -2
  180. package/src/helpers/environment.helper.ts +11 -0
  181. package/src/helpers/field-crud-managers/IntFieldCrudManager.ts +4 -1
  182. package/src/helpers/model-metadata-helper.service.ts +8 -3
  183. package/src/helpers/nodemon-heartbeat.ts +59 -0
  184. package/src/helpers/solid-registry.ts +7 -1
  185. package/src/helpers/typeorm-db-helper.ts +15 -0
  186. package/src/index.ts +3 -2
  187. package/src/interfaces/datasource-introspection-provider.interface.ts +1 -0
  188. package/src/interfaces.ts +1 -0
  189. package/src/repository/scheduled-job.repository.ts +83 -4
  190. package/src/repository/security-rule.repository.ts +10 -4
  191. package/src/seeders/module-metadata-seeder.service.ts +1415 -264
  192. package/src/seeders/seed-data/solid-core-metadata.json +128 -34
  193. package/src/services/action-metadata.service.ts +87 -2
  194. package/src/services/api-key.service.ts +36 -36
  195. package/src/services/authentication.service.ts +46 -12
  196. package/src/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.ts +11 -5
  197. package/src/services/computed-fields/entity/concat-entity-computed-field-provider.service.ts +15 -1
  198. package/src/services/crud-helper.service.ts +25 -12
  199. package/src/services/crud.service.ts +36 -11
  200. package/src/services/datasource-introspection/mssql-datasource-introspection-provider.service.ts +12 -0
  201. package/src/services/datasource-introspection/mysql-datasource-introspection-provider.service.ts +2 -0
  202. package/src/services/datasource-introspection/postgres-datasource-introspection-provider.service.ts +28 -15
  203. package/src/services/datasource-introspection.service.ts +811 -161
  204. package/src/services/import-transaction.service.ts +5 -0
  205. package/src/services/locale.service.ts +111 -3
  206. package/src/services/mediaStorageProviders/file-s3-storage-provider.ts +2 -2
  207. package/src/services/menu-item-metadata.service.ts +2 -1
  208. package/src/services/model-metadata.service.ts +109 -1
  209. package/src/services/module-metadata.service.ts +36 -0
  210. package/src/services/removed-field-migration.service.ts +334 -0
  211. package/src/services/role-metadata.service.ts +112 -49
  212. package/src/services/settings/default-settings-provider.service.ts +120 -0
  213. package/src/services/solid-ts-morph.service.ts +61 -1
  214. package/src/services/view-metadata.service.ts +83 -9
  215. package/src/solid-core.module.ts +4 -0
  216. package/src/subscribers/audit.subscriber.ts +101 -18
  217. package/src/subscribers/computed-entity-field.subscriber.ts +81 -28
  218. package/src/subscribers/created-by-updated-by.subscriber.ts +3 -0
  219. package/src/subscribers/field-metadata.subscriber.ts +3 -0
  220. package/src/subscribers/scheduled-job.subscriber.ts +3 -2
  221. package/src/subscribers/security-rule.subscriber.ts +8 -3
  222. package/dist/entities/legacy-common-with-id.entity.d.ts.map +0 -1
  223. package/dist/entities/legacy-common-with-id.entity.js.map +0 -1
  224. package/dist/entities/legacy-common.entity.d.ts.map +0 -1
  225. package/dist/entities/legacy-common.entity.js.map +0 -1
  226. /package/src/entities/{legacy-common.entity.ts → legacy-common.entity-with-existing-id.entity.ts} +0 -0
@@ -52,6 +52,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
52
52
  exports.ModuleMetadataSeederService = void 0;
53
53
  const common_1 = require("@nestjs/common");
54
54
  const fs = __importStar(require("fs"));
55
+ const os = __importStar(require("os"));
55
56
  const path = __importStar(require("path"));
56
57
  const security_rule_repository_1 = require("../repository/security-rule.repository");
57
58
  const authentication_service_1 = require("../services/authentication.service");
@@ -64,6 +65,7 @@ const typeorm_1 = require("typeorm");
64
65
  const module_helper_1 = require("../helpers/module.helper");
65
66
  const solid_registry_1 = require("../helpers/solid-registry");
66
67
  const action_metadata_service_1 = require("../services/action-metadata.service");
68
+ const api_key_service_1 = require("../services/api-key.service");
67
69
  const field_metadata_service_1 = require("../services/field-metadata.service");
68
70
  const media_storage_provider_metadata_service_1 = require("../services/media-storage-provider-metadata.service");
69
71
  const model_metadata_service_1 = require("../services/model-metadata.service");
@@ -76,6 +78,7 @@ const action_metadata_entity_1 = require("../entities/action-metadata.entity");
76
78
  const menu_item_metadata_entity_1 = require("../entities/menu-item-metadata.entity");
77
79
  const module_metadata_entity_1 = require("../entities/module-metadata.entity");
78
80
  const role_metadata_entity_1 = require("../entities/role-metadata.entity");
81
+ const user_entity_1 = require("../entities/user.entity");
79
82
  const create_menu_item_metadata_dto_1 = require("../dtos/create-menu-item-metadata.dto");
80
83
  const create_user_dto_1 = require("../dtos/create-user.dto");
81
84
  const create_role_metadata_dto_1 = require("../dtos/create-role-metadata.dto");
@@ -83,7 +86,9 @@ const permission_metadata_repository_1 = require("../repository/permission-metad
83
86
  const saved_filters_repository_1 = require("../repository/saved-filters.repository");
84
87
  const scheduled_job_repository_1 = require("../repository/scheduled-job.repository");
85
88
  const setting_repository_1 = require("../repository/setting.repository");
89
+ const user_api_key_repository_1 = require("../repository/user-api-key.repository");
86
90
  const model_sequence_repository_1 = require("../repository/model-sequence.repository");
91
+ const locale_repository_1 = require("../repository/locale.repository");
87
92
  const model_sequence_entity_1 = require("../entities/model-sequence.entity");
88
93
  const saved_filters_entity_1 = require("../entities/saved-filters.entity");
89
94
  const scheduled_job_entity_1 = require("../entities/scheduled-job.entity");
@@ -94,7 +99,7 @@ const model_metadata_entity_1 = require("../entities/model-metadata.entity");
94
99
  const permission_metadata_entity_1 = require("../entities/permission-metadata.entity");
95
100
  const view_metadata_entity_1 = require("../entities/view-metadata.entity");
96
101
  let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMetadataSeederService {
97
- constructor(moduleMetadataService, modelMetadataService, fieldMetadataService, mediaStorageProviderMetadataService, roleService, userService, authenticationService, solidActionService, solidViewService, emailTemplateService, smsTemplateService, listOfValuesService, permissionRepo, solidRegistry, settingService, settingsRepo, securityRuleRepo, systemFieldsSeederService, scheduledJobRepository, savedFiltersRepo, dataSource, modelSequenceRepo) {
102
+ constructor(moduleMetadataService, modelMetadataService, fieldMetadataService, mediaStorageProviderMetadataService, roleService, userService, authenticationService, apiKeyService, solidActionService, solidViewService, emailTemplateService, smsTemplateService, listOfValuesService, userApiKeyRepository, permissionRepo, solidRegistry, settingService, settingsRepo, securityRuleRepo, systemFieldsSeederService, scheduledJobRepository, savedFiltersRepo, dataSource, modelSequenceRepo, localeRepo) {
98
103
  this.moduleMetadataService = moduleMetadataService;
99
104
  this.modelMetadataService = modelMetadataService;
100
105
  this.fieldMetadataService = fieldMetadataService;
@@ -102,11 +107,13 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
102
107
  this.roleService = roleService;
103
108
  this.userService = userService;
104
109
  this.authenticationService = authenticationService;
110
+ this.apiKeyService = apiKeyService;
105
111
  this.solidActionService = solidActionService;
106
112
  this.solidViewService = solidViewService;
107
113
  this.emailTemplateService = emailTemplateService;
108
114
  this.smsTemplateService = smsTemplateService;
109
115
  this.listOfValuesService = listOfValuesService;
116
+ this.userApiKeyRepository = userApiKeyRepository;
110
117
  this.permissionRepo = permissionRepo;
111
118
  this.solidRegistry = solidRegistry;
112
119
  this.settingService = settingService;
@@ -117,7 +124,16 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
117
124
  this.savedFiltersRepo = savedFiltersRepo;
118
125
  this.dataSource = dataSource;
119
126
  this.modelSequenceRepo = modelSequenceRepo;
127
+ this.localeRepo = localeRepo;
120
128
  this.logger = new common_1.Logger(ModuleMetadataSeederService_1.name);
129
+ this.seedTimingTag = 'SEED_TIMING';
130
+ this.permissionSeedBatchSize = 500;
131
+ this.viewComparableFields = ['name', 'displayName', 'type', 'context', 'layout', 'module', 'model'];
132
+ this.actionComparableFields = ['name', 'displayName', 'type', 'domain', 'context', 'customComponent', 'customIsModal', 'serverEndpoint', 'module', 'model', 'view'];
133
+ this.moduleLookupCache = new Map();
134
+ this.modelLookupCache = new Map();
135
+ this.viewLookupCache = new Map();
136
+ this.mediaStorageProviderLookupCache = new Map();
121
137
  this.enablePruning = false;
122
138
  }
123
139
  async seed(conf) {
@@ -127,105 +143,114 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
127
143
  const shouldSeedGlobalMetadata = conf?.seedGlobalMetadata !== false;
128
144
  try {
129
145
  this.enablePruning = Boolean(conf?.pruneMetadata);
146
+ this.resetLookupCaches();
130
147
  console.log(this.enablePruning ? '▶ Pruning enabled: metadata not present in JSON will be removed.' : '▶ Pruning disabled: existing metadata will be kept.');
131
- if (shouldSeedGlobalMetadata) {
132
- currentStep = 'seedGlobalMetadata';
133
- await this.seedGlobalMetadata();
134
- }
135
- else {
136
- this.logger.log(`Skipping global metadata seeding.`);
137
- }
138
- const seedDataFiles = this.seedDataFiles;
139
- this.logger.debug(`Found seed data for modules: ${seedDataFiles.map(s => s.moduleMetadata?.name)}`);
140
- currentStep = 'resolveModulesToSeed';
141
- if (conf && Array.isArray(conf.modulesToSeed)) {
142
- modulesToSeed = conf.modulesToSeed;
143
- console.log(`▶ Selective seeding enabled. Modules to seed: ${modulesToSeed.join(', ')}`);
144
- this.logger.log(`Selective seeding enabled. Modules to seed: ${modulesToSeed.join(', ')}`);
145
- }
146
- else {
147
- console.log(`▶ No modulesToSeed provided. Seeding ALL modules.`);
148
- this.logger.log(`No modulesToSeed provided. Seeding ALL modules.`);
149
- }
150
- const filteredSeedDataFiles = modulesToSeed ? seedDataFiles.filter((file) => modulesToSeed.includes(file.moduleMetadata?.name)) : seedDataFiles;
151
- if (filteredSeedDataFiles.length === 0) {
152
- this.logger.warn(`No modules matched the provided modulesToSeed list.`);
153
- return;
154
- }
155
- for (let i = 0; i < filteredSeedDataFiles.length; i++) {
156
- const overallMetadata = filteredSeedDataFiles[i];
157
- const moduleMetadata = overallMetadata.moduleMetadata;
158
- currentModule = moduleMetadata?.name ?? 'unknown';
159
- if (!moduleMetadata?.name) {
160
- this.logger.warn(`Skipping seed metadata file because moduleMetadata.name is missing.`);
161
- continue;
148
+ await this.timeOperation('seed-run', async () => {
149
+ if (shouldSeedGlobalMetadata) {
150
+ currentStep = 'seedGlobalMetadata';
151
+ await this.timeOperation('global-seed', () => this.seedGlobalMetadata(), { moduleName: 'global', component: 'global-metadata' });
162
152
  }
163
- console.log(`▶ Seeding Metadata for Module: ${moduleMetadata.name}`);
164
- this.logger.log(`Seeding Metadata for Module: ${moduleMetadata.name}`);
165
- currentStep = 'seedMediaStorageProviders';
166
- this.logger.log(`Seeding Media Storage Providers`);
167
- const mediaStorageCounts = await this.seedMediaStorageProviders(overallMetadata.mediaStorageProviders);
168
- console.log(`${this.formatSeedResult(moduleMetadata.name, 'Media Storage Providers', mediaStorageCounts)}`);
169
- currentStep = 'seedModuleModelFields';
170
- this.logger.log(`Seeding Module / Model / Fields`);
171
- const moduleModelFieldCounts = await this.seedModuleModelFields(moduleMetadata);
172
- console.log(`${this.formatSeedResult(moduleMetadata.name, 'Module/Model/Fields', moduleModelFieldCounts)}`);
173
- currentStep = 'seedPermissions';
174
- this.logger.log(`Seeding Permissions`);
175
- const permissionCounts = await this.seedPermissions(overallMetadata);
176
- console.log(`${this.formatSeedResult(moduleMetadata.name, 'Permissions', permissionCounts)}`);
177
- currentStep = 'seedRoles';
178
- this.logger.log(`Seeding Roles`);
179
- const roleCounts = await this.seedRoles(overallMetadata);
180
- console.log(`${this.formatSeedResult(moduleMetadata.name, 'Roles', roleCounts)}`);
181
- currentStep = 'seedUsers';
182
- this.logger.log(`Seeding Users`);
183
- const userCounts = await this.seedUsers(overallMetadata);
184
- console.log(`${this.formatSeedResult(moduleMetadata.name, 'Users', userCounts)}`);
185
- currentStep = 'seedViews';
186
- this.logger.log(`Seeding Views`);
187
- const viewCounts = await this.seedViews(overallMetadata);
188
- console.log(`${this.formatSeedResult(moduleMetadata.name, 'Views', viewCounts)}`);
189
- currentStep = 'seedActions';
190
- this.logger.log(`Seeding Actions`);
191
- const actionCounts = await this.seedActions(overallMetadata);
192
- console.log(`${this.formatSeedResult(moduleMetadata.name, 'Actions', actionCounts)}`);
193
- currentStep = 'seedMenus';
194
- this.logger.log(`Seeding Menus`);
195
- const menuCounts = await this.seedMenus(overallMetadata);
196
- console.log(`${this.formatSeedResult(moduleMetadata.name, 'Menus', menuCounts)}`);
197
- currentStep = 'seedEmailTemplates';
198
- this.logger.log(`Seeding Email Templates`);
199
- const emailTemplateCounts = await this.seedEmailTemplates(overallMetadata, moduleMetadata.name);
200
- console.log(`${this.formatSeedResult(moduleMetadata.name, 'Email Templates', emailTemplateCounts)}`);
201
- currentStep = 'seedSmsTemplates';
202
- this.logger.log(`Seeding Sms Templates`);
203
- const smsTemplateCounts = await this.seedSmsTemplates(overallMetadata, moduleMetadata.name);
204
- console.log(`${this.formatSeedResult(moduleMetadata.name, 'Sms Templates', smsTemplateCounts)}`);
205
- currentStep = 'seedSecurityRules';
206
- this.logger.log(`Seeding Security Rules`);
207
- const securityRuleCounts = await this.seedSecurityRules(overallMetadata);
208
- console.log(`${this.formatSeedResult(moduleMetadata.name, 'Security Rules', securityRuleCounts)}`);
209
- currentStep = 'seedListOfValues';
210
- this.logger.log(`Seeding List Of Values`);
211
- const lovCounts = await this.seedListOfValues(moduleMetadata, overallMetadata);
212
- console.log(`${this.formatSeedResult(moduleMetadata.name, 'List Of Values', lovCounts)}`);
213
- currentStep = 'seedScheduledJobs';
214
- this.logger.log(`Seeding Scheduled Jobs`);
215
- const scheduledJobCounts = await this.seedScheduledJobs(moduleMetadata, overallMetadata);
216
- console.log(`${this.formatSeedResult(moduleMetadata.name, 'Scheduled Jobs', scheduledJobCounts)}`);
217
- currentStep = 'seedSavedFilters';
218
- this.logger.log(`Seeding Saved Filters`);
219
- const savedFilterCounts = await this.seedSavedFilters(moduleMetadata, overallMetadata);
220
- console.log(`${this.formatSeedResult(moduleMetadata.name, 'Saved Filters', savedFilterCounts)}`);
221
- currentStep = 'seedModelSequences';
222
- this.logger.log(`Seeding Model Sequences`);
223
- const modelSequenceCounts = await this.seedModelSequences(overallMetadata);
224
- console.log(`${this.formatSeedResult(moduleMetadata.name, 'Model Sequences', modelSequenceCounts)}`);
225
- }
226
- currentModule = 'global';
227
- currentStep = 'setupDefaultRolesWithPermissions';
228
- await this.setupDefaultRolesWithPermissions();
153
+ else {
154
+ this.logger.log(`Skipping global metadata seeding.`);
155
+ }
156
+ const seedDataFiles = this.seedDataFiles;
157
+ this.logger.debug(`Found seed data for modules: ${seedDataFiles.map(s => s.moduleMetadata?.name)}`);
158
+ currentStep = 'resolveModulesToSeed';
159
+ if (conf && Array.isArray(conf.modulesToSeed)) {
160
+ modulesToSeed = conf.modulesToSeed;
161
+ console.log(`▶ Selective seeding enabled. Modules to seed: ${modulesToSeed.join(', ')}`);
162
+ this.logger.log(`Selective seeding enabled. Modules to seed: ${modulesToSeed.join(', ')}`);
163
+ }
164
+ else {
165
+ console.log(`▶ No modulesToSeed provided. Seeding ALL modules.`);
166
+ this.logger.log(`No modulesToSeed provided. Seeding ALL modules.`);
167
+ }
168
+ const filteredSeedDataFiles = modulesToSeed ? seedDataFiles.filter((file) => modulesToSeed.includes(file.moduleMetadata?.name)) : seedDataFiles;
169
+ if (filteredSeedDataFiles.length === 0) {
170
+ this.logger.warn(`No modules matched the provided modulesToSeed list.`);
171
+ return;
172
+ }
173
+ for (let i = 0; i < filteredSeedDataFiles.length; i++) {
174
+ const overallMetadata = filteredSeedDataFiles[i];
175
+ const moduleMetadata = overallMetadata.moduleMetadata;
176
+ currentModule = moduleMetadata?.name ?? 'unknown';
177
+ if (!moduleMetadata?.name) {
178
+ this.logger.warn(`Skipping seed metadata file because moduleMetadata.name is missing.`);
179
+ continue;
180
+ }
181
+ console.log(`▶ Seeding Metadata for Module: ${moduleMetadata.name}`);
182
+ this.logger.log(`Seeding Metadata for Module: ${moduleMetadata.name}`);
183
+ await this.timeOperation('module-total', async () => {
184
+ currentStep = 'seedMediaStorageProviders';
185
+ this.logger.log(`Seeding Media Storage Providers`);
186
+ const mediaStorageCounts = await this.timeOperation('seed-media-storage-providers', () => this.seedMediaStorageProviders(overallMetadata.mediaStorageProviders), { moduleName: moduleMetadata.name, component: 'media-storage-providers' });
187
+ console.log(`${this.formatSeedResult(moduleMetadata.name, 'Media Storage Providers', mediaStorageCounts)}`);
188
+ currentStep = 'seedModuleModelFields';
189
+ this.logger.log(`Seeding Module / Model / Fields`);
190
+ const moduleModelFieldCounts = await this.timeOperation('seed-module-model-fields', () => this.seedModuleModelFields(moduleMetadata), { moduleName: moduleMetadata.name, component: 'module-model-fields' });
191
+ console.log(`${this.formatSeedResult(moduleMetadata.name, 'Module/Model/Fields', moduleModelFieldCounts)}`);
192
+ currentStep = 'seedLocales';
193
+ this.logger.log(`Seeding Locales`);
194
+ const localeCounts = await this.seedLocales(overallMetadata);
195
+ console.log(`${this.formatSeedResult(moduleMetadata.name, 'Locales', localeCounts)}`);
196
+ currentStep = 'seedPermissions';
197
+ this.logger.log(`Seeding Permissions`);
198
+ const permissionCounts = await this.timeOperation('seed-permissions', () => this.seedPermissions(overallMetadata), { moduleName: moduleMetadata.name, component: 'permissions' });
199
+ console.log(`${this.formatSeedResult(moduleMetadata.name, 'Permissions', permissionCounts)}`);
200
+ currentStep = 'seedRoles';
201
+ this.logger.log(`Seeding Roles`);
202
+ const roleCounts = await this.timeOperation('seed-roles', () => this.seedRoles(overallMetadata), { moduleName: moduleMetadata.name, component: 'roles' });
203
+ console.log(`${this.formatSeedResult(moduleMetadata.name, 'Roles', roleCounts)}`);
204
+ currentStep = 'seedUsers';
205
+ this.logger.log(`Seeding Users`);
206
+ const userCounts = await this.timeOperation('seed-users', () => this.seedUsers(overallMetadata), { moduleName: moduleMetadata.name, component: 'users' });
207
+ console.log(`${this.formatSeedResult(moduleMetadata.name, 'Users', userCounts)}`);
208
+ currentStep = 'seedViews';
209
+ this.logger.log(`Seeding Views`);
210
+ const viewCounts = await this.timeOperation('seed-views', () => this.seedViews(overallMetadata), { moduleName: moduleMetadata.name, component: 'views' });
211
+ console.log(`${this.formatSeedResult(moduleMetadata.name, 'Views', viewCounts)}`);
212
+ currentStep = 'seedActions';
213
+ this.logger.log(`Seeding Actions`);
214
+ const actionCounts = await this.timeOperation('seed-actions', () => this.seedActions(overallMetadata), { moduleName: moduleMetadata.name, component: 'actions' });
215
+ console.log(`${this.formatSeedResult(moduleMetadata.name, 'Actions', actionCounts)}`);
216
+ currentStep = 'seedMenus';
217
+ this.logger.log(`Seeding Menus`);
218
+ const menuCounts = await this.timeOperation('seed-menus', () => this.seedMenus(overallMetadata), { moduleName: moduleMetadata.name, component: 'menus' });
219
+ console.log(`${this.formatSeedResult(moduleMetadata.name, 'Menus', menuCounts)}`);
220
+ currentStep = 'seedEmailTemplates';
221
+ this.logger.log(`Seeding Email Templates`);
222
+ const emailTemplateCounts = await this.timeOperation('seed-email-templates', () => this.seedEmailTemplates(overallMetadata, moduleMetadata.name), { moduleName: moduleMetadata.name, component: 'email-templates' });
223
+ console.log(`${this.formatSeedResult(moduleMetadata.name, 'Email Templates', emailTemplateCounts)}`);
224
+ currentStep = 'seedSmsTemplates';
225
+ this.logger.log(`Seeding Sms Templates`);
226
+ const smsTemplateCounts = await this.timeOperation('seed-sms-templates', () => this.seedSmsTemplates(overallMetadata, moduleMetadata.name), { moduleName: moduleMetadata.name, component: 'sms-templates' });
227
+ console.log(`${this.formatSeedResult(moduleMetadata.name, 'Sms Templates', smsTemplateCounts)}`);
228
+ currentStep = 'seedSecurityRules';
229
+ this.logger.log(`Seeding Security Rules`);
230
+ const securityRuleCounts = await this.timeOperation('seed-security-rules', () => this.seedSecurityRules(overallMetadata), { moduleName: moduleMetadata.name, component: 'security-rules' });
231
+ console.log(`${this.formatSeedResult(moduleMetadata.name, 'Security Rules', securityRuleCounts)}`);
232
+ currentStep = 'seedListOfValues';
233
+ this.logger.log(`Seeding List Of Values`);
234
+ const lovCounts = await this.timeOperation('seed-list-of-values', () => this.seedListOfValues(moduleMetadata, overallMetadata), { moduleName: moduleMetadata.name, component: 'list-of-values' });
235
+ console.log(`${this.formatSeedResult(moduleMetadata.name, 'List Of Values', lovCounts)}`);
236
+ currentStep = 'seedScheduledJobs';
237
+ this.logger.log(`Seeding Scheduled Jobs`);
238
+ const scheduledJobCounts = await this.timeOperation('seed-scheduled-jobs', () => this.seedScheduledJobs(moduleMetadata, overallMetadata), { moduleName: moduleMetadata.name, component: 'scheduled-jobs' });
239
+ console.log(`${this.formatSeedResult(moduleMetadata.name, 'Scheduled Jobs', scheduledJobCounts)}`);
240
+ currentStep = 'seedSavedFilters';
241
+ this.logger.log(`Seeding Saved Filters`);
242
+ const savedFilterCounts = await this.timeOperation('seed-saved-filters', () => this.seedSavedFilters(moduleMetadata, overallMetadata), { moduleName: moduleMetadata.name, component: 'saved-filters' });
243
+ console.log(`${this.formatSeedResult(moduleMetadata.name, 'Saved Filters', savedFilterCounts)}`);
244
+ currentStep = 'seedModelSequences';
245
+ this.logger.log(`Seeding Model Sequences`);
246
+ const modelSequenceCounts = await this.timeOperation('seed-model-sequences', () => this.seedModelSequences(overallMetadata), { moduleName: moduleMetadata.name, component: 'model-sequences' });
247
+ console.log(`${this.formatSeedResult(moduleMetadata.name, 'Model Sequences', modelSequenceCounts)}`);
248
+ }, { moduleName: moduleMetadata.name, component: 'module-seed' });
249
+ }
250
+ currentModule = 'global';
251
+ currentStep = 'setupDefaultRolesWithPermissions';
252
+ await this.timeOperation('setup-default-roles-with-permissions', () => this.setupDefaultRolesWithPermissions(), { moduleName: 'global', component: 'default-roles' });
253
+ }, { moduleName: 'global', component: 'seed-run' });
229
254
  console.log(`✔ Seeding completed.`);
230
255
  }
231
256
  catch (error) {
@@ -238,117 +263,303 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
238
263
  throw error;
239
264
  }
240
265
  }
266
+ buildTimingPrefix(itemTag, options) {
267
+ const parts = [`[${this.seedTimingTag}]`, `[ITEM:${itemTag}]`];
268
+ if (options?.moduleName) {
269
+ parts.push(`[MODULE:${options.moduleName}]`);
270
+ }
271
+ if (options?.component) {
272
+ parts.push(`[COMPONENT:${options.component}]`);
273
+ }
274
+ if (options?.serviceCall) {
275
+ parts.push(`[CALL:${options.serviceCall}]`);
276
+ }
277
+ return parts.join(' ');
278
+ }
279
+ formatDuration(durationMs) {
280
+ return durationMs >= 1000
281
+ ? `${(durationMs / 1000).toFixed(2)} s (${durationMs.toFixed(2)} ms)`
282
+ : `${durationMs.toFixed(2)} ms`;
283
+ }
284
+ resetLookupCaches() {
285
+ this.moduleLookupCache.clear();
286
+ this.modelLookupCache.clear();
287
+ this.viewLookupCache.clear();
288
+ this.mediaStorageProviderLookupCache.clear();
289
+ }
290
+ async getModuleByUserKeyCached(moduleUserKey, options) {
291
+ if (!moduleUserKey) {
292
+ return null;
293
+ }
294
+ if (this.moduleLookupCache.has(moduleUserKey)) {
295
+ return this.moduleLookupCache.get(moduleUserKey) ?? null;
296
+ }
297
+ const module = await this.timeOperation('module-find-by-user-key-cache-miss', () => this.moduleMetadataService.findOneByUserKey(moduleUserKey), {
298
+ moduleName: options?.moduleName ?? moduleUserKey,
299
+ component: options?.component,
300
+ serviceCall: 'moduleMetadataService.findOneByUserKey',
301
+ details: options?.details ?? `module=${moduleUserKey}`,
302
+ });
303
+ this.moduleLookupCache.set(moduleUserKey, module ?? null);
304
+ return module ?? null;
305
+ }
306
+ async getModelByUserKeyCached(modelUserKey, options) {
307
+ if (!modelUserKey) {
308
+ return null;
309
+ }
310
+ if (this.modelLookupCache.has(modelUserKey)) {
311
+ return this.modelLookupCache.get(modelUserKey) ?? null;
312
+ }
313
+ const model = await this.timeOperation('model-find-by-user-key-cache-miss', () => this.modelMetadataService.findOneByUserKey(modelUserKey), {
314
+ moduleName: options?.moduleName,
315
+ component: options?.component,
316
+ serviceCall: 'modelMetadataService.findOneByUserKey',
317
+ details: options?.details ?? `model=${modelUserKey}`,
318
+ });
319
+ this.modelLookupCache.set(modelUserKey, model ?? null);
320
+ return model ?? null;
321
+ }
322
+ async getViewByUserKeyCached(viewUserKey, options) {
323
+ if (!viewUserKey) {
324
+ return null;
325
+ }
326
+ if (this.viewLookupCache.has(viewUserKey)) {
327
+ return this.viewLookupCache.get(viewUserKey) ?? null;
328
+ }
329
+ const view = await this.timeOperation('view-find-by-user-key-cache-miss', () => this.solidViewService.findOneByUserKey(viewUserKey), {
330
+ moduleName: options?.moduleName,
331
+ component: options?.component,
332
+ serviceCall: 'solidViewService.findOneByUserKey',
333
+ details: options?.details ?? `view=${viewUserKey}`,
334
+ });
335
+ this.viewLookupCache.set(viewUserKey, view ?? null);
336
+ return view ?? null;
337
+ }
338
+ async getMediaStorageProviderByUserKeyCached(mediaStorageProviderUserKey, options) {
339
+ if (!mediaStorageProviderUserKey) {
340
+ return null;
341
+ }
342
+ if (this.mediaStorageProviderLookupCache.has(mediaStorageProviderUserKey)) {
343
+ return this.mediaStorageProviderLookupCache.get(mediaStorageProviderUserKey) ?? null;
344
+ }
345
+ const mediaStorageProvider = await this.timeOperation('media-storage-provider-find-by-user-key-cache-miss', () => this.mediaStorageProviderMetadataService.findOneByUserKey(mediaStorageProviderUserKey), {
346
+ moduleName: options?.moduleName,
347
+ component: options?.component,
348
+ serviceCall: 'mediaStorageProviderMetadataService.findOneByUserKey',
349
+ details: options?.details ?? `provider=${mediaStorageProviderUserKey}`,
350
+ });
351
+ this.mediaStorageProviderLookupCache.set(mediaStorageProviderUserKey, mediaStorageProvider ?? null);
352
+ return mediaStorageProvider ?? null;
353
+ }
354
+ async timeOperation(itemTag, operation, options) {
355
+ const prefix = this.buildTimingPrefix(itemTag, options);
356
+ const detailSuffix = options?.details ? ` ${options.details}` : '';
357
+ const start = process.hrtime.bigint();
358
+ try {
359
+ const result = await operation();
360
+ const durationMs = Number(process.hrtime.bigint() - start) / 1_000_000;
361
+ this.logger.debug(`${prefix} done in ${this.formatDuration(durationMs)}${detailSuffix}`);
362
+ return result;
363
+ }
364
+ catch (error) {
365
+ const durationMs = Number(process.hrtime.bigint() - start) / 1_000_000;
366
+ this.logger.debug(`${prefix} failed after ${this.formatDuration(durationMs)}${detailSuffix}`);
367
+ throw error;
368
+ }
369
+ }
241
370
  async seedScheduledJobs(moduleMetadata, overallMetadata) {
242
- this.logger.debug(`[Start] Processing scheduled jobs for ${moduleMetadata.name}`);
243
371
  const scheduledJobs = this.getSeedArray(overallMetadata?.scheduledJobs);
244
- const pruned = this.enablePruning ? await this.pruneScheduledJobs(scheduledJobs, moduleMetadata.name) : 0;
372
+ const pruned = this.enablePruning ? await this.timeOperation('prune-scheduled-jobs', () => this.pruneScheduledJobs(scheduledJobs, moduleMetadata.name), {
373
+ moduleName: moduleMetadata.name,
374
+ component: 'scheduled-jobs',
375
+ serviceCall: 'pruneScheduledJobs',
376
+ }) : 0;
245
377
  if (scheduledJobs.length > 0) {
246
- await this.handleSeedScheduledJobs(scheduledJobs);
378
+ await this.timeOperation('handle-scheduled-jobs', () => this.handleSeedScheduledJobs(scheduledJobs), {
379
+ moduleName: moduleMetadata.name,
380
+ component: 'scheduled-jobs',
381
+ serviceCall: 'handleSeedScheduledJobs',
382
+ });
247
383
  }
248
- this.logger.debug(`[End] Processing scheduled jobs for ${moduleMetadata.name}`);
249
384
  return { pruned, upserted: scheduledJobs.length };
250
385
  }
251
386
  async seedSavedFilters(moduleMetadata, overallMetadata) {
252
- this.logger.debug(`[Start] Processing saved filters for ${moduleMetadata.name}`);
253
387
  const savedFilters = this.getSeedArray(overallMetadata?.savedFilters);
254
- const pruned = this.enablePruning ? await this.pruneSavedFilters(savedFilters, moduleMetadata.name) : 0;
388
+ const pruned = this.enablePruning ? await this.timeOperation('prune-saved-filters', () => this.pruneSavedFilters(savedFilters, moduleMetadata.name), {
389
+ moduleName: moduleMetadata.name,
390
+ component: 'saved-filters',
391
+ serviceCall: 'pruneSavedFilters',
392
+ }) : 0;
255
393
  if (savedFilters.length > 0) {
256
- await this.handleSeedSavedFilters(savedFilters);
394
+ await this.timeOperation('handle-saved-filters', () => this.handleSeedSavedFilters(savedFilters), {
395
+ moduleName: moduleMetadata.name,
396
+ component: 'saved-filters',
397
+ serviceCall: 'handleSeedSavedFilters',
398
+ });
257
399
  }
258
- this.logger.debug(`[End] Processing saved filters for ${moduleMetadata.name}`);
259
400
  return { pruned, upserted: savedFilters.length };
260
401
  }
261
402
  async seedListOfValues(moduleMetadata, overallMetadata) {
262
- this.logger.debug(`[Start] Processing List Of Values for ${moduleMetadata.name}`);
263
403
  const listOfValues = this.getSeedArray(overallMetadata?.listOfValues);
264
- const pruned = this.enablePruning ? await this.pruneListOfValues(listOfValues, moduleMetadata.name) : 0;
265
- await this.handleSeedListOfValues(listOfValues);
266
- this.logger.debug(`[End] Processing List Of Values for ${moduleMetadata.name}`);
404
+ const pruned = this.enablePruning ? await this.timeOperation('prune-list-of-values', () => this.pruneListOfValues(listOfValues, moduleMetadata.name), {
405
+ moduleName: moduleMetadata.name,
406
+ component: 'list-of-values',
407
+ serviceCall: 'pruneListOfValues',
408
+ }) : 0;
409
+ await this.timeOperation('handle-list-of-values', () => this.handleSeedListOfValues(listOfValues), {
410
+ moduleName: moduleMetadata.name,
411
+ component: 'list-of-values',
412
+ serviceCall: 'handleSeedListOfValues',
413
+ });
267
414
  return { pruned, upserted: listOfValues.length };
268
415
  }
416
+ async seedLocales(overallMetadata) {
417
+ this.logger.debug(`[Start] Processing locales`);
418
+ const locales = this.getSeedArray(overallMetadata?.locales);
419
+ const existingLocales = await this.localeRepo.find();
420
+ if (existingLocales.length > 0) {
421
+ this.solidRegistry.registerlocales(existingLocales);
422
+ this.logger.debug(`[End] Skipping locale seed because locales already exist`);
423
+ return { pruned: 0, upserted: 0 };
424
+ }
425
+ await this.handleSeedLocales(locales);
426
+ this.logger.debug(`[End] Processing locales`);
427
+ return { pruned: 0, upserted: locales.length };
428
+ }
269
429
  async setupDefaultRolesWithPermissions() {
270
430
  this.logger.debug(`About to add all permissions to the Admin role`);
271
- await this.roleService.addAllPermissionsToRole(create_role_metadata_dto_1.ADMIN_ROLE_NAME);
431
+ await this.timeOperation('role-add-all-permissions', () => this.roleService.addAllPermissionsToRole(create_role_metadata_dto_1.ADMIN_ROLE_NAME), {
432
+ moduleName: 'global',
433
+ component: 'default-roles',
434
+ serviceCall: 'roleService.addAllPermissionsToRole',
435
+ details: `role=${create_role_metadata_dto_1.ADMIN_ROLE_NAME}`,
436
+ });
272
437
  }
273
438
  async seedSecurityRules(overallMetadata) {
274
- this.logger.debug(`[Start] Processing security rules`);
275
439
  const securityRules = this.getSeedArray(overallMetadata?.securityRules);
276
- const pruned = this.enablePruning ? await this.pruneSecurityRules(securityRules, overallMetadata?.moduleMetadata?.name) : 0;
277
- await this.handleSeedSecurityRules(securityRules);
278
- this.logger.debug(`[End] Processing security rules`);
440
+ const pruned = this.enablePruning ? await this.timeOperation('prune-security-rules', () => this.pruneSecurityRules(securityRules, overallMetadata?.moduleMetadata?.name), {
441
+ moduleName: overallMetadata?.moduleMetadata?.name,
442
+ component: 'security-rules',
443
+ serviceCall: 'pruneSecurityRules',
444
+ }) : 0;
445
+ await this.timeOperation('handle-security-rules', () => this.handleSeedSecurityRules(securityRules), {
446
+ moduleName: overallMetadata?.moduleMetadata?.name,
447
+ component: 'security-rules',
448
+ serviceCall: 'handleSeedSecurityRules',
449
+ });
279
450
  return { pruned, upserted: securityRules.length };
280
451
  }
281
452
  async seedDefaultSettings() {
282
- this.logger.debug(`[Start] Processing settings`);
283
- await this.settingService.seedSystemAdminEditableAndAboveSettings();
284
- this.logger.debug(`[End] Processing settings`);
453
+ await this.timeOperation('seed-default-settings-call', () => this.settingService.seedSystemAdminEditableAndAboveSettings(), {
454
+ moduleName: 'global',
455
+ component: 'settings',
456
+ serviceCall: 'settingService.seedSystemAdminEditableAndAboveSettings',
457
+ });
285
458
  }
286
459
  async seedSmsTemplates(overallMetadata, moduleName) {
287
- this.logger.debug(`[Start] Processing sms templates`);
288
460
  const smsTemplates = this.getSeedArray(overallMetadata?.smsTemplates);
289
- await this.handleSeedSmsTemplates(smsTemplates, moduleName);
290
- this.logger.debug(`[End] Processing sms templates`);
461
+ await this.timeOperation('handle-sms-templates', () => this.handleSeedSmsTemplates(smsTemplates, moduleName), {
462
+ moduleName,
463
+ component: 'sms-templates',
464
+ serviceCall: 'handleSeedSmsTemplates',
465
+ });
291
466
  return { pruned: 0, upserted: smsTemplates.length };
292
467
  }
293
468
  async seedEmailTemplates(overallMetadata, moduleName) {
294
- this.logger.debug(`[Start] Processing email templates`);
295
469
  const emailTemplates = this.getSeedArray(overallMetadata?.emailTemplates);
296
- await this.handleSeedEmailTemplates(emailTemplates, moduleName);
297
- this.logger.debug(`[End] Processing email templates`);
470
+ await this.timeOperation('handle-email-templates', () => this.handleSeedEmailTemplates(emailTemplates, moduleName), {
471
+ moduleName,
472
+ component: 'email-templates',
473
+ serviceCall: 'handleSeedEmailTemplates',
474
+ });
298
475
  return { pruned: 0, upserted: emailTemplates.length };
299
476
  }
300
477
  async seedMenus(overallMetadata) {
301
- this.logger.debug(`[Start] Processing menus`);
302
478
  const menus = this.getSeedArray(overallMetadata?.menus);
303
- const pruned = this.enablePruning ? await this.pruneMenus(menus, overallMetadata?.moduleMetadata?.name) : 0;
304
- await this.handleSeedMenus(menus);
305
- this.logger.debug(`[End] Processing menus`);
479
+ const pruned = this.enablePruning ? await this.timeOperation('prune-menus', () => this.pruneMenus(menus, overallMetadata?.moduleMetadata?.name), {
480
+ moduleName: overallMetadata?.moduleMetadata?.name,
481
+ component: 'menus',
482
+ serviceCall: 'pruneMenus',
483
+ }) : 0;
484
+ await this.timeOperation('handle-menus', () => this.handleSeedMenus(menus), {
485
+ moduleName: overallMetadata?.moduleMetadata?.name,
486
+ component: 'menus',
487
+ serviceCall: 'handleSeedMenus',
488
+ });
306
489
  return { pruned, upserted: menus.length };
307
490
  }
308
491
  async seedActions(overallMetadata) {
309
- this.logger.debug(`[Start] Processing actions`);
310
492
  const actions = this.getSeedArray(overallMetadata?.actions);
311
- const pruned = this.enablePruning ? await this.pruneActions(actions, overallMetadata?.moduleMetadata?.name) : 0;
312
- await this.handleSeedActions(actions);
313
- this.logger.debug(`[End] Processing actions`);
493
+ const pruned = this.enablePruning ? await this.timeOperation('prune-actions', () => this.pruneActions(actions, overallMetadata?.moduleMetadata?.name), {
494
+ moduleName: overallMetadata?.moduleMetadata?.name,
495
+ component: 'actions',
496
+ serviceCall: 'pruneActions',
497
+ }) : 0;
498
+ await this.timeOperation('handle-actions', () => this.handleSeedActions(actions), {
499
+ moduleName: overallMetadata?.moduleMetadata?.name,
500
+ component: 'actions',
501
+ serviceCall: 'handleSeedActions',
502
+ });
314
503
  return { pruned, upserted: actions.length };
315
504
  }
316
505
  async seedViews(overallMetadata) {
317
- this.logger.debug(`[Start] Processing views`);
318
506
  const views = this.getSeedArray(overallMetadata?.views);
319
- const pruned = this.enablePruning ? await this.pruneViews(views, overallMetadata?.moduleMetadata?.name) : 0;
320
- await this.handleSeedViews(views);
321
- this.logger.debug(`[End] Processing views`);
507
+ const pruned = this.enablePruning ? await this.timeOperation('prune-views', () => this.pruneViews(views, overallMetadata?.moduleMetadata?.name), {
508
+ moduleName: overallMetadata?.moduleMetadata?.name,
509
+ component: 'views',
510
+ serviceCall: 'pruneViews',
511
+ }) : 0;
512
+ await this.timeOperation('handle-views', () => this.handleSeedViews(views), {
513
+ moduleName: overallMetadata?.moduleMetadata?.name,
514
+ component: 'views',
515
+ serviceCall: 'handleSeedViews',
516
+ });
322
517
  return { pruned, upserted: views.length };
323
518
  }
324
519
  async seedUsers(overallMetadata) {
325
- this.logger.debug(`[Start] Processing users`);
326
520
  const users = this.getSeedArray(overallMetadata?.users);
327
- await this.handleSeedUsers(users);
328
- this.logger.debug(`[End] Processing users`);
521
+ await this.timeOperation('handle-users', () => this.handleSeedUsers(users), {
522
+ moduleName: overallMetadata?.moduleMetadata?.name,
523
+ component: 'users',
524
+ serviceCall: 'handleSeedUsers',
525
+ });
329
526
  return { pruned: 0, upserted: users.length };
330
527
  }
331
528
  async seedRoles(overallMetadata) {
332
- this.logger.debug(`[Start] Processing roles`);
333
529
  const roles = this.getSeedArray(overallMetadata?.roles);
334
- await this.roleService.createRolesIfNotExists(roles
530
+ await this.timeOperation('roles-create-if-not-exists', () => this.roleService.createRolesIfNotExists(roles
335
531
  .filter((role) => role?.name)
336
- .map((role) => ({ name: role.name })));
532
+ .map((role) => ({
533
+ name: role.name,
534
+ moduleId: role.moduleId,
535
+ moduleUserKey: role.moduleUserKey ?? overallMetadata?.moduleMetadata?.name,
536
+ }))), {
537
+ moduleName: overallMetadata?.moduleMetadata?.name,
538
+ component: 'roles',
539
+ serviceCall: 'roleService.createRolesIfNotExists',
540
+ details: `roleCount=${roles.length}`,
541
+ });
337
542
  for (const role of roles) {
338
543
  if (role.permissions) {
339
- await this.roleService.addPermissionsToRole(role.name, role.permissions
544
+ await this.timeOperation('role-add-permissions', () => this.roleService.addPermissionsToRole(role.name, role.permissions
340
545
  .map((permission) => typeof permission === 'string' ? permission : permission?.name)
341
- .filter(Boolean));
546
+ .filter(Boolean)), {
547
+ moduleName: overallMetadata?.moduleMetadata?.name,
548
+ component: 'roles',
549
+ serviceCall: 'roleService.addPermissionsToRole',
550
+ details: `role=${role.name} permissionCount=${role.permissions.length}`,
551
+ });
342
552
  }
343
553
  }
344
- this.logger.debug(`[End] Processing roles`);
345
554
  return { pruned: 0, upserted: roles.length };
346
555
  }
347
556
  async seedPermissions(overallMetadata) {
348
- this.logger.debug(`[Start] Processing permissions`);
349
557
  const permissions = overallMetadata.permissions ?? [];
350
- await this.handleSeedPermissions(permissions);
351
- this.logger.debug(`[End] Processing permissions`);
558
+ await this.timeOperation('handle-permissions', () => this.handleSeedPermissions(permissions), {
559
+ moduleName: overallMetadata?.moduleMetadata?.name,
560
+ component: 'permissions',
561
+ serviceCall: 'handleSeedPermissions',
562
+ });
352
563
  return { pruned: 0, upserted: permissions?.length ?? 0 };
353
564
  }
354
565
  get seedDataFiles() {
@@ -367,15 +578,28 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
367
578
  }
368
579
  async seedGlobalMetadata() {
369
580
  this.logger.log(`Seeding Permissions`);
370
- await this.seedControllerPermissions();
581
+ await this.timeOperation('seed-controller-permissions', () => this.seedControllerPermissions(), {
582
+ moduleName: 'global',
583
+ component: 'controller-permissions',
584
+ });
371
585
  this.logger.log(`Seeding System Fields Metadata`);
372
- await this.seedDefaultSystemFields();
586
+ await this.timeOperation('seed-default-system-fields', () => this.seedDefaultSystemFields(), {
587
+ moduleName: 'global',
588
+ component: 'system-fields',
589
+ });
373
590
  this.logger.log(`Seeding Default Settings`);
374
- await this.seedDefaultSettings();
591
+ await this.timeOperation('seed-default-settings', () => this.seedDefaultSettings(), {
592
+ moduleName: 'global',
593
+ component: 'settings',
594
+ });
375
595
  this.logger.debug(`Global metadata seeding completed`);
376
596
  }
377
597
  async seedDefaultSystemFields() {
378
- await this.systemFieldsSeederService.seed();
598
+ await this.timeOperation('system-fields-seed', () => this.systemFieldsSeederService.seed(), {
599
+ moduleName: 'global',
600
+ component: 'system-fields',
601
+ serviceCall: 'systemFieldsSeederService.seed',
602
+ });
379
603
  }
380
604
  async seedControllerPermissions() {
381
605
  const controllers = this.solidRegistry.getControllers();
@@ -388,55 +612,112 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
388
612
  const methodName = methods[mId];
389
613
  const permissionName = `${controller.name}.${methodName}`;
390
614
  permissionNames.push(permissionName);
391
- await this.createPermissionIfNotExists(permissionName);
392
615
  }
393
616
  }
394
617
  catch (error) {
395
618
  this.logger.error(error);
396
619
  }
397
620
  }
621
+ await this.timeOperation('seed-controller-permissions-bulk', () => this.seedPermissionsInBatches(permissionNames, {
622
+ moduleName: 'global',
623
+ component: 'controller-permissions',
624
+ }), {
625
+ moduleName: 'global',
626
+ component: 'controller-permissions',
627
+ serviceCall: 'seedPermissionsInBatches',
628
+ details: `permissionCount=${permissionNames.length} batchSize=${this.permissionSeedBatchSize}`,
629
+ });
398
630
  if (this.enablePruning) {
399
- await this.prunePermissions(permissionNames);
631
+ await this.timeOperation('prune-controller-permissions', () => this.prunePermissions(permissionNames), {
632
+ moduleName: 'global',
633
+ component: 'controller-permissions',
634
+ serviceCall: 'prunePermissions',
635
+ });
400
636
  }
401
637
  }
402
- async createPermissionIfNotExists(permissionName) {
403
- const existingPermission = await this.permissionRepo.findOne({
404
- where: {
405
- name: permissionName
406
- }
638
+ async handleSeedPermissions(permissions) {
639
+ const permissionNames = permissions
640
+ .map((permission) => typeof permission === 'string' ? permission : permission?.name)
641
+ .filter(Boolean);
642
+ await this.seedPermissionsInBatches(permissionNames, {
643
+ component: 'permissions',
407
644
  });
408
- if (!existingPermission) {
409
- this.logger.log(`Permission ${permissionName} does not exist, creating new.`);
410
- const newPermission = this.permissionRepo.create({
411
- name: permissionName
645
+ }
646
+ async seedPermissionsInBatches(permissionNames, options) {
647
+ const uniquePermissionNames = this.getUniquePermissionNames(permissionNames);
648
+ if (uniquePermissionNames.length === 0) {
649
+ return;
650
+ }
651
+ for (let index = 0; index < uniquePermissionNames.length; index += this.permissionSeedBatchSize) {
652
+ const batch = uniquePermissionNames.slice(index, index + this.permissionSeedBatchSize);
653
+ const batchNumber = Math.floor(index / this.permissionSeedBatchSize) + 1;
654
+ const existingPermissions = await this.timeOperation('permission-batch-find', () => this.permissionRepo.find({
655
+ where: {
656
+ name: (0, typeorm_1.In)(batch),
657
+ }
658
+ }), {
659
+ moduleName: options?.moduleName,
660
+ component: options?.component ?? 'permissions',
661
+ serviceCall: 'permissionRepo.find',
662
+ details: `batch=${batchNumber} batchSize=${batch.length}`,
663
+ });
664
+ const existingPermissionNames = new Set(existingPermissions.map((permission) => this.normalizePermissionName(permission.name)));
665
+ const missingPermissionNames = batch.filter((name) => !existingPermissionNames.has(this.normalizePermissionName(name)));
666
+ if (missingPermissionNames.length === 0) {
667
+ continue;
668
+ }
669
+ this.logger.log(`Creating ${missingPermissionNames.length} missing permissions in batch ${batchNumber}.`);
670
+ await this.timeOperation('permission-batch-save', () => this.permissionRepo.save(missingPermissionNames.map((name) => this.permissionRepo.create({ name }))), {
671
+ moduleName: options?.moduleName,
672
+ component: options?.component ?? 'permissions',
673
+ serviceCall: 'permissionRepo.save',
674
+ details: `batch=${batchNumber} createCount=${missingPermissionNames.length}`,
412
675
  });
413
- await this.permissionRepo.save(newPermission);
414
676
  }
415
677
  }
416
- async handleSeedPermissions(permissions) {
417
- for (const permission of permissions) {
418
- const permissionName = typeof permission === 'string' ? permission : permission?.name;
419
- if (permissionName) {
420
- await this.createPermissionIfNotExists(permissionName);
678
+ getUniquePermissionNames(permissionNames) {
679
+ const normalizedPermissionNames = new Set();
680
+ const uniquePermissionNames = [];
681
+ for (const permissionName of permissionNames) {
682
+ if (!permissionName) {
683
+ continue;
421
684
  }
685
+ const normalizedPermissionName = this.normalizePermissionName(permissionName);
686
+ if (normalizedPermissionNames.has(normalizedPermissionName)) {
687
+ continue;
688
+ }
689
+ normalizedPermissionNames.add(normalizedPermissionName);
690
+ uniquePermissionNames.push(permissionName.trim());
422
691
  }
692
+ return uniquePermissionNames;
693
+ }
694
+ normalizePermissionName(permissionName) {
695
+ return permissionName.trim().toLowerCase();
423
696
  }
424
697
  async seedMediaStorageProviders(mediaStorageProviders) {
425
- this.logger.debug(`[Start] Processing Media Storage Provider`);
426
698
  const providers = this.getSeedArray(mediaStorageProviders);
427
699
  for (let i = 0; i < providers.length; i++) {
428
700
  const mediaStorageProvider = providers[i];
429
- await this.mediaStorageProviderMetadataService.upsert(mediaStorageProvider);
701
+ await this.timeOperation('media-storage-provider-upsert', () => this.mediaStorageProviderMetadataService.upsert(mediaStorageProvider), {
702
+ component: 'media-storage-providers',
703
+ serviceCall: 'mediaStorageProviderMetadataService.upsert',
704
+ details: `provider=${mediaStorageProvider?.name ?? mediaStorageProvider?.userKey ?? i}`,
705
+ });
430
706
  }
431
- this.logger.debug(`[End] Processing Media Storage Provider`);
432
707
  return { pruned: 0, upserted: providers.length };
433
708
  }
434
709
  async seedModelSequences(overallMetadata) {
435
- this.logger.debug(`[Start] Processing model sequences`);
436
710
  const modelSequences = this.getSeedArray(overallMetadata?.modelSequences);
437
- const pruned = this.enablePruning ? await this.pruneModelSequences(modelSequences, overallMetadata?.moduleMetadata?.name) : 0;
438
- await this.handleSeedModelSequences(modelSequences);
439
- this.logger.debug(`[End] Processing model sequences`);
711
+ const pruned = this.enablePruning ? await this.timeOperation('prune-model-sequences', () => this.pruneModelSequences(modelSequences, overallMetadata?.moduleMetadata?.name), {
712
+ moduleName: overallMetadata?.moduleMetadata?.name,
713
+ component: 'model-sequences',
714
+ serviceCall: 'pruneModelSequences',
715
+ }) : 0;
716
+ await this.timeOperation('handle-model-sequences', () => this.handleSeedModelSequences(modelSequences), {
717
+ moduleName: overallMetadata?.moduleMetadata?.name,
718
+ component: 'model-sequences',
719
+ serviceCall: 'handleSeedModelSequences',
720
+ });
440
721
  return { pruned, upserted: modelSequences.length };
441
722
  }
442
723
  async handleSeedEmailTemplates(emailTemplates, moduleName) {
@@ -473,8 +754,18 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
473
754
  emailTemplate.body = fs.readFileSync(fullPath, 'utf-8').toString();
474
755
  }
475
756
  }
476
- await this.emailTemplateService.removeByName(emailTemplate.name);
477
- await this.emailTemplateService.create(emailTemplate);
757
+ await this.timeOperation('email-template-remove', () => this.emailTemplateService.removeByName(emailTemplate.name), {
758
+ moduleName,
759
+ component: 'email-templates',
760
+ serviceCall: 'emailTemplateService.removeByName',
761
+ details: `template=${emailTemplate.name}`,
762
+ });
763
+ await this.timeOperation('email-template-create', () => this.emailTemplateService.create(emailTemplate), {
764
+ moduleName,
765
+ component: 'email-templates',
766
+ serviceCall: 'emailTemplateService.create',
767
+ details: `template=${emailTemplate.name}`,
768
+ });
478
769
  }
479
770
  }
480
771
  async handleSeedSmsTemplates(smsTemplates, moduleName) {
@@ -511,32 +802,62 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
511
802
  smsTemplate.body = fs.readFileSync(fullPath, 'utf-8').toString();
512
803
  }
513
804
  }
514
- await this.smsTemplateService.removeByName(smsTemplate.name);
515
- await this.smsTemplateService.create(smsTemplate);
805
+ await this.timeOperation('sms-template-remove', () => this.smsTemplateService.removeByName(smsTemplate.name), {
806
+ moduleName,
807
+ component: 'sms-templates',
808
+ serviceCall: 'smsTemplateService.removeByName',
809
+ details: `template=${smsTemplate.name}`,
810
+ });
811
+ await this.timeOperation('sms-template-create', () => this.smsTemplateService.create(smsTemplate), {
812
+ moduleName,
813
+ component: 'sms-templates',
814
+ serviceCall: 'smsTemplateService.create',
815
+ details: `template=${smsTemplate.name}`,
816
+ });
516
817
  }
517
818
  }
518
819
  async handleSeedMenus(menus) {
519
820
  if (!menus) {
520
821
  return;
521
822
  }
522
- await this.dataSource.transaction(async (trx) => {
823
+ await this.timeOperation('menus-transaction', () => this.dataSource.transaction(async (trx) => {
523
824
  const menuRepo = trx.getRepository(menu_item_metadata_entity_1.MenuItemMetadata);
524
825
  const roleRepo = trx.getRepository(role_metadata_entity_1.RoleMetadata);
525
826
  const actionRepo = trx.getRepository(action_metadata_entity_1.ActionMetadata);
526
827
  const moduleRepo = trx.getRepository(module_metadata_entity_1.ModuleMetadata);
527
828
  for (const m of menus) {
528
829
  const action = m.actionUserKey
529
- ? await actionRepo.findOne({ where: { name: m.actionUserKey }, select: ["id"] })
830
+ ? await this.timeOperation('menu-action-find-one', () => actionRepo.findOne({ where: { name: m.actionUserKey }, select: ["id"] }), {
831
+ component: 'menus',
832
+ serviceCall: 'actionRepo.findOne',
833
+ details: `action=${m.actionUserKey}`,
834
+ })
530
835
  : null;
531
836
  const module = m.moduleUserKey
532
- ? await moduleRepo.findOne({ where: { name: m.moduleUserKey }, select: ["id"] })
837
+ ? await this.timeOperation('menu-module-find-one', () => moduleRepo.findOne({ where: { name: m.moduleUserKey }, select: ["id"] }), {
838
+ component: 'menus',
839
+ serviceCall: 'moduleRepo.findOne',
840
+ details: `module=${m.moduleUserKey}`,
841
+ })
533
842
  : null;
534
843
  const parentMenuItem = m.parentMenuItemUserKey
535
- ? await menuRepo.findOne({ where: { name: m.parentMenuItemUserKey }, select: ["id"] })
844
+ ? await this.timeOperation('menu-parent-find-one', () => menuRepo.findOne({ where: { name: m.parentMenuItemUserKey }, select: ["id"] }), {
845
+ component: 'menus',
846
+ serviceCall: 'menuRepo.findOne',
847
+ details: `parent=${m.parentMenuItemUserKey}`,
848
+ })
536
849
  : null;
537
- const existing = await menuRepo.findOne({
850
+ const existing = await this.timeOperation('menu-existing-find-one', () => menuRepo.findOne({
538
851
  where: { name: m.name },
539
- select: ["id"],
852
+ relations: {
853
+ action: true,
854
+ module: true,
855
+ parentMenuItem: true,
856
+ },
857
+ }), {
858
+ component: 'menus',
859
+ serviceCall: 'menuRepo.findOne',
860
+ details: `menu=${m.name}`,
540
861
  });
541
862
  const base = {
542
863
  name: m.name,
@@ -547,23 +868,51 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
547
868
  sequenceNumber: m.sequenceNumber,
548
869
  iconName: m.iconName,
549
870
  };
871
+ const hasChanges = existing
872
+ ? existing.displayName !== base.displayName
873
+ || existing.sequenceNumber !== base.sequenceNumber
874
+ || existing.iconName !== base.iconName
875
+ || existing.action?.id !== base.action?.id
876
+ || existing.module?.id !== base.module?.id
877
+ || existing.parentMenuItem?.id !== base.parentMenuItem?.id
878
+ : true;
879
+ if (existing && !hasChanges) {
880
+ this.logger.debug(`Skipping menu upsert for ${m.name}; no changes detected.`);
881
+ continue;
882
+ }
550
883
  const entity = menuRepo.create(existing ? { id: existing.id, ...base } : base);
551
- await menuRepo.save(entity);
884
+ await this.timeOperation('menu-save', () => menuRepo.save(entity), {
885
+ component: 'menus',
886
+ serviceCall: 'menuRepo.save',
887
+ details: `menu=${m.name}`,
888
+ });
552
889
  }
553
- const seeded = await menuRepo.find({
890
+ const seeded = await this.timeOperation('menu-seeded-find', () => menuRepo.find({
554
891
  where: { name: (0, typeorm_1.In)(menus.map((m) => m.name)) },
555
892
  select: ["id", "name"],
893
+ }), {
894
+ component: 'menus',
895
+ serviceCall: 'menuRepo.find',
896
+ details: `count=${menus.length}`,
556
897
  });
557
898
  const idByName = new Map(seeded.map(s => [s.name, s.id]));
558
- const admin = await roleRepo.findOne({ where: { name: create_role_metadata_dto_1.ADMIN_ROLE_NAME }, select: ["id", "name"] });
899
+ const admin = await this.timeOperation('menu-admin-role-find-one', () => roleRepo.findOne({ where: { name: create_role_metadata_dto_1.ADMIN_ROLE_NAME }, select: ["id", "name"] }), {
900
+ component: 'menus',
901
+ serviceCall: 'roleRepo.findOne',
902
+ details: `role=${create_role_metadata_dto_1.ADMIN_ROLE_NAME}`,
903
+ });
559
904
  const allRoleNames = new Set();
560
905
  for (const m of menus)
561
906
  (m.roles ?? []).forEach((r) => allRoleNames.add(r));
562
907
  if (admin)
563
908
  allRoleNames.add(admin.name);
564
- const roles = await roleRepo.find({
909
+ const roles = await this.timeOperation('menu-roles-find', () => roleRepo.find({
565
910
  where: { name: (0, typeorm_1.In)([...allRoleNames]) },
566
911
  select: ["id", "name"],
912
+ }), {
913
+ component: 'menus',
914
+ serviceCall: 'roleRepo.find',
915
+ details: `roleCount=${allRoleNames.size}`,
567
916
  });
568
917
  const roleByName = new Map(roles.map(r => [r.name, r]));
569
918
  const joinRows = [];
@@ -578,57 +927,153 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
578
927
  }
579
928
  const menuIds = [...new Set(joinRows.map(r => r.menuId))];
580
929
  if (menuIds.length) {
581
- await trx
930
+ await this.timeOperation('menu-role-joins-delete', () => trx
582
931
  .createQueryBuilder()
583
932
  .delete()
584
933
  .from(create_menu_item_metadata_dto_1.MENU_ROLE_JOIN_TABLE_NAME)
585
934
  .where(`${create_menu_item_metadata_dto_1.MENU_ROLE_JOIN_TABLE_NAME_MENU_COL} IN (:...ids)`, { ids: menuIds })
586
- .execute();
935
+ .execute(), {
936
+ component: 'menus',
937
+ serviceCall: 'trx.delete.menuRoleJoins',
938
+ details: `menuCount=${menuIds.length}`,
939
+ });
587
940
  }
588
941
  if (joinRows.length) {
589
942
  const values = joinRows.map(r => ({
590
943
  [create_menu_item_metadata_dto_1.MENU_ROLE_JOIN_TABLE_NAME_MENU_COL]: r.menuId,
591
944
  [create_menu_item_metadata_dto_1.MENU_ROLE_JOIN_TABLE_NAME_ROLE_COL]: r.roleId,
592
945
  }));
593
- await trx
946
+ await this.timeOperation('menu-role-joins-insert', () => trx
594
947
  .createQueryBuilder()
595
948
  .insert()
596
949
  .into(create_menu_item_metadata_dto_1.MENU_ROLE_JOIN_TABLE_NAME)
597
950
  .values(values)
598
- .execute();
951
+ .execute(), {
952
+ component: 'menus',
953
+ serviceCall: 'trx.insert.menuRoleJoins',
954
+ details: `rowCount=${values.length}`,
955
+ });
599
956
  }
600
- });
957
+ }), { component: 'menus', serviceCall: 'dataSource.transaction' });
601
958
  }
602
959
  async handleSeedActions(actions) {
603
960
  if (!actions) {
604
961
  return;
605
962
  }
963
+ const actionRepo = this.dataSource.getRepository(action_metadata_entity_1.ActionMetadata);
964
+ await this.timeOperation('action-prime-module-cache', () => this.primeModuleLookupCache(actions.map((action) => action?.moduleUserKey)), {
965
+ component: 'actions',
966
+ serviceCall: 'primeModuleLookupCache',
967
+ details: `count=${actions.length}`,
968
+ });
969
+ await this.timeOperation('action-prime-model-cache', () => this.primeModelLookupCache(actions.map((action) => action?.modelUserKey)), {
970
+ component: 'actions',
971
+ serviceCall: 'primeModelLookupCache',
972
+ details: `count=${actions.length}`,
973
+ });
974
+ await this.timeOperation('action-prime-view-cache', () => this.primeViewLookupCache(actions.map((action) => action?.viewUserKey)), {
975
+ component: 'actions',
976
+ serviceCall: 'primeViewLookupCache',
977
+ details: `count=${actions.length}`,
978
+ });
979
+ const existingActionsByName = await this.timeOperation('action-preload-existing', () => this.loadExistingActionsByName(actionRepo, actions.map((action) => action?.name).filter(Boolean)), {
980
+ component: 'actions',
981
+ serviceCall: 'loadExistingActionsByName',
982
+ details: `count=${actions.length}`,
983
+ });
984
+ let created = 0;
985
+ let updated = 0;
986
+ let skipped = 0;
606
987
  for (let j = 0; j < actions.length; j++) {
607
988
  const actionData = actions[j];
608
- actionData['module'] = await this.moduleMetadataService.findOneByUserKey(actionData.moduleUserKey);
989
+ actionData['module'] = await this.getModuleByUserKeyCached(actionData.moduleUserKey, {
990
+ moduleName: actionData.moduleUserKey,
991
+ component: 'actions',
992
+ details: `module=${actionData.moduleUserKey}`,
993
+ });
609
994
  if (actionData.type === 'solid') {
610
- actionData['model'] = await this.modelMetadataService.findOneByUserKey(actionData.modelUserKey);
611
- actionData['view'] = await this.solidViewService.findOneByUserKey(actionData.viewUserKey);
995
+ actionData['model'] = await this.getModelByUserKeyCached(actionData.modelUserKey, {
996
+ moduleName: actionData.moduleUserKey,
997
+ component: 'actions',
998
+ details: `model=${actionData.modelUserKey}`,
999
+ });
1000
+ actionData['view'] = await this.getViewByUserKeyCached(actionData.viewUserKey, {
1001
+ moduleName: actionData.moduleUserKey,
1002
+ component: 'actions',
1003
+ details: `view=${actionData.viewUserKey}`,
1004
+ });
612
1005
  }
613
1006
  else {
614
1007
  if (actionData.modelUserKey) {
615
- actionData['model'] = await this.modelMetadataService.findOneByUserKey(actionData.modelUserKey);
1008
+ actionData['model'] = await this.getModelByUserKeyCached(actionData.modelUserKey, {
1009
+ moduleName: actionData.moduleUserKey,
1010
+ component: 'actions',
1011
+ details: `model=${actionData.modelUserKey}`,
1012
+ });
616
1013
  }
617
1014
  }
618
- await this.solidActionService.upsert(actionData);
1015
+ const result = await this.upsertActionMetadataWithPreloadedExisting(actionRepo, existingActionsByName, actionData);
1016
+ if (result.outcome === 'created') {
1017
+ created += 1;
1018
+ }
1019
+ else if (result.outcome === 'updated') {
1020
+ updated += 1;
1021
+ }
1022
+ else {
1023
+ skipped += 1;
1024
+ }
619
1025
  }
1026
+ this.logger.debug(`Action seed summary: created=${created}, updated=${updated}, skipped=${skipped}.`);
620
1027
  }
621
1028
  async handleSeedViews(views) {
622
1029
  if (!views) {
623
1030
  return;
624
1031
  }
1032
+ const viewRepo = this.dataSource.getRepository(view_metadata_entity_1.ViewMetadata);
1033
+ await this.timeOperation('view-prime-module-cache', () => this.primeModuleLookupCache(views.map((view) => view?.moduleUserKey)), {
1034
+ component: 'views',
1035
+ serviceCall: 'primeModuleLookupCache',
1036
+ details: `count=${views.length}`,
1037
+ });
1038
+ await this.timeOperation('view-prime-model-cache', () => this.primeModelLookupCache(views.map((view) => view?.modelUserKey)), {
1039
+ component: 'views',
1040
+ serviceCall: 'primeModelLookupCache',
1041
+ details: `count=${views.length}`,
1042
+ });
1043
+ const existingViewsByName = await this.timeOperation('view-preload-existing', () => this.loadExistingViewsByName(viewRepo, views.map((view) => view?.name).filter(Boolean)), {
1044
+ component: 'views',
1045
+ serviceCall: 'loadExistingViewsByName',
1046
+ details: `count=${views.length}`,
1047
+ });
1048
+ let created = 0;
1049
+ let updated = 0;
1050
+ let skipped = 0;
625
1051
  for (let j = 0; j < views.length; j++) {
626
1052
  const viewData = views[j];
627
1053
  viewData['layout'] = JSON.stringify(viewData['layout'], null, 2);
628
- viewData['module'] = await this.moduleMetadataService.findOneByUserKey(viewData.moduleUserKey);
629
- viewData['model'] = await this.modelMetadataService.findOneByUserKey(viewData.modelUserKey);
630
- await this.solidViewService.upsert(viewData);
1054
+ viewData['module'] = await this.getModuleByUserKeyCached(viewData.moduleUserKey, {
1055
+ moduleName: viewData.moduleUserKey,
1056
+ component: 'views',
1057
+ details: `module=${viewData.moduleUserKey}`,
1058
+ });
1059
+ viewData['model'] = await this.getModelByUserKeyCached(viewData.modelUserKey, {
1060
+ moduleName: viewData.moduleUserKey,
1061
+ component: 'views',
1062
+ details: `model=${viewData.modelUserKey}`,
1063
+ });
1064
+ const result = await this.upsertViewMetadataWithPreloadedExisting(viewRepo, existingViewsByName, viewData);
1065
+ this.viewLookupCache.set(viewData.name, result.entity ?? null);
1066
+ if (result.outcome === 'created') {
1067
+ created += 1;
1068
+ }
1069
+ else if (result.outcome === 'updated') {
1070
+ updated += 1;
1071
+ }
1072
+ else {
1073
+ skipped += 1;
1074
+ }
631
1075
  }
1076
+ this.logger.debug(`View seed summary: created=${created}, updated=${updated}, skipped=${skipped}.`);
632
1077
  }
633
1078
  async handleSeedUsers(users) {
634
1079
  if (!users) {
@@ -636,19 +1081,127 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
636
1081
  }
637
1082
  for (let l = 0; l < users.length; l++) {
638
1083
  const user = users[l];
639
- let exisitingUser = await this.userService.findOneByUsername(user.username);
1084
+ const isSystemAdminUser = user.username === 'sa';
1085
+ let exisitingUser = await this.timeOperation('user-find-by-username', () => this.userService.findOneByUsername(user.username), {
1086
+ component: 'users',
1087
+ serviceCall: 'userService.findOneByUsername',
1088
+ details: `username=${user.username}`,
1089
+ });
640
1090
  if (!exisitingUser) {
641
1091
  if (user.username === 'sa') {
642
1092
  user.password = create_user_dto_1.DEFAULT_SA_PASSWORD;
643
1093
  }
644
- exisitingUser = await this.authenticationService.signUp(user);
1094
+ if (isSystemAdminUser) {
1095
+ user.isAllowedToGenerateApiKeys = true;
1096
+ }
1097
+ exisitingUser = await this.timeOperation('user-sign-up', () => this.authenticationService.signUp(user), {
1098
+ component: 'users',
1099
+ serviceCall: 'authenticationService.signUp',
1100
+ details: `username=${user.username}`,
1101
+ });
1102
+ if (isSystemAdminUser) {
1103
+ await this.timeOperation('seed-sa-api-key', async () => {
1104
+ const generatedApiKey = await this.apiKeyService.generate(exisitingUser.id, {
1105
+ name: 'Default SA API Key',
1106
+ });
1107
+ await this.writeSolidxAdminApiKeyConfig(generatedApiKey);
1108
+ }, {
1109
+ component: 'users',
1110
+ serviceCall: 'apiKeyService.generate',
1111
+ details: `username=${user.username}`,
1112
+ });
1113
+ }
645
1114
  this.logger.log(`Newly created user ${user.username}`);
646
1115
  }
1116
+ if (isSystemAdminUser) {
1117
+ await this.ensureSystemAdminApiKey(exisitingUser);
1118
+ }
647
1119
  }
648
1120
  }
1121
+ async ensureSystemAdminApiKey(existingUser) {
1122
+ if (!existingUser?.id) {
1123
+ return;
1124
+ }
1125
+ if (!existingUser.isAllowedToGenerateApiKeys) {
1126
+ await this.timeOperation('enable-sa-api-key-generation', () => this.userApiKeyRepository.manager.update(user_entity_1.User, { id: existingUser.id }, {
1127
+ isAllowedToGenerateApiKeys: true,
1128
+ }), {
1129
+ component: 'users',
1130
+ serviceCall: 'userRepository.update',
1131
+ details: `username=${existingUser.username}`,
1132
+ });
1133
+ existingUser.isAllowedToGenerateApiKeys = true;
1134
+ }
1135
+ const existingDefaultKey = await this.timeOperation('find-sa-default-api-key', () => this.userApiKeyRepository.findOne({
1136
+ where: {
1137
+ user: { id: existingUser.id },
1138
+ name: 'Default SA API Key',
1139
+ },
1140
+ relations: {
1141
+ user: true,
1142
+ },
1143
+ }), {
1144
+ component: 'users',
1145
+ serviceCall: 'userApiKeyRepository.findOne',
1146
+ details: `username=${existingUser.username}`,
1147
+ });
1148
+ if (existingDefaultKey) {
1149
+ return;
1150
+ }
1151
+ await this.timeOperation('seed-sa-api-key', async () => {
1152
+ const generatedApiKey = await this.apiKeyService.generate(existingUser.id, {
1153
+ name: 'Default SA API Key',
1154
+ });
1155
+ await this.writeSolidxAdminApiKeyConfig(generatedApiKey);
1156
+ }, {
1157
+ component: 'users',
1158
+ serviceCall: 'apiKeyService.generate',
1159
+ details: `username=${existingUser.username}`,
1160
+ });
1161
+ }
1162
+ async writeSolidxAdminApiKeyConfig(generatedApiKey) {
1163
+ const consumingProjectRoot = path.resolve(process.cwd(), '..');
1164
+ const consumingProjectName = path.basename(consumingProjectRoot);
1165
+ const solidxDir = path.join(os.homedir(), '.solidx', consumingProjectName);
1166
+ const configPath = path.join(solidxDir, 'mcp.json');
1167
+ await fs.promises.mkdir(solidxDir, { recursive: true });
1168
+ let existingConfig = {};
1169
+ if (fs.existsSync(configPath)) {
1170
+ const rawConfig = await fs.promises.readFile(configPath, 'utf8');
1171
+ if (rawConfig.trim()) {
1172
+ const parsedConfig = JSON.parse(rawConfig);
1173
+ if (parsedConfig && typeof parsedConfig === 'object' && !Array.isArray(parsedConfig)) {
1174
+ existingConfig = parsedConfig;
1175
+ }
1176
+ else {
1177
+ this.logger.warn(`Expected ${configPath} to contain a JSON object. Overwriting with a new object.`);
1178
+ }
1179
+ }
1180
+ }
1181
+ const nextConfig = {
1182
+ ...existingConfig,
1183
+ solidxAdminApiKey: {
1184
+ id: generatedApiKey.record.id,
1185
+ name: generatedApiKey.record.name,
1186
+ apiKey: generatedApiKey.apiKey,
1187
+ maskedKey: generatedApiKey.record.maskedKey,
1188
+ isActive: generatedApiKey.record.isActive,
1189
+ expiresAt: generatedApiKey.record.expiresAt,
1190
+ createdAt: generatedApiKey.record.createdAt,
1191
+ updatedAt: generatedApiKey.record.updatedAt,
1192
+ },
1193
+ };
1194
+ await fs.promises.writeFile(configPath, `${JSON.stringify(nextConfig, null, 2)}\n`, 'utf8');
1195
+ }
649
1196
  async seedModuleModelFields(moduleMetadata) {
650
- this.logger.debug(`[Start] Processing module metadata`);
651
- const module = await this.moduleMetadataService.upsert(moduleMetadata);
1197
+ const fieldMetadataRepo = this.dataSource.getRepository(field_metadata_entity_1.FieldMetadata);
1198
+ const module = await this.timeOperation('module-upsert', () => this.moduleMetadataService.upsert(moduleMetadata), {
1199
+ moduleName: moduleMetadata.name,
1200
+ component: 'module-model-fields',
1201
+ serviceCall: 'moduleMetadataService.upsert',
1202
+ details: `module=${moduleMetadata.name}`,
1203
+ });
1204
+ this.moduleLookupCache.set(moduleMetadata.name, module ?? null);
652
1205
  let pruned = 0;
653
1206
  let upserted = 1;
654
1207
  const modelsMetadata = this.getSeedArray(moduleMetadata?.models);
@@ -658,24 +1211,59 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
658
1211
  modelMetadata['module'] = module;
659
1212
  const { fields: fieldsMetadata, ...modelMetaDataWithoutFields } = modelMetadata;
660
1213
  if (modelMetadata.isChild && modelMetadata.parentModelUserKey) {
661
- const parentModel = await this.modelMetadataService.findOneByUserKey(modelMetadata.parentModelUserKey);
1214
+ const parentModel = await this.getModelByUserKeyCached(modelMetadata.parentModelUserKey, {
1215
+ moduleName: moduleMetadata.name,
1216
+ component: 'module-model-fields',
1217
+ details: `parentModel=${modelMetadata.parentModelUserKey}`,
1218
+ });
662
1219
  modelMetaDataWithoutFields['parentModel'] = parentModel;
663
1220
  }
664
- await this.modelMetadataService.upsert(modelMetaDataWithoutFields);
665
- const model = await this.modelMetadataService.findOneBySingularName(modelMetadata.singularName);
1221
+ const upsertedModel = await this.timeOperation('model-upsert', () => this.modelMetadataService.upsert(modelMetaDataWithoutFields), {
1222
+ moduleName: moduleMetadata.name,
1223
+ component: 'module-model-fields',
1224
+ serviceCall: 'modelMetadataService.upsert',
1225
+ details: `model=${modelMetadata.singularName}`,
1226
+ });
1227
+ this.modelLookupCache.set(modelMetadata.singularName, upsertedModel ?? null);
1228
+ const model = await this.timeOperation('model-find-by-singular-name', () => this.modelMetadataService.findOneBySingularName(modelMetadata.singularName), {
1229
+ moduleName: moduleMetadata.name,
1230
+ component: 'module-model-fields',
1231
+ serviceCall: 'modelMetadataService.findOneBySingularName',
1232
+ details: `model=${modelMetadata.singularName}`,
1233
+ });
666
1234
  if (this.enablePruning) {
667
- pruned += await this.pruneFieldsForModel(model, fieldsMetadata);
1235
+ pruned += await this.timeOperation('prune-fields-for-model', () => this.pruneFieldsForModel(model, fieldsMetadata), {
1236
+ moduleName: moduleMetadata.name,
1237
+ component: 'module-model-fields',
1238
+ serviceCall: 'pruneFieldsForModel',
1239
+ details: `model=${modelMetadata.singularName}`,
1240
+ });
668
1241
  }
669
1242
  let userKeyField = null;
670
1243
  const userKeyFieldName = modelMetadata.userKeyFieldUserKey;
1244
+ const existingFieldsByName = await this.timeOperation('field-preload-for-model', () => this.loadExistingFieldsByName(fieldMetadataRepo, model.id), {
1245
+ moduleName: moduleMetadata.name,
1246
+ component: 'module-model-fields',
1247
+ serviceCall: 'loadExistingFieldsByName',
1248
+ details: `model=${modelMetadata.singularName}`,
1249
+ });
671
1250
  upserted += fieldsMetadata?.length ?? 0;
672
1251
  for (let k = 0; k < fieldsMetadata.length; k++) {
673
1252
  const fieldMetadata = fieldsMetadata[k];
674
1253
  fieldMetadata['model'] = model;
675
1254
  if (fieldMetadata.mediaStorageProviderUserKey) {
676
- fieldMetadata['mediaStorageProvider'] = await this.mediaStorageProviderMetadataService.findOneByUserKey(fieldMetadata.mediaStorageProviderUserKey);
1255
+ fieldMetadata['mediaStorageProvider'] = await this.getMediaStorageProviderByUserKeyCached(fieldMetadata.mediaStorageProviderUserKey, {
1256
+ moduleName: moduleMetadata.name,
1257
+ component: 'module-model-fields',
1258
+ details: `provider=${fieldMetadata.mediaStorageProviderUserKey}`,
1259
+ });
677
1260
  }
678
- const affectedField = await this.fieldMetadataService.upsert(fieldMetadata);
1261
+ const affectedField = await this.timeOperation('field-upsert', () => this.upsertFieldMetadataWithPreloadedExisting(fieldMetadataRepo, existingFieldsByName, fieldMetadata), {
1262
+ moduleName: moduleMetadata.name,
1263
+ component: 'module-model-fields',
1264
+ serviceCall: 'upsertFieldMetadataWithPreloadedExisting',
1265
+ details: `field=${fieldMetadata.name} model=${modelMetadata.singularName}`,
1266
+ });
679
1267
  if (fieldMetadata.name === userKeyFieldName || fieldMetadata.isUserKey) {
680
1268
  const { model, ...fieldData } = affectedField;
681
1269
  userKeyField = fieldData;
@@ -683,25 +1271,285 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
683
1271
  }
684
1272
  if (userKeyField) {
685
1273
  modelMetaDataWithoutFields['userKeyField'] = userKeyField;
686
- await this.modelMetadataService.upsert(modelMetaDataWithoutFields);
1274
+ await this.timeOperation('model-user-key-field-upsert', () => this.modelMetadataService.upsert(modelMetaDataWithoutFields), {
1275
+ moduleName: moduleMetadata.name,
1276
+ component: 'module-model-fields',
1277
+ serviceCall: 'modelMetadataService.upsert',
1278
+ details: `model=${modelMetadata.singularName} userKeyField=${userKeyField?.name ?? 'unknown'}`,
1279
+ });
687
1280
  }
688
1281
  }
689
1282
  if (this.enablePruning) {
690
- pruned += await this.pruneModels(modelsMetadata, moduleMetadata.name);
1283
+ pruned += await this.timeOperation('prune-models', () => this.pruneModels(modelsMetadata, moduleMetadata.name), {
1284
+ moduleName: moduleMetadata.name,
1285
+ component: 'module-model-fields',
1286
+ serviceCall: 'pruneModels',
1287
+ });
691
1288
  }
692
- this.logger.debug(`[End] Processing module metadata`);
693
1289
  return { pruned, upserted };
694
1290
  }
695
1291
  getSeedArray(value) {
696
1292
  return Array.isArray(value) ? value : [];
697
1293
  }
1294
+ async loadExistingFieldsByName(fieldMetadataRepo, modelId) {
1295
+ const existingFields = await fieldMetadataRepo.find({
1296
+ where: {
1297
+ model: { id: modelId },
1298
+ },
1299
+ relations: {
1300
+ model: true,
1301
+ mediaStorageProvider: true,
1302
+ },
1303
+ });
1304
+ return new Map(existingFields.map((field) => [field.name, field]));
1305
+ }
1306
+ async primeModuleLookupCache(moduleUserKeys) {
1307
+ const missingModuleUserKeys = [...new Set(moduleUserKeys.filter((moduleUserKey) => Boolean(moduleUserKey) && !this.moduleLookupCache.has(moduleUserKey)))];
1308
+ if (missingModuleUserKeys.length === 0) {
1309
+ return;
1310
+ }
1311
+ const moduleRepo = this.dataSource.getRepository(module_metadata_entity_1.ModuleMetadata);
1312
+ const existingModules = await moduleRepo.find({
1313
+ where: {
1314
+ name: (0, typeorm_1.In)(missingModuleUserKeys),
1315
+ },
1316
+ });
1317
+ const moduleByName = new Map(existingModules.map((module) => [module.name, module]));
1318
+ for (const moduleUserKey of missingModuleUserKeys) {
1319
+ this.moduleLookupCache.set(moduleUserKey, moduleByName.get(moduleUserKey) ?? null);
1320
+ }
1321
+ }
1322
+ async primeModelLookupCache(modelUserKeys) {
1323
+ const missingModelUserKeys = [...new Set(modelUserKeys.filter((modelUserKey) => Boolean(modelUserKey) && !this.modelLookupCache.has(modelUserKey)))];
1324
+ if (missingModelUserKeys.length === 0) {
1325
+ return;
1326
+ }
1327
+ const modelRepo = this.dataSource.getRepository(model_metadata_entity_1.ModelMetadata);
1328
+ const existingModels = await modelRepo.find({
1329
+ where: {
1330
+ singularName: (0, typeorm_1.In)(missingModelUserKeys),
1331
+ },
1332
+ relations: {
1333
+ module: true,
1334
+ userKeyField: true,
1335
+ },
1336
+ });
1337
+ const modelBySingularName = new Map(existingModels.map((model) => [model.singularName, model]));
1338
+ for (const modelUserKey of missingModelUserKeys) {
1339
+ this.modelLookupCache.set(modelUserKey, modelBySingularName.get(modelUserKey) ?? null);
1340
+ }
1341
+ }
1342
+ async primeViewLookupCache(viewUserKeys) {
1343
+ const missingViewUserKeys = [...new Set(viewUserKeys.filter((viewUserKey) => Boolean(viewUserKey) && !this.viewLookupCache.has(viewUserKey)))];
1344
+ if (missingViewUserKeys.length === 0) {
1345
+ return;
1346
+ }
1347
+ const viewRepo = this.dataSource.getRepository(view_metadata_entity_1.ViewMetadata);
1348
+ const existingViews = await viewRepo.find({
1349
+ where: {
1350
+ name: (0, typeorm_1.In)(missingViewUserKeys),
1351
+ },
1352
+ relations: {
1353
+ module: true,
1354
+ model: true,
1355
+ },
1356
+ });
1357
+ const viewByName = new Map(existingViews.map((view) => [view.name, view]));
1358
+ for (const viewUserKey of missingViewUserKeys) {
1359
+ this.viewLookupCache.set(viewUserKey, viewByName.get(viewUserKey) ?? null);
1360
+ }
1361
+ }
1362
+ async loadExistingViewsByName(viewRepo, viewNames) {
1363
+ const uniqueViewNames = [...new Set(viewNames.filter(Boolean))];
1364
+ if (uniqueViewNames.length === 0) {
1365
+ return new Map();
1366
+ }
1367
+ const existingViews = await viewRepo.find({
1368
+ where: {
1369
+ name: (0, typeorm_1.In)(uniqueViewNames),
1370
+ },
1371
+ relations: {
1372
+ module: true,
1373
+ model: true,
1374
+ },
1375
+ });
1376
+ return new Map(existingViews.map((view) => [view.name, view]));
1377
+ }
1378
+ async loadExistingActionsByName(actionRepo, actionNames) {
1379
+ const uniqueActionNames = [...new Set(actionNames.filter(Boolean))];
1380
+ if (uniqueActionNames.length === 0) {
1381
+ return new Map();
1382
+ }
1383
+ const existingActions = await actionRepo.find({
1384
+ where: {
1385
+ name: (0, typeorm_1.In)(uniqueActionNames),
1386
+ },
1387
+ relations: {
1388
+ module: true,
1389
+ model: true,
1390
+ view: true,
1391
+ },
1392
+ });
1393
+ return new Map(existingActions.map((action) => [action.name, action]));
1394
+ }
1395
+ normalizeJsonFieldValue(value) {
1396
+ if (typeof value === 'string') {
1397
+ const trimmedValue = value.trim();
1398
+ if ((trimmedValue.startsWith('{') && trimmedValue.endsWith('}'))
1399
+ || (trimmedValue.startsWith('[') && trimmedValue.endsWith(']'))) {
1400
+ try {
1401
+ return this.normalizeJsonFieldValue(JSON.parse(trimmedValue));
1402
+ }
1403
+ catch {
1404
+ return value;
1405
+ }
1406
+ }
1407
+ return value;
1408
+ }
1409
+ if (Array.isArray(value)) {
1410
+ return value.map((item) => this.normalizeJsonFieldValue(item));
1411
+ }
1412
+ if (value && typeof value === 'object') {
1413
+ return Object.keys(value)
1414
+ .sort()
1415
+ .reduce((result, key) => {
1416
+ result[key] = this.normalizeJsonFieldValue(value[key]);
1417
+ return result;
1418
+ }, {});
1419
+ }
1420
+ return value;
1421
+ }
1422
+ getCanonicalJsonFieldString(value) {
1423
+ return JSON.stringify(this.normalizeJsonFieldValue(value) ?? null);
1424
+ }
1425
+ hasViewMetadataChanges(existingView, updateDto) {
1426
+ const relationFields = new Set(['module', 'model']);
1427
+ const jsonFields = new Set(['layout', 'context']);
1428
+ return this.viewComparableFields.some((key) => {
1429
+ const value = updateDto[key];
1430
+ if (typeof value === 'undefined') {
1431
+ return false;
1432
+ }
1433
+ if (relationFields.has(key)) {
1434
+ const relationValue = value;
1435
+ return existingView[key]?.id !== relationValue?.id;
1436
+ }
1437
+ if (jsonFields.has(key)) {
1438
+ return this.getCanonicalJsonFieldString(existingView[key]) !== this.getCanonicalJsonFieldString(value);
1439
+ }
1440
+ return existingView[key] !== value;
1441
+ });
1442
+ }
1443
+ hasActionMetadataChanges(existingAction, updateDto) {
1444
+ const relationFields = new Set(['module', 'model', 'view']);
1445
+ const jsonFields = new Set(['domain', 'context']);
1446
+ return this.actionComparableFields.some((key) => {
1447
+ const value = updateDto[key];
1448
+ if (typeof value === 'undefined') {
1449
+ return false;
1450
+ }
1451
+ if (relationFields.has(key)) {
1452
+ const relationValue = value;
1453
+ return existingAction[key]?.id !== relationValue?.id;
1454
+ }
1455
+ if (jsonFields.has(key)) {
1456
+ return this.getCanonicalJsonFieldString(existingAction[key]) !== this.getCanonicalJsonFieldString(value);
1457
+ }
1458
+ return existingAction[key] !== value;
1459
+ });
1460
+ }
1461
+ async upsertViewMetadataWithPreloadedExisting(viewRepo, existingViewsByName, updateDto) {
1462
+ const existingView = existingViewsByName.get(updateDto.name);
1463
+ if (existingView) {
1464
+ if (!this.hasViewMetadataChanges(existingView, updateDto)) {
1465
+ return { entity: existingView, outcome: 'skipped' };
1466
+ }
1467
+ const updatedView = { ...existingView, ...updateDto };
1468
+ const savedView = await this.timeOperation('view-save', () => viewRepo.save(updatedView), {
1469
+ component: 'views',
1470
+ serviceCall: 'viewRepo.save',
1471
+ details: `view=${updateDto.name}`,
1472
+ });
1473
+ existingViewsByName.set(updateDto.name, savedView);
1474
+ return { entity: savedView, outcome: 'updated' };
1475
+ }
1476
+ const view = viewRepo.create(updateDto);
1477
+ const savedView = await this.timeOperation('view-save', () => viewRepo.save(view), {
1478
+ component: 'views',
1479
+ serviceCall: 'viewRepo.save',
1480
+ details: `view=${updateDto.name}`,
1481
+ });
1482
+ existingViewsByName.set(updateDto.name, savedView);
1483
+ return { entity: savedView, outcome: 'created' };
1484
+ }
1485
+ async upsertActionMetadataWithPreloadedExisting(actionRepo, existingActionsByName, updateDto) {
1486
+ const existingAction = existingActionsByName.get(updateDto.name);
1487
+ if (existingAction) {
1488
+ if (!this.hasActionMetadataChanges(existingAction, updateDto)) {
1489
+ return { entity: existingAction, outcome: 'skipped' };
1490
+ }
1491
+ const updatedAction = { ...existingAction, ...updateDto };
1492
+ const savedAction = await this.timeOperation('action-save', () => actionRepo.save(updatedAction), {
1493
+ component: 'actions',
1494
+ serviceCall: 'actionRepo.save',
1495
+ details: `action=${updateDto.name}`,
1496
+ });
1497
+ existingActionsByName.set(updateDto.name, savedAction);
1498
+ return { entity: savedAction, outcome: 'updated' };
1499
+ }
1500
+ const action = actionRepo.create(updateDto);
1501
+ const savedAction = await this.timeOperation('action-save', () => actionRepo.save(action), {
1502
+ component: 'actions',
1503
+ serviceCall: 'actionRepo.save',
1504
+ details: `action=${updateDto.name}`,
1505
+ });
1506
+ existingActionsByName.set(updateDto.name, savedAction);
1507
+ return { entity: savedAction, outcome: 'created' };
1508
+ }
1509
+ async upsertFieldMetadataWithPreloadedExisting(fieldMetadataRepo, existingFieldsByName, updateDto) {
1510
+ const existingFieldMetadata = existingFieldsByName.get(updateDto.name);
1511
+ if (existingFieldMetadata) {
1512
+ const hasChanges = Object.entries(updateDto).some(([key, value]) => {
1513
+ const relationValue = value;
1514
+ if (key === 'model') {
1515
+ return existingFieldMetadata.model?.id !== relationValue?.id;
1516
+ }
1517
+ if (key === 'mediaStorageProvider') {
1518
+ return existingFieldMetadata.mediaStorageProvider?.id !== relationValue?.id;
1519
+ }
1520
+ const currentValue = existingFieldMetadata[key];
1521
+ if (Array.isArray(currentValue) || Array.isArray(value)) {
1522
+ return JSON.stringify(currentValue ?? null) !== JSON.stringify(value ?? null);
1523
+ }
1524
+ if (value && typeof value === 'object') {
1525
+ return JSON.stringify(currentValue ?? null) !== JSON.stringify(value ?? null);
1526
+ }
1527
+ return currentValue !== value;
1528
+ });
1529
+ if (!hasChanges) {
1530
+ return existingFieldMetadata;
1531
+ }
1532
+ const updatedFieldMetadata = { ...existingFieldMetadata, ...updateDto };
1533
+ const savedFieldMetadata = await fieldMetadataRepo.save(updatedFieldMetadata);
1534
+ existingFieldsByName.set(updateDto.name, savedFieldMetadata);
1535
+ return savedFieldMetadata;
1536
+ }
1537
+ const fieldMetadata = fieldMetadataRepo.create(updateDto);
1538
+ const savedFieldMetadata = await fieldMetadataRepo.save(fieldMetadata);
1539
+ existingFieldsByName.set(updateDto.name, savedFieldMetadata);
1540
+ return savedFieldMetadata;
1541
+ }
698
1542
  async handleSeedSecurityRules(rulesDto) {
699
1543
  if (!rulesDto || rulesDto.length === 0) {
700
1544
  this.logger.debug(`No security rules found to seed`);
701
1545
  return;
702
1546
  }
703
1547
  for (const dto of rulesDto) {
704
- await this.securityRuleRepo.upsertWithDto({ ...dto, securityRuleConfig: JSON.stringify(dto.securityRuleConfig) });
1548
+ await this.timeOperation('security-rule-upsert', () => this.securityRuleRepo.upsertWithDto({ ...dto, securityRuleConfig: JSON.stringify(dto.securityRuleConfig) }), {
1549
+ component: 'security-rules',
1550
+ serviceCall: 'securityRuleRepo.upsertWithDto',
1551
+ details: `rule=${dto.name}`,
1552
+ });
705
1553
  }
706
1554
  }
707
1555
  async handleSeedListOfValues(listOfValuesDto) {
@@ -711,8 +1559,16 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
711
1559
  }
712
1560
  for (let j = 0; j < listOfValuesDto.length; j++) {
713
1561
  const listOfValueDto = listOfValuesDto[j];
714
- listOfValueDto['module'] = await this.moduleMetadataService.findOneByUserKey(listOfValueDto.moduleUserKey);
715
- await this.listOfValuesService.upsert(listOfValuesDto[j]);
1562
+ listOfValueDto['module'] = await this.getModuleByUserKeyCached(listOfValueDto.moduleUserKey, {
1563
+ moduleName: listOfValueDto.moduleUserKey,
1564
+ component: 'list-of-values',
1565
+ details: `module=${listOfValueDto.moduleUserKey}`,
1566
+ });
1567
+ await this.timeOperation('lov-upsert', () => this.listOfValuesService.upsert(listOfValuesDto[j]), {
1568
+ component: 'list-of-values',
1569
+ serviceCall: 'listOfValuesService.upsert',
1570
+ details: `type=${listOfValueDto.type} value=${listOfValueDto.value}`,
1571
+ });
716
1572
  }
717
1573
  }
718
1574
  async handleSeedScheduledJobs(createScheduledJobDto) {
@@ -721,7 +1577,11 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
721
1577
  return;
722
1578
  }
723
1579
  for (const dto of createScheduledJobDto) {
724
- await this.scheduledJobRepository.upsertWithDto(dto);
1580
+ await this.timeOperation('scheduled-job-upsert', () => this.scheduledJobRepository.upsertWithDto(dto), {
1581
+ component: 'scheduled-jobs',
1582
+ serviceCall: 'scheduledJobRepository.upsertWithDto',
1583
+ details: `schedule=${dto.scheduleName}`,
1584
+ });
725
1585
  }
726
1586
  }
727
1587
  async handleSeedSavedFilters(createSavedFilterDto) {
@@ -731,9 +1591,47 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
731
1591
  }
732
1592
  for (const dto of createSavedFilterDto) {
733
1593
  this.validateSavedFilterQueryJsonWrapper(dto);
734
- await this.savedFiltersRepo.upsertWithDto({ ...dto, filterQueryJson: JSON.stringify(dto.filterQueryJson), isSeeded: true });
1594
+ await this.timeOperation('saved-filter-upsert', () => this.savedFiltersRepo.upsertWithDto({ ...dto, filterQueryJson: JSON.stringify(dto.filterQueryJson), isSeeded: true }), {
1595
+ component: 'saved-filters',
1596
+ serviceCall: 'savedFiltersRepo.upsertWithDto',
1597
+ details: `filter=${dto.name}`,
1598
+ });
735
1599
  }
736
1600
  }
1601
+ async handleSeedLocales(localesDto) {
1602
+ if (!localesDto || localesDto.length === 0) {
1603
+ this.logger.debug(`No locales found to seed`);
1604
+ return;
1605
+ }
1606
+ for (const dto of localesDto) {
1607
+ if (dto.isDefault) {
1608
+ const existingDefaultLocales = await this.localeRepo.find({
1609
+ where: {
1610
+ isDefault: true,
1611
+ },
1612
+ });
1613
+ for (const locale of existingDefaultLocales) {
1614
+ if (locale.locale !== dto.locale) {
1615
+ await this.localeRepo.save({
1616
+ ...locale,
1617
+ isDefault: false,
1618
+ });
1619
+ }
1620
+ }
1621
+ }
1622
+ const existingLocale = await this.localeRepo.findOne({
1623
+ where: {
1624
+ locale: dto.locale,
1625
+ },
1626
+ });
1627
+ await this.localeRepo.save(this.localeRepo.create({
1628
+ ...existingLocale,
1629
+ ...dto,
1630
+ }));
1631
+ }
1632
+ const locales = await this.localeRepo.find();
1633
+ this.solidRegistry.registerlocales(locales);
1634
+ }
737
1635
  validateSavedFilterQueryJsonWrapper(dto) {
738
1636
  const filterName = dto?.name ?? '<unnamed>';
739
1637
  const filterQueryJson = dto?.filterQueryJson;
@@ -755,7 +1653,11 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
755
1653
  return;
756
1654
  }
757
1655
  for (const dto of modelSequencesDto) {
758
- await this.modelSequenceRepo.upsertWithDto(dto);
1656
+ await this.timeOperation('model-sequence-upsert', () => this.modelSequenceRepo.upsertWithDto(dto), {
1657
+ component: 'model-sequences',
1658
+ serviceCall: 'modelSequenceRepo.upsertWithDto',
1659
+ details: `sequence=${dto.sequenceName}`,
1660
+ });
759
1661
  }
760
1662
  }
761
1663
  async pruneModelSequences(modelSequencesDto, moduleName) {
@@ -764,7 +1666,11 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
764
1666
  return 0;
765
1667
  }
766
1668
  const sequences = modelSequencesDto ?? [];
767
- const module = await this.moduleMetadataService.findOneByUserKey(moduleName);
1669
+ const module = await this.getModuleByUserKeyCached(moduleName, {
1670
+ moduleName,
1671
+ component: 'model-sequences',
1672
+ details: `module=${moduleName}`,
1673
+ });
768
1674
  if (!module) {
769
1675
  this.logger.warn(`Skipping model sequence prune: module not found for ${moduleName}.`);
770
1676
  return 0;
@@ -798,7 +1704,11 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
798
1704
  return 0;
799
1705
  }
800
1706
  const savedFilters = savedFiltersDto ?? [];
801
- const module = await this.moduleMetadataService.findOneByUserKey(moduleName);
1707
+ const module = await this.getModuleByUserKeyCached(moduleName, {
1708
+ moduleName,
1709
+ component: 'saved-filters',
1710
+ details: `module=${moduleName}`,
1711
+ });
802
1712
  if (!module) {
803
1713
  this.logger.warn(`Skipping saved filters prune: module not found for ${moduleName}.`);
804
1714
  return 0;
@@ -833,7 +1743,11 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
833
1743
  return 0;
834
1744
  }
835
1745
  const scheduledJobs = scheduledJobsDto ?? [];
836
- const module = await this.moduleMetadataService.findOneByUserKey(moduleName);
1746
+ const module = await this.getModuleByUserKeyCached(moduleName, {
1747
+ moduleName,
1748
+ component: 'scheduled-jobs',
1749
+ details: `module=${moduleName}`,
1750
+ });
837
1751
  if (!module) {
838
1752
  this.logger.warn(`Skipping scheduled jobs prune: module not found for ${moduleName}.`);
839
1753
  return 0;
@@ -867,7 +1781,11 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
867
1781
  return 0;
868
1782
  }
869
1783
  const securityRules = securityRulesDto ?? [];
870
- const module = await this.moduleMetadataService.findOneByUserKey(moduleName);
1784
+ const module = await this.getModuleByUserKeyCached(moduleName, {
1785
+ moduleName,
1786
+ component: 'security-rules',
1787
+ details: `module=${moduleName}`,
1788
+ });
871
1789
  if (!module) {
872
1790
  this.logger.warn(`Skipping security rules prune: module not found for ${moduleName}.`);
873
1791
  return 0;
@@ -902,7 +1820,11 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
902
1820
  return 0;
903
1821
  }
904
1822
  const listOfValues = listOfValuesDto ?? [];
905
- const module = await this.moduleMetadataService.findOneByUserKey(moduleName);
1823
+ const module = await this.getModuleByUserKeyCached(moduleName, {
1824
+ moduleName,
1825
+ component: 'list-of-values',
1826
+ details: `module=${moduleName}`,
1827
+ });
906
1828
  if (!module) {
907
1829
  this.logger.warn(`Skipping list of values prune: module not found for ${moduleName}.`);
908
1830
  return 0;
@@ -944,7 +1866,11 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
944
1866
  return 0;
945
1867
  }
946
1868
  const menus = menusDto ?? [];
947
- const module = await this.moduleMetadataService.findOneByUserKey(moduleName);
1869
+ const module = await this.getModuleByUserKeyCached(moduleName, {
1870
+ moduleName,
1871
+ component: 'menus',
1872
+ details: `module=${moduleName}`,
1873
+ });
948
1874
  if (!module) {
949
1875
  this.logger.warn(`Skipping menus prune: module not found for ${moduleName}.`);
950
1876
  return 0;
@@ -986,7 +1912,11 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
986
1912
  return 0;
987
1913
  }
988
1914
  const views = viewsDto ?? [];
989
- const module = await this.moduleMetadataService.findOneByUserKey(moduleName);
1915
+ const module = await this.getModuleByUserKeyCached(moduleName, {
1916
+ moduleName,
1917
+ component: 'views',
1918
+ details: `module=${moduleName}`,
1919
+ });
990
1920
  if (!module) {
991
1921
  this.logger.warn(`Skipping views prune: module not found for ${moduleName}.`);
992
1922
  return 0;
@@ -1039,7 +1969,11 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
1039
1969
  return 0;
1040
1970
  }
1041
1971
  const actions = actionsDto ?? [];
1042
- const module = await this.moduleMetadataService.findOneByUserKey(moduleName);
1972
+ const module = await this.getModuleByUserKeyCached(moduleName, {
1973
+ moduleName,
1974
+ component: 'actions',
1975
+ details: `module=${moduleName}`,
1976
+ });
1043
1977
  if (!module) {
1044
1978
  this.logger.warn(`Skipping actions prune: module not found for ${moduleName}.`);
1045
1979
  return 0;
@@ -1125,7 +2059,11 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
1125
2059
  return 0;
1126
2060
  }
1127
2061
  const models = modelsMetadata ?? [];
1128
- const module = await this.moduleMetadataService.findOneByUserKey(moduleName);
2062
+ const module = await this.getModuleByUserKeyCached(moduleName, {
2063
+ moduleName,
2064
+ component: 'module-model-fields',
2065
+ details: `module=${moduleName}`,
2066
+ });
1129
2067
  if (!module) {
1130
2068
  this.logger.warn(`Skipping models prune: module not found for ${moduleName}.`);
1131
2069
  return 0;
@@ -1241,11 +2179,13 @@ exports.ModuleMetadataSeederService = ModuleMetadataSeederService = ModuleMetada
1241
2179
  role_metadata_service_1.RoleMetadataService,
1242
2180
  user_service_1.UserService,
1243
2181
  authentication_service_1.AuthenticationService,
2182
+ api_key_service_1.ApiKeyService,
1244
2183
  action_metadata_service_1.ActionMetadataService,
1245
2184
  view_metadata_service_1.ViewMetadataService,
1246
2185
  email_template_service_1.EmailTemplateService,
1247
2186
  sms_template_service_1.SmsTemplateService,
1248
2187
  list_of_values_service_1.ListOfValuesService,
2188
+ user_api_key_repository_1.UserApiKeyRepository,
1249
2189
  permission_metadata_repository_1.PermissionMetadataRepository,
1250
2190
  solid_registry_1.SolidRegistry,
1251
2191
  setting_service_1.SettingService,
@@ -1255,6 +2195,7 @@ exports.ModuleMetadataSeederService = ModuleMetadataSeederService = ModuleMetada
1255
2195
  scheduled_job_repository_1.ScheduledJobRepository,
1256
2196
  saved_filters_repository_1.SavedFiltersRepository,
1257
2197
  typeorm_1.DataSource,
1258
- model_sequence_repository_1.ModelSequenceRepository])
2198
+ model_sequence_repository_1.ModelSequenceRepository,
2199
+ locale_repository_1.LocaleRepository])
1259
2200
  ], ModuleMetadataSeederService);
1260
2201
  //# sourceMappingURL=module-metadata-seeder.service.js.map